Coverage Report

Created: 2024-05-20 06:23

/src/nss/lib/ssl/sslprimitive.c
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/*
3
 * SSL Primitives: Public HKDF and AEAD Functions
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 "blapit.h"
10
#include "keyhi.h"
11
#include "pk11pub.h"
12
#include "sechash.h"
13
#include "ssl.h"
14
#include "sslexp.h"
15
#include "sslerr.h"
16
#include "sslproto.h"
17
18
#include "sslimpl.h"
19
#include "tls13con.h"
20
#include "tls13hkdf.h"
21
22
struct SSLAeadContextStr {
23
    /* sigh, the API creates a single context, but then uses either encrypt
24
     * and decrypt on that context. We should take an encrypt/decrypt
25
     * variable here, but for now create two contexts. */
26
    PK11Context *encryptContext;
27
    PK11Context *decryptContext;
28
    int tagLen;
29
    int ivLen;
30
    unsigned char iv[MAX_IV_LENGTH];
31
};
32
33
SECStatus
34
SSLExp_MakeVariantAead(PRUint16 version, PRUint16 cipherSuite, SSLProtocolVariant variant,
35
                       PK11SymKey *secret, const char *labelPrefix,
36
                       unsigned int labelPrefixLen, SSLAeadContext **ctx)
37
0
{
38
0
    SSLAeadContext *out = NULL;
39
0
    char label[255]; // Maximum length label.
40
0
    static const char *const keySuffix = "key";
41
0
    static const char *const ivSuffix = "iv";
42
0
    CK_MECHANISM_TYPE mech;
43
0
    SECItem nullParams = { siBuffer, NULL, 0 };
44
0
    PK11SymKey *key = NULL;
45
46
0
    PORT_Assert(strlen(keySuffix) >= strlen(ivSuffix));
47
0
    if (secret == NULL || ctx == NULL ||
48
0
        (labelPrefix == NULL && labelPrefixLen > 0) ||
49
0
        labelPrefixLen + strlen(keySuffix) > sizeof(label)) {
50
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
51
0
        goto loser;
52
0
    }
53
54
0
    SSLHashType hash;
55
0
    const ssl3BulkCipherDef *cipher;
56
0
    SECStatus rv = tls13_GetHashAndCipher(version, cipherSuite,
57
0
                                          &hash, &cipher);
58
0
    if (rv != SECSuccess) {
59
0
        goto loser; /* Code already set. */
60
0
    }
61
62
0
    out = PORT_ZNew(SSLAeadContext);
63
0
    if (out == NULL) {
64
0
        goto loser;
65
0
    }
66
0
    mech = ssl3_Alg2Mech(cipher->calg);
67
0
    out->ivLen = cipher->iv_size + cipher->explicit_nonce_size;
68
0
    out->tagLen = cipher->tag_size;
69
70
0
    memcpy(label, labelPrefix, labelPrefixLen);
71
0
    memcpy(label + labelPrefixLen, ivSuffix, strlen(ivSuffix));
72
0
    unsigned int labelLen = labelPrefixLen + strlen(ivSuffix);
73
0
    unsigned int ivLen = cipher->iv_size + cipher->explicit_nonce_size;
74
0
    rv = tls13_HkdfExpandLabelRaw(secret, hash,
75
0
                                  NULL, 0, // Handshake hash.
76
0
                                  label, labelLen, variant,
77
0
                                  out->iv, ivLen);
78
0
    if (rv != SECSuccess) {
79
0
        goto loser;
80
0
    }
81
82
0
    memcpy(label + labelPrefixLen, keySuffix, strlen(keySuffix));
83
0
    labelLen = labelPrefixLen + strlen(keySuffix);
84
0
    rv = tls13_HkdfExpandLabel(secret, hash,
85
0
                               NULL, 0, // Handshake hash.
86
0
                               label, labelLen, mech, cipher->key_size,
87
0
                               variant, &key);
88
0
    if (rv != SECSuccess) {
89
0
        goto loser;
90
0
    }
91
92
    /* We really need to change the API to Create a context for each
93
     * encrypt and decrypt rather than a single call that does both. it's
94
     * almost certain that the underlying application tries to use the same
95
     * context for both. */
96
0
    out->encryptContext = PK11_CreateContextBySymKey(mech,
97
0
                                                     CKA_NSS_MESSAGE | CKA_ENCRYPT,
98
0
                                                     key, &nullParams);
99
0
    if (out->encryptContext == NULL) {
100
0
        goto loser;
101
0
    }
102
103
0
    out->decryptContext = PK11_CreateContextBySymKey(mech,
104
0
                                                     CKA_NSS_MESSAGE | CKA_DECRYPT,
105
0
                                                     key, &nullParams);
106
0
    if (out->decryptContext == NULL) {
107
0
        goto loser;
108
0
    }
109
110
0
    PK11_FreeSymKey(key);
111
0
    *ctx = out;
112
0
    return SECSuccess;
113
114
0
loser:
115
0
    PK11_FreeSymKey(key);
116
0
    SSLExp_DestroyAead(out);
117
0
    return SECFailure;
118
0
}
119
120
SECStatus
121
SSLExp_MakeAead(PRUint16 version, PRUint16 cipherSuite, PK11SymKey *secret,
122
                const char *labelPrefix, unsigned int labelPrefixLen, SSLAeadContext **ctx)
