Coverage Report

Created: 2024-05-20 06:23

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