1// Copyright 2015 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// Package pkcs12 implements some of PKCS#12.
6//
7// This implementation is distilled from https://tools.ietf.org/html/rfc7292
8// and referenced documents. It is intended for decoding P12/PFX-stored
9// certificates and keys for use with the crypto/tls package.
10package pkcs12
11
12import (
13	"crypto/ecdsa"
14	"crypto/rsa"
15	"crypto/x509"
16	"crypto/x509/pkix"
17	"encoding/asn1"
18	"encoding/hex"
19	"encoding/pem"
20	"errors"
21)
22
23var (
24	oidDataContentType          = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 7, 1})
25	oidEncryptedDataContentType = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 7, 6})
26
27	oidFriendlyName     = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 9, 20})
28	oidLocalKeyID       = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 9, 21})
29	oidMicrosoftCSPName = asn1.ObjectIdentifier([]int{1, 3, 6, 1, 4, 1, 311, 17, 1})
30)
31
32type pfxPdu struct {
33	Version  int
34	AuthSafe contentInfo
35	MacData  macData `asn1:"optional"`
36}
37
38type contentInfo struct {
39	ContentType asn1.ObjectIdentifier
40	Content     asn1.RawValue `asn1:"tag:0,explicit,optional"`
41}
42
43type encryptedData struct {
44	Version              int
45	EncryptedContentInfo encryptedContentInfo
46}
47
48type encryptedContentInfo struct {
49	ContentType                asn1.ObjectIdentifier
50	ContentEncryptionAlgorithm pkix.AlgorithmIdentifier
51	EncryptedContent           []byte `asn1:"tag:0,optional"`
52}
53
54func (i encryptedContentInfo) Algorithm() pkix.AlgorithmIdentifier {
55	return i.ContentEncryptionAlgorithm
56}
57
58func (i encryptedContentInfo) Data() []byte { return i.EncryptedContent }
59
60type safeBag struct {
61	Id         asn1.ObjectIdentifier
62	Value      asn1.RawValue     `asn1:"tag:0,explicit"`
63	Attributes []pkcs12Attribute `asn1:"set,optional"`
64}
65
66type pkcs12Attribute struct {
67	Id    asn1.ObjectIdentifier
68	Value asn1.RawValue `asn1:"set"`
69}
70
71type encryptedPrivateKeyInfo struct {
72	AlgorithmIdentifier pkix.AlgorithmIdentifier
73	EncryptedData       []byte
74}
75
76func (i encryptedPrivateKeyInfo) Algorithm() pkix.AlgorithmIdentifier {
77	return i.AlgorithmIdentifier
78}
79
80func (i encryptedPrivateKeyInfo) Data() []byte {
81	return i.EncryptedData
82}
83
84// PEM block types
85const (
86	certificateType = "CERTIFICATE"
87	privateKeyType  = "PRIVATE KEY"
88)
89
90// unmarshal calls asn1.Unmarshal, but also returns an error if there is any
91// trailing data after unmarshaling.
92func unmarshal(in []byte, out interface{}) error {
93	trailing, err := asn1.Unmarshal(in, out)
94	if err != nil {
95		return err
96	}
97	if len(trailing) != 0 {
98		return errors.New("pkcs12: trailing data found")
99	}
100	return nil
101}
102
103// ConvertToPEM converts all "safe bags" contained in pfxData to PEM blocks.
104func ToPEM(pfxData []byte, password string) ([]*pem.Block, error) {
105	encodedPassword, err := bmpString(password)
106	if err != nil {
107		return nil, ErrIncorrectPassword
108	}
109
110	bags, encodedPassword, err := getSafeContents(pfxData, encodedPassword)
111
112	if err != nil {
113		return nil, err
114	}
115
116	blocks := make([]*pem.Block, 0, len(bags))
117	for _, bag := range bags {
118		block, err := convertBag(&bag, encodedPassword)
119		if err != nil {
120			return nil, err
121		}
122		blocks = append(blocks, block)
123	}
124
125	return blocks, nil
126}
127
128func convertBag(bag *safeBag, password []byte) (*pem.Block, error) {
129	block := &pem.Block{
130		Headers: make(map[string]string),
131	}
132
133	for _, attribute := range bag.Attributes {
134		k, v, err := convertAttribute(&attribute)
135		if err != nil {
136			return nil, err
137		}
138		block.Headers[k] = v
139	}
140
141	switch {
142	case bag.Id.Equal(oidCertBag):
143		block.Type = certificateType
144		certsData, err := decodeCertBag(bag.Value.Bytes)
145		if err != nil {
146			return nil, err
147		}
148		block.Bytes = certsData
149	case bag.Id.Equal(oidPKCS8ShroundedKeyBag):
150		block.Type = privateKeyType
151
152		key, err := decodePkcs8ShroudedKeyBag(bag.Value.Bytes, password)
153		if err != nil {
154			return nil, err
155		}
156
157		switch key := key.(type) {
158		case *rsa.PrivateKey:
159			block.Bytes = x509.MarshalPKCS1PrivateKey(key)
160		case *ecdsa.PrivateKey:
161			block.Bytes, err = x509.MarshalECPrivateKey(key)
162			if err != nil {
163				return nil, err
164			}
165		default:
166			return nil, errors.New("found unknown private key type in PKCS#8 wrapping")
167		}
168	default:
169		return nil, errors.New("don't know how to convert a safe bag of type " + bag.Id.String())
170	}
171	return block, nil
172}
173
174func convertAttribute(attribute *pkcs12Attribute) (key, value string, err error) {
175	isString := false
176
177	switch {
178	case attribute.Id.Equal(oidFriendlyName):
179		key = "friendlyName"
180		isString = true
181	case attribute.Id.Equal(oidLocalKeyID):
182		key = "localKeyId"
183	case attribute.Id.Equal(oidMicrosoftCSPName):
184		// This key is chosen to match OpenSSL.
185		key = "Microsoft CSP Name"
186		isString = true
187	default:
188		return "", "", errors.New("pkcs12: unknown attribute with OID " + attribute.Id.String())
189	}
190
191	if isString {
192		if err := unmarshal(attribute.Value.Bytes, &attribute.Value); err != nil {
193			return "", "", err
194		}
195		if value, err = decodeBMPString(attribute.Value.Bytes); err != nil {
196			return "", "", err
197		}
198	} else {
199		var id []byte
200		if err := unmarshal(attribute.Value.Bytes, &id); err != nil {
201			return "", "", err
202		}
203		value = hex.EncodeToString(id)
204	}
205
206	return key, value, nil
207}
208
209// Decode extracts a certificate and private key from pfxData. This function
210// assumes that there is only one certificate and only one private key in the
211// pfxData.
212func Decode(pfxData []byte, password string) (privateKey interface{}, certificate *x509.Certificate, err error) {
213	encodedPassword, err := bmpString(password)
214	if err != nil {
215		return nil, nil, err
216	}
217
218	bags, encodedPassword, err := getSafeContents(pfxData, encodedPassword)
219	if err != nil {
220		return nil, nil, err
221	}
222
223	if len(bags) != 2 {
224		err = errors.New("pkcs12: expected exactly two safe bags in the PFX PDU")
225		return
226	}
227
228	for _, bag := range bags {
229		switch {
230		case bag.Id.Equal(oidCertBag):
231			if certificate != nil {
232				err = errors.New("pkcs12: expected exactly one certificate bag")
233			}
234
235			certsData, err := decodeCertBag(bag.Value.Bytes)
236			if err != nil {
237				return nil, nil, err
238			}
239			certs, err := x509.ParseCertificates(certsData)
240			if err != nil {
241				return nil, nil, err
242			}
243			if len(certs) != 1 {
244				err = errors.New("pkcs12: expected exactly one certificate in the certBag")
245				return nil, nil, err
246			}
247			certificate = certs[0]
248
249		case bag.Id.Equal(oidPKCS8ShroundedKeyBag):
250			if privateKey != nil {
251				err = errors.New("pkcs12: expected exactly one key bag")
252			}
253
254			if privateKey, err = decodePkcs8ShroudedKeyBag(bag.Value.Bytes, encodedPassword); err != nil {
255				return nil, nil, err
256			}
257		}
258	}
259
260	if certificate == nil {
261		return nil, nil, errors.New("pkcs12: certificate missing")
262	}
263	if privateKey == nil {
264		return nil, nil, errors.New("pkcs12: private key missing")
265	}
266
267	return
268}
269
270func getSafeContents(p12Data, password []byte) (bags []safeBag, updatedPassword []byte, err error) {
271	pfx := new(pfxPdu)
272	if err := unmarshal(p12Data, pfx); err != nil {
273		return nil, nil, errors.New("pkcs12: error reading P12 data: " + err.Error())
274	}
275
276	if pfx.Version != 3 {
277		return nil, nil, NotImplementedError("can only decode v3 PFX PDU's")
278	}
279
280	if !pfx.AuthSafe.ContentType.Equal(oidDataContentType) {
281		return nil, nil, NotImplementedError("only password-protected PFX is implemented")
282	}
283
284	// unmarshal the explicit bytes in the content for type 'data'
285	if err := unmarshal(pfx.AuthSafe.Content.Bytes, &pfx.AuthSafe.Content); err != nil {
286		return nil, nil, err
287	}
288
289	if len(pfx.MacData.Mac.Algorithm.Algorithm) == 0 {
290		return nil, nil, errors.New("pkcs12: no MAC in data")
291	}
292
293	if err := verifyMac(&pfx.MacData, pfx.AuthSafe.Content.Bytes, password); err != nil {
294		if err == ErrIncorrectPassword && len(password) == 2 && password[0] == 0 && password[1] == 0 {
295			// some implementations use an empty byte array
296			// for the empty string password try one more
297			// time with empty-empty password
298			password = nil
299			err = verifyMac(&pfx.MacData, pfx.AuthSafe.Content.Bytes, password)
300		}
301		if err != nil {
302			return nil, nil, err
303		}
304	}
305
306	var authenticatedSafe []contentInfo
307	if err := unmarshal(pfx.AuthSafe.Content.Bytes, &authenticatedSafe); err != nil {
308		return nil, nil, err
309	}
310
311	if len(authenticatedSafe) != 2 {
312		return nil, nil, NotImplementedError("expected exactly two items in the authenticated safe")
313	}
314
315	for _, ci := range authenticatedSafe {
316		var data []byte
317
318		switch {
319		case ci.ContentType.Equal(oidDataContentType):
320			if err := unmarshal(ci.Content.Bytes, &data); err != nil {
321				return nil, nil, err
322			}
323		case ci.ContentType.Equal(oidEncryptedDataContentType):
324			var encryptedData encryptedData
325			if err := unmarshal(ci.Content.Bytes, &encryptedData); err != nil {
326				return nil, nil, err
327			}
328			if encryptedData.Version != 0 {
329				return nil, nil, NotImplementedError("only version 0 of EncryptedData is supported")
330			}
331			if data, err = pbDecrypt(encryptedData.EncryptedContentInfo, password); err != nil {
332				return nil, nil, err
333			}
334		default:
335			return nil, nil, NotImplementedError("only data and encryptedData content types are supported in authenticated safe")
336		}
337
338		var safeContents []safeBag
339		if err := unmarshal(data, &safeContents); err != nil {
340			return nil, nil, err
341		}
342		bags = append(bags, safeContents...)
343	}
344
345	return bags, password, nil
346}
347