Skip to content

Commit

Permalink
[FAB-11135] Add cache for pkcs11 object handle
Browse files Browse the repository at this point in the history
Change-Id: I171aac72cc09cd5baab76b4410e4418ec138f5fe
Signed-off-by: Firas Qutishat <firas.qutishat@securekey.com>
Signed-off-by: Sudesh Shetty <sudesh.shetty@securekey.com>
  • Loading branch information
sudeshrshetty authored and troyronda committed Jul 12, 2018
1 parent 93590f0 commit 5cecd16
Show file tree
Hide file tree
Showing 3 changed files with 176 additions and 34 deletions.
8 changes: 7 additions & 1 deletion internal/github.com/hyperledger/fabric/bccsp/pkcs11/impl.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,13 @@ import (
"math/big"
"os"

"sync"

"github.com/hyperledger/fabric-sdk-go/internal/github.com/hyperledger/fabric/bccsp"
"github.com/hyperledger/fabric-sdk-go/internal/github.com/hyperledger/fabric/bccsp/sw"
"github.com/hyperledger/fabric-sdk-go/internal/github.com/hyperledger/fabric/bccsp/utils"
flogging "github.com/hyperledger/fabric-sdk-go/internal/github.com/hyperledger/fabric/sdkpatch/logbridge"
"github.com/hyperledger/fabric-sdk-go/internal/github.com/hyperledger/fabric/sdkpatch/sessioncache"
"github.com/miekg/pkcs11"
"github.com/pkg/errors"
)
Expand Down Expand Up @@ -71,8 +74,10 @@ func New(opts PKCS11Opts, keyStore bccsp.KeyStore) (bccsp.BCCSP, error) {
}

sessions := make(chan pkcs11.SessionHandle, sessionCacheSize)
csp := &impl{swCSP, conf, keyStore, ctx, sessions, slot, lib, opts.Sensitive, opts.SoftVerify}
csp := &impl{BCCSP: swCSP, conf: conf, ks: keyStore, ctx: ctx, sessions: sessions, slot: slot, lib: lib, noPrivImport: opts.Sensitive, softVerify: opts.SoftVerify}
csp.returnSession(*session)
sessioncache.ClearAllSession(csp.rwMtx)

return csp, nil
}

Expand All @@ -89,6 +94,7 @@ type impl struct {
lib string
noPrivImport bool
softVerify bool
rwMtx sync.RWMutex
}

// KeyGen generates a key using opts.
Expand Down
53 changes: 20 additions & 33 deletions internal/github.com/hyperledger/fabric/bccsp/pkcs11/pkcs11.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ import (
"math/big"
"sync"

"time"

logging "github.com/hyperledger/fabric-sdk-go/internal/github.com/hyperledger/fabric/sdkpatch/logbridge"
"github.com/hyperledger/fabric-sdk-go/internal/github.com/hyperledger/fabric/sdkpatch/sessioncache"
"github.com/miekg/pkcs11"
)

Expand Down Expand Up @@ -107,7 +110,11 @@ func (csp *impl) getSession() (session pkcs11.SessionHandle) {
}
logger.Debugf("Created new pkcs11 session %+v on slot %d\n", s, csp.slot)
session = s
sessioncache.ClearSession(csp.rwMtx, fmt.Sprintf("%d", session))
}

sessioncache.AddSession(csp.rwMtx, fmt.Sprintf("%d", session))

return session
}

