/* 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/rsa" "crypto/sha1" "crypto/x509" "encoding/asn1" "fmt" "path/filepath" "src.lwithers.me.uk/go/rsa/pkg/pemfile" ) type CA struct { dir string key *rsa.PrivateKey root *x509.Certificate crl *x509.RevocationList crlKey *rsa.PrivateKey crlCert *x509.Certificate } const ( rootKeyFilename = "root-key.pem" rootCertFilename = "root-cert.pem" ) // Open an existing certificate authority in the given directory. func Open(dir string) (*CA, error) { ca := &CA{ dir: dir, } var err error ca.key, err = pemfile.ReadKey(filepath.Join(dir, rootKeyFilename)) if err != nil { return nil, fmt.Errorf("while opening CA (root key): %w", err) } ca.root, err = pemfile.ReadCert(filepath.Join(dir, rootCertFilename)) if err != nil { return nil, fmt.Errorf("while opening CA (root cert): %w", err) } if err = ca.loadCRLState(); err != nil { return nil, fmt.Errorf("while opening CA (CRL state): %w", err) } return ca, nil } func (ca *CA) GetRoot() *x509.Certificate { return ca.root } func (ca *CA) GetCRLSigner() *x509.Certificate { return ca.crlCert } func (ca *CA) GetCRL() *x509.RevocationList { return ca.crl } func ComputeSubjectKeyId(key *rsa.PublicKey) []byte { der, _ := asn1.Marshal(key) h := sha1.Sum(der) return h[:] }