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.
5 // Package pkcs12 implements some of PKCS#12.
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.
24 oidDataContentType = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 7, 1})
25 oidEncryptedDataContentType = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 7, 6})
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})
35 MacData macData `asn1:"optional"`
38 type contentInfo struct {
39 ContentType asn1.ObjectIdentifier
40 Content asn1.RawValue `asn1:"tag:0,explicit,optional"`
43 type encryptedData struct {
45 EncryptedContentInfo encryptedContentInfo
48 type encryptedContentInfo struct {
49 ContentType asn1.ObjectIdentifier
50 ContentEncryptionAlgorithm pkix.AlgorithmIdentifier
51 EncryptedContent []byte `asn1:"tag:0,optional"`
54 func (i encryptedContentInfo) Algorithm() pkix.AlgorithmIdentifier {
55 return i.ContentEncryptionAlgorithm
58 func (i encryptedContentInfo) Data() []byte { return i.EncryptedContent }
61 Id asn1.ObjectIdentifier
62 Value asn1.RawValue `asn1:"tag:0,explicit"`
63 Attributes []pkcs12Attribute `asn1:"set,optional"`
66 type pkcs12Attribute struct {
67 Id asn1.ObjectIdentifier
68 Value asn1.RawValue `asn1:"set"`
71 type encryptedPrivateKeyInfo struct {
72 AlgorithmIdentifier pkix.AlgorithmIdentifier
76 func (i encryptedPrivateKeyInfo) Algorithm() pkix.AlgorithmIdentifier {
77 return i.AlgorithmIdentifier
80 func (i encryptedPrivateKeyInfo) Data() []byte {
81 return i.EncryptedData
86 certificateType = "CERTIFICATE"
87 privateKeyType = "PRIVATE KEY"
90 // unmarshal calls asn1.Unmarshal, but also returns an error if there is any
91 // trailing data after unmarshaling.
92 func unmarshal(in []byte, out interface{}) error {
93 trailing, err := asn1.Unmarshal(in, out)
97 if len(trailing) != 0 {
98 return errors.New("pkcs12: trailing data found")
103 // ConvertToPEM converts all "safe bags" contained in pfxData to PEM blocks.
104 func ToPEM(pfxData []byte, password string) ([]*pem.Block, error) {
105 encodedPassword, err := bmpString(password)
107 return nil, ErrIncorrectPassword
110 bags, encodedPassword, err := getSafeContents(pfxData, encodedPassword)
116 blocks := make([]*pem.Block, 0, len(bags))
117 for _, bag := range bags {
118 block, err := convertBag(&bag, encodedPassword)
122 blocks = append(blocks, block)
128 func convertBag(bag *safeBag, password []byte) (*pem.Block, error) {
130 Headers: make(map[string]string),
133 for _, attribute := range bag.Attributes {
134 k, v, err := convertAttribute(&attribute)
142 case bag.Id.Equal(oidCertBag):
143 block.Type = certificateType
144 certsData, err := decodeCertBag(bag.Value.Bytes)
148 block.Bytes = certsData
149 case bag.Id.Equal(oidPKCS8ShroundedKeyBag):
150 block.Type = privateKeyType
152 key, err := decodePkcs8ShroudedKeyBag(bag.Value.Bytes, password)
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)
166 return nil, errors.New("found unknown private key type in PKCS#8 wrapping")
169 return nil, errors.New("don't know how to convert a safe bag of type " + bag.Id.String())
174 func convertAttribute(attribute *pkcs12Attribute) (key, value string, err error) {
178 case attribute.Id.Equal(oidFriendlyName):
181 case attribute.Id.Equal(oidLocalKeyID):
183 case attribute.Id.Equal(oidMicrosoftCSPName):
184 // This key is chosen to match OpenSSL.
185 key = "Microsoft CSP Name"
188 return "", "", errors.New("pkcs12: unknown attribute with OID " + attribute.Id.String())
192 if err := unmarshal(attribute.Value.Bytes, &attribute.Value); err != nil {
195 if value, err = decodeBMPString(attribute.Value.Bytes); err != nil {
200 if err := unmarshal(attribute.Value.Bytes, &id); err != nil {
203 value = hex.EncodeToString(id)
206 return key, value, nil
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
212 func Decode(pfxData []byte, password string) (privateKey interface{}, certificate *x509.Certificate, err error) {
213 encodedPassword, err := bmpString(password)
218 bags, encodedPassword, err := getSafeContents(pfxData, encodedPassword)
224 err = errors.New("pkcs12: expected exactly two safe bags in the PFX PDU")
228 for _, bag := range bags {
230 case bag.Id.Equal(oidCertBag):
231 if certificate != nil {
232 err = errors.New("pkcs12: expected exactly one certificate bag")
235 certsData, err := decodeCertBag(bag.Value.Bytes)
239 certs, err := x509.ParseCertificates(certsData)
244 err = errors.New("pkcs12: expected exactly one certificate in the certBag")
247 certificate = certs[0]
249 case bag.Id.Equal(oidPKCS8ShroundedKeyBag):
250 if privateKey != nil {
251 err = errors.New("pkcs12: expected exactly one key bag")
254 if privateKey, err = decodePkcs8ShroudedKeyBag(bag.Value.Bytes, encodedPassword); err != nil {
260 if certificate == nil {
261 return nil, nil, errors.New("pkcs12: certificate missing")
263 if privateKey == nil {
264 return nil, nil, errors.New("pkcs12: private key missing")
270 func getSafeContents(p12Data, password []byte) (bags []safeBag, updatedPassword []byte, err error) {
272 if err := unmarshal(p12Data, pfx); err != nil {
273 return nil, nil, errors.New("pkcs12: error reading P12 data: " + err.Error())
276 if pfx.Version != 3 {
277 return nil, nil, NotImplementedError("can only decode v3 PFX PDU's")
280 if !pfx.AuthSafe.ContentType.Equal(oidDataContentType) {
281 return nil, nil, NotImplementedError("only password-protected PFX is implemented")
284 // unmarshal the explicit bytes in the content for type 'data'
285 if err := unmarshal(pfx.AuthSafe.Content.Bytes, &pfx.AuthSafe.Content); err != nil {
289 if len(pfx.MacData.Mac.Algorithm.Algorithm) == 0 {
290 return nil, nil, errors.New("pkcs12: no MAC in data")
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
299 err = verifyMac(&pfx.MacData, pfx.AuthSafe.Content.Bytes, password)
306 var authenticatedSafe []contentInfo
307 if err := unmarshal(pfx.AuthSafe.Content.Bytes, &authenticatedSafe); err != nil {
311 if len(authenticatedSafe) != 2 {
312 return nil, nil, NotImplementedError("expected exactly two items in the authenticated safe")
315 for _, ci := range authenticatedSafe {
319 case ci.ContentType.Equal(oidDataContentType):
320 if err := unmarshal(ci.Content.Bytes, &data); err != nil {
323 case ci.ContentType.Equal(oidEncryptedDataContentType):
324 var encryptedData encryptedData
325 if err := unmarshal(ci.Content.Bytes, &encryptedData); err != nil {
328 if encryptedData.Version != 0 {
329 return nil, nil, NotImplementedError("only version 0 of EncryptedData is supported")
331 if data, err = pbDecrypt(encryptedData.EncryptedContentInfo, password); err != nil {
335 return nil, nil, NotImplementedError("only data and encryptedData content types are supported in authenticated safe")
338 var safeContents []safeBag
339 if err := unmarshal(data, &safeContents); err != nil {
342 bags = append(bags, safeContents...)
345 return bags, password, nil