Coverage Report

Created: 2026-10-13 06:23

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/nss/lib/ssl/selfencrypt.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 "nss.h"
10
#include "blapit.h"
11
#include "pk11func.h"
12
#include "ssl.h"
13
#include "sslt.h"
14
#include "sslimpl.h"
15
#include "selfencrypt.h"
16
17
static SECStatus
18
ssl_MacBuffer(PK11SymKey *key, CK_MECHANISM_TYPE mech,
19
              const unsigned char *in, unsigned int len,
20
              unsigned char *mac, unsigned int *macLen, unsigned int maxMacLen)
21
482
{
22
482
    PK11Context *ctx;
23
482
    SECItem macParam = { 0, NULL, 0 };
24
482
    unsigned int computedLen;
25
482
    SECStatus rv;
26
27
482
    ctx = PK11_CreateContextBySymKey(mech, CKA_SIGN, key, &macParam);
28
482
    if (!ctx) {
29
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
30
0
        return SECFailure;
31
0
    }
32
33
482
    rv = PK11_DigestBegin(ctx);
34
482
    if (rv != SECSuccess) {
35
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
36
0
        goto loser;
37
0
    }
38
39
482
    rv = PK11_DigestOp(ctx, in, len);
40
482
    if (rv != SECSuccess) {
41
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
42
0
        goto loser;
43
0
    }
44
45
482
    rv = PK11_DigestFinal(ctx, mac, &computedLen, maxMacLen);
46
482
    if (rv != SECSuccess) {
47
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
48
0
        goto loser;
49
0
    }
50
51
482
    *macLen = maxMacLen;
52
482
    PK11_DestroyContext(ctx, PR_TRUE);
53
482
    return SECSuccess;
54
55
0
loser:
56
0
    PK11_DestroyContext(ctx, PR_TRUE);
57
0
    return SECFailure;
58
482
}
Unexecuted instantiation: selfencrypt.c:ssl_MacBuffer
selfencrypt.c:ssl_MacBuffer
Line
Count
Source
21
482
{
22
482
    PK11Context *ctx;
23
482
    SECItem macParam = { 0, NULL, 0 };
24
482
    unsigned int computedLen;
25
482
    SECStatus rv;
26
27
482
    ctx = PK11_CreateContextBySymKey(mech, CKA_SIGN, key, &macParam);
28
482
    if (!ctx) {
29
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
30
0
        return SECFailure;
31
0
    }
32
33
482
    rv = PK11_DigestBegin(ctx);
34
482
    if (rv != SECSuccess) {
35
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
36
0
        goto loser;
37
0
    }
38
39
482
    rv = PK11_DigestOp(ctx, in, len);
40
482
    if (rv != SECSuccess) {
41
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
42
0
        goto loser;
43
0
    }
44
45
482
    rv = PK11_DigestFinal(ctx, mac, &computedLen, maxMacLen);
46
482
    if (rv != SECSuccess) {
47
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
48
0
        goto loser;
49
0
    }
50
51
482
    *macLen = maxMacLen;
52
482
    PK11_DestroyContext(ctx, PR_TRUE);
53
482
    return SECSuccess;
54
55
0
loser:
56
0
    PK11_DestroyContext(ctx, PR_TRUE);
57
0
    return SECFailure;
58
482
}
59
60
#ifdef UNSAFE_FUZZER_MODE
61
SECStatus
62
ssl_SelfEncryptProtectInt(
63
    PK11SymKey *encKey, PK11SymKey *macKey,
64
    const unsigned char *keyName,
65
    const PRUint8 *in, unsigned int inLen,
66
    PRUint8 *out, unsigned int *outLen, unsigned int maxOutLen)
67
3.73k
{
68
3.73k
    if (inLen > maxOutLen) {
69
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
70
0
        return SECFailure;
71
0
    }
72
73
3.73k
    PORT_Memcpy(out, in, inLen);
74
3.73k
    *outLen = inLen;
75
76
3.73k
    return 0;
77
3.73k
}
78
79
SECStatus
80
ssl_SelfEncryptUnprotectInt(
81
    PK11SymKey *encKey, PK11SymKey *macKey, const unsigned char *keyName,
82
    const PRUint8 *in, unsigned int inLen,
83
    PRUint8 *out, unsigned int *outLen, unsigned int maxOutLen)
84
1.30k
{
85
1.30k
    if (inLen > maxOutLen) {
86
5
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
87
5
        return SECFailure;
88
5
    }
89
90
1.30k
    PORT_Memcpy(out, in, inLen);
91
1.30k
    *outLen = inLen;
92
93
1.30k
    return 0;
94
1.30k
}
95
96
#else
97
/*
98
 * Structure is.
99
 *
100
 * struct {
101
 *   opaque keyName[16];
102
 *   opaque iv[16];
103
 *   opaque ciphertext<16..2^16-1>;
104
 *   opaque mac[32];
105
 * } SelfEncrypted;
106
 *
107
 * We are using AES-CBC + HMAC-SHA256 in Encrypt-then-MAC mode for
108
 * two reasons:
109
 *
110
 * 1. It's what we already used for tickets.
111
 * 2. We don't have to worry about nonce collisions as much
112
 *    (the chance is lower because we have a random 128-bit nonce
113
 *    and they are less serious than with AES-GCM).
114
 */
115
SECStatus
116
ssl_SelfEncryptProtectInt(
117
    PK11SymKey *encKey, PK11SymKey *macKey,
118
    const unsigned char *keyName,
119
    const PRUint8 *in, unsigned int inLen,
120
    PRUint8 *out, unsigned int *outLen, unsigned int maxOutLen)
121
464
{
122
464
    unsigned int len;
123
464
    unsigned int lenOffset;
124
464
    unsigned char iv[AES_BLOCK_SIZE];
125
464
    SECItem ivItem = { siBuffer, iv, sizeof(iv) };
126
    /* Write directly to out. */
127
464
    sslBuffer buf = SSL_BUFFER_FIXED(out, maxOutLen);
128
464
    SECStatus rv;
129
130
    /* Generate a random IV */
131
464
    rv = PK11_GenerateRandom(iv, sizeof(iv));
132
464
    if (rv != SECSuccess) {
133
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
134
0
        return SECFailure;
135
0
    }
136
137
    /* Add header. */
138
464
    rv = sslBuffer_Append(&buf, keyName, SELF_ENCRYPT_KEY_NAME_LEN);
139
464
    if (rv != SECSuccess) {
140
0
        return SECFailure;
141
0
    }
142
464
    rv = sslBuffer_Append(&buf, iv, sizeof(iv));
143
464
    if (rv != SECSuccess) {
144
0
        return SECFailure;
145
0
    }
146
147
    /* Leave space for the length of the ciphertext. */
148
464
    rv = sslBuffer_Skip(&buf, 2, &lenOffset);
149
464
    if (rv != SECSuccess) {
150
0
        return SECFailure;
151
0
    }
152
153
    /* Encode the ciphertext in place. */
154
464
    rv = PK11_Encrypt(encKey, CKM_AES_CBC_PAD, &ivItem,
155
464
                      SSL_BUFFER_NEXT(&buf), &len,
156
464
                      SSL_BUFFER_SPACE(&buf), in, inLen);
157
464
    if (rv != SECSuccess) {
158
0
        return SECFailure;
159
0
    }
160
464
    rv = sslBuffer_Skip(&buf, len, NULL);
161
464
    if (rv != SECSuccess) {
162
0
        return SECFailure;
163
0
    }
164
165
464
    rv = sslBuffer_InsertLength(&buf, lenOffset, 2);
166
464
    if (rv != SECSuccess) {
167
0
        return SECFailure;
168
0
    }
169
170
    /* MAC the entire output buffer into the output. */
171
464
    PORT_Assert(buf.space - buf.len >= SHA256_LENGTH);
172
464
    rv = ssl_MacBuffer(macKey, CKM_SHA256_HMAC,
173
464
                       SSL_BUFFER_BASE(&buf), /* input */
174
464
                       SSL_BUFFER_LEN(&buf),
175
464
                       SSL_BUFFER_NEXT(&buf), &len, /* output */
176
464
                       SHA256_LENGTH);
177
464
    if (rv != SECSuccess) {
178
0
        return SECFailure;
179
0
    }
180
464
    rv = sslBuffer_Skip(&buf, len, NULL);
181
464
    if (rv != SECSuccess) {
182
0
        return SECFailure;
183
0
    }
184
185
464
    *outLen = SSL_BUFFER_LEN(&buf);
186
464
    return SECSuccess;
187
464
}
188
189
SECStatus
190
ssl_SelfEncryptUnprotectInt(
191
    PK11SymKey *encKey, PK11SymKey *macKey, const unsigned char *keyName,
192
    const PRUint8 *in, unsigned int inLen,
193
    PRUint8 *out, unsigned int *outLen, unsigned int maxOutLen)
