mirror of https://github.com/docker/docs.git
				
				
				
			
		
			
				
	
	
		
			145 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			145 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Go
		
	
	
	
| package trustmanager
 | |
| 
 | |
| import (
 | |
| 	"crypto/x509"
 | |
| 	"errors"
 | |
| 	"fmt"
 | |
| )
 | |
| 
 | |
| const certExtension string = "crt"
 | |
| 
 | |
| // ErrNoCertificatesFound is returned when no certificates are found for a
 | |
| // GetCertificatesBy*
 | |
| type ErrNoCertificatesFound struct {
 | |
| 	query string
 | |
| }
 | |
| 
 | |
| // ErrNoCertificatesFound is returned when no certificates are found for a
 | |
| // GetCertificatesBy*
 | |
| func (err ErrNoCertificatesFound) Error() string {
 | |
| 	return fmt.Sprintf("error, no certificates found in the keystore match: %s", err.query)
 | |
| }
 | |
| 
 | |
| // ErrCertValidation is returned when a certificate doesn't pass the store specific
 | |
| // validations
 | |
| type ErrCertValidation struct {
 | |
| }
 | |
| 
 | |
| // ErrCertValidation is returned when a certificate doesn't pass the store specific
 | |
| // validations
 | |
| func (err ErrCertValidation) Error() string {
 | |
| 	return fmt.Sprintf("store-specific certificate validations failed")
 | |
| }
 | |
| 
 | |
| // ErrCertExists is returned when a Certificate already exists in the key store
 | |
| type ErrCertExists struct {
 | |
| }
 | |
| 
 | |
| // ErrCertExists is returned when a Certificate already exists in the key store
 | |
| func (err ErrCertExists) Error() string {
 | |
| 	return fmt.Sprintf("certificate already in the store")
 | |
| }
 | |
| 
 | |
| // ErrBadCertificateStore is returned when there is an internal inconsistency
 | |
| // in our x509 store
 | |
| type ErrBadCertificateStore struct {
 | |
| }
 | |
| 
 | |
| // ErrBadCertificateStore is returned when there is an internal inconsistency
 | |
| // in our x509 store
 | |
| func (err ErrBadCertificateStore) Error() string {
 | |
| 	return fmt.Sprintf("inconsistent certificate store")
 | |
| }
 | |
| 
 | |
| // X509Store is the interface for all X509Stores
 | |
| type X509Store interface {
 | |
| 	AddCert(cert *x509.Certificate) error
 | |
| 	AddCertFromPEM(pemCerts []byte) error
 | |
| 	AddCertFromFile(filename string) error
 | |
| 	RemoveCert(cert *x509.Certificate) error
 | |
| 	RemoveAll() 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)
 | |
| }
 | |
| 
 | |
| // CertID represent the ID used to identify certificates
 | |
| type CertID string
 | |
| 
 | |
| // Validator is a convenience type to create validating function that filters
 | |
| // certificates that get added to the store
 | |
| type Validator interface {
 | |
| 	Validate(cert *x509.Certificate) bool
 | |
| }
 | |
| 
 | |
| // ValidatorFunc is a convenience type to create functions that implement
 | |
| // the Validator interface
 | |
| type ValidatorFunc func(cert *x509.Certificate) bool
 | |
| 
 | |
| // Validate implements the Validator interface to allow for any func() bool method
 | |
| // to be passed as a Validator
 | |
| func (vf ValidatorFunc) Validate(cert *x509.Certificate) bool {
 | |
| 	return vf(cert)
 | |
| }
 | |
| 
 | |
| // Verify operates on an X509Store and validates the existence of a chain of trust
 | |
| // between a leafCertificate and a CA present inside of the X509 Store.
 | |
| // It requires at least two certificates in certList, a leaf Certificate and an
 | |
| // intermediate CA certificate.
 | |
| func Verify(s X509Store, dnsName string, certList []*x509.Certificate) error {
 | |
| 	// If we have no Certificates loaded return error (we don't want to revert to using
 | |
| 	// system CAs).
 | |
| 	if len(s.GetCertificates()) == 0 {
 | |
| 		return errors.New("no root CAs available")
 | |
| 	}
 | |
| 
 | |
| 	// At a minimum we should be provided a leaf cert and an intermediate.
 | |
| 	if len(certList) < 2 {
 | |
| 		return errors.New("certificate and at least one intermediate needed")
 | |
| 	}
 | |
| 
 | |
| 	// Get the VerifyOptions from the keystore for a base dnsName
 | |
| 	opts, err := s.GetVerifyOptions(dnsName)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	// Create a Certificate Pool for our intermediate certificates
 | |
| 	intPool := x509.NewCertPool()
 | |
| 	var leafCert *x509.Certificate
 | |
| 
 | |
| 	// Iterate through all the certificates
 | |
| 	for _, c := range certList {
 | |
| 		// If the cert is a CA, we add it to the intermediates pool. If not, we call
 | |
| 		// it the leaf cert
 | |
| 		if c.IsCA {
 | |
| 			intPool.AddCert(c)
 | |
| 			continue
 | |
| 		}
 | |
| 		// Certificate is not a CA, it must be our leaf certificate.
 | |
| 		// If we already found one, bail with error
 | |
| 		if leafCert != nil {
 | |
| 			return errors.New("more than one leaf certificate found")
 | |
| 		}
 | |
| 		leafCert = c
 | |
| 	}
 | |
| 
 | |
| 	// We exited the loop with no leaf certificates
 | |
| 	if leafCert == nil {
 | |
| 		return errors.New("no leaf certificates found")
 | |
| 	}
 | |
| 
 | |
| 	// We have one leaf certificate and at least one intermediate. Lets add this
 | |
| 	// Cert Pool as the Intermediates list on our VerifyOptions
 | |
| 	opts.Intermediates = intPool
 | |
| 
 | |
| 	// Finally, let's call Verify on our leafCert with our fully configured options
 | |
| 	chains, err := leafCert.Verify(opts)
 | |
| 	if len(chains) == 0 || err != nil {
 | |
| 		return fmt.Errorf("certificate verification failed: %v", err)
 | |
| 	}
 | |
| 	return nil
 | |
| }
 |