@@ -89,11 +89,13 @@ func loadLib(lib, pin, label string) (*pkcs11.Ctx, uint, *pkcs11.SessionHandle,
8989}
9090
9191func (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
118234func (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