/
cacert.go
125 lines (106 loc) · 3.02 KB
/
cacert.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
package depot
import (
"crypto"
"crypto/x509"
"crypto/x509/pkix"
"io"
"math/big"
"time"
"github.com/admin-punon/scep/v2/cryptoutil"
)
// CACert represents a new self-signed CA certificate
type CACert struct {
commonName string
country string
organization string
organizationalUnit string
years int
keyUsage x509.KeyUsage
}
// NewCACert creates a new CACert object with options
func NewCACert(opts ...CACertOption) *CACert {
c := &CACert{
organization: "scep-ca",
organizationalUnit: "SCEP CA",
years: 10,
keyUsage: x509.KeyUsageCertSign |
x509.KeyUsageCRLSign |
x509.KeyUsageDigitalSignature,
}
for _, opt := range opts {
opt(c)
}
return c
}
type CACertOption func(*CACert)
// WithOrganization specifies the Organization on the CA template.
func WithOrganization(o string) CACertOption {
return func(c *CACert) {
c.organization = o
}
}
// WithOrganizationalUnit specifies the OrganizationalUnit on the CA template.
func WithOrganizationalUnit(ou string) CACertOption {
return func(c *CACert) {
c.organizationalUnit = ou
}
}
// WithYears specifies the validity date of the CA.
func WithYears(y int) CACertOption {
return func(c *CACert) {
c.years = y
}
}
// WithCountry specifies the Country on the CA template.
func WithCountry(country string) CACertOption {
return func(c *CACert) {
c.country = country
}
}
// WithCommonName specifies the CommonName on the CA template.
func WithCommonName(name string) CACertOption {
return func(c *CACert) {
c.commonName = name
}
}
// WithKeyUsage specifies the X.509 Key Usage on the CA template.
func WithKeyUsage(usage x509.KeyUsage) CACertOption {
return func(c *CACert) {
c.keyUsage = usage
}
}
// newPkixName creates a new pkix.Name from c
func (c *CACert) newPkixName() *pkix.Name {
return &pkix.Name{
Country: []string{c.country},
Organization: []string{c.organization},
OrganizationalUnit: []string{c.organizationalUnit},
CommonName: c.commonName,
}
}
// SelfSign creates an x509 template based off our settings and self-signs it using priv.
func (c *CACert) SelfSign(rand io.Reader, pub crypto.PublicKey, priv interface{}) ([]byte, error) {
subjKeyId, err := cryptoutil.GenerateSubjectKeyID(pub)
if err != nil {
return nil, err
}
// Build CA based on RFC5280
tmpl := x509.Certificate{
Subject: *c.newPkixName(),
SerialNumber: big.NewInt(1),
// NotBefore is set to be 10min earlier to fix gap on time difference in cluster
NotBefore: time.Now().Add(-600).UTC(),
NotAfter: time.Now().AddDate(c.years, 0, 0).UTC(),
// Used for certificate signing only
KeyUsage: c.keyUsage,
// activate CA
BasicConstraintsValid: true,
IsCA: true,
// Not allow any non-self-issued intermediate CA
MaxPathLen: 0,
// 160-bit SHA-1 hash of the value of the BIT STRING subjectPublicKey
// (excluding the tag, length, and number of unused bits)
SubjectKeyId: subjKeyId,
}
return x509.CreateCertificate(rand, &tmpl, &tmpl, pub, priv)
}