Expand All @@ -128,13 +135,13 @@ func (csp *impl) getECKey(ski []byte) (pubKey *ecdsa.PublicKey, isPriv bool, err
session := csp.getSession()
defer csp.returnSession(session)
isPriv = true
_, err = findKeyPairFromSKI(p11lib, session, ski, privateKeyFlag)
_, err = csp.findKeyPairFromSKI(p11lib, session, ski, privateKeyFlag)
if err != nil {
isPriv = false
logger.Debugf("Private key not found [%s] for SKI [%s], looking for Public key", err, hex.EncodeToString(ski))
}

publicKey, err := findKeyPairFromSKI(p11lib, session, ski, publicKeyFlag)
publicKey, err := csp.findKeyPairFromSKI(p11lib, session, ski, publicKeyFlag)
if err != nil {
return nil, false, fmt.Errorf("Public key not found [%s] for SKI [%s]", err, hex.EncodeToString(ski))
}
Expand Down Expand Up @@ -306,7 +313,8 @@ func (csp *impl) signP11ECDSA(ski []byte, msg []byte) (R, S *big.Int, err error)
session := csp.getSession()
defer csp.returnSession(session)

privateKey, err := findKeyPairFromSKI(p11lib, session, ski, privateKeyFlag)
privateKey, err := csp.findKeyPairFromSKI(p11lib, session, ski, privateKeyFlag)
defer timeTrack(time.Now(), fmt.Sprintf("signing [session: %d]", session))
if err != nil {
return nil, nil, fmt.Errorf("Private key not found [%s]\n", err)
}
Expand Down Expand Up @@ -338,7 +346,7 @@ func (csp *impl) verifyP11ECDSA(ski []byte, msg []byte, R, S *big.Int, byteSize

logger.Debugf("Verify ECDSA\n")

publicKey, err := findKeyPairFromSKI(p11lib, session, ski, publicKeyFlag)
publicKey, err := csp.findKeyPairFromSKI(p11lib, session, ski, publicKeyFlag)
if err != nil {
return false, fmt.Errorf("Public key not found [%s]\n", err)
}
Expand Down Expand Up @@ -442,34 +450,8 @@ const (
publicKeyFlag = false
)

func findKeyPairFromSKI(mod *pkcs11.Ctx, session pkcs11.SessionHandle, ski []byte, keyType bool) (*pkcs11.ObjectHandle, error) {
ktype := pkcs11.CKO_PUBLIC_KEY
if keyType == privateKeyFlag {
ktype = pkcs11.CKO_PRIVATE_KEY
}

template := []*pkcs11.Attribute{
pkcs11.NewAttribute(pkcs11.CKA_CLASS, ktype),
pkcs11.NewAttribute(pkcs11.CKA_ID, ski),
}
if err := mod.FindObjectsInit(session, template); err != nil {
return nil, err
}

// single session instance, assume one hit only
objs, _, err := mod.FindObjects(session, 1)
if err != nil {
return nil, err
}
if err = mod.FindObjectsFinal(session); err != nil {
return nil, err
}

if len(objs) == 0 {
return nil, fmt.Errorf("Key not found [%s]", hex.Dump(ski))
}

return &objs[0], nil
func (csp *impl) findKeyPairFromSKI(mod *pkcs11.Ctx, session pkcs11.SessionHandle, ski []byte, keyType bool) (*pkcs11.ObjectHandle, error) {
return sessioncache.GetKeyPairFromSessionSKI(csp.rwMtx, &sessioncache.KeyPairCacheKey{Mod: mod, Session: session, SKI: ski, KeyType: keyType})
}

// Fairly straightforward EC-point query, other than opencryptoki
Expand Down Expand Up @@ -585,7 +567,7 @@ func (csp *impl) getSecretValue(ski []byte) []byte {
session := csp.getSession()
defer csp.returnSession(session)

keyHandle, err := findKeyPairFromSKI(p11lib, session, ski, privateKeyFlag)
keyHandle, err := csp.findKeyPairFromSKI(p11lib, session, ski, privateKeyFlag)

var privKey []byte
template := []*pkcs11.Attribute{
Expand Down Expand Up @@ -619,3 +601,8 @@ func nextIDCtr() *big.Int {
id_mutex.Unlock()
return id_ctr
}

func timeTrack(start time.Time, msg string) {
elapsed := time.Since(start)
logger.Debugf("%s took %s", msg, elapsed)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
/*
Copyright SecureKey Technologies Inc. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
/*
Notice: This file has been modified for Hyperledger Fabric SDK Go usage.
Please review third_party pinning scripts and patches for more details.
*/

package sessioncache

import (
"fmt"
"time"

"sync"

"encoding/hex"

flogging "github.com/hyperledger/fabric-sdk-go/internal/github.com/hyperledger/fabric/sdkpatch/logbridge"
"github.com/hyperledger/fabric-sdk-go/pkg/util/concurrent/lazycache"
"github.com/hyperledger/fabric-sdk-go/pkg/util/concurrent/lazyref"
"github.com/miekg/pkcs11"
)

var sessionCache map[string]*lazycache.Cache

var logger = flogging.MustGetLogger("bccsp_p11_sessioncache")

const (
privateKeyFlag = true
)

// keyPairCacheKey
type KeyPairCacheKey struct {
Mod *pkcs11.Ctx
Session pkcs11.SessionHandle
SKI []byte
KeyType bool
}

//String return string value for config key
func (keyPairCacheKey *KeyPairCacheKey) String() string {
return fmt.Sprintf("%x_%t", keyPairCacheKey.SKI, keyPairCacheKey.KeyType)
}

func timeTrack(start time.Time, msg string) {
elapsed := time.Since(start)
logger.Debugf("%s took %s", msg, elapsed)
}

func ClearAllSession(rwMtx sync.RWMutex) {

if sessionCache != nil && len(sessionCache) > 0 {
rwMtx.Lock()
for _, val := range sessionCache {
val.Close()
}
sessionCache = nil
rwMtx.Unlock()
}
}

func ClearSession(rwMtx sync.RWMutex, key string) {
rwMtx.RLock()
val, ok := sessionCache[key]
rwMtx.RUnlock()
if ok {
rwMtx.Lock()
val.Close()
sessionCache[key] = nil
rwMtx.Unlock()

}
}

func AddSession(rwMtx sync.RWMutex, key string) {
rwMtx.RLock()
_, ok := sessionCache[key]
rwMtx.RUnlock()

if !ok {
if sessionCache == nil {
sessionCache = make(map[string]*lazycache.Cache)
}
rwMtx.Lock()
sessionCache[key] = lazycache.New(
"KeyPair_Resolver_Cache",
func(key lazycache.Key) (interface{}, error) {
return lazyref.New(
func() (interface{}, error) {
return getKeyPairFromSKI(key.(*KeyPairCacheKey))
},
), nil
})
rwMtx.Unlock()
}
}

func GetKeyPairFromSessionSKI(rwMtx sync.RWMutex, keyPairCacheKey *KeyPairCacheKey) (*pkcs11.ObjectHandle, error) {
rwMtx.RLock()
val, ok := sessionCache[fmt.Sprintf("%d", keyPairCacheKey.Session)]
rwMtx.RUnlock()
if ok {
defer timeTrack(time.Now(), fmt.Sprintf("finding key [session: %d] [ski: %x]", keyPairCacheKey.Session, keyPairCacheKey.SKI))
value, err := val.Get(keyPairCacheKey)
if err != nil {
return nil, err
}
lazyRef := value.(*lazyref.Reference)
resolver, err := lazyRef.Get()
if err != nil {
return nil, err
}
return resolver.(*pkcs11.ObjectHandle), nil
}
return nil, fmt.Errorf("cannot find session in sessionCache")
}

func getKeyPairFromSKI(keyPairCacheKey *KeyPairCacheKey) (*pkcs11.ObjectHandle, error) {
ktype := pkcs11.CKO_PUBLIC_KEY
if keyPairCacheKey.KeyType == privateKeyFlag {
ktype = pkcs11.CKO_PRIVATE_KEY
}

template := []*pkcs11.Attribute{
pkcs11.NewAttribute(pkcs11.CKA_CLASS, ktype),
pkcs11.NewAttribute(pkcs11.CKA_ID, keyPairCacheKey.SKI),
}
if err := keyPairCacheKey.Mod.FindObjectsInit(keyPairCacheKey.Session, template); err != nil {
return nil, err
}

// single session instance, assume one hit only
objs, _, err := keyPairCacheKey.Mod.FindObjects(keyPairCacheKey.Session, 1)
if err != nil {
return nil, err
}
if err = keyPairCacheKey.Mod.FindObjectsFinal(keyPairCacheKey.Session); err != nil {
return nil, err
}

if len(objs) == 0 {
return nil, fmt.Errorf("Key not found [%s]", hex.Dump(keyPairCacheKey.SKI))
}

return &objs[0], nil
}

0 comments on commit 5cecd16

Please sign in to comment.