58 lines
1.5 KiB
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
|
||
|
}
|