Coverage Report

Created: 2026-02-18 06:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/nss/lib/ssl/tls13hashstate.c
Line
Count
Source
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/*
3
 * This file is PRIVATE to SSL.
4
 *
5
 * This Source Code Form is subject to the terms of the Mozilla Public
6
 * License, v. 2.0. If a copy of the MPL was not distributed with this
7
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8
9
#include "pk11func.h"
10
#include "ssl.h"
11
#include "sslt.h"
12
#include "sslimpl.h"
13
#include "selfencrypt.h"
14
#include "tls13con.h"
15
#include "tls13ech.h"
16
#include "tls13err.h"
17
#include "tls13hashstate.h"
18
19
/*
20
 * The cookie is structured as a self-encrypted structure with the
21
 * inner value being.
22
 *
23
 * struct {
24
 *     uint8 indicator = 0xff;            // To disambiguate from tickets.
25
 *     uint16 cipherSuite;                // Selected cipher suite.
26
 *     uint16 keyShare;                   // Requested key share group (0=none)
27
 *     PRUint8 echConfigId;               // ECH config_id
28
 *     HpkeKdfId kdfId;                   // ECH KDF (uint16)
29
 *     HpkeAeadId aeadId;                 // ECH AEAD (uint16)
30
 *     opaque echHpkeCtx<0..65535>;       // ECH serialized HPKE context
31
 *     opaque applicationToken<0..65535>; // Application token
32
 *     opaque ch_hash[rest_of_buffer];    // H(ClientHello)
33
 * } CookieInner;
34
 *
35
 * An empty echConfigId means that ECH was not offered in the first ClientHello.
36
 * An empty echHrrPsk means that ECH was not accepted in CH1.
37
 */
38
SECStatus
39
tls13_MakeHrrCookie(sslSocket *ss, const sslNamedGroupDef *selectedGroup,
40
                    const PRUint8 *appToken, unsigned int appTokenLen,
41
                    PRUint8 *buf, unsigned int *len, unsigned int maxlen)
42
956
{
43
956
    SECStatus rv;
44
956
    SSL3Hashes hashes;
45
956
    PRUint8 cookie[1024];
46
956
    sslBuffer cookieBuf = SSL_BUFFER(cookie);
47
956
    static const PRUint8 indicator = 0xff;
48
956
    SECItem *echHpkeCtx = NULL;
49
50
    /* Encode header. */
51
956
    rv = sslBuffer_Append(&cookieBuf, &indicator, 1);
52
956
    if (rv != SECSuccess) {
53
0
        return SECFailure;
54
0
    }
55
956
    rv = sslBuffer_AppendNumber(&cookieBuf, ss->ssl3.hs.cipher_suite, 2);
56
956
    if (rv != SECSuccess) {
57
0
        return SECFailure;
58
0
    }
59
956
    rv = sslBuffer_AppendNumber(&cookieBuf,
60
956
                                selectedGroup ? selectedGroup->name : 0, 2);
61
956
    if (rv != SECSuccess) {
62
0
        return SECFailure;
63
0
    }
64
65
956
    if (ss->xtnData.ech) {
66
        /* Record that we received ECH. See sslEchCookieData */
67
40
        rv = sslBuffer_AppendNumber(&cookieBuf, PR_TRUE, 1);
68
40
        if (rv != SECSuccess) {
69
0
            return SECFailure;
70
0
        }
71
72
40
        rv = sslBuffer_AppendNumber(&cookieBuf, ss->xtnData.ech->configId,
73
40
                                    1);
74
40
        if (rv != SECSuccess) {
75
0
            return SECFailure;
76
0
        }
77
78
40
        rv = sslBuffer_AppendNumber(&cookieBuf, ss->xtnData.ech->kdfId, 2);
79
40
        if (rv != SECSuccess) {
80
0
            return SECFailure;
81
0
        }
82
40
        rv = sslBuffer_AppendNumber(&cookieBuf, ss->xtnData.ech->aeadId, 2);
83
40
        if (rv != SECSuccess) {
84
0
            return SECFailure;
85
0
        }
86
        /* We need to send a ECH HRR Extension containing a signal for the client,
87
         * we must store the signal in the cookie so we can reconstruct the transcript
88
         * later. To avoid leaking whether ECH was accepted in the length of the cookie
89
         * we include the empty signal in the cookie regardless.
90
         */
91
40
        PR_ASSERT(SSL_BUFFER_LEN(&ss->ssl3.hs.greaseEchBuf) == TLS13_ECH_SIGNAL_LEN);
92
40
        rv = sslBuffer_AppendBuffer(&cookieBuf, &ss->ssl3.hs.greaseEchBuf);
93
40
        if (rv != SECSuccess) {
94
0
            return SECFailure;
95
0
        }
96
97
        /* There might be no HPKE Context, e.g. when we lack a matching ECHConfig. */
98
40
        if (ss->ssl3.hs.echHpkeCtx) {
99
0
            rv = PK11_HPKE_ExportContext(ss->ssl3.hs.echHpkeCtx, NULL, &echHpkeCtx);
100
0
            if (rv != SECSuccess) {
101
0
                return SECFailure;
102
0
            }
103
0
            rv = sslBuffer_AppendVariable(&cookieBuf, echHpkeCtx->data, echHpkeCtx->len, 2);
104
0
            SECITEM_ZfreeItem(echHpkeCtx, PR_TRUE);
105
40
        } else {
106
            /* Zero length HPKE context. */
107
40
            rv = sslBuffer_AppendNumber(&cookieBuf, 0, 2);
108
40
        }
109
40
        if (rv != SECSuccess) {
110
0
            return SECFailure;
111
0
        }
112
916
    } else {
113
916
        rv = sslBuffer_AppendNumber(&cookieBuf, PR_FALSE, 1);
114
916
        if (rv != SECSuccess) {
115
0
            return SECFailure;
116
0
        }
117
916
    }
118
119
    /* Application token. */
120
956
    rv = sslBuffer_AppendVariable(&cookieBuf, appToken, appTokenLen, 2);
121
956
    if (rv != SECSuccess) {
122
0
        return SECFailure;
123
0
    }
124
125
    /* Compute and encode hashes. */
126
956
    rv = tls13_ComputeHandshakeHashes(ss, &hashes);
127
956
    if (rv != SECSuccess) {
128
0
        return SECFailure;
129
0
    }
130
956
    rv = sslBuffer_Append(&cookieBuf, hashes.u.raw, hashes.len);
131
956
    if (rv != SECSuccess) {
132
0
        return SECFailure;
133
0
    }
134
135
    /* Encrypt right into the buffer. */
136
956
    rv = ssl_SelfEncryptProtect(ss, cookieBuf.buf, cookieBuf.len,
137
956
                                buf, len, maxlen);
138
956
    if (rv != SECSuccess) {
139
0
        return SECFailure;
140
0
    }
141
142
956
    return SECSuccess;
143
956
}
144
145
/* Given a cookie and cookieLen, decrypt and parse, returning
146
 * any values that were requested via the "previous_" params. If
147
 * recoverState is true, the transcript state and application
148
 * token are restored. Note that previousEchKdfId, previousEchAeadId,
149
 * previousEchConfigId, and previousEchHpkeCtx are not modified if ECH was not
150
 * previously negotiated (i.e., previousEchOffered is PR_FALSE). */
151
SECStatus
152
tls13_HandleHrrCookie(sslSocket *ss,
153
                      unsigned char *cookie, unsigned int cookieLen,
154
                      ssl3CipherSuite *previousCipherSuite,
155
                      const sslNamedGroupDef **previousGroup,
156
                      PRBool *previousOfferedEch,
157
                      sslEchCookieData *echData,
158
                      PRBool recoverState)
