Coverage Report

Created: 2026-06-07 07:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/nss/lib/ssl/tls13hkdf.c
Line
Count
Source
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/*
3
 * TLS 1.3 Protocol
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 "keyhi.h"
10
#include "pk11func.h"
11
#include "secitem.h"
12
#include "ssl.h"
13
#include "sslt.h"
14
#include "sslerr.h"
15
#include "sslimpl.h"
16
17
/* This table contains the mapping between TLS hash identifiers and the
18
 * PKCS#11 identifiers */
19
static const struct {
20
    SSLHashType hash;
21
    CK_MECHANISM_TYPE pkcs11Mech;
22
    unsigned int hashSize;
23
} kTlsHkdfInfo[] = {
24
    { ssl_hash_none, 0, 0 },
25
    { ssl_hash_md5, 0, 0 },
26
    { ssl_hash_sha1, 0, 0 },
27
    { ssl_hash_sha224, 0 },
28
    { ssl_hash_sha256, CKM_SHA256, 32 },
29
    { ssl_hash_sha384, CKM_SHA384, 48 },
30
    { ssl_hash_sha512, CKM_SHA512, 64 }
31
};
32
33
SECStatus
34
tls13_HkdfExtract(PK11SymKey *ikm1, PK11SymKey *ikm2, SSLHashType baseHash,
35
                  PK11SymKey **prkp)
36
22.2k
{
37
22.2k
    CK_HKDF_PARAMS params;
38
22.2k
    SECItem paramsi;
39
22.2k
    PK11SymKey *prk;
40
22.2k
    static const PRUint8 zeroKeyBuf[HASH_LENGTH_MAX];
41
22.2k
    SECItem zeroKeyItem = { siBuffer, CONST_CAST(PRUint8, zeroKeyBuf), kTlsHkdfInfo[baseHash].hashSize };
42
22.2k
    PK11SlotInfo *slot = NULL;
43
22.2k
    PK11SymKey *newIkm2 = NULL;
44
22.2k
    PK11SymKey *newIkm1 = NULL;
45
22.2k
    SECStatus rv;
46
47
22.2k
    params.bExtract = CK_TRUE;
48
22.2k
    params.bExpand = CK_FALSE;
49
22.2k
    params.prfHashMechanism = kTlsHkdfInfo[baseHash].pkcs11Mech;
50
22.2k
    params.pInfo = NULL;
51
22.2k
    params.ulInfoLen = 0UL;
52
22.2k
    params.pSalt = NULL;
53
22.2k
    params.ulSaltLen = 0UL;
54
22.2k
    params.hSaltKey = CK_INVALID_HANDLE;
55
56
22.2k
    if (!ikm1) {
57
        /* PKCS #11 v3.0 has and explict NULL value, which equates to
58
         * a sequence of zeros equal in length to the HMAC. */
59
12.3k
        params.ulSaltType = CKF_HKDF_SALT_NULL;
60
12.3k
    } else {
61
        /* PKCS #11 v3.0 can take the salt as a key handle */
62
9.98k
        params.hSaltKey = PK11_GetSymKeyHandle(ikm1);
63
9.98k
        params.ulSaltType = CKF_HKDF_SALT_KEY;
64
65
        /* if we have both keys, make sure they are in the same slot */
66
9.98k
        if (ikm2) {
67
4.99k
            rv = PK11_SymKeysToSameSlot(CKM_HKDF_DERIVE,
68
4.99k
                                        CKA_DERIVE, CKA_DERIVE,
69
4.99k
                                        ikm2, ikm1, &newIkm2, &newIkm1);
70
4.99k
            if (rv != SECSuccess) {
71
0
                SECItem *salt;
72
                /* couldn't move the keys, try extracting the salt */
73
0
                rv = PK11_ExtractKeyValue(ikm1);
74
0
                if (rv != SECSuccess)
75
0
                    return rv;
76
0
                salt = PK11_GetKeyData(ikm1);
77
0
                if (!salt)
78
0
                    return SECFailure;
79
0
                PORT_Assert(salt->len > 0);
80
                /* Set up for Salt as Data instead of Salt as key */
81
0
                params.pSalt = salt->data;
82
0
                params.ulSaltLen = salt->len;
83
0
                params.ulSaltType = CKF_HKDF_SALT_DATA;
84
0
            }
85
            /* use the new keys */
86
4.99k
            if (newIkm1) {
87
                /* we've moved the key, get the handle for the new key */
88
4.98k
                params.hSaltKey = PK11_GetSymKeyHandle(newIkm1);
89
                /* we don't use ikm1 after this, so don't bother setting it */
90
4.98k
            }
91
4.99k
            if (newIkm2) {
92
                /* new ikm2 key, use the new key */
93
0
                ikm2 = newIkm2;
94
0
            }
95
4.99k
        }
96
9.98k
    }
97
22.2k
    paramsi.data = (unsigned char *)&params;
98
22.2k
    paramsi.len = sizeof(params);
99
100
22.2k
    PORT_Assert(kTlsHkdfInfo[baseHash].pkcs11Mech);
101
22.2k
    PORT_Assert(kTlsHkdfInfo[baseHash].hashSize);
102
22.2k
    PORT_Assert(kTlsHkdfInfo[baseHash].hash == baseHash);
103
104
    /* A zero ikm2 is a key of hash-length 0s. */
105
22.2k
    if (!ikm2) {
106
        /* if we have ikm1, put the zero key in the same slot */
107
9.97k
        slot = ikm1 ? PK11_GetSlotFromKey(ikm1) : PK11_GetBestSlot(CKM_HKDF_DERIVE, NULL);
108
9.97k
        if (!slot) {
109
0
            return SECFailure;
110
0
        }
111
112
9.97k
        newIkm2 = PK11_ImportDataKey(slot, CKM_HKDF_DERIVE, PK11_OriginUnwrap,
113
9.97k
                                     CKA_DERIVE, &zeroKeyItem, NULL);
114
9.97k
        if (!newIkm2) {
115
0
            return SECFailure;
116
0
        }
117
9.97k
        ikm2 = newIkm2;
118
9.97k
    }
119
22.2k
    PORT_Assert(ikm2);
120
121
22.2k
    PRINT_BUF(50, (NULL, "HKDF Extract: IKM1/Salt", params.pSalt, params.ulSaltLen));
122
22.2k
    PRINT_KEY(50, (NULL, "HKDF Extract: IKM2", ikm2));
123
124
22.2k
    prk = PK11_Derive(ikm2, CKM_HKDF_DERIVE, &paramsi, CKM_HKDF_DERIVE,
125
22.2k
                      CKA_DERIVE, 0);
126
22.2k
    PK11_FreeSymKey(newIkm2);
127
22.2k
    PK11_FreeSymKey(newIkm1);
128
22.2k
    if (slot)
129
9.97k
        PK11_FreeSlot(slot);
130
22.2k
    if (!prk) {
131
0
        return SECFailure;
132
0
    }
133
134
22.2k
    PRINT_KEY(50, (NULL, "HKDF Extract", prk));
135
22.2k
    *prkp = prk;
136
137
22.2k
    return SECSuccess;
138
22.2k
}
139
140
SECStatus
141
tls13_HkdfExpandLabelGeneral(CK_MECHANISM_TYPE deriveMech, PK11SymKey *prk,
142
                             SSLHashType baseHash,
143
                             const PRUint8 *handshakeHash, unsigned int handshakeHashLen,
144
                             const char *label, unsigned int labelLen,
145
                             CK_MECHANISM_TYPE algorithm, unsigned int keySize,
146
                             SSLProtocolVariant variant, PK11SymKey **keyp)
