mirror of
https://github.com/openziti/ziti.git
synced 2026-10-23 20:26:05 +00:00
Merge pull request #1226 from openziti/add.pki.ec.support.65
fixed #65 adds EC generation support to the PKI sub command
This commit is contained in:
@@ -13,7 +13,6 @@ require (
|
||||
github.com/go-openapi/runtime v0.26.0
|
||||
github.com/go-openapi/strfmt v0.21.7
|
||||
github.com/go-resty/resty/v2 v2.7.0
|
||||
github.com/golang/protobuf v1.5.3
|
||||
github.com/google/go-cmp v0.5.9
|
||||
github.com/gorilla/websocket v1.5.0
|
||||
github.com/jedib0t/go-pretty/v6 v6.4.0
|
||||
@@ -89,6 +88,7 @@ require (
|
||||
github.com/go-openapi/swag v0.22.4 // indirect
|
||||
github.com/go-openapi/validate v0.22.1 // indirect
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/gomarkdown/markdown v0.0.0-20230322041520-c84983bdbf2a // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/gorilla/handlers v1.5.1 // indirect
|
||||
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/pem"
|
||||
@@ -200,10 +201,27 @@ func generateCert(options *verifyCaOptions, token string) ([]byte, crypto.Signer
|
||||
}
|
||||
|
||||
var caKey crypto.Signer
|
||||
if caPrivateKeyBlock.Type == "EC PRIVATE KEY" {
|
||||
|
||||
switch caPrivateKeyBlock.Type {
|
||||
case "EC PRIVATE KEY":
|
||||
caKey, err = x509.ParseECPrivateKey(caPrivateKeyBlock.Bytes)
|
||||
} else {
|
||||
case "RSA PRIVATE KEY":
|
||||
caKey, err = x509.ParsePKCS1PrivateKey(caPrivateKeyBlock.Bytes)
|
||||
case "PRIVATE KEY":
|
||||
key, err := x509.ParsePKCS8PrivateKey(caPrivateKeyBlock.Bytes)
|
||||
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("could not parse PKCS8 key file (%s)", err)
|
||||
}
|
||||
|
||||
switch typedKey := key.(type) {
|
||||
case *rsa.PrivateKey:
|
||||
caKey = typedKey
|
||||
case *ecdsa.PrivateKey:
|
||||
caKey = typedKey
|
||||
default:
|
||||
return nil, nil, fmt.Errorf("unsupported private key parsed from PKCS8 %T", typedKey)
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
||||
@@ -181,7 +181,7 @@ func (s *AccountsStorage) GetPrivateKey(keyType certcrypto.KeyType) crypto.Priva
|
||||
|
||||
privateKey, err := loadPrivateKey(accKeyPath)
|
||||
if err != nil {
|
||||
log.Fatalf("Could not load RSA private key from file %s: %v", accKeyPath, err)
|
||||
log.Fatalf("Could not load private key from file %s: %v", accKeyPath, err)
|
||||
}
|
||||
|
||||
return privateKey
|
||||
@@ -227,6 +227,8 @@ func loadPrivateKey(file string) (crypto.PrivateKey, error) {
|
||||
return x509.ParsePKCS1PrivateKey(keyBlock.Bytes)
|
||||
case "EC PRIVATE KEY":
|
||||
return x509.ParseECPrivateKey(keyBlock.Bytes)
|
||||
case "PRIVATE KEY":
|
||||
return x509.ParsePKCS8PrivateKey(keyBlock.Bytes)
|
||||
}
|
||||
|
||||
return nil, errors.New("unknown private key type")
|
||||
|
||||
+2
-1
@@ -43,7 +43,7 @@ type PKIFlags struct {
|
||||
CAName string
|
||||
CommonName string
|
||||
CAExpire int
|
||||
CAMaxpath int
|
||||
CAMaxPath int
|
||||
CAPrivateKeySize int
|
||||
IntermediateFile string
|
||||
IntermediateName string
|
||||
@@ -61,6 +61,7 @@ type PKIFlags struct {
|
||||
PKI *pki.ZitiPKI
|
||||
SpiffeID string
|
||||
AllowOverwrite bool
|
||||
EcCurve string
|
||||
}
|
||||
|
||||
var (
|
||||
|
||||
+108
-59
@@ -17,12 +17,14 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"crypto/elliptic"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"errors"
|
||||
"fmt"
|
||||
cmdhelper "github.com/openziti/ziti/ziti/cmd/helpers"
|
||||
"github.com/openziti/ziti/ziti/pki/pki"
|
||||
"github.com/openziti/ziti/ziti/util"
|
||||
"io"
|
||||
"net"
|
||||
@@ -119,111 +121,111 @@ func (o *PKICreateOptions) Run() error {
|
||||
|
||||
// ObtainPKIRoot returns the value for pki-root
|
||||
func (o *PKICreateOptions) ObtainPKIRoot() (string, error) {
|
||||
pkiroot := o.Flags.PKIRoot
|
||||
if pkiroot == "" {
|
||||
pkiroot = viper.GetString("pki-root")
|
||||
if pkiroot == "" {
|
||||
pkiRoot := o.Flags.PKIRoot
|
||||
if pkiRoot == "" {
|
||||
pkiRoot = viper.GetString("pki-root")
|
||||
if pkiRoot == "" {
|
||||
pkiRootDir, err := util.PKIRootDir()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
pkiroot, err = util.PickValue("Required flag 'pki-root' not specified; Enter PKI Root now:", pkiRootDir, true)
|
||||
pkiRoot, err = util.PickValue("Required flag 'pki-root' not specified; Enter PKI Root now:", pkiRootDir, true)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
}
|
||||
return pkiroot, nil
|
||||
return pkiRoot, nil
|
||||
}
|
||||
|
||||
// ObtainCAFile returns the value for ca-file
|
||||
func (o *PKICreateOptions) ObtainCAFile() (string, error) {
|
||||
cafile := o.Flags.CAFile
|
||||
if cafile == "" {
|
||||
cafile = viper.GetString("ca-file")
|
||||
if cafile == "" {
|
||||
caFile := o.Flags.CAFile
|
||||
if caFile == "" {
|
||||
caFile = viper.GetString("ca-file")
|
||||
if caFile == "" {
|
||||
var err error
|
||||
cafile, err = util.PickValue("Required flag 'ca-file' not specified; Enter CA name now:", "ca", true)
|
||||
caFile, err = util.PickValue("Required flag 'ca-file' not specified; Enter CA name now:", "ca", true)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
}
|
||||
return cafile, nil
|
||||
return caFile, nil
|
||||
}
|
||||
|
||||
// ObtainIntermediateCAFile returns the value for intermediate-file
|
||||
func (o *PKICreateOptions) ObtainIntermediateCAFile() (string, error) {
|
||||
intermediatefile := o.Flags.IntermediateFile
|
||||
if intermediatefile == "" {
|
||||
intermediatefile = viper.GetString("intermediate-file")
|
||||
if intermediatefile == "" {
|
||||
intermediateFile := o.Flags.IntermediateFile
|
||||
if intermediateFile == "" {
|
||||
intermediateFile = viper.GetString("intermediate-file")
|
||||
if intermediateFile == "" {
|
||||
var err error
|
||||
intermediatefile, err = util.PickValue("Required flag 'intermediate-file' not specified; Enter Intermediate CA name now:", "intermediate", true)
|
||||
intermediateFile, err = util.PickValue("Required flag 'intermediate-file' not specified; Enter Intermediate CA name now:", "intermediate", true)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
}
|
||||
return intermediatefile, nil
|
||||
return intermediateFile, nil
|
||||
}
|
||||
|
||||
// ObtainIntermediateCSRFile returns the value for intermediate-file
|
||||
func (o *PKICreateOptions) ObtainIntermediateCSRFile() (string, error) {
|
||||
intermediatecsrfile := viper.GetString("intermediate-csr-file")
|
||||
if intermediatecsrfile == "" {
|
||||
intermediateCsrFile := viper.GetString("intermediate-csr-file")
|
||||
if intermediateCsrFile == "" {
|
||||
var err error
|
||||
intermediatecsrfile, err = util.PickValue("Required flag 'intermediate--csr-file' not specified; Enter Intermediate CSR file name now:", "intermediate-csr", true)
|
||||
intermediateCsrFile, err = util.PickValue("Required flag 'intermediate--csr-file' not specified; Enter Intermediate CSR file name now:", "intermediate-csr", true)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
return intermediatecsrfile, nil
|
||||
return intermediateCsrFile, nil
|
||||
}
|
||||
|
||||
// ObtainCSRFile returns the value for csr-file
|
||||
func (o *PKICreateOptions) ObtainCSRFile() (string, error) {
|
||||
csrfile := viper.GetString("csr-file")
|
||||
if csrfile == "" {
|
||||
csrFile := viper.GetString("csr-file")
|
||||
if csrFile == "" {
|
||||
var err error
|
||||
csrfile, err = util.PickValue("Required flag 'csr-file' not specified; Enter CSR name now:", "csr", true)
|
||||
csrFile, err = util.PickValue("Required flag 'csr-file' not specified; Enter CSR name now:", "csr", true)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
return csrfile, nil
|
||||
return csrFile, nil
|
||||
}
|
||||
|
||||
// ObtainServerCertFile returns the value for server-file
|
||||
func (o *PKICreateOptions) ObtainServerCertFile() (string, error) {
|
||||
serverfile := o.Flags.ServerFile
|
||||
if serverfile == "" {
|
||||
serverfile = viper.GetString("server-file")
|
||||
if serverfile == "" {
|
||||
serverFile := o.Flags.ServerFile
|
||||
if serverFile == "" {
|
||||
serverFile = viper.GetString("server-file")
|
||||
if serverFile == "" {
|
||||
var err error
|
||||
serverfile, err = util.PickValue("Required flag 'server-file' not specified; Enter name now:", "server", true)
|
||||
serverFile, err = util.PickValue("Required flag 'server-file' not specified; Enter name now:", "server", true)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
}
|
||||
return serverfile, nil
|
||||
return serverFile, nil
|
||||
}
|
||||
|
||||
// ObtainClientCertFile returns the value for client-file
|
||||
func (o *PKICreateOptions) ObtainClientCertFile() (string, error) {
|
||||
clientfile := o.Flags.ClientFile
|
||||
if clientfile == "" {
|
||||
clientfile = viper.GetString("client-file")
|
||||
if clientfile == "" {
|
||||
clientFile := o.Flags.ClientFile
|
||||
if clientFile == "" {
|
||||
clientFile = viper.GetString("client-file")
|
||||
if clientFile == "" {
|
||||
var err error
|
||||
clientfile, err = util.PickValue("Required flag 'client-file' not specified; Enter name now:", "client", true)
|
||||
clientFile, err = util.PickValue("Required flag 'client-file' not specified; Enter name now:", "client", true)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
}
|
||||
return clientfile, nil
|
||||
return clientFile, nil
|
||||
}
|
||||
|
||||
// ObtainKeyFile returns the value for key-file
|
||||
@@ -245,13 +247,13 @@ func (o *PKICreateOptions) ObtainKeyFile(required bool) (string, error) {
|
||||
}
|
||||
|
||||
// ObtainCAName returns the value for ca-name
|
||||
func (o *PKICreateOptions) ObtainCAName(pkiroot string) (string, error) {
|
||||
caname := o.Flags.CAName
|
||||
if caname == "" {
|
||||
caname = viper.GetString("ca-name")
|
||||
if caname == "" {
|
||||
func (o *PKICreateOptions) ObtainCAName(pkiRoot string) (string, error) {
|
||||
caName := o.Flags.CAName
|
||||
if caName == "" {
|
||||
caName = viper.GetString("ca-name")
|
||||
if caName == "" {
|
||||
var err error
|
||||
files, err := os.ReadDir(pkiroot)
|
||||
files, err := os.ReadDir(pkiRoot)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -263,14 +265,14 @@ func (o *PKICreateOptions) ObtainCAName(pkiroot string) (string, error) {
|
||||
}
|
||||
}
|
||||
}
|
||||
caname, err = util.PickName(names, "Required flag 'ca-name' not specified; choose from below (dirs seen in your ZITI_PKI_ROOT):")
|
||||
caName, err = util.PickName(names, "Required flag 'ca-name' not specified; choose from below (dirs seen in your ZITI_PKI_ROOT):")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
}
|
||||
fmt.Println("Using CA name: ", caname)
|
||||
return caname, nil
|
||||
fmt.Println("Using CA name: ", caName)
|
||||
return caName, nil
|
||||
}
|
||||
|
||||
// ObtainCommonName returns the value for CN
|
||||
@@ -290,9 +292,9 @@ func (o *PKICreateOptions) ObtainCommonName() (string, error) {
|
||||
}
|
||||
|
||||
// ObtainFileName returns the value for the 'name' used in the PKI request
|
||||
func (o *PKICreateOptions) ObtainFileName(cafile string, commonName string) string {
|
||||
func (o *PKICreateOptions) ObtainFileName(caFile string, commonName string) string {
|
||||
var filename string
|
||||
if filename = cafile; len(cafile) == 0 {
|
||||
if filename = caFile; len(caFile) == 0 {
|
||||
filename = strings.Replace(commonName, " ", "_", -1)
|
||||
filename = strings.Replace(filename, "*", "wildcard", -1)
|
||||
}
|
||||
@@ -322,18 +324,18 @@ func (o *PKICreateOptions) ObtainPKIRequestTemplate(commonName string) *x509.Cer
|
||||
template := &x509.Certificate{
|
||||
Subject: subject,
|
||||
NotAfter: time.Now().AddDate(0, 0, o.Flags.CAExpire),
|
||||
MaxPathLen: o.Flags.CAMaxpath,
|
||||
MaxPathLen: o.Flags.CAMaxPath,
|
||||
}
|
||||
|
||||
return template
|
||||
}
|
||||
|
||||
// ObtainKeyName returns the private key from the key-file
|
||||
func (o *PKICreateOptions) ObtainKeyName(pkiroot string) (string, error) {
|
||||
keyname := viper.GetString("key-name")
|
||||
if keyname == "" {
|
||||
func (o *PKICreateOptions) ObtainKeyName(pkiRoot string) (string, error) {
|
||||
keyName := viper.GetString("key-name")
|
||||
if keyName == "" {
|
||||
var err error
|
||||
files, err := os.ReadDir(pkiroot)
|
||||
files, err := os.ReadDir(pkiRoot)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -343,13 +345,13 @@ func (o *PKICreateOptions) ObtainKeyName(pkiroot string) (string, error) {
|
||||
names = append(names, f.Name())
|
||||
}
|
||||
}
|
||||
keyname, err = util.PickName(names, "Required flag 'key-name' not specified; choose from below (dirs seen in your ZITI_PKI_ROOT):")
|
||||
keyName, err = util.PickName(names, "Required flag 'key-name' not specified; choose from below (dirs seen in your ZITI_PKI_ROOT):")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
return keyname, nil
|
||||
return keyName, nil
|
||||
}
|
||||
|
||||
// ObtainPKICSRRequestTemplate returns the CSR 'template' used in the PKI request
|
||||
@@ -380,8 +382,7 @@ func (o *PKICreateOptions) ObtainPKICSRRequestTemplate(commonName string) *x509.
|
||||
val, _ := asn1.Marshal(basicConstraints{true, 0})
|
||||
|
||||
csrTemplate := &x509.CertificateRequest{
|
||||
Subject: subject,
|
||||
SignatureAlgorithm: x509.SHA512WithRSA,
|
||||
Subject: subject,
|
||||
ExtraExtensions: []pkix.Extension{
|
||||
{
|
||||
Id: asn1.ObjectIdentifier{2, 5, 29, 19},
|
||||
@@ -394,7 +395,7 @@ func (o *PKICreateOptions) ObtainPKICSRRequestTemplate(commonName string) *x509.
|
||||
return csrTemplate
|
||||
}
|
||||
|
||||
// ObtainIPsAndDNSNames returns the IP addrs and/or DNS names used in the PKI request template
|
||||
// ObtainIPsAndDNSNames returns the IP address and/or DNS names used in the PKI request template
|
||||
func (o *PKICreateOptions) ObtainIPsAndDNSNames() ([]net.IP, []string, error) {
|
||||
|
||||
if (len(o.Flags.IP) == 0) && (len(o.Flags.DNSName) == 0) {
|
||||
@@ -410,3 +411,51 @@ func (o *PKICreateOptions) ObtainIPsAndDNSNames() ([]net.IP, []string, error) {
|
||||
|
||||
return IPs, o.Flags.DNSName, nil
|
||||
}
|
||||
|
||||
// ObtainPrivateKeyOptions returns the private key options necessary to generate a private key
|
||||
func (o *PKICreateOptions) ObtainPrivateKeyOptions() (pki.PrivateKeyOptions, error) {
|
||||
isEc := o.Flags.EcCurve != ""
|
||||
|
||||
if isEc {
|
||||
return o.obtainEcOptions()
|
||||
}
|
||||
|
||||
return o.obtainRsaOptions()
|
||||
}
|
||||
|
||||
func (o *PKICreateOptions) obtainEcOptions() (pki.PrivateKeyOptions, error) {
|
||||
target := strings.Replace(strings.ToLower(o.Flags.EcCurve), "-", "", -1)
|
||||
|
||||
validCurves := []elliptic.Curve{
|
||||
elliptic.P224(),
|
||||
elliptic.P256(),
|
||||
elliptic.P384(),
|
||||
elliptic.P521(),
|
||||
}
|
||||
for _, validCurve := range validCurves {
|
||||
curCurveName := strings.Replace(strings.ToLower(validCurve.Params().Name), "-", "", -1)
|
||||
|
||||
if curCurveName == target {
|
||||
return &pki.EcPrivateKeyOptions{
|
||||
Curve: validCurve,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
validCurveString := ""
|
||||
|
||||
for _, validCurve := range validCurves {
|
||||
if validCurveString != "" {
|
||||
validCurveString = validCurveString + ", "
|
||||
}
|
||||
|
||||
validCurveString = validCurveString + strings.Replace(validCurve.Params().Name, "-", "", -1)
|
||||
}
|
||||
return nil, fmt.Errorf("unknown curve name '%s', valid curves (case and dash insensitive) %s", o.Flags.EcCurve, validCurveString)
|
||||
}
|
||||
|
||||
func (o *PKICreateOptions) obtainRsaOptions() (pki.PrivateKeyOptions, error) {
|
||||
return &pki.RsaPrivateKeyOptions{
|
||||
Size: o.Flags.CAPrivateKeySize,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/openziti/fabric/controller/idgen"
|
||||
cmdhelper "github.com/openziti/ziti/ziti/cmd/helpers"
|
||||
"github.com/openziti/ziti/ziti/internal/log"
|
||||
@@ -70,23 +71,24 @@ func (o *PKICreateCAOptions) addPKICreateCAFlags(cmd *cobra.Command) {
|
||||
cmd.Flags().StringVarP(&o.Flags.CAFile, "ca-file", "", "", "Dir/File name (within PKI_ROOT) in which to store new CA")
|
||||
cmd.Flags().StringVarP(&o.Flags.CAName, FlagCaName, "", "NetFoundry Inc. Certificate Authority", "Name of CA")
|
||||
cmd.Flags().IntVarP(&o.Flags.CAExpire, "expire-limit", "", 3650, "Expiration limit in days")
|
||||
cmd.Flags().IntVarP(&o.Flags.CAMaxpath, "max-path-len", "", -1, "Intermediate maximum path length")
|
||||
cmd.Flags().IntVarP(&o.Flags.CAPrivateKeySize, "private-key-size", "", 4096, "Size of the private key")
|
||||
cmd.Flags().IntVarP(&o.Flags.CAMaxPath, "max-path-len", "", -1, "Intermediate maximum path length")
|
||||
cmd.Flags().IntVarP(&o.Flags.CAPrivateKeySize, "private-key-size", "", 4096, "Size of the RSA private key, ignored if -curve is set")
|
||||
cmd.Flags().StringVarP(&o.Flags.EcCurve, "curve", "", "", "If set an EC private key is generated and -private-key-size is ignored, options: P224, P256, P384, P521")
|
||||
cmd.Flags().StringVar(&o.Flags.SpiffeID, "trust-domain", "", "An optional spiffe trust domain. spiffe:// will be automatically prefixed, if not provided")
|
||||
}
|
||||
|
||||
// Run implements this command
|
||||
func (o *PKICreateCAOptions) Run() error {
|
||||
pkiroot, err := o.ObtainPKIRoot()
|
||||
pkiRoot, err := o.ObtainPKIRoot()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o.Flags.PKI = &pki.ZitiPKI{Store: &store.Local{}}
|
||||
local := o.Flags.PKI.Store.(*store.Local)
|
||||
local.Root = pkiroot
|
||||
local.Root = pkiRoot
|
||||
|
||||
cafile, err := o.ObtainCAFile()
|
||||
caFile, err := o.ObtainCAFile()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -98,7 +100,7 @@ func (o *PKICreateCAOptions) Run() error {
|
||||
|
||||
commonName := o.Flags.CAName
|
||||
|
||||
filename := o.ObtainFileName(cafile, commonName)
|
||||
filename := o.ObtainFileName(caFile, commonName)
|
||||
template := o.ObtainPKIRequestTemplate(commonName)
|
||||
|
||||
template.IsCA = true
|
||||
@@ -114,13 +116,19 @@ func (o *PKICreateCAOptions) Run() error {
|
||||
template.URIs = append(template.URIs, spiffeId)
|
||||
}
|
||||
|
||||
privateKeyOptions, err := o.ObtainPrivateKeyOptions()
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not resolve private key options: %w", err)
|
||||
}
|
||||
|
||||
var signer *certificate.Bundle
|
||||
|
||||
req := &pki.Request{
|
||||
Name: filename,
|
||||
Template: template,
|
||||
IsClientCertificate: false,
|
||||
PrivateKeySize: o.Flags.CAPrivateKeySize,
|
||||
PrivateKeyOptions: privateKeyOptions,
|
||||
}
|
||||
|
||||
if err = o.Flags.PKI.Sign(signer, req); err != nil {
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/openziti/fabric/controller/idgen"
|
||||
cmdhelper "github.com/openziti/ziti/ziti/cmd/helpers"
|
||||
"github.com/openziti/ziti/ziti/internal/log"
|
||||
@@ -73,21 +74,22 @@ func (o *PKICreateClientOptions) addPKICreateClientFlags(cmd *cobra.Command) {
|
||||
cmd.Flags().StringVarP(&o.Flags.ClientName, FlagCaClientName, "", "NetFoundry Inc. Client", "Common Name (CN) to use for new Client certificate")
|
||||
cmd.Flags().StringSliceVar(&o.Flags.Email, "email", []string{}, "Email addr(s) to add to Subject Alternate Name (SAN) for new Client certificate")
|
||||
cmd.Flags().IntVarP(&o.Flags.CAExpire, "expire-limit", "", 365, "Expiration limit in days")
|
||||
cmd.Flags().IntVarP(&o.Flags.CAMaxpath, "max-path-len", "", -1, "Intermediate maximum path length")
|
||||
cmd.Flags().IntVarP(&o.Flags.CAPrivateKeySize, "private-key-size", "", 2048, "Size of the private key")
|
||||
cmd.Flags().IntVarP(&o.Flags.CAMaxPath, "max-path-len", "", -1, "Intermediate maximum path length")
|
||||
cmd.Flags().IntVarP(&o.Flags.CAPrivateKeySize, "private-key-size", "", 4096, "Size of the RSA private key, ignored if -curve is set")
|
||||
cmd.Flags().StringVarP(&o.Flags.EcCurve, "curve", "", "", "If set an EC private key is generated and -private-key-size is ignored, options: P224, P256, P384, P521")
|
||||
cmd.Flags().StringVar(&o.Flags.SpiffeID, "spiffe-id", "", "Optionally provide the path portion of a SPIFFE id. The trust domain will be taken from the signing certificate.")
|
||||
}
|
||||
|
||||
// Run implements this command
|
||||
func (o *PKICreateClientOptions) Run() error {
|
||||
pkiroot, err := o.ObtainPKIRoot()
|
||||
pkiRoot, err := o.ObtainPKIRoot()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o.Flags.PKI = &pki.ZitiPKI{Store: &store.Local{}}
|
||||
local := o.Flags.PKI.Store.(*store.Local)
|
||||
local.Root = pkiroot
|
||||
local.Root = pkiRoot
|
||||
|
||||
if !o.Cmd.Flags().Changed(FlagCaClientName) {
|
||||
o.Flags.ClientName = o.Flags.ClientName + " " + idgen.New()
|
||||
@@ -108,7 +110,7 @@ func (o *PKICreateClientOptions) Run() error {
|
||||
|
||||
var signer *certificate.Bundle
|
||||
|
||||
caname, err := o.ObtainCAName(pkiroot)
|
||||
caName, err := o.ObtainCAName(pkiRoot)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -118,7 +120,7 @@ func (o *PKICreateClientOptions) Run() error {
|
||||
return err
|
||||
}
|
||||
|
||||
signer, err = o.Flags.PKI.GetCA(caname)
|
||||
signer, err = o.Flags.PKI.GetCA(caName)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "cannot locate signer")
|
||||
}
|
||||
@@ -143,12 +145,18 @@ func (o *PKICreateClientOptions) Run() error {
|
||||
template.URIs = append(template.URIs, &spiffId)
|
||||
}
|
||||
|
||||
privateKeyOptions, err := o.ObtainPrivateKeyOptions()
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not resolve private key options: %w", err)
|
||||
}
|
||||
|
||||
req := &pki.Request{
|
||||
Name: filename,
|
||||
KeyName: keyFile,
|
||||
Template: template,
|
||||
IsClientCertificate: true,
|
||||
PrivateKeySize: o.Flags.CAPrivateKeySize,
|
||||
PrivateKeyOptions: privateKeyOptions,
|
||||
}
|
||||
|
||||
if err := o.Flags.PKI.Sign(signer, req); err != nil {
|
||||
|
||||
@@ -64,28 +64,27 @@ func (o *PKICreateCSROptions) addPKICreateCSRFlags(cmd *cobra.Command) {
|
||||
cmd.Flags().StringVarP(&o.Flags.CSRName, "csr-name", "", "NetFoundry Inc. CSR", "Name of CSR")
|
||||
cmd.Flags().StringVarP(&o.Flags.KeyName, "key-name", "", "", "Name of file that contains private key for CSR")
|
||||
cmd.Flags().IntVarP(&o.Flags.CAExpire, "expire-limit", "", 365, "Expiration limit in days")
|
||||
cmd.Flags().IntVarP(&o.Flags.CAMaxpath, "max-path-len", "", -1, "Intermediate maximum path length")
|
||||
cmd.Flags().IntVarP(&o.Flags.CAPrivateKeySize, "private-key-size", "", 4096, "Size of the private key")
|
||||
cmd.Flags().IntVarP(&o.Flags.CAMaxPath, "max-path-len", "", -1, "Intermediate maximum path length")
|
||||
}
|
||||
|
||||
// Run implements this command
|
||||
func (o *PKICreateCSROptions) Run() error {
|
||||
|
||||
pkiroot, err := o.ObtainPKIRoot()
|
||||
pkiRoot, err := o.ObtainPKIRoot()
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s", err)
|
||||
}
|
||||
|
||||
o.Flags.PKI = &pki.ZitiPKI{Store: &store.Local{}}
|
||||
local := o.Flags.PKI.Store.(*store.Local)
|
||||
local.Root = pkiroot
|
||||
local.Root = pkiRoot
|
||||
|
||||
csrfile, err := o.ObtainCSRFile()
|
||||
csrFile, err := o.ObtainCSRFile()
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s", err)
|
||||
}
|
||||
|
||||
keyname, err := o.ObtainKeyName(pkiroot)
|
||||
keyName, err := o.ObtainKeyName(pkiRoot)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s", err)
|
||||
}
|
||||
@@ -93,13 +92,13 @@ func (o *PKICreateCSROptions) Run() error {
|
||||
commonName := o.Flags.CSRName
|
||||
template := o.ObtainPKICSRRequestTemplate(commonName)
|
||||
|
||||
key, err := o.Flags.PKI.GetPrivateKey(keyname, keyname)
|
||||
key, err := o.Flags.PKI.GetPrivateKey(keyName, keyName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Cannot locate private key: %v", err)
|
||||
return fmt.Errorf("cannot locate private key: %v", err)
|
||||
}
|
||||
|
||||
if err := o.Flags.PKI.CSR(keyname, csrfile, *template, key); err != nil {
|
||||
return fmt.Errorf("Cannot create CSR: %v", err)
|
||||
if err := o.Flags.PKI.CSR(keyName, csrFile, *template, key); err != nil {
|
||||
return fmt.Errorf("cannot create CSR: %v", err)
|
||||
}
|
||||
|
||||
log.Infoln("Success")
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/openziti/fabric/controller/idgen"
|
||||
cmdhelper "github.com/openziti/ziti/ziti/cmd/helpers"
|
||||
"github.com/openziti/ziti/ziti/internal/log"
|
||||
@@ -70,22 +71,23 @@ func (o *PKICreateIntermediateOptions) addPKICreateIntermediateFlags(cmd *cobra.
|
||||
cmd.Flags().StringVarP(&o.Flags.IntermediateFile, "intermediate-file", "", "intermediate", "Dir/File name (within PKI_ROOT) in which to store new Intermediate CA")
|
||||
cmd.Flags().StringVarP(&o.Flags.IntermediateName, FlagCaIntermediateName, "", "NetFoundry Inc. Intermediate CA", "Common Name (CN) to use for new Intermediate CA")
|
||||
cmd.Flags().IntVarP(&o.Flags.CAExpire, "expire-limit", "", 3650, "Expiration limit in days")
|
||||
cmd.Flags().IntVarP(&o.Flags.CAMaxpath, "max-path-len", "", 0, "Intermediate maximum path length")
|
||||
cmd.Flags().IntVarP(&o.Flags.CAPrivateKeySize, "private-key-size", "", 4096, "Size of the private key")
|
||||
cmd.Flags().IntVarP(&o.Flags.CAMaxPath, "max-path-len", "", 0, "Intermediate maximum path length")
|
||||
cmd.Flags().IntVarP(&o.Flags.CAPrivateKeySize, "private-key-size", "", 4096, "Size of the RSA private key, ignored if -curve is set")
|
||||
cmd.Flags().StringVarP(&o.Flags.EcCurve, "curve", "", "", "If set an EC private key is generated and -private-key-size is ignored, options: P224, P256, P384, P521")
|
||||
}
|
||||
|
||||
// Run implements this command
|
||||
func (o *PKICreateIntermediateOptions) Run() error {
|
||||
pkiroot, err := o.ObtainPKIRoot()
|
||||
pkiRoot, err := o.ObtainPKIRoot()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o.Flags.PKI = &pki.ZitiPKI{Store: &store.Local{}}
|
||||
local := o.Flags.PKI.Store.(*store.Local)
|
||||
local.Root = pkiroot
|
||||
local.Root = pkiRoot
|
||||
|
||||
intermediatefile, err := o.ObtainIntermediateCAFile()
|
||||
intermediateFile, err := o.ObtainIntermediateCAFile()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -96,19 +98,19 @@ func (o *PKICreateIntermediateOptions) Run() error {
|
||||
|
||||
commonName := o.Flags.IntermediateName
|
||||
|
||||
filename := o.ObtainFileName(intermediatefile, commonName)
|
||||
filename := o.ObtainFileName(intermediateFile, commonName)
|
||||
template := o.ObtainPKIRequestTemplate(commonName)
|
||||
|
||||
template.IsCA = true
|
||||
|
||||
var signer *certificate.Bundle
|
||||
|
||||
caname, err := o.ObtainCAName(pkiroot)
|
||||
caName, err := o.ObtainCAName(pkiRoot)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
signer, err = o.Flags.PKI.GetCA(caname)
|
||||
signer, err = o.Flags.PKI.GetCA(caName)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "cannot locate signer")
|
||||
}
|
||||
@@ -119,11 +121,17 @@ func (o *PKICreateIntermediateOptions) Run() error {
|
||||
}
|
||||
}
|
||||
|
||||
privateKeyOptions, err := o.ObtainPrivateKeyOptions()
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not resolve private key options: %w", err)
|
||||
}
|
||||
|
||||
req := &pki.Request{
|
||||
Name: filename,
|
||||
Template: template,
|
||||
IsClientCertificate: false,
|
||||
PrivateKeySize: o.Flags.CAPrivateKeySize,
|
||||
PrivateKeyOptions: privateKeyOptions,
|
||||
}
|
||||
|
||||
if err := o.Flags.PKI.Sign(signer, req); err != nil {
|
||||
|
||||
@@ -65,27 +65,28 @@ func (o *PKICreateKeyOptions) addPKICreateKeyFlags(cmd *cobra.Command) {
|
||||
cmd.Flags().StringVarP(&o.Flags.PKIRoot, "pki-root", "", "", "Directory in which PKI resides")
|
||||
cmd.Flags().StringVarP(&o.Flags.CAName, "ca-name", "", "intermediate", "Name of Intermediate CA (within PKI_ROOT) to use to sign the new Client certificate")
|
||||
cmd.Flags().StringVarP(&o.Flags.KeyFile, "key-file", "", "key", "Name of file (under chosen CA) in which to store new private key")
|
||||
cmd.Flags().IntVarP(&o.Flags.CAPrivateKeySize, "private-key-size", "", 4096, "Size of the private key")
|
||||
cmd.Flags().IntVarP(&o.Flags.CAPrivateKeySize, "private-key-size", "", 4096, "Size of the RSA private key, ignored if -curve is set")
|
||||
cmd.Flags().StringVarP(&o.Flags.EcCurve, "curve", "", "", "If set an EC private key is generated and -private-key-size is ignored, options: P224, P256, P384, P521")
|
||||
}
|
||||
|
||||
// Run implements this command
|
||||
func (o *PKICreateKeyOptions) Run() error {
|
||||
|
||||
pkiroot, err := o.ObtainPKIRoot()
|
||||
pkiRoot, err := o.ObtainPKIRoot()
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s", err)
|
||||
}
|
||||
|
||||
o.Flags.PKI = &pki.ZitiPKI{Store: &store.Local{}}
|
||||
local := o.Flags.PKI.Store.(*store.Local)
|
||||
local.Root = pkiroot
|
||||
local.Root = pkiRoot
|
||||
|
||||
keyFile, err := o.ObtainKeyFile(true)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s", err)
|
||||
}
|
||||
|
||||
caname, err := o.ObtainCAName(pkiroot)
|
||||
caName, err := o.ObtainCAName(pkiRoot)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s", err)
|
||||
}
|
||||
@@ -93,20 +94,26 @@ func (o *PKICreateKeyOptions) Run() error {
|
||||
template := o.ObtainPKIRequestTemplate("")
|
||||
var signer *certificate.Bundle
|
||||
|
||||
signer, err = o.Flags.PKI.GetCA(caname)
|
||||
signer, err = o.Flags.PKI.GetCA(caName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Cannot locate signer: %v", err)
|
||||
return fmt.Errorf("cannot locate signer: %v", err)
|
||||
}
|
||||
|
||||
privateKeyOptions, err := o.ObtainPrivateKeyOptions()
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not resolve private key options: %w", err)
|
||||
}
|
||||
|
||||
req := &pki.Request{
|
||||
KeyName: keyFile,
|
||||
Template: template,
|
||||
IsClientCertificate: false,
|
||||
PrivateKeySize: o.Flags.CAPrivateKeySize,
|
||||
PrivateKeyOptions: privateKeyOptions,
|
||||
}
|
||||
|
||||
if err := o.Flags.PKI.GeneratePrivateKey(signer, req); err != nil {
|
||||
return fmt.Errorf("Cannot Generate Private key: %v", err)
|
||||
return fmt.Errorf("cannot Generate Private key: %v", err)
|
||||
}
|
||||
|
||||
log.Infoln("Success")
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/openziti/fabric/controller/idgen"
|
||||
cmdhelper "github.com/openziti/ziti/ziti/cmd/helpers"
|
||||
"github.com/openziti/ziti/ziti/internal/log"
|
||||
@@ -74,8 +75,9 @@ func (o *PKICreateServerOptions) addPKICreateServerFlags(cmd *cobra.Command) {
|
||||
cmd.Flags().StringSliceVar(&o.Flags.DNSName, "dns", []string{}, "DNS name(s) to add to Subject Alternate Name (SAN) for new Server certificate")
|
||||
cmd.Flags().StringSliceVar(&o.Flags.IP, "ip", []string{}, "IP addr(s) to add to Subject Alternate Name (SAN) for new Server certificate")
|
||||
cmd.Flags().IntVarP(&o.Flags.CAExpire, "expire-limit", "", 365, "Expiration limit in days")
|
||||
cmd.Flags().IntVarP(&o.Flags.CAMaxpath, "max-path-len", "", -1, "Intermediate maximum path length")
|
||||
cmd.Flags().IntVarP(&o.Flags.CAPrivateKeySize, "private-key-size", "", 4096, "Size of the private key")
|
||||
cmd.Flags().IntVarP(&o.Flags.CAMaxPath, "max-path-len", "", -1, "Intermediate maximum path length")
|
||||
cmd.Flags().IntVarP(&o.Flags.CAPrivateKeySize, "private-key-size", "", 4096, "Size of the RSA private key, ignored if -curve is set")
|
||||
cmd.Flags().StringVarP(&o.Flags.EcCurve, "curve", "", "", "If set an EC private key is generated and -private-key-size is ignored, options: P224, P256, P384, P521")
|
||||
cmd.Flags().StringVar(&o.Flags.SpiffeID, "spiffe-id", "", "Optionally provide the path portion of a SPIFFE id. The trust domain will be taken from the signing certificate.")
|
||||
cmd.Flags().BoolVar(&o.Flags.AllowOverwrite, "allow-overwrite", false, "Allow overwrite existing certs")
|
||||
}
|
||||
@@ -151,12 +153,18 @@ func (o *PKICreateServerOptions) Run() error {
|
||||
template.URIs = append(template.URIs, &spiffId)
|
||||
}
|
||||
|
||||
privateKeyOptions, err := o.ObtainPrivateKeyOptions()
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not resolve private key options: %w", err)
|
||||
}
|
||||
|
||||
req := &pki.Request{
|
||||
Name: filename,
|
||||
KeyName: keyFile,
|
||||
Template: template,
|
||||
IsClientCertificate: false,
|
||||
PrivateKeySize: o.Flags.CAPrivateKeySize,
|
||||
PrivateKeyOptions: privateKeyOptions,
|
||||
AllowOverwrite: o.Flags.AllowOverwrite,
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
package certificate
|
||||
|
||||
import (
|
||||
"crypto/rsa"
|
||||
"crypto"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
)
|
||||
@@ -25,21 +25,29 @@ import (
|
||||
// Bundle represents a pair of private key and certificate.
|
||||
type Bundle struct {
|
||||
Name string
|
||||
Key *rsa.PrivateKey
|
||||
Key crypto.PrivateKey
|
||||
Cert *x509.Certificate
|
||||
}
|
||||
|
||||
// Raw returns the raw bytes for the private key and certificate.
|
||||
func (b *Bundle) Raw() ([]byte, []byte) {
|
||||
return x509.MarshalPKCS1PrivateKey(b.Key), b.Cert.Raw
|
||||
keyBytes, _ := x509.MarshalPKCS8PrivateKey(b.Key)
|
||||
return keyBytes, b.Cert.Raw
|
||||
}
|
||||
|
||||
// RawToBundle creates a bundle from the name and bytes given for a private key
|
||||
// and a certificate.
|
||||
func RawToBundle(name string, key []byte, cert []byte) (*Bundle, error) {
|
||||
k, err := x509.ParsePKCS1PrivateKey(key)
|
||||
k, err := x509.ParsePKCS8PrivateKey(key)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed parsing private key: %v", err)
|
||||
//previous versions may have stored private keys as PKCS1 (aka RSA only) try as a secondary action
|
||||
var pkcs1Err error
|
||||
k, pkcs1Err = x509.ParsePKCS1PrivateKey(key)
|
||||
|
||||
if pkcs1Err != nil {
|
||||
return nil, fmt.Errorf("failed parsing private key PKCS8 error: %w, PKCS1 error: %w", err, pkcs1Err)
|
||||
}
|
||||
|
||||
}
|
||||
c, err := x509.ParseCertificate(cert)
|
||||
if err != nil {
|
||||
|
||||
+82
-15
@@ -20,6 +20,7 @@ package pki
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
@@ -42,13 +43,40 @@ var (
|
||||
ErrMaxPathLenReached = errors.New("max path len reached")
|
||||
)
|
||||
|
||||
type PrivateKeyOptions interface {
|
||||
GenerateKey() (crypto.PrivateKey, error)
|
||||
}
|
||||
|
||||
var _ PrivateKeyOptions = &RsaPrivateKeyOptions{}
|
||||
|
||||
type RsaPrivateKeyOptions struct {
|
||||
Size int
|
||||
}
|
||||
|
||||
func (r *RsaPrivateKeyOptions) GenerateKey() (crypto.PrivateKey, error) {
|
||||
if r.Size == 0 {
|
||||
r.Size = defaultPrivateKeySize
|
||||
}
|
||||
return rsa.GenerateKey(rand.Reader, r.Size)
|
||||
}
|
||||
|
||||
var _ PrivateKeyOptions = &EcPrivateKeyOptions{}
|
||||
|
||||
type EcPrivateKeyOptions struct {
|
||||
Curve elliptic.Curve
|
||||
}
|
||||
|
||||
func (e *EcPrivateKeyOptions) GenerateKey() (crypto.PrivateKey, error) {
|
||||
return ecdsa.GenerateKey(e.Curve, rand.Reader)
|
||||
}
|
||||
|
||||
// Request is a struct for providing configuration to
|
||||
// GenerateCertificate when actioning a certification generation request.
|
||||
type Request struct {
|
||||
Name string
|
||||
KeyName string
|
||||
IsClientCertificate bool
|
||||
PrivateKeySize int
|
||||
PrivateKeyOptions PrivateKeyOptions
|
||||
Template *x509.Certificate
|
||||
AllowOverwrite bool
|
||||
}
|
||||
@@ -101,13 +129,11 @@ func (e *ZitiPKI) Sign(signer *certificate.Bundle, req *Request) error {
|
||||
}
|
||||
|
||||
var err error
|
||||
var privateKey *rsa.PrivateKey
|
||||
var privateKey crypto.PrivateKey
|
||||
|
||||
if req.KeyName == "" {
|
||||
if req.PrivateKeySize == 0 {
|
||||
req.PrivateKeySize = defaultPrivateKeySize
|
||||
}
|
||||
privateKey, err = rsa.GenerateKey(rand.Reader, req.PrivateKeySize)
|
||||
privateKey, err = req.PrivateKeyOptions.GenerateKey()
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed generating private key: %v", err)
|
||||
}
|
||||
@@ -118,7 +144,12 @@ func (e *ZitiPKI) Sign(signer *certificate.Bundle, req *Request) error {
|
||||
}
|
||||
privateKey = pk.(*rsa.PrivateKey)
|
||||
}
|
||||
publicKey := privateKey.Public()
|
||||
|
||||
publicKey, err := publicKeyFromPrivate(privateKey)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := defaultTemplate(req, publicKey); err != nil {
|
||||
return fmt.Errorf("failed updating generation request: %v", err)
|
||||
@@ -148,12 +179,29 @@ func (e *ZitiPKI) Sign(signer *certificate.Bundle, req *Request) error {
|
||||
return fmt.Errorf("failed creating and signing certificate: %v", err)
|
||||
}
|
||||
|
||||
if err := e.Store.Add(signer.Name, req.Name, req.Template.IsCA, x509.MarshalPKCS1PrivateKey(privateKey), rawCert, req.AllowOverwrite); err != nil {
|
||||
keyBytes, err := x509.MarshalPKCS8PrivateKey(privateKey)
|
||||
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := e.Store.Add(signer.Name, req.Name, req.Template.IsCA, keyBytes, rawCert, req.AllowOverwrite); err != nil {
|
||||
return fmt.Errorf("failed saving generated bundle: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func publicKeyFromPrivate(key crypto.PrivateKey) (crypto.PublicKey, error) {
|
||||
switch pk := key.(type) {
|
||||
case *rsa.PrivateKey:
|
||||
return &pk.PublicKey, nil
|
||||
case *ecdsa.PrivateKey:
|
||||
return &pk.PublicKey, nil
|
||||
}
|
||||
|
||||
return nil, errors.New("unsupported key type")
|
||||
}
|
||||
|
||||
// Chain will...
|
||||
func (e *ZitiPKI) Chain(signer *certificate.Bundle, req *Request) error {
|
||||
destCA := signer.Name
|
||||
@@ -166,16 +214,22 @@ func (e *ZitiPKI) Chain(signer *certificate.Bundle, req *Request) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Generate and store a private key
|
||||
// GeneratePrivateKey generates and stores a private key
|
||||
func (e *ZitiPKI) GeneratePrivateKey(signer *certificate.Bundle, req *Request) error {
|
||||
if req.PrivateKeySize == 0 {
|
||||
req.PrivateKeySize = defaultPrivateKeySize
|
||||
}
|
||||
privateKey, err := rsa.GenerateKey(rand.Reader, req.PrivateKeySize)
|
||||
|
||||
privateKey, err := req.PrivateKeyOptions.GenerateKey()
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed generating private key: %v", err)
|
||||
}
|
||||
if err := e.Store.AddKey(signer.Name, req.KeyName, x509.MarshalPKCS1PrivateKey(privateKey)); err != nil {
|
||||
|
||||
keyBytes, err := x509.MarshalPKCS8PrivateKey(privateKey)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed marshalling private key: %v", err)
|
||||
}
|
||||
|
||||
if err := e.Store.AddKey(signer.Name, req.KeyName, keyBytes); err != nil {
|
||||
return fmt.Errorf("failed saving generated key: %v", err)
|
||||
}
|
||||
return nil
|
||||
@@ -200,7 +254,20 @@ func (e *ZitiPKI) CRL(caName string, expire time.Time) ([]byte, error) {
|
||||
return nil, fmt.Errorf("failed retrieving CA bundle %v: %v", caName, err)
|
||||
}
|
||||
|
||||
crl, err := ca.Cert.CreateCRL(rand.Reader, ca.Key, revoked, time.Now(), expire)
|
||||
signer, ok := ca.Key.(crypto.Signer)
|
||||
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("could not convert %T to %T", ca.Key, signer)
|
||||
}
|
||||
|
||||
template := &x509.RevocationList{
|
||||
RevokedCertificates: revoked,
|
||||
ThisUpdate: time.Now(),
|
||||
NextUpdate: expire,
|
||||
}
|
||||
|
||||
crl, err := x509.CreateRevocationList(rand.Reader, template, ca.Cert, signer)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed creating crl for %v: %v", caName, err)
|
||||
}
|
||||
|
||||
@@ -19,17 +19,16 @@ package pki
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/sha1"
|
||||
"crypto/x509"
|
||||
"encoding/asn1"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"time"
|
||||
)
|
||||
|
||||
func defaultTemplate(genReq *Request, publicKey crypto.PublicKey) error {
|
||||
publicKeyBytes, err := asn1.Marshal(*publicKey.(*rsa.PublicKey))
|
||||
publicKeyBytes, err := x509.MarshalPKIXPublicKey(publicKey)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed marshaling public key: %v", err)
|
||||
}
|
||||
@@ -45,7 +44,6 @@ func defaultTemplate(genReq *Request, publicKey crypto.PublicKey) error {
|
||||
genReq.Template.SerialNumber = sn
|
||||
|
||||
genReq.Template.NotBefore = time.Now().Add(-time.Minute)
|
||||
genReq.Template.SignatureAlgorithm = x509.SHA256WithRSA
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
+29
-5
@@ -156,19 +156,22 @@ func (l *Local) AddCSR(caName, name string, isCa bool, key, cert []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddKey adds the given key to the local filesystem.
|
||||
// AddKey adds the given private key to the local filesystem.
|
||||
func (l *Local) AddKey(caName string, name string, key []byte) error {
|
||||
if l.Exists(caName, name) {
|
||||
return fmt.Errorf("a key already exists for the key name %v within CA %v", name, caName)
|
||||
}
|
||||
if err := l.writeKey(caName, name, key); err != nil {
|
||||
|
||||
pemType := getPkPemType(key)
|
||||
|
||||
if err := l.writeKey(caName, name, pemType, key); err != nil {
|
||||
return fmt.Errorf("failed writing key %v within CA %v to the local filesystem: %v", name, caName, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// writeKey encodes in PEM format the bundle private key and stores it on the local filesystem.
|
||||
func (l *Local) writeKey(caName string, name string, key []byte) error {
|
||||
func (l *Local) writeKey(caName, name, pemType string, key []byte) error {
|
||||
caDir := filepath.Join(l.Root, caName)
|
||||
if _, err := os.Stat(caDir); err != nil {
|
||||
if err := InitCADir(caDir); err != nil {
|
||||
@@ -176,12 +179,30 @@ func (l *Local) writeKey(caName string, name string, key []byte) error {
|
||||
}
|
||||
}
|
||||
keyPath, _ := l.path(caName, name)
|
||||
if err := encodeAndWrite(keyPath, "RSA PRIVATE KEY", key); err != nil {
|
||||
if err := encodeAndWrite(keyPath, pemType, key); err != nil {
|
||||
return fmt.Errorf("failed encoding and writing private key file: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getPkPemType(key []byte) string {
|
||||
var pkcs1Err error
|
||||
_, pkcs1Err = x509.ParsePKCS1PrivateKey(key)
|
||||
|
||||
if pkcs1Err == nil {
|
||||
return "RSA PRIVATE KEY"
|
||||
}
|
||||
|
||||
var pkcsEcErr error
|
||||
_, pkcsEcErr = x509.ParseECPrivateKey(key)
|
||||
|
||||
if pkcsEcErr == nil {
|
||||
return "EC PRIVATE KEY"
|
||||
}
|
||||
|
||||
return "PRIVATE KEY"
|
||||
}
|
||||
|
||||
// writeBundle encodes in PEM format the bundle private key and
|
||||
// certificate and stores them on the local filesystem.
|
||||
func (l *Local) writeBundle(caName, name string, isCa bool, key, cert []byte) error {
|
||||
@@ -191,8 +212,11 @@ func (l *Local) writeBundle(caName, name string, isCa bool, key, cert []byte) er
|
||||
return fmt.Errorf("root directory for CA %v does not exist and cannot be created: %v", caDir, err)
|
||||
}
|
||||
}
|
||||
|
||||
keyPemType := getPkPemType(key)
|
||||
|
||||
keyPath, certPath := l.path(caName, name)
|
||||
if err := encodeAndWrite(keyPath, "RSA PRIVATE KEY", key); err != nil {
|
||||
if err := encodeAndWrite(keyPath, keyPemType, key); err != nil {
|
||||
return fmt.Errorf("failed encoding and writing private key file: %v", err)
|
||||
}
|
||||
if err := encodeAndWrite(certPath, "CERTIFICATE", cert); err != nil {
|
||||
|
||||
@@ -65,7 +65,7 @@ type Store interface {
|
||||
// Args:
|
||||
// The intermediate CA name
|
||||
// The Key name
|
||||
// The raw private key.
|
||||
// The private key
|
||||
//
|
||||
// Returns an error if it failed to store the bundle.
|
||||
AddKey(string, string, []byte) error
|
||||
|
||||
Reference in New Issue
Block a user