cert-manager/pkg/util/pki/generate.go
James Munnelly 51195e4c5f Update license header and add header to every file
Signed-off-by: James Munnelly <james.munnelly@jetstack.io>
2018-08-13 15:53:37 +01:00

163 lines
4.4 KiB
Go

/*
Copyright 2018 The Jetstack cert-manager contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package pki
import (
"crypto"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"fmt"
"github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha1"
)
const (
MinRSAKeySize = 2048
MaxRSAKeySize = 8192
ECCurve256 = 256
ECCurve384 = 384
ECCurve521 = 521
)
func GeneratePrivateKeyForCertificate(crt *v1alpha1.Certificate) (crypto.PrivateKey, error) {
switch crt.Spec.KeyAlgorithm {
case v1alpha1.KeyAlgorithm(""), v1alpha1.RSAKeyAlgorithm:
keySize := MinRSAKeySize
if crt.Spec.KeySize > 0 {
keySize = crt.Spec.KeySize
}
return GenerateRSAPrivateKey(keySize)
case v1alpha1.ECDSAKeyAlgorithm:
keySize := ECCurve256
if crt.Spec.KeySize > 0 {
keySize = crt.Spec.KeySize
}
return GenerateECPrivateKey(keySize)
default:
return nil, fmt.Errorf("unsupported private key algorithm specified: %s", crt.Spec.KeyAlgorithm)
}
}
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)
}
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)
}
func EncodePrivateKey(pk crypto.PrivateKey) ([]byte, error) {
switch k := pk.(type) {
case *rsa.PrivateKey:
return EncodePKCS1PrivateKey(k), nil
case *ecdsa.PrivateKey:
return EncodeECPrivateKey(k)
default:
return nil, fmt.Errorf("error encoding private key: unknown key type: %T", pk)
}
}
func EncodePKCS1PrivateKey(pk *rsa.PrivateKey) []byte {
block := &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(pk)}
return pem.EncodeToMemory(block)
}
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
}
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
default:
return nil, fmt.Errorf("unknown private key type: %T", pk)
}
}
// PublicKeyMatchesCertificate can be used to verify the given public key
// is the correct counter-part to the given x509 Certificate.
// It will return false and no error if the public key is *not* valid for the
// given Certificate.
// It will return true if the public key *is* valid for the given Certificate.
// It will return an error if either of the passed parameters are of an
// unrecognised type (i.e. non RSA/ECDSA)
func PublicKeyMatchesCertificate(check crypto.PublicKey, crt *x509.Certificate) (bool, error) {
switch pub := crt.PublicKey.(type) {
case *rsa.PublicKey:
rsaCheck, ok := check.(*rsa.PublicKey)
if !ok {
return false, nil
}
if pub.N.Cmp(rsaCheck.N) != 0 {
return false, nil
}
return true, nil
case *ecdsa.PublicKey:
ecdsaCheck, ok := check.(*ecdsa.PublicKey)
if !ok {
return false, nil
}
if pub.X.Cmp(ecdsaCheck.X) != 0 || pub.Y.Cmp(ecdsaCheck.Y) != 0 {
return false, nil
}
return true, nil
default:
return false, fmt.Errorf("unrecognised Certificate public key type")
}
}