123
0
{
124
0
    return SSLExp_MakeVariantAead(version, cipherSuite, ssl_variant_stream, secret,
125
0
                                  labelPrefix, labelPrefixLen, ctx);
126
0
}
127
128
SECStatus
129
SSLExp_DestroyAead(SSLAeadContext *ctx)
130
0
{
131
0
    if (!ctx) {
132
0
        return SECSuccess;
133
0
    }
134
0
    if (ctx->encryptContext) {
135
0
        PK11_DestroyContext(ctx->encryptContext, PR_TRUE);
136
0
    }
137
0
    if (ctx->decryptContext) {
138
0
        PK11_DestroyContext(ctx->decryptContext, PR_TRUE);
139
0
    }
140
141
0
    PORT_ZFree(ctx, sizeof(*ctx));
142
0
    return SECSuccess;
143
0
}
144
145
/* Bug 1529440 exists to refactor this and the other AEAD uses. */
146
static SECStatus
147
ssl_AeadInner(const SSLAeadContext *ctx, PK11Context *context,
148
              PRBool decrypt, PRUint64 counter,
149
              const PRUint8 *aad, unsigned int aadLen,
150
              const PRUint8 *in, unsigned int inLen,
151
              PRUint8 *out, unsigned int *outLen, unsigned int maxOut)
152
0
{
153
0
    if (ctx == NULL || (aad == NULL && aadLen > 0) || in == NULL ||
154
0
        out == NULL || outLen == NULL) {
155
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
156
0
        return SECFailure;
157
0
    }
158
159
    // Setup the nonce.
160
0
    PRUint8 nonce[sizeof(counter)] = { 0 };
161
0
    sslBuffer nonceBuf = SSL_BUFFER_FIXED(nonce, sizeof(counter));
162
0
    SECStatus rv = sslBuffer_AppendNumber(&nonceBuf, counter, sizeof(counter));
163
0
    if (rv != SECSuccess) {
164
0
        PORT_Assert(0);
165
0
        return SECFailure;
166
0
    }
167
    /* at least on encrypt, we should not be using CKG_NO_GENERATE, but
168
     * the current experimental API has the application tracking the counter
169
     * rather than token. We should look at the QUIC code and see if the
170
     * counter can be moved internally where it belongs. That would
171
     * also get rid of the  formatting code above and have the API
172
     * call tls13_AEAD directly in SSLExp_Aead* */
173
0
    return tls13_AEAD(context, decrypt, CKG_NO_GENERATE, 0, ctx->iv, NULL,
174
0
                      ctx->ivLen, nonce, sizeof(counter), aad, aadLen,
175
0
                      out, outLen, maxOut, ctx->tagLen, in, inLen);
176
0
}
177
178
SECStatus
179
SSLExp_AeadEncrypt(const SSLAeadContext *ctx, PRUint64 counter,
180
                   const PRUint8 *aad, unsigned int aadLen,
181
                   const PRUint8 *plaintext, unsigned int plaintextLen,
182
                   PRUint8 *out, unsigned int *outLen, unsigned int maxOut)
183
0
{
184
    // false == encrypt
185
0
    return ssl_AeadInner(ctx, ctx->encryptContext, PR_FALSE, counter,
186
0
                         aad, aadLen, plaintext, plaintextLen,
187
0
                         out, outLen, maxOut);
188
0
}
189
190
SECStatus
191
SSLExp_AeadDecrypt(const SSLAeadContext *ctx, PRUint64 counter,
192
                   const PRUint8 *aad, unsigned int aadLen,
193
                   const PRUint8 *ciphertext, unsigned int ciphertextLen,
194
                   PRUint8 *out, unsigned int *outLen, unsigned int maxOut)
195
0
{
196
    // true == decrypt
197
0
    return ssl_AeadInner(ctx, ctx->decryptContext, PR_TRUE, counter,
198
0
                         aad, aadLen, ciphertext, ciphertextLen,
199
0
                         out, outLen, maxOut);
200
0
}
201
202
SECStatus
203
SSLExp_HkdfExtract(PRUint16 version, PRUint16 cipherSuite,
204
                   PK11SymKey *salt, PK11SymKey *ikm, PK11SymKey **keyp)
205
0
{
206
0
    if (keyp == NULL) {
207
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
208
0
        return SECFailure;
209
0
    }
210
211
0
    SSLHashType hash;
212
0
    SECStatus rv = tls13_GetHashAndCipher(version, cipherSuite,
213
0
                                          &hash, NULL);
214
0
    if (rv != SECSuccess) {
215
0
        return SECFailure; /* Code already set. */
216
0
    }
217
0
    return tls13_HkdfExtract(salt, ikm, hash, keyp);
218
0
}
219
220
SECStatus
221
SSLExp_HkdfExpandLabel(PRUint16 version, PRUint16 cipherSuite, PK11SymKey *prk,
222
                       const PRUint8 *hsHash, unsigned int hsHashLen,
223
                       const char *label, unsigned int labelLen, PK11SymKey **keyp)
224
0
{
225
0
    return SSLExp_HkdfVariantExpandLabel(version, cipherSuite, prk, hsHash, hsHashLen,
226
0
                                         label, labelLen, ssl_variant_stream, keyp);
227
0
}
228
229
SECStatus
230
SSLExp_HkdfVariantExpandLabel(PRUint16 version, PRUint16 cipherSuite, PK11SymKey *prk,
231
                              const PRUint8 *hsHash, unsigned int hsHashLen,
232
                              const char *label, unsigned int labelLen,
233
                              SSLProtocolVariant variant, PK11SymKey **keyp)
234
0
{
235
0
    if (prk == NULL || keyp == NULL ||
236
0
        label == NULL || labelLen == 0) {
237
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
238
0
        return SECFailure;
239
0
    }
240
241
0
    SSLHashType hash;
242
0
    SECStatus rv = tls13_GetHashAndCipher(version, cipherSuite,
243
0
                                          &hash, NULL);
244
0
    if (rv != SECSuccess) {
245
0
        return SECFailure; /* Code already set. */
246
0
    }
247
0
    return tls13_HkdfExpandLabel(prk, hash, hsHash, hsHashLen, label, labelLen,
248
0
                                 CKM_HKDF_DERIVE,
249
0
                                 tls13_GetHashSizeForHash(hash), variant, keyp);
250
0
}
251
252
SECStatus
253
SSLExp_HkdfExpandLabelWithMech(PRUint16 version, PRUint16 cipherSuite, PK11SymKey *prk,
254
                               const PRUint8 *hsHash, unsigned int hsHashLen,
255
                               const char *label, unsigned int labelLen,
256
                               CK_MECHANISM_TYPE mech, unsigned int keySize,
257
                               PK11SymKey **keyp)
258
0
{
259
0
    return SSLExp_HkdfVariantExpandLabelWithMech(version, cipherSuite, prk, hsHash, hsHashLen,
260
0
                                                 label, labelLen, mech, keySize,
261
0
                                                 ssl_variant_stream, keyp);
262
0
}
263
264
SECStatus
265
SSLExp_HkdfVariantExpandLabelWithMech(PRUint16 version, PRUint16 cipherSuite, PK11SymKey *prk,
266
                                      const PRUint8 *hsHash, unsigned int hsHashLen,
267
                                      const char *label, unsigned int labelLen,
268
                                      CK_MECHANISM_TYPE mech, unsigned int keySize,
269
                                      SSLProtocolVariant variant, PK11SymKey **keyp)
