From 5d049c8c850e7485467b4d72f400c4a0f79abc79 Mon Sep 17 00:00:00 2001 From: Chris Newman Date: Thu, 18 Mar 2021 00:37:06 +0000 Subject: [PATCH] Issue-10: add back in RSA Issue-11: remove hardcoded EC so RSA works for Generate Root, Generater Intermediate, though Sign Intermediate can use EC 521 because internal as part of Vault's auto CSR gen and Sign Issue-12: HSM connection checks on path calls Issue-13: detect if in metamode or plugin startup --- Makefile | 11 ++++ TESTING.md | 8 ++- go.mod | 2 +- go.sum | 4 +- pkg/hsmpki/backend.go | 82 ++++++++++++++++------------ pkg/hsmpki/backend_test.go | 64 +++++++++++----------- pkg/hsmpki/hsmcert_util.go | 1 - pkg/hsmpki/hsmconsts.go | 9 ++-- pkg/hsmpki/hsmhelpers.go | 87 +++++++++++++++++------------- pkg/hsmpki/hsmpath_fetch.go | 2 +- pkg/hsmpki/hsmpath_intermediate.go | 4 ++ pkg/hsmpki/hsmpath_issue_sign.go | 4 +- pkg/hsmpki/hsmpath_root.go | 19 ++++++- pkg/pki/pki_api.go | 4 ++ 14 files changed, 183 insertions(+), 118 deletions(-) diff --git a/Makefile b/Makefile index 08564b8..7a73f94 100644 --- a/Makefile +++ b/Makefile @@ -55,5 +55,16 @@ pathrotatecrl: pathtidycrl: go test -v -run TestPathTidyCRL ./pkg/hsmpki +pathgenerateroot: + go test -v -run TestPathGenerateRoot ./pkg/hsmpki + +pathgenerateintermediate: + go test -v -run TestPathGenerateIntermediate ./pkg/hsmpki + +pathissue: + go test -v -run TestPathIssue ./pkg/hsmpki + +pathdeleteroot: + go test -v -run TestPathDeleteRoot ./pkg/hsmpki .PHONY: build clean fmt start enable diff --git a/TESTING.md b/TESTING.md index 812db8c..dfa688e 100755 --- a/TESTING.md +++ b/TESTING.md @@ -8,7 +8,7 @@ If you want to run tests in an IDE then source DPoD in a shell and start the IDE ## Makefile Command Line Tests -Test the HSM connection where the conf is loaded in from conf/config-hsm.hcl +Test the HSM connection where the conf is loaded in from conf/config-safenet.hcl `make test hsmconnection` @@ -19,3 +19,9 @@ Test the HSM connection where the conf is loaded in from conf/config-hsm.hcl `make test pathfetchcrl` `make test pathsetsignedintermediate` + +`make test pathgenerateroot` + +`make test pathgenerateintermediate` + +`make test pathdeleteroot` diff --git a/go.mod b/go.mod index f10f809..1d9c564 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( github.com/miekg/pkcs11 v1.0.3 github.com/mitchellh/mapstructure v1.3.3 // indirect github.com/mitchellh/reflectwalk v1.0.1 // indirect - github.com/mode51software/pkcs11helper v0.3.2 + github.com/mode51software/pkcs11helper v0.3.3 github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect github.com/ryanuber/go-glob v1.0.0 github.com/stretchr/objx v0.2.0 // indirect diff --git a/go.sum b/go.sum index 3e85c5b..1c976fc 100644 --- a/go.sum +++ b/go.sum @@ -243,8 +243,8 @@ github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mitchellh/reflectwalk v1.0.1 h1:FVzMWA5RllMAKIdUSC8mdWo3XtwoecrH79BY70sEEpE= github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/mode51software/pkcs11helper v0.3.2 h1:FNCo8jeEOpq5d8kfpSKbMEZ5ft8el9+MmT1zQh0yPc8= -github.com/mode51software/pkcs11helper v0.3.2/go.mod h1:kTP66TAfYMJTuND7oT1y4FWyTmAtkJh/b7QwtH1VOcI= +github.com/mode51software/pkcs11helper v0.3.3 h1:ea11q6DrS8zmRXIst8W7Bs60WN9/ZSPSKyI/sfS1uVg= +github.com/mode51software/pkcs11helper v0.3.3/go.mod h1:kTP66TAfYMJTuND7oT1y4FWyTmAtkJh/b7QwtH1VOcI= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= diff --git a/pkg/hsmpki/backend.go b/pkg/hsmpki/backend.go index 26f1369..7ab3b13 100644 --- a/pkg/hsmpki/backend.go +++ b/pkg/hsmpki/backend.go @@ -29,6 +29,9 @@ type HsmPkiBackend struct { cachedCAConfig cachedCAConfig // needs to be re-cached on startup refreshMutex sync.Mutex store map[string][]byte + connChannel chan int + backendConfig *logical.BackendConfig + // this is the same storage as in the pki Backend, so ref here for convenience //storage logical.Storage } @@ -45,64 +48,61 @@ func Factory(ctx context.Context, conf *logical.BackendConfig) (logical.Backend, if err = b.pkiBackend.Backend.Setup(ctx, conf); err != nil { return nil, err } + b.backendConfig = conf + if _, ok := conf.Config[CONFIG_PARAM]; !ok { + b.pkiBackend.Backend.Logger().Error("Please add a parameter specifying a file containing the HSM's configuration. Plugin mounting aborted.") + } + return b.pkiBackend.Backend, nil + +} - if confFile, ok := conf.Config[CONFIG_PARAM]; ok { +// plugins are launched first in metadata mode then lazily loaded later so don't create the connection until fully loaded +// https://groups.google.com/g/vault-tool/c/z6iaU_B159A/m/ag7OJaeECQAJ +func (b *HsmPkiBackend) initnow(ctx context.Context, req *logical.InitializationRequest) error { + b.pkiBackend.Backend.Logger().Info("Init") + + if confFile, ok := b.backendConfig.Config[CONFIG_PARAM]; ok { b.pkiBackend.Backend.Logger().Info("found conf: " + confFile) // check the conf is valid - if err = b.loadConf(confFile); err != nil { - return nil, errwrap.Wrapf("Conf file error: {{err}}", err) + if err := b.loadConf(confFile); err != nil { + return errwrap.Wrapf("Conf file error: {{err}}", err) } - b.loadStorage() + b.loadStorage() b.configurePkcs11Connection() - b.checkPkcs11ConnectionAsync() //; err != nil { - // b.pkiBackend.Backend.Logger().Error("PKCS#11 connection timed out on startup, will retry on request") - //} - - return b.pkiBackend.Backend, nil + b.checkPkcs11ConnectionAsync() } else { - for key, value := range conf.Config { - b.pkiBackend.Backend.Logger().Info("Conf key=" + key + " Val=" + value) - } b.pkiBackend.Backend.Logger().Error("Please add a parameter specifying a file containing the HSM's configuration. Plugin mounting aborted.") - // infer whether the plugin is being registered in the catalog or being mounted by checking for the presence of plugin_name - // there may be a better way to do this! - if _, ok := conf.Config[CONFIG_PLUGIN_NAME]; ok { - // if the plugin is being mounted and the config file hasn't been included then fail with a message - return nil, errors.New("Please add a parameter specifying a file containing the HSM's configuration. Plugin mounting aborted.") - } else { - // a Backend is returned here so that the plugin can be registered in the catalog - return b.pkiBackend.Backend, nil - } + return errors.New("Please add a parameter specifying a file containing the HSM's configuration. Plugin mounting aborted.") } + return nil } func Backend(conf *logical.BackendConfig) (*HsmPkiBackend, error) { b := &HsmPkiBackend{ - //keyConfig: pkcs11client.KeyConfig{Label: "SSL Root CA 02", Type: pkcs11client.CKK_RSA }, - // keyConfig: pkcs11client.KeyConfig{Id: "0007", Type: pkcs11.CKK_RSA}, store: make(map[string][]byte), } b.pkiBackend.Backend.Backend = &framework.Backend{ - Help: strings.TrimSpace(PLUGIN_HELP), - BackendType: logical.TypeLogical, + Help: strings.TrimSpace(PLUGIN_HELP), + BackendType: logical.TypeLogical, + InitializeFunc: b.initnow, Paths: []*framework.Path{ pki.PathListRoles(&b.pkiBackend.Backend), pki.PathRoles(&b.pkiBackend.Backend), pathGenerateRoot(b), pathSignIntermediate(b), //pathSignSelfIssued(&b), - //pathDeleteRoot(&b), + pathDeleteRoot(b), pathGenerateIntermediate(b), pathSetSignedIntermediate(b), - //pathConfigCA(&b), + //pathConfigCA(&b), // not implemented pki.PathConfigCRL(&b.pkiBackend.Backend), - //pathConfigURLs(&b), + pki.PathConfigURLs(&b.pkiBackend.Backend), //pathSignVerbatim(&b), pathSign(b), pathIssue(b), @@ -115,7 +115,7 @@ func Backend(conf *logical.BackendConfig) (*HsmPkiBackend, error) { pki.PathFetchListCerts(&b.pkiBackend.Backend), pathRevoke(b), pathTidy(b), - pathFetchCAKeyAlias(b), // new path + pathFetchCAKeyLabel(b), // new path }, PathsSpecial: &logical.Paths{ Unauthenticated: []string{ @@ -156,13 +156,25 @@ func (b *HsmPkiBackend) configurePkcs11Connection() { // on startup attempt to connect asynchronously func (b *HsmPkiBackend) checkPkcs11ConnectionAsync() { - go func() { + b.connChannel = make(chan int) - //b.pkcs11client.Pkcs11Mutex.Lock() - //b.pkcs11client.FlushSession() - //b.pkcs11client.Pkcs11Mutex.Unlock() - - b.checkPkcs11ConnectionSync() + go func() { + //for { + + b.pkiBackend.Backend.Logger().Info("Checking PKCS#11 connection") + + // plugins are launched first in metadata mode then lazily loaded later so don't create the connection until fully loaded + // https://groups.google.com/g/vault-tool/c/z6iaU_B159A/m/ag7OJaeECQAJ + timer := time.NewTimer(time.Second * 3) + select { + case <-b.connChannel: + b.pkiBackend.Backend.Logger().Info("Shutting down PKCS#11 connection monitor") + return + case <-timer.C: + // continue + b.checkPkcs11ConnectionSync() + } + //} }() return } diff --git a/pkg/hsmpki/backend_test.go b/pkg/hsmpki/backend_test.go index f180cfd..291cc0f 100644 --- a/pkg/hsmpki/backend_test.go +++ b/pkg/hsmpki/backend_test.go @@ -3,7 +3,6 @@ package hsmpki import ( "context" "github.com/hashicorp/vault/sdk/framework" - "github.com/hashicorp/vault/sdk/helper/certutil" "github.com/hashicorp/vault/sdk/logical" "github.com/mode51software/pkcs11helper/pkg/pkcs11client" "github.com/mode51software/vaultplugin-hsmpki/pkg/pki" @@ -92,7 +91,7 @@ func testFetchCAKeyLabel(t *testing.T, integraTest *testEnv) { req := &logical.Request{ Operation: logical.ReadOperation, - Path: PATH_CAKEYALIAS, + Path: PATH_CAKEYLABEL, Storage: integraTest.Storage, } @@ -384,8 +383,8 @@ func testGenerateRoot(t *testing.T, integraTest *testEnv) { } data.Raw[FIELD_COMMON_NAME] = TEST_CAROOTCOMMONNAME data.Raw[FIELD_EXPORTED] = TEST_EXPORTED - data.Raw[FIELD_KEY_TYPE] = TEST_CAKEYTYPE - data.Raw[FIELD_KEY_BITS] = TEST_CAKEYBITS + data.Raw[FIELD_KEY_TYPE] = TEST_CAKEYTYPERSA + data.Raw[FIELD_KEY_BITS] = TEST_CAKEYBITSRSA // data.Raw[FIELD_PERMITTED_DNS_NAMES] = TEST_CAPERMITTEDDNSDOMAINS data.Raw[FIELD_ORGANIZATION] = TEST_CAORGANIZATION data.Raw[FIELD_OU] = TEST_CAOU @@ -398,7 +397,6 @@ func testGenerateRoot(t *testing.T, integraTest *testEnv) { data.Raw[FIELD_TTL] = TEST_CATTL //caKeyAlias := "ECTestCARootKey0017" - //integraTest.HsmPkiBackend.saveCAKeyAlias(context.Background(), integraTest.Storage, &caKeyAlias) //integraTest.HsmPkiBackend.cachedCAConfig.caKeyAlias = caKeyAlias @@ -443,8 +441,8 @@ func testGenerateIntermediate(t *testing.T, integraTest *testEnv) string { } data.Raw[FIELD_COMMON_NAME] = TEST_CAINTERCOMMONNAME data.Raw[FIELD_EXPORTED] = TEST_EXPORTED - data.Raw[FIELD_KEY_TYPE] = TEST_CAKEYTYPE - data.Raw[FIELD_KEY_BITS] = TEST_CAKEYBITS + data.Raw[FIELD_KEY_TYPE] = TEST_CAKEYTYPEEC + data.Raw[FIELD_KEY_BITS] = TEST_CAKEYBITSEC // data.Raw[FIELD_PERMITTED_DNS_NAMES] = TEST_CAPERMITTEDDNSDOMAINS data.Raw[FIELD_ORGANIZATION] = TEST_CAORGANIZATION data.Raw[FIELD_OU] = TEST_CAOU @@ -479,6 +477,7 @@ func testGenerateIntermediate(t *testing.T, integraTest *testEnv) string { } +/* // sign intermediate needs a CSR as input that is to be signed with the RootCA // usually Generate Root will be run on mount path A, then Generate Intermediate on mount path B, // then Sign Intermediate on mount path A, followed by Set Signed Intermediate on mount path B @@ -491,25 +490,6 @@ func TestPathSignIntermediate(t *testing.T) { testConnectPkcs11Connection(t, integraTest) - /* testGenerateRoot(t, integraTest) - - bundleEntry, err := integraTest.Storage.Get(context.Background(), "config/rootca_bundle") - var bundle certutil.CertBundle - if err = bundleEntry.DecodeJSON(&bundle); err != nil { - return //, errutil.InternalError{Err: fmt.Sprintf("unable to decode local CA certificate/key: %v", err)} - } - t.Logf("bundle=%s", bundle.Certificate) - - csr := testGenerateIntermediate(t, integraTest) - - bundleEntry2, err := integraTest.Storage.Get(context.Background(), CA_BUNDLE) - var bundle2 certutil.CertBundle - if err = bundleEntry2.DecodeJSON(&bundle2); err != nil { - return //, errutil.InternalError{Err: fmt.Sprintf("unable to decode local CA certificate/key: %v", err)} - } - t.Logf("bundle2=%s", bundle2.Certificate) - */ - rootCACert, err := pkcs11client.LoadFromFileAsString(TEST_ROOTCACERTFILE) cb := &certutil.CertBundle{} cb.Certificate = *rootCACert @@ -543,8 +523,8 @@ func testSignIntermediate(t *testing.T, integraTest *testEnv, csr *string) { } data.Raw[FIELD_COMMON_NAME] = TEST_CAINTERCOMMONNAME data.Raw[FIELD_EXPORTED] = TEST_EXPORTED - data.Raw[FIELD_KEY_TYPE] = TEST_CAKEYTYPE - data.Raw[FIELD_KEY_BITS] = TEST_CAKEYBITS + data.Raw[FIELD_KEY_TYPE] = TEST_CAKEYTYPEEC + data.Raw[FIELD_KEY_BITS] = TEST_CAKEYBITSEC // data.Raw[FIELD_PERMITTED_DNS_NAMES] = TEST_CAPERMITTEDDNSDOMAINS data.Raw[FIELD_ORGANIZATION] = TEST_CAORGANIZATION data.Raw[FIELD_OU] = []string{TEST_CAOU} @@ -630,8 +610,8 @@ func testIssue(t *testing.T, integraTest *testEnv) { t.Logf("Issue succeeded: %s", response.Data["certificate"]) } } - -/*func TestGenerateAll(t *testing.T) { +*/ +func TestPathDeleteRoot(t *testing.T) { integraTest, err := newIntegrationTestEnv() if err != nil { @@ -640,7 +620,23 @@ func testIssue(t *testing.T, integraTest *testEnv) { testConnectPkcs11Connection(t, integraTest) testGenerateRoot(t, integraTest) - csr := testGenerateIntermediate(t, integraTest) - testSignIntermediate(t, integraTest, &csr) - testPathI -}*/ + testDeleteRoot(t, integraTest) +} + +func testDeleteRoot(t *testing.T, integraTest *testEnv) { + req := &logical.Request{ + Operation: logical.DeleteOperation, + Path: PATH_ROOT, + Storage: integraTest.Storage, + } + if response, err := integraTest.HsmPkiBackend.pathCADeleteRoot(integraTest.Context, req, nil); err != nil || response.Error() != nil { + if err != nil { + t.Error(err) + } else if response.Error() != nil { + t.Error(response.Error()) + } + } else { + t.Logf("Delete CA succeeded: %s", integraTest.HsmPkiBackend.cachedCAConfig.caKeyAlias) + } + +} diff --git a/pkg/hsmpki/hsmcert_util.go b/pkg/hsmpki/hsmcert_util.go index 2b5a8be..87d5889 100644 --- a/pkg/hsmpki/hsmcert_util.go +++ b/pkg/hsmpki/hsmcert_util.go @@ -196,7 +196,6 @@ func signCert(b *HsmPkiBackend, creation.Params.PermittedDNSDomains = data.ApiData.Get("permitted_dns_domains").([]string) } - //parsedBundle, err := certutil.SignCertificate(creation) parsedBundle, err := SignCertificate(b, creation) if err != nil { diff --git a/pkg/hsmpki/hsmconsts.go b/pkg/hsmpki/hsmconsts.go index e153f3d..34866cc 100644 --- a/pkg/hsmpki/hsmconsts.go +++ b/pkg/hsmpki/hsmconsts.go @@ -15,6 +15,7 @@ const ( PATH_GENERATEINTERMEDIATE = "intermediate/generate/" PATH_SIGNINTERMEDIATE = "root/sign-intermediate" PATH_ISSUE = "issue/" + PATH_ROOT = "root" PATH_HASHALGO = "hash_algo" @@ -61,14 +62,16 @@ const ( TEST_COMMON_NAME = "localhost" TEST_ROLE_NAME = "localhost" //TEST_SIGNEDCACERTFILE = "../../data/softhsm-inter-0002.ca.cert.pem" - TEST_SIGNEDCACERTFILE = "../../data/safenet-inter-0016.ca.cert.pem" + TEST_SIGNEDCACERTFILE = "../../data/safenet-inter-02.ca.cert.pem" TEST_ROOTCACERTFILE = "../../data/testrootca.cert.pem" TEST_INTERCSRFILE = "../../data/testintermediate.csr.pem" TEST_INTERCERTFILE = "../../data/testintermediate.cert.pem" TEST_CAROOTCOMMONNAME = "safenet.ec17.rootca.mode51.software" TEST_CAINTERCOMMONNAME = "safenet.ec17.interca.mode51.software" - TEST_CAKEYTYPE = "ec" - TEST_CAKEYBITS = "521" + TEST_CAKEYTYPERSA = "rsa" + TEST_CAKEYBITSRSA = "4096" + TEST_CAKEYTYPEEC = "ec" + TEST_CAKEYBITSEC = "521" TEST_CAPERMITTEDDNSDOMAINS = "localhost" TEST_CAORGANIZATION = "mode51 Software Ltd" TEST_CAOU = "Security" diff --git a/pkg/hsmpki/hsmhelpers.go b/pkg/hsmpki/hsmhelpers.go index 2ebdcf2..6d0ab7c 100644 --- a/pkg/hsmpki/hsmhelpers.go +++ b/pkg/hsmpki/hsmhelpers.go @@ -79,7 +79,11 @@ func CreateCSR(b *HsmPkiBackend, data *certutil.CreationBundle, addBasicConstrai b.cachedCAConfig.caKeyAlias = keyLabel } - keyConfig := pkcs11client.KeyConfig{Label: b.cachedCAConfig.caKeyAlias, Id: []byte{59}, Type: pkcs11.CKK_EC, KeyBits: 521} + keyType, err := GetDataKeyType(&data.Params.KeyType) + if err != nil { + return nil, err + } + keyConfig := pkcs11client.KeyConfig{Label: b.cachedCAConfig.caKeyAlias, Id: []byte{59}, Type: keyType, KeyBits: data.Params.KeyBits} // if the key already exists, carry on so we can generate a new CSR if err = b.pkcs11client.CheckExistsOkCreateKeyPair(&keyConfig); err != nil { @@ -133,6 +137,7 @@ func CreateCSR(b *HsmPkiBackend, data *certutil.CreationBundle, addBasicConstrai csrTemplate.SignatureAlgorithm = x509.ECDSAWithSHA256 } + // we can choose the signing type internally here var caSigner pkcs11client.HsmSigner caSigner.KeyConfig.Label = b.cachedCAConfig.caKeyAlias caSigner.KeyConfig.Type = pkcs11.CKK_EC @@ -273,25 +278,22 @@ func SignCertificate(b *HsmPkiBackend, data *certutil.CreationBundle) (*certutil caSigner.Pkcs11Client = &b.pkcs11client caSigner.PublicKey = data.SigningBundle.Certificate.PublicKey - //pubKey, err := b.pkcs11client.ReadECPublicKey(&caSigner.KeyConfig) - //caSigner.PublicKey = pubKey - b.pkcs11client.Pkcs11Mutex.Lock() certBytes, err = x509.CreateCertificate(rand.Reader, certTemplate, caCert, data.CSR.PublicKey, caSigner) // whilst the Pkcs11Client is locked, the last error and code can be used - if b.pkcs11client.LastErrCode == pkcs11client.PKCS11ERR_READTIMEOUT { - b.pkiBackend.Backend.Logger().Info("pkcs11helper: Timeout processing PKCS#11 function") - b.checkPkcs11ConnectionFailed() - } else if b.pkcs11client.LastErrCode == pkcs11client.PKCS11ERR_GENERICERROR { - b.pkiBackend.Backend.Logger().Info("pkcs11helper: generic error") - // TODO: defend against deliberate errors which cause a reconnection attempt - b.checkPkcs11ConnectionFailed() - } else if b.pkcs11client.LastErrCode == 0 { - b.pkiBackend.Backend.Logger().Info("pkcs11helper: no error") - } + /* if b.pkcs11client.LastErrCode == pkcs11client.PKCS11ERR_READTIMEOUT { + b.pkiBackend.Backend.Logger().Info("pkcs11helper: Timeout processing PKCS#11 function") + b.checkPkcs11ConnectionFailed() + } else if b.pkcs11client.LastErrCode == pkcs11client.PKCS11ERR_GENERICERROR { + b.pkiBackend.Backend.Logger().Info("pkcs11helper: generic error") + // TODO: defend against deliberate errors which cause a reconnection attempt + b.checkPkcs11ConnectionFailed() + } else if b.pkcs11client.LastErrCode == 0 { + b.pkiBackend.Backend.Logger().Info("pkcs11helper: no error") + }*/ b.pkcs11client.Pkcs11Mutex.Unlock() // unlock asap rather than have deferred @@ -332,11 +334,17 @@ func CreateCertificate(b *HsmPkiBackend, data *certutil.CreationBundle) (*certut b.cachedCAConfig.caKeyAlias = keyLabel b.saveCAKeyAlias(context.Background(), b.pkiBackend.GetStorage(), &keyLabel) } - keyConfig := &pkcs11client.KeyConfig{Label: b.cachedCAConfig.caKeyAlias, Id: []byte{43}, Type: pkcs11.CKK_EC, KeyBits: 521} + + keyType, err := GetDataKeyType(&data.Params.KeyType) + if err != nil { + return nil, err + } + + keyConfig := &pkcs11client.KeyConfig{Label: b.cachedCAConfig.caKeyAlias, Type: keyType, KeyBits: data.Params.KeyBits} if err = b.pkcs11client.CheckExistsCreateKeyPair(keyConfig); err != nil { return nil, errutil.UserError{err.Error()} } - if subjKeyID, publicKey, err = b.pkcs11client.GetGenSubjectKeyId(keyConfig, pkcs11.CKK_EC); err != nil { + if subjKeyID, publicKey, err = b.pkcs11client.GetGenSubjectKeyId(keyConfig, keyType); err != nil { return nil, errutil.UserError{err.Error()} } @@ -360,10 +368,6 @@ func CreateCertificate(b *HsmPkiBackend, data *certutil.CreationBundle) (*certut // IsCA: false, SubjectKeyId: subjKeyID, Subject: data.Params.Subject, - // DNSNames: data.Params.DNSNames, - // EmailAddresses: data.Params.EmailAddresses, - // IPAddresses: data.Params.IPAddresses, - // URIs: data.Params.URIs, } if data.Params.NotBeforeDuration > 0 { certTemplate.NotBefore = time.Now().Add(-1 * data.Params.NotBeforeDuration) @@ -387,8 +391,6 @@ func CreateCertificate(b *HsmPkiBackend, data *certutil.CreationBundle) (*certut } // Add this before calling addKeyUsages - //if data.SigningBundle == nil { - //} else if data.Params.BasicConstraintsValidForNonCA { certTemplate.BasicConstraintsValid = true certTemplate.IsCA = false @@ -410,11 +412,6 @@ func CreateCertificate(b *HsmPkiBackend, data *certutil.CreationBundle) (*certut certTemplate.CRLDistributionPoints = data.Params.URLs.CRLDistributionPoints certTemplate.OCSPServer = data.Params.URLs.OCSPServers - //if data.Params.IsCA { - // certTemplate.BasicConstraintsValid = true - // certTemplate.IsCA = true - //} - var certBytes []byte if data.SigningBundle != nil { @@ -434,19 +431,23 @@ func CreateCertificate(b *HsmPkiBackend, data *certutil.CreationBundle) (*certut certBytes, err = x509.CreateCertificate(rand.Reader, certTemplate, caCert, result.PrivateKey.Public(), caSigner) //data.SigningBundle.PrivateKey) } else { - certTemplate.SignatureAlgorithm = selectHashAlgo(x509.ECDSA, b.cachedCAConfig.hashAlgo) - if certTemplate.SignatureAlgorithm == 0 { - return nil, errutil.InternalError{Err: errwrap.Wrapf("Unknown SignatureAlgorithm", nil).Error()} - } + if keyType, err := pkcs11client.GetPubKeyType(publicKey); err != nil { + return nil, errutil.InternalError{Err: errwrap.Wrapf("Unsupported PublicKeyAlgorithm", nil).Error()} + } else { + certTemplate.SignatureAlgorithm = selectHashAlgo(keyType, b.cachedCAConfig.hashAlgo) + if certTemplate.SignatureAlgorithm == 0 { + return nil, errutil.InternalError{Err: errwrap.Wrapf("Unknown SignatureAlgorithm", nil).Error()} + } - var caSigner pkcs11client.HsmSigner - caSigner.KeyConfig.Label = b.cachedCAConfig.caKeyAlias - caSigner.Pkcs11Client = &b.pkcs11client - caSigner.PublicKey = publicKey + var caSigner pkcs11client.HsmSigner + caSigner.KeyConfig.Label = b.cachedCAConfig.caKeyAlias + caSigner.Pkcs11Client = &b.pkcs11client + caSigner.PublicKey = publicKey - certBytes, err = x509.CreateCertificate(rand.Reader, certTemplate, certTemplate, caSigner.PublicKey, caSigner) + certBytes, err = x509.CreateCertificate(rand.Reader, certTemplate, certTemplate, caSigner.PublicKey, caSigner) - // return nil, errutil.InternalError{Err: errwrap.Wrapf("Self-signed roots are unsupported", nil).Error()} + // return nil, errutil.InternalError{Err: errwrap.Wrapf("Self-signed roots are unsupported", nil).Error()} + } } if err != nil { @@ -511,3 +512,15 @@ func selectHashAlgo(pubKeyAlgo x509.PublicKeyAlgorithm, cachedHashAlgo crypto.Ha } } + +func GetDataKeyType(data *string) (keyType uint, err error) { + switch *data { + case "rsa": + keyType = pkcs11.CKK_RSA + case "ec": + keyType = pkcs11.CKK_EC + default: + return 0, errutil.UserError{"Unsupported key type please specify rsa or ec"} + } + return +} diff --git a/pkg/hsmpki/hsmpath_fetch.go b/pkg/hsmpki/hsmpath_fetch.go index 762ddd2..c60d869 100644 --- a/pkg/hsmpki/hsmpath_fetch.go +++ b/pkg/hsmpki/hsmpath_fetch.go @@ -9,7 +9,7 @@ import ( ) // This returns the currently configured key alias that corresponds to the Intermediate CA's private key in the HSM -func pathFetchCAKeyAlias(b *HsmPkiBackend) *framework.Path { +func pathFetchCAKeyLabel(b *HsmPkiBackend) *framework.Path { return &framework.Path{ Pattern: PATH_CAKEYLABEL, diff --git a/pkg/hsmpki/hsmpath_intermediate.go b/pkg/hsmpki/hsmpath_intermediate.go index a07a578..560569e 100644 --- a/pkg/hsmpki/hsmpath_intermediate.go +++ b/pkg/hsmpki/hsmpath_intermediate.go @@ -83,6 +83,10 @@ For RSA and ECDSA the options are SHA-256, SHA-384 or SHA-512. func (b *HsmPkiBackend) pathGenerateIntermediate(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { var err error + if err = b.checkPkcs11ConnectionSync(); err != nil { + return nil, err + } + exported, format, role, errorResp := b.getGenerationParams(data) if errorResp != nil { return errorResp, nil diff --git a/pkg/hsmpki/hsmpath_issue_sign.go b/pkg/hsmpki/hsmpath_issue_sign.go index c1df229..61b68b8 100644 --- a/pkg/hsmpki/hsmpath_issue_sign.go +++ b/pkg/hsmpki/hsmpath_issue_sign.go @@ -94,7 +94,9 @@ func (b *HsmPkiBackend) pathSign(ctx context.Context, req *logical.Request, data func (b *HsmPkiBackend) pathIssueSignCert(ctx context.Context, req *logical.Request, data *framework.FieldData, role *pki.RoleEntry, useCSR, useCSRValues bool) (*logical.Response, error) { - b.checkPkcs11ConnectionSync() + if err := b.checkPkcs11ConnectionSync(); err != nil { + return nil, err + } // If storing the certificate and on a performance standby, forward this request on to the primary if !role.NoStore && b.pkiBackend.Backend.System().ReplicationState().HasState(consts.ReplicationPerformanceStandby) { diff --git a/pkg/hsmpki/hsmpath_root.go b/pkg/hsmpki/hsmpath_root.go index 815b231..c08afed 100644 --- a/pkg/hsmpki/hsmpath_root.go +++ b/pkg/hsmpki/hsmpath_root.go @@ -7,6 +7,7 @@ import ( "encoding/base64" "encoding/pem" "fmt" + "github.com/mode51software/pkcs11helper/pkg/pkcs11client" "github.com/mode51software/vaultplugin-hsmpki/pkg/pki" "reflect" "strings" @@ -115,12 +116,26 @@ func pathSignSelfIssued(b *HsmPkiBackend) *framework.Path { } func (b *HsmPkiBackend) pathCADeleteRoot(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { - return nil, req.Storage.Delete(ctx, "config/rootca_bundle") + + if len(b.cachedCAConfig.caKeyAlias) > 0 { + + keyConfig := pkcs11client.KeyConfig{Label: b.cachedCAConfig.caKeyAlias} + + if err := b.pkcs11client.DeleteKeyPair(&keyConfig); err != nil { + return nil, errutil.UserError{"Unable to delete CA #{{err}}"} + } + + } + return nil, req.Storage.Delete(ctx, CA_BUNDLE) } func (b *HsmPkiBackend) pathCAGenerateRoot(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { var err error + if err = b.checkPkcs11ConnectionSync(); err != nil { + return nil, err + } + entry, err := req.Storage.Get(ctx, CA_BUNDLE) if err != nil { return nil, err @@ -237,7 +252,7 @@ func (b *HsmPkiBackend) pathCAGenerateRoot(ctx context.Context, req *logical.Req } // Build a fresh CRL - //err = buildCRL(ctx, b, req, true) + err = buildCRL(ctx, b, req, true) if err != nil { return nil, err } diff --git a/pkg/pki/pki_api.go b/pkg/pki/pki_api.go index 3b2e81a..5ed7e29 100644 --- a/pkg/pki/pki_api.go +++ b/pkg/pki/pki_api.go @@ -111,6 +111,10 @@ func PathConfigCRL(b *backend) *framework.Path { return pathConfigCRL(b) } +func PathConfigURLs(b *backend) *framework.Path { + return pathConfigURLs(b) +} + func (b *backend) PathCRLWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { return b.pathCRLWrite(ctx, req, d) }