diff --git a/builtin/logical/pki/cert_util.go b/builtin/logical/pki/cert_util.go index c04894e7d..5bf0307ac 100644 --- a/builtin/logical/pki/cert_util.go +++ b/builtin/logical/pki/cert_util.go @@ -585,10 +585,9 @@ func createCertificate(creationInfo *creationBundle) (*certutil.ParsedCertBundle return nil, err } - resultIface := interface{}(result) if err := certutil.GeneratePrivateKey(creationInfo.KeyType, creationInfo.KeyBits, - resultIface.(certutil.EmbeddedParsedPrivateKeyContainer)); err != nil { + result); err != nil { return nil, err } @@ -693,10 +692,9 @@ func createCSR(creationInfo *creationBundle) (*certutil.ParsedCSRBundle, error) var err error result := &certutil.ParsedCSRBundle{} - resultIface := interface{}(result) if err := certutil.GeneratePrivateKey(creationInfo.KeyType, creationInfo.KeyBits, - resultIface.(certutil.EmbeddedParsedPrivateKeyContainer)); err != nil { + result); err != nil { return nil, err } diff --git a/helper/certutil/helpers.go b/helper/certutil/helpers.go index c283ee912..64036ba44 100644 --- a/helper/certutil/helpers.go +++ b/helper/certutil/helpers.go @@ -184,20 +184,22 @@ func ParsePEMBundle(pemBundle string) (*ParsedCertBundle, error) { } // GeneratePrivateKey generates a private key with the specified type and key bits -func GeneratePrivateKey(keyType string, keyBits int, emb EmbeddedParsedPrivateKeyContainer) error { +func GeneratePrivateKey(keyType string, keyBits int, container ParsedPrivateKeyContainer) error { var err error - result := &EmbeddedParsedPrivateKey{} + var privateKeyType int + var privateKeyBytes []byte + var privateKey crypto.Signer switch keyType { case "rsa": - result.PrivateKeyType = RSAPrivateKey - result.PrivateKey, err = rsa.GenerateKey(rand.Reader, keyBits) + privateKeyType = RSAPrivateKey + privateKey, err = rsa.GenerateKey(rand.Reader, keyBits) if err != nil { return InternalError{Err: fmt.Sprintf("error generating RSA private key: %v", err)} } - result.PrivateKeyBytes = x509.MarshalPKCS1PrivateKey(result.PrivateKey.(*rsa.PrivateKey)) + privateKeyBytes = x509.MarshalPKCS1PrivateKey(privateKey.(*rsa.PrivateKey)) case "ec": - result.PrivateKeyType = ECPrivateKey + privateKeyType = ECPrivateKey var curve elliptic.Curve switch keyBits { case 224: @@ -211,11 +213,11 @@ func GeneratePrivateKey(keyType string, keyBits int, emb EmbeddedParsedPrivateKe default: return UserError{Err: fmt.Sprintf("unsupported bit length for EC key: %d", keyBits)} } - result.PrivateKey, err = ecdsa.GenerateKey(curve, rand.Reader) + privateKey, err = ecdsa.GenerateKey(curve, rand.Reader) if err != nil { return InternalError{Err: fmt.Sprintf("error generating EC private key: %v", err)} } - result.PrivateKeyBytes, err = x509.MarshalECPrivateKey(result.PrivateKey.(*ecdsa.PrivateKey)) + privateKeyBytes, err = x509.MarshalECPrivateKey(privateKey.(*ecdsa.PrivateKey)) if err != nil { return InternalError{Err: fmt.Sprintf("error marshalling EC private key: %v", err)} } @@ -223,7 +225,7 @@ func GeneratePrivateKey(keyType string, keyBits int, emb EmbeddedParsedPrivateKe return UserError{Err: fmt.Sprintf("unknown key type: %s", keyType)} } - emb.SetParsedPrivateKey(result) + container.SetParsedPrivateKey(privateKey, privateKeyType, privateKeyBytes) return nil } diff --git a/helper/certutil/types.go b/helper/certutil/types.go index d1c92e49a..80209b526 100644 --- a/helper/certutil/types.go +++ b/helper/certutil/types.go @@ -64,47 +64,28 @@ func (e InternalError) Error() string { return e.Err } -// EmbeddedPrivateKey contains private key information -type EmbeddedPrivateKey struct { - PrivateKeyType string `json:"private_key_type" structs:"private_key_type" mapstructure:"private_key_type"` - PrivateKey string `json:"private_key" structs:"private_key" mapstructure:"private_key"` -} - -// EmbeddedParsedPrivateKey contains parsed private key information -type EmbeddedParsedPrivateKey struct { - PrivateKeyType int - PrivateKeyBytes []byte - PrivateKey crypto.Signer -} - -// EmbeddedPrivateKeyContainer abstracts the private key from -// certificates and CSRs to allow common functions -type EmbeddedPrivateKeyContainer interface { - GetPrivateKey() *EmbeddedPrivateKey - SetPrivateKey(*EmbeddedPrivateKey) -} - -// EmbeddedParsedPrivateKeyContainer abstracts the private key from -// parsed certificates and parsed CSRs to allow common functions -type EmbeddedParsedPrivateKeyContainer interface { - GetParsedPrivateKey() *EmbeddedParsedPrivateKey - SetParsedPrivateKey(*EmbeddedParsedPrivateKey) +// Used to allow common key setting for certs and CSRs +type ParsedPrivateKeyContainer interface { + SetParsedPrivateKey(crypto.Signer, int, []byte) } // CertBundle contains a key type, a PEM-encoded private key, // a PEM-encoded certificate, and a string-encoded serial number, // returned from a successful Issue request type CertBundle struct { - EmbeddedPrivateKey - Certificate string `json:"certificate" structs:"certificate" mapstructure:"certificate"` - IssuingCA string `json:"issuing_ca" structs:"issuing_ca" mapstructure:"issuing_ca"` - SerialNumber string `json:"serial_number" structs:"serial_number" mapstructure:"serial_number"` + PrivateKeyType string `json:"private_key_type" structs:"private_key_type" mapstructure:"private_key_type"` + Certificate string `json:"certificate" structs:"certificate" mapstructure:"certificate"` + IssuingCA string `json:"issuing_ca" structs:"issuing_ca" mapstructure:"issuing_ca"` + PrivateKey string `json:"private_key" structs:"private_key" mapstructure:"private_key"` + SerialNumber string `json:"serial_number" structs:"serial_number" mapstructure:"serial_number"` } // ParsedCertBundle contains a key type, a DER-encoded private key, // and a DER-encoded certificate type ParsedCertBundle struct { - EmbeddedParsedPrivateKey + PrivateKeyType int + PrivateKeyBytes []byte + PrivateKey crypto.Signer IssuingCABytes []byte IssuingCA *x509.Certificate CertificateBytes []byte @@ -114,29 +95,19 @@ type ParsedCertBundle struct { // CSRBundle contains a key type, a PEM-encoded private key, // and a PEM-encoded CSR type CSRBundle struct { - EmbeddedPrivateKey - CSR string `json:"csr" structs:"csr" mapstructure:"csr"` + PrivateKeyType string `json:"private_key_type" structs:"private_key_type" mapstructure:"private_key_type"` + CSR string `json:"csr" structs:"csr" mapstructure:"csr"` + PrivateKey string `json:"private_key" structs:"private_key" mapstructure:"private_key"` } // ParsedCSRBundle contains a key type, a DER-encoded private key, // and a DER-encoded certificate request type ParsedCSRBundle struct { - EmbeddedParsedPrivateKey - CSRBytes []byte - CSR *x509.CertificateRequest -} - -// GetPrivateKey returns the embedded private key values -func (c *CertBundle) GetPrivateKey() *EmbeddedPrivateKey { - return &EmbeddedPrivateKey{ - PrivateKeyType: c.PrivateKeyType, - PrivateKey: c.PrivateKey, - } -} - -// SetPrivateKey sets the embedded private key values -func (c *CertBundle) SetPrivateKey(emb *EmbeddedPrivateKey) { - c.EmbeddedPrivateKey = *emb + PrivateKeyType int + PrivateKeyBytes []byte + PrivateKey crypto.Signer + CSRBytes []byte + CSR *x509.CertificateRequest } // ToParsedCertBundle converts a string-based certificate bundle @@ -248,18 +219,164 @@ func (p *ParsedCertBundle) ToCertBundle() (*CertBundle, error) { return result, nil } -// GetParsedPrivateKey returns the embedded private key values -func (p *ParsedCertBundle) GetParsedPrivateKey() *EmbeddedParsedPrivateKey { - return &EmbeddedParsedPrivateKey{ - PrivateKeyType: p.PrivateKeyType, - PrivateKey: p.PrivateKey, - PrivateKeyBytes: p.PrivateKeyBytes, +// GetSigner returns a crypto.Signer corresponding to the private key +// contained in this ParsedCertBundle. The Signer contains a Public() function +// for getting the corresponding public. The Signer can also be +// type-converted to private keys +func (p *ParsedCertBundle) getSigner() (crypto.Signer, error) { + var signer crypto.Signer + var err error + + if p.PrivateKeyBytes == nil || len(p.PrivateKeyBytes) == 0 { + return nil, UserError{"Given parsed cert bundle does not have private key information"} } + + switch p.PrivateKeyType { + case ECPrivateKey: + signer, err = x509.ParseECPrivateKey(p.PrivateKeyBytes) + if err != nil { + return nil, UserError{fmt.Sprintf("Unable to parse CA's private EC key: %s", err)} + } + + case RSAPrivateKey: + signer, err = x509.ParsePKCS1PrivateKey(p.PrivateKeyBytes) + if err != nil { + return nil, UserError{fmt.Sprintf("Unable to parse CA's private RSA key: %s", err)} + } + + default: + return nil, UserError{"Unable to determine type of private key; only RSA and EC are supported"} + } + return signer, nil } -// SetParsedPrivateKey sets the embedded private key values -func (p *ParsedCertBundle) SetParsedPrivateKey(emb *EmbeddedParsedPrivateKey) { - p.EmbeddedParsedPrivateKey = *emb +// SetParsedPrivateKey sets the private key parameters on the bundle +func (p *ParsedCertBundle) SetParsedPrivateKey(privateKey crypto.Signer, privateKeyType int, privateKeyBytes []byte) { + p.PrivateKey = privateKey + p.PrivateKeyType = privateKeyType + p.PrivateKeyBytes = privateKeyBytes +} + +// ToParsedCSRBundle converts a string-based CSR bundle +// to a byte-based raw CSR bundle +func (c *CSRBundle) ToParsedCSRBundle() (*ParsedCSRBundle, error) { + result := &ParsedCSRBundle{} + var err error + var pemBlock *pem.Block + + if len(c.PrivateKey) > 0 { + pemBlock, _ = pem.Decode([]byte(c.PrivateKey)) + if pemBlock == nil { + return nil, UserError{"Error decoding private key from cert bundle"} + } + result.PrivateKeyBytes = pemBlock.Bytes + + switch c.PrivateKeyType { + case "ec": + result.PrivateKeyType = ECPrivateKey + case "rsa": + result.PrivateKeyType = RSAPrivateKey + default: + // Try to figure it out and correct + if _, err := x509.ParseECPrivateKey(pemBlock.Bytes); err == nil { + result.PrivateKeyType = ECPrivateKey + c.PrivateKeyType = "ec" + } else if _, err := x509.ParsePKCS1PrivateKey(pemBlock.Bytes); err == nil { + result.PrivateKeyType = RSAPrivateKey + c.PrivateKeyType = "rsa" + } else { + return nil, UserError{fmt.Sprintf("Unknown private key type in bundle: %s", c.PrivateKeyType)} + } + } + + result.PrivateKey, err = result.getSigner() + if err != nil { + return nil, UserError{fmt.Sprintf("Error getting signer: %s", err)} + } + } + + if len(c.CSR) > 0 { + pemBlock, _ = pem.Decode([]byte(c.CSR)) + if pemBlock == nil { + return nil, UserError{"Error decoding certificate from cert bundle"} + } + result.CSRBytes = pemBlock.Bytes + result.CSR, err = x509.ParseCertificateRequest(result.CSRBytes) + if err != nil { + return nil, UserError{"Error encountered parsing certificate bytes from raw bundle"} + } + } + + return result, nil +} + +// ToCSRBundle converts a byte-based raw DER certificate bundle +// to a PEM-based string certificate bundle +func (p *ParsedCSRBundle) ToCSRBundle() (*CSRBundle, error) { + result := &CSRBundle{} + block := pem.Block{ + Type: "CERTIFICATE REQUEST", + } + + if p.CSRBytes != nil && len(p.CSRBytes) > 0 { + block.Bytes = p.CSRBytes + result.CSR = strings.TrimSpace(string(pem.EncodeToMemory(&block))) + } + + if p.PrivateKeyBytes != nil && len(p.PrivateKeyBytes) > 0 { + block.Bytes = p.PrivateKeyBytes + switch p.PrivateKeyType { + case RSAPrivateKey: + result.PrivateKeyType = "rsa" + block.Type = "RSA PRIVATE KEY" + case ECPrivateKey: + result.PrivateKeyType = "ec" + block.Type = "EC PRIVATE KEY" + default: + return nil, InternalError{"Could not determine private key type when creating block"} + } + result.PrivateKey = strings.TrimSpace(string(pem.EncodeToMemory(&block))) + } + + return result, nil +} + +// GetSigner returns a crypto.Signer corresponding to the private key +// contained in this ParsedCSRBundle. The Signer contains a Public() function +// for getting the corresponding public. The Signer can also be +// type-converted to private keys +func (p *ParsedCSRBundle) getSigner() (crypto.Signer, error) { + var signer crypto.Signer + var err error + + if p.PrivateKeyBytes == nil || len(p.PrivateKeyBytes) == 0 { + return nil, UserError{"Given parsed cert bundle does not have private key information"} + } + + switch p.PrivateKeyType { + case ECPrivateKey: + signer, err = x509.ParseECPrivateKey(p.PrivateKeyBytes) + if err != nil { + return nil, UserError{fmt.Sprintf("Unable to parse CA's private EC key: %s", err)} + } + + case RSAPrivateKey: + signer, err = x509.ParsePKCS1PrivateKey(p.PrivateKeyBytes) + if err != nil { + return nil, UserError{fmt.Sprintf("Unable to parse CA's private RSA key: %s", err)} + } + + default: + return nil, UserError{"Unable to determine type of private key; only RSA and EC are supported"} + } + return signer, nil +} + +// SetParsedPrivateKey sets the private key parameters on the bundle +func (p *ParsedCSRBundle) SetParsedPrivateKey(privateKey crypto.Signer, privateKeyType int, privateKeyBytes []byte) { + p.PrivateKey = privateKey + p.PrivateKeyType = privateKeyType + p.PrivateKeyBytes = privateKeyBytes } // GetTLSConfig returns a TLS config generally suitable for client @@ -320,148 +437,6 @@ func (p *ParsedCertBundle) GetTLSConfig(usage TLSUsage) (*tls.Config, error) { return tlsConfig, nil } -// GetPrivateKey returns the embedded private key values -func (c *CSRBundle) GetPrivateKey() *EmbeddedPrivateKey { - return &EmbeddedPrivateKey{ - PrivateKeyType: c.PrivateKeyType, - PrivateKey: c.PrivateKey, - } -} - -// SetPrivateKey sets the embedded private key values -func (c *CSRBundle) SetPrivateKey(emb *EmbeddedPrivateKey) { - c.EmbeddedPrivateKey = *emb -} - -// ToParsedCSRBundle converts a string-based CSR bundle -// to a byte-based raw CSR bundle -func (c *CSRBundle) ToParsedCSRBundle() (*ParsedCSRBundle, error) { - result := &ParsedCSRBundle{} - var err error - var pemBlock *pem.Block - - if len(c.PrivateKey) > 0 { - pemBlock, _ = pem.Decode([]byte(c.PrivateKey)) - if pemBlock == nil { - return nil, UserError{"Error decoding private key from cert bundle"} - } - result.PrivateKeyBytes = pemBlock.Bytes - - switch c.PrivateKeyType { - case "ec": - result.PrivateKeyType = ECPrivateKey - case "rsa": - result.PrivateKeyType = RSAPrivateKey - default: - // Try to figure it out and correct - if _, err := x509.ParseECPrivateKey(pemBlock.Bytes); err == nil { - result.PrivateKeyType = ECPrivateKey - c.PrivateKeyType = "ec" - } else if _, err := x509.ParsePKCS1PrivateKey(pemBlock.Bytes); err == nil { - result.PrivateKeyType = RSAPrivateKey - c.PrivateKeyType = "rsa" - } else { - return nil, UserError{fmt.Sprintf("Unknown private key type in bundle: %s", c.PrivateKeyType)} - } - } - - result.PrivateKey, err = result.getSigner() - if err != nil { - return nil, UserError{fmt.Sprintf("Error getting signer: %s", err)} - } - } - - if len(c.CSR) > 0 { - pemBlock, _ = pem.Decode([]byte(c.CSR)) - if pemBlock == nil { - return nil, UserError{"Error decoding certificate from cert bundle"} - } - result.CSRBytes = pemBlock.Bytes - result.CSR, err = x509.ParseCertificateRequest(result.CSRBytes) - if err != nil { - return nil, UserError{"Error encountered parsing certificate bytes from raw bundle"} - } - } - - return result, nil -} - -// GetParsedPrivateKey returns the embedded private key values -func (p *ParsedCSRBundle) GetParsedPrivateKey() *EmbeddedParsedPrivateKey { - return &EmbeddedParsedPrivateKey{ - PrivateKeyType: p.PrivateKeyType, - PrivateKey: p.PrivateKey, - PrivateKeyBytes: p.PrivateKeyBytes, - } -} - -// SetParsedPrivateKey sets the embedded private key values -func (p *ParsedCSRBundle) SetParsedPrivateKey(emb *EmbeddedParsedPrivateKey) { - p.EmbeddedParsedPrivateKey = *emb -} - -// ToCSRBundle converts a byte-based raw DER certificate bundle -// to a PEM-based string certificate bundle -func (p *ParsedCSRBundle) ToCSRBundle() (*CSRBundle, error) { - result := &CSRBundle{} - block := pem.Block{ - Type: "CERTIFICATE REQUEST", - } - - if p.CSRBytes != nil && len(p.CSRBytes) > 0 { - block.Bytes = p.CSRBytes - result.CSR = strings.TrimSpace(string(pem.EncodeToMemory(&block))) - } - - if p.PrivateKeyBytes != nil && len(p.PrivateKeyBytes) > 0 { - block.Bytes = p.PrivateKeyBytes - switch p.PrivateKeyType { - case RSAPrivateKey: - result.PrivateKeyType = "rsa" - block.Type = "RSA PRIVATE KEY" - case ECPrivateKey: - result.PrivateKeyType = "ec" - block.Type = "EC PRIVATE KEY" - default: - return nil, InternalError{"Could not determine private key type when creating block"} - } - result.PrivateKey = strings.TrimSpace(string(pem.EncodeToMemory(&block))) - } - - return result, nil -} - -// GetSigner returns a crypto.Signer corresponding to the private key -// contained in this ParsedCSRBundle. The Signer contains a Public() function -// for getting the corresponding public. The Signer can also be -// type-converted to private keys -func (e *EmbeddedParsedPrivateKey) getSigner() (crypto.Signer, error) { - var signer crypto.Signer - var err error - - if e.PrivateKeyBytes == nil || len(e.PrivateKeyBytes) == 0 { - return nil, UserError{"given parsed bundle does not have private key information"} - } - - switch e.PrivateKeyType { - case ECPrivateKey: - signer, err = x509.ParseECPrivateKey(e.PrivateKeyBytes) - if err != nil { - return nil, UserError{fmt.Sprintf("unable to parse EC key: %s", err)} - } - - case RSAPrivateKey: - signer, err = x509.ParsePKCS1PrivateKey(e.PrivateKeyBytes) - if err != nil { - return nil, UserError{fmt.Sprintf("Unable to parse RSA key: %s", err)} - } - - default: - return nil, UserError{"unable to determine type of private key; only RSA and EC are supported"} - } - return signer, nil -} - // IssueData is a structure that is suitable for marshaling into a request; // either via JSON, or into a map[string]interface{} via the structs package type IssueData struct {