213 lines
5.3 KiB
Go
213 lines
5.3 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/pem"
|
|
"fmt"
|
|
"net"
|
|
|
|
"github.com/gibheer/pki"
|
|
"github.com/gibheer/pkiadm"
|
|
)
|
|
|
|
type (
|
|
CSR struct {
|
|
// ID is the unique identifier of the CSR.
|
|
ID string
|
|
|
|
// The following options are used to generate the content of the CSR.
|
|
DNSNames []string
|
|
EmailAddresses []string
|
|
IPAddresses []net.IP
|
|
|
|
// PrivateKey is needed to sign the certificate sign request.
|
|
PrivateKey pkiadm.ResourceName
|
|
Subject pkiadm.ResourceName
|
|
|
|
// Data contains the pem representation of the CSR.
|
|
Data []byte
|
|
}
|
|
)
|
|
|
|
// NewCSR creates a new CSR.
|
|
func NewCSR(id string, pk, subject pkiadm.ResourceName, dnsNames []string,
|
|
emailAddresses []string, iPAddresses []net.IP) (*CSR, error) {
|
|
return &CSR{
|
|
ID: id,
|
|
Subject: subject,
|
|
DNSNames: dnsNames,
|
|
EmailAddresses: emailAddresses,
|
|
IPAddresses: iPAddresses,
|
|
PrivateKey: pk,
|
|
}, nil
|
|
}
|
|
|
|
// Return the unique ResourceName
|
|
func (c *CSR) Name() pkiadm.ResourceName {
|
|
return pkiadm.ResourceName{c.ID, pkiadm.RTCSR}
|
|
}
|
|
|
|
// AddDependency registers a depending resource to be retuened by Dependencies()
|
|
// Refresh must trigger a rebuild of the resource.
|
|
func (c *CSR) Refresh(lookup *Storage) error {
|
|
pk, err := lookup.GetPrivateKey(c.PrivateKey)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
key, err := pk.GetKey()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
subjRes, err := lookup.GetSubject(c.Subject)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
subject := subjRes.GetName()
|
|
|
|
opts := pki.CertificateData{
|
|
Subject: subject,
|
|
DNSNames: c.DNSNames,
|
|
EmailAddresses: c.EmailAddresses,
|
|
IPAddresses: c.IPAddresses,
|
|
}
|
|
csr, err := opts.ToCertificateRequest(key)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
block, err := csr.ToPem()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
block.Headers = map[string]string{"ID": c.ID}
|
|
c.Data = pem.EncodeToMemory(&block)
|
|
return nil
|
|
}
|
|
|
|
// Return the PEM output of the contained resource.
|
|
func (c *CSR) Pem() ([]byte, error) { return c.Data, nil }
|
|
func (c *CSR) Checksum() []byte { return Hash(c.Data) }
|
|
|
|
// DependsOn must return the resource names it is depending on.
|
|
func (c *CSR) DependsOn() []pkiadm.ResourceName {
|
|
return []pkiadm.ResourceName{c.PrivateKey}
|
|
}
|
|
|
|
func (c *CSR) GetCSR() (*pki.CertificateRequest, error) {
|
|
// TODO fix this, we must check if there is anything else
|
|
block, _ := pem.Decode(c.Data)
|
|
csr, err := pki.LoadCertificateSignRequest(block.Bytes)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return csr, nil
|
|
}
|
|
|
|
func (s *Server) CreateCSR(inCSR pkiadm.CSR, res *pkiadm.Result) error {
|
|
s.lock()
|
|
defer s.unlock()
|
|
|
|
csr, err := NewCSR(
|
|
inCSR.ID,
|
|
inCSR.PrivateKey,
|
|
inCSR.Subject,
|
|
inCSR.DNSNames,
|
|
inCSR.EmailAddresses,
|
|
inCSR.IPAddresses,
|
|
)
|
|
if err != nil {
|
|
res.SetError(err, "Could not create new private key '%s'", inCSR.ID)
|
|
return nil
|
|
}
|
|
if err := s.storage.AddCSR(csr); err != nil {
|
|
res.SetError(err, "Could not add private key '%s'", inCSR.ID)
|
|
return nil
|
|
}
|
|
return s.store(res)
|
|
}
|
|
func (s *Server) SetCSR(changeset pkiadm.CSRChange, res *pkiadm.Result) error {
|
|
s.lock()
|
|
defer s.unlock()
|
|
|
|
csr, err := s.storage.GetCSR(pkiadm.ResourceName{ID: changeset.CSR.ID, Type: pkiadm.RTCSR})
|
|
if err != nil {
|
|
res.SetError(err, "Could not find private key '%s'", changeset.CSR.ID)
|
|
return nil
|
|
}
|
|
|
|
change := changeset.CSR
|
|
for _, field := range changeset.FieldList {
|
|
switch field {
|
|
case "private-key":
|
|
csr.PrivateKey = change.PrivateKey
|
|
case "subject":
|
|
csr.Subject = change.Subject
|
|
case "ip":
|
|
csr.IPAddresses = change.IPAddresses
|
|
case "fqdn":
|
|
csr.DNSNames = change.DNSNames
|
|
case "mail":
|
|
csr.EmailAddresses = change.EmailAddresses
|
|
default:
|
|
res.SetError(fmt.Errorf("unknown field"), "unknown field '%s'", field)
|
|
return nil
|
|
}
|
|
}
|
|
if err := s.storage.Update(pkiadm.ResourceName{ID: csr.ID, Type: pkiadm.RTCSR}); err != nil {
|
|
res.SetError(err, "Could not update private key '%s'", changeset.CSR.ID)
|
|
return nil
|
|
}
|
|
return s.store(res)
|
|
}
|
|
func (s *Server) DeleteCSR(inCSR pkiadm.ResourceName, res *pkiadm.Result) error {
|
|
s.lock()
|
|
defer s.unlock()
|
|
|
|
csr, err := s.storage.GetCSR(pkiadm.ResourceName{ID: inCSR.ID, Type: pkiadm.RTCSR})
|
|
if err != nil {
|
|
res.SetError(err, "Could not find private key '%s'", inCSR.ID)
|
|
return nil
|
|
}
|
|
|
|
if err := s.storage.Remove(csr); err != nil {
|
|
res.SetError(err, "Could not remove private key '%s'", csr.ID)
|
|
return nil
|
|
}
|
|
return s.store(res)
|
|
}
|
|
func (s *Server) ShowCSR(inCSR pkiadm.ResourceName, res *pkiadm.ResultCSR) error {
|
|
s.lock()
|
|
defer s.unlock()
|
|
|
|
csr, err := s.storage.GetCSR(pkiadm.ResourceName{ID: inCSR.ID, Type: pkiadm.RTCSR})
|
|
if err != nil {
|
|
res.Result.SetError(err, "Could not find private key '%s'", inCSR.ID)
|
|
return nil
|
|
}
|
|
res.CSRs = []pkiadm.CSR{pkiadm.CSR{
|
|
ID: csr.ID,
|
|
Subject: csr.Subject,
|
|
PrivateKey: csr.PrivateKey,
|
|
EmailAddresses: csr.EmailAddresses,
|
|
DNSNames: csr.DNSNames,
|
|
IPAddresses: csr.IPAddresses,
|
|
Checksum: csr.Checksum(),
|
|
}}
|
|
return nil
|
|
}
|
|
func (s *Server) ListCSR(filter pkiadm.Filter, res *pkiadm.ResultCSR) error {
|
|
s.lock()
|
|
defer s.unlock()
|
|
|
|
for _, csr := range s.storage.CSRs {
|
|
res.CSRs = append(res.CSRs, pkiadm.CSR{
|
|
ID: csr.ID,
|
|
Subject: csr.Subject,
|
|
PrivateKey: csr.PrivateKey,
|
|
EmailAddresses: csr.EmailAddresses,
|
|
DNSNames: csr.DNSNames,
|
|
IPAddresses: csr.IPAddresses,
|
|
Checksum: csr.Checksum(),
|
|
})
|
|
}
|
|
return nil
|
|
}
|