Newer
Older
AnthosCertManager / pkg / util / pki / generate.go
package pki

import (
	"crypto"
	"crypto/ecdsa"
	"crypto/ed25519"
	"crypto/elliptic"
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"encoding/pem"
	"fmt"

	acmapi "gitbucket.jerxie.com/yangyangxie/AnthosCertManager/pkg/apis/anthoscertmanager/v1"
	v1 "gitbucket.jerxie.com/yangyangxie/AnthosCertManager/pkg/apis/anthoscertmanager/v1"
)

const (
	// MinRSAKeySize is the minimum RSA keysize allowed to be generated by the
	// generator functions in this package.
	MinRSAKeySize = 2048

	// MaxRSAKeySize is the maximum RSA keysize allowed to be generated by the
	// generator functions in this package.
	MaxRSAKeySize = 8192

	// ECCurve256 represents a secp256r1 / prime256v1 / NIST P-256 ECDSA key.
	ECCurve256 = 256
	// ECCurve384 represents a secp384r1 / NIST P-384 ECDSA key.
	ECCurve384 = 384
	// ECCurve521 represents a secp521r1 / NIST P-521 ECDSA key.
	ECCurve521 = 521
)

// EncodePrivateKey will encode a given crypto.PrivateKey by first inspecting
// the type of key encoding and then inspecting the type of key provided.
// It only supports encoding RSA or ECDSA keys.
func EncodePrivateKey(pk crypto.PrivateKey, keyEncoding acmapi.PrivateKeyEncoding) ([]byte, error) {
	switch keyEncoding {
	case acmapi.PrivateKeyEncoding(""), acmapi.PKCS1:
		switch k := pk.(type) {
		case *rsa.PrivateKey:
			return EncodePKCS1PrivateKey(k), nil
		case *ecdsa.PrivateKey:
			return EncodeECPrivateKey(k)
		case ed25519.PrivateKey:
			return EncodePKCS8PrivateKey(k)
		default:
			return nil, fmt.Errorf("error encoding private key: unknown key type: %T", pk)
		}
	case acmapi.PKCS8:
		return EncodePKCS8PrivateKey(pk)
	default:
		return nil, fmt.Errorf("error encoding private key: unknown key encoding: %s", keyEncoding)
	}
}

// EncodePKCS1PrivateKey will marshal a RSA private key into x509 PEM format.
func EncodePKCS1PrivateKey(pk *rsa.PrivateKey) []byte {
	block := &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(pk)}

	return pem.EncodeToMemory(block)
}

// EncodePKCS8PrivateKey will marshal a private key into x509 PEM format.
func EncodePKCS8PrivateKey(pk interface{}) ([]byte, error) {
	keyBytes, err := x509.MarshalPKCS8PrivateKey(pk)
	if err != nil {
		return nil, err
	}
	block := &pem.Block{Type: "PRIVATE KEY", Bytes: keyBytes}

	return pem.EncodeToMemory(block), nil
}

// EncodeECPrivateKey will marshal an ECDSA private key into x509 PEM format.
func EncodeECPrivateKey(pk *ecdsa.PrivateKey) ([]byte, error) {
	asnBytes, err := x509.MarshalECPrivateKey(pk)
	if err != nil {
		return nil, fmt.Errorf("error encoding private key: %s", err.Error())
	}

	block := &pem.Block{Type: "EC PRIVATE KEY", Bytes: asnBytes}
	return pem.EncodeToMemory(block), nil
}

// PublicKeyMatchesCSR can be used to verify the given public key matches the
// public key in the given x509.CertificateRequest.
// Returns false and no error if the given public key is *not* the same as the CSR's key
// Returns true and no error if the given public key *is* the same as the CSR's key
// Returns an error if the CSR's key type cannot be determined (i.e. non RSA/ECDSA keys)
func PublicKeyMatchesCSR(check crypto.PublicKey, csr *x509.CertificateRequest) (bool, error) {
	return PublicKeysEqual(csr.PublicKey, check)
}