194
295
{
195
295
    sslReader reader = SSL_READER(in, inLen);
196
197
295
    sslReadBuffer encodedKeyNameBuffer = { 0 };
198
295
    SECStatus rv = sslRead_Read(&reader, SELF_ENCRYPT_KEY_NAME_LEN,
199
295
                                &encodedKeyNameBuffer);
200
295
    if (rv != SECSuccess) {
201
136
        return SECFailure;
202
136
    }
203
204
159
    sslReadBuffer ivBuffer = { 0 };
205
159
    rv = sslRead_Read(&reader, AES_BLOCK_SIZE, &ivBuffer);
206
159
    if (rv != SECSuccess) {
207
66
        return SECFailure;
208
66
    }
209
210
93
    PRUint64 cipherTextLen = 0;
211
93
    rv = sslRead_ReadNumber(&reader, 2, &cipherTextLen);
212
93
    if (rv != SECSuccess) {
213
4
        return SECFailure;
214
4
    }
215
216
89
    sslReadBuffer cipherTextBuffer = { 0 };
217
89
    rv = sslRead_Read(&reader, (unsigned int)cipherTextLen, &cipherTextBuffer);
218
89
    if (rv != SECSuccess) {
219
20
        return SECFailure;
220
20
    }
221
69
    unsigned int bytesToMac = reader.offset;
222
223
69
    sslReadBuffer encodedMacBuffer = { 0 };
224
69
    rv = sslRead_Read(&reader, SHA256_LENGTH, &encodedMacBuffer);
225
69
    if (rv != SECSuccess) {
226
10
        return SECFailure;
227
10
    }
228
229
    /* Make sure we're at the end of the block. */
230
59
    if (reader.offset != reader.buf.len) {
231
11
        PORT_SetError(SEC_ERROR_BAD_DATA);
232
11
        return SECFailure;
233
11
    }
234
235
    /* Now that everything is decoded, we can make progress. */
236
    /* 1. Check that we have the right key. */
237
48
    if (PORT_Memcmp(keyName, encodedKeyNameBuffer.buf, SELF_ENCRYPT_KEY_NAME_LEN)) {
238
30
        PORT_SetError(SEC_ERROR_NOT_A_RECIPIENT);
239
30
        return SECFailure;
240
30
    }
241
242
    /* 2. Check the MAC */
243
18
    unsigned char computedMac[SHA256_LENGTH];
244
18
    unsigned int computedMacLen = 0;
245
18
    rv = ssl_MacBuffer(macKey, CKM_SHA256_HMAC, in, bytesToMac,
246
18
                       computedMac, &computedMacLen, sizeof(computedMac));
247
18
    if (rv != SECSuccess) {
248
0
        return SECFailure;
249
0
    }
250
18
    PORT_Assert(computedMacLen == SHA256_LENGTH);
251
18
    if (NSS_SecureMemcmp(computedMac, encodedMacBuffer.buf, computedMacLen) != 0) {
252
18
        PORT_SetError(SEC_ERROR_BAD_DATA);
253
18
        return SECFailure;
254
18
    }
255
256
    /* 3. OK, it verifies, now decrypt. */
257
0
    SECItem ivItem = { siBuffer, (unsigned char *)ivBuffer.buf, AES_BLOCK_SIZE };
258
0
    rv = PK11_Decrypt(encKey, CKM_AES_CBC_PAD, &ivItem,
259
0
                      out, outLen, maxOutLen, cipherTextBuffer.buf, cipherTextLen);
260
0
    if (rv != SECSuccess) {
261
0
        return SECFailure;
262
0
    }
263
264
0
    return SECSuccess;
265
0
}
266
#endif
267
268
/* Predict the size of the encrypted data, including padding */
269
unsigned int
270
ssl_SelfEncryptGetProtectedSize(unsigned int inLen)
271
3.26k
{
272
3.26k
    return SELF_ENCRYPT_KEY_NAME_LEN +
273
3.26k
           AES_BLOCK_SIZE +
274
3.26k
           2 +
275
3.26k
           ((inLen / AES_BLOCK_SIZE) + 1) * AES_BLOCK_SIZE + /* Padded */
276
3.26k
           SHA256_LENGTH;
277
3.26k
}
278
279
SECStatus
280
ssl_SelfEncryptProtect(
281
    sslSocket *ss, const PRUint8 *in, unsigned int inLen,
282
    PRUint8 *out, unsigned int *outLen, unsigned int maxOutLen)
