73 lines
1.5 KiB
Go
73 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/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[:]
|
||
|
}
|