/src/nss/lib/ssl/tls13hkdf.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 | | * 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 | 0 | { |
37 | 0 | CK_HKDF_PARAMS params; |
38 | 0 | SECItem paramsi; |
39 | 0 | PK11SymKey *prk; |
40 | 0 | static const PRUint8 zeroKeyBuf[HASH_LENGTH_MAX]; |
41 | 0 | SECItem zeroKeyItem = { siBuffer, CONST_CAST(PRUint8, zeroKeyBuf), kTlsHkdfInfo[baseHash].hashSize }; |
42 | 0 | PK11SlotInfo *slot = NULL; |
43 | 0 | PK11SymKey *newIkm2 = NULL; |
44 | 0 | PK11SymKey *newIkm1 = NULL; |
45 | 0 | SECStatus rv; |
46 | |
|
47 | 0 | params.bExtract = CK_TRUE; |
48 | 0 | params.bExpand = CK_FALSE; |
49 | 0 | params.prfHashMechanism = kTlsHkdfInfo[baseHash].pkcs11Mech; |
50 | 0 | params.pInfo = NULL; |
51 | 0 | params.ulInfoLen = 0UL; |
52 | 0 | params.pSalt = NULL; |
53 | 0 | params.ulSaltLen = 0UL; |
54 | 0 | params.hSaltKey = CK_INVALID_HANDLE; |
55 | |
|
56 | 0 | 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 | 0 | params.ulSaltType = CKF_HKDF_SALT_NULL; |
60 | 0 | } else { |
61 | | /* PKCS #11 v3.0 can take the salt as a key handle */ |
62 | 0 | params.hSaltKey = PK11_GetSymKeyHandle(ikm1); |
63 | 0 | params.ulSaltType = CKF_HKDF_SALT_KEY; |
64 | | |
65 | | /* if we have both keys, make sure they are in the same slot */ |
66 | 0 | if (ikm2) { |
67 | 0 | rv = PK11_SymKeysToSameSlot(CKM_HKDF_DERIVE, |
68 | 0 | CKA_DERIVE, CKA_DERIVE, |
69 | 0 | ikm2, ikm1, &newIkm2, &newIkm1); |
70 | 0 | 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 | 0 | if (newIkm1) { |
87 | | /* we've moved the key, get the handle for the new key */ |
88 | 0 | params.hSaltKey = PK11_GetSymKeyHandle(newIkm1); |
89 | | /* we don't use ikm1 after this, so don't bother setting it */ |
90 | 0 | } |
91 | 0 | if (newIkm2) { |
92 | | /* new ikm2 key, use the new key */ |
93 | 0 | ikm2 = newIkm2; |
94 | 0 | } |
95 | 0 | } |
96 | 0 | } |
97 | 0 | paramsi.data = (unsigned char *)¶ms; |
98 | 0 | paramsi.len = sizeof(params); |
99 | |
|
100 | 0 | PORT_Assert(kTlsHkdfInfo[baseHash].pkcs11Mech); |
101 | 0 | PORT_Assert(kTlsHkdfInfo[baseHash].hashSize); |
102 | 0 | PORT_Assert(kTlsHkdfInfo[baseHash].hash == baseHash); |
103 | | |
104 | | /* A zero ikm2 is a key of hash-length 0s. */ |
105 | 0 | if (!ikm2) { |
106 | | /* if we have ikm1, put the zero key in the same slot */ |
107 | 0 | slot = ikm1 ? PK11_GetSlotFromKey(ikm1) : PK11_GetBestSlot(CKM_HKDF_DERIVE, NULL); |
108 | 0 | if (!slot) { |
109 | 0 | return SECFailure; |
110 | 0 | } |
111 | | |
112 | 0 | newIkm2 = PK11_ImportDataKey(slot, CKM_HKDF_DERIVE, PK11_OriginUnwrap, |
113 | 0 | CKA_DERIVE, &zeroKeyItem, NULL); |
114 | 0 | if (!newIkm2) { |
115 | 0 | return SECFailure; |
116 | 0 | } |
117 | 0 | ikm2 = newIkm2; |
118 | 0 | } |
119 | 0 | PORT_Assert(ikm2); |
120 | |
|
121 | 0 | PRINT_BUF(50, (NULL, "HKDF Extract: IKM1/Salt", params.pSalt, params.ulSaltLen)); |
122 | 0 | PRINT_KEY(50, (NULL, "HKDF Extract: IKM2", ikm2)); |
123 | |
|
124 | 0 | prk = PK11_Derive(ikm2, CKM_HKDF_DERIVE, ¶msi, CKM_HKDF_DERIVE, |
125 | 0 | CKA_DERIVE, 0); |
126 | 0 | PK11_FreeSymKey(newIkm2); |
127 | 0 | PK11_FreeSymKey(newIkm1); |
128 | 0 | if (slot) |
129 | 0 | PK11_FreeSlot(slot); |
130 | 0 | if (!prk) { |
131 | 0 | return SECFailure; |
132 | 0 | } |
133 | | |
134 | 0 | PRINT_KEY(50, (NULL, "HKDF Extract", prk)); |
135 | 0 | *prkp = prk; |
136 | |
|
137 | 0 | return SECSuccess; |
138 | 0 | } |
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 | 0 | { |
148 | 0 | CK_HKDF_PARAMS params; |
149 | 0 | 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 | 0 | PRUint8 info[256]; |
154 | 0 | sslBuffer infoBuf = SSL_BUFFER(info); |
155 | 0 | PK11SymKey *derived; |
156 | 0 | SECStatus rv; |
157 | 0 | const char *kLabelPrefixTls = "tls13 "; |
158 | 0 | const char *kLabelPrefixDtls = "dtls13"; |
159 | 0 | const unsigned int kLabelPrefixLen = |
160 | 0 | (variant == ssl_variant_stream) ? strlen(kLabelPrefixTls) : strlen(kLabelPrefixDtls); |
161 | 0 | const char *kLabelPrefix = |
162 | 0 | (variant == ssl_variant_stream) ? kLabelPrefixTls : kLabelPrefixDtls; |
163 | |
|
164 | 0 | PORT_Assert(prk); |
165 | 0 | PORT_Assert(keyp); |
166 | 0 | if ((handshakeHashLen > 255) || |
167 | 0 | (handshakeHash == NULL && handshakeHashLen > 0) || |
168 | 0 | (labelLen + kLabelPrefixLen > 255)) { |
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 | 0 | rv = sslBuffer_AppendNumber(&infoBuf, keySize, 2); |
194 | 0 | if (rv != SECSuccess) { |
195 | 0 | return SECFailure; |
196 | 0 | } |
197 | 0 | rv = sslBuffer_AppendNumber(&infoBuf, labelLen + kLabelPrefixLen, 1); |
198 | 0 | if (rv != SECSuccess) { |
199 | 0 | return SECFailure; |
200 | 0 | } |
201 | 0 | rv = sslBuffer_Append(&infoBuf, kLabelPrefix, kLabelPrefixLen); |
202 | 0 | if (rv != SECSuccess) { |
203 | 0 | return SECFailure; |
204 | 0 | } |
205 | 0 | rv = sslBuffer_Append(&infoBuf, label, labelLen); |
206 | 0 | if (rv != SECSuccess) { |
207 | 0 | return SECFailure; |
208 | 0 | } |
209 | 0 | rv = sslBuffer_AppendVariable(&infoBuf, handshakeHash, handshakeHashLen, 1); |
210 | 0 | if (rv != SECSuccess) { |
211 | 0 | return SECFailure; |
212 | 0 | } |
213 | | |
214 | 0 | params.bExtract = CK_FALSE; |
215 | 0 | params.bExpand = CK_TRUE; |
216 | 0 | params.prfHashMechanism = kTlsHkdfInfo[baseHash].pkcs11Mech; |
217 | 0 | params.pInfo = SSL_BUFFER_BASE(&infoBuf); |
218 | 0 | params.ulInfoLen = SSL_BUFFER_LEN(&infoBuf); |
219 | 0 | paramsi.data = (unsigned char *)¶ms; |
220 | 0 | paramsi.len = sizeof(params); |
221 | 0 | derived = PK11_DeriveWithFlags(prk, deriveMech, |
222 | 0 | ¶msi, algorithm, |
223 | 0 | CKA_DERIVE, keySize, |
224 | 0 | CKF_SIGN | CKF_VERIFY); |
225 | 0 | if (!derived) { |
226 | 0 | return SECFailure; |
227 | 0 | } |
228 | | |
229 | 0 | *keyp = derived; |
230 | |
|
231 | 0 | #ifdef TRACE |
232 | 0 | 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 | 0 | PRINT_KEY(50, (NULL, "PRK", prk)); |
241 | 0 | PRINT_BUF(50, (NULL, "Hash", handshakeHash, handshakeHashLen)); |
242 | 0 | PRINT_BUF(50, (NULL, "Info", SSL_BUFFER_BASE(&infoBuf), |
243 | 0 | SSL_BUFFER_LEN(&infoBuf))); |
244 | 0 | PRINT_KEY(50, (NULL, "Derived key", derived)); |
245 | 0 | #endif |
246 | |
|
247 | 0 | return SECSuccess; |
248 | 0 | } |
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 | 0 | { |
257 | 0 | return tls13_HkdfExpandLabelGeneral(CKM_HKDF_DERIVE, prk, baseHash, |
258 | 0 | handshakeHash, handshakeHashLen, |
259 | 0 | label, labelLen, algorithm, keySize, |
260 | 0 | variant, keyp); |
261 | 0 | } |
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 | 0 | { |
270 | 0 | PK11SymKey *derived = NULL; |
271 | 0 | SECItem *rawkey; |
272 | 0 | SECStatus rv; |
273 | | |
274 | | /* the result is not really a key, it's a data object */ |
275 | 0 | rv = tls13_HkdfExpandLabelGeneral(CKM_HKDF_DATA, prk, baseHash, |
276 | 0 | handshakeHash, handshakeHashLen, |
277 | 0 | label, labelLen, CKM_HKDF_DERIVE, outputLen, |
278 | 0 | variant, &derived); |
279 | 0 | if (rv != SECSuccess || !derived) { |
280 | 0 | goto abort; |
281 | 0 | } |
282 | | |
283 | 0 | rv = PK11_ExtractKeyValue(derived); |
284 | 0 | if (rv != SECSuccess) { |
285 | 0 | goto abort; |
286 | 0 | } |
287 | | |
288 | 0 | rawkey = PK11_GetKeyData(derived); |
289 | 0 | if (!rawkey) { |
290 | 0 | goto abort; |
291 | 0 | } |
292 | | |
293 | 0 | PORT_Assert(rawkey->len == outputLen); |
294 | 0 | memcpy(output, rawkey->data, outputLen); |
295 | 0 | PK11_FreeSymKey(derived); |
296 | |
|
297 | 0 | 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 | 0 | } |