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)
112
blocks := make([]*pem.Block, 0, len(bags))
113
for _, bag := range bags {
114
block, err := convertBag(&bag, encodedPassword)
118
blocks = append(blocks, block)
124
func convertBag(bag *safeBag, password []byte) (*pem.Block, error) {
126
Headers: make(map[string]string),
129
for _, attribute := range bag.Attributes {
130
k, v, err := convertAttribute(&attribute)
138
case bag.Id.Equal(oidCertBag):
139
block.Type = certificateType
140
certsData, err := decodeCertBag(bag.Value.Bytes)
144
block.Bytes = certsData
145
case bag.Id.Equal(oidPKCS8ShroundedKeyBag):
146
block.Type = privateKeyType
148
key, err := decodePkcs8ShroudedKeyBag(bag.Value.Bytes, password)
153
switch key := key.(type) {
154
case *rsa.PrivateKey:
155
block.Bytes = x509.MarshalPKCS1PrivateKey(key)
156
case *ecdsa.PrivateKey:
157
block.Bytes, err = x509.MarshalECPrivateKey(key)
162
return nil, errors.New("found unknown private key type in PKCS#8 wrapping")
165
return nil, errors.New("don't know how to convert a safe bag of type " + bag.Id.String())
170
func convertAttribute(attribute *pkcs12Attribute) (key, value string, err error) {
174
case attribute.Id.Equal(oidFriendlyName):
177
case attribute.Id.Equal(oidLocalKeyID):
179
case attribute.Id.Equal(oidMicrosoftCSPName):
180
// This key is chosen to match OpenSSL.
181
key = "Microsoft CSP Name"
184
return "", "", errors.New("pkcs12: unknown attribute with OID " + attribute.Id.String())
188
if err := unmarshal(attribute.Value.Bytes, &attribute.Value); err != nil {
191
if value, err = decodeBMPString(attribute.Value.Bytes); err != nil {
196
if err := unmarshal(attribute.Value.Bytes, &id); err != nil {
199
value = hex.EncodeToString(id)
202
return key, value, nil
205
// Decode extracts a certificate and private key from pfxData. This function
206
// assumes that there is only one certificate and only one private key in the
208
func Decode(pfxData []byte, password string) (privateKey interface{}, certificate *x509.Certificate, err error) {
209
encodedPassword, err := bmpString(password)
214
bags, encodedPassword, err := getSafeContents(pfxData, encodedPassword)
220
err = errors.New("pkcs12: expected exactly two safe bags in the PFX PDU")
224
for _, bag := range bags {
226
case bag.Id.Equal(oidCertBag):
227
if certificate != nil {
228
err = errors.New("pkcs12: expected exactly one certificate bag")
231
certsData, err := decodeCertBag(bag.Value.Bytes)
235
certs, err := x509.ParseCertificates(certsData)
240
err = errors.New("pkcs12: expected exactly one certificate in the certBag")
243
certificate = certs[0]
245
case bag.Id.Equal(oidPKCS8ShroundedKeyBag):
246
if privateKey != nil {
247
err = errors.New("pkcs12: expected exactly one key bag")
250
if privateKey, err = decodePkcs8ShroudedKeyBag(bag.Value.Bytes, encodedPassword); err != nil {
256
if certificate == nil {
257
return nil, nil, errors.New("pkcs12: certificate missing")
259
if privateKey == nil {
260
return nil, nil, errors.New("pkcs12: private key missing")
266
func getSafeContents(p12Data, password []byte) (bags []safeBag, updatedPassword []byte, err error) {
268
if err := unmarshal(p12Data, pfx); err != nil {
269
return nil, nil, errors.New("pkcs12: error reading P12 data: " + err.Error())
272
if pfx.Version != 3 {
273
return nil, nil, NotImplementedError("can only decode v3 PFX PDU's")
276
if !pfx.AuthSafe.ContentType.Equal(oidDataContentType) {
277
return nil, nil, NotImplementedError("only password-protected PFX is implemented")
280
// unmarshal the explicit bytes in the content for type 'data'
281
if err := unmarshal(pfx.AuthSafe.Content.Bytes, &pfx.AuthSafe.Content); err != nil {
285
if len(pfx.MacData.Mac.Algorithm.Algorithm) == 0 {
286
return nil, nil, errors.New("pkcs12: no MAC in data")
289
if err := verifyMac(&pfx.MacData, pfx.AuthSafe.Content.Bytes, password); err != nil {
290
if err == ErrIncorrectPassword && len(password) == 2 && password[0] == 0 && password[1] == 0 {
291
// some implementations use an empty byte array
292
// for the empty string password try one more
293
// time with empty-empty password
295
err = verifyMac(&pfx.MacData, pfx.AuthSafe.Content.Bytes, password)
302
var authenticatedSafe []contentInfo
303
if err := unmarshal(pfx.AuthSafe.Content.Bytes, &authenticatedSafe); err != nil {
307
if len(authenticatedSafe) != 2 {
308
return nil, nil, NotImplementedError("expected exactly two items in the authenticated safe")
311
for _, ci := range authenticatedSafe {
315
case ci.ContentType.Equal(oidDataContentType):
316
if err := unmarshal(ci.Content.Bytes, &data); err != nil {
319
case ci.ContentType.Equal(oidEncryptedDataContentType):
320
var encryptedData encryptedData
321
if err := unmarshal(ci.Content.Bytes, &encryptedData); err != nil {
324
if encryptedData.Version != 0 {
325
return nil, nil, NotImplementedError("only version 0 of EncryptedData is supported")
327
if data, err = pbDecrypt(encryptedData.EncryptedContentInfo, password); err != nil {
331
return nil, nil, NotImplementedError("only data and encryptedData content types are supported in authenticated safe")
334
var safeContents []safeBag
335
if err := unmarshal(data, &safeContents); err != nil {
338
bags = append(bags, safeContents...)
341
return bags, password, nil