add basic certificate support
This is the first draft of the basic certificate support. Some fields need to be shown when inspecting a certificate, but it should work fine for now.
This commit is contained in:
parent
53e4bc7425
commit
0586796bf5
|
@ -0,0 +1,70 @@
|
|||
package pkiadm
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type (
|
||||
Certificate struct {
|
||||
ID string
|
||||
|
||||
IsCA bool
|
||||
Duration time.Duration
|
||||
|
||||
PrivateKey ResourceName
|
||||
Serial ResourceName
|
||||
CSR ResourceName
|
||||
CA ResourceName
|
||||
|
||||
// Checksum is filled by the server with the checksum of the currently valid
|
||||
// certificate.
|
||||
Checksum []byte
|
||||
}
|
||||
|
||||
CertificateChange struct {
|
||||
Certificate Certificate
|
||||
FieldList []string
|
||||
}
|
||||
|
||||
ResultCertificate struct {
|
||||
Result Result
|
||||
Certificates []Certificate
|
||||
}
|
||||
)
|
||||
|
||||
// CreatePrivateKey sends a RPC request to create a new private key.
|
||||
func (c *Client) CreateCertificate(pk Certificate) error {
|
||||
return c.exec("CreateCertificate", pk)
|
||||
}
|
||||
func (c *Client) SetCertificate(pk Certificate, fieldList []string) error {
|
||||
changeset := CertificateChange{pk, fieldList}
|
||||
return c.exec("SetCertificate", changeset)
|
||||
}
|
||||
func (c *Client) DeleteCertificate(id string) error {
|
||||
pk := ResourceName{ID: id, Type: RTCertificate}
|
||||
return c.exec("DeleteCertificate", pk)
|
||||
}
|
||||
func (c *Client) ListCertificate() ([]Certificate, error) {
|
||||
result := &ResultCertificate{}
|
||||
if err := c.query("ListCertificate", Filter{}, result); err != nil {
|
||||
return []Certificate{}, err
|
||||
}
|
||||
if result.Result.HasError {
|
||||
return []Certificate{}, result.Result.Error
|
||||
}
|
||||
return result.Certificates, nil
|
||||
}
|
||||
func (c *Client) ShowCertificate(id string) (Certificate, error) {
|
||||
pk := ResourceName{ID: id, Type: RTCertificate}
|
||||
result := &ResultCertificate{}
|
||||
if err := c.query("ShowCertificate", pk, result); err != nil {
|
||||
return Certificate{}, err
|
||||
}
|
||||
if result.Result.HasError {
|
||||
return Certificate{}, result.Result.Error
|
||||
}
|
||||
for _, privateKey := range result.Certificates {
|
||||
return privateKey, nil
|
||||
}
|
||||
return Certificate{}, nil
|
||||
}
|
|
@ -0,0 +1,119 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"os"
|
||||
"text/tabwriter"
|
||||
"time"
|
||||
|
||||
"github.com/gibheer/pkiadm"
|
||||
"github.com/pkg/errors"
|
||||
flag "github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
func createCertificate(args []string, client *pkiadm.Client) error {
|
||||
fs := flag.NewFlagSet("create-cert", flag.ExitOnError)
|
||||
fs.Usage = func() {
|
||||
fmt.Printf("Usage of %s:\n", "pkiadm create-cert")
|
||||
fmt.Println(`
|
||||
This command creates a new certificate and signes it with the provided CA. If you want to buid your own CA, add the self-sign option and leave the ca option blank.
|
||||
`)
|
||||
fs.PrintDefaults()
|
||||
}
|
||||
cert := pkiadm.Certificate{}
|
||||
fs.StringVar(&cert.ID, "id", "", "set the unique id for the new certificate")
|
||||
parseCertificateArgs(fs, args, &cert)
|
||||
|
||||
if err := client.CreateCertificate(cert); err != nil {
|
||||
return errors.Wrap(err, "could not create certificate")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
func setCertificate(args []string, client *pkiadm.Client) error {
|
||||
fs := flag.NewFlagSet("set-cert", flag.ExitOnError)
|
||||
cert := pkiadm.Certificate{}
|
||||
fs.StringVar(&cert.ID, "id", "", "set the id of the certificate to change")
|
||||
parseCertificateArgs(fs, args, &cert)
|
||||
|
||||
fieldList := []string{}
|
||||
for _, field := range []string{"private", "csr", "ca", "serial", "duration", "self-sign"} {
|
||||
flag := fs.Lookup(field)
|
||||
if flag.Changed {
|
||||
fieldList = append(fieldList, field)
|
||||
}
|
||||
}
|
||||
|
||||
if err := client.SetCertificate(cert, fieldList); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func parseCertificateArgs(fs *flag.FlagSet, args []string, cert *pkiadm.Certificate) {
|
||||
pk := flag.String("private", "", "the private key id to sign the certificate sign request")
|
||||
csr := flag.String("csr", "", "the CSR to sign to get the resulting certificate")
|
||||
ca := flag.String("ca", "", "the certificate to use to sign the certificate sign request")
|
||||
serial := flag.String("serial", "", "the serial generator used to fetch a serial")
|
||||
flag.DurationVar(&cert.Duration, "duration", time.Duration(1461190656), "the time the certificate is valid (in h, m, s)") // these are 360 days
|
||||
flag.BoolVar(&cert.IsCA, "self-sign", false, "set this to true to create a self signed certificate (for CA usage)")
|
||||
fs.Parse(args)
|
||||
|
||||
cert.PrivateKey = pkiadm.ResourceName{*pk, pkiadm.RTPrivateKey}
|
||||
cert.CSR = pkiadm.ResourceName{*csr, pkiadm.RTCSR}
|
||||
cert.CA = pkiadm.ResourceName{*ca, pkiadm.RTCertificate}
|
||||
cert.Serial = pkiadm.ResourceName{*serial, pkiadm.RTSerial}
|
||||
}
|
||||
|
||||
func deleteCertificate(args []string, client *pkiadm.Client) error {
|
||||
fs := flag.NewFlagSet("delete-cert", flag.ExitOnError)
|
||||
var id = fs.String("id", "", "set the id of the private key to delete")
|
||||
fs.Parse(args)
|
||||
|
||||
if err := client.DeleteCertificate(*id); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func listCertificate(args []string, client *pkiadm.Client) error {
|
||||
fs := flag.NewFlagSet("list-cert", flag.ExitOnError)
|
||||
fs.Parse(args)
|
||||
|
||||
certs, err := client.ListCertificate()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(certs) == 0 {
|
||||
return nil
|
||||
}
|
||||
out := tabwriter.NewWriter(os.Stdout, 2, 2, 1, ' ', tabwriter.AlignRight)
|
||||
fmt.Fprintf(out, "%s\t%s\t%s\t%s\t%s\t%s\t%s\t\n", "id", "private", "csr", "ca", "serial", "duration", "self-signed")
|
||||
for _, cert := range certs {
|
||||
fmt.Fprintf(out, "%s\t%s\t%s\t%s\t%s\t%s\t%t\t\n", cert.ID, cert.PrivateKey.ID, cert.CSR.ID, cert.CA.ID, cert.Serial.ID, cert.Duration, cert.IsCA)
|
||||
}
|
||||
out.Flush()
|
||||
|
||||
return nil
|
||||
}
|
||||
func showCertificate(args []string, client *pkiadm.Client) error {
|
||||
fs := flag.NewFlagSet("show-cert", flag.ExitOnError)
|
||||
var id = fs.String("id", "", "set the id of the private key to show")
|
||||
fs.Parse(args)
|
||||
|
||||
cert, err := client.ShowCertificate(*id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
out := tabwriter.NewWriter(os.Stdout, 2, 2, 1, ' ', tabwriter.AlignRight)
|
||||
fmt.Fprintf(out, "id:\t%s\t\n", cert.ID)
|
||||
fmt.Fprintf(out, "private:\t%s\t\n", cert.PrivateKey.ID)
|
||||
fmt.Fprintf(out, "csr:\t%s\t\n", cert.CSR.ID)
|
||||
fmt.Fprintf(out, "ca:\t%s\t\n", cert.CA.ID)
|
||||
fmt.Fprintf(out, "serial:\t%s\t\n", cert.Serial.ID)
|
||||
fmt.Fprintf(out, "duration:\t%s\t\n", cert.Duration)
|
||||
fmt.Fprintf(out, "self-signed:\t%s\t\n", cert.IsCA)
|
||||
fmt.Fprintf(out, "checksum:\t%s\t\n", base64.StdEncoding.EncodeToString(cert.Checksum))
|
||||
out.Flush()
|
||||
return nil
|
||||
}
|
|
@ -2,6 +2,7 @@ package main
|
|||
|
||||
import (
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/gibheer/pki"
|
||||
|
@ -9,6 +10,10 @@ import (
|
|||
)
|
||||
|
||||
type (
|
||||
Signer interface {
|
||||
Sign(*CSR) (pki.Certificate, error)
|
||||
}
|
||||
|
||||
Certificate struct {
|
||||
ID string
|
||||
|
||||
|
@ -24,14 +29,14 @@ type (
|
|||
}
|
||||
)
|
||||
|
||||
func NewCertificate(id string, privateKey, serial, csr, ca pkiadm.ResourceName, isCA bool, duration time.Duration) (*Certificate, error) {
|
||||
func NewCertificate(id string, privateKey, serial, csr, ca pkiadm.ResourceName, selfSign bool, duration time.Duration) (*Certificate, error) {
|
||||
return &Certificate{
|
||||
ID: id,
|
||||
PrivateKey: privateKey,
|
||||
Serial: serial,
|
||||
CSR: csr,
|
||||
CA: ca,
|
||||
IsCA: isCA,
|
||||
IsCA: selfSign,
|
||||
Duration: duration,
|
||||
}, nil
|
||||
}
|
||||
|
@ -128,3 +133,118 @@ func (c *Certificate) DependsOn() []pkiadm.ResourceName {
|
|||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func (s *Server) CreateCertificate(inCert pkiadm.Certificate, res *pkiadm.Result) error {
|
||||
s.lock()
|
||||
defer s.unlock()
|
||||
|
||||
cert, err := NewCertificate(
|
||||
inCert.ID,
|
||||
inCert.PrivateKey,
|
||||
inCert.Serial,
|
||||
inCert.CSR,
|
||||
inCert.CA,
|
||||
inCert.IsCA,
|
||||
inCert.Duration,
|
||||
)
|
||||
if err != nil {
|
||||
res.SetError(err, "Could not create new certificate '%s'", inCert.ID)
|
||||
return nil
|
||||
}
|
||||
if err := s.storage.AddCertificate(cert); err != nil {
|
||||
res.SetError(err, "Could not add certificate '%s'", inCert.ID)
|
||||
return nil
|
||||
}
|
||||
return s.store(res)
|
||||
}
|
||||
|
||||
func (s *Server) SetCertificate(changeset pkiadm.CertificateChange, res *pkiadm.Result) error {
|
||||
s.lock()
|
||||
defer s.unlock()
|
||||
|
||||
cert, err := s.storage.GetCertificate(pkiadm.ResourceName{ID: changeset.Certificate.ID, Type: pkiadm.RTCertificate})
|
||||
if err != nil {
|
||||
res.SetError(err, "Could not find certficate '%s'", changeset.Certificate.ID)
|
||||
return nil
|
||||
}
|
||||
|
||||
change := changeset.Certificate
|
||||
for _, field := range changeset.FieldList {
|
||||
switch field {
|
||||
case "duration":
|
||||
cert.Duration = change.Duration
|
||||
case "private":
|
||||
cert.PrivateKey = change.PrivateKey
|
||||
case "csr":
|
||||
cert.CSR = change.CSR
|
||||
case "serial":
|
||||
cert.Serial = change.Serial
|
||||
case "ca":
|
||||
cert.CA = change.CA
|
||||
case "self-sign":
|
||||
cert.IsCA = change.IsCA
|
||||
default:
|
||||
res.SetError(fmt.Errorf("unknown field"), "unknown field '%s'", field)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
if err := s.storage.Update(cert.Name()); err != nil {
|
||||
res.SetError(err, "Could not update certificate '%s'", changeset.Certificate.ID)
|
||||
return nil
|
||||
}
|
||||
return s.store(res)
|
||||
}
|
||||
|
||||
func (s *Server) DeleteCertificate(inCert pkiadm.ResourceName, res *pkiadm.Result) error {
|
||||
s.lock()
|
||||
defer s.unlock()
|
||||
|
||||
cert, err := s.storage.GetCertificate(pkiadm.ResourceName{ID: inCert.ID, Type: pkiadm.RTCertificate})
|
||||
if err != nil {
|
||||
res.SetError(err, "Could not find certificate '%s'", inCert.ID)
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := s.storage.Remove(cert); err != nil {
|
||||
res.SetError(err, "Could not remove certificate '%s'", cert.ID)
|
||||
return nil
|
||||
}
|
||||
return s.store(res)
|
||||
}
|
||||
func (s *Server) ShowCertificate(inCert pkiadm.ResourceName, res *pkiadm.ResultCertificate) error {
|
||||
s.lock()
|
||||
defer s.unlock()
|
||||
|
||||
cert, err := s.storage.GetCertificate(pkiadm.ResourceName{ID: inCert.ID, Type: pkiadm.RTCertificate})
|
||||
if err != nil {
|
||||
res.Result.SetError(err, "Could not find certificate '%s'", inCert.ID)
|
||||
return nil
|
||||
}
|
||||
res.Certificates = []pkiadm.Certificate{pkiadm.Certificate{
|
||||
ID: cert.ID,
|
||||
Duration: cert.Duration,
|
||||
PrivateKey: cert.PrivateKey,
|
||||
Serial: cert.Serial,
|
||||
CA: cert.CA,
|
||||
CSR: cert.CSR,
|
||||
Checksum: cert.Checksum(),
|
||||
}}
|
||||
return nil
|
||||
}
|
||||
func (s *Server) ListCertificate(filter pkiadm.Filter, res *pkiadm.ResultCertificate) error {
|
||||
s.lock()
|
||||
defer s.unlock()
|
||||
|
||||
for _, cert := range s.storage.Certificates {
|
||||
res.Certificates = append(res.Certificates, pkiadm.Certificate{
|
||||
ID: cert.ID,
|
||||
Duration: cert.Duration,
|
||||
PrivateKey: cert.PrivateKey,
|
||||
Serial: cert.Serial,
|
||||
CA: cert.CA,
|
||||
CSR: cert.CSR,
|
||||
Checksum: cert.Checksum(),
|
||||
})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue