Commit a4413156 authored by Martin Thomson's avatar Martin Thomson

Bug 1692930 - Update HPKE to final version, r=bbeurdouche

This adds the final HPKE version string.

This removes the draft version markers from the implementation and stops
tracking the draft version with the exported syntax.

I've added the script that I used to convert the JSON test vectors from the
specification; that should allow us to pick up new tests relatively easily,
especially if we need to add new algorithms.

This change breaks several ECH test cases.  As fixing those tests is
extraordinarily fiddly, I'm going to defer making those changes until we need to
update ECH.  As we can't land this code until ECH is updated to depend on the
final HPKE and until we have coordinated with servers on when the ECH update can
be deployed, it should be OK to defer.

In short, don't land this without the matching ECH changes.

Differential Revision: https://phabricator.services.mozilla.com/D105256

--HG--
extra : rebase_source : b0717403cf5136efc14f85499182763aa551efc3
parent 71f201b8
......@@ -573,11 +573,6 @@
'NSS_DISABLE_DBM',
],
}],
[ 'enable_draft_hpke==1', {
'defines': [
'NSS_ENABLE_DRAFT_HPKE',
],
}],
[ 'disable_libpkix==1', {
'defines': [
'NSS_DISABLE_LIBPKIX',
......
......@@ -195,10 +195,6 @@ ifdef NSS_PKIX_NO_LDAP
DEFINES += -DNSS_PKIX_NO_LDAP
endif
ifdef NSS_ENABLE_DRAFT_HPKE
DEFINES += -DNSS_ENABLE_DRAFT_HPKE
endif
# FIPS support requires startup tests to be executed at load time of shared modules.
# For performance reasons, these tests are disabled by default.
# When compiling binaries that must support FIPS mode,
......
#!/usr/bin/env python3
# This script converts the test vectors referenced by the specification into
# a form that matches our implementation.
import json
import sys
def pkcs8(sk, pk):
print(
f'"3067020100301406072a8648ce3d020106092b06010401da470f01044c304a0201010420{sk}a123032100{pk}",'
)
i = 0
for tc in json.load(sys.stdin):
# Only mode_base and mode_psk
if tc["mode"] != 0 and tc["mode"] != 1:
continue
# X25519
if tc["kem_id"] != 32:
continue
# SHA-2 256, 384, and 512
if tc["kdf_id"] != 1 and tc["kdf_id"] != 2 and tc["kdf_id"] != 3:
continue
# AES-128-GCM and ChaCha20Poly1305
if tc["aead_id"] != 1 and tc["aead_id"] != 3:
continue
print(f"{{{i},")
print(f"static_cast<HpkeModeId>({tc['mode']}),")
print(f"static_cast<HpkeKemId>({tc['kem_id']}),")
print(f"static_cast<HpkeKdfId>({tc['kdf_id']}),")
print(f"static_cast<HpkeAeadId>({tc['aead_id']}),")
print(f'"{tc["info"]}", // info')
pkcs8(tc["skEm"], tc["pkEm"])
pkcs8(tc["skRm"], tc["pkRm"])
print(f'"{tc.get("psk", "")}", // psk')
print(f'"{tc.get("psk_id", "")}", // psk_id')
print(f'"{tc["enc"]}", // enc')
print(f'"{tc["key"]}", // key')
print(f'"{tc["base_nonce"]}", // nonce')
print("{ // Encryptions")
for e in tc["encryptions"]:
print("{")
print(f'"{e["plaintext"]}", // pt')
print(f'"{e["aad"]}", // aad')
print(f'"{e["ciphertext"]}", // ct')
print("},")
print("},")
print("{ // Exports")
for e in tc["exports"]:
print("{")
print(f'"{e["exporter_context"]}", // context')
print(f'{e["L"]}, // len')
print(f'"{e["exported_value"]}", // exported')
print("},")
print("},")
print("},")
i = i + 1
This diff is collapsed.
......@@ -19,7 +19,6 @@
namespace nss_test {
/* See note in pk11pub.h. */
#ifdef NSS_ENABLE_DRAFT_HPKE
#include "cpputil.h"
class HpkeTest {
......@@ -682,14 +681,5 @@ TEST_F(ModeParameterizedTest, InvalidReceiverKeyType) {
pub_key.get(), &info_item));
EXPECT_EQ(SEC_ERROR_BAD_KEY, PORT_GetError());
}
#else
TEST(HpkeTest, EnsureNotImplemented) {
ScopedHpkeContext cx(
PK11_HPKE_NewContext(HpkeDhKemX25519Sha256, HpkeKdfHkdfSha256,
HpkeAeadChaCha20Poly1305, nullptr, nullptr));
EXPECT_FALSE(cx.get());
EXPECT_EQ(SEC_ERROR_INVALID_ALGORITHM, PORT_GetError());
}
#endif // NSS_ENABLE_DRAFT_HPKE
} // namespace nss_test
......@@ -660,7 +660,6 @@ TEST_P(TlsConnectGeneric, ClientAuthEcdsa) {
CheckKeys(ssl_kea_ecdh, ssl_auth_ecdsa);
}
#ifdef NSS_ENABLE_DRAFT_HPKE
TEST_P(TlsConnectGeneric, ClientAuthWithEch) {
Reset(TlsAgent::kServerEcdsa256);
EnsureTlsSetup();
......@@ -670,7 +669,6 @@ TEST_P(TlsConnectGeneric, ClientAuthWithEch) {
Connect();
CheckKeys(ssl_kea_ecdh, ssl_auth_ecdsa);
}
#endif
TEST_P(TlsConnectGeneric, ClientAuthBigRsa) {
Reset(TlsAgent::kServerRsa, TlsAgent::kRsa2048);
......
......@@ -214,7 +214,6 @@ TEST_F(Tls13CompatTest, EnabledHrrZeroRtt) {
CheckForCompatHandshake();
}
#ifdef NSS_ENABLE_DRAFT_HPKE
TEST_F(Tls13CompatTest, EnabledAcceptedEch) {
EnsureTlsSetup();
SetupEch(client_, server_);
......@@ -237,7 +236,6 @@ TEST_F(Tls13CompatTest, EnabledRejectedEch) {
// Reset expectations for the TlsAgent dtor.
server_->ExpectReceiveAlert(kTlsAlertCloseNotify, kTlsAlertWarning);
}
#endif
class TlsSessionIDEchoFilter : public TlsHandshakeFilter {
public:
......
......@@ -31,7 +31,6 @@ class TlsAgentEchTest : public TlsAgentTestClient13 {
}
};
#ifdef NSS_ENABLE_DRAFT_HPKE
#include "cpputil.h" // Unused function error if included without HPKE.
static std::string kPublicName("public.name");
......@@ -1755,25 +1754,5 @@ TEST_F(TlsConnectStreamTls13, EchBackendAcceptance) {
INSTANTIATE_TEST_SUITE_P(EchAgentTest, TlsAgentEchTest,
::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
TlsConnectTestBase::kTlsV13));
#else
TEST_P(TlsAgentEchTest, NoEchWithoutHpke) {
EnsureInit();
uint8_t non_null[1];
SECKEYPublicKey pub;
SECKEYPrivateKey priv;
ASSERT_EQ(SECFailure, SSL_SetClientEchConfigs(agent_->ssl_fd(), non_null,
sizeof(non_null)));
ASSERT_EQ(SSL_ERROR_FEATURE_DISABLED, PORT_GetError());
ASSERT_EQ(SECFailure, SSL_SetServerEchConfigs(agent_->ssl_fd(), &pub, &priv,
non_null, sizeof(non_null)));
ASSERT_EQ(SSL_ERROR_FEATURE_DISABLED, PORT_GetError());
}
INSTANTIATE_TEST_SUITE_P(EchAgentTest, TlsAgentEchTest,
::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
TlsConnectTestBase::kTlsV13));
#endif // NSS_ENABLE_DRAFT_HPKE
} // namespace nss_test
......@@ -18,97 +18,9 @@
#include "secmodti.h"
#include "secutil.h"
#ifndef NSS_ENABLE_DRAFT_HPKE
/* "Not Implemented" stubs to maintain the ABI. */
SECStatus
PK11_HPKE_ValidateParameters(HpkeKemId kemId, HpkeKdfId kdfId, HpkeAeadId aeadId)
{
PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
return SECFailure;
}
HpkeContext *
PK11_HPKE_NewContext(HpkeKemId kemId, HpkeKdfId kdfId, HpkeAeadId aeadId,
PK11SymKey *psk, const SECItem *pskId)
{
PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
return NULL;
}
SECStatus
PK11_HPKE_Deserialize(const HpkeContext *cx, const PRUint8 *enc,
unsigned int encLen, SECKEYPublicKey **outPubKey)
{
PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
return SECFailure;
}
void
PK11_HPKE_DestroyContext(HpkeContext *cx, PRBool freeit)
{
PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
}
const SECItem *
PK11_HPKE_GetEncapPubKey(const HpkeContext *cx)
{
PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
return NULL;
}
SECStatus
PK11_HPKE_ExportContext(const HpkeContext *cx, PK11SymKey *wrapKey, SECItem **serialized)
{
PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
return SECFailure;
}
SECStatus
PK11_HPKE_ExportSecret(const HpkeContext *cx, const SECItem *info,
unsigned int L, PK11SymKey **outKey)
{
PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
return SECFailure;
}
HpkeContext *
PK11_HPKE_ImportContext(const SECItem *serialized, PK11SymKey *wrapKey)
{
PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
return NULL;
}
SECStatus
PK11_HPKE_Open(HpkeContext *cx, const SECItem *aad, const SECItem *ct,
SECItem **outPt)
{
PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
return SECFailure;
}
SECStatus
PK11_HPKE_Seal(HpkeContext *cx, const SECItem *aad, const SECItem *pt, SECItem **outCt)
{
PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
return SECFailure;
}
SECStatus
PK11_HPKE_Serialize(const SECKEYPublicKey *pk, PRUint8 *buf, unsigned int *len, unsigned int maxLen)
{
PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
return SECFailure;
}
SECStatus
PK11_HPKE_SetupS(HpkeContext *cx, const SECKEYPublicKey *pkE, SECKEYPrivateKey *skE,
SECKEYPublicKey *pkR, const SECItem *info)
{
PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
return SECFailure;
}
SECStatus
PK11_HPKE_SetupR(HpkeContext *cx, const SECKEYPublicKey *pkR, SECKEYPrivateKey *skR,
const SECItem *enc, const SECItem *info)
{
PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
return SECFailure;
}
#else
#define SERIALIZATION_VERSION 1
#define SERIALIZATION_VERSION 2
static const char *DRAFT_LABEL = "HPKE-07";
static const char *V1_LABEL = "HPKE-v1";
static const char *EXP_LABEL = "exp";
static const char *HPKE_LABEL = "HPKE";
static const char *INFO_LABEL = "info_hash";
......@@ -142,14 +54,14 @@ static const hpkeKemParams kemParams[] = {
{ HpkeDhKemX25519Sha256, 32, 32, 32, SEC_OID_CURVE25519, CKM_SHA256 },
};
#define MAX_WRAPPED_EXP_LEN 72 // Largest kdfParams->Nh + 8
#define MAX_WRAPPED_EXP_LEN 72 // Largest kdfParams->Nh + 8
static const hpkeKdfParams kdfParams[] = {
/* KDF, Nh, mechanism */
{ HpkeKdfHkdfSha256, SHA256_LENGTH, CKM_SHA256 },
{ HpkeKdfHkdfSha384, SHA384_LENGTH, CKM_SHA384 },
{ HpkeKdfHkdfSha512, SHA512_LENGTH, CKM_SHA512 },
};
#define MAX_WRAPPED_KEY_LEN 40 // Largest aeadParams->Nk + 8
#define MAX_WRAPPED_KEY_LEN 40 // Largest aeadParams->Nk + 8
static const hpkeAeadParams aeadParams[] = {
/* AEAD, Nk, Nn, tagLen, mechanism */
{ HpkeAeadAes128Gcm, 16, 12, 16, CKM_AES_GCM },
......@@ -320,7 +232,6 @@ PK11_HPKE_DestroyContext(HpkeContext *cx, PRBool freeit)
/* Export Format:
struct {
uint8 serilizationVersion;
uint8 hpkeVersion;
uint16 kemId;
uint16 kdfId;
uint16 aeadId;
......@@ -332,7 +243,7 @@ PK11_HPKE_DestroyContext(HpkeContext *cx, PRBool freeit)
opaque exporterSecret<1..2^16-1>;
} HpkeSerializedContext
*/
#define EXPORTED_CTX_BASE_LEN 26 /* Fixed size plus 2B for each variable. */
#define EXPORTED_CTX_BASE_LEN 25 /* Fixed size plus 2B for each variable. */
#define REMAINING_BYTES(walker, buf) \
buf->len - (walker - buf->data)
SECStatus
......@@ -388,7 +299,6 @@ PK11_HPKE_ExportContext(const HpkeContext *cx, PK11SymKey *wrapKey, SECItem **se
walker = &serializedCx->data[0];
*(walker)++ = (PRUint8)SERIALIZATION_VERSION;
*(walker)++ = (PRUint8)HPKE_DRAFT_VERSION;
walker = encodeNumber(cx->kemParams->id, walker, 2);
walker = encodeNumber(cx->kdfParams->id, walker, 2);
......@@ -451,8 +361,6 @@ PK11_HPKE_ImportContext(const SECItem *serialized, PK11SymKey *wrapKey)
tmp8 = *(walker++);
CHECK_FAIL_ERR((tmp8 != SERIALIZATION_VERSION), SEC_ERROR_BAD_DATA);
tmp8 = *(walker++);
CHECK_FAIL_ERR((tmp8 != HPKE_DRAFT_VERSION), SEC_ERROR_INVALID_ALGORITHM);
walker = decodeNumber(&tmpn, walker, 2);
kem = (HpkeKemId)tmpn;
......@@ -745,7 +653,7 @@ pk11_hpke_LabeledExtractData(const HpkeContext *cx, SECItem *salt,
sizeof(params) };
PORT_Assert(cx && ikm && label && labelLen && out && suiteId);
labeledIkm = pk11_hpke_MakeExtractLabel(DRAFT_LABEL, strlen(DRAFT_LABEL), label, labelLen, suiteId, ikm);
labeledIkm = pk11_hpke_MakeExtractLabel(V1_LABEL, strlen(V1_LABEL), label, labelLen, suiteId, ikm);
CHECK_FAIL(!labeledIkm);
params.bExtract = CK_TRUE;
params.bExpand = CK_FALSE;
......@@ -800,7 +708,7 @@ pk11_hpke_LabeledExtract(const HpkeContext *cx, PK11SymKey *salt,
sizeof(params) };
PORT_Assert(cx && ikm && label && labelLen && out && suiteId);
innerLabel = pk11_hpke_MakeExtractLabel(DRAFT_LABEL, strlen(DRAFT_LABEL), label, labelLen, suiteId, NULL);
innerLabel = pk11_hpke_MakeExtractLabel(V1_LABEL, strlen(V1_LABEL), label, labelLen, suiteId, NULL);
CHECK_FAIL(!innerLabel);
labelData.pData = innerLabel->data;
labelData.ulLen = innerLabel->len;
......@@ -849,15 +757,15 @@ pk11_hpke_LabeledExpand(const HpkeContext *cx, PK11SymKey *prk, const SECItem *s
walker = encodeNumber(L, walker, 2);
len = info ? info->len : 0;
len += sizeof(encodedL) + strlen(DRAFT_LABEL) + suiteId->len + labelLen;
len += sizeof(encodedL) + strlen(V1_LABEL) + suiteId->len + labelLen;
labeledInfoItem = SECITEM_AllocItem(NULL, NULL, len);
CHECK_FAIL(!labeledInfoItem);
walker = labeledInfoItem->data;
PORT_Memcpy(walker, encodedL, sizeof(encodedL));
walker += sizeof(encodedL);
PORT_Memcpy(walker, DRAFT_LABEL, strlen(DRAFT_LABEL));
walker += strlen(DRAFT_LABEL);
PORT_Memcpy(walker, V1_LABEL, strlen(V1_LABEL));
walker += strlen(V1_LABEL);
PORT_Memcpy(walker, suiteId->data, suiteId->len);
walker += suiteId->len;
PORT_Memcpy(walker, label, labelLen);
......@@ -1362,5 +1270,3 @@ CLEANUP:
}
return rv;
}
#endif // NSS_ENABLE_DRAFT_HPKE
......@@ -8,9 +8,6 @@
#include "blapit.h"
#include "seccomon.h"
#ifdef NSS_ENABLE_DRAFT_HPKE
#define HPKE_DRAFT_VERSION 7
#define CLEANUP \
PORT_Assert(rv == SECSuccess); \
cleanup
......@@ -35,8 +32,6 @@
goto cleanup; \
}
#endif /* NSS_ENABLE_DRAFT_HPKE */
typedef enum {
HpkeModeBase = 0,
HpkeModePsk = 1,
......
......@@ -738,14 +738,8 @@ CK_BBOOL PK11_HasAttributeSet(PK11SlotInfo *slot,
PRBool haslock /* must be set to PR_FALSE */);
/**********************************************************************
* Hybrid Public Key Encryption (draft-07)
* Hybrid Public Key Encryption
**********************************************************************/
/*
* NOTE: All HPKE functions will fail with SEC_ERROR_INVALID_ALGORITHM
* unless NSS is compiled with NSS_ENABLE_DRAFT_HPKE while spec (and
* implementation) is in draft. The eventual RFC number is an input to
* the key schedule, so applications opting into this MUST be prepared for
* outputs to change when the implementation is updated or finalized. */
/* Some of the various HPKE arguments would ideally be const, but the
* underlying PK11 functions take them as non-const. To avoid lying to
......
......@@ -622,10 +622,6 @@ SSLExp_SetServerEchConfigs(PRFileDesc *fd,
const SECKEYPublicKey *pubKey, const SECKEYPrivateKey *privKey,
const PRUint8 *echConfigs, unsigned int echConfigsLen)
{
#ifndef NSS_ENABLE_DRAFT_HPKE
PORT_SetError(SSL_ERROR_FEATURE_DISABLED);
return SECFailure;
#else
sslSocket *ss;
SECStatus rv;
SECItem data = { siBuffer, CONST_CAST(PRUint8, echConfigs), echConfigsLen };
......@@ -675,7 +671,6 @@ loser:
ss->echPubKey = NULL;
ss->echPrivKey = NULL;
return SECFailure;
#endif
}
/* Client enable. For now, we'll use the first
......@@ -685,10 +680,6 @@ SSLExp_SetClientEchConfigs(PRFileDesc *fd,
const PRUint8 *echConfigs,
unsigned int echConfigsLen)
{
#ifndef NSS_ENABLE_DRAFT_HPKE
PORT_SetError(SSL_ERROR_FEATURE_DISABLED);
return SECFailure;
#else
SECStatus rv;
sslSocket *ss;
SECItem data = { siBuffer, CONST_CAST(PRUint8, echConfigs), echConfigsLen };
......@@ -722,7 +713,6 @@ SSLExp_SetClientEchConfigs(PRFileDesc *fd,
}
return SECSuccess;
#endif
}
/* Set up ECH. This generates an ephemeral sender
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment