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