| 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;
|
| +}
|
|
|