283
4.19k
{
284
4.19k
    PRUint8 keyName[SELF_ENCRYPT_KEY_NAME_LEN];
285
4.19k
    PK11SymKey *encKey;
286
4.19k
    PK11SymKey *macKey;
287
4.19k
    SECStatus rv;
288
289
    /* Get session ticket keys. */
290
4.19k
    rv = ssl_GetSelfEncryptKeys(ss, keyName, &encKey, &macKey);
291
4.19k
    if (rv != SECSuccess) {
292
0
        SSL_DBG(("%d: SSL[%d]: Unable to get/generate self-encrypt keys.",
293
0
                 SSL_GETPID(), ss->fd));
294
0
        return SECFailure;
295
0
    }
296
297
4.19k
    return ssl_SelfEncryptProtectInt(encKey, macKey, keyName,
298
4.19k
                                     in, inLen, out, outLen, maxOutLen);
299
4.19k
}
300
301
SECStatus
302
ssl_SelfEncryptUnprotect(
303
    sslSocket *ss, const PRUint8 *in, unsigned int inLen,
304
    PRUint8 *out, unsigned int *outLen, unsigned int maxOutLen)
305
1.60k
{
306
1.60k
    PRUint8 keyName[SELF_ENCRYPT_KEY_NAME_LEN];
307
1.60k
    PK11SymKey *encKey;
308
1.60k
    PK11SymKey *macKey;
309
1.60k
    SECStatus rv;
310
311
    /* Get session ticket keys. */
312
1.60k
    rv = ssl_GetSelfEncryptKeys(ss, keyName, &encKey, &macKey);
313
1.60k
    if (rv != SECSuccess) {
314
0
        SSL_DBG(("%d: SSL[%d]: Unable to get/generate self-encrypt keys.",
315
0
                 SSL_GETPID(), ss->fd));
316
0
        return SECFailure;
317
0
    }
318
319
1.60k
    return ssl_SelfEncryptUnprotectInt(encKey, macKey, keyName,
320
1.60k
                                       in, inLen, out, outLen, maxOutLen);
321
1.60k
}