1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 
5 /*
6  * token.c
7  *
8  * This file implements the NSSCKFWToken type and methods.
9  */
10 
11 #ifndef CK_T
12 #include "ck.h"
13 #endif /* CK_T */
14 
15 /*
16  * NSSCKFWToken
17  *
18  *  -- create/destroy --
19  *  nssCKFWToken_Create
20  *  nssCKFWToken_Destroy
21  *
22  *  -- public accessors --
23  *  NSSCKFWToken_GetMDToken
24  *  NSSCKFWToken_GetFWSlot
25  *  NSSCKFWToken_GetMDSlot
26  *  NSSCKFWToken_GetSessionState
27  *
28  *  -- implement public accessors --
29  *  nssCKFWToken_GetMDToken
30  *  nssCKFWToken_GetFWSlot
31  *  nssCKFWToken_GetMDSlot
32  *  nssCKFWToken_GetSessionState
33  *  nssCKFWToken_SetSessionState
34  *
35  *  -- private accessors --
36  *  nssCKFWToken_SetSessionState
37  *  nssCKFWToken_RemoveSession
38  *  nssCKFWToken_CloseAllSessions
39  *  nssCKFWToken_GetSessionCount
40  *  nssCKFWToken_GetRwSessionCount
41  *  nssCKFWToken_GetRoSessionCount
42  *  nssCKFWToken_GetSessionObjectHash
43  *  nssCKFWToken_GetMDObjectHash
44  *  nssCKFWToken_GetObjectHandleHash
45  *
46  *  -- module fronts --
47  *  nssCKFWToken_InitToken
48  *  nssCKFWToken_GetLabel
49  *  nssCKFWToken_GetManufacturerID
50  *  nssCKFWToken_GetModel
51  *  nssCKFWToken_GetSerialNumber
52  *  nssCKFWToken_GetHasRNG
53  *  nssCKFWToken_GetIsWriteProtected
54  *  nssCKFWToken_GetLoginRequired
55  *  nssCKFWToken_GetUserPinInitialized
56  *  nssCKFWToken_GetRestoreKeyNotNeeded
57  *  nssCKFWToken_GetHasClockOnToken
58  *  nssCKFWToken_GetHasProtectedAuthenticationPath
59  *  nssCKFWToken_GetSupportsDualCryptoOperations
60  *  nssCKFWToken_GetMaxSessionCount
61  *  nssCKFWToken_GetMaxRwSessionCount
62  *  nssCKFWToken_GetMaxPinLen
63  *  nssCKFWToken_GetMinPinLen
64  *  nssCKFWToken_GetTotalPublicMemory
65  *  nssCKFWToken_GetFreePublicMemory
66  *  nssCKFWToken_GetTotalPrivateMemory
67  *  nssCKFWToken_GetFreePrivateMemory
68  *  nssCKFWToken_GetHardwareVersion
69  *  nssCKFWToken_GetFirmwareVersion
70  *  nssCKFWToken_GetUTCTime
71  *  nssCKFWToken_OpenSession
72  *  nssCKFWToken_GetMechanismCount
73  *  nssCKFWToken_GetMechanismTypes
74  *  nssCKFWToken_GetMechanism
75  */
76 
77 struct NSSCKFWTokenStr {
78     NSSCKFWMutex *mutex;
79     NSSArena *arena;
80     NSSCKMDToken *mdToken;
81     NSSCKFWSlot *fwSlot;
82     NSSCKMDSlot *mdSlot;
83     NSSCKFWInstance *fwInstance;
84     NSSCKMDInstance *mdInstance;
85 
86     /*
87      * Everything above is set at creation time, and then not modified.
88      * The invariants the mutex protects are:
89      *
90      * 1) Each of the cached descriptions (versions, etc.) are in an
91      *    internally consistant state.
92      *
93      * 2) The session counts and hashes are consistant.
94      *
95      * 3) The object hashes are consistant.
96      *
97      * Note that the calls accessing the cached descriptions will call
98      * the NSSCKMDToken methods with the mutex locked.  Those methods
99      * may then call the public NSSCKFWToken routines.  Those public
100      * routines only access the constant data above and the atomic
101      * CK_STATE session state variable below, so there's no problem.
102      * But be careful if you add to this object; mutexes are in
103      * general not reentrant, so don't create deadlock situations.
104      */
105 
106     NSSUTF8 *label;
107     NSSUTF8 *manufacturerID;
108     NSSUTF8 *model;
109     NSSUTF8 *serialNumber;
110     CK_VERSION hardwareVersion;
111     CK_VERSION firmwareVersion;
112 
113     CK_ULONG sessionCount;
114     CK_ULONG rwSessionCount;
115     nssCKFWHash *sessions;
116     nssCKFWHash *sessionObjectHash;
117     nssCKFWHash *mdObjectHash;
118     nssCKFWHash *mdMechanismHash;
119 
120     CK_STATE state;
121 };
122 
123 #ifdef DEBUG
124 /*
125  * But first, the pointer-tracking stuff.
126  *
127  * NOTE: the pointer-tracking support in NSS/base currently relies
128  * upon NSPR's CallOnce support.  That, however, relies upon NSPR's
129  * locking, which is tied into the runtime.  We need a pointer-tracker
130  * implementation that uses the locks supplied through C_Initialize.
131  * That support, however, can be filled in later.  So for now, I'll
132  * just do this routines as no-ops.
133  */
134 
135 static CK_RV
token_add_pointer(const NSSCKFWToken * fwToken)136 token_add_pointer(
137     const NSSCKFWToken *fwToken)
138 {
139     return CKR_OK;
140 }
141 
142 static CK_RV
token_remove_pointer(const NSSCKFWToken * fwToken)143 token_remove_pointer(
144     const NSSCKFWToken *fwToken)
145 {
146     return CKR_OK;
147 }
148 
149 NSS_IMPLEMENT CK_RV
nssCKFWToken_verifyPointer(const NSSCKFWToken * fwToken)150 nssCKFWToken_verifyPointer(
151     const NSSCKFWToken *fwToken)
152 {
153     return CKR_OK;
154 }
155 
156 #endif /* DEBUG */
157 
158 /*
159  * nssCKFWToken_Create
160  *
161  */
162 NSS_IMPLEMENT NSSCKFWToken *
nssCKFWToken_Create(NSSCKFWSlot * fwSlot,NSSCKMDToken * mdToken,CK_RV * pError)163 nssCKFWToken_Create(
164     NSSCKFWSlot *fwSlot,
165     NSSCKMDToken *mdToken,
166     CK_RV *pError)
167 {
168     NSSArena *arena = (NSSArena *)NULL;
169     NSSCKFWToken *fwToken = (NSSCKFWToken *)NULL;
170     CK_BBOOL called_setup = CK_FALSE;
171 
172     /*
173      * We have already verified the arguments in nssCKFWSlot_GetToken.
174      */
175 
176     arena = NSSArena_Create();
177     if (!arena) {
178         *pError = CKR_HOST_MEMORY;
179         goto loser;
180     }
181 
182     fwToken = nss_ZNEW(arena, NSSCKFWToken);
183     if (!fwToken) {
184         *pError = CKR_HOST_MEMORY;
185         goto loser;
186     }
187 
188     fwToken->arena = arena;
189     fwToken->mdToken = mdToken;
190     fwToken->fwSlot = fwSlot;
191     fwToken->fwInstance = nssCKFWSlot_GetFWInstance(fwSlot);
192     fwToken->mdInstance = nssCKFWSlot_GetMDInstance(fwSlot);
193     fwToken->state = CKS_RO_PUBLIC_SESSION; /* some default */
194     fwToken->sessionCount = 0;
195     fwToken->rwSessionCount = 0;
196 
197     fwToken->mutex = nssCKFWInstance_CreateMutex(fwToken->fwInstance, arena, pError);
198     if (!fwToken->mutex) {
199         if (CKR_OK == *pError) {
200             *pError = CKR_GENERAL_ERROR;
201         }
202         goto loser;
203     }
204 
205     fwToken->sessions = nssCKFWHash_Create(fwToken->fwInstance, arena, pError);
206     if (!fwToken->sessions) {
207         if (CKR_OK == *pError) {
208             *pError = CKR_GENERAL_ERROR;
209         }
210         goto loser;
211     }
212 
213     if (CK_TRUE != nssCKFWInstance_GetModuleHandlesSessionObjects(
214                        fwToken->fwInstance)) {
215         fwToken->sessionObjectHash = nssCKFWHash_Create(fwToken->fwInstance,
216                                                         arena, pError);
217         if (!fwToken->sessionObjectHash) {
218             if (CKR_OK == *pError) {
219                 *pError = CKR_GENERAL_ERROR;
220             }
221             goto loser;
222         }
223     }
224 
225     fwToken->mdObjectHash = nssCKFWHash_Create(fwToken->fwInstance,
226                                                arena, pError);
227     if (!fwToken->mdObjectHash) {
228         if (CKR_OK == *pError) {
229             *pError = CKR_GENERAL_ERROR;
230         }
231         goto loser;
232     }
233 
234     fwToken->mdMechanismHash = nssCKFWHash_Create(fwToken->fwInstance,
235                                                   arena, pError);
236     if (!fwToken->mdMechanismHash) {
237         if (CKR_OK == *pError) {
238             *pError = CKR_GENERAL_ERROR;
239         }
240         goto loser;
241     }
242 
243     /* More here */
244 
245     if (mdToken->Setup) {
246         *pError = mdToken->Setup(mdToken, fwToken, fwToken->mdInstance, fwToken->fwInstance);
247         if (CKR_OK != *pError) {
248             goto loser;
249         }
250     }
251 
252     called_setup = CK_TRUE;
253 
254 #ifdef DEBUG
255     *pError = token_add_pointer(fwToken);
256     if (CKR_OK != *pError) {
257         goto loser;
258     }
259 #endif /* DEBUG */
260 
261     *pError = CKR_OK;
262     return fwToken;
263 
264 loser:
265 
266     if (CK_TRUE == called_setup) {
267         if (mdToken->Invalidate) {
268             mdToken->Invalidate(mdToken, fwToken, fwToken->mdInstance, fwToken->fwInstance);
269         }
270     }
271 
272     if (arena) {
273         (void)NSSArena_Destroy(arena);
274     }
275 
276     return (NSSCKFWToken *)NULL;
277 }
278 
279 static void
nss_ckfwtoken_session_iterator(const void * key,void * value,void * closure)280 nss_ckfwtoken_session_iterator(
281     const void *key,
282     void *value,
283     void *closure)
284 {
285     /*
286      * Remember that the fwToken->mutex is locked
287      */
288     NSSCKFWSession *fwSession = (NSSCKFWSession *)value;
289     (void)nssCKFWSession_Destroy(fwSession, CK_FALSE);
290     return;
291 }
292 
293 static void
nss_ckfwtoken_object_iterator(const void * key,void * value,void * closure)294 nss_ckfwtoken_object_iterator(
295     const void *key,
296     void *value,
297     void *closure)
298 {
299     /*
300      * Remember that the fwToken->mutex is locked
301      */
302     NSSCKFWObject *fwObject = (NSSCKFWObject *)value;
303     (void)nssCKFWObject_Finalize(fwObject, CK_FALSE);
304     return;
305 }
306 
307 /*
308  * nssCKFWToken_Destroy
309  *
310  */
311 NSS_IMPLEMENT CK_RV
nssCKFWToken_Destroy(NSSCKFWToken * fwToken)312 nssCKFWToken_Destroy(
313     NSSCKFWToken *fwToken)
314 {
315     CK_RV error = CKR_OK;
316 
317 #ifdef NSSDEBUG
318     error = nssCKFWToken_verifyPointer(fwToken);
319     if (CKR_OK != error) {
320         return error;
321     }
322 #endif /* NSSDEBUG */
323 
324     (void)nssCKFWMutex_Destroy(fwToken->mutex);
325 
326     if (fwToken->mdToken->Invalidate) {
327         fwToken->mdToken->Invalidate(fwToken->mdToken, fwToken,
328                                      fwToken->mdInstance, fwToken->fwInstance);
329     }
330     /* we can destroy the list without locking now because no one else is
331      * referencing us (or _Destroy was invalidly called!)
332      */
333     nssCKFWHash_Iterate(fwToken->sessions, nss_ckfwtoken_session_iterator,
334                         (void *)NULL);
335     nssCKFWHash_Destroy(fwToken->sessions);
336 
337     /* session objects go away when their sessions are removed */
338     if (fwToken->sessionObjectHash) {
339         nssCKFWHash_Destroy(fwToken->sessionObjectHash);
340     }
341 
342     /* free up the token objects */
343     if (fwToken->mdObjectHash) {
344         nssCKFWHash_Iterate(fwToken->mdObjectHash, nss_ckfwtoken_object_iterator,
345                             (void *)NULL);
346         nssCKFWHash_Destroy(fwToken->mdObjectHash);
347     }
348     if (fwToken->mdMechanismHash) {
349         nssCKFWHash_Destroy(fwToken->mdMechanismHash);
350     }
351 
352     nssCKFWSlot_ClearToken(fwToken->fwSlot);
353 
354 #ifdef DEBUG
355     error = token_remove_pointer(fwToken);
356 #endif /* DEBUG */
357 
358     (void)NSSArena_Destroy(fwToken->arena);
359     return error;
360 }
361 
362 /*
363  * nssCKFWToken_GetMDToken
364  *
365  */
366 NSS_IMPLEMENT NSSCKMDToken *
nssCKFWToken_GetMDToken(NSSCKFWToken * fwToken)367 nssCKFWToken_GetMDToken(
368     NSSCKFWToken *fwToken)
369 {
370 #ifdef NSSDEBUG
371     if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) {
372         return (NSSCKMDToken *)NULL;
373     }
374 #endif /* NSSDEBUG */
375 
376     return fwToken->mdToken;
377 }
378 
379 /*
380  * nssCKFWToken_GetArena
381  *
382  */
383 NSS_IMPLEMENT NSSArena *
nssCKFWToken_GetArena(NSSCKFWToken * fwToken,CK_RV * pError)384 nssCKFWToken_GetArena(
385     NSSCKFWToken *fwToken,
386     CK_RV *pError)
387 {
388 #ifdef NSSDEBUG
389     if (!pError) {
390         return (NSSArena *)NULL;
391     }
392 
393     *pError = nssCKFWToken_verifyPointer(fwToken);
394     if (CKR_OK != *pError) {
395         return (NSSArena *)NULL;
396     }
397 #endif /* NSSDEBUG */
398 
399     return fwToken->arena;
400 }
401 
402 /*
403  * nssCKFWToken_GetFWSlot
404  *
405  */
406 NSS_IMPLEMENT NSSCKFWSlot *
nssCKFWToken_GetFWSlot(NSSCKFWToken * fwToken)407 nssCKFWToken_GetFWSlot(
408     NSSCKFWToken *fwToken)
409 {
410 #ifdef NSSDEBUG
411     if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) {
412         return (NSSCKFWSlot *)NULL;
413     }
414 #endif /* NSSDEBUG */
415 
416     return fwToken->fwSlot;
417 }
418 
419 /*
420  * nssCKFWToken_GetMDSlot
421  *
422  */
423 NSS_IMPLEMENT NSSCKMDSlot *
nssCKFWToken_GetMDSlot(NSSCKFWToken * fwToken)424 nssCKFWToken_GetMDSlot(
425     NSSCKFWToken *fwToken)
426 {
427 #ifdef NSSDEBUG
428     if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) {
429         return (NSSCKMDSlot *)NULL;
430     }
431 #endif /* NSSDEBUG */
432 
433     return fwToken->mdSlot;
434 }
435 
436 /*
437  * nssCKFWToken_GetSessionState
438  *
439  */
440 NSS_IMPLEMENT CK_STATE
nssCKFWToken_GetSessionState(NSSCKFWToken * fwToken)441 nssCKFWToken_GetSessionState(
442     NSSCKFWToken *fwToken)
443 {
444 #ifdef NSSDEBUG
445     if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) {
446         return CKS_RO_PUBLIC_SESSION; /* whatever */
447     }
448 #endif /* NSSDEBUG */
449 
450     /*
451      * BTW, do not lock the token in this method.
452      */
453 
454     /*
455      * Theoretically, there is no state if there aren't any
456      * sessions open.  But then we'd need to worry about
457      * reporting an error, etc.  What the heck-- let's just
458      * revert to CKR_RO_PUBLIC_SESSION as the "default."
459      */
460 
461     return fwToken->state;
462 }
463 
464 /*
465  * nssCKFWToken_InitToken
466  *
467  */
468 NSS_IMPLEMENT CK_RV
nssCKFWToken_InitToken(NSSCKFWToken * fwToken,NSSItem * pin,NSSUTF8 * label)469 nssCKFWToken_InitToken(
470     NSSCKFWToken *fwToken,
471     NSSItem *pin,
472     NSSUTF8 *label)
473 {
474     CK_RV error;
475 
476 #ifdef NSSDEBUG
477     error = nssCKFWToken_verifyPointer(fwToken);
478     if (CKR_OK != error) {
479         return CKR_ARGUMENTS_BAD;
480     }
481 #endif /* NSSDEBUG */
482 
483     error = nssCKFWMutex_Lock(fwToken->mutex);
484     if (CKR_OK != error) {
485         return error;
486     }
487 
488     if (fwToken->sessionCount > 0) {
489         error = CKR_SESSION_EXISTS;
490         goto done;
491     }
492 
493     if (!fwToken->mdToken->InitToken) {
494         error = CKR_DEVICE_ERROR;
495         goto done;
496     }
497 
498     if (!pin) {
499         if (nssCKFWToken_GetHasProtectedAuthenticationPath(fwToken)) {
500             ; /* okay */
501         } else {
502             error = CKR_PIN_INCORRECT;
503             goto done;
504         }
505     }
506 
507     if (!label) {
508         label = (NSSUTF8 *)"";
509     }
510 
511     error = fwToken->mdToken->InitToken(fwToken->mdToken, fwToken,
512                                         fwToken->mdInstance, fwToken->fwInstance, pin, label);
513 
514 done:
515     (void)nssCKFWMutex_Unlock(fwToken->mutex);
516     return error;
517 }
518 
519 /*
520  * nssCKFWToken_GetLabel
521  *
522  */
523 NSS_IMPLEMENT CK_RV
nssCKFWToken_GetLabel(NSSCKFWToken * fwToken,CK_CHAR label[32])524 nssCKFWToken_GetLabel(
525     NSSCKFWToken *fwToken,
526     CK_CHAR label[32])
527 {
528     CK_RV error = CKR_OK;
529 
530 #ifdef NSSDEBUG
531     if ((CK_CHAR_PTR)NULL == label) {
532         return CKR_ARGUMENTS_BAD;
533     }
534 
535     error = nssCKFWToken_verifyPointer(fwToken);
536     if (CKR_OK != error) {
537         return error;
538     }
539 #endif /* NSSDEBUG */
540 
541     error = nssCKFWMutex_Lock(fwToken->mutex);
542     if (CKR_OK != error) {
543         return error;
544     }
545 
546     if (!fwToken->label) {
547         if (fwToken->mdToken->GetLabel) {
548             fwToken->label = fwToken->mdToken->GetLabel(fwToken->mdToken, fwToken,
549                                                         fwToken->mdInstance, fwToken->fwInstance, &error);
550             if ((!fwToken->label) && (CKR_OK != error)) {
551                 goto done;
552             }
553         } else {
554             fwToken->label = (NSSUTF8 *)"";
555         }
556     }
557 
558     (void)nssUTF8_CopyIntoFixedBuffer(fwToken->label, (char *)label, 32, ' ');
559     error = CKR_OK;
560 
561 done:
562     (void)nssCKFWMutex_Unlock(fwToken->mutex);
563     return error;
564 }
565 
566 /*
567  * nssCKFWToken_GetManufacturerID
568  *
569  */
570 NSS_IMPLEMENT CK_RV
nssCKFWToken_GetManufacturerID(NSSCKFWToken * fwToken,CK_CHAR manufacturerID[32])571 nssCKFWToken_GetManufacturerID(
572     NSSCKFWToken *fwToken,
573     CK_CHAR manufacturerID[32])
574 {
575     CK_RV error = CKR_OK;
576 
577 #ifdef NSSDEBUG
578     if ((CK_CHAR_PTR)NULL == manufacturerID) {
579         return CKR_ARGUMENTS_BAD;
580     }
581 
582     error = nssCKFWToken_verifyPointer(fwToken);
583     if (CKR_OK != error) {
584         return error;
585     }
586 #endif /* NSSDEBUG */
587 
588     error = nssCKFWMutex_Lock(fwToken->mutex);
589     if (CKR_OK != error) {
590         return error;
591     }
592 
593     if (!fwToken->manufacturerID) {
594         if (fwToken->mdToken->GetManufacturerID) {
595             fwToken->manufacturerID = fwToken->mdToken->GetManufacturerID(fwToken->mdToken,
596                                                                           fwToken, fwToken->mdInstance, fwToken->fwInstance, &error);
597             if ((!fwToken->manufacturerID) && (CKR_OK != error)) {
598                 goto done;
599             }
600         } else {
601             fwToken->manufacturerID = (NSSUTF8 *)"";
602         }
603     }
604 
605     (void)nssUTF8_CopyIntoFixedBuffer(fwToken->manufacturerID, (char *)manufacturerID, 32, ' ');
606     error = CKR_OK;
607 
608 done:
609     (void)nssCKFWMutex_Unlock(fwToken->mutex);
610     return error;
611 }
612 
613 /*
614  * nssCKFWToken_GetModel
615  *
616  */
617 NSS_IMPLEMENT CK_RV
nssCKFWToken_GetModel(NSSCKFWToken * fwToken,CK_CHAR model[16])618 nssCKFWToken_GetModel(
619     NSSCKFWToken *fwToken,
620     CK_CHAR model[16])
621 {
622     CK_RV error = CKR_OK;
623 
624 #ifdef NSSDEBUG
625     if ((CK_CHAR_PTR)NULL == model) {
626         return CKR_ARGUMENTS_BAD;
627     }
628 
629     error = nssCKFWToken_verifyPointer(fwToken);
630     if (CKR_OK != error) {
631         return error;
632     }
633 #endif /* NSSDEBUG */
634 
635     error = nssCKFWMutex_Lock(fwToken->mutex);
636     if (CKR_OK != error) {
637         return error;
638     }
639 
640     if (!fwToken->model) {
641         if (fwToken->mdToken->GetModel) {
642             fwToken->model = fwToken->mdToken->GetModel(fwToken->mdToken, fwToken,
643                                                         fwToken->mdInstance, fwToken->fwInstance, &error);
644             if ((!fwToken->model) && (CKR_OK != error)) {
645                 goto done;
646             }
647         } else {
648             fwToken->model = (NSSUTF8 *)"";
649         }
650     }
651 
652     (void)nssUTF8_CopyIntoFixedBuffer(fwToken->model, (char *)model, 16, ' ');
653     error = CKR_OK;
654 
655 done:
656     (void)nssCKFWMutex_Unlock(fwToken->mutex);
657     return error;
658 }
659 
660 /*
661  * nssCKFWToken_GetSerialNumber
662  *
663  */
664 NSS_IMPLEMENT CK_RV
nssCKFWToken_GetSerialNumber(NSSCKFWToken * fwToken,CK_CHAR serialNumber[16])665 nssCKFWToken_GetSerialNumber(
666     NSSCKFWToken *fwToken,
667     CK_CHAR serialNumber[16])
668 {
669     CK_RV error = CKR_OK;
670 
671 #ifdef NSSDEBUG
672     if ((CK_CHAR_PTR)NULL == serialNumber) {
673         return CKR_ARGUMENTS_BAD;
674     }
675 
676     error = nssCKFWToken_verifyPointer(fwToken);
677     if (CKR_OK != error) {
678         return error;
679     }
680 #endif /* NSSDEBUG */
681 
682     error = nssCKFWMutex_Lock(fwToken->mutex);
683     if (CKR_OK != error) {
684         return error;
685     }
686 
687     if (!fwToken->serialNumber) {
688         if (fwToken->mdToken->GetSerialNumber) {
689             fwToken->serialNumber = fwToken->mdToken->GetSerialNumber(fwToken->mdToken,
690                                                                       fwToken, fwToken->mdInstance, fwToken->fwInstance, &error);
691             if ((!fwToken->serialNumber) && (CKR_OK != error)) {
692                 goto done;
693             }
694         } else {
695             fwToken->serialNumber = (NSSUTF8 *)"";
696         }
697     }
698 
699     (void)nssUTF8_CopyIntoFixedBuffer(fwToken->serialNumber, (char *)serialNumber, 16, ' ');
700     error = CKR_OK;
701 
702 done:
703     (void)nssCKFWMutex_Unlock(fwToken->mutex);
704     return error;
705 }
706 
707 /*
708  * nssCKFWToken_GetHasRNG
709  *
710  */
711 NSS_IMPLEMENT CK_BBOOL
nssCKFWToken_GetHasRNG(NSSCKFWToken * fwToken)712 nssCKFWToken_GetHasRNG(
713     NSSCKFWToken *fwToken)
714 {
715 #ifdef NSSDEBUG
716     if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) {
717         return CK_FALSE;
718     }
719 #endif /* NSSDEBUG */
720 
721     if (!fwToken->mdToken->GetHasRNG) {
722         return CK_FALSE;
723     }
724 
725     return fwToken->mdToken->GetHasRNG(fwToken->mdToken, fwToken,
726                                        fwToken->mdInstance, fwToken->fwInstance);
727 }
728 
729 /*
730  * nssCKFWToken_GetIsWriteProtected
731  *
732  */
733 NSS_IMPLEMENT CK_BBOOL
nssCKFWToken_GetIsWriteProtected(NSSCKFWToken * fwToken)734 nssCKFWToken_GetIsWriteProtected(
735     NSSCKFWToken *fwToken)
736 {
737 #ifdef NSSDEBUG
738     if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) {
739         return CK_FALSE;
740     }
741 #endif /* NSSDEBUG */
742 
743     if (!fwToken->mdToken->GetIsWriteProtected) {
744         return CK_FALSE;
745     }
746 
747     return fwToken->mdToken->GetIsWriteProtected(fwToken->mdToken, fwToken,
748                                                  fwToken->mdInstance, fwToken->fwInstance);
749 }
750 
751 /*
752  * nssCKFWToken_GetLoginRequired
753  *
754  */
755 NSS_IMPLEMENT CK_BBOOL
nssCKFWToken_GetLoginRequired(NSSCKFWToken * fwToken)756 nssCKFWToken_GetLoginRequired(
757     NSSCKFWToken *fwToken)
758 {
759 #ifdef NSSDEBUG
760     if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) {
761         return CK_FALSE;
762     }
763 #endif /* NSSDEBUG */
764 
765     if (!fwToken->mdToken->GetLoginRequired) {
766         return CK_FALSE;
767     }
768 
769     return fwToken->mdToken->GetLoginRequired(fwToken->mdToken, fwToken,
770                                               fwToken->mdInstance, fwToken->fwInstance);
771 }
772 
773 /*
774  * nssCKFWToken_GetUserPinInitialized
775  *
776  */
777 NSS_IMPLEMENT CK_BBOOL
nssCKFWToken_GetUserPinInitialized(NSSCKFWToken * fwToken)778 nssCKFWToken_GetUserPinInitialized(
779     NSSCKFWToken *fwToken)
780 {
781 #ifdef NSSDEBUG
782     if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) {
783         return CK_FALSE;
784     }
785 #endif /* NSSDEBUG */
786 
787     if (!fwToken->mdToken->GetUserPinInitialized) {
788         return CK_FALSE;
789     }
790 
791     return fwToken->mdToken->GetUserPinInitialized(fwToken->mdToken, fwToken,
792                                                    fwToken->mdInstance, fwToken->fwInstance);
793 }
794 
795 /*
796  * nssCKFWToken_GetRestoreKeyNotNeeded
797  *
798  */
799 NSS_IMPLEMENT CK_BBOOL
nssCKFWToken_GetRestoreKeyNotNeeded(NSSCKFWToken * fwToken)800 nssCKFWToken_GetRestoreKeyNotNeeded(
801     NSSCKFWToken *fwToken)
802 {
803 #ifdef NSSDEBUG
804     if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) {
805         return CK_FALSE;
806     }
807 #endif /* NSSDEBUG */
808 
809     if (!fwToken->mdToken->GetRestoreKeyNotNeeded) {
810         return CK_FALSE;
811     }
812 
813     return fwToken->mdToken->GetRestoreKeyNotNeeded(fwToken->mdToken, fwToken,
814                                                     fwToken->mdInstance, fwToken->fwInstance);
815 }
816 
817 /*
818  * nssCKFWToken_GetHasClockOnToken
819  *
820  */
821 NSS_IMPLEMENT CK_BBOOL
nssCKFWToken_GetHasClockOnToken(NSSCKFWToken * fwToken)822 nssCKFWToken_GetHasClockOnToken(
823     NSSCKFWToken *fwToken)
824 {
825 #ifdef NSSDEBUG
826     if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) {
827         return CK_FALSE;
828     }
829 #endif /* NSSDEBUG */
830 
831     if (!fwToken->mdToken->GetHasClockOnToken) {
832         return CK_FALSE;
833     }
834 
835     return fwToken->mdToken->GetHasClockOnToken(fwToken->mdToken, fwToken,
836                                                 fwToken->mdInstance, fwToken->fwInstance);
837 }
838 
839 /*
840  * nssCKFWToken_GetHasProtectedAuthenticationPath
841  *
842  */
843 NSS_IMPLEMENT CK_BBOOL
nssCKFWToken_GetHasProtectedAuthenticationPath(NSSCKFWToken * fwToken)844 nssCKFWToken_GetHasProtectedAuthenticationPath(
845     NSSCKFWToken *fwToken)
846 {
847 #ifdef NSSDEBUG
848     if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) {
849         return CK_FALSE;
850     }
851 #endif /* NSSDEBUG */
852 
853     if (!fwToken->mdToken->GetHasProtectedAuthenticationPath) {
854         return CK_FALSE;
855     }
856 
857     return fwToken->mdToken->GetHasProtectedAuthenticationPath(fwToken->mdToken,
858                                                                fwToken, fwToken->mdInstance, fwToken->fwInstance);
859 }
860 
861 /*
862  * nssCKFWToken_GetSupportsDualCryptoOperations
863  *
864  */
865 NSS_IMPLEMENT CK_BBOOL
nssCKFWToken_GetSupportsDualCryptoOperations(NSSCKFWToken * fwToken)866 nssCKFWToken_GetSupportsDualCryptoOperations(
867     NSSCKFWToken *fwToken)
868 {
869 #ifdef NSSDEBUG
870     if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) {
871         return CK_FALSE;
872     }
873 #endif /* NSSDEBUG */
874 
875     if (!fwToken->mdToken->GetSupportsDualCryptoOperations) {
876         return CK_FALSE;
877     }
878 
879     return fwToken->mdToken->GetSupportsDualCryptoOperations(fwToken->mdToken,
880                                                              fwToken, fwToken->mdInstance, fwToken->fwInstance);
881 }
882 
883 /*
884  * nssCKFWToken_GetMaxSessionCount
885  *
886  */
887 NSS_IMPLEMENT CK_ULONG
nssCKFWToken_GetMaxSessionCount(NSSCKFWToken * fwToken)888 nssCKFWToken_GetMaxSessionCount(
889     NSSCKFWToken *fwToken)
890 {
891 #ifdef NSSDEBUG
892     if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) {
893         return CK_UNAVAILABLE_INFORMATION;
894     }
895 #endif /* NSSDEBUG */
896 
897     if (!fwToken->mdToken->GetMaxSessionCount) {
898         return CK_UNAVAILABLE_INFORMATION;
899     }
900 
901     return fwToken->mdToken->GetMaxSessionCount(fwToken->mdToken, fwToken,
902                                                 fwToken->mdInstance, fwToken->fwInstance);
903 }
904 
905 /*
906  * nssCKFWToken_GetMaxRwSessionCount
907  *
908  */
909 NSS_IMPLEMENT CK_ULONG
nssCKFWToken_GetMaxRwSessionCount(NSSCKFWToken * fwToken)910 nssCKFWToken_GetMaxRwSessionCount(
911     NSSCKFWToken *fwToken)
912 {
913 #ifdef NSSDEBUG
914     if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) {
915         return CK_UNAVAILABLE_INFORMATION;
916     }
917 #endif /* NSSDEBUG */
918 
919     if (!fwToken->mdToken->GetMaxRwSessionCount) {
920         return CK_UNAVAILABLE_INFORMATION;
921     }
922 
923     return fwToken->mdToken->GetMaxRwSessionCount(fwToken->mdToken, fwToken,
924                                                   fwToken->mdInstance, fwToken->fwInstance);
925 }
926 
927 /*
928  * nssCKFWToken_GetMaxPinLen
929  *
930  */
931 NSS_IMPLEMENT CK_ULONG
nssCKFWToken_GetMaxPinLen(NSSCKFWToken * fwToken)932 nssCKFWToken_GetMaxPinLen(
933     NSSCKFWToken *fwToken)
934 {
935 #ifdef NSSDEBUG
936     if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) {
937         return CK_UNAVAILABLE_INFORMATION;
938     }
939 #endif /* NSSDEBUG */
940 
941     if (!fwToken->mdToken->GetMaxPinLen) {
942         return CK_UNAVAILABLE_INFORMATION;
943     }
944 
945     return fwToken->mdToken->GetMaxPinLen(fwToken->mdToken, fwToken,
946                                           fwToken->mdInstance, fwToken->fwInstance);
947 }
948 
949 /*
950  * nssCKFWToken_GetMinPinLen
951  *
952  */
953 NSS_IMPLEMENT CK_ULONG
nssCKFWToken_GetMinPinLen(NSSCKFWToken * fwToken)954 nssCKFWToken_GetMinPinLen(
955     NSSCKFWToken *fwToken)
956 {
957 #ifdef NSSDEBUG
958     if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) {
959         return CK_UNAVAILABLE_INFORMATION;
960     }
961 #endif /* NSSDEBUG */
962 
963     if (!fwToken->mdToken->GetMinPinLen) {
964         return CK_UNAVAILABLE_INFORMATION;
965     }
966 
967     return fwToken->mdToken->GetMinPinLen(fwToken->mdToken, fwToken,
968                                           fwToken->mdInstance, fwToken->fwInstance);
969 }
970 
971 /*
972  * nssCKFWToken_GetTotalPublicMemory
973  *
974  */
975 NSS_IMPLEMENT CK_ULONG
nssCKFWToken_GetTotalPublicMemory(NSSCKFWToken * fwToken)976 nssCKFWToken_GetTotalPublicMemory(
977     NSSCKFWToken *fwToken)
978 {
979 #ifdef NSSDEBUG
980     if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) {
981         return CK_UNAVAILABLE_INFORMATION;
982     }
983 #endif /* NSSDEBUG */
984 
985     if (!fwToken->mdToken->GetTotalPublicMemory) {
986         return CK_UNAVAILABLE_INFORMATION;
987     }
988 
989     return fwToken->mdToken->GetTotalPublicMemory(fwToken->mdToken, fwToken,
990                                                   fwToken->mdInstance, fwToken->fwInstance);
991 }
992 
993 /*
994  * nssCKFWToken_GetFreePublicMemory
995  *
996  */
997 NSS_IMPLEMENT CK_ULONG
nssCKFWToken_GetFreePublicMemory(NSSCKFWToken * fwToken)998 nssCKFWToken_GetFreePublicMemory(
999     NSSCKFWToken *fwToken)
1000 {
1001 #ifdef NSSDEBUG
1002     if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) {
1003         return CK_UNAVAILABLE_INFORMATION;
1004     }
1005 #endif /* NSSDEBUG */
1006 
1007     if (!fwToken->mdToken->GetFreePublicMemory) {
1008         return CK_UNAVAILABLE_INFORMATION;
1009     }
1010 
1011     return fwToken->mdToken->GetFreePublicMemory(fwToken->mdToken, fwToken,
1012                                                  fwToken->mdInstance, fwToken->fwInstance);
1013 }
1014 
1015 /*
1016  * nssCKFWToken_GetTotalPrivateMemory
1017  *
1018  */
1019 NSS_IMPLEMENT CK_ULONG
nssCKFWToken_GetTotalPrivateMemory(NSSCKFWToken * fwToken)1020 nssCKFWToken_GetTotalPrivateMemory(
1021     NSSCKFWToken *fwToken)
1022 {
1023 #ifdef NSSDEBUG
1024     if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) {
1025         return CK_UNAVAILABLE_INFORMATION;
1026     }
1027 #endif /* NSSDEBUG */
1028 
1029     if (!fwToken->mdToken->GetTotalPrivateMemory) {
1030         return CK_UNAVAILABLE_INFORMATION;
1031     }
1032 
1033     return fwToken->mdToken->GetTotalPrivateMemory(fwToken->mdToken, fwToken,
1034                                                    fwToken->mdInstance, fwToken->fwInstance);
1035 }
1036 
1037 /*
1038  * nssCKFWToken_GetFreePrivateMemory
1039  *
1040  */
1041 NSS_IMPLEMENT CK_ULONG
nssCKFWToken_GetFreePrivateMemory(NSSCKFWToken * fwToken)1042 nssCKFWToken_GetFreePrivateMemory(
1043     NSSCKFWToken *fwToken)
1044 {
1045 #ifdef NSSDEBUG
1046     if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) {
1047         return CK_UNAVAILABLE_INFORMATION;
1048     }
1049 #endif /* NSSDEBUG */
1050 
1051     if (!fwToken->mdToken->GetFreePrivateMemory) {
1052         return CK_UNAVAILABLE_INFORMATION;
1053     }
1054 
1055     return fwToken->mdToken->GetFreePrivateMemory(fwToken->mdToken, fwToken,
1056                                                   fwToken->mdInstance, fwToken->fwInstance);
1057 }
1058 
1059 /*
1060  * nssCKFWToken_GetHardwareVersion
1061  *
1062  */
1063 NSS_IMPLEMENT CK_VERSION
nssCKFWToken_GetHardwareVersion(NSSCKFWToken * fwToken)1064 nssCKFWToken_GetHardwareVersion(
1065     NSSCKFWToken *fwToken)
1066 {
1067     CK_VERSION rv;
1068 
1069 #ifdef NSSDEBUG
1070     if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) {
1071         rv.major = rv.minor = 0;
1072         return rv;
1073     }
1074 #endif /* NSSDEBUG */
1075 
1076     if (CKR_OK != nssCKFWMutex_Lock(fwToken->mutex)) {
1077         rv.major = rv.minor = 0;
1078         return rv;
1079     }
1080 
1081     if ((0 != fwToken->hardwareVersion.major) ||
1082         (0 != fwToken->hardwareVersion.minor)) {
1083         rv = fwToken->hardwareVersion;
1084         goto done;
1085     }
1086 
1087     if (fwToken->mdToken->GetHardwareVersion) {
1088         fwToken->hardwareVersion = fwToken->mdToken->GetHardwareVersion(
1089             fwToken->mdToken, fwToken, fwToken->mdInstance, fwToken->fwInstance);
1090     } else {
1091         fwToken->hardwareVersion.major = 0;
1092         fwToken->hardwareVersion.minor = 1;
1093     }
1094 
1095     rv = fwToken->hardwareVersion;
1096 
1097 done:
1098     (void)nssCKFWMutex_Unlock(fwToken->mutex);
1099     return rv;
1100 }
1101 
1102 /*
1103  * nssCKFWToken_GetFirmwareVersion
1104  *
1105  */
1106 NSS_IMPLEMENT CK_VERSION
nssCKFWToken_GetFirmwareVersion(NSSCKFWToken * fwToken)1107 nssCKFWToken_GetFirmwareVersion(
1108     NSSCKFWToken *fwToken)
1109 {
1110     CK_VERSION rv;
1111 
1112 #ifdef NSSDEBUG
1113     if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) {
1114         rv.major = rv.minor = 0;
1115         return rv;
1116     }
1117 #endif /* NSSDEBUG */
1118 
1119     if (CKR_OK != nssCKFWMutex_Lock(fwToken->mutex)) {
1120         rv.major = rv.minor = 0;
1121         return rv;
1122     }
1123 
1124     if ((0 != fwToken->firmwareVersion.major) ||
1125         (0 != fwToken->firmwareVersion.minor)) {
1126         rv = fwToken->firmwareVersion;
1127         goto done;
1128     }
1129 
1130     if (fwToken->mdToken->GetFirmwareVersion) {
1131         fwToken->firmwareVersion = fwToken->mdToken->GetFirmwareVersion(
1132             fwToken->mdToken, fwToken, fwToken->mdInstance, fwToken->fwInstance);
1133     } else {
1134         fwToken->firmwareVersion.major = 0;
1135         fwToken->firmwareVersion.minor = 1;
1136     }
1137 
1138     rv = fwToken->firmwareVersion;
1139 
1140 done:
1141     (void)nssCKFWMutex_Unlock(fwToken->mutex);
1142     return rv;
1143 }
1144 
1145 /*
1146  * nssCKFWToken_GetUTCTime
1147  *
1148  */
1149 NSS_IMPLEMENT CK_RV
nssCKFWToken_GetUTCTime(NSSCKFWToken * fwToken,CK_CHAR utcTime[16])1150 nssCKFWToken_GetUTCTime(
1151     NSSCKFWToken *fwToken,
1152     CK_CHAR utcTime[16])
1153 {
1154     CK_RV error = CKR_OK;
1155 
1156 #ifdef NSSDEBUG
1157     error = nssCKFWToken_verifyPointer(fwToken);
1158     if (CKR_OK != error) {
1159         return error;
1160     }
1161 
1162     if ((CK_CHAR_PTR)NULL == utcTime) {
1163         return CKR_ARGUMENTS_BAD;
1164     }
1165 #endif /* DEBUG */
1166 
1167     if (CK_TRUE != nssCKFWToken_GetHasClockOnToken(fwToken)) {
1168         /* return CKR_DEVICE_ERROR; */
1169         (void)nssUTF8_CopyIntoFixedBuffer((NSSUTF8 *)NULL, (char *)utcTime, 16, ' ');
1170         return CKR_OK;
1171     }
1172 
1173     if (!fwToken->mdToken->GetUTCTime) {
1174         /* It said it had one! */
1175         return CKR_GENERAL_ERROR;
1176     }
1177 
1178     error = fwToken->mdToken->GetUTCTime(fwToken->mdToken, fwToken,
1179                                          fwToken->mdInstance, fwToken->fwInstance, utcTime);
1180     if (CKR_OK != error) {
1181         return error;
1182     }
1183 
1184     /* Sanity-check the data */
1185     {
1186         /* Format is YYYYMMDDhhmmss00 */
1187         int i;
1188         int Y, M, D, h, m, s;
1189         static int dims[] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
1190 
1191         for (i = 0; i < 16; i++) {
1192             if ((utcTime[i] < '0') || (utcTime[i] > '9')) {
1193                 goto badtime;
1194             }
1195         }
1196 
1197         Y = ((utcTime[0] - '0') * 1000) + ((utcTime[1] - '0') * 100) +
1198             ((utcTime[2] - '0') * 10) + (utcTime[3] - '0');
1199         M = ((utcTime[4] - '0') * 10) + (utcTime[5] - '0');
1200         D = ((utcTime[6] - '0') * 10) + (utcTime[7] - '0');
1201         h = ((utcTime[8] - '0') * 10) + (utcTime[9] - '0');
1202         m = ((utcTime[10] - '0') * 10) + (utcTime[11] - '0');
1203         s = ((utcTime[12] - '0') * 10) + (utcTime[13] - '0');
1204 
1205         if ((Y < 1990) || (Y > 3000))
1206             goto badtime; /* Y3K problem.  heh heh heh */
1207         if ((M < 1) || (M > 12))
1208             goto badtime;
1209         if ((D < 1) || (D > 31))
1210             goto badtime;
1211 
1212         if (D > dims[M - 1])
1213             goto badtime; /* per-month check */
1214         if ((2 == M) && (((Y % 4) || !(Y % 100)) &&
1215                          (Y % 400)) &&
1216             (D > 28))
1217             goto badtime; /* leap years */
1218 
1219         if ((h < 0) || (h > 23))
1220             goto badtime;
1221         if ((m < 0) || (m > 60))
1222             goto badtime;
1223         if ((s < 0) || (s > 61))
1224             goto badtime;
1225 
1226         /* 60m and 60 or 61s is only allowed for leap seconds. */
1227         if ((60 == m) || (s >= 60)) {
1228             if ((23 != h) || (60 != m) || (s < 60))
1229                 goto badtime;
1230             /* leap seconds can only happen on June 30 or Dec 31.. I think */
1231             /* if( ((6 != M) || (30 != D)) && ((12 != M) || (31 != D)) ) goto badtime; */
1232         }
1233     }
1234 
1235     return CKR_OK;
1236 
1237 badtime:
1238     return CKR_GENERAL_ERROR;
1239 }
1240 
1241 /*
1242  * nssCKFWToken_OpenSession
1243  *
1244  */
1245 NSS_IMPLEMENT NSSCKFWSession *
nssCKFWToken_OpenSession(NSSCKFWToken * fwToken,CK_BBOOL rw,CK_VOID_PTR pApplication,CK_NOTIFY Notify,CK_RV * pError)1246 nssCKFWToken_OpenSession(
1247     NSSCKFWToken *fwToken,
1248     CK_BBOOL rw,
1249     CK_VOID_PTR pApplication,
1250     CK_NOTIFY Notify,
1251     CK_RV *pError)
1252 {
1253     NSSCKFWSession *fwSession = (NSSCKFWSession *)NULL;
1254     NSSCKMDSession *mdSession;
1255 
1256 #ifdef NSSDEBUG
1257     if (!pError) {
1258         return (NSSCKFWSession *)NULL;
1259     }
1260 
1261     *pError = nssCKFWToken_verifyPointer(fwToken);
1262     if (CKR_OK != *pError) {
1263         return (NSSCKFWSession *)NULL;
1264     }
1265 
1266     switch (rw) {
1267         case CK_TRUE:
1268         case CK_FALSE:
1269             break;
1270         default:
1271             *pError = CKR_ARGUMENTS_BAD;
1272             return (NSSCKFWSession *)NULL;
1273     }
1274 #endif /* NSSDEBUG */
1275 
1276     *pError = nssCKFWMutex_Lock(fwToken->mutex);
1277     if (CKR_OK != *pError) {
1278         return (NSSCKFWSession *)NULL;
1279     }
1280 
1281     if (CK_TRUE == rw) {
1282         /* Read-write session desired */
1283         if (CK_TRUE == nssCKFWToken_GetIsWriteProtected(fwToken)) {
1284             *pError = CKR_TOKEN_WRITE_PROTECTED;
1285             goto done;
1286         }
1287     } else {
1288         /* Read-only session desired */
1289         if (CKS_RW_SO_FUNCTIONS == nssCKFWToken_GetSessionState(fwToken)) {
1290             *pError = CKR_SESSION_READ_WRITE_SO_EXISTS;
1291             goto done;
1292         }
1293     }
1294 
1295     /* We could compare sesion counts to any limits we know of, I guess.. */
1296 
1297     if (!fwToken->mdToken->OpenSession) {
1298         /*
1299          * I'm not sure that the Module actually needs to implement
1300          * mdSessions -- the Framework can keep track of everything
1301          * needed, really.  But I'll sort out that detail later..
1302          */
1303         *pError = CKR_GENERAL_ERROR;
1304         goto done;
1305     }
1306 
1307     fwSession = nssCKFWSession_Create(fwToken, rw, pApplication, Notify, pError);
1308     if (!fwSession) {
1309         if (CKR_OK == *pError) {
1310             *pError = CKR_GENERAL_ERROR;
1311         }
1312         goto done;
1313     }
1314 
1315     mdSession = fwToken->mdToken->OpenSession(fwToken->mdToken, fwToken,
1316                                               fwToken->mdInstance, fwToken->fwInstance, fwSession,
1317                                               rw, pError);
1318     if (!mdSession) {
1319         (void)nssCKFWSession_Destroy(fwSession, CK_FALSE);
1320         if (CKR_OK == *pError) {
1321             *pError = CKR_GENERAL_ERROR;
1322         }
1323         goto done;
1324     }
1325 
1326     *pError = nssCKFWSession_SetMDSession(fwSession, mdSession);
1327     if (CKR_OK != *pError) {
1328         if (mdSession->Close) {
1329             mdSession->Close(mdSession, fwSession, fwToken->mdToken, fwToken,
1330                              fwToken->mdInstance, fwToken->fwInstance);
1331         }
1332         (void)nssCKFWSession_Destroy(fwSession, CK_FALSE);
1333         goto done;
1334     }
1335 
1336     *pError = nssCKFWHash_Add(fwToken->sessions, fwSession, fwSession);
1337     if (CKR_OK != *pError) {
1338         (void)nssCKFWSession_Destroy(fwSession, CK_FALSE);
1339         fwSession = (NSSCKFWSession *)NULL;
1340         goto done;
1341     }
1342 
1343 done:
1344     (void)nssCKFWMutex_Unlock(fwToken->mutex);
1345     return fwSession;
1346 }
1347 
1348 /*
1349  * nssCKFWToken_GetMechanismCount
1350  *
1351  */
1352 NSS_IMPLEMENT CK_ULONG
nssCKFWToken_GetMechanismCount(NSSCKFWToken * fwToken)1353 nssCKFWToken_GetMechanismCount(
1354     NSSCKFWToken *fwToken)
1355 {
1356 #ifdef NSSDEBUG
1357     if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) {
1358         return 0;
1359     }
1360 #endif /* NSSDEBUG */
1361 
1362     if (!fwToken->mdToken->GetMechanismCount) {
1363         return 0;
1364     }
1365 
1366     return fwToken->mdToken->GetMechanismCount(fwToken->mdToken, fwToken,
1367                                                fwToken->mdInstance, fwToken->fwInstance);
1368 }
1369 
1370 /*
1371  * nssCKFWToken_GetMechanismTypes
1372  *
1373  */
1374 NSS_IMPLEMENT CK_RV
nssCKFWToken_GetMechanismTypes(NSSCKFWToken * fwToken,CK_MECHANISM_TYPE types[])1375 nssCKFWToken_GetMechanismTypes(
1376     NSSCKFWToken *fwToken,
1377     CK_MECHANISM_TYPE types[])
1378 {
1379 #ifdef NSSDEBUG
1380     if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) {
1381         return CKR_ARGUMENTS_BAD;
1382     }
1383 
1384     if (!types) {
1385         return CKR_ARGUMENTS_BAD;
1386     }
1387 #endif /* NSSDEBUG */
1388 
1389     if (!fwToken->mdToken->GetMechanismTypes) {
1390         /*
1391          * This should only be called with a sufficiently-large
1392          * "types" array, which can only be done if GetMechanismCount
1393          * is implemented.  If that's implemented (and returns nonzero),
1394          * then this should be too.  So return an error.
1395          */
1396         return CKR_GENERAL_ERROR;
1397     }
1398 
1399     return fwToken->mdToken->GetMechanismTypes(fwToken->mdToken, fwToken,
1400                                                fwToken->mdInstance, fwToken->fwInstance, types);
1401 }
1402 
1403 /*
1404  * nssCKFWToken_GetMechanism
1405  *
1406  */
1407 NSS_IMPLEMENT NSSCKFWMechanism *
nssCKFWToken_GetMechanism(NSSCKFWToken * fwToken,CK_MECHANISM_TYPE which,CK_RV * pError)1408 nssCKFWToken_GetMechanism(
1409     NSSCKFWToken *fwToken,
1410     CK_MECHANISM_TYPE which,
1411     CK_RV *pError)
1412 {
1413     NSSCKMDMechanism *mdMechanism;
1414     if (!fwToken->mdMechanismHash) {
1415         *pError = CKR_GENERAL_ERROR;
1416         return (NSSCKFWMechanism *)NULL;
1417     }
1418 
1419     if (!fwToken->mdToken->GetMechanism) {
1420         /*
1421          * If we don't implement any GetMechanism function, then we must
1422          * not support any.
1423          */
1424         *pError = CKR_MECHANISM_INVALID;
1425         return (NSSCKFWMechanism *)NULL;
1426     }
1427 
1428     /* lookup in hash table */
1429     mdMechanism = fwToken->mdToken->GetMechanism(fwToken->mdToken, fwToken,
1430                                                  fwToken->mdInstance, fwToken->fwInstance, which, pError);
1431     if (!mdMechanism) {
1432         return (NSSCKFWMechanism *)NULL;
1433     }
1434     /* store in hash table */
1435     return nssCKFWMechanism_Create(mdMechanism, fwToken->mdToken, fwToken,
1436                                    fwToken->mdInstance, fwToken->fwInstance);
1437 }
1438 
1439 NSS_IMPLEMENT CK_RV
nssCKFWToken_SetSessionState(NSSCKFWToken * fwToken,CK_STATE newState)1440 nssCKFWToken_SetSessionState(
1441     NSSCKFWToken *fwToken,
1442     CK_STATE newState)
1443 {
1444     CK_RV error = CKR_OK;
1445 
1446 #ifdef NSSDEBUG
1447     error = nssCKFWToken_verifyPointer(fwToken);
1448     if (CKR_OK != error) {
1449         return error;
1450     }
1451 
1452     switch (newState) {
1453         case CKS_RO_PUBLIC_SESSION:
1454         case CKS_RO_USER_FUNCTIONS:
1455         case CKS_RW_PUBLIC_SESSION:
1456         case CKS_RW_USER_FUNCTIONS:
1457         case CKS_RW_SO_FUNCTIONS:
1458             break;
1459         default:
1460             return CKR_ARGUMENTS_BAD;
1461     }
1462 #endif /* NSSDEBUG */
1463 
1464     error = nssCKFWMutex_Lock(fwToken->mutex);
1465     if (CKR_OK != error) {
1466         return error;
1467     }
1468 
1469     fwToken->state = newState;
1470     (void)nssCKFWMutex_Unlock(fwToken->mutex);
1471     return CKR_OK;
1472 }
1473 
1474 /*
1475  * nssCKFWToken_RemoveSession
1476  *
1477  */
1478 NSS_IMPLEMENT CK_RV
nssCKFWToken_RemoveSession(NSSCKFWToken * fwToken,NSSCKFWSession * fwSession)1479 nssCKFWToken_RemoveSession(
1480     NSSCKFWToken *fwToken,
1481     NSSCKFWSession *fwSession)
1482 {
1483     CK_RV error = CKR_OK;
1484 
1485 #ifdef NSSDEBUG
1486     error = nssCKFWToken_verifyPointer(fwToken);
1487     if (CKR_OK != error) {
1488         return error;
1489     }
1490 
1491     error = nssCKFWSession_verifyPointer(fwSession);
1492     if (CKR_OK != error) {
1493         return error;
1494     }
1495 #endif /* NSSDEBUG */
1496 
1497     error = nssCKFWMutex_Lock(fwToken->mutex);
1498     if (CKR_OK != error) {
1499         return error;
1500     }
1501 
1502     if (CK_TRUE != nssCKFWHash_Exists(fwToken->sessions, fwSession)) {
1503         error = CKR_SESSION_HANDLE_INVALID;
1504         goto done;
1505     }
1506 
1507     nssCKFWHash_Remove(fwToken->sessions, fwSession);
1508     fwToken->sessionCount--;
1509 
1510     if (nssCKFWSession_IsRWSession(fwSession)) {
1511         fwToken->rwSessionCount--;
1512     }
1513 
1514     if (0 == fwToken->sessionCount) {
1515         fwToken->rwSessionCount = 0;            /* sanity */
1516         fwToken->state = CKS_RO_PUBLIC_SESSION; /* some default */
1517     }
1518 
1519     error = CKR_OK;
1520 
1521 done:
1522     (void)nssCKFWMutex_Unlock(fwToken->mutex);
1523     return error;
1524 }
1525 
1526 /*
1527  * nssCKFWToken_CloseAllSessions
1528  *
1529  */
1530 NSS_IMPLEMENT CK_RV
nssCKFWToken_CloseAllSessions(NSSCKFWToken * fwToken)1531 nssCKFWToken_CloseAllSessions(
1532     NSSCKFWToken *fwToken)
1533 {
1534     CK_RV error = CKR_OK;
1535 
1536 #ifdef NSSDEBUG
1537     error = nssCKFWToken_verifyPointer(fwToken);
1538     if (CKR_OK != error) {
1539         return error;
1540     }
1541 #endif /* NSSDEBUG */
1542 
1543     error = nssCKFWMutex_Lock(fwToken->mutex);
1544     if (CKR_OK != error) {
1545         return error;
1546     }
1547 
1548     nssCKFWHash_Iterate(fwToken->sessions, nss_ckfwtoken_session_iterator, (void *)NULL);
1549 
1550     nssCKFWHash_Destroy(fwToken->sessions);
1551 
1552     fwToken->sessions = nssCKFWHash_Create(fwToken->fwInstance, fwToken->arena, &error);
1553     if (!fwToken->sessions) {
1554         if (CKR_OK == error) {
1555             error = CKR_GENERAL_ERROR;
1556         }
1557         goto done;
1558     }
1559 
1560     fwToken->state = CKS_RO_PUBLIC_SESSION; /* some default */
1561     fwToken->sessionCount = 0;
1562     fwToken->rwSessionCount = 0;
1563 
1564     error = CKR_OK;
1565 
1566 done:
1567     (void)nssCKFWMutex_Unlock(fwToken->mutex);
1568     return error;
1569 }
1570 
1571 /*
1572  * nssCKFWToken_GetSessionCount
1573  *
1574  */
1575 NSS_IMPLEMENT CK_ULONG
nssCKFWToken_GetSessionCount(NSSCKFWToken * fwToken)1576 nssCKFWToken_GetSessionCount(
1577     NSSCKFWToken *fwToken)
1578 {
1579     CK_ULONG rv;
1580 
1581 #ifdef NSSDEBUG
1582     if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) {
1583         return (CK_ULONG)0;
1584     }
1585 #endif /* NSSDEBUG */
1586 
1587     if (CKR_OK != nssCKFWMutex_Lock(fwToken->mutex)) {
1588         return (CK_ULONG)0;
1589     }
1590 
1591     rv = fwToken->sessionCount;
1592     (void)nssCKFWMutex_Unlock(fwToken->mutex);
1593     return rv;
1594 }
1595 
1596 /*
1597  * nssCKFWToken_GetRwSessionCount
1598  *
1599  */
1600 NSS_IMPLEMENT CK_ULONG
nssCKFWToken_GetRwSessionCount(NSSCKFWToken * fwToken)1601 nssCKFWToken_GetRwSessionCount(
1602     NSSCKFWToken *fwToken)
1603 {
1604     CK_ULONG rv;
1605 
1606 #ifdef NSSDEBUG
1607     if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) {
1608         return (CK_ULONG)0;
1609     }
1610 #endif /* NSSDEBUG */
1611 
1612     if (CKR_OK != nssCKFWMutex_Lock(fwToken->mutex)) {
1613         return (CK_ULONG)0;
1614     }
1615 
1616     rv = fwToken->rwSessionCount;
1617     (void)nssCKFWMutex_Unlock(fwToken->mutex);
1618     return rv;
1619 }
1620 
1621 /*
1622  * nssCKFWToken_GetRoSessionCount
1623  *
1624  */
1625 NSS_IMPLEMENT CK_ULONG
nssCKFWToken_GetRoSessionCount(NSSCKFWToken * fwToken)1626 nssCKFWToken_GetRoSessionCount(
1627     NSSCKFWToken *fwToken)
1628 {
1629     CK_ULONG rv;
1630 
1631 #ifdef NSSDEBUG
1632     if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) {
1633         return (CK_ULONG)0;
1634     }
1635 #endif /* NSSDEBUG */
1636 
1637     if (CKR_OK != nssCKFWMutex_Lock(fwToken->mutex)) {
1638         return (CK_ULONG)0;
1639     }
1640 
1641     rv = fwToken->sessionCount - fwToken->rwSessionCount;
1642     (void)nssCKFWMutex_Unlock(fwToken->mutex);
1643     return rv;
1644 }
1645 
1646 /*
1647  * nssCKFWToken_GetSessionObjectHash
1648  *
1649  */
1650 NSS_IMPLEMENT nssCKFWHash *
nssCKFWToken_GetSessionObjectHash(NSSCKFWToken * fwToken)1651 nssCKFWToken_GetSessionObjectHash(
1652     NSSCKFWToken *fwToken)
1653 {
1654 #ifdef NSSDEBUG
1655     if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) {
1656         return (nssCKFWHash *)NULL;
1657     }
1658 #endif /* NSSDEBUG */
1659 
1660     return fwToken->sessionObjectHash;
1661 }
1662 
1663 /*
1664  * nssCKFWToken_GetMDObjectHash
1665  *
1666  */
1667 NSS_IMPLEMENT nssCKFWHash *
nssCKFWToken_GetMDObjectHash(NSSCKFWToken * fwToken)1668 nssCKFWToken_GetMDObjectHash(
1669     NSSCKFWToken *fwToken)
1670 {
1671 #ifdef NSSDEBUG
1672     if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) {
1673         return (nssCKFWHash *)NULL;
1674     }
1675 #endif /* NSSDEBUG */
1676 
1677     return fwToken->mdObjectHash;
1678 }
1679 
1680 /*
1681  * nssCKFWToken_GetObjectHandleHash
1682  *
1683  */
1684 NSS_IMPLEMENT nssCKFWHash *
nssCKFWToken_GetObjectHandleHash(NSSCKFWToken * fwToken)1685 nssCKFWToken_GetObjectHandleHash(
1686     NSSCKFWToken *fwToken)
1687 {
1688 #ifdef NSSDEBUG
1689     if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) {
1690         return (nssCKFWHash *)NULL;
1691     }
1692 #endif /* NSSDEBUG */
1693 
1694     return fwToken->mdObjectHash;
1695 }
1696 
1697 /*
1698  * NSSCKFWToken_GetMDToken
1699  *
1700  */
1701 
1702 NSS_IMPLEMENT NSSCKMDToken *
NSSCKFWToken_GetMDToken(NSSCKFWToken * fwToken)1703 NSSCKFWToken_GetMDToken(
1704     NSSCKFWToken *fwToken)
1705 {
1706 #ifdef DEBUG
1707     if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) {
1708         return (NSSCKMDToken *)NULL;
1709     }
1710 #endif /* DEBUG */
1711 
1712     return nssCKFWToken_GetMDToken(fwToken);
1713 }
1714 
1715 /*
1716  * NSSCKFWToken_GetArena
1717  *
1718  */
1719 
1720 NSS_IMPLEMENT NSSArena *
NSSCKFWToken_GetArena(NSSCKFWToken * fwToken,CK_RV * pError)1721 NSSCKFWToken_GetArena(
1722     NSSCKFWToken *fwToken,
1723     CK_RV *pError)
1724 {
1725 #ifdef DEBUG
1726     if (!pError) {
1727         return (NSSArena *)NULL;
1728     }
1729 
1730     if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) {
1731         *pError = CKR_ARGUMENTS_BAD;
1732         return (NSSArena *)NULL;
1733     }
1734 #endif /* DEBUG */
1735 
1736     return nssCKFWToken_GetArena(fwToken, pError);
1737 }
1738 
1739 /*
1740  * NSSCKFWToken_GetFWSlot
1741  *
1742  */
1743 
1744 NSS_IMPLEMENT NSSCKFWSlot *
NSSCKFWToken_GetFWSlot(NSSCKFWToken * fwToken)1745 NSSCKFWToken_GetFWSlot(
1746     NSSCKFWToken *fwToken)
1747 {
1748 #ifdef DEBUG
1749     if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) {
1750         return (NSSCKFWSlot *)NULL;
1751     }
1752 #endif /* DEBUG */
1753 
1754     return nssCKFWToken_GetFWSlot(fwToken);
1755 }
1756 
1757 /*
1758  * NSSCKFWToken_GetMDSlot
1759  *
1760  */
1761 
1762 NSS_IMPLEMENT NSSCKMDSlot *
NSSCKFWToken_GetMDSlot(NSSCKFWToken * fwToken)1763 NSSCKFWToken_GetMDSlot(
1764     NSSCKFWToken *fwToken)
1765 {
1766 #ifdef DEBUG
1767     if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) {
1768         return (NSSCKMDSlot *)NULL;
1769     }
1770 #endif /* DEBUG */
1771 
1772     return nssCKFWToken_GetMDSlot(fwToken);
1773 }
1774 
1775 /*
1776  * NSSCKFWToken_GetSessionState
1777  *
1778  */
1779 
1780 NSS_IMPLEMENT CK_STATE
NSSCKFWSession_GetSessionState(NSSCKFWToken * fwToken)1781 NSSCKFWSession_GetSessionState(
1782     NSSCKFWToken *fwToken)
1783 {
1784 #ifdef DEBUG
1785     if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) {
1786         return CKS_RO_PUBLIC_SESSION;
1787     }
1788 #endif /* DEBUG */
1789 
1790     return nssCKFWToken_GetSessionState(fwToken);
1791 }
1792