Coverage Report

Created: 2024-05-20 06:23

/src/nss/lib/freebl/hmacct.c
Line
Count
Source (jump to first uncovered line)
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
#ifdef FREEBL_NO_DEPEND
6
#include "stubs.h"
7
#endif
8
9
#include "secport.h"
10
#include "hasht.h"
11
#include "blapit.h"
12
#include "hmacct.h"
13
#include "secerr.h"
14
15
/* MAX_HASH_BIT_COUNT_BYTES is the maximum number of bytes in the hash's length
16
 * field. (SHA-384/512 have 128-bit length.) */
17
#define MAX_HASH_BIT_COUNT_BYTES 16
18
19
/* constantTimeGE returns 0xff if a>=b and 0x00 otherwise, where a, b <
20
 * MAX_UINT/2. */
21
static unsigned char
22
constantTimeGE(unsigned int a, unsigned int b)
23
5.86M
{
24
5.86M
    return PORT_CT_GE(a, b);
25
5.86M
}
26
27
/* constantTimeEQ8 returns 0xff if a==b and 0x00 otherwise. */
28
static unsigned char
29
constantTimeEQ(unsigned char a, unsigned char b)
30
91.6k
{
31
91.6k
    return PORT_CT_EQ(a, b);
32
91.6k
}
33
34
/* MAC performs a constant time SSLv3/TLS MAC of |dataLen| bytes of |data|,
35
 * where |dataLen| includes both the authenticated bytes and the MAC tag from
36
 * the sender. |dataLen| must be >= the length of the MAC tag.
37
 *
38
 * |dataTotalLen| is >= |dataLen| and also accounts for any padding bytes
39
 * that may follow the sender's MAC. (Only a single block of padding may
40
 * follow in SSLv3, or up to 255 bytes in TLS.)
41
 *
42
 * Since the results of decryption are secret information (otherwise a
43
 * padding-oracle is created), this function is constant-time with respect to
44
 * |dataLen|.
45
 *
46
 * |header| contains either the 13-byte TLS header (containing the sequence
47
 * number, record type etc), or it contains the SSLv3 header with the SSLv3
48
 * padding bytes etc. */
49
static SECStatus
50
MAC(unsigned char *mdOut,
51
    unsigned int *mdOutLen,
52
    unsigned int mdOutMax,
53
    const SECHashObject *hashObj,
54
    const unsigned char *macSecret,
55
    unsigned int macSecretLen,
56
    const unsigned char *header,
57
    unsigned int headerLen,
58
    const unsigned char *data,
59
    unsigned int dataLen,
60
    unsigned int dataTotalLen,
61
    unsigned char isSSLv3)
