/src/mozilla-central/security/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_NSS_HKDF_SHA256, 32 }, |
29 | | { ssl_hash_sha384, CKM_NSS_HKDF_SHA384, 48 }, |
30 | | { ssl_hash_sha512, CKM_NSS_HKDF_SHA512, 64 } |
31 | | }; |
32 | | |
33 | | SECStatus |
34 | | tls13_HkdfExtract(PK11SymKey *ikm1, PK11SymKey *ikm2in, SSLHashType baseHash, |
35 | | PK11SymKey **prkp) |
36 | 0 | { |
37 | 0 | CK_NSS_HKDFParams params; |
38 | 0 | SECItem paramsi; |
39 | 0 | SECStatus rv; |
40 | 0 | SECItem *salt; |
41 | 0 | PK11SymKey *prk; |
42 | 0 | static const PRUint8 zeroKeyBuf[HASH_LENGTH_MAX]; |
43 | 0 | PK11SymKey *zeroKey = NULL; |
44 | 0 | PK11SlotInfo *slot = NULL; |
45 | 0 | PK11SymKey *ikm2; |
46 | 0 |
|
47 | 0 | params.bExtract = CK_TRUE; |
48 | 0 | params.bExpand = CK_FALSE; |
49 | 0 | params.pInfo = NULL; |
50 | 0 | params.ulInfoLen = 0UL; |
51 | 0 |
|
52 | 0 | if (ikm1) { |
53 | 0 | /* TODO(ekr@rtfm.com): This violates the PKCS#11 key boundary |
54 | 0 | * but is imposed on us by the present HKDF interface. */ |
55 | 0 | rv = PK11_ExtractKeyValue(ikm1); |
56 | 0 | if (rv != SECSuccess) |
57 | 0 | return rv; |
58 | 0 | |
59 | 0 | salt = PK11_GetKeyData(ikm1); |
60 | 0 | if (!salt) |
61 | 0 | return SECFailure; |
62 | 0 | |
63 | 0 | params.pSalt = salt->data; |
64 | 0 | params.ulSaltLen = salt->len; |
65 | 0 | PORT_Assert(salt->len > 0); |
66 | 0 | } else { |
67 | 0 | /* Per documentation for CKM_NSS_HKDF_*: |
68 | 0 | * |
69 | 0 | * If the optional salt is given, it is used; otherwise, the salt is |
70 | 0 | * set to a sequence of zeros equal in length to the HMAC output. |
71 | 0 | */ |
72 | 0 | params.pSalt = NULL; |
73 | 0 | params.ulSaltLen = 0UL; |
74 | 0 | } |
75 | 0 | paramsi.data = (unsigned char *)¶ms; |
76 | 0 | paramsi.len = sizeof(params); |
77 | 0 |
|
78 | 0 | PORT_Assert(kTlsHkdfInfo[baseHash].pkcs11Mech); |
79 | 0 | PORT_Assert(kTlsHkdfInfo[baseHash].hashSize); |
80 | 0 | PORT_Assert(kTlsHkdfInfo[baseHash].hash == baseHash); |
81 | 0 |
|
82 | 0 | /* A zero ikm2 is a key of hash-length 0s. */ |
83 | 0 | if (!ikm2in) { |
84 | 0 | SECItem zeroItem = { |
85 | 0 | siBuffer, |
86 | 0 | (unsigned char *)zeroKeyBuf, |
87 | 0 | kTlsHkdfInfo[baseHash].hashSize |
88 | 0 | }; |
89 | 0 | slot = PK11_GetInternalSlot(); |
90 | 0 | if (!slot) { |
91 | 0 | return SECFailure; |
92 | 0 | } |
93 | 0 | zeroKey = PK11_ImportSymKey(slot, |
94 | 0 | kTlsHkdfInfo[baseHash].pkcs11Mech, |
95 | 0 | PK11_OriginUnwrap, |
96 | 0 | CKA_DERIVE, &zeroItem, NULL); |
97 | 0 | if (!zeroKey) |
98 | 0 | return SECFailure; |
99 | 0 | ikm2 = zeroKey; |
100 | 0 | } else { |
101 | 0 | ikm2 = ikm2in; |
102 | 0 | } |
103 | 0 | PORT_Assert(ikm2); |
104 | 0 |
|
105 | 0 | PRINT_BUF(50, (NULL, "HKDF Extract: IKM1/Salt", params.pSalt, params.ulSaltLen)); |
106 | 0 | PRINT_KEY(50, (NULL, "HKDF Extract: IKM2", ikm2)); |
107 | 0 |
|
108 | 0 | prk = PK11_Derive(ikm2, kTlsHkdfInfo[baseHash].pkcs11Mech, |
109 | 0 | ¶msi, kTlsHkdfInfo[baseHash].pkcs11Mech, |
110 | 0 | CKA_DERIVE, kTlsHkdfInfo[baseHash].hashSize); |
111 | 0 | if (zeroKey) |
112 | 0 | PK11_FreeSymKey(zeroKey); |
113 | 0 | if (slot) |
114 | 0 | PK11_FreeSlot(slot); |
115 | 0 | if (!prk) |
116 | 0 | return SECFailure; |
117 | 0 | |
118 | 0 | PRINT_KEY(50, (NULL, "HKDF Extract", prk)); |
119 | 0 | *prkp = prk; |
120 | 0 |
|
121 | 0 | return SECSuccess; |
122 | 0 | } |
123 | | |
124 | | SECStatus |
125 | | tls13_HkdfExpandLabel(PK11SymKey *prk, SSLHashType baseHash, |
126 | | const PRUint8 *handshakeHash, unsigned int handshakeHashLen, |
127 | | const char *label, unsigned int labelLen, |
128 | | CK_MECHANISM_TYPE algorithm, unsigned int keySize, |
129 | | PK11SymKey **keyp) |
130 | 0 | { |
131 | 0 | CK_NSS_HKDFParams params; |
132 | 0 | SECItem paramsi = { siBuffer, NULL, 0 }; |
133 | 0 | /* Size of info array needs to be big enough to hold the maximum Prefix, |
134 | 0 | * Label, plus HandshakeHash. If it's ever to small, the code will abort. |
135 | 0 | */ |
136 | 0 | PRUint8 info[256]; |
137 | 0 | sslBuffer infoBuf = SSL_BUFFER(info); |
138 | 0 | PK11SymKey *derived; |
139 | 0 | SECStatus rv; |
140 | 0 | const char *kLabelPrefix = "tls13 "; |
141 | 0 | const unsigned int kLabelPrefixLen = strlen(kLabelPrefix); |
142 | 0 |
|
143 | 0 | if (handshakeHash) { |
144 | 0 | if (handshakeHashLen > 255) { |
145 | 0 | PORT_Assert(0); |
146 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
147 | 0 | return SECFailure; |
148 | 0 | } |
149 | 0 | } else { |
150 | 0 | PORT_Assert(!handshakeHashLen); |
151 | 0 | } |
152 | 0 |
|
153 | 0 | /* |
154 | 0 | * [draft-ietf-tls-tls13-11] Section 7.1: |
155 | 0 | * |
156 | 0 | * HKDF-Expand-Label(Secret, Label, HashValue, Length) = |
157 | 0 | * HKDF-Expand(Secret, HkdfLabel, Length) |
158 | 0 | * |
159 | 0 | * Where HkdfLabel is specified as: |
160 | 0 | * |
161 | 0 | * struct HkdfLabel { |
162 | 0 | * uint16 length; |
163 | 0 | * opaque label<9..255>; |
164 | 0 | * opaque hash_value<0..255>; |
165 | 0 | * }; |
166 | 0 | * |
167 | 0 | * Where: |
168 | 0 | * - HkdfLabel.length is Length |
169 | 0 | * - HkdfLabel.hash_value is HashValue. |
170 | 0 | * - HkdfLabel.label is "TLS 1.3, " + Label |
171 | 0 | * |
172 | 0 | */ |
173 | 0 | rv = sslBuffer_AppendNumber(&infoBuf, keySize, 2); |
174 | 0 | if (rv != SECSuccess) { |
175 | 0 | return SECFailure; |
176 | 0 | } |
177 | 0 | rv = sslBuffer_AppendNumber(&infoBuf, labelLen + kLabelPrefixLen, 1); |
178 | 0 | if (rv != SECSuccess) { |
179 | 0 | return SECFailure; |
180 | 0 | } |
181 | 0 | rv = sslBuffer_Append(&infoBuf, kLabelPrefix, kLabelPrefixLen); |
182 | 0 | if (rv != SECSuccess) { |
183 | 0 | return SECFailure; |
184 | 0 | } |
185 | 0 | rv = sslBuffer_Append(&infoBuf, label, labelLen); |
186 | 0 | if (rv != SECSuccess) { |
187 | 0 | return SECFailure; |
188 | 0 | } |
189 | 0 | rv = sslBuffer_AppendVariable(&infoBuf, handshakeHash, handshakeHashLen, 1); |
190 | 0 | if (rv != SECSuccess) { |
191 | 0 | return SECFailure; |
192 | 0 | } |
193 | 0 | |
194 | 0 | params.bExtract = CK_FALSE; |
195 | 0 | params.bExpand = CK_TRUE; |
196 | 0 | params.pInfo = SSL_BUFFER_BASE(&infoBuf); |
197 | 0 | params.ulInfoLen = SSL_BUFFER_LEN(&infoBuf); |
198 | 0 | paramsi.data = (unsigned char *)¶ms; |
199 | 0 | paramsi.len = sizeof(params); |
200 | 0 |
|
201 | 0 | derived = PK11_DeriveWithFlags(prk, kTlsHkdfInfo[baseHash].pkcs11Mech, |
202 | 0 | ¶msi, algorithm, |
203 | 0 | CKA_DERIVE, keySize, |
204 | 0 | CKF_SIGN | CKF_VERIFY); |
205 | 0 | if (!derived) |
206 | 0 | return SECFailure; |
207 | 0 | |
208 | 0 | *keyp = derived; |
209 | 0 |
|
210 | | #ifdef TRACE |
211 | | if (ssl_trace >= 10) { |
212 | | /* Make sure the label is null terminated. */ |
213 | | char labelStr[100]; |
214 | | PORT_Memcpy(labelStr, label, labelLen); |
215 | | labelStr[labelLen] = 0; |
216 | | SSL_TRC(50, ("HKDF Expand: label='tls13 %s',requested length=%d", |
217 | | labelStr, keySize)); |
218 | | } |
219 | | PRINT_KEY(50, (NULL, "PRK", prk)); |
220 | | PRINT_BUF(50, (NULL, "Hash", handshakeHash, handshakeHashLen)); |
221 | | PRINT_BUF(50, (NULL, "Info", SSL_BUFFER_BASE(&infoBuf), |
222 | | SSL_BUFFER_LEN(&infoBuf))); |
223 | | PRINT_KEY(50, (NULL, "Derived key", derived)); |
224 | | #endif |
225 | |
|
226 | 0 | return SECSuccess; |
227 | 0 | } |
228 | | |
229 | | SECStatus |
230 | | tls13_HkdfExpandLabelRaw(PK11SymKey *prk, SSLHashType baseHash, |
231 | | const PRUint8 *handshakeHash, unsigned int handshakeHashLen, |
232 | | const char *label, unsigned int labelLen, |
233 | | unsigned char *output, unsigned int outputLen) |
234 | 0 | { |
235 | 0 | PK11SymKey *derived = NULL; |
236 | 0 | SECItem *rawkey; |
237 | 0 | SECStatus rv; |
238 | 0 |
|
239 | 0 | rv = tls13_HkdfExpandLabel(prk, baseHash, handshakeHash, handshakeHashLen, |
240 | 0 | label, labelLen, |
241 | 0 | kTlsHkdfInfo[baseHash].pkcs11Mech, outputLen, |
242 | 0 | &derived); |
243 | 0 | if (rv != SECSuccess || !derived) { |
244 | 0 | goto abort; |
245 | 0 | } |
246 | 0 | |
247 | 0 | rv = PK11_ExtractKeyValue(derived); |
248 | 0 | if (rv != SECSuccess) { |
249 | 0 | goto abort; |
250 | 0 | } |
251 | 0 | |
252 | 0 | rawkey = PK11_GetKeyData(derived); |
253 | 0 | if (!rawkey) { |
254 | 0 | goto abort; |
255 | 0 | } |
256 | 0 | |
257 | 0 | PORT_Assert(rawkey->len == outputLen); |
258 | 0 | memcpy(output, rawkey->data, outputLen); |
259 | 0 | PK11_FreeSymKey(derived); |
260 | 0 |
|
261 | 0 | return SECSuccess; |
262 | 0 | |
263 | 0 | abort: |
264 | 0 | if (derived) { |
265 | 0 | PK11_FreeSymKey(derived); |
266 | 0 | } |
267 | 0 | PORT_SetError(SSL_ERROR_SYM_KEY_CONTEXT_FAILURE); |
268 | 0 | return SECFailure; |
269 | 0 | } |