mirror of
				https://gitea.com/Lydanne/buildx.git
				synced 2025-11-04 18:13:42 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			565 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			565 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package utils
 | 
						|
 | 
						|
import (
 | 
						|
	"bytes"
 | 
						|
	"crypto/ecdsa"
 | 
						|
	"crypto/elliptic"
 | 
						|
	"crypto/rand"
 | 
						|
	"crypto/rsa"
 | 
						|
	"crypto/x509"
 | 
						|
	"crypto/x509/pkix"
 | 
						|
	"encoding/pem"
 | 
						|
	"errors"
 | 
						|
	"fmt"
 | 
						|
	"io"
 | 
						|
	"io/ioutil"
 | 
						|
	"math/big"
 | 
						|
	"time"
 | 
						|
 | 
						|
	"github.com/agl/ed25519"
 | 
						|
	"github.com/sirupsen/logrus"
 | 
						|
	"github.com/theupdateframework/notary"
 | 
						|
	"github.com/theupdateframework/notary/tuf/data"
 | 
						|
)
 | 
						|
 | 
						|
// CanonicalKeyID returns the ID of the public bytes version of a TUF key.
 | 
						|
// On regular RSA/ECDSA TUF keys, this is just the key ID.  On X509 RSA/ECDSA
 | 
						|
// TUF keys, this is the key ID of the public key part of the key in the leaf cert
 | 
						|
