Skip to content

Commit

Permalink
Add object handle and key cache to bccsp/pkcs11
Browse files Browse the repository at this point in the history
With this change, object handles obtained through findKeyPairFromSKI are
cached in the PKCS#11 implementation of BCCSP. Keys constructed by
getECKey are also cached.

In support of these changes, in addition to pooling idle sessions, the
provider tracks active sessions. If some condition occurs that results
in all sessions being closed, cached object handles are no longer valid
so the caches are purged.

Signed-off-by: Gari Singh <gari.r.singh@gmail.com>
Signed-off-by: Matthew Sykes <sykesmat@us.ibm.com>
  • Loading branch information
mastersingh24 authored and ale-linux committed Sep 7, 2020
1 parent d626146 commit 11cbae9
Show file tree
Hide file tree
Showing 4 changed files with 434 additions and 132 deletions.
78 changes: 57 additions & 21 deletions bccsp/pkcs11/impl.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ import (
"crypto/ecdsa"
"crypto/rsa"
"crypto/x509"
"encoding/hex"
"os"
"sync"

"github.com/hyperledger/fabric/bccsp"
"github.com/hyperledger/fabric/bccsp/sw"
Expand Down Expand Up @@ -44,19 +46,24 @@ func New(opts PKCS11Opts, keyStore bccsp.KeyStore) (bccsp.BCCSP, error) {
return nil, errors.New("Invalid bccsp.KeyStore instance. It must be different from nil")
}

lib := opts.Library
pin := opts.Pin
label := opts.Label
ctx, slot, session, err := loadLib(lib, pin, label)
if err != nil {
return nil, errors.Wrapf(err, "Failed initializing PKCS11 library %s %s",
lib, label)
var sessPool chan pkcs11.SessionHandle
if sessionCacheSize > 0 {
sessPool = make(chan pkcs11.SessionHandle, sessionCacheSize)
}

csp := &impl{
BCCSP: swCSP,
conf: conf,
softVerify: opts.SoftVerify,
immutable: opts.Immutable,
sessPool: sessPool,
sessions: map[pkcs11.SessionHandle]struct{}{},
handleCache: map[string]pkcs11.ObjectHandle{},
keyCache: map[string]bccsp.Key{},
altId: opts.AltId,
}

sessions := make(chan pkcs11.SessionHandle, sessionCacheSize)
csp := &impl{swCSP, conf, keyStore, ctx, sessions, slot, pin, lib, opts.SoftVerify, opts.Immutable, opts.AltId}
csp.returnSession(*session)
return csp, nil
return csp.initialize(opts)
}

type impl struct {
Expand All @@ -65,17 +72,24 @@ type impl struct {
conf *config
ks bccsp.KeyStore

ctx *pkcs11.Ctx
sessions chan pkcs11.SessionHandle
slot uint
pin string
ctx *pkcs11.Ctx
slot uint
pin string

lib string
softVerify bool
//Immutable flag makes object immutable
immutable bool
// Alternate identifier of the private key
altId string

sessLock sync.Mutex
sessPool chan pkcs11.SessionHandle
sessions map[pkcs11.SessionHandle]struct{}

cacheLock sync.RWMutex
handleCache map[string]pkcs11.ObjectHandle
keyCache map[string]bccsp.Key
}

// KeyGen generates a key using opts.
Expand Down Expand Up @@ -117,6 +131,19 @@ func (csp *impl) KeyGen(opts bccsp.KeyGenOpts) (k bccsp.Key, err error) {
return k, nil
}

func (csp *impl) cacheKey(ski []byte, key bccsp.Key) {
csp.cacheLock.Lock()
csp.keyCache[hex.EncodeToString(ski)] = key
csp.cacheLock.Unlock()
}

func (csp *impl) cachedKey(ski []byte) (bccsp.Key, bool) {
csp.cacheLock.RLock()
defer csp.cacheLock.RUnlock()
key, ok := csp.keyCache[hex.EncodeToString(ski)]
return key, ok
}

// KeyImport imports a key from its raw representation using opts.
// The opts argument should be appropriate for the primitive used.
func (csp *impl) KeyImport(raw interface{}, opts bccsp.KeyImportOpts) (k bccsp.Key, err error) {
Expand Down Expand Up @@ -157,14 +184,23 @@ func (csp *impl) KeyImport(raw interface{}, opts bccsp.KeyImportOpts) (k bccsp.K
// GetKey returns the key this CSP associates to
// the Subject Key Identifier ski.
func (csp *impl) GetKey(ski []byte) (bccsp.Key, error) {
if key, ok := csp.cachedKey(ski); ok {
return key, nil
}

pubKey, isPriv, err := csp.getECKey(ski)
if err == nil {
if isPriv {
return &ecdsaPrivateKey{ski, ecdsaPublicKey{ski, pubKey}}, nil
}
return &ecdsaPublicKey{ski, pubKey}, nil
if err != nil {
logger.Debugf("Key not found using PKCS11: %v", err)
return csp.BCCSP.GetKey(ski)
}

var key bccsp.Key = &ecdsaPublicKey{ski, pubKey}
if isPriv {
key = &ecdsaPrivateKey{ski, ecdsaPublicKey{ski, pubKey}}
}
return csp.BCCSP.GetKey(ski)

csp.cacheKey(ski, key)
return key, nil
}

// Sign signs digest using key k.
Expand Down
2 changes: 1 addition & 1 deletion bccsp/pkcs11/impl_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ func TestNew(t *testing.T) {
opts.Library = ""
_, err = New(opts, currentKS)
assert.Error(t, err)
assert.Contains(t, err.Error(), "Failed initializing PKCS11 library")
assert.Contains(t, err.Error(), "pkcs11: library path not provided")
}

func TestFindPKCS11LibEnvVars(t *testing.T) {
Expand Down

0 comments on commit 11cbae9

Please sign in to comment.