62
6.54k
{
63
6.54k
    void *mdState = hashObj->create();
64
6.54k
    const unsigned int mdSize = hashObj->length;
65
6.54k
    const unsigned int mdBlockSize = hashObj->blocklength;
66
    /* mdLengthSize is the number of bytes in the length field that terminates
67
     * the hash.
68
     *
69
     * This assumes that hash functions with a 64 byte block size use a 64-bit
70
     * length, and otherwise they use a 128-bit length. This is true of {MD5,
71
     * SHA*} (which are all of the hash functions specified for use with TLS
72
     * today). */
73
6.54k
    const unsigned int mdLengthSize = mdBlockSize == 64 ? 8 : 16;
74
75
6.54k
    const unsigned int sslv3PadLen = hashObj->type == HASH_AlgMD5 ? 48 : 40;
76
77
    /* varianceBlocks is the number of blocks of the hash that we have to
78
     * calculate in constant time because they could be altered by the
79
     * padding value.
80
     *
81
     * In SSLv3, the padding must be minimal so the end of the plaintext
82
     * varies by, at most, 15+20 = 35 bytes. (We conservatively assume that
83
     * the MAC size varies from 0..20 bytes.) In case the 9 bytes of hash
84
     * termination (0x80 + 64-bit length) don't fit in the final block, we
85
     * say that the final two blocks can vary based on the padding.
86
     *
87
     * TLSv1 has MACs up to 48 bytes long (SHA-384) and the padding is not
88
     * required to be minimal. Therefore we say that the final six blocks
89
     * can vary based on the padding.
90
     *
91
     * Later in the function, if the message is short and there obviously
92
     * cannot be this many blocks then varianceBlocks can be reduced. */
93
6.54k
    unsigned int varianceBlocks = isSSLv3 ? 2 : 6;
94
    /* From now on we're dealing with the MAC, which conceptually has 13
95
     * bytes of `header' before the start of the data (TLS) or 71/75 bytes
96
     * (SSLv3) */
97
6.54k
    const unsigned int len = dataTotalLen + headerLen;
98
    /* maxMACBytes contains the maximum bytes of bytes in the MAC, including
99
     * |header|, assuming that there's no padding. */
100
6.54k
    const unsigned int maxMACBytes = len - mdSize - 1;
101
    /* numBlocks is the maximum number of hash blocks. */
102
6.54k
    const unsigned int numBlocks =
103
6.54k
        (maxMACBytes + 1 + mdLengthSize + mdBlockSize - 1) / mdBlockSize;
104
    /* macEndOffset is the index just past the end of the data to be
105
     * MACed. */
106
6.54k
    const unsigned int macEndOffset = dataLen + headerLen - mdSize;
107
    /* c is the index of the 0x80 byte in the final hash block that
108
     * contains application data. */
109
6.54k
    const unsigned int c = macEndOffset % mdBlockSize;
110
    /* indexA is the hash block number that contains the 0x80 terminating
111
     * value. */
112
6.54k
    const unsigned int indexA = macEndOffset / mdBlockSize;
113
    /* indexB is the hash block number that contains the 64-bit hash
114
     * length, in bits. */
115
6.54k
    const unsigned int indexB = (macEndOffset + mdLengthSize) / mdBlockSize;
116
    /* bits is the hash-length in bits. It includes the additional hash
117
     * block for the masked HMAC key, or whole of |header| in the case of
118
     * SSLv3. */
119
6.54k
    unsigned int bits;
120
    /* In order to calculate the MAC in constant time we have to handle
121
     * the final blocks specially because the padding value could cause the
122
     * end to appear somewhere in the final |varianceBlocks| blocks and we
123
     * can't leak where. However, |numStartingBlocks| worth of data can
124
     * be hashed right away because no padding value can affect whether
125
     * they are plaintext. */
126
6.54k
    unsigned int numStartingBlocks = 0;
127
    /* k is the starting byte offset into the conceptual header||data where
128
     * we start processing. */
129
6.54k
    unsigned int k = 0;
130
6.54k
    unsigned char lengthBytes[MAX_HASH_BIT_COUNT_BYTES];
131
    /* hmacPad is the masked HMAC key. */
132
6.54k
    unsigned char hmacPad[HASH_BLOCK_LENGTH_MAX];
133
6.54k
    unsigned char firstBlock[HASH_BLOCK_LENGTH_MAX];
134
6.54k
    unsigned char macOut[HASH_LENGTH_MAX];
135
6.54k
    unsigned i, j;
136
137
    /* For SSLv3, if we're going to have any starting blocks then we need
138
     * at least two because the header is larger than a single block. */
139
6.54k
    if (numBlocks > varianceBlocks + (isSSLv3 ? 1 : 0)) {
140
247
        numStartingBlocks = numBlocks - varianceBlocks;
141
247
        k = mdBlockSize * numStartingBlocks;
142
247
    }
143
144
6.54k
    bits = 8 * macEndOffset;
145
6.54k
    hashObj->begin(mdState);
146
6.54k
    if (!isSSLv3) {
147
        /* Compute the initial HMAC block. For SSLv3, the padding and
148
         * secret bytes are included in |header| because they take more
149
         * than a single block. */
150
6.54k
        bits += 8 * mdBlockSize;
151
6.54k
        memset(hmacPad, 0, mdBlockSize);
152
6.54k
        PORT_Assert(macSecretLen <= sizeof(hmacPad));
153
6.54k
        memcpy(hmacPad, macSecret, macSecretLen);
154
425k
        for (i = 0; i < mdBlockSize; i++)
155
419k
            hmacPad[i] ^= 0x36;
156
6.54k
        hashObj->update(mdState, hmacPad, mdBlockSize);
157
6.54k
    }
158
159
6.54k
    j = 0;
160
6.54k
    memset(lengthBytes, 0, sizeof(lengthBytes));
161
6.54k
    if (mdLengthSize == 16) {
162
0
        j = 8;
163
0
    }
164
6.54k
    if (hashObj->type == HASH_AlgMD5) {
165
        /* MD5 appends a little-endian length. */
166
0
        for (i = 0; i < 4; i++) {
167
0
            lengthBytes[i + j] = bits >> (8 * i);
168
0
        }
169
6.54k
    } else {
170
        /* All other TLS hash functions use a big-endian length. */
171
32.7k
        for (i = 0; i < 4; i++) {
172
26.1k
            lengthBytes[4 + i + j] = bits >> (8 * (3 - i));
173
26.1k
        }
174
6.54k
    }
175
176
6.54k
    if (k > 0) {
177
247
        if (isSSLv3) {
178
            /* The SSLv3 header is larger than a single block.
179
             * overhang is the number of bytes beyond a single
180
             * block that the header consumes: either 7 bytes
181
             * (SHA1) or 11 bytes (MD5). */
182
0
            const unsigned int overhang = headerLen - mdBlockSize;
183
0
            hashObj->update(mdState, header, mdBlockSize);
184
0
            memcpy(firstBlock, header + mdBlockSize, overhang);
185
0
            memcpy(firstBlock + overhang, data, mdBlockSize - overhang);
186
0
            hashObj->update(mdState, firstBlock, mdBlockSize);
187
0
            for (i = 1; i < k / mdBlockSize - 1; i++) {
188
0
                hashObj->update(mdState, data + mdBlockSize * i - overhang,
189
0
                                mdBlockSize);
190
0
            }
191
247
        } else {
192
            /* k is a multiple of mdBlockSize. */
193
247
            memcpy(firstBlock, header, 13);
194
247
            memcpy(firstBlock + 13, data, mdBlockSize - 13);
195
247
            hashObj->update(mdState, firstBlock, mdBlockSize);
196
8.81k
            for (i = 1; i < k / mdBlockSize; i++) {
197
8.56k
                hashObj->update(mdState, data + mdBlockSize * i - 13,
198
8.56k
                                mdBlockSize);
199
8.56k
            }
200
247
        }
201
247
    }
202
203
6.54k
    memset(macOut, 0, sizeof(macOut));
204
205
    /* We now process the final hash blocks. For each block, we construct
206
     * it in constant time. If i == indexA then we'll include the 0x80
207
     * bytes and zero pad etc. For each block we selectively copy it, in
208
     * constant time, to |macOut|. */
209
52.3k
    for (i = numStartingBlocks; i <= numStartingBlocks + varianceBlocks; i++) {
210
45.8k
        unsigned char block[HASH_BLOCK_LENGTH_MAX];
211
45.8k
        unsigned char isBlockA = constantTimeEQ(i, indexA);
212
45.8k
        unsigned char isBlockB = constantTimeEQ(i, indexB);
213
2.97M
        for (j = 0; j < mdBlockSize; j++) {
214
2.93M
            unsigned char isPastC = isBlockA & constantTimeGE(j, c);
215
2.93M
            unsigned char isPastCPlus1 = isBlockA & constantTimeGE(j, c + 1);
216
2.93M
            unsigned char b = 0;
217
2.93M
            if (k < headerLen) {
218
81.9k
                b = header[k];
219
2.85M
            } else if (k < dataTotalLen + headerLen) {
220
331k
                b = data[k - headerLen];
221
331k
            }
222
2.93M
            k++;
223
224
            /* If this is the block containing the end of the
225
             * application data, and we are at the offset for the
226
             * 0x80 value, then overwrite b with 0x80. */
227
2.93M
            b = (b & ~isPastC) | (0x80 & isPastC);
228
            /* If this the the block containing the end of the
229
             * application data and we're past the 0x80 value then
230
             * just write zero. */
231
2.93M
            b = b & ~isPastCPlus1;
232
            /* If this is indexB (the final block), but not
233
             * indexA (the end of the data), then the 64-bit
234
             * length didn't fit into indexA and we're having to
235
             * add an extra block of zeros. */
236
2.93M
            b &= ~isBlockB | isBlockA;
237
238
            /* The final bytes of one of the blocks contains the length. */
239
2.93M
            if (j >= mdBlockSize - mdLengthSize) {
240
                /* If this is indexB, write a length byte. */
241
366k
                b = (b & ~isBlockB) |
242
366k
                    (isBlockB & lengthBytes[j - (mdBlockSize - mdLengthSize)]);
243
366k
            }
244
2.93M
            block[j] = b;
245
2.93M
        }
246
247
45.8k
        hashObj->update(mdState, block, mdBlockSize);
248
45.8k
        hashObj->end_raw(mdState, block, NULL, mdSize);
249
        /* If this is indexB, copy the hash value to |macOut|. */
250
1.04M
        for (j = 0; j < mdSize; j++) {
251
996k
            macOut[j] |= block[j] & isBlockB;
252
996k
        }
253
45.8k
    }
254
255
6.54k
    hashObj->begin(mdState);
256
257
6.54k
    if (isSSLv3) {
258
        /* We repurpose |hmacPad| to contain the SSLv3 pad2 block. */
259
0
        for (i = 0; i < sslv3PadLen; i++)
260
0
            hmacPad[i] = 0x5c;
261
262
0
        hashObj->update(mdState, macSecret, macSecretLen);
263
0
        hashObj->update(mdState, hmacPad, sslv3PadLen);
264
0
        hashObj->update(mdState, macOut, mdSize);
265
6.54k
    } else {
266
        /* Complete the HMAC in the standard manner. */
267
425k
        for (i = 0; i < mdBlockSize; i++)
268
419k
            hmacPad[i] ^= 0x6a;
269
270
6.54k
        hashObj->update(mdState, hmacPad, mdBlockSize);
271
6.54k
        hashObj->update(mdState, macOut, mdSize);
272
6.54k
    }
273
274
6.54k
    hashObj->end(mdState, mdOut, mdOutLen, mdOutMax);
275
6.54k
    hashObj->destroy(mdState, PR_TRUE);
276
277
6.54k
    PORT_Memset(lengthBytes, 0, sizeof lengthBytes);
278
6.54k
    PORT_Memset(hmacPad, 0, sizeof hmacPad);
279
6.54k
    PORT_Memset(firstBlock, 0, sizeof firstBlock);
280
6.54k
    PORT_Memset(macOut, 0, sizeof macOut);
281
282
6.54k
    return SECSuccess;
283
6.54k
}
284
285
SECStatus
286
HMAC_ConstantTime(
287
    unsigned char *result,
288
    unsigned int *resultLen,
289
    unsigned int maxResultLen,
290
    const SECHashObject *hashObj,
291
    const unsigned char *secret,
292
    unsigned int secretLen,
293
    const unsigned char *header,
294
    unsigned int headerLen,
295
    const unsigned char *body,
296
    unsigned int bodyLen,
297
    unsigned int bodyTotalLen)
298
6.54k
{
299
6.54k
    if (hashObj->end_raw == NULL)
300
0
        return SECFailure;
301
6.54k
    return MAC(result, resultLen, maxResultLen, hashObj, secret, secretLen,
302
6.54k
               header, headerLen, body, bodyLen, bodyTotalLen,
303
6.54k
               0 /* not SSLv3 */);
304
6.54k
}
305
306
SECStatus
307
SSLv3_MAC_ConstantTime(
308
    unsigned char *result,
309
    unsigned int *resultLen,
310
    unsigned int maxResultLen,
311
    const SECHashObject *hashObj,
312
    const unsigned char *secret,
313
    unsigned int secretLen,
314
    const unsigned char *header,
315
    unsigned int headerLen,
316
    const unsigned char *body,
317
    unsigned int bodyLen,
318
    unsigned int bodyTotalLen)
319
0
{
320
0
    if (hashObj->end_raw == NULL)
321
0
        return SECFailure;
322
0
    return MAC(result, resultLen, maxResultLen, hashObj, secret, secretLen,
323
0
               header, headerLen, body, bodyLen, bodyTotalLen,
324
0
               1 /* SSLv3 */);
325
0
}