...

Source file src/github.com/linkerd/linkerd2/pkg/tls/ca.go

Documentation: github.com/linkerd/linkerd2/pkg/tls

     1  package tls
     2  
     3  import (
     4  	"crypto/ecdsa"
     5  	"crypto/elliptic"
     6  	"crypto/rand"
     7  	"crypto/x509"
     8  	"crypto/x509/pkix"
     9  	"fmt"
    10  	"math/big"
    11  	"time"
    12  )
    13  
    14  type (
    15  	// CA provides a certificate authority for TLS-enabled installs.
    16  	// Issuing certificates concurrently is not supported.
    17  	CA struct {
    18  		// Cred contains the CA's credentials.
    19  		Cred Cred
    20  
    21  		// Validity configures the NotBefore and NotAfter parameters for certificates
    22  		// issued by this CA.
    23  		//
    24  		// Currently this is used for the CA's validity too, but nothing should
    25  		// assume that the CA's validity period is the same as issued certificates'
    26  		// validity.
    27  		Validity Validity
    28  
    29  		// nextSerialNumber is the serial number of the next certificate to issue.
    30  		// Serial numbers must not be reused.
    31  		//
    32  		// It is assumed there is only one instance of CA and it is assumed that a
    33  		// given CA object isn't requested to issue certificates concurrently.
    34  		//
    35  		// For now we do not attempt to meet CABForum requirements (e.g. regarding
    36  		// randomness).
    37  		nextSerialNumber uint64
    38  
    39  		// firstCrtExpiration is the time when the first expiration of a certificate
    40  		// in the trust chain occurs
    41  		firstCrtExpiration time.Time
    42  	}
    43  
    44  	// Validity configures the expiry times of issued certificates.
    45  	Validity struct {
    46  		// Validity is the duration for which issued certificates are valid. This
    47  		// is approximately cert.NotAfter - cert.NotBefore with some additional
    48  		// allowance for clock skew.
    49  		//
    50  		// Currently this is used for the CA's validity too, but nothing should
    51  		// assume that the CA's validity period is the same as issued certificates'
    52  		// validity.
    53  		Lifetime time.Duration
    54  
    55  		// ClockSkewAllowance is the maximum supported clock skew. Everything that
    56  		// processes the certificates must have a system clock that is off by no
    57  		// more than this allowance in either direction.
    58  		ClockSkewAllowance time.Duration
    59  
    60  		// ValidFrom is the point in time from which the certificate is valid.
    61  		// This is cert.NotBefore with some clock skew allowance.
    62  		ValidFrom *time.Time
    63  	}
    64  
    65  	// Issuer implementors signs certificate requests.
    66  	Issuer interface {
    67  		IssueEndEntityCrt(*x509.CertificateRequest) (Crt, error)
    68  	}
    69  )
    70  
    71  const (
    72  	// DefaultLifetime configures certificate validity.
    73  	//
    74  	// Initially all certificates will be valid for one year.
    75  	//
    76  	// TODO: Shorten the validity duration of CA and end-entity certificates downward.
    77  	DefaultLifetime = (24 * 365) * time.Hour
    78  
    79  	// DefaultClockSkewAllowance indicates the maximum allowed difference in clocks
    80  	// in the network.
    81  	//
    82  	// TODO: make it tunable.
    83  	//
    84  	// TODO: Reconsider how this interacts with the similar logic in the webpki
    85  	// verifier; since both are trying to account for clock skew, there is
    86  	// somewhat of an over-correction.
    87  	DefaultClockSkewAllowance = 10 * time.Second
    88  )
    89  
    90  // Finds the time at which the first certificate
    91  // from the chain will expire
    92  func findFirstExpiration(cred *Cred) time.Time {
    93  	firstExpiration := cred.Certificate.NotAfter
    94  	for _, c := range cred.TrustChain {
    95  		if c.NotAfter.Before(firstExpiration) {
    96  			firstExpiration = c.NotAfter
    97  		}
    98  	}
    99  	return firstExpiration
   100  }
   101  
   102  // NewCA initializes a new CA with default settings.
   103  func NewCA(cred Cred, validity Validity) *CA {
   104  	return &CA{cred, validity, uint64(1), findFirstExpiration(&cred)}
   105  }
   106  
   107  func init() {
   108  	// Assert that the struct implements the interface.
   109  	var _ Issuer = &CA{}
   110  }
   111  
   112  // CreateRootCA configures a new root CA with the given settings
   113  func CreateRootCA(
   114  	name string,
   115  	key *ecdsa.PrivateKey,
   116  	validity Validity,
   117  ) (*CA, error) {
   118  	// Configure the root certificate.
   119  	t := createTemplate(1, &key.PublicKey, validity)
   120  	t.Subject = pkix.Name{CommonName: name}
   121  	t.IsCA = true
   122  	t.MaxPathLen = -1
   123  	t.BasicConstraintsValid = true
   124  	t.KeyUsage = x509.KeyUsageCertSign | x509.KeyUsageCRLSign
   125  
   126  	// Self-sign the root certificate.
   127  	crtb, err := x509.CreateCertificate(rand.Reader, t, t, key.Public(), key)
   128  	if err != nil {
   129  		return nil, err
   130  	}
   131  	c, err := x509.ParseCertificate(crtb)
   132  	if err != nil {
   133  		return nil, err
   134  	}
   135  
   136  	// The Crt has an empty TrustChain because it's at the root.
   137  	cred := validCredOrPanic(key, Crt{Certificate: c})
   138  	ca := NewCA(cred, validity)
   139  	ca.nextSerialNumber++ // Because we've already created the root cert.
   140  	return ca, nil
   141  }
   142  
   143  // GenerateKey creates a new P-256 ECDSA private key from the default random
   144  // source.
   145  func GenerateKey() (*ecdsa.PrivateKey, error) {
   146  	return ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
   147  }
   148  
   149  // GenerateRootCAWithDefaults generates a new root CA with default settings.
   150  func GenerateRootCAWithDefaults(name string) (*CA, error) {
   151  	// Generate a new root key.
   152  	key, err := GenerateKey()
   153  	if err != nil {
   154  		return nil, err
   155  	}
   156  
   157  	return CreateRootCA(name, key, Validity{})
   158  }
   159  
   160  // GenerateCA generates a new intermediate CA.
   161  func (ca *CA) GenerateCA(name string, maxPathLen int) (*CA, error) {
   162  	key, err := GenerateKey()
   163  	if err != nil {
   164  		return nil, err
   165  	}
   166  
   167  	t := ca.createTemplate(&key.PublicKey)
   168  	t.Subject = pkix.Name{CommonName: name}
   169  	t.IsCA = true
   170  	t.MaxPathLen = maxPathLen
   171  	t.MaxPathLenZero = true // 0-values are actually 0
   172  	t.BasicConstraintsValid = true
   173  	t.KeyUsage = x509.KeyUsageCertSign | x509.KeyUsageCRLSign
   174  	crt, err := ca.Cred.SignCrt(t)
   175  	if err != nil {
   176  		return nil, err
   177  	}
   178  
   179  	return NewCA(validCredOrPanic(key, crt), ca.Validity), nil
   180  }
   181  
   182  // GenerateEndEntityCred creates a new certificate that is valid for the
   183  // given DNS name, generating a new keypair for it.
   184  func (ca *CA) GenerateEndEntityCred(dnsName string) (*Cred, error) {
   185  	key, err := GenerateKey()
   186  	if err != nil {
   187  		return nil, err
   188  	}
   189  
   190  	csr := x509.CertificateRequest{
   191  		Subject:   pkix.Name{CommonName: dnsName},
   192  		DNSNames:  []string{dnsName},
   193  		PublicKey: &key.PublicKey,
   194  	}
   195  	crt, err := ca.IssueEndEntityCrt(&csr)
   196  	if err != nil {
   197  		return nil, err
   198  	}
   199  
   200  	c := validCredOrPanic(key, crt)
   201  	return &c, nil
   202  }
   203  
   204  // IssueEndEntityCrt creates a new certificate that is valid for the
   205  // given DNS name, generating a new keypair for it.
   206  func (ca *CA) IssueEndEntityCrt(csr *x509.CertificateRequest) (Crt, error) {
   207  	pubkey, ok := csr.PublicKey.(*ecdsa.PublicKey)
   208  	if !ok {
   209  		return Crt{}, fmt.Errorf("CSR must contain an ECDSA public key: %+v", csr.PublicKey)
   210  	}
   211  
   212  	t := ca.createTemplate(pubkey)
   213  	t.Issuer = ca.Cred.Crt.Certificate.Subject
   214  	t.Subject = csr.Subject
   215  	t.Extensions = csr.Extensions
   216  	t.ExtraExtensions = csr.ExtraExtensions
   217  	t.DNSNames = csr.DNSNames
   218  	t.EmailAddresses = csr.EmailAddresses
   219  	t.IPAddresses = csr.IPAddresses
   220  	t.URIs = csr.URIs
   221  
   222  	return ca.Cred.SignCrt(t)
   223  }
   224  
   225  // createTemplate returns a certificate t for a non-CA certificate with
   226  // no subject name, no subjectAltNames. The t can then be modified into
   227  // a (root) CA t or an end-entity t by the caller.
   228  func (ca *CA) createTemplate(pubkey *ecdsa.PublicKey) *x509.Certificate {
   229  	c := createTemplate(ca.nextSerialNumber, pubkey, ca.Validity)
   230  	ca.nextSerialNumber++
   231  	// if our trust chain contains a certificate that expires
   232  	// sooner than the one we intend to issue, we clamp the
   233  	// NotAfter time of our newly issued certificate. That ensures
   234  	// the proxy will request a new cert before any of the
   235  	// certs in the chain are expired.
   236  	if ca.firstCrtExpiration.Before(c.NotAfter) {
   237  		c.NotAfter = ca.firstCrtExpiration
   238  	}
   239  	return c
   240  }
   241  
   242  // createTemplate returns a certificate t for a non-CA certificate with
   243  // no subject name, no subjectAltNames. The t can then be modified into
   244  // a (root) CA t or an end-entity t by the caller.
   245  func createTemplate(
   246  	serialNumber uint64,
   247  	k *ecdsa.PublicKey,
   248  	v Validity,
   249  ) *x509.Certificate {
   250  	// ECDSA is used instead of RSA because ECDSA key generation is
   251  	// straightforward and fast whereas RSA key generation is extremely slow
   252  	// and error-prone.
   253  	//
   254  	// CA certificates are signed with the same algorithm as end-entity
   255  	// certificates because they are relatively short-lived, because using one
   256  	// algorithm minimizes exposure to implementation flaws, and to speed up
   257  	// signature verification time.
   258  	//
   259  	// SHA-256 is used because any larger digest would be truncated to 256 bits
   260  	// anyway since a P-256 scalar is only 256 bits long.
   261  	const SignatureAlgorithm = x509.ECDSAWithSHA256
   262  
   263  	if v.ValidFrom == nil {
   264  		now := time.Now()
   265  		v.ValidFrom = &now
   266  	}
   267  	notBefore, notAfter := v.Window(*v.ValidFrom)
   268  
   269  	return &x509.Certificate{
   270  		SerialNumber:       big.NewInt(int64(serialNumber)),
   271  		SignatureAlgorithm: SignatureAlgorithm,
   272  		NotBefore:          notBefore,
   273  		NotAfter:           notAfter,
   274  		PublicKey:          k,
   275  		KeyUsage:           x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
   276  		ExtKeyUsage: []x509.ExtKeyUsage{
   277  			x509.ExtKeyUsageServerAuth,
   278  			x509.ExtKeyUsageClientAuth,
   279  		},
   280  	}
   281  }
   282  
   283  // Window returns the time window for which a certificate should be valid.
   284  func (v *Validity) Window(t time.Time) (time.Time, time.Time) {
   285  	life := v.Lifetime
   286  	if life == 0 {
   287  		life = DefaultLifetime
   288  	}
   289  	skew := v.ClockSkewAllowance
   290  	if skew == 0 {
   291  		skew = DefaultClockSkewAllowance
   292  	}
   293  	start := t.Add(-skew)
   294  	end := t.Add(life).Add(skew)
   295  	return start, end
   296  }
   297  

View as plain text