pkiadm/cmd/pkiadmd/ca.go

197 lines
4.5 KiB
Go

package main
import (
"log"
"github.com/gibheer/pki"
"github.com/gibheer/pkiadm"
)
var (
CASelfSign = &CA{
ID: "self-sign",
Type: pkiadm.CALocal,
}
)
type (
// CA is an instance that can sign certificates. When a certificate needs an
// update, the given CSR is signed by the CA.
// A CA can be responsible for multiple certificates to sign.
CA struct {
ID string
Type pkiadm.CAType
Certificate pkiadm.ResourceName
Interval Interval
}
)
func NewCA(id string, caType pkiadm.CAType, cert pkiadm.ResourceName) (*CA, error) {
ca := &CA{
ID: id,
Type: caType,
Certificate: cert,
}
return ca, nil
}
// Sign the certificate sign request with this CA
func (ca *CA) Sign(lookup *Storage, csr pkiadm.ResourceName, opts pki.CertificateOptions) (*pki.Certificate, error) {
var caCert *pki.Certificate
var pk pki.PrivateKey
var caCertDef *Certificate
csrRes, err := lookup.GetCSR(csr)
if err != nil {
return nil, err
}
csrIns, err := csrRes.GetCSR()
if err != nil {
return nil, err
}
if ca == CASelfSign {
pkDef, err := lookup.GetPrivateKey(csrRes.PrivateKey)
if err != nil {
return nil, err
}
pk, err = pkDef.GetKey()
if err != nil {
return nil, err
}
caCertDef = &Certificate{ID: "self-signed"}
} else {
caCertDef, err = lookup.GetCertificate(ca.Certificate)
if err != nil {
return nil, err
}
caCert, err = caCertDef.GetCertificate()
if err != nil {
return nil, err
}
pkDef, err := lookup.GetPrivateKey(caCertDef.PrivateKey)
if err != nil {
return nil, err
}
pk, err = pkDef.GetKey()
if err != nil {
return nil, err
}
}
log.Printf("ca '%s' signing csr '%s' using cert '%s'", ca.ID, csr.ID, caCertDef.ID)
return csrIns.ToCertificate(pk, opts, caCert)
}
// Return the unique ResourceName
func (ca *CA) Name() pkiadm.ResourceName {
return pkiadm.ResourceName{ca.ID, pkiadm.RTCA}
}
// Refresh must trigger a rebuild of the resource. In this case, this is a NOOP.
func (ca *CA) Refresh(*Storage) error {
return nil
}
// RefreshInterval returns the dates and interval settings which are used to
// decide when to trigger a refresh for the resource.
// For CAs, this is a NOOP, as the underlying cert needs the refresh.
func (ca *CA) RefreshInterval() Interval {
return NoInterval
}
// Return the PEM output of the contained resource.
func (ca *CA) Pem() ([]byte, error) { return []byte{}, nil }
func (ca *CA) Checksum() []byte { return []byte{} }
// DependsOn must return the resource names it is depending on.
func (ca *CA) DependsOn() []pkiadm.ResourceName {
return []pkiadm.ResourceName{
ca.Certificate,
}
}
func (s *Server) CreateCA(inCA pkiadm.CA, res *pkiadm.Result) error {
s.lock()
defer s.unlock()
ca, err := NewCA(inCA.ID, inCA.Type, inCA.Certificate)
if err != nil {
res.SetError(err, "could not create CA '%s'", inCA.ID)
return nil
}
if err := s.storage.AddCA(ca); err != nil {
res.SetError(err, "could not add CA '%s'", inCA.ID)
return nil
}
return s.store(res)
}
func (s *Server) SetCA(change pkiadm.CAChange, res *pkiadm.Result) error {
s.lock()
defer s.unlock()
ca, err := s.storage.GetCA(pkiadm.ResourceName{ID: change.CA.ID, Type: pkiadm.RTCA})
if err != nil {
res.SetError(err, "could not find CA '%s'", change.CA.ID)
return nil
}
for _, field := range change.FieldList {
switch field {
case "type":
ca.Type = change.CA.Type
case "certificate":
ca.Certificate = change.CA.Certificate
}
}
return s.store(res)
}
func (s *Server) DeleteCA(inCA pkiadm.CA, res *pkiadm.Result) error {
s.lock()
defer s.unlock()
ca, err := s.storage.GetCA(pkiadm.ResourceName{inCA.ID, pkiadm.RTCA})
if err != nil {
res.SetError(err, "Could not find ca '%s'", ca.ID)
return nil
}
if err := s.storage.Remove(ca); err != nil {
res.SetError(err, "Could not remove ca '%s'", ca.ID)
return nil
}
return s.store(res)
}
func (s *Server) ShowCA(inCA pkiadm.CA, res *pkiadm.ResultCA) error {
s.lock()
defer s.unlock()
ca, err := s.storage.GetCA(pkiadm.ResourceName{ID: inCA.ID, Type: pkiadm.RTCA})
if err != nil {
res.Result.SetError(err, "Could not find CA '%s'", inCA.ID)
return nil
}
res.CAs = []pkiadm.CA{pkiadm.CA{
ID: ca.ID,
Type: ca.Type,
Certificate: ca.Certificate,
}}
return nil
}
func (s *Server) ListCA(filter pkiadm.Filter, res *pkiadm.ResultCA) error {
s.lock()
defer s.unlock()
for _, ca := range s.storage.CAs {
res.CAs = append(res.CAs, pkiadm.CA{
ID: ca.ID,
Type: ca.Type,
Certificate: ca.Certificate,
})
}
return nil
}