Index: net/third_party/nss/ssl/tls13hkdf.c |
diff --git a/net/third_party/nss/ssl/tls13hkdf.c b/net/third_party/nss/ssl/tls13hkdf.c |
new file mode 100644 |
index 0000000000000000000000000000000000000000..3dc2d1bf8d05fc46ba03d951c7057657891a0cb2 |
--- /dev/null |
+++ b/net/third_party/nss/ssl/tls13hkdf.c |
@@ -0,0 +1,212 @@ |
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
+/* |
+ * TLS 1.3 Protocol |
+ * |
+ * This Source Code Form is subject to the terms of the Mozilla Public |
+ * License, v. 2.0. If a copy of the MPL was not distributed with this |
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
+ |
+#include "keyhi.h" |
+#include "pk11func.h" |
+#include "secitem.h" |
+#include "sslt.h" |
+#include "sslerr.h" |
+ |
+// TODO(ekr@rtfm.com): Export this separately. |
+unsigned char *tls13_EncodeUintX(PRUint32 value, unsigned int bytes, unsigned char *to); |
+ |
+/* This table contains the mapping between TLS hash identifiers and the |
+ * PKCS#11 identifiers */ |
+static const struct { |
+ SSLHashType hash; |
+ CK_MECHANISM_TYPE pkcs11Mech; |
+ unsigned int hashSize; |
+} kTlsHkdfInfo[] = { |
+ { ssl_hash_none, 0, 0 }, |
+ { ssl_hash_md5, 0, 0 }, |
+ { ssl_hash_sha1, 0, 0 }, |
+ { ssl_hash_sha224, 0 }, |
+ { ssl_hash_sha256, CKM_NSS_HKDF_SHA256, 32 }, |
+ { ssl_hash_sha384, CKM_NSS_HKDF_SHA384, 48 }, |
+ { ssl_hash_sha512, CKM_NSS_HKDF_SHA512, 64 } |
+}; |
+ |
+SECStatus |
+tls13_HkdfExtract(PK11SymKey *ikm1, PK11SymKey *ikm2, SSLHashType baseHash, |
+ PK11SymKey **prkp) |
+{ |
+ CK_NSS_HKDFParams params; |
+ SECItem paramsi; |
+ SECStatus rv; |
+ SECItem *salt; |
+ PK11SymKey *prk; |
+ |
+ params.bExtract = CK_TRUE; |
+ params.bExpand = CK_FALSE; |
+ params.pInfo = NULL; |
+ params.ulInfoLen = 0UL; |
+ |
+ if (ikm1) { |
+ /* TODO(ekr@rtfm.com): This violates the PKCS#11 key boundary |
+ * but is imposed on us by the present HKDF interface. */ |
+ rv = PK11_ExtractKeyValue(ikm1); |
+ if (rv != SECSuccess) |
+ return rv; |
+ |
+ salt = PK11_GetKeyData(ikm1); |
+ if (!salt) |
+ return SECFailure; |
+ |
+ params.pSalt = salt->data; |
+ params.ulSaltLen = salt->len; |
+ PORT_Assert(salt->len > 0); |
+ } else { |
+ /* Per documentation for CKM_NSS_HKDF_*: |
+ * |
+ * If the optional salt is given, it is used; otherwise, the salt is |
+ * set to a sequence of zeros equal in length to the HMAC output. |
+ */ |
+ params.pSalt = NULL; |
+ params.ulSaltLen = 0UL; |
+ } |
+ paramsi.data = (unsigned char *)¶ms; |
+ paramsi.len = sizeof(params); |
+ |
+ PORT_Assert(kTlsHkdfInfo[baseHash].pkcs11Mech); |
+ PORT_Assert(kTlsHkdfInfo[baseHash].hashSize); |
+ PORT_Assert(kTlsHkdfInfo[baseHash].hash == baseHash); |
+ prk = PK11_Derive(ikm2, kTlsHkdfInfo[baseHash].pkcs11Mech, |
+ ¶msi, kTlsHkdfInfo[baseHash].pkcs11Mech, |
+ CKA_DERIVE, kTlsHkdfInfo[baseHash].hashSize); |
+ if (!prk) |
+ return SECFailure; |
+ |
+ *prkp = prk; |
+ return SECSuccess; |
+} |
+ |
+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, |
+ PK11SymKey **keyp) |
+{ |
+ CK_NSS_HKDFParams params; |
+ SECItem paramsi = { siBuffer, NULL, 0 }; |
+ PRUint8 info[100]; |
+ PRUint8 *ptr = info; |
+ unsigned int infoLen; |
+ PK11SymKey *derived; |
+ const char *kLabelPrefix = "TLS 1.3, "; |
+ const unsigned int kLabelPrefixLen = strlen(kLabelPrefix); |
+ |
+ if (handshakeHash) { |
+ PORT_Assert(handshakeHashLen == kTlsHkdfInfo[baseHash].hashSize); |
+ } else { |
+ PORT_Assert(!handshakeHashLen); |
+ } |
+ |
+ /* |
+ * [draft-ietf-tls-tls13-11] Section 7.1: |
+ * |
+ * HKDF-Expand-Label(Secret, Label, HashValue, Length) = |
+ * HKDF-Expand(Secret, HkdfLabel, Length) |
+ * |
+ * Where HkdfLabel is specified as: |
+ * |
+ * struct HkdfLabel { |
+ * uint16 length; |
+ * opaque label<9..255>; |
+ * opaque hash_value<0..255>; |
+ * }; |
+ * |
+ * Where: |
+ * - HkdfLabel.length is Length |
+ * - HkdfLabel.hash_value is HashValue. |
+ * - HkdfLabel.label is "TLS 1.3, " + Label |
+ * |
+ */ |
+ infoLen = 2 + 1 + kLabelPrefixLen + labelLen + 1 + handshakeHashLen; |
+ if (infoLen > sizeof(info)) { |
+ PORT_Assert(0); |
+ goto abort; |
+ } |
+ |
+ ptr = tls13_EncodeUintX(keySize, 2, ptr); |
+ ptr = tls13_EncodeUintX(labelLen + kLabelPrefixLen, 1, ptr); |
+ PORT_Memcpy(ptr, kLabelPrefix, kLabelPrefixLen); |
+ ptr += kLabelPrefixLen; |
+ PORT_Memcpy(ptr, label, labelLen); |
+ ptr += labelLen; |
+ ptr = tls13_EncodeUintX(handshakeHashLen, 1, ptr); |
+ if (handshakeHash) { |
+ PORT_Memcpy(ptr, handshakeHash, handshakeHashLen); |
+ ptr += handshakeHashLen; |
+ } |
+ PORT_Assert((ptr - info) == infoLen); |
+ |
+ params.bExtract = CK_FALSE; |
+ params.bExpand = CK_TRUE; |
+ params.pInfo = info; |
+ params.ulInfoLen = infoLen; |
+ paramsi.data = (unsigned char *)¶ms; |
+ paramsi.len = sizeof(params); |
+ |
+ derived = PK11_DeriveWithFlags(prk, kTlsHkdfInfo[baseHash].pkcs11Mech, |
+ ¶msi, algorithm, |
+ CKA_DERIVE, keySize, |
+ CKF_SIGN | CKF_VERIFY); |
+ if (!derived) |
+ return SECFailure; |
+ |
+ *keyp = derived; |
+ |
+ return SECSuccess; |
+ |
+abort: |
+ PORT_SetError(SSL_ERROR_SYM_KEY_CONTEXT_FAILURE); |
+ return SECFailure; |
+} |
+ |
+SECStatus |
+tls13_HkdfExpandLabelRaw(PK11SymKey *prk, SSLHashType baseHash, |
+ const PRUint8 *handshakeHash, unsigned int handshakeHashLen, |
+ const char *label, unsigned int labelLen, |
+ unsigned char *output, unsigned int outputLen) |
+{ |
+ PK11SymKey *derived = NULL; |
+ SECItem *rawkey; |
+ SECStatus rv; |
+ |
+ rv = tls13_HkdfExpandLabel(prk, baseHash, handshakeHash, handshakeHashLen, |
+ label, labelLen, |
+ kTlsHkdfInfo[baseHash].pkcs11Mech, outputLen, |
+ &derived); |
+ if (rv != SECSuccess || !derived) { |
+ goto abort; |
+ } |
+ |
+ rv = PK11_ExtractKeyValue(derived); |
+ if (rv != SECSuccess) { |
+ goto abort; |
+ } |
+ |
+ rawkey = PK11_GetKeyData(derived); |
+ if (!rawkey) { |
+ goto abort; |
+ } |
+ |
+ PORT_Assert(rawkey->len == outputLen); |
+ memcpy(output, rawkey->data, outputLen); |
+ PK11_FreeSymKey(derived); |
+ |
+ return SECSuccess; |
+ |
+abort: |
+ if (derived) { |
+ PK11_FreeSymKey(derived); |
+ } |
+ PORT_SetError(SSL_ERROR_SYM_KEY_CONTEXT_FAILURE); |
+ return SECFailure; |
+} |