159
224
{
160
224
    SECStatus rv;
161
224
    unsigned char plaintext[1024];
162
224
    unsigned int plaintextLen = 0;
163
224
    sslBuffer messageBuf = SSL_BUFFER_EMPTY;
164
224
    sslReadBuffer echHpkeBuf = { 0 };
165
224
    PRBool receivedEch;
166
224
    PRUint64 sentinel;
167
224
    PRUint64 cipherSuite;
168
224
    sslEchCookieData parsedEchData = { 0 };
169
224
    sslReadBuffer greaseReadBuf = { 0 };
170
224
    PRUint64 group;
171
224
    PRUint64 tmp64;
172
224
    const sslNamedGroupDef *selectedGroup;
173
224
    PRUint64 appTokenLen;
174
175
224
    rv = ssl_SelfEncryptUnprotect(ss, cookie, cookieLen,
176
224
                                  plaintext, &plaintextLen, sizeof(plaintext));
177
224
    if (rv != SECSuccess) {
178
80
        SSL_TRC(100, ("Error decrypting cookie."));
179
80
        return SECFailure;
180
80
    }
181
182
144
    sslReader reader = SSL_READER(plaintext, plaintextLen);
183
184
    /* Should start with the sentinel value. */
185
144
    rv = sslRead_ReadNumber(&reader, 1, &sentinel);
186
144
    if ((rv != SECSuccess) || (sentinel != TLS13_COOKIE_SENTINEL)) {
187
17
        FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
188
17
        return SECFailure;
189
17
    }
190
    /* The cipher suite should be the same or there are some shenanigans. */
191
127
    rv = sslRead_ReadNumber(&reader, 2, &cipherSuite);
192
127
    if (rv != SECSuccess) {
193
3
        FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
194
3
        return SECFailure;
195
3
    }
196
197
    /* The named group, if any. */
198
124
    rv = sslRead_ReadNumber(&reader, 2, &group);
199
124
    if (rv != SECSuccess) {
200
3
        FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
201
3
        return SECFailure;
202
3
    }
203
121
    selectedGroup = ssl_LookupNamedGroup(group);
204
205
    /* Was ECH received. */
206
121
    rv = sslRead_ReadNumber(&reader, 1, &tmp64);
207
121
    if (rv != SECSuccess) {
208
1
        FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
209
1
        return SECFailure;
210
1
    }
211
120
    receivedEch = tmp64 == PR_TRUE;
212
120
    *previousOfferedEch = receivedEch;
213
120
    if (receivedEch) {
214
        /* ECH config ID */
215
46
        rv = sslRead_ReadNumber(&reader, 1, &tmp64);
216
46
        if (rv != SECSuccess) {
217
1
            FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
218
1
            return SECFailure;
219
1
        }
220
45
        parsedEchData.configId = (PRUint8)tmp64;
221
222
        /* ECH Ciphersuite */
223
45
        rv = sslRead_ReadNumber(&reader, 2, &tmp64);
224
45
        if (rv != SECSuccess) {
225
1
            FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
226
1
            return SECFailure;
227
1
        }
228
44
        parsedEchData.kdfId = (HpkeKdfId)tmp64;
229
230
44
        rv = sslRead_ReadNumber(&reader, 2, &tmp64);
231
44
        if (rv != SECSuccess) {
232
2
            FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
233
2
            return SECFailure;
234
2
        }
235
42
        parsedEchData.aeadId = (HpkeAeadId)tmp64;
236
237
        /* ECH accept_confirmation signal. */
238
42
        rv = sslRead_Read(&reader, TLS13_ECH_SIGNAL_LEN, &greaseReadBuf);
239
42
        if (rv != SECSuccess) {
240
3
            FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
241
3
            return SECFailure;
242
3
        }
243
39
        PORT_Memcpy(parsedEchData.signal, greaseReadBuf.buf, TLS13_ECH_SIGNAL_LEN);
244
245
        /* ECH HPKE context may be empty. */
246
39
        rv = sslRead_ReadVariable(&reader, 2, &echHpkeBuf);
247
39
        if (rv != SECSuccess) {
248
5
            FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
249
5
            return SECFailure;
250
5
        }
251
34
        if (echData && echHpkeBuf.len) {
252
3
            const SECItem hpkeItem = { siBuffer, CONST_CAST(unsigned char, echHpkeBuf.buf),
253
3
                                       echHpkeBuf.len };
254
3
            parsedEchData.hpkeCtx = PK11_HPKE_ImportContext(&hpkeItem, NULL);
255
3
            if (!parsedEchData.hpkeCtx) {
256
3
                FATAL_ERROR(ss, PORT_GetError(), illegal_parameter);
257
3
                return SECFailure;
258
3
            }
259
3
        }
260
34
    }
261
262
    /* Application token. */
263
105
    rv = sslRead_ReadNumber(&reader, 2, &appTokenLen);
264
105
    if (rv != SECSuccess) {
265
2
        FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
266
2
        return SECFailure;
267
2
    }
268
103
    sslReadBuffer appTokenReader = { 0 };
269
103
    rv = sslRead_Read(&reader, appTokenLen, &appTokenReader);
270
103
    if (rv != SECSuccess) {
271
54
        FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
272
54
        return SECFailure;
273
54
    }
274
49
    PORT_Assert(appTokenReader.len == appTokenLen);
275
276
49
    if (recoverState) {
277
14
        PORT_Assert(ss->xtnData.applicationToken.len == 0);
278
14
        if (SECITEM_AllocItem(NULL, &ss->xtnData.applicationToken,
279
14
                              appTokenLen) == NULL) {
280
0
            FATAL_ERROR(ss, PORT_GetError(), internal_error);
281
0
            return SECFailure;
282
0
        }
283
14
        PORT_Memcpy(ss->xtnData.applicationToken.data, appTokenReader.buf, appTokenLen);
284
14
        ss->xtnData.applicationToken.len = appTokenLen;
285
286
        /* The remainder is the hash. */
287
14
        unsigned int hashLen = SSL_READER_REMAINING(&reader);
288
14
        if (hashLen != tls13_GetHashSize(ss)) {
289
14
            FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
290
14
            return SECFailure;
291
14
        }
292
293
        /* Now reinject the message. */
294
0
        SSL_ASSERT_HASHES_EMPTY(ss);
295
0
        rv = ssl_HashHandshakeMessageInt(ss, ssl_hs_message_hash, 0,
296
0
                                         SSL_READER_CURRENT(&reader), hashLen,
297
0
                                         ssl3_UpdateHandshakeHashes);
298
0
        if (rv != SECSuccess) {
299
0
            return SECFailure;
300
0
        }
301
302
        /* And finally reinject the HRR. */
303
0
        rv = tls13_ConstructHelloRetryRequest(ss, cipherSuite,
304
0
                                              selectedGroup,
305
0
                                              cookie, cookieLen,
306
0
                                              parsedEchData.signal,
307
0
                                              &messageBuf);
308
0
        if (rv != SECSuccess) {
309
0
            return SECFailure;
310
0
        }
311
312
0
        rv = ssl_HashHandshakeMessageInt(ss, ssl_hs_server_hello, 0,
313
0
                                         SSL_BUFFER_BASE(&messageBuf),
314
0
                                         SSL_BUFFER_LEN(&messageBuf),
315
0
                                         ssl3_UpdateHandshakeHashes);
316
0
        sslBuffer_Clear(&messageBuf);
317
0
        if (rv != SECSuccess) {
318
0
            return SECFailure;
319
0
        }
320
0
    }
321
322
35
    if (previousCipherSuite) {
323
0
        *previousCipherSuite = cipherSuite;
324
0
    }
325
35
    if (previousGroup) {
326
0
        *previousGroup = selectedGroup;
327
0
    }
328
35
    if (echData) {
329
35
        PORT_Memcpy(echData, &parsedEchData, sizeof(parsedEchData));
330
35
    }
331
35
    return SECSuccess;
332
49
}