blob: b8c2aed26878e03e3d21eab2e08ae30ec66c3b8a [file] [log] [blame]
Serge Bazanski9411f7c2021-03-10 13:12:53 +01001// Copyright 2020 The Monogon Project Authors.
2//
3// SPDX-License-Identifier: Apache-2.0
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16
17package pki
18
19import (
20 "context"
21 "crypto/ed25519"
22 "crypto/rand"
23 "crypto/x509"
24 "fmt"
25 "math/big"
26 "time"
27
Lorenz Brund13c1c62022-03-30 19:58:58 +020028 clientv3 "go.etcd.io/etcd/client/v3"
Serge Bazanski9411f7c2021-03-10 13:12:53 +010029)
30
31// Issuer is an entity that can issue certificates. This interface is
32// implemented by SelfSigned, which is an issuer that emits self-signed
33// certificates, and any other Certificate that has been created with CA(),
34// which makes this Certificate act as a CA and issue (sign) ceritficates.
35type Issuer interface {
Serge Bazanski216fe7b2021-05-21 18:36:16 +020036 // CACertificate returns the DER-encoded x509 certificate of the CA that
37 // will sign certificates when Issue is called, or nil if this is
38 // self-signing issuer.
Serge Bazanski9411f7c2021-03-10 13:12:53 +010039 CACertificate(ctx context.Context, kv clientv3.KV) ([]byte, error)
Serge Bazanski52538842021-08-11 16:22:41 +020040 // Issue will generate a certificate signed by the Issuer. The returned
41 // certificate is x509 DER-encoded.
42 Issue(ctx context.Context, req *Certificate, kv clientv3.KV) (cert []byte, err error)
Serge Bazanski9411f7c2021-03-10 13:12:53 +010043}
44
Serge Bazanski216fe7b2021-05-21 18:36:16 +020045// issueCertificate is a generic low level certificate-and-key issuance
Serge Bazanski52538842021-08-11 16:22:41 +020046// function. If ca is null, the certificate will be self-signed. The returned
47// certificate is DER-encoded
48func issueCertificate(req *Certificate, ca *x509.Certificate, caKey ed25519.PrivateKey) (cert []byte, err error) {
Serge Bazanski9411f7c2021-03-10 13:12:53 +010049 serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 127)
50 serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
51 if err != nil {
52 err = fmt.Errorf("failed to generate serial number: %w", err)
53 return
54 }
55
Serge Bazanski52538842021-08-11 16:22:41 +020056 skid, err := calculateSKID(req.PublicKey)
Serge Bazanski9411f7c2021-03-10 13:12:53 +010057 if err != nil {
Serge Bazanski52538842021-08-11 16:22:41 +020058 return nil, err
Serge Bazanski9411f7c2021-03-10 13:12:53 +010059 }
60
Serge Bazanski52538842021-08-11 16:22:41 +020061 req.Template.SerialNumber = serialNumber
62 req.Template.NotBefore = time.Now()
Serge Bazanskid7d6e022021-09-01 15:03:06 +020063 req.Template.NotAfter = UnknownNotAfter
Serge Bazanski52538842021-08-11 16:22:41 +020064 req.Template.BasicConstraintsValid = true
65 req.Template.SubjectKeyId = skid
Serge Bazanski9411f7c2021-03-10 13:12:53 +010066
Serge Bazanski216fe7b2021-05-21 18:36:16 +020067 // Set the AuthorityKeyID to the SKID of the signing certificate (or self,
68 // if self-signing).
Serge Bazanski52538842021-08-11 16:22:41 +020069 if ca != nil {
Lorenz Brun237cf402022-07-04 12:14:37 +000070 req.Template.AuthorityKeyId = ca.SubjectKeyId
Serge Bazanski9411f7c2021-03-10 13:12:53 +010071 } else {
Serge Bazanski52538842021-08-11 16:22:41 +020072 req.Template.AuthorityKeyId = req.Template.SubjectKeyId
73 ca = &req.Template
Serge Bazanski9411f7c2021-03-10 13:12:53 +010074 }
75
Serge Bazanski52538842021-08-11 16:22:41 +020076 return x509.CreateCertificate(rand.Reader, &req.Template, ca, req.PublicKey, caKey)
Serge Bazanski9411f7c2021-03-10 13:12:53 +010077}
78
79type selfSigned struct{}
80
81var (
82 // SelfSigned is an Issuer that generates self-signed certificates.
83 SelfSigned = &selfSigned{}
84)
85
86// Issue will generate a key and certificate that is self-signed.
Serge Bazanski52538842021-08-11 16:22:41 +020087func (s *selfSigned) Issue(ctx context.Context, req *Certificate, kv clientv3.KV) (cert []byte, err error) {
88 if err := req.ensureKey(ctx, kv); err != nil {
89 return nil, err
90 }
91 if req.PrivateKey == nil {
92 return nil, fmt.Errorf("cannot issue self-signed certificate without a private key")
93 }
94 return issueCertificate(req, nil, req.PrivateKey)
Serge Bazanski9411f7c2021-03-10 13:12:53 +010095}
96
97// CACertificate returns nil for self-signed issuers.
98func (s *selfSigned) CACertificate(ctx context.Context, kv clientv3.KV) ([]byte, error) {
99 return nil, nil
100}
101
102// Issue will generate a key and certificate that is signed by this
103// Certificate, if the Certificate is a CA.
Serge Bazanski52538842021-08-11 16:22:41 +0200104func (c *Certificate) Issue(ctx context.Context, req *Certificate, kv clientv3.KV) (cert []byte, err error) {
105 if err := c.ensureKey(ctx, kv); err != nil {
106 return nil, fmt.Errorf("could not ensure CA %q key exists: %w", c.Name, err)
107 }
108 if err := req.ensureKey(ctx, kv); err != nil {
109 return nil, fmt.Errorf("could not subject %q key exists: %w", req.Name, err)
110 }
111 if c.PrivateKey == nil {
112 return nil, fmt.Errorf("cannot use certificate without private key as CA")
113 }
114
115 caCert, err := c.ensure(ctx, kv)
Serge Bazanski9411f7c2021-03-10 13:12:53 +0100116 if err != nil {
Serge Bazanski52538842021-08-11 16:22:41 +0200117 return nil, fmt.Errorf("could not ensure CA %q certificate exists: %w", c.Name, err)
Serge Bazanski9411f7c2021-03-10 13:12:53 +0100118 }
119
120 ca, err := x509.ParseCertificate(caCert)
121 if err != nil {
Serge Bazanski52538842021-08-11 16:22:41 +0200122 return nil, fmt.Errorf("could not parse CA certificate: %w", err)
Serge Bazanski9411f7c2021-03-10 13:12:53 +0100123 }
124 // Ensure only one level of CAs exist, and that they are created explicitly.
Serge Bazanski52538842021-08-11 16:22:41 +0200125 req.Template.IsCA = false
126 return issueCertificate(req, ca, c.PrivateKey)
Serge Bazanski9411f7c2021-03-10 13:12:53 +0100127}
128
129// CACertificate returns the DER encoded x509 form of this Certificate that
130// will be the used to issue child certificates.
131func (c *Certificate) CACertificate(ctx context.Context, kv clientv3.KV) ([]byte, error) {
Serge Bazanski52538842021-08-11 16:22:41 +0200132 return c.ensure(ctx, kv)
Serge Bazanski9411f7c2021-03-10 13:12:53 +0100133}