Skip to content

Commit

Permalink
[FABG-721] notification on pkcs11 ctx reload
Browse files Browse the repository at this point in the history
Change-Id: Iafbe6b135cef4c346f8c5c09ed46e3e32fb10e1e
Signed-off-by: Sudesh Shetty <[email protected]>
  • Loading branch information
sudeshrshetty committed Sep 13, 2018
1 parent a739834 commit 1eb1d28
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 22 deletions.
74 changes: 56 additions & 18 deletions pkg/core/cryptosuite/common/pkcs11/contextHandle.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
var logger = logging.NewLogger("fabsdk/core")
var ctxCache *lazycache.Cache
var once sync.Once
var errSlotIDChanged = fmt.Errorf("slot id changed")

//LoadPKCS11ContextHandle loads PKCS11 context handler instance from underlying cache
func LoadPKCS11ContextHandle(lib, label, pin string, opts ...Options) (*ContextHandle, error) {
Expand Down Expand Up @@ -58,14 +59,20 @@ func LoadContextAndLogin(lib, pin, label string) (*ContextHandle, error) {

//ContextHandle encapsulate basic pkcs11.Ctx operations and manages sessions
type ContextHandle struct {
ctx *pkcs11.Ctx
slot uint
pin string
lib string
label string
sessions chan pkcs11.SessionHandle
opts ctxOpts
lock sync.RWMutex
ctx *pkcs11.Ctx
slot uint
pin string
lib string
label string
sessions chan pkcs11.SessionHandle
opts ctxOpts
reloadNotification chan struct{}
lock sync.RWMutex
}

// NotifyCtxReload registers a channel to get notification when underlying pkcs11.Ctx is recreated
func (handle *ContextHandle) NotifyCtxReload(ch chan struct{}) {
handle.reloadNotification = ch
}

//OpenSession opens a session between an application and a token.
Expand Down Expand Up @@ -319,22 +326,20 @@ func (handle *ContextHandle) FindKeyPairFromSKI(session pkcs11.SessionHandle, sk
func (handle *ContextHandle) validateSession(currentSession pkcs11.SessionHandle) pkcs11.SessionHandle {

handle.lock.RLock()
_, e := handle.ctx.GetSessionInfo(currentSession)

if e == nil {
_, e = handle.ctx.GetOperationState(currentSession)
}
e := handle.detectErrorCondition(currentSession)

switch e {
case pkcs11.Error(pkcs11.CKR_OBJECT_HANDLE_INVALID),
case errSlotIDChanged,
pkcs11.Error(pkcs11.CKR_OBJECT_HANDLE_INVALID),
pkcs11.Error(pkcs11.CKR_SESSION_HANDLE_INVALID),
pkcs11.Error(pkcs11.CKR_SESSION_CLOSED),
pkcs11.Error(pkcs11.CKR_TOKEN_NOT_PRESENT),
pkcs11.Error(pkcs11.CKR_DEVICE_ERROR),
pkcs11.Error(pkcs11.CKR_GENERAL_ERROR),
pkcs11.Error(pkcs11.CKR_USER_NOT_LOGGED_IN):

logger.Warnf("Found error condition [%s], attempting to recreate session and re-login....", e)
logger.Warnf("Found error condition [%s], attempting to recreate pkcs11 context and re-login....", e)

handle.lock.RUnlock()
handle.lock.Lock()
Expand All @@ -345,32 +350,35 @@ func (handle *ContextHandle) validateSession(currentSession pkcs11.SessionHandle
//create new context
newCtx := handle.createNewPKCS11Ctx()
if newCtx == nil {
logger.Warn("Failed to recreate new context for given library")
return currentSession
logger.Warn("Failed to recreate new pkcs11 context for given library")
return 0
}

//find slot
slot, found := handle.findSlot(newCtx)
if !found {
logger.Warnf("Unable to find slot for label :%s", handle.label)
return currentSession
return 0
}
logger.Debug("got the slot ", slot)

//open new session for given slot
newSession, err := createNewSession(newCtx, slot)
if err != nil {
logger.Fatalf("OpenSession [%s]\n", err)
return 0
}
logger.Debugf("Recreated new pkcs11 session %+v on slot %d\n", newSession, slot)

//login with new session
err = newCtx.Login(newSession, pkcs11.CKU_USER, handle.pin)
if err != nil && err != pkcs11.Error(pkcs11.CKR_USER_ALREADY_LOGGED_IN) {
logger.Warnf("Unable to login with new session :%s", newSession)
return currentSession
return 0
}

handle.sendNotification()

handle.ctx = newCtx
handle.slot = slot
handle.sessions = make(chan pkcs11.SessionHandle, handle.opts.sessionCacheSize)
Expand All @@ -390,6 +398,36 @@ func (handle *ContextHandle) validateSession(currentSession pkcs11.SessionHandle
}
}

//detectErrorCondition checks if given session handle has errors
func (handle *ContextHandle) detectErrorCondition(currentSession pkcs11.SessionHandle) error {
var e error
slot, ok := handle.findSlot(handle.ctx)
if !ok || slot != handle.slot {
e = errSlotIDChanged
}

if e == nil {
_, e = handle.ctx.GetSessionInfo(currentSession)
if e == nil {
_, e = handle.ctx.GetOperationState(currentSession)
}
}

return e
}

//sendNotification sends ctx reload notificatin if channel available
func (handle *ContextHandle) sendNotification() {
if handle.reloadNotification != nil {
select {
case handle.reloadNotification <- struct{}{}:
logger.Info("Notification sent for recreated pkcs11 ctx")
default:
logger.Warn("Unable to send notification for recreated pkcs11 ctx")
}
}
}

//disposePKCS11Ctx disposes pkcs11.Ctx object
func (handle *ContextHandle) disposePKCS11Ctx() {
//ignore error on close all sessions
Expand Down
20 changes: 16 additions & 4 deletions pkg/core/cryptosuite/common/pkcs11/contextHandle_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@ import (
)

const (
pin = "98765432"
label = "ForFabric"
label1 = "ForFabric1"
allLibs = "/usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so,/usr/lib/softhsm/libsofthsm2.so,/usr/lib/s390x-linux-gnu/softhsm/libsofthsm2.so,/usr/lib/powerpc64le-linux-gnu/softhsm/libsofthsm2.so, /usr/local/Cellar/softhsm/2.1.0/lib/softhsm/libsofthsm2.so"
pin = "98765432"
label = "ForFabric"
label1 = "ForFabric1"
allLibs = "/usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so,/usr/lib/softhsm/libsofthsm2.so,/usr/lib/s390x-linux-gnu/softhsm/libsofthsm2.so,/usr/lib/powerpc64le-linux-gnu/softhsm/libsofthsm2.so, /usr/local/Cellar/softhsm/2.1.0/lib/softhsm/libsofthsm2.so"
ctxReloadTimeout = 2 * time.Second
)

var lib string
Expand Down Expand Up @@ -314,10 +315,21 @@ func TestContextRefreshOnInvalidSession(t *testing.T) {
assert.Equal(t, oldCtx, handle.ctx)

//get session again, now ctx should be refreshed
ch := make(chan struct{}, 1)
handle.NotifyCtxReload(ch)
session = handle.GetSession()
assert.NotEqual(t, oldCtx, handle.ctx)
assert.NotNil(t, session)

var receivedNotification bool
select {
case <-ch:
receivedNotification = true
case <-time.After(ctxReloadTimeout):
t.Fatal("couldn't get notification on ctx update")
}

assert.True(t, receivedNotification)
//reset session pool after test
handle.sessions = make(chan pkcs11.SessionHandle, handle.opts.sessionCacheSize)
}
Expand Down

0 comments on commit 1eb1d28

Please sign in to comment.