rsa/pkg/ca/sign.go

58 lines
1.5 KiB
Go

/*
Package ca implements a disk file-backed certificate authority with a built-in
CRL signer. The certificate authority can issue new certificates (including the
creation of intermediate CAs) and revoke existing certificates, resulting in a
fresh CRL.
*/
package ca
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"fmt"
"os"
"path/filepath"
"src.lwithers.me.uk/go/rsa/pkg/pemfile"
"src.lwithers.me.uk/go/rsa/pkg/serial"
)
const (
auditLogDir = "audit.log"
)
func (ca *CA) Sign(template *x509.Certificate, key *rsa.PublicKey) (*x509.Certificate, string, error) {
if template.SerialNumber == nil {
template.SerialNumber = serial.Rand()
}
// sign the certificate
der, err := x509.CreateCertificate(rand.Reader, template, ca.root, key, ca.key)
if err != nil {
return nil, "",
fmt.Errorf("failed to sign certificate: %w", err)
}
// parse the just-signed certificate
cert, err := x509.ParseCertificate(der)
if err != nil {
return nil, "",
fmt.Errorf("failed to parse certificate after signing: %w", err)
}
// save the newly-signed cert in the audit log
auditDir := filepath.Join(ca.dir, auditLogDir, template.SerialNumber.Text(16))
if err := os.MkdirAll(auditDir, 0700); err != nil {
return nil, "",
fmt.Errorf("failed to create audit log directory: %w", err)
}
if err := pemfile.Write(filepath.Join(auditDir, "cert.pem"), pemfile.TypeX509Certificate, der); err != nil {
return nil, "",
fmt.Errorf("failed to save certificate in audit log: %w", err)
}
return cert, auditDir, nil
}