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/micromdm/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)
}
|