147
376k
{
148
376k
    CK_HKDF_PARAMS params;
149
376k
    SECItem paramsi = { siBuffer, NULL, 0 };
150
    /* Size of info array needs to be big enough to hold the maximum Prefix,
151
     * Label, plus HandshakeHash. If it's ever to small, the code will abort.
152
     */
153
376k
    PRUint8 info[256];
154
376k
    sslBuffer infoBuf = SSL_BUFFER(info);
155
376k
    PK11SymKey *derived;
156
376k
    SECStatus rv;
157
376k
    const char *kLabelPrefixTls = "tls13 ";
158
376k
    const char *kLabelPrefixDtls = "dtls13";
159
376k
    const unsigned int kLabelPrefixLen =
160
376k
        (variant == ssl_variant_stream) ? strlen(kLabelPrefixTls) : strlen(kLabelPrefixDtls);
161
376k
    const char *kLabelPrefix =
162
376k
        (variant == ssl_variant_stream) ? kLabelPrefixTls : kLabelPrefixDtls;
163
164
376k
    PORT_Assert(prk);
165
376k
    PORT_Assert(keyp);
166
376k
    if ((handshakeHashLen > 255) ||
167
376k
        (handshakeHash == NULL && handshakeHashLen > 0) ||
168
376k
        (labelLen > 255 - kLabelPrefixLen)) {
169
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
170
0
        return SECFailure;
171
0
    }
172
173
    /*
174
     *  [draft-ietf-tls-tls13-11] Section 7.1:
175
     *
176
     *  HKDF-Expand-Label(Secret, Label, HashValue, Length) =
177
     *       HKDF-Expand(Secret, HkdfLabel, Length)
178
     *
179
     *  Where HkdfLabel is specified as:
180
     *
181
     *  struct HkdfLabel {
182
     *    uint16 length;
183
     *    opaque label<9..255>;
184
     *    opaque hash_value<0..255>;
185
     *  };
186
     *
187
     *  Where:
188
     *  - HkdfLabel.length is Length
189
     *  - HkdfLabel.hash_value is HashValue.
190
     *  - HkdfLabel.label is "TLS 1.3, " + Label
191
     *
192
     */
193
376k
    rv = sslBuffer_AppendNumber(&infoBuf, keySize, 2);
194
376k
    if (rv != SECSuccess) {
195
0
        return SECFailure;
196
0
    }
197
376k
    rv = sslBuffer_AppendNumber(&infoBuf, labelLen + kLabelPrefixLen, 1);
198
376k
    if (rv != SECSuccess) {
199
0
        return SECFailure;
200
0
    }
201
376k
    rv = sslBuffer_Append(&infoBuf, kLabelPrefix, kLabelPrefixLen);
202
376k
    if (rv != SECSuccess) {
203
0
        return SECFailure;
204
0
    }
205
376k
    rv = sslBuffer_Append(&infoBuf, label, labelLen);
206
376k
    if (rv != SECSuccess) {
207
0
        return SECFailure;
208
0
    }
209
376k
    rv = sslBuffer_AppendVariable(&infoBuf, handshakeHash, handshakeHashLen, 1);
210
376k
    if (rv != SECSuccess) {
211
0
        return SECFailure;
212
0
    }
213
214
376k
    params.bExtract = CK_FALSE;
215
376k
    params.bExpand = CK_TRUE;
216
376k
    params.prfHashMechanism = kTlsHkdfInfo[baseHash].pkcs11Mech;
217
376k
    params.pInfo = SSL_BUFFER_BASE(&infoBuf);
218
376k
    params.ulInfoLen = SSL_BUFFER_LEN(&infoBuf);
219
376k
    paramsi.data = (unsigned char *)&params;
220
376k
    paramsi.len = sizeof(params);
221
376k
    derived = PK11_DeriveWithFlags(prk, deriveMech,
222
376k
                                   &paramsi, algorithm,
223
376k
                                   CKA_DERIVE, keySize,
224
376k
                                   CKF_SIGN | CKF_VERIFY);
225
376k
    if (!derived) {
226
0
        return SECFailure;
227
0
    }
228
229
376k
    *keyp = derived;
230
231
376k
#ifdef TRACE
232
376k
    if (ssl_trace >= 50) {
233
        /* Make sure the label is null terminated. */
234
0
        char labelStr[100];
235
0
        PORT_Memcpy(labelStr, label, labelLen);
236
0
        labelStr[labelLen] = 0;
237
0
        SSL_TRC(50, ("HKDF Expand: label='tls13 %s',requested length=%d",
238
0
                     labelStr, keySize));
239
0
    }
240
376k
    PRINT_KEY(50, (NULL, "PRK", prk));
241
376k
    PRINT_BUF(50, (NULL, "Hash", handshakeHash, handshakeHashLen));
242
376k
    PRINT_BUF(50, (NULL, "Info", SSL_BUFFER_BASE(&infoBuf),
243
376k
                   SSL_BUFFER_LEN(&infoBuf)));
244
376k
    PRINT_KEY(50, (NULL, "Derived key", derived));
245
376k
#endif
246
247
376k
    return SECSuccess;
248
376k
}
249
250
SECStatus
251
tls13_HkdfExpandLabel(PK11SymKey *prk, SSLHashType baseHash,
252
                      const PRUint8 *handshakeHash, unsigned int handshakeHashLen,
253
                      const char *label, unsigned int labelLen,
254
                      CK_MECHANISM_TYPE algorithm, unsigned int keySize,
255
                      SSLProtocolVariant variant, PK11SymKey **keyp)
