tor-browser

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

tlsprfalg.c (3977B)


      1 /* tlsprfalg.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 #ifdef FREEBL_NO_DEPEND
      8 #include "stubs.h"
      9 #endif
     10 
     11 #include "blapi.h"
     12 #include "hasht.h"
     13 #include "alghmac.h"
     14 
     15 #define PHASH_STATE_MAX_LEN HASH_LENGTH_MAX
     16 
     17 /* TLS P_hash function */
     18 SECStatus
     19 TLS_P_hash(HASH_HashType hashType, const SECItem *secret, const char *label,
     20           SECItem *seed, SECItem *result, PRBool isFIPS)
     21 {
     22    unsigned char state[PHASH_STATE_MAX_LEN];
     23    unsigned char outbuf[PHASH_STATE_MAX_LEN];
     24    unsigned int state_len = 0, label_len = 0, outbuf_len = 0, chunk_size;
     25    unsigned int remaining;
     26    unsigned char *res;
     27    SECStatus status;
     28    HMACContext *cx;
     29    SECStatus rv = SECFailure;
     30    const SECHashObject *hashObj = HASH_GetRawHashObject(hashType);
     31 
     32    PORT_Assert((secret != NULL) && (secret->data != NULL || !secret->len));
     33    PORT_Assert((seed != NULL) && (seed->data != NULL));
     34    PORT_Assert((result != NULL) && (result->data != NULL));
     35 
     36    remaining = result->len;
     37    res = result->data;
     38 
     39    if (label != NULL)
     40        label_len = PORT_Strlen(label);
     41 
     42    cx = HMAC_Create(hashObj, secret->data, secret->len, isFIPS);
     43    if (cx == NULL)
     44        goto loser;
     45 
     46    /* initialize the state = A(1) = HMAC_hash(secret, seed) */
     47    HMAC_Begin(cx);
     48    HMAC_Update(cx, (unsigned char *)label, label_len);
     49    HMAC_Update(cx, seed->data, seed->len);
     50    status = HMAC_Finish(cx, state, &state_len, sizeof(state));
     51    if (status != SECSuccess)
     52        goto loser;
     53 
     54    /* generate a block at a time until we're done */
     55    while (remaining > 0) {
     56 
     57        HMAC_Begin(cx);
     58        HMAC_Update(cx, state, state_len);
     59        if (label_len)
     60            HMAC_Update(cx, (unsigned char *)label, label_len);
     61        HMAC_Update(cx, seed->data, seed->len);
     62        status = HMAC_Finish(cx, outbuf, &outbuf_len, sizeof(outbuf));
     63        if (status != SECSuccess)
     64            goto loser;
     65 
     66        /* Update the state = A(i) = HMAC_hash(secret, A(i-1)) */
     67        HMAC_Begin(cx);
     68        HMAC_Update(cx, state, state_len);
     69        status = HMAC_Finish(cx, state, &state_len, sizeof(state));
     70        if (status != SECSuccess)
     71            goto loser;
     72 
     73        chunk_size = PR_MIN(outbuf_len, remaining);
     74        PORT_Memcpy(res, &outbuf, chunk_size);
     75        res += chunk_size;
     76        remaining -= chunk_size;
     77    }
     78 
     79    rv = SECSuccess;
     80 
     81 loser:
     82    /* clear out state so it's not left on the stack */
     83    if (cx)
     84        HMAC_Destroy(cx, PR_TRUE);
     85    PORT_SafeZero(state, sizeof(state));
     86    PORT_SafeZero(outbuf, sizeof(outbuf));
     87    return rv;
     88 }
     89 
     90 SECStatus
     91 TLS_PRF(const SECItem *secret, const char *label, SECItem *seed,
     92        SECItem *result, PRBool isFIPS)
     93 {
     94    SECStatus rv = SECFailure, status;
     95    unsigned int i;
     96    SECItem tmp = { siBuffer, NULL, 0 };
     97    SECItem S1;
     98    SECItem S2;
     99 
    100    PORT_Assert((secret != NULL) && (secret->data != NULL || !secret->len));
    101    PORT_Assert((seed != NULL) && (seed->data != NULL));
    102    PORT_Assert((result != NULL) && (result->data != NULL));
    103 
    104    S1.type = siBuffer;
    105    S1.len = (secret->len / 2) + (secret->len & 1);
    106    S1.data = secret->data;
    107 
    108    S2.type = siBuffer;
    109    S2.len = S1.len;
    110    S2.data = secret->data + (secret->len - S2.len);
    111 
    112    tmp.data = (unsigned char *)PORT_Alloc(result->len);
    113    if (tmp.data == NULL)
    114        goto loser;
    115    tmp.len = result->len;
    116 
    117    status = TLS_P_hash(HASH_AlgMD5, &S1, label, seed, result, isFIPS);
    118    if (status != SECSuccess)
    119        goto loser;
    120 
    121    status = TLS_P_hash(HASH_AlgSHA1, &S2, label, seed, &tmp, isFIPS);
    122    if (status != SECSuccess)
    123        goto loser;
    124 
    125    for (i = 0; i < result->len; i++)
    126        result->data[i] ^= tmp.data[i];
    127 
    128    rv = SECSuccess;
    129 
    130 loser:
    131    if (tmp.data != NULL)
    132        PORT_ZFree(tmp.data, tmp.len);
    133    return rv;
    134 }