This repository has been archived by the owner on Feb 1, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
x509.go
153 lines (133 loc) · 3.66 KB
/
x509.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
package x509
import (
"bytes"
"crypto/rand"
"crypto/rsa"
cx509 "crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"math/big"
"time"
"github.com/deweppro/go-errors"
)
type (
Cert struct {
Public []byte
Private []byte
}
Config struct {
Organization string
OrganizationalUnit string
Country string
Province string
Locality string
StreetAddress string
PostalCode string
}
)
func (v *Config) ToSubject() pkix.Name {
result := pkix.Name{}
if len(v.Country) > 0 {
result.Country = []string{v.Country}
}
if len(v.Organization) > 0 {
result.Organization = []string{v.Organization}
}
if len(v.OrganizationalUnit) > 0 {
result.OrganizationalUnit = []string{v.OrganizationalUnit}
}
if len(v.Locality) > 0 {
result.Locality = []string{v.Locality}
}
if len(v.Province) > 0 {
result.Province = []string{v.Province}
}
if len(v.StreetAddress) > 0 {
result.StreetAddress = []string{v.StreetAddress}
}
if len(v.PostalCode) > 0 {
result.PostalCode = []string{v.PostalCode}
}
return result
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
func generate(c *Config, ttl time.Duration, sn int64, ca *Cert, cn ...string) (*Cert, error) {
crt := &cx509.Certificate{
SerialNumber: big.NewInt(sn),
Subject: c.ToSubject(),
NotBefore: time.Now(),
NotAfter: time.Now().Add(ttl),
ExtKeyUsage: []cx509.ExtKeyUsage{cx509.ExtKeyUsageClientAuth, cx509.ExtKeyUsageServerAuth},
}
var (
bits int
b []byte
)
if ca == nil {
bits = 4096
crt.IsCA = true
crt.BasicConstraintsValid = true
crt.KeyUsage = cx509.KeyUsageDigitalSignature | cx509.KeyUsageCertSign
if len(cn) > 0 {
crt.Subject.CommonName = cn[0]
}
} else {
bits = 2048
crt.KeyUsage = cx509.KeyUsageDigitalSignature
crt.PermittedDNSDomainsCritical = true
for i, s := range cn {
if i == 0 {
crt.Subject.CommonName = cn[0]
}
crt.DNSNames = append(crt.DNSNames, s)
}
}
pk, err := rsa.GenerateKey(rand.Reader, bits)
if err != nil {
return nil, errors.WrapMessage(err, "generate private key")
}
if ca == nil {
b, err = cx509.CreateCertificate(rand.Reader, crt, crt, &pk.PublicKey, pk)
} else {
block, _ := pem.Decode(ca.Public)
if block == nil {
return nil, errors.New("invalid decode public CA pem ")
}
var caCrt *cx509.Certificate
caCrt, err = cx509.ParseCertificate(block.Bytes)
if err != nil {
return nil, errors.WrapMessage(err, "parse CA certificate")
}
block, _ = pem.Decode(ca.Private)
if block == nil {
return nil, errors.New("invalid decode private CA pem ")
}
var caPK *rsa.PrivateKey
caPK, err = cx509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
return nil, errors.WrapMessage(err, "decode CA private key")
}
b, err = cx509.CreateCertificate(rand.Reader, crt, caCrt, &pk.PublicKey, caPK)
}
if err != nil {
return nil, errors.WrapMessage(err, "generate certificate")
}
var pubPEM bytes.Buffer
if err = pem.Encode(&pubPEM, &pem.Block{Type: "CERTIFICATE", Bytes: b}); err != nil {
return nil, errors.WrapMessage(err, "encode public pem")
}
var privPEM bytes.Buffer
if err = pem.Encode(&privPEM, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: cx509.MarshalPKCS1PrivateKey(pk)}); err != nil {
return nil, errors.WrapMessage(err, "encode private pem")
}
return &Cert{
Public: pubPEM.Bytes(),
Private: privPEM.Bytes(),
}, nil
}
func NewCertCA(c *Config, ttl time.Duration, cn string) (*Cert, error) {
return generate(c, ttl, 1, nil, cn)
}
func NewCert(c *Config, ttl time.Duration, sn int64, ca *Cert, cn ...string) (*Cert, error) {
return generate(c, ttl, 1, ca, cn...)
}