// PublicKeysEqual compares two given public keys for equality.
// The definition of "equality" depends on the type of the public keys.
// Returns true if the keys are the same, false if they differ or an error if
// the key type of `a` cannot be determined.
func PublicKeysEqual(a, b crypto.PublicKey) (bool, error) {
	switch pub := a.(type) {
	case *rsa.PublicKey:
		return pub.Equal(b), nil
	case *ecdsa.PublicKey:
		return pub.Equal(b), nil
	case ed25519.PublicKey:
		return pub.Equal(b), nil
	default:
		return false, fmt.Errorf("unrecognised public key type: %T", a)
	}
}

// GeneratePrivateKeyForCertificate will generate a private key suitable for
// the provided cert-manager Certificate resource, taking into account the
// parameters on the provided resource.
// The returned key will either be RSA or ECDSA.
func GeneratePrivateKeyForCertificate(crt *v1.Certificate) (crypto.Signer, error) {
	crt = crt.DeepCopy()
	if crt.Spec.PrivateKey == nil {
		crt.Spec.PrivateKey = &v1.CertificatePrivateKey{}
	}
	switch crt.Spec.PrivateKey.Algorithm {
	case v1.PrivateKeyAlgorithm(""), v1.RSAKeyAlgorithm:
		keySize := MinRSAKeySize

		if crt.Spec.PrivateKey.Size > 0 {
			keySize = crt.Spec.PrivateKey.Size
		}

		return GenerateRSAPrivateKey(keySize)
	case v1.ECDSAKeyAlgorithm:
		keySize := ECCurve256

		if crt.Spec.PrivateKey.Size > 0 {
			keySize = crt.Spec.PrivateKey.Size
		}

		return GenerateECPrivateKey(keySize)
	case v1.Ed25519KeyAlgorithm:
		return GenerateEd25519PrivateKey()
	default:
		return nil, fmt.Errorf("unsupported private key algorithm specified: %s", crt.Spec.PrivateKey.Algorithm)
	}
}

// GenerateRSAPrivateKey will generate a RSA private key of the given size.
// It places restrictions on the minimum and maximum RSA keysize.
func GenerateRSAPrivateKey(keySize int) (*rsa.PrivateKey, error) {
	// Do not allow keySize < 2048
	// https://en.wikipedia.org/wiki/Key_size#cite_note-twirl-14
	if keySize < MinRSAKeySize {
		return nil, fmt.Errorf("weak rsa key size specified: %d. minimum key size: %d", keySize, MinRSAKeySize)
	}
	if keySize > MaxRSAKeySize {
		return nil, fmt.Errorf("rsa key size specified too big: %d. maximum key size: %d", keySize, MaxRSAKeySize)
	}

	return rsa.GenerateKey(rand.Reader, keySize)
}

// GenerateECPrivateKey will generate an ECDSA private key of the given size.
// It can be used to generate 256, 384 and 521 sized keys.
func GenerateECPrivateKey(keySize int) (*ecdsa.PrivateKey, error) {
	var ecCurve elliptic.Curve

	switch keySize {
	case ECCurve256:
		ecCurve = elliptic.P256()
	case ECCurve384:
		ecCurve = elliptic.P384()
	case ECCurve521:
		ecCurve = elliptic.P521()
	default:
		return nil, fmt.Errorf("unsupported ecdsa key size specified: %d", keySize)
	}

	return ecdsa.GenerateKey(ecCurve, rand.Reader)
}

// GenerateEd25519PrivateKey will generate an Ed25519 private key
func GenerateEd25519PrivateKey() (ed25519.PrivateKey, error) {

	_, prvkey, err := ed25519.GenerateKey(rand.Reader)

	return prvkey, err
}

// PublicKeyForPrivateKey will return the crypto.PublicKey for the given
// crypto.PrivateKey. It only supports RSA and ECDSA keys.
func PublicKeyForPrivateKey(pk crypto.PrivateKey) (crypto.PublicKey, error) {
	switch k := pk.(type) {
	case *rsa.PrivateKey:
		return k.Public(), nil
	case *ecdsa.PrivateKey:
		return k.Public(), nil
	case ed25519.PrivateKey:
		return k.Public(), nil
	default:
		return nil, fmt.Errorf("unknown private key type: %T", pk)
	}
}