From 85d38439688b6b3ff5ca6c740d0f7f88fcd0dafa Mon Sep 17 00:00:00 2001 From: Mariano Cano Date: Wed, 20 Nov 2019 19:11:54 -0800 Subject: [PATCH] Add Identity helpers. --- ca/client.go | 39 +++++++++++++++++++++++++++++++++++++++ ca/identity.go | 15 +++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/ca/client.go b/ca/client.go index 6c288ee2..bf26e4c5 100644 --- a/ca/client.go +++ b/ca/client.go @@ -26,6 +26,7 @@ import ( "github.com/smallstep/certificates/authority" "github.com/smallstep/certificates/authority/provisioner" "github.com/smallstep/cli/config" + "github.com/smallstep/cli/crypto/keys" "github.com/smallstep/cli/crypto/x509util" "golang.org/x/net/http2" "gopkg.in/square/go-jose.v2/jwt" @@ -1033,6 +1034,44 @@ func CreateSignRequest(ott string) (*api.SignRequest, crypto.PrivateKey, error) }, pk, nil } +// CreateCertificateRequest creates a new CSR with the given common name and +// SANs. If no san is provided the commonName will set also a SAN. +func CreateCertificateRequest(commonName string, sans ...string) (*api.CertificateRequest, crypto.PrivateKey, error) { + key, err := keys.GenerateDefaultKey() + if err != nil { + return nil, nil, err + } + return createCertificateRequest(commonName, sans, key) +} + +func createCertificateRequest(commonName string, sans []string, key crypto.PrivateKey) (*api.CertificateRequest, crypto.PrivateKey, error) { + if len(sans) == 0 { + sans = []string{commonName} + } + dnsNames, ips, emails := x509util.SplitSANs(sans) + template := &x509.CertificateRequest{ + Subject: pkix.Name{ + CommonName: commonName, + }, + DNSNames: dnsNames, + IPAddresses: ips, + EmailAddresses: emails, + } + csr, err := x509.CreateCertificateRequest(rand.Reader, template, key) + if err != nil { + return nil, nil, err + } + cr, err := x509.ParseCertificateRequest(csr) + if err != nil { + return nil, nil, err + } + if err := cr.CheckSignature(); err != nil { + return nil, nil, err + } + + return &api.CertificateRequest{CertificateRequest: cr}, key, nil +} + func getInsecureClient() *http.Client { return &http.Client{ Transport: &http.Transport{ diff --git a/ca/identity.go b/ca/identity.go index f7f37049..1d3699c6 100644 --- a/ca/identity.go +++ b/ca/identity.go @@ -40,6 +40,21 @@ type Identity struct { Key string `json:"key"` } +// NewIdentityRequest returns a new CSR to create the identity. If an identity +// was already present it reuses the private key. +func NewIdentityRequest(commonName string, sans ...string) (*api.CertificateRequest, crypto.PrivateKey, error) { + var identityKey crypto.PrivateKey + if i, err := LoadDefaultIdentity(); err == nil && i.Key != "" { + if k, err := pemutil.Read(i.Key); err == nil { + identityKey = k + } + } + if identityKey == nil { + return CreateCertificateRequest(commonName, sans...) + } + return createCertificateRequest(commonName, sans, identityKey) +} + // LoadDefaultIdentity loads the default identity. func LoadDefaultIdentity() (*Identity, error) { b, err := ioutil.ReadFile(IdentityFile)