tor-browser

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

tlsprf.c (6645B)


      1 /* tlsprf.c - TLS Pseudo Random Function (PRF) implementation
      2 *
      3 * This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "pkcs11i.h"
      8 #include "blapi.h"
      9 #include "secerr.h"
     10 
     11 static void
     12 sftk_TLSPRFNull(void *data, PRBool freeit)
     13 {
     14    return;
     15 }
     16 
     17 typedef struct {
     18    PRUint32 cxSize;          /* size of allocated block, in bytes.        */
     19    PRUint32 cxBufSize;       /* sizeof buffer at cxBufPtr.                */
     20    unsigned char *cxBufPtr;  /* points to real buffer, may be cxBuf.      */
     21    PRUint32 cxKeyLen;        /* bytes of cxBufPtr containing key.         */
     22    PRUint32 cxDataLen;       /* bytes of cxBufPtr containing data.        */
     23    SECStatus cxRv;           /* records failure of void functions.        */
     24    PRBool cxIsFIPS;          /* true if conforming to FIPS 198.           */
     25    HASH_HashType cxHashAlg;  /* hash algorithm to use for TLS 1.2+        */
     26    unsigned int cxOutLen;    /* bytes of output if nonzero                */
     27    unsigned char cxBuf[512]; /* actual size may be larger than 512.       */
     28 } TLSPRFContext;
     29 
     30 static void
     31 sftk_TLSPRFHashUpdate(void *ctx, const unsigned char *data,
     32                      unsigned int data_len)
     33 {
     34    TLSPRFContext *cx = ctx;
     35    PRUint32 bytesUsed = cx->cxKeyLen + cx->cxDataLen;
     36 
     37    if (cx->cxRv != SECSuccess) /* function has previously failed. */
     38        return;
     39    if (bytesUsed + data_len > cx->cxBufSize) {
     40        /* We don't use realloc here because
     41        ** (a) realloc doesn't zero out the old block, and
     42        ** (b) if realloc fails, we lose the old block.
     43        */
     44        PRUint32 newBufSize = bytesUsed + data_len + 512;
     45        unsigned char *newBuf = (unsigned char *)PORT_Alloc(newBufSize);
     46        if (!newBuf) {
     47            cx->cxRv = SECFailure;
     48            return;
     49        }
     50        PORT_Memcpy(newBuf, cx->cxBufPtr, bytesUsed);
     51        if (cx->cxBufPtr != cx->cxBuf) {
     52            PORT_ZFree(cx->cxBufPtr, bytesUsed);
     53        }
     54        cx->cxBufPtr = newBuf;
     55        cx->cxBufSize = newBufSize;
     56    }
     57    PORT_Memcpy(cx->cxBufPtr + bytesUsed, data, data_len);
     58    cx->cxDataLen += data_len;
     59 }
     60 
     61 static void
     62 sftk_TLSPRFEnd(void *ctx, unsigned char *hashout,
     63               unsigned int *pDigestLen, unsigned int maxDigestLen)
     64 {
     65    *pDigestLen = 0; /* tells Verify that no data has been input yet. */
     66 }
     67 
     68 /* Compute the PRF values from the data previously input. */
     69 static SECStatus
     70 sftk_TLSPRFUpdate(void *ctx,
     71                  unsigned char *sig,        /* output goes here. */
     72                  unsigned int *sigLen,      /* how much output.  */
     73                  unsigned int maxLen,       /* output buffer size */
     74                  const unsigned char *hash, /* unused. */
     75                  unsigned int hashLen)      /* unused. */
     76 {
     77    TLSPRFContext *cx = ctx;
     78    SECStatus rv;
     79    SECItem sigItem;
     80    SECItem seedItem;
     81    SECItem secretItem;
     82 
     83    if (cx->cxRv != SECSuccess)
     84        return cx->cxRv;
     85 
     86    secretItem.data = cx->cxBufPtr;
     87    secretItem.len = cx->cxKeyLen;
     88 
     89    seedItem.data = cx->cxBufPtr + cx->cxKeyLen;
     90    seedItem.len = cx->cxDataLen;
     91 
     92    sigItem.data = sig;
     93    if (cx->cxOutLen == 0) {
     94        sigItem.len = maxLen;
     95    } else if (cx->cxOutLen <= maxLen) {
     96        sigItem.len = cx->cxOutLen;
     97    } else {
     98        PORT_SetError(SEC_ERROR_OUTPUT_LEN);
     99        return SECFailure;
    100    }
    101 
    102    if (cx->cxHashAlg != HASH_AlgNULL) {
    103        rv = TLS_P_hash(cx->cxHashAlg, &secretItem, NULL, &seedItem, &sigItem,
    104                        cx->cxIsFIPS);
    105    } else {
    106        rv = TLS_PRF(&secretItem, NULL, &seedItem, &sigItem, cx->cxIsFIPS);
    107    }
    108    if (rv == SECSuccess && sigLen != NULL)
    109        *sigLen = sigItem.len;
    110    return rv;
    111 }
    112 
    113 static SECStatus
    114 sftk_TLSPRFVerify(void *ctx,
    115                  const unsigned char *sig,  /* input, for comparison. */
    116                  unsigned int sigLen,       /* length of sig.         */
    117                  const unsigned char *hash, /* data to be verified.   */
    118                  unsigned int hashLen)      /* size of hash data.     */
    119 {
    120    TLSPRFContext *cx = ctx;
    121    unsigned char *tmp = (unsigned char *)PORT_Alloc(sigLen);
    122    unsigned int tmpLen = sigLen;
    123    SECStatus rv;
    124 
    125    if (!tmp)
    126        return SECFailure;
    127    if (hashLen) {
    128        /* hashLen is non-zero when the user does a one-step verify.
    129        ** In this case, none of the data has been input yet.
    130        */
    131        sftk_TLSPRFHashUpdate(cx, hash, hashLen);
    132    }
    133    rv = sftk_TLSPRFUpdate(cx, tmp, &tmpLen, sigLen, NULL, 0);
    134    if (rv == SECSuccess) {
    135        rv = (SECStatus)(1 - !NSS_SecureMemcmp(tmp, sig, sigLen));
    136    }
    137    PORT_ZFree(tmp, sigLen);
    138    return rv;
    139 }
    140 
    141 static void
    142 sftk_TLSPRFHashDestroy(void *ctx, PRBool freeit)
    143 {
    144    TLSPRFContext *cx = ctx;
    145    if (freeit) {
    146        if (cx->cxBufPtr != cx->cxBuf)
    147            PORT_ZFree(cx->cxBufPtr, cx->cxBufSize);
    148        PORT_ZFree(cx, cx->cxSize);
    149    }
    150 }
    151 
    152 CK_RV
    153 sftk_TLSPRFInit(SFTKSessionContext *context,
    154                SFTKObject *key,
    155                CK_KEY_TYPE key_type,
    156                HASH_HashType hash_alg,
    157                unsigned int out_len)
    158 {
    159    SFTKAttribute *keyVal;
    160    TLSPRFContext *prf_cx;
    161    CK_RV crv = CKR_HOST_MEMORY;
    162    PRUint32 keySize;
    163    PRUint32 blockSize;
    164 
    165    if (key_type != CKK_GENERIC_SECRET)
    166        return CKR_KEY_TYPE_INCONSISTENT; /* CKR_KEY_FUNCTION_NOT_PERMITTED */
    167 
    168    context->multi = PR_TRUE;
    169 
    170    keyVal = sftk_FindAttribute(key, CKA_VALUE);
    171    keySize = (!keyVal) ? 0 : keyVal->attrib.ulValueLen;
    172    blockSize = keySize + sizeof(TLSPRFContext);
    173    prf_cx = (TLSPRFContext *)PORT_Alloc(blockSize);
    174    if (!prf_cx)
    175        goto done;
    176    prf_cx->cxSize = blockSize;
    177    prf_cx->cxKeyLen = keySize;
    178    prf_cx->cxDataLen = 0;
    179    prf_cx->cxBufSize = blockSize - offsetof(TLSPRFContext, cxBuf);
    180    prf_cx->cxRv = SECSuccess;
    181    prf_cx->cxIsFIPS = sftk_isFIPS(key->slot->slotID);
    182    prf_cx->cxBufPtr = prf_cx->cxBuf;
    183    prf_cx->cxHashAlg = hash_alg;
    184    prf_cx->cxOutLen = out_len;
    185    if (keySize)
    186        PORT_Memcpy(prf_cx->cxBufPtr, keyVal->attrib.pValue, keySize);
    187 
    188    context->hashInfo = (void *)prf_cx;
    189    context->cipherInfo = (void *)prf_cx;
    190    context->hashUpdate = sftk_TLSPRFHashUpdate;
    191    context->end = sftk_TLSPRFEnd;
    192    context->update = sftk_TLSPRFUpdate;
    193    context->verify = sftk_TLSPRFVerify;
    194    context->destroy = sftk_TLSPRFNull;
    195    context->hashdestroy = sftk_TLSPRFHashDestroy;
    196    crv = CKR_OK;
    197 
    198 done:
    199    if (keyVal)
    200        sftk_FreeAttribute(keyVal);
    201    return crv;
    202 }