Coverage Report

Created: 2026-05-19 06:33

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
978
{
43
978
    SECStatus rv;
44
978
    SSL3Hashes hashes;
45
978
    PRUint8 cookie[1024];
46
978
    sslBuffer cookieBuf = SSL_BUFFER(cookie);
47
978
    static const PRUint8 indicator = 0xff;
48
978
    SECItem *echHpkeCtx = NULL;
49
50
    /* Encode header. */
51
978
    rv = sslBuffer_Append(&cookieBuf, &indicator, 1);
52
978
    if (rv != SECSuccess) {
53
0
        return SECFailure;
54
0
    }
55
978
    rv = sslBuffer_AppendNumber(&cookieBuf, ss->ssl3.hs.cipher_suite, 2);
56
978
    if (rv != SECSuccess) {
57
0
        return SECFailure;
58
0
    }
59
978
    rv = sslBuffer_AppendNumber(&cookieBuf,
60
978
                                selectedGroup ? selectedGroup->name : 0, 2);
61
978
    if (rv != SECSuccess) {
62
0
        return SECFailure;
63
0
    }
64
65
978
    if (ss->xtnData.ech) {
66
        /* Record that we received ECH. See sslEchCookieData */
67
42
        rv = sslBuffer_AppendNumber(&cookieBuf, PR_TRUE, 1);
68
42
        if (rv != SECSuccess) {
69
0
            return SECFailure;
70
0
        }
71
72
42
        rv = sslBuffer_AppendNumber(&cookieBuf, ss->xtnData.ech->configId,
73
42
                                    1);
74
42
        if (rv != SECSuccess) {
75
0
            return SECFailure;
76
0
        }
77
78
42
        rv = sslBuffer_AppendNumber(&cookieBuf, ss->xtnData.ech->kdfId, 2);
79
42
        if (rv != SECSuccess) {
80
0
            return SECFailure;
81
0
        }
82
42
        rv = sslBuffer_AppendNumber(&cookieBuf, ss->xtnData.ech->aeadId, 2);
83
42
        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
42
        PR_ASSERT(SSL_BUFFER_LEN(&ss->ssl3.hs.greaseEchBuf) == TLS13_ECH_SIGNAL_LEN);
92
42
        rv = sslBuffer_AppendBuffer(&cookieBuf, &ss->ssl3.hs.greaseEchBuf);
93
42
        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
42
        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
42
        } else {
106
            /* Zero length HPKE context. */
107
42
            rv = sslBuffer_AppendNumber(&cookieBuf, 0, 2);
108
42
        }
109
42
        if (rv != SECSuccess) {
110
0
            return SECFailure;
111
0
        }
112
936
    } else {
113
936
        rv = sslBuffer_AppendNumber(&cookieBuf, PR_FALSE, 1);
114
936
        if (rv != SECSuccess) {
115
0
            return SECFailure;
116
0
        }
117
936
    }
118
119
    /* Application token. */
120
978
    rv = sslBuffer_AppendVariable(&cookieBuf, appToken, appTokenLen, 2);
121
978
    if (rv != SECSuccess) {
122
0
        return SECFailure;
123
0
    }
124
125
    /* Compute and encode hashes. */
126
978
    rv = tls13_ComputeHandshakeHashes(ss, &hashes);
127
978
    if (rv != SECSuccess) {
128
0
        return SECFailure;
129
0
    }
130
978
    rv = sslBuffer_Append(&cookieBuf, hashes.u.raw, hashes.len);
131
978
    if (rv != SECSuccess) {
132
0
        return SECFailure;
133
0
    }
134
135
    /* Encrypt right into the buffer. */
136
978
    rv = ssl_SelfEncryptProtect(ss, cookieBuf.buf, cookieBuf.len,
137
978
                                buf, len, maxlen);
138
978
    if (rv != SECSuccess) {
139
0
        return SECFailure;
140
0
    }
141
142
978
    return SECSuccess;
