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, ¶ms); 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