func CanonicalKeyID(k data.PublicKey) (string, error) {
 | 
						|
	if k == nil {
 | 
						|
		return "", errors.New("public key is nil")
 | 
						|
	}
 | 
						|
	switch k.Algorithm() {
 | 
						|
	case data.ECDSAx509Key, data.RSAx509Key:
 | 
						|
		return X509PublicKeyID(k)
 | 
						|
	default:
 | 
						|
		return k.ID(), nil
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// LoadCertFromPEM returns the first certificate found in a bunch of bytes or error
 | 
						|
// if nothing is found. Taken from https://golang.org/src/crypto/x509/cert_pool.go#L85.
 | 
						|
func LoadCertFromPEM(pemBytes []byte) (*x509.Certificate, error) {
 | 
						|
	for len(pemBytes) > 0 {
 | 
						|
		var block *pem.Block
 | 
						|
		block, pemBytes = pem.Decode(pemBytes)
 | 
						|
		if block == nil {
 | 
						|
			return nil, errors.New("no certificates found in PEM data")
 | 
						|
		}
 | 
						|
		if block.Type != "CERTIFICATE" || len(block.Headers) != 0 {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
 | 
						|
		cert, err := x509.ParseCertificate(block.Bytes)
 | 
						|
		if err != nil {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
 | 
						|
		return cert, nil
 | 
						|
	}
 | 
						|
 | 
						|
	return nil, errors.New("no certificates found in PEM data")
 | 
						|
}
 | 
						|
 | 
						|
// X509PublicKeyID returns a public key ID as a string, given a
 | 
						|
// data.PublicKey that contains an X509 Certificate
 | 
						|
func X509PublicKeyID(certPubKey data.PublicKey) (string, error) {
 | 
						|
	// Note that this only loads the first certificate from the public key
 | 
						|
	cert, err := LoadCertFromPEM(certPubKey.Public())
 | 
						|
	if err != nil {
 | 
						|
		return "", err
 | 
						|
	}
 | 
						|
	pubKeyBytes, err := x509.MarshalPKIXPublicKey(cert.PublicKey)
 | 
						|
	if err != nil {
 | 
						|
		return "", err
 | 
						|
	}
 | 
						|
 | 
						|
	var key data.PublicKey
 | 
						|
	switch certPubKey.Algorithm() {
 | 
						|
	case data.ECDSAx509Key:
 | 
						|
		key = data.NewECDSAPublicKey(pubKeyBytes)
 | 
						|
	case data.RSAx509Key:
 | 
						|
		key = data.NewRSAPublicKey(pubKeyBytes)
 | 
						|
	}
 | 
						|
 | 
						|
	return key.ID(), nil
 | 
						|
}
 | 
						|
 | 
						|
func parseLegacyPrivateKey(block *pem.Block, passphrase string) (data.PrivateKey, error) {
 | 
						|
	var privKeyBytes []byte
 | 
						|
	var err error
 | 
						|
	if x509.IsEncryptedPEMBlock(block) {
 | 
						|
		privKeyBytes, err = x509.DecryptPEMBlock(block, []byte(passphrase))
 | 
						|
		if err != nil {
 | 
						|
			return nil, errors.New("could not decrypt private key")
 | 
						|
		}
 | 
						|
	} else {
 | 
						|
		privKeyBytes = block.Bytes
 | 
						|
	}
 | 
						|
 | 
						|
	switch block.Type {
 | 
						|
	case "RSA PRIVATE KEY":
 | 
						|
		rsaPrivKey, err := x509.ParsePKCS1PrivateKey(privKeyBytes)
 | 
						|
		if err != nil {
 | 
						|
			return nil, fmt.Errorf("could not parse DER encoded key: %v", err)
 | 
						|
		}
 | 
						|
 | 
						|
		tufRSAPrivateKey, err := RSAToPrivateKey(rsaPrivKey)
 | 
						|
		if err != nil {
 | 
						|
			return nil, fmt.Errorf("could not convert rsa.PrivateKey to data.PrivateKey: %v", err)
 | 
						|
		}
 | 
						|
 | 
						|
		return tufRSAPrivateKey, nil
 | 
						|
	case "EC PRIVATE KEY":
 | 
						|
		ecdsaPrivKey, err := x509.ParseECPrivateKey(privKeyBytes)
 | 
						|
		if err != nil {
 | 
						|
			return nil, fmt.Errorf("could not parse DER encoded private key: %v", err)
 | 
						|
		}
 | 
						|
 | 
						|
		tufECDSAPrivateKey, err := ECDSAToPrivateKey(ecdsaPrivKey)
 | 
						|
		if err != nil {
 | 
						|
			return nil, fmt.Errorf("could not convert ecdsa.PrivateKey to data.PrivateKey: %v", err)
 | 
						|
		}
 | 
						|
 | 
						|
		return tufECDSAPrivateKey, nil
 | 
						|
	case "ED25519 PRIVATE KEY":
 | 
						|
		// We serialize ED25519 keys by concatenating the private key
 | 
						|
		// to the public key and encoding with PEM. See the
 | 
						|
		// ED25519ToPrivateKey function.
 | 
						|
		tufECDSAPrivateKey, err := ED25519ToPrivateKey(privKeyBytes)
 | 
						|
		if err != nil {
 | 
						|
			return nil, fmt.Errorf("could not convert ecdsa.PrivateKey to data.PrivateKey: %v", err)
 | 
						|
		}
 | 
						|
 | 
						|
		return tufECDSAPrivateKey, nil
 | 
						|
 | 
						|
	default:
 | 
						|
		return nil, fmt.Errorf("unsupported key type %q", block.Type)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// ParsePEMPrivateKey returns a data.PrivateKey from a PEM encoded private key. It
 | 
						|
// supports PKCS#8 as well as RSA/ECDSA (PKCS#1) only in non-FIPS mode and
 | 
						|
// attempts to decrypt using the passphrase, if encrypted.
 | 
						|
func ParsePEMPrivateKey(pemBytes []byte, passphrase string) (data.PrivateKey, error) {
 | 
						|
	return parsePEMPrivateKey(pemBytes, passphrase, notary.FIPSEnabled())
 | 
						|
}
 | 
						|
 | 
						|
func parsePEMPrivateKey(pemBytes []byte, passphrase string, fips bool) (data.PrivateKey, error) {
 | 
						|
	block, _ := pem.Decode(pemBytes)
 | 
						|
	if block == nil {
 | 
						|
		return nil, errors.New("no valid private key found")
 | 
						|
	}
 | 
						|
 | 
						|
	switch block.Type {
 | 
						|
	case "RSA PRIVATE KEY", "EC PRIVATE KEY", "ED25519 PRIVATE KEY":
 | 
						|
		if fips {
 | 
						|
			return nil, fmt.Errorf("%s not supported in FIPS mode", block.Type)
 | 
						|
		}
 | 
						|
		return parseLegacyPrivateKey(block, passphrase)
 | 
						|
	case "ENCRYPTED PRIVATE KEY", "PRIVATE KEY":
 | 
						|
		if passphrase == "" {
 | 
						|
			return ParsePKCS8ToTufKey(block.Bytes, nil)
 | 
						|
		}
 | 
						|
		return ParsePKCS8ToTufKey(block.Bytes, []byte(passphrase))
 | 
						|
	default:
 | 
						|
		return nil, fmt.Errorf("unsupported key type %q", block.Type)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// CertToPEM is a utility function returns a PEM encoded x509 Certificate
 | 
						|
func CertToPEM(cert *x509.Certificate) []byte {
 | 
						|
	pemCert := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw})
 | 
						|
 | 
						|
	return pemCert
 | 
						|
}
 | 
						|
 | 
						|
// CertChainToPEM is a utility function returns a PEM encoded chain of x509 Certificates, in the order they are passed
 | 
						|
func CertChainToPEM(certChain []*x509.Certificate) ([]byte, error) {
 | 
						|
	var pemBytes bytes.Buffer
 | 
						|
	for _, cert := range certChain {
 | 
						|
		if err := pem.Encode(&pemBytes, &pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw}); err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return pemBytes.Bytes(), nil
 | 
						|
}
 | 
						|
 | 
						|
// LoadCertFromFile loads the first certificate from the file provided. The
 | 
						|
// data is expected to be PEM Encoded and contain one of more certificates
 | 
						|
// with PEM type "CERTIFICATE"
 | 
						|
func LoadCertFromFile(filename string) (*x509.Certificate, error) {
 | 
						|
	certs, err := LoadCertBundleFromFile(filename)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	return certs[0], nil
 | 
						|
}
 | 
						|
 | 
						|
// LoadCertBundleFromFile loads certificates from the []byte provided. The
 | 
						|
// data is expected to be PEM Encoded and contain one of more certificates
 | 
						|
// with PEM type "CERTIFICATE"
 | 
						|
func LoadCertBundleFromFile(filename string) ([]*x509.Certificate, error) {
 | 
						|
	b, err := ioutil.ReadFile(filename)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	return LoadCertBundleFromPEM(b)
 | 
						|
}
 | 
						|
 | 
						|
// LoadCertBundleFromPEM loads certificates from the []byte provided. The
 | 
						|
// data is expected to be PEM Encoded and contain one of more certificates
 | 
						|
// with PEM type "CERTIFICATE"
 | 
						|
func LoadCertBundleFromPEM(pemBytes []byte) ([]*x509.Certificate, error) {
 | 
						|
	certificates := []*x509.Certificate{}
 | 
						|
	var block *pem.Block
 | 
						|
	block, pemBytes = pem.Decode(pemBytes)
 | 
						|
	for ; block != nil; block, pemBytes = pem.Decode(pemBytes) {
 | 
						|
		if block.Type == "CERTIFICATE" {
 | 
						|
			cert, err := x509.ParseCertificate(block.Bytes)
 | 
						|
			if err != nil {
 | 
						|
				return nil, err
 | 
						|
			}
 | 
						|
			certificates = append(certificates, cert)
 | 
						|
		} else {
 | 
						|
			return nil, fmt.Errorf("invalid pem block type: %s", block.Type)
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if len(certificates) == 0 {
 | 
						|
		return nil, fmt.Errorf("no valid certificates found")
 | 
						|
	}
 | 
						|
 | 
						|
	return certificates, nil
 | 
						|
}
 | 
						|
 | 
						|
// GetLeafCerts parses a list of x509 Certificates and returns all of them
 | 
						|
// that aren't CA
 | 
						|
func GetLeafCerts(certs []*x509.Certificate) []*x509.Certificate {
 | 
						|
	var leafCerts []*x509.Certificate
 | 
						|
	for _, cert := range certs {
 | 
						|
		if cert.IsCA {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		leafCerts = append(leafCerts, cert)
 | 
						|
	}
 | 
						|
	return leafCerts
 | 
						|
}
 | 
						|
 | 
						|
// GetIntermediateCerts parses a list of x509 Certificates and returns all of the
 | 
						|
// ones marked as a CA, to be used as intermediates
 | 
						|
func GetIntermediateCerts(certs []*x509.Certificate) []*x509.Certificate {
 | 
						|
	var intCerts []*x509.Certificate
 | 
						|
	for _, cert := range certs {
 | 
						|
		if cert.IsCA {
 | 
						|
			intCerts = append(intCerts, cert)
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return intCerts
 | 
						|
}
 | 
						|
 | 
						|
// ParsePEMPublicKey returns a data.PublicKey from a PEM encoded public key or certificate.
 | 
						|
func ParsePEMPublicKey(pubKeyBytes []byte) (data.PublicKey, error) {
 | 
						|
	pemBlock, _ := pem.Decode(pubKeyBytes)
 | 
						|
	if pemBlock == nil {
 | 
						|
		return nil, errors.New("no valid public key found")
 | 
						|
	}
 | 
						|
 | 
						|
	switch pemBlock.Type {
 | 
						|
	case "CERTIFICATE":
 | 
						|
		cert, err := x509.ParseCertificate(pemBlock.Bytes)
 | 
						|
		if err != nil {
 | 
						|
			return nil, fmt.Errorf("could not parse provided certificate: %v", err)
 | 
						|
		}
 | 
						|
		err = ValidateCertificate(cert, true)
 | 
						|
		if err != nil {
 | 
						|
			return nil, fmt.Errorf("invalid certificate: %v", err)
 | 
						|
		}
 | 
						|
		return CertToKey(cert), nil
 | 
						|
	case "PUBLIC KEY":
 | 
						|
		keyType, err := keyTypeForPublicKey(pemBlock.Bytes)
 | 
						|
		if err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
		return data.NewPublicKey(keyType, pemBlock.Bytes), nil
 | 
						|
	default:
 | 
						|
		return nil, fmt.Errorf("unsupported PEM block type %q, expected CERTIFICATE or PUBLIC KEY", pemBlock.Type)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func keyTypeForPublicKey(pubKeyBytes []byte) (string, error) {
 | 
						|
	pub, err := x509.ParsePKIXPublicKey(pubKeyBytes)
 | 
						|
	if err != nil {
 | 
						|
		return "", fmt.Errorf("unable to parse pem encoded public key: %v", err)
 | 
						|
	}
 | 
						|
	switch pub.(type) {
 | 
						|
	case *ecdsa.PublicKey:
 | 
						|
		return data.ECDSAKey, nil
 | 
						|
	case *rsa.PublicKey:
 | 
						|
		return data.RSAKey, nil
 | 
						|
	}
 | 
						|
	return "", fmt.Errorf("unknown public key format")
 | 
						|
}
 | 
						|
 | 
						|
// ValidateCertificate returns an error if the certificate is not valid for notary
 | 
						|
// Currently this is only ensuring the public key has a large enough modulus if RSA,
 | 
						|
// using a non SHA1 signature algorithm, and an optional time expiry check
 | 
						|
func ValidateCertificate(c *x509.Certificate, checkExpiry bool) error {
 | 
						|
	if (c.NotBefore).After(c.NotAfter) {
 | 
						|
		return fmt.Errorf("certificate validity window is invalid")
 | 
						|
	}
 | 
						|
	// Can't have SHA1 sig algorithm
 | 
						|
	if c.SignatureAlgorithm == x509.SHA1WithRSA || c.SignatureAlgorithm == x509.DSAWithSHA1 || c.SignatureAlgorithm == x509.ECDSAWithSHA1 {
 | 
						|
		return fmt.Errorf("certificate with CN %s uses invalid SHA1 signature algorithm", c.Subject.CommonName)
 | 
						|
	}
 | 
						|
	// If we have an RSA key, make sure it's long enough
 | 
						|
	if c.PublicKeyAlgorithm == x509.RSA {
 | 
						|
		rsaKey, ok := c.PublicKey.(*rsa.PublicKey)
 | 
						|
		if !ok {
 | 
						|
			return fmt.Errorf("unable to parse RSA public key")
 | 
						|
		}
 | 
						|
		if rsaKey.N.BitLen() < notary.MinRSABitSize {
 | 
						|
			return fmt.Errorf("RSA bit length is too short")
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if checkExpiry {
 | 
						|
		now := time.Now()
 | 
						|
		tomorrow := now.AddDate(0, 0, 1)
 | 
						|
		// Give one day leeway on creation "before" time, check "after" against today
 | 
						|
		if (tomorrow).Before(c.NotBefore) || now.After(c.NotAfter) {
 | 
						|
			return data.ErrCertExpired{CN: c.Subject.CommonName}
 | 
						|
		}
 | 
						|
		// If this certificate is expiring within 6 months, put out a warning
 | 
						|
		if (c.NotAfter).Before(time.Now().AddDate(0, 6, 0)) {
 | 
						|
			logrus.Warnf("certificate with CN %s is near expiry", c.Subject.CommonName)
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
// GenerateKey returns a new private key using the provided algorithm or an
 | 
						|
// error detailing why the key could not be generated
 | 
						|
func GenerateKey(algorithm string) (data.PrivateKey, error) {
 | 
						|
	switch algorithm {
 | 
						|
	case data.ECDSAKey:
 | 
						|
		return GenerateECDSAKey(rand.Reader)
 | 
						|
	case data.ED25519Key:
 | 
						|
		return GenerateED25519Key(rand.Reader)
 | 
						|
	}
 | 
						|
	return nil, fmt.Errorf("private key type not supported for key generation: %s", algorithm)
 | 
						|
}
 | 
						|
 | 
						|
// RSAToPrivateKey converts an rsa.Private key to a TUF data.PrivateKey type
 | 
						|
func RSAToPrivateKey(rsaPrivKey *rsa.PrivateKey) (data.PrivateKey, error) {
 | 
						|
	// Get a DER-encoded representation of the PublicKey
 | 
						|
	rsaPubBytes, err := x509.MarshalPKIXPublicKey(&rsaPrivKey.PublicKey)
 | 
						|
	if err != nil {
 | 
						|
		return nil, fmt.Errorf("failed to marshal public key: %v", err)
 | 
						|
	}
 | 
						|
 | 
						|
	// Get a DER-encoded representation of the PrivateKey
 | 
						|
	rsaPrivBytes := x509.MarshalPKCS1PrivateKey(rsaPrivKey)
 | 
						|
 | 
						|
	pubKey := data.NewRSAPublicKey(rsaPubBytes)
 | 
						|
	return data.NewRSAPrivateKey(pubKey, rsaPrivBytes)
 | 
						|
}
 | 
						|
 | 
						|
// GenerateECDSAKey generates an ECDSA Private key and returns a TUF PrivateKey
 | 
						|
func GenerateECDSAKey(random io.Reader) (data.PrivateKey, error) {
 | 
						|
	ecdsaPrivKey, err := ecdsa.GenerateKey(elliptic.P256(), random)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	tufPrivKey, err := ECDSAToPrivateKey(ecdsaPrivKey)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	logrus.Debugf("generated ECDSA key with keyID: %s", tufPrivKey.ID())
 | 
						|
 | 
						|
	return tufPrivKey, nil
 | 
						|
}
 | 
						|
 | 
						|
// GenerateED25519Key generates an ED25519 private key and returns a TUF
 | 
						|
// PrivateKey. The serialization format we use is just the public key bytes
 | 
						|
// followed by the private key bytes
 | 
						|
func GenerateED25519Key(random io.Reader) (data.PrivateKey, error) {
 | 
						|
	pub, priv, err := ed25519.GenerateKey(random)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	var serialized [ed25519.PublicKeySize + ed25519.PrivateKeySize]byte
 | 
						|
	copy(serialized[:], pub[:])
 | 
						|
	copy(serialized[ed25519.PublicKeySize:], priv[:])
 | 
						|
 | 
						|
	tufPrivKey, err := ED25519ToPrivateKey(serialized[:])
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	logrus.Debugf("generated ED25519 key with keyID: %s", tufPrivKey.ID())
 | 
						|
 | 
						|
	return tufPrivKey, nil
 | 
						|
}
 | 
						|
 | 
						|
// ECDSAToPrivateKey converts an ecdsa.Private key to a TUF data.PrivateKey type
 | 
						|
func ECDSAToPrivateKey(ecdsaPrivKey *ecdsa.PrivateKey) (data.PrivateKey, error) {
 | 
						|
	// Get a DER-encoded representation of the PublicKey
 | 
						|
	ecdsaPubBytes, err := x509.MarshalPKIXPublicKey(&ecdsaPrivKey.PublicKey)
 | 
						|
	if err != nil {
 | 
						|
		return nil, fmt.Errorf("failed to marshal public key: %v", err)
 | 
						|
	}
 | 
						|
 | 
						|
	// Get a DER-encoded representation of the PrivateKey
 | 
						|
	ecdsaPrivKeyBytes, err := x509.MarshalECPrivateKey(ecdsaPrivKey)
 | 
						|
	if err != nil {
 | 
						|
		return nil, fmt.Errorf("failed to marshal private key: %v", err)
 | 
						|
	}
 | 
						|
 | 
						|
	pubKey := data.NewECDSAPublicKey(ecdsaPubBytes)
 | 
						|
	return data.NewECDSAPrivateKey(pubKey, ecdsaPrivKeyBytes)
 | 
						|
}
 | 
						|
 | 
						|
// ED25519ToPrivateKey converts a serialized ED25519 key to a TUF
 | 
						|
// data.PrivateKey type
 | 
						|
func ED25519ToPrivateKey(privKeyBytes []byte) (data.PrivateKey, error) {
 | 
						|
	if len(privKeyBytes) != ed25519.PublicKeySize+ed25519.PrivateKeySize {
 | 
						|
		return nil, errors.New("malformed ed25519 private key")
 | 
						|
	}
 | 
						|
 | 
						|
	pubKey := data.NewED25519PublicKey(privKeyBytes[:ed25519.PublicKeySize])
 | 
						|
	return data.NewED25519PrivateKey(*pubKey, privKeyBytes)
 | 
						|
}
 | 
						|
 | 
						|
// ExtractPrivateKeyAttributes extracts role and gun values from private key bytes
 | 
						|
func ExtractPrivateKeyAttributes(pemBytes []byte) (data.RoleName, data.GUN, error) {
 | 
						|
	return extractPrivateKeyAttributes(pemBytes, notary.FIPSEnabled())
 | 
						|
}
 | 
						|
 | 
						|
func extractPrivateKeyAttributes(pemBytes []byte, fips bool) (data.RoleName, data.GUN, error) {
 | 
						|
	block, _ := pem.Decode(pemBytes)
 | 
						|
	if block == nil {
 | 
						|
		return "", "", errors.New("PEM block is empty")
 | 
						|
	}
 | 
						|
 | 
						|
	switch block.Type {
 | 
						|
	case "RSA PRIVATE KEY", "EC PRIVATE KEY", "ED25519 PRIVATE KEY":
 | 
						|
		if fips {
 | 
						|
			return "", "", fmt.Errorf("%s not supported in FIPS mode", block.Type)
 | 
						|
		}
 | 
						|
	case "PRIVATE KEY", "ENCRYPTED PRIVATE KEY":
 | 
						|
		// do nothing for PKCS#8 keys
 | 
						|
	default:
 | 
						|
		return "", "", errors.New("unknown key format")
 | 
						|
	}
 | 
						|
	return data.RoleName(block.Headers["role"]), data.GUN(block.Headers["gun"]), nil
 | 
						|
}
 | 
						|
 | 
						|
// ConvertPrivateKeyToPKCS8 converts a data.PrivateKey to PKCS#8 Format
 | 
						|
func ConvertPrivateKeyToPKCS8(key data.PrivateKey, role data.RoleName, gun data.GUN, passphrase string) ([]byte, error) {
 | 
						|
	var (
 | 
						|
		err       error
 | 
						|
		der       []byte
 | 
						|
		blockType = "PRIVATE KEY"
 | 
						|
	)
 | 
						|
 | 
						|
	if passphrase == "" {
 | 
						|
		der, err = ConvertTUFKeyToPKCS8(key, nil)
 | 
						|
	} else {
 | 
						|
		blockType = "ENCRYPTED PRIVATE KEY"
 | 
						|
		der, err = ConvertTUFKeyToPKCS8(key, []byte(passphrase))
 | 
						|
	}
 | 
						|
	if err != nil {
 | 
						|
		return nil, fmt.Errorf("unable to convert to PKCS8 key")
 | 
						|
	}
 | 
						|
 | 
						|
	headers := make(map[string]string)
 | 
						|
	if role != "" {
 | 
						|
		headers["role"] = role.String()
 | 
						|
	}
 | 
						|
 | 
						|
	if gun != "" {
 | 
						|
		headers["gun"] = gun.String()
 | 
						|
	}
 | 
						|
 | 
						|
	return pem.EncodeToMemory(&pem.Block{Bytes: der, Type: blockType, Headers: headers}), nil
 | 
						|
}
 | 
						|
 | 
						|
// CertToKey transforms a single input certificate into its corresponding
 | 
						|
// PublicKey
 | 
						|
func CertToKey(cert *x509.Certificate) data.PublicKey {
 | 
						|
	block := pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw}
 | 
						|
	pemdata := pem.EncodeToMemory(&block)
 | 
						|
 | 
						|
	switch cert.PublicKeyAlgorithm {
 | 
						|
	case x509.RSA:
 | 
						|
		return data.NewRSAx509PublicKey(pemdata)
 | 
						|
	case x509.ECDSA:
 | 
						|
		return data.NewECDSAx509PublicKey(pemdata)
 | 
						|
	default:
 | 
						|
		logrus.Debugf("Unknown key type parsed from certificate: %v", cert.PublicKeyAlgorithm)
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// CertsToKeys transforms each of the input certificate chains into its corresponding
 | 
						|
// PublicKey
 | 
						|
func CertsToKeys(leafCerts map[string]*x509.Certificate, intCerts map[string][]*x509.Certificate) map[string]data.PublicKey {
 | 
						|
	keys := make(map[string]data.PublicKey)
 | 
						|
	for id, leafCert := range leafCerts {
 | 
						|
		if key, err := CertBundleToKey(leafCert, intCerts[id]); err == nil {
 | 
						|
			keys[key.ID()] = key
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return keys
 | 
						|
}
 | 
						|
 | 
						|
// CertBundleToKey creates a TUF key from a leaf certs and a list of
 | 
						|
// intermediates
 | 
						|
func CertBundleToKey(leafCert *x509.Certificate, intCerts []*x509.Certificate) (data.PublicKey, error) {
 | 
						|
	certBundle := []*x509.Certificate{leafCert}
 | 
						|
	certBundle = append(certBundle, intCerts...)
 | 
						|
	certChainPEM, err := CertChainToPEM(certBundle)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	var newKey data.PublicKey
 | 
						|
	// Use the leaf cert's public key algorithm for typing
 | 
						|
	switch leafCert.PublicKeyAlgorithm {
 | 
						|
	case x509.RSA:
 | 
						|
		newKey = data.NewRSAx509PublicKey(certChainPEM)
 | 
						|
	case x509.ECDSA:
 | 
						|
		newKey = data.NewECDSAx509PublicKey(certChainPEM)
 | 
						|
	default:
 | 
						|
		logrus.Debugf("Unknown key type parsed from certificate: %v", leafCert.PublicKeyAlgorithm)
 | 
						|
		return nil, x509.ErrUnsupportedAlgorithm
 | 
						|
	}
 | 
						|
	return newKey, nil
 | 
						|
}
 | 
						|
 | 
						|
// NewCertificate returns an X509 Certificate following a template, given a Common Name and validity interval.
 | 
						|
func NewCertificate(commonName string, startTime, endTime time.Time) (*x509.Certificate, error) {
 | 
						|
	serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
 | 
						|
 | 
						|
	serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
 | 
						|
	if err != nil {
 | 
						|
		return nil, fmt.Errorf("failed to generate new certificate: %v", err)
 | 
						|
	}
 | 
						|
 | 
						|
	return &x509.Certificate{
 | 
						|
		SerialNumber: serialNumber,
 | 
						|
		Subject: pkix.Name{
 | 
						|
			CommonName: commonName,
 | 
						|
		},
 | 
						|
		NotBefore: startTime,
 | 
						|
		NotAfter:  endTime,
 | 
						|
 | 
						|
		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
 | 
						|
		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageCodeSigning},
 | 
						|
		BasicConstraintsValid: true,
 | 
						|
	}, nil
 | 
						|
}
 |