blob: b8c2aed26878e03e3d21eab2e08ae30ec66c3b8a [file] [log] [blame] [edit]
// Copyright 2020 The Monogon Project Authors.
//
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package pki
import (
"context"
"crypto/ed25519"
"crypto/rand"
"crypto/x509"
"fmt"
"math/big"
"time"
clientv3 "go.etcd.io/etcd/client/v3"
)
// Issuer is an entity that can issue certificates. This interface is
// implemented by SelfSigned, which is an issuer that emits self-signed
// certificates, and any other Certificate that has been created with CA(),
// which makes this Certificate act as a CA and issue (sign) ceritficates.
type Issuer interface {
// CACertificate returns the DER-encoded x509 certificate of the CA that
// will sign certificates when Issue is called, or nil if this is
// self-signing issuer.
CACertificate(ctx context.Context, kv clientv3.KV) ([]byte, error)
// Issue will generate a certificate signed by the Issuer. The returned
// certificate is x509 DER-encoded.
Issue(ctx context.Context, req *Certificate, kv clientv3.KV) (cert []byte, err error)
}
// issueCertificate is a generic low level certificate-and-key issuance
// function. If ca is null, the certificate will be self-signed. The returned
// certificate is DER-encoded
func issueCertificate(req *Certificate, ca *x509.Certificate, caKey ed25519.PrivateKey) (cert []byte, err error) {
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 127)
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
if err != nil {
err = fmt.Errorf("failed to generate serial number: %w", err)
return
}
skid, err := calculateSKID(req.PublicKey)
if err != nil {
return nil, err
}
req.Template.SerialNumber = serialNumber
req.Template.NotBefore = time.Now()
req.Template.NotAfter = UnknownNotAfter
req.Template.BasicConstraintsValid = true
req.Template.SubjectKeyId = skid
// Set the AuthorityKeyID to the SKID of the signing certificate (or self,
// if self-signing).
if ca != nil {
req.Template.AuthorityKeyId = ca.SubjectKeyId
} else {
req.Template.AuthorityKeyId = req.Template.SubjectKeyId
ca = &req.Template
}
return x509.CreateCertificate(rand.Reader, &req.Template, ca, req.PublicKey, caKey)
}
type selfSigned struct{}
var (
// SelfSigned is an Issuer that generates self-signed certificates.
SelfSigned = &selfSigned{}
)
// Issue will generate a key and certificate that is self-signed.
func (s *selfSigned) Issue(ctx context.Context, req *Certificate, kv clientv3.KV) (cert []byte, err error) {
if err := req.ensureKey(ctx, kv); err != nil {
return nil, err
}
if req.PrivateKey == nil {
return nil, fmt.Errorf("cannot issue self-signed certificate without a private key")
}
return issueCertificate(req, nil, req.PrivateKey)
}
// CACertificate returns nil for self-signed issuers.
func (s *selfSigned) CACertificate(ctx context.Context, kv clientv3.KV) ([]byte, error) {
return nil, nil
}
// Issue will generate a key and certificate that is signed by this
// Certificate, if the Certificate is a CA.
func (c *Certificate) Issue(ctx context.Context, req *Certificate, kv clientv3.KV) (cert []byte, err error) {
if err := c.ensureKey(ctx, kv); err != nil {
return nil, fmt.Errorf("could not ensure CA %q key exists: %w", c.Name, err)
}
if err := req.ensureKey(ctx, kv); err != nil {
return nil, fmt.Errorf("could not subject %q key exists: %w", req.Name, err)
}
if c.PrivateKey == nil {
return nil, fmt.Errorf("cannot use certificate without private key as CA")
}
caCert, err := c.ensure(ctx, kv)
if err != nil {
return nil, fmt.Errorf("could not ensure CA %q certificate exists: %w", c.Name, err)
}
ca, err := x509.ParseCertificate(caCert)
if err != nil {
return nil, fmt.Errorf("could not parse CA certificate: %w", err)
}
// Ensure only one level of CAs exist, and that they are created explicitly.
req.Template.IsCA = false
return issueCertificate(req, ca, c.PrivateKey)
}
// CACertificate returns the DER encoded x509 form of this Certificate that
// will be the used to issue child certificates.
func (c *Certificate) CACertificate(ctx context.Context, kv clientv3.KV) ([]byte, error) {
return c.ensure(ctx, kv)
}