github.com/microsoft/moc@v0.17.1/pkg/certs/util.go (about)

     1  // Copyright (c) Microsoft Corporation. All rights reserved.
     2  // Licensed under the Apache v2.0 license.
     3  package certs
     4  
     5  import (
     6  	"bytes"
     7  	"crypto/rand"
     8  	"crypto/rsa"
     9  	"crypto/tls"
    10  	"crypto/x509"
    11  	"crypto/x509/pkix"
    12  	"encoding/pem"
    13  	"math"
    14  	"math/big"
    15  	"net"
    16  	"time"
    17  
    18  	"github.com/microsoft/moc/pkg/errors"
    19  	wssdnet "github.com/microsoft/moc/pkg/net"
    20  )
    21  
    22  // KeyPair holds the raw bytes for a certificate and key.
    23  type KeyPair struct {
    24  	Cert, Key []byte
    25  }
    26  
    27  // Config contains the basic fields required for creating a certificate.
    28  type Config struct {
    29  	CommonName   string
    30  	Organization []string
    31  	AltNames     AltNames
    32  	Usages       []x509.ExtKeyUsage
    33  }
    34  
    35  // Config contains the basic fields required for signing a certificate.
    36  type SignConfig struct {
    37  	Offset     time.Duration
    38  	Identity   string
    39  	ServerAuth bool
    40  	IsCA       bool
    41  }
    42  
    43  // AltNames contains the domain names and IP addresses for a cert
    44  type AltNames struct {
    45  	DNSNames []string
    46  	IPs      []net.IP
    47  }
    48  
    49  func publicKey(priv interface{}) interface{} {
    50  	switch k := priv.(type) {
    51  	case *rsa.PrivateKey:
    52  		return &k.PublicKey
    53  	default:
    54  		return nil
    55  	}
    56  }
    57  
    58  // IsValid returns true if both the certificate and key are non-nil.
    59  func (k *KeyPair) IsValid() bool {
    60  	return k.Cert != nil && k.Key != nil
    61  }
    62  
    63  // NewPrivateKey creates an RSA private key
    64  func NewPrivateKey() (*rsa.PrivateKey, error) {
    65  	pk, err := rsa.GenerateKey(rand.Reader, 2048)
    66  	return pk, err
    67  }
    68  
    69  // EncodeCertPEM returns PEM-endcoded certificate data.
    70  func EncodeCertPEM(cert *x509.Certificate) []byte {
    71  	block := pem.Block{
    72  		Type:  "CERTIFICATE",
    73  		Bytes: cert.Raw,
    74  	}
    75  	return pem.EncodeToMemory(&block)
    76  }
    77  
    78  // EncodeCertRequestPEM returns PEM-endcoded certificate request data.
    79  func EncodeCertRequestPEM(cert *x509.CertificateRequest) []byte {
    80  	block := pem.Block{
    81  		Type:  "CERTIFICATE REQUEST",
    82  		Bytes: cert.Raw,
    83  	}
    84  	return pem.EncodeToMemory(&block)
    85  }
    86  
    87  // EncodePrivateKeyPEM returns PEM-encoded private key data.
    88  func EncodePrivateKeyPEM(key *rsa.PrivateKey) []byte {
    89  	block := pem.Block{
    90  		Type:  "RSA PRIVATE KEY",
    91  		Bytes: x509.MarshalPKCS1PrivateKey(key),
    92  	}
    93  
    94  	return pem.EncodeToMemory(&block)
    95  }
    96  
    97  // EncodePublicKeyPEM returns PEM-encoded public key data.
    98  func EncodePublicKeyBytePEM(key []byte) ([]byte, error) {
    99  	block := pem.Block{
   100  		Type:  "PUBLIC KEY",
   101  		Bytes: key,
   102  	}
   103  	return pem.EncodeToMemory(&block), nil
   104  }
   105  
   106  // EncodePublicKeyPEM returns PEM-encoded public key data.
   107  func EncodePublicKeyPEM(key *rsa.PublicKey) ([]byte, error) {
   108  	der, err := x509.MarshalPKIXPublicKey(key)
   109  	if err != nil {
   110  		return []byte{}, err
   111  	}
   112  	return EncodePublicKeyBytePEM(der)
   113  }
   114  
   115  // DecodeCertPEM attempts to return a decoded certificate or nil
   116  // if the encoded input does not contain a certificate.
   117  func DecodeCertPEM(encoded []byte) (*x509.Certificate, error) {
   118  	block, _ := pem.Decode(encoded)
   119  	if block == nil {
   120  		return nil, nil
   121  	}
   122  
   123  	return x509.ParseCertificate(block.Bytes)
   124  }
   125  
   126  // DecodeCertRequestPEM attempts to return a decoded certificate request or nil
   127  // if the encoded input does not contain a certificate request.
   128  func DecodeCertRequestPEM(encoded []byte) (*x509.CertificateRequest, error) {
   129  	block, _ := pem.Decode(encoded)
   130  	if block == nil {
   131  		return nil, nil
   132  	}
   133  
   134  	return x509.ParseCertificateRequest(block.Bytes)
   135  }
   136  
   137  // DecodePrivateKeyPEM attempts to return a decoded key or nil
   138  // if the encoded input does not contain a private key.
   139  func DecodePrivateKeyPEM(encoded []byte) (*rsa.PrivateKey, error) {
   140  	block, _ := pem.Decode(encoded)
   141  	if block == nil {
   142  		return nil, nil
   143  	}
   144  
   145  	return x509.ParsePKCS1PrivateKey(block.Bytes)
   146  }
   147  
   148  func GenerateClientCertificate(name string) (*x509.Certificate, *rsa.PrivateKey, error) {
   149  	key, err := rsa.GenerateKey(rand.Reader, 2048)
   150  	if err != nil {
   151  		return nil, key, err
   152  	}
   153  
   154  	nodeFqdn, err := wssdnet.GetIPAddress()
   155  	if err != nil {
   156  		return nil, key, err
   157  	}
   158  
   159  	now := time.Now().UTC()
   160  
   161  	serial, err := rand.Int(rand.Reader, new(big.Int).SetInt64(math.MaxInt64))
   162  	if err != nil {
   163  		return nil, key, err
   164  	}
   165  
   166  	tmpl := x509.Certificate{
   167  		SerialNumber: serial,
   168  		Subject: pkix.Name{
   169  			CommonName:   name,
   170  			Organization: []string{"microsoft"},
   171  		},
   172  		NotBefore:             now.Add(time.Minute * -5),
   173  		NotAfter:              now.Add(time.Hour * 24 * 365 * 10), // 10 years
   174  		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
   175  		MaxPathLenZero:        true,
   176  		BasicConstraintsValid: true,
   177  		MaxPathLen:            0,
   178  		IsCA:                  true,
   179  		DNSNames:              []string{"localhost"},
   180  		IPAddresses:           []net.IP{wssdnet.StringToNetIPAddress(wssdnet.LOOPBACK_ADDRESS), wssdnet.StringToNetIPAddress(nodeFqdn)},
   181  	}
   182  
   183  	b, err := x509.CreateCertificate(rand.Reader, &tmpl, &tmpl, key.Public(), key)
   184  	if err != nil {
   185  		return nil, key, err
   186  	}
   187  
   188  	x509Cert, err := x509.ParseCertificate(b)
   189  	if err != nil {
   190  		return nil, key, err
   191  	}
   192  
   193  	return x509Cert, key, nil
   194  }
   195  
   196  func NewSignedCert(key *rsa.PrivateKey, caCert *x509.Certificate, caKey *rsa.PrivateKey, conf Config) (*x509.Certificate, error) {
   197  	serial, err := rand.Int(rand.Reader, new(big.Int).SetInt64(math.MaxInt64))
   198  	if err != nil {
   199  		return nil, err
   200  	}
   201  
   202  	now := time.Now().UTC()
   203  
   204  	tmpl := x509.Certificate{
   205  		SerialNumber: serial,
   206  		Subject: pkix.Name{
   207  			CommonName:   conf.CommonName,
   208  			Organization: conf.Organization,
   209  		},
   210  		NotBefore:             now.Add(time.Minute * -5),
   211  		NotAfter:              now.Add(time.Hour * 24 * 365), // 1 year
   212  		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
   213  		ExtKeyUsage:           conf.Usages,
   214  		BasicConstraintsValid: true,
   215  		DNSNames:              conf.AltNames.DNSNames,
   216  		IPAddresses:           conf.AltNames.IPs,
   217  	}
   218  
   219  	b, err := x509.CreateCertificate(rand.Reader, &tmpl, caCert, key.Public(), caKey)
   220  	if err != nil {
   221  		return nil, err
   222  	}
   223  
   224  	return x509.ParseCertificate(b)
   225  }
   226  
   227  // GenerateCertificateRequest creates a CSR
   228  // if privKey is not provided, a new one will be created and returned
   229  // if privKey is provided, it will be used to create csr and the same key will be returned
   230  func GenerateCertificateRequest(conf *Config, privKey []byte) (csr []byte, retPrivKey []byte, err error) {
   231  
   232  	var key *rsa.PrivateKey
   233  	// It private key does not exist create a new key
   234  	if privKey == nil || len(privKey) == 0 {
   235  		key, err = rsa.GenerateKey(rand.Reader, 2048)
   236  		if err != nil {
   237  			return
   238  		}
   239  		retPrivKey = EncodePrivateKeyPEM(key)
   240  	} else {
   241  		key, err = DecodePrivateKeyPEM(privKey)
   242  		if err != nil {
   243  			return
   244  		}
   245  		retPrivKey = privKey
   246  	}
   247  
   248  	tmpl := x509.CertificateRequest{
   249  		Subject: pkix.Name{
   250  			CommonName:   conf.CommonName,
   251  			Organization: conf.Organization,
   252  		},
   253  		SignatureAlgorithm: x509.SHA256WithRSA,
   254  		PublicKey:          key.Public(),
   255  		DNSNames:           conf.AltNames.DNSNames,
   256  		IPAddresses:        conf.AltNames.IPs,
   257  	}
   258  
   259  	b, err := x509.CreateCertificateRequest(rand.Reader, &tmpl, key)
   260  	if err != nil {
   261  		return
   262  	}
   263  
   264  	x509CertReq, err := x509.ParseCertificateRequest(b)
   265  	if err != nil {
   266  		return
   267  	}
   268  
   269  	csr = EncodeCertRequestPEM(x509CertReq)
   270  
   271  	return
   272  }
   273  
   274  func createCSRRenewExtensions(csrCertificate []byte, currentCertificate [][]byte) (extensions []pkix.Extension, err error) {
   275  	certsBuffer := bytes.Buffer{}
   276  	certPEMBlock := &pem.Block{
   277  		Type:  "CERTIFICATE",
   278  		Bytes: csrCertificate,
   279  	}
   280  
   281  	err = pem.Encode(&certsBuffer, certPEMBlock)
   282  	if err != nil {
   283  		return nil, errors.Wrapf(errors.Failed, "unable to PEM encode CSR certificate: %v", err)
   284  	}
   285  
   286  	for _, cert := range currentCertificate {
   287  		certPEMBlock.Bytes = cert
   288  		err = pem.Encode(&certsBuffer, certPEMBlock)
   289  		if err != nil {
   290  			return nil, errors.Wrapf(errors.Failed, "unable to PEM encode certificates: %v", err)
   291  		}
   292  	}
   293  
   294  	extensions = []pkix.Extension{
   295  		{
   296  			Id:       oidRenewCertificates,
   297  			Critical: false,
   298  			Value:    certsBuffer.Bytes(),
   299  		},
   300  	}
   301  
   302  	return extensions, nil
   303  }
   304  
   305  // GenerateCertificateRenewRequest creates a renew CSR
   306  // A new private key will be created, used to create CSR and returned
   307  func GenerateCertificateRenewRequest(cert *tls.Certificate) (retCsr []byte, retPriv []byte, err error) {
   308  	leaf := cert.Leaf
   309  	if leaf == nil {
   310  		leaf, err = x509.ParseCertificate(cert.Certificate[0])
   311  		if err != nil {
   312  			return nil, nil, errors.Wrapf(errors.Failed, "unable to parse leaf: %v", err)
   313  		}
   314  	}
   315  
   316  	var privateKey *rsa.PrivateKey
   317  
   318  	switch pub := leaf.PublicKey.(type) {
   319  	case *rsa.PublicKey:
   320  		privateKey, err = rsa.GenerateKey(rand.Reader, pub.Size()*8)
   321  	default:
   322  		err = errors.Wrapf(errors.NotSupported, "unsupported public key type: %T", pub)
   323  	}
   324  	if err != nil {
   325  		return nil, nil, errors.Wrapf(errors.Failed, "unable to generate private key: %v", err)
   326  	}
   327  	retPriv = EncodePrivateKeyPEM(privateKey)
   328  	csrKeyTemplate := x509.Certificate{
   329  		SerialNumber: big.NewInt(1),
   330  		Subject: pkix.Name{
   331  			CommonName: "CSR Key",
   332  		},
   333  		NotBefore: time.Now(),
   334  		NotAfter:  leaf.NotAfter,
   335  	}
   336  
   337  	csrCertificate, err := x509.CreateCertificate(rand.Reader, &csrKeyTemplate, leaf,
   338  		privateKey.Public(), cert.PrivateKey)
   339  	if err != nil {
   340  		return nil, nil, errors.Wrapf(errors.Failed, "unable to create CSR Key certificate: %v", err)
   341  	}
   342  
   343  	csrTemplate := x509.CertificateRequest{
   344  		Subject:     leaf.Subject,
   345  		DNSNames:    leaf.DNSNames,
   346  		IPAddresses: leaf.IPAddresses,
   347  	}
   348  	template := &csrTemplate
   349  
   350  	template.ExtraExtensions, err = createCSRRenewExtensions(csrCertificate, cert.Certificate)
   351  	if err != nil {
   352  		return nil, nil, errors.Wrapf(errors.Failed, "unable to create CSR renew extensions: %v", err)
   353  	}
   354  
   355  	csr, err := x509.CreateCertificateRequest(rand.Reader, template, privateKey)
   356  	if err != nil {
   357  		return nil, nil, errors.Wrapf(errors.Failed, "unable to create CSR request: %v", err)
   358  	}
   359  
   360  	x509CertReq, err := x509.ParseCertificateRequest(csr)
   361  	if err != nil {
   362  		return
   363  	}
   364  	retCsr = EncodeCertRequestPEM(x509CertReq)
   365  	return
   366  }
   367  
   368  // GenerateCertificateRenewRequestSameKey creates a renew CSR
   369  // A same private key in cert will be used to create CSR
   370  func GenerateCertificateRenewRequestSameKey(cert *tls.Certificate) (retCsr []byte, err error) {
   371  
   372  	leaf := cert.Leaf
   373  	if leaf == nil {
   374  		leaf, err = x509.ParseCertificate(cert.Certificate[0])
   375  		if err != nil {
   376  			return nil, errors.Wrapf(errors.Failed, "unable to parse leaf: %v", err)
   377  		}
   378  	}
   379  
   380  	csrKeyTemplate := x509.Certificate{
   381  		SerialNumber: big.NewInt(1),
   382  		Subject: pkix.Name{
   383  			CommonName: "CSR Key",
   384  		},
   385  		NotBefore:   time.Now(),
   386  		NotAfter:    leaf.NotAfter,
   387  		DNSNames:    leaf.DNSNames,
   388  		IPAddresses: leaf.IPAddresses,
   389  	}
   390  
   391  	csrCertificate, err := x509.CreateCertificate(rand.Reader, &csrKeyTemplate, leaf,
   392  		publicKey(cert.PrivateKey), cert.PrivateKey)
   393  	if err != nil {
   394  		return nil, errors.Wrapf(errors.Failed, "unable to create CSR Key certificate: %v", err)
   395  	}
   396  
   397  	csrTemplate := x509.CertificateRequest{
   398  		Subject:     leaf.Subject,
   399  		DNSNames:    leaf.DNSNames,
   400  		IPAddresses: leaf.IPAddresses,
   401  	}
   402  	template := &csrTemplate
   403  
   404  	template.ExtraExtensions, err = createCSRRenewExtensions(csrCertificate, cert.Certificate)
   405  	if err != nil {
   406  		return nil, errors.Wrapf(errors.Failed, "unable to create CSR renew extensions: %v", err)
   407  	}
   408  
   409  	csr, err := x509.CreateCertificateRequest(rand.Reader, template, cert.PrivateKey)
   410  	if err != nil {
   411  		return nil, errors.Wrapf(errors.Failed, "unable to create CSR request: %v", err)
   412  	}
   413  
   414  	x509CertReq, err := x509.ParseCertificateRequest(csr)
   415  	if err != nil {
   416  		return nil, err
   417  	}
   418  	retCsr = EncodeCertRequestPEM(x509CertReq)
   419  	return
   420  }