2015-06-17 16:43:36 +00:00
|
|
|
package certutil
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"crypto"
|
2015-11-16 21:32:49 +00:00
|
|
|
"crypto/ecdsa"
|
|
|
|
"crypto/elliptic"
|
|
|
|
"crypto/rand"
|
|
|
|
"crypto/rsa"
|
2015-06-17 16:43:36 +00:00
|
|
|
"crypto/sha1"
|
|
|
|
"crypto/x509"
|
|
|
|
"encoding/pem"
|
|
|
|
"fmt"
|
2015-11-16 21:32:49 +00:00
|
|
|
"math/big"
|
2015-10-08 01:50:57 +00:00
|
|
|
"strconv"
|
|
|
|
"strings"
|
2015-06-17 16:43:36 +00:00
|
|
|
|
2016-07-28 19:19:27 +00:00
|
|
|
"github.com/hashicorp/vault/helper/errutil"
|
2016-07-06 16:25:40 +00:00
|
|
|
"github.com/hashicorp/vault/helper/jsonutil"
|
2015-06-17 16:43:36 +00:00
|
|
|
"github.com/mitchellh/mapstructure"
|
|
|
|
)
|
|
|
|
|
2016-09-16 15:05:43 +00:00
|
|
|
// GetHexFormatted returns the byte buffer formatted in hex with
|
2015-06-17 16:43:36 +00:00
|
|
|
// the specified separator between bytes.
|
2016-09-16 15:05:43 +00:00
|
|
|
func GetHexFormatted(buf []byte, sep string) string {
|
2015-06-17 16:43:36 +00:00
|
|
|
var ret bytes.Buffer
|
|
|
|
for _, cur := range buf {
|
|
|
|
if ret.Len() > 0 {
|
|
|
|
fmt.Fprintf(&ret, sep)
|
|
|
|
}
|
|
|
|
fmt.Fprintf(&ret, "%02x", cur)
|
|
|
|
}
|
|
|
|
return ret.String()
|
|
|
|
}
|
|
|
|
|
2015-10-08 01:50:57 +00:00
|
|
|
func ParseHexFormatted(in, sep string) []byte {
|
|
|
|
var ret bytes.Buffer
|
|
|
|
var err error
|
|
|
|
var inBits int64
|
|
|
|
inBytes := strings.Split(in, sep)
|
|
|
|
for _, inByte := range inBytes {
|
|
|
|
if inBits, err = strconv.ParseInt(inByte, 16, 8); err != nil {
|
|
|
|
return nil
|
|
|
|
} else {
|
|
|
|
ret.WriteByte(byte(inBits))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret.Bytes()
|
|
|
|
}
|
|
|
|
|
2015-06-17 16:43:36 +00:00
|
|
|
// GetSubjKeyID returns the subject key ID, e.g. the SHA1 sum
|
|
|
|
// of the marshaled public key
|
|
|
|
func GetSubjKeyID(privateKey crypto.Signer) ([]byte, error) {
|
|
|
|
if privateKey == nil {
|
2016-07-28 19:19:27 +00:00
|
|
|
return nil, errutil.InternalError{"passed-in private key is nil"}
|
2015-06-17 16:43:36 +00:00
|
|
|
}
|
2015-06-18 14:44:02 +00:00
|
|
|
|
2015-06-17 16:43:36 +00:00
|
|
|
marshaledKey, err := x509.MarshalPKIXPublicKey(privateKey.Public())
|
|
|
|
if err != nil {
|
2016-07-28 19:19:27 +00:00
|
|
|
return nil, errutil.InternalError{fmt.Sprintf("error marshalling public key: %s", err)}
|
2015-06-17 16:43:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
subjKeyID := sha1.Sum(marshaledKey)
|
|
|
|
|
|
|
|
return subjKeyID[:], nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// ParsePKIMap takes a map (for instance, the Secret.Data
|
|
|
|
// returned from the PKI backend) and returns a ParsedCertBundle.
|
|
|
|
func ParsePKIMap(data map[string]interface{}) (*ParsedCertBundle, error) {
|
|
|
|
result := &CertBundle{}
|
|
|
|
err := mapstructure.Decode(data, result)
|
|
|
|
if err != nil {
|
2016-07-28 19:19:27 +00:00
|
|
|
return nil, errutil.UserError{err.Error()}
|
2015-06-17 16:43:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return result.ToParsedCertBundle()
|
|
|
|
}
|
|
|
|
|
2015-11-16 17:45:31 +00:00
|
|
|
// ParsePKIJSON takes a JSON-encoded string and returns a ParsedCertBundle.
|
2015-06-17 16:43:36 +00:00
|
|
|
//
|
|
|
|
// This can be either the output of an
|
|
|
|
// issue call from the PKI backend or just its data member; or,
|
|
|
|
// JSON not coming from the PKI backend.
|
|
|
|
func ParsePKIJSON(input []byte) (*ParsedCertBundle, error) {
|
|
|
|
result := &CertBundle{}
|
2016-07-06 16:25:40 +00:00
|
|
|
err := jsonutil.DecodeJSON(input, &result)
|
2015-06-17 16:43:36 +00:00
|
|
|
|
|
|
|
if err == nil {
|
|
|
|
return result.ToParsedCertBundle()
|
|
|
|
}
|
|
|
|
|
2015-06-18 10:42:57 +00:00
|
|
|
var secret Secret
|
2016-07-06 16:25:40 +00:00
|
|
|
err = jsonutil.DecodeJSON(input, &secret)
|
2015-06-17 16:43:36 +00:00
|
|
|
|
|
|
|
if err == nil {
|
|
|
|
return ParsePKIMap(secret.Data)
|
|
|
|
}
|
|
|
|
|
2016-07-28 19:19:27 +00:00
|
|
|
return nil, errutil.UserError{"unable to parse out of either secret data or a secret object"}
|
2015-06-17 16:43:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ParsePEMBundle takes a string of concatenated PEM-format certificate
|
|
|
|
// and private key values and decodes/parses them, checking validity along
|
|
|
|
// the way. There must be at max two certificates (a certificate and its
|
|
|
|
// issuing certificate) and one private key.
|
|
|
|
func ParsePEMBundle(pemBundle string) (*ParsedCertBundle, error) {
|
|
|
|
if len(pemBundle) == 0 {
|
2016-07-28 19:19:27 +00:00
|
|
|
return nil, errutil.UserError{"empty pem bundle"}
|
2015-06-17 16:43:36 +00:00
|
|
|
}
|
|
|
|
|
2016-07-20 17:57:49 +00:00
|
|
|
pemBundle = strings.TrimSpace(pemBundle)
|
|
|
|
|
2015-06-17 16:43:36 +00:00
|
|
|
pemBytes := []byte(pemBundle)
|
|
|
|
var pemBlock *pem.Block
|
|
|
|
parsedBundle := &ParsedCertBundle{}
|
2016-09-28 00:50:17 +00:00
|
|
|
var certPath []*CertBlock
|
2015-06-17 16:43:36 +00:00
|
|
|
|
2016-09-28 00:50:17 +00:00
|
|
|
for len(pemBytes) > 0 {
|
2015-06-17 16:43:36 +00:00
|
|
|
pemBlock, pemBytes = pem.Decode(pemBytes)
|
|
|
|
if pemBlock == nil {
|
2016-07-28 19:19:27 +00:00
|
|
|
return nil, errutil.UserError{"no data found"}
|
2015-06-17 16:43:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if signer, err := x509.ParseECPrivateKey(pemBlock.Bytes); err == nil {
|
|
|
|
if parsedBundle.PrivateKeyType != UnknownPrivateKey {
|
2016-07-28 19:19:27 +00:00
|
|
|
return nil, errutil.UserError{"more than one private key given; provide only one private key in the bundle"}
|
2015-06-17 16:43:36 +00:00
|
|
|
}
|
2015-12-11 20:43:14 +00:00
|
|
|
parsedBundle.PrivateKeyFormat = ECBlock
|
2015-06-17 16:43:36 +00:00
|
|
|
parsedBundle.PrivateKeyType = ECPrivateKey
|
|
|
|
parsedBundle.PrivateKeyBytes = pemBlock.Bytes
|
|
|
|
parsedBundle.PrivateKey = signer
|
|
|
|
|
|
|
|
} else if signer, err := x509.ParsePKCS1PrivateKey(pemBlock.Bytes); err == nil {
|
|
|
|
if parsedBundle.PrivateKeyType != UnknownPrivateKey {
|
2016-07-28 19:19:27 +00:00
|
|
|
return nil, errutil.UserError{"more than one private key given; provide only one private key in the bundle"}
|
2015-06-17 16:43:36 +00:00
|
|
|
}
|
|
|
|
parsedBundle.PrivateKeyType = RSAPrivateKey
|
2015-12-11 20:43:14 +00:00
|
|
|
parsedBundle.PrivateKeyFormat = PKCS1Block
|
2015-06-17 16:43:36 +00:00
|
|
|
parsedBundle.PrivateKeyBytes = pemBlock.Bytes
|
|
|
|
parsedBundle.PrivateKey = signer
|
2015-12-09 19:49:36 +00:00
|
|
|
} else if signer, err := x509.ParsePKCS8PrivateKey(pemBlock.Bytes); err == nil {
|
2015-12-11 20:43:14 +00:00
|
|
|
parsedBundle.PrivateKeyFormat = PKCS8Block
|
2015-12-09 20:52:55 +00:00
|
|
|
|
2015-12-09 19:49:36 +00:00
|
|
|
if parsedBundle.PrivateKeyType != UnknownPrivateKey {
|
2016-07-28 19:19:27 +00:00
|
|
|
return nil, errutil.UserError{"More than one private key given; provide only one private key in the bundle"}
|
2015-12-09 19:49:36 +00:00
|
|
|
}
|
|
|
|
switch signer := signer.(type) {
|
|
|
|
case *rsa.PrivateKey:
|
|
|
|
parsedBundle.PrivateKey = signer
|
|
|
|
parsedBundle.PrivateKeyType = RSAPrivateKey
|
|
|
|
parsedBundle.PrivateKeyBytes = pemBlock.Bytes
|
|
|
|
case *ecdsa.PrivateKey:
|
|
|
|
parsedBundle.PrivateKey = signer
|
|
|
|
parsedBundle.PrivateKeyType = ECPrivateKey
|
|
|
|
parsedBundle.PrivateKeyBytes = pemBlock.Bytes
|
|
|
|
}
|
2015-06-17 16:43:36 +00:00
|
|
|
} else if certificates, err := x509.ParseCertificates(pemBlock.Bytes); err == nil {
|
2016-09-28 00:50:17 +00:00
|
|
|
certPath = append(certPath, &CertBlock{
|
|
|
|
Certificate: certificates[0],
|
|
|
|
Bytes: pemBlock.Bytes,
|
|
|
|
})
|
2015-06-17 16:43:36 +00:00
|
|
|
}
|
2016-09-28 00:50:17 +00:00
|
|
|
}
|
2015-06-17 16:43:36 +00:00
|
|
|
|
2016-09-28 00:50:17 +00:00
|
|
|
for i, certBlock := range certPath {
|
|
|
|
if i == 0 {
|
|
|
|
parsedBundle.Certificate = certBlock.Certificate
|
|
|
|
parsedBundle.CertificateBytes = certBlock.Bytes
|
|
|
|
} else {
|
|
|
|
parsedBundle.CAChain = append(parsedBundle.CAChain, certBlock)
|
2015-06-17 16:43:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-28 00:50:17 +00:00
|
|
|
if err := parsedBundle.Verify(); err != nil {
|
|
|
|
return nil, errutil.UserError{Err: fmt.Sprintf("verification of parsed bundle failed: %s", err)}
|
|
|
|
}
|
|
|
|
|
2015-06-17 16:43:36 +00:00
|
|
|
return parsedBundle, nil
|
|
|
|
}
|
2015-11-16 21:32:49 +00:00
|
|
|
|
2015-11-17 15:01:42 +00:00
|
|
|
// GeneratePrivateKey generates a private key with the specified type and key bits
|
2015-11-19 19:15:36 +00:00
|
|
|
func GeneratePrivateKey(keyType string, keyBits int, container ParsedPrivateKeyContainer) error {
|
2015-11-16 21:32:49 +00:00
|
|
|
var err error
|
2015-12-11 20:43:14 +00:00
|
|
|
var privateKeyType PrivateKeyType
|
2015-11-19 19:15:36 +00:00
|
|
|
var privateKeyBytes []byte
|
|
|
|
var privateKey crypto.Signer
|
2015-11-16 21:32:49 +00:00
|
|
|
|
|
|
|
switch keyType {
|
|
|
|
case "rsa":
|
2015-11-19 19:15:36 +00:00
|
|
|
privateKeyType = RSAPrivateKey
|
|
|
|
privateKey, err = rsa.GenerateKey(rand.Reader, keyBits)
|
2015-11-16 21:32:49 +00:00
|
|
|
if err != nil {
|
2016-07-28 19:19:27 +00:00
|
|
|
return errutil.InternalError{Err: fmt.Sprintf("error generating RSA private key: %v", err)}
|
2015-11-16 21:32:49 +00:00
|
|
|
}
|
2015-11-19 19:15:36 +00:00
|
|
|
privateKeyBytes = x509.MarshalPKCS1PrivateKey(privateKey.(*rsa.PrivateKey))
|
2015-11-16 21:32:49 +00:00
|
|
|
case "ec":
|
2015-11-19 19:15:36 +00:00
|
|
|
privateKeyType = ECPrivateKey
|
2015-11-16 21:32:49 +00:00
|
|
|
var curve elliptic.Curve
|
|
|
|
switch keyBits {
|
|
|
|
case 224:
|
|
|
|
curve = elliptic.P224()
|
|
|
|
case 256:
|
|
|
|
curve = elliptic.P256()
|
|
|
|
case 384:
|
|
|
|
curve = elliptic.P384()
|
|
|
|
case 521:
|
|
|
|
curve = elliptic.P521()
|
|
|
|
default:
|
2016-07-28 19:19:27 +00:00
|
|
|
return errutil.UserError{Err: fmt.Sprintf("unsupported bit length for EC key: %d", keyBits)}
|
2015-11-16 21:32:49 +00:00
|
|
|
}
|
2015-11-19 19:15:36 +00:00
|
|
|
privateKey, err = ecdsa.GenerateKey(curve, rand.Reader)
|
2015-11-16 21:32:49 +00:00
|
|
|
if err != nil {
|
2016-07-28 19:19:27 +00:00
|
|
|
return errutil.InternalError{Err: fmt.Sprintf("error generating EC private key: %v", err)}
|
2015-11-16 21:32:49 +00:00
|
|
|
}
|
2015-11-19 19:15:36 +00:00
|
|
|
privateKeyBytes, err = x509.MarshalECPrivateKey(privateKey.(*ecdsa.PrivateKey))
|
2015-11-16 21:32:49 +00:00
|
|
|
if err != nil {
|
2016-07-28 19:19:27 +00:00
|
|
|
return errutil.InternalError{Err: fmt.Sprintf("error marshalling EC private key: %v", err)}
|
2015-11-16 21:32:49 +00:00
|
|
|
}
|
|
|
|
default:
|
2016-07-28 19:19:27 +00:00
|
|
|
return errutil.UserError{Err: fmt.Sprintf("unknown key type: %s", keyType)}
|
2015-11-16 21:32:49 +00:00
|
|
|
}
|
|
|
|
|
2015-11-19 19:15:36 +00:00
|
|
|
container.SetParsedPrivateKey(privateKey, privateKeyType, privateKeyBytes)
|
2015-11-16 21:32:49 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2015-11-17 15:01:42 +00:00
|
|
|
// GenerateSerialNumber generates a serial number suitable for a certificate
|
2015-11-16 21:32:49 +00:00
|
|
|
func GenerateSerialNumber() (*big.Int, error) {
|
|
|
|
serial, err := rand.Int(rand.Reader, (&big.Int{}).Exp(big.NewInt(2), big.NewInt(159), nil))
|
|
|
|
if err != nil {
|
2016-07-28 19:19:27 +00:00
|
|
|
return nil, errutil.InternalError{Err: fmt.Sprintf("error generating serial number: %v", err)}
|
2015-11-16 21:32:49 +00:00
|
|
|
}
|
|
|
|
return serial, nil
|
|
|
|
}
|
2015-11-17 15:01:42 +00:00
|
|
|
|
|
|
|
// ComparePublicKeys compares two public keys and returns true if they match
|
|
|
|
func ComparePublicKeys(key1Iface, key2Iface crypto.PublicKey) (bool, error) {
|
|
|
|
switch key1Iface.(type) {
|
|
|
|
case *rsa.PublicKey:
|
|
|
|
key1 := key1Iface.(*rsa.PublicKey)
|
|
|
|
key2, ok := key2Iface.(*rsa.PublicKey)
|
|
|
|
if !ok {
|
|
|
|
return false, fmt.Errorf("key types do not match: %T and %T", key1Iface, key2Iface)
|
|
|
|
}
|
|
|
|
if key1.N.Cmp(key2.N) != 0 ||
|
|
|
|
key1.E != key2.E {
|
|
|
|
return false, nil
|
|
|
|
}
|
|
|
|
return true, nil
|
|
|
|
|
|
|
|
case *ecdsa.PublicKey:
|
|
|
|
key1 := key1Iface.(*ecdsa.PublicKey)
|
|
|
|
key2, ok := key2Iface.(*ecdsa.PublicKey)
|
|
|
|
if !ok {
|
|
|
|
return false, fmt.Errorf("key types do not match: %T and %T", key1Iface, key2Iface)
|
|
|
|
}
|
|
|
|
if key1.X.Cmp(key2.X) != 0 ||
|
|
|
|
key1.Y.Cmp(key2.Y) != 0 {
|
|
|
|
return false, nil
|
|
|
|
}
|
|
|
|
key1Params := key1.Params()
|
|
|
|
key2Params := key2.Params()
|
|
|
|
if key1Params.P.Cmp(key2Params.P) != 0 ||
|
|
|
|
key1Params.N.Cmp(key2Params.N) != 0 ||
|
|
|
|
key1Params.B.Cmp(key2Params.B) != 0 ||
|
|
|
|
key1Params.Gx.Cmp(key2Params.Gx) != 0 ||
|
|
|
|
key1Params.Gy.Cmp(key2Params.Gy) != 0 ||
|
|
|
|
key1Params.BitSize != key2Params.BitSize {
|
|
|
|
return false, nil
|
|
|
|
}
|
|
|
|
return true, nil
|
|
|
|
|
|
|
|
default:
|
|
|
|
return false, fmt.Errorf("cannot compare key with type %T", key1Iface)
|
|
|
|
}
|
|
|
|
}
|