diff --git a/ziti/cmd/pki/pki_create_client.go b/ziti/cmd/pki/pki_create_client.go index fd6437ff9b..08a6ae58ed 100644 --- a/ziti/cmd/pki/pki_create_client.go +++ b/ziti/cmd/pki/pki_create_client.go @@ -181,7 +181,7 @@ func (o *PKICreateClientOptions) Run() error { } // Concat the newly-created client cert with the intermediate cert to create a client.chain.pem file - if err := o.Flags.PKI.Chain(signer, req); err != nil { + if err := o.Flags.PKI.Chain(signer, req, o.Flags.AllowOverwrite); err != nil { return errors.Wrap(err, "unable to generate cert chain") } diff --git a/ziti/cmd/pki/pki_create_intermediate.go b/ziti/cmd/pki/pki_create_intermediate.go index e8985117f0..a22fbf2398 100644 --- a/ziti/cmd/pki/pki_create_intermediate.go +++ b/ziti/cmd/pki/pki_create_intermediate.go @@ -142,7 +142,7 @@ func (o *PKICreateIntermediateOptions) Run() error { } // Concat the newly-created intermediate cert with the signing cert to create an intermediate.chain.pem file - if err := o.Flags.PKI.Chain(signer, req); err != nil { + if err := o.Flags.PKI.Chain(signer, req, false); err != nil { return errors.Wrap(err, "unable to generate cert chain") } diff --git a/ziti/cmd/pki/pki_create_server.go b/ziti/cmd/pki/pki_create_server.go index 5248af3718..3fbc61a523 100644 --- a/ziti/cmd/pki/pki_create_server.go +++ b/ziti/cmd/pki/pki_create_server.go @@ -188,7 +188,7 @@ func (o *PKICreateServerOptions) Run() error { } // Concat the newly-created server cert with the intermediate cert to create a server.chain.pem file - if err := o.Flags.PKI.Chain(signer, req); err != nil { + if err := o.Flags.PKI.Chain(signer, req, o.Flags.AllowOverwrite); err != nil { return errors.Wrap(err, "unable to generate cert chain") } diff --git a/ziti/pki/pki/pki.go b/ziti/pki/pki/pki.go index 7ba5f9885d..4735d86202 100644 --- a/ziti/pki/pki/pki.go +++ b/ziti/pki/pki/pki.go @@ -202,13 +202,13 @@ func publicKeyFromPrivate(key crypto.PrivateKey) (crypto.PublicKey, error) { return nil, errors.New("unsupported key type") } -// Chain will... -func (e *ZitiPKI) Chain(signer *certificate.Bundle, req *Request) error { +// Chain concats a signing cert and a newly signed certificate and stores the chained PEM. +func (e *ZitiPKI) Chain(signer *certificate.Bundle, req *Request, allowOverwrite bool) error { destCA := signer.Name if req.Template.IsCA { destCA = req.Name } - if err := e.Store.Chain(signer.Name, destCA, req.Name); err != nil { + if err := e.Store.Chain(signer.Name, destCA, req.Name, allowOverwrite); err != nil { return fmt.Errorf("failed saving generated chain: %v", err) } return nil diff --git a/ziti/pki/store/local.go b/ziti/pki/store/local.go index 916dd77ad4..7cc57cc849 100644 --- a/ziti/pki/store/local.go +++ b/ziti/pki/store/local.go @@ -69,15 +69,14 @@ func (l *Local) path(caName, name string) (key string, cert string) { // Exists checks if a certificate or private key already exist on the local // filesystem for a given name. +// Exists returns true when a complete bundle (both key and cert) exists. +// A key without a cert (e.g., created separately via "ziti pki create key") +// is not a complete bundle and should not block certificate creation. func (l *Local) Exists(caName, name string) bool { privPath, certPath := l.path(caName, name) - if _, err := os.Stat(privPath); err == nil { - return true - } - if _, err := os.Stat(certPath); err == nil { - return true - } - return false + _, keyErr := os.Stat(privPath) + _, certErr := os.Stat(certPath) + return keyErr == nil && certErr == nil } // Fetch fetches the private key and certificate for a given name signed by caName. @@ -135,10 +134,14 @@ func (l *Local) Add(caName, name string, isCa bool, key, cert []byte, allowOverw } // Chain concats an intermediate cert and a newly signed certificate bundle and adds the chained cert to the store. -func (l *Local) Chain(caName, destCaName, name string) error { +// Chain concats an intermediate cert and a newly signed certificate bundle and adds the chained cert to the store. +func (l *Local) Chain(caName, destCaName, name string, allowOverwrite bool) error { chainName := name + ".chain.pem" - if l.Exists(destCaName, chainName) { - return fmt.Errorf("a bundle already exists for the name %v within CA %v", chainName, destCaName) + if !allowOverwrite { + chainPath := filepath.Join(l.Root, destCaName, "certs", chainName) + if _, err := os.Stat(chainPath); err == nil { + return fmt.Errorf("a bundle already exists for the name %v within CA %v", chainName, destCaName) + } } if err := l.writeChainBundle(caName, destCaName, name, chainName); err != nil { return fmt.Errorf("failed writing chain %v to the local filesystem: %v", chainName, err) diff --git a/ziti/pki/store/store.go b/ziti/pki/store/store.go index 7d0ca8c198..c12d819b3b 100644 --- a/ziti/pki/store/store.go +++ b/ziti/pki/store/store.go @@ -45,9 +45,10 @@ type Store interface { // The signing CA name. // The destination CA name. // The certificate bundle name. + // Flag indicating if existing chain can be overwritten. // // Returns an error if it failed to store the bundle. - Chain(string, string, string) error + Chain(string, string, string, bool) error // AddCSR adds a CSR to the store. //