Skip to content
This repository was archived by the owner on Apr 25, 2025. It is now read-only.

Commit 2b73bc2

Browse files
committed
[FABG-721] HSM Resilience in internal/fabric/bccsp
Clear all session, recreate session and relogin for following errors CKR_OBJECT_HANDLE_INVALID, CKR_USER_NOT_LOGGED_IN(if login fails after x amount of times then panic) CKR_TOKEN_NOT_PRESENT, CKR_DEVICE_ERROR, CKR_GENERAL_ERROR, CKR_SESSION_HANDLE_INVALID or CKR_SESSION_CLOSED Panic for following errors CKR_DEVICE_MEMORY, CKR_DEVICE_REMOVED Change-Id: I773eeb596f55ffd0b03f8a0f3378218ba9b77d8f Signed-off-by: Sudesh Shetty <sudesh.shetty@securekey.com>
1 parent beccd9c commit 2b73bc2

File tree

2 files changed

+132
-1
lines changed

2 files changed

+132
-1
lines changed

internal/github.com/hyperledger/fabric/bccsp/pkcs11/impl.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ import (
3030

3131
"github.com/hyperledger/fabric-sdk-go/internal/github.com/hyperledger/fabric/sdkpatch/cachebridge"
3232

33+
"sync"
34+
3335
"github.com/hyperledger/fabric-sdk-go/internal/github.com/hyperledger/fabric/bccsp"
3436
"github.com/hyperledger/fabric-sdk-go/internal/github.com/hyperledger/fabric/bccsp/sw"
3537
"github.com/hyperledger/fabric-sdk-go/internal/github.com/hyperledger/fabric/bccsp/utils"
@@ -92,6 +94,9 @@ type impl struct {
9294
lib string
9395
privImport bool
9496
softVerify bool
97+
98+
opts PKCS11Opts
99+
ctxlock sync.RWMutex
95100
}
96101

97102
// KeyGen generates a key using opts.

internal/github.com/hyperledger/fabric/bccsp/pkcs11/pkcs11.go

Lines changed: 127 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,11 +89,13 @@ func loadLib(lib, pin, label string) (*pkcs11.Ctx, uint, *pkcs11.SessionHandle,
8989
}
9090

9191
func (csp *impl) getSession() (session pkcs11.SessionHandle) {
92+
csp.ctxlock.RLock()
9293
select {
9394
case session = <-csp.sessions:
9495
logger.Debugf("Reusing existing pkcs11 session %+v on slot %d\n", session, csp.slot)
9596

9697
default:
98+
9799
// cache is empty (or completely in use), create a new session
98100
var s pkcs11.SessionHandle
99101
var err error
@@ -112,10 +114,134 @@ func (csp *impl) getSession() (session pkcs11.SessionHandle) {
112114
session = s
113115
cachebridge.ClearSession(fmt.Sprintf("%d", session))
114116
}
115-
return session
117+
csp.ctxlock.RUnlock()
118+
119+
return csp.validateSession(session)
120+
}
121+
122+
func (csp *impl) validateSession(currentSession pkcs11.SessionHandle) pkcs11.SessionHandle {
123+
124+
csp.ctxlock.RLock()
125+
_, e := csp.ctx.GetSessionInfo(currentSession)
126+
127+
switch e {
128+
case pkcs11.Error(pkcs11.CKR_OBJECT_HANDLE_INVALID),
129+
pkcs11.Error(pkcs11.CKR_SESSION_HANDLE_INVALID),
130+
pkcs11.Error(pkcs11.CKR_SESSION_CLOSED),
131+
pkcs11.Error(pkcs11.CKR_TOKEN_NOT_PRESENT),
132+
pkcs11.Error(pkcs11.CKR_DEVICE_ERROR),
133+
pkcs11.Error(pkcs11.CKR_GENERAL_ERROR),
134+
pkcs11.Error(pkcs11.CKR_USER_NOT_LOGGED_IN):
135+
136+
logger.Warnf("Found error condition [%s], attempting to recreate session and re-login....", e)
137+
138+
csp.ctxlock.RUnlock()
139+
csp.ctxlock.Lock()
140+
defer csp.ctxlock.Unlock()
141+
142+
//ignore error on close all sessions
143+
csp.ctx.CloseAllSessions(csp.slot)
144+
145+
//clear cache
146+
cachebridge.ClearAllSession()
147+
148+
//Destroy context
149+
csp.ctx.Destroy()
150+
151+
//create new context
152+
newCtx := pkcs11.New(csp.opts.Library)
153+
if newCtx == nil {
154+
logger.Warn("Failed to recreate new context for given library")
155+
return currentSession
156+
}
157+
158+
//initialize new context
159+
newCtx.Initialize()
160+
161+
//get all slots
162+
slots, err := newCtx.GetSlotList(true)
163+
if err != nil {
164+
logger.Warn("Failed to get slot list for recreated context")
165+
return currentSession
166+
}
167+
168+
found := false
169+
var slot uint = 0
170+
171+
//find slot matching label
172+
for _, s := range slots {
173+
info, err := newCtx.GetTokenInfo(s)
174+
if err != nil {
175+
continue
176+
}
177+
logger.Debugf("Looking for %s, found label %s\n", csp.opts.Label, info.Label)
178+
if csp.opts.Label == info.Label {
179+
found = true
180+
slot = s
181+
break
182+
}
183+
}
184+
if !found {
185+
logger.Warnf("Unable to find slot for label :%s", csp.opts.Label)
186+
return currentSession
187+
}
188+
logger.Debug("got the slot ", slot)
189+
190+
//open new session for given slot
191+
var newSession pkcs11.SessionHandle
192+
for i := 0; i < 10; i++ {
193+
newSession, err = newCtx.OpenSession(slot, pkcs11.CKF_SERIAL_SESSION|pkcs11.CKF_RW_SESSION)
194+
if err != nil {
195+
logger.Warningf("OpenSession failed, retrying [%s]\n", err)
196+
} else {
197+
break
198+
}
199+
}
200+
if err != nil {
201+
logger.Fatalf("OpenSession [%s]\n", err)
202+
}
203+
logger.Debugf("Recreated new pkcs11 session %+v on slot %d\n", newSession, slot)
204+
205+
//login with new session
206+
err = newCtx.Login(newSession, pkcs11.CKU_USER, csp.opts.Pin)
207+
if err != nil {
208+
if err != pkcs11.Error(pkcs11.CKR_USER_ALREADY_LOGGED_IN) {
209+
logger.Warnf("Unable to login with new session :%s", newSession)
210+
return currentSession
211+
}
212+
}
213+
214+
csp.ctx = newCtx
215+
csp.slot = slot
216+
csp.sessions = make(chan pkcs11.SessionHandle, sessionCacheSize)
217+
218+
logger.Infof("Able to login with recreated session successfully")
219+
return newSession
220+
221+
case pkcs11.Error(pkcs11.CKR_DEVICE_MEMORY),
222+
pkcs11.Error(pkcs11.CKR_DEVICE_REMOVED):
223+
csp.ctxlock.RUnlock()
224+
panic(fmt.Sprintf("PKCS11 Session failure: [%s]", e))
225+
226+
default:
227+
defer csp.ctxlock.RUnlock()
228+
// default should be a valid session or valid error, return session as it is
229+
return currentSession
230+
}
231+
116232
}
117233

118234
func (csp *impl) returnSession(session pkcs11.SessionHandle) {
235+
csp.ctxlock.RLock()
236+
defer csp.ctxlock.RUnlock()
237+
238+
_, e := csp.ctx.GetSessionInfo(session)
239+
if e != nil {
240+
logger.Warnf("not returning session [%d], due to error [%s]. Discarding it", session, e)
241+
csp.ctx.CloseSession(session)
242+
return
243+
}
244+
119245
select {
120246
case csp.sessions <- session:
121247
// returned session back to session cache

0 commit comments

Comments
 (0)