143
978
}
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
242
{
160
242
    SECStatus rv;
161
242
    unsigned char plaintext[1024];
162
242
    unsigned int plaintextLen = 0;
163
242
    sslBuffer messageBuf = SSL_BUFFER_EMPTY;
164
242
    sslReadBuffer echHpkeBuf = { 0 };
165
242
    PRBool receivedEch;
166
242
    PRUint64 sentinel;
167
242
    PRUint64 cipherSuite;
168
242
    sslEchCookieData parsedEchData = { 0 };
169
242
    sslReadBuffer greaseReadBuf = { 0 };
170
242
    PRUint64 group;
171
242
    PRUint64 tmp64;
172
242
    const sslNamedGroupDef *selectedGroup;
173
242
    PRUint64 appTokenLen;
174
175
242
    rv = ssl_SelfEncryptUnprotect(ss, cookie, cookieLen,
176
242
                                  plaintext, &plaintextLen, sizeof(plaintext));
177
242
    if (rv != SECSuccess) {
178
79
        SSL_TRC(100, ("Error decrypting cookie."));
179
79
        return SECFailure;
180
79
    }
181
182
163
    sslReader reader = SSL_READER(plaintext, plaintextLen);
183
184
    /* Should start with the sentinel value. */
185
163
    rv = sslRead_ReadNumber(&reader, 1, &sentinel);
186
163
    if ((rv != SECSuccess) || (sentinel != TLS13_COOKIE_SENTINEL)) {
187
32
        FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
188
32
        return SECFailure;
189
32
    }
190
    /* The cipher suite should be the same or there are some shenanigans. */
191
131
    rv = sslRead_ReadNumber(&reader, 2, &cipherSuite);
192
131
    if (rv != SECSuccess) {
193
2
        FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
194
2
        return SECFailure;
195
2
    }
196
197
    /* The named group, if any. */
198
129
    rv = sslRead_ReadNumber(&reader, 2, &group);
199
129
    if (rv != SECSuccess) {
200
2
        FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
201
2
        return SECFailure;
202
2
    }
203
127
    selectedGroup = ssl_LookupNamedGroup(group);
204
205
    /* Was ECH received. */
206
127
    rv = sslRead_ReadNumber(&reader, 1, &tmp64);
207
127
    if (rv != SECSuccess) {
208
1
        FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
209
1
        return SECFailure;
210
1
    }
211
126
    receivedEch = tmp64 == PR_TRUE;
212
126
    *previousOfferedEch = receivedEch;
213
126
    if (receivedEch) {
214
        /* ECH config ID */
215
63
        rv = sslRead_ReadNumber(&reader, 1, &tmp64);
216
63
        if (rv != SECSuccess) {
217
1
            FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
218
1
            return SECFailure;
219
1
        }
220
62
        parsedEchData.configId = (PRUint8)tmp64;
221
222
        /* ECH Ciphersuite */
223
62
        rv = sslRead_ReadNumber(&reader, 2, &tmp64);
224
62
        if (rv != SECSuccess) {
225
1
            FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
226
1
            return SECFailure;
227
1
        }
228
61
        parsedEchData.kdfId = (HpkeKdfId)tmp64;
229
230
61
        rv = sslRead_ReadNumber(&reader, 2, &tmp64);
231
61
        if (rv != SECSuccess) {
232
2
            FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
233
2
            return SECFailure;
234
2
        }
235
59
        parsedEchData.aeadId = (HpkeAeadId)tmp64;
236
237
        /* ECH accept_confirmation signal. */
238
59
        rv = sslRead_Read(&reader, TLS13_ECH_SIGNAL_LEN, &greaseReadBuf);
239
59
        if (rv != SECSuccess) {
240
4
            FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
241
4
            return SECFailure;
242
4
        }
243
55
        PORT_Memcpy(parsedEchData.signal, greaseReadBuf.buf, TLS13_ECH_SIGNAL_LEN);
244
245
        /* ECH HPKE context may be empty. */
246
55
        rv = sslRead_ReadVariable(&reader, 2, &echHpkeBuf);
247
55
        if (rv != SECSuccess) {
248
4
            FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
249
4
            return SECFailure;
250
4
        }
251
51
        if (echData && echHpkeBuf.len) {
252
5
            const SECItem hpkeItem = { siBuffer, CONST_CAST(unsigned char, echHpkeBuf.buf),
253
5
                                       echHpkeBuf.len };
254
5
            parsedEchData.hpkeCtx = PK11_HPKE_ImportContext(&hpkeItem, NULL);
255
5
            if (!parsedEchData.hpkeCtx) {
256
5
                FATAL_ERROR(ss, PORT_GetError(), illegal_parameter);
257
5
                return SECFailure;
258
5
            }
259
5
        }
260
51
    }
261
262
    /* Application token. */
263
109
    rv = sslRead_ReadNumber(&reader, 2, &appTokenLen);
264
109
    if (rv != SECSuccess) {
265
3
        FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
266
3
        return SECFailure;
267
3
    }
268
106
    sslReadBuffer appTokenReader = { 0 };
269
106
    rv = sslRead_Read(&reader, appTokenLen, &appTokenReader);
270
106
    if (rv != SECSuccess) {
271
42
        FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
272
42
        return SECFailure;
273
42
    }
274
64
    PORT_Assert(appTokenReader.len == appTokenLen);
275
276
64
    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
50
    if (previousCipherSuite) {
323
0
        *previousCipherSuite = cipherSuite;
324
0
    }
325
50
    if (previousGroup) {
326
0
        *previousGroup = selectedGroup;
327
0
    }
328
50
    if (echData) {
329
50
        PORT_Memcpy(echData, &parsedEchData, sizeof(parsedEchData));
330
50
    }
331
50
    return SECSuccess;
332
64
}