...

Source file src/github.com/theupdateframework/go-tuf/verify/verify.go

Documentation: github.com/theupdateframework/go-tuf/verify

     1  package verify
     2  
     3  import (
     4  	"encoding/json"
     5  	"strings"
     6  	"time"
     7  
     8  	"github.com/secure-systems-lab/go-securesystemslib/cjson"
     9  	"github.com/theupdateframework/go-tuf/data"
    10  	"github.com/theupdateframework/go-tuf/internal/roles"
    11  	"github.com/theupdateframework/go-tuf/pkg/keys"
    12  )
    13  
    14  type signedMeta struct {
    15  	Type    string    `json:"_type"`
    16  	Expires time.Time `json:"expires"`
    17  	Version int64     `json:"version"`
    18  }
    19  
    20  // VerifySignature takes a signed JSON message, a signature, and a
    21  // verifier and verifies the given signature on the JSON message
    22  // using the verifier. It returns an error if verification fails.
    23  func VerifySignature(signed json.RawMessage, sig data.HexBytes,
    24  	verifier keys.Verifier) error {
    25  	var decoded map[string]interface{}
    26  	if err := json.Unmarshal(signed, &decoded); err != nil {
    27  		return err
    28  	}
    29  	msg, err := cjson.EncodeCanonical(decoded)
    30  	if err != nil {
    31  		return err
    32  	}
    33  	return verifier.Verify(msg, sig)
    34  }
    35  
    36  func (db *DB) VerifyIgnoreExpiredCheck(s *data.Signed, role string, minVersion int64) error {
    37  	if err := db.VerifySignatures(s, role); err != nil {
    38  		return err
    39  	}
    40  
    41  	sm := &signedMeta{}
    42  	if err := json.Unmarshal(s.Signed, sm); err != nil {
    43  		return err
    44  	}
    45  
    46  	if roles.IsTopLevelRole(role) {
    47  		// Top-level roles can only sign metadata of the same type (e.g. snapshot
    48  		// metadata must be signed by the snapshot role).
    49  		if !strings.EqualFold(sm.Type, role) {
    50  			return ErrWrongMetaType
    51  		}
    52  	} else {
    53  		// Delegated (non-top-level) roles may only sign targets metadata.
    54  		if strings.ToLower(sm.Type) != "targets" {
    55  			return ErrWrongMetaType
    56  		}
    57  	}
    58  
    59  	if sm.Version < minVersion {
    60  		return ErrLowVersion{sm.Version, minVersion}
    61  	}
    62  
    63  	return nil
    64  }
    65  
    66  func (db *DB) Verify(s *data.Signed, role string, minVersion int64) error {
    67  	// Verify signatures and versions
    68  	err := db.VerifyIgnoreExpiredCheck(s, role, minVersion)
    69  
    70  	if err != nil {
    71  		return err
    72  	}
    73  
    74  	sm := &signedMeta{}
    75  	if err := json.Unmarshal(s.Signed, sm); err != nil {
    76  		return err
    77  	}
    78  	// Verify expiration
    79  	if IsExpired(sm.Expires) {
    80  		return ErrExpired{sm.Expires}
    81  	}
    82  
    83  	return nil
    84  }
    85  
    86  var IsExpired = func(t time.Time) bool {
    87  	return time.Until(t) <= 0
    88  }
    89  
    90  func (db *DB) VerifySignatures(s *data.Signed, role string) error {
    91  	if len(s.Signatures) == 0 {
    92  		return ErrNoSignatures
    93  	}
    94  
    95  	roleData := db.GetRole(role)
    96  	if roleData == nil {
    97  		return ErrUnknownRole{role}
    98  	}
    99  
   100  	// Verify that a threshold of keys signed the data. Since keys can have
   101  	// multiple key ids, we need to protect against multiple attached
   102  	// signatures that just differ on the key id.
   103  	verifiedKeyIDs := make(map[string]struct{})
   104  	numVerifiedKeys := 0
   105  	for _, sig := range s.Signatures {
   106  		if !roleData.ValidKey(sig.KeyID) {
   107  			continue
   108  		}
   109  		verifier, err := db.GetVerifier(sig.KeyID)
   110  		if err != nil {
   111  			continue
   112  		}
   113  
   114  		if err := VerifySignature(s.Signed, sig.Signature, verifier); err != nil {
   115  			// If a signature fails verification, don't count it towards the
   116  			// threshold but also return early and error out immediately.
   117  			// Note: Because of this, it is impossible to distinguish between
   118  			// an error of an invalid signature and a threshold not achieved.
   119  			// Invalid signatures lead to not achieving the threshold.
   120  			continue
   121  		}
   122  
   123  		// Only consider this key valid if we haven't seen any of it's
   124  		// key ids before.
   125  		// Careful: we must not rely on the key IDs _declared in the file_,
   126  		// instead we get to decide what key IDs this key correspond to.
   127  		// XXX dangerous; better stop supporting multiple key IDs altogether.
   128  		keyIDs := verifier.MarshalPublicKey().IDs()
   129  		wasKeySeen := false
   130  		for _, keyID := range keyIDs {
   131  			if _, present := verifiedKeyIDs[keyID]; present {
   132  				wasKeySeen = true
   133  			}
   134  		}
   135  		if !wasKeySeen {
   136  			for _, id := range keyIDs {
   137  				verifiedKeyIDs[id] = struct{}{}
   138  			}
   139  
   140  			numVerifiedKeys++
   141  		}
   142  	}
   143  	if numVerifiedKeys < roleData.Threshold {
   144  		return ErrRoleThreshold{roleData.Threshold, numVerifiedKeys}
   145  	}
   146  
   147  	return nil
   148  }
   149  
   150  func (db *DB) Unmarshal(b []byte, v interface{}, role string, minVersion int64) error {
   151  	s := &data.Signed{}
   152  	if err := json.Unmarshal(b, s); err != nil {
   153  		return err
   154  	}
   155  	if err := db.Verify(s, role, minVersion); err != nil {
   156  		return err
   157  	}
   158  	return json.Unmarshal(s.Signed, v)
   159  }
   160  
   161  // UnmarshalExpired is exactly like Unmarshal except ignores expired timestamp error.
   162  func (db *DB) UnmarshalIgnoreExpired(b []byte, v interface{}, role string, minVersion int64) error {
   163  	s := &data.Signed{}
   164  	if err := json.Unmarshal(b, s); err != nil {
   165  		return err
   166  	}
   167  	// Note: If verification fails, then we wont attempt to unmarshal
   168  	// unless when verification error is errExpired.
   169  	verifyErr := db.Verify(s, role, minVersion)
   170  	if verifyErr != nil {
   171  		if _, ok := verifyErr.(ErrExpired); !ok {
   172  			return verifyErr
   173  		}
   174  	}
   175  	return json.Unmarshal(s.Signed, v)
   176  }
   177  
   178  func (db *DB) UnmarshalTrusted(b []byte, v interface{}, role string) error {
   179  	s := &data.Signed{}
   180  	if err := json.Unmarshal(b, s); err != nil {
   181  		return err
   182  	}
   183  	if err := db.VerifySignatures(s, role); err != nil {
   184  		return err
   185  	}
   186  	return json.Unmarshal(s.Signed, v)
   187  }
   188  

View as plain text