OSDN Git Service

new repo
[bytom/vapor.git] / vendor / golang.org / x / crypto / pkcs12 / pkcs12.go
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.
10 package pkcs12
11
12 import (
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
23 var (
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
32 type pfxPdu struct {
33         Version  int
34         AuthSafe contentInfo
35         MacData  macData `asn1:"optional"`
36 }
37
38 type contentInfo struct {
39         ContentType asn1.ObjectIdentifier
40         Content     asn1.RawValue `asn1:"tag:0,explicit,optional"`
41 }
42
43 type encryptedData struct {
44         Version              int
45         EncryptedContentInfo encryptedContentInfo
46 }
47
48 type encryptedContentInfo struct {
49         ContentType                asn1.ObjectIdentifier
50         ContentEncryptionAlgorithm pkix.AlgorithmIdentifier
51         EncryptedContent           []byte `asn1:"tag:0,optional"`
52 }
53
54 func (i encryptedContentInfo) Algorithm() pkix.AlgorithmIdentifier {
55         return i.ContentEncryptionAlgorithm
56 }
57
58 func (i encryptedContentInfo) Data() []byte { return i.EncryptedContent }
59
60 type safeBag struct {
61         Id         asn1.ObjectIdentifier
62         Value      asn1.RawValue     `asn1:"tag:0,explicit"`
63         Attributes []pkcs12Attribute `asn1:"set,optional"`
64 }
65
66 type pkcs12Attribute struct {
67         Id    asn1.ObjectIdentifier
68         Value asn1.RawValue `asn1:"set"`
69 }
70
71 type encryptedPrivateKeyInfo struct {
72         AlgorithmIdentifier pkix.AlgorithmIdentifier
73         EncryptedData       []byte
74 }
75
76 func (i encryptedPrivateKeyInfo) Algorithm() pkix.AlgorithmIdentifier {
77         return i.AlgorithmIdentifier
78 }
79
80 func (i encryptedPrivateKeyInfo) Data() []byte {
81         return i.EncryptedData
82 }
83
84 // PEM block types
85 const (
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.
92 func 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.
104 func 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
128 func 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
174 func 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.
212 func 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
270 func 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 }