/
PFX.go
159 lines (135 loc) · 4.51 KB
/
PFX.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
package libICP
import (
"crypto/rsa"
"io/ioutil"
"math/big"
"time"
"github.com/OpenICP-BR/asn1"
)
// Represents a .p12/.pfx file containing a public certificate and a private key which is usually encrypted.
//
// Only password privacy mode and password integrity mode are supported.
type PFX struct {
base pfx_raw
Cert *Certificate
rsa_key *rsa.PrivateKey
}
func (pfx PFX) HasKey() bool {
return pfx.rsa_key != nil
}
func NewPFXFromFile(path string, password string) (PFX, CodedError) {
// Open file
dat, err := ioutil.ReadFile(path)
if err != nil {
merr := NewMultiError("failed to read PFX file", ERR_READ_FILE, nil, err)
merr.SetParam("path", path)
return PFX{}, merr
}
return NewPFXFromDER(dat, password)
}
func NewPFXFromDER(dat []byte, password string) (PFX, CodedError) {
pfx := PFX{}
var cerr CodedError
var der_cert []byte
// Parse
_, err := asn1.Unmarshal(dat, &pfx.base)
if err != nil {
merr := NewMultiError("failed to parse PFX file", ERR_PARSE_PFX, nil, err)
merr.SetParam("raw-data", dat)
return PFX{}, merr
}
der_cert, pfx.rsa_key, cerr = pfx.base.Unmarshal(password)
if cerr != nil {
return PFX{}, cerr
}
certs, cerrs := NewCertificateFromBytes(der_cert)
if len(cerrs) > 1 {
return PFX{}, cerrs[0]
}
if len(certs) > 0 {
pfx.Cert = certs[0]
}
return pfx, nil
}
// Generates a new root CA with subject and issuer TESTING_ROOT_CA_SUBJECT
//
// BUG: Subject Public Key Info leads to PKEY_SET_TYPE:unsupported algorithm and X509_PUBKEY_get:unsupported algorithm on openssl
//
// BUG: Lack of propper extensions leads the rest of the code to not consider it as a CA (key usage and extended key usage).
func NewRootCA(not_before, not_after time.Time) (PFX, CodedError) {
name := nameT{
[]atv{atv{Type: idCountryName, Value: "BR"}},
[]atv{atv{Type: idOrganizationName, Value: "Fake ICP-Brasil"}},
[]atv{atv{Type: idOrganizationalUnitName, Value: "Apenas para testes - SEM VALOR LEGAL"}},
[]atv{atv{Type: idCommonName, Value: "Autoridade Certificadora Raiz de Testes - SEM VALOR LEGAL"}},
}
return new_cert_and_key(name, name, big.NewInt(1), not_before, not_after)
}
func NewCertAndKey(subject map[string]string, issuer Certificate, serial *big.Int, not_before, not_after time.Time) (pfx PFX, cerr CodedError) {
// Parse subject
subject_name := nameT{}
for k, v := range subject {
typ := str2oid_key(k)
if typ == nil {
continue
}
item := []atv{atv{Type: idCountryName, Value: v}}
subject_name = append(subject_name, item)
}
return new_cert_and_key(subject_name, issuer.base.TBSCertificate.Issuer, serial, not_before, not_after)
}
func new_cert_and_key(subject_name, issuer_name nameT, serial *big.Int, not_before, not_after time.Time) (pfx PFX, cerr CodedError) {
var pair pair_alg_pub_key
// Generate key pair
pfx.rsa_key, pair, cerr = new_rsa_key(2048)
if cerr != nil {
return
}
// Set data
pfx.Cert = new(Certificate)
pfx.Cert.base.TBSCertificate.Issuer = issuer_name
pfx.Cert.base.TBSCertificate.Subject = subject_name
pfx.Cert.base.TBSCertificate.SerialNumber = serial
pfx.Cert.base.TBSCertificate.Validity.NotBeforeTime = not_before
pfx.Cert.base.TBSCertificate.Validity.NotAfterTime = not_after
pfx.Cert.base.TBSCertificate.Signature.Algorithm = idSha512WithRSAEncryption
pfx.Cert.base.SignatureAlgorithm.Algorithm = idSha512WithRSAEncryption
pfx.Cert.base.TBSCertificate.SubjectPublicKeyInfo.Algorithm.Algorithm = idSha512WithRSAEncryption
pfx.Cert.base.TBSCertificate.SubjectPublicKeyInfo.PublicKey = pair.PublicKey
pfx.Cert.base.TBSCertificate.SetAppropriateVersion()
pfx.Cert.finish_parsing()
// Marshal certificate
cerr = pfx.Cert.base.MarshalCert()
if cerr != nil {
return
}
// Sign certificate
cerr = Sign(&pfx.Cert.base, pfx.rsa_key)
return
}
// Saves the certificate to an unencrypted DER file. The private key is NOT included in the output.
func (pfx PFX) SaveCertToFile(path string) CodedError {
// Marshal pack
cerr := pfx.Cert.base.MarshalPack()
if cerr != nil {
return cerr
}
err := ioutil.WriteFile(path, pfx.Cert.base.RawContent, 0644)
if err != nil {
return NewMultiError("failed to write to file", ERR_FAILED_TO_WRITE_FILE, nil, err)
}
return nil
}
// Saves the certificate and the private key to a DER file.
func (pfx PFX) SaveToFile(path, password string) CodedError {
// Marshal
dat, cerr := marshal_pfx(password, pfx.Cert.base, pfx.rsa_key)
if cerr != nil {
return cerr
}
err := ioutil.WriteFile(path, dat, 0644)
if err != nil {
return NewMultiError("failed to write to file", ERR_FAILED_TO_WRITE_FILE, nil, err)
}
return nil
}