...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package certloader
18
19 import (
20 "crypto"
21 "crypto/x509"
22 "encoding/pem"
23 "errors"
24
25 "github.com/sassoftware/relic/lib/passprompt"
26 "github.com/sassoftware/relic/lib/x509tools"
27 "golang.org/x/crypto/pkcs12"
28 )
29
30 func ParsePKCS12(blob []byte, prompt passprompt.PasswordGetter) (*Certificate, error) {
31 var password string
32 var blocks []*pem.Block
33 var triedEmpty bool
34 for {
35 var err error
36 password, err = prompt.GetPasswd("Password for PKCS12: ")
37 if err != nil {
38 return nil, err
39 } else if password == "" {
40 if triedEmpty {
41 return nil, errors.New("aborted")
42 }
43 triedEmpty = true
44 }
45 blocks, err = pkcs12.ToPEM(blob, password)
46 if err == nil {
47 break
48 } else if err != pkcs12.ErrIncorrectPassword {
49 return nil, err
50 }
51 }
52 var certs []*x509.Certificate
53 var privKey crypto.PrivateKey
54 for _, block := range blocks {
55 switch block.Type {
56 case "CERTIFICATE":
57 newcerts, err := parseCertificatesDer(block.Bytes)
58 if err != nil {
59 return nil, err
60 }
61 certs = append(certs, newcerts.Certificates...)
62 case "PRIVATE KEY":
63 if privKey != nil {
64 return nil, errors.New("multiple private keys")
65 }
66 var err error
67 privKey, err = parsePrivateKey(block.Bytes)
68 if err != nil {
69 return nil, err
70 }
71 }
72 }
73 if privKey == nil {
74 return nil, errors.New("incorrect password or no private key")
75 }
76 ret := &Certificate{PrivateKey: privKey, Certificates: certs}
77 for _, cert := range certs {
78 if x509tools.SameKey(cert.PublicKey, privKey) {
79 ret.Leaf = cert
80 }
81 }
82 if ret.Leaf == nil {
83 return nil, errors.New("leaf certificate not found")
84 }
85 return ret, nil
86 }
87
View as plain text