diff --git a/cmd/notary/keys.go b/cmd/notary/keys.go index cc7831e03f..62b9e7a47c 100644 --- a/cmd/notary/keys.go +++ b/cmd/notary/keys.go @@ -64,7 +64,7 @@ func keysRemove(cmd *cobra.Command, args []string) { gunOrID := args[0] // Try to retrieve the ID from the CA store. - cert, err := caStore.GetCertificateByKeyID(gunOrID) + cert, err := caStore.GetCertificateByCertID(gunOrID) if err == nil { fmt.Printf("Removing: ") printCert(cert) @@ -78,7 +78,7 @@ func keysRemove(cmd *cobra.Command, args []string) { } // Try to retrieve the ID from the Certificate store. - cert, err = certificateStore.GetCertificateByKeyID(gunOrID) + cert, err = certificateStore.GetCertificateByCertID(gunOrID) if err == nil { fmt.Printf("Removing: ") printCert(cert) @@ -216,12 +216,12 @@ func keysGenerate(cmd *cobra.Command, args []string) { func printCert(cert *x509.Certificate) { timeDifference := cert.NotAfter.Sub(time.Now()) - keyID, err := trustmanager.FingerprintCert(cert) + certID, err := trustmanager.FingerprintCert(cert) if err != nil { fatalf("could not fingerprint certificate: %v", err) } - fmt.Printf("%s %s (expires in: %v days)\n", cert.Subject.CommonName, keyID, math.Floor(timeDifference.Hours()/24)) + fmt.Printf("%s %s (expires in: %v days)\n", cert.Subject.CommonName, certID, math.Floor(timeDifference.Hours()/24)) } func printKey(keyPath string) { diff --git a/trustmanager/x509filestore.go b/trustmanager/x509filestore.go index 553565356b..d6c23647ea 100644 --- a/trustmanager/x509filestore.go +++ b/trustmanager/x509filestore.go @@ -70,14 +70,14 @@ func (s X509FileStore) AddCert(cert *x509.Certificate) error { // addNamedCert allows adding a certificate while controling the filename it gets // stored under. If the file does not exist on disk, saves it. func (s X509FileStore) addNamedCert(cert *x509.Certificate) error { - fileName, keyID, err := fileName(cert) + fileName, certID, err := fileName(cert) if err != nil { return err } - logrus.Debug("Adding cert with keyID: ", keyID) + logrus.Debug("Adding cert with certID: ", certID) // Validate if we already loaded this certificate before - if _, ok := s.fingerprintMap[keyID]; ok { + if _, ok := s.fingerprintMap[certID]; ok { return errors.New("certificate already in the store") } @@ -98,11 +98,11 @@ func (s X509FileStore) addNamedCert(cert *x509.Certificate) error { } // We wrote the certificate succcessfully, add it to our in-memory storage - s.fingerprintMap[keyID] = cert - s.fileMap[keyID] = fileName + s.fingerprintMap[certID] = cert + s.fileMap[certID] = fileName - name := string(cert.RawSubject) - s.nameMap[name] = append(s.nameMap[name], keyID) + name := string(cert.Subject.CommonName) + s.nameMap[name] = append(s.nameMap[name], certID) return nil } @@ -113,13 +113,13 @@ func (s X509FileStore) RemoveCert(cert *x509.Certificate) error { return errors.New("removing nil Certificate from X509Store") } - keyID, err := fingerprintCert(cert) + certID, err := fingerprintCert(cert) if err != nil { return err } - delete(s.fingerprintMap, keyID) - filename := s.fileMap[keyID] - delete(s.fileMap, keyID) + delete(s.fingerprintMap, certID) + filename := s.fileMap[certID] + delete(s.fileMap, certID) name := string(cert.RawSubject) @@ -127,7 +127,7 @@ func (s X509FileStore) RemoveCert(cert *x509.Certificate) error { fpList := s.nameMap[name] newfpList := fpList[:0] for _, x := range fpList { - if x != keyID { + if x != certID { newfpList = append(newfpList, x) } } @@ -183,21 +183,48 @@ func (s X509FileStore) GetCertificatePool() *x509.CertPool { return pool } -// GetCertificateByKeyID returns the certificate that matches a certain keyID or error -func (s X509FileStore) GetCertificateByKeyID(keyID string) (*x509.Certificate, error) { +// GetCertificateByCertID returns the certificate that matches a certain certID +func (s X509FileStore) GetCertificateByCertID(certID string) (*x509.Certificate, error) { + return s.getCertificateByCertID(CertID(certID)) +} + +// getCertificateByCertID returns the certificate that matches a certain certID +func (s X509FileStore) getCertificateByCertID(certID CertID) (*x509.Certificate, error) { // If it does not look like a hex encoded sha256 hash, error - if len(keyID) != 64 { + if len(certID) != 64 { return nil, errors.New("invalid Subject Key Identifier") } // Check to see if this subject key identifier exists - if cert, ok := s.fingerprintMap[CertID(keyID)]; ok { + if cert, ok := s.fingerprintMap[CertID(certID)]; ok { return cert, nil } return nil, errors.New("certificate not found in Key Store") } +// GetCertificatesByCN returns all the certificates that match a specific +// CommonName +func (s X509FileStore) GetCertificatesByCN(cn string) ([]*x509.Certificate, error) { + var certs []*x509.Certificate + if ids, ok := s.nameMap[cn]; ok { + for _, v := range ids { + cert, err := s.getCertificateByCertID(v) + if err != nil { + // This error should never happen. This would mean that we have + // an inconsistent X509FileStore + return nil, err + } + certs = append(certs, cert) + } + } + if len(certs) == 0 { + return nil, errors.New("common name not found in Key Store") + } + + return certs, nil +} + // GetVerifyOptions returns VerifyOptions with the certificates within the KeyStore // as part of the roots list. This never allows the use of system roots, returning // an error if there are no root CAs. @@ -217,10 +244,10 @@ func (s X509FileStore) GetVerifyOptions(dnsName string) (x509.VerifyOptions, err } func fileName(cert *x509.Certificate) (string, CertID, error) { - keyID, err := fingerprintCert(cert) + certID, err := fingerprintCert(cert) if err != nil { return "", "", err } - return path.Join(cert.Subject.CommonName, string(keyID)), keyID, nil + return path.Join(cert.Subject.CommonName, string(certID)), certID, nil } diff --git a/trustmanager/x509memstore.go b/trustmanager/x509memstore.go index f6bcb9d796..db5b60b100 100644 --- a/trustmanager/x509memstore.go +++ b/trustmanager/x509memstore.go @@ -23,7 +23,7 @@ func NewX509MemStore() *X509MemStore { } } -// NewX509FilteredMemStore returns a new X509FileStore that validates certificates +// NewX509FilteredMemStore returns a new X509Memstore that validates certificates // that are added. func NewX509FilteredMemStore(validate func(*x509.Certificate) bool) *X509MemStore { s := &X509MemStore{ @@ -46,14 +46,14 @@ func (s X509MemStore) AddCert(cert *x509.Certificate) error { return errors.New("certificate failed validation") } - keyID, err := fingerprintCert(cert) + certID, err := fingerprintCert(cert) if err != nil { return err } - s.fingerprintMap[keyID] = cert + s.fingerprintMap[certID] = cert name := string(cert.RawSubject) - s.nameMap[name] = append(s.nameMap[name], keyID) + s.nameMap[name] = append(s.nameMap[name], certID) return nil } @@ -64,18 +64,18 @@ func (s X509MemStore) RemoveCert(cert *x509.Certificate) error { return errors.New("removing nil Certificate to X509Store") } - keyID, err := fingerprintCert(cert) + certID, err := fingerprintCert(cert) if err != nil { return err } - delete(s.fingerprintMap, keyID) + delete(s.fingerprintMap, certID) name := string(cert.RawSubject) // Filter the fingerprint out of this name entry fpList := s.nameMap[name] newfpList := fpList[:0] for _, x := range fpList { - if x != keyID { + if x != certID { newfpList = append(newfpList, x) } } @@ -125,21 +125,48 @@ func (s X509MemStore) GetCertificatePool() *x509.CertPool { return pool } -// GetCertificateByKeyID returns the certificate that matches a certain keyID or error -func (s X509MemStore) GetCertificateByKeyID(keyID string) (*x509.Certificate, error) { +// GetCertificateByCertID returns the certificate that matches a certain certID +func (s X509MemStore) GetCertificateByCertID(certID string) (*x509.Certificate, error) { + return s.getCertificateByCertID(CertID(certID)) +} + +// getCertificateByCertID returns the certificate that matches a certain certID or error +func (s X509MemStore) getCertificateByCertID(certID CertID) (*x509.Certificate, error) { // If it does not look like a hex encoded sha256 hash, error - if len(keyID) != 64 { + if len(certID) != 64 { return nil, errors.New("invalid Subject Key Identifier") } // Check to see if this subject key identifier exists - if cert, ok := s.fingerprintMap[CertID(keyID)]; ok { + if cert, ok := s.fingerprintMap[CertID(certID)]; ok { return cert, nil } return nil, errors.New("certificate not found in Key Store") } +// GetCertificatesByCN returns all the certificates that match a specific +// CommonName +func (s X509MemStore) GetCertificatesByCN(cn string) ([]*x509.Certificate, error) { + var certs []*x509.Certificate + if ids, ok := s.nameMap[cn]; ok { + for _, v := range ids { + cert, err := s.getCertificateByCertID(v) + if err != nil { + // This error should never happen. This would mean that we have + // an inconsistent X509MemStore + return nil, err + } + certs = append(certs, cert) + } + } + if len(certs) == 0 { + return nil, errors.New("common name not found in Key Store") + } + + return certs, nil +} + // GetVerifyOptions returns VerifyOptions with the certificates within the KeyStore // as part of the roots list. This never allows the use of system roots, returning // an error if there are no root CAs. diff --git a/trustmanager/x509memstore_test.go b/trustmanager/x509memstore_test.go index 9cb46cd5c9..9560208bb1 100644 --- a/trustmanager/x509memstore_test.go +++ b/trustmanager/x509memstore_test.go @@ -106,14 +106,14 @@ func TestRemoveCert(t *testing.T) { } } -func TestInexistentGetCertificateByKeyID(t *testing.T) { +func TestInexistentGetCertificateByCertID(t *testing.T) { store := NewX509MemStore() err := store.AddCertFromFile("../fixtures/root-ca.crt") if err != nil { t.Fatalf("failed to load certificate from file: %v", err) } - _, err = store.GetCertificateByKeyID("4d06afd30b8bed131d2a84c97d00b37f422021598bfae34285ce98e77b708b5a") + _, err = store.GetCertificateByCertID("4d06afd30b8bed131d2a84c97d00b37f422021598bfae34285ce98e77b708b5a") if err == nil { t.Fatalf("no error returned for inexistent certificate") } @@ -138,15 +138,15 @@ func TestGetCertificateByKeyID(t *testing.T) { t.Fatalf("failed to load certificate from PEM: %v", err) } - keyID, err := FingerprintCert(cert) + certID, err := FingerprintCert(cert) if err != nil { t.Fatalf("failed to fingerprint the certificate: %v", err) } // Tries to retrieve cert by Subject Key IDs - _, err = store.GetCertificateByKeyID(keyID) + _, err = store.GetCertificateByCertID(certID) if err != nil { - t.Fatalf("expected certificate in store: %s", keyID) + t.Fatalf("expected certificate in store: %s", certID) } } diff --git a/trustmanager/x509store.go b/trustmanager/x509store.go index 85307b5fce..7c15456b01 100644 --- a/trustmanager/x509store.go +++ b/trustmanager/x509store.go @@ -14,7 +14,8 @@ type X509Store interface { AddCertFromPEM(pemCerts []byte) error AddCertFromFile(filename string) error RemoveCert(cert *x509.Certificate) error - GetCertificateByKeyID(keyID string) (*x509.Certificate, error) + GetCertificateByCertID(certID string) (*x509.Certificate, error) + GetCertificatesByCN(cn string) ([]*x509.Certificate, error) GetCertificates() []*x509.Certificate GetCertificatePool() *x509.CertPool GetVerifyOptions(dnsName string) (x509.VerifyOptions, error)