blob: ff6d639efc816eae9223d9ae22a6da47c5f5ccd5 [file] [log] [blame]
Tim Windelschmidt6d33a432025-02-04 14:34:25 +01001// Copyright The Monogon Project Authors.
Serge Bazanski9411f7c2021-03-10 13:12:53 +01002// SPDX-License-Identifier: Apache-2.0
Serge Bazanski9411f7c2021-03-10 13:12:53 +01003
4package pki
5
6import (
7 "context"
8 "crypto/ed25519"
9 "crypto/rand"
10 "crypto/x509"
11 "fmt"
12 "math/big"
13 "time"
14
Lorenz Brund13c1c62022-03-30 19:58:58 +020015 clientv3 "go.etcd.io/etcd/client/v3"
Serge Bazanski9411f7c2021-03-10 13:12:53 +010016)
17
18// Issuer is an entity that can issue certificates. This interface is
19// implemented by SelfSigned, which is an issuer that emits self-signed
20// certificates, and any other Certificate that has been created with CA(),
21// which makes this Certificate act as a CA and issue (sign) ceritficates.
22type Issuer interface {
Serge Bazanski216fe7b2021-05-21 18:36:16 +020023 // CACertificate returns the DER-encoded x509 certificate of the CA that
24 // will sign certificates when Issue is called, or nil if this is
25 // self-signing issuer.
Serge Bazanski9411f7c2021-03-10 13:12:53 +010026 CACertificate(ctx context.Context, kv clientv3.KV) ([]byte, error)
Serge Bazanski52538842021-08-11 16:22:41 +020027 // Issue will generate a certificate signed by the Issuer. The returned
28 // certificate is x509 DER-encoded.
29 Issue(ctx context.Context, req *Certificate, kv clientv3.KV) (cert []byte, err error)
Serge Bazanski9411f7c2021-03-10 13:12:53 +010030}
31
Serge Bazanski216fe7b2021-05-21 18:36:16 +020032// issueCertificate is a generic low level certificate-and-key issuance
Serge Bazanski52538842021-08-11 16:22:41 +020033// function. If ca is null, the certificate will be self-signed. The returned
34// certificate is DER-encoded
35func issueCertificate(req *Certificate, ca *x509.Certificate, caKey ed25519.PrivateKey) (cert []byte, err error) {
Serge Bazanski9411f7c2021-03-10 13:12:53 +010036 serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 127)
37 serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
38 if err != nil {
39 err = fmt.Errorf("failed to generate serial number: %w", err)
40 return
41 }
42
Serge Bazanski52538842021-08-11 16:22:41 +020043 skid, err := calculateSKID(req.PublicKey)
Serge Bazanski9411f7c2021-03-10 13:12:53 +010044 if err != nil {
Serge Bazanski52538842021-08-11 16:22:41 +020045 return nil, err
Serge Bazanski9411f7c2021-03-10 13:12:53 +010046 }
47
Serge Bazanski52538842021-08-11 16:22:41 +020048 req.Template.SerialNumber = serialNumber
49 req.Template.NotBefore = time.Now()
Serge Bazanskid7d6e022021-09-01 15:03:06 +020050 req.Template.NotAfter = UnknownNotAfter
Serge Bazanski52538842021-08-11 16:22:41 +020051 req.Template.BasicConstraintsValid = true
52 req.Template.SubjectKeyId = skid
Serge Bazanski9411f7c2021-03-10 13:12:53 +010053
Serge Bazanski216fe7b2021-05-21 18:36:16 +020054 // Set the AuthorityKeyID to the SKID of the signing certificate (or self,
55 // if self-signing).
Serge Bazanski52538842021-08-11 16:22:41 +020056 if ca != nil {
Lorenz Brun237cf402022-07-04 12:14:37 +000057 req.Template.AuthorityKeyId = ca.SubjectKeyId
Serge Bazanski9411f7c2021-03-10 13:12:53 +010058 } else {
Serge Bazanski52538842021-08-11 16:22:41 +020059 req.Template.AuthorityKeyId = req.Template.SubjectKeyId
60 ca = &req.Template
Serge Bazanski9411f7c2021-03-10 13:12:53 +010061 }
62
Serge Bazanski52538842021-08-11 16:22:41 +020063 return x509.CreateCertificate(rand.Reader, &req.Template, ca, req.PublicKey, caKey)
Serge Bazanski9411f7c2021-03-10 13:12:53 +010064}
65
66type selfSigned struct{}
67
68var (
69 // SelfSigned is an Issuer that generates self-signed certificates.
70 SelfSigned = &selfSigned{}
71)
72
73// Issue will generate a key and certificate that is self-signed.
Serge Bazanski52538842021-08-11 16:22:41 +020074func (s *selfSigned) Issue(ctx context.Context, req *Certificate, kv clientv3.KV) (cert []byte, err error) {
75 if err := req.ensureKey(ctx, kv); err != nil {
76 return nil, err
77 }
78 if req.PrivateKey == nil {
79 return nil, fmt.Errorf("cannot issue self-signed certificate without a private key")
80 }
81 return issueCertificate(req, nil, req.PrivateKey)
Serge Bazanski9411f7c2021-03-10 13:12:53 +010082}
83
84// CACertificate returns nil for self-signed issuers.
85func (s *selfSigned) CACertificate(ctx context.Context, kv clientv3.KV) ([]byte, error) {
86 return nil, nil
87}
88
89// Issue will generate a key and certificate that is signed by this
90// Certificate, if the Certificate is a CA.
Serge Bazanski52538842021-08-11 16:22:41 +020091func (c *Certificate) Issue(ctx context.Context, req *Certificate, kv clientv3.KV) (cert []byte, err error) {
92 if err := c.ensureKey(ctx, kv); err != nil {
93 return nil, fmt.Errorf("could not ensure CA %q key exists: %w", c.Name, err)
94 }
95 if err := req.ensureKey(ctx, kv); err != nil {
96 return nil, fmt.Errorf("could not subject %q key exists: %w", req.Name, err)
97 }
98 if c.PrivateKey == nil {
99 return nil, fmt.Errorf("cannot use certificate without private key as CA")
100 }
101
102 caCert, err := c.ensure(ctx, kv)
Serge Bazanski9411f7c2021-03-10 13:12:53 +0100103 if err != nil {
Serge Bazanski52538842021-08-11 16:22:41 +0200104 return nil, fmt.Errorf("could not ensure CA %q certificate exists: %w", c.Name, err)
Serge Bazanski9411f7c2021-03-10 13:12:53 +0100105 }
106
107 ca, err := x509.ParseCertificate(caCert)
108 if err != nil {
Serge Bazanski52538842021-08-11 16:22:41 +0200109 return nil, fmt.Errorf("could not parse CA certificate: %w", err)
Serge Bazanski9411f7c2021-03-10 13:12:53 +0100110 }
111 // Ensure only one level of CAs exist, and that they are created explicitly.
Serge Bazanski52538842021-08-11 16:22:41 +0200112 req.Template.IsCA = false
113 return issueCertificate(req, ca, c.PrivateKey)
Serge Bazanski9411f7c2021-03-10 13:12:53 +0100114}
115
116// CACertificate returns the DER encoded x509 form of this Certificate that
117// will be the used to issue child certificates.
118func (c *Certificate) CACertificate(ctx context.Context, kv clientv3.KV) ([]byte, error) {
Serge Bazanski52538842021-08-11 16:22:41 +0200119 return c.ensure(ctx, kv)
Serge Bazanski9411f7c2021-03-10 13:12:53 +0100120}