-
Notifications
You must be signed in to change notification settings - Fork 0
/
ca.go
138 lines (118 loc) · 3.7 KB
/
ca.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
package ca
import (
"bytes"
"crypto/ecdsa"
"crypto/ed25519"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"errors"
"github.com/c3b2a7/easy-ca/ca/internal"
"io"
"strings"
)
func GetKeyPairGenerator(algorithm string, opts KeyOptions) (KeyPairGenerator, error) {
algorithm = strings.ToUpper(algorithm)
if choice, ok := generateList[algorithm]; ok {
return &keyPairGenerator{
generate: choice,
opts: opts,
}, nil
}
return nil, UnknownAlgorithmError
}
func CreateSelfSignedCACertificate(keyPair KeyPair, opts CertificateOptions) (*x509.Certificate, error) {
if !opts.IsRootCA() {
return nil, errors.New("invalid certificate options")
}
subjectKeyId := internal.CalculateKeyID(keyPair.PublicKey)
template := opts.ToX509Template()
template.BasicConstraintsValid = true
template.SubjectKeyId = subjectKeyId
template.AuthorityKeyId = subjectKeyId
template.KeyUsage = x509.KeyUsageCertSign | x509.KeyUsageCRLSign | x509.KeyUsageDigitalSignature
der, err := x509.CreateCertificate(rand.Reader, template, template, keyPair.PublicKey, keyPair.PrivateKey)
if err != nil {
return nil, err
}
return x509.ParseCertificate(der)
}
func CreateMiddleCACertificate(keyPair KeyPair, opts CertificateOptions) (*x509.Certificate, error) {
if !opts.IsMiddleCA() {
return nil, errors.New("invalid certificate options")
}
template := opts.ToX509Template()
template.BasicConstraintsValid = true
template.SubjectKeyId = internal.CalculateKeyID(keyPair.PublicKey)
template.AuthorityKeyId = opts.Issuer.SubjectKeyId
template.KeyUsage = x509.KeyUsageCertSign | x509.KeyUsageCRLSign | x509.KeyUsageDigitalSignature
template.MaxPathLen = 1
der, err := x509.CreateCertificate(rand.Reader, template, opts.Issuer, keyPair.PublicKey, opts.IssuerPrivateKey)
if err != nil {
return nil, err
}
return x509.ParseCertificate(der)
}
func CreateCertificate(keyPair KeyPair, opts CertificateOptions) (*x509.Certificate, error) {
if opts.IsRootCA() || opts.IsMiddleCA() {
return nil, errors.New("invalid certificate options")
}
template := opts.ToX509Template()
template.SubjectKeyId = internal.CalculateKeyID(keyPair.PublicKey)
template.AuthorityKeyId = opts.Issuer.SubjectKeyId
template.KeyUsage = x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment | x509.KeyUsageDataEncipherment
template.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth}
der, err := x509.CreateCertificate(rand.Reader, template, opts.Issuer, keyPair.PublicKey, opts.IssuerPrivateKey)
if err != nil {
return nil, err
}
return x509.ParseCertificate(der)
}
func EncodeCertificateChain(out io.Writer, certificates []*x509.Certificate) (err error) {
buf := new(bytes.Buffer)
for _, certificate := range certificates {
err = pem.Encode(buf, &pem.Block{
Type: "CERTIFICATE",
Bytes: certificate.Raw,
})
if err != nil {
return
}
}
_, err = io.CopyBuffer(out, buf, make([]byte, 4096))
return
}
func EncodePKCS1PrivateKey(out io.Writer, privateKey any) (err error) {
var bytes []byte
var pemType string
switch k := privateKey.(type) {
case *rsa.PrivateKey:
bytes = x509.MarshalPKCS1PrivateKey(k)
pemType = "RSA PRIVATE KEY"
case *ecdsa.PrivateKey:
bytes, err = x509.MarshalECPrivateKey(k)
pemType = "EC PRIVATE KEY"
case ed25519.PrivateKey:
err = errors.New("unsupported private key type: ed25591")
default:
err = UnknownAlgorithmError
}
if err != nil {
return
}
return pem.Encode(out, &pem.Block{
Type: pemType,
Bytes: bytes,
})
}
func EncodePKCS8PrivateKey(out io.Writer, privateKey any) error {
bytes, err := x509.MarshalPKCS8PrivateKey(privateKey)
if err != nil {
return err
}
return pem.Encode(out, &pem.Block{
Type: "PRIVATE KEY",
Bytes: bytes,
})
}