270
0
{
271
0
    if (prk == NULL || keyp == NULL ||
272
0
        label == NULL || labelLen == 0 ||
273
0
        mech == CKM_INVALID_MECHANISM || keySize == 0) {
274
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
275
0
        return SECFailure;
276
0
    }
277
278
0
    SSLHashType hash;
279
0
    SECStatus rv = tls13_GetHashAndCipher(version, cipherSuite,
280
0
                                          &hash, NULL);
281
0
    if (rv != SECSuccess) {
282
0
        return SECFailure; /* Code already set. */
283
0
    }
284
0
    return tls13_HkdfExpandLabel(prk, hash, hsHash, hsHashLen, label, labelLen,
285
0
                                 mech, keySize, variant, keyp);
286
0
}
287
288
SECStatus
289
ssl_CreateMaskingContextInner(PRUint16 version, PRUint16 cipherSuite,
290
                              SSLProtocolVariant variant,
291
                              PK11SymKey *secret,
292
                              const char *label,
293
                              unsigned int labelLen,
294
                              SSLMaskingContext **ctx)
295
0
{
296
0
    if (!secret || !ctx || (!label && labelLen)) {
297
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
298
0
        return SECFailure;
299
0
    }
300
301
0
    SSLMaskingContext *out = PORT_ZNew(SSLMaskingContext);
302
0
    if (out == NULL) {
303
0
        goto loser;
304
0
    }
305
306
0
    SSLHashType hash;
307
0
    const ssl3BulkCipherDef *cipher;
308
0
    SECStatus rv = tls13_GetHashAndCipher(version, cipherSuite,
309
0
                                          &hash, &cipher);
310
0
    if (rv != SECSuccess) {
311
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
312
0
        goto loser; /* Code already set. */
313
0
    }
314
315
0
    out->mech = tls13_SequenceNumberEncryptionMechanism(cipher->calg);
316
0
    if (out->mech == CKM_INVALID_MECHANISM) {
317
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
318
0
        goto loser;
319
0
    }
320
321
    // Derive the masking key
322
0
    rv = tls13_HkdfExpandLabel(secret, hash,
323
0
                               NULL, 0, // Handshake hash.
324
0
                               label, labelLen,
325
0
                               out->mech,
326
0
                               cipher->key_size, variant,
327
0
                               &out->secret);
328
0
    if (rv != SECSuccess) {
329
0
        goto loser;
330
0
    }
331
332
0
    out->version = version;
333
0
    out->cipherSuite = cipherSuite;
334
335
0
    *ctx = out;
336
0
    return SECSuccess;
337
0
loser:
338
0
    SSLExp_DestroyMaskingContext(out);
339
0
    return SECFailure;
340
0
}
341
342
SECStatus
343
ssl_CreateMaskInner(SSLMaskingContext *ctx, const PRUint8 *sample,
344
                    unsigned int sampleLen, PRUint8 *outMask,
345
                    unsigned int maskLen)
