tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

token.c (42635B)


      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
    136 token_add_pointer(
    137    const NSSCKFWToken *fwToken)
    138 {
    139    return CKR_OK;
    140 }
    141 
    142 static CK_RV
    143 token_remove_pointer(
    144    const NSSCKFWToken *fwToken)
    145 {
    146    return CKR_OK;
    147 }
    148 
    149 NSS_IMPLEMENT CK_RV
    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 *
    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
    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
    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
    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 *
    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 *
    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 *
    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 *
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
   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
   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
   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
   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
   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)) && (Y % 400)) &&
   1215            (D > 28))
   1216            goto badtime; /* leap years */
   1217 
   1218        if ((h < 0) || (h > 23))
   1219            goto badtime;
   1220        if ((m < 0) || (m > 60))
   1221            goto badtime;
   1222        if ((s < 0) || (s > 61))
   1223            goto badtime;
   1224 
   1225        /* 60m and 60 or 61s is only allowed for leap seconds. */
   1226        if ((60 == m) || (s >= 60)) {
   1227            if ((23 != h) || (60 != m) || (s < 60))
   1228                goto badtime;
   1229            /* leap seconds can only happen on June 30 or Dec 31.. I think */
   1230            /* if( ((6 != M) || (30 != D)) && ((12 != M) || (31 != D)) ) goto badtime; */
   1231        }
   1232    }
   1233 
   1234    return CKR_OK;
   1235 
   1236 badtime:
   1237    return CKR_GENERAL_ERROR;
   1238 }
   1239 
   1240 /*
   1241 * nssCKFWToken_OpenSession
   1242 *
   1243 */
   1244 NSS_IMPLEMENT NSSCKFWSession *
   1245 nssCKFWToken_OpenSession(
   1246    NSSCKFWToken *fwToken,
   1247    CK_BBOOL rw,
   1248    CK_VOID_PTR pApplication,
   1249    CK_NOTIFY Notify,
   1250    CK_RV *pError)
   1251 {
   1252    NSSCKFWSession *fwSession = (NSSCKFWSession *)NULL;
   1253    NSSCKMDSession *mdSession;
   1254 
   1255 #ifdef NSSDEBUG
   1256    if (!pError) {
   1257        return (NSSCKFWSession *)NULL;
   1258    }
   1259 
   1260    *pError = nssCKFWToken_verifyPointer(fwToken);
   1261    if (CKR_OK != *pError) {
   1262        return (NSSCKFWSession *)NULL;
   1263    }
   1264 
   1265    switch (rw) {
   1266        case CK_TRUE:
   1267        case CK_FALSE:
   1268            break;
   1269        default:
   1270            *pError = CKR_ARGUMENTS_BAD;
   1271            return (NSSCKFWSession *)NULL;
   1272    }
   1273 #endif /* NSSDEBUG */
   1274 
   1275    *pError = nssCKFWMutex_Lock(fwToken->mutex);
   1276    if (CKR_OK != *pError) {
   1277        return (NSSCKFWSession *)NULL;
   1278    }
   1279 
   1280    if (CK_TRUE == rw) {
   1281        /* Read-write session desired */
   1282        if (CK_TRUE == nssCKFWToken_GetIsWriteProtected(fwToken)) {
   1283            *pError = CKR_TOKEN_WRITE_PROTECTED;
   1284            goto done;
   1285        }
   1286    } else {
   1287        /* Read-only session desired */
   1288        if (CKS_RW_SO_FUNCTIONS == nssCKFWToken_GetSessionState(fwToken)) {
   1289            *pError = CKR_SESSION_READ_WRITE_SO_EXISTS;
   1290            goto done;
   1291        }
   1292    }
   1293 
   1294    /* We could compare sesion counts to any limits we know of, I guess.. */
   1295 
   1296    if (!fwToken->mdToken->OpenSession) {
   1297        /*
   1298         * I'm not sure that the Module actually needs to implement
   1299         * mdSessions -- the Framework can keep track of everything
   1300         * needed, really.  But I'll sort out that detail later..
   1301         */
   1302        *pError = CKR_GENERAL_ERROR;
   1303        goto done;
   1304    }
   1305 
   1306    fwSession = nssCKFWSession_Create(fwToken, rw, pApplication, Notify, pError);
   1307    if (!fwSession) {
   1308        if (CKR_OK == *pError) {
   1309            *pError = CKR_GENERAL_ERROR;
   1310        }
   1311        goto done;
   1312    }
   1313 
   1314    mdSession = fwToken->mdToken->OpenSession(fwToken->mdToken, fwToken,
   1315                                              fwToken->mdInstance, fwToken->fwInstance, fwSession,
   1316                                              rw, pError);
   1317    if (!mdSession) {
   1318        (void)nssCKFWSession_Destroy(fwSession, CK_FALSE);
   1319        if (CKR_OK == *pError) {
   1320            *pError = CKR_GENERAL_ERROR;
   1321        }
   1322        goto done;
   1323    }
   1324 
   1325    *pError = nssCKFWSession_SetMDSession(fwSession, mdSession);
   1326    if (CKR_OK != *pError) {
   1327        if (mdSession->Close) {
   1328            mdSession->Close(mdSession, fwSession, fwToken->mdToken, fwToken,
   1329                             fwToken->mdInstance, fwToken->fwInstance);
   1330        }
   1331        (void)nssCKFWSession_Destroy(fwSession, CK_FALSE);
   1332        goto done;
   1333    }
   1334 
   1335    *pError = nssCKFWHash_Add(fwToken->sessions, fwSession, fwSession);
   1336    if (CKR_OK != *pError) {
   1337        (void)nssCKFWSession_Destroy(fwSession, CK_FALSE);
   1338        fwSession = (NSSCKFWSession *)NULL;
   1339        goto done;
   1340    }
   1341 
   1342 done:
   1343    (void)nssCKFWMutex_Unlock(fwToken->mutex);
   1344    return fwSession;
   1345 }
   1346 
   1347 /*
   1348 * nssCKFWToken_GetMechanismCount
   1349 *
   1350 */
   1351 NSS_IMPLEMENT CK_ULONG
   1352 nssCKFWToken_GetMechanismCount(
   1353    NSSCKFWToken *fwToken)
   1354 {
   1355 #ifdef NSSDEBUG
   1356    if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) {
   1357        return 0;
   1358    }
   1359 #endif /* NSSDEBUG */
   1360 
   1361    if (!fwToken->mdToken->GetMechanismCount) {
   1362        return 0;
   1363    }
   1364 
   1365    return fwToken->mdToken->GetMechanismCount(fwToken->mdToken, fwToken,
   1366                                               fwToken->mdInstance, fwToken->fwInstance);
   1367 }
   1368 
   1369 /*
   1370 * nssCKFWToken_GetMechanismTypes
   1371 *
   1372 */
   1373 NSS_IMPLEMENT CK_RV
   1374 nssCKFWToken_GetMechanismTypes(
   1375    NSSCKFWToken *fwToken,
   1376    CK_MECHANISM_TYPE types[])
   1377 {
   1378 #ifdef NSSDEBUG
   1379    if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) {
   1380        return CKR_ARGUMENTS_BAD;
   1381    }
   1382 
   1383    if (!types) {
   1384        return CKR_ARGUMENTS_BAD;
   1385    }
   1386 #endif /* NSSDEBUG */
   1387 
   1388    if (!fwToken->mdToken->GetMechanismTypes) {
   1389        /*
   1390         * This should only be called with a sufficiently-large
   1391         * "types" array, which can only be done if GetMechanismCount
   1392         * is implemented.  If that's implemented (and returns nonzero),
   1393         * then this should be too.  So return an error.
   1394         */
   1395        return CKR_GENERAL_ERROR;
   1396    }
   1397 
   1398    return fwToken->mdToken->GetMechanismTypes(fwToken->mdToken, fwToken,
   1399                                               fwToken->mdInstance, fwToken->fwInstance, types);
   1400 }
   1401 
   1402 /*
   1403 * nssCKFWToken_GetMechanism
   1404 *
   1405 */
   1406 NSS_IMPLEMENT NSSCKFWMechanism *
   1407 nssCKFWToken_GetMechanism(
   1408    NSSCKFWToken *fwToken,
   1409    CK_MECHANISM_TYPE which,
   1410    CK_RV *pError)
   1411 {
   1412    NSSCKMDMechanism *mdMechanism;
   1413    if (!fwToken->mdMechanismHash) {
   1414        *pError = CKR_GENERAL_ERROR;
   1415        return (NSSCKFWMechanism *)NULL;
   1416    }
   1417 
   1418    if (!fwToken->mdToken->GetMechanism) {
   1419        /*
   1420         * If we don't implement any GetMechanism function, then we must
   1421         * not support any.
   1422         */
   1423        *pError = CKR_MECHANISM_INVALID;
   1424        return (NSSCKFWMechanism *)NULL;
   1425    }
   1426 
   1427    /* lookup in hash table */
   1428    mdMechanism = fwToken->mdToken->GetMechanism(fwToken->mdToken, fwToken,
   1429                                                 fwToken->mdInstance, fwToken->fwInstance, which, pError);
   1430    if (!mdMechanism) {
   1431        return (NSSCKFWMechanism *)NULL;
   1432    }
   1433    /* store in hash table */
   1434    return nssCKFWMechanism_Create(mdMechanism, fwToken->mdToken, fwToken,
   1435                                   fwToken->mdInstance, fwToken->fwInstance);
   1436 }
   1437 
   1438 NSS_IMPLEMENT CK_RV
   1439 nssCKFWToken_SetSessionState(
   1440    NSSCKFWToken *fwToken,
   1441    CK_STATE newState)
   1442 {
   1443    CK_RV error = CKR_OK;
   1444 
   1445 #ifdef NSSDEBUG
   1446    error = nssCKFWToken_verifyPointer(fwToken);
   1447    if (CKR_OK != error) {
   1448        return error;
   1449    }
   1450 
   1451    switch (newState) {
   1452        case CKS_RO_PUBLIC_SESSION:
   1453        case CKS_RO_USER_FUNCTIONS:
   1454        case CKS_RW_PUBLIC_SESSION:
   1455        case CKS_RW_USER_FUNCTIONS:
   1456        case CKS_RW_SO_FUNCTIONS:
   1457            break;
   1458        default:
   1459            return CKR_ARGUMENTS_BAD;
   1460    }
   1461 #endif /* NSSDEBUG */
   1462 
   1463    error = nssCKFWMutex_Lock(fwToken->mutex);
   1464    if (CKR_OK != error) {
   1465        return error;
   1466    }
   1467 
   1468    fwToken->state = newState;
   1469    (void)nssCKFWMutex_Unlock(fwToken->mutex);
   1470    return CKR_OK;
   1471 }
   1472 
   1473 /*
   1474 * nssCKFWToken_RemoveSession
   1475 *
   1476 */
   1477 NSS_IMPLEMENT CK_RV
   1478 nssCKFWToken_RemoveSession(
   1479    NSSCKFWToken *fwToken,
   1480    NSSCKFWSession *fwSession)
   1481 {
   1482    CK_RV error = CKR_OK;
   1483 
   1484 #ifdef NSSDEBUG
   1485    error = nssCKFWToken_verifyPointer(fwToken);
   1486    if (CKR_OK != error) {
   1487        return error;
   1488    }
   1489 
   1490    error = nssCKFWSession_verifyPointer(fwSession);
   1491    if (CKR_OK != error) {
   1492        return error;
   1493    }
   1494 #endif /* NSSDEBUG */
   1495 
   1496    error = nssCKFWMutex_Lock(fwToken->mutex);
   1497    if (CKR_OK != error) {
   1498        return error;
   1499    }
   1500 
   1501    if (CK_TRUE != nssCKFWHash_Exists(fwToken->sessions, fwSession)) {
   1502        error = CKR_SESSION_HANDLE_INVALID;
   1503        goto done;
   1504    }
   1505 
   1506    nssCKFWHash_Remove(fwToken->sessions, fwSession);
   1507    fwToken->sessionCount--;
   1508 
   1509    if (nssCKFWSession_IsRWSession(fwSession)) {
   1510        fwToken->rwSessionCount--;
   1511    }
   1512 
   1513    if (0 == fwToken->sessionCount) {
   1514        fwToken->rwSessionCount = 0;            /* sanity */
   1515        fwToken->state = CKS_RO_PUBLIC_SESSION; /* some default */
   1516    }
   1517 
   1518    error = CKR_OK;
   1519 
   1520 done:
   1521    (void)nssCKFWMutex_Unlock(fwToken->mutex);
   1522    return error;
   1523 }
   1524 
   1525 /*
   1526 * nssCKFWToken_CloseAllSessions
   1527 *
   1528 */
   1529 NSS_IMPLEMENT CK_RV
   1530 nssCKFWToken_CloseAllSessions(
   1531    NSSCKFWToken *fwToken)
   1532 {
   1533    CK_RV error = CKR_OK;
   1534 
   1535 #ifdef NSSDEBUG
   1536    error = nssCKFWToken_verifyPointer(fwToken);
   1537    if (CKR_OK != error) {
   1538        return error;
   1539    }
   1540 #endif /* NSSDEBUG */
   1541 
   1542    error = nssCKFWMutex_Lock(fwToken->mutex);
   1543    if (CKR_OK != error) {
   1544        return error;
   1545    }
   1546 
   1547    nssCKFWHash_Iterate(fwToken->sessions, nss_ckfwtoken_session_iterator, (void *)NULL);
   1548 
   1549    nssCKFWHash_Destroy(fwToken->sessions);
   1550 
   1551    fwToken->sessions = nssCKFWHash_Create(fwToken->fwInstance, fwToken->arena, &error);
   1552    if (!fwToken->sessions) {
   1553        if (CKR_OK == error) {
   1554            error = CKR_GENERAL_ERROR;
   1555        }
   1556        goto done;
   1557    }
   1558 
   1559    fwToken->state = CKS_RO_PUBLIC_SESSION; /* some default */
   1560    fwToken->sessionCount = 0;
   1561    fwToken->rwSessionCount = 0;
   1562 
   1563    error = CKR_OK;
   1564 
   1565 done:
   1566    (void)nssCKFWMutex_Unlock(fwToken->mutex);
   1567    return error;
   1568 }
   1569 
   1570 /*
   1571 * nssCKFWToken_GetSessionCount
   1572 *
   1573 */
   1574 NSS_IMPLEMENT CK_ULONG
   1575 nssCKFWToken_GetSessionCount(
   1576    NSSCKFWToken *fwToken)
   1577 {
   1578    CK_ULONG rv;
   1579 
   1580 #ifdef NSSDEBUG
   1581    if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) {
   1582        return (CK_ULONG)0;
   1583    }
   1584 #endif /* NSSDEBUG */
   1585 
   1586    if (CKR_OK != nssCKFWMutex_Lock(fwToken->mutex)) {
   1587        return (CK_ULONG)0;
   1588    }
   1589 
   1590    rv = fwToken->sessionCount;
   1591    (void)nssCKFWMutex_Unlock(fwToken->mutex);
   1592    return rv;
   1593 }
   1594 
   1595 /*
   1596 * nssCKFWToken_GetRwSessionCount
   1597 *
   1598 */
   1599 NSS_IMPLEMENT CK_ULONG
   1600 nssCKFWToken_GetRwSessionCount(
   1601    NSSCKFWToken *fwToken)
   1602 {
   1603    CK_ULONG rv;
   1604 
   1605 #ifdef NSSDEBUG
   1606    if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) {
   1607        return (CK_ULONG)0;
   1608    }
   1609 #endif /* NSSDEBUG */
   1610 
   1611    if (CKR_OK != nssCKFWMutex_Lock(fwToken->mutex)) {
   1612        return (CK_ULONG)0;
   1613    }
   1614 
   1615    rv = fwToken->rwSessionCount;
   1616    (void)nssCKFWMutex_Unlock(fwToken->mutex);
   1617    return rv;
   1618 }
   1619 
   1620 /*
   1621 * nssCKFWToken_GetRoSessionCount
   1622 *
   1623 */
   1624 NSS_IMPLEMENT CK_ULONG
   1625 nssCKFWToken_GetRoSessionCount(
   1626    NSSCKFWToken *fwToken)
   1627 {
   1628    CK_ULONG rv;
   1629 
   1630 #ifdef NSSDEBUG
   1631    if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) {
   1632        return (CK_ULONG)0;
   1633    }
   1634 #endif /* NSSDEBUG */
   1635 
   1636    if (CKR_OK != nssCKFWMutex_Lock(fwToken->mutex)) {
   1637        return (CK_ULONG)0;
   1638    }
   1639 
   1640    rv = fwToken->sessionCount - fwToken->rwSessionCount;
   1641    (void)nssCKFWMutex_Unlock(fwToken->mutex);
   1642    return rv;
   1643 }
   1644 
   1645 /*
   1646 * nssCKFWToken_GetSessionObjectHash
   1647 *
   1648 */
   1649 NSS_IMPLEMENT nssCKFWHash *
   1650 nssCKFWToken_GetSessionObjectHash(
   1651    NSSCKFWToken *fwToken)
   1652 {
   1653 #ifdef NSSDEBUG
   1654    if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) {
   1655        return (nssCKFWHash *)NULL;
   1656    }
   1657 #endif /* NSSDEBUG */
   1658 
   1659    return fwToken->sessionObjectHash;
   1660 }
   1661 
   1662 /*
   1663 * nssCKFWToken_GetMDObjectHash
   1664 *
   1665 */
   1666 NSS_IMPLEMENT nssCKFWHash *
   1667 nssCKFWToken_GetMDObjectHash(
   1668    NSSCKFWToken *fwToken)
   1669 {
   1670 #ifdef NSSDEBUG
   1671    if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) {
   1672        return (nssCKFWHash *)NULL;
   1673    }
   1674 #endif /* NSSDEBUG */
   1675 
   1676    return fwToken->mdObjectHash;
   1677 }
   1678 
   1679 /*
   1680 * nssCKFWToken_GetObjectHandleHash
   1681 *
   1682 */
   1683 NSS_IMPLEMENT nssCKFWHash *
   1684 nssCKFWToken_GetObjectHandleHash(
   1685    NSSCKFWToken *fwToken)
   1686 {
   1687 #ifdef NSSDEBUG
   1688    if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) {
   1689        return (nssCKFWHash *)NULL;
   1690    }
   1691 #endif /* NSSDEBUG */
   1692 
   1693    return fwToken->mdObjectHash;
   1694 }
   1695 
   1696 /*
   1697 * NSSCKFWToken_GetMDToken
   1698 *
   1699 */
   1700 
   1701 NSS_IMPLEMENT NSSCKMDToken *
   1702 NSSCKFWToken_GetMDToken(
   1703    NSSCKFWToken *fwToken)
   1704 {
   1705 #ifdef DEBUG
   1706    if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) {
   1707        return (NSSCKMDToken *)NULL;
   1708    }
   1709 #endif /* DEBUG */
   1710 
   1711    return nssCKFWToken_GetMDToken(fwToken);
   1712 }
   1713 
   1714 /*
   1715 * NSSCKFWToken_GetArena
   1716 *
   1717 */
   1718 
   1719 NSS_IMPLEMENT NSSArena *
   1720 NSSCKFWToken_GetArena(
   1721    NSSCKFWToken *fwToken,
   1722    CK_RV *pError)
   1723 {
   1724 #ifdef DEBUG
   1725    if (!pError) {
   1726        return (NSSArena *)NULL;
   1727    }
   1728 
   1729    if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) {
   1730        *pError = CKR_ARGUMENTS_BAD;
   1731        return (NSSArena *)NULL;
   1732    }
   1733 #endif /* DEBUG */
   1734 
   1735    return nssCKFWToken_GetArena(fwToken, pError);
   1736 }
   1737 
   1738 /*
   1739 * NSSCKFWToken_GetFWSlot
   1740 *
   1741 */
   1742 
   1743 NSS_IMPLEMENT NSSCKFWSlot *
   1744 NSSCKFWToken_GetFWSlot(
   1745    NSSCKFWToken *fwToken)
   1746 {
   1747 #ifdef DEBUG
   1748    if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) {
   1749        return (NSSCKFWSlot *)NULL;
   1750    }
   1751 #endif /* DEBUG */
   1752 
   1753    return nssCKFWToken_GetFWSlot(fwToken);
   1754 }
   1755 
   1756 /*
   1757 * NSSCKFWToken_GetMDSlot
   1758 *
   1759 */
   1760 
   1761 NSS_IMPLEMENT NSSCKMDSlot *
   1762 NSSCKFWToken_GetMDSlot(
   1763    NSSCKFWToken *fwToken)
   1764 {
   1765 #ifdef DEBUG
   1766    if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) {
   1767        return (NSSCKMDSlot *)NULL;
   1768    }
   1769 #endif /* DEBUG */
   1770 
   1771    return nssCKFWToken_GetMDSlot(fwToken);
   1772 }
   1773 
   1774 /*
   1775 * NSSCKFWToken_GetSessionState
   1776 *
   1777 */
   1778 
   1779 NSS_IMPLEMENT CK_STATE
   1780 NSSCKFWSession_GetSessionState(
   1781    NSSCKFWToken *fwToken)
   1782 {
   1783 #ifdef DEBUG
   1784    if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) {
   1785        return CKS_RO_PUBLIC_SESSION;
   1786    }
   1787 #endif /* DEBUG */
   1788 
   1789    return nssCKFWToken_GetSessionState(fwToken);
   1790 }