add variable entropy readers to cert gen helpers [VAULT-1179] (#10653)

* move entropy augmentation in cert gen to oss

* changelog

* go mod vendor

* updated helpers to allow custom entropy

* comments

* comments
This commit is contained in:
Hridoy Roy 2021-01-08 09:48:27 -08:00 committed by GitHub
parent 77d27cb968
commit f6bdda8c9c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 157 additions and 34 deletions

3
changelog/10653.txt Normal file
View File

@ -0,0 +1,3 @@
```release-note:feature
sdk: Private key generation in the certutil package now allows custom io.Readers to be used.
```

View File

@ -191,17 +191,34 @@ func ParsePEMBundle(pemBundle string) (*ParsedCertBundle, error) {
return parsedBundle, nil return parsedBundle, nil
} }
// GeneratePrivateKey generates a private key with the specified type and key bits // GeneratePrivateKey generates a private key with the specified type and key bits.
func GeneratePrivateKey(keyType string, keyBits int, container ParsedPrivateKeyContainer) error { func GeneratePrivateKey(keyType string, keyBits int, container ParsedPrivateKeyContainer) error {
return generatePrivateKey(keyType, keyBits, container, nil)
}
// GeneratePrivateKeyWithRandomSource generates a private key with the specified type and key bits.
// GeneratePrivateKeyWithRandomSource uses randomness from the entropyReader to generate the private key.
func GeneratePrivateKeyWithRandomSource(keyType string, keyBits int, container ParsedPrivateKeyContainer, entropyReader io.Reader) error {
return generatePrivateKey(keyType, keyBits, container, entropyReader)
}
// generatePrivateKey generates a private key with the specified type and key bits.
// generatePrivateKey uses randomness from the entropyReader to generate the private key.
func generatePrivateKey(keyType string, keyBits int, container ParsedPrivateKeyContainer, entropyReader io.Reader) error {
var err error var err error
var privateKeyType PrivateKeyType var privateKeyType PrivateKeyType
var privateKeyBytes []byte var privateKeyBytes []byte
var privateKey crypto.Signer var privateKey crypto.Signer
var randReader io.Reader = rand.Reader
if entropyReader != nil {
randReader = entropyReader
}
switch keyType { switch keyType {
case "rsa": case "rsa":
privateKeyType = RSAPrivateKey privateKeyType = RSAPrivateKey
privateKey, err = rsa.GenerateKey(rand.Reader, keyBits) privateKey, err = rsa.GenerateKey(randReader, keyBits)
if err != nil { if err != nil {
return errutil.InternalError{Err: fmt.Sprintf("error generating RSA private key: %v", err)} return errutil.InternalError{Err: fmt.Sprintf("error generating RSA private key: %v", err)}
} }
@ -221,7 +238,7 @@ func GeneratePrivateKey(keyType string, keyBits int, container ParsedPrivateKeyC
default: default:
return errutil.UserError{Err: fmt.Sprintf("unsupported bit length for EC key: %d", keyBits)} return errutil.UserError{Err: fmt.Sprintf("unsupported bit length for EC key: %d", keyBits)}
} }
privateKey, err = ecdsa.GenerateKey(curve, rand.Reader) privateKey, err = ecdsa.GenerateKey(curve, randReader)
if err != nil { if err != nil {
return errutil.InternalError{Err: fmt.Sprintf("error generating EC private key: %v", err)} return errutil.InternalError{Err: fmt.Sprintf("error generating EC private key: %v", err)}
} }
@ -239,7 +256,17 @@ func GeneratePrivateKey(keyType string, keyBits int, container ParsedPrivateKeyC
// GenerateSerialNumber generates a serial number suitable for a certificate // GenerateSerialNumber generates a serial number suitable for a certificate
func GenerateSerialNumber() (*big.Int, error) { func GenerateSerialNumber() (*big.Int, error) {
serial, err := rand.Int(rand.Reader, (&big.Int{}).Exp(big.NewInt(2), big.NewInt(159), nil)) return generateSerialNumber(rand.Reader)
}
// GenerateSerialNumberWithRandomSource generates a serial number suitable
// for a certificate with custom entropy.
func GenerateSerialNumberWithRandomSource(randReader io.Reader) (*big.Int, error) {
return generateSerialNumber(randReader)
}
func generateSerialNumber(randReader io.Reader) (*big.Int, error) {
serial, err := rand.Int(randReader, (&big.Int{}).Exp(big.NewInt(2), big.NewInt(159), nil))
if err != nil { if err != nil {
return nil, errutil.InternalError{Err: fmt.Sprintf("error generating serial number: %v", err)} return nil, errutil.InternalError{Err: fmt.Sprintf("error generating serial number: %v", err)}
} }
@ -491,9 +518,19 @@ func ValidateKeyTypeLength(keyType string, keyBits int) error {
return nil return nil
} }
// Performs the heavy lifting of creating a certificate. Returns // CreateCertificate uses CreationBundle and the default rand.Reader to
// a fully-filled-in ParsedCertBundle. // generate a cert/keypair.
func CreateCertificate(data *CreationBundle) (*ParsedCertBundle, error) { func CreateCertificate(data *CreationBundle) (*ParsedCertBundle, error) {
return createCertificate(data, rand.Reader)
}
// CreateCertificateWithRandomSource uses CreationBundle and a custom
// io.Reader for randomness to generate a cert/keypair.
func CreateCertificateWithRandomSource(data *CreationBundle, randReader io.Reader) (*ParsedCertBundle, error) {
return createCertificate(data, randReader)
}
func createCertificate(data *CreationBundle, randReader io.Reader) (*ParsedCertBundle, error) {
var err error var err error
result := &ParsedCertBundle{} result := &ParsedCertBundle{}
@ -502,9 +539,9 @@ func CreateCertificate(data *CreationBundle) (*ParsedCertBundle, error) {
return nil, err return nil, err
} }
if err := GeneratePrivateKey(data.Params.KeyType, if err := generatePrivateKey(data.Params.KeyType,
data.Params.KeyBits, data.Params.KeyBits,
result); err != nil { result, randReader); err != nil {
return nil, err return nil, err
} }
@ -569,7 +606,7 @@ func CreateCertificate(data *CreationBundle) (*ParsedCertBundle, error) {
caCert := data.SigningBundle.Certificate caCert := data.SigningBundle.Certificate
certTemplate.AuthorityKeyId = caCert.SubjectKeyId certTemplate.AuthorityKeyId = caCert.SubjectKeyId
certBytes, err = x509.CreateCertificate(rand.Reader, certTemplate, caCert, result.PrivateKey.Public(), data.SigningBundle.PrivateKey) certBytes, err = x509.CreateCertificate(randReader, certTemplate, caCert, result.PrivateKey.Public(), data.SigningBundle.PrivateKey)
} else { } else {
// Creating a self-signed root // Creating a self-signed root
if data.Params.MaxPathLength == 0 { if data.Params.MaxPathLength == 0 {
@ -588,7 +625,7 @@ func CreateCertificate(data *CreationBundle) (*ParsedCertBundle, error) {
certTemplate.AuthorityKeyId = subjKeyID certTemplate.AuthorityKeyId = subjKeyID
certTemplate.BasicConstraintsValid = true certTemplate.BasicConstraintsValid = true
certBytes, err = x509.CreateCertificate(rand.Reader, certTemplate, certTemplate, result.PrivateKey.Public(), result.PrivateKey) certBytes, err = x509.CreateCertificate(randReader, certTemplate, certTemplate, result.PrivateKey.Public(), result.PrivateKey)
} }
if err != nil { if err != nil {
@ -620,15 +657,26 @@ func CreateCertificate(data *CreationBundle) (*ParsedCertBundle, error) {
var oidExtensionBasicConstraints = []int{2, 5, 29, 19} var oidExtensionBasicConstraints = []int{2, 5, 29, 19}
// Creates a CSR. This is currently only meant for use when // CreateCSR creates a CSR with the default rand.Reader to
// generating an intermediate certificate. // generate a cert/keypair. This is currently only meant
// for use when generating an intermediate certificate.
func CreateCSR(data *CreationBundle, addBasicConstraints bool) (*ParsedCSRBundle, error) { func CreateCSR(data *CreationBundle, addBasicConstraints bool) (*ParsedCSRBundle, error) {
return createCSR(data, addBasicConstraints, rand.Reader)
}
// CreateCSRWithRandomSource creates a CSR with a custom io.Reader
// for randomness to generate a cert/keypair.
func CreateCSRWithRandomSource(data *CreationBundle, addBasicConstraints bool, randReader io.Reader) (*ParsedCSRBundle, error) {
return createCSR(data, addBasicConstraints, randReader)
}
func createCSR(data *CreationBundle, addBasicConstraints bool, randReader io.Reader) (*ParsedCSRBundle, error) {
var err error var err error
result := &ParsedCSRBundle{} result := &ParsedCSRBundle{}
if err := GeneratePrivateKey(data.Params.KeyType, if err := generatePrivateKey(data.Params.KeyType,
data.Params.KeyBits, data.Params.KeyBits,
result); err != nil { result, randReader); err != nil {
return nil, err return nil, err
} }
@ -669,7 +717,7 @@ func CreateCSR(data *CreationBundle, addBasicConstraints bool) (*ParsedCSRBundle
csrTemplate.SignatureAlgorithm = x509.ECDSAWithSHA256 csrTemplate.SignatureAlgorithm = x509.ECDSAWithSHA256
} }
csr, err := x509.CreateCertificateRequest(rand.Reader, csrTemplate, result.PrivateKey) csr, err := x509.CreateCertificateRequest(randReader, csrTemplate, result.PrivateKey)
if err != nil { if err != nil {
return nil, errutil.InternalError{Err: fmt.Sprintf("unable to create certificate: %s", err)} return nil, errutil.InternalError{Err: fmt.Sprintf("unable to create certificate: %s", err)}
} }
@ -683,9 +731,21 @@ func CreateCSR(data *CreationBundle, addBasicConstraints bool) (*ParsedCSRBundle
return result, nil return result, nil
} }
// Performs the heavy lifting of generating a certificate from a CSR. // SignCertificate performs the heavy lifting
// of generating a certificate from a CSR.
// Returns a ParsedCertBundle sans private keys. // Returns a ParsedCertBundle sans private keys.
func SignCertificate(data *CreationBundle) (*ParsedCertBundle, error) { func SignCertificate(data *CreationBundle) (*ParsedCertBundle, error) {
return signCertificate(data, rand.Reader)
}
// SignCertificateWithRandomSource generates a certificate
// from a CSR, using custom randomness from the randReader.
// Returns a ParsedCertBundle sans private keys.
func SignCertificateWithRandomSource(data *CreationBundle, randReader io.Reader) (*ParsedCertBundle, error) {
return signCertificate(data, randReader)
}
func signCertificate(data *CreationBundle, randReader io.Reader) (*ParsedCertBundle, error) {
switch { switch {
case data == nil: case data == nil:
return nil, errutil.UserError{Err: "nil data bundle given to signCertificate"} return nil, errutil.UserError{Err: "nil data bundle given to signCertificate"}
@ -797,7 +857,7 @@ func SignCertificate(data *CreationBundle) (*ParsedCertBundle, error) {
certTemplate.PermittedDNSDomainsCritical = true certTemplate.PermittedDNSDomainsCritical = true
} }
certBytes, err = x509.CreateCertificate(rand.Reader, certTemplate, caCert, data.CSR.PublicKey, data.SigningBundle.PrivateKey) certBytes, err = x509.CreateCertificate(randReader, certTemplate, caCert, data.CSR.PublicKey, data.SigningBundle.PrivateKey)
if err != nil { if err != nil {
return nil, errutil.InternalError{Err: fmt.Sprintf("unable to create certificate: %s", err)} return nil, errutil.InternalError{Err: fmt.Sprintf("unable to create certificate: %s", err)}

View File

@ -191,17 +191,34 @@ func ParsePEMBundle(pemBundle string) (*ParsedCertBundle, error) {
return parsedBundle, nil return parsedBundle, nil
} }
// GeneratePrivateKey generates a private key with the specified type and key bits // GeneratePrivateKey generates a private key with the specified type and key bits.
func GeneratePrivateKey(keyType string, keyBits int, container ParsedPrivateKeyContainer) error { func GeneratePrivateKey(keyType string, keyBits int, container ParsedPrivateKeyContainer) error {
return generatePrivateKey(keyType, keyBits, container, nil)
}
// GeneratePrivateKeyWithRandomSource generates a private key with the specified type and key bits.
// GeneratePrivateKeyWithRandomSource uses randomness from the entropyReader to generate the private key.
func GeneratePrivateKeyWithRandomSource(keyType string, keyBits int, container ParsedPrivateKeyContainer, entropyReader io.Reader) error {
return generatePrivateKey(keyType, keyBits, container, entropyReader)
}
// generatePrivateKey generates a private key with the specified type and key bits.
// generatePrivateKey uses randomness from the entropyReader to generate the private key.
func generatePrivateKey(keyType string, keyBits int, container ParsedPrivateKeyContainer, entropyReader io.Reader) error {
var err error var err error
var privateKeyType PrivateKeyType var privateKeyType PrivateKeyType
var privateKeyBytes []byte var privateKeyBytes []byte
var privateKey crypto.Signer var privateKey crypto.Signer
var randReader io.Reader = rand.Reader
if entropyReader != nil {
randReader = entropyReader
}
switch keyType { switch keyType {
case "rsa": case "rsa":
privateKeyType = RSAPrivateKey privateKeyType = RSAPrivateKey
privateKey, err = rsa.GenerateKey(rand.Reader, keyBits) privateKey, err = rsa.GenerateKey(randReader, keyBits)
if err != nil { if err != nil {
return errutil.InternalError{Err: fmt.Sprintf("error generating RSA private key: %v", err)} return errutil.InternalError{Err: fmt.Sprintf("error generating RSA private key: %v", err)}
} }
@ -221,7 +238,7 @@ func GeneratePrivateKey(keyType string, keyBits int, container ParsedPrivateKeyC
default: default:
return errutil.UserError{Err: fmt.Sprintf("unsupported bit length for EC key: %d", keyBits)} return errutil.UserError{Err: fmt.Sprintf("unsupported bit length for EC key: %d", keyBits)}
} }
privateKey, err = ecdsa.GenerateKey(curve, rand.Reader) privateKey, err = ecdsa.GenerateKey(curve, randReader)
if err != nil { if err != nil {
return errutil.InternalError{Err: fmt.Sprintf("error generating EC private key: %v", err)} return errutil.InternalError{Err: fmt.Sprintf("error generating EC private key: %v", err)}
} }
@ -239,7 +256,17 @@ func GeneratePrivateKey(keyType string, keyBits int, container ParsedPrivateKeyC
// GenerateSerialNumber generates a serial number suitable for a certificate // GenerateSerialNumber generates a serial number suitable for a certificate
func GenerateSerialNumber() (*big.Int, error) { func GenerateSerialNumber() (*big.Int, error) {
serial, err := rand.Int(rand.Reader, (&big.Int{}).Exp(big.NewInt(2), big.NewInt(159), nil)) return generateSerialNumber(rand.Reader)
}
// GenerateSerialNumberWithRandomSource generates a serial number suitable
// for a certificate with custom entropy.
func GenerateSerialNumberWithRandomSource(randReader io.Reader) (*big.Int, error) {
return generateSerialNumber(randReader)
}
func generateSerialNumber(randReader io.Reader) (*big.Int, error) {
serial, err := rand.Int(randReader, (&big.Int{}).Exp(big.NewInt(2), big.NewInt(159), nil))
if err != nil { if err != nil {
return nil, errutil.InternalError{Err: fmt.Sprintf("error generating serial number: %v", err)} return nil, errutil.InternalError{Err: fmt.Sprintf("error generating serial number: %v", err)}
} }
@ -491,9 +518,19 @@ func ValidateKeyTypeLength(keyType string, keyBits int) error {
return nil return nil
} }
// Performs the heavy lifting of creating a certificate. Returns // CreateCertificate uses CreationBundle and the default rand.Reader to
// a fully-filled-in ParsedCertBundle. // generate a cert/keypair.
func CreateCertificate(data *CreationBundle) (*ParsedCertBundle, error) { func CreateCertificate(data *CreationBundle) (*ParsedCertBundle, error) {
return createCertificate(data, rand.Reader)
}
// CreateCertificateWithRandomSource uses CreationBundle and a custom
// io.Reader for randomness to generate a cert/keypair.
func CreateCertificateWithRandomSource(data *CreationBundle, randReader io.Reader) (*ParsedCertBundle, error) {
return createCertificate(data, randReader)
}
func createCertificate(data *CreationBundle, randReader io.Reader) (*ParsedCertBundle, error) {
var err error var err error
result := &ParsedCertBundle{} result := &ParsedCertBundle{}
@ -502,9 +539,9 @@ func CreateCertificate(data *CreationBundle) (*ParsedCertBundle, error) {
return nil, err return nil, err
} }
if err := GeneratePrivateKey(data.Params.KeyType, if err := generatePrivateKey(data.Params.KeyType,
data.Params.KeyBits, data.Params.KeyBits,
result); err != nil { result, randReader); err != nil {
return nil, err return nil, err
} }
@ -569,7 +606,7 @@ func CreateCertificate(data *CreationBundle) (*ParsedCertBundle, error) {
caCert := data.SigningBundle.Certificate caCert := data.SigningBundle.Certificate
certTemplate.AuthorityKeyId = caCert.SubjectKeyId certTemplate.AuthorityKeyId = caCert.SubjectKeyId
certBytes, err = x509.CreateCertificate(rand.Reader, certTemplate, caCert, result.PrivateKey.Public(), data.SigningBundle.PrivateKey) certBytes, err = x509.CreateCertificate(randReader, certTemplate, caCert, result.PrivateKey.Public(), data.SigningBundle.PrivateKey)
} else { } else {
// Creating a self-signed root // Creating a self-signed root
if data.Params.MaxPathLength == 0 { if data.Params.MaxPathLength == 0 {
@ -588,7 +625,7 @@ func CreateCertificate(data *CreationBundle) (*ParsedCertBundle, error) {
certTemplate.AuthorityKeyId = subjKeyID certTemplate.AuthorityKeyId = subjKeyID
certTemplate.BasicConstraintsValid = true certTemplate.BasicConstraintsValid = true
certBytes, err = x509.CreateCertificate(rand.Reader, certTemplate, certTemplate, result.PrivateKey.Public(), result.PrivateKey) certBytes, err = x509.CreateCertificate(randReader, certTemplate, certTemplate, result.PrivateKey.Public(), result.PrivateKey)
} }
if err != nil { if err != nil {
@ -620,15 +657,26 @@ func CreateCertificate(data *CreationBundle) (*ParsedCertBundle, error) {
var oidExtensionBasicConstraints = []int{2, 5, 29, 19} var oidExtensionBasicConstraints = []int{2, 5, 29, 19}
// Creates a CSR. This is currently only meant for use when // CreateCSR creates a CSR with the default rand.Reader to
// generating an intermediate certificate. // generate a cert/keypair. This is currently only meant
// for use when generating an intermediate certificate.
func CreateCSR(data *CreationBundle, addBasicConstraints bool) (*ParsedCSRBundle, error) { func CreateCSR(data *CreationBundle, addBasicConstraints bool) (*ParsedCSRBundle, error) {
return createCSR(data, addBasicConstraints, rand.Reader)
}
// CreateCSRWithRandomSource creates a CSR with a custom io.Reader
// for randomness to generate a cert/keypair.
func CreateCSRWithRandomSource(data *CreationBundle, addBasicConstraints bool, randReader io.Reader) (*ParsedCSRBundle, error) {
return createCSR(data, addBasicConstraints, randReader)
}
func createCSR(data *CreationBundle, addBasicConstraints bool, randReader io.Reader) (*ParsedCSRBundle, error) {
var err error var err error
result := &ParsedCSRBundle{} result := &ParsedCSRBundle{}
if err := GeneratePrivateKey(data.Params.KeyType, if err := generatePrivateKey(data.Params.KeyType,
data.Params.KeyBits, data.Params.KeyBits,
result); err != nil { result, randReader); err != nil {
return nil, err return nil, err
} }
@ -669,7 +717,7 @@ func CreateCSR(data *CreationBundle, addBasicConstraints bool) (*ParsedCSRBundle
csrTemplate.SignatureAlgorithm = x509.ECDSAWithSHA256 csrTemplate.SignatureAlgorithm = x509.ECDSAWithSHA256
} }
csr, err := x509.CreateCertificateRequest(rand.Reader, csrTemplate, result.PrivateKey) csr, err := x509.CreateCertificateRequest(randReader, csrTemplate, result.PrivateKey)
if err != nil { if err != nil {
return nil, errutil.InternalError{Err: fmt.Sprintf("unable to create certificate: %s", err)} return nil, errutil.InternalError{Err: fmt.Sprintf("unable to create certificate: %s", err)}
} }
@ -683,9 +731,21 @@ func CreateCSR(data *CreationBundle, addBasicConstraints bool) (*ParsedCSRBundle
return result, nil return result, nil
} }
// Performs the heavy lifting of generating a certificate from a CSR. // SignCertificate performs the heavy lifting
// of generating a certificate from a CSR.
// Returns a ParsedCertBundle sans private keys. // Returns a ParsedCertBundle sans private keys.
func SignCertificate(data *CreationBundle) (*ParsedCertBundle, error) { func SignCertificate(data *CreationBundle) (*ParsedCertBundle, error) {
return signCertificate(data, rand.Reader)
}
// SignCertificateWithRandomSource generates a certificate
// from a CSR, using custom randomness from the randReader.
// Returns a ParsedCertBundle sans private keys.
func SignCertificateWithRandomSource(data *CreationBundle, randReader io.Reader) (*ParsedCertBundle, error) {
return signCertificate(data, randReader)
}
func signCertificate(data *CreationBundle, randReader io.Reader) (*ParsedCertBundle, error) {
switch { switch {
case data == nil: case data == nil:
return nil, errutil.UserError{Err: "nil data bundle given to signCertificate"} return nil, errutil.UserError{Err: "nil data bundle given to signCertificate"}
@ -797,7 +857,7 @@ func SignCertificate(data *CreationBundle) (*ParsedCertBundle, error) {
certTemplate.PermittedDNSDomainsCritical = true certTemplate.PermittedDNSDomainsCritical = true
} }
certBytes, err = x509.CreateCertificate(rand.Reader, certTemplate, caCert, data.CSR.PublicKey, data.SigningBundle.PrivateKey) certBytes, err = x509.CreateCertificate(randReader, certTemplate, caCert, data.CSR.PublicKey, data.SigningBundle.PrivateKey)
if err != nil { if err != nil {
return nil, errutil.InternalError{Err: fmt.Sprintf("unable to create certificate: %s", err)} return nil, errutil.InternalError{Err: fmt.Sprintf("unable to create certificate: %s", err)}