Adding Cert retrieval by common name, and renaming KeyID to CertID

Signed-off-by: Diogo Monica <diogo@docker.com>
This commit is contained in:
Diogo Monica 2015-07-15 17:30:21 -07:00
parent 0313aa5958
commit 58e6544d0a
5 changed files with 94 additions and 39 deletions

View File

@ -64,7 +64,7 @@ func keysRemove(cmd *cobra.Command, args []string) {
gunOrID := args[0] gunOrID := args[0]
// Try to retrieve the ID from the CA store. // Try to retrieve the ID from the CA store.
cert, err := caStore.GetCertificateByKeyID(gunOrID) cert, err := caStore.GetCertificateByCertID(gunOrID)
if err == nil { if err == nil {
fmt.Printf("Removing: ") fmt.Printf("Removing: ")
printCert(cert) printCert(cert)
@ -78,7 +78,7 @@ func keysRemove(cmd *cobra.Command, args []string) {
} }
// Try to retrieve the ID from the Certificate store. // Try to retrieve the ID from the Certificate store.
cert, err = certificateStore.GetCertificateByKeyID(gunOrID) cert, err = certificateStore.GetCertificateByCertID(gunOrID)
if err == nil { if err == nil {
fmt.Printf("Removing: ") fmt.Printf("Removing: ")
printCert(cert) printCert(cert)
@ -216,12 +216,12 @@ func keysGenerate(cmd *cobra.Command, args []string) {
func printCert(cert *x509.Certificate) { func printCert(cert *x509.Certificate) {
timeDifference := cert.NotAfter.Sub(time.Now()) timeDifference := cert.NotAfter.Sub(time.Now())
keyID, err := trustmanager.FingerprintCert(cert) certID, err := trustmanager.FingerprintCert(cert)
if err != nil { if err != nil {
fatalf("could not fingerprint certificate: %v", err) 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) { func printKey(keyPath string) {

View File

@ -70,14 +70,14 @@ func (s X509FileStore) AddCert(cert *x509.Certificate) error {
// addNamedCert allows adding a certificate while controling the filename it gets // addNamedCert allows adding a certificate while controling the filename it gets
// stored under. If the file does not exist on disk, saves it. // stored under. If the file does not exist on disk, saves it.
func (s X509FileStore) addNamedCert(cert *x509.Certificate) error { func (s X509FileStore) addNamedCert(cert *x509.Certificate) error {
fileName, keyID, err := fileName(cert) fileName, certID, err := fileName(cert)
if err != nil { if err != nil {
return err return err
} }
logrus.Debug("Adding cert with keyID: ", keyID) logrus.Debug("Adding cert with certID: ", certID)
// Validate if we already loaded this certificate before // 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") 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 // We wrote the certificate succcessfully, add it to our in-memory storage
s.fingerprintMap[keyID] = cert s.fingerprintMap[certID] = cert
s.fileMap[keyID] = fileName s.fileMap[certID] = fileName
name := string(cert.RawSubject) name := string(cert.Subject.CommonName)
s.nameMap[name] = append(s.nameMap[name], keyID) s.nameMap[name] = append(s.nameMap[name], certID)
return nil return nil
} }
@ -113,13 +113,13 @@ func (s X509FileStore) RemoveCert(cert *x509.Certificate) error {
return errors.New("removing nil Certificate from X509Store") return errors.New("removing nil Certificate from X509Store")
} }
keyID, err := fingerprintCert(cert) certID, err := fingerprintCert(cert)
if err != nil { if err != nil {
return err return err
} }
delete(s.fingerprintMap, keyID) delete(s.fingerprintMap, certID)
filename := s.fileMap[keyID] filename := s.fileMap[certID]
delete(s.fileMap, keyID) delete(s.fileMap, certID)
name := string(cert.RawSubject) name := string(cert.RawSubject)
@ -127,7 +127,7 @@ func (s X509FileStore) RemoveCert(cert *x509.Certificate) error {
fpList := s.nameMap[name] fpList := s.nameMap[name]
newfpList := fpList[:0] newfpList := fpList[:0]
for _, x := range fpList { for _, x := range fpList {
if x != keyID { if x != certID {
newfpList = append(newfpList, x) newfpList = append(newfpList, x)
} }
} }
@ -183,21 +183,48 @@ func (s X509FileStore) GetCertificatePool() *x509.CertPool {
return pool return pool
} }
// GetCertificateByKeyID returns the certificate that matches a certain keyID or error // GetCertificateByCertID returns the certificate that matches a certain certID
func (s X509FileStore) GetCertificateByKeyID(keyID string) (*x509.Certificate, error) { 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 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") return nil, errors.New("invalid Subject Key Identifier")
} }
// Check to see if this subject key identifier exists // 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 cert, nil
} }
return nil, errors.New("certificate not found in Key Store") 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 // GetVerifyOptions returns VerifyOptions with the certificates within the KeyStore
// as part of the roots list. This never allows the use of system roots, returning // as part of the roots list. This never allows the use of system roots, returning
// an error if there are no root CAs. // 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) { func fileName(cert *x509.Certificate) (string, CertID, error) {
keyID, err := fingerprintCert(cert) certID, err := fingerprintCert(cert)
if err != nil { if err != nil {
return "", "", err return "", "", err
} }
return path.Join(cert.Subject.CommonName, string(keyID)), keyID, nil return path.Join(cert.Subject.CommonName, string(certID)), certID, nil
} }

View File

@ -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. // that are added.
func NewX509FilteredMemStore(validate func(*x509.Certificate) bool) *X509MemStore { func NewX509FilteredMemStore(validate func(*x509.Certificate) bool) *X509MemStore {
s := &X509MemStore{ s := &X509MemStore{
@ -46,14 +46,14 @@ func (s X509MemStore) AddCert(cert *x509.Certificate) error {
return errors.New("certificate failed validation") return errors.New("certificate failed validation")
} }
keyID, err := fingerprintCert(cert) certID, err := fingerprintCert(cert)
if err != nil { if err != nil {
return err return err
} }
s.fingerprintMap[keyID] = cert s.fingerprintMap[certID] = cert
name := string(cert.RawSubject) name := string(cert.RawSubject)
s.nameMap[name] = append(s.nameMap[name], keyID) s.nameMap[name] = append(s.nameMap[name], certID)
return nil return nil
} }
@ -64,18 +64,18 @@ func (s X509MemStore) RemoveCert(cert *x509.Certificate) error {
return errors.New("removing nil Certificate to X509Store") return errors.New("removing nil Certificate to X509Store")
} }
keyID, err := fingerprintCert(cert) certID, err := fingerprintCert(cert)
if err != nil { if err != nil {
return err return err
} }
delete(s.fingerprintMap, keyID) delete(s.fingerprintMap, certID)
name := string(cert.RawSubject) name := string(cert.RawSubject)
// Filter the fingerprint out of this name entry // Filter the fingerprint out of this name entry
fpList := s.nameMap[name] fpList := s.nameMap[name]
newfpList := fpList[:0] newfpList := fpList[:0]
for _, x := range fpList { for _, x := range fpList {
if x != keyID { if x != certID {
newfpList = append(newfpList, x) newfpList = append(newfpList, x)
} }
} }
@ -125,21 +125,48 @@ func (s X509MemStore) GetCertificatePool() *x509.CertPool {
return pool return pool
} }
// GetCertificateByKeyID returns the certificate that matches a certain keyID or error // GetCertificateByCertID returns the certificate that matches a certain certID
func (s X509MemStore) GetCertificateByKeyID(keyID string) (*x509.Certificate, error) { 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 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") return nil, errors.New("invalid Subject Key Identifier")
} }
// Check to see if this subject key identifier exists // 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 cert, nil
} }
return nil, errors.New("certificate not found in Key Store") 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 // GetVerifyOptions returns VerifyOptions with the certificates within the KeyStore
// as part of the roots list. This never allows the use of system roots, returning // as part of the roots list. This never allows the use of system roots, returning
// an error if there are no root CAs. // an error if there are no root CAs.

View File

@ -106,14 +106,14 @@ func TestRemoveCert(t *testing.T) {
} }
} }
func TestInexistentGetCertificateByKeyID(t *testing.T) { func TestInexistentGetCertificateByCertID(t *testing.T) {
store := NewX509MemStore() store := NewX509MemStore()
err := store.AddCertFromFile("../fixtures/root-ca.crt") err := store.AddCertFromFile("../fixtures/root-ca.crt")
if err != nil { if err != nil {
t.Fatalf("failed to load certificate from file: %v", err) t.Fatalf("failed to load certificate from file: %v", err)
} }
_, err = store.GetCertificateByKeyID("4d06afd30b8bed131d2a84c97d00b37f422021598bfae34285ce98e77b708b5a") _, err = store.GetCertificateByCertID("4d06afd30b8bed131d2a84c97d00b37f422021598bfae34285ce98e77b708b5a")
if err == nil { if err == nil {
t.Fatalf("no error returned for inexistent certificate") 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) t.Fatalf("failed to load certificate from PEM: %v", err)
} }
keyID, err := FingerprintCert(cert) certID, err := FingerprintCert(cert)
if err != nil { if err != nil {
t.Fatalf("failed to fingerprint the certificate: %v", err) t.Fatalf("failed to fingerprint the certificate: %v", err)
} }
// Tries to retrieve cert by Subject Key IDs // Tries to retrieve cert by Subject Key IDs
_, err = store.GetCertificateByKeyID(keyID) _, err = store.GetCertificateByCertID(certID)
if err != nil { if err != nil {
t.Fatalf("expected certificate in store: %s", keyID) t.Fatalf("expected certificate in store: %s", certID)
} }
} }

View File

@ -14,7 +14,8 @@ type X509Store interface {
AddCertFromPEM(pemCerts []byte) error AddCertFromPEM(pemCerts []byte) error
AddCertFromFile(filename string) error AddCertFromFile(filename string) error
RemoveCert(cert *x509.Certificate) 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 GetCertificates() []*x509.Certificate
GetCertificatePool() *x509.CertPool GetCertificatePool() *x509.CertPool
GetVerifyOptions(dnsName string) (x509.VerifyOptions, error) GetVerifyOptions(dnsName string) (x509.VerifyOptions, error)