-
Notifications
You must be signed in to change notification settings - Fork 2
/
cert.go
275 lines (258 loc) · 6.84 KB
/
cert.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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
/*
Copyright 2020 RS4
@Author: Weny Xu
@Date: 2021/01/07 5:55
*/
/*
Utility for key and cert file
*/
package cert
import (
"crypto/md5"
"crypto/rsa"
"crypto/x509"
"encoding/hex"
"encoding/pem"
"errors"
"fmt"
"io/ioutil"
"strings"
"github.com/WenyXu/better-alipay-go/global"
"github.com/WenyXu/better-alipay-go/sign"
)
// LoadCertSN load root cert sn form path or bytes
func LoadCertSN(certPathOrData interface{}) (sn string, err error) {
var certData []byte
switch certPathOrData.(type) {
case string:
certData, err = ioutil.ReadFile(certPathOrData.(string))
case []byte:
certData = certPathOrData.([]byte)
}
if err != nil {
return sn, err
}
if block, _ := pem.Decode(certData); block != nil {
cert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
return sn, err
}
name := cert.Issuer.String()
serialNumber := cert.SerialNumber.String()
h := md5.New()
h.Write([]byte(name))
h.Write([]byte(serialNumber))
sn = hex.EncodeToString(h.Sum(nil))
}
if sn == "" {
return "", errors.New("failed to load cert sn,check the cert path or data")
}
return sn, nil
}
// LoadRootCertSN load root cert sn form path or bytes
func LoadRootCertSN(rootCertPathOrData interface{}) (sn string, err error) {
var certData []byte
var certEnd = `-----END CERTIFICATE-----`
switch rootCertPathOrData.(type) {
case string:
certData, err = ioutil.ReadFile(rootCertPathOrData.(string))
case []byte:
certData = rootCertPathOrData.([]byte)
}
pems := strings.Split(string(certData), certEnd)
for _, c := range pems {
if block, _ := pem.Decode([]byte(c + certEnd)); block != nil {
cert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
continue
}
if !allowedSignatureAlgorithm[cert.SignatureAlgorithm.String()] {
continue
}
name := cert.Issuer.String()
serialNumber := cert.SerialNumber.String()
h := md5.New()
h.Write([]byte(name))
h.Write([]byte(serialNumber))
if sn == "" {
sn += hex.EncodeToString(h.Sum(nil))
} else {
sn += "_" + hex.EncodeToString(h.Sum(nil))
}
}
}
if sn == "" {
return sn, errors.New("failed to get sn,please check your cert")
}
return sn, nil
}
// FormatPrivateKey convert private key string to cert file text pattern
func FormatPrivateKey(privateKey string) (pKey string) {
var buffer strings.Builder
buffer.WriteString("-----BEGIN RSA PRIVATE KEY-----\n")
rawLen := 64
keyLen := len(privateKey)
raws := keyLen / rawLen
temp := keyLen % rawLen
if temp > 0 {
raws++
}
start := 0
end := start + rawLen
for i := 0; i < raws; i++ {
if i == raws-1 {
buffer.WriteString(privateKey[start:])
} else {
buffer.WriteString(privateKey[start:end])
}
buffer.WriteByte('\n')
start += rawLen
end = start + rawLen
}
buffer.WriteString("-----END RSA PRIVATE KEY-----\n")
pKey = buffer.String()
return
}
// FormatPublicKey convert public key string to cert file text pattern
func FormatPublicKey(publicKey string) (pKey string) {
var buffer strings.Builder
buffer.WriteString("-----BEGIN PUBLIC KEY-----\n")
rawLen := 64
keyLen := len(publicKey)
raws := keyLen / rawLen
temp := keyLen % rawLen
if temp > 0 {
raws++
}
start := 0
end := start + rawLen
for i := 0; i < raws; i++ {
if i == raws-1 {
buffer.WriteString(publicKey[start:])
} else {
buffer.WriteString(publicKey[start:end])
}
buffer.WriteByte('\n')
start += rawLen
end = start + rawLen
}
buffer.WriteString("-----END PUBLIC KEY-----\n")
pKey = buffer.String()
return
}
var allowedSignatureAlgorithm = map[string]bool{
"MD2-RSA": true,
"MD5-RSA": true,
"SHA1-RSA": true,
"SHA256-RSA": true,
"SHA384-RSA": true,
"SHA512-RSA": true,
"SHA256-RSAPSS": true,
"SHA384-RSAPSS": true,
"SHA512-RSAPSS": true,
}
// LoadPrivateKeyFormString load private key form string
//
// by default key type is PKCS8, sign type is SHA256
func LoadPrivateKeyFormString(privateKeyType string, privateKey string) sign.LoadPrivateKeyFunc {
return LoadPrivateKeyFormBytes(privateKeyType, []byte(FormatPrivateKey(privateKey)))
}
// LoadPrivateKeyFormBytes load private key form byte
func LoadPrivateKeyFormBytes(privateKeyType string, input []byte) sign.LoadPrivateKeyFunc {
return func() (publicKey *rsa.PrivateKey, err error) {
var (
block *pem.Block
)
if block, _ = pem.Decode(input); block == nil {
err = errors.New("pem.Decode:privateKey decode error")
return
}
switch privateKeyType {
case global.PKCS1:
if publicKey, err = x509.ParsePKCS1PrivateKey(block.Bytes); err != nil {
return
}
case global.PKCS8:
pkcs8Key, err := x509.ParsePKCS8PrivateKey(block.Bytes)
if err != nil {
return nil, err
}
pk8, ok := pkcs8Key.(*rsa.PrivateKey)
if !ok {
err = errors.New("parse PKCS8 key error")
return nil, err
}
publicKey = pk8
default:
if publicKey, err = x509.ParsePKCS1PrivateKey(block.Bytes); err != nil {
return
}
}
return
}
}
// LoadPublicKeyFormBytes load public key form byte
func LoadPublicKeyFormBytes(input []byte) (publicKey *rsa.PublicKey, err error) {
var (
block *pem.Block
pubKey interface{}
ok bool
)
if block, _ = pem.Decode(input); block == nil {
err = errors.New("支付宝公钥Decode错误")
return
}
if pubKey, err = x509.ParsePKIXPublicKey(block.Bytes); err != nil {
err = fmt.Errorf("x509.ParsePKIXPublicKey:%w", err)
return
}
if _, ok = pubKey.(*rsa.PublicKey); !ok {
err = errors.New("public key 类型断言错误")
return
}
return pubKey.(*rsa.PublicKey), nil
}
// LoadPublicCertFormBytes load public cert form byte
func LoadPublicCertFormBytes(input []byte) (publicKey *rsa.PublicKey, err error) {
var (
block *pem.Block
pubKey *x509.Certificate
ok bool
)
if block, _ = pem.Decode(input); block == nil {
err = errors.New("支付宝公钥Decode错误")
return
}
if pubKey, err = x509.ParseCertificate(block.Bytes); err != nil {
err = fmt.Errorf("x509.ParsePKIXPublicKey:%w", err)
return
}
if _, ok = pubKey.PublicKey.(*rsa.PublicKey); !ok {
err = errors.New("public key 类型断言错误")
return
}
return pubKey.PublicKey.(*rsa.PublicKey), nil
}
// PublicKeyFormString load public key form string
func PublicKeyFormString(input string) sign.LoadPublicKeyFunc {
return func() (publicKey *rsa.PublicKey, err error) {
return LoadPublicKeyFormBytes([]byte(FormatPublicKey(input)))
}
}
// PublicCertFormBytes load public key form byte
func PublicCertFormBytes(input []byte) sign.LoadPublicKeyFunc {
return func() (publicKey *rsa.PublicKey, err error) {
return LoadPublicCertFormBytes(input)
}
}
// PublicCertFormPath load public key form path
func PublicCertFormPath(input string) sign.LoadPublicKeyFunc {
return func() (publicKey *rsa.PublicKey, err error) {
bytes, err := ioutil.ReadFile(input)
if err != nil {
err = fmt.Errorf("支付宝公钥文件读取失败: %w", err)
return nil, err
}
return LoadPublicCertFormBytes(bytes)
}
}