1
2
3
4
5
6
7
8
9
10 package pkcs12
11
12 import (
13 "crypto/ecdsa"
14 "crypto/rand"
15 "crypto/rsa"
16 "crypto/sha1"
17 "crypto/x509"
18 "crypto/x509/pkix"
19 "encoding/asn1"
20 "encoding/hex"
21 "encoding/pem"
22 "errors"
23 "github.com/tjfoc/gmsm/sm2"
24 x "github.com/tjfoc/gmsm/x509"
25 "io/ioutil"
26 )
27
28 var (
29 oidDataContentType = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 7, 1})
30 oidEncryptedDataContentType = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 7, 6})
31
32 oidFriendlyName = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 9, 20})
33 oidLocalKeyID = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 9, 21})
34 oidMicrosoftCSPName = asn1.ObjectIdentifier([]int{1, 3, 6, 1, 4, 1, 311, 17, 1})
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 func (i *encryptedContentInfo) SetData(data []byte) { i.EncryptedContent = data }
66
67 type safeBag struct {
68 Id asn1.ObjectIdentifier
69 Value asn1.RawValue `asn1:"tag:0,explicit"`
70 Attributes []pkcs12Attribute `asn1:"set,optional"`
71 }
72
73 type pkcs12Attribute struct {
74 Id asn1.ObjectIdentifier
75 Value asn1.RawValue `asn1:"set"`
76 }
77
78 type encryptedPrivateKeyInfo struct {
79 AlgorithmIdentifier pkix.AlgorithmIdentifier
80 EncryptedData []byte
81 }
82
83 func (i encryptedPrivateKeyInfo) Algorithm() pkix.AlgorithmIdentifier {
84 return i.AlgorithmIdentifier
85 }
86
87 func (i encryptedPrivateKeyInfo) Data() []byte {
88 return i.EncryptedData
89 }
90
91 func (i *encryptedPrivateKeyInfo) SetData(data []byte) {
92 i.EncryptedData = data
93 }
94
95
96 const (
97 certificateType = "CERTIFICATE"
98 privateKeyType = "PRIVATE KEY"
99 )
100
101
102
103 func unmarshal(in []byte, out interface{}) error {
104 trailing, err := asn1.Unmarshal(in, out)
105 if err != nil {
106 return err
107 }
108 if len(trailing) != 0 {
109 return errors.New("go-pkcs12: trailing data found")
110 }
111 return nil
112 }
113
114
115 func ToPEM(pfxData []byte, password string) ([]*pem.Block, error) {
116 encodedPassword, err := bmpString(password)
117 if err != nil {
118 return nil, ErrIncorrectPassword
119 }
120
121 bags, encodedPassword, err := getSafeContents(pfxData, encodedPassword)
122
123 blocks := make([]*pem.Block, 0, len(bags))
124 for _, bag := range bags {
125 block, err := convertBag(&bag, encodedPassword)
126 if err != nil {
127 return nil, err
128 }
129 blocks = append(blocks, block)
130 }
131
132 return blocks, nil
133 }
134
135 func convertBag(bag *safeBag, password []byte) (*pem.Block, error) {
136 block := &pem.Block{
137 Headers: make(map[string]string),
138 }
139
140 for _, attribute := range bag.Attributes {
141 k, v, err := convertAttribute(&attribute)
142 if err != nil {
143 return nil, err
144 }
145 block.Headers[k] = v
146 }
147
148 switch {
149 case bag.Id.Equal(oidCertBag):
150 block.Type = certificateType
151 certsData, err := decodeCertBag(bag.Value.Bytes)
152 if err != nil {
153 return nil, err
154 }
155 block.Bytes = certsData
156 case bag.Id.Equal(oidPKCS8ShroundedKeyBag):
157 block.Type = privateKeyType
158
159 key, err := decodePkcs8ShroudedKeyBag(bag.Value.Bytes, password)
160 if err != nil {
161 return nil, err
162 }
163
164 switch key := key.(type) {
165 case *rsa.PrivateKey:
166 block.Bytes = x509.MarshalPKCS1PrivateKey(key)
167 case *ecdsa.PrivateKey:
168 block.Bytes, err = x509.MarshalECPrivateKey(key)
169 if err != nil {
170 return nil, err
171 }
172 default:
173 return nil, errors.New("found unknown private key type in PKCS#8 wrapping")
174 }
175 default:
176 return nil, errors.New("don't know how to convert a safe bag of type " + bag.Id.String())
177 }
178 return block, nil
179 }
180
181 func convertAttribute(attribute *pkcs12Attribute) (key, value string, err error) {
182 isString := false
183
184 switch {
185 case attribute.Id.Equal(oidFriendlyName):
186 key = "friendlyName"
187 isString = true
188 case attribute.Id.Equal(oidLocalKeyID):
189 key = "localKeyId"
190 case attribute.Id.Equal(oidMicrosoftCSPName):
191
192 key = "Microsoft CSP Name"
193 isString = true
194 default:
195 return "", "", errors.New("go-pkcs12: unknown attribute with OID " + attribute.Id.String())
196 }
197
198 if isString {
199 if err := unmarshal(attribute.Value.Bytes, &attribute.Value); err != nil {
200 return "", "", err
201 }
202 if value, err = decodeBMPString(attribute.Value.Bytes); err != nil {
203 return "", "", err
204 }
205 } else {
206 var id []byte
207 if err := unmarshal(attribute.Value.Bytes, &id); err != nil {
208 return "", "", err
209 }
210 value = hex.EncodeToString(id)
211 }
212
213 return key, value, nil
214 }
215
216
217 func DecodeAll(pfxData []byte, password string) (privateKey interface{}, certificate []*x.Certificate, err error) {
218 encodedPassword, err := bmpString(password)
219 if err != nil {
220 return nil, nil, err
221 }
222
223 bags, encodedPassword, err := getSafeContents(pfxData, encodedPassword)
224 if err != nil {
225 return nil, nil, err
226 }
227
228
229
230
231
232
233 for _, bag := range bags {
234 switch {
235 case bag.Id.Equal(oidCertBag):
236 if certificate != nil {
237 err = errors.New("go-pkcs12: expected exactly one certificate bag")
238 }
239
240 certsData, err := decodeCertBag(bag.Value.Bytes)
241 if err != nil {
242 return nil, nil, err
243 }
244 certs, err := x.ParseCertificates(certsData)
245 if err != nil {
246 return nil, nil, err
247 }
248 if len(certs) != 1 {
249 err = errors.New("go-pkcs12: expected exactly one certificate in the certBag")
250 return nil, nil, err
251 }
252 certificate = append(certificate, certs[0])
253
254 case bag.Id.Equal(oidPKCS8ShroundedKeyBag):
255 if privateKey != nil {
256 err = errors.New("go-pkcs12: expected exactly one key bag")
257 }
258
259 if privateKey, err = decodePkcs8ShroudedKeyBag(bag.Value.Bytes, encodedPassword); err != nil {
260 return nil, nil, err
261 }
262 }
263 }
264
265 if certificate == nil {
266 return nil, nil, errors.New("go-pkcs12: certificate missing")
267 }
268 if privateKey == nil {
269 return nil, nil, errors.New("go-pkcs12: private key missing")
270 }
271
272 return
273 }
274
275
276
277
278 func Decode(pfxData []byte, password string) (privateKey interface{}, certificate *x509.Certificate, err error) {
279 encodedPassword, err := bmpString(password)
280 if err != nil {
281 return nil, nil, err
282 }
283
284 bags, encodedPassword, err := getSafeContents(pfxData, encodedPassword)
285 if err != nil {
286 return nil, nil, err
287 }
288
289
290
291
292
293
294 for _, bag := range bags {
295 switch {
296 case bag.Id.Equal(oidCertBag):
297 if certificate != nil {
298 err = errors.New("go-pkcs12: expected exactly one certificate bag")
299 }
300
301 certsData, err := decodeCertBag(bag.Value.Bytes)
302 if err != nil {
303 return nil, nil, err
304 }
305 certs, err := x509.ParseCertificates(certsData)
306 if err != nil {
307 return nil, nil, err
308 }
309 if len(certs) != 1 {
310 err = errors.New("go-pkcs12: expected exactly one certificate in the certBag")
311 return nil, nil, err
312 }
313 certificate = certs[0]
314
315 case bag.Id.Equal(oidPKCS8ShroundedKeyBag):
316 if privateKey != nil {
317 err = errors.New("go-pkcs12: expected exactly one key bag")
318 }
319
320 if privateKey, err = decodePkcs8ShroudedKeyBag(bag.Value.Bytes, encodedPassword); err != nil {
321 return nil, nil, err
322 }
323 }
324 }
325
326 if certificate == nil {
327 return nil, nil, errors.New("go-pkcs12: certificate missing")
328 }
329 if privateKey == nil {
330 return nil, nil, errors.New("go-pkcs12: private key missing")
331 }
332
333 return
334 }
335
336 func getSafeContents(p12Data, password []byte) (bags []safeBag, updatedPassword []byte, err error) {
337 pfx := new(pfxPdu)
338 if err := unmarshal(p12Data, pfx); err != nil {
339 return nil, nil, errors.New("go-pkcs12: error reading P12 data: " + err.Error())
340 }
341
342 if pfx.Version != 3 {
343 return nil, nil, NotImplementedError("can only decode v3 PFX PDU's")
344 }
345
346 if !pfx.AuthSafe.ContentType.Equal(oidDataContentType) {
347 return nil, nil, NotImplementedError("only password-protected PFX is implemented")
348 }
349
350
351 if err := unmarshal(pfx.AuthSafe.Content.Bytes, &pfx.AuthSafe.Content); err != nil {
352 return nil, nil, err
353 }
354
355 if len(pfx.MacData.Mac.Algorithm.Algorithm) == 0 {
356 return nil, nil, errors.New("go-pkcs12: no MAC in data")
357 }
358
359 if err := verifyMac(&pfx.MacData, pfx.AuthSafe.Content.Bytes, password); err != nil {
360 if err == ErrIncorrectPassword && len(password) == 2 && password[0] == 0 && password[1] == 0 {
361
362
363
364 password = nil
365 err = verifyMac(&pfx.MacData, pfx.AuthSafe.Content.Bytes, password)
366 }
367 if err != nil {
368 return nil, nil, err
369 }
370 }
371
372 var authenticatedSafe []contentInfo
373 if err := unmarshal(pfx.AuthSafe.Content.Bytes, &authenticatedSafe); err != nil {
374 return nil, nil, err
375 }
376
377 if len(authenticatedSafe) != 2 {
378 return nil, nil, NotImplementedError("expected exactly two items in the authenticated safe")
379 }
380
381 for _, ci := range authenticatedSafe {
382 var data []byte
383
384 switch {
385 case ci.ContentType.Equal(oidDataContentType):
386 if err := unmarshal(ci.Content.Bytes, &data); err != nil {
387 return nil, nil, err
388 }
389 case ci.ContentType.Equal(oidEncryptedDataContentType):
390 var encryptedData encryptedData
391 if err := unmarshal(ci.Content.Bytes, &encryptedData); err != nil {
392 return nil, nil, err
393 }
394 if encryptedData.Version != 0 {
395 return nil, nil, NotImplementedError("only version 0 of EncryptedData is supported")
396 }
397 if data, err = pbDecrypt(encryptedData.EncryptedContentInfo, password); err != nil {
398 return nil, nil, err
399 }
400 default:
401 return nil, nil, NotImplementedError("only data and encryptedData content types are supported in authenticated safe")
402 }
403
404 var safeContents []safeBag
405 if err := unmarshal(data, &safeContents); err != nil {
406 return nil, nil, err
407 }
408 bags = append(bags, safeContents...)
409 }
410
411 return bags, password, nil
412 }
413
414
415
416
417
418
419 func Encode(privateKey interface{}, certificate *x.Certificate, caCerts []*x509.Certificate, password string) (pfxData []byte, err error) {
420 encodedPassword, err := bmpString(password)
421 if err != nil {
422 return nil, err
423 }
424
425 var pfx pfxPdu
426 pfx.Version = 3
427
428 var certFingerprint = sha1.Sum(certificate.Raw)
429 var localKeyIdAttr pkcs12Attribute
430 localKeyIdAttr.Id = oidLocalKeyID
431 localKeyIdAttr.Value.Class = 0
432 localKeyIdAttr.Value.Tag = 17
433 localKeyIdAttr.Value.IsCompound = true
434 if localKeyIdAttr.Value.Bytes, err = asn1.Marshal(certFingerprint[:]); err != nil {
435 return nil, err
436 }
437
438 var certBags []safeBag
439 var certBag *safeBag
440 if certBag, err = makeCertBag(certificate.Raw, []pkcs12Attribute{localKeyIdAttr}); err != nil {
441 return nil, err
442 }
443 certBags = append(certBags, *certBag)
444
445 for _, cert := range caCerts {
446 if certBag, err = makeCertBag(cert.Raw, []pkcs12Attribute{}); err != nil {
447 return nil, err
448 }
449 certBags = append(certBags, *certBag)
450 }
451
452 var keyBag safeBag
453 keyBag.Id = oidPKCS8ShroundedKeyBag
454 keyBag.Value.Class = 2
455 keyBag.Value.Tag = 0
456 keyBag.Value.IsCompound = true
457 if keyBag.Value.Bytes, err = encodePkcs8ShroudedKeyBag(privateKey, encodedPassword); err != nil {
458 return nil, err
459 }
460 keyBag.Attributes = append(keyBag.Attributes, localKeyIdAttr)
461
462
463
464
465 var authenticatedSafe [2]contentInfo
466 if authenticatedSafe[0], err = makeSafeContents(certBags, encodedPassword); err != nil {
467 return nil, err
468 }
469 if authenticatedSafe[1], err = makeSafeContents([]safeBag{keyBag}, nil); err != nil {
470 return nil, err
471 }
472
473 var authenticatedSafeBytes []byte
474 if authenticatedSafeBytes, err = asn1.Marshal(authenticatedSafe[:]); err != nil {
475 return nil, err
476 }
477
478
479 pfx.MacData.Mac.Algorithm.Algorithm = oidSHA1
480 pfx.MacData.MacSalt = make([]byte, 8)
481 if _, err = rand.Read(pfx.MacData.MacSalt); err != nil {
482 return nil, err
483 }
484 pfx.MacData.Iterations = 1
485 if err = computeMac(&pfx.MacData, authenticatedSafeBytes, encodedPassword); err != nil {
486 return nil, err
487 }
488
489 pfx.AuthSafe.ContentType = oidDataContentType
490 pfx.AuthSafe.Content.Class = 2
491 pfx.AuthSafe.Content.Tag = 0
492 pfx.AuthSafe.Content.IsCompound = true
493 if pfx.AuthSafe.Content.Bytes, err = asn1.Marshal(authenticatedSafeBytes); err != nil {
494 return nil, err
495 }
496
497 if pfxData, err = asn1.Marshal(pfx); err != nil {
498 return nil, errors.New("go-pkcs12: error writing P12 data: " + err.Error())
499 }
500 return
501 }
502
503 func makeCertBag(certBytes []byte, attributes []pkcs12Attribute) (certBag *safeBag, err error) {
504 certBag = new(safeBag)
505 certBag.Id = oidCertBag
506 certBag.Value.Class = 2
507 certBag.Value.Tag = 0
508 certBag.Value.IsCompound = true
509 if certBag.Value.Bytes, err = encodeCertBag(certBytes); err != nil {
510 return nil, err
511 }
512 certBag.Attributes = attributes
513 return
514 }
515
516 func makeSafeContents(bags []safeBag, password []byte) (ci contentInfo, err error) {
517 var data []byte
518 if data, err = asn1.Marshal(bags); err != nil {
519 return
520 }
521
522 if password == nil {
523 ci.ContentType = oidDataContentType
524 ci.Content.Class = 2
525 ci.Content.Tag = 0
526 ci.Content.IsCompound = true
527 if ci.Content.Bytes, err = asn1.Marshal(data); err != nil {
528 return
529 }
530 } else {
531 randomSalt := make([]byte, 8)
532 if _, err = rand.Read(randomSalt); err != nil {
533 return
534 }
535
536 var algo pkix.AlgorithmIdentifier
537 algo.Algorithm = oidPBEWithSHAAnd40BitRC2CBC
538 if algo.Parameters.FullBytes, err = asn1.Marshal(pbeParams{Salt: randomSalt, Iterations: 2048}); err != nil {
539 return
540 }
541
542 var encryptedData encryptedData
543 encryptedData.Version = 0
544 encryptedData.EncryptedContentInfo.ContentType = oidDataContentType
545 encryptedData.EncryptedContentInfo.ContentEncryptionAlgorithm = algo
546 if err = pbEncrypt(&encryptedData.EncryptedContentInfo, data, password); err != nil {
547 return
548 }
549
550 ci.ContentType = oidEncryptedDataContentType
551 ci.Content.Class = 2
552 ci.Content.Tag = 0
553 ci.Content.IsCompound = true
554 if ci.Content.Bytes, err = asn1.Marshal(encryptedData); err != nil {
555 return
556 }
557 }
558 return
559 }
560 func SM2P12Encrypt(certificate *x.Certificate, pwd string, priv *sm2.PrivateKey, fileName string) error {
561 pfxDataNew, err := Encode(priv, certificate, nil, pwd)
562 if err != nil {
563 return err
564 }
565 err = ioutil.WriteFile(fileName, pfxDataNew, 0666)
566 return err
567 }
568 func SM2P12Decrypt(fileName string, pwd string) (*x.Certificate, *sm2.PrivateKey, error) {
569 pfxData, _ := ioutil.ReadFile(fileName)
570 pv, cer, err := DecodeAll(pfxData, pwd)
571 if err != nil {
572 return nil, nil, err
573 }
574 switch k := pv.(type) {
575 case *ecdsa.PrivateKey:
576 switch k.Curve {
577 case sm2.P256Sm2():
578 sm2pub := &sm2.PublicKey{
579 Curve: k.Curve,
580 X: k.X,
581 Y: k.Y,
582 }
583 sm2Pri := &sm2.PrivateKey{
584 PublicKey: *sm2pub,
585 D: k.D,
586 }
587 if !k.IsOnCurve(k.X,k.Y) {
588 return nil, nil, errors.New("error while validating SM2 private key: %v")
589 }
590 return cer[0], sm2Pri, nil
591 }
592 default:
593 return nil, nil, errors.New("unexpected type for p12 private key")
594 }
595 return nil,nil,nil
596 }
597
View as plain text