Coverage Report

Created: 2026-05-19 06:33

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
497
{
22
497
    PK11Context *ctx;
23
497
    SECItem macParam = { 0, NULL, 0 };
24
497
    unsigned int computedLen;
25
497
    SECStatus rv;
26
27
497
    ctx = PK11_CreateContextBySymKey(mech, CKA_SIGN, key, &macParam);
28
497
    if (!ctx) {
29
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
30
0
        return SECFailure;
31
0
    }
32
33
497
    rv = PK11_DigestBegin(ctx);
34
497
    if (rv != SECSuccess) {
35
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
36
0
        goto loser;
37
0
    }
38
39
497
    rv = PK11_DigestOp(ctx, in, len);
40
497
    if (rv != SECSuccess) {
41
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
42
0
        goto loser;
43
0
    }
44
45
497
    rv = PK11_DigestFinal(ctx, mac, &computedLen, maxMacLen);
46
497
    if (rv != SECSuccess) {
47
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
48
0
        goto loser;
49
0
    }
50
51
497
    *macLen = maxMacLen;
52
497
    PK11_DestroyContext(ctx, PR_TRUE);
53
497
    return SECSuccess;
54
55
0
loser:
56
0
    PK11_DestroyContext(ctx, PR_TRUE);
57
0
    return SECFailure;
58
497
}
Unexecuted instantiation: selfencrypt.c:ssl_MacBuffer
selfencrypt.c:ssl_MacBuffer
Line
Count
Source
21
497
{
22
497
    PK11Context *ctx;
23
497
    SECItem macParam = { 0, NULL, 0 };
24
497
    unsigned int computedLen;
25
497
    SECStatus rv;
26
27
497
    ctx = PK11_CreateContextBySymKey(mech, CKA_SIGN, key, &macParam);
28
497
    if (!ctx) {
29
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
30
0
        return SECFailure;
31
0
    }
32
33
497
    rv = PK11_DigestBegin(ctx);
34
497
    if (rv != SECSuccess) {
35
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
36
0
        goto loser;
37
0
    }
38
39
497
    rv = PK11_DigestOp(ctx, in, len);
40
497
    if (rv != SECSuccess) {
41
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
42
0
        goto loser;
43
0
    }
44
45
497
    rv = PK11_DigestFinal(ctx, mac, &computedLen, maxMacLen);
46
497
    if (rv != SECSuccess) {
47
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
48
0
        goto loser;
49
0
    }
50
51
497
    *macLen = maxMacLen;
52
497
    PK11_DestroyContext(ctx, PR_TRUE);
53
497
    return SECSuccess;
54
55
0
loser:
56
0
    PK11_DestroyContext(ctx, PR_TRUE);
57
0
    return SECFailure;
58
497
}
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
4.37k
{
68
4.37k
    if (inLen > maxOutLen) {
69
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
70
0
        return SECFailure;
71
0
    }
72
73
4.37k
    PORT_Memcpy(out, in, inLen);
74
4.37k
    *outLen = inLen;
75
76
4.37k
    return 0;
77
4.37k
}
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.25k
{
85
1.25k
    if (inLen > maxOutLen) {
86
5
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
87
5
        return SECFailure;
88
5
    }
89
90
1.24k
    PORT_Memcpy(out, in, inLen);
91
1.24k
    *outLen = inLen;
92
93
1.24k
    return 0;
94
1.25k
}
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
483
{
122
483
    unsigned int len;
123
483
    unsigned int lenOffset;
124
483
    unsigned char iv[AES_BLOCK_SIZE];
125
483
    SECItem ivItem = { siBuffer, iv, sizeof(iv) };
126
    /* Write directly to out. */
127
483
    sslBuffer buf = SSL_BUFFER_FIXED(out, maxOutLen);
128
483
    SECStatus rv;
129
130
    /* Generate a random IV */
131
483
    rv = PK11_GenerateRandom(iv, sizeof(iv));
132
483
    if (rv != SECSuccess) {
133
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
134
0
        return SECFailure;
135
0
    }
136
137
    /* Add header. */
138
483
    rv = sslBuffer_Append(&buf, keyName, SELF_ENCRYPT_KEY_NAME_LEN);
139
483
    if (rv != SECSuccess) {
140
0
        return SECFailure;
141
0
    }
142
483
    rv = sslBuffer_Append(&buf, iv, sizeof(iv));
143
483
    if (rv != SECSuccess) {
144
0
        return SECFailure;
145
0
    }
146
147
    /* Leave space for the length of the ciphertext. */
148
483
    rv = sslBuffer_Skip(&buf, 2, &lenOffset);
149
483
    if (rv != SECSuccess) {
150
0
        return SECFailure;
151
0
    }
152
153
    /* Encode the ciphertext in place. */
154
483
    rv = PK11_Encrypt(encKey, CKM_AES_CBC_PAD, &ivItem,
155
483
                      SSL_BUFFER_NEXT(&buf), &len,
156
483
                      SSL_BUFFER_SPACE(&buf), in, inLen);
157
483
    if (rv != SECSuccess) {
158
0
        return SECFailure;
159
0
    }
160
483
    rv = sslBuffer_Skip(&buf, len, NULL);
161
483
    if (rv != SECSuccess) {
162
0
        return SECFailure;
163
0
    }
164
165
483
    rv = sslBuffer_InsertLength(&buf, lenOffset, 2);
166
483
    if (rv != SECSuccess) {
167
0
        return SECFailure;
168
0
    }
169
170
    /* MAC the entire output buffer into the output. */
171
483
    PORT_Assert(buf.space - buf.len >= SHA256_LENGTH);
172
483
    rv = ssl_MacBuffer(macKey, CKM_SHA256_HMAC,
173
483
                       SSL_BUFFER_BASE(&buf), /* input */
174
483
                       SSL_BUFFER_LEN(&buf),
175
483
                       SSL_BUFFER_NEXT(&buf), &len, /* output */
176
483
                       SHA256_LENGTH);
177
483
    if (rv != SECSuccess) {
178
0
        return SECFailure;
179
0
    }
180
483
    rv = sslBuffer_Skip(&buf, len, NULL);
181
483
    if (rv != SECSuccess) {
182
0
        return SECFailure;
183
0
    }
184
185
483
    *outLen = SSL_BUFFER_LEN(&buf);
186
483
    return SECSuccess;
187
483
}
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
331
{
195
331
    sslReader reader = SSL_READER(in, inLen);
196
197
331
    sslReadBuffer encodedKeyNameBuffer = { 0 };
198
331
    SECStatus rv = sslRead_Read(&reader, SELF_ENCRYPT_KEY_NAME_LEN,
199
331
                                &encodedKeyNameBuffer);
200
331
    if (rv != SECSuccess) {
201
150
        return SECFailure;
202
150
    }
203
204
181
    sslReadBuffer ivBuffer = { 0 };
205
181
    rv = sslRead_Read(&reader, AES_BLOCK_SIZE, &ivBuffer);
206
181
    if (rv != SECSuccess) {
207
69
        return SECFailure;
208
69
    }
209
210
112
    PRUint64 cipherTextLen = 0;
211
112
    rv = sslRead_ReadNumber(&reader, 2, &cipherTextLen);
212
112
    if (rv != SECSuccess) {
213
4
        return SECFailure;
214
4
    }
215
216
108
    sslReadBuffer cipherTextBuffer = { 0 };
217
108
    rv = sslRead_Read(&reader, (unsigned int)cipherTextLen, &cipherTextBuffer);
218
108
    if (rv != SECSuccess) {
219
40
        return SECFailure;
220
40
    }
221
68
    unsigned int bytesToMac = reader.offset;
222
223
68
    sslReadBuffer encodedMacBuffer = { 0 };
224
68
    rv = sslRead_Read(&reader, SHA256_LENGTH, &encodedMacBuffer);
225
68
    if (rv != SECSuccess) {
226
10
        return SECFailure;
227
10
    }
228
229
    /* Make sure we're at the end of the block. */
230
58
    if (reader.offset != reader.buf.len) {
231
15
        PORT_SetError(SEC_ERROR_BAD_DATA);
232
15
        return SECFailure;
233
15
    }
234
235
    /* Now that everything is decoded, we can make progress. */
236
    /* 1. Check that we have the right key. */
237
43
    if (PORT_Memcmp(keyName, encodedKeyNameBuffer.buf, SELF_ENCRYPT_KEY_NAME_LEN)) {
238
29
        PORT_SetError(SEC_ERROR_NOT_A_RECIPIENT);
239
29
        return SECFailure;
240
29
    }
241
242
    /* 2. Check the MAC */
243
14
    unsigned char computedMac[SHA256_LENGTH];
244
14
    unsigned int computedMacLen = 0;
245
14
    rv = ssl_MacBuffer(macKey, CKM_SHA256_HMAC, in, bytesToMac,
246
14
                       computedMac, &computedMacLen, sizeof(computedMac));
247
14
    if (rv != SECSuccess) {
248
0
        return SECFailure;
249
0
    }
250
14
    PORT_Assert(computedMacLen == SHA256_LENGTH);
251
14
    if (NSS_SecureMemcmp(computedMac, encodedMacBuffer.buf, computedMacLen) != 0) {
252
14
        PORT_SetError(SEC_ERROR_BAD_DATA);
253
14
        return SECFailure;
254
14
    }
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.88k
{
272
3.88k
    return SELF_ENCRYPT_KEY_NAME_LEN +
273
3.88k
           AES_BLOCK_SIZE +
274
3.88k
           2 +
275
3.88k
           ((inLen / AES_BLOCK_SIZE) + 1) * AES_BLOCK_SIZE + /* Padded */
276
3.88k
           SHA256_LENGTH;
277
3.88k
}
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.86k
{
284
4.86k
    PRUint8 keyName[SELF_ENCRYPT_KEY_NAME_LEN];
285
4.86k
    PK11SymKey *encKey;
286
4.86k
    PK11SymKey *macKey;
287
4.86k
    SECStatus rv;
288
289
    /* Get session ticket keys. */
290
4.86k
    rv = ssl_GetSelfEncryptKeys(ss, keyName, &encKey, &macKey);
291
4.86k
    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.86k
    return ssl_SelfEncryptProtectInt(encKey, macKey, keyName,
298
4.86k
                                     in, inLen, out, outLen, maxOutLen);
299
4.86k
}
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.58k
{
306
1.58k
    PRUint8 keyName[SELF_ENCRYPT_KEY_NAME_LEN];
307
1.58k
    PK11SymKey *encKey;
308
1.58k
    PK11SymKey *macKey;
309
1.58k
    SECStatus rv;
310
311
    /* Get session ticket keys. */
312
1.58k
    rv = ssl_GetSelfEncryptKeys(ss, keyName, &encKey, &macKey);
313
1.58k
    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.58k
    return ssl_SelfEncryptUnprotectInt(encKey, macKey, keyName,
320
1.58k
                                       in, inLen, out, outLen, maxOutLen);
321
1.58k
}