256
264k
{
257
264k
    return tls13_HkdfExpandLabelGeneral(CKM_HKDF_DERIVE, prk, baseHash,
258
264k
                                        handshakeHash, handshakeHashLen,
259
264k
                                        label, labelLen, algorithm, keySize,
260
264k
                                        variant, keyp);
261
264k
}
262
263
SECStatus
264
tls13_HkdfExpandLabelRaw(PK11SymKey *prk, SSLHashType baseHash,
265
                         const PRUint8 *handshakeHash, unsigned int handshakeHashLen,
266
                         const char *label, unsigned int labelLen,
267
                         SSLProtocolVariant variant, unsigned char *output,
268
                         unsigned int outputLen)
269
112k
{
270
112k
    PK11SymKey *derived = NULL;
271
112k
    SECItem *rawkey;
272
112k
    SECStatus rv;
273
274
    /* the result is not really a key, it's a data object */
275
112k
    rv = tls13_HkdfExpandLabelGeneral(CKM_HKDF_DATA, prk, baseHash,
276
112k
                                      handshakeHash, handshakeHashLen,
277
112k
                                      label, labelLen, CKM_HKDF_DERIVE, outputLen,
278
112k
                                      variant, &derived);
279
112k
    if (rv != SECSuccess || !derived) {
280
0
        goto abort;
281
0
    }
282
283
112k
    rv = PK11_ExtractKeyValue(derived);
284
112k
    if (rv != SECSuccess) {
285
0
        goto abort;
286
0
    }
287
288
112k
    rawkey = PK11_GetKeyData(derived);
289
112k
    if (!rawkey) {
290
0
        goto abort;
291
0
    }
292
293
112k
    PORT_Assert(rawkey->len == outputLen);
294
112k
    memcpy(output, rawkey->data, outputLen);
295
112k
    PK11_FreeSymKey(derived);
296
297
112k
    return SECSuccess;
298
299
0
abort:
300
0
    if (derived) {
301
0
        PK11_FreeSymKey(derived);
302
0
    }
303
0
    PORT_SetError(SSL_ERROR_SYM_KEY_CONTEXT_FAILURE);
304
0
    return SECFailure;
305
112k
}