// VerifyCanSign returns nil if the role exists and we have at least one // signing key for the role, false otherwise. This does not check that we have // enough signing keys to meet the threshold, since we want to support the use // case of multiple signers for a role. It returns an error if the role doesn't // exist or if there are no signing keys. func (tr *Repo) VerifyCanSign(roleName string) error { var ( role data.BaseRole err error ) // we only need the BaseRole part of a delegation because we're just // checking KeyIDs if data.IsDelegation(roleName) { r, err := tr.GetDelegationRole(roleName) if err != nil { return err } role = r.BaseRole } else { role, err = tr.GetBaseRole(roleName) } if err != nil { return data.ErrInvalidRole{Role: roleName, Reason: "does not exist"} } for keyID, k := range role.Keys { check := []string{keyID} if canonicalID, err := utils.CanonicalKeyID(k); err == nil { check = append(check, canonicalID) } for _, id := range check { p, _, err := tr.cryptoService.GetPrivateKey(id) if err == nil && p != nil { return nil } } } return signed.ErrNoKeys{KeyIDs: role.ListKeyIDs()} }
func (tr Repo) sign(signedData *data.Signed, role data.BaseRole) (*data.Signed, error) { ks := role.ListKeys() if len(ks) < 1 { return nil, signed.ErrNoKeys{} } err := signed.Sign(tr.cryptoService, signedData, ks...) if err != nil { return nil, err } return signedData, nil }
// VerifySignatures checks the we have sufficient valid signatures for the given role func VerifySignatures(s *data.Signed, roleData data.BaseRole) error { if len(s.Signatures) == 0 { return ErrNoSignatures } if roleData.Threshold < 1 { return ErrRoleThreshold{} } logrus.Debugf("%s role has key IDs: %s", roleData.Name, strings.Join(roleData.ListKeyIDs(), ",")) // remarshal the signed part so we can verify the signature, since the signature has // to be of a canonically marshalled signed object var decoded map[string]interface{} if err := json.Unmarshal(s.Signed, &decoded); err != nil { return err } msg, err := json.MarshalCanonical(decoded) if err != nil { return err } valid := make(map[string]struct{}) for _, sig := range s.Signatures { logrus.Debug("verifying signature for key ID: ", sig.KeyID) key, ok := roleData.Keys[sig.KeyID] if !ok { logrus.Debugf("continuing b/c keyid lookup was nil: %s\n", sig.KeyID) continue } // method lookup is consistent due to Unmarshal JSON doing lower case for us. method := sig.Method verifier, ok := Verifiers[method] if !ok { logrus.Debugf("continuing b/c signing method is not supported: %s\n", sig.Method) continue } if err := verifier.Verify(key, sig.Signature, msg); err != nil { logrus.Debugf("continuing b/c signature was invalid\n") continue } valid[sig.KeyID] = struct{}{} } if len(valid) < roleData.Threshold { return ErrRoleThreshold{} } return nil }
// VerifySignatures checks the we have sufficient valid signatures for the given role func VerifySignatures(s *data.Signed, roleData data.BaseRole) error { if len(s.Signatures) == 0 { return ErrNoSignatures } if roleData.Threshold < 1 { return ErrRoleThreshold{} } logrus.Debugf("%s role has key IDs: %s", roleData.Name, strings.Join(roleData.ListKeyIDs(), ",")) // remarshal the signed part so we can verify the signature, since the signature has // to be of a canonically marshalled signed object var decoded map[string]interface{} if err := json.Unmarshal(*s.Signed, &decoded); err != nil { return err } msg, err := json.MarshalCanonical(decoded) if err != nil { return err } valid := make(map[string]struct{}) for i := range s.Signatures { sig := &(s.Signatures[i]) logrus.Debug("verifying signature for key ID: ", sig.KeyID) key, ok := roleData.Keys[sig.KeyID] if !ok { logrus.Debugf("continuing b/c keyid lookup was nil: %s\n", sig.KeyID) continue } // Check that the signature key ID actually matches the content ID of the key if key.ID() != sig.KeyID { return ErrInvalidKeyID{} } if err := VerifySignature(msg, sig, key); err != nil { logrus.Debugf("continuing b/c %s", err.Error()) continue } valid[sig.KeyID] = struct{}{} } if len(valid) < roleData.Threshold { return ErrRoleThreshold{ Msg: fmt.Sprintf("valid signatures did not meet threshold for %s", roleData.Name), } } return nil }
// SignRoot signs the root, using all keys from the "root" role (i.e. currently trusted) // as well as available keys used to sign the previous version, if the public part is // carried in tr.Root.Keys and the private key is available (i.e. probably previously // trusted keys, to allow rollover). If there are any errors, attempt to put root // back to the way it was (so version won't be incremented, for instance). func (tr *Repo) SignRoot(expires time.Time) (*data.Signed, error) { logrus.Debug("signing root...") // duplicate root and attempt to modify it rather than the existing root rootBytes, err := tr.Root.MarshalJSON() if err != nil { return nil, err } tempRoot := data.SignedRoot{} if err := json.Unmarshal(rootBytes, &tempRoot); err != nil { return nil, err } currRoot, err := tr.GetBaseRole(data.CanonicalRootRole) if err != nil { return nil, err } oldRootRoles := tr.getOldRootRoles() var latestSavedRole data.BaseRole rolesToSignWith := make([]data.BaseRole, 0, len(oldRootRoles)) if len(oldRootRoles) > 0 { sort.Sort(oldRootRoles) for _, vRole := range oldRootRoles { rolesToSignWith = append(rolesToSignWith, vRole.BaseRole) } latest := rolesToSignWith[len(rolesToSignWith)-1] latestSavedRole = data.BaseRole{ Name: data.CanonicalRootRole, Threshold: latest.Threshold, Keys: latest.Keys, } } // if the root role has changed and original role had not been saved as a previous role, save it now if !tr.originalRootRole.Equals(currRoot) && !tr.originalRootRole.Equals(latestSavedRole) { rolesToSignWith = append(rolesToSignWith, tr.originalRootRole) latestSavedRole = tr.originalRootRole versionName := oldRootVersionName(tempRoot.Signed.Version) tempRoot.Signed.Roles[versionName] = &data.RootRole{ KeyIDs: latestSavedRole.ListKeyIDs(), Threshold: latestSavedRole.Threshold} } tempRoot.Signed.Expires = expires tempRoot.Signed.Version++ // if the current role doesn't match with the latest saved role, save it if !currRoot.Equals(latestSavedRole) { rolesToSignWith = append(rolesToSignWith, currRoot) versionName := oldRootVersionName(tempRoot.Signed.Version) tempRoot.Signed.Roles[versionName] = &data.RootRole{ KeyIDs: currRoot.ListKeyIDs(), Threshold: currRoot.Threshold} } signed, err := tempRoot.ToSigned() if err != nil { return nil, err } signed, err = tr.sign(signed, rolesToSignWith, tr.getOptionalRootKeys(rolesToSignWith)) if err != nil { return nil, err } tr.Root = &tempRoot tr.Root.Signatures = signed.Signatures tr.originalRootRole = currRoot return signed, nil }
// SignRoot signs the root, using all keys from the "root" role (i.e. currently trusted) // as well as available keys used to sign the previous version, if the public part is // carried in tr.Root.Keys and the private key is available (i.e. probably previously // trusted keys, to allow rollover). If there are any errors, attempt to put root // back to the way it was (so version won't be incremented, for instance). func (tr *Repo) SignRoot(expires time.Time) (*data.Signed, error) { logrus.Debug("signing root...") // duplicate root and attempt to modify it rather than the existing root rootBytes, err := tr.Root.MarshalJSON() if err != nil { return nil, err } tempRoot := data.SignedRoot{} if err := json.Unmarshal(rootBytes, &tempRoot); err != nil { return nil, err } currRoot, err := tr.GetBaseRole(data.CanonicalRootRole) if err != nil { return nil, err } oldRootRoles := tr.getOldRootRoles() var latestSavedRole data.BaseRole rolesToSignWith := make([]data.BaseRole, 0, len(oldRootRoles)) if len(oldRootRoles) > 0 { sort.Sort(oldRootRoles) for _, vRole := range oldRootRoles { rolesToSignWith = append(rolesToSignWith, vRole.BaseRole) } latest := rolesToSignWith[len(rolesToSignWith)-1] latestSavedRole = data.BaseRole{ Name: data.CanonicalRootRole, Threshold: latest.Threshold, Keys: latest.Keys, } } // If the root role (root keys or root threshold) has changed, save the // previous role under the role name "root.<n>", such that the "n" is the // latest root.json version for which previous root role was valid. // Also, guard against re-saving the previous role if the latest // saved role is the same (which should not happen). // n = root.json version of the originalRootRole (previous role) // n+1 = root.json version of the currRoot (current role) // n-m = root.json version of latestSavedRole (not necessarily n-1, because the // last root rotation could have happened several root.json versions ago if !tr.originalRootRole.Equals(currRoot) && !tr.originalRootRole.Equals(latestSavedRole) { rolesToSignWith = append(rolesToSignWith, tr.originalRootRole) latestSavedRole = tr.originalRootRole versionName := oldRootVersionName(tempRoot.Signed.Version) tempRoot.Signed.Roles[versionName] = &data.RootRole{ KeyIDs: latestSavedRole.ListKeyIDs(), Threshold: latestSavedRole.Threshold} } tempRoot.Signed.Expires = expires tempRoot.Signed.Version++ rolesToSignWith = append(rolesToSignWith, currRoot) signed, err := tempRoot.ToSigned() if err != nil { return nil, err } signed, err = tr.sign(signed, rolesToSignWith, tr.getOptionalRootKeys(rolesToSignWith)) if err != nil { return nil, err } tr.Root = &tempRoot tr.Root.Signatures = signed.Signatures tr.originalRootRole = currRoot return signed, nil }
func (tr Repo) sign(signedData *data.Signed, role data.BaseRole) (*data.Signed, error) { if err := signed.Sign(tr.cryptoService, signedData, role.ListKeys()...); err != nil { return nil, err } return signedData, nil }