346
0
{
347
0
    if (!ctx || !sample || !sampleLen || !outMask || !maskLen) {
348
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
349
0
        return SECFailure;
350
0
    }
351
352
0
    if (ctx->secret == NULL) {
353
0
        PORT_SetError(SEC_ERROR_NO_KEY);
354
0
        return SECFailure;
355
0
    }
356
357
0
    SECStatus rv = SECFailure;
358
0
    unsigned int outMaskLen = 0;
359
0
    int paramLen = 0;
360
361
    /* Internal output len/buf, for use if the caller allocated and requested
362
     * less than one block of output. |oneBlock| should have size equal to the
363
     * largest block size supported below. */
364
0
    PRUint8 oneBlock[AES_BLOCK_SIZE];
365
0
    PRUint8 *outMask_ = outMask;
366
0
    unsigned int maskLen_ = maskLen;
367
368
0
    switch (ctx->mech) {
369
0
        case CKM_AES_ECB:
370
0
            if (sampleLen < AES_BLOCK_SIZE) {
371
0
                PORT_SetError(SEC_ERROR_INVALID_ARGS);
372
0
                return SECFailure;
373
0
            }
374
0
            if (maskLen_ < AES_BLOCK_SIZE) {
375
0
                outMask_ = oneBlock;
376
0
                maskLen_ = sizeof(oneBlock);
377
0
            }
378
0
            rv = PK11_Encrypt(ctx->secret,
379
0
                              ctx->mech,
380
0
                              NULL,
381
0
                              outMask_, &outMaskLen, maskLen_,
382
0
                              sample, AES_BLOCK_SIZE);
383
0
            if (rv == SECSuccess &&
384
0
                maskLen < AES_BLOCK_SIZE) {
385
0
                memcpy(outMask, outMask_, maskLen);
386
0
            }
387
0
            break;
388
0
        case CKM_NSS_CHACHA20_CTR:
389
0
            paramLen = 16;
390
        /* fall through */
391
0
        case CKM_CHACHA20:
392
0
            paramLen = (paramLen) ? paramLen : sizeof(CK_CHACHA20_PARAMS);
393
0
            if (sampleLen < paramLen) {
394
0
                PORT_SetError(SEC_ERROR_INVALID_ARGS);
395
0
                return SECFailure;
396
0
            }
397
398
0
            SECItem param;
399
0
            param.type = siBuffer;
400
0
            param.len = paramLen;
401
0
            param.data = (PRUint8 *)sample; // const-cast :(
402
0
            unsigned char zeros[128] = { 0 };
403
404
0
            if (maskLen > sizeof(zeros)) {
405
0
                PORT_SetError(SEC_ERROR_OUTPUT_LEN);
406
0
                return SECFailure;
407
0
            }
408
409
0
            rv = PK11_Encrypt(ctx->secret,
410
0
                              ctx->mech,
411
0
                              &param,
412
0
                              outMask, &outMaskLen,
413
0
                              maskLen,
414
0
                              zeros, maskLen);
415
0
            break;
416
0
        default:
417
0
            PORT_SetError(SEC_ERROR_INVALID_ARGS);
418
0
            return SECFailure;
419
0
    }
420
421
0
    if (rv != SECSuccess) {
422
0
        PORT_SetError(SEC_ERROR_PKCS11_FUNCTION_FAILED);
423
0
        return SECFailure;
424
0
    }
425
426
    // Ensure we produced at least as much material as requested.
427
0
    if (outMaskLen < maskLen) {
428
0
        PORT_SetError(SEC_ERROR_OUTPUT_LEN);
429
0
        return SECFailure;
430
0
    }
431
432
0
    return SECSuccess;
433
0
}
434
435
SECStatus
436
ssl_DestroyMaskingContextInner(SSLMaskingContext *ctx)
437
23.4k
{
438
23.4k
    if (!ctx) {
439
23.4k
        return SECSuccess;
440
23.4k
    }
441
442
0
    PK11_FreeSymKey(ctx->secret);
443
0
    PORT_ZFree(ctx, sizeof(*ctx));
444
0
    return SECSuccess;
445
23.4k
}
446
447
SECStatus
448
SSLExp_CreateMask(SSLMaskingContext *ctx, const PRUint8 *sample,
449
                  unsigned int sampleLen, PRUint8 *outMask,
450
                  unsigned int maskLen)
451
0
{
452
0
    return ssl_CreateMaskInner(ctx, sample, sampleLen, outMask, maskLen);
453
0
}
454
455
SECStatus
456
SSLExp_CreateMaskingContext(PRUint16 version, PRUint16 cipherSuite,
457
                            PK11SymKey *secret,
458
                            const char *label,
459
                            unsigned int labelLen,
460
                            SSLMaskingContext **ctx)
461
0
{
462
0
    return ssl_CreateMaskingContextInner(version, cipherSuite, ssl_variant_stream, secret,
463
0
                                         label, labelLen, ctx);
464
0
}
465
466
SECStatus
467
SSLExp_CreateVariantMaskingContext(PRUint16 version, PRUint16 cipherSuite,
468
                                   SSLProtocolVariant variant,
469
                                   PK11SymKey *secret,
470
                                   const char *label,
471
                                   unsigned int labelLen,
472
                                   SSLMaskingContext **ctx)
473
0
{
474
0
    return ssl_CreateMaskingContextInner(version, cipherSuite, variant, secret,
475
0
                                         label, labelLen, ctx);
476
0
}
477
478
SECStatus
479
SSLExp_DestroyMaskingContext(SSLMaskingContext *ctx)
480
0
{
481
0
    return ssl_DestroyMaskingContextInner(ctx);
482
0
}