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 *)&params;
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, &paramsi, 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 *)&params;
220     paramsi.len = sizeof(params);
221     derived = PK11_DeriveWithFlags(prk, deriveMech,
222                                    &paramsi, 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