tor-browser

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

session.c (62399B)


      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 * session.c
      7 *
      8 * This file implements the NSSCKFWSession type and methods.
      9 */
     10 
     11 #ifndef CK_T
     12 #include "ck.h"
     13 #endif /* CK_T */
     14 
     15 /*
     16 * NSSCKFWSession
     17 *
     18 *  -- create/destroy --
     19 *  nssCKFWSession_Create
     20 *  nssCKFWSession_Destroy
     21 *
     22 *  -- public accessors --
     23 *  NSSCKFWSession_GetMDSession
     24 *  NSSCKFWSession_GetArena
     25 *  NSSCKFWSession_CallNotification
     26 *  NSSCKFWSession_IsRWSession
     27 *  NSSCKFWSession_IsSO
     28 *  NSSCKFWSession_GetFWSlot
     29 *
     30 *  -- implement public accessors --
     31 *  nssCKFWSession_GetMDSession
     32 *  nssCKFWSession_GetArena
     33 *  nssCKFWSession_CallNotification
     34 *  nssCKFWSession_IsRWSession
     35 *  nssCKFWSession_IsSO
     36 *  nssCKFWSession_GetFWSlot
     37 *
     38 *  -- private accessors --
     39 *  nssCKFWSession_GetSessionState
     40 *  nssCKFWSession_SetFWFindObjects
     41 *  nssCKFWSession_GetFWFindObjects
     42 *  nssCKFWSession_SetMDSession
     43 *  nssCKFWSession_SetHandle
     44 *  nssCKFWSession_GetHandle
     45 *  nssCKFWSession_RegisterSessionObject
     46 *  nssCKFWSession_DeegisterSessionObject
     47 *
     48 *  -- module fronts --
     49 *  nssCKFWSession_GetDeviceError
     50 *  nssCKFWSession_Login
     51 *  nssCKFWSession_Logout
     52 *  nssCKFWSession_InitPIN
     53 *  nssCKFWSession_SetPIN
     54 *  nssCKFWSession_GetOperationStateLen
     55 *  nssCKFWSession_GetOperationState
     56 *  nssCKFWSession_SetOperationState
     57 *  nssCKFWSession_CreateObject
     58 *  nssCKFWSession_CopyObject
     59 *  nssCKFWSession_FindObjectsInit
     60 *  nssCKFWSession_SeedRandom
     61 *  nssCKFWSession_GetRandom
     62 */
     63 
     64 struct NSSCKFWSessionStr {
     65    NSSArena *arena;
     66    NSSCKMDSession *mdSession;
     67    NSSCKFWToken *fwToken;
     68    NSSCKMDToken *mdToken;
     69    NSSCKFWInstance *fwInstance;
     70    NSSCKMDInstance *mdInstance;
     71    CK_VOID_PTR pApplication;
     72    CK_NOTIFY Notify;
     73 
     74    /*
     75     * Everything above is set at creation time, and then not modified.
     76     * The items below are atomic.  No locking required.  If we fear
     77     * about pointer-copies being nonatomic, we'll lock fwFindObjects.
     78     */
     79 
     80    CK_BBOOL rw;
     81    NSSCKFWFindObjects *fwFindObjects;
     82    NSSCKFWCryptoOperation *fwOperationArray[NSSCKFWCryptoOperationState_Max];
     83    nssCKFWHash *sessionObjectHash;
     84    CK_SESSION_HANDLE hSession;
     85 };
     86 
     87 #ifdef DEBUG
     88 /*
     89 * But first, the pointer-tracking stuff.
     90 *
     91 * NOTE: the pointer-tracking support in NSS/base currently relies
     92 * upon NSPR's CallOnce support.  That, however, relies upon NSPR's
     93 * locking, which is tied into the runtime.  We need a pointer-tracker
     94 * implementation that uses the locks supplied through C_Initialize.
     95 * That support, however, can be filled in later.  So for now, I'll
     96 * just do this routines as no-ops.
     97 */
     98 
     99 static CK_RV
    100 session_add_pointer(
    101    const NSSCKFWSession *fwSession)
    102 {
    103    return CKR_OK;
    104 }
    105 
    106 static CK_RV
    107 session_remove_pointer(
    108    const NSSCKFWSession *fwSession)
    109 {
    110    return CKR_OK;
    111 }
    112 
    113 NSS_IMPLEMENT CK_RV
    114 nssCKFWSession_verifyPointer(
    115    const NSSCKFWSession *fwSession)
    116 {
    117    return CKR_OK;
    118 }
    119 
    120 #endif /* DEBUG */
    121 
    122 /*
    123 * nssCKFWSession_Create
    124 *
    125 */
    126 NSS_IMPLEMENT NSSCKFWSession *
    127 nssCKFWSession_Create(
    128    NSSCKFWToken *fwToken,
    129    CK_BBOOL rw,
    130    CK_VOID_PTR pApplication,
    131    CK_NOTIFY Notify,
    132    CK_RV *pError)
    133 {
    134    NSSArena *arena = (NSSArena *)NULL;
    135    NSSCKFWSession *fwSession;
    136    NSSCKFWSlot *fwSlot;
    137 
    138 #ifdef NSSDEBUG
    139    if (!pError) {
    140        return (NSSCKFWSession *)NULL;
    141    }
    142 
    143    *pError = nssCKFWToken_verifyPointer(fwToken);
    144    if (CKR_OK != *pError) {
    145        return (NSSCKFWSession *)NULL;
    146    }
    147 #endif /* NSSDEBUG */
    148 
    149    arena = NSSArena_Create();
    150    if (!arena) {
    151        *pError = CKR_HOST_MEMORY;
    152        return (NSSCKFWSession *)NULL;
    153    }
    154 
    155    fwSession = nss_ZNEW(arena, NSSCKFWSession);
    156    if (!fwSession) {
    157        *pError = CKR_HOST_MEMORY;
    158        goto loser;
    159    }
    160 
    161    fwSession->arena = arena;
    162    fwSession->mdSession = (NSSCKMDSession *)NULL; /* set later */
    163    fwSession->fwToken = fwToken;
    164    fwSession->mdToken = nssCKFWToken_GetMDToken(fwToken);
    165 
    166    fwSlot = nssCKFWToken_GetFWSlot(fwToken);
    167    fwSession->fwInstance = nssCKFWSlot_GetFWInstance(fwSlot);
    168    fwSession->mdInstance = nssCKFWSlot_GetMDInstance(fwSlot);
    169 
    170    fwSession->rw = rw;
    171    fwSession->pApplication = pApplication;
    172    fwSession->Notify = Notify;
    173 
    174    fwSession->fwFindObjects = (NSSCKFWFindObjects *)NULL;
    175 
    176    fwSession->sessionObjectHash = nssCKFWHash_Create(fwSession->fwInstance, arena, pError);
    177    if (!fwSession->sessionObjectHash) {
    178        if (CKR_OK == *pError) {
    179            *pError = CKR_GENERAL_ERROR;
    180        }
    181        goto loser;
    182    }
    183 
    184 #ifdef DEBUG
    185    *pError = session_add_pointer(fwSession);
    186    if (CKR_OK != *pError) {
    187        goto loser;
    188    }
    189 #endif /* DEBUG */
    190 
    191    return fwSession;
    192 
    193 loser:
    194    if (arena) {
    195        if (fwSession && fwSession->sessionObjectHash) {
    196            (void)nssCKFWHash_Destroy(fwSession->sessionObjectHash);
    197        }
    198        NSSArena_Destroy(arena);
    199    }
    200 
    201    return (NSSCKFWSession *)NULL;
    202 }
    203 
    204 static void
    205 nss_ckfw_session_object_destroy_iterator(
    206    const void *key,
    207    void *value,
    208    void *closure)
    209 {
    210    NSSCKFWObject *fwObject = (NSSCKFWObject *)value;
    211    nssCKFWObject_Finalize(fwObject, PR_TRUE);
    212 }
    213 
    214 /*
    215 * nssCKFWSession_Destroy
    216 *
    217 */
    218 NSS_IMPLEMENT CK_RV
    219 nssCKFWSession_Destroy(
    220    NSSCKFWSession *fwSession,
    221    CK_BBOOL removeFromTokenHash)
    222 {
    223    CK_RV error = CKR_OK;
    224    nssCKFWHash *sessionObjectHash;
    225    NSSCKFWCryptoOperationState i;
    226 
    227 #ifdef NSSDEBUG
    228    error = nssCKFWSession_verifyPointer(fwSession);
    229    if (CKR_OK != error) {
    230        return error;
    231    }
    232 #endif /* NSSDEBUG */
    233 
    234    if (removeFromTokenHash) {
    235        error = nssCKFWToken_RemoveSession(fwSession->fwToken, fwSession);
    236    }
    237 
    238    /*
    239     * Invalidate session objects
    240     */
    241 
    242    sessionObjectHash = fwSession->sessionObjectHash;
    243    fwSession->sessionObjectHash = (nssCKFWHash *)NULL;
    244 
    245    nssCKFWHash_Iterate(sessionObjectHash,
    246                        nss_ckfw_session_object_destroy_iterator,
    247                        (void *)NULL);
    248 
    249    for (i = 0; i < NSSCKFWCryptoOperationState_Max; i++) {
    250        if (fwSession->fwOperationArray[i]) {
    251            nssCKFWCryptoOperation_Destroy(fwSession->fwOperationArray[i]);
    252        }
    253    }
    254 
    255 #ifdef DEBUG
    256    (void)session_remove_pointer(fwSession);
    257 #endif /* DEBUG */
    258    (void)nssCKFWHash_Destroy(sessionObjectHash);
    259    NSSArena_Destroy(fwSession->arena);
    260 
    261    return error;
    262 }
    263 
    264 /*
    265 * nssCKFWSession_GetMDSession
    266 *
    267 */
    268 NSS_IMPLEMENT NSSCKMDSession *
    269 nssCKFWSession_GetMDSession(
    270    NSSCKFWSession *fwSession)
    271 {
    272 #ifdef NSSDEBUG
    273    if (CKR_OK != nssCKFWSession_verifyPointer(fwSession)) {
    274        return (NSSCKMDSession *)NULL;
    275    }
    276 #endif /* NSSDEBUG */
    277 
    278    return fwSession->mdSession;
    279 }
    280 
    281 /*
    282 * nssCKFWSession_GetArena
    283 *
    284 */
    285 NSS_IMPLEMENT NSSArena *
    286 nssCKFWSession_GetArena(
    287    NSSCKFWSession *fwSession,
    288    CK_RV *pError)
    289 {
    290 #ifdef NSSDEBUG
    291    if (!pError) {
    292        return (NSSArena *)NULL;
    293    }
    294 
    295    *pError = nssCKFWSession_verifyPointer(fwSession);
    296    if (CKR_OK != *pError) {
    297        return (NSSArena *)NULL;
    298    }
    299 #endif /* NSSDEBUG */
    300 
    301    return fwSession->arena;
    302 }
    303 
    304 /*
    305 * nssCKFWSession_CallNotification
    306 *
    307 */
    308 NSS_IMPLEMENT CK_RV
    309 nssCKFWSession_CallNotification(
    310    NSSCKFWSession *fwSession,
    311    CK_NOTIFICATION event)
    312 {
    313    CK_RV error = CKR_OK;
    314    CK_SESSION_HANDLE handle;
    315 
    316 #ifdef NSSDEBUG
    317    error = nssCKFWSession_verifyPointer(fwSession);
    318    if (CKR_OK != error) {
    319        return error;
    320    }
    321 #endif /* NSSDEBUG */
    322 
    323    if ((CK_NOTIFY)NULL == fwSession->Notify) {
    324        return CKR_OK;
    325    }
    326 
    327    handle = nssCKFWInstance_FindSessionHandle(fwSession->fwInstance, fwSession);
    328    if ((CK_SESSION_HANDLE)0 == handle) {
    329        return CKR_GENERAL_ERROR;
    330    }
    331 
    332    error = fwSession->Notify(handle, event, fwSession->pApplication);
    333 
    334    return error;
    335 }
    336 
    337 /*
    338 * nssCKFWSession_IsRWSession
    339 *
    340 */
    341 NSS_IMPLEMENT CK_BBOOL
    342 nssCKFWSession_IsRWSession(
    343    NSSCKFWSession *fwSession)
    344 {
    345 #ifdef NSSDEBUG
    346    if (CKR_OK != nssCKFWSession_verifyPointer(fwSession)) {
    347        return CK_FALSE;
    348    }
    349 #endif /* NSSDEBUG */
    350 
    351    return fwSession->rw;
    352 }
    353 
    354 /*
    355 * nssCKFWSession_IsSO
    356 *
    357 */
    358 NSS_IMPLEMENT CK_BBOOL
    359 nssCKFWSession_IsSO(
    360    NSSCKFWSession *fwSession)
    361 {
    362    CK_STATE state;
    363 
    364 #ifdef NSSDEBUG
    365    if (CKR_OK != nssCKFWSession_verifyPointer(fwSession)) {
    366        return CK_FALSE;
    367    }
    368 #endif /* NSSDEBUG */
    369 
    370    state = nssCKFWToken_GetSessionState(fwSession->fwToken);
    371    switch (state) {
    372        case CKS_RO_PUBLIC_SESSION:
    373        case CKS_RO_USER_FUNCTIONS:
    374        case CKS_RW_PUBLIC_SESSION:
    375        case CKS_RW_USER_FUNCTIONS:
    376            return CK_FALSE;
    377        case CKS_RW_SO_FUNCTIONS:
    378            return CK_TRUE;
    379        default:
    380            return CK_FALSE;
    381    }
    382 }
    383 
    384 /*
    385 * nssCKFWSession_GetFWSlot
    386 *
    387 */
    388 NSS_IMPLEMENT NSSCKFWSlot *
    389 nssCKFWSession_GetFWSlot(
    390    NSSCKFWSession *fwSession)
    391 {
    392 #ifdef NSSDEBUG
    393    if (CKR_OK != nssCKFWSession_verifyPointer(fwSession)) {
    394        return (NSSCKFWSlot *)NULL;
    395    }
    396 #endif /* NSSDEBUG */
    397 
    398    return nssCKFWToken_GetFWSlot(fwSession->fwToken);
    399 }
    400 
    401 /*
    402 * nssCFKWSession_GetSessionState
    403 *
    404 */
    405 NSS_IMPLEMENT CK_STATE
    406 nssCKFWSession_GetSessionState(
    407    NSSCKFWSession *fwSession)
    408 {
    409 #ifdef NSSDEBUG
    410    if (CKR_OK != nssCKFWSession_verifyPointer(fwSession)) {
    411        return CKS_RO_PUBLIC_SESSION; /* whatever */
    412    }
    413 #endif /* NSSDEBUG */
    414 
    415    return nssCKFWToken_GetSessionState(fwSession->fwToken);
    416 }
    417 
    418 /*
    419 * nssCKFWSession_SetFWFindObjects
    420 *
    421 */
    422 NSS_IMPLEMENT CK_RV
    423 nssCKFWSession_SetFWFindObjects(
    424    NSSCKFWSession *fwSession,
    425    NSSCKFWFindObjects *fwFindObjects)
    426 {
    427 #ifdef NSSDEBUG
    428    CK_RV error = CKR_OK;
    429 #endif /* NSSDEBUG */
    430 
    431 #ifdef NSSDEBUG
    432    error = nssCKFWSession_verifyPointer(fwSession);
    433    if (CKR_OK != error) {
    434        return error;
    435    }
    436 
    437 /* fwFindObjects may be null */
    438 #endif /* NSSDEBUG */
    439 
    440    if ((fwSession->fwFindObjects) &&
    441        (fwFindObjects)) {
    442        return CKR_OPERATION_ACTIVE;
    443    }
    444 
    445    fwSession->fwFindObjects = fwFindObjects;
    446 
    447    return CKR_OK;
    448 }
    449 
    450 /*
    451 * nssCKFWSession_GetFWFindObjects
    452 *
    453 */
    454 NSS_IMPLEMENT NSSCKFWFindObjects *
    455 nssCKFWSession_GetFWFindObjects(
    456    NSSCKFWSession *fwSession,
    457    CK_RV *pError)
    458 {
    459 #ifdef NSSDEBUG
    460    if (!pError) {
    461        return (NSSCKFWFindObjects *)NULL;
    462    }
    463 
    464    *pError = nssCKFWSession_verifyPointer(fwSession);
    465    if (CKR_OK != *pError) {
    466        return (NSSCKFWFindObjects *)NULL;
    467    }
    468 #endif /* NSSDEBUG */
    469 
    470    if (!fwSession->fwFindObjects) {
    471        *pError = CKR_OPERATION_NOT_INITIALIZED;
    472        return (NSSCKFWFindObjects *)NULL;
    473    }
    474 
    475    return fwSession->fwFindObjects;
    476 }
    477 
    478 /*
    479 * nssCKFWSession_SetMDSession
    480 *
    481 */
    482 NSS_IMPLEMENT CK_RV
    483 nssCKFWSession_SetMDSession(
    484    NSSCKFWSession *fwSession,
    485    NSSCKMDSession *mdSession)
    486 {
    487 #ifdef NSSDEBUG
    488    CK_RV error = CKR_OK;
    489 #endif /* NSSDEBUG */
    490 
    491 #ifdef NSSDEBUG
    492    error = nssCKFWSession_verifyPointer(fwSession);
    493    if (CKR_OK != error) {
    494        return error;
    495    }
    496 
    497    if (!mdSession) {
    498        return CKR_ARGUMENTS_BAD;
    499    }
    500 #endif /* NSSDEBUG */
    501 
    502    if (fwSession->mdSession) {
    503        return CKR_GENERAL_ERROR;
    504    }
    505 
    506    fwSession->mdSession = mdSession;
    507 
    508    return CKR_OK;
    509 }
    510 
    511 /*
    512 * nssCKFWSession_SetHandle
    513 *
    514 */
    515 NSS_IMPLEMENT CK_RV
    516 nssCKFWSession_SetHandle(
    517    NSSCKFWSession *fwSession,
    518    CK_SESSION_HANDLE hSession)
    519 {
    520 #ifdef NSSDEBUG
    521    CK_RV error = CKR_OK;
    522 #endif /* NSSDEBUG */
    523 
    524 #ifdef NSSDEBUG
    525    error = nssCKFWSession_verifyPointer(fwSession);
    526    if (CKR_OK != error) {
    527        return error;
    528    }
    529 #endif /* NSSDEBUG */
    530 
    531    if ((CK_SESSION_HANDLE)0 != fwSession->hSession) {
    532        return CKR_GENERAL_ERROR;
    533    }
    534 
    535    fwSession->hSession = hSession;
    536 
    537    return CKR_OK;
    538 }
    539 
    540 /*
    541 * nssCKFWSession_GetHandle
    542 *
    543 */
    544 NSS_IMPLEMENT CK_SESSION_HANDLE
    545 nssCKFWSession_GetHandle(
    546    NSSCKFWSession *fwSession)
    547 {
    548 #ifdef NSSDEBUG
    549    if (CKR_OK != nssCKFWSession_verifyPointer(fwSession)) {
    550        return NULL;
    551    }
    552 #endif /* NSSDEBUG */
    553 
    554    return fwSession->hSession;
    555 }
    556 
    557 /*
    558 * nssCKFWSession_RegisterSessionObject
    559 *
    560 */
    561 NSS_IMPLEMENT CK_RV
    562 nssCKFWSession_RegisterSessionObject(
    563    NSSCKFWSession *fwSession,
    564    NSSCKFWObject *fwObject)
    565 {
    566    CK_RV rv = CKR_OK;
    567 
    568 #ifdef NSSDEBUG
    569    if (CKR_OK != nssCKFWSession_verifyPointer(fwSession)) {
    570        return CKR_GENERAL_ERROR;
    571    }
    572 #endif /* NSSDEBUG */
    573 
    574    if (fwSession->sessionObjectHash) {
    575        rv = nssCKFWHash_Add(fwSession->sessionObjectHash, fwObject, fwObject);
    576    }
    577 
    578    return rv;
    579 }
    580 
    581 /*
    582 * nssCKFWSession_DeregisterSessionObject
    583 *
    584 */
    585 NSS_IMPLEMENT CK_RV
    586 nssCKFWSession_DeregisterSessionObject(
    587    NSSCKFWSession *fwSession,
    588    NSSCKFWObject *fwObject)
    589 {
    590 #ifdef NSSDEBUG
    591    if (CKR_OK != nssCKFWSession_verifyPointer(fwSession)) {
    592        return CKR_GENERAL_ERROR;
    593    }
    594 #endif /* NSSDEBUG */
    595 
    596    if (fwSession->sessionObjectHash) {
    597        nssCKFWHash_Remove(fwSession->sessionObjectHash, fwObject);
    598    }
    599 
    600    return CKR_OK;
    601 }
    602 
    603 /*
    604 * nssCKFWSession_GetDeviceError
    605 *
    606 */
    607 NSS_IMPLEMENT CK_ULONG
    608 nssCKFWSession_GetDeviceError(
    609    NSSCKFWSession *fwSession)
    610 {
    611 #ifdef NSSDEBUG
    612    if (CKR_OK != nssCKFWSession_verifyPointer(fwSession)) {
    613        return (CK_ULONG)0;
    614    }
    615 
    616    if (!fwSession->mdSession) {
    617        return (CK_ULONG)0;
    618    }
    619 #endif /* NSSDEBUG */
    620 
    621    if (!fwSession->mdSession->GetDeviceError) {
    622        return (CK_ULONG)0;
    623    }
    624 
    625    return fwSession->mdSession->GetDeviceError(fwSession->mdSession,
    626                                                fwSession, fwSession->mdToken, fwSession->fwToken,
    627                                                fwSession->mdInstance, fwSession->fwInstance);
    628 }
    629 
    630 /*
    631 * nssCKFWSession_Login
    632 *
    633 */
    634 NSS_IMPLEMENT CK_RV
    635 nssCKFWSession_Login(
    636    NSSCKFWSession *fwSession,
    637    CK_USER_TYPE userType,
    638    NSSItem *pin)
    639 {
    640    CK_RV error = CKR_OK;
    641    CK_STATE oldState;
    642    CK_STATE newState;
    643 
    644 #ifdef NSSDEBUG
    645    error = nssCKFWSession_verifyPointer(fwSession);
    646    if (CKR_OK != error) {
    647        return error;
    648    }
    649 
    650    switch (userType) {
    651        case CKU_SO:
    652        case CKU_USER:
    653            break;
    654        default:
    655            return CKR_USER_TYPE_INVALID;
    656    }
    657 
    658    if (!pin) {
    659        if (CK_TRUE != nssCKFWToken_GetHasProtectedAuthenticationPath(fwSession->fwToken)) {
    660            return CKR_ARGUMENTS_BAD;
    661        }
    662    }
    663 
    664    if (!fwSession->mdSession) {
    665        return CKR_GENERAL_ERROR;
    666    }
    667 #endif /* NSSDEBUG */
    668 
    669    oldState = nssCKFWToken_GetSessionState(fwSession->fwToken);
    670 
    671    /*
    672     * It's not clear what happens when you're already logged in.
    673     * I'll just fail; but if we decide to change, the logic is
    674     * all right here.
    675     */
    676 
    677    if (CKU_SO == userType) {
    678        switch (oldState) {
    679            case CKS_RO_PUBLIC_SESSION:
    680                /*
    681                 * There's no such thing as a read-only security officer
    682                 * session, so fail.  The error should be CKR_SESSION_READ_ONLY,
    683                 * except that C_Login isn't defined to return that.  So we'll
    684                 * do CKR_SESSION_READ_ONLY_EXISTS, which is what is documented.
    685                 */
    686                return CKR_SESSION_READ_ONLY_EXISTS;
    687            case CKS_RO_USER_FUNCTIONS:
    688                return CKR_USER_ANOTHER_ALREADY_LOGGED_IN;
    689            case CKS_RW_PUBLIC_SESSION:
    690                newState =
    691                    CKS_RW_SO_FUNCTIONS;
    692                break;
    693            case CKS_RW_USER_FUNCTIONS:
    694                return CKR_USER_ANOTHER_ALREADY_LOGGED_IN;
    695            case CKS_RW_SO_FUNCTIONS:
    696                return CKR_USER_ALREADY_LOGGED_IN;
    697            default:
    698                return CKR_GENERAL_ERROR;
    699        }
    700    } else /* CKU_USER == userType */ {
    701        switch (oldState) {
    702            case CKS_RO_PUBLIC_SESSION:
    703                newState =
    704                    CKS_RO_USER_FUNCTIONS;
    705                break;
    706            case CKS_RO_USER_FUNCTIONS:
    707                return CKR_USER_ALREADY_LOGGED_IN;
    708            case CKS_RW_PUBLIC_SESSION:
    709                newState =
    710                    CKS_RW_USER_FUNCTIONS;
    711                break;
    712            case CKS_RW_USER_FUNCTIONS:
    713                return CKR_USER_ALREADY_LOGGED_IN;
    714            case CKS_RW_SO_FUNCTIONS:
    715                return CKR_USER_ANOTHER_ALREADY_LOGGED_IN;
    716            default:
    717                return CKR_GENERAL_ERROR;
    718        }
    719    }
    720 
    721    /*
    722     * So now we're in one of three cases:
    723     *
    724     * Old == CKS_RW_PUBLIC_SESSION, New == CKS_RW_SO_FUNCTIONS;
    725     * Old == CKS_RW_PUBLIC_SESSION, New == CKS_RW_USER_FUNCTIONS;
    726     * Old == CKS_RO_PUBLIC_SESSION, New == CKS_RO_USER_FUNCTIONS;
    727     */
    728 
    729    if (!fwSession->mdSession->Login) {
    730        /*
    731         * The Module doesn't want to be informed (or check the pin)
    732         * it'll just rely on the Framework as needed.
    733         */
    734        ;
    735    } else {
    736        error = fwSession->mdSession->Login(fwSession->mdSession, fwSession,
    737                                            fwSession->mdToken, fwSession->fwToken, fwSession->mdInstance,
    738                                            fwSession->fwInstance, userType, pin, oldState, newState);
    739        if (CKR_OK != error) {
    740            return error;
    741        }
    742    }
    743 
    744    (void)nssCKFWToken_SetSessionState(fwSession->fwToken, newState);
    745    return CKR_OK;
    746 }
    747 
    748 /*
    749 * nssCKFWSession_Logout
    750 *
    751 */
    752 NSS_IMPLEMENT CK_RV
    753 nssCKFWSession_Logout(
    754    NSSCKFWSession *fwSession)
    755 {
    756    CK_RV error = CKR_OK;
    757    CK_STATE oldState;
    758    CK_STATE newState;
    759 
    760 #ifdef NSSDEBUG
    761    error = nssCKFWSession_verifyPointer(fwSession);
    762    if (CKR_OK != error) {
    763        return error;
    764    }
    765 
    766    if (!fwSession->mdSession) {
    767        return CKR_GENERAL_ERROR;
    768    }
    769 #endif /* NSSDEBUG */
    770 
    771    oldState = nssCKFWToken_GetSessionState(fwSession->fwToken);
    772 
    773    switch (oldState) {
    774        case CKS_RO_PUBLIC_SESSION:
    775            return CKR_USER_NOT_LOGGED_IN;
    776        case CKS_RO_USER_FUNCTIONS:
    777            newState = CKS_RO_PUBLIC_SESSION;
    778            break;
    779        case CKS_RW_PUBLIC_SESSION:
    780            return CKR_USER_NOT_LOGGED_IN;
    781        case CKS_RW_USER_FUNCTIONS:
    782            newState = CKS_RW_PUBLIC_SESSION;
    783            break;
    784        case CKS_RW_SO_FUNCTIONS:
    785            newState = CKS_RW_PUBLIC_SESSION;
    786            break;
    787        default:
    788            return CKR_GENERAL_ERROR;
    789    }
    790 
    791    /*
    792     * So now we're in one of three cases:
    793     *
    794     * Old == CKS_RW_SO_FUNCTIONS,   New == CKS_RW_PUBLIC_SESSION;
    795     * Old == CKS_RW_USER_FUNCTIONS, New == CKS_RW_PUBLIC_SESSION;
    796     * Old == CKS_RO_USER_FUNCTIONS, New == CKS_RO_PUBLIC_SESSION;
    797     */
    798 
    799    if (!fwSession->mdSession->Logout) {
    800        /*
    801         * The Module doesn't want to be informed.  Okay.
    802         */
    803        ;
    804    } else {
    805        error = fwSession->mdSession->Logout(fwSession->mdSession, fwSession,
    806                                             fwSession->mdToken, fwSession->fwToken, fwSession->mdInstance,
    807                                             fwSession->fwInstance, oldState, newState);
    808        if (CKR_OK != error) {
    809            /*
    810             * Now what?!  A failure really should end up with the Framework
    811             * considering it logged out, right?
    812             */
    813            ;
    814        }
    815    }
    816 
    817    (void)nssCKFWToken_SetSessionState(fwSession->fwToken, newState);
    818    return error;
    819 }
    820 
    821 /*
    822 * nssCKFWSession_InitPIN
    823 *
    824 */
    825 NSS_IMPLEMENT CK_RV
    826 nssCKFWSession_InitPIN(
    827    NSSCKFWSession *fwSession,
    828    NSSItem *pin)
    829 {
    830    CK_RV error = CKR_OK;
    831    CK_STATE state;
    832 
    833 #ifdef NSSDEBUG
    834    error = nssCKFWSession_verifyPointer(fwSession);
    835    if (CKR_OK != error) {
    836        return error;
    837    }
    838 
    839    if (!fwSession->mdSession) {
    840        return CKR_GENERAL_ERROR;
    841    }
    842 #endif /* NSSDEBUG */
    843 
    844    state = nssCKFWToken_GetSessionState(fwSession->fwToken);
    845    if (CKS_RW_SO_FUNCTIONS != state) {
    846        return CKR_USER_NOT_LOGGED_IN;
    847    }
    848 
    849    if (!pin) {
    850        CK_BBOOL has = nssCKFWToken_GetHasProtectedAuthenticationPath(fwSession->fwToken);
    851        if (CK_TRUE != has) {
    852            return CKR_ARGUMENTS_BAD;
    853        }
    854    }
    855 
    856    if (!fwSession->mdSession->InitPIN) {
    857        return CKR_TOKEN_WRITE_PROTECTED;
    858    }
    859 
    860    error = fwSession->mdSession->InitPIN(fwSession->mdSession, fwSession,
    861                                          fwSession->mdToken, fwSession->fwToken, fwSession->mdInstance,
    862                                          fwSession->fwInstance, pin);
    863 
    864    return error;
    865 }
    866 
    867 /*
    868 * nssCKFWSession_SetPIN
    869 *
    870 */
    871 NSS_IMPLEMENT CK_RV
    872 nssCKFWSession_SetPIN(
    873    NSSCKFWSession *fwSession,
    874    const NSSItem *oldPin,
    875    NSSItem *newPin)
    876 {
    877    CK_RV error = CKR_OK;
    878 
    879 #ifdef NSSDEBUG
    880    error = nssCKFWSession_verifyPointer(fwSession);
    881    if (CKR_OK != error) {
    882        return error;
    883    }
    884 
    885    if (!fwSession->mdSession) {
    886        return CKR_GENERAL_ERROR;
    887    }
    888 #endif /* NSSDEBUG */
    889 
    890    if (!newPin) {
    891        CK_BBOOL has = nssCKFWToken_GetHasProtectedAuthenticationPath(fwSession->fwToken);
    892        if (CK_TRUE != has) {
    893            return CKR_ARGUMENTS_BAD;
    894        }
    895    }
    896 
    897    if (!oldPin) {
    898        CK_BBOOL has = nssCKFWToken_GetHasProtectedAuthenticationPath(fwSession->fwToken);
    899        if (CK_TRUE != has) {
    900            return CKR_ARGUMENTS_BAD;
    901        }
    902    }
    903 
    904    if (!fwSession->mdSession->SetPIN) {
    905        return CKR_TOKEN_WRITE_PROTECTED;
    906    }
    907 
    908    error = fwSession->mdSession->SetPIN(fwSession->mdSession, fwSession,
    909                                         fwSession->mdToken, fwSession->fwToken, fwSession->mdInstance,
    910                                         fwSession->fwInstance, (NSSItem *)oldPin, newPin);
    911 
    912    return error;
    913 }
    914 
    915 /*
    916 * nssCKFWSession_GetOperationStateLen
    917 *
    918 */
    919 NSS_IMPLEMENT CK_ULONG
    920 nssCKFWSession_GetOperationStateLen(
    921    NSSCKFWSession *fwSession,
    922    CK_RV *pError)
    923 {
    924    CK_ULONG mdAmt;
    925    CK_ULONG fwAmt;
    926 
    927 #ifdef NSSDEBUG
    928    if (!pError) {
    929        return (CK_ULONG)0;
    930    }
    931 
    932    *pError = nssCKFWSession_verifyPointer(fwSession);
    933    if (CKR_OK != *pError) {
    934        return (CK_ULONG)0;
    935    }
    936 
    937    if (!fwSession->mdSession) {
    938        *pError = CKR_GENERAL_ERROR;
    939        return (CK_ULONG)0;
    940    }
    941 #endif /* NSSDEBUG */
    942 
    943    if (!fwSession->mdSession->GetOperationStateLen) {
    944        *pError = CKR_STATE_UNSAVEABLE;
    945        return (CK_ULONG)0;
    946    }
    947 
    948    /*
    949     * We could check that the session is actually in some state..
    950     */
    951 
    952    mdAmt = fwSession->mdSession->GetOperationStateLen(fwSession->mdSession,
    953                                                       fwSession, fwSession->mdToken, fwSession->fwToken, fwSession->mdInstance,
    954                                                       fwSession->fwInstance, pError);
    955 
    956    if (((CK_ULONG)0 == mdAmt) && (CKR_OK != *pError)) {
    957        return (CK_ULONG)0;
    958    }
    959 
    960    /*
    961     * Add a bit of sanity-checking
    962     */
    963    fwAmt = mdAmt + 2 * sizeof(CK_ULONG);
    964 
    965    return fwAmt;
    966 }
    967 
    968 /*
    969 * nssCKFWSession_GetOperationState
    970 *
    971 */
    972 NSS_IMPLEMENT CK_RV
    973 nssCKFWSession_GetOperationState(
    974    NSSCKFWSession *fwSession,
    975    NSSItem *buffer)
    976 {
    977    CK_RV error = CKR_OK;
    978    CK_ULONG fwAmt;
    979    CK_ULONG *ulBuffer;
    980    NSSItem i2;
    981    CK_ULONG n, i;
    982 
    983 #ifdef NSSDEBUG
    984    error = nssCKFWSession_verifyPointer(fwSession);
    985    if (CKR_OK != error) {
    986        return error;
    987    }
    988 
    989    if (!buffer) {
    990        return CKR_ARGUMENTS_BAD;
    991    }
    992 
    993    if (!buffer->data) {
    994        return CKR_ARGUMENTS_BAD;
    995    }
    996 
    997    if (!fwSession->mdSession) {
    998        return CKR_GENERAL_ERROR;
    999    }
   1000 #endif /* NSSDEBUG */
   1001 
   1002    if (!fwSession->mdSession->GetOperationState) {
   1003        return CKR_STATE_UNSAVEABLE;
   1004    }
   1005 
   1006    /*
   1007     * Sanity-check the caller's buffer.
   1008     */
   1009 
   1010    error = CKR_OK;
   1011    fwAmt = nssCKFWSession_GetOperationStateLen(fwSession, &error);
   1012    if (((CK_ULONG)0 == fwAmt) && (CKR_OK != error)) {
   1013        return error;
   1014    }
   1015 
   1016    if (buffer->size < fwAmt) {
   1017        return CKR_BUFFER_TOO_SMALL;
   1018    }
   1019 
   1020    ulBuffer = (CK_ULONG *)buffer->data;
   1021 
   1022    i2.size = buffer->size - 2 * sizeof(CK_ULONG);
   1023    i2.data = (void *)&ulBuffer[2];
   1024 
   1025    error = fwSession->mdSession->GetOperationState(fwSession->mdSession,
   1026                                                    fwSession, fwSession->mdToken, fwSession->fwToken,
   1027                                                    fwSession->mdInstance, fwSession->fwInstance, &i2);
   1028 
   1029    if (CKR_OK != error) {
   1030        return error;
   1031    }
   1032 
   1033    /*
   1034     * Add a little integrety/identity check.
   1035     * NOTE: right now, it's pretty stupid.
   1036     * A CRC or something would be better.
   1037     */
   1038 
   1039    ulBuffer[0] = 0x434b4657; /* CKFW */
   1040    ulBuffer[1] = 0;
   1041    n = i2.size / sizeof(CK_ULONG);
   1042    for (i = 0; i < n; i++) {
   1043        ulBuffer[1] ^= ulBuffer[2 + i];
   1044    }
   1045 
   1046    return CKR_OK;
   1047 }
   1048 
   1049 /*
   1050 * nssCKFWSession_SetOperationState
   1051 *
   1052 */
   1053 NSS_IMPLEMENT CK_RV
   1054 nssCKFWSession_SetOperationState(
   1055    NSSCKFWSession *fwSession,
   1056    NSSItem *state,
   1057    NSSCKFWObject *encryptionKey,
   1058    NSSCKFWObject *authenticationKey)
   1059 {
   1060    CK_RV error = CKR_OK;
   1061    CK_ULONG *ulBuffer;
   1062    CK_ULONG n, i;
   1063    CK_ULONG x;
   1064    NSSItem s;
   1065    NSSCKMDObject *mdek;
   1066    NSSCKMDObject *mdak;
   1067 
   1068 #ifdef NSSDEBUG
   1069    error = nssCKFWSession_verifyPointer(fwSession);
   1070    if (CKR_OK != error) {
   1071        return error;
   1072    }
   1073 
   1074    if (!state) {
   1075        return CKR_ARGUMENTS_BAD;
   1076    }
   1077 
   1078    if (!state->data) {
   1079        return CKR_ARGUMENTS_BAD;
   1080    }
   1081 
   1082    if (encryptionKey) {
   1083        error = nssCKFWObject_verifyPointer(encryptionKey);
   1084        if (CKR_OK != error) {
   1085            return error;
   1086        }
   1087    }
   1088 
   1089    if (authenticationKey) {
   1090        error = nssCKFWObject_verifyPointer(authenticationKey);
   1091        if (CKR_OK != error) {
   1092            return error;
   1093        }
   1094    }
   1095 
   1096    if (!fwSession->mdSession) {
   1097        return CKR_GENERAL_ERROR;
   1098    }
   1099 #endif /* NSSDEBUG */
   1100 
   1101    ulBuffer = (CK_ULONG *)state->data;
   1102    if (0x43b4657 != ulBuffer[0]) {
   1103        return CKR_SAVED_STATE_INVALID;
   1104    }
   1105    n = (state->size / sizeof(CK_ULONG)) - 2;
   1106    x = (CK_ULONG)0;
   1107    for (i = 0; i < n; i++) {
   1108        x ^= ulBuffer[2 + i];
   1109    }
   1110 
   1111    if (x != ulBuffer[1]) {
   1112        return CKR_SAVED_STATE_INVALID;
   1113    }
   1114 
   1115    if (!fwSession->mdSession->SetOperationState) {
   1116        return CKR_GENERAL_ERROR;
   1117    }
   1118 
   1119    s.size = state->size - 2 * sizeof(CK_ULONG);
   1120    s.data = (void *)&ulBuffer[2];
   1121 
   1122    if (encryptionKey) {
   1123        mdek = nssCKFWObject_GetMDObject(encryptionKey);
   1124    } else {
   1125        mdek = (NSSCKMDObject *)NULL;
   1126    }
   1127 
   1128    if (authenticationKey) {
   1129        mdak = nssCKFWObject_GetMDObject(authenticationKey);
   1130    } else {
   1131        mdak = (NSSCKMDObject *)NULL;
   1132    }
   1133 
   1134    error = fwSession->mdSession->SetOperationState(fwSession->mdSession,
   1135                                                    fwSession, fwSession->mdToken, fwSession->fwToken, fwSession->mdInstance,
   1136                                                    fwSession->fwInstance, &s, mdek, encryptionKey, mdak, authenticationKey);
   1137 
   1138    if (CKR_OK != error) {
   1139        return error;
   1140    }
   1141 
   1142    /*
   1143     * Here'd we restore any session data
   1144     */
   1145 
   1146    return CKR_OK;
   1147 }
   1148 
   1149 static CK_BBOOL
   1150 nss_attributes_form_token_object(
   1151    CK_ATTRIBUTE_PTR pTemplate,
   1152    CK_ULONG ulAttributeCount)
   1153 {
   1154    CK_ULONG i;
   1155    CK_BBOOL rv;
   1156 
   1157    for (i = 0; i < ulAttributeCount; i++) {
   1158        if (CKA_TOKEN == pTemplate[i].type) {
   1159            /* If we sanity-check, we can remove this sizeof check */
   1160            if (sizeof(CK_BBOOL) == pTemplate[i].ulValueLen) {
   1161                (void)nsslibc_memcpy(&rv, pTemplate[i].pValue, sizeof(CK_BBOOL));
   1162                return rv;
   1163            } else {
   1164                return CK_FALSE;
   1165            }
   1166        }
   1167    }
   1168 
   1169    return CK_FALSE;
   1170 }
   1171 
   1172 /*
   1173 * nssCKFWSession_CreateObject
   1174 *
   1175 */
   1176 NSS_IMPLEMENT NSSCKFWObject *
   1177 nssCKFWSession_CreateObject(
   1178    NSSCKFWSession *fwSession,
   1179    CK_ATTRIBUTE_PTR pTemplate,
   1180    CK_ULONG ulAttributeCount,
   1181    CK_RV *pError)
   1182 {
   1183    NSSArena *arena;
   1184    NSSCKMDObject *mdObject;
   1185    NSSCKFWObject *fwObject;
   1186    CK_BBOOL isTokenObject;
   1187 
   1188 #ifdef NSSDEBUG
   1189    if (!pError) {
   1190        return (NSSCKFWObject *)NULL;
   1191    }
   1192 
   1193    *pError = nssCKFWSession_verifyPointer(fwSession);
   1194    if (CKR_OK != pError) {
   1195        return (NSSCKFWObject *)NULL;
   1196    }
   1197 
   1198    if ((CK_ATTRIBUTE_PTR)NULL == pTemplate) {
   1199        *pError = CKR_ARGUMENTS_BAD;
   1200        return (NSSCKFWObject *)NULL;
   1201    }
   1202 
   1203    if (!fwSession->mdSession) {
   1204        *pError = CKR_GENERAL_ERROR;
   1205        return (NSSCKFWObject *)NULL;
   1206    }
   1207 #endif /* NSSDEBUG */
   1208 
   1209    /*
   1210     * Here would be an excellent place to sanity-check the object.
   1211     */
   1212 
   1213    isTokenObject = nss_attributes_form_token_object(pTemplate, ulAttributeCount);
   1214    if (CK_TRUE == isTokenObject) {
   1215        /* === TOKEN OBJECT === */
   1216 
   1217        if (!fwSession->mdSession->CreateObject) {
   1218            *pError = CKR_TOKEN_WRITE_PROTECTED;
   1219            return (NSSCKFWObject *)NULL;
   1220        }
   1221 
   1222        arena = nssCKFWToken_GetArena(fwSession->fwToken, pError);
   1223        if (!arena) {
   1224            if (CKR_OK == *pError) {
   1225                *pError = CKR_GENERAL_ERROR;
   1226            }
   1227            return (NSSCKFWObject *)NULL;
   1228        }
   1229 
   1230        goto callmdcreateobject;
   1231    } else {
   1232        /* === SESSION OBJECT === */
   1233 
   1234        arena = nssCKFWSession_GetArena(fwSession, pError);
   1235        if (!arena) {
   1236            if (CKR_OK == *pError) {
   1237                *pError = CKR_GENERAL_ERROR;
   1238            }
   1239            return (NSSCKFWObject *)NULL;
   1240        }
   1241 
   1242        if (CK_TRUE == nssCKFWInstance_GetModuleHandlesSessionObjects(
   1243                           fwSession->fwInstance)) {
   1244            /* --- module handles the session object -- */
   1245 
   1246            if (!fwSession->mdSession->CreateObject) {
   1247                *pError = CKR_GENERAL_ERROR;
   1248                return (NSSCKFWObject *)NULL;
   1249            }
   1250 
   1251            goto callmdcreateobject;
   1252        } else {
   1253            /* --- framework handles the session object -- */
   1254            mdObject = nssCKMDSessionObject_Create(fwSession->fwToken,
   1255                                                   arena, pTemplate, ulAttributeCount, pError);
   1256            goto gotmdobject;
   1257        }
   1258    }
   1259 
   1260 callmdcreateobject:
   1261    mdObject = fwSession->mdSession->CreateObject(fwSession->mdSession,
   1262                                                  fwSession, fwSession->mdToken, fwSession->fwToken,
   1263                                                  fwSession->mdInstance, fwSession->fwInstance, arena, pTemplate,
   1264                                                  ulAttributeCount, pError);
   1265 
   1266 gotmdobject:
   1267    if (!mdObject) {
   1268        if (CKR_OK == *pError) {
   1269            *pError = CKR_GENERAL_ERROR;
   1270        }
   1271        return (NSSCKFWObject *)NULL;
   1272    }
   1273 
   1274    fwObject = nssCKFWObject_Create(isTokenObject ? arena : NULL, mdObject,
   1275                                    isTokenObject ? NULL
   1276                                                  : fwSession,
   1277                                    fwSession->fwToken, fwSession->fwInstance, pError);
   1278    if (!fwObject) {
   1279        if (CKR_OK == *pError) {
   1280            *pError = CKR_GENERAL_ERROR;
   1281        }
   1282 
   1283        if (mdObject->Destroy) {
   1284            (void)mdObject->Destroy(mdObject, (NSSCKFWObject *)NULL,
   1285                                    fwSession->mdSession, fwSession, fwSession->mdToken,
   1286                                    fwSession->fwToken, fwSession->mdInstance, fwSession->fwInstance);
   1287        }
   1288 
   1289        return (NSSCKFWObject *)NULL;
   1290    }
   1291 
   1292    if (CK_FALSE == isTokenObject) {
   1293        if (CK_FALSE == nssCKFWHash_Exists(fwSession->sessionObjectHash, fwObject)) {
   1294            *pError = nssCKFWHash_Add(fwSession->sessionObjectHash, fwObject, fwObject);
   1295            if (CKR_OK != *pError) {
   1296                nssCKFWObject_Finalize(fwObject, PR_TRUE);
   1297                return (NSSCKFWObject *)NULL;
   1298            }
   1299        }
   1300    }
   1301 
   1302    return fwObject;
   1303 }
   1304 
   1305 /*
   1306 * nssCKFWSession_CopyObject
   1307 *
   1308 */
   1309 NSS_IMPLEMENT NSSCKFWObject *
   1310 nssCKFWSession_CopyObject(
   1311    NSSCKFWSession *fwSession,
   1312    NSSCKFWObject *fwObject,
   1313    CK_ATTRIBUTE_PTR pTemplate,
   1314    CK_ULONG ulAttributeCount,
   1315    CK_RV *pError)
   1316 {
   1317    CK_BBOOL oldIsToken;
   1318    CK_BBOOL newIsToken;
   1319    CK_ULONG i;
   1320    NSSCKFWObject *rv;
   1321 
   1322 #ifdef NSSDEBUG
   1323    if (!pError) {
   1324        return (NSSCKFWObject *)NULL;
   1325    }
   1326 
   1327    *pError = nssCKFWSession_verifyPointer(fwSession);
   1328    if (CKR_OK != *pError) {
   1329        return (NSSCKFWObject *)NULL;
   1330    }
   1331 
   1332    *pError = nssCKFWObject_verifyPointer(fwObject);
   1333    if (CKR_OK != *pError) {
   1334        return (NSSCKFWObject *)NULL;
   1335    }
   1336 
   1337    if (!fwSession->mdSession) {
   1338        *pError = CKR_GENERAL_ERROR;
   1339        return (NSSCKFWObject *)NULL;
   1340    }
   1341 #endif /* NSSDEBUG */
   1342 
   1343    /*
   1344     * Sanity-check object
   1345     */
   1346 
   1347    if (!fwObject) {
   1348        *pError = CKR_ARGUMENTS_BAD;
   1349        return (NSSCKFWObject *)NULL;
   1350    }
   1351 
   1352    oldIsToken = nssCKFWObject_IsTokenObject(fwObject);
   1353 
   1354    newIsToken = oldIsToken;
   1355    for (i = 0; i < ulAttributeCount; i++) {
   1356        if (CKA_TOKEN == pTemplate[i].type) {
   1357            /* Since we sanity-checked the object, we know this is the right size. */
   1358            (void)nsslibc_memcpy(&newIsToken, pTemplate[i].pValue, sizeof(CK_BBOOL));
   1359            break;
   1360        }
   1361    }
   1362 
   1363    /*
   1364     * If the Module handles its session objects, or if both the new
   1365     * and old object are token objects, use CopyObject if it exists.
   1366     */
   1367 
   1368    if ((fwSession->mdSession->CopyObject) &&
   1369        (((CK_TRUE == oldIsToken) && (CK_TRUE == newIsToken)) ||
   1370         (CK_TRUE == nssCKFWInstance_GetModuleHandlesSessionObjects(
   1371                         fwSession->fwInstance)))) {
   1372        /* use copy object */
   1373        NSSArena *arena;
   1374        NSSCKMDObject *mdOldObject;
   1375        NSSCKMDObject *mdObject;
   1376 
   1377        mdOldObject = nssCKFWObject_GetMDObject(fwObject);
   1378 
   1379        if (CK_TRUE == newIsToken) {
   1380            arena = nssCKFWToken_GetArena(fwSession->fwToken, pError);
   1381        } else {
   1382            arena = nssCKFWSession_GetArena(fwSession, pError);
   1383        }
   1384        if (!arena) {
   1385            if (CKR_OK == *pError) {
   1386                *pError = CKR_GENERAL_ERROR;
   1387            }
   1388            return (NSSCKFWObject *)NULL;
   1389        }
   1390 
   1391        mdObject = fwSession->mdSession->CopyObject(fwSession->mdSession,
   1392                                                    fwSession, fwSession->mdToken, fwSession->fwToken,
   1393                                                    fwSession->mdInstance, fwSession->fwInstance, mdOldObject,
   1394                                                    fwObject, arena, pTemplate, ulAttributeCount, pError);
   1395        if (!mdObject) {
   1396            if (CKR_OK == *pError) {
   1397                *pError = CKR_GENERAL_ERROR;
   1398            }
   1399            return (NSSCKFWObject *)NULL;
   1400        }
   1401 
   1402        rv = nssCKFWObject_Create(newIsToken ? arena : NULL, mdObject,
   1403                                  newIsToken ? NULL
   1404                                             : fwSession,
   1405                                  fwSession->fwToken, fwSession->fwInstance, pError);
   1406 
   1407        if (CK_FALSE == newIsToken) {
   1408            if (CK_FALSE == nssCKFWHash_Exists(fwSession->sessionObjectHash, rv)) {
   1409                *pError = nssCKFWHash_Add(fwSession->sessionObjectHash, rv, rv);
   1410                if (CKR_OK != *pError) {
   1411                    nssCKFWObject_Finalize(rv, PR_TRUE);
   1412                    return (NSSCKFWObject *)NULL;
   1413                }
   1414            }
   1415        }
   1416 
   1417        return rv;
   1418    } else {
   1419        /* use create object */
   1420        NSSArena *tmpArena;
   1421        CK_ATTRIBUTE_PTR newTemplate;
   1422        CK_ULONG j, n, newLength, k;
   1423        CK_ATTRIBUTE_TYPE_PTR oldTypes;
   1424 
   1425        n = nssCKFWObject_GetAttributeCount(fwObject, pError);
   1426        if ((0 == n) && (CKR_OK != *pError)) {
   1427            return (NSSCKFWObject *)NULL;
   1428        }
   1429 
   1430        tmpArena = NSSArena_Create();
   1431        if (!tmpArena) {
   1432            *pError = CKR_HOST_MEMORY;
   1433            return (NSSCKFWObject *)NULL;
   1434        }
   1435 
   1436        oldTypes = nss_ZNEWARRAY(tmpArena, CK_ATTRIBUTE_TYPE, n);
   1437        if ((CK_ATTRIBUTE_TYPE_PTR)NULL == oldTypes) {
   1438            NSSArena_Destroy(tmpArena);
   1439            *pError = CKR_HOST_MEMORY;
   1440            return (NSSCKFWObject *)NULL;
   1441        }
   1442 
   1443        *pError = nssCKFWObject_GetAttributeTypes(fwObject, oldTypes, n);
   1444        if (CKR_OK != *pError) {
   1445            NSSArena_Destroy(tmpArena);
   1446            return (NSSCKFWObject *)NULL;
   1447        }
   1448 
   1449        newLength = n;
   1450        for (i = 0; i < ulAttributeCount; i++) {
   1451            for (j = 0; j < n; j++) {
   1452                if (oldTypes[j] == pTemplate[i].type) {
   1453                    if ((CK_VOID_PTR)NULL ==
   1454                        pTemplate[i].pValue) {
   1455                        /* Removing the attribute */
   1456                        newLength--;
   1457                    }
   1458                    break;
   1459                }
   1460            }
   1461            if (j == n) {
   1462                /* Not found */
   1463                newLength++;
   1464            }
   1465        }
   1466 
   1467        newTemplate = nss_ZNEWARRAY(tmpArena, CK_ATTRIBUTE, newLength);
   1468        if ((CK_ATTRIBUTE_PTR)NULL == newTemplate) {
   1469            NSSArena_Destroy(tmpArena);
   1470            *pError = CKR_HOST_MEMORY;
   1471            return (NSSCKFWObject *)NULL;
   1472        }
   1473 
   1474        k = 0;
   1475        for (j = 0; j < n; j++) {
   1476            for (i = 0; i < ulAttributeCount; i++) {
   1477                if (oldTypes[j] == pTemplate[i].type) {
   1478                    if ((CK_VOID_PTR)NULL ==
   1479                        pTemplate[i].pValue) {
   1480                        /* This attribute is being deleted */
   1481                        ;
   1482                    } else {
   1483                        /* This attribute is being replaced */
   1484                        newTemplate[k].type =
   1485                            pTemplate[i].type;
   1486                        newTemplate[k].pValue =
   1487                            pTemplate[i].pValue;
   1488                        newTemplate[k].ulValueLen =
   1489                            pTemplate[i].ulValueLen;
   1490                        k++;
   1491                    }
   1492                    break;
   1493                }
   1494            }
   1495            if (i == ulAttributeCount) {
   1496                /* This attribute is being copied over from the old object */
   1497                NSSItem item, *it;
   1498                item.size = 0;
   1499                item.data = (void *)NULL;
   1500                it = nssCKFWObject_GetAttribute(fwObject, oldTypes[j],
   1501                                                &item, tmpArena, pError);
   1502                if (!it) {
   1503                    if (CKR_OK ==
   1504                        *pError) {
   1505                        *pError =
   1506                            CKR_GENERAL_ERROR;
   1507                    }
   1508                    NSSArena_Destroy(tmpArena);
   1509                    return (NSSCKFWObject *)NULL;
   1510                }
   1511                newTemplate[k].type = oldTypes[j];
   1512                newTemplate[k].pValue = it->data;
   1513                newTemplate[k].ulValueLen = it->size;
   1514                k++;
   1515            }
   1516        }
   1517        /* assert that k == newLength */
   1518 
   1519        rv = nssCKFWSession_CreateObject(fwSession, newTemplate, newLength, pError);
   1520        if (!rv) {
   1521            if (CKR_OK == *pError) {
   1522                *pError = CKR_GENERAL_ERROR;
   1523            }
   1524            NSSArena_Destroy(tmpArena);
   1525            return (NSSCKFWObject *)NULL;
   1526        }
   1527 
   1528        NSSArena_Destroy(tmpArena);
   1529        return rv;
   1530    }
   1531 }
   1532 
   1533 /*
   1534 * nssCKFWSession_FindObjectsInit
   1535 *
   1536 */
   1537 NSS_IMPLEMENT NSSCKFWFindObjects *
   1538 nssCKFWSession_FindObjectsInit(
   1539    NSSCKFWSession *fwSession,
   1540    CK_ATTRIBUTE_PTR pTemplate,
   1541    CK_ULONG ulAttributeCount,
   1542    CK_RV *pError)
   1543 {
   1544    NSSCKMDFindObjects *mdfo1 = (NSSCKMDFindObjects *)NULL;
   1545    NSSCKMDFindObjects *mdfo2 = (NSSCKMDFindObjects *)NULL;
   1546 
   1547 #ifdef NSSDEBUG
   1548    if (!pError) {
   1549        return (NSSCKFWFindObjects *)NULL;
   1550    }
   1551 
   1552    *pError = nssCKFWSession_verifyPointer(fwSession);
   1553    if (CKR_OK != *pError) {
   1554        return (NSSCKFWFindObjects *)NULL;
   1555    }
   1556 
   1557    if (((CK_ATTRIBUTE_PTR)NULL == pTemplate) && (ulAttributeCount != 0)) {
   1558        *pError = CKR_ARGUMENTS_BAD;
   1559        return (NSSCKFWFindObjects *)NULL;
   1560    }
   1561 
   1562    if (!fwSession->mdSession) {
   1563        *pError = CKR_GENERAL_ERROR;
   1564        return (NSSCKFWFindObjects *)NULL;
   1565    }
   1566 #endif /* NSSDEBUG */
   1567 
   1568    if (CK_TRUE != nssCKFWInstance_GetModuleHandlesSessionObjects(
   1569                       fwSession->fwInstance)) {
   1570        CK_ULONG i;
   1571 
   1572        /*
   1573         * Does the search criteria restrict us to token or session
   1574         * objects?
   1575         */
   1576 
   1577        for (i = 0; i < ulAttributeCount; i++) {
   1578            if (CKA_TOKEN == pTemplate[i].type) {
   1579                /* Yes, it does. */
   1580                CK_BBOOL isToken;
   1581                if (sizeof(CK_BBOOL) != pTemplate[i].ulValueLen) {
   1582                    *pError =
   1583                        CKR_ATTRIBUTE_VALUE_INVALID;
   1584                    return (NSSCKFWFindObjects *)NULL;
   1585                }
   1586                (void)nsslibc_memcpy(&isToken, pTemplate[i].pValue, sizeof(CK_BBOOL));
   1587 
   1588                if (CK_TRUE == isToken) {
   1589                    /* Pass it on to the module's search routine */
   1590                    if (!fwSession->mdSession->FindObjectsInit) {
   1591                        goto wrap;
   1592                    }
   1593 
   1594                    mdfo1 =
   1595                        fwSession->mdSession->FindObjectsInit(fwSession->mdSession,
   1596                                                              fwSession, fwSession->mdToken, fwSession->fwToken,
   1597                                                              fwSession->mdInstance, fwSession->fwInstance,
   1598                                                              pTemplate, ulAttributeCount, pError);
   1599                } else {
   1600                    /* Do the search ourselves */
   1601                    mdfo1 =
   1602                        nssCKMDFindSessionObjects_Create(fwSession->fwToken,
   1603                                                         pTemplate, ulAttributeCount, pError);
   1604                }
   1605 
   1606                if (!mdfo1) {
   1607                    if (CKR_OK ==
   1608                        *pError) {
   1609                        *pError =
   1610                            CKR_GENERAL_ERROR;
   1611                    }
   1612                    return (NSSCKFWFindObjects *)NULL;
   1613                }
   1614 
   1615                goto wrap;
   1616            }
   1617        }
   1618 
   1619        if (i == ulAttributeCount) {
   1620            /* No, it doesn't.  Do a hybrid search. */
   1621            mdfo1 = fwSession->mdSession->FindObjectsInit(fwSession->mdSession,
   1622                                                          fwSession, fwSession->mdToken, fwSession->fwToken,
   1623                                                          fwSession->mdInstance, fwSession->fwInstance,
   1624                                                          pTemplate, ulAttributeCount, pError);
   1625 
   1626            if (!mdfo1) {
   1627                if (CKR_OK == *pError) {
   1628                    *pError =
   1629                        CKR_GENERAL_ERROR;
   1630                }
   1631                return (NSSCKFWFindObjects *)NULL;
   1632            }
   1633 
   1634            mdfo2 = nssCKMDFindSessionObjects_Create(fwSession->fwToken,
   1635                                                     pTemplate, ulAttributeCount, pError);
   1636            if (!mdfo2) {
   1637                if (CKR_OK == *pError) {
   1638                    *pError =
   1639                        CKR_GENERAL_ERROR;
   1640                }
   1641                if (mdfo1->Final) {
   1642                    mdfo1->Final(mdfo1, (NSSCKFWFindObjects *)NULL, fwSession->mdSession,
   1643                                 fwSession, fwSession->mdToken, fwSession->fwToken,
   1644                                 fwSession->mdInstance, fwSession->fwInstance);
   1645                }
   1646                return (NSSCKFWFindObjects *)NULL;
   1647            }
   1648 
   1649            goto wrap;
   1650        }
   1651        /*NOTREACHED*/
   1652    } else {
   1653        /* Module handles all its own objects.  Pass on to module's search */
   1654        mdfo1 = fwSession->mdSession->FindObjectsInit(fwSession->mdSession,
   1655                                                      fwSession, fwSession->mdToken, fwSession->fwToken,
   1656                                                      fwSession->mdInstance, fwSession->fwInstance,
   1657                                                      pTemplate, ulAttributeCount, pError);
   1658 
   1659        if (!mdfo1) {
   1660            if (CKR_OK == *pError) {
   1661                *pError = CKR_GENERAL_ERROR;
   1662            }
   1663            return (NSSCKFWFindObjects *)NULL;
   1664        }
   1665 
   1666        goto wrap;
   1667    }
   1668 
   1669 wrap:
   1670    return nssCKFWFindObjects_Create(fwSession, fwSession->fwToken,
   1671                                     fwSession->fwInstance, mdfo1, mdfo2, pError);
   1672 }
   1673 
   1674 /*
   1675 * nssCKFWSession_SeedRandom
   1676 *
   1677 */
   1678 NSS_IMPLEMENT CK_RV
   1679 nssCKFWSession_SeedRandom(
   1680    NSSCKFWSession *fwSession,
   1681    NSSItem *seed)
   1682 {
   1683    CK_RV error = CKR_OK;
   1684 
   1685 #ifdef NSSDEBUG
   1686    error = nssCKFWSession_verifyPointer(fwSession);
   1687    if (CKR_OK != error) {
   1688        return error;
   1689    }
   1690 
   1691    if (!seed) {
   1692        return CKR_ARGUMENTS_BAD;
   1693    }
   1694 
   1695    if (!seed->data) {
   1696        return CKR_ARGUMENTS_BAD;
   1697    }
   1698 
   1699    if (0 == seed->size) {
   1700        return CKR_ARGUMENTS_BAD;
   1701    }
   1702 
   1703    if (!fwSession->mdSession) {
   1704        return CKR_GENERAL_ERROR;
   1705    }
   1706 #endif /* NSSDEBUG */
   1707 
   1708    if (!fwSession->mdSession->SeedRandom) {
   1709        return CKR_RANDOM_SEED_NOT_SUPPORTED;
   1710    }
   1711 
   1712    error = fwSession->mdSession->SeedRandom(fwSession->mdSession, fwSession,
   1713                                             fwSession->mdToken, fwSession->fwToken, fwSession->mdInstance,
   1714                                             fwSession->fwInstance, seed);
   1715 
   1716    return error;
   1717 }
   1718 
   1719 /*
   1720 * nssCKFWSession_GetRandom
   1721 *
   1722 */
   1723 NSS_IMPLEMENT CK_RV
   1724 nssCKFWSession_GetRandom(
   1725    NSSCKFWSession *fwSession,
   1726    NSSItem *buffer)
   1727 {
   1728    CK_RV error = CKR_OK;
   1729 
   1730 #ifdef NSSDEBUG
   1731    error = nssCKFWSession_verifyPointer(fwSession);
   1732    if (CKR_OK != error) {
   1733        return error;
   1734    }
   1735 
   1736    if (!buffer) {
   1737        return CKR_ARGUMENTS_BAD;
   1738    }
   1739 
   1740    if (!buffer->data) {
   1741        return CKR_ARGUMENTS_BAD;
   1742    }
   1743 
   1744    if (!fwSession->mdSession) {
   1745        return CKR_GENERAL_ERROR;
   1746    }
   1747 #endif /* NSSDEBUG */
   1748 
   1749    if (!fwSession->mdSession->GetRandom) {
   1750        if (CK_TRUE == nssCKFWToken_GetHasRNG(fwSession->fwToken)) {
   1751            return CKR_GENERAL_ERROR;
   1752        } else {
   1753            return CKR_RANDOM_NO_RNG;
   1754        }
   1755    }
   1756 
   1757    if (0 == buffer->size) {
   1758        return CKR_OK;
   1759    }
   1760 
   1761    error = fwSession->mdSession->GetRandom(fwSession->mdSession, fwSession,
   1762                                            fwSession->mdToken, fwSession->fwToken, fwSession->mdInstance,
   1763                                            fwSession->fwInstance, buffer);
   1764 
   1765    return error;
   1766 }
   1767 
   1768 /*
   1769 * nssCKFWSession_SetCurrentCryptoOperation
   1770 */
   1771 NSS_IMPLEMENT void
   1772 nssCKFWSession_SetCurrentCryptoOperation(
   1773    NSSCKFWSession *fwSession,
   1774    NSSCKFWCryptoOperation *fwOperation,
   1775    NSSCKFWCryptoOperationState state)
   1776 {
   1777 #ifdef NSSDEBUG
   1778    CK_RV error = CKR_OK;
   1779    error = nssCKFWSession_verifyPointer(fwSession);
   1780    if (CKR_OK != error) {
   1781        return;
   1782    }
   1783 
   1784    if (state >= NSSCKFWCryptoOperationState_Max) {
   1785        return;
   1786    }
   1787 
   1788    if (!fwSession->mdSession) {
   1789        return;
   1790    }
   1791 #endif /* NSSDEBUG */
   1792    fwSession->fwOperationArray[state] = fwOperation;
   1793    return;
   1794 }
   1795 
   1796 /*
   1797 * nssCKFWSession_GetCurrentCryptoOperation
   1798 */
   1799 NSS_IMPLEMENT NSSCKFWCryptoOperation *
   1800 nssCKFWSession_GetCurrentCryptoOperation(
   1801    NSSCKFWSession *fwSession,
   1802    NSSCKFWCryptoOperationState state)
   1803 {
   1804 #ifdef NSSDEBUG
   1805    CK_RV error = CKR_OK;
   1806    error = nssCKFWSession_verifyPointer(fwSession);
   1807    if (CKR_OK != error) {
   1808        return (NSSCKFWCryptoOperation *)NULL;
   1809    }
   1810 
   1811    if (state >= NSSCKFWCryptoOperationState_Max) {
   1812        return (NSSCKFWCryptoOperation *)NULL;
   1813    }
   1814 
   1815    if (!fwSession->mdSession) {
   1816        return (NSSCKFWCryptoOperation *)NULL;
   1817    }
   1818 #endif /* NSSDEBUG */
   1819    return fwSession->fwOperationArray[state];
   1820 }
   1821 
   1822 /*
   1823 * nssCKFWSession_Final
   1824 */
   1825 NSS_IMPLEMENT CK_RV
   1826 nssCKFWSession_Final(
   1827    NSSCKFWSession *fwSession,
   1828    NSSCKFWCryptoOperationType type,
   1829    NSSCKFWCryptoOperationState state,
   1830    CK_BYTE_PTR outBuf,
   1831    CK_ULONG_PTR outBufLen)
   1832 {
   1833    NSSCKFWCryptoOperation *fwOperation;
   1834    NSSItem outputBuffer;
   1835    CK_RV error = CKR_OK;
   1836 
   1837 #ifdef NSSDEBUG
   1838    error = nssCKFWSession_verifyPointer(fwSession);
   1839    if (CKR_OK != error) {
   1840        return error;
   1841    }
   1842 
   1843    if (!fwSession->mdSession) {
   1844        return CKR_GENERAL_ERROR;
   1845    }
   1846 #endif /* NSSDEBUG */
   1847 
   1848    /* make sure we have a valid operation initialized */
   1849    fwOperation = nssCKFWSession_GetCurrentCryptoOperation(fwSession, state);
   1850    if (!fwOperation) {
   1851        return CKR_OPERATION_NOT_INITIALIZED;
   1852    }
   1853 
   1854    /* make sure it's the correct type */
   1855    if (type != nssCKFWCryptoOperation_GetType(fwOperation)) {
   1856        return CKR_OPERATION_NOT_INITIALIZED;
   1857    }
   1858 
   1859    /* handle buffer issues, note for Verify, the type is an input buffer. */
   1860    if (NSSCKFWCryptoOperationType_Verify == type) {
   1861        if ((CK_BYTE_PTR)NULL == outBuf) {
   1862            error = CKR_ARGUMENTS_BAD;
   1863            goto done;
   1864        }
   1865    } else {
   1866        CK_ULONG len = nssCKFWCryptoOperation_GetFinalLength(fwOperation, &error);
   1867        CK_ULONG maxBufLen = *outBufLen;
   1868 
   1869        if (CKR_OK != error) {
   1870            goto done;
   1871        }
   1872        *outBufLen = len;
   1873        if ((CK_BYTE_PTR)NULL == outBuf) {
   1874            return CKR_OK;
   1875        }
   1876 
   1877        if (len > maxBufLen) {
   1878            return CKR_BUFFER_TOO_SMALL;
   1879        }
   1880    }
   1881    outputBuffer.data = outBuf;
   1882    outputBuffer.size = *outBufLen;
   1883 
   1884    error = nssCKFWCryptoOperation_Final(fwOperation, &outputBuffer);
   1885 done:
   1886    if (CKR_BUFFER_TOO_SMALL == error) {
   1887        return error;
   1888    }
   1889    /* clean up our state */
   1890    nssCKFWCryptoOperation_Destroy(fwOperation);
   1891    nssCKFWSession_SetCurrentCryptoOperation(fwSession, NULL, state);
   1892    return error;
   1893 }
   1894 
   1895 /*
   1896 * nssCKFWSession_Update
   1897 */
   1898 NSS_IMPLEMENT CK_RV
   1899 nssCKFWSession_Update(
   1900    NSSCKFWSession *fwSession,
   1901    NSSCKFWCryptoOperationType type,
   1902    NSSCKFWCryptoOperationState state,
   1903    CK_BYTE_PTR inBuf,
   1904    CK_ULONG inBufLen,
   1905    CK_BYTE_PTR outBuf,
   1906    CK_ULONG_PTR outBufLen)
   1907 {
   1908    NSSCKFWCryptoOperation *fwOperation;
   1909    NSSItem inputBuffer;
   1910    NSSItem outputBuffer;
   1911    CK_ULONG len;
   1912    CK_ULONG maxBufLen;
   1913    CK_RV error = CKR_OK;
   1914 
   1915 #ifdef NSSDEBUG
   1916    error = nssCKFWSession_verifyPointer(fwSession);
   1917    if (CKR_OK != error) {
   1918        return error;
   1919    }
   1920 
   1921    if (!fwSession->mdSession) {
   1922        return CKR_GENERAL_ERROR;
   1923    }
   1924 #endif /* NSSDEBUG */
   1925 
   1926    /* make sure we have a valid operation initialized */
   1927    fwOperation = nssCKFWSession_GetCurrentCryptoOperation(fwSession, state);
   1928    if (!fwOperation) {
   1929        return CKR_OPERATION_NOT_INITIALIZED;
   1930    }
   1931 
   1932    /* make sure it's the correct type */
   1933    if (type != nssCKFWCryptoOperation_GetType(fwOperation)) {
   1934        return CKR_OPERATION_NOT_INITIALIZED;
   1935    }
   1936 
   1937    inputBuffer.data = inBuf;
   1938    inputBuffer.size = inBufLen;
   1939 
   1940    /* handle buffer issues, note for Verify, the type is an input buffer. */
   1941    len = nssCKFWCryptoOperation_GetOperationLength(fwOperation, &inputBuffer,
   1942                                                    &error);
   1943    if (CKR_OK != error) {
   1944        return error;
   1945    }
   1946    maxBufLen = *outBufLen;
   1947 
   1948    *outBufLen = len;
   1949    if ((CK_BYTE_PTR)NULL == outBuf) {
   1950        return CKR_OK;
   1951    }
   1952 
   1953    if (len > maxBufLen) {
   1954        return CKR_BUFFER_TOO_SMALL;
   1955    }
   1956    outputBuffer.data = outBuf;
   1957    outputBuffer.size = *outBufLen;
   1958 
   1959    return nssCKFWCryptoOperation_Update(fwOperation,
   1960                                         &inputBuffer, &outputBuffer);
   1961 }
   1962 
   1963 /*
   1964 * nssCKFWSession_DigestUpdate
   1965 */
   1966 NSS_IMPLEMENT CK_RV
   1967 nssCKFWSession_DigestUpdate(
   1968    NSSCKFWSession *fwSession,
   1969    NSSCKFWCryptoOperationType type,
   1970    NSSCKFWCryptoOperationState state,
   1971    CK_BYTE_PTR inBuf,
   1972    CK_ULONG inBufLen)
   1973 {
   1974    NSSCKFWCryptoOperation *fwOperation;
   1975    NSSItem inputBuffer;
   1976    CK_RV error = CKR_OK;
   1977 
   1978 #ifdef NSSDEBUG
   1979    error = nssCKFWSession_verifyPointer(fwSession);
   1980    if (CKR_OK != error) {
   1981        return error;
   1982    }
   1983 
   1984    if (!fwSession->mdSession) {
   1985        return CKR_GENERAL_ERROR;
   1986    }
   1987 #endif /* NSSDEBUG */
   1988 
   1989    /* make sure we have a valid operation initialized */
   1990    fwOperation = nssCKFWSession_GetCurrentCryptoOperation(fwSession, state);
   1991    if (!fwOperation) {
   1992        return CKR_OPERATION_NOT_INITIALIZED;
   1993    }
   1994 
   1995    /* make sure it's the correct type */
   1996    if (type != nssCKFWCryptoOperation_GetType(fwOperation)) {
   1997        return CKR_OPERATION_NOT_INITIALIZED;
   1998    }
   1999 
   2000    inputBuffer.data = inBuf;
   2001    inputBuffer.size = inBufLen;
   2002 
   2003    error = nssCKFWCryptoOperation_DigestUpdate(fwOperation, &inputBuffer);
   2004    return error;
   2005 }
   2006 
   2007 /*
   2008 * nssCKFWSession_DigestUpdate
   2009 */
   2010 NSS_IMPLEMENT CK_RV
   2011 nssCKFWSession_DigestKey(
   2012    NSSCKFWSession *fwSession,
   2013    NSSCKFWObject *fwKey)
   2014 {
   2015    NSSCKFWCryptoOperation *fwOperation;
   2016    NSSItem *inputBuffer;
   2017    CK_RV error = CKR_OK;
   2018 
   2019 #ifdef NSSDEBUG
   2020    error = nssCKFWSession_verifyPointer(fwSession);
   2021    if (CKR_OK != error) {
   2022        return error;
   2023    }
   2024 
   2025    if (!fwSession->mdSession) {
   2026        return CKR_GENERAL_ERROR;
   2027    }
   2028 #endif /* NSSDEBUG */
   2029 
   2030    /* make sure we have a valid operation initialized */
   2031    fwOperation = nssCKFWSession_GetCurrentCryptoOperation(fwSession,
   2032                                                           NSSCKFWCryptoOperationState_Digest);
   2033    if (!fwOperation) {
   2034        return CKR_OPERATION_NOT_INITIALIZED;
   2035    }
   2036 
   2037    /* make sure it's the correct type */
   2038    if (NSSCKFWCryptoOperationType_Digest !=
   2039        nssCKFWCryptoOperation_GetType(fwOperation)) {
   2040        return CKR_OPERATION_NOT_INITIALIZED;
   2041    }
   2042 
   2043    error = nssCKFWCryptoOperation_DigestKey(fwOperation, fwKey);
   2044    if (CKR_FUNCTION_FAILED != error) {
   2045        return error;
   2046    }
   2047 
   2048    /* no machine depended way for this to happen, do it by hand */
   2049    inputBuffer = nssCKFWObject_GetAttribute(fwKey, CKA_VALUE, NULL, NULL, &error);
   2050    if (!inputBuffer) {
   2051        /* couldn't get the value, just fail then */
   2052        return error;
   2053    }
   2054    error = nssCKFWCryptoOperation_DigestUpdate(fwOperation, inputBuffer);
   2055    nssItem_Destroy(inputBuffer);
   2056    return error;
   2057 }
   2058 
   2059 /*
   2060 * nssCKFWSession_UpdateFinal
   2061 */
   2062 NSS_IMPLEMENT CK_RV
   2063 nssCKFWSession_UpdateFinal(
   2064    NSSCKFWSession *fwSession,
   2065    NSSCKFWCryptoOperationType type,
   2066    NSSCKFWCryptoOperationState state,
   2067    CK_BYTE_PTR inBuf,
   2068    CK_ULONG inBufLen,
   2069    CK_BYTE_PTR outBuf,
   2070    CK_ULONG_PTR outBufLen)
   2071 {
   2072    NSSCKFWCryptoOperation *fwOperation;
   2073    NSSItem inputBuffer;
   2074    NSSItem outputBuffer;
   2075    PRBool isEncryptDecrypt;
   2076    CK_RV error = CKR_OK;
   2077 
   2078 #ifdef NSSDEBUG
   2079    error = nssCKFWSession_verifyPointer(fwSession);
   2080    if (CKR_OK != error) {
   2081        return error;
   2082    }
   2083 
   2084    if (!fwSession->mdSession) {
   2085        return CKR_GENERAL_ERROR;
   2086    }
   2087 #endif /* NSSDEBUG */
   2088 
   2089    /* make sure we have a valid operation initialized */
   2090    fwOperation = nssCKFWSession_GetCurrentCryptoOperation(fwSession, state);
   2091    if (!fwOperation) {
   2092        return CKR_OPERATION_NOT_INITIALIZED;
   2093    }
   2094 
   2095    /* make sure it's the correct type */
   2096    if (type != nssCKFWCryptoOperation_GetType(fwOperation)) {
   2097        return CKR_OPERATION_NOT_INITIALIZED;
   2098    }
   2099 
   2100    inputBuffer.data = inBuf;
   2101    inputBuffer.size = inBufLen;
   2102    isEncryptDecrypt = (PRBool)((NSSCKFWCryptoOperationType_Encrypt == type) ||
   2103                                (NSSCKFWCryptoOperationType_Decrypt == type));
   2104 
   2105    /* handle buffer issues, note for Verify, the type is an input buffer. */
   2106    if (NSSCKFWCryptoOperationType_Verify == type) {
   2107        if ((CK_BYTE_PTR)NULL == outBuf) {
   2108            error = CKR_ARGUMENTS_BAD;
   2109            goto done;
   2110        }
   2111    } else {
   2112        CK_ULONG maxBufLen = *outBufLen;
   2113        CK_ULONG len;
   2114 
   2115        len = (isEncryptDecrypt) ? nssCKFWCryptoOperation_GetOperationLength(fwOperation,
   2116                                                                             &inputBuffer, &error)
   2117                                 : nssCKFWCryptoOperation_GetFinalLength(fwOperation, &error);
   2118 
   2119        if (CKR_OK != error) {
   2120            goto done;
   2121        }
   2122 
   2123        *outBufLen = len;
   2124        if ((CK_BYTE_PTR)NULL == outBuf) {
   2125            return CKR_OK;
   2126        }
   2127 
   2128        if (len > maxBufLen) {
   2129            return CKR_BUFFER_TOO_SMALL;
   2130        }
   2131    }
   2132    outputBuffer.data = outBuf;
   2133    outputBuffer.size = *outBufLen;
   2134 
   2135    error = nssCKFWCryptoOperation_UpdateFinal(fwOperation,
   2136                                               &inputBuffer, &outputBuffer);
   2137 
   2138    /* UpdateFinal isn't support, manually use Update and Final */
   2139    if (CKR_FUNCTION_FAILED == error) {
   2140        error = isEncryptDecrypt ? nssCKFWCryptoOperation_Update(fwOperation, &inputBuffer, &outputBuffer)
   2141                                 : nssCKFWCryptoOperation_DigestUpdate(fwOperation, &inputBuffer);
   2142 
   2143        if (CKR_OK == error) {
   2144            error = nssCKFWCryptoOperation_Final(fwOperation, &outputBuffer);
   2145        }
   2146    }
   2147 
   2148 done:
   2149    if (CKR_BUFFER_TOO_SMALL == error) {
   2150        /* if we return CKR_BUFFER_TOO_SMALL, we the caller is not expecting.
   2151         * the crypto state to be freed */
   2152        return error;
   2153    }
   2154 
   2155    /* clean up our state */
   2156    nssCKFWCryptoOperation_Destroy(fwOperation);
   2157    nssCKFWSession_SetCurrentCryptoOperation(fwSession, NULL, state);
   2158    return error;
   2159 }
   2160 
   2161 NSS_IMPLEMENT CK_RV
   2162 nssCKFWSession_UpdateCombo(
   2163    NSSCKFWSession *fwSession,
   2164    NSSCKFWCryptoOperationType encryptType,
   2165    NSSCKFWCryptoOperationType digestType,
   2166    NSSCKFWCryptoOperationState digestState,
   2167    CK_BYTE_PTR inBuf,
   2168    CK_ULONG inBufLen,
   2169    CK_BYTE_PTR outBuf,
   2170    CK_ULONG_PTR outBufLen)
   2171 {
   2172    NSSCKFWCryptoOperation *fwOperation;
   2173    NSSCKFWCryptoOperation *fwPeerOperation;
   2174    NSSItem inputBuffer;
   2175    NSSItem outputBuffer;
   2176    CK_ULONG maxBufLen = *outBufLen;
   2177    CK_ULONG len;
   2178    CK_RV error = CKR_OK;
   2179 
   2180 #ifdef NSSDEBUG
   2181    error = nssCKFWSession_verifyPointer(fwSession);
   2182    if (CKR_OK != error) {
   2183        return error;
   2184    }
   2185 
   2186    if (!fwSession->mdSession) {
   2187        return CKR_GENERAL_ERROR;
   2188    }
   2189 #endif /* NSSDEBUG */
   2190 
   2191    /* make sure we have a valid operation initialized */
   2192    fwOperation = nssCKFWSession_GetCurrentCryptoOperation(fwSession,
   2193                                                           NSSCKFWCryptoOperationState_EncryptDecrypt);
   2194    if (!fwOperation) {
   2195        return CKR_OPERATION_NOT_INITIALIZED;
   2196    }
   2197 
   2198    /* make sure it's the correct type */
   2199    if (encryptType != nssCKFWCryptoOperation_GetType(fwOperation)) {
   2200        return CKR_OPERATION_NOT_INITIALIZED;
   2201    }
   2202    /* make sure we have a valid operation initialized */
   2203    fwPeerOperation = nssCKFWSession_GetCurrentCryptoOperation(fwSession,
   2204                                                               digestState);
   2205    if (!fwPeerOperation) {
   2206        return CKR_OPERATION_NOT_INITIALIZED;
   2207    }
   2208 
   2209    /* make sure it's the correct type */
   2210    if (digestType != nssCKFWCryptoOperation_GetType(fwOperation)) {
   2211        return CKR_OPERATION_NOT_INITIALIZED;
   2212    }
   2213 
   2214    inputBuffer.data = inBuf;
   2215    inputBuffer.size = inBufLen;
   2216    len = nssCKFWCryptoOperation_GetOperationLength(fwOperation,
   2217                                                    &inputBuffer, &error);
   2218    if (CKR_OK != error) {
   2219        return error;
   2220    }
   2221 
   2222    *outBufLen = len;
   2223    if ((CK_BYTE_PTR)NULL == outBuf) {
   2224        return CKR_OK;
   2225    }
   2226 
   2227    if (len > maxBufLen) {
   2228        return CKR_BUFFER_TOO_SMALL;
   2229    }
   2230 
   2231    outputBuffer.data = outBuf;
   2232    outputBuffer.size = *outBufLen;
   2233 
   2234    error = nssCKFWCryptoOperation_UpdateCombo(fwOperation, fwPeerOperation,
   2235                                               &inputBuffer, &outputBuffer);
   2236    if (CKR_FUNCTION_FAILED == error) {
   2237        PRBool isEncrypt =
   2238            (PRBool)(NSSCKFWCryptoOperationType_Encrypt == encryptType);
   2239 
   2240        if (isEncrypt) {
   2241            error = nssCKFWCryptoOperation_DigestUpdate(fwPeerOperation,
   2242                                                        &inputBuffer);
   2243            if (CKR_OK != error) {
   2244                return error;
   2245            }
   2246        }
   2247        error = nssCKFWCryptoOperation_Update(fwOperation,
   2248                                              &inputBuffer, &outputBuffer);
   2249        if (CKR_OK != error) {
   2250            return error;
   2251        }
   2252        if (!isEncrypt) {
   2253            error = nssCKFWCryptoOperation_DigestUpdate(fwPeerOperation,
   2254                                                        &outputBuffer);
   2255        }
   2256    }
   2257    return error;
   2258 }
   2259 
   2260 /*
   2261 * NSSCKFWSession_GetMDSession
   2262 *
   2263 */
   2264 
   2265 NSS_IMPLEMENT NSSCKMDSession *
   2266 NSSCKFWSession_GetMDSession(
   2267    NSSCKFWSession *fwSession)
   2268 {
   2269 #ifdef DEBUG
   2270    if (CKR_OK != nssCKFWSession_verifyPointer(fwSession)) {
   2271        return (NSSCKMDSession *)NULL;
   2272    }
   2273 #endif /* DEBUG */
   2274 
   2275    return nssCKFWSession_GetMDSession(fwSession);
   2276 }
   2277 
   2278 /*
   2279 * NSSCKFWSession_GetArena
   2280 *
   2281 */
   2282 
   2283 NSS_IMPLEMENT NSSArena *
   2284 NSSCKFWSession_GetArena(
   2285    NSSCKFWSession *fwSession,
   2286    CK_RV *pError)
   2287 {
   2288 #ifdef DEBUG
   2289    if (!pError) {
   2290        return (NSSArena *)NULL;
   2291    }
   2292 
   2293    *pError = nssCKFWSession_verifyPointer(fwSession);
   2294    if (CKR_OK != *pError) {
   2295        return (NSSArena *)NULL;
   2296    }
   2297 #endif /* DEBUG */
   2298 
   2299    return nssCKFWSession_GetArena(fwSession, pError);
   2300 }
   2301 
   2302 /*
   2303 * NSSCKFWSession_CallNotification
   2304 *
   2305 */
   2306 
   2307 NSS_IMPLEMENT CK_RV
   2308 NSSCKFWSession_CallNotification(
   2309    NSSCKFWSession *fwSession,
   2310    CK_NOTIFICATION event)
   2311 {
   2312 #ifdef DEBUG
   2313    CK_RV error = CKR_OK;
   2314 
   2315    error = nssCKFWSession_verifyPointer(fwSession);
   2316    if (CKR_OK != error) {
   2317        return error;
   2318    }
   2319 #endif /* DEBUG */
   2320 
   2321    return nssCKFWSession_CallNotification(fwSession, event);
   2322 }
   2323 
   2324 /*
   2325 * NSSCKFWSession_IsRWSession
   2326 *
   2327 */
   2328 
   2329 NSS_IMPLEMENT CK_BBOOL
   2330 NSSCKFWSession_IsRWSession(
   2331    NSSCKFWSession *fwSession)
   2332 {
   2333 #ifdef DEBUG
   2334    if (CKR_OK != nssCKFWSession_verifyPointer(fwSession)) {
   2335        return CK_FALSE;
   2336    }
   2337 #endif /* DEBUG */
   2338 
   2339    return nssCKFWSession_IsRWSession(fwSession);
   2340 }
   2341 
   2342 /*
   2343 * NSSCKFWSession_IsSO
   2344 *
   2345 */
   2346 
   2347 NSS_IMPLEMENT CK_BBOOL
   2348 NSSCKFWSession_IsSO(
   2349    NSSCKFWSession *fwSession)
   2350 {
   2351 #ifdef DEBUG
   2352    if (CKR_OK != nssCKFWSession_verifyPointer(fwSession)) {
   2353        return CK_FALSE;
   2354    }
   2355 #endif /* DEBUG */
   2356 
   2357    return nssCKFWSession_IsSO(fwSession);
   2358 }
   2359 
   2360 NSS_IMPLEMENT NSSCKFWCryptoOperation *
   2361 NSSCKFWSession_GetCurrentCryptoOperation(
   2362    NSSCKFWSession *fwSession,
   2363    NSSCKFWCryptoOperationState state)
   2364 {
   2365 #ifdef DEBUG
   2366    CK_RV error = CKR_OK;
   2367    error = nssCKFWSession_verifyPointer(fwSession);
   2368    if (CKR_OK != error) {
   2369        return (NSSCKFWCryptoOperation *)NULL;
   2370    }
   2371 
   2372    if (state >= NSSCKFWCryptoOperationState_Max) {
   2373        return (NSSCKFWCryptoOperation *)NULL;
   2374    }
   2375 #endif /* DEBUG */
   2376    return nssCKFWSession_GetCurrentCryptoOperation(fwSession, state);
   2377 }
   2378 
   2379 /*
   2380 * NSSCKFWSession_GetFWSlot
   2381 *
   2382 */
   2383 
   2384 NSS_IMPLEMENT NSSCKFWSlot *
   2385 NSSCKFWSession_GetFWSlot(
   2386    NSSCKFWSession *fwSession)
   2387 {
   2388    return nssCKFWSession_GetFWSlot(fwSession);
   2389 }