pkcs8.go raw

   1  // Package pkcs8 implements functions to parse and convert private keys in PKCS#8 format, as defined in RFC5208 and RFC5958
   2  package pkcs8
   3  
   4  import (
   5  	"crypto"
   6  	"crypto/ecdsa"
   7  	"crypto/rand"
   8  	"crypto/rsa"
   9  	"crypto/x509"
  10  	"crypto/x509/pkix"
  11  	"encoding/asn1"
  12  	"errors"
  13  	"fmt"
  14  )
  15  
  16  // DefaultOpts are the default options for encrypting a key if none are given.
  17  // The defaults can be changed by the library user.
  18  var DefaultOpts = &Opts{
  19  	Cipher: AES256CBC,
  20  	KDFOpts: PBKDF2Opts{
  21  		SaltSize:       8,
  22  		IterationCount: 10000,
  23  		HMACHash:       crypto.SHA256,
  24  	},
  25  }
  26  
  27  // KDFOpts contains options for a key derivation function.
  28  // An implementation of this interface must be specified when encrypting a PKCS#8 key.
  29  type KDFOpts interface {
  30  	// DeriveKey derives a key of size bytes from the given password and salt.
  31  	// It returns the key and the ASN.1-encodable parameters used.
  32  	DeriveKey(password, salt []byte, size int) (key []byte, params KDFParameters, err error)
  33  	// GetSaltSize returns the salt size specified.
  34  	GetSaltSize() int
  35  	// OID returns the OID of the KDF specified.
  36  	OID() asn1.ObjectIdentifier
  37  }
  38  
  39  // KDFParameters contains parameters (salt, etc.) for a key deriviation function.
  40  // It must be a ASN.1-decodable structure.
  41  // An implementation of this interface is created when decoding an encrypted PKCS#8 key.
  42  type KDFParameters interface {
  43  	// DeriveKey derives a key of size bytes from the given password.
  44  	// It uses the salt from the decoded parameters.
  45  	DeriveKey(password []byte, size int) (key []byte, err error)
  46  }
  47  
  48  var kdfs = make(map[string]func() KDFParameters)
  49  
  50  // RegisterKDF registers a function that returns a new instance of the given KDF
  51  // parameters. This allows the library to support client-provided KDFs.
  52  func RegisterKDF(oid asn1.ObjectIdentifier, params func() KDFParameters) {
  53  	kdfs[oid.String()] = params
  54  }
  55  
  56  // Cipher represents a cipher for encrypting the key material.
  57  type Cipher interface {
  58  	// IVSize returns the IV size of the cipher, in bytes.
  59  	IVSize() int
  60  	// KeySize returns the key size of the cipher, in bytes.
  61  	KeySize() int
  62  	// Encrypt encrypts the key material.
  63  	Encrypt(key, iv, plaintext []byte) ([]byte, error)
  64  	// Decrypt decrypts the key material.
  65  	Decrypt(key, iv, ciphertext []byte) ([]byte, error)
  66  	// OID returns the OID of the cipher specified.
  67  	OID() asn1.ObjectIdentifier
  68  }
  69  
  70  var ciphers = make(map[string]func() Cipher)
  71  
  72  // RegisterCipher registers a function that returns a new instance of the given
  73  // cipher. This allows the library to support client-provided ciphers.
  74  func RegisterCipher(oid asn1.ObjectIdentifier, cipher func() Cipher) {
  75  	ciphers[oid.String()] = cipher
  76  }
  77  
  78  // Opts contains options for encrypting a PKCS#8 key.
  79  type Opts struct {
  80  	Cipher  Cipher
  81  	KDFOpts KDFOpts
  82  }
  83  
  84  // Unecrypted PKCS8
  85  var (
  86  	oidPBES2 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 5, 13}
  87  )
  88  
  89  type encryptedPrivateKeyInfo struct {
  90  	EncryptionAlgorithm pkix.AlgorithmIdentifier
  91  	EncryptedData       []byte
  92  }
  93  
  94  type pbes2Params struct {
  95  	KeyDerivationFunc pkix.AlgorithmIdentifier
  96  	EncryptionScheme  pkix.AlgorithmIdentifier
  97  }
  98  
  99  type privateKeyInfo struct {
 100  	Version             int
 101  	PrivateKeyAlgorithm pkix.AlgorithmIdentifier
 102  	PrivateKey          []byte
 103  }
 104  
 105  func parseKeyDerivationFunc(keyDerivationFunc pkix.AlgorithmIdentifier) (KDFParameters, error) {
 106  	oid := keyDerivationFunc.Algorithm.String()
 107  	newParams, ok := kdfs[oid]
 108  	if !ok {
 109  		return nil, fmt.Errorf("pkcs8: unsupported KDF (OID: %s)", oid)
 110  	}
 111  	params := newParams()
 112  	_, err := asn1.Unmarshal(keyDerivationFunc.Parameters.FullBytes, params)
 113  	if err != nil {
 114  		return nil, errors.New("pkcs8: invalid KDF parameters")
 115  	}
 116  	return params, nil
 117  }
 118  
 119  func parseEncryptionScheme(encryptionScheme pkix.AlgorithmIdentifier) (Cipher, []byte, error) {
 120  	oid := encryptionScheme.Algorithm.String()
 121  	newCipher, ok := ciphers[oid]
 122  	if !ok {
 123  		return nil, nil, fmt.Errorf("pkcs8: unsupported cipher (OID: %s)", oid)
 124  	}
 125  	cipher := newCipher()
 126  	var iv []byte
 127  	if _, err := asn1.Unmarshal(encryptionScheme.Parameters.FullBytes, &iv); err != nil {
 128  		return nil, nil, errors.New("pkcs8: invalid cipher parameters")
 129  	}
 130  	return cipher, iv, nil
 131  }
 132  
 133  // ParsePrivateKey parses a DER-encoded PKCS#8 private key.
 134  // Password can be nil.
 135  // This is equivalent to ParsePKCS8PrivateKey.
 136  func ParsePrivateKey(der []byte, password []byte) (interface{}, KDFParameters, error) {
 137  	// No password provided, assume the private key is unencrypted
 138  	if len(password) == 0 {
 139  		privateKey, err := x509.ParsePKCS8PrivateKey(der)
 140  		return privateKey, nil, err
 141  	}
 142  
 143  	// Use the password provided to decrypt the private key
 144  	var privKey encryptedPrivateKeyInfo
 145  	if _, err := asn1.Unmarshal(der, &privKey); err != nil {
 146  		return nil, nil, errors.New("pkcs8: only PKCS #5 v2.0 supported")
 147  	}
 148  
 149  	if !privKey.EncryptionAlgorithm.Algorithm.Equal(oidPBES2) {
 150  		return nil, nil, errors.New("pkcs8: only PBES2 supported")
 151  	}
 152  
 153  	var params pbes2Params
 154  	if _, err := asn1.Unmarshal(privKey.EncryptionAlgorithm.Parameters.FullBytes, &params); err != nil {
 155  		return nil, nil, errors.New("pkcs8: invalid PBES2 parameters")
 156  	}
 157  
 158  	cipher, iv, err := parseEncryptionScheme(params.EncryptionScheme)
 159  	if err != nil {
 160  		return nil, nil, err
 161  	}
 162  
 163  	kdfParams, err := parseKeyDerivationFunc(params.KeyDerivationFunc)
 164  	if err != nil {
 165  		return nil, nil, err
 166  	}
 167  
 168  	keySize := cipher.KeySize()
 169  	symkey, err := kdfParams.DeriveKey(password, keySize)
 170  	if err != nil {
 171  		return nil, nil, err
 172  	}
 173  
 174  	encryptedKey := privKey.EncryptedData
 175  	decryptedKey, err := cipher.Decrypt(symkey, iv, encryptedKey)
 176  	if err != nil {
 177  		return nil, nil, err
 178  	}
 179  
 180  	key, err := x509.ParsePKCS8PrivateKey(decryptedKey)
 181  	if err != nil {
 182  		return nil, nil, errors.New("pkcs8: incorrect password")
 183  	}
 184  	return key, kdfParams, nil
 185  }
 186  
 187  // MarshalPrivateKey encodes a private key into DER-encoded PKCS#8 with the given options.
 188  // Password can be nil.
 189  func MarshalPrivateKey(priv interface{}, password []byte, opts *Opts) ([]byte, error) {
 190  	if len(password) == 0 {
 191  		return x509.MarshalPKCS8PrivateKey(priv)
 192  	}
 193  
 194  	if opts == nil {
 195  		opts = DefaultOpts
 196  	}
 197  
 198  	// Convert private key into PKCS8 format
 199  	pkey, err := x509.MarshalPKCS8PrivateKey(priv)
 200  	if err != nil {
 201  		return nil, err
 202  	}
 203  
 204  	encAlg := opts.Cipher
 205  	salt := make([]byte, opts.KDFOpts.GetSaltSize())
 206  	_, err = rand.Read(salt)
 207  	if err != nil {
 208  		return nil, err
 209  	}
 210  	iv := make([]byte, encAlg.IVSize())
 211  	_, err = rand.Read(iv)
 212  	if err != nil {
 213  		return nil, err
 214  	}
 215  	key, kdfParams, err := opts.KDFOpts.DeriveKey(password, salt, encAlg.KeySize())
 216  	if err != nil {
 217  		return nil, err
 218  	}
 219  
 220  	encryptedKey, err := encAlg.Encrypt(key, iv, pkey)
 221  	if err != nil {
 222  		return nil, err
 223  	}
 224  
 225  	marshalledParams, err := asn1.Marshal(kdfParams)
 226  	if err != nil {
 227  		return nil, err
 228  	}
 229  	keyDerivationFunc := pkix.AlgorithmIdentifier{
 230  		Algorithm:  opts.KDFOpts.OID(),
 231  		Parameters: asn1.RawValue{FullBytes: marshalledParams},
 232  	}
 233  	marshalledIV, err := asn1.Marshal(iv)
 234  	if err != nil {
 235  		return nil, err
 236  	}
 237  	encryptionScheme := pkix.AlgorithmIdentifier{
 238  		Algorithm:  encAlg.OID(),
 239  		Parameters: asn1.RawValue{FullBytes: marshalledIV},
 240  	}
 241  
 242  	encryptionAlgorithmParams := pbes2Params{
 243  		EncryptionScheme:  encryptionScheme,
 244  		KeyDerivationFunc: keyDerivationFunc,
 245  	}
 246  	marshalledEncryptionAlgorithmParams, err := asn1.Marshal(encryptionAlgorithmParams)
 247  	if err != nil {
 248  		return nil, err
 249  	}
 250  	encryptionAlgorithm := pkix.AlgorithmIdentifier{
 251  		Algorithm:  oidPBES2,
 252  		Parameters: asn1.RawValue{FullBytes: marshalledEncryptionAlgorithmParams},
 253  	}
 254  
 255  	encryptedPkey := encryptedPrivateKeyInfo{
 256  		EncryptionAlgorithm: encryptionAlgorithm,
 257  		EncryptedData:       encryptedKey,
 258  	}
 259  
 260  	return asn1.Marshal(encryptedPkey)
 261  }
 262  
 263  // ParsePKCS8PrivateKey parses encrypted/unencrypted private keys in PKCS#8 format. To parse encrypted private keys, a password of []byte type should be provided to the function as the second parameter.
 264  func ParsePKCS8PrivateKey(der []byte, v ...[]byte) (interface{}, error) {
 265  	var password []byte
 266  	if len(v) > 0 {
 267  		password = v[0]
 268  	}
 269  	privateKey, _, err := ParsePrivateKey(der, password)
 270  	return privateKey, err
 271  }
 272  
 273  // ParsePKCS8PrivateKeyRSA parses encrypted/unencrypted private keys in PKCS#8 format. To parse encrypted private keys, a password of []byte type should be provided to the function as the second parameter.
 274  func ParsePKCS8PrivateKeyRSA(der []byte, v ...[]byte) (*rsa.PrivateKey, error) {
 275  	key, err := ParsePKCS8PrivateKey(der, v...)
 276  	if err != nil {
 277  		return nil, err
 278  	}
 279  	typedKey, ok := key.(*rsa.PrivateKey)
 280  	if !ok {
 281  		return nil, errors.New("key block is not of type RSA")
 282  	}
 283  	return typedKey, nil
 284  }
 285  
 286  // ParsePKCS8PrivateKeyECDSA parses encrypted/unencrypted private keys in PKCS#8 format. To parse encrypted private keys, a password of []byte type should be provided to the function as the second parameter.
 287  func ParsePKCS8PrivateKeyECDSA(der []byte, v ...[]byte) (*ecdsa.PrivateKey, error) {
 288  	key, err := ParsePKCS8PrivateKey(der, v...)
 289  	if err != nil {
 290  		return nil, err
 291  	}
 292  	typedKey, ok := key.(*ecdsa.PrivateKey)
 293  	if !ok {
 294  		return nil, errors.New("key block is not of type ECDSA")
 295  	}
 296  	return typedKey, nil
 297  }
 298  
 299  // ConvertPrivateKeyToPKCS8 converts the private key into PKCS#8 format.
 300  // To encrypt the private key, the password of []byte type should be provided as the second parameter.
 301  //
 302  // The only supported key types are RSA and ECDSA (*rsa.PrivateKey or *ecdsa.PrivateKey for priv)
 303  func ConvertPrivateKeyToPKCS8(priv interface{}, v ...[]byte) ([]byte, error) {
 304  	var password []byte
 305  	if len(v) > 0 {
 306  		password = v[0]
 307  	}
 308  	return MarshalPrivateKey(priv, password, nil)
 309  }
 310