tor-browser

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

pk11skey.c (117390B)


      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 * This file implements the Symkey wrapper and the PKCS context
      6 * Interfaces.
      7 */
      8 
      9 #include <stddef.h>
     10 #include <limits.h>
     11 
     12 #include "seccomon.h"
     13 #include "secmod.h"
     14 #include "nssilock.h"
     15 #include "secmodi.h"
     16 #include "secmodti.h"
     17 #include "pkcs11.h"
     18 #include "pk11func.h"
     19 #include "secitem.h"
     20 #include "secoid.h"
     21 #include "secerr.h"
     22 #include "hasht.h"
     23 
     24 static ECPointEncoding pk11_ECGetPubkeyEncoding(const SECKEYPublicKey *pubKey);
     25 
     26 static void
     27 pk11_EnterKeyMonitor(PK11SymKey *symKey)
     28 {
     29    if (!symKey->sessionOwner || !(symKey->slot->isThreadSafe))
     30        PK11_EnterSlotMonitor(symKey->slot);
     31 }
     32 
     33 static void
     34 pk11_ExitKeyMonitor(PK11SymKey *symKey)
     35 {
     36    if (!symKey->sessionOwner || !(symKey->slot->isThreadSafe))
     37        PK11_ExitSlotMonitor(symKey->slot);
     38 }
     39 
     40 /*
     41 * pk11_getKeyFromList returns a symKey that has a session (if needSession
     42 * was specified), or explicitly does not have a session (if needSession
     43 * was not specified).
     44 */
     45 static PK11SymKey *
     46 pk11_getKeyFromList(PK11SlotInfo *slot, PRBool needSession)
     47 {
     48    PK11SymKey *symKey = NULL;
     49 
     50    PZ_Lock(slot->freeListLock);
     51    /* own session list are symkeys with sessions that the symkey owns.
     52     * 'most' symkeys will own their own session. */
     53    if (needSession) {
     54        if (slot->freeSymKeysWithSessionHead) {
     55            symKey = slot->freeSymKeysWithSessionHead;
     56            slot->freeSymKeysWithSessionHead = symKey->next;
     57            slot->keyCount--;
     58        }
     59    }
     60    /* if we don't need a symkey with its own session, or we couldn't find
     61     * one on the owner list, get one from the non-owner free list. */
     62    if (!symKey) {
     63        if (slot->freeSymKeysHead) {
     64            symKey = slot->freeSymKeysHead;
     65            slot->freeSymKeysHead = symKey->next;
     66            slot->keyCount--;
     67        }
     68    }
     69    PZ_Unlock(slot->freeListLock);
     70    if (symKey) {
     71        symKey->next = NULL;
     72        if (!needSession) {
     73            return symKey;
     74        }
     75        /* if we are getting an owner key, make sure we have a valid session.
     76         * session could be invalid if the token has been removed or because
     77         * we got it from the non-owner free list */
     78        if ((symKey->series != slot->series) ||
     79            (symKey->session == CK_INVALID_HANDLE)) {
     80            symKey->session = pk11_GetNewSession(slot, &symKey->sessionOwner);
     81        }
     82        PORT_Assert(symKey->session != CK_INVALID_HANDLE);
     83        if (symKey->session != CK_INVALID_HANDLE)
     84            return symKey;
     85        PK11_FreeSymKey(symKey);
     86        /* if we are here, we need a session, but couldn't get one, it's
     87         * unlikely we pk11_GetNewSession will succeed if we call it a second
     88         * time. */
     89        return NULL;
     90    }
     91 
     92    symKey = PORT_New(PK11SymKey);
     93    if (symKey == NULL) {
     94        return NULL;
     95    }
     96 
     97    symKey->next = NULL;
     98    if (needSession) {
     99        symKey->session = pk11_GetNewSession(slot, &symKey->sessionOwner);
    100        PORT_Assert(symKey->session != CK_INVALID_HANDLE);
    101        if (symKey->session == CK_INVALID_HANDLE) {
    102            PK11_FreeSymKey(symKey);
    103            symKey = NULL;
    104        }
    105    } else {
    106        symKey->session = CK_INVALID_HANDLE;
    107    }
    108    return symKey;
    109 }
    110 
    111 /* Caller MUST hold slot->freeListLock (or ref count == 0?) !! */
    112 void
    113 PK11_CleanKeyList(PK11SlotInfo *slot)
    114 {
    115    PK11SymKey *symKey = NULL;
    116 
    117    while (slot->freeSymKeysWithSessionHead) {
    118        symKey = slot->freeSymKeysWithSessionHead;
    119        slot->freeSymKeysWithSessionHead = symKey->next;
    120        pk11_CloseSession(slot, symKey->session, symKey->sessionOwner);
    121        PORT_Free(symKey);
    122    }
    123    while (slot->freeSymKeysHead) {
    124        symKey = slot->freeSymKeysHead;
    125        slot->freeSymKeysHead = symKey->next;
    126        pk11_CloseSession(slot, symKey->session, symKey->sessionOwner);
    127        PORT_Free(symKey);
    128    }
    129    return;
    130 }
    131 
    132 /*
    133 * create a symetric key:
    134 *      Slot is the slot to create the key in.
    135 *      type is the mechanism type
    136 *      owner is does this symKey structure own it's object handle (rare
    137 *        that this is false).
    138 *      needSession means the returned symKey will return with a valid session
    139 *        allocated already.
    140 */
    141 static PK11SymKey *
    142 pk11_CreateSymKey(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
    143                  PRBool owner, PRBool needSession, void *wincx)
    144 {
    145 
    146    PK11SymKey *symKey = pk11_getKeyFromList(slot, needSession);
    147 
    148    if (symKey == NULL) {
    149        return NULL;
    150    }
    151    /* if needSession was specified, make sure we have a valid session.
    152     * callers which specify needSession as false should do their own
    153     * check of the session before returning the symKey */
    154    if (needSession && symKey->session == CK_INVALID_HANDLE) {
    155        PK11_FreeSymKey(symKey);
    156        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
    157        return NULL;
    158    }
    159 
    160    symKey->type = type;
    161    symKey->data.type = siBuffer;
    162    symKey->data.data = NULL;
    163    symKey->data.len = 0;
    164    symKey->owner = owner;
    165    symKey->objectID = CK_INVALID_HANDLE;
    166    symKey->slot = slot;
    167    symKey->series = slot->series;
    168    symKey->cx = wincx;
    169    symKey->size = 0;
    170    symKey->refCount = 1;
    171    symKey->origin = PK11_OriginNULL;
    172    symKey->parent = NULL;
    173    symKey->freeFunc = NULL;
    174    symKey->userData = NULL;
    175    PK11_ReferenceSlot(slot);
    176    return symKey;
    177 }
    178 
    179 /*
    180 * destroy a symetric key
    181 */
    182 void
    183 PK11_FreeSymKey(PK11SymKey *symKey)
    184 {
    185    PK11SlotInfo *slot;
    186    PRBool freeit = PR_TRUE;
    187 
    188    if (!symKey) {
    189        return;
    190    }
    191 
    192    if (PR_ATOMIC_DECREMENT(&symKey->refCount) == 0) {
    193        PK11SymKey *parent = symKey->parent;
    194 
    195        symKey->parent = NULL;
    196        if ((symKey->owner) && symKey->objectID != CK_INVALID_HANDLE) {
    197            pk11_EnterKeyMonitor(symKey);
    198            (void)PK11_GETTAB(symKey->slot)->C_DestroyObject(symKey->session, symKey->objectID);
    199            pk11_ExitKeyMonitor(symKey);
    200        }
    201        if (symKey->data.data) {
    202            PORT_Memset(symKey->data.data, 0, symKey->data.len);
    203            PORT_Free(symKey->data.data);
    204        }
    205        /* free any existing data */
    206        if (symKey->userData && symKey->freeFunc) {
    207            (*symKey->freeFunc)(symKey->userData);
    208        }
    209        slot = symKey->slot;
    210        PZ_Lock(slot->freeListLock);
    211        if (slot->keyCount < slot->maxKeyCount) {
    212            /*
    213             * freeSymkeysWithSessionHead contain a list of reusable
    214             *  SymKey structures with valid sessions.
    215             *    sessionOwner must be true.
    216             *    session must be valid.
    217             * freeSymKeysHead contain a list of SymKey structures without
    218             *  valid session.
    219             *    session must be CK_INVALID_HANDLE.
    220             *    though sessionOwner is false, callers should not depend on
    221             *    this fact.
    222             */
    223            if (symKey->sessionOwner) {
    224                PORT_Assert(symKey->session != CK_INVALID_HANDLE);
    225                symKey->next = slot->freeSymKeysWithSessionHead;
    226                slot->freeSymKeysWithSessionHead = symKey;
    227            } else {
    228                symKey->session = CK_INVALID_HANDLE;
    229                symKey->next = slot->freeSymKeysHead;
    230                slot->freeSymKeysHead = symKey;
    231            }
    232            slot->keyCount++;
    233            symKey->slot = NULL;
    234            freeit = PR_FALSE;
    235        }
    236        PZ_Unlock(slot->freeListLock);
    237        if (freeit) {
    238            pk11_CloseSession(symKey->slot, symKey->session,
    239                              symKey->sessionOwner);
    240            PORT_Free(symKey);
    241        }
    242        PK11_FreeSlot(slot);
    243 
    244        if (parent) {
    245            PK11_FreeSymKey(parent);
    246        }
    247    }
    248 }
    249 
    250 PK11SymKey *
    251 PK11_ReferenceSymKey(PK11SymKey *symKey)
    252 {
    253    PR_ATOMIC_INCREMENT(&symKey->refCount);
    254    return symKey;
    255 }
    256 
    257 /*
    258 * Accessors
    259 */
    260 CK_MECHANISM_TYPE
    261 PK11_GetMechanism(PK11SymKey *symKey)
    262 {
    263    return symKey->type;
    264 }
    265 
    266 /*
    267 * return the slot associated with a symetric key
    268 */
    269 PK11SlotInfo *
    270 PK11_GetSlotFromKey(PK11SymKey *symKey)
    271 {
    272    return PK11_ReferenceSlot(symKey->slot);
    273 }
    274 
    275 CK_KEY_TYPE
    276 PK11_GetSymKeyType(PK11SymKey *symKey)
    277 {
    278    return PK11_GetKeyType(symKey->type, symKey->size);
    279 }
    280 
    281 PK11SymKey *
    282 PK11_GetNextSymKey(PK11SymKey *symKey)
    283 {
    284    return symKey ? symKey->next : NULL;
    285 }
    286 
    287 char *
    288 PK11_GetSymKeyNickname(PK11SymKey *symKey)
    289 {
    290    return PK11_GetObjectNickname(symKey->slot, symKey->objectID);
    291 }
    292 
    293 SECStatus
    294 PK11_SetSymKeyNickname(PK11SymKey *symKey, const char *nickname)
    295 {
    296    return PK11_SetObjectNickname(symKey->slot, symKey->objectID, nickname);
    297 }
    298 
    299 void *
    300 PK11_GetSymKeyUserData(PK11SymKey *symKey)
    301 {
    302    return symKey->userData;
    303 }
    304 
    305 void
    306 PK11_SetSymKeyUserData(PK11SymKey *symKey, void *userData,
    307                       PK11FreeDataFunc freeFunc)
    308 {
    309    /* free any existing data */
    310    if (symKey->userData && symKey->freeFunc) {
    311        (*symKey->freeFunc)(symKey->userData);
    312    }
    313    symKey->userData = userData;
    314    symKey->freeFunc = freeFunc;
    315    return;
    316 }
    317 
    318 /*
    319 * turn key handle into an appropriate key object
    320 */
    321 PK11SymKey *
    322 PK11_SymKeyFromHandle(PK11SlotInfo *slot, PK11SymKey *parent, PK11Origin origin,
    323                      CK_MECHANISM_TYPE type, CK_OBJECT_HANDLE keyID, PRBool owner, void *wincx)
    324 {
    325    PK11SymKey *symKey;
    326    PRBool needSession = !(owner && parent);
    327 
    328    if (keyID == CK_INVALID_HANDLE) {
    329        return NULL;
    330    }
    331 
    332    symKey = pk11_CreateSymKey(slot, type, owner, needSession, wincx);
    333    if (symKey == NULL) {
    334        return NULL;
    335    }
    336 
    337    symKey->objectID = keyID;
    338    symKey->origin = origin;
    339 
    340    /* adopt the parent's session */
    341    /* This is only used by SSL. What we really want here is a session
    342     * structure with a ref count so  the session goes away only after all the
    343     * keys do. */
    344    if (!needSession) {
    345        symKey->sessionOwner = PR_FALSE;
    346        symKey->session = parent->session;
    347        symKey->parent = PK11_ReferenceSymKey(parent);
    348        /* This is the only case where pk11_CreateSymKey does not explicitly
    349         * check symKey->session. We need to assert here to make sure.
    350         * the session isn't invalid. */
    351        PORT_Assert(parent->session != CK_INVALID_HANDLE);
    352        if (parent->session == CK_INVALID_HANDLE) {
    353            PK11_FreeSymKey(symKey);
    354            PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
    355            return NULL;
    356        }
    357    }
    358 
    359    return symKey;
    360 }
    361 
    362 /*
    363 * Restore a symmetric wrapping key that was saved using PK11_SetWrapKey.
    364 *
    365 * This function is provided for ABI compatibility; see PK11_SetWrapKey below.
    366 */
    367 PK11SymKey *
    368 PK11_GetWrapKey(PK11SlotInfo *slot, int wrap, CK_MECHANISM_TYPE type,
    369                int series, void *wincx)
    370 {
    371    PK11SymKey *symKey = NULL;
    372    CK_OBJECT_HANDLE keyHandle;
    373 
    374    PK11_EnterSlotMonitor(slot);
    375    if (slot->series != series ||
    376        slot->refKeys[wrap] == CK_INVALID_HANDLE) {
    377        PK11_ExitSlotMonitor(slot);
    378        return NULL;
    379    }
    380 
    381    if (type == CKM_INVALID_MECHANISM) {
    382        type = slot->wrapMechanism;
    383    }
    384 
    385    keyHandle = slot->refKeys[wrap];
    386    PK11_ExitSlotMonitor(slot);
    387    symKey = PK11_SymKeyFromHandle(slot, NULL, PK11_OriginDerive,
    388                                   slot->wrapMechanism, keyHandle, PR_FALSE, wincx);
    389    return symKey;
    390 }
    391 
    392 /*
    393 * This function sets an attribute on the current slot with a wrapping key.  The
    394 * data saved is ephemeral; it needs to be run every time the program is
    395 * invoked.
    396 *
    397 * Since NSS 3.45, this function is marginally more thread safe.  It uses the
    398 * slot lock (if present) and fails silently if a value is already set.  Use
    399 * PK11_GetWrapKey() after calling this function to get the current wrapping key
    400 * in case there was an update on another thread.
    401 *
    402 * Either way, using this function is inadvisable.  It's provided for ABI
    403 * compatibility only.
    404 */
    405 void
    406 PK11_SetWrapKey(PK11SlotInfo *slot, int wrap, PK11SymKey *wrapKey)
    407 {
    408    PK11_EnterSlotMonitor(slot);
    409    if (wrap >= 0) {
    410        size_t uwrap = (size_t)wrap;
    411        if (uwrap < PR_ARRAY_SIZE(slot->refKeys) &&
    412            slot->refKeys[uwrap] == CK_INVALID_HANDLE) {
    413            /* save the handle and mechanism for the wrapping key */
    414            /* mark the key and session as not owned by us so they don't get
    415             * freed when the key goes way... that lets us reuse the key
    416             * later */
    417            slot->refKeys[uwrap] = wrapKey->objectID;
    418            wrapKey->owner = PR_FALSE;
    419            wrapKey->sessionOwner = PR_FALSE;
    420            slot->wrapMechanism = wrapKey->type;
    421        }
    422    }
    423    PK11_ExitSlotMonitor(slot);
    424 }
    425 
    426 /*
    427 * figure out if a key is still valid or if it is stale.
    428 */
    429 PRBool
    430 PK11_VerifyKeyOK(PK11SymKey *key)
    431 {
    432    if (!PK11_IsPresent(key->slot)) {
    433        return PR_FALSE;
    434    }
    435    return (PRBool)(key->series == key->slot->series);
    436 }
    437 
    438 static PK11SymKey *
    439 pk11_ImportSymKeyWithTempl(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
    440                           PK11Origin origin, PRBool isToken, CK_ATTRIBUTE *keyTemplate,
    441                           unsigned int templateCount, SECItem *key, void *wincx)
    442 {
    443    PK11SymKey *symKey;
    444    SECStatus rv;
    445 
    446    symKey = pk11_CreateSymKey(slot, type, !isToken, PR_TRUE, wincx);
    447    if (symKey == NULL) {
    448        return NULL;
    449    }
    450 
    451    symKey->size = key->len;
    452 
    453    PK11_SETATTRS(&keyTemplate[templateCount], CKA_VALUE, key->data, key->len);
    454    templateCount++;
    455 
    456    if (SECITEM_CopyItem(NULL, &symKey->data, key) != SECSuccess) {
    457        PK11_FreeSymKey(symKey);
    458        return NULL;
    459    }
    460 
    461    symKey->origin = origin;
    462 
    463    /* import the keys */
    464    rv = PK11_CreateNewObject(slot, symKey->session, keyTemplate,
    465                              templateCount, isToken, &symKey->objectID);
    466    if (rv != SECSuccess) {
    467        PK11_FreeSymKey(symKey);
    468        return NULL;
    469    }
    470 
    471    return symKey;
    472 }
    473 
    474 /*
    475 * turn key bits into an appropriate key object
    476 */
    477 PK11SymKey *
    478 PK11_ImportSymKey(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
    479                  PK11Origin origin, CK_ATTRIBUTE_TYPE operation, SECItem *key, void *wincx)
    480 {
    481    PK11SymKey *symKey;
    482    unsigned int templateCount = 0;
    483    CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY;
    484    CK_KEY_TYPE keyType = CKK_GENERIC_SECRET;
    485    CK_BBOOL cktrue = CK_TRUE; /* sigh */
    486    CK_ATTRIBUTE keyTemplate[5];
    487    CK_ATTRIBUTE *attrs = keyTemplate;
    488 
    489    /* CKA_NSS_MESSAGE is a fake operation to distinguish between
    490     * Normal Encrypt/Decrypt and MessageEncrypt/Decrypt. Don't try to set
    491     * it as a real attribute */
    492    if ((operation & CKA_NSS_MESSAGE_MASK) == CKA_NSS_MESSAGE) {
    493        /* Message is or'd with a real Attribute (CKA_ENCRYPT, CKA_DECRYPT),
    494         * etc. Strip out the real attribute here */
    495        operation &= ~CKA_NSS_MESSAGE_MASK;
    496    }
    497 
    498    PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass));
    499    attrs++;
    500    PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType));
    501    attrs++;
    502    PK11_SETATTRS(attrs, operation, &cktrue, 1);
    503    attrs++;
    504    templateCount = attrs - keyTemplate;
    505    PR_ASSERT(templateCount + 1 <= sizeof(keyTemplate) / sizeof(CK_ATTRIBUTE));
    506 
    507    keyType = PK11_GetKeyType(type, key->len);
    508    symKey = pk11_ImportSymKeyWithTempl(slot, type, origin, PR_FALSE,
    509                                        keyTemplate, templateCount, key, wincx);
    510    return symKey;
    511 }
    512 /* Import a PKCS #11 data object and return it as a key. This key is
    513 * only useful in a limited number of mechanisms, such as HKDF. */
    514 PK11SymKey *
    515 PK11_ImportDataKey(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, PK11Origin origin,
    516                   CK_ATTRIBUTE_TYPE operation, SECItem *key, void *wincx)
    517 {
    518    CK_OBJECT_CLASS ckoData = CKO_DATA;
    519    CK_ATTRIBUTE template[2] = { { CKA_CLASS, (CK_BYTE_PTR)&ckoData, sizeof(ckoData) },
    520                                 { CKA_VALUE, (CK_BYTE_PTR)key->data, key->len } };
    521    CK_OBJECT_HANDLE handle;
    522    PK11GenericObject *genObject;
    523 
    524    genObject = PK11_CreateGenericObject(slot, template, PR_ARRAY_SIZE(template), PR_FALSE);
    525    if (genObject == NULL) {
    526        return NULL;
    527    }
    528    handle = PK11_GetObjectHandle(PK11_TypeGeneric, genObject, NULL);
    529    /* A note about ownership of the PKCS #11 handle:
    530     * PK11_CreateGenericObject() will not destroy the object it creates
    531     * on Free, For that you want PK11_CreateManagedGenericObject().
    532     * Below we import the handle into the symKey structure. We pass
    533     * PR_TRUE as the owner so that the symKey will destroy the object
    534     * once it's freed. This is why it's safe to destroy genObject now. */
    535    PK11_DestroyGenericObject(genObject);
    536    if (handle == CK_INVALID_HANDLE) {
    537        return NULL;
    538    }
    539    return PK11_SymKeyFromHandle(slot, NULL, origin, type, handle, PR_TRUE, wincx);
    540 }
    541 
    542 /* turn key bits into an appropriate key object */
    543 PK11SymKey *
    544 PK11_ImportSymKeyWithFlags(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
    545                           PK11Origin origin, CK_ATTRIBUTE_TYPE operation, SECItem *key,
    546                           CK_FLAGS flags, PRBool isPerm, void *wincx)
    547 {
    548    PK11SymKey *symKey;
    549    unsigned int templateCount = 0;
    550    CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY;
    551    CK_KEY_TYPE keyType = CKK_GENERIC_SECRET;
    552    CK_BBOOL cktrue = CK_TRUE; /* sigh */
    553    CK_ATTRIBUTE keyTemplate[MAX_TEMPL_ATTRS];
    554    CK_ATTRIBUTE *attrs = keyTemplate;
    555 
    556    /* CKA_NSS_MESSAGE is a fake operation to distinguish between
    557     * Normal Encrypt/Decrypt and MessageEncrypt/Decrypt. Don't try to set
    558     * it as a real attribute */
    559    if ((operation & CKA_NSS_MESSAGE_MASK) == CKA_NSS_MESSAGE) {
    560        /* Message is or'd with a real Attribute (CKA_ENCRYPT, CKA_DECRYPT),
    561         * etc. Strip out the real attribute here */
    562        operation &= ~CKA_NSS_MESSAGE_MASK;
    563    }
    564 
    565    PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass));
    566    attrs++;
    567    PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType));
    568    attrs++;
    569    if (isPerm) {
    570        PK11_SETATTRS(attrs, CKA_TOKEN, &cktrue, sizeof(cktrue));
    571        attrs++;
    572        /* sigh some tokens think CKA_PRIVATE = false is a reasonable
    573         * default for secret keys */
    574        PK11_SETATTRS(attrs, CKA_PRIVATE, &cktrue, sizeof(cktrue));
    575        attrs++;
    576    }
    577    attrs += pk11_OpFlagsToAttributes(flags, attrs, &cktrue);
    578    if ((operation != CKA_FLAGS_ONLY) &&
    579        !pk11_FindAttrInTemplate(keyTemplate, attrs - keyTemplate, operation)) {
    580        PK11_SETATTRS(attrs, operation, &cktrue, sizeof(cktrue));
    581        attrs++;
    582    }
    583    templateCount = attrs - keyTemplate;
    584    PR_ASSERT(templateCount + 1 <= sizeof(keyTemplate) / sizeof(CK_ATTRIBUTE));
    585 
    586    keyType = PK11_GetKeyType(type, key->len);
    587    symKey = pk11_ImportSymKeyWithTempl(slot, type, origin, isPerm,
    588                                        keyTemplate, templateCount, key, wincx);
    589    if (symKey && isPerm) {
    590        symKey->owner = PR_FALSE;
    591    }
    592    return symKey;
    593 }
    594 
    595 PK11SymKey *
    596 PK11_FindFixedKey(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, SECItem *keyID,
    597                  void *wincx)
    598 {
    599    CK_ATTRIBUTE findTemp[5];
    600    CK_ATTRIBUTE *attrs;
    601    CK_BBOOL ckTrue = CK_TRUE;
    602    CK_OBJECT_CLASS keyclass = CKO_SECRET_KEY;
    603    size_t tsize = 0;
    604    CK_OBJECT_HANDLE key_id;
    605    CK_KEY_TYPE keyType = PK11_GetKeyType(type, 0);
    606 
    607    attrs = findTemp;
    608    PK11_SETATTRS(attrs, CKA_CLASS, &keyclass, sizeof(keyclass));
    609    attrs++;
    610    PK11_SETATTRS(attrs, CKA_TOKEN, &ckTrue, sizeof(ckTrue));
    611    attrs++;
    612    PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType));
    613    attrs++;
    614    if (keyID) {
    615        PK11_SETATTRS(attrs, CKA_ID, keyID->data, keyID->len);
    616        attrs++;
    617    }
    618    tsize = attrs - findTemp;
    619    PORT_Assert(tsize <= sizeof(findTemp) / sizeof(CK_ATTRIBUTE));
    620 
    621    key_id = pk11_FindObjectByTemplate(slot, findTemp, tsize);
    622    if (key_id == CK_INVALID_HANDLE) {
    623        return NULL;
    624    }
    625    return PK11_SymKeyFromHandle(slot, NULL, PK11_OriginDerive, type, key_id,
    626                                 PR_FALSE, wincx);
    627 }
    628 
    629 PK11SymKey *
    630 PK11_ListFixedKeysInSlot(PK11SlotInfo *slot, char *nickname, void *wincx)
    631 {
    632    CK_ATTRIBUTE findTemp[4];
    633    CK_ATTRIBUTE *attrs;
    634    CK_BBOOL ckTrue = CK_TRUE;
    635    CK_OBJECT_CLASS keyclass = CKO_SECRET_KEY;
    636    int tsize = 0;
    637    int objCount = 0;
    638    CK_OBJECT_HANDLE *key_ids;
    639    PK11SymKey *nextKey = NULL;
    640    PK11SymKey *topKey = NULL;
    641    int i, len;
    642 
    643    attrs = findTemp;
    644    PK11_SETATTRS(attrs, CKA_CLASS, &keyclass, sizeof(keyclass));
    645    attrs++;
    646    PK11_SETATTRS(attrs, CKA_TOKEN, &ckTrue, sizeof(ckTrue));
    647    attrs++;
    648    if (nickname) {
    649        len = PORT_Strlen(nickname);
    650        PK11_SETATTRS(attrs, CKA_LABEL, nickname, len);
    651        attrs++;
    652    }
    653    tsize = attrs - findTemp;
    654    PORT_Assert(tsize <= sizeof(findTemp) / sizeof(CK_ATTRIBUTE));
    655 
    656    key_ids = pk11_FindObjectsByTemplate(slot, findTemp, tsize, &objCount);
    657    if (key_ids == NULL) {
    658        return NULL;
    659    }
    660 
    661    for (i = 0; i < objCount; i++) {
    662        SECItem typeData;
    663        CK_KEY_TYPE type = CKK_GENERIC_SECRET;
    664        SECStatus rv = PK11_ReadAttribute(slot, key_ids[i],
    665                                          CKA_KEY_TYPE, NULL, &typeData);
    666        if (rv == SECSuccess) {
    667            if (typeData.len == sizeof(CK_KEY_TYPE)) {
    668                type = *(CK_KEY_TYPE *)typeData.data;
    669            }
    670            PORT_Free(typeData.data);
    671        }
    672        nextKey = PK11_SymKeyFromHandle(slot, NULL, PK11_OriginDerive,
    673                                        PK11_GetKeyMechanism(type), key_ids[i], PR_FALSE, wincx);
    674        if (nextKey) {
    675            nextKey->next = topKey;
    676            topKey = nextKey;
    677        }
    678    }
    679    PORT_Free(key_ids);
    680    return topKey;
    681 }
    682 
    683 void *
    684 PK11_GetWindow(PK11SymKey *key)
    685 {
    686    return key->cx;
    687 }
    688 
    689 /*
    690 * extract a symmetric key value. NOTE: if the key is sensitive, we will
    691 * not be able to do this operation. This function is used to move
    692 * keys from one token to another */
    693 SECStatus
    694 PK11_ExtractKeyValue(PK11SymKey *symKey)
    695 {
    696    SECStatus rv;
    697 
    698    if (symKey == NULL) {
    699        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    700        return SECFailure;
    701    }
    702 
    703    if (symKey->data.data != NULL) {
    704        if (symKey->size == 0) {
    705            symKey->size = symKey->data.len;
    706        }
    707        return SECSuccess;
    708    }
    709 
    710    if (symKey->slot == NULL) {
    711        PORT_SetError(SEC_ERROR_INVALID_KEY);
    712        return SECFailure;
    713    }
    714 
    715    rv = PK11_ReadAttribute(symKey->slot, symKey->objectID, CKA_VALUE, NULL,
    716                            &symKey->data);
    717    if (rv == SECSuccess) {
    718        symKey->size = symKey->data.len;
    719    }
    720    return rv;
    721 }
    722 
    723 SECStatus
    724 PK11_DeleteTokenSymKey(PK11SymKey *symKey)
    725 {
    726    if (!PK11_IsPermObject(symKey->slot, symKey->objectID)) {
    727        return SECFailure;
    728    }
    729    PK11_DestroyTokenObject(symKey->slot, symKey->objectID);
    730    symKey->objectID = CK_INVALID_HANDLE;
    731    return SECSuccess;
    732 }
    733 
    734 SECItem *
    735 PK11_GetKeyData(PK11SymKey *symKey)
    736 {
    737    return &symKey->data;
    738 }
    739 
    740 /* This symbol is exported for backward compatibility. */
    741 SECItem *
    742 __PK11_GetKeyData(PK11SymKey *symKey)
    743 {
    744    return PK11_GetKeyData(symKey);
    745 }
    746 
    747 /*
    748 * PKCS #11 key Types with predefined length
    749 */
    750 unsigned int
    751 pk11_GetPredefinedKeyLength(CK_KEY_TYPE keyType)
    752 {
    753    int length = 0;
    754    switch (keyType) {
    755        case CKK_DES:
    756            length = 8;
    757            break;
    758        case CKK_DES2:
    759            length = 16;
    760            break;
    761        case CKK_DES3:
    762            length = 24;
    763            break;
    764        case CKK_SKIPJACK:
    765            length = 10;
    766            break;
    767        case CKK_BATON:
    768            length = 20;
    769            break;
    770        case CKK_JUNIPER:
    771            length = 20;
    772            break;
    773        default:
    774            break;
    775    }
    776    return length;
    777 }
    778 
    779 /* return the keylength if possible.  '0' if not */
    780 unsigned int
    781 PK11_GetKeyLength(PK11SymKey *key)
    782 {
    783    CK_KEY_TYPE keyType;
    784 
    785    if (key->size != 0)
    786        return key->size;
    787 
    788    /* First try to figure out the key length from its type */
    789    keyType = PK11_ReadULongAttribute(key->slot, key->objectID, CKA_KEY_TYPE);
    790    key->size = pk11_GetPredefinedKeyLength(keyType);
    791    if ((keyType == CKK_GENERIC_SECRET) &&
    792        (key->type == CKM_SSL3_PRE_MASTER_KEY_GEN)) {
    793        key->size = 48;
    794    }
    795 
    796    if (key->size != 0)
    797        return key->size;
    798 
    799    if (key->data.data == NULL) {
    800        PK11_ExtractKeyValue(key);
    801    }
    802    /* key is probably secret. Look up its length */
    803    /*  this is new PKCS #11 version 2.0 functionality. */
    804    if (key->size == 0) {
    805        CK_ULONG keyLength;
    806 
    807        keyLength = PK11_ReadULongAttribute(key->slot, key->objectID, CKA_VALUE_LEN);
    808        if (keyLength != CK_UNAVAILABLE_INFORMATION) {
    809            key->size = (unsigned int)keyLength;
    810        }
    811    }
    812 
    813    return key->size;
    814 }
    815 
    816 /* return the strength of a key. This is different from length in that
    817 * 1) it returns the size in bits, and 2) it returns only the secret portions
    818 * of the key minus any checksums or parity.
    819 */
    820 unsigned int
    821 PK11_GetKeyStrength(PK11SymKey *key, SECAlgorithmID *algid)
    822 {
    823    int size = 0;
    824    CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM; /* RC2 only */
    825    SECItem *param = NULL;                               /* RC2 only */
    826    CK_RC2_CBC_PARAMS *rc2_params = NULL;                /* RC2 ONLY */
    827    unsigned int effectiveBits = 0;                      /* RC2 ONLY */
    828 
    829    switch (PK11_GetKeyType(key->type, 0)) {
    830        case CKK_CDMF:
    831            return 40;
    832        case CKK_DES:
    833            return 56;
    834        case CKK_DES3:
    835        case CKK_DES2:
    836            size = PK11_GetKeyLength(key);
    837            if (size == 16) {
    838                /* double des */
    839                return 112; /* 16*7 */
    840            }
    841            return 168;
    842        /*
    843         * RC2 has is different than other ciphers in that it allows the user
    844         * to deprecating keysize while still requiring all the bits for the
    845         * original key. The info
    846         * on what the effective key strength is in the parameter for the key.
    847         * In S/MIME this parameter is stored in the DER encoded algid. In Our
    848         * other uses of RC2, effectiveBits == keyBits, so this code functions
    849         * correctly without an algid.
    850         */
    851        case CKK_RC2:
    852            /* if no algid was provided, fall through to default */
    853            if (!algid) {
    854                break;
    855            }
    856            /* verify that the algid is for RC2 */
    857            mechanism = PK11_AlgtagToMechanism(SECOID_GetAlgorithmTag(algid));
    858            if ((mechanism != CKM_RC2_CBC) && (mechanism != CKM_RC2_ECB)) {
    859                break;
    860            }
    861 
    862            /* now get effective bits from the algorithm ID. */
    863            param = PK11_ParamFromAlgid(algid);
    864            /* if we couldn't get memory just use key length */
    865            if (param == NULL) {
    866                break;
    867            }
    868 
    869            rc2_params = (CK_RC2_CBC_PARAMS *)param->data;
    870            /* paranoia... shouldn't happen */
    871            PORT_Assert(param->data != NULL);
    872            if (param->data == NULL) {
    873                SECITEM_FreeItem(param, PR_TRUE);
    874                break;
    875            }
    876            effectiveBits = (unsigned int)rc2_params->ulEffectiveBits;
    877            SECITEM_FreeItem(param, PR_TRUE);
    878            param = NULL;
    879            rc2_params = NULL; /* paranoia */
    880 
    881            /* we have effective bits, is and allocated memory is free, now
    882             * we need to return the smaller of effective bits and keysize */
    883            size = PK11_GetKeyLength(key);
    884            if ((unsigned int)size * 8 > effectiveBits) {
    885                return effectiveBits;
    886            }
    887 
    888            return size * 8; /* the actual key is smaller, the strength can't be
    889                              * greater than the actual key size */
    890 
    891        default:
    892            break;
    893    }
    894    return PK11_GetKeyLength(key) * 8;
    895 }
    896 
    897 /*
    898 * The next three utilities are to deal with the fact that a given operation
    899 * may be a multi-slot affair. This creates a new key object that is copied
    900 * into the new slot.
    901 */
    902 PK11SymKey *
    903 pk11_CopyToSlotPerm(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
    904                    CK_ATTRIBUTE_TYPE operation, CK_FLAGS flags,
    905                    PRBool isPerm, PK11SymKey *symKey)
    906 {
    907    SECStatus rv;
    908    PK11SymKey *newKey = NULL;
    909 
    910    /* Extract the raw key data if possible */
    911    if (symKey->data.data == NULL) {
    912        rv = PK11_ExtractKeyValue(symKey);
    913        /* KEY is sensitive, we're try key exchanging it. */
    914        if (rv != SECSuccess) {
    915            return pk11_KeyExchange(slot, type, operation,
    916                                    flags, isPerm, symKey);
    917        }
    918    }
    919 
    920    newKey = PK11_ImportSymKeyWithFlags(slot, type, symKey->origin,
    921                                        operation, &symKey->data, flags, isPerm, symKey->cx);
    922    if (newKey == NULL) {
    923        newKey = pk11_KeyExchange(slot, type, operation, flags, isPerm, symKey);
    924    }
    925    return newKey;
    926 }
    927 
    928 PK11SymKey *
    929 pk11_CopyToSlot(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
    930                CK_ATTRIBUTE_TYPE operation, PK11SymKey *symKey)
    931 {
    932    return pk11_CopyToSlotPerm(slot, type, operation, 0, PR_FALSE, symKey);
    933 }
    934 
    935 /*
    936 * Make sure the slot we are in is the correct slot for the operation
    937 * by verifying that it supports all of the specified mechanism types.
    938 */
    939 PK11SymKey *
    940 pk11_ForceSlotMultiple(PK11SymKey *symKey, CK_MECHANISM_TYPE *type,
    941                       int mechCount, CK_ATTRIBUTE_TYPE operation)
    942 {
    943    PK11SlotInfo *slot = symKey->slot;
    944    PK11SymKey *newKey = NULL;
    945    PRBool needToCopy = PR_FALSE;
    946    int i;
    947 
    948    if (slot == NULL) {
    949        needToCopy = PR_TRUE;
    950    } else {
    951        i = 0;
    952        while ((i < mechCount) && (needToCopy == PR_FALSE)) {
    953            if (!PK11_DoesMechanism(slot, type[i])) {
    954                needToCopy = PR_TRUE;
    955            }
    956            i++;
    957        }
    958    }
    959 
    960    if (needToCopy == PR_TRUE) {
    961        slot = PK11_GetBestSlotMultiple(type, mechCount, symKey->cx);
    962        if (slot == NULL) {
    963            PORT_SetError(SEC_ERROR_NO_MODULE);
    964            return NULL;
    965        }
    966        newKey = pk11_CopyToSlot(slot, type[0], operation, symKey);
    967        PK11_FreeSlot(slot);
    968    }
    969    return newKey;
    970 }
    971 
    972 /*
    973 * Make sure the slot we are in is the correct slot for the operation
    974 */
    975 PK11SymKey *
    976 pk11_ForceSlot(PK11SymKey *symKey, CK_MECHANISM_TYPE type,
    977               CK_ATTRIBUTE_TYPE operation)
    978 {
    979    return pk11_ForceSlotMultiple(symKey, &type, 1, operation);
    980 }
    981 
    982 PK11SymKey *
    983 PK11_MoveSymKey(PK11SlotInfo *slot, CK_ATTRIBUTE_TYPE operation,
    984                CK_FLAGS flags, PRBool perm, PK11SymKey *symKey)
    985 {
    986    if (symKey->slot == slot) {
    987        if (perm) {
    988            return PK11_ConvertSessionSymKeyToTokenSymKey(symKey, symKey->cx);
    989        } else {
    990            return PK11_ReferenceSymKey(symKey);
    991        }
    992    }
    993 
    994    return pk11_CopyToSlotPerm(slot, symKey->type,
    995                               operation, flags, perm, symKey);
    996 }
    997 
    998 /*
    999 * Use the token to generate a key.
   1000 *
   1001 * keySize must be 'zero' for fixed key length algorithms. A nonzero
   1002 *  keySize causes the CKA_VALUE_LEN attribute to be added to the template
   1003 *  for the key. Most PKCS #11 modules fail if you specify the CKA_VALUE_LEN
   1004 *  attribute for keys with fixed length. The exception is DES2. If you
   1005 *  select a CKM_DES3_CBC mechanism, this code will not add the CKA_VALUE_LEN
   1006 *  parameter and use the key size to determine which underlying DES keygen
   1007 *  function to use (CKM_DES2_KEY_GEN or CKM_DES3_KEY_GEN).
   1008 *
   1009 * keyType must be -1 for most algorithms. Some PBE algorthims cannot
   1010 *  determine the correct key type from the mechanism or the parameters,
   1011 *  so key type must be specified. Other PKCS #11 mechanisms may do so in
   1012 *  the future. Currently there is no need to export this publically.
   1013 *  Keep it private until there is a need in case we need to expand the
   1014 *  keygen parameters again...
   1015 *
   1016 * CK_FLAGS flags: key operation flags
   1017 * PK11AttrFlags attrFlags: PK11_ATTR_XXX key attribute flags
   1018 */
   1019 PK11SymKey *
   1020 pk11_TokenKeyGenWithFlagsAndKeyType(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
   1021                                    SECItem *param, CK_KEY_TYPE keyType, int keySize, SECItem *keyid,
   1022                                    CK_FLAGS opFlags, PK11AttrFlags attrFlags, void *wincx)
   1023 {
   1024    PK11SymKey *symKey;
   1025    CK_ATTRIBUTE genTemplate[MAX_TEMPL_ATTRS];
   1026    CK_ATTRIBUTE *attrs = genTemplate;
   1027    int count = sizeof(genTemplate) / sizeof(genTemplate[0]);
   1028    CK_MECHANISM_TYPE keyGenType;
   1029    CK_BBOOL cktrue = CK_TRUE;
   1030    CK_BBOOL ckfalse = CK_FALSE;
   1031    CK_ULONG ck_key_size; /* only used for variable-length keys */
   1032 
   1033    if (pk11_BadAttrFlags(attrFlags)) {
   1034        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1035        return NULL;
   1036    }
   1037 
   1038    if ((keySize != 0) && (type != CKM_DES3_CBC) &&
   1039        (type != CKM_DES3_CBC_PAD) && (type != CKM_DES3_ECB)) {
   1040        ck_key_size = keySize; /* Convert to PK11 type */
   1041 
   1042        PK11_SETATTRS(attrs, CKA_VALUE_LEN, &ck_key_size, sizeof(ck_key_size));
   1043        attrs++;
   1044    }
   1045 
   1046    if (keyType != -1) {
   1047        PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(CK_KEY_TYPE));
   1048        attrs++;
   1049    }
   1050 
   1051    /* Include key id value if provided */
   1052    if (keyid) {
   1053        PK11_SETATTRS(attrs, CKA_ID, keyid->data, keyid->len);
   1054        attrs++;
   1055    }
   1056 
   1057    attrs += pk11_AttrFlagsToAttributes(attrFlags, attrs, &cktrue, &ckfalse);
   1058    attrs += pk11_OpFlagsToAttributes(opFlags, attrs, &cktrue);
   1059 
   1060    count = attrs - genTemplate;
   1061    PR_ASSERT(count <= sizeof(genTemplate) / sizeof(CK_ATTRIBUTE));
   1062 
   1063    keyGenType = PK11_GetKeyGenWithSize(type, keySize);
   1064    if (keyGenType == CKM_FAKE_RANDOM) {
   1065        PORT_SetError(SEC_ERROR_NO_MODULE);
   1066        return NULL;
   1067    }
   1068    symKey = PK11_KeyGenWithTemplate(slot, type, keyGenType,
   1069                                     param, genTemplate, count, wincx);
   1070    if (symKey != NULL) {
   1071        symKey->size = keySize;
   1072    }
   1073    return symKey;
   1074 }
   1075 
   1076 /*
   1077 * Use the token to generate a key.  - Public
   1078 *
   1079 * keySize must be 'zero' for fixed key length algorithms. A nonzero
   1080 *  keySize causes the CKA_VALUE_LEN attribute to be added to the template
   1081 *  for the key. Most PKCS #11 modules fail if you specify the CKA_VALUE_LEN
   1082 *  attribute for keys with fixed length. The exception is DES2. If you
   1083 *  select a CKM_DES3_CBC mechanism, this code will not add the CKA_VALUE_LEN
   1084 *  parameter and use the key size to determine which underlying DES keygen
   1085 *  function to use (CKM_DES2_KEY_GEN or CKM_DES3_KEY_GEN).
   1086 *
   1087 * CK_FLAGS flags: key operation flags
   1088 * PK11AttrFlags attrFlags: PK11_ATTR_XXX key attribute flags
   1089 */
   1090 PK11SymKey *
   1091 PK11_TokenKeyGenWithFlags(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
   1092                          SECItem *param, int keySize, SECItem *keyid, CK_FLAGS opFlags,
   1093                          PK11AttrFlags attrFlags, void *wincx)
   1094 {
   1095    return pk11_TokenKeyGenWithFlagsAndKeyType(slot, type, param, -1, keySize,
   1096                                               keyid, opFlags, attrFlags, wincx);
   1097 }
   1098 
   1099 /*
   1100 * Use the token to generate a key. keySize must be 'zero' for fixed key
   1101 * length algorithms. A nonzero keySize causes the CKA_VALUE_LEN attribute
   1102 * to be added to the template for the key. PKCS #11 modules fail if you
   1103 * specify the CKA_VALUE_LEN attribute for keys with fixed length.
   1104 * NOTE: this means to generate a DES2 key from this interface you must
   1105 * specify CKM_DES2_KEY_GEN as the mechanism directly; specifying
   1106 * CKM_DES3_CBC as the mechanism and 16 as keySize currently doesn't work.
   1107 */
   1108 PK11SymKey *
   1109 PK11_TokenKeyGen(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, SECItem *param,
   1110                 int keySize, SECItem *keyid, PRBool isToken, void *wincx)
   1111 {
   1112    PK11SymKey *symKey;
   1113    PRBool weird = PR_FALSE; /* hack for fortezza */
   1114    CK_FLAGS opFlags = CKF_SIGN;
   1115    PK11AttrFlags attrFlags = 0;
   1116 
   1117    if ((keySize == -1) && (type == CKM_SKIPJACK_CBC64)) {
   1118        weird = PR_TRUE;
   1119        keySize = 0;
   1120    }
   1121 
   1122    opFlags |= weird ? CKF_DECRYPT : CKF_ENCRYPT;
   1123 
   1124    if (isToken) {
   1125        attrFlags |= (PK11_ATTR_TOKEN | PK11_ATTR_PRIVATE);
   1126    }
   1127 
   1128    symKey = pk11_TokenKeyGenWithFlagsAndKeyType(slot, type, param,
   1129                                                 -1, keySize, keyid, opFlags, attrFlags, wincx);
   1130    if (symKey && weird) {
   1131        PK11_SetFortezzaHack(symKey);
   1132    }
   1133 
   1134    return symKey;
   1135 }
   1136 
   1137 PK11SymKey *
   1138 PK11_KeyGen(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, SECItem *param,
   1139            int keySize, void *wincx)
   1140 {
   1141    return PK11_TokenKeyGen(slot, type, param, keySize, 0, PR_FALSE, wincx);
   1142 }
   1143 
   1144 PK11SymKey *
   1145 PK11_KeyGenWithTemplate(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
   1146                        CK_MECHANISM_TYPE keyGenType,
   1147                        SECItem *param, CK_ATTRIBUTE *attrs,
   1148                        unsigned int attrsCount, void *wincx)
   1149 {
   1150    PK11SymKey *symKey;
   1151    CK_SESSION_HANDLE session;
   1152    CK_MECHANISM mechanism;
   1153    CK_RV crv;
   1154    PRBool isToken = CK_FALSE;
   1155    CK_ULONG keySize = 0;
   1156    unsigned i;
   1157 
   1158    /* Extract the template's CKA_VALUE_LEN into keySize and CKA_TOKEN into
   1159       isToken. */
   1160    for (i = 0; i < attrsCount; ++i) {
   1161        switch (attrs[i].type) {
   1162            case CKA_VALUE_LEN:
   1163                if (attrs[i].pValue == NULL ||
   1164                    attrs[i].ulValueLen != sizeof(CK_ULONG)) {
   1165                    PORT_SetError(PK11_MapError(CKR_TEMPLATE_INCONSISTENT));
   1166                    return NULL;
   1167                }
   1168                keySize = *(CK_ULONG *)attrs[i].pValue;
   1169                break;
   1170            case CKA_TOKEN:
   1171                if (attrs[i].pValue == NULL ||
   1172                    attrs[i].ulValueLen != sizeof(CK_BBOOL)) {
   1173                    PORT_SetError(PK11_MapError(CKR_TEMPLATE_INCONSISTENT));
   1174                    return NULL;
   1175                }
   1176                isToken = (*(CK_BBOOL *)attrs[i].pValue) ? PR_TRUE : PR_FALSE;
   1177                break;
   1178        }
   1179    }
   1180 
   1181    /* find a slot to generate the key into */
   1182    /* Only do slot management if this is not a token key */
   1183    if (!isToken && (slot == NULL || !PK11_DoesMechanism(slot, type))) {
   1184        PK11SlotInfo *bestSlot = PK11_GetBestSlot(type, wincx);
   1185        if (bestSlot == NULL) {
   1186            PORT_SetError(SEC_ERROR_NO_MODULE);
   1187            return NULL;
   1188        }
   1189        symKey = pk11_CreateSymKey(bestSlot, type, !isToken, PR_TRUE, wincx);
   1190        PK11_FreeSlot(bestSlot);
   1191    } else {
   1192        symKey = pk11_CreateSymKey(slot, type, !isToken, PR_TRUE, wincx);
   1193    }
   1194    if (symKey == NULL)
   1195        return NULL;
   1196 
   1197    symKey->size = keySize;
   1198    symKey->origin = PK11_OriginGenerated;
   1199 
   1200    /* Set the parameters for the key gen if provided */
   1201    mechanism.mechanism = keyGenType;
   1202    mechanism.pParameter = NULL;
   1203    mechanism.ulParameterLen = 0;
   1204    if (param) {
   1205        mechanism.pParameter = param->data;
   1206        mechanism.ulParameterLen = param->len;
   1207    }
   1208 
   1209    /* Get session and perform locking */
   1210    if (isToken) {
   1211        PK11_Authenticate(symKey->slot, PR_TRUE, wincx);
   1212        /* Should always be original slot */
   1213        session = PK11_GetRWSession(symKey->slot);
   1214        symKey->owner = PR_FALSE;
   1215    } else {
   1216        session = symKey->session;
   1217        if (session != CK_INVALID_HANDLE)
   1218            pk11_EnterKeyMonitor(symKey);
   1219    }
   1220    if (session == CK_INVALID_HANDLE) {
   1221        PK11_FreeSymKey(symKey);
   1222        PORT_SetError(SEC_ERROR_BAD_DATA);
   1223        return NULL;
   1224    }
   1225 
   1226    crv = PK11_GETTAB(symKey->slot)->C_GenerateKey(session, &mechanism, attrs, attrsCount, &symKey->objectID);
   1227 
   1228    /* Release lock and session */
   1229    if (isToken) {
   1230        PK11_RestoreROSession(symKey->slot, session);
   1231    } else {
   1232        pk11_ExitKeyMonitor(symKey);
   1233    }
   1234 
   1235    if (crv != CKR_OK) {
   1236        PK11_FreeSymKey(symKey);
   1237        PORT_SetError(PK11_MapError(crv));
   1238        return NULL;
   1239    }
   1240 
   1241    return symKey;
   1242 }
   1243 
   1244 PK11SymKey *
   1245 PK11_ConvertSessionSymKeyToTokenSymKey(PK11SymKey *symk, void *wincx)
   1246 {
   1247    PK11SlotInfo *slot = symk->slot;
   1248    CK_ATTRIBUTE template[1];
   1249    CK_ATTRIBUTE *attrs = template;
   1250    CK_BBOOL cktrue = CK_TRUE;
   1251    CK_RV crv;
   1252    CK_OBJECT_HANDLE newKeyID;
   1253    CK_SESSION_HANDLE rwsession;
   1254 
   1255    PK11_SETATTRS(attrs, CKA_TOKEN, &cktrue, sizeof(cktrue));
   1256    attrs++;
   1257 
   1258    PK11_Authenticate(slot, PR_TRUE, wincx);
   1259    rwsession = PK11_GetRWSession(slot);
   1260    if (rwsession == CK_INVALID_HANDLE) {
   1261        PORT_SetError(SEC_ERROR_BAD_DATA);
   1262        return NULL;
   1263    }
   1264    crv = PK11_GETTAB(slot)->C_CopyObject(rwsession, symk->objectID,
   1265                                          template, 1, &newKeyID);
   1266    PK11_RestoreROSession(slot, rwsession);
   1267 
   1268    if (crv != CKR_OK) {
   1269        PORT_SetError(PK11_MapError(crv));
   1270        return NULL;
   1271    }
   1272 
   1273    return PK11_SymKeyFromHandle(slot, NULL /*parent*/, symk->origin,
   1274                                 symk->type, newKeyID, PR_FALSE /*owner*/, NULL /*wincx*/);
   1275 }
   1276 
   1277 /* This function does a straight public key wrap with the CKM_RSA_PKCS
   1278 * mechanism. */
   1279 SECStatus
   1280 PK11_PubWrapSymKey(CK_MECHANISM_TYPE type, SECKEYPublicKey *pubKey,
   1281                   PK11SymKey *symKey, SECItem *wrappedKey)
   1282 {
   1283    CK_MECHANISM_TYPE inferred = pk11_mapWrapKeyType(pubKey->keyType);
   1284    return PK11_PubWrapSymKeyWithMechanism(pubKey, inferred, NULL, symKey,
   1285                                           wrappedKey);
   1286 }
   1287 
   1288 /* This function wraps a symmetric key with a public key, such as with the
   1289 * CKM_RSA_PKCS and CKM_RSA_PKCS_OAEP mechanisms. */
   1290 SECStatus
   1291 PK11_PubWrapSymKeyWithMechanism(SECKEYPublicKey *pubKey,
   1292                                CK_MECHANISM_TYPE mechType, SECItem *param,
   1293                                PK11SymKey *symKey, SECItem *wrappedKey)
   1294 {
   1295    PK11SlotInfo *slot;
   1296    CK_ULONG len = wrappedKey->len;
   1297    PK11SymKey *newKey = NULL;
   1298    CK_OBJECT_HANDLE id;
   1299    CK_MECHANISM mechanism;
   1300    PRBool owner = PR_TRUE;
   1301    CK_SESSION_HANDLE session;
   1302    CK_RV crv;
   1303 
   1304    if (symKey == NULL) {
   1305        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1306        return SECFailure;
   1307    }
   1308 
   1309    /* if this slot doesn't support the mechanism, go to a slot that does */
   1310    newKey = pk11_ForceSlot(symKey, mechType, CKA_ENCRYPT);
   1311    if (newKey != NULL) {
   1312        symKey = newKey;
   1313    }
   1314 
   1315    if (symKey->slot == NULL) {
   1316        PORT_SetError(SEC_ERROR_NO_MODULE);
   1317        return SECFailure;
   1318    }
   1319 
   1320    slot = symKey->slot;
   1321 
   1322    mechanism.mechanism = mechType;
   1323    if (param == NULL) {
   1324        mechanism.pParameter = NULL;
   1325        mechanism.ulParameterLen = 0;
   1326    } else {
   1327        mechanism.pParameter = param->data;
   1328        mechanism.ulParameterLen = param->len;
   1329    }
   1330 
   1331    id = PK11_ImportPublicKey(slot, pubKey, PR_FALSE);
   1332    if (id == CK_INVALID_HANDLE) {
   1333        if (newKey) {
   1334            PK11_FreeSymKey(newKey);
   1335        }
   1336        return SECFailure; /* Error code has been set. */
   1337    }
   1338 
   1339    session = pk11_GetNewSession(slot, &owner);
   1340    if (!owner || !(slot->isThreadSafe))
   1341        PK11_EnterSlotMonitor(slot);
   1342    crv = PK11_GETTAB(slot)->C_WrapKey(session, &mechanism,
   1343                                       id, symKey->objectID, wrappedKey->data, &len);
   1344    if (!owner || !(slot->isThreadSafe))
   1345        PK11_ExitSlotMonitor(slot);
   1346    pk11_CloseSession(slot, session, owner);
   1347    if (newKey) {
   1348        PK11_FreeSymKey(newKey);
   1349    }
   1350 
   1351    if (crv != CKR_OK) {
   1352        PORT_SetError(PK11_MapError(crv));
   1353        return SECFailure;
   1354    }
   1355    wrappedKey->len = len;
   1356    return SECSuccess;
   1357 }
   1358 
   1359 /*
   1360 * this little function uses the Encrypt function to wrap a key, just in
   1361 * case we have problems with the wrap implementation for a token.
   1362 */
   1363 static SECStatus
   1364 pk11_HandWrap(PK11SymKey *wrappingKey, SECItem *param, CK_MECHANISM_TYPE type,
   1365              SECItem *inKey, SECItem *outKey)
   1366 {
   1367    PK11SlotInfo *slot;
   1368    CK_ULONG len;
   1369    SECItem *data;
   1370    CK_MECHANISM mech;
   1371    PRBool owner = PR_TRUE;
   1372    CK_SESSION_HANDLE session;
   1373    CK_RV crv;
   1374 
   1375    slot = wrappingKey->slot;
   1376    /* use NULL IV's for wrapping */
   1377    mech.mechanism = type;
   1378    if (param) {
   1379        mech.pParameter = param->data;
   1380        mech.ulParameterLen = param->len;
   1381    } else {
   1382        mech.pParameter = NULL;
   1383        mech.ulParameterLen = 0;
   1384    }
   1385    session = pk11_GetNewSession(slot, &owner);
   1386    if (!owner || !(slot->isThreadSafe))
   1387        PK11_EnterSlotMonitor(slot);
   1388    crv = PK11_GETTAB(slot)->C_EncryptInit(session, &mech,
   1389                                           wrappingKey->objectID);
   1390    if (crv != CKR_OK) {
   1391        if (!owner || !(slot->isThreadSafe))
   1392            PK11_ExitSlotMonitor(slot);
   1393        pk11_CloseSession(slot, session, owner);
   1394        PORT_SetError(PK11_MapError(crv));
   1395        return SECFailure;
   1396    }
   1397 
   1398    /* keys are almost always aligned, but if we get this far,
   1399     * we've gone above and beyond anyway... */
   1400    data = PK11_BlockData(inKey, PK11_GetBlockSize(type, param));
   1401    if (data == NULL) {
   1402        if (!owner || !(slot->isThreadSafe))
   1403            PK11_ExitSlotMonitor(slot);
   1404        pk11_CloseSession(slot, session, owner);
   1405        PORT_SetError(SEC_ERROR_NO_MEMORY);
   1406        return SECFailure;
   1407    }
   1408    len = outKey->len;
   1409    crv = PK11_GETTAB(slot)->C_Encrypt(session, data->data, data->len,
   1410                                       outKey->data, &len);
   1411    if (!owner || !(slot->isThreadSafe))
   1412        PK11_ExitSlotMonitor(slot);
   1413    pk11_CloseSession(slot, session, owner);
   1414    SECITEM_FreeItem(data, PR_TRUE);
   1415    outKey->len = len;
   1416    if (crv != CKR_OK) {
   1417        PORT_SetError(PK11_MapError(crv));
   1418        return SECFailure;
   1419    }
   1420    return SECSuccess;
   1421 }
   1422 
   1423 /*
   1424 * helper function which moves two keys into a new slot based on the
   1425 * desired mechanism.
   1426 */
   1427 static SECStatus
   1428 pk11_moveTwoKeys(CK_MECHANISM_TYPE mech,
   1429                 CK_ATTRIBUTE_TYPE preferedOperation,
   1430                 CK_ATTRIBUTE_TYPE movingOperation,
   1431                 PK11SymKey *preferedKey, PK11SymKey *movingKey,
   1432                 PK11SymKey **newPreferedKey, PK11SymKey **newMovingKey)
   1433 {
   1434    PK11SlotInfo *newSlot;
   1435    *newMovingKey = NULL;
   1436    *newPreferedKey = NULL;
   1437 
   1438    newSlot = PK11_GetBestSlot(mech, preferedKey->cx);
   1439    if (newSlot == NULL) {
   1440        return SECFailure;
   1441    }
   1442    *newMovingKey = pk11_CopyToSlot(newSlot, movingKey->type,
   1443                                    movingOperation, movingKey);
   1444    if (*newMovingKey == NULL) {
   1445        goto loser;
   1446    }
   1447    *newPreferedKey = pk11_CopyToSlot(newSlot, preferedKey->type,
   1448                                      preferedOperation, preferedKey);
   1449    if (*newPreferedKey == NULL) {
   1450        goto loser;
   1451    }
   1452 
   1453    PK11_FreeSlot(newSlot);
   1454    return SECSuccess;
   1455 loser:
   1456    PK11_FreeSlot(newSlot);
   1457    PK11_FreeSymKey(*newMovingKey);
   1458    PK11_FreeSymKey(*newPreferedKey);
   1459    *newMovingKey = NULL;
   1460    *newPreferedKey = NULL;
   1461    return SECFailure;
   1462 }
   1463 
   1464 /*
   1465 * To do joint operations, we often need two keys in the same slot.
   1466 * Usually the PKCS #11 wrappers handle this correctly (like for PK11_WrapKey),
   1467 * but sometimes the wrappers don't know about mechanism specific keys in
   1468 * the Mechanism params. This function makes sure the two keys are in the
   1469 * same slot by copying one or both of the keys into a common slot. This
   1470 * functions makes sure the slot can handle the target mechanism. If the copy
   1471 * is warranted, this function will prefer to move the movingKey first, then
   1472 * the preferedKey. If the keys are moved, the new keys are returned in
   1473 * newMovingKey and/or newPreferedKey. The application is responsible
   1474 * for freeing those keys once the operation is complete.
   1475 */
   1476 SECStatus
   1477 PK11_SymKeysToSameSlot(CK_MECHANISM_TYPE mech,
   1478                       CK_ATTRIBUTE_TYPE preferedOperation,
   1479                       CK_ATTRIBUTE_TYPE movingOperation,
   1480                       PK11SymKey *preferedKey, PK11SymKey *movingKey,
   1481                       PK11SymKey **newPreferedKey, PK11SymKey **newMovingKey)
   1482 {
   1483    /* usually don't return new keys */
   1484    *newMovingKey = NULL;
   1485    *newPreferedKey = NULL;
   1486    if (movingKey->slot == preferedKey->slot) {
   1487 
   1488        /* this should be the most common case */
   1489        if ((preferedKey->slot != NULL) &&
   1490            PK11_DoesMechanism(preferedKey->slot, mech)) {
   1491            return SECSuccess;
   1492        }
   1493 
   1494        /* we are in the same slot, but it doesn't do the operation,
   1495         * move both keys to an appropriate target slot */
   1496        return pk11_moveTwoKeys(mech, preferedOperation, movingOperation,
   1497                                preferedKey, movingKey,
   1498                                newPreferedKey, newMovingKey);
   1499    }
   1500 
   1501    /* keys are in different slot, try moving the moving key to the prefered
   1502     * key's slot */
   1503    if ((preferedKey->slot != NULL) &&
   1504        PK11_DoesMechanism(preferedKey->slot, mech)) {
   1505        *newMovingKey = pk11_CopyToSlot(preferedKey->slot, movingKey->type,
   1506                                        movingOperation, movingKey);
   1507        if (*newMovingKey != NULL) {
   1508            return SECSuccess;
   1509        }
   1510    }
   1511    /* couldn't moving the moving key to the prefered slot, try moving
   1512     * the prefered key */
   1513    if ((movingKey->slot != NULL) &&
   1514        PK11_DoesMechanism(movingKey->slot, mech)) {
   1515        *newPreferedKey = pk11_CopyToSlot(movingKey->slot, preferedKey->type,
   1516                                          preferedOperation, preferedKey);
   1517        if (*newPreferedKey != NULL) {
   1518            return SECSuccess;
   1519        }
   1520    }
   1521    /* Neither succeeded, but that could be that they were not in slots that
   1522     * supported the operation, try moving both keys into a common slot that
   1523     * can do the operation. */
   1524    return pk11_moveTwoKeys(mech, preferedOperation, movingOperation,
   1525                            preferedKey, movingKey,
   1526                            newPreferedKey, newMovingKey);
   1527 }
   1528 
   1529 /*
   1530 * This function does a symetric based wrap.
   1531 */
   1532 SECStatus
   1533 PK11_WrapSymKey(CK_MECHANISM_TYPE type, SECItem *param,
   1534                PK11SymKey *wrappingKey, PK11SymKey *symKey,
   1535                SECItem *wrappedKey)
   1536 {
   1537    PK11SlotInfo *slot;
   1538    CK_ULONG len = wrappedKey->len;
   1539    PK11SymKey *newSymKey = NULL;
   1540    PK11SymKey *newWrappingKey = NULL;
   1541    SECItem *param_save = NULL;
   1542    CK_MECHANISM mechanism;
   1543    PRBool owner = PR_TRUE;
   1544    CK_SESSION_HANDLE session;
   1545    CK_RV crv;
   1546    SECStatus rv;
   1547 
   1548    /* force the keys into same slot */
   1549    rv = PK11_SymKeysToSameSlot(type, CKA_ENCRYPT, CKA_WRAP,
   1550                                symKey, wrappingKey,
   1551                                &newSymKey, &newWrappingKey);
   1552    if (rv != SECSuccess) {
   1553        /* Couldn't move the keys as desired, try to hand unwrap if possible */
   1554        if (symKey->data.data == NULL) {
   1555            rv = PK11_ExtractKeyValue(symKey);
   1556            if (rv != SECSuccess) {
   1557                PORT_SetError(SEC_ERROR_NO_MODULE);
   1558                return SECFailure;
   1559            }
   1560        }
   1561        if (param == NULL) {
   1562            param_save = param = PK11_ParamFromIV(type, NULL);
   1563        }
   1564        rv = pk11_HandWrap(wrappingKey, param, type, &symKey->data, wrappedKey);
   1565        if (param_save)
   1566            SECITEM_FreeItem(param_save, PR_TRUE);
   1567        return rv;
   1568    }
   1569    if (newSymKey) {
   1570        symKey = newSymKey;
   1571    }
   1572    if (newWrappingKey) {
   1573        wrappingKey = newWrappingKey;
   1574    }
   1575 
   1576    /* at this point both keys are in the same token */
   1577    slot = wrappingKey->slot;
   1578    mechanism.mechanism = type;
   1579    /* use NULL IV's for wrapping */
   1580    if (param == NULL) {
   1581        param_save = param = PK11_ParamFromIV(type, NULL);
   1582    }
   1583    if (param) {
   1584        mechanism.pParameter = param->data;
   1585        mechanism.ulParameterLen = param->len;
   1586    } else {
   1587        mechanism.pParameter = NULL;
   1588        mechanism.ulParameterLen = 0;
   1589    }
   1590 
   1591    len = wrappedKey->len;
   1592 
   1593    session = pk11_GetNewSession(slot, &owner);
   1594    if (!owner || !(slot->isThreadSafe))
   1595        PK11_EnterSlotMonitor(slot);
   1596    crv = PK11_GETTAB(slot)->C_WrapKey(session, &mechanism,
   1597                                       wrappingKey->objectID, symKey->objectID,
   1598                                       wrappedKey->data, &len);
   1599    if (!owner || !(slot->isThreadSafe))
   1600        PK11_ExitSlotMonitor(slot);
   1601    pk11_CloseSession(slot, session, owner);
   1602    rv = SECSuccess;
   1603    if (crv != CKR_OK) {
   1604        /* can't wrap it? try hand wrapping it... */
   1605        do {
   1606            if (symKey->data.data == NULL) {
   1607                rv = PK11_ExtractKeyValue(symKey);
   1608                if (rv != SECSuccess)
   1609                    break;
   1610            }
   1611            rv = pk11_HandWrap(wrappingKey, param, type, &symKey->data,
   1612                               wrappedKey);
   1613        } while (PR_FALSE);
   1614    } else {
   1615        wrappedKey->len = len;
   1616    }
   1617    PK11_FreeSymKey(newSymKey);
   1618    PK11_FreeSymKey(newWrappingKey);
   1619    if (param_save)
   1620        SECITEM_FreeItem(param_save, PR_TRUE);
   1621    return rv;
   1622 }
   1623 
   1624 /*
   1625 * This Generates a new key based on a symetricKey
   1626 */
   1627 PK11SymKey *
   1628 PK11_Derive(PK11SymKey *baseKey, CK_MECHANISM_TYPE derive, SECItem *param,
   1629            CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation,
   1630            int keySize)
   1631 {
   1632    return PK11_DeriveWithTemplate(baseKey, derive, param, target, operation,
   1633                                   keySize, NULL, 0, PR_FALSE);
   1634 }
   1635 
   1636 PK11SymKey *
   1637 PK11_DeriveWithFlags(PK11SymKey *baseKey, CK_MECHANISM_TYPE derive,
   1638                     SECItem *param, CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation,
   1639                     int keySize, CK_FLAGS flags)
   1640 {
   1641    CK_BBOOL ckTrue = CK_TRUE;
   1642    CK_ATTRIBUTE keyTemplate[MAX_TEMPL_ATTRS];
   1643    unsigned int templateCount;
   1644 
   1645    templateCount = pk11_OpFlagsToAttributes(flags, keyTemplate, &ckTrue);
   1646    return PK11_DeriveWithTemplate(baseKey, derive, param, target, operation,
   1647                                   keySize, keyTemplate, templateCount, PR_FALSE);
   1648 }
   1649 
   1650 PK11SymKey *
   1651 PK11_DeriveWithFlagsPerm(PK11SymKey *baseKey, CK_MECHANISM_TYPE derive,
   1652                         SECItem *param, CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation,
   1653                         int keySize, CK_FLAGS flags, PRBool isPerm)
   1654 {
   1655    CK_BBOOL cktrue = CK_TRUE;
   1656    CK_ATTRIBUTE keyTemplate[MAX_TEMPL_ATTRS];
   1657    CK_ATTRIBUTE *attrs;
   1658    unsigned int templateCount = 0;
   1659 
   1660    attrs = keyTemplate;
   1661    if (isPerm) {
   1662        PK11_SETATTRS(attrs, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL));
   1663        attrs++;
   1664    }
   1665    templateCount = attrs - keyTemplate;
   1666    templateCount += pk11_OpFlagsToAttributes(flags, attrs, &cktrue);
   1667    return PK11_DeriveWithTemplate(baseKey, derive, param, target, operation,
   1668                                   keySize, keyTemplate, templateCount, isPerm);
   1669 }
   1670 
   1671 PK11SymKey *
   1672 PK11_DeriveWithTemplate(PK11SymKey *baseKey, CK_MECHANISM_TYPE derive,
   1673                        SECItem *param, CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation,
   1674                        int keySize, CK_ATTRIBUTE *userAttr, unsigned int numAttrs,
   1675                        PRBool isPerm)
   1676 {
   1677    PK11SlotInfo *slot = baseKey->slot;
   1678    PK11SymKey *symKey;
   1679    PK11SymKey *newBaseKey = NULL;
   1680    CK_BBOOL cktrue = CK_TRUE;
   1681    CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY;
   1682    CK_KEY_TYPE keyType = CKK_GENERIC_SECRET;
   1683    CK_ULONG valueLen = 0;
   1684    CK_MECHANISM mechanism;
   1685    CK_RV crv;
   1686 #define MAX_ADD_ATTRS 4
   1687    CK_ATTRIBUTE keyTemplate[MAX_TEMPL_ATTRS + MAX_ADD_ATTRS];
   1688 #undef MAX_ADD_ATTRS
   1689    CK_ATTRIBUTE *attrs = keyTemplate;
   1690    CK_SESSION_HANDLE session;
   1691    unsigned int templateCount;
   1692 
   1693    if (numAttrs > MAX_TEMPL_ATTRS) {
   1694        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1695        return NULL;
   1696    }
   1697    /* CKA_NSS_MESSAGE is a fake operation to distinguish between
   1698     * Normal Encrypt/Decrypt and MessageEncrypt/Decrypt. Don't try to set
   1699     * it as a real attribute */
   1700    if ((operation & CKA_NSS_MESSAGE_MASK) == CKA_NSS_MESSAGE) {
   1701        /* Message is or'd with a real Attribute (CKA_ENCRYPT, CKA_DECRYPT),
   1702         * etc. Strip out the real attribute here */
   1703        operation &= ~CKA_NSS_MESSAGE_MASK;
   1704    }
   1705 
   1706    /* first copy caller attributes in. */
   1707    for (templateCount = 0; templateCount < numAttrs; ++templateCount) {
   1708        *attrs++ = *userAttr++;
   1709    }
   1710 
   1711    /* We only add the following attributes to the template if the caller
   1712    ** didn't already supply them.
   1713    */
   1714    if (!pk11_FindAttrInTemplate(keyTemplate, numAttrs, CKA_CLASS)) {
   1715        PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof keyClass);
   1716        attrs++;
   1717    }
   1718    if (!pk11_FindAttrInTemplate(keyTemplate, numAttrs, CKA_KEY_TYPE)) {
   1719        keyType = PK11_GetKeyType(target, keySize);
   1720        PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof keyType);
   1721        attrs++;
   1722    }
   1723    if (keySize > 0 &&
   1724        !pk11_FindAttrInTemplate(keyTemplate, numAttrs, CKA_VALUE_LEN)) {
   1725        valueLen = (CK_ULONG)keySize;
   1726        PK11_SETATTRS(attrs, CKA_VALUE_LEN, &valueLen, sizeof valueLen);
   1727        attrs++;
   1728    }
   1729    if ((operation != CKA_FLAGS_ONLY) &&
   1730        !pk11_FindAttrInTemplate(keyTemplate, numAttrs, operation)) {
   1731        PK11_SETATTRS(attrs, operation, &cktrue, sizeof cktrue);
   1732        attrs++;
   1733    }
   1734 
   1735    templateCount = attrs - keyTemplate;
   1736    PR_ASSERT(templateCount <= sizeof(keyTemplate) / sizeof(CK_ATTRIBUTE));
   1737 
   1738    /* move the key to a slot that can do the function */
   1739    if (!PK11_DoesMechanism(slot, derive)) {
   1740        /* get a new base key & slot */
   1741        PK11SlotInfo *newSlot = PK11_GetBestSlot(derive, baseKey->cx);
   1742 
   1743        if (newSlot == NULL)
   1744            return NULL;
   1745 
   1746        newBaseKey = pk11_CopyToSlot(newSlot, derive, CKA_DERIVE,
   1747                                     baseKey);
   1748        PK11_FreeSlot(newSlot);
   1749        if (newBaseKey == NULL)
   1750            return NULL;
   1751        baseKey = newBaseKey;
   1752        slot = baseKey->slot;
   1753    }
   1754 
   1755    /* get our key Structure */
   1756    symKey = pk11_CreateSymKey(slot, target, !isPerm, PR_TRUE, baseKey->cx);
   1757    if (symKey == NULL) {
   1758        return NULL;
   1759    }
   1760 
   1761    symKey->size = keySize;
   1762 
   1763    mechanism.mechanism = derive;
   1764    if (param) {
   1765        mechanism.pParameter = param->data;
   1766        mechanism.ulParameterLen = param->len;
   1767    } else {
   1768        mechanism.pParameter = NULL;
   1769        mechanism.ulParameterLen = 0;
   1770    }
   1771    symKey->origin = PK11_OriginDerive;
   1772 
   1773    if (isPerm) {
   1774        session = PK11_GetRWSession(slot);
   1775    } else {
   1776        pk11_EnterKeyMonitor(symKey);
   1777        session = symKey->session;
   1778    }
   1779    if (session == CK_INVALID_HANDLE) {
   1780        if (!isPerm)
   1781            pk11_ExitKeyMonitor(symKey);
   1782        crv = CKR_SESSION_HANDLE_INVALID;
   1783    } else {
   1784        crv = PK11_GETTAB(slot)->C_DeriveKey(session, &mechanism,
   1785                                             baseKey->objectID, keyTemplate, templateCount, &symKey->objectID);
   1786        if (isPerm) {
   1787            PK11_RestoreROSession(slot, session);
   1788        } else {
   1789            pk11_ExitKeyMonitor(symKey);
   1790        }
   1791    }
   1792    if (newBaseKey)
   1793        PK11_FreeSymKey(newBaseKey);
   1794    if (crv != CKR_OK) {
   1795        PK11_FreeSymKey(symKey);
   1796        PORT_SetError(PK11_MapError(crv));
   1797        return NULL;
   1798    }
   1799    return symKey;
   1800 }
   1801 
   1802 /* Create a new key by concatenating base and data
   1803 */
   1804 static PK11SymKey *
   1805 pk11_ConcatenateBaseAndData(PK11SymKey *base,
   1806                            CK_BYTE *data, CK_ULONG dataLen, CK_MECHANISM_TYPE target,
   1807                            CK_ATTRIBUTE_TYPE operation)
   1808 {
   1809    CK_KEY_DERIVATION_STRING_DATA mechParams;
   1810    SECItem param;
   1811 
   1812    if (base == NULL) {
   1813        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1814        return NULL;
   1815    }
   1816 
   1817    mechParams.pData = data;
   1818    mechParams.ulLen = dataLen;
   1819    param.data = (unsigned char *)&mechParams;
   1820    param.len = sizeof(CK_KEY_DERIVATION_STRING_DATA);
   1821 
   1822    return PK11_Derive(base, CKM_CONCATENATE_BASE_AND_DATA,
   1823                       &param, target, operation, 0);
   1824 }
   1825 
   1826 /* Create a new key by concatenating base and key
   1827 */
   1828 static PK11SymKey *
   1829 pk11_ConcatenateBaseAndKey(PK11SymKey *base,
   1830                           PK11SymKey *key, CK_MECHANISM_TYPE target,
   1831                           CK_ATTRIBUTE_TYPE operation, CK_ULONG keySize)
   1832 {
   1833    SECItem param;
   1834 
   1835    if ((base == NULL) || (key == NULL)) {
   1836        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1837        return NULL;
   1838    }
   1839 
   1840    param.data = (unsigned char *)&(key->objectID);
   1841    param.len = sizeof(CK_OBJECT_HANDLE);
   1842 
   1843    return PK11_Derive(base, CKM_CONCATENATE_BASE_AND_KEY,
   1844                       &param, target, operation, keySize);
   1845 }
   1846 
   1847 PK11SymKey *
   1848 PK11_ConcatSymKeys(PK11SymKey *left, PK11SymKey *right, CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation)
   1849 {
   1850    PK11SymKey *out = NULL;
   1851    PK11SymKey *copyOfLeft = NULL;
   1852    PK11SymKey *copyOfRight = NULL;
   1853 
   1854    if ((left == NULL) || (right == NULL)) {
   1855        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1856        return NULL;
   1857    }
   1858 
   1859    SECStatus rv = PK11_SymKeysToSameSlot(CKM_CONCATENATE_BASE_AND_KEY,
   1860                                          CKA_DERIVE, CKA_DERIVE, left, right,
   1861                                          &copyOfLeft, &copyOfRight);
   1862    if (rv != SECSuccess) {
   1863        /* error code already set */
   1864        return NULL;
   1865    }
   1866 
   1867    out = pk11_ConcatenateBaseAndKey(copyOfLeft ? copyOfLeft : left, copyOfRight ? copyOfRight : right, target, operation, 0);
   1868    PK11_FreeSymKey(copyOfLeft);
   1869    PK11_FreeSymKey(copyOfRight);
   1870    return out;
   1871 }
   1872 
   1873 /* Create a new key whose value is the hash of tobehashed.
   1874 * type is the mechanism for the derived key.
   1875 */
   1876 static PK11SymKey *
   1877 pk11_HashKeyDerivation(PK11SymKey *toBeHashed,
   1878                       CK_MECHANISM_TYPE hashMechanism, CK_MECHANISM_TYPE target,
   1879                       CK_ATTRIBUTE_TYPE operation, CK_ULONG keySize)
   1880 {
   1881    return PK11_Derive(toBeHashed, hashMechanism, NULL, target, operation, keySize);
   1882 }
   1883 
   1884 /* This function implements the ANSI X9.63 key derivation function
   1885 */
   1886 static PK11SymKey *
   1887 pk11_ANSIX963Derive(PK11SymKey *sharedSecret,
   1888                    CK_EC_KDF_TYPE kdf, SECItem *sharedData,
   1889                    CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation,
   1890                    CK_ULONG keySize)
   1891 {
   1892    CK_KEY_TYPE keyType;
   1893    CK_MECHANISM_TYPE hashMechanism, mechanismArray[4];
   1894    CK_ULONG derivedKeySize, HashLen, counter, maxCounter, bufferLen;
   1895    CK_ULONG SharedInfoLen;
   1896    CK_BYTE *buffer = NULL;
   1897    PK11SymKey *toBeHashed, *hashOutput;
   1898    PK11SymKey *newSharedSecret = NULL;
   1899    PK11SymKey *oldIntermediateResult, *intermediateResult = NULL;
   1900 
   1901    if (sharedSecret == NULL) {
   1902        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1903        return NULL;
   1904    }
   1905 
   1906    switch (kdf) {
   1907        case CKD_SHA1_KDF:
   1908            HashLen = SHA1_LENGTH;
   1909            hashMechanism = CKM_SHA1_KEY_DERIVATION;
   1910            break;
   1911        case CKD_SHA224_KDF:
   1912            HashLen = SHA224_LENGTH;
   1913            hashMechanism = CKM_SHA224_KEY_DERIVATION;
   1914            break;
   1915        case CKD_SHA256_KDF:
   1916            HashLen = SHA256_LENGTH;
   1917            hashMechanism = CKM_SHA256_KEY_DERIVATION;
   1918            break;
   1919        case CKD_SHA384_KDF:
   1920            HashLen = SHA384_LENGTH;
   1921            hashMechanism = CKM_SHA384_KEY_DERIVATION;
   1922            break;
   1923        case CKD_SHA512_KDF:
   1924            HashLen = SHA512_LENGTH;
   1925            hashMechanism = CKM_SHA512_KEY_DERIVATION;
   1926            break;
   1927        default:
   1928            PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1929            return NULL;
   1930    }
   1931 
   1932    derivedKeySize = keySize;
   1933    if (derivedKeySize == 0) {
   1934        keyType = PK11_GetKeyType(target, keySize);
   1935        derivedKeySize = pk11_GetPredefinedKeyLength(keyType);
   1936        if (derivedKeySize == 0) {
   1937            derivedKeySize = HashLen;
   1938        }
   1939    }
   1940 
   1941    /* Check that key_len isn't too long.  The maximum key length could be
   1942     * greatly increased if the code below did not limit the 4-byte counter
   1943     * to a maximum value of 255. */
   1944    if (derivedKeySize > 254 * HashLen) {
   1945        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1946        return NULL;
   1947    }
   1948 
   1949    maxCounter = derivedKeySize / HashLen;
   1950    if (derivedKeySize > maxCounter * HashLen)
   1951        maxCounter++;
   1952 
   1953    if ((sharedData == NULL) || (sharedData->data == NULL))
   1954        SharedInfoLen = 0;
   1955    else
   1956        SharedInfoLen = sharedData->len;
   1957 
   1958    bufferLen = SharedInfoLen + 4;
   1959 
   1960    /* Populate buffer with Counter || sharedData
   1961     * where Counter is 0x00000001. */
   1962    buffer = (unsigned char *)PORT_Alloc(bufferLen);
   1963    if (buffer == NULL) {
   1964        PORT_SetError(SEC_ERROR_NO_MEMORY);
   1965        return NULL;
   1966    }
   1967 
   1968    buffer[0] = 0;
   1969    buffer[1] = 0;
   1970    buffer[2] = 0;
   1971    buffer[3] = 1;
   1972    if (SharedInfoLen > 0) {
   1973        PORT_Memcpy(&buffer[4], sharedData->data, SharedInfoLen);
   1974    }
   1975 
   1976    /* Look for a slot that supports the mechanisms needed
   1977     * to implement the ANSI X9.63 KDF as well as the
   1978     * target mechanism.
   1979     */
   1980    mechanismArray[0] = CKM_CONCATENATE_BASE_AND_DATA;
   1981    mechanismArray[1] = hashMechanism;
   1982    mechanismArray[2] = CKM_CONCATENATE_BASE_AND_KEY;
   1983    mechanismArray[3] = target;
   1984 
   1985    newSharedSecret = pk11_ForceSlotMultiple(sharedSecret,
   1986                                             mechanismArray, 4, operation);
   1987    if (newSharedSecret != NULL) {
   1988        sharedSecret = newSharedSecret;
   1989    }
   1990 
   1991    for (counter = 1; counter <= maxCounter; counter++) {
   1992        /* Concatenate shared_secret and buffer */
   1993        toBeHashed = pk11_ConcatenateBaseAndData(sharedSecret, buffer,
   1994                                                 bufferLen, hashMechanism, operation);
   1995        if (toBeHashed == NULL) {
   1996            goto loser;
   1997        }
   1998 
   1999        /* Hash value */
   2000        if (maxCounter == 1) {
   2001            /* In this case the length of the key to be derived is
   2002             * less than or equal to the length of the hash output.
   2003             * So, the output of the hash operation will be the
   2004             * dervied key. */
   2005            hashOutput = pk11_HashKeyDerivation(toBeHashed, hashMechanism,
   2006                                                target, operation, keySize);
   2007        } else {
   2008            /* In this case, the output of the hash operation will be
   2009             * concatenated with other data to create the derived key. */
   2010            hashOutput = pk11_HashKeyDerivation(toBeHashed, hashMechanism,
   2011                                                CKM_CONCATENATE_BASE_AND_KEY, operation, 0);
   2012        }
   2013        PK11_FreeSymKey(toBeHashed);
   2014        if (hashOutput == NULL) {
   2015            goto loser;
   2016        }
   2017 
   2018        /* Append result to intermediate result, if necessary */
   2019        oldIntermediateResult = intermediateResult;
   2020 
   2021        if (oldIntermediateResult == NULL) {
   2022            intermediateResult = hashOutput;
   2023        } else {
   2024            if (counter == maxCounter) {
   2025                /* This is the final concatenation, and so the output
   2026                 * will be the derived key. */
   2027                intermediateResult =
   2028                    pk11_ConcatenateBaseAndKey(oldIntermediateResult,
   2029                                               hashOutput, target, operation, keySize);
   2030            } else {
   2031                /* The output of this concatenation will be concatenated
   2032                 * with other data to create the derived key. */
   2033                intermediateResult =
   2034                    pk11_ConcatenateBaseAndKey(oldIntermediateResult,
   2035                                               hashOutput, CKM_CONCATENATE_BASE_AND_KEY,
   2036                                               operation, 0);
   2037            }
   2038 
   2039            PK11_FreeSymKey(hashOutput);
   2040            PK11_FreeSymKey(oldIntermediateResult);
   2041            if (intermediateResult == NULL) {
   2042                goto loser;
   2043            }
   2044        }
   2045 
   2046        /* Increment counter (assumes maxCounter < 255) */
   2047        buffer[3]++;
   2048    }
   2049 
   2050    PORT_ZFree(buffer, bufferLen);
   2051    if (newSharedSecret != NULL)
   2052        PK11_FreeSymKey(newSharedSecret);
   2053    return intermediateResult;
   2054 
   2055 loser:
   2056    PORT_ZFree(buffer, bufferLen);
   2057    if (newSharedSecret != NULL)
   2058        PK11_FreeSymKey(newSharedSecret);
   2059    if (intermediateResult != NULL)
   2060        PK11_FreeSymKey(intermediateResult);
   2061    return NULL;
   2062 }
   2063 
   2064 /*
   2065 * This regenerate a public key from a private key. This function is currently
   2066 * NSS private. If we want to make it public, we need to add and optional
   2067 * template or at least flags (a.la. PK11_DeriveWithFlags).
   2068 */
   2069 CK_OBJECT_HANDLE
   2070 PK11_DerivePubKeyFromPrivKey(SECKEYPrivateKey *privKey)
   2071 {
   2072    PK11SlotInfo *slot = privKey->pkcs11Slot;
   2073    CK_MECHANISM mechanism;
   2074    CK_OBJECT_HANDLE objectID = CK_INVALID_HANDLE;
   2075    CK_RV crv;
   2076 
   2077    mechanism.mechanism = CKM_NSS_PUB_FROM_PRIV;
   2078    mechanism.pParameter = NULL;
   2079    mechanism.ulParameterLen = 0;
   2080 
   2081    PK11_EnterSlotMonitor(slot);
   2082    crv = PK11_GETTAB(slot)->C_DeriveKey(slot->session, &mechanism,
   2083                                         privKey->pkcs11ID, NULL, 0,
   2084                                         &objectID);
   2085    PK11_ExitSlotMonitor(slot);
   2086    if (crv != CKR_OK) {
   2087        PORT_SetError(PK11_MapError(crv));
   2088        return CK_INVALID_HANDLE;
   2089    }
   2090    return objectID;
   2091 }
   2092 
   2093 /*
   2094 * This Generates a wrapping key based on a privateKey, publicKey, and two
   2095 * random numbers. For Mail usage RandomB should be NULL. In the Sender's
   2096 * case RandomA is generate, otherwise it is passed.
   2097 */
   2098 PK11SymKey *
   2099 PK11_PubDerive(SECKEYPrivateKey *privKey, SECKEYPublicKey *pubKey,
   2100               PRBool isSender, SECItem *randomA, SECItem *randomB,
   2101               CK_MECHANISM_TYPE derive, CK_MECHANISM_TYPE target,
   2102               CK_ATTRIBUTE_TYPE operation, int keySize, void *wincx)
   2103 {
   2104    PK11SlotInfo *slot = privKey->pkcs11Slot;
   2105    CK_MECHANISM mechanism;
   2106    PK11SymKey *symKey;
   2107    CK_RV crv;
   2108 
   2109    /* get our key Structure */
   2110    symKey = pk11_CreateSymKey(slot, target, PR_TRUE, PR_TRUE, wincx);
   2111    if (symKey == NULL) {
   2112        return NULL;
   2113    }
   2114 
   2115    /* CKA_NSS_MESSAGE is a fake operation to distinguish between
   2116     * Normal Encrypt/Decrypt and MessageEncrypt/Decrypt. Don't try to set
   2117     * it as a real attribute */
   2118    if ((operation & CKA_NSS_MESSAGE_MASK) == CKA_NSS_MESSAGE) {
   2119        /* Message is or'd with a real Attribute (CKA_ENCRYPT, CKA_DECRYPT),
   2120         * etc. Strip out the real attribute here */
   2121        operation &= ~CKA_NSS_MESSAGE_MASK;
   2122    }
   2123 
   2124    symKey->origin = PK11_OriginDerive;
   2125 
   2126    switch (privKey->keyType) {
   2127        case keaKey:
   2128        case fortezzaKey: {
   2129            static unsigned char rb_email[128] = { 0 };
   2130            CK_KEA_DERIVE_PARAMS param;
   2131            param.isSender = (CK_BBOOL)isSender;
   2132            param.ulRandomLen = randomA->len;
   2133            param.pRandomA = randomA->data;
   2134            param.pRandomB = rb_email;
   2135            param.pRandomB[127] = 1;
   2136            if (randomB)
   2137                param.pRandomB = randomB->data;
   2138            if (pubKey->keyType == fortezzaKey) {
   2139                param.ulPublicDataLen = pubKey->u.fortezza.KEAKey.len;
   2140                param.pPublicData = pubKey->u.fortezza.KEAKey.data;
   2141            } else {
   2142                /* assert type == keaKey */
   2143                /* XXX change to match key key types */
   2144                param.ulPublicDataLen = pubKey->u.fortezza.KEAKey.len;
   2145                param.pPublicData = pubKey->u.fortezza.KEAKey.data;
   2146            }
   2147 
   2148            mechanism.mechanism = derive;
   2149            mechanism.pParameter = &param;
   2150            mechanism.ulParameterLen = sizeof(param);
   2151 
   2152            /* get a new symKey structure */
   2153            pk11_EnterKeyMonitor(symKey);
   2154            crv = PK11_GETTAB(slot)->C_DeriveKey(symKey->session, &mechanism,
   2155                                                 privKey->pkcs11ID, NULL, 0,
   2156                                                 &symKey->objectID);
   2157            pk11_ExitKeyMonitor(symKey);
   2158            if (crv == CKR_OK)
   2159                return symKey;
   2160            PORT_SetError(PK11_MapError(crv));
   2161        } break;
   2162        case dhKey: {
   2163            CK_BBOOL cktrue = CK_TRUE;
   2164            CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY;
   2165            CK_KEY_TYPE keyType = CKK_GENERIC_SECRET;
   2166            CK_ULONG key_size = 0;
   2167            CK_ATTRIBUTE keyTemplate[4];
   2168            int templateCount;
   2169            CK_ATTRIBUTE *attrs = keyTemplate;
   2170 
   2171            if (pubKey->keyType != dhKey) {
   2172                PORT_SetError(SEC_ERROR_BAD_KEY);
   2173                break;
   2174            }
   2175 
   2176            PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass));
   2177            attrs++;
   2178            PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType));
   2179            attrs++;
   2180            PK11_SETATTRS(attrs, operation, &cktrue, 1);
   2181            attrs++;
   2182            PK11_SETATTRS(attrs, CKA_VALUE_LEN, &key_size, sizeof(key_size));
   2183            attrs++;
   2184            templateCount = attrs - keyTemplate;
   2185            PR_ASSERT(templateCount <= sizeof(keyTemplate) / sizeof(CK_ATTRIBUTE));
   2186 
   2187            keyType = PK11_GetKeyType(target, keySize);
   2188            key_size = keySize;
   2189            symKey->size = keySize;
   2190            if (key_size == 0)
   2191                templateCount--;
   2192 
   2193            mechanism.mechanism = derive;
   2194 
   2195            /* we can undefine these when we define diffie-helman keys */
   2196 
   2197            mechanism.pParameter = pubKey->u.dh.publicValue.data;
   2198            mechanism.ulParameterLen = pubKey->u.dh.publicValue.len;
   2199 
   2200            pk11_EnterKeyMonitor(symKey);
   2201            crv = PK11_GETTAB(slot)->C_DeriveKey(symKey->session, &mechanism,
   2202                                                 privKey->pkcs11ID, keyTemplate,
   2203                                                 templateCount, &symKey->objectID);
   2204            pk11_ExitKeyMonitor(symKey);
   2205            if (crv == CKR_OK)
   2206                return symKey;
   2207            PORT_SetError(PK11_MapError(crv));
   2208        } break;
   2209        case ecKey: {
   2210            CK_BBOOL cktrue = CK_TRUE;
   2211            CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY;
   2212            CK_KEY_TYPE keyType = CKK_GENERIC_SECRET;
   2213            CK_ULONG key_size = 0;
   2214            CK_ATTRIBUTE keyTemplate[4];
   2215            int templateCount;
   2216            CK_ATTRIBUTE *attrs = keyTemplate;
   2217            CK_ECDH1_DERIVE_PARAMS *mechParams = NULL;
   2218 
   2219            if (pubKey->keyType != ecKey) {
   2220                PORT_SetError(SEC_ERROR_BAD_KEY);
   2221                break;
   2222            }
   2223 
   2224            PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass));
   2225            attrs++;
   2226            PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType));
   2227            attrs++;
   2228            PK11_SETATTRS(attrs, operation, &cktrue, 1);
   2229            attrs++;
   2230            PK11_SETATTRS(attrs, CKA_VALUE_LEN, &key_size, sizeof(key_size));
   2231            attrs++;
   2232            templateCount = attrs - keyTemplate;
   2233            PR_ASSERT(templateCount <= sizeof(keyTemplate) / sizeof(CK_ATTRIBUTE));
   2234 
   2235            keyType = PK11_GetKeyType(target, keySize);
   2236            key_size = keySize;
   2237            if (key_size == 0) {
   2238                if ((key_size = pk11_GetPredefinedKeyLength(keyType))) {
   2239                    templateCount--;
   2240                } else {
   2241                    /* sigh, some tokens can't figure this out and require
   2242                     * CKA_VALUE_LEN to be set */
   2243                    key_size = SHA1_LENGTH;
   2244                }
   2245            }
   2246            symKey->size = key_size;
   2247 
   2248            mechParams = PORT_ZNew(CK_ECDH1_DERIVE_PARAMS);
   2249            mechParams->kdf = CKD_SHA1_KDF;
   2250            mechParams->ulSharedDataLen = 0;
   2251            mechParams->pSharedData = NULL;
   2252            mechParams->ulPublicDataLen = pubKey->u.ec.publicValue.len;
   2253            mechParams->pPublicData = pubKey->u.ec.publicValue.data;
   2254 
   2255            mechanism.mechanism = derive;
   2256            mechanism.pParameter = mechParams;
   2257            mechanism.ulParameterLen = sizeof(CK_ECDH1_DERIVE_PARAMS);
   2258 
   2259            pk11_EnterKeyMonitor(symKey);
   2260            crv = PK11_GETTAB(slot)->C_DeriveKey(symKey->session,
   2261                                                 &mechanism, privKey->pkcs11ID, keyTemplate,
   2262                                                 templateCount, &symKey->objectID);
   2263            pk11_ExitKeyMonitor(symKey);
   2264 
   2265            /* old PKCS #11 spec was ambiguous on what needed to be passed,
   2266             * try this again with and encoded public key */
   2267            if (crv != CKR_OK && pk11_ECGetPubkeyEncoding(pubKey) != ECPoint_XOnly) {
   2268                SECItem *pubValue = SEC_ASN1EncodeItem(NULL, NULL,
   2269                                                       &pubKey->u.ec.publicValue,
   2270                                                       SEC_ASN1_GET(SEC_OctetStringTemplate));
   2271                if (pubValue == NULL) {
   2272                    PORT_ZFree(mechParams, sizeof(CK_ECDH1_DERIVE_PARAMS));
   2273                    break;
   2274                }
   2275                mechParams->ulPublicDataLen = pubValue->len;
   2276                mechParams->pPublicData = pubValue->data;
   2277 
   2278                pk11_EnterKeyMonitor(symKey);
   2279                crv = PK11_GETTAB(slot)->C_DeriveKey(symKey->session,
   2280                                                     &mechanism, privKey->pkcs11ID, keyTemplate,
   2281                                                     templateCount, &symKey->objectID);
   2282                pk11_ExitKeyMonitor(symKey);
   2283 
   2284                SECITEM_FreeItem(pubValue, PR_TRUE);
   2285            }
   2286 
   2287            PORT_ZFree(mechParams, sizeof(CK_ECDH1_DERIVE_PARAMS));
   2288 
   2289            if (crv == CKR_OK)
   2290                return symKey;
   2291            PORT_SetError(PK11_MapError(crv));
   2292        }
   2293        /* most keys are not KEA keys, so assume they are bad if they
   2294         * are not handled explicitly */
   2295        default:
   2296            PORT_SetError(SEC_ERROR_BAD_KEY);
   2297            break;
   2298    }
   2299 
   2300    PK11_FreeSymKey(symKey);
   2301    return NULL;
   2302 }
   2303 
   2304 /* Test for curves that are known to use a special encoding.
   2305 * Extend this function when additional curves are added. */
   2306 static ECPointEncoding
   2307 pk11_ECGetPubkeyEncoding(const SECKEYPublicKey *pubKey)
   2308 {
   2309    SECItem oid;
   2310    SECStatus rv;
   2311    PORTCheapArenaPool tmpArena;
   2312    ECPointEncoding encoding = ECPoint_Undefined;
   2313 
   2314    PORT_InitCheapArena(&tmpArena, DER_DEFAULT_CHUNKSIZE);
   2315 
   2316    /* decode the OID tag */
   2317    rv = SEC_QuickDERDecodeItem(&tmpArena.arena, &oid,
   2318                                SEC_ASN1_GET(SEC_ObjectIDTemplate),
   2319                                &pubKey->u.ec.DEREncodedParams);
   2320    if (rv == SECSuccess) {
   2321        SECOidTag tag = SECOID_FindOIDTag(&oid);
   2322        switch (tag) {
   2323            case SEC_OID_X25519:
   2324            case SEC_OID_CURVE25519:
   2325                encoding = ECPoint_XOnly;
   2326                break;
   2327            case SEC_OID_SECG_EC_SECP256R1:
   2328            case SEC_OID_SECG_EC_SECP384R1:
   2329            case SEC_OID_SECG_EC_SECP521R1:
   2330            default:
   2331                /* unknown curve, default to uncompressed */
   2332                encoding = ECPoint_Uncompressed;
   2333        }
   2334    }
   2335    PORT_DestroyCheapArena(&tmpArena);
   2336    return encoding;
   2337 }
   2338 
   2339 /* Returns the size of the public key, or 0 if there
   2340 * is an error. */
   2341 static CK_ULONG
   2342 pk11_ECPubKeySize(SECKEYPublicKey *pubKey)
   2343 {
   2344    SECItem *publicValue = &pubKey->u.ec.publicValue;
   2345 
   2346    ECPointEncoding encoding = pk11_ECGetPubkeyEncoding(pubKey);
   2347    if (encoding == ECPoint_XOnly) {
   2348        return publicValue->len;
   2349    }
   2350    if (encoding == ECPoint_Uncompressed) {
   2351        /* key encoded in uncompressed form */
   2352        return ((publicValue->len - 1) / 2);
   2353    }
   2354    /* key encoding not recognized */
   2355    return 0;
   2356 }
   2357 
   2358 static PK11SymKey *
   2359 pk11_PubDeriveECKeyWithKDF(
   2360    SECKEYPrivateKey *privKey, SECKEYPublicKey *pubKey,
   2361    PRBool isSender, SECItem *randomA, SECItem *randomB,
   2362    CK_MECHANISM_TYPE derive, CK_MECHANISM_TYPE target,
   2363    CK_ATTRIBUTE_TYPE operation, int keySize,
   2364    CK_ULONG kdf, SECItem *sharedData, void *wincx)
   2365 {
   2366    PK11SlotInfo *slot = privKey->pkcs11Slot;
   2367    PK11SymKey *symKey;
   2368    PK11SymKey *SharedSecret;
   2369    CK_MECHANISM mechanism;
   2370    CK_RV crv;
   2371    CK_BBOOL cktrue = CK_TRUE;
   2372    CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY;
   2373    CK_KEY_TYPE keyType = CKK_GENERIC_SECRET;
   2374    CK_ULONG key_size = 0;
   2375    CK_ATTRIBUTE keyTemplate[4];
   2376    int templateCount;
   2377    CK_ATTRIBUTE *attrs = keyTemplate;
   2378    CK_ECDH1_DERIVE_PARAMS *mechParams = NULL;
   2379 
   2380    if (pubKey->keyType != ecKey && pubKey->keyType != ecMontKey) {
   2381        PORT_SetError(SEC_ERROR_BAD_KEY);
   2382        return NULL;
   2383    }
   2384    if ((kdf != CKD_NULL) && (kdf != CKD_SHA1_KDF) &&
   2385        (kdf != CKD_SHA224_KDF) && (kdf != CKD_SHA256_KDF) &&
   2386        (kdf != CKD_SHA384_KDF) && (kdf != CKD_SHA512_KDF)) {
   2387        PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
   2388        return NULL;
   2389    }
   2390 
   2391    /* get our key Structure */
   2392    symKey = pk11_CreateSymKey(slot, target, PR_TRUE, PR_TRUE, wincx);
   2393    if (symKey == NULL) {
   2394        return NULL;
   2395    }
   2396    /* CKA_NSS_MESSAGE is a fake operation to distinguish between
   2397     * Normal Encrypt/Decrypt and MessageEncrypt/Decrypt. Don't try to set
   2398     * it as a real attribute */
   2399    if ((operation & CKA_NSS_MESSAGE_MASK) == CKA_NSS_MESSAGE) {
   2400        /* Message is or'd with a real Attribute (CKA_ENCRYPT, CKA_DECRYPT),
   2401         * etc. Strip out the real attribute here */
   2402        operation &= ~CKA_NSS_MESSAGE_MASK;
   2403    }
   2404 
   2405    symKey->origin = PK11_OriginDerive;
   2406 
   2407    PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass));
   2408    attrs++;
   2409    PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType));
   2410    attrs++;
   2411    PK11_SETATTRS(attrs, operation, &cktrue, 1);
   2412    attrs++;
   2413    PK11_SETATTRS(attrs, CKA_VALUE_LEN, &key_size, sizeof(key_size));
   2414    attrs++;
   2415    templateCount = attrs - keyTemplate;
   2416    PR_ASSERT(templateCount <= sizeof(keyTemplate) / sizeof(CK_ATTRIBUTE));
   2417 
   2418    keyType = PK11_GetKeyType(target, keySize);
   2419    key_size = keySize;
   2420    if (key_size == 0) {
   2421        if ((key_size = pk11_GetPredefinedKeyLength(keyType))) {
   2422            templateCount--;
   2423        } else {
   2424            /* sigh, some tokens can't figure this out and require
   2425             * CKA_VALUE_LEN to be set */
   2426            switch (kdf) {
   2427                case CKD_NULL:
   2428                    key_size = pk11_ECPubKeySize(pubKey);
   2429                    if (key_size == 0) {
   2430                        PK11_FreeSymKey(symKey);
   2431                        return NULL;
   2432                    }
   2433                    break;
   2434                case CKD_SHA1_KDF:
   2435                    key_size = SHA1_LENGTH;
   2436                    break;
   2437                case CKD_SHA224_KDF:
   2438                    key_size = SHA224_LENGTH;
   2439                    break;
   2440                case CKD_SHA256_KDF:
   2441                    key_size = SHA256_LENGTH;
   2442                    break;
   2443                case CKD_SHA384_KDF:
   2444                    key_size = SHA384_LENGTH;
   2445                    break;
   2446                case CKD_SHA512_KDF:
   2447                    key_size = SHA512_LENGTH;
   2448                    break;
   2449                default:
   2450                    PORT_AssertNotReached("Invalid CKD");
   2451                    PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
   2452                    PK11_FreeSymKey(symKey);
   2453                    return NULL;
   2454            }
   2455        }
   2456    }
   2457    symKey->size = key_size;
   2458 
   2459    mechParams = PORT_ZNew(CK_ECDH1_DERIVE_PARAMS);
   2460    if (!mechParams) {
   2461        PK11_FreeSymKey(symKey);
   2462        return NULL;
   2463    }
   2464    mechParams->kdf = kdf;
   2465    if (sharedData == NULL) {
   2466        mechParams->ulSharedDataLen = 0;
   2467        mechParams->pSharedData = NULL;
   2468    } else {
   2469        mechParams->ulSharedDataLen = sharedData->len;
   2470        mechParams->pSharedData = sharedData->data;
   2471    }
   2472    mechParams->ulPublicDataLen = pubKey->u.ec.publicValue.len;
   2473    mechParams->pPublicData = pubKey->u.ec.publicValue.data;
   2474 
   2475    mechanism.mechanism = derive;
   2476    mechanism.pParameter = mechParams;
   2477    mechanism.ulParameterLen = sizeof(CK_ECDH1_DERIVE_PARAMS);
   2478 
   2479    pk11_EnterKeyMonitor(symKey);
   2480    crv = PK11_GETTAB(slot)->C_DeriveKey(symKey->session, &mechanism,
   2481                                         privKey->pkcs11ID, keyTemplate,
   2482                                         templateCount, &symKey->objectID);
   2483    pk11_ExitKeyMonitor(symKey);
   2484 
   2485    /* old PKCS #11 spec was ambiguous on what needed to be passed,
   2486     * try this again with an encoded public key */
   2487    if (crv != CKR_OK) {
   2488        /* For curves that only use X as public value and no encoding we don't
   2489         * have to try again. (Currently only Curve25519) */
   2490        if (pk11_ECGetPubkeyEncoding(pubKey) == ECPoint_XOnly) {
   2491            goto loser;
   2492        }
   2493        SECItem *pubValue = SEC_ASN1EncodeItem(NULL, NULL,
   2494                                               &pubKey->u.ec.publicValue,
   2495                                               SEC_ASN1_GET(SEC_OctetStringTemplate));
   2496        if (pubValue == NULL) {
   2497            goto loser;
   2498        }
   2499        mechParams->ulPublicDataLen = pubValue->len;
   2500        mechParams->pPublicData = pubValue->data;
   2501 
   2502        pk11_EnterKeyMonitor(symKey);
   2503        crv = PK11_GETTAB(slot)->C_DeriveKey(symKey->session,
   2504                                             &mechanism, privKey->pkcs11ID, keyTemplate,
   2505                                             templateCount, &symKey->objectID);
   2506        pk11_ExitKeyMonitor(symKey);
   2507 
   2508        if ((crv != CKR_OK) && (kdf != CKD_NULL)) {
   2509            /* Some PKCS #11 libraries cannot perform the key derivation
   2510             * function. So, try calling C_DeriveKey with CKD_NULL and then
   2511             * performing the KDF separately.
   2512             */
   2513            CK_ULONG derivedKeySize = key_size;
   2514 
   2515            keyType = CKK_GENERIC_SECRET;
   2516            key_size = pk11_ECPubKeySize(pubKey);
   2517            if (key_size == 0) {
   2518                SECITEM_FreeItem(pubValue, PR_TRUE);
   2519                goto loser;
   2520            }
   2521            SharedSecret = symKey;
   2522            SharedSecret->size = key_size;
   2523 
   2524            mechParams->kdf = CKD_NULL;
   2525            mechParams->ulSharedDataLen = 0;
   2526            mechParams->pSharedData = NULL;
   2527            mechParams->ulPublicDataLen = pubKey->u.ec.publicValue.len;
   2528            mechParams->pPublicData = pubKey->u.ec.publicValue.data;
   2529 
   2530            pk11_EnterKeyMonitor(SharedSecret);
   2531            crv = PK11_GETTAB(slot)->C_DeriveKey(SharedSecret->session,
   2532                                                 &mechanism, privKey->pkcs11ID, keyTemplate,
   2533                                                 templateCount, &SharedSecret->objectID);
   2534            pk11_ExitKeyMonitor(SharedSecret);
   2535 
   2536            if (crv != CKR_OK) {
   2537                /* old PKCS #11 spec was ambiguous on what needed to be passed,
   2538                 * try this one final time with an encoded public key */
   2539                mechParams->ulPublicDataLen = pubValue->len;
   2540                mechParams->pPublicData = pubValue->data;
   2541 
   2542                pk11_EnterKeyMonitor(SharedSecret);
   2543                crv = PK11_GETTAB(slot)->C_DeriveKey(SharedSecret->session,
   2544                                                     &mechanism, privKey->pkcs11ID, keyTemplate,
   2545                                                     templateCount, &SharedSecret->objectID);
   2546                pk11_ExitKeyMonitor(SharedSecret);
   2547            }
   2548 
   2549            /* Perform KDF. */
   2550            if (crv == CKR_OK) {
   2551                symKey = pk11_ANSIX963Derive(SharedSecret, kdf,
   2552                                             sharedData, target, operation,
   2553                                             derivedKeySize);
   2554                PK11_FreeSymKey(SharedSecret);
   2555                if (symKey == NULL) {
   2556                    SECITEM_FreeItem(pubValue, PR_TRUE);
   2557                    PORT_ZFree(mechParams, sizeof(CK_ECDH1_DERIVE_PARAMS));
   2558                    return NULL;
   2559                }
   2560            }
   2561        }
   2562        SECITEM_FreeItem(pubValue, PR_TRUE);
   2563    }
   2564 
   2565 loser:
   2566    PORT_ZFree(mechParams, sizeof(CK_ECDH1_DERIVE_PARAMS));
   2567 
   2568    if (crv != CKR_OK) {
   2569        PK11_FreeSymKey(symKey);
   2570        symKey = NULL;
   2571        PORT_SetError(PK11_MapError(crv));
   2572    }
   2573    return symKey;
   2574 }
   2575 
   2576 PK11SymKey *
   2577 PK11_PubDeriveWithKDF(SECKEYPrivateKey *privKey, SECKEYPublicKey *pubKey,
   2578                      PRBool isSender, SECItem *randomA, SECItem *randomB,
   2579                      CK_MECHANISM_TYPE derive, CK_MECHANISM_TYPE target,
   2580                      CK_ATTRIBUTE_TYPE operation, int keySize,
   2581                      CK_ULONG kdf, SECItem *sharedData, void *wincx)
   2582 {
   2583 
   2584    switch (privKey->keyType) {
   2585        case keaKey:
   2586        case fortezzaKey:
   2587        case dhKey:
   2588            return PK11_PubDerive(privKey, pubKey, isSender, randomA, randomB,
   2589                                  derive, target, operation, keySize, wincx);
   2590        case ecKey:
   2591        case ecMontKey:
   2592            return pk11_PubDeriveECKeyWithKDF(privKey, pubKey, isSender,
   2593                                              randomA, randomB, derive, target,
   2594                                              operation, keySize,
   2595                                              kdf, sharedData, wincx);
   2596        default:
   2597            PORT_SetError(SEC_ERROR_BAD_KEY);
   2598            break;
   2599    }
   2600 
   2601    return NULL;
   2602 }
   2603 
   2604 /*
   2605 * this little function uses the Decrypt function to unwrap a key, just in
   2606 * case we are having problem with unwrap. NOTE: The key size may
   2607 * not be preserved properly for some algorithms!
   2608 */
   2609 static PK11SymKey *
   2610 pk11_HandUnwrap(PK11SlotInfo *slot, CK_OBJECT_HANDLE wrappingKey,
   2611                CK_MECHANISM *mech, SECItem *inKey, CK_MECHANISM_TYPE target,
   2612                CK_ATTRIBUTE *keyTemplate, unsigned int templateCount,
   2613                int key_size, void *wincx, CK_RV *crvp, PRBool isPerm)
   2614 {
   2615    CK_ULONG len;
   2616    SECItem outKey;
   2617    PK11SymKey *symKey;
   2618    CK_RV crv;
   2619    PRBool owner = PR_TRUE;
   2620    CK_SESSION_HANDLE session;
   2621 
   2622    /* remove any VALUE_LEN parameters */
   2623    if (keyTemplate[templateCount - 1].type == CKA_VALUE_LEN) {
   2624        templateCount--;
   2625    }
   2626 
   2627    /* keys are almost always aligned, but if we get this far,
   2628     * we've gone above and beyond anyway... */
   2629    outKey.data = (unsigned char *)PORT_Alloc(inKey->len);
   2630    if (outKey.data == NULL) {
   2631        PORT_SetError(SEC_ERROR_NO_MEMORY);
   2632        if (crvp)
   2633            *crvp = CKR_HOST_MEMORY;
   2634        return NULL;
   2635    }
   2636    len = inKey->len;
   2637 
   2638    /* use NULL IV's for wrapping */
   2639    session = pk11_GetNewSession(slot, &owner);
   2640    if (!owner || !(slot->isThreadSafe))
   2641        PK11_EnterSlotMonitor(slot);
   2642    crv = PK11_GETTAB(slot)->C_DecryptInit(session, mech, wrappingKey);
   2643    if (crv != CKR_OK) {
   2644        if (!owner || !(slot->isThreadSafe))
   2645            PK11_ExitSlotMonitor(slot);
   2646        pk11_CloseSession(slot, session, owner);
   2647        PORT_Free(outKey.data);
   2648        PORT_SetError(PK11_MapError(crv));
   2649        if (crvp)
   2650            *crvp = crv;
   2651        return NULL;
   2652    }
   2653    crv = PK11_GETTAB(slot)->C_Decrypt(session, inKey->data, inKey->len,
   2654                                       outKey.data, &len);
   2655    if (!owner || !(slot->isThreadSafe))
   2656        PK11_ExitSlotMonitor(slot);
   2657    pk11_CloseSession(slot, session, owner);
   2658    if (crv != CKR_OK) {
   2659        PORT_Free(outKey.data);
   2660        PORT_SetError(PK11_MapError(crv));
   2661        if (crvp)
   2662            *crvp = crv;
   2663        return NULL;
   2664    }
   2665 
   2666    outKey.len = (key_size == 0) ? len : key_size;
   2667    outKey.type = siBuffer;
   2668 
   2669    if (PK11_DoesMechanism(slot, target)) {
   2670        symKey = pk11_ImportSymKeyWithTempl(slot, target, PK11_OriginUnwrap,
   2671                                            isPerm, keyTemplate,
   2672                                            templateCount, &outKey, wincx);
   2673    } else {
   2674        slot = PK11_GetBestSlot(target, wincx);
   2675        if (slot == NULL) {
   2676            PORT_SetError(SEC_ERROR_NO_MODULE);
   2677            PORT_Free(outKey.data);
   2678            if (crvp)
   2679                *crvp = CKR_DEVICE_ERROR;
   2680            return NULL;
   2681        }
   2682        symKey = pk11_ImportSymKeyWithTempl(slot, target, PK11_OriginUnwrap,
   2683                                            isPerm, keyTemplate,
   2684                                            templateCount, &outKey, wincx);
   2685        PK11_FreeSlot(slot);
   2686    }
   2687    PORT_Free(outKey.data);
   2688 
   2689    if (crvp)
   2690        *crvp = symKey ? CKR_OK : CKR_DEVICE_ERROR;
   2691    return symKey;
   2692 }
   2693 
   2694 /*
   2695 * The wrap/unwrap function is pretty much the same for private and
   2696 * public keys. It's just getting the Object ID and slot right. This is
   2697 * the combined unwrap function.
   2698 */
   2699 static PK11SymKey *
   2700 pk11_AnyUnwrapKey(PK11SlotInfo *slot, CK_OBJECT_HANDLE wrappingKey,
   2701                  CK_MECHANISM_TYPE wrapType, SECItem *param, SECItem *wrappedKey,
   2702                  CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation, int keySize,
   2703                  void *wincx, CK_ATTRIBUTE *userAttr, unsigned int numAttrs, PRBool isPerm)
   2704 {
   2705    PK11SymKey *symKey;
   2706    SECItem *param_free = NULL;
   2707    CK_BBOOL cktrue = CK_TRUE;
   2708    CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY;
   2709    CK_KEY_TYPE keyType = CKK_GENERIC_SECRET;
   2710    CK_ULONG valueLen = 0;
   2711    CK_MECHANISM mechanism;
   2712    CK_SESSION_HANDLE rwsession;
   2713    CK_RV crv;
   2714    CK_MECHANISM_INFO mechanism_info;
   2715 #define MAX_ADD_ATTRS 4
   2716    CK_ATTRIBUTE keyTemplate[MAX_TEMPL_ATTRS + MAX_ADD_ATTRS];
   2717 #undef MAX_ADD_ATTRS
   2718    CK_ATTRIBUTE *attrs = keyTemplate;
   2719    unsigned int templateCount;
   2720 
   2721    if (numAttrs > MAX_TEMPL_ATTRS) {
   2722        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   2723        return NULL;
   2724    }
   2725    /* CKA_NSS_MESSAGE is a fake operation to distinguish between
   2726     * Normal Encrypt/Decrypt and MessageEncrypt/Decrypt. Don't try to set
   2727     * it as a real attribute */
   2728    if ((operation & CKA_NSS_MESSAGE_MASK) == CKA_NSS_MESSAGE) {
   2729        /* Message is or'd with a real Attribute (CKA_ENCRYPT, CKA_DECRYPT),
   2730         * etc. Strip out the real attribute here */
   2731        operation &= ~CKA_NSS_MESSAGE_MASK;
   2732    }
   2733 
   2734    /* first copy caller attributes in. */
   2735    for (templateCount = 0; templateCount < numAttrs; ++templateCount) {
   2736        *attrs++ = *userAttr++;
   2737    }
   2738 
   2739    /* We only add the following attributes to the template if the caller
   2740    ** didn't already supply them.
   2741    */
   2742    if (!pk11_FindAttrInTemplate(keyTemplate, numAttrs, CKA_CLASS)) {
   2743        PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof keyClass);
   2744        attrs++;
   2745    }
   2746    if (!pk11_FindAttrInTemplate(keyTemplate, numAttrs, CKA_KEY_TYPE)) {
   2747        keyType = PK11_GetKeyType(target, keySize);
   2748        PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof keyType);
   2749        attrs++;
   2750    }
   2751    if ((operation != CKA_FLAGS_ONLY) &&
   2752        !pk11_FindAttrInTemplate(keyTemplate, numAttrs, operation)) {
   2753        PK11_SETATTRS(attrs, operation, &cktrue, 1);
   2754        attrs++;
   2755    }
   2756 
   2757    /*
   2758     * must be last in case we need to use this template to import the key
   2759     */
   2760    if (keySize > 0 &&
   2761        !pk11_FindAttrInTemplate(keyTemplate, numAttrs, CKA_VALUE_LEN)) {
   2762        valueLen = (CK_ULONG)keySize;
   2763        PK11_SETATTRS(attrs, CKA_VALUE_LEN, &valueLen, sizeof valueLen);
   2764        attrs++;
   2765    }
   2766 
   2767    templateCount = attrs - keyTemplate;
   2768    PR_ASSERT(templateCount <= sizeof(keyTemplate) / sizeof(CK_ATTRIBUTE));
   2769 
   2770    /* find out if we can do wrap directly. Because the RSA case if *very*
   2771     * common, cache the results for it. */
   2772    if ((wrapType == CKM_RSA_PKCS) && (slot->hasRSAInfo)) {
   2773        mechanism_info.flags = slot->RSAInfoFlags;
   2774    } else {
   2775        if (!slot->isThreadSafe)
   2776            PK11_EnterSlotMonitor(slot);
   2777        crv = PK11_GETTAB(slot)->C_GetMechanismInfo(slot->slotID, wrapType,
   2778                                                    &mechanism_info);
   2779        if (!slot->isThreadSafe)
   2780            PK11_ExitSlotMonitor(slot);
   2781        if (crv != CKR_OK) {
   2782            mechanism_info.flags = 0;
   2783        }
   2784        if (wrapType == CKM_RSA_PKCS) {
   2785            slot->RSAInfoFlags = mechanism_info.flags;
   2786            slot->hasRSAInfo = PR_TRUE;
   2787        }
   2788    }
   2789 
   2790    /* initialize the mechanism structure */
   2791    mechanism.mechanism = wrapType;
   2792    /* use NULL IV's for wrapping */
   2793    if (param == NULL)
   2794        param = param_free = PK11_ParamFromIV(wrapType, NULL);
   2795    if (param) {
   2796        mechanism.pParameter = param->data;
   2797        mechanism.ulParameterLen = param->len;
   2798    } else {
   2799        mechanism.pParameter = NULL;
   2800        mechanism.ulParameterLen = 0;
   2801    }
   2802 
   2803    if ((mechanism_info.flags & CKF_DECRYPT) && !PK11_DoesMechanism(slot, target)) {
   2804        symKey = pk11_HandUnwrap(slot, wrappingKey, &mechanism, wrappedKey,
   2805                                 target, keyTemplate, templateCount, keySize,
   2806                                 wincx, &crv, isPerm);
   2807        if (symKey) {
   2808            if (param_free)
   2809                SECITEM_FreeItem(param_free, PR_TRUE);
   2810            return symKey;
   2811        }
   2812        /*
   2813         * if the RSA OP simply failed, don't try to unwrap again
   2814         * with this module.
   2815         */
   2816        if (crv == CKR_DEVICE_ERROR) {
   2817            if (param_free)
   2818                SECITEM_FreeItem(param_free, PR_TRUE);
   2819            return NULL;
   2820        }
   2821        /* fall through, maybe they incorrectly set CKF_DECRYPT */
   2822    }
   2823 
   2824    /* get our key Structure */
   2825    symKey = pk11_CreateSymKey(slot, target, !isPerm, PR_TRUE, wincx);
   2826    if (symKey == NULL) {
   2827        if (param_free)
   2828            SECITEM_FreeItem(param_free, PR_TRUE);
   2829        return NULL;
   2830    }
   2831 
   2832    symKey->size = keySize;
   2833    symKey->origin = PK11_OriginUnwrap;
   2834 
   2835    if (isPerm) {
   2836        rwsession = PK11_GetRWSession(slot);
   2837    } else {
   2838        pk11_EnterKeyMonitor(symKey);
   2839        rwsession = symKey->session;
   2840    }
   2841    PORT_Assert(rwsession != CK_INVALID_HANDLE);
   2842    if (rwsession == CK_INVALID_HANDLE)
   2843        crv = CKR_SESSION_HANDLE_INVALID;
   2844    else
   2845        crv = PK11_GETTAB(slot)->C_UnwrapKey(rwsession, &mechanism, wrappingKey,
   2846                                             wrappedKey->data, wrappedKey->len,
   2847                                             keyTemplate, templateCount,
   2848                                             &symKey->objectID);
   2849    if (isPerm) {
   2850        if (rwsession != CK_INVALID_HANDLE)
   2851            PK11_RestoreROSession(slot, rwsession);
   2852    } else {
   2853        pk11_ExitKeyMonitor(symKey);
   2854    }
   2855    if (param_free)
   2856        SECITEM_FreeItem(param_free, PR_TRUE);
   2857    if (crv != CKR_OK) {
   2858        PK11_FreeSymKey(symKey);
   2859        symKey = NULL;
   2860        if (crv != CKR_DEVICE_ERROR) {
   2861            /* try hand Unwrapping */
   2862            symKey = pk11_HandUnwrap(slot, wrappingKey, &mechanism, wrappedKey,
   2863                                     target, keyTemplate, templateCount,
   2864                                     keySize, wincx, NULL, isPerm);
   2865        }
   2866    }
   2867 
   2868    return symKey;
   2869 }
   2870 
   2871 /* use a symetric key to unwrap another symetric key */
   2872 PK11SymKey *
   2873 PK11_UnwrapSymKey(PK11SymKey *wrappingKey, CK_MECHANISM_TYPE wrapType,
   2874                  SECItem *param, SECItem *wrappedKey,
   2875                  CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation,
   2876                  int keySize)
   2877 {
   2878    return pk11_AnyUnwrapKey(wrappingKey->slot, wrappingKey->objectID,
   2879                             wrapType, param, wrappedKey, target, operation, keySize,
   2880                             wrappingKey->cx, NULL, 0, PR_FALSE);
   2881 }
   2882 
   2883 /* use a symetric key to unwrap another symetric key */
   2884 PK11SymKey *
   2885 PK11_UnwrapSymKeyWithFlags(PK11SymKey *wrappingKey, CK_MECHANISM_TYPE wrapType,
   2886                           SECItem *param, SECItem *wrappedKey,
   2887                           CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation,
   2888                           int keySize, CK_FLAGS flags)
   2889 {
   2890    CK_BBOOL ckTrue = CK_TRUE;
   2891    CK_ATTRIBUTE keyTemplate[MAX_TEMPL_ATTRS];
   2892    unsigned int templateCount;
   2893 
   2894    templateCount = pk11_OpFlagsToAttributes(flags, keyTemplate, &ckTrue);
   2895    return pk11_AnyUnwrapKey(wrappingKey->slot, wrappingKey->objectID,
   2896                             wrapType, param, wrappedKey, target, operation, keySize,
   2897                             wrappingKey->cx, keyTemplate, templateCount, PR_FALSE);
   2898 }
   2899 
   2900 PK11SymKey *
   2901 PK11_UnwrapSymKeyWithFlagsPerm(PK11SymKey *wrappingKey,
   2902                               CK_MECHANISM_TYPE wrapType,
   2903                               SECItem *param, SECItem *wrappedKey,
   2904                               CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation,
   2905                               int keySize, CK_FLAGS flags, PRBool isPerm)
   2906 {
   2907    CK_BBOOL cktrue = CK_TRUE;
   2908    CK_ATTRIBUTE keyTemplate[MAX_TEMPL_ATTRS];
   2909    CK_ATTRIBUTE *attrs;
   2910    unsigned int templateCount;
   2911 
   2912    attrs = keyTemplate;
   2913    if (isPerm) {
   2914        PK11_SETATTRS(attrs, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL));
   2915        attrs++;
   2916    }
   2917    templateCount = attrs - keyTemplate;
   2918    templateCount += pk11_OpFlagsToAttributes(flags, attrs, &cktrue);
   2919 
   2920    return pk11_AnyUnwrapKey(wrappingKey->slot, wrappingKey->objectID,
   2921                             wrapType, param, wrappedKey, target, operation, keySize,
   2922                             wrappingKey->cx, keyTemplate, templateCount, isPerm);
   2923 }
   2924 
   2925 /* unwrap a symmetric key with a private key. Only supports CKM_RSA_PKCS. */
   2926 PK11SymKey *
   2927 PK11_PubUnwrapSymKey(SECKEYPrivateKey *wrappingKey, SECItem *wrappedKey,
   2928                     CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation, int keySize)
   2929 {
   2930    CK_MECHANISM_TYPE wrapType = pk11_mapWrapKeyType(wrappingKey->keyType);
   2931 
   2932    return PK11_PubUnwrapSymKeyWithMechanism(wrappingKey, wrapType, NULL,
   2933                                             wrappedKey, target, operation,
   2934                                             keySize);
   2935 }
   2936 
   2937 /* unwrap a symmetric key with a private key with the given parameters. */
   2938 PK11SymKey *
   2939 PK11_PubUnwrapSymKeyWithMechanism(SECKEYPrivateKey *wrappingKey,
   2940                                  CK_MECHANISM_TYPE mechType, SECItem *param,
   2941                                  SECItem *wrappedKey, CK_MECHANISM_TYPE target,
   2942                                  CK_ATTRIBUTE_TYPE operation, int keySize)
   2943 {
   2944    PK11SlotInfo *slot = wrappingKey->pkcs11Slot;
   2945 
   2946    if (SECKEY_HAS_ATTRIBUTE_SET(wrappingKey, CKA_PRIVATE)) {
   2947        PK11_HandlePasswordCheck(slot, wrappingKey->wincx);
   2948    }
   2949 
   2950    return pk11_AnyUnwrapKey(slot, wrappingKey->pkcs11ID, mechType, param,
   2951                             wrappedKey, target, operation, keySize,
   2952                             wrappingKey->wincx, NULL, 0, PR_FALSE);
   2953 }
   2954 
   2955 /* unwrap a symetric key with a private key. */
   2956 PK11SymKey *
   2957 PK11_PubUnwrapSymKeyWithFlags(SECKEYPrivateKey *wrappingKey,
   2958                              SECItem *wrappedKey, CK_MECHANISM_TYPE target,
   2959                              CK_ATTRIBUTE_TYPE operation, int keySize, CK_FLAGS flags)
   2960 {
   2961    CK_MECHANISM_TYPE wrapType = pk11_mapWrapKeyType(wrappingKey->keyType);
   2962    CK_BBOOL ckTrue = CK_TRUE;
   2963    CK_ATTRIBUTE keyTemplate[MAX_TEMPL_ATTRS];
   2964    unsigned int templateCount;
   2965    PK11SlotInfo *slot = wrappingKey->pkcs11Slot;
   2966 
   2967    templateCount = pk11_OpFlagsToAttributes(flags, keyTemplate, &ckTrue);
   2968 
   2969    if (SECKEY_HAS_ATTRIBUTE_SET(wrappingKey, CKA_PRIVATE)) {
   2970        PK11_HandlePasswordCheck(slot, wrappingKey->wincx);
   2971    }
   2972 
   2973    return pk11_AnyUnwrapKey(slot, wrappingKey->pkcs11ID,
   2974                             wrapType, NULL, wrappedKey, target, operation, keySize,
   2975                             wrappingKey->wincx, keyTemplate, templateCount, PR_FALSE);
   2976 }
   2977 
   2978 PK11SymKey *
   2979 PK11_PubUnwrapSymKeyWithFlagsPerm(SECKEYPrivateKey *wrappingKey,
   2980                                  SECItem *wrappedKey, CK_MECHANISM_TYPE target,
   2981                                  CK_ATTRIBUTE_TYPE operation, int keySize,
   2982                                  CK_FLAGS flags, PRBool isPerm)
   2983 {
   2984    CK_MECHANISM_TYPE wrapType = pk11_mapWrapKeyType(wrappingKey->keyType);
   2985    CK_BBOOL cktrue = CK_TRUE;
   2986    CK_ATTRIBUTE keyTemplate[MAX_TEMPL_ATTRS];
   2987    CK_ATTRIBUTE *attrs;
   2988    unsigned int templateCount;
   2989    PK11SlotInfo *slot = wrappingKey->pkcs11Slot;
   2990 
   2991    attrs = keyTemplate;
   2992    if (isPerm) {
   2993        PK11_SETATTRS(attrs, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL));
   2994        attrs++;
   2995    }
   2996    templateCount = attrs - keyTemplate;
   2997 
   2998    templateCount += pk11_OpFlagsToAttributes(flags, attrs, &cktrue);
   2999 
   3000    if (SECKEY_HAS_ATTRIBUTE_SET(wrappingKey, CKA_PRIVATE)) {
   3001        PK11_HandlePasswordCheck(slot, wrappingKey->wincx);
   3002    }
   3003 
   3004    return pk11_AnyUnwrapKey(slot, wrappingKey->pkcs11ID,
   3005                             wrapType, NULL, wrappedKey, target, operation, keySize,
   3006                             wrappingKey->wincx, keyTemplate, templateCount, isPerm);
   3007 }
   3008 
   3009 PK11SymKey *
   3010 PK11_CopySymKeyForSigning(PK11SymKey *originalKey, CK_MECHANISM_TYPE mech)
   3011 {
   3012    CK_RV crv;
   3013    CK_ATTRIBUTE setTemplate;
   3014    CK_BBOOL ckTrue = CK_TRUE;
   3015    PK11SlotInfo *slot = originalKey->slot;
   3016 
   3017    /* first just try to set this key up for signing */
   3018    PK11_SETATTRS(&setTemplate, CKA_SIGN, &ckTrue, sizeof(ckTrue));
   3019    pk11_EnterKeyMonitor(originalKey);
   3020    crv = PK11_GETTAB(slot)->C_SetAttributeValue(originalKey->session,
   3021                                                 originalKey->objectID, &setTemplate, 1);
   3022    pk11_ExitKeyMonitor(originalKey);
   3023    if (crv == CKR_OK) {
   3024        return PK11_ReferenceSymKey(originalKey);
   3025    }
   3026 
   3027    /* nope, doesn't like it, use the pk11 copy object command */
   3028    return pk11_CopyToSlot(slot, mech, CKA_SIGN, originalKey);
   3029 }
   3030 
   3031 void
   3032 PK11_SetFortezzaHack(PK11SymKey *symKey)
   3033 {
   3034    symKey->origin = PK11_OriginFortezzaHack;
   3035 }
   3036 
   3037 /*
   3038 * This is required to allow FORTEZZA_NULL and FORTEZZA_RC4
   3039 * working. This function simply gets a valid IV for the keys.
   3040 */
   3041 SECStatus
   3042 PK11_GenerateFortezzaIV(PK11SymKey *symKey, unsigned char *iv, int len)
   3043 {
   3044    CK_MECHANISM mech_info;
   3045    CK_ULONG count = 0;
   3046    CK_RV crv;
   3047    SECStatus rv = SECFailure;
   3048 
   3049    mech_info.mechanism = CKM_SKIPJACK_CBC64;
   3050    mech_info.pParameter = iv;
   3051    mech_info.ulParameterLen = len;
   3052 
   3053    /* generate the IV for fortezza */
   3054    PK11_EnterSlotMonitor(symKey->slot);
   3055    crv = PK11_GETTAB(symKey->slot)->C_EncryptInit(symKey->slot->session, &mech_info, symKey->objectID);
   3056    if (crv == CKR_OK) {
   3057        PK11_GETTAB(symKey->slot)->C_EncryptFinal(symKey->slot->session, NULL, &count);
   3058        rv = SECSuccess;
   3059    }
   3060    PK11_ExitSlotMonitor(symKey->slot);
   3061    return rv;
   3062 }
   3063 
   3064 CK_OBJECT_HANDLE
   3065 PK11_GetSymKeyHandle(PK11SymKey *symKey)
   3066 {
   3067    return symKey->objectID;
   3068 }
   3069 
   3070 SECStatus
   3071 PK11_Encapsulate(SECKEYPublicKey *pubKey, CK_MECHANISM_TYPE target,
   3072                 PK11AttrFlags attrFlags, CK_FLAGS opFlags,
   3073                 PK11SymKey **outKey, SECItem **outCiphertext)
   3074 {
   3075    PORT_Assert(pubKey);
   3076    PORT_Assert(outKey);
   3077    PORT_Assert(outCiphertext);
   3078 
   3079    PK11SlotInfo *slot = pubKey->pkcs11Slot;
   3080 
   3081    PK11SymKey *sharedSecret = NULL;
   3082    SECItem *ciphertext = NULL;
   3083 
   3084    CK_ATTRIBUTE keyTemplate[MAX_TEMPL_ATTRS];
   3085    unsigned int templateCount;
   3086 
   3087    CK_ATTRIBUTE *attrs;
   3088    CK_BBOOL cktrue = CK_TRUE;
   3089    CK_BBOOL ckfalse = CK_FALSE;
   3090    CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY;
   3091    CK_KEY_TYPE keyType = CKK_GENERIC_SECRET;
   3092    CK_MECHANISM_TYPE kemType = pk11_mapKemKeyType(pubKey->keyType);
   3093    CK_MECHANISM mech = { kemType, NULL, 0 };
   3094    CK_ULONG ciphertextLen = 0;
   3095    CK_RV crv;
   3096 
   3097    /* set up the target key template */
   3098    attrs = keyTemplate;
   3099    PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass));
   3100    attrs++;
   3101 
   3102    PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType));
   3103    attrs++;
   3104 
   3105    attrs += pk11_AttrFlagsToAttributes(attrFlags, attrs, &cktrue, &ckfalse);
   3106    attrs += pk11_OpFlagsToAttributes(opFlags, attrs, &cktrue);
   3107 
   3108    templateCount = attrs - keyTemplate;
   3109    PR_ASSERT(templateCount <= sizeof(keyTemplate) / sizeof(CK_ATTRIBUTE));
   3110 
   3111    *outKey = NULL;
   3112    *outCiphertext = NULL;
   3113 
   3114    /* create a struxture for the target key */
   3115    sharedSecret = pk11_CreateSymKey(slot, target, PR_TRUE, PR_TRUE, NULL);
   3116    if (sharedSecret == NULL) {
   3117        PORT_SetError(SEC_ERROR_NO_MEMORY);
   3118        return SECFailure;
   3119    }
   3120    sharedSecret->origin = PK11_OriginDerive;
   3121 
   3122    /* this path is KEM mechanism agnostic */
   3123    if (PK11_CheckPKCS11Version(slot, 3, 2, PR_TRUE) >= 0) {
   3124        pk11_EnterKeyMonitor(sharedSecret);
   3125        /* get the length the normal PKCS #11 way. This works no matter
   3126         * what the KEM is and we don't have to try to guess the KEM length
   3127         * from the key */
   3128        crv = PK11_GETTAB(slot)->C_EncapsulateKey(sharedSecret->session,
   3129                                                  &mech,
   3130                                                  pubKey->pkcs11ID,
   3131                                                  keyTemplate,
   3132                                                  templateCount,
   3133                                                  NULL,
   3134                                                  &ciphertextLen,
   3135                                                  &sharedSecret->objectID);
   3136        pk11_ExitKeyMonitor(sharedSecret);
   3137        if ((crv != CKR_OK) && (crv != CKR_BUFFER_TOO_SMALL) &&
   3138            (crv != CKR_KEY_SIZE_RANGE)) {
   3139            goto loser;
   3140        }
   3141        ciphertext = SECITEM_AllocItem(NULL, NULL, ciphertextLen);
   3142        if (ciphertext == NULL) {
   3143            crv = CKR_HOST_MEMORY;
   3144            goto loser;
   3145        }
   3146        pk11_EnterKeyMonitor(sharedSecret);
   3147        /* Now do the encapsulate */
   3148        /* NOTE: the PKCS #11 order of the parameters is different from
   3149         * the vendor interface */
   3150        crv = PK11_GETTAB(slot)->C_EncapsulateKey(sharedSecret->session,
   3151                                                  &mech,
   3152                                                  pubKey->pkcs11ID,
   3153                                                  keyTemplate,
   3154                                                  templateCount,
   3155                                                  ciphertext->data,
   3156                                                  &ciphertextLen,
   3157                                                  &sharedSecret->objectID);
   3158        pk11_ExitKeyMonitor(sharedSecret);
   3159        if (crv != CKR_OK) {
   3160            goto loser;
   3161        }
   3162        ciphertext->len = ciphertextLen;
   3163    } else {
   3164        /* use the old NSS private interface */
   3165        CK_INTERFACE_PTR KEMInterface = NULL;
   3166        CK_UTF8CHAR_PTR KEMInterfaceName =
   3167            (CK_UTF8CHAR_PTR) "Vendor NSS KEM Interface";
   3168        CK_VERSION KEMInterfaceVersion = { 1, 0 };
   3169        CK_NSS_KEM_FUNCTIONS *KEMInterfaceFunctions = NULL;
   3170        CK_NSS_KEM_PARAMETER_SET_TYPE kemParameterSet;
   3171 
   3172        crv = PK11_GETTAB(slot)->C_GetInterface(KEMInterfaceName,
   3173                                                &KEMInterfaceVersion,
   3174                                                &KEMInterface, 0);
   3175        if (crv != CKR_OK) {
   3176            goto loser;
   3177        }
   3178        KEMInterfaceFunctions = (CK_NSS_KEM_FUNCTIONS *)(KEMInterface->pFunctionList);
   3179 
   3180        /* the old API expected the parameter set as a parameter, the
   3181         * pkcs11 v3.2 gets it from the key */
   3182        kemParameterSet = PK11_ReadULongAttribute(slot,
   3183                                                  pubKey->pkcs11ID,
   3184                                                  CKA_NSS_PARAMETER_SET);
   3185        if (kemParameterSet == CK_UNAVAILABLE_INFORMATION) {
   3186            kemParameterSet = PK11_ReadULongAttribute(slot,
   3187                                                      pubKey->pkcs11ID,
   3188                                                      CKA_PARAMETER_SET);
   3189            if (kemParameterSet == CK_UNAVAILABLE_INFORMATION) {
   3190                crv = CKR_PUBLIC_KEY_INVALID;
   3191                goto loser;
   3192            }
   3193        }
   3194        /* The old interface only ever supported KYBER768 and MLKEM768
   3195         * SOME versions of RHEL has MLKEM1024  support, if we want to
   3196         * make sure this works with those versions of softoken (without their
   3197         * NSS) we should check the kemParamSet and set the mech to
   3198         * CKM_NSS_ML_KEM if the key isn't KYBER and the cipher test to
   3199         * MLKEM104_CIPHERTEXT_BYTES if the kemParmset is MLKEM1024 */
   3200        mech.mechanism = CKM_NSS_KYBER;
   3201        mech.pParameter = (CK_VOID_PTR)&kemParameterSet;
   3202        mech.ulParameterLen = sizeof(kemParameterSet);
   3203        ciphertextLen = KYBER768_CIPHERTEXT_BYTES;
   3204 
   3205        ciphertext = SECITEM_AllocItem(NULL, NULL, ciphertextLen);
   3206        if (ciphertext == NULL) {
   3207            crv = CKR_HOST_MEMORY;
   3208            goto loser;
   3209        }
   3210 
   3211        pk11_EnterKeyMonitor(sharedSecret);
   3212        crv = KEMInterfaceFunctions->C_Encapsulate(sharedSecret->session,
   3213                                                   &mech,
   3214                                                   pubKey->pkcs11ID,
   3215                                                   keyTemplate,
   3216                                                   templateCount,
   3217                                                   &sharedSecret->objectID,
   3218                                                   ciphertext->data,
   3219                                                   &ciphertextLen);
   3220        pk11_ExitKeyMonitor(sharedSecret);
   3221        if (crv != CKR_OK) {
   3222            goto loser;
   3223        }
   3224 
   3225        PORT_Assert(ciphertextLen == ciphertext->len);
   3226    }
   3227 
   3228    *outKey = sharedSecret;
   3229    *outCiphertext = ciphertext;
   3230 
   3231    return SECSuccess;
   3232 
   3233 loser:
   3234    PK11_FreeSymKey(sharedSecret);
   3235    SECITEM_FreeItem(ciphertext, PR_TRUE);
   3236    PORT_SetError(PK11_MapError(crv));
   3237    return SECFailure;
   3238 }
   3239 
   3240 SECStatus
   3241 PK11_Decapsulate(SECKEYPrivateKey *privKey, const SECItem *ciphertext,
   3242                 CK_MECHANISM_TYPE target, PK11AttrFlags attrFlags,
   3243                 CK_FLAGS opFlags, PK11SymKey **outKey)
   3244 {
   3245    PORT_Assert(privKey);
   3246    PORT_Assert(ciphertext);
   3247    PORT_Assert(outKey);
   3248 
   3249    PK11SlotInfo *slot = privKey->pkcs11Slot;
   3250 
   3251    PK11SymKey *sharedSecret;
   3252 
   3253    CK_ATTRIBUTE keyTemplate[MAX_TEMPL_ATTRS];
   3254    unsigned int templateCount;
   3255 
   3256    CK_ATTRIBUTE *attrs;
   3257    CK_BBOOL cktrue = CK_TRUE;
   3258    CK_BBOOL ckfalse = CK_FALSE;
   3259    CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY;
   3260    CK_KEY_TYPE keyType = CKK_GENERIC_SECRET;
   3261    CK_MECHANISM_TYPE kemType = pk11_mapKemKeyType(privKey->keyType);
   3262    CK_MECHANISM mech = { kemType, NULL, 0 };
   3263 
   3264    CK_RV crv;
   3265 
   3266    *outKey = NULL;
   3267    sharedSecret = pk11_CreateSymKey(slot, target, PR_TRUE, PR_TRUE, NULL);
   3268    if (sharedSecret == NULL) {
   3269        PORT_SetError(SEC_ERROR_NO_MEMORY);
   3270        return SECFailure;
   3271    }
   3272    sharedSecret->origin = PK11_OriginUnwrap;
   3273 
   3274    attrs = keyTemplate;
   3275    PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass));
   3276    attrs++;
   3277 
   3278    PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType));
   3279    attrs++;
   3280 
   3281    attrs += pk11_AttrFlagsToAttributes(attrFlags, attrs, &cktrue, &ckfalse);
   3282    attrs += pk11_OpFlagsToAttributes(opFlags, attrs, &cktrue);
   3283 
   3284    templateCount = attrs - keyTemplate;
   3285    PR_ASSERT(templateCount <= sizeof(keyTemplate) / sizeof(CK_ATTRIBUTE));
   3286 
   3287    if (PK11_CheckPKCS11Version(slot, 3, 2, PR_TRUE) >= 0) {
   3288        pk11_EnterKeyMonitor(sharedSecret);
   3289        crv = PK11_GETTAB(slot)->C_DecapsulateKey(sharedSecret->session,
   3290                                                  &mech,
   3291                                                  privKey->pkcs11ID,
   3292                                                  keyTemplate,
   3293                                                  templateCount,
   3294                                                  ciphertext->data,
   3295                                                  ciphertext->len,
   3296                                                  &sharedSecret->objectID);
   3297        pk11_ExitKeyMonitor(sharedSecret);
   3298        if (crv != CKR_OK) {
   3299            goto loser;
   3300        }
   3301    } else {
   3302        CK_INTERFACE_PTR KEMInterface = NULL;
   3303        CK_UTF8CHAR_PTR KEMInterfaceName =
   3304            (CK_UTF8CHAR_PTR) "Vendor NSS KEM Interface";
   3305        CK_VERSION KEMInterfaceVersion = { 1, 0 };
   3306        CK_NSS_KEM_FUNCTIONS *KEMInterfaceFunctions = NULL;
   3307 
   3308        crv = PK11_GETTAB(slot)->C_GetInterface(KEMInterfaceName,
   3309                                                &KEMInterfaceVersion,
   3310                                                &KEMInterface, 0);
   3311        if (crv != CKR_OK) {
   3312            PORT_SetError(PK11_MapError(crv));
   3313            goto loser;
   3314        }
   3315        KEMInterfaceFunctions =
   3316            (CK_NSS_KEM_FUNCTIONS *)(KEMInterface->pFunctionList);
   3317 
   3318        /* the old API expected the parameter set as a parameter, the
   3319         * pkcs11 v3.2 gets it from the key */
   3320        CK_ULONG kemParameterSet = PK11_ReadULongAttribute(slot,
   3321                                                           privKey->pkcs11ID,
   3322                                                           CKA_NSS_PARAMETER_SET);
   3323        if (kemParameterSet == CK_UNAVAILABLE_INFORMATION) {
   3324            kemParameterSet = PK11_ReadULongAttribute(slot,
   3325                                                      privKey->pkcs11ID,
   3326                                                      CKA_PARAMETER_SET);
   3327            if (kemParameterSet == CK_UNAVAILABLE_INFORMATION) {
   3328                crv = CKR_KEY_HANDLE_INVALID;
   3329                goto loser;
   3330            }
   3331        }
   3332        /* The old interface only ever supported KYBER768 and MLKEM768
   3333         * SOME versions of RHEL has MLKEM1024  support, if we want to
   3334         * make sure this works with those versions of softoken (without their
   3335         * NSS) we should check the kemParamSet and set the mech to
   3336         * CKM_NSS_ML_KEM if the key isn't KYBER and the cipher test to
   3337         * MLKEM104_CIPHERTEXT_BYTES if the kemParmset is MLKEM1024 */
   3338        mech.mechanism = CKM_NSS_KYBER;
   3339        mech.pParameter = (CK_VOID_PTR)&kemParameterSet;
   3340        mech.ulParameterLen = sizeof(kemParameterSet);
   3341 
   3342        pk11_EnterKeyMonitor(sharedSecret);
   3343        crv = KEMInterfaceFunctions->C_Decapsulate(sharedSecret->session,
   3344                                                   &mech,
   3345                                                   privKey->pkcs11ID,
   3346                                                   ciphertext->data,
   3347                                                   ciphertext->len,
   3348                                                   keyTemplate,
   3349                                                   templateCount,
   3350                                                   &sharedSecret->objectID);
   3351        pk11_ExitKeyMonitor(sharedSecret);
   3352        if (crv != CKR_OK) {
   3353            goto loser;
   3354        }
   3355    }
   3356 
   3357    *outKey = sharedSecret;
   3358    return SECSuccess;
   3359 
   3360 loser:
   3361    PK11_FreeSymKey(sharedSecret);
   3362    return SECFailure;
   3363 }