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