From 5d702751c3997c0a0f99a4841384cd44b5006e3a Mon Sep 17 00:00:00 2001 From: Nick Smith Date: Tue, 9 May 2023 09:37:48 +0100 Subject: [PATCH 1/4] Add function for accessing underlying PKCS#11 keys Add a function to allow users of this package to access underlying PKCS#11-isms so that custom extensions can be built. For example the new function could be used to wrap/export a key or unwrap/import a key using the handle associated with an existing private or secret key. --- keys.go | 22 ++++++++++++++++++++++ keys_test.go | 17 +++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/keys.go b/keys.go index 998663a..354fb63 100644 --- a/keys.go +++ b/keys.go @@ -611,3 +611,25 @@ func (c *Context) GetPubAttribute(key interface{}, attribute AttributeType) (a * return set[attribute], nil } + +// WithPKCS11Key provides a custom extension point that exposes the underlying PKCS#11 key handle and an active session to the +// supplied callback. This can be used to e.g. extend this package non-intrusively and provide custom HSM interaction code. +func (c *Context) WithPKCS11Key(key interface{}, f func(ctx *pkcs11.Ctx, sessionHandle pkcs11.SessionHandle, keyHandle pkcs11.ObjectHandle) error) error { + if c.closed.Get() { + return errClosed + } + var keyHandle pkcs11.ObjectHandle + switch k := (key).(type) { + case *pkcs11PrivateKeyDSA: + keyHandle = k.pubKeyHandle + case *pkcs11PrivateKeyRSA: + keyHandle = k.pubKeyHandle + case *pkcs11PrivateKeyECDSA: + keyHandle = k.pubKeyHandle + default: + return errors.Errorf("not a PKCS#11 secret or private key") + } + return c.withSession(func(session *pkcs11Session) error { + return f(session.ctx, session.handle, keyHandle) + }) +} diff --git a/keys_test.go b/keys_test.go index ca8ab6a..934373d 100644 --- a/keys_test.go +++ b/keys_test.go @@ -221,3 +221,20 @@ func TestGettingUnsupportedKeyTypeAttributes(t *testing.T) { require.Error(t, err) }) } + +func TestWithKey(t *testing.T) { + withContext(t, func(ctx *Context) { + id := randomBytes() + key, err := ctx.GenerateSecretKey(id, 128, CipherAES) + require.NoError(t, err) + + ctx.WithPKCS11Key(key, func(ctx *pkcs11.Ctx, sessionHandle pkcs11.SessionHandle, keyHandle pkcs11.ObjectHandle) error { + assert.NotNil(t, key) + // PKCS#11 2.20 spec: "Valid session handles and object handles in Cryptoki always have nonzero values." + assert.True(t, sessionHandle != 0) + // Verify the key's internal handle matches what is passed down. + assert.Equal(t, keyHandle, key.handle) + return nil + }) + }) +} From b22039c6c84befdef8b315a8b75d6e02c18fba25 Mon Sep 17 00:00:00 2001 From: Nick Smith Date: Fri, 12 May 2023 20:33:43 +0100 Subject: [PATCH 2/4] Use correct handle --- keys.go | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/keys.go b/keys.go index 354fb63..64bde0d 100644 --- a/keys.go +++ b/keys.go @@ -612,24 +612,27 @@ func (c *Context) GetPubAttribute(key interface{}, attribute AttributeType) (a * return set[attribute], nil } -// WithPKCS11Key provides a custom extension point that exposes the underlying PKCS#11 key handle and an active session to the +// WithPKCS11Key provides a custom extension point that exposes the underlying PKCS#11 object handle and an active session to the // supplied callback. This can be used to e.g. extend this package non-intrusively and provide custom HSM interaction code. -func (c *Context) WithPKCS11Key(key interface{}, f func(ctx *pkcs11.Ctx, sessionHandle pkcs11.SessionHandle, keyHandle pkcs11.ObjectHandle) error) error { +func (c *Context) WithPKCS11Key(key interface{}, f func(*pkcs11.Ctx, pkcs11.SessionHandle, pkcs11.ObjectHandle) error) error { if c.closed.Get() { return errClosed } - var keyHandle pkcs11.ObjectHandle + var objectHandle pkcs11.ObjectHandle switch k := (key).(type) { case *pkcs11PrivateKeyDSA: - keyHandle = k.pubKeyHandle + objectHandle = k.handle case *pkcs11PrivateKeyRSA: - keyHandle = k.pubKeyHandle + objectHandle = k.handle case *pkcs11PrivateKeyECDSA: - keyHandle = k.pubKeyHandle + objectHandle = k.handle + case *SecretKey: + objectHandle = k.handle default: - return errors.Errorf("not a PKCS#11 secret or private key") + return errors.Errorf("not a PKCS#11 key") } + // invoke f with a valid session. return c.withSession(func(session *pkcs11Session) error { - return f(session.ctx, session.handle, keyHandle) + return f(session.ctx, session.handle, objectHandle) }) } From 4b231846447e4fbeb54f2076da7d0c23fb72b503 Mon Sep 17 00:00:00 2001 From: Nick Smith Date: Fri, 12 May 2023 20:35:18 +0100 Subject: [PATCH 3/4] Fix test name --- keys_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/keys_test.go b/keys_test.go index 934373d..e21a54b 100644 --- a/keys_test.go +++ b/keys_test.go @@ -222,7 +222,7 @@ func TestGettingUnsupportedKeyTypeAttributes(t *testing.T) { }) } -func TestWithKey(t *testing.T) { +func TestWithPKCS11Key(t *testing.T) { withContext(t, func(ctx *Context) { id := randomBytes() key, err := ctx.GenerateSecretKey(id, 128, CipherAES) From bc2b8384236c217d0f11b44534e8892f9734bc35 Mon Sep 17 00:00:00 2001 From: Nick Smith Date: Fri, 12 May 2023 20:38:36 +0100 Subject: [PATCH 4/4] Fixup assertions --- keys_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/keys_test.go b/keys_test.go index e21a54b..b29398b 100644 --- a/keys_test.go +++ b/keys_test.go @@ -229,7 +229,6 @@ func TestWithPKCS11Key(t *testing.T) { require.NoError(t, err) ctx.WithPKCS11Key(key, func(ctx *pkcs11.Ctx, sessionHandle pkcs11.SessionHandle, keyHandle pkcs11.ObjectHandle) error { - assert.NotNil(t, key) // PKCS#11 2.20 spec: "Valid session handles and object handles in Cryptoki always have nonzero values." assert.True(t, sessionHandle != 0) // Verify the key's internal handle matches what is passed down.