// CertsToKeys transforms each of the input certificate chains into its corresponding // PublicKey func CertsToKeys(leafCerts []*x509.Certificate, intCerts map[string][]*x509.Certificate) map[string]data.PublicKey { keys := make(map[string]data.PublicKey) for _, leafCert := range leafCerts { certBundle := []*x509.Certificate{leafCert} certID, err := FingerprintCert(leafCert) if err != nil { continue } if intCertsForLeafs, ok := intCerts[certID]; ok { certBundle = append(certBundle, intCertsForLeafs...) } certChainPEM, err := CertChainToPEM(certBundle) if err != nil { continue } var newKey data.PublicKey // Use the leaf cert's public key algorithm for typing switch leafCert.PublicKeyAlgorithm { case x509.RSA: newKey = data.NewRSAx509PublicKey(certChainPEM) case x509.ECDSA: newKey = data.NewECDSAx509PublicKey(certChainPEM) default: logrus.Debugf("Unknown key type parsed from certificate: %v", leafCert.PublicKeyAlgorithm) continue } keys[newKey.ID()] = newKey } return keys }
func (r *NotaryRepository) initializeRoles(rootKeys []data.PublicKey, localRoles, remoteRoles []string) ( root, targets, snapshot, timestamp data.BaseRole, err error) { root = data.NewBaseRole( data.CanonicalRootRole, notary.MinThreshold, rootKeys..., ) // we want to create all the local keys first so we don't have to // make unnecessary network calls for _, role := range localRoles { // This is currently hardcoding the keys to ECDSA. var key data.PublicKey key, err = r.CryptoService.Create(role, r.gun, data.ECDSAKey) if err != nil { return } switch role { case data.CanonicalSnapshotRole: snapshot = data.NewBaseRole( role, notary.MinThreshold, key, ) case data.CanonicalTargetsRole: targets = data.NewBaseRole( role, notary.MinThreshold, key, ) } } for _, role := range remoteRoles { // This key is generated by the remote server. var key data.PublicKey key, err = getRemoteKey(r.baseURL, r.gun, role, r.roundTrip) if err != nil { return } logrus.Debugf("got remote %s %s key with keyID: %s", role, key.Algorithm(), key.ID()) switch role { case data.CanonicalSnapshotRole: snapshot = data.NewBaseRole( role, notary.MinThreshold, key, ) case data.CanonicalTimestampRole: timestamp = data.NewBaseRole( role, notary.MinThreshold, key, ) } } return root, targets, snapshot, timestamp, nil }
// CanonicalKeyID returns the ID of the public bytes version of a TUF key. // On regular RSA/ECDSA TUF keys, this is just the key ID. On X509 RSA/ECDSA // TUF keys, this is the key ID of the public key part of the key. func CanonicalKeyID(k data.PublicKey) (string, error) { switch k.Algorithm() { case data.ECDSAx509Key, data.RSAx509Key: return trustmanager.X509PublicKeyID(k) default: return k.ID(), nil } }
//CreateKey returns a PublicKey created using KeyManagementServer's SigningService func (s *KeyManagementServer) CreateKey(ctx context.Context, req *pb.CreateKeyRequest) (*pb.PublicKey, error) { service := s.CryptoServices[req.Algorithm] logger := ctxu.GetLogger(ctx) if service == nil { logger.Error("CreateKey: unsupported algorithm: ", req.Algorithm) return nil, fmt.Errorf("algorithm %s not supported for create key", req.Algorithm) } var tufKey data.PublicKey var err error tufKey, err = service.Create(req.Role, req.Gun, req.Algorithm) if err != nil { logger.Error("CreateKey: failed to create key: ", err) return nil, grpc.Errorf(codes.Internal, "Key creation failed") } logger.Info("CreateKey: Created KeyID ", tufKey.ID()) return &pb.PublicKey{ KeyInfo: &pb.KeyInfo{ KeyID: &pb.KeyID{ID: tufKey.ID()}, Algorithm: &pb.Algorithm{Algorithm: tufKey.Algorithm()}, }, PublicKey: tufKey.Public(), }, nil }
// add a key to a KeyDB, and create a role for the key and add it. func addKeyForRole(kdb *keys.KeyDB, role string, key data.PublicKey) error { theRole, err := data.NewRole(role, 1, []string{key.ID()}, nil, nil) if err != nil { return err } kdb.AddKey(key) if err := kdb.AddRole(theRole); err != nil { return err } return nil }
// RotateKey removes all existing keys associated with the role, and either // creates and adds one new key or delegates managing the key to the server. // These changes are staged in a changelist until publish is called. func (r *NotaryRepository) RotateKey(role string, serverManagesKey bool) error { // We currently support remotely managing timestamp and snapshot keys canBeRemoteKey := role == data.CanonicalTimestampRole || role == data.CanonicalSnapshotRole // And locally managing root, targets, and snapshot keys canBeLocalKey := (role == data.CanonicalSnapshotRole || role == data.CanonicalTargetsRole || role == data.CanonicalRootRole) switch { case !data.ValidRole(role) || data.IsDelegation(role): return fmt.Errorf("notary does not currently permit rotating the %s key", role) case serverManagesKey && !canBeRemoteKey: return ErrInvalidRemoteRole{Role: role} case !serverManagesKey && !canBeLocalKey: return ErrInvalidLocalRole{Role: role} } var ( pubKey data.PublicKey err error errFmtMsg string ) switch serverManagesKey { case true: pubKey, err = getRemoteKey(r.baseURL, r.gun, role, r.roundTrip) errFmtMsg = "unable to rotate remote key: %s" default: pubKey, err = r.CryptoService.Create(role, r.gun, data.ECDSAKey) errFmtMsg = "unable to generate key: %s" } if err != nil { return fmt.Errorf(errFmtMsg, err) } // if this is a root role, generate a root cert for the public key if role == data.CanonicalRootRole { privKey, _, err := r.CryptoService.GetPrivateKey(pubKey.ID()) if err != nil { return err } pubKey, err = rootCertKey(r.gun, privKey) if err != nil { return err } } cl := changelist.NewMemChangelist() if err := r.rootFileKeyChange(cl, role, changelist.ActionCreate, pubKey); err != nil { return err } return r.publish(cl) }
func initRoles(kdb *keys.KeyDB, rootKey, targetsKey, snapshotKey, timestampKey data.PublicKey) error { rootRole, err := data.NewRole("root", 1, []string{rootKey.ID()}, nil, nil) if err != nil { return err } targetsRole, err := data.NewRole("targets", 1, []string{targetsKey.ID()}, nil, nil) if err != nil { return err } snapshotRole, err := data.NewRole("snapshot", 1, []string{snapshotKey.ID()}, nil, nil) if err != nil { return err } timestampRole, err := data.NewRole("timestamp", 1, []string{timestampKey.ID()}, nil, nil) if err != nil { return err } if err := kdb.AddRole(rootRole); err != nil { return err } if err := kdb.AddRole(targetsRole); err != nil { return err } if err := kdb.AddRole(snapshotRole); err != nil { return err } if err := kdb.AddRole(timestampRole); err != nil { return err } return nil }
func fingerprintCert(cert *x509.Certificate) (CertID, error) { block := pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw} pemdata := pem.EncodeToMemory(&block) var tufKey data.PublicKey switch cert.PublicKeyAlgorithm { case x509.RSA: tufKey = data.NewRSAx509PublicKey(pemdata) case x509.ECDSA: tufKey = data.NewECDSAx509PublicKey(pemdata) default: return "", fmt.Errorf("got Unknown key type while fingerprinting certificate") } return CertID(tufKey.ID()), nil }
// RotateKey rotates the key for a role - this can invalidate that role's metadata // if it is not signed by that key. Particularly if the key being rotated is the // root key, because it is not signed by the new key, only the old key. func (m *MetadataSwizzler) RotateKey(role string, key data.PublicKey) error { roleSpecifier := data.CanonicalRootRole if data.IsDelegation(role) { roleSpecifier = path.Dir(role) } b, err := m.MetadataCache.GetSized(roleSpecifier, store.NoSizeLimit) if err != nil { return err } signedThing := &data.Signed{} if err := json.Unmarshal(b, signedThing); err != nil { return err } // get keys before the keys are rotated pubKeys, err := getPubKeys(m.CryptoService, signedThing, roleSpecifier) if err != nil { return err } if roleSpecifier == data.CanonicalRootRole { signedRoot, err := data.RootFromSigned(signedThing) if err != nil { return err } signedRoot.Signed.Roles[role].KeyIDs = []string{key.ID()} signedRoot.Signed.Keys[key.ID()] = key if signedThing, err = signedRoot.ToSigned(); err != nil { return err } } else { signedTargets, err := data.TargetsFromSigned(signedThing, roleSpecifier) if err != nil { return err } for _, roleObject := range signedTargets.Signed.Delegations.Roles { if roleObject.Name == role { roleObject.KeyIDs = []string{key.ID()} break } } signedTargets.Signed.Delegations.Keys[key.ID()] = key if signedThing, err = signedTargets.ToSigned(); err != nil { return err } } metaBytes, err := serializeMetadata(m.CryptoService, signedThing, roleSpecifier, pubKeys...) if err != nil { return err } return m.MetadataCache.Set(roleSpecifier, metaBytes) }
// Verify does the actual check. // N.B. We have not been able to make this work in a way that is compatible // with PyCrypto. func (v RSAPyCryptoVerifier) Verify(key data.PublicKey, sig []byte, msg []byte) error { digest := sha256.Sum256(msg) if key.Algorithm() != data.RSAKey { return ErrInvalidKeyType{} } k, _ := pem.Decode([]byte(key.Public())) if k == nil { logrus.Debugf("failed to decode PEM-encoded x509 certificate") return ErrInvalid } pub, err := x509.ParsePKIXPublicKey(k.Bytes) if err != nil { logrus.Debugf("failed to parse public key: %s\n", err) return ErrInvalid } return verifyPSS(pub, digest[:], sig) }
// RotateKey removes all existing keys associated with the role, and either // creates and adds one new key or delegates managing the key to the server. // These changes are staged in a changelist until publish is called. func (r *NotaryRepository) RotateKey(role string, serverManagesKey bool) error { if err := checkRotationInput(role, serverManagesKey); err != nil { return err } var ( pubKey data.PublicKey err error errFmtMsg string ) switch serverManagesKey { case true: pubKey, err = rotateRemoteKey(r.baseURL, r.gun, role, r.roundTrip) errFmtMsg = "unable to rotate remote key: %s" default: pubKey, err = r.CryptoService.Create(role, r.gun, data.ECDSAKey) errFmtMsg = "unable to generate key: %s" } if err != nil { return fmt.Errorf(errFmtMsg, err) } // if this is a root role, generate a root cert for the public key if role == data.CanonicalRootRole { privKey, _, err := r.CryptoService.GetPrivateKey(pubKey.ID()) if err != nil { return err } pubKey, err = rootCertKey(r.gun, privKey) if err != nil { return err } } cl := changelist.NewMemChangelist() if err := r.rootFileKeyChange(cl, role, changelist.ActionCreate, pubKey); err != nil { return err } return r.publish(cl) }
// Verify checks that an ed25519 signature is valid func (v Ed25519Verifier) Verify(key data.PublicKey, sig []byte, msg []byte) error { if key.Algorithm() != data.ED25519Key { return ErrInvalidKeyType{} } var sigBytes [ed25519.SignatureSize]byte if len(sig) != ed25519.SignatureSize { logrus.Debugf("signature length is incorrect, must be %d, was %d.", ed25519.SignatureSize, len(sig)) return ErrInvalid } copy(sigBytes[:], sig) var keyBytes [ed25519.PublicKeySize]byte pub := key.Public() if len(pub) != ed25519.PublicKeySize { logrus.Errorf("public key is incorrect size, must be %d, was %d.", ed25519.PublicKeySize, len(pub)) return ErrInvalidKeyLength{msg: fmt.Sprintf("ed25519 public key must be %d bytes.", ed25519.PublicKeySize)} } n := copy(keyBytes[:], key.Public()) if n < ed25519.PublicKeySize { logrus.Errorf("failed to copy the key, must have %d bytes, copied %d bytes.", ed25519.PublicKeySize, n) return ErrInvalid } if !ed25519.Verify(&keyBytes, msg, &sigBytes) { logrus.Debugf("failed ed25519 verification") return ErrInvalid } return nil }
func getRSAPubKey(key data.PublicKey) (crypto.PublicKey, error) { algorithm := key.Algorithm() var pubKey crypto.PublicKey switch algorithm { case data.RSAx509Key: pemCert, _ := pem.Decode([]byte(key.Public())) if pemCert == nil { logrus.Debugf("failed to decode PEM-encoded x509 certificate") return nil, ErrInvalid } cert, err := x509.ParseCertificate(pemCert.Bytes) if err != nil { logrus.Debugf("failed to parse x509 certificate: %s\n", err) return nil, ErrInvalid } pubKey = cert.PublicKey case data.RSAKey: var err error pubKey, err = x509.ParsePKIXPublicKey(key.Public()) if err != nil { logrus.Debugf("failed to parse public key: %s\n", err) return nil, ErrInvalid } default: // only accept RSA keys logrus.Debugf("invalid key type for RSAPSS verifier: %s", algorithm) return nil, ErrInvalidKeyType{} } return pubKey, nil }
// X509PublicKeyID returns a public key ID as a string, given a // data.PublicKey that contains an X509 Certificate func X509PublicKeyID(certPubKey data.PublicKey) (string, error) { cert, err := LoadCertFromPEM(certPubKey.Public()) if err != nil { return "", err } pubKeyBytes, err := x509.MarshalPKIXPublicKey(cert.PublicKey) if err != nil { return "", err } var key data.PublicKey switch certPubKey.Algorithm() { case data.ECDSAx509Key: key = data.NewECDSAPublicKey(pubKeyBytes) case data.RSAx509Key: key = data.NewRSAPublicKey(pubKeyBytes) } return key.ID(), nil }
// X509PublicKeyID returns a public key ID as a string, given a // data.PublicKey that contains an X509 Certificate func X509PublicKeyID(certPubKey data.PublicKey) (string, error) { // Note that this only loads the first certificate from the public key cert, err := LoadCertFromPEM(certPubKey.Public()) if err != nil { return "", err } pubKeyBytes, err := x509.MarshalPKIXPublicKey(cert.PublicKey) if err != nil { return "", err } var key data.PublicKey switch certPubKey.Algorithm() { case data.ECDSAx509Key: key = data.NewECDSAPublicKey(pubKeyBytes) case data.RSAx509Key: key = data.NewRSAPublicKey(pubKeyBytes) } return key.ID(), nil }
func verifyRootSignatureAgainstKey(t *testing.T, signedRoot *data.Signed, key data.PublicKey) error { roleWithKeys := data.BaseRole{Name: data.CanonicalRootRole, Keys: data.Keys{key.ID(): key}, Threshold: 1} return signed.VerifySignatures(signedRoot, roleWithKeys) }
// AddKey adds a public key to the database func (db *KeyDB) AddKey(k data.PublicKey) { db.keys[k.ID()] = k }
// Verify does the actual check. func (v ECDSAVerifier) Verify(key data.PublicKey, sig []byte, msg []byte) error { algorithm := key.Algorithm() var pubKey crypto.PublicKey switch algorithm { case data.ECDSAx509Key: pemCert, _ := pem.Decode([]byte(key.Public())) if pemCert == nil { logrus.Debugf("failed to decode PEM-encoded x509 certificate for keyID: %s", key.ID()) logrus.Debugf("certificate bytes: %s", string(key.Public())) return ErrInvalid } cert, err := x509.ParseCertificate(pemCert.Bytes) if err != nil { logrus.Debugf("failed to parse x509 certificate: %s\n", err) return ErrInvalid } pubKey = cert.PublicKey case data.ECDSAKey: var err error pubKey, err = x509.ParsePKIXPublicKey(key.Public()) if err != nil { logrus.Debugf("Failed to parse private key for keyID: %s, %s\n", key.ID(), err) return ErrInvalid } default: // only accept ECDSA keys. logrus.Debugf("invalid key type for ECDSA verifier: %s", algorithm) return ErrInvalidKeyType{} } ecdsaPubKey, ok := pubKey.(*ecdsa.PublicKey) if !ok { logrus.Debugf("value isn't an ECDSA public key") return ErrInvalid } sigLength := len(sig) expectedOctetLength := 2 * ((ecdsaPubKey.Params().BitSize + 7) >> 3) if sigLength != expectedOctetLength { logrus.Debugf("signature had an unexpected length") return ErrInvalid } rBytes, sBytes := sig[:sigLength/2], sig[sigLength/2:] r := new(big.Int).SetBytes(rBytes) s := new(big.Int).SetBytes(sBytes) digest := sha256.Sum256(msg) if !ecdsa.Verify(ecdsaPubKey, digest[:], r, s) { logrus.Debugf("failed ECDSA signature validation") return ErrInvalid } return nil }
// checkRoot errors if an invalid rotation has taken place, if the // threshold number of signatures is invalid, if there are an invalid // number of roles and keys, or if the timestamp keys are invalid func checkRoot(oldRoot, newRoot *data.SignedRoot, timestampKey data.PublicKey) error { rootRole := data.CanonicalRootRole targetsRole := data.CanonicalTargetsRole snapshotRole := data.CanonicalSnapshotRole timestampRole := data.CanonicalTimestampRole var oldRootRole *data.RootRole newRootRole, ok := newRoot.Signed.Roles[rootRole] if !ok { return errors.New("new root is missing role entry for root role") } oldThreshold := 1 rotation := false oldKeys := map[string]data.PublicKey{} newKeys := map[string]data.PublicKey{} if oldRoot != nil { // check for matching root key IDs oldRootRole = oldRoot.Signed.Roles[rootRole] oldThreshold = oldRootRole.Threshold for _, kid := range oldRootRole.KeyIDs { k, ok := oldRoot.Signed.Keys[kid] if !ok { // if the key itself wasn't contained in the root // we're skipping it because it could never have // been used to validate this root. continue } oldKeys[kid] = data.NewPublicKey(k.Algorithm(), k.Public()) } // super simple check for possible rotation rotation = len(oldKeys) != len(newRootRole.KeyIDs) } // if old and new had the same number of keys, iterate // to see if there's a difference. for _, kid := range newRootRole.KeyIDs { k, ok := newRoot.Signed.Keys[kid] if !ok { // if the key itself wasn't contained in the root // we're skipping it because it could never have // been used to validate this root. continue } newKeys[kid] = data.NewPublicKey(k.Algorithm(), k.Public()) if oldRoot != nil { if _, ok := oldKeys[kid]; !ok { // if there is any difference in keys, a key rotation may have // occurred. rotation = true } } } newSigned, err := newRoot.ToSigned() if err != nil { return err } if rotation { err = signed.VerifyRoot(newSigned, oldThreshold, oldKeys) if err != nil { return fmt.Errorf("rotation detected and new root was not signed with at least %d old keys", oldThreshold) } } err = signed.VerifyRoot(newSigned, newRootRole.Threshold, newKeys) if err != nil { return err } root, err := data.RootFromSigned(newSigned) if err != nil { return err } var timestampKeyIDs []string // at a minimum, check the 4 required roles are present for _, r := range []string{rootRole, targetsRole, snapshotRole, timestampRole} { role, ok := root.Signed.Roles[r] if !ok { return fmt.Errorf("missing required %s role from root", r) } // According to the TUF spec, any role may have more than one signing // key and require a threshold signature. However, notary-server // creates the timestamp, and there is only ever one, so a threshold // greater than one would just always fail validation if (r == timestampRole && role.Threshold != 1) || role.Threshold < 1 { return fmt.Errorf("%s role has invalid threshold", r) } if len(role.KeyIDs) < role.Threshold { return fmt.Errorf("%s role has insufficient number of keys", r) } if r == timestampRole { timestampKeyIDs = role.KeyIDs } } // ensure that at least one of the timestamp keys specified in the role // actually exists for _, keyID := range timestampKeyIDs { if timestampKey.ID() == keyID { return nil } } return fmt.Errorf("none of the following timestamp keys exist: %s", strings.Join(timestampKeyIDs, ", ")) }