tor-browser

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

pk11kea.c (5022B)


      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 
     11 #include "seccomon.h"
     12 #include "secmod.h"
     13 #include "nssilock.h"
     14 #include "secmodi.h"
     15 #include "secmodti.h"
     16 #include "pkcs11.h"
     17 #include "pk11func.h"
     18 #include "secitem.h"
     19 #include "keyhi.h"
     20 #include "secasn1.h"
     21 #include "sechash.h"
     22 #include "cert.h"
     23 #include "secerr.h"
     24 
     25 /*
     26 * find an RSA public key on a card
     27 */
     28 static CK_OBJECT_HANDLE
     29 pk11_FindRSAPubKey(PK11SlotInfo *slot)
     30 {
     31    CK_KEY_TYPE key_type = CKK_RSA;
     32    CK_OBJECT_CLASS class_type = CKO_PUBLIC_KEY;
     33    CK_ATTRIBUTE theTemplate[2];
     34    size_t template_count = sizeof(theTemplate) / sizeof(theTemplate[0]);
     35    CK_ATTRIBUTE *attrs = theTemplate;
     36 
     37    PK11_SETATTRS(attrs, CKA_CLASS, &class_type, sizeof(class_type));
     38    attrs++;
     39    PK11_SETATTRS(attrs, CKA_KEY_TYPE, &key_type, sizeof(key_type));
     40    attrs++;
     41    template_count = attrs - theTemplate;
     42    PR_ASSERT(template_count <= sizeof(theTemplate) / sizeof(CK_ATTRIBUTE));
     43 
     44    return pk11_FindObjectByTemplate(slot, theTemplate, template_count);
     45 }
     46 
     47 PK11SymKey *
     48 pk11_KeyExchange(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
     49                 CK_ATTRIBUTE_TYPE operation, CK_FLAGS flags,
     50                 PRBool isPerm, PK11SymKey *symKey)
     51 {
     52    PK11SymKey *newSymKey = NULL;
     53    SECStatus rv;
     54    /* performance improvement can go here --- use a generated key at startup
     55     * to generate a per token wrapping key. If it exists, use it, otherwise
     56     * do a full key exchange. */
     57 
     58    /* find a common Key Exchange algorithm */
     59    /* RSA */
     60    if (PK11_DoesMechanism(symKey->slot, CKM_RSA_PKCS) &&
     61        PK11_DoesMechanism(slot, CKM_RSA_PKCS)) {
     62        CK_OBJECT_HANDLE pubKeyHandle = CK_INVALID_HANDLE;
     63        CK_OBJECT_HANDLE privKeyHandle = CK_INVALID_HANDLE;
     64        SECKEYPublicKey *pubKey = NULL;
     65        SECKEYPrivateKey *privKey = NULL;
     66        SECItem wrapData;
     67        unsigned int symKeyLength = PK11_GetKeyLength(symKey);
     68 
     69        wrapData.data = NULL;
     70 
     71        /* find RSA Public Key on target */
     72        pubKeyHandle = pk11_FindRSAPubKey(slot);
     73        if (pubKeyHandle != CK_INVALID_HANDLE) {
     74            privKeyHandle = PK11_MatchItem(slot, pubKeyHandle, CKO_PRIVATE_KEY);
     75        }
     76 
     77        /* if no key exists, generate a key pair */
     78        if (privKeyHandle == CK_INVALID_HANDLE) {
     79            PK11RSAGenParams rsaParams;
     80 
     81            if (symKeyLength > 120) /* bytes */ {
     82                /* we'd have to generate an RSA key pair > 1024 bits long,
     83                ** and that's too costly.  Don't even try.
     84                */
     85                PORT_SetError(SEC_ERROR_CANNOT_MOVE_SENSITIVE_KEY);
     86                goto rsa_failed;
     87            }
     88            rsaParams.keySizeInBits = 1024;
     89            rsaParams.pe = 0x10001;
     90            privKey = PK11_GenerateKeyPair(slot, CKM_RSA_PKCS_KEY_PAIR_GEN,
     91                                           &rsaParams, &pubKey, PR_FALSE, PR_TRUE, symKey->cx);
     92        } else {
     93            /* if keys exist, build SECKEY data structures for them */
     94            privKey = PK11_MakePrivKey(slot, nullKey, PR_TRUE, privKeyHandle,
     95                                       symKey->cx);
     96            if (privKey != NULL) {
     97                pubKey = PK11_ExtractPublicKey(slot, rsaKey, pubKeyHandle);
     98                if (pubKey && pubKey->pkcs11Slot) {
     99                    PK11_FreeSlot(pubKey->pkcs11Slot);
    100                    pubKey->pkcs11Slot = NULL;
    101                    pubKey->pkcs11ID = CK_INVALID_HANDLE;
    102                }
    103            }
    104        }
    105        if (privKey == NULL)
    106            goto rsa_failed;
    107        if (pubKey == NULL)
    108            goto rsa_failed;
    109 
    110        wrapData.len = SECKEY_PublicKeyStrength(pubKey);
    111        if (!wrapData.len)
    112            goto rsa_failed;
    113        wrapData.data = PORT_Alloc(wrapData.len);
    114        if (wrapData.data == NULL)
    115            goto rsa_failed;
    116 
    117        /* now wrap the keys in and out */
    118        rv = PK11_PubWrapSymKey(CKM_RSA_PKCS, pubKey, symKey, &wrapData);
    119        if (rv == SECSuccess) {
    120            newSymKey = PK11_PubUnwrapSymKeyWithFlagsPerm(privKey,
    121                                                          &wrapData, type, operation,
    122                                                          symKeyLength, flags, isPerm);
    123            /* make sure we wound up where we wanted to be! */
    124            if (newSymKey && newSymKey->slot != slot) {
    125                PK11_FreeSymKey(newSymKey);
    126                newSymKey = NULL;
    127            }
    128        }
    129    rsa_failed:
    130        if (wrapData.data != NULL)
    131            PORT_Free(wrapData.data);
    132        if (privKey != NULL)
    133            SECKEY_DestroyPrivateKey(privKey);
    134        if (pubKey != NULL)
    135            SECKEY_DestroyPublicKey(pubKey);
    136 
    137        return newSymKey;
    138    }
    139    PORT_SetError(SEC_ERROR_NO_MODULE);
    140    return NULL;
    141 }