File: cacert.go

package info (click to toggle)
golang-github-micromdm-scep 2.3.0-1
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 404 kB
  • sloc: makefile: 50; sh: 27
file content (125 lines) | stat: -rw-r--r-- 3,093 bytes parent folder | download
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)
}