/* 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 }