Bug 1688685 - land NSS 92dcda94c1d4 UPGRADE_NSS_RELEASE, r=bbeurdouche

2021-01-22  Kevin Jacobs  <kjacobs@mozilla.com>

	* automation/abi-check/previous-nss-release, lib/nss/nss.h,
	lib/softoken/softkver.h, lib/util/nssutil.h:
	Set version numbers to 3.62 Beta
	[680ec01577b9]

2021-01-23  Kevin Jacobs  <kjacobs@mozilla.com>

	* tests/chains/scenarios/nameconstraints.cfg,
	tests/libpkix/certs/NameConstraints.ipaca.cert,
	tests/libpkix/certs/NameConstraints.ocsp1.cert:
	Bug 1686134 - Renew two chains libpkix test certificates. r=rrelyea

	[3ddcd845704c]

2021-01-25  Kevin Jacobs  <kjacobs@mozilla.com>

	* gtests/common/testvectors/hpke-vectors.h,
	gtests/pk11_gtest/pk11_hpke_unittest.cc, lib/pk11wrap/pk11hpke.c,
	lib/pk11wrap/pk11hpke.h, lib/pk11wrap/pk11pub.h:
	Bug 1678398 - Update HPKE to draft-07. r=mt

	This patch updates HPKE to draft-07. A few other minor changes are
	included:
	- Refactor HPKE gtests for increased parameterized testing.
	- Replace memcpy calls with PORT_Memcpy
	- Serialization tweaks to make way for context Export/Import (D99277).

	This should not be landed without an ECH update, as fixed ECH test
	vectors will otherwise fail to decrypt.

	[e0bf8cadadc7]

	* automation/abi-check/expected-report-libnss3.so.txt,
	gtests/pk11_gtest/pk11_hpke_unittest.cc, lib/nss/nss.def,
	lib/pk11wrap/pk11hpke.c, lib/pk11wrap/pk11pub.h:
	Bug 1678398 - Add Export/Import functions for HPKE context. r=mt

	This patch adds and exports two new HPKE functions:
	`PK11_HPKE_ExportContext` and `PK11_HPKE_ImportContext`, which are
	used to export a serialized HPKE context, then later reimport that
	context and resume Open and Export operations. Only receiver
	contexts are currently supported for export (see the rationale in
	pk11pub.h).

	One other change introduced here is that `PK11_HPKE_GetEncapPubKey`
	now works as expected on the receiver side.

	If the `wrapKey` argument is provided to the Export/Import
	functions, then the symmetric keys are wrapped with AES Key Wrap
	with Padding (SP800-38F, 6.3) prior to serialization.

	[8bcd12ab3b34]

	* automation/abi-check/expected-report-libssl3.so.txt,
	gtests/ssl_gtest/libssl_internals.c,
	gtests/ssl_gtest/libssl_internals.h,
	gtests/ssl_gtest/ssl_extension_unittest.cc,
	gtests/ssl_gtest/tls_ech_unittest.cc, lib/ssl/ssl3con.c,
	lib/ssl/ssl3ext.c, lib/ssl/ssl3ext.h, lib/ssl/sslexp.h,
	lib/ssl/sslimpl.h, lib/ssl/sslsecur.c, lib/ssl/sslsock.c,
	lib/ssl/sslt.h, lib/ssl/tls13con.c, lib/ssl/tls13con.h,
	lib/ssl/tls13ech.c, lib/ssl/tls13ech.h, lib/ssl/tls13exthandle.c,
	lib/ssl/tls13exthandle.h, lib/ssl/tls13hashstate.c,
	lib/ssl/tls13hashstate.h:
	Bug 1681585 - Update ECH to Draft-09. r=mt

	This patch updates ECH implementation to draft-09. Changes of note
	are:

	- Acceptance signal derivation is now based on the handshake secret.
	- `config_id` hint changes from 32B to 8B, trial decryption added on
	the server.
	- Duplicate code in HRR cookie handling has been consolidated into
	`tls13_HandleHrrCookie`.
	- `ech_is_inner` extension is added, which causes a server to indicate
	ECH acceptance.
	- Per the above, support signaling ECH acceptance when acting as a
	backend server in split-mode (i.e. when there is no other local
	Encrypted Client Hello state).

	[ed07a2e2a124]

2021-01-24  Kevin Jacobs  <kjacobs@mozilla.com>

	* cmd/selfserv/selfserv.c:
	Bug 1681585 - Add ECH support to selfserv. r=mt

	Usage example: mkdir dbdir && cd dbdir certutil -N -d . certutil -S
	-s "CN=ech-public.com" -n ech-public.com -x -t "C,C,C" -m 1234 -d .
	certutil -S -s "CN=ech-private-backend.com" -n ech-private-
	backend.com -x -t "C,C,C" -m 2345 -d . ../dist/Debug/bin/selfserv -a
	ech-public.com -a ech-private-backend.com -n ech-public.com -n ech-
	private-backend.com -p 8443 -d dbdir/ -X publicname:ech-public.com
	(Copy echconfig from selfserv output and paste into the below
	command) ../dist/Debug/bin/tstclnt -D -p 8443 -v -A
	tests/ssl/sslreq.dat -h ech-private-backend.com -o -N <echconfig> -v

	[92dcda94c1d4]

Differential Revision: https://phabricator.services.mozilla.com/D102982
This commit is contained in:
Kevin Jacobs 2021-01-26 15:30:01 +00:00
Родитель cdd336deb4
Коммит f9716bc8ab
39 изменённых файлов: 2416 добавлений и 1241 удалений

Просмотреть файл

@ -9,7 +9,7 @@ option("--with-system-nss", help="Use system NSS")
imply_option("--with-system-nspr", True, when="--with-system-nss")
nss_pkg = pkg_check_modules(
"NSS", "nss >= 3.61", when="--with-system-nss", config=False
"NSS", "nss >= 3.62", when="--with-system-nss", config=False
)
set_config("MOZ_SYSTEM_NSS", True, when="--with-system-nss")

Просмотреть файл

@ -1 +1 @@
NSS_3_61_RTM
92dcda94c1d4

Просмотреть файл

@ -0,0 +1,5 @@
2 Added functions:
[A] 'function SECStatus PK11_HPKE_ExportContext(const HpkeContext*, PK11SymKey*, SECItem**)' {PK11_HPKE_ExportContext@@NSS_3.62}
[A] 'function HpkeContext* PK11_HPKE_ImportContext(const SECItem*, PK11SymKey*)' {PK11_HPKE_ImportContext@@NSS_3.62}

Просмотреть файл

@ -0,0 +1,11 @@
1 function with some indirect sub-type change:
[C] 'function SECStatus SSL_HandshakeNegotiatedExtension(PRFileDesc*, SSLExtensionType, PRBool*)' at sslreveal.c:72:1 has some indirect sub-type changes:
parameter 2 of type 'typedef SSLExtensionType' has sub-type changes:
underlying type 'enum __anonymous_enum__' at sslt.h:519:1 changed:
type size hasn't changed
1 enumerator insertion:
'__anonymous_enum__::ssl_tls13_ech_is_inner_xtn' value '55817'
1 enumerator change:
'__anonymous_enum__::ssl_tls13_encrypted_client_hello_xtn' from value '65032' to '65033' at sslt.h:519:1

Просмотреть файл

@ -1 +1 @@
NSS_3_60_BRANCH
NSS_3_61_BRANCH

Просмотреть файл

@ -42,6 +42,7 @@
#include "cert.h"
#include "certt.h"
#include "ocsp.h"
#include "nssb64.h"
#ifndef PORT_Sprintf
#define PORT_Sprintf sprintf
@ -140,6 +141,7 @@ static int configureReuseECDHE = -1; /* -1: don't configure, 0 refresh, >=1 reus
static int configureWeakDHE = -1; /* -1: don't configure, 0 disable, >=1 enable*/
SECItem psk = { siBuffer, NULL, 0 };
SECItem pskLabel = { siBuffer, NULL, 0 };
char *echParamsStr = NULL;
static PRThread *acceptorThread;
@ -247,7 +249,14 @@ PrintParameterUsage()
"-z Configure a TLS 1.3 External PSK with the given hex string for a key.\n"
" To specify a label, use ':' as a delimiter. For example:\n"
" 0xAAAABBBBCCCCDDDD:mylabel. Otherwise, the default label of\n"
" 'Client_identity' will be used.\n",
" 'Client_identity' will be used.\n"
"-X Configure the server for ECH via the given <ECHParams>. ECHParams\n"
" are expected in one of two formats:\n"
" 1. A string containing the ECH public name prefixed by the substring\n"
" \"publicname:\". For example, \"publicname:example.com\". In this mode,\n"
" an ephemeral ECH keypair is generated and ECHConfigs are printed to stdout.\n"
" 2. As a Base64 tuple of <ECHRawPrivateKey> || <ECHConfigs>. In this mode, the\n"
" raw private key is used to bootstrap the HPKE context.\n",
stderr);
}
@ -1873,6 +1882,196 @@ importPsk(PRFileDesc *model_sock)
return rv;
}
static SECStatus
configureEchWithPublicName(PRFileDesc *model_sock, const char *public_name)
{
SECStatus rv;
#define OID_LEN 65
unsigned char paramBuf[OID_LEN];
SECItem ecParams = { siBuffer, paramBuf, sizeof(paramBuf) };
SECKEYPublicKey *pubKey = NULL;
SECKEYPrivateKey *privKey = NULL;
SECOidData *oidData;
char *echConfigBase64 = NULL;
PRUint8 configBuf[1000];
unsigned int len = 0;
unsigned int echCipherSuite = ((unsigned int)HpkeKdfHkdfSha256 << 16) |
HpkeAeadChaCha20Poly1305;
PK11SlotInfo *slot = PK11_GetInternalKeySlot();
if (!slot) {
errWarn("PK11_GetInternalKeySlot failed");
return SECFailure;
}
oidData = SECOID_FindOIDByTag(SEC_OID_CURVE25519);
if (oidData && (2 + oidData->oid.len) < sizeof(paramBuf)) {
ecParams.data[0] = SEC_ASN1_OBJECT_ID;
ecParams.data[1] = oidData->oid.len;
memcpy(ecParams.data + 2, oidData->oid.data, oidData->oid.len);
ecParams.len = oidData->oid.len + 2;
} else {
errWarn("SECOID_FindOIDByTag failed");
goto loser;
}
privKey = PK11_GenerateKeyPair(slot, CKM_EC_KEY_PAIR_GEN, &ecParams,
&pubKey, PR_FALSE, PR_FALSE, NULL);
if (!privKey || !pubKey) {
errWarn("Failed to generate ECH keypair");
goto loser;
}
rv = SSL_EncodeEchConfig(echParamsStr, &echCipherSuite, 1,
HpkeDhKemX25519Sha256, pubKey, 50,
configBuf, &len, sizeof(configBuf));
if (rv != SECSuccess) {
errWarn("SSL_EncodeEchConfig failed");
goto loser;
}
rv = SSL_SetServerEchConfigs(model_sock, pubKey, privKey, configBuf, len);
if (rv != SECSuccess) {
errWarn("SSL_SetServerEchConfigs failed");
goto loser;
}
SECItem echConfigItem = { siBuffer, configBuf, len };
echConfigBase64 = NSSBase64_EncodeItem(NULL, NULL, 0, &echConfigItem);
if (!echConfigBase64) {
errWarn("NSSBase64_EncodeItem failed");
goto loser;
}
// Remove the newline characters that NSSBase64_EncodeItem unhelpfully inserts.
char *newline = strstr(echConfigBase64, "\r\n");
if (newline) {
memmove(newline, newline + 2, strlen(newline + 2) + 1);
}
printf("%s\n", echConfigBase64);
PORT_Free(echConfigBase64);
SECKEY_DestroyPrivateKey(privKey);
SECKEY_DestroyPublicKey(pubKey);
PK11_FreeSlot(slot);
return SECSuccess;
loser:
PORT_Free(echConfigBase64);
SECKEY_DestroyPrivateKey(privKey);
SECKEY_DestroyPublicKey(pubKey);
PK11_FreeSlot(slot);
return SECFailure;
}
static SECStatus
configureEchWithData(PRFileDesc *model_sock)
{
/* The input should be a Base64-encoded ECHKey struct:
* struct {
* opaque sk<0..2^16-1>;
* ECHConfig config<0..2^16>; // draft-ietf-tls-esni-09
* } ECHKey;
*
* This is not a standardized format, rather it's designed for
* interoperability with https://github.com/xvzcf/tls-interop-runner.
*/
#define REMAINING_BYTES(rdr, buf) \
buf->len - (rdr - buf->data)
SECStatus rv;
size_t len;
unsigned char *reader;
PK11SlotInfo *slot = NULL;
SECItem *decoded = NULL;
SECItem *pkcs8Key = NULL;
SECKEYPublicKey *pk = NULL;
SECKEYPrivateKey *sk = NULL;
decoded = NSSBase64_DecodeBuffer(NULL, NULL, echParamsStr, PORT_Strlen(echParamsStr));
if (!decoded || decoded->len < 2) {
errWarn("Couldn't decode ECHParams");
goto loser;
};
reader = decoded->data;
len = (*(reader++) << 8);
len |= *(reader++);
if (len > (REMAINING_BYTES(reader, decoded) - 2)) {
errWarn("Bad ECHParams encoding");
goto loser;
}
/* Importing a raw KEM private key is generally awful,
* however since we only support X25519, we can hardcode
* all the OID data. */
const PRUint8 pkcs8Start[] = { 0x30, 0x67, 0x02, 0x01, 0x00, 0x30, 0x14, 0x06,
0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01,
0x06, 0x09, 0x2B, 0x06, 0x01, 0x04, 0x01, 0xDA,
0x47, 0x0F, 0x01, 0x04, 0x4C, 0x30, 0x4A, 0x02,
0x01, 0x01, 0x04, 0x20 };
const PRUint8 pkcs8End[] = { 0xA1, 0x23, 0x03, 0x21, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00 };
pkcs8Key = SECITEM_AllocItem(NULL, NULL, sizeof(pkcs8Start) + len + sizeof(pkcs8End));
if (!pkcs8Key) {
goto loser;
}
PORT_Memcpy(pkcs8Key->data, pkcs8Start, sizeof(pkcs8Start));
PORT_Memcpy(&pkcs8Key->data[sizeof(pkcs8Start)], reader, len);
PORT_Memcpy(&pkcs8Key->data[sizeof(pkcs8Start) + len], pkcs8End, sizeof(pkcs8End));
reader += len;
/* Convert the key bytes to key handles */
slot = PK11_GetInternalKeySlot();
rv = PK11_ImportDERPrivateKeyInfoAndReturnKey(
slot, pkcs8Key, NULL, NULL, PR_FALSE, PR_FALSE, KU_ALL, &sk, NULL);
if (rv != SECSuccess || !sk) {
errWarn("ECH key import failed");
goto loser;
}
pk = SECKEY_ConvertToPublicKey(sk);
if (!pk) {
errWarn("ECH key conversion failed");
goto loser;
}
/* Remainder is the ECHConfig. */
rv = SSL_SetServerEchConfigs(model_sock, pk, sk, reader,
REMAINING_BYTES(reader, decoded));
if (rv != SECSuccess) {
errWarn("SSL_SetServerEchConfigs failed");
goto loser;
}
PK11_FreeSlot(slot);
SECKEY_DestroyPrivateKey(sk);
SECKEY_DestroyPublicKey(pk);
SECITEM_FreeItem(pkcs8Key, PR_TRUE);
SECITEM_FreeItem(decoded, PR_TRUE);
return SECSuccess;
loser:
if (slot) {
PK11_FreeSlot(slot);
}
SECKEY_DestroyPrivateKey(sk);
SECKEY_DestroyPublicKey(pk);
SECITEM_FreeItem(pkcs8Key, PR_TRUE);
SECITEM_FreeItem(decoded, PR_TRUE);
return SECFailure;
}
static SECStatus
configureEch(PRFileDesc *model_sock)
{
if (!PORT_Strncmp(echParamsStr, "publicname:", PORT_Strlen("publicname:"))) {
return configureEchWithPublicName(model_sock,
&echParamsStr[PORT_Strlen("publicname:")]);
}
return configureEchWithData(model_sock);
}
void
server_main(
PRFileDesc *listen_sock,
@ -2089,6 +2288,13 @@ server_main(
}
}
if (echParamsStr) {
rv = configureEch(model_sock);
if (rv != SECSuccess) {
errExit("configureEch failed");
}
}
if (MakeCertOK)
SSL_BadCertHook(model_sock, myBadCertHandler, NULL);
@ -2332,7 +2538,7 @@ main(int argc, char **argv)
** XXX: 'B', and 'q' were used in the past but removed
** in 3.28, please leave some time before resuing those. */
optstate = PL_CreateOptState(argc, argv,
"2:A:C:DEGH:I:J:L:M:NP:QRS:T:U:V:W:YZa:bc:d:e:f:g:hi:jk:lmn:op:rst:uvw:x:yz:");
"2:A:C:DEGH:I:J:L:M:NP:QRS:T:U:V:W:X:YZa:bc:d:e:f:g:hi:jk:lmn:op:rst:uvw:x:yz:");
while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
++optionsFound;
switch (optstate->option) {
@ -2599,9 +2805,17 @@ main(int argc, char **argv)
}
break;
case 'X':
echParamsStr = PORT_Strdup(optstate->value);
if (echParamsStr == NULL) {
PL_DestroyOptState(optstate);
fprintf(stderr, "echParamsStr copy failed.\n");
exit(5);
}
break;
default:
case '?':
fprintf(stderr, "Unrecognized or bad option specified.\n");
fprintf(stderr, "Unrecognized or bad option specified: %c\n", optstate->option);
fprintf(stderr, "Run '%s -h' for usage information.\n", progName);
exit(4);
break;
@ -2921,6 +3135,7 @@ cleanup:
}
SECITEM_ZfreeItem(&psk, PR_FALSE);
SECITEM_ZfreeItem(&pskLabel, PR_FALSE);
PORT_Free(echParamsStr);
if (NSS_Shutdown() != SECSuccess) {
SECU_PrintError(progName, "NSS_Shutdown");
if (loggerThread) {

Просмотреть файл

@ -10,3 +10,4 @@
*/
#error "Do not include this header file."

Просмотреть файл

@ -52,48 +52,37 @@ const hpke_vector kHpkeTestVectors[] = {
static_cast<HpkeKdfId>(1),
static_cast<HpkeAeadId>(1),
"4f6465206f6e2061204772656369616e2055726e",
"3067020100301406072a8648ce3d020106092b06010401da470f01044c304a"
"02010104208c490e5b0c7dbe0c6d2192484d2b7a0423b3b4544f2481095a9"
"9dbf238fb350fa1230321008a07563949fac6232936ed6f36c4fa735930ecd"
"eaef6734e314aeac35a56fd0a",
"3067020100301406072a8648ce3d020106092b06010401da470f01044c304a"
"02010104205a8aa0d2476b28521588e0c704b14db82cdd4970d340d293a957"
"6deaee9ec1c7a1230321008756e2580c07c1d2ffcb662f5fadc6d6ff13da85"
"abd7adfecf984aaa102c1269",
"3067020100301406072a8648ce3d020106092b06010401da470f01044c304a02010104206"
"cee2e2755790708a2a1be22667883a5e3f9ec52810404a0d889a0ed3e28de00a123032100"
"950897e0d37a8bdb0f2153edf5fa580a64b399c39fbb3d014f80983352a63617",
"3067020100301406072a8648ce3d020106092b06010401da470f01044c304a0201010420e"
"caf25b8485bcf40b9f013dbb96a6230f25733b8435bba0997a1dedbc7f78806a123032100"
"a5912b20892e36905bac635267e2353d58f8cc7525271a2bf57b9c48d2ec2c07",
"",
"",
"8a07563949fac6232936ed6f36c4fa735930ecdeaef6734e314aeac35a56fd0a",
"550ee0b7ec1ea2532f2e2bac87040a4c",
"2b855847756795a57229559a",
"950897e0d37a8bdb0f2153edf5fa580a64b399c39fbb3d014f80983352a63617",
"e20cee1bf5392ad2d3a442e231f187ae",
"5d99b2f03c452f7a9441933a",
{// Encryptions
{"4265617574792069732074727574682c20747275746820626561757479",
"436f756e742d30",
"971ba65db526758ea30ae748cd769bc8d90579b62a037816057f24ce4274"
"16bd47c05ed1c2446ac8e19ec9ae79"},
"9418f1ae06eddc43aa911032aed4a951754ee2286a786733761857f8d96a7ec8d852da9"
"3bc5eeab49623344aba"},
{"4265617574792069732074727574682c20747275746820626561757479",
"436f756e742d31",
"f18f1ec397667ca069b9a6ee0bebf0890cd5caa34bb9875b3600ca0142cb"
"a774dd35f2aafd79a02a08ca5f2806"},
"74d69c61899b9158bb50e95d92fbad106f612ea67c61b3c4bef65c8bf3dc18e17bf41ec"
"4c408688aae58358d0e"},
{"4265617574792069732074727574682c20747275746820626561757479",
"436f756e742d32",
"51a8dea350fe6e753f743ec17c956de4cbdfa35f3018fc6a12752c51d137"
"2c5093959f18c7253da9c953c6cfbe"}},
"e6602db9be05d81c4ab8fa621bc35993a7b759851075a34b3bffd257340011c70c9fa1f"
"5c11868a076fc3adb3b"}},
{// Exports
{"436f6e746578742d30", 32,
"0df04ac640d34a56561419bab20a68e6b7331070208004f89c7b973f4c47"
"2e92"},
{"436f6e746578742d31", 32,
"723c2c8f80e6b827e72bd8e80973a801a05514afe3d4bc46e82e505dceb9"
"53aa"},
{"436f6e746578742d32", 32,
"38010c7d5d81093a11b55e2403a258e9a195bcf066817b332dd996b0a9bc"
"bc9a"},
{"436f6e746578742d33", 32,
"ebf6ab4c3186131de9b2c3c0bc3e2ad21dfcbc4efaf050cd0473f5b1535a"
"8b6d"},
{"436f6e746578742d34", 32,
"c4823eeb3efd2d5216b2d3b16e542bf57470dc9b9ea9af6bce85b151a358"
"9d90"}}},
{"", 32,
"be82c06bd83fd6edd74385de5a70859b9e03def4c7bb224a10cfae86087f8a25"},
{"00", 32,
"82cbfd3c2b2db75e2311d457e569cf12b6387eb4309bca8e77adb2f2b599fc85"},
{"54657374436f6e74657874", 32,
"c8387c1e6ec4f026c7f3577e3f29df51f46161295eec84c4f64a9174f7b64e4f"}}},
// A.1. DHKEM(X25519, HKDF-SHA256), HKDF-SHA256, AES-128-GCM, PSK mode
{1,
@ -102,132 +91,153 @@ const hpke_vector kHpkeTestVectors[] = {
static_cast<HpkeKdfId>(1),
static_cast<HpkeAeadId>(1),
"4f6465206f6e2061204772656369616e2055726e",
"3067020100301406072a8648ce3d020106092b06010401da470f01044c304a020"
"1010420e7d2b539792a48a24451303ccd0cfe77176b6cb06823c439edfd217458"
"a1398aa12303210008d39d3e7f9b586341b6004dafba9679d2bd9340066edb247"
"e3e919013efcd0f",
"3067020100301406072a8648ce3d020106092b06010401da470f01044c304a020"
"10104204b41ef269169090551fcea177ecdf622bca86d82298e21cd93119b804c"
"cc5eaba123032100a5c85773bed3a831e7096f7df4ff5d1d8bac48fc97bfac366"
"141efab91892a3a",
"5db3b80a81cb63ca59470c83414ef70a",
"3067020100301406072a8648ce3d020106092b06010401da470f01044c304a02010104204"
"c1feed23e15ec6a55b8457e0c0f42a3a1ab3ccc309b7cbb7ac6165fc657bd3ba123032100"
"f16fa9440b2cb36c855b4b82fb87e1c02ce656dd132f7a7aec739294b6912768",
"3067020100301406072a8648ce3d020106092b06010401da470f01044c304a02010104208"
"e5430f0d821407670e5e3f6eecc9f52b2cad27b15a5fad1f3d05359ae30d81ca123032100"
"13c789187a2dda71889e4b98dc5443624ae68f309cea91865561cfa207586e3a",
"0247fd33b913760fa1fa51e1892d9f307fbe65eb171e8132c2af18555a738b82",
"456e6e796e20447572696e206172616e204d6f726961",
"08d39d3e7f9b586341b6004dafba9679d2bd9340066edb247e3e919013efcd0f",
"811e9b2d7a10f4f9d58786bf8a534ca6",
"b79b0c5a8c3808e238b10411",
"f16fa9440b2cb36c855b4b82fb87e1c02ce656dd132f7a7aec739294b6912768",
"70030b55bfb737d4f4355cf62302d281",
"746d5e6255902701c3e0b99f",
{// Encryptions
{"4265617574792069732074727574682c20747275746820626561757479",
"436f756e742d30",
"fb68f911b4e4033d1547f646ea30c9cee987fb4b4a8c30918e5de6e96de32fc"
"63466f2fc05e09aeff552489741"},
"63f7ed3d99e625d4a7373982b5f04daf0c3dfff39cac4b38eeb9d5c225cc3183bdbc91a"
"053db9b195319cc8c45"},
{"4265617574792069732074727574682c20747275746820626561757479",
"436f756e742d31",
"85e7472fbb7e2341af35fb2a0795df9a85caa99a8f584056b11d452bc160470"
"672e297f9892ce2c5020e794ae1"},
"65e7160f80fdf47893a5abe1edcff46c85899f04acb97882e194ce6d4fceec2dc4cb2d3"
"abe5d969880722859b2"},
{"4265617574792069732074727574682c20747275746820626561757479",
"436f756e742d32",
"74229b7491102bcf94cf7633888bc48baa4e5a73cc544bfad4ff61585506fac"
"b44b359ade03c0b2b35c6430e4c"}},
"915e08e6e340fca64982e90ad93490826bfb74af8f48062212c87105dad2b7569c83688"
"e564ed5862592b77cdc"}},
{// Exports
{"436f6e746578742d30", 32,
"bd292b132fae00243851451c3f3a87e9e11c3293c14d61b114b7e12e07245ffd"},
{"436f6e746578742d31", 32,
"695de26bc9336caee01cb04826f6e224f4d2108066ab17fc18f0c993dce05f24"},
{"436f6e746578742d32", 32,
"c53f26ef1bf4f5fd5469d807c418a0e103d035c76ccdbc6afb5bc42b24968f6c"},
{"436f6e746578742d33", 32,
"8cea4a595dfe3de84644ca8ea7ea9401a345f0db29bb4beebc2c471afc602ec4"},
{"436f6e746578742d34", 32,
"e6313f12f6c2054c69018f273211c54fcf2439d90173392eaa34b4caac929068"}}},
// A.2. DHKEM(X25519, HKDF-SHA256), HKDF-SHA256, ChaCha20Poly1305, Base mode
{"", 32,
"7c40ceb745e14d19fceeac6e4756c796957fe5ff28709198c3f8cbdb5d368fe1"},
{"00", 32,
"1ef0fd07bd40326f1b88f3545c92969cff202ca7186b9fd1315241f93fcc2edf"},
{"54657374436f6e74657874", 32,
"997368419db9490aa96c977cdd90bda8fd6234054d4add3d2f31aaaa2f8c1172"}}},
// A.2. DHKEM(X25519, HKDF-SHA256), HKDF-SHA256, ChaCha20Poly1305, Base
// mode
{2,
static_cast<HpkeModeId>(0),
static_cast<HpkeKemId>(32),
static_cast<HpkeKdfId>(1),
static_cast<HpkeAeadId>(3),
"4f6465206f6e2061204772656369616e2055726e",
"3067020100301406072a8648ce3d020106092b06010401da470f01044c304a020"
"10104205006a9a0f0138b9b5d577ed4a67c4f795aee8fc146ac63d7a4167765be"
"3ad7dca123032100716281787b035b2fee90455d951fa70b3db6cc92f13bedfd7"
"58c3487994b7020",
"3067020100301406072a8648ce3d020106092b06010401da470f01044c304a020"
"101042062139576dcbf9878ccd56262d1b28dbea897821c03370d81971513cc74"
"aea3ffa1230321001ae26f65041b36ad69eb392c198bfd33df1c6ff17a910cb3e"
"49db7506b6a4e7f",
"3067020100301406072a8648ce3d020106092b06010401da470f01044c304a0201010420e"
"fda8f0538ce6ab9f165aae26e02ad96dcb1775b248267174aeb3d140e002ee3a123032100"
"1440805f4e60cbd34835baf0813c3071d17def1dbd8c04e75889bb2271d7823a",
"3067020100301406072a8648ce3d020106092b06010401da470f01044c304a02010104201"
"4365bb26500e7cf263720c4ab04bd45b8e146b4f724facd1fa01d58b63975e4a123032100"
"26147d5c2978bccc3cc03a4f9ac607560b5d83f852be4e9024f2cb7207d4c30e",
"",
"",
"716281787b035b2fee90455d951fa70b3db6cc92f13bedfd758c3487994b7020",
"1d5e71e2885ddadbcc479798cc65ea74d308f2a9e99c0cc7fe480adce66b5722",
"8354a7fcfef97d4bbef6d24e",
"1440805f4e60cbd34835baf0813c3071d17def1dbd8c04e75889bb2271d7823a",
"a17448a542d0d6d75e3b21be0a1f68607904b4802c6b19a7e7e90976aa00a5c8",
"6f6b832dba944a91e5684514",
{// Encryptions
{"4265617574792069732074727574682c20747275746820626561757479",
"436f756e742d30",
"fa4632a400962c98143e58450e75d879365359afca81a5f5b5997c6555647ec"
"302045a80c57d3e2c2abe7e1ced"},
"1b9ce69bd0e6b4242ac2dd841ef093fc9dfa9e684f81c2d1778fd3268ca5aa7d612cd87"
"f72acd2aeaee084dee2"},
{"4265617574792069732074727574682c20747275746820626561757479",
"436f756e742d31",
"8313fcbf760714f5a93b6864820e48dcec3ddd476ad4408ff1c1a1f7bfb8cb8"
"699fada4a9e59bf8086eb1c0635"},
"f041fb8de275b5319587269cb39190029906b9267eb5619b7bec8a5e0b3b3a0bead1696"
"17f2c4d45d028b1b654"},
{"4265617574792069732074727574682c20747275746820626561757479",
"436f756e742d32",
"020f2856d95b85e1def9549bf327c484d327616f1e213045f117be4c287571a"
"b983958f74766cbc6f8197c8d8d"}},
"0042c74002608a20e432ee9628e84cba76482aca29359e93d60067371be547355acca2c"
"271a2072b85a77a6237"}},
{// Exports
{"436f6e746578742d30", 32,
"22bbe971392c685b55e13544cdaf976f36b89dc1dbe1296c2884971a5aa9e331"},
{"436f6e746578742d31", 32,
"5c0fa72053a2622d8999b726446db9ef743e725e2cb040afac2d83eae0d41981"},
{"436f6e746578742d32", 32,
"72b0f9999fd37ac2b948a07dadd01132587501a5a9460d596c1f7383299a2442"},
{"436f6e746578742d33", 32,
"73d2308ed5bdd63aacd236effa0db2d3a30742b6293a924d95a372e76d90486b"},
{"436f6e746578742d34", 32,
"d4f8878dbc471935e86cdee08746e53837bbb4b6013003bebb0bc1cc3e074085"}}},
// A.2. DHKEM(X25519, HKDF-SHA256), HKDF-SHA256, ChaCha20Poly1305, PSK mode
{"", 32,
"996dc6fda1dc47e687613e0e221d64a3598e1ead9585177d22f230716569c04d"},
{"00", 32,
"6d07b4e3e06ace3dc3f1b2a0826a0f896aa828769ff993c2e3829ae40325c27d"},
{"54657374436f6e74657874", 32,
"bb69068c4f7767331512d375e4ab0ca0c6c51446040096ea0ae1cc3f9a3f54bd"}}},
// A.2. DHKEM(X25519, HKDF-SHA256), HKDF-SHA256, ChaCha20Poly1305, PSK
// mode
{3,
static_cast<HpkeModeId>(1),
static_cast<HpkeKemId>(32),
static_cast<HpkeKdfId>(1),
static_cast<HpkeAeadId>(3),
"4f6465206f6e2061204772656369616e2055726e",
"3067020100301406072a8648ce3d020106092b06010401da470f01044c304a020"
"10104204bfdb62b95ae2a1f29f20ea49e24aa2673e0d240c6e967f668f55ed5de"
"e996dca123032100f4639297e3305b03d34dd5d86522ddc6ba11a608a0003670a"
"30734823cdd3763",
"3067020100301406072a8648ce3d020106092b06010401da470f01044c304a020"
"1010420a6ab4e1bb782d580d837843089d65ebe271a0ee9b5a951777cecf1293c"
"58c150a123032100c49b46ed73ecb7d3a6a3e44f54b8f00f9ab872b57dd79ded6"
"6d7231a14c64144",
"5db3b80a81cb63ca59470c83414ef70a",
"3067020100301406072a8648ce3d020106092b06010401da470f01044c304a0201010420d"
"b1c9dfba77e1e3b8687ea18af207cffca803bdd983f955376b8271ef9c78a46a123032100"
"8e4b29035c22b67b3a7a0f5a52f12b3ab17a9ae1f0c63b029137ba09f420224a",
"3067020100301406072a8648ce3d020106092b06010401da470f01044c304a02010104204"
"e335da3ec60e68c156586b8217de6801cb83b5a4de413645fcb112c00b2228ba123032100"
"94ea1227a357dfd3548aadb9ef19d9974add594871498e123390a8bcb4db5d51",
"0247fd33b913760fa1fa51e1892d9f307fbe65eb171e8132c2af18555a738b82",
"456e6e796e20447572696e206172616e204d6f726961",
"f4639297e3305b03d34dd5d86522ddc6ba11a608a0003670a30734823cdd3763",
"396c06a52b39d0930594aa2c6944561cc1741f638557a12bef1c1cad349157c9",
"baa4ecf96b5d6d536d0d7210",
"8e4b29035c22b67b3a7a0f5a52f12b3ab17a9ae1f0c63b029137ba09f420224a",
"a603fe0f9897dc6ce042a467d6bd430a01cd679e930f1b5706ad425e4153496d",
"318e48afae42913a928146e6",
{// Encryptions
{"4265617574792069732074727574682c20747275746820626561757479",
"436f756e742d30",
"f97ca72675b8199e8ffec65b4c200d901110b177b246f241b6f9716fb60b35b"
"32a6d452675534b591e8141468a"},
"c87f8158a501c7a2f31708bbdba10f9c5ad035624c3153eeb028e65b82f41f38cbe1cd9"
"aafb10e502d328b83c1"},
{"4265617574792069732074727574682c20747275746820626561757479",
"436f756e742d31",
"57796e2b9dd0ddf807f1a7cb5884dfc50e61468c4fd69fa03963731e51674ca"
"88fee94eeac3290734e1627ded6"},
"aef7a0b0e3a58b177dac9628439b44d1e706724e265ab3b46d791612b51637342479ad9"
"45607b8b54112bd8c86"},
{"4265617574792069732074727574682c20747275746820626561757479",
"436f756e742d32",
"b514150af1057151687d0036a9b4a3ad50fb186253f839d8433622baa85719e"
"d5d2532017a0ce7b9ca0007f276"}},
"c00884a5c658213bd4381d65b54d93682692fef9408a6e437a97a904267727269b242d3"
"d81725ad8f0c764e082"}},
{// Exports
{"436f6e746578742d30", 32,
"735400cd9b9193daffe840f412074728ade6b1978e9ae27957aacd588dbd7c9e"},
{"436f6e746578742d31", 32,
"cf4e351e1943d171ff2d88726f18160086ecbec52a8151dba8cf5ba0737a6097"},
{"436f6e746578742d32", 32,
"8e23b44d4f23dd906d1c100580a670d171132c9786212c4ca2876a1541a84fae"},
{"436f6e746578742d33", 32,
"56252a940ece53d4013eb619b444ee1d019a08eec427ded2b6dbf24be624a4a0"},
{"436f6e746578742d34", 32,
"fc6cdca9ce8ab062401478ffd16ee1c07e2b15d7c781d4227f07c6043d937fad"}}}};
{"", 32,
"23c31ee2757bbecf105f74c90bf1e640b6ddc545dc8d80b1abbf2aa9dd1786ce"},
{"00", 32,
"05af7597519945fe8443f7cb84cdb651a8dd18cd7bbbd65d31095d3c69c1257e"},
{"54657374436f6e74657874", 32,
"5814619f842c7c328c9657854154e51b581c7bbd3b646bd773be67f93900a109"}}},
// DHKEM(X25519, HKDF-SHA256), HKDF-SHA512, ChaCha20Poly1305, Base mode
// Tests KEM.hash != KDF.hash.
{4,
static_cast<HpkeModeId>(0),
static_cast<HpkeKemId>(32),
static_cast<HpkeKdfId>(3),
static_cast<HpkeAeadId>(3),
"4f6465206f6e2061204772656369616e2055726e",
"3067020100301406072a8648ce3d020106092b06010401da470f01044c304a02010104200"
"6e74abcc8b65671d1ef4a6cb273662c6a3b3ff6590852bfebc7bc94887f5c4ea123032100"
"de2746f66f3e14a3389f570e8f8cc1de4e39a89d1cbb445fad711d7acf407e15",
"3067020100301406072a8648ce3d020106092b06010401da470f01044c304a02010104202"
"dc14b2f31b233963f0a2d9a836072f29666fdea84a5893d30254deb9183e0a9a123032100"
"318f92c9e96142c4ce9a06ea04f7099698ee4160044f2db585d9e2b02abd6041",
"",
"",
"de2746f66f3e14a3389f570e8f8cc1de4e39a89d1cbb445fad711d7acf407e15",
"4a54adb318d8a420506b0473815a32c2b1923a936fa7c735c8a038a38fcc80d2",
"9c6d83a59628e7327d19a3d8",
{// Encryptions
{"4265617574792069732074727574682c20747275746820626561757479",
"436f756e742d30",
"59cbc98df2d7640598377e3184e07c008dea1c264c72a8414028715960ab6d6909a3110"
"e633a23baf8b9b5e2f1"},
{"4265617574792069732074727574682c20747275746820626561757479",
"436f756e742d31",
"c9a4b68ea349eea9fdf499f7577c9325e9b76f24308a81ac5dfbbee3489dd41c85d7fb3"
"5e585859ea5c790f155"},
{"4265617574792069732074727574682c20747275746820626561757479",
"436f756e742d32",
"5d9f717b192b43bea1f6bd25ee63d7b88b06019132c31a4e262a4c1d4f01c7bd70d00df"
"0e2f858cf654ae86447"}},
{// Exports
{"", 32,
"97b0ac016b9dedb5f115cf6fd24b927f8e75b48a2ab6069efe7fec6a18ff4272"},
{"00", 32,
"c994b47854104e476d9e47bb15f9fb66f4879f68bc89a4cfccc259e80a30c913"},
{"54657374436f6e74657874", 32,
"9199e5beeda45397b1bbee3dd13ad1afbd2963f83d9e5ebdf1e23b6c7e012317"}}},
};
#endif // hpke_vectors_h__

Просмотреть файл

@ -22,36 +22,8 @@ namespace nss_test {
#ifdef NSS_ENABLE_DRAFT_HPKE
#include "cpputil.h"
class Pkcs11HpkeTest : public ::testing::TestWithParam<hpke_vector> {
class HpkeTest {
protected:
void ReadVector(const hpke_vector &vec) {
ScopedPK11SymKey vec_psk;
if (!vec.psk.empty()) {
ASSERT_FALSE(vec.psk_id.empty());
vec_psk_id = hex_string_to_bytes(vec.psk_id);
std::vector<uint8_t> psk_bytes = hex_string_to_bytes(vec.psk);
SECItem psk_item = {siBuffer, toUcharPtr(psk_bytes.data()),
static_cast<unsigned int>(psk_bytes.size())};
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
ASSERT_TRUE(slot);
PK11SymKey *psk_key =
PK11_ImportSymKey(slot.get(), CKM_HKDF_KEY_GEN, PK11_OriginUnwrap,
CKA_WRAP, &psk_item, nullptr);
ASSERT_NE(nullptr, psk_key);
vec_psk_key.reset(psk_key);
}
vec_pkcs8_r = hex_string_to_bytes(vec.pkcs8_r);
vec_pkcs8_e = hex_string_to_bytes(vec.pkcs8_e);
vec_key = hex_string_to_bytes(vec.key);
vec_nonce = hex_string_to_bytes(vec.nonce);
vec_enc = hex_string_to_bytes(vec.enc);
vec_info = hex_string_to_bytes(vec.info);
vec_encryptions = vec.encrypt_vecs;
vec_exports = vec.export_vecs;
}
void CheckEquality(const std::vector<uint8_t> &expected, SECItem *actual) {
if (!actual) {
EXPECT_TRUE(expected.empty());
@ -102,55 +74,185 @@ class Pkcs11HpkeTest : public ::testing::TestWithParam<hpke_vector> {
CheckEquality(expected_vec, actual);
}
void SetupS(const ScopedHpkeContext &cx, const ScopedSECKEYPublicKey &pkE,
const ScopedSECKEYPrivateKey &skE,
const ScopedSECKEYPublicKey &pkR,
const std::vector<uint8_t> &info) {
SECItem info_item = {siBuffer, toUcharPtr(vec_info.data()),
static_cast<unsigned int>(vec_info.size())};
SECStatus rv =
PK11_HPKE_SetupS(cx.get(), pkE.get(), skE.get(), pkR.get(), &info_item);
EXPECT_EQ(SECSuccess, rv);
}
void SetupR(const ScopedHpkeContext &cx, const ScopedSECKEYPublicKey &pkR,
const ScopedSECKEYPrivateKey &skR,
const std::vector<uint8_t> &enc,
const std::vector<uint8_t> &info) {
SECItem enc_item = {siBuffer, toUcharPtr(enc.data()),
static_cast<unsigned int>(enc.size())};
SECItem info_item = {siBuffer, toUcharPtr(vec_info.data()),
static_cast<unsigned int>(vec_info.size())};
SECStatus rv =
PK11_HPKE_SetupR(cx.get(), pkR.get(), skR.get(), &enc_item, &info_item);
EXPECT_EQ(SECSuccess, rv);
}
void Seal(const ScopedHpkeContext &cx, std::vector<uint8_t> &aad_vec,
std::vector<uint8_t> &pt_vec, SECItem **out_ct) {
std::vector<uint8_t> &pt_vec, std::vector<uint8_t> &out_sealed) {
SECItem aad_item = {siBuffer, toUcharPtr(aad_vec.data()),
static_cast<unsigned int>(aad_vec.size())};
SECItem pt_item = {siBuffer, toUcharPtr(pt_vec.data()),
static_cast<unsigned int>(pt_vec.size())};
SECStatus rv = PK11_HPKE_Seal(cx.get(), &aad_item, &pt_item, out_ct);
EXPECT_EQ(SECSuccess, rv);
SECItem *sealed_item = nullptr;
EXPECT_EQ(SECSuccess,
PK11_HPKE_Seal(cx.get(), &aad_item, &pt_item, &sealed_item));
ASSERT_NE(nullptr, sealed_item);
ScopedSECItem sealed(sealed_item);
out_sealed.assign(sealed->data, sealed->data + sealed->len);
}
void Open(const ScopedHpkeContext &cx, std::vector<uint8_t> &aad_vec,
std::vector<uint8_t> &ct_vec, SECItem **out_pt) {
std::vector<uint8_t> &ct_vec, std::vector<uint8_t> &out_opened) {
SECItem aad_item = {siBuffer, toUcharPtr(aad_vec.data()),
static_cast<unsigned int>(aad_vec.size())};
SECItem ct_item = {siBuffer, toUcharPtr(ct_vec.data()),
static_cast<unsigned int>(ct_vec.size())};
SECStatus rv = PK11_HPKE_Open(cx.get(), &aad_item, &ct_item, out_pt);
EXPECT_EQ(SECSuccess, rv);
SECItem *opened_item = nullptr;
EXPECT_EQ(SECSuccess,
PK11_HPKE_Open(cx.get(), &aad_item, &ct_item, &opened_item));
ASSERT_NE(nullptr, opened_item);
ScopedSECItem opened(opened_item);
out_opened.assign(opened->data, opened->data + opened->len);
}
void SealOpen(const ScopedHpkeContext &sender,
const ScopedHpkeContext &receiver, std::vector<uint8_t> &msg,
std::vector<uint8_t> &aad, const std::vector<uint8_t> *expect) {
std::vector<uint8_t> sealed;
std::vector<uint8_t> opened;
Seal(sender, aad, msg, sealed);
if (expect) {
EXPECT_EQ(*expect, sealed);
}
Open(receiver, aad, sealed, opened);
EXPECT_EQ(msg, opened);
}
void ExportSecret(const ScopedHpkeContext &receiver,
ScopedPK11SymKey &exported) {
std::vector<uint8_t> context = {'c', 't', 'x', 't'};
SECItem context_item = {siBuffer, context.data(),
static_cast<unsigned int>(context.size())};
PK11SymKey *tmp_exported = nullptr;
ASSERT_EQ(SECSuccess, PK11_HPKE_ExportSecret(receiver.get(), &context_item,
64, &tmp_exported));
exported.reset(tmp_exported);
}
void ExportImportRecvContext(ScopedHpkeContext &scoped_cx,
PK11SymKey *wrapping_key) {
SECItem *tmp_exported = nullptr;
EXPECT_EQ(SECSuccess, PK11_HPKE_ExportContext(scoped_cx.get(), wrapping_key,
&tmp_exported));
EXPECT_NE(nullptr, tmp_exported);
ScopedSECItem context(tmp_exported);
scoped_cx.reset();
HpkeContext *tmp_imported =
PK11_HPKE_ImportContext(context.get(), wrapping_key);
EXPECT_NE(nullptr, tmp_imported);
scoped_cx.reset(tmp_imported);
}
bool GenerateKeyPair(ScopedSECKEYPublicKey &pub_key,
ScopedSECKEYPrivateKey &priv_key) {
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
if (!slot) {
ADD_FAILURE() << "Couldn't get slot";
return false;
}
unsigned char param_buf[65];
SECItem ecdsa_params = {siBuffer, param_buf, sizeof(param_buf)};
SECOidData *oid_data = SECOID_FindOIDByTag(SEC_OID_CURVE25519);
if (!oid_data) {
ADD_FAILURE() << "Couldn't get oid_data";
return false;
}
ecdsa_params.data[0] = SEC_ASN1_OBJECT_ID;
ecdsa_params.data[1] = oid_data->oid.len;
memcpy(ecdsa_params.data + 2, oid_data->oid.data, oid_data->oid.len);
ecdsa_params.len = oid_data->oid.len + 2;
SECKEYPublicKey *pub_tmp;
SECKEYPrivateKey *priv_tmp;
priv_tmp =
PK11_GenerateKeyPair(slot.get(), CKM_EC_KEY_PAIR_GEN, &ecdsa_params,
&pub_tmp, PR_FALSE, PR_TRUE, nullptr);
if (!pub_tmp || !priv_tmp) {
ADD_FAILURE() << "PK11_GenerateKeyPair failed";
return false;
}
pub_key.reset(pub_tmp);
priv_key.reset(priv_tmp);
return true;
}
void SetUpEphemeralContexts(ScopedHpkeContext &sender,
ScopedHpkeContext &receiver,
HpkeModeId mode = HpkeModeBase,
HpkeKemId kem = HpkeDhKemX25519Sha256,
HpkeKdfId kdf = HpkeKdfHkdfSha256,
HpkeAeadId aead = HpkeAeadAes128Gcm) {
// Generate a PSK, if the mode calls for it.
PRUint8 psk_id_buf[] = {'p', 's', 'k', '-', 'i', 'd'};
SECItem psk_id = {siBuffer, psk_id_buf, sizeof(psk_id_buf)};
SECItem *psk_id_item = (mode == HpkeModePsk) ? &psk_id : nullptr;
ScopedPK11SymKey psk;
if (mode == HpkeModePsk) {
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
ASSERT_TRUE(slot);
PK11SymKey *tmp_psk =
PK11_KeyGen(slot.get(), CKM_HKDF_DERIVE, nullptr, 16, nullptr);
ASSERT_NE(nullptr, tmp_psk);
psk.reset(tmp_psk);
}
std::vector<uint8_t> info = {'t', 'e', 's', 't', '-', 'i', 'n', 'f', 'o'};
SECItem info_item = {siBuffer, info.data(),
static_cast<unsigned int>(info.size())};
sender.reset(PK11_HPKE_NewContext(kem, kdf, aead, psk.get(), psk_id_item));
receiver.reset(
PK11_HPKE_NewContext(kem, kdf, aead, psk.get(), psk_id_item));
ASSERT_TRUE(sender);
ASSERT_TRUE(receiver);
ScopedSECKEYPublicKey pub_key_r;
ScopedSECKEYPrivateKey priv_key_r;
ASSERT_TRUE(GenerateKeyPair(pub_key_r, priv_key_r));
EXPECT_EQ(SECSuccess, PK11_HPKE_SetupS(sender.get(), nullptr, nullptr,
pub_key_r.get(), &info_item));
const SECItem *enc = PK11_HPKE_GetEncapPubKey(sender.get());
EXPECT_NE(nullptr, enc);
EXPECT_EQ(SECSuccess, PK11_HPKE_SetupR(
receiver.get(), pub_key_r.get(), priv_key_r.get(),
const_cast<SECItem *>(enc), &info_item));
}
};
class TestVectors : public HpkeTest,
public ::testing::TestWithParam<hpke_vector> {
protected:
void ReadVector(const hpke_vector &vec) {
ScopedPK11SymKey vec_psk;
if (!vec.psk.empty()) {
ASSERT_FALSE(vec.psk_id.empty());
vec_psk_id = hex_string_to_bytes(vec.psk_id);
std::vector<uint8_t> psk_bytes = hex_string_to_bytes(vec.psk);
SECItem psk_item = {siBuffer, toUcharPtr(psk_bytes.data()),
static_cast<unsigned int>(psk_bytes.size())};
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
ASSERT_TRUE(slot);
PK11SymKey *psk_key =
PK11_ImportSymKey(slot.get(), CKM_HKDF_KEY_GEN, PK11_OriginUnwrap,
CKA_WRAP, &psk_item, nullptr);
ASSERT_NE(nullptr, psk_key);
vec_psk_key.reset(psk_key);
}
vec_pkcs8_r = hex_string_to_bytes(vec.pkcs8_r);
vec_pkcs8_e = hex_string_to_bytes(vec.pkcs8_e);
vec_key = hex_string_to_bytes(vec.key);
vec_nonce = hex_string_to_bytes(vec.nonce);
vec_enc = hex_string_to_bytes(vec.enc);
vec_info = hex_string_to_bytes(vec.info);
vec_encryptions = vec.encrypt_vecs;
vec_exports = vec.export_vecs;
}
void TestExports(const ScopedHpkeContext &sender,
const ScopedHpkeContext &receiver) {
SECStatus rv;
for (auto &vec : vec_exports) {
std::vector<uint8_t> context = hex_string_to_bytes(vec.ctxt);
std::vector<uint8_t> expected = hex_string_to_bytes(vec.exported);
@ -158,12 +260,11 @@ class Pkcs11HpkeTest : public ::testing::TestWithParam<hpke_vector> {
static_cast<unsigned int>(context.size())};
PK11SymKey *actual_r = nullptr;
PK11SymKey *actual_s = nullptr;
rv = PK11_HPKE_ExportSecret(sender.get(), &context_item, vec.len,
&actual_s);
ASSERT_EQ(SECSuccess, rv);
rv = PK11_HPKE_ExportSecret(receiver.get(), &context_item, vec.len,
&actual_r);
ASSERT_EQ(SECSuccess, rv);
ASSERT_EQ(SECSuccess, PK11_HPKE_ExportSecret(sender.get(), &context_item,
vec.len, &actual_s));
ASSERT_EQ(SECSuccess,
PK11_HPKE_ExportSecret(receiver.get(), &context_item, vec.len,
&actual_r));
ScopedPK11SymKey scoped_act_s(actual_s);
ScopedPK11SymKey scoped_act_r(actual_r);
CheckEquality(expected, scoped_act_s.get());
@ -177,15 +278,7 @@ class Pkcs11HpkeTest : public ::testing::TestWithParam<hpke_vector> {
std::vector<uint8_t> msg = hex_string_to_bytes(enc_vec.pt);
std::vector<uint8_t> aad = hex_string_to_bytes(enc_vec.aad);
std::vector<uint8_t> expect_ct = hex_string_to_bytes(enc_vec.ct);
SECItem *act_ct = nullptr;
Seal(sender, aad, msg, &act_ct);
CheckEquality(expect_ct, act_ct);
ScopedSECItem scoped_ct(act_ct);
SECItem *act_pt = nullptr;
Open(receiver, aad, expect_ct, &act_pt);
CheckEquality(msg, act_pt);
ScopedSECItem scoped_pt(act_pt);
SealOpen(sender, receiver, msg, aad, &expect_ct);
}
}
@ -200,10 +293,9 @@ class Pkcs11HpkeTest : public ::testing::TestWithParam<hpke_vector> {
SECItem pkcs8_e_item = {siBuffer, toUcharPtr(vec_pkcs8_e.data()),
static_cast<unsigned int>(vec_pkcs8_e.size())};
SECKEYPrivateKey *sk_e = nullptr;
SECStatus rv = PK11_ImportDERPrivateKeyInfoAndReturnKey(
slot.get(), &pkcs8_e_item, nullptr, nullptr, false, false, KU_ALL,
&sk_e, nullptr);
EXPECT_EQ(SECSuccess, rv);
EXPECT_EQ(SECSuccess, PK11_ImportDERPrivateKeyInfoAndReturnKey(
slot.get(), &pkcs8_e_item, nullptr, nullptr,
false, false, KU_ALL, &sk_e, nullptr));
skE_derived.reset(sk_e);
SECKEYPublicKey *pk_e = SECKEY_ConvertToPublicKey(skE_derived.get());
ASSERT_NE(nullptr, pk_e);
@ -212,64 +304,49 @@ class Pkcs11HpkeTest : public ::testing::TestWithParam<hpke_vector> {
SECItem pkcs8_r_item = {siBuffer, toUcharPtr(vec_pkcs8_r.data()),
static_cast<unsigned int>(vec_pkcs8_r.size())};
SECKEYPrivateKey *sk_r = nullptr;
rv = PK11_ImportDERPrivateKeyInfoAndReturnKey(
slot.get(), &pkcs8_r_item, nullptr, nullptr, false, false, KU_ALL,
&sk_r, nullptr);
EXPECT_EQ(SECSuccess, rv);
EXPECT_EQ(SECSuccess, PK11_ImportDERPrivateKeyInfoAndReturnKey(
slot.get(), &pkcs8_r_item, nullptr, nullptr,
false, false, KU_ALL, &sk_r, nullptr));
skR_derived.reset(sk_r);
SECKEYPublicKey *pk_r = SECKEY_ConvertToPublicKey(skR_derived.get());
ASSERT_NE(nullptr, pk_r);
pkR_derived.reset(pk_r);
}
void SetupS(const ScopedHpkeContext &cx, const ScopedSECKEYPublicKey &pkE,
const ScopedSECKEYPrivateKey &skE,
const ScopedSECKEYPublicKey &pkR,
const std::vector<uint8_t> &info) {
SECItem info_item = {siBuffer, toUcharPtr(vec_info.data()),
static_cast<unsigned int>(vec_info.size())};
EXPECT_EQ(SECSuccess, PK11_HPKE_SetupS(cx.get(), pkE.get(), skE.get(),
pkR.get(), &info_item));
}
void SetupR(const ScopedHpkeContext &cx, const ScopedSECKEYPublicKey &pkR,
const ScopedSECKEYPrivateKey &skR,
const std::vector<uint8_t> &enc,
const std::vector<uint8_t> &info) {
SECItem enc_item = {siBuffer, toUcharPtr(enc.data()),
static_cast<unsigned int>(enc.size())};
SECItem info_item = {siBuffer, toUcharPtr(vec_info.data()),
static_cast<unsigned int>(vec_info.size())};
EXPECT_EQ(SECSuccess, PK11_HPKE_SetupR(cx.get(), pkR.get(), skR.get(),
&enc_item, &info_item));
}
void SetupSenderReceiver(const ScopedHpkeContext &sender,
const ScopedHpkeContext &receiver) {
SetupS(sender, pkE_derived, skE_derived, pkR_derived, vec_info);
uint8_t buf[32]; // Curve25519 only, fixed size.
SECItem encap_item = {siBuffer, const_cast<uint8_t *>(buf), sizeof(buf)};
SECStatus rv = PK11_HPKE_Serialize(pkE_derived.get(), encap_item.data,
&encap_item.len, encap_item.len);
ASSERT_EQ(SECSuccess, rv);
ASSERT_EQ(SECSuccess,
PK11_HPKE_Serialize(pkE_derived.get(), encap_item.data,
&encap_item.len, encap_item.len));
CheckEquality(vec_enc, &encap_item);
SetupR(receiver, pkR_derived, skR_derived, vec_enc, vec_info);
}
bool GenerateKeyPair(ScopedSECKEYPublicKey &pub_key,
ScopedSECKEYPrivateKey &priv_key) {
unsigned char param_buf[65];
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
if (!slot) {
ADD_FAILURE() << "Couldn't get slot";
return false;
}
SECItem ecdsa_params = {siBuffer, param_buf, sizeof(param_buf)};
SECOidData *oid_data = SECOID_FindOIDByTag(SEC_OID_CURVE25519);
if (!oid_data) {
ADD_FAILURE() << "Couldn't get oid_data";
return false;
}
ecdsa_params.data[0] = SEC_ASN1_OBJECT_ID;
ecdsa_params.data[1] = oid_data->oid.len;
memcpy(ecdsa_params.data + 2, oid_data->oid.data, oid_data->oid.len);
ecdsa_params.len = oid_data->oid.len + 2;
SECKEYPublicKey *pub_tmp;
SECKEYPrivateKey *priv_tmp;
priv_tmp =
PK11_GenerateKeyPair(slot.get(), CKM_EC_KEY_PAIR_GEN, &ecdsa_params,
&pub_tmp, PR_FALSE, PR_TRUE, nullptr);
if (!pub_tmp || !priv_tmp) {
ADD_FAILURE() << "PK11_GenerateKeyPair failed";
return false;
}
pub_key.reset(pub_tmp);
priv_key.reset(priv_tmp);
return true;
}
void RunTestVector(const hpke_vector &vec) {
ReadVector(vec);
SECItem psk_id_item = {siBuffer, toUcharPtr(vec_psk_id.data()),
@ -307,12 +384,31 @@ class Pkcs11HpkeTest : public ::testing::TestWithParam<hpke_vector> {
ScopedSECKEYPrivateKey skR_derived;
};
TEST_P(Pkcs11HpkeTest, TestVectors) { RunTestVector(GetParam()); }
TEST_P(TestVectors, TestVectors) { RunTestVector(GetParam()); }
INSTANTIATE_TEST_SUITE_P(Pkcs11HpkeTests, Pkcs11HpkeTest,
INSTANTIATE_TEST_SUITE_P(Pk11Hpke, TestVectors,
::testing::ValuesIn(kHpkeTestVectors));
TEST_F(Pkcs11HpkeTest, BadEncapsulatedPubKey) {
class ModeParameterizedTest
: public HpkeTest,
public ::testing::TestWithParam<
std::tuple<HpkeModeId, HpkeKemId, HpkeKdfId, HpkeAeadId>> {};
static const HpkeModeId kHpkeModesAll[] = {HpkeModeBase, HpkeModePsk};
static const HpkeKemId kHpkeKemIdsAll[] = {HpkeDhKemX25519Sha256};
static const HpkeKdfId kHpkeKdfIdsAll[] = {HpkeKdfHkdfSha256, HpkeKdfHkdfSha384,
HpkeKdfHkdfSha512};
static const HpkeAeadId kHpkeAeadIdsAll[] = {HpkeAeadAes128Gcm,
HpkeAeadChaCha20Poly1305};
INSTANTIATE_TEST_SUITE_P(
Pk11Hpke, ModeParameterizedTest,
::testing::Combine(::testing::ValuesIn(kHpkeModesAll),
::testing::ValuesIn(kHpkeKemIdsAll),
::testing::ValuesIn(kHpkeKdfIdsAll),
::testing::ValuesIn(kHpkeAeadIdsAll)));
TEST_F(ModeParameterizedTest, BadEncapsulatedPubKey) {
ScopedHpkeContext sender(
PK11_HPKE_NewContext(HpkeDhKemX25519Sha256, HpkeKdfHkdfSha256,
HpkeAeadAes128Gcm, nullptr, nullptr));
@ -331,157 +427,211 @@ TEST_F(Pkcs11HpkeTest, BadEncapsulatedPubKey) {
ASSERT_TRUE(GenerateKeyPair(pub_key, priv_key));
// Decapsulating an empty buffer should fail.
SECStatus rv =
PK11_HPKE_Deserialize(sender.get(), empty.data, empty.len, &tmp_pub_key);
EXPECT_EQ(SECFailure, rv);
EXPECT_EQ(SECFailure, PK11_HPKE_Deserialize(sender.get(), empty.data,
empty.len, &tmp_pub_key));
EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError());
// Decapsulating anything else will succeed, but the setup will fail.
rv = PK11_HPKE_Deserialize(sender.get(), short_encap.data, short_encap.len,
&tmp_pub_key);
// Decapsulating anything short will succeed, but the setup will fail.
EXPECT_EQ(SECSuccess, PK11_HPKE_Deserialize(sender.get(), short_encap.data,
short_encap.len, &tmp_pub_key));
ScopedSECKEYPublicKey bad_pub_key(tmp_pub_key);
EXPECT_EQ(SECSuccess, rv);
rv = PK11_HPKE_SetupS(receiver.get(), pub_key.get(), priv_key.get(),
bad_pub_key.get(), &empty);
EXPECT_EQ(SECFailure, rv);
EXPECT_EQ(SECFailure,
PK11_HPKE_SetupS(receiver.get(), pub_key.get(), priv_key.get(),
bad_pub_key.get(), &empty));
EXPECT_EQ(SEC_ERROR_INVALID_KEY, PORT_GetError());
// Test the same for a receiver.
rv = PK11_HPKE_SetupR(sender.get(), pub_key.get(), priv_key.get(), &empty,
&empty);
EXPECT_EQ(SECFailure, rv);
EXPECT_EQ(SECFailure, PK11_HPKE_SetupR(sender.get(), pub_key.get(),
priv_key.get(), &empty, &empty));
EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError());
rv = PK11_HPKE_SetupR(sender.get(), pub_key.get(), priv_key.get(),
&short_encap, &empty);
EXPECT_EQ(SECFailure, rv);
EXPECT_EQ(SECFailure, PK11_HPKE_SetupR(sender.get(), pub_key.get(),
priv_key.get(), &short_encap, &empty));
EXPECT_EQ(SEC_ERROR_INVALID_KEY, PORT_GetError());
// Encapsulated key too long
rv = PK11_HPKE_Deserialize(sender.get(), long_encap.data, long_encap.len,
&tmp_pub_key);
EXPECT_EQ(SECSuccess, PK11_HPKE_Deserialize(sender.get(), long_encap.data,
long_encap.len, &tmp_pub_key));
bad_pub_key.reset(tmp_pub_key);
EXPECT_EQ(SECSuccess, rv);
rv = PK11_HPKE_SetupS(receiver.get(), pub_key.get(), priv_key.get(),
bad_pub_key.get(), &empty);
EXPECT_EQ(SECFailure, rv);
EXPECT_EQ(SECFailure,
PK11_HPKE_SetupS(receiver.get(), pub_key.get(), priv_key.get(),
bad_pub_key.get(), &empty));
EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError());
rv = PK11_HPKE_SetupR(sender.get(), pub_key.get(), priv_key.get(),
&long_encap, &empty);
EXPECT_EQ(SECFailure, rv);
EXPECT_EQ(SECFailure, PK11_HPKE_SetupR(sender.get(), pub_key.get(),
priv_key.get(), &long_encap, &empty));
EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError());
}
// Vectors used fixed keypairs on each end. Make sure the
// ephemeral (particularly sender) path works.
TEST_F(Pkcs11HpkeTest, EphemeralKeys) {
unsigned char info[] = {"info"};
unsigned char msg[] = {"secret"};
unsigned char aad[] = {"aad"};
SECItem info_item = {siBuffer, info, sizeof(info)};
SECItem msg_item = {siBuffer, msg, sizeof(msg)};
SECItem aad_item = {siBuffer, aad, sizeof(aad)};
TEST_P(ModeParameterizedTest, ContextExportImportEncrypt) {
std::vector<uint8_t> msg = {'s', 'e', 'c', 'r', 'e', 't'};
std::vector<uint8_t> aad = {'a', 'a', 'd'};
ScopedHpkeContext sender(
PK11_HPKE_NewContext(HpkeDhKemX25519Sha256, HpkeKdfHkdfSha256,
HpkeAeadAes128Gcm, nullptr, nullptr));
ScopedHpkeContext receiver(
PK11_HPKE_NewContext(HpkeDhKemX25519Sha256, HpkeKdfHkdfSha256,
HpkeAeadAes128Gcm, nullptr, nullptr));
ASSERT_TRUE(sender);
ASSERT_TRUE(receiver);
ScopedHpkeContext sender;
ScopedHpkeContext receiver;
SetUpEphemeralContexts(sender, receiver, std::get<0>(GetParam()),
std::get<1>(GetParam()), std::get<2>(GetParam()),
std::get<3>(GetParam()));
SealOpen(sender, receiver, msg, aad, nullptr);
ExportImportRecvContext(receiver, nullptr);
SealOpen(sender, receiver, msg, aad, nullptr);
}
ScopedSECKEYPublicKey pub_key_r;
ScopedSECKEYPrivateKey priv_key_r;
ASSERT_TRUE(GenerateKeyPair(pub_key_r, priv_key_r));
TEST_P(ModeParameterizedTest, ContextExportImportExport) {
ScopedHpkeContext sender;
ScopedHpkeContext receiver;
ScopedPK11SymKey sender_export;
ScopedPK11SymKey receiver_export;
ScopedPK11SymKey receiver_reexport;
SetUpEphemeralContexts(sender, receiver, std::get<0>(GetParam()),
std::get<1>(GetParam()), std::get<2>(GetParam()),
std::get<3>(GetParam()));
ExportSecret(sender, sender_export);
ExportSecret(receiver, receiver_export);
CheckEquality(sender_export.get(), receiver_export.get());
ExportImportRecvContext(receiver, nullptr);
ExportSecret(receiver, receiver_reexport);
CheckEquality(receiver_export.get(), receiver_reexport.get());
}
SECStatus rv = PK11_HPKE_SetupS(sender.get(), nullptr, nullptr,
pub_key_r.get(), &info_item);
EXPECT_EQ(SECSuccess, rv);
TEST_P(ModeParameterizedTest, ContextExportImportWithWrap) {
std::vector<uint8_t> msg = {'s', 'e', 'c', 'r', 'e', 't'};
std::vector<uint8_t> aad = {'a', 'a', 'd'};
const SECItem *enc = PK11_HPKE_GetEncapPubKey(sender.get());
EXPECT_NE(nullptr, enc);
rv = PK11_HPKE_SetupR(receiver.get(), pub_key_r.get(), priv_key_r.get(),
const_cast<SECItem *>(enc), &info_item);
EXPECT_EQ(SECSuccess, rv);
// Generate a wrapping key, then use it for export.
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
ASSERT_TRUE(slot);
ScopedPK11SymKey kek(
PK11_KeyGen(slot.get(), CKM_AES_CBC, nullptr, 16, nullptr));
ASSERT_NE(nullptr, kek);
SECItem *tmp_sealed = nullptr;
rv = PK11_HPKE_Seal(sender.get(), &aad_item, &msg_item, &tmp_sealed);
EXPECT_EQ(SECSuccess, rv);
ScopedSECItem sealed(tmp_sealed);
ScopedHpkeContext sender;
ScopedHpkeContext receiver;
SetUpEphemeralContexts(sender, receiver, std::get<0>(GetParam()),
std::get<1>(GetParam()), std::get<2>(GetParam()),
std::get<3>(GetParam()));
SealOpen(sender, receiver, msg, aad, nullptr);
ExportImportRecvContext(receiver, kek.get());
SealOpen(sender, receiver, msg, aad, nullptr);
}
SECItem *tmp_unsealed = nullptr;
rv = PK11_HPKE_Open(receiver.get(), &aad_item, sealed.get(), &tmp_unsealed);
EXPECT_EQ(SECSuccess, rv);
CheckEquality(&msg_item, tmp_unsealed);
ScopedSECItem unsealed(tmp_unsealed);
TEST_P(ModeParameterizedTest, ExportSenderContext) {
std::vector<uint8_t> msg = {'s', 'e', 'c', 'r', 'e', 't'};
std::vector<uint8_t> aad = {'a', 'a', 'd'};
// Once more
tmp_sealed = nullptr;
rv = PK11_HPKE_Seal(sender.get(), &aad_item, &msg_item, &tmp_sealed);
EXPECT_EQ(SECSuccess, rv);
ASSERT_NE(nullptr, sealed);
sealed.reset(tmp_sealed);
tmp_unsealed = nullptr;
rv = PK11_HPKE_Open(receiver.get(), &aad_item, sealed.get(), &tmp_unsealed);
EXPECT_EQ(SECSuccess, rv);
CheckEquality(&msg_item, tmp_unsealed);
unsealed.reset(tmp_unsealed);
ScopedHpkeContext sender;
ScopedHpkeContext receiver;
SetUpEphemeralContexts(sender, receiver, std::get<0>(GetParam()),
std::get<1>(GetParam()), std::get<2>(GetParam()),
std::get<3>(GetParam()));
SECItem *tmp_exported = nullptr;
EXPECT_EQ(SECFailure,
PK11_HPKE_ExportContext(sender.get(), nullptr, &tmp_exported));
EXPECT_EQ(nullptr, tmp_exported);
EXPECT_EQ(SEC_ERROR_NOT_A_RECIPIENT, PORT_GetError());
}
TEST_P(ModeParameterizedTest, ContextUnwrapBadKey) {
std::vector<uint8_t> msg = {'s', 'e', 'c', 'r', 'e', 't'};
std::vector<uint8_t> aad = {'a', 'a', 'd'};
// Generate a wrapping key, then use it for export.
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
ASSERT_TRUE(slot);
ScopedPK11SymKey kek(
PK11_KeyGen(slot.get(), CKM_AES_CBC, nullptr, 16, nullptr));
ASSERT_NE(nullptr, kek);
ScopedPK11SymKey not_kek(
PK11_KeyGen(slot.get(), CKM_AES_CBC, nullptr, 16, nullptr));
ASSERT_NE(nullptr, not_kek);
ScopedHpkeContext sender;
ScopedHpkeContext receiver;
SetUpEphemeralContexts(sender, receiver, std::get<0>(GetParam()),
std::get<1>(GetParam()), std::get<2>(GetParam()),
std::get<3>(GetParam()));
SECItem *tmp_exported = nullptr;
EXPECT_EQ(SECSuccess,
PK11_HPKE_ExportContext(receiver.get(), kek.get(), &tmp_exported));
EXPECT_NE(nullptr, tmp_exported);
ScopedSECItem context(tmp_exported);
EXPECT_EQ(nullptr, PK11_HPKE_ImportContext(context.get(), not_kek.get()));
EXPECT_EQ(SEC_ERROR_BAD_DATA, PORT_GetError());
}
TEST_P(ModeParameterizedTest, EphemeralKeys) {
std::vector<uint8_t> msg = {'s', 'e', 'c', 'r', 'e', 't'};
std::vector<uint8_t> aad = {'a', 'a', 'd'};
SECItem msg_item = {siBuffer, msg.data(),
static_cast<unsigned int>(msg.size())};
SECItem aad_item = {siBuffer, aad.data(),
static_cast<unsigned int>(aad.size())};
ScopedHpkeContext sender;
ScopedHpkeContext receiver;
SetUpEphemeralContexts(sender, receiver, std::get<0>(GetParam()),
std::get<1>(GetParam()), std::get<2>(GetParam()),
std::get<3>(GetParam()));
SealOpen(sender, receiver, msg, aad, nullptr);
// Seal for negative tests
tmp_sealed = nullptr;
tmp_unsealed = nullptr;
rv = PK11_HPKE_Seal(sender.get(), &aad_item, &msg_item, &tmp_sealed);
EXPECT_EQ(SECSuccess, rv);
ASSERT_NE(nullptr, sealed);
sealed.reset(tmp_sealed);
SECItem *tmp_sealed = nullptr;
SECItem *tmp_unsealed = nullptr;
EXPECT_EQ(SECSuccess,
PK11_HPKE_Seal(sender.get(), &aad_item, &msg_item, &tmp_sealed));
ASSERT_NE(nullptr, tmp_sealed);
ScopedSECItem sealed(tmp_sealed);
// Drop AAD
rv = PK11_HPKE_Open(receiver.get(), nullptr, sealed.get(), &tmp_unsealed);
EXPECT_EQ(SECFailure, rv);
EXPECT_EQ(SECFailure, PK11_HPKE_Open(receiver.get(), nullptr, sealed.get(),
&tmp_unsealed));
EXPECT_EQ(SEC_ERROR_BAD_DATA, PORT_GetError());
EXPECT_EQ(nullptr, tmp_unsealed);
// Modify AAD
aad_item.data[0] ^= 0xff;
rv = PK11_HPKE_Open(receiver.get(), &aad_item, sealed.get(), &tmp_unsealed);
EXPECT_EQ(SECFailure, rv);
EXPECT_EQ(SECFailure, PK11_HPKE_Open(receiver.get(), &aad_item, sealed.get(),
&tmp_unsealed));
EXPECT_EQ(SEC_ERROR_BAD_DATA, PORT_GetError());
EXPECT_EQ(nullptr, tmp_unsealed);
aad_item.data[0] ^= 0xff;
// Modify ciphertext
sealed->data[0] ^= 0xff;
rv = PK11_HPKE_Open(receiver.get(), &aad_item, sealed.get(), &tmp_unsealed);
EXPECT_EQ(SECFailure, rv);
EXPECT_EQ(SECFailure, PK11_HPKE_Open(receiver.get(), &aad_item, sealed.get(),
&tmp_unsealed));
EXPECT_EQ(SEC_ERROR_BAD_DATA, PORT_GetError());
EXPECT_EQ(nullptr, tmp_unsealed);
sealed->data[0] ^= 0xff;
rv = PK11_HPKE_Open(receiver.get(), &aad_item, sealed.get(), &tmp_unsealed);
EXPECT_EQ(SECSuccess, rv);
EXPECT_EQ(SECSuccess, PK11_HPKE_Open(receiver.get(), &aad_item, sealed.get(),
&tmp_unsealed));
EXPECT_NE(nullptr, tmp_unsealed);
unsealed.reset(tmp_unsealed);
ScopedSECItem unsealed(tmp_unsealed);
CheckEquality(&msg_item, unsealed.get());
}
TEST_F(Pkcs11HpkeTest, InvalidContextParams) {
TEST_F(ModeParameterizedTest, InvalidContextParams) {
HpkeContext *cx =
PK11_HPKE_NewContext(static_cast<HpkeKemId>(1), HpkeKdfHkdfSha256,
PK11_HPKE_NewContext(static_cast<HpkeKemId>(0xff), HpkeKdfHkdfSha256,
HpkeAeadChaCha20Poly1305, nullptr, nullptr);
EXPECT_EQ(nullptr, cx);
EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError());
cx = PK11_HPKE_NewContext(HpkeDhKemX25519Sha256, static_cast<HpkeKdfId>(2),
cx = PK11_HPKE_NewContext(HpkeDhKemX25519Sha256, static_cast<HpkeKdfId>(0xff),
HpkeAeadChaCha20Poly1305, nullptr, nullptr);
EXPECT_EQ(nullptr, cx);
EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError());
cx = PK11_HPKE_NewContext(HpkeDhKemX25519Sha256, HpkeKdfHkdfSha256,
static_cast<HpkeAeadId>(4), nullptr, nullptr);
static_cast<HpkeAeadId>(0xff), nullptr, nullptr);
EXPECT_EQ(nullptr, cx);
EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError());
}
TEST_F(Pkcs11HpkeTest, InvalidReceiverKeyType) {
TEST_F(ModeParameterizedTest, InvalidReceiverKeyType) {
ScopedHpkeContext sender(
PK11_HPKE_NewContext(HpkeDhKemX25519Sha256, HpkeKdfHkdfSha256,
HpkeAeadChaCha20Poly1305, nullptr, nullptr));
@ -507,9 +657,8 @@ TEST_F(Pkcs11HpkeTest, InvalidReceiverKeyType) {
pub_key.reset(pub_tmp);
SECItem info_item = {siBuffer, nullptr, 0};
SECStatus rv = PK11_HPKE_SetupS(sender.get(), nullptr, nullptr, pub_key.get(),
&info_item);
EXPECT_EQ(SECFailure, rv);
EXPECT_EQ(SECFailure, PK11_HPKE_SetupS(sender.get(), nullptr, nullptr,
pub_key.get(), &info_item));
EXPECT_EQ(SEC_ERROR_BAD_KEY, PORT_GetError());
// Try with an unexpected curve
@ -529,13 +678,12 @@ TEST_F(Pkcs11HpkeTest, InvalidReceiverKeyType) {
ASSERT_NE(nullptr, priv_key);
ASSERT_NE(nullptr, pub_tmp);
pub_key.reset(pub_tmp);
rv = PK11_HPKE_SetupS(sender.get(), nullptr, nullptr, pub_key.get(),
&info_item);
EXPECT_EQ(SECFailure, rv);
EXPECT_EQ(SECFailure, PK11_HPKE_SetupS(sender.get(), nullptr, nullptr,
pub_key.get(), &info_item));
EXPECT_EQ(SEC_ERROR_BAD_KEY, PORT_GetError());
}
#else
TEST(Pkcs11HpkeTest, EnsureNotImplemented) {
TEST(HpkeTest, EnsureNotImplemented) {
ScopedHpkeContext cx(
PK11_HPKE_NewContext(HpkeDhKemX25519Sha256, HpkeKdfHkdfSha256,
HpkeAeadChaCha20Poly1305, nullptr, nullptr));

Просмотреть файл

@ -494,6 +494,27 @@ SECStatus SSLInt_SetRawEchConfigForRetry(PRFileDesc *fd, const uint8_t *buf,
sslEchConfig *cfg = (sslEchConfig *)PR_LIST_HEAD(&ss->echConfigs);
SECITEM_FreeItem(&cfg->raw, PR_FALSE);
SECITEM_AllocItem(NULL, &cfg->raw, len);
memcpy(cfg->raw.data, buf, len);
PORT_Memcpy(cfg->raw.data, buf, len);
return SECSuccess;
}
// Zero the echConfig.config_id for all configured echConfigs.
// This mimics a collision on the 8B config ID so that we can
// test trial decryption.
SECStatus SSLInt_ZeroEchConfigIds(PRFileDesc *fd) {
if (!fd) {
return SECFailure;
}
sslSocket *ss = ssl_FindSocket(fd);
if (!ss) {
return SECFailure;
}
for (PRCList *cur_p = PR_LIST_HEAD(&ss->echConfigs); cur_p != &ss->echConfigs;
cur_p = PR_NEXT_LINK(cur_p)) {
PORT_Memset(((sslEchConfig *)cur_p)->configId, 0,
sizeof(((sslEchConfig *)cur_p)->configId));
}
return SECSuccess;
}

Просмотреть файл

@ -51,5 +51,5 @@ SECStatus SSLInt_SetDCAdvertisedSigSchemes(PRFileDesc *fd,
SECStatus SSLInt_RemoveServerCertificates(PRFileDesc *fd);
SECStatus SSLInt_SetRawEchConfigForRetry(PRFileDesc *fd, const uint8_t *buf,
size_t len);
#endif // ndef libssl_internals_h_
SECStatus SSLInt_ZeroEchConfigIds(PRFileDesc *fd);
#endif // ifndef libssl_internals_h_

Просмотреть файл

@ -1098,22 +1098,6 @@ TEST_P(TlsExtensionTest13, HrrThenRemoveSupportedGroups) {
SSL_ERROR_MISSING_SUPPORTED_GROUPS_EXTENSION);
}
#ifdef NSS_ENABLE_DRAFT_HPKE
TEST_P(TlsExtensionTest13, HrrThenRemoveEch) {
if (variant_ == ssl_variant_datagram) {
// ECH not supported in DTLS.
GTEST_SKIP();
}
EnsureTlsSetup();
SetupEch(client_, server_);
ExpectAlert(server_, kTlsAlertIllegalParameter);
HrrThenRemoveExtensionsTest(ssl_tls13_encrypted_client_hello_xtn,
SSL_ERROR_ILLEGAL_PARAMETER_ALERT,
SSL_ERROR_BAD_2ND_CLIENT_HELLO);
}
#endif
TEST_P(TlsExtensionTest13, EmptyVersionList) {
static const uint8_t ext[] = {0x00, 0x00};
ConnectWithBogusVersionList(ext, sizeof(ext));

Просмотреть файл

@ -19,9 +19,9 @@ namespace nss_test {
class TlsAgentEchTest : public TlsAgentTestClient13 {
protected:
void InstallEchConfig(const DataBuffer& record, PRErrorCode err = 0) {
SECStatus rv =
SSL_SetClientEchConfigs(agent_->ssl_fd(), record.data(), record.len());
void InstallEchConfig(const DataBuffer& echconfig, PRErrorCode err = 0) {
SECStatus rv = SSL_SetClientEchConfigs(agent_->ssl_fd(), echconfig.data(),
echconfig.len());
if (err == 0) {
ASSERT_EQ(SECSuccess, rv);
} else {
@ -143,18 +143,6 @@ class TlsConnectStreamTls13Ech : public TlsConnectTestBase {
Connect();
}
private:
// Testing certan invalid CHInner configurations is tricky, particularly
// since the CHOuter forms AAD and isn't available in filters. Instead of
// generating these inputs on the fly, use a fixed server keypair so that
// the input can be generated once (e.g. via a debugger) and replayed in
// each invocation of the test.
std::string kFixedServerPubkey =
"3067020100301406072a8648ce3d020106092b06010401da470f01044c304a"
"02010104205a8aa0d2476b28521588e0c704b14db82cdd4970d340d293a957"
"6deaee9ec1c7a1230321008756e2580c07c1d2ffcb662f5fadc6d6ff13da85"
"abd7adfecf984aaa102c1269";
void ImportFixedEchKeypair(ScopedSECKEYPublicKey& pub,
ScopedSECKEYPrivateKey& priv) {
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
@ -176,16 +164,30 @@ class TlsConnectStreamTls13Ech : public TlsConnectTestBase {
ASSERT_NE(nullptr, tmp_pub);
}
private:
// Testing certan invalid CHInner configurations is tricky, particularly
// since the CHOuter forms AAD and isn't available in filters. Instead of
// generating these inputs on the fly, use a fixed server keypair so that
// the input can be generated once (e.g. via a debugger) and replayed in
// each invocation of the test.
std::string kFixedServerPubkey =
"3067020100301406072a8648ce3d020106092b06010401da470f01044c304a"
"02010104205a8aa0d2476b28521588e0c704b14db82cdd4970d340d293a957"
"6deaee9ec1c7a1230321008756e2580c07c1d2ffcb662f5fadc6d6ff13da85"
"abd7adfecf984aaa102c1269";
void SetMutualEchConfigs(ScopedSECKEYPublicKey& pub,
ScopedSECKEYPrivateKey& priv) {
DataBuffer record;
DataBuffer echconfig;
TlsConnectTestBase::GenerateEchConfig(HpkeDhKemX25519Sha256, kDefaultSuites,
kPublicName, 100, record, pub, priv);
kPublicName, 100, echconfig, pub,
priv);
ASSERT_EQ(SECSuccess,
SSL_SetServerEchConfigs(server_->ssl_fd(), pub.get(), priv.get(),
record.data(), record.len()));
ASSERT_EQ(SECSuccess, SSL_SetClientEchConfigs(client_->ssl_fd(),
record.data(), record.len()));
echconfig.data(), echconfig.len()));
ASSERT_EQ(SECSuccess,
SSL_SetClientEchConfigs(client_->ssl_fd(), echconfig.data(),
echconfig.len()));
}
};
@ -224,17 +226,17 @@ TEST_P(TlsAgentEchTest, EchConfigsSupportedYesNo) {
// ECHConfig 2 cipher_suites are unsupported.
const std::string mixed =
"0086FE08003F000B7075626C69632E6E616D6500203BB6D46C201B820F1AE4AFD4DEC304"
"444156E4E04D1BF0FFDA7783B6B457F75600200008000100030001000100640000FE0800"
"0086FE09003F000B7075626C69632E6E616D6500203BB6D46C201B820F1AE4AFD4DEC304"
"444156E4E04D1BF0FFDA7783B6B457F75600200008000100030001000100640000FE0900"
"3F000B7075626C69632E6E616D6500203BB6D46C201B820F1AE4AFD4DEC304444156E4E0"
"4D1BF0FFDA7783B6B457F756002000080001FFFFFFFF000100640000";
std::vector<uint8_t> config = hex_string_to_bytes(mixed);
DataBuffer record(config.data(), config.size());
DataBuffer echconfig(config.data(), config.size());
EnsureInit();
EXPECT_EQ(SECSuccess, SSL_EnableTls13GreaseEch(agent_->ssl_fd(),
PR_FALSE)); // Don't GREASE
InstallEchConfig(record, 0);
InstallEchConfig(echconfig, 0);
auto filter = MakeTlsFilter<TlsExtensionCapture>(
agent_, ssl_tls13_encrypted_client_hello_xtn);
agent_->Handshake();
@ -249,17 +251,17 @@ TEST_P(TlsAgentEchTest, EchConfigsSupportedNoYes) {
// ECHConfig 1 cipher_suites are unsupported.
const std::string mixed =
"0086FE08003F000B7075626C69632E6E616D6500203BB6D46C201B820F1AE4AFD4DEC304"
"444156E4E04D1BF0FFDA7783B6B457F756002000080001FFFFFFFF000100640000FE0800"
"0086FE09003F000B7075626C69632E6E616D6500203BB6D46C201B820F1AE4AFD4DEC304"
"444156E4E04D1BF0FFDA7783B6B457F756002000080001FFFFFFFF000100640000FE0900"
"3F000B7075626C69632E6E616D6500203BB6D46C201B820F1AE4AFD4DEC304444156E4E0"
"4D1BF0FFDA7783B6B457F75600200008000100030001000100640000";
std::vector<uint8_t> config = hex_string_to_bytes(mixed);
DataBuffer record(config.data(), config.size());
DataBuffer echconfig(config.data(), config.size());
EnsureInit();
EXPECT_EQ(SECSuccess, SSL_EnableTls13GreaseEch(agent_->ssl_fd(),
PR_FALSE)); // Don't GREASE
InstallEchConfig(record, 0);
InstallEchConfig(echconfig, 0);
auto filter = MakeTlsFilter<TlsExtensionCapture>(
agent_, ssl_tls13_encrypted_client_hello_xtn);
agent_->Handshake();
@ -274,17 +276,17 @@ TEST_P(TlsAgentEchTest, EchConfigsSupportedNoNo) {
// ECHConfig 1 and 2 cipher_suites are unsupported.
const std::string unsupported =
"0086FE08003F000B7075626C69632E6E616D6500203BB6D46C201B820F1AE4AFD4DEC304"
"444156E4E04D1BF0FFDA7783B6B457F756002000080001FFFF0001FFFF00640000FE0800"
"0086FE09003F000B7075626C69632E6E616D6500203BB6D46C201B820F1AE4AFD4DEC304"
"444156E4E04D1BF0FFDA7783B6B457F756002000080001FFFF0001FFFF00640000FE0900"
"3F000B7075626C69632E6E616D6500203BB6D46C201B820F1AE4AFD4DEC304444156E4E0"
"4D1BF0FFDA7783B6B457F75600200008FFFF0003FFFF000100640000";
std::vector<uint8_t> config = hex_string_to_bytes(unsupported);
DataBuffer record(config.data(), config.size());
DataBuffer echconfig(config.data(), config.size());
EnsureInit();
EXPECT_EQ(SECSuccess, SSL_EnableTls13GreaseEch(agent_->ssl_fd(),
PR_FALSE)); // Don't GREASE
InstallEchConfig(record, SEC_ERROR_INVALID_ARGS);
InstallEchConfig(echconfig, SEC_ERROR_INVALID_ARGS);
auto filter = MakeTlsFilter<TlsExtensionCapture>(
agent_, ssl_tls13_encrypted_client_hello_xtn);
agent_->Handshake();
@ -296,11 +298,11 @@ TEST_P(TlsAgentEchTest, ShortEchConfig) {
EnsureInit();
ScopedSECKEYPublicKey pub;
ScopedSECKEYPrivateKey priv;
DataBuffer record;
DataBuffer echconfig;
TlsConnectTestBase::GenerateEchConfig(HpkeDhKemX25519Sha256, kDefaultSuites,
kPublicName, 100, record, pub, priv);
record.Truncate(record.len() - 1);
InstallEchConfig(record, SEC_ERROR_BAD_DATA);
kPublicName, 100, echconfig, pub, priv);
echconfig.Truncate(echconfig.len() - 1);
InstallEchConfig(echconfig, SEC_ERROR_BAD_DATA);
EXPECT_EQ(SECSuccess, SSL_EnableTls13GreaseEch(agent_->ssl_fd(),
PR_FALSE)); // Don't GREASE
auto filter = MakeTlsFilter<TlsExtensionCapture>(
@ -314,11 +316,11 @@ TEST_P(TlsAgentEchTest, LongEchConfig) {
EnsureInit();
ScopedSECKEYPublicKey pub;
ScopedSECKEYPrivateKey priv;
DataBuffer record;
DataBuffer echconfig;
TlsConnectTestBase::GenerateEchConfig(HpkeDhKemX25519Sha256, kDefaultSuites,
kPublicName, 100, record, pub, priv);
record.Write(record.len(), 1, 1); // Append one byte
InstallEchConfig(record, SEC_ERROR_BAD_DATA);
kPublicName, 100, echconfig, pub, priv);
echconfig.Write(echconfig.len(), 1, 1); // Append one byte
InstallEchConfig(echconfig, SEC_ERROR_BAD_DATA);
EXPECT_EQ(SECSuccess, SSL_EnableTls13GreaseEch(agent_->ssl_fd(),
PR_FALSE)); // Don't GREASE
auto filter = MakeTlsFilter<TlsExtensionCapture>(
@ -332,13 +334,13 @@ TEST_P(TlsAgentEchTest, UnsupportedEchConfigVersion) {
EnsureInit();
ScopedSECKEYPublicKey pub;
ScopedSECKEYPrivateKey priv;
DataBuffer record;
DataBuffer echconfig;
static const uint8_t bad_version[] = {0xff, 0xff};
DataBuffer bad_ver_buf(bad_version, sizeof(bad_version));
TlsConnectTestBase::GenerateEchConfig(HpkeDhKemX25519Sha256, kDefaultSuites,
kPublicName, 100, record, pub, priv);
record.Splice(bad_ver_buf, 2, 2);
InstallEchConfig(record, SEC_ERROR_INVALID_ARGS);
kPublicName, 100, echconfig, pub, priv);
echconfig.Splice(bad_ver_buf, 2, 2);
InstallEchConfig(echconfig, SEC_ERROR_INVALID_ARGS);
EXPECT_EQ(SECSuccess, SSL_EnableTls13GreaseEch(agent_->ssl_fd(),
PR_FALSE)); // Don't GREASE
auto filter = MakeTlsFilter<TlsExtensionCapture>(
@ -352,12 +354,12 @@ TEST_P(TlsAgentEchTest, UnsupportedHpkeKem) {
EnsureInit();
ScopedSECKEYPublicKey pub;
ScopedSECKEYPrivateKey priv;
DataBuffer record;
DataBuffer echconfig;
// SSL_EncodeEchConfig encodes without validation.
TlsConnectTestBase::GenerateEchConfig(static_cast<HpkeKemId>(0xff),
kDefaultSuites, kPublicName, 100,
record, pub, priv);
InstallEchConfig(record, SEC_ERROR_INVALID_ARGS);
echconfig, pub, priv);
InstallEchConfig(echconfig, SEC_ERROR_INVALID_ARGS);
EXPECT_EQ(SECSuccess, SSL_EnableTls13GreaseEch(agent_->ssl_fd(),
PR_FALSE)); // Don't GREASE
auto filter = MakeTlsFilter<TlsExtensionCapture>(
@ -371,10 +373,26 @@ TEST_P(TlsAgentEchTest, EchRejectIgnoreAllUnknownSuites) {
EnsureInit();
ScopedSECKEYPublicKey pub;
ScopedSECKEYPrivateKey priv;
DataBuffer record;
DataBuffer echconfig;
TlsConnectTestBase::GenerateEchConfig(HpkeDhKemX25519Sha256, kBogusSuite,
kPublicName, 100, record, pub, priv);
InstallEchConfig(record, SEC_ERROR_INVALID_ARGS);
kPublicName, 100, echconfig, pub, priv);
InstallEchConfig(echconfig, SEC_ERROR_INVALID_ARGS);
EXPECT_EQ(SECSuccess, SSL_EnableTls13GreaseEch(agent_->ssl_fd(),
PR_FALSE)); // Don't GREASE
auto filter = MakeTlsFilter<TlsExtensionCapture>(
agent_, ssl_tls13_encrypted_client_hello_xtn);
agent_->Handshake();
ASSERT_FALSE(filter->captured());
}
TEST_P(TlsAgentEchTest, EchConfigRejectEmptyPublicName) {
EnsureInit();
ScopedSECKEYPublicKey pub;
ScopedSECKEYPrivateKey priv;
DataBuffer echconfig;
TlsConnectTestBase::GenerateEchConfig(HpkeDhKemX25519Sha256, kBogusSuite, "",
100, echconfig, pub, priv);
InstallEchConfig(echconfig, SSL_ERROR_RX_MALFORMED_ECH_CONFIG);
EXPECT_EQ(SECSuccess, SSL_EnableTls13GreaseEch(agent_->ssl_fd(),
PR_FALSE)); // Don't GREASE
auto filter = MakeTlsFilter<TlsExtensionCapture>(
@ -385,17 +403,18 @@ TEST_P(TlsAgentEchTest, EchRejectIgnoreAllUnknownSuites) {
TEST_F(TlsConnectStreamTls13, EchAcceptIgnoreSingleUnknownSuite) {
EnsureTlsSetup();
DataBuffer record;
DataBuffer echconfig;
ScopedSECKEYPublicKey pub;
ScopedSECKEYPrivateKey priv;
TlsConnectTestBase::GenerateEchConfig(HpkeDhKemX25519Sha256,
kUnknownFirstSuite, kPublicName, 100,
record, pub, priv);
ASSERT_EQ(SECSuccess, SSL_SetClientEchConfigs(client_->ssl_fd(),
record.data(), record.len()));
echconfig, pub, priv);
ASSERT_EQ(SECSuccess,
SSL_SetClientEchConfigs(client_->ssl_fd(), echconfig.data(),
echconfig.len()));
ASSERT_EQ(SECSuccess,
SSL_SetServerEchConfigs(server_->ssl_fd(), pub.get(), priv.get(),
record.data(), record.len()));
echconfig.data(), echconfig.len()));
client_->ExpectEch();
server_->ExpectEch();
@ -488,10 +507,10 @@ TEST_P(TlsAgentEchTest, NoEarlyRetryConfigs) {
ScopedSECKEYPublicKey pub;
ScopedSECKEYPrivateKey priv;
DataBuffer record;
DataBuffer echconfig;
TlsConnectTestBase::GenerateEchConfig(HpkeDhKemX25519Sha256, kDefaultSuites,
kPublicName, 100, record, pub, priv);
InstallEchConfig(record, 0);
kPublicName, 100, echconfig, pub, priv);
InstallEchConfig(echconfig, 0);
EXPECT_EQ(SECFailure,
SSL_GetEchRetryConfigs(agent_->ssl_fd(), &retry_configs));
@ -502,11 +521,11 @@ TEST_P(TlsAgentEchTest, NoSniSoNoEch) {
EnsureInit();
ScopedSECKEYPublicKey pub;
ScopedSECKEYPrivateKey priv;
DataBuffer record;
DataBuffer echconfig;
TlsConnectTestBase::GenerateEchConfig(HpkeDhKemX25519Sha256, kDefaultSuites,
kPublicName, 100, record, pub, priv);
kPublicName, 100, echconfig, pub, priv);
SSL_SetURL(agent_->ssl_fd(), "");
InstallEchConfig(record, 0);
InstallEchConfig(echconfig, 0);
SSL_SetURL(agent_->ssl_fd(), "");
EXPECT_EQ(SECSuccess, SSL_EnableTls13GreaseEch(agent_->ssl_fd(),
PR_FALSE)); // Don't GREASE
@ -520,7 +539,7 @@ TEST_P(TlsAgentEchTest, NoEchConfigSoNoEch) {
EnsureInit();
ScopedSECKEYPublicKey pub;
ScopedSECKEYPrivateKey priv;
DataBuffer record;
DataBuffer echconfig;
EXPECT_EQ(SECSuccess, SSL_EnableTls13GreaseEch(agent_->ssl_fd(),
PR_FALSE)); // Don't GREASE
auto filter = MakeTlsFilter<TlsExtensionCapture>(
@ -533,29 +552,29 @@ TEST_P(TlsAgentEchTest, EchConfigDuplicateExtensions) {
EnsureInit();
ScopedSECKEYPublicKey pub;
ScopedSECKEYPrivateKey priv;
DataBuffer record;
DataBuffer echconfig;
TlsConnectTestBase::GenerateEchConfig(HpkeDhKemX25519Sha256, kDefaultSuites,
kPublicName, 100, record, pub, priv);
kPublicName, 100, echconfig, pub, priv);
static const uint8_t duped_xtn[] = {0x00, 0x08, 0x00, 0x01, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00};
DataBuffer buf(duped_xtn, sizeof(duped_xtn));
record.Truncate(record.len() - 2);
record.Append(buf);
echconfig.Truncate(echconfig.len() - 2);
echconfig.Append(buf);
uint32_t len;
ASSERT_TRUE(record.Read(0, 2, &len));
ASSERT_TRUE(echconfig.Read(0, 2, &len));
len += buf.len() - 2;
DataBuffer new_len;
ASSERT_TRUE(new_len.Write(0, len, 2));
record.Splice(new_len, 0, 2);
echconfig.Splice(new_len, 0, 2);
new_len.Truncate(0);
ASSERT_TRUE(record.Read(4, 2, &len));
ASSERT_TRUE(echconfig.Read(4, 2, &len));
len += buf.len() - 2;
ASSERT_TRUE(new_len.Write(0, len, 2));
record.Splice(new_len, 4, 2);
echconfig.Splice(new_len, 4, 2);
InstallEchConfig(record, SEC_ERROR_EXTENSION_VALUE_INVALID);
InstallEchConfig(echconfig, SEC_ERROR_EXTENSION_VALUE_INVALID);
EXPECT_EQ(SECSuccess, SSL_EnableTls13GreaseEch(agent_->ssl_fd(),
PR_FALSE)); // Don't GREASE
auto filter = MakeTlsFilter<TlsExtensionCapture>(
@ -570,17 +589,16 @@ TEST_P(TlsAgentEchTest, EchConfigDuplicateExtensions) {
// extension in ClientHelloOuter.
TEST_F(TlsConnectStreamTls13Ech, EchOuterExtensionsReferencesMissing) {
std::string ch =
"01000170030374d616d97efe591bf9bee4496bcc1118145b4dd02f7d1ff979fd0cf61749"
"a91e0000061301130313020100014100000010000e00000b7075626c69632e6e616d65ff"
"010001580303dfff91b5e1ba00f29d2338419b3abf125ee1051a942ae25163bbf609a1ea"
"11920000061301130313020100012900000010000e00000b7075626c69632e6e616d65ff"
"01000100000a00140012001d00170018001901000101010201030104003300260024001d"
"00204f346f86351b077492c83564c909d1aaab4f6f3ee2566af0e90a4684c793805d002b"
"0020d94c1590c261e9ea8ae55bc9581f397cc598115f8b70aec1b0236f4c8c555537002b"
"0003020304000d0018001604030503060302030804080508060401050106010201002d00"
"020101001c00024001fe0800b30001000320a10698ccbd4bd86df91f617e58dd2ca96b8b"
"a5f058dd5c5ab1ca9750ef9d28c70020924764b36fe5d4a985f9857ceb75edb10b5f4b5b"
"f9d59290db70743e3c582163006acea5d7785cc506ecf5c859a9cad18f2b1df1a32231fe"
"0330471ee0e88ece9047e6491a381bfabed58f7fc542f0ba78eb55030bcfe1d400f67275"
"eac8619d1e4237e9d6176dd4eb54f3f25865686756f313a4ba47901c83e5ad5413609d39"
"816346b940115fd68e534609";
"020101001c00024001fe09009b0001000308fde4163c5c6e8bb6002067a895efa2721c88"
"63ecfa1bea1e520ae6f6cf938e3e37802688f7a83a871a04006aa693f053f87db87cf82a"
"7caa20670d79b92ccda97893fdf99352fc766fb3dd5570948311dddb6d41214234fae585"
"e354a048c072b3fb00a0a64e8e089e4a90152ee91a2c5b947c99d3dcebfb6334453b023d"
"4d725010996a290a0552e4b238ec91c21440adc0d51a4435";
ReplayChWithMalformedInner(ch, kTlsAlertIllegalParameter,
SSL_ERROR_RX_MALFORMED_ECH_EXTENSION,
SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
@ -589,17 +607,16 @@ TEST_F(TlsConnectStreamTls13Ech, EchOuterExtensionsReferencesMissing) {
// Drop supported_versions from CHInner, make sure we don't negotiate 1.2+ECH.
TEST_F(TlsConnectStreamTls13Ech, EchVersion12Inner) {
std::string ch =
"0100017003034dd5bf4c12835e9be21f983953720e3595b3a8eeb4a44467678caceb7727"
"3be90000061301130313020100014100000010000e00000b7075626c69632e6e616d65ff"
"0100015103038fbe6f75b0123116fa5c4eccf0cf26c17ab1ded5529307e419c036ac7e9c"
"e8e30000061301130313020100012200000010000e00000b7075626c69632e6e616d65ff"
"01000100000a00140012001d00170018001901000101010201030104003300260024001d"
"0020af7b976cdf69ffcd494ca5a93ae3ecde692b09be518ee033aad908c45b82c368002b"
"002078d644583b4f056bec4d8ae9bddd383aed6eb7cdb3294f88b0e37a4f26a02549002b"
"0003020304000d0018001604030503060302030804080508060401050106010201002d00"
"020101001c0002400100150003000000fe0800ac0001000320a10698ccbd4bd86df91f61"
"7e58dd2ca96b8ba5f058dd5c5ab1ca9750ef9d28c70020f5ece4c187b76f7e3d467c7506"
"215e73c27c918cd863c0e80d76a7987ec274320063e037492868eff5296a22dc50885e9d"
"f6964a5e26546f1bada043f8834988dfea5394b4c45a4d0b3afc52142d33f94161135a63"
"ed3c1b63f60d8133fb1cff17e1f9ced6c871984e412ed8ddb0f487c4d09d7aea80488004"
"c45a17cd3b5cdca316155fdb";
"020101001c00024001fe0900940001000308fde4163c5c6e8bb600208958e66d1d4bbd46"
"4792f392e119dbce91ee3e65067899b45c83855dae61e67a00637df038e7b35483786707"
"dd1b25be5cd3dd07f1ca4b33a3595ddb959e5c0da3d2f0b3314417614968691700c05232"
"07c729b34f3b5de62728b3cb6b45b00e6f94b204a9504d0e7e24c66f42aacc73591c86ef"
"571e61cebd6ba671081150a2dae89e7493";
ReplayChWithMalformedInner(ch, kTlsAlertProtocolVersion,
SSL_ERROR_UNSUPPORTED_VERSION,
SSL_ERROR_PROTOCOL_VERSION_ALERT);
@ -608,40 +625,103 @@ TEST_F(TlsConnectStreamTls13Ech, EchVersion12Inner) {
// Use CHInner supported_versions to negotiate 1.2.
TEST_F(TlsConnectStreamTls13Ech, EchVersion12InnerSupportedVersions) {
std::string ch =
"010001700303845c298db4017d2ed2584284b90e4ecba57a63663560c57aa0b1ac51203d"
"c8560000061301130313020100014100000010000e00000b7075626c69632e6e616d65ff"
"01000158030378a601a3f12229e53e0b8d92c3599bf1782e8261d2ecaec9bbe595d4c901"
"98770000061301130313020100012900000010000e00000b7075626c69632e6e616d65ff"
"01000100000a00140012001d00170018001901000101010201030104003300260024001d"
"00203356719e88b539645438f645916aeeffe93c38803a59d6997938aa98eefbcf64002b"
"00201c8017d6970f3a92ac1c9919c3a26788052f84599fb0c3cb7bd381304148724e002b"
"0003020304000d0018001604030503060302030804080508060401050106010201002d00"
"020101001c00024001fe0800b30001000320a10698ccbd4bd86df91f617e58dd2ca96b8b"
"a5f058dd5c5ab1ca9750ef9d28c700208412c945c53624bcace5eda0dc1ad300a1620e86"
"5a0f4a27755a3477b115b65b006abf1dfd77ddc1b80c5976732174a5fe7ebcf9ff1a548b"
"097daa12a37f3e32a613a0798544ba1d96239431bc807ddd9055ac3fb3e32b2eb42cec30"
"e915357418a953027d73020fd739287414205349eeff376dd464750ca70a965141a88800"
"6a043fe1d6d882d9a2c2f6f3";
"020101001c00024001fe09009b0001000308fde4163c5c6e8bb60020f7347d34f125e866"
"76b1cdc43455c6c00918a3c8a961335e1b9aa864da2b5313006a21e6ad81533e90cea24e"
"c2c3656f6b53114b4c63bf89462696f1c8ad4e1193d87062a5537edbe83c9b35c41e9763"
"1d2333270854758ee02548afb7f2264f904474465415a5085024487f22b017208e250ca4"
"7902d61d98fbd1cb8afc0a14dcd70a68343cf67c258758d9";
ReplayChWithMalformedInner(ch, kTlsAlertProtocolVersion,
SSL_ERROR_UNSUPPORTED_VERSION,
SSL_ERROR_PROTOCOL_VERSION_ALERT);
}
// Replay a CH for which the ECH Inner lacks the required
// empty ECH extension.
// Replay a CH for which CHInner lacks the required ech_is_inner extension.
TEST_F(TlsConnectStreamTls13Ech, EchInnerMissingEmptyEch) {
std::string ch =
"0100017103032bf866cbd6d4abdec8ce23107eaef9af51b644043953e3b70f2f28f1898e"
"87880000061301130313020100014200000010000e00000b7075626c69632e6e616d65ff"
"010001540303033b3284790ada882445bfb38b8af3509659033c931e6ae97febbaa62b19"
"b4ac0000061301130313020100012500000010000e00000b7075626c69632e6e616d65ff"
"01000100000a00140012001d00170018001901000101010201030104003300260024001d"
"00208f614d3017575332ca009a42d33bcaf876b4ba6d44b052e8019c31f6f1559e41002b"
"00209d1ed410ccb05ce9e424f52b1be3599bcc1efb0913ae14a24d9a69cbfbc39744002b"
"0003020304000d0018001604030503060302030804080508060401050106010201002d00"
"020101001c000240010015000100fe0800af0001000320a10698ccbd4bd86df91f617e58"
"dd2ca96b8ba5f058dd5c5ab1ca9750ef9d28c70020da1d5d9f183a5d5e49892e38eaae5e"
"9e3e6c5d404a5fdb672ca37f9cebabd57400660ea1d61917cc1049aab22506078ccecfc4"
"16a364a1beaa8915b250bb86ac2c725698c3c641830c4aa4e8b7f50152b5732b29b1ac43"
"45c97fc018855fd68e5600d0ef188e905b69997c3711b0ec0114a857177df728c7b84f52"
"2923f932838f7f15bb22644fd4";
ReplayChWithMalformedInner(ch, kTlsAlertDecodeError,
"020101001c00024001fe0900970001000308fde4163c5c6e8bb600206321bdc543a23d47"
"7a7104ba69177cb722927c6c485117df4a077b8e82167f0b0066103d9aac7e5fc4ef990b"
"2ce38593589f7f6ba043847d7db6c9136adb811f63b956d56e6ca8cbe6864e3fc43a3bc5"
"94a332d4d63833e411c89ef14af63b5cd18c7adee99ffd1ad3112449ea18d6650bbaca66"
"528f7e4146fafbf338c27cf89b145a55022b26a3";
ReplayChWithMalformedInner(ch, kTlsAlertIllegalParameter,
SSL_ERROR_MISSING_ECH_EXTENSION,
SSL_ERROR_DECODE_ERROR_ALERT);
SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
}
// Replay a CH for which CHInner contains both an ECH and ech_is_inner
// extension.
TEST_F(TlsConnectStreamTls13Ech, InnerWithEchAndEchIsInner) {
std::string ch =
"0100015c030383fb49c98b62bcdf04cbbae418dd684f8f9512f40fca6861ba40555269a9"
"789f0000061301130313020100012d00000010000e00000b7075626c69632e6e616d65ff"
"01000100000a00140012001d00170018001901000101010201030104003300260024001d"
"00201e3d35a6755b7dddf7e481359429e9677baaa8dd99569c2bf0b0f7ea56e68b12002b"
"0003020304000d0018001604030503060302030804080508060401050106010201002d00"
"020101001c00024001fe09009f0001000308fde4163c5c6e8bb6002090110b89c1ba6618"
"942ea7aae8c472c22e97f10bef7dd490bee50cc108082b48006eed016fa2b3e3419cf5ef"
"9b41ab9ecffa84a4b60e2f4cc710cf31c739d1f6f88b48207aaf7ccabdd744a25a8f2a38"
"029d1b133e9d990681cf08c07a255d9242b3a002bc0865935cbb609b2b1996fab0626cb0"
"2ece6544bbde0d3218333ffd95c383a41854b76b1a254bb346a2702b";
ReplayChWithMalformedInner(ch, kTlsAlertIllegalParameter,
SSL_ERROR_RX_MALFORMED_CLIENT_HELLO,
SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
}
TEST_F(TlsConnectStreamTls13, OuterWithEchAndEchIsInner) {
static uint8_t empty_buf[1] = {0};
DataBuffer empty(empty_buf, 0);
EnsureTlsSetup();
EXPECT_EQ(SECSuccess, SSL_EnableTls13GreaseEch(client_->ssl_fd(), PR_TRUE));
MakeTlsFilter<TlsExtensionAppender>(client_, kTlsHandshakeClientHello,
ssl_tls13_ech_is_inner_xtn, empty);
ConnectExpectAlert(server_, kTlsAlertIllegalParameter);
client_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
server_->CheckErrorCode(SSL_ERROR_RX_UNEXPECTED_EXTENSION);
}
// Apply two ECHConfigs on the server. They are identical with the exception
// of the public key: the first ECHConfig contains a public key for which we
// lack the private value. Use an SSLInt function to zero all the config_ids
// (client and server), then confirm that trial decryption works.
TEST_F(TlsConnectStreamTls13Ech, EchConfigsTrialDecrypt) {
ScopedSECKEYPublicKey pub;
ScopedSECKEYPrivateKey priv;
EnsureTlsSetup();
ImportFixedEchKeypair(pub, priv);
const std::string two_configs_str =
"007EFE09003B000B7075626C69632E6E616D650020111111111111111111111111111111"
"1111111111111111111111111111111111002000040001000100640000fe09003B000B70"
"75626C69632E6E616D6500208756E2580C07C1D2FFCB662F5FADC6D6FF13DA85ABD7ADFE"
"CF984AAA102C1269002000040001000100640000";
const std::string second_config_str =
"003FFE09003B000B7075626C69632E6E616D6500208756E2580C07C1D2FFCB662F5FADC6"
"D6FF13DA85ABD7ADFECF984AAA102C1269002000040001000100640000";
std::vector<uint8_t> two_configs = hex_string_to_bytes(two_configs_str);
std::vector<uint8_t> second_config = hex_string_to_bytes(second_config_str);
ASSERT_EQ(SECSuccess,
SSL_SetServerEchConfigs(server_->ssl_fd(), pub.get(), priv.get(),
two_configs.data(), two_configs.size()));
ASSERT_EQ(SECSuccess,
SSL_SetClientEchConfigs(client_->ssl_fd(), second_config.data(),
second_config.size()));
ASSERT_EQ(SECSuccess, SSLInt_ZeroEchConfigIds(client_->ssl_fd()));
ASSERT_EQ(SECSuccess, SSLInt_ZeroEchConfigIds(server_->ssl_fd()));
client_->ExpectEch();
server_->ExpectEch();
Connect();
}
// An empty config_id should prompt an alert. We don't support
@ -769,16 +849,17 @@ SSLHelloRetryRequestAction RetryEchHello(PRBool firstHello,
TEST_F(TlsConnectStreamTls13, EchAcceptWithHrr) {
ScopedSECKEYPublicKey pub;
ScopedSECKEYPrivateKey priv;
DataBuffer record;
DataBuffer echconfig;
ConfigureSelfEncrypt();
EnsureTlsSetup();
TlsConnectTestBase::GenerateEchConfig(HpkeDhKemX25519Sha256, kDefaultSuites,
kPublicName, 100, record, pub, priv);
kPublicName, 100, echconfig, pub, priv);
ASSERT_EQ(SECSuccess,
SSL_SetServerEchConfigs(server_->ssl_fd(), pub.get(), priv.get(),
record.data(), record.len()));
ASSERT_EQ(SECSuccess, SSL_SetClientEchConfigs(client_->ssl_fd(),
record.data(), record.len()));
echconfig.data(), echconfig.len()));
ASSERT_EQ(SECSuccess,
SSL_SetClientEchConfigs(client_->ssl_fd(), echconfig.data(),
echconfig.len()));
client_->ExpectEch();
server_->ExpectEch();
client_->SetAuthCertificateCallback(AuthCompleteSuccess);
@ -795,7 +876,7 @@ TEST_F(TlsConnectStreamTls13, EchAcceptWithHrr) {
MakeNewServer();
ASSERT_EQ(SECSuccess,
SSL_SetServerEchConfigs(server_->ssl_fd(), pub.get(), priv.get(),
record.data(), record.len()));
echconfig.data(), echconfig.len()));
client_->ExpectEch();
server_->ExpectEch();
client_->SetAuthCertificateCallback(AuthCompleteSuccess);
@ -805,6 +886,42 @@ TEST_F(TlsConnectStreamTls13, EchAcceptWithHrr) {
SendReceive();
}
// Send GREASE ECH in CH1. CH2 must send exactly the same GREASE ECH contents.
TEST_F(TlsConnectStreamTls13, GreaseEchHrrMatches) {
ConfigureSelfEncrypt();
EnsureTlsSetup();
size_t cb_called = 0;
EXPECT_EQ(SECSuccess, SSL_HelloRetryRequestCallback(
server_->ssl_fd(), RetryEchHello, &cb_called));
EXPECT_EQ(SECSuccess, SSL_EnableTls13GreaseEch(client_->ssl_fd(),
PR_TRUE)); // GREASE
auto capture = MakeTlsFilter<TlsExtensionCapture>(
client_, ssl_tls13_encrypted_client_hello_xtn);
// Start the handshake.
client_->StartConnect();
server_->StartConnect();
client_->Handshake(); // Send CH1
EXPECT_TRUE(capture->captured());
DataBuffer ch1_grease = capture->extension();
server_->Handshake();
MakeNewServer();
capture = MakeTlsFilter<TlsExtensionCapture>(
client_, ssl_tls13_encrypted_client_hello_xtn);
EXPECT_FALSE(capture->captured());
client_->Handshake(); // Send CH2
EXPECT_TRUE(capture->captured());
EXPECT_EQ(ch1_grease, capture->extension());
EXPECT_EQ(1U, cb_called);
server_->StartConnect();
Handshake();
CheckConnected();
}
// Fail to decrypt CH2. Unlike CH1, this generates an alert.
TEST_F(TlsConnectStreamTls13, EchFailDecryptCH2) {
EnsureTlsSetup();
@ -848,9 +965,9 @@ TEST_F(TlsConnectStreamTls13, EchHrrChangeCh2OfferingYN) {
MakeNewServer();
EXPECT_EQ(SECSuccess, SSL_EnableTls13GreaseEch(client_->ssl_fd(),
PR_FALSE)); // Don't GREASE
ExpectAlert(server_, kTlsAlertIllegalParameter);
ExpectAlert(server_, kTlsAlertMissingExtension);
Handshake();
client_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
client_->CheckErrorCode(SSL_ERROR_MISSING_EXTENSION_ALERT);
server_->CheckErrorCode(SSL_ERROR_BAD_2ND_CLIENT_HELLO);
EXPECT_EQ(1U, cb_called);
}
@ -858,20 +975,47 @@ TEST_F(TlsConnectStreamTls13, EchHrrChangeCh2OfferingYN) {
TEST_F(TlsConnectStreamTls13, EchHrrChangeCh2OfferingNY) {
ConfigureSelfEncrypt();
EnsureTlsSetup();
SetupEch(client_, server_);
size_t cb_called = 0;
EXPECT_EQ(SECSuccess, SSL_HelloRetryRequestCallback(
server_->ssl_fd(), RetryEchHello, &cb_called));
EXPECT_EQ(SECSuccess, SSL_EnableTls13GreaseEch(client_->ssl_fd(),
PR_FALSE)); // Don't GREASE
MakeTlsFilter<TlsExtensionDropper>(client_,
ssl_tls13_encrypted_client_hello_xtn);
// Start the handshake.
client_->StartConnect();
server_->StartConnect();
client_->Handshake();
server_->Handshake();
MakeNewServer();
EXPECT_EQ(SECSuccess, SSL_EnableTls13GreaseEch(client_->ssl_fd(),
PR_TRUE)); // Send GREASE
client_->ClearFilter(); // Let the second ECH offering through.
ExpectAlert(server_, kTlsAlertIllegalParameter);
Handshake();
client_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
server_->CheckErrorCode(SSL_ERROR_BAD_2ND_CLIENT_HELLO);
EXPECT_EQ(1U, cb_called);
}
// Change the ECHCipherSuite between CH1 and CH2. Expect alert.
TEST_F(TlsConnectStreamTls13, EchHrrChangeCipherSuite) {
ConfigureSelfEncrypt();
EnsureTlsSetup();
SetupEch(client_, server_);
size_t cb_called = 0;
EXPECT_EQ(SECSuccess, SSL_HelloRetryRequestCallback(
server_->ssl_fd(), RetryEchHello, &cb_called));
// Start the handshake and trigger HRR.
client_->StartConnect();
server_->StartConnect();
client_->Handshake();
server_->Handshake();
MakeNewServer();
// Damage the first byte of the ciphersuite (offset 0)
MakeTlsFilter<TlsExtensionDamager>(client_,
ssl_tls13_encrypted_client_hello_xtn, 0);
ExpectAlert(server_, kTlsAlertIllegalParameter);
Handshake();
client_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
@ -884,17 +1028,18 @@ TEST_F(TlsConnectStreamTls13, EchHrrChangeCh2OfferingNY) {
TEST_F(TlsConnectStreamTls13, EchAcceptWithHrrAndPsk) {
ScopedSECKEYPublicKey pub;
ScopedSECKEYPrivateKey priv;
DataBuffer record;
DataBuffer echconfig;
ConfigureSelfEncrypt();
EnsureTlsSetup();
TlsConnectTestBase::GenerateEchConfig(HpkeDhKemX25519Sha256, kDefaultSuites,
kPublicName, 100, record, pub, priv);
kPublicName, 100, echconfig, pub, priv);
ASSERT_EQ(SECSuccess,
SSL_SetServerEchConfigs(server_->ssl_fd(), pub.get(), priv.get(),
record.data(), record.len()));
ASSERT_EQ(SECSuccess, SSL_SetClientEchConfigs(client_->ssl_fd(),
record.data(), record.len()));
echconfig.data(), echconfig.len()));
ASSERT_EQ(SECSuccess,
SSL_SetClientEchConfigs(client_->ssl_fd(), echconfig.data(),
echconfig.len()));
client_->ExpectEch();
server_->ExpectEch();
@ -922,7 +1067,7 @@ TEST_F(TlsConnectStreamTls13, EchAcceptWithHrrAndPsk) {
MakeNewServer();
ASSERT_EQ(SECSuccess,
SSL_SetServerEchConfigs(server_->ssl_fd(), pub.get(), priv.get(),
record.data(), record.len()));
echconfig.data(), echconfig.len()));
client_->ExpectEch();
server_->ExpectEch();
EXPECT_EQ(SECSuccess,
@ -940,7 +1085,7 @@ TEST_F(TlsConnectStreamTls13, EchAcceptWithHrrAndPsk) {
TEST_F(TlsConnectStreamTls13Ech, EchRejectWithHrr) {
ScopedSECKEYPublicKey pub;
ScopedSECKEYPrivateKey priv;
DataBuffer record;
DataBuffer echconfig;
ConfigureSelfEncrypt();
EnsureTlsSetup();
SetupForEchRetry();
@ -966,19 +1111,20 @@ TEST_F(TlsConnectStreamTls13Ech, EchRejectWithHrr) {
EXPECT_EQ(1U, cb_called);
}
// Reject ECH on CH1 and (HRR) CH2. PSKs are no longer allowed
// in CHOuter, but can still make sure the handshake succeeds.
// (prompting ech_required at the completion).
// Reject ECH on CH1 and CH2. PSKs are no longer allowed
// in CHOuter, but we can still make sure the handshake succeeds.
// This prompts an ech_required alert when the handshake completes.
TEST_F(TlsConnectStreamTls13, EchRejectWithHrrAndPsk) {
ScopedSECKEYPublicKey pub;
ScopedSECKEYPrivateKey priv;
DataBuffer record;
DataBuffer echconfig;
ConfigureSelfEncrypt();
EnsureTlsSetup();
TlsConnectTestBase::GenerateEchConfig(HpkeDhKemX25519Sha256, kDefaultSuites,
kPublicName, 100, record, pub, priv);
ASSERT_EQ(SECSuccess, SSL_SetClientEchConfigs(client_->ssl_fd(),
record.data(), record.len()));
kPublicName, 100, echconfig, pub, priv);
ASSERT_EQ(SECSuccess,
SSL_SetClientEchConfigs(client_->ssl_fd(), echconfig.data(),
echconfig.len()));
size_t cb_called = 0;
EXPECT_EQ(SECSuccess, SSL_HelloRetryRequestCallback(
@ -1113,7 +1259,7 @@ TEST_F(TlsConnectStreamTls13, EchRejectUnknownCriticalExtension) {
EnsureTlsSetup();
ScopedSECKEYPublicKey pub;
ScopedSECKEYPrivateKey priv;
DataBuffer record;
DataBuffer echconfig;
DataBuffer crit_rec;
DataBuffer len_buf;
uint64_t tmp;
@ -1124,9 +1270,9 @@ TEST_F(TlsConnectStreamTls13, EchRejectUnknownCriticalExtension) {
DataBuffer non_crit_exts(extensions, sizeof(extensions));
TlsConnectTestBase::GenerateEchConfig(HpkeDhKemX25519Sha256, kSuiteChaCha,
kPublicName, 100, record, pub, priv);
record.Truncate(record.len() - 2); // Eat the empty extensions.
crit_rec.Assign(record);
kPublicName, 100, echconfig, pub, priv);
echconfig.Truncate(echconfig.len() - 2); // Eat the empty extensions.
crit_rec.Assign(echconfig);
ASSERT_TRUE(crit_rec.Read(0, 2, &tmp));
len_buf.Write(0, tmp + crit_exts.len() - 2, 2); // two bytes of length
crit_rec.Splice(len_buf, 0, 2);
@ -1138,13 +1284,13 @@ TEST_F(TlsConnectStreamTls13, EchRejectUnknownCriticalExtension) {
crit_rec.Splice(len_buf, 4, 2);
len_buf.Truncate(0);
ASSERT_TRUE(record.Read(0, 2, &tmp));
ASSERT_TRUE(echconfig.Read(0, 2, &tmp));
len_buf.Write(0, tmp + non_crit_exts.len() - 2, 2);
record.Append(non_crit_exts);
record.Splice(len_buf, 0, 2);
ASSERT_TRUE(record.Read(4, 2, &tmp));
echconfig.Append(non_crit_exts);
echconfig.Splice(len_buf, 0, 2);
ASSERT_TRUE(echconfig.Read(4, 2, &tmp));
len_buf.Write(0, tmp + non_crit_exts.len() - 2, 2);
record.Splice(len_buf, 4, 2);
echconfig.Splice(len_buf, 4, 2);
EXPECT_EQ(SECFailure,
SSL_SetClientEchConfigs(client_->ssl_fd(), crit_rec.data(),
@ -1162,8 +1308,9 @@ TEST_F(TlsConnectStreamTls13, EchRejectUnknownCriticalExtension) {
// Now try a variant with non-critical extensions, it should work.
Reset();
EnsureTlsSetup();
EXPECT_EQ(SECSuccess, SSL_SetClientEchConfigs(client_->ssl_fd(),
record.data(), record.len()));
EXPECT_EQ(SECSuccess,
SSL_SetClientEchConfigs(client_->ssl_fd(), echconfig.data(),
echconfig.len()));
filter = MakeTlsFilter<TlsExtensionCapture>(
client_, ssl_tls13_encrypted_client_hello_xtn);
StartConnect();
@ -1577,6 +1724,34 @@ TEST_F(TlsConnectStreamTls13, EchOuterExtensionsInCHOuter) {
server_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
}
// At draft-09: If a CH containing the ech_is_inner extension is received, the
// server acts as backend server in split-mode by responding with the ECH
// acceptance signal. The signal value itself depends on the handshake secret,
// which we've broken by appending ech_is_inner. For now, just check that the
// server negotiates ech_is_inner (which is what triggers sending the signal).
TEST_F(TlsConnectStreamTls13, EchBackendAcceptance) {
DataBuffer ch_buf;
static uint8_t empty_buf[1] = {0};
DataBuffer empty(empty_buf, 0);
EnsureTlsSetup();
StartConnect();
EXPECT_EQ(SECSuccess, SSL_EnableTls13GreaseEch(client_->ssl_fd(), PR_FALSE));
MakeTlsFilter<TlsExtensionAppender>(client_, kTlsHandshakeClientHello,
ssl_tls13_ech_is_inner_xtn, empty);
EXPECT_EQ(SECSuccess, SSL_EnableTls13BackendEch(server_->ssl_fd(), PR_TRUE));
client_->Handshake();
server_->Handshake();
ExpectAlert(client_, kTlsAlertBadRecordMac);
client_->Handshake();
EXPECT_EQ(TlsAgent::STATE_ERROR, client_->state());
EXPECT_EQ(PR_TRUE, SSLInt_ExtensionNegotiated(server_->ssl_fd(),
ssl_tls13_ech_is_inner_xtn));
server_->ExpectReceiveAlert(kTlsAlertCloseNotify, kTlsAlertWarning);
}
INSTANTIATE_TEST_SUITE_P(EchAgentTest, TlsAgentEchTest,
::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
TlsConnectTestBase::kTlsV13));

Просмотреть файл

@ -1213,3 +1213,10 @@ PK11_PubUnwrapSymKeyWithMechanism;
;+ local:
;+ *;
;+};
;+NSS_3.62 { # NSS 3.62 release
;+ global:
PK11_HPKE_ExportContext;
PK11_HPKE_ImportContext;
;+ local:
;+ *;
;+};

Просмотреть файл

@ -22,12 +22,12 @@
* The format of the version string should be
* "<major version>.<minor version>[.<patch level>[.<build number>]][ <ECC>][ <Beta>]"
*/
#define NSS_VERSION "3.61" _NSS_CUSTOMIZED
#define NSS_VERSION "3.62" _NSS_CUSTOMIZED " Beta"
#define NSS_VMAJOR 3
#define NSS_VMINOR 61
#define NSS_VMINOR 62
#define NSS_VPATCH 0
#define NSS_VBUILD 0
#define NSS_BETA PR_FALSE
#define NSS_BETA PR_TRUE
#ifndef RC_INVOKED

Просмотреть файл

@ -1,5 +1,5 @@
/*
* draft-irtf-cfrg-hpke-05
* draft-irtf-cfrg-hpke-07
*
* 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
@ -53,12 +53,24 @@ PK11_HPKE_GetEncapPubKey(const HpkeContext *cx)
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)
@ -94,15 +106,16 @@ PK11_HPKE_SetupR(HpkeContext *cx, const SECKEYPublicKey *pkR, SECKEYPrivateKey *
}
#else
static const char *DRAFT_LABEL = "HPKE-05 ";
#define SERIALIZATION_VERSION 1
static const char *DRAFT_LABEL = "HPKE-07";
static const char *EXP_LABEL = "exp";
static const char *HPKE_LABEL = "HPKE";
static const char *INFO_LABEL = "info_hash";
static const char *KEM_LABEL = "KEM";
static const char *KEY_LABEL = "key";
static const char *NONCE_LABEL = "nonce";
static const char *NONCE_LABEL = "base_nonce";
static const char *PSK_ID_LABEL = "psk_id_hash";
static const char *PSK_LABEL = "psk_hash";
static const char *SECRET_LABEL = "secret";
static const char *SEC_LABEL = "sec";
static const char *EAE_PRK_LABEL = "eae_prk";
@ -114,7 +127,7 @@ struct HpkeContextStr {
const hpkeAeadParams *aeadParams;
PRUint8 mode; /* Base and PSK modes supported. */
SECItem *encapPubKey; /* Marshalled public key, sent to receiver. */
SECItem *nonce; /* Deterministic nonce for AEAD. */
SECItem *baseNonce; /* Deterministic nonce for AEAD. */
SECItem *pskId; /* PSK identifier (non-secret). */
PK11Context *aeadContext; /* AEAD context used by Seal/Open. */
PRUint64 sequenceNumber; /* seqNo for decrypt IV construction. */
@ -129,10 +142,14 @@ static const hpkeKemParams kemParams[] = {
{ HpkeDhKemX25519Sha256, 32, 32, 32, SEC_OID_CURVE25519, CKM_SHA256 },
};
#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
static const hpkeAeadParams aeadParams[] = {
/* AEAD, Nk, Nn, tagLen, mechanism */
{ HpkeAeadAes128Gcm, 16, 12, 16, CKM_AES_GCM },
@ -156,6 +173,10 @@ kdfId2Params(HpkeKdfId kdfId)
switch (kdfId) {
case HpkeKdfHkdfSha256:
return &kdfParams[0];
case HpkeKdfHkdfSha384:
return &kdfParams[1];
case HpkeKdfHkdfSha512:
return &kdfParams[2];
default:
return NULL;
}
@ -174,16 +195,30 @@ aeadId2Params(HpkeAeadId aeadId)
}
}
static SECStatus
encodeShort(PRUint32 val, PRUint8 *b)
static PRUint8 *
encodeNumber(PRUint64 value, PRUint8 *b, size_t count)
{
if (val > 0xFFFF || !b) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
PRUint64 encoded;
PORT_Assert(b && count > 0 && count <= sizeof(encoded));
encoded = PR_htonll(value);
PORT_Memcpy(b, ((unsigned char *)(&encoded)) + (sizeof(encoded) - count),
count);
return b + count;
}
static PRUint8 *
decodeNumber(PRUint64 *value, PRUint8 *b, size_t count)
{
unsigned int i;
PRUint64 number = 0;
PORT_Assert(b && value && count <= sizeof(*value));
for (i = 0; i < count; i++) {
number = (number << 8) + b[i];
}
b[0] = (val >> 8) & 0xff;
b[1] = val & 0xff;
return SECSuccess;
*value = number;
return b + count;
}
SECStatus
@ -268,20 +303,260 @@ PK11_HPKE_DestroyContext(HpkeContext *cx, PRBool freeit)
PK11_FreeSymKey(cx->key);
PK11_FreeSymKey(cx->psk);
SECITEM_FreeItem(cx->pskId, PR_TRUE);
SECITEM_FreeItem(cx->nonce, PR_TRUE);
SECITEM_FreeItem(cx->baseNonce, PR_TRUE);
SECITEM_FreeItem(cx->encapPubKey, PR_TRUE);
cx->exporterSecret = NULL;
cx->sharedSecret = NULL;
cx->key = NULL;
cx->psk = NULL;
cx->pskId = NULL;
cx->nonce = NULL;
cx->baseNonce = NULL;
cx->encapPubKey = NULL;
if (freeit) {
PORT_ZFree(cx, sizeof(HpkeContext));
}
}
/* Export Format:
struct {
uint8 serilizationVersion;
uint8 hpkeVersion;
uint16 kemId;
uint16 kdfId;
uint16 aeadId;
uint16 modeId;
uint64 sequenceNumber;
opaque senderPubKey<1..2^16-1>;
opaque baseNonce<1..2^16-1>;
opaque key<1..2^16-1>;
opaque exporterSecret<1..2^16-1>;
} HpkeSerializedContext
*/
#define EXPORTED_CTX_BASE_LEN 26 /* Fixed size plus 2B for each variable. */
#define REMAINING_BYTES(walker, buf) \
buf->len - (walker - buf->data)
SECStatus
PK11_HPKE_ExportContext(const HpkeContext *cx, PK11SymKey *wrapKey, SECItem **serialized)
{
SECStatus rv;
size_t allocLen;
PRUint8 *walker;
SECItem *keyBytes = NULL; // Maybe wrapped
SECItem *exporterBytes = NULL; // Maybe wrapped
SECItem *serializedCx = NULL;
PRUint8 wrappedKeyBytes[MAX_WRAPPED_KEY_LEN] = { 0 };
PRUint8 wrappedExpBytes[MAX_WRAPPED_EXP_LEN] = { 0 };
SECItem wrappedKey = { siBuffer, wrappedKeyBytes, sizeof(wrappedKeyBytes) };
SECItem wrappedExp = { siBuffer, wrappedExpBytes, sizeof(wrappedExpBytes) };
CHECK_FAIL_ERR((!cx || !cx->aeadContext || !serialized), SEC_ERROR_INVALID_ARGS);
CHECK_FAIL_ERR((cx->aeadContext->operation != (CKA_NSS_MESSAGE | CKA_DECRYPT)),
SEC_ERROR_NOT_A_RECIPIENT);
/* If a wrapping key was provided, do the wrap first
* so that we know what size to allocate. */
if (wrapKey) {
rv = PK11_WrapSymKey(CKM_AES_KEY_WRAP_KWP, NULL, wrapKey,
cx->key, &wrappedKey);
CHECK_RV(rv);
rv = PK11_WrapSymKey(CKM_AES_KEY_WRAP_KWP, NULL, wrapKey,
cx->exporterSecret, &wrappedExp);
CHECK_RV(rv);
keyBytes = &wrappedKey;
exporterBytes = &wrappedExp;
} else {
rv = PK11_ExtractKeyValue(cx->key);
CHECK_RV(rv);
keyBytes = PK11_GetKeyData(cx->key);
CHECK_FAIL(!keyBytes);
PORT_Assert(keyBytes->len == cx->aeadParams->Nk);
rv = PK11_ExtractKeyValue(cx->exporterSecret);
CHECK_RV(rv);
exporterBytes = PK11_GetKeyData(cx->exporterSecret);
CHECK_FAIL(!exporterBytes);
PORT_Assert(exporterBytes->len == cx->kdfParams->Nh);
}
allocLen = EXPORTED_CTX_BASE_LEN + cx->baseNonce->len + cx->encapPubKey->len;
allocLen += wrapKey ? wrappedKey.len : cx->aeadParams->Nk;
allocLen += wrapKey ? wrappedExp.len : cx->kdfParams->Nh;
serializedCx = SECITEM_AllocItem(NULL, NULL, allocLen);
CHECK_FAIL(!serializedCx);
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);
walker = encodeNumber(cx->aeadParams->id, walker, 2);
walker = encodeNumber(cx->mode, walker, 2);
walker = encodeNumber(cx->sequenceNumber, walker, 8);
/* sender public key, serialized. */
walker = encodeNumber(cx->encapPubKey->len, walker, 2);
PORT_Memcpy(walker, cx->encapPubKey->data, cx->encapPubKey->len);
walker += cx->encapPubKey->len;
/* base nonce */
walker = encodeNumber(cx->baseNonce->len, walker, 2);
PORT_Memcpy(walker, cx->baseNonce->data, cx->baseNonce->len);
walker += cx->baseNonce->len;
/* key. */
walker = encodeNumber(keyBytes->len, walker, 2);
PORT_Memcpy(walker, keyBytes->data, keyBytes->len);
walker += keyBytes->len;
/* exporter_secret. */
walker = encodeNumber(exporterBytes->len, walker, 2);
PORT_Memcpy(walker, exporterBytes->data, exporterBytes->len);
walker += exporterBytes->len;
CHECK_FAIL_ERR(REMAINING_BYTES(walker, serializedCx) != 0,
SEC_ERROR_LIBRARY_FAILURE);
*serialized = serializedCx;
CLEANUP:
if (rv != SECSuccess) {
SECITEM_ZfreeItem(serializedCx, PR_TRUE);
}
return rv;
}
HpkeContext *
PK11_HPKE_ImportContext(const SECItem *serialized, PK11SymKey *wrapKey)
{
SECStatus rv = SECSuccess;
HpkeContext *cx = NULL;
PRUint8 *walker;
PRUint64 tmpn;
PRUint8 tmp8;
HpkeKemId kem;
HpkeKdfId kdf;
HpkeAeadId aead;
PK11SlotInfo *slot = NULL;
PK11SymKey *tmpKey = NULL;
SECItem tmpItem = { siBuffer, NULL, 0 };
SECItem emptyItem = { siBuffer, NULL, 0 };
CHECK_FAIL_ERR((!serialized || !serialized->data || serialized->len == 0),
SEC_ERROR_INVALID_ARGS);
CHECK_FAIL_ERR((serialized->len < EXPORTED_CTX_BASE_LEN), SEC_ERROR_BAD_DATA);
walker = serialized->data;
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;
walker = decodeNumber(&tmpn, walker, 2);
kdf = (HpkeKdfId)tmpn;
walker = decodeNumber(&tmpn, walker, 2);
aead = (HpkeAeadId)tmpn;
/* Create context. We'll manually set the mode, though we
* no longer have the PSK and have no need for it. */
cx = PK11_HPKE_NewContext(kem, kdf, aead, NULL, NULL);
CHECK_FAIL(!cx);
walker = decodeNumber(&tmpn, walker, 2);
CHECK_FAIL_ERR((tmpn != HpkeModeBase && tmpn != HpkeModePsk),
SEC_ERROR_BAD_DATA);
cx->mode = (HpkeModeId)tmpn;
walker = decodeNumber(&cx->sequenceNumber, walker, 8);
slot = PK11_GetBestSlot(CKM_HKDF_DERIVE, NULL);
CHECK_FAIL(!slot);
/* Import sender public key (serialized). */
walker = decodeNumber(&tmpn, walker, 2);
CHECK_FAIL_ERR(tmpn >= REMAINING_BYTES(walker, serialized),
SEC_ERROR_BAD_DATA);
tmpItem.data = walker;
tmpItem.len = tmpn;
cx->encapPubKey = SECITEM_DupItem(&tmpItem);
CHECK_FAIL(!cx->encapPubKey);
walker += tmpItem.len;
/* Import base_nonce. */
walker = decodeNumber(&tmpn, walker, 2);
CHECK_FAIL_ERR(tmpn != cx->aeadParams->Nn, SEC_ERROR_BAD_DATA);
CHECK_FAIL_ERR(tmpn >= REMAINING_BYTES(walker, serialized),
SEC_ERROR_BAD_DATA);
tmpItem.data = walker;
tmpItem.len = tmpn;
cx->baseNonce = SECITEM_DupItem(&tmpItem);
CHECK_FAIL(!cx->baseNonce);
walker += tmpItem.len;
/* Import key */
walker = decodeNumber(&tmpn, walker, 2);
CHECK_FAIL_ERR(tmpn >= REMAINING_BYTES(walker, serialized),
SEC_ERROR_BAD_DATA);
tmpItem.data = walker;
tmpItem.len = tmpn;
walker += tmpItem.len;
if (wrapKey) {
cx->key = PK11_UnwrapSymKey(wrapKey, CKM_AES_KEY_WRAP_KWP,
NULL, &tmpItem, cx->aeadParams->mech,
CKA_NSS_MESSAGE | CKA_DECRYPT, 0);
CHECK_FAIL(!cx->key);
} else {
CHECK_FAIL_ERR(tmpn != cx->aeadParams->Nk, SEC_ERROR_BAD_DATA);
tmpKey = PK11_ImportSymKey(slot, cx->aeadParams->mech,
PK11_OriginUnwrap, CKA_NSS_MESSAGE | CKA_DECRYPT,
&tmpItem, NULL);
CHECK_FAIL(!tmpKey);
cx->key = tmpKey;
}
/* Import exporter_secret. */
walker = decodeNumber(&tmpn, walker, 2);
CHECK_FAIL_ERR(tmpn != REMAINING_BYTES(walker, serialized),
SEC_ERROR_BAD_DATA);
tmpItem.data = walker;
tmpItem.len = tmpn;
walker += tmpItem.len;
if (wrapKey) {
cx->exporterSecret = PK11_UnwrapSymKey(wrapKey, CKM_AES_KEY_WRAP_KWP,
NULL, &tmpItem, cx->kdfParams->mech,
CKM_HKDF_DERIVE, 0);
CHECK_FAIL(!cx->exporterSecret);
} else {
CHECK_FAIL_ERR(tmpn != cx->kdfParams->Nh, SEC_ERROR_BAD_DATA);
tmpKey = PK11_ImportSymKey(slot, CKM_HKDF_DERIVE, PK11_OriginUnwrap,
CKA_DERIVE, &tmpItem, NULL);
CHECK_FAIL(!tmpKey);
cx->exporterSecret = tmpKey;
}
cx->aeadContext = PK11_CreateContextBySymKey(cx->aeadParams->mech,
CKA_NSS_MESSAGE | CKA_DECRYPT,
cx->key, &emptyItem);
CLEANUP:
if (rv != SECSuccess) {
PK11_FreeSymKey(tmpKey);
PK11_HPKE_DestroyContext(cx, PR_TRUE);
cx = NULL;
}
if (slot) {
PK11_FreeSlot(slot);
}
return cx;
}
SECStatus
PK11_HPKE_Serialize(const SECKEYPublicKey *pk, PRUint8 *buf, unsigned int *len, unsigned int maxLen)
{
@ -347,7 +622,7 @@ PK11_HPKE_Deserialize(const HpkeContext *cx, const PRUint8 *enc,
// Set parameters.
pubKey->u.ec.DEREncodedParams.data[0] = SEC_ASN1_OBJECT_ID;
pubKey->u.ec.DEREncodedParams.data[1] = oidData->oid.len;
memcpy(pubKey->u.ec.DEREncodedParams.data + 2, oidData->oid.data, oidData->oid.len);
PORT_Memcpy(pubKey->u.ec.DEREncodedParams.data + 2, oidData->oid.data, oidData->oid.len);
*outPubKey = pubKey;
CLEANUP:
@ -403,7 +678,7 @@ pk11_hpke_GenerateKeyPair(const HpkeContext *cx, SECKEYPublicKey **pkE,
ecp.type = siDEROID;
ecp.data[0] = SEC_ASN1_OBJECT_ID;
ecp.data[1] = oidData->oid.len;
memcpy(&ecp.data[2], oidData->oid.data, oidData->oid.len);
PORT_Memcpy(&ecp.data[2], oidData->oid.data, oidData->oid.len);
slot = PK11_GetBestSlot(CKM_EC_KEY_PAIR_GEN, NULL);
CHECK_FAIL(!slot);
@ -433,21 +708,21 @@ pk11_hpke_MakeExtractLabel(const char *prefix, unsigned int prefixLen,
const SECItem *suiteId, const SECItem *ikm)
{
SECItem *out = NULL;
size_t off = 0;
PRUint8 *walker;
out = SECITEM_AllocItem(NULL, NULL, prefixLen + labelLen + suiteId->len + (ikm ? ikm->len : 0));
if (!out) {
return NULL;
}
memcpy(&out->data[off], prefix, prefixLen);
off += prefixLen;
memcpy(&out->data[off], suiteId->data, suiteId->len);
off += suiteId->len;
memcpy(&out->data[off], label, labelLen);
off += labelLen;
walker = out->data;
PORT_Memcpy(walker, prefix, prefixLen);
walker += prefixLen;
PORT_Memcpy(walker, suiteId->data, suiteId->len);
walker += suiteId->len;
PORT_Memcpy(walker, label, labelLen);
walker += labelLen;
if (ikm && ikm->data) {
memcpy(&out->data[off], ikm->data, ikm->len);
off += ikm->len;
PORT_Memcpy(walker, ikm->data, ikm->len);
}
return out;
@ -474,7 +749,7 @@ pk11_hpke_LabeledExtractData(const HpkeContext *cx, SECItem *salt,
CHECK_FAIL(!labeledIkm);
params.bExtract = CK_TRUE;
params.bExpand = CK_FALSE;
params.prfHashMechanism = cx->kemParams->hashMech;
params.prfHashMechanism = cx->kdfParams->mech;
params.ulSaltType = salt ? CKF_HKDF_SALT_DATA : CKF_HKDF_SALT_NULL;
params.pSalt = salt ? (CK_BYTE_PTR)salt->data : NULL;
params.ulSaltLen = salt ? salt->len : 0;
@ -511,7 +786,7 @@ CLEANUP:
static SECStatus
pk11_hpke_LabeledExtract(const HpkeContext *cx, PK11SymKey *salt,
const SECItem *suiteId, const char *label,
const SECItem *suiteId, const char *label, CK_MECHANISM_TYPE hashMech,
unsigned int labelLen, PK11SymKey *ikm, PK11SymKey **out)
{
SECStatus rv = SECSuccess;
@ -537,7 +812,7 @@ pk11_hpke_LabeledExtract(const HpkeContext *cx, PK11SymKey *salt,
params.bExtract = CK_TRUE;
params.bExpand = CK_FALSE;
params.prfHashMechanism = cx->kemParams->hashMech;
params.prfHashMechanism = hashMech;
params.ulSaltType = salt ? CKF_HKDF_SALT_KEY : CKF_HKDF_SALT_NULL;
params.hSaltKey = salt ? PK11_GetSymKeyHandle(salt) : CK_INVALID_HANDLE;
@ -555,9 +830,10 @@ CLEANUP:
static SECStatus
pk11_hpke_LabeledExpand(const HpkeContext *cx, PK11SymKey *prk, const SECItem *suiteId,
const char *label, unsigned int labelLen, const SECItem *info,
unsigned int L, PK11SymKey **outKey, SECItem **outItem)
unsigned int L, CK_MECHANISM_TYPE hashMech, PK11SymKey **outKey,
SECItem **outItem)
{
SECStatus rv;
SECStatus rv = SECSuccess;
CK_MECHANISM_TYPE keyMech;
CK_MECHANISM_TYPE deriveMech;
CK_HKDF_PARAMS params = { 0 };
@ -567,34 +843,32 @@ pk11_hpke_LabeledExpand(const HpkeContext *cx, PK11SymKey *prk, const SECItem *s
sizeof(params) };
SECItem *derivedKeyData;
PRUint8 encodedL[2];
size_t off = 0;
PRUint8 *walker = encodedL;
size_t len;
PORT_Assert(cx && prk && label && (!!outKey != !!outItem));
rv = encodeShort(L, encodedL);
CHECK_RV(rv);
walker = encodeNumber(L, walker, 2);
len = info ? info->len : 0;
len += sizeof(encodedL) + strlen(DRAFT_LABEL) + suiteId->len + labelLen;
labeledInfoItem = SECITEM_AllocItem(NULL, NULL, len);
CHECK_FAIL(!labeledInfoItem);
memcpy(&labeledInfoItem->data[off], encodedL, sizeof(encodedL));
off += sizeof(encodedL);
memcpy(&labeledInfoItem->data[off], DRAFT_LABEL, strlen(DRAFT_LABEL));
off += strlen(DRAFT_LABEL);
memcpy(&labeledInfoItem->data[off], suiteId->data, suiteId->len);
off += suiteId->len;
memcpy(&labeledInfoItem->data[off], label, labelLen);
off += labelLen;
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, suiteId->data, suiteId->len);
walker += suiteId->len;
PORT_Memcpy(walker, label, labelLen);
walker += labelLen;
if (info) {
memcpy(&labeledInfoItem->data[off], info->data, info->len);
off += info->len;
PORT_Memcpy(walker, info->data, info->len);
}
params.bExtract = CK_FALSE;
params.bExpand = CK_TRUE;
params.prfHashMechanism = cx->kemParams->hashMech;
params.prfHashMechanism = hashMech;
params.ulSaltType = CKF_HKDF_SALT_NULL;
params.pInfo = labeledInfoItem->data;
params.ulInfoLen = labeledInfoItem->len;
@ -635,19 +909,22 @@ pk11_hpke_ExtractAndExpand(const HpkeContext *cx, PK11SymKey *ikm,
PK11SymKey *eaePrk = NULL;
PK11SymKey *sharedSecret = NULL;
PRUint8 suiteIdBuf[5];
PRUint8 *walker;
PORT_Memcpy(suiteIdBuf, KEM_LABEL, strlen(KEM_LABEL));
SECItem suiteIdItem = { siBuffer, suiteIdBuf, sizeof(suiteIdBuf) };
PORT_Assert(cx && ikm && kemContext && out);
rv = encodeShort(cx->kemParams->id, &suiteIdBuf[3]);
CHECK_RV(rv);
walker = &suiteIdBuf[3];
walker = encodeNumber(cx->kemParams->id, walker, 2);
rv = pk11_hpke_LabeledExtract(cx, NULL, &suiteIdItem, EAE_PRK_LABEL,
strlen(EAE_PRK_LABEL), ikm, &eaePrk);
cx->kemParams->hashMech, strlen(EAE_PRK_LABEL),
ikm, &eaePrk);
CHECK_RV(rv);
rv = pk11_hpke_LabeledExpand(cx, eaePrk, &suiteIdItem, SH_SEC_LABEL, strlen(SH_SEC_LABEL),
kemContext, cx->kemParams->Nsecret, &sharedSecret, NULL);
kemContext, cx->kemParams->Nsecret, cx->kemParams->hashMech,
&sharedSecret, NULL);
CHECK_RV(rv);
*out = sharedSecret;
@ -698,7 +975,7 @@ pk11_hpke_Encap(HpkeContext *cx, const SECKEYPublicKey *pkE, SECKEYPrivateKey *s
kemContext = SECITEM_AllocItem(NULL, NULL, cx->encapPubKey->len + tmpLen);
CHECK_FAIL(!kemContext);
memcpy(kemContext->data, cx->encapPubKey->data, cx->encapPubKey->len);
PORT_Memcpy(kemContext->data, cx->encapPubKey->data, cx->encapPubKey->len);
rv = PK11_HPKE_Serialize(pkR, &kemContext->data[cx->encapPubKey->len], &tmpLen, tmpLen);
CHECK_RV(rv);
@ -723,6 +1000,7 @@ PK11_HPKE_ExportSecret(const HpkeContext *cx, const SECItem *info, unsigned int
SECStatus rv;
PK11SymKey *exported;
PRUint8 suiteIdBuf[10];
PRUint8 *walker;
PORT_Memcpy(suiteIdBuf, HPKE_LABEL, strlen(HPKE_LABEL));
SECItem suiteIdItem = { siBuffer, suiteIdBuf, sizeof(suiteIdBuf) };
@ -733,15 +1011,14 @@ PK11_HPKE_ExportSecret(const HpkeContext *cx, const SECItem *info, unsigned int
return SECFailure;
}
rv = encodeShort(cx->kemParams->id, &suiteIdBuf[4]);
CHECK_RV(rv);
rv = encodeShort(cx->kdfParams->id, &suiteIdBuf[6]);
CHECK_RV(rv);
rv = encodeShort(cx->aeadParams->id, &suiteIdBuf[8]);
CHECK_RV(rv);
walker = &suiteIdBuf[4];
walker = encodeNumber(cx->kemParams->id, walker, 2);
walker = encodeNumber(cx->kdfParams->id, walker, 2);
walker = encodeNumber(cx->aeadParams->id, walker, 2);
rv = pk11_hpke_LabeledExpand(cx, cx->exporterSecret, &suiteIdItem, SEC_LABEL,
strlen(SEC_LABEL), info, L, &exported, NULL);
strlen(SEC_LABEL), info, L, cx->kdfParams->mech,
&exported, NULL);
CHECK_RV(rv);
*out = exported;
@ -785,12 +1062,18 @@ pk11_hpke_Decap(HpkeContext *cx, const SECKEYPublicKey *pkR, SECKEYPrivateKey *s
kemContext = SECITEM_AllocItem(NULL, NULL, encS->len + tmpLen);
CHECK_FAIL(!kemContext);
memcpy(kemContext->data, encS->data, encS->len);
PORT_Memcpy(kemContext->data, encS->data, encS->len);
rv = PK11_HPKE_Serialize(pkR, &kemContext->data[encS->len], &tmpLen,
kemContext->len - encS->len);
CHECK_RV(rv);
rv = pk11_hpke_ExtractAndExpand(cx, dh, kemContext, &cx->sharedSecret);
CHECK_RV(rv);
/* Store the sender serialized public key, which
* may be required by application use cases. */
cx->encapPubKey = SECITEM_DupItem(encS);
CHECK_FAIL(!cx->encapPubKey);
CLEANUP:
if (rv != SECSuccess) {
PK11_FreeSymKey(cx->sharedSecret);
@ -809,7 +1092,6 @@ PK11_HPKE_GetEncapPubKey(const HpkeContext *cx)
if (!cx) {
return NULL;
}
/* Will be NULL on receiver. */
return cx->encapPubKey;
}
@ -820,21 +1102,19 @@ pk11_hpke_KeySchedule(HpkeContext *cx, const SECItem *info)
SECItem contextItem = { siBuffer, NULL, 0 };
unsigned int len;
unsigned int off;
PK11SymKey *pskHash = NULL;
PK11SymKey *secret = NULL;
SECItem *pskIdHash = NULL;
SECItem *infoHash = NULL;
PRUint8 suiteIdBuf[10];
PRUint8 *walker;
PORT_Memcpy(suiteIdBuf, HPKE_LABEL, strlen(HPKE_LABEL));
SECItem suiteIdItem = { siBuffer, suiteIdBuf, sizeof(suiteIdBuf) };
PORT_Assert(cx && info && cx->psk && cx->pskId);
rv = encodeShort(cx->kemParams->id, &suiteIdBuf[4]);
CHECK_RV(rv);
rv = encodeShort(cx->kdfParams->id, &suiteIdBuf[6]);
CHECK_RV(rv);
rv = encodeShort(cx->aeadParams->id, &suiteIdBuf[8]);
CHECK_RV(rv);
walker = &suiteIdBuf[4];
walker = encodeNumber(cx->kemParams->id, walker, 2);
walker = encodeNumber(cx->kdfParams->id, walker, 2);
walker = encodeNumber(cx->aeadParams->id, walker, 2);
rv = pk11_hpke_LabeledExtractData(cx, NULL, &suiteIdItem, PSK_ID_LABEL,
strlen(PSK_ID_LABEL), cx->pskId, &pskIdHash);
@ -847,33 +1127,33 @@ pk11_hpke_KeySchedule(HpkeContext *cx, const SECItem *info)
len = sizeof(cx->mode) + pskIdHash->len + infoHash->len;
CHECK_FAIL(!SECITEM_AllocItem(NULL, &contextItem, len));
off = 0;
memcpy(&contextItem.data[off], &cx->mode, sizeof(cx->mode));
PORT_Memcpy(&contextItem.data[off], &cx->mode, sizeof(cx->mode));
off += sizeof(cx->mode);
memcpy(&contextItem.data[off], pskIdHash->data, pskIdHash->len);
PORT_Memcpy(&contextItem.data[off], pskIdHash->data, pskIdHash->len);
off += pskIdHash->len;
memcpy(&contextItem.data[off], infoHash->data, infoHash->len);
PORT_Memcpy(&contextItem.data[off], infoHash->data, infoHash->len);
off += infoHash->len;
// Compute the keys
rv = pk11_hpke_LabeledExtract(cx, NULL, &suiteIdItem, PSK_LABEL,
strlen(PSK_LABEL), cx->psk, &pskHash);
CHECK_RV(rv);
rv = pk11_hpke_LabeledExtract(cx, pskHash, &suiteIdItem, SECRET_LABEL,
strlen(SECRET_LABEL), cx->sharedSecret, &secret);
rv = pk11_hpke_LabeledExtract(cx, cx->sharedSecret, &suiteIdItem, SECRET_LABEL,
cx->kdfParams->mech, strlen(SECRET_LABEL),
cx->psk, &secret);
CHECK_RV(rv);
rv = pk11_hpke_LabeledExpand(cx, secret, &suiteIdItem, KEY_LABEL, strlen(KEY_LABEL),
&contextItem, cx->aeadParams->Nk, &cx->key, NULL);
&contextItem, cx->aeadParams->Nk, cx->kdfParams->mech,
&cx->key, NULL);
CHECK_RV(rv);
rv = pk11_hpke_LabeledExpand(cx, secret, &suiteIdItem, NONCE_LABEL, strlen(NONCE_LABEL),
&contextItem, cx->aeadParams->Nn, NULL, &cx->nonce);
&contextItem, cx->aeadParams->Nn, cx->kdfParams->mech,
NULL, &cx->baseNonce);
CHECK_RV(rv);
rv = pk11_hpke_LabeledExpand(cx, secret, &suiteIdItem, EXP_LABEL, strlen(EXP_LABEL),
&contextItem, cx->kdfParams->Nh, &cx->exporterSecret, NULL);
&contextItem, cx->kdfParams->Nh, cx->kdfParams->mech,
&cx->exporterSecret, NULL);
CHECK_RV(rv);
CLEANUP:
/* If !SECSuccess, callers will tear down the context. */
PK11_FreeSymKey(pskHash);
PK11_FreeSymKey(secret);
SECITEM_FreeItem(&contextItem, PR_FALSE);
SECITEM_FreeItem(infoHash, PR_TRUE);
@ -886,7 +1166,7 @@ PK11_HPKE_SetupR(HpkeContext *cx, const SECKEYPublicKey *pkR, SECKEYPrivateKey *
const SECItem *enc, const SECItem *info)
{
SECStatus rv;
SECItem nullParams = { siBuffer, NULL, 0 };
SECItem empty = { siBuffer, NULL, 0 };
CHECK_FAIL_ERR((!cx || !skR || !info || !enc || !enc->data || !enc->len),
SEC_ERROR_INVALID_ARGS);
@ -903,7 +1183,7 @@ PK11_HPKE_SetupR(HpkeContext *cx, const SECKEYPublicKey *pkR, SECKEYPrivateKey *
PORT_Assert(cx->key);
cx->aeadContext = PK11_CreateContextBySymKey(cx->aeadParams->mech,
CKA_NSS_MESSAGE | CKA_DECRYPT,
cx->key, &nullParams);
cx->key, &empty);
CHECK_FAIL_ERR((!cx->aeadContext), SEC_ERROR_LIBRARY_FAILURE);
CLEANUP:
@ -973,8 +1253,8 @@ PK11_HPKE_Seal(HpkeContext *cx, const SECItem *aad, const SECItem *pt,
unsigned char tagBuf[HASH_LENGTH_MAX];
size_t tagLen;
unsigned int fixedBits;
PORT_Assert(cx->nonce->len == sizeof(ivOut));
memcpy(ivOut, cx->nonce->data, cx->nonce->len);
PORT_Assert(cx->baseNonce->len == sizeof(ivOut));
PORT_Memcpy(ivOut, cx->baseNonce->data, cx->baseNonce->len);
/* aad may be NULL, PT may be zero-length but not NULL. */
if (!cx || !cx->aeadContext ||
@ -987,7 +1267,7 @@ PK11_HPKE_Seal(HpkeContext *cx, const SECItem *aad, const SECItem *pt,
tagLen = cx->aeadParams->tagLen;
maxOut = pt->len + tagLen;
fixedBits = (cx->nonce->len - 8) * 8;
fixedBits = (cx->baseNonce->len - 8) * 8;
ct = SECITEM_AllocItem(NULL, NULL, maxOut);
CHECK_FAIL(!ct);
@ -1003,7 +1283,7 @@ PK11_HPKE_Seal(HpkeContext *cx, const SECItem *aad, const SECItem *pt,
CHECK_FAIL_ERR((ct->len > maxOut - tagLen), SEC_ERROR_LIBRARY_FAILURE);
/* Append the tag to the ciphertext. */
memcpy(&ct->data[ct->len], tagBuf, tagLen);
PORT_Memcpy(&ct->data[ct->len], tagBuf, tagLen);
ct->len += tagLen;
*out = ct;
@ -1023,7 +1303,7 @@ static SECStatus
pk11_hpke_makeIv(HpkeContext *cx, PRUint8 *iv, size_t ivLen)
{
unsigned int counterLen = sizeof(cx->sequenceNumber);
PORT_Assert(cx->nonce->len == ivLen);
PORT_Assert(cx->baseNonce->len == ivLen);
PORT_Assert(counterLen == 8);
if (cx->sequenceNumber == PR_UINT64(0xffffffffffffffff)) {
/* Overflow */
@ -1031,9 +1311,9 @@ pk11_hpke_makeIv(HpkeContext *cx, PRUint8 *iv, size_t ivLen)
return SECFailure;
}
memcpy(iv, cx->nonce->data, cx->nonce->len);
PORT_Memcpy(iv, cx->baseNonce->data, cx->baseNonce->len);
for (size_t i = 0; i < counterLen; i++) {
iv[cx->nonce->len - 1 - i] ^=
iv[cx->baseNonce->len - 1 - i] ^=
PORT_GET_BYTE_BE(cx->sequenceNumber,
counterLen - 1 - i, counterLen);
}
@ -1082,4 +1362,5 @@ CLEANUP:
}
return rv;
}
#endif // NSS_ENABLE_DRAFT_HPKE

Просмотреть файл

@ -9,7 +9,7 @@
#include "seccomon.h"
#ifdef NSS_ENABLE_DRAFT_HPKE
#define HPKE_DRAFT_VERSION 5
#define HPKE_DRAFT_VERSION 7
#define CLEANUP \
PORT_Assert(rv == SECSuccess); \
@ -42,13 +42,15 @@ typedef enum {
HpkeModePsk = 1,
} HpkeModeId;
/* https://tools.ietf.org/html/draft-irtf-cfrg-hpke-05#section-7.1 */
/* https://tools.ietf.org/html/draft-irtf-cfrg-hpke-07#section-7.1 */
typedef enum {
HpkeDhKemX25519Sha256 = 0x20,
} HpkeKemId;
typedef enum {
HpkeKdfHkdfSha256 = 1,
HpkeKdfHkdfSha384 = 2,
HpkeKdfHkdfSha512 = 3,
} HpkeKdfId;
typedef enum {

Просмотреть файл

@ -728,7 +728,7 @@ CK_BBOOL PK11_HasAttributeSet(PK11SlotInfo *slot,
PRBool haslock /* must be set to PR_FALSE */);
/**********************************************************************
* Hybrid Public Key Encryption (draft-05)
* Hybrid Public Key Encryption (draft-07)
**********************************************************************/
/*
* NOTE: All HPKE functions will fail with SEC_ERROR_INVALID_ALGORITHM
@ -746,9 +746,28 @@ HpkeContext *PK11_HPKE_NewContext(HpkeKemId kemId, HpkeKdfId kdfId, HpkeAeadId a
SECStatus PK11_HPKE_Deserialize(const HpkeContext *cx, const PRUint8 *enc,
unsigned int encLen, SECKEYPublicKey **outPubKey);
void PK11_HPKE_DestroyContext(HpkeContext *cx, PRBool freeit);
const SECItem *PK11_HPKE_GetEncapPubKey(const HpkeContext *cx);
/* Serialize an initialized receiver context. This only retains the keys and
* associated information necessary to resume Export and Open operations after
* import. Serialization is currently supported for receiver contexts only.
* This is done for two reasons: 1) it avoids having to move the encryption
* sequence number outside of the token (or adding encryption context
* serialization support to softoken), and 2) we don't have to worry about IV
* reuse due to sequence number cloning.
*
* |wrapKey| is required when exporting in FIPS mode. If exported with a
* wrapping key, that same key must be provided to the import function,
* otherwise behavior is undefined.
*
* Even when exported with key wrap, HPKE expects the nonce to also be kept
* secret and that value is not protected by wrapKey. Applications are
* responsible for maintaining the confidentiality of the exported information.
*/
SECStatus PK11_HPKE_ExportContext(const HpkeContext *cx, PK11SymKey *wrapKey, SECItem **serialized);
SECStatus PK11_HPKE_ExportSecret(const HpkeContext *cx, const SECItem *info, unsigned int L,
PK11SymKey **outKey);
const SECItem *PK11_HPKE_GetEncapPubKey(const HpkeContext *cx);
HpkeContext *PK11_HPKE_ImportContext(const SECItem *serialized, PK11SymKey *wrapKey);
SECStatus PK11_HPKE_Open(HpkeContext *cx, const SECItem *aad, const SECItem *ct, SECItem **outPt);
SECStatus PK11_HPKE_Seal(HpkeContext *cx, const SECItem *aad, const SECItem *pt, SECItem **outCt);
SECStatus PK11_HPKE_Serialize(const SECKEYPublicKey *pk, PRUint8 *buf, unsigned int *len, unsigned int maxLen);

Просмотреть файл

@ -17,11 +17,11 @@
* The format of the version string should be
* "<major version>.<minor version>[.<patch level>[.<build number>]][ <ECC>][ <Beta>]"
*/
#define SOFTOKEN_VERSION "3.61" SOFTOKEN_ECC_STRING
#define SOFTOKEN_VERSION "3.62" SOFTOKEN_ECC_STRING " Beta"
#define SOFTOKEN_VMAJOR 3
#define SOFTOKEN_VMINOR 61
#define SOFTOKEN_VMINOR 62
#define SOFTOKEN_VPATCH 0
#define SOFTOKEN_VBUILD 0
#define SOFTOKEN_BETA PR_FALSE
#define SOFTOKEN_BETA PR_TRUE
#endif /* _SOFTKVER_H_ */

Просмотреть файл

@ -70,6 +70,9 @@ PRBool ssl_IsRsaPssSignatureScheme(SSLSignatureScheme scheme);
PRBool ssl_IsRsaeSignatureScheme(SSLSignatureScheme scheme);
PRBool ssl_IsRsaPkcs1SignatureScheme(SSLSignatureScheme scheme);
PRBool ssl_IsDsaSignatureScheme(SSLSignatureScheme scheme);
static SECStatus ssl3_UpdateDefaultHandshakeHashes(sslSocket *ss,
const unsigned char *b,
unsigned int l);
const PRUint8 ssl_hello_retry_random[] = {
0xCF, 0x21, 0xAD, 0x74, 0xE5, 0x9A, 0x61, 0x11,
@ -3848,11 +3851,18 @@ ssl3_InitHandshakeHashes(sslSocket *ss)
if (ss->ssl3.hs.hashType != handshake_hash_record &&
ss->ssl3.hs.messages.len > 0) {
if (ssl3_UpdateHandshakeHashes(ss, ss->ssl3.hs.messages.buf,
ss->ssl3.hs.messages.len) != SECSuccess) {
/* When doing ECH, ssl3_UpdateHandshakeHashes will store outer messages into
* the both the outer and inner transcripts. ssl3_UpdateDefaultHandshakeHashes
* uses only the default context (which is the outer when doing ECH). */
if (ssl3_UpdateDefaultHandshakeHashes(ss, ss->ssl3.hs.messages.buf,
ss->ssl3.hs.messages.len) != SECSuccess) {
return SECFailure;
}
sslBuffer_Clear(&ss->ssl3.hs.messages);
/* When doing ECH, deriving accept_confirmation requires all messages
* up to SH, then a synthetic SH. Don't free the buffers just yet. */
if (!ss->ssl3.hs.echHpkeCtx) {
sslBuffer_Clear(&ss->ssl3.hs.messages);
}
}
if (ss->ssl3.hs.shaEchInner &&
ss->ssl3.hs.echInnerMessages.len > 0) {
@ -3861,7 +3871,9 @@ ssl3_InitHandshakeHashes(sslSocket *ss)
ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE);
return SECFailure;
}
sslBuffer_Clear(&ss->ssl3.hs.echInnerMessages);
if (!ss->ssl3.hs.echHpkeCtx) {
sslBuffer_Clear(&ss->ssl3.hs.echInnerMessages);
}
}
return SECSuccess;
@ -3893,52 +3905,28 @@ ssl3_RestartHandshakeHashes(sslSocket *ss)
}
}
/* For TLS 1.3 EncryptedClientHello, add the provided buffer to the
* given hash context. This is only needed for the initial CH,
* after which ssl3_UpdateHandshakeHashes will update both contexts
* until ssl3_CoalesceEchHandshakeHashes. */
/* Add the provided bytes to the handshake hash context. When doing
* TLS 1.3 ECH, |target| may be provided to specify only the inner/outer
* transcript, else the input is added to both contexts. This happens
* only on the client. On the server, only the default context is used. */
SECStatus
ssl3_UpdateExplicitHandshakeTranscript(sslSocket *ss, const unsigned char *b,
unsigned int l, sslBuffer *target)
{
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
PORT_Assert(ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_3);
if (ss->sec.isServer) {
/* Only the client maintains two states at the outset. */
PORT_Assert(target != &ss->ssl3.hs.echInnerMessages);
}
return sslBuffer_Append(target, b, l);
}
static SECStatus
ssl3_UpdateOuterHandshakeHashes(sslSocket *ss, const unsigned char *b,
unsigned int l)
{
return ssl3_UpdateExplicitHandshakeTranscript(ss, b, l,
&ss->ssl3.hs.messages);
}
static SECStatus
ssl3_UpdateInnerHandshakeHashes(sslSocket *ss, const unsigned char *b,
unsigned int l)
{
return ssl3_UpdateExplicitHandshakeTranscript(ss, b, l,
&ss->ssl3.hs.echInnerMessages);
}
/*
* Handshake messages
*/
/* Called from ssl3_InitHandshakeHashes()
** ssl3_AppendHandshake()
** ssl3_HandleV2ClientHello()
** ssl3_HandleHandshakeMessage()
** Caller must hold the ssl3Handshake lock.
*/
SECStatus
ssl3_UpdateHandshakeHashes(sslSocket *ss, const unsigned char *b, unsigned int l)
ssl3_UpdateHandshakeHashesInt(sslSocket *ss, const unsigned char *b,
unsigned int l, sslBuffer *target)
{
SECStatus rv = SECSuccess;
PRBool explicit = (target != NULL);
PRBool appendToEchInner = !ss->sec.isServer &&
ss->ssl3.hs.echHpkeCtx &&
!explicit;
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
PORT_Assert(target != &ss->ssl3.hs.echInnerMessages ||
!ss->sec.isServer);
if (target == NULL) {
/* Default context. */
target = &ss->ssl3.hs.messages;
}
/* With TLS 1.3, and versions TLS.1.1 and older, we keep the hash(es)
* always up to date. However, we must initially buffer the handshake
* messages, until we know what to do.
@ -3950,15 +3938,14 @@ ssl3_UpdateHandshakeHashes(sslSocket *ss, const unsigned char *b, unsigned int l
* and never update the hash, because the hash function we must use for
* certificate_verify might be different from the hash function we use
* when signing other handshake hashes. */
if (ss->ssl3.hs.hashType == handshake_hash_unknown ||
ss->ssl3.hs.hashType == handshake_hash_record) {
rv = sslBuffer_Append(&ss->ssl3.hs.messages, b, l);
rv = sslBuffer_Append(target, b, l);
if (rv != SECSuccess) {
return SECFailure;
}
if (!ss->sec.isServer && ss->ssl3.hs.echHpkeCtx) {
return ssl3_UpdateInnerHandshakeHashes(ss, b, l);
if (appendToEchInner) {
return sslBuffer_Append(&ss->ssl3.hs.echInnerMessages, b, l);
}
return SECSuccess;
}
@ -3967,10 +3954,20 @@ ssl3_UpdateHandshakeHashes(sslSocket *ss, const unsigned char *b, unsigned int l
if (ss->ssl3.hs.hashType == handshake_hash_single) {
PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3);
rv = PK11_DigestOp(ss->ssl3.hs.sha, b, l);
if (rv != SECSuccess) {
ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE);
return rv;
if (target == &ss->ssl3.hs.messages) {
rv = PK11_DigestOp(ss->ssl3.hs.sha, b, l);
if (rv != SECSuccess) {
ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE);
return rv;
}
}
if (ss->ssl3.hs.shaEchInner &&
(target == &ss->ssl3.hs.echInnerMessages || !explicit)) {
rv = PK11_DigestOp(ss->ssl3.hs.shaEchInner, b, l);
if (rv != SECSuccess) {
ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE);
return rv;
}
}
} else if (ss->ssl3.hs.hashType == handshake_hash_combo) {
rv = PK11_DigestOp(ss->ssl3.hs.md5, b, l);
@ -3987,6 +3984,37 @@ ssl3_UpdateHandshakeHashes(sslSocket *ss, const unsigned char *b, unsigned int l
return rv;
}
static SECStatus
ssl3_UpdateDefaultHandshakeHashes(sslSocket *ss, const unsigned char *b,
unsigned int l)
{
return ssl3_UpdateHandshakeHashesInt(ss, b, l,
&ss->ssl3.hs.messages);
}
static SECStatus
ssl3_UpdateInnerHandshakeHashes(sslSocket *ss, const unsigned char *b,
unsigned int l)
{
return ssl3_UpdateHandshakeHashesInt(ss, b, l,
&ss->ssl3.hs.echInnerMessages);
}
/*
* Handshake messages
*/
/* Called from ssl3_InitHandshakeHashes()
** ssl3_AppendHandshake()
** ssl3_HandleV2ClientHello()
** ssl3_HandleHandshakeMessage()
** Caller must hold the ssl3Handshake lock.
*/
SECStatus
ssl3_UpdateHandshakeHashes(sslSocket *ss, const unsigned char *b, unsigned int l)
{
return ssl3_UpdateHandshakeHashesInt(ss, b, l, NULL);
}
SECStatus
ssl3_UpdatePostHandshakeHashes(sslSocket *ss, const unsigned char *b, unsigned int l)
{
@ -5513,7 +5541,7 @@ ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type)
if (rv != SECSuccess) {
goto loser; /* code set */
}
rv = ssl3_UpdateOuterHandshakeHashes(ss, chBuf.buf, chBuf.len);
rv = ssl3_UpdateDefaultHandshakeHashes(ss, chBuf.buf, chBuf.len);
if (rv != SECSuccess) {
goto loser; /* code set */
}
@ -7064,11 +7092,6 @@ ssl3_HandleServerHello(sslSocket *ss, PRUint8 *b, PRUint32 length)
return SECSuccess;
}
rv = tls13_MaybeHandleEchSignal(ss);
if (rv != SECSuccess) {
goto alert_loser;
}
rv = ssl3_HandleParsedExtensions(ss, ssl_hs_server_hello);
ssl3_DestroyRemoteExtensions(&ss->ssl3.hs.remoteExtensions);
if (rv != SECSuccess) {
@ -7082,7 +7105,7 @@ ssl3_HandleServerHello(sslSocket *ss, PRUint8 *b, PRUint32 length)
}
if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
rv = tls13_HandleServerHelloPart2(ss);
rv = tls13_HandleServerHelloPart2(ss, savedMsg, savedLength);
if (rv != SECSuccess) {
errCode = PORT_GetError();
goto loser;
@ -7093,6 +7116,7 @@ ssl3_HandleServerHello(sslSocket *ss, PRUint8 *b, PRUint32 length)
goto loser;
}
ss->ssl3.hs.preliminaryInfo |= ssl_preinfo_ech;
return SECSuccess;
alert_loser:
@ -8628,13 +8652,6 @@ ssl_GenerateServerRandom(sslSocket *ss)
return SECFailure;
}
if (ss->ssl3.hs.echAccepted) {
rv = tls13_WriteServerEchSignal(ss);
if (rv != SECSuccess) {
return SECFailure;
}
}
if (ss->version == ss->vrange.max) {
return SECSuccess;
}
@ -9775,6 +9792,15 @@ ssl_ConstructServerHello(sslSocket *ss, PRBool helloRetry,
}
}
if (!helloRetry && ssl3_ExtensionNegotiated(ss, ssl_tls13_ech_is_inner_xtn)) {
/* Signal ECH acceptance if we handled handled both CHOuter/CHInner (i.e.
* in shared mode), or if we received a CHInner in split/backend mode. */
if (ss->ssl3.hs.echAccepted || ss->opt.enableTls13BackendEch) {
return tls13_WriteServerEchSignal(ss, SSL_BUFFER_BASE(messageBuf),
SSL_BUFFER_LEN(messageBuf));
}
}
return SECSuccess;
}
@ -12284,7 +12310,7 @@ ssl_HashHandshakeMessageDefault(sslSocket *ss, SSLHandshakeType ct,
const PRUint8 *b, PRUint32 length)
{
return ssl_HashHandshakeMessageInt(ss, ct, ss->ssl3.hs.recvMessageSeq,
b, length, ssl3_UpdateOuterHandshakeHashes);
b, length, ssl3_UpdateDefaultHandshakeHashes);
}
SECStatus
ssl_HashHandshakeMessageEchInner(sslSocket *ss, SSLHandshakeType ct,
@ -13847,6 +13873,7 @@ ssl3_DestroySSL3Info(sslSocket *ss)
/* TLS 1.3 ECH state. */
PK11_HPKE_DestroyContext(ss->ssl3.hs.echHpkeCtx, PR_TRUE);
PORT_Free((void *)ss->ssl3.hs.echPublicName); /* CONST */
sslBuffer_Clear(&ss->ssl3.hs.greaseEchBuf);
}
/*

Просмотреть файл

@ -15,6 +15,7 @@
#include "sslimpl.h"
#include "sslproto.h"
#include "ssl3exthandle.h"
#include "tls13ech.h"
#include "tls13err.h"
#include "tls13exthandle.h"
#include "tls13subcerts.h"
@ -54,6 +55,7 @@ static const ssl3ExtensionHandler clientHelloHandlers[] = {
{ ssl_tls13_psk_key_exchange_modes_xtn, &tls13_ServerHandlePskModesXtn },
{ ssl_tls13_cookie_xtn, &tls13_ServerHandleCookieXtn },
{ ssl_tls13_post_handshake_auth_xtn, &tls13_ServerHandlePostHandshakeAuthXtn },
{ ssl_tls13_ech_is_inner_xtn, &tls13_ServerHandleEchIsInnerXtn },
{ ssl_record_size_limit_xtn, &ssl_HandleRecordSizeLimitXtn },
{ 0, NULL }
};
@ -1020,12 +1022,8 @@ ssl3_DestroyExtensionData(TLSExtensionData *xtnData)
PORT_Free(xtnData->advertised);
tls13_DestroyDelegatedCredential(xtnData->peerDelegCred);
/* ECH State */
SECITEM_FreeItem(&xtnData->innerCh, PR_FALSE);
SECITEM_FreeItem(&xtnData->echSenderPubKey, PR_FALSE);
SECITEM_FreeItem(&xtnData->echConfigId, PR_FALSE);
SECITEM_FreeItem(&xtnData->echRetryConfigs, PR_FALSE);
xtnData->echRetryConfigsValid = PR_FALSE;
tls13_DestroyEchXtnState(xtnData->ech);
xtnData->ech = NULL;
}
/* Free everything that has been allocated and then reset back to

Просмотреть файл

@ -131,13 +131,9 @@ struct TLSExtensionDataStr {
* rather through tls13_DestoryPskList(). */
sslPsk *selectedPsk;
/* ECH working state. */
SECItem innerCh; /* Server: "payload value of ClientECH. */
SECItem echSenderPubKey; /* Server: "enc value of ClientECH, required for CHInner decryption. */
SECItem echConfigId; /* Server: "config_id" value of ClientECH. */
PRUint32 echCipherSuite; /* Server: "cipher_suite" value of ClientECH. */
SECItem echRetryConfigs; /* Client: Retry_configs from ServerEncryptedCH. */
PRBool echRetryConfigsValid; /* Client: Permits retry_configs to be extracted. */
/* ECH working state. Non-null when a valid Encrypted Client Hello extension
* was received. */
sslEchXtnState *ech;
};
typedef struct TLSExtensionStr {

Просмотреть файл

@ -509,6 +509,14 @@ typedef SECStatus(PR_CALLBACK *SSLResumptionTokenCallback)(
SSL_EXPERIMENTAL_API("SSL_EnableTls13GreaseEch", \
(PRFileDesc * _fd, PRBool _enabled), (fd, enabled))
/* If |enabled|, a server receiving a Client Hello containing the ech_is_inner
* (and not encrypted_client_hello) extension will respond with the ECH
* acceptance signal. This signals the client to continue with the inner
* transcript rather than outer. */
#define SSL_EnableTls13BackendEch(fd, enabled) \
SSL_EXPERIMENTAL_API("SSL_EnableTls13BackendEch", \
(PRFileDesc * _fd, PRBool _enabled), (fd, enabled))
/* Called by the client after an initial ECH connection fails with
* SSL_ERROR_ECH_RETRY_WITH_ECH. Returns compatible ECHConfigs, which
* are configured via SetClientEchConfigs for an ECH retry attempt.

Просмотреть файл

@ -36,9 +36,9 @@
typedef struct sslSocketStr sslSocket;
typedef struct sslNamedGroupDefStr sslNamedGroupDef;
typedef struct sslEsniKeysStr sslEsniKeys;
typedef struct sslEchConfigStr sslEchConfig;
typedef struct sslEchConfigContentsStr sslEchConfigContents;
typedef struct sslEchXtnStateStr sslEchXtnState;
typedef struct sslPskStr sslPsk;
typedef struct sslDelegatedCredentialStr sslDelegatedCredential;
typedef struct sslEphemeralKeyPairStr sslEphemeralKeyPair;
@ -287,6 +287,7 @@ typedef struct sslOptionsStr {
unsigned int enableDtls13VersionCompat : 1;
unsigned int suppressEndOfEarlyData : 1;
unsigned int enableTls13GreaseEch : 1;
unsigned int enableTls13BackendEch : 1;
} sslOptions;
typedef enum { sslHandshakingUndetermined = 0,
@ -748,6 +749,7 @@ typedef struct SSL3HandshakeStateStr {
HpkeContext *echHpkeCtx; /* Client/Server: HPKE context for ECH. */
const char *echPublicName; /* Client: If rejected, the ECHConfig.publicName to
* use for certificate verification. */
sslBuffer greaseEchBuf; /* Client: Remember GREASE ECH, as advertised, for CH2 (HRR case). */
} SSL3HandshakeState;
@ -1122,8 +1124,9 @@ struct sslSocketStr {
SSLProtocolVariant protocolVariant;
/* TLS 1.3 Encrypted Client Hello. */
PRCList echConfigs; /* Client/server: Must not change while hs is in-progress. */
SECKEYPublicKey *echPubKey; /* Server: The ECH keypair used in HPKE setup */
PRCList echConfigs; /* Client/server: Must not change while hs
* is in-progress. */
SECKEYPublicKey *echPubKey; /* Server: The ECH keypair used in HPKE. */
SECKEYPrivateKey *echPrivKey; /* As above. */
/* Anti-replay for TLS 1.3 0-RTT. */
@ -1948,6 +1951,8 @@ SECStatus SSLExp_DestroyMaskingContext(SSLMaskingContext *ctx);
SECStatus SSLExp_EnableTls13GreaseEch(PRFileDesc *fd, PRBool enabled);
SECStatus SSLExp_EnableTls13BackendEch(PRFileDesc *fd, PRBool enabled);
SEC_END_PROTOS
#if defined(XP_UNIX) || defined(XP_OS2) || defined(XP_BEOS)

Просмотреть файл

@ -183,6 +183,7 @@ SSL_ResetHandshake(PRFileDesc *s, PRBool asServer)
PORT_Assert(ss->ssl3.hs.echPublicName);
PORT_Free((void *)ss->ssl3.hs.echPublicName); /* CONST */
ss->ssl3.hs.echPublicName = NULL;
sslBuffer_Clear(&ss->ssl3.hs.greaseEchBuf);
}
if (!ss->TCPconnected)

Просмотреть файл

@ -93,7 +93,8 @@ static sslOptions ssl_defaults = {
.enableV2CompatibleHello = PR_FALSE,
.enablePostHandshakeAuth = PR_FALSE,
.suppressEndOfEarlyData = PR_FALSE,
.enableTls13GreaseEch = PR_FALSE
.enableTls13GreaseEch = PR_FALSE,
.enableTls13BackendEch = PR_FALSE
};
/*
@ -4293,6 +4294,7 @@ struct {
EXP(DestroyAead),
EXP(DestroyMaskingContext),
EXP(DestroyResumptionTokenInfo),
EXP(EnableTls13BackendEch),
EXP(EnableTls13GreaseEch),
EXP(EncodeEchConfig),
EXP(GetCurrentEpoch),
@ -4371,6 +4373,17 @@ SSLExp_EnableTls13GreaseEch(PRFileDesc *fd, PRBool enabled)
return SECSuccess;
}
SECStatus
SSLExp_EnableTls13BackendEch(PRFileDesc *fd, PRBool enabled)
{
sslSocket *ss = ssl_FindSocket(fd);
if (!ss) {
return SECFailure;
}
ss->opt.enableTls13BackendEch = enabled;
return SECSuccess;
}
SECStatus
SSLExp_SetDtls13VersionWorkaround(PRFileDesc *fd, PRBool enabled)
{

Просмотреть файл

@ -545,8 +545,9 @@ typedef enum {
ssl_next_proto_nego_xtn = 13172, /* Deprecated. */
ssl_renegotiation_info_xtn = 0xff01,
ssl_tls13_short_header_xtn = 0xff03, /* Deprecated. */
ssl_tls13_ech_is_inner_xtn = 0xda09,
ssl_tls13_outer_extensions_xtn = 0xfd00,
ssl_tls13_encrypted_client_hello_xtn = 0xfe08,
ssl_tls13_encrypted_client_hello_xtn = 0xfe09,
ssl_tls13_encrypted_sni_xtn = 0xffce, /* Deprecated. */
} SSLExtensionType;

Просмотреть файл

@ -61,7 +61,7 @@ tls13_DeriveSecretWrap(sslSocket *ss, PK11SymKey *key,
const char *suffix,
const char *keylogLabel,
PK11SymKey **dest);
static SECStatus
SECStatus
tls13_DeriveSecret(sslSocket *ss, PK11SymKey *key,
const char *label,
unsigned int labelLen,
@ -1184,13 +1184,12 @@ tls13_DeriveEarlySecrets(sslSocket *ss)
}
static SECStatus
tls13_ComputeHandshakeSecrets(sslSocket *ss)
tls13_ComputeHandshakeSecret(sslSocket *ss)
{
SECStatus rv;
PK11SymKey *derivedSecret = NULL;
PK11SymKey *newSecret = NULL;
SSL_TRC(5, ("%d: TLS13[%d]: compute handshake secrets (%s)",
SSL_TRC(5, ("%d: TLS13[%d]: compute handshake secret (%s)",
SSL_GETPID(), ss->fd, SSL_ROLE(ss)));
/* If no PSK, generate the default early secret. */
@ -1205,7 +1204,7 @@ tls13_ComputeHandshakeSecrets(sslSocket *ss)
PORT_Assert(ss->ssl3.hs.currentSecret);
PORT_Assert(ss->ssl3.hs.dheSecret);
/* Expand before we extract. */
/* Derive-Secret(., "derived", "") */
rv = tls13_DeriveSecretNullHash(ss, ss->ssl3.hs.currentSecret,
kHkdfLabelDerivedSecret,
strlen(kHkdfLabelDerivedSecret),
@ -1215,18 +1214,32 @@ tls13_ComputeHandshakeSecrets(sslSocket *ss)
return rv;
}
/* HKDF-Extract(ECDHE, .) = Handshake Secret */
rv = tls13_HkdfExtract(derivedSecret, ss->ssl3.hs.dheSecret,
tls13_GetHash(ss), &newSecret);
PK11_FreeSymKey(derivedSecret);
if (rv != SECSuccess) {
LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE);
return rv;
}
PK11_FreeSymKey(ss->ssl3.hs.dheSecret);
ss->ssl3.hs.dheSecret = NULL;
PK11_FreeSymKey(ss->ssl3.hs.currentSecret);
ss->ssl3.hs.currentSecret = newSecret;
return SECSuccess;
}
static SECStatus
tls13_ComputeHandshakeSecrets(sslSocket *ss)
{
SECStatus rv;
PK11SymKey *derivedSecret = NULL;
PK11SymKey *newSecret = NULL;
PK11_FreeSymKey(ss->ssl3.hs.dheSecret);
ss->ssl3.hs.dheSecret = NULL;
SSL_TRC(5, ("%d: TLS13[%d]: compute handshake secrets (%s)",
SSL_GETPID(), ss->fd, SSL_ROLE(ss)));
/* Now compute |*HsTrafficSecret| */
rv = tls13_DeriveSecretWrap(ss, ss->ssl3.hs.currentSecret,
@ -1865,22 +1878,16 @@ tls13_HandleClientHelloPart2(sslSocket *ss,
PRINT_BUF(50, (ss, "Client sent cookie",
ss->xtnData.cookie.data, ss->xtnData.cookie.len));
rv = tls13_RecoverHashState(ss, ss->xtnData.cookie.data,
ss->xtnData.cookie.len,
&previousCipherSuite,
&previousGroup,
&previousEchOffered);
rv = tls13_HandleHrrCookie(ss, ss->xtnData.cookie.data,
ss->xtnData.cookie.len,
&previousCipherSuite,
&previousGroup,
&previousEchOffered,
NULL, NULL, NULL, NULL, PR_TRUE);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SSL_ERROR_BAD_2ND_CLIENT_HELLO, illegal_parameter);
goto loser;
}
/* CH1/CH2 must either both include ECH, or both exclude it. */
if ((ss->xtnData.echConfigId.len > 0) != previousEchOffered) {
FATAL_ERROR(ss, SSL_ERROR_BAD_2ND_CLIENT_HELLO,
illegal_parameter);
goto loser;
}
}
/* Now merge the ClientHello into the hash state. */
@ -1936,6 +1943,13 @@ tls13_HandleClientHelloPart2(sslSocket *ss,
goto loser;
}
/* CH1/CH2 must either both include ECH, or both exclude it. */
if (previousEchOffered != (ss->xtnData.ech != NULL)) {
FATAL_ERROR(ss, SSL_ERROR_BAD_2ND_CLIENT_HELLO,
previousEchOffered ? missing_extension : illegal_parameter);
goto loser;
}
/* If we requested a new key share, check that the client provided just
* one of the right type. */
if (previousGroup) {
@ -2825,6 +2839,11 @@ tls13_SendServerHelloSequence(sslSocket *ss)
return SECFailure;
}
rv = tls13_ComputeHandshakeSecret(ss);
if (rv != SECSuccess) {
return SECFailure; /* error code is set. */
}
rv = ssl3_SendServerHello(ss);
if (rv != SECSuccess) {
return rv; /* err code is set. */
@ -2909,7 +2928,7 @@ tls13_SendServerHelloSequence(sslSocket *ss)
}
SECStatus
tls13_HandleServerHelloPart2(sslSocket *ss)
tls13_HandleServerHelloPart2(sslSocket *ss, const PRUint8 *savedMsg, PRUint32 savedLength)
{
SECStatus rv;
sslSessionID *sid = ss->sec.ci.sid;
@ -2991,6 +3010,17 @@ tls13_HandleServerHelloPart2(sslSocket *ss)
if (rv != SECSuccess) {
return SECFailure;
}
rv = tls13_ComputeHandshakeSecret(ss);
if (rv != SECSuccess) {
return SECFailure; /* error code is set. */
}
rv = tls13_MaybeHandleEchSignal(ss, savedMsg, savedLength);
if (rv != SECSuccess) {
return SECFailure; /* error code is set. */
}
rv = tls13_ComputeHandshakeSecrets(ss);
if (rv != SECSuccess) {
return SECFailure; /* error code is set. */
@ -4960,15 +4990,16 @@ tls13_FinishHandshake(sslSocket *ss)
TLS13_SET_HS_STATE(ss, idle_handshake);
if (offeredEch &&
!ssl3_ExtensionNegotiated(ss, ssl_tls13_encrypted_client_hello_xtn)) {
PORT_Assert(ss->ssl3.hs.echAccepted ==
ssl3_ExtensionNegotiated(ss, ssl_tls13_encrypted_client_hello_xtn));
if (offeredEch && !ss->ssl3.hs.echAccepted) {
SSL3_SendAlert(ss, alert_fatal, ech_required);
/* "If [one, none] of the values contains a supported version, the client can
/* "If [one, none] of the retry_configs contains a supported version, the client can
* regard ECH as securely [replaced, disabled] by the server." */
if (ss->xtnData.echRetryConfigs.len) {
if (ss->xtnData.ech && ss->xtnData.ech->retryConfigs.len) {
PORT_SetError(SSL_ERROR_ECH_RETRY_WITH_ECH);
ss->xtnData.echRetryConfigsValid = PR_TRUE;
ss->xtnData.ech->retryConfigsValid = PR_TRUE;
} else {
PORT_SetError(SSL_ERROR_ECH_RETRY_WITHOUT_ECH);
}
@ -5520,6 +5551,7 @@ static const struct {
hello_retry_request) },
{ ssl_record_size_limit_xtn, _M2(client_hello, encrypted_extensions) },
{ ssl_tls13_encrypted_client_hello_xtn, _M2(client_hello, encrypted_extensions) },
{ ssl_tls13_ech_is_inner_xtn, _M1(client_hello) },
{ ssl_tls13_outer_extensions_xtn, _M_NONE /* Encoding/decoding only */ },
{ ssl_tls13_post_handshake_auth_xtn, _M1(client_hello) }
};

Просмотреть файл

@ -76,7 +76,7 @@ SECStatus tls13_HandleClientHelloPart2(sslSocket *ss,
sslSessionID *sid,
const PRUint8 *msg,
unsigned int len);
SECStatus tls13_HandleServerHelloPart2(sslSocket *ss);
SECStatus tls13_HandleServerHelloPart2(sslSocket *ss, const PRUint8 *savedMsg, PRUint32 savedLength);
SECStatus tls13_HandlePostHelloHandshakeMessage(sslSocket *ss, PRUint8 *b,
PRUint32 length);
SECStatus tls13_ConstructHelloRetryRequest(sslSocket *ss,

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -11,7 +11,7 @@
#include "pk11hpke.h"
/* draft-08, shared-mode only.
/* draft-09, supporting shared-mode and split-mode as a backend server only.
* Notes on the implementation status:
* - Padding (https://tools.ietf.org/html/draft-ietf-tls-esni-08#section-6.2),
* is not implemented (see bug 1677181).
@ -21,12 +21,10 @@
* - Some of the buffering (construction/compression/decompression) could likely
* be optimized, but the spec is still evolving so that work is deferred.
*/
#define TLS13_ECH_VERSION 0xfe08
#define TLS13_ECH_VERSION 0xfe09
#define TLS13_ECH_SIGNAL_LEN 8
static const char kHpkeInfoEch[] = "tls ech";
static const char kHpkeInfoEchHrr[] = "tls ech hrr key";
static const char kHpkeLabelHrrPsk[] = "hrr key";
static const char hHkdfInfoEchConfigID[] = "tls ech config id";
static const char kHkdfInfoEchConfirm[] = "ech accept confirmation";
@ -45,11 +43,23 @@ struct sslEchConfigContentsStr {
struct sslEchConfigStr {
PRCList link;
SECItem raw;
PRUint8 configId[32];
PRUint8 configId[8];
PRUint16 version;
sslEchConfigContents contents;
};
struct sslEchXtnStateStr {
SECItem innerCh; /* Server: ClientECH.payload */
SECItem senderPubKey; /* Server: ClientECH.enc */
SECItem configId; /* Server: ClientECH.config_id */
HpkeKdfId kdfId; /* Server: ClientECH.cipher_suite.kdf */
HpkeAeadId aeadId; /* Server: ClientECH.cipher_suite.aead */
SECItem retryConfigs; /* Client: ServerECH.retry_configs*/
PRBool retryConfigsValid; /* Client: Extraction of retry_configss is allowed.
* This is set once the handshake completes (having
* verified to the ECHConfig public name). */
};
SECStatus SSLExp_EncodeEchConfig(const char *publicName, const PRUint32 *hpkeSuites,
unsigned int hpkeSuiteCount, HpkeKemId kemId,
const SECKEYPublicKey *pubKey, PRUint16 maxNameLen,
@ -69,14 +79,15 @@ SECStatus tls13_ConstructClientHelloWithEch(sslSocket *ss, const sslSessionID *s
SECStatus tls13_CopyEchConfigs(PRCList *oconfigs, PRCList *configs);
SECStatus tls13_DecodeEchConfigs(const SECItem *data, PRCList *configs);
void tls13_DestroyEchConfigs(PRCList *list);
void tls13_DestroyEchXtnState(sslEchXtnState *state);
SECStatus tls13_GetMatchingEchConfig(const sslSocket *ss, HpkeKdfId kdf, HpkeAeadId aead,
const SECItem *configId, sslEchConfig **cfg);
SECStatus tls13_MaybeHandleEch(sslSocket *ss, const PRUint8 *msg, PRUint32 msgLen, SECItem *sidBytes,
SECItem *comps, SECItem *cookieBytes, SECItem *suites, SECItem **echInner);
SECStatus tls13_MaybeHandleEchSignal(sslSocket *ss);
SECStatus tls13_MaybeHandleEchSignal(sslSocket *ss, const PRUint8 *savedMsg, PRUint32 savedLength);
SECStatus tls13_MaybeAcceptEch(sslSocket *ss, const SECItem *sidBytes, const PRUint8 *chOuter,
unsigned int chOuterLen, SECItem **chInner);
SECStatus tls13_MaybeGreaseEch(sslSocket *ss, unsigned int prefixLen, sslBuffer *buf);
SECStatus tls13_WriteServerEchSignal(sslSocket *ss);
SECStatus tls13_WriteServerEchSignal(sslSocket *ss, PRUint8 *sh, unsigned int shLen);
#endif

Просмотреть файл

@ -1211,6 +1211,12 @@ tls13_ClientHandleEchXtn(const sslSocket *ss, TLSExtensionData *xtnData,
PRCList parsedConfigs;
PR_INIT_CLIST(&parsedConfigs);
PORT_Assert(!xtnData->ech);
xtnData->ech = PORT_ZNew(sslEchXtnState);
if (!xtnData->ech) {
return SECFailure;
}
/* Parse the list to determine 1) That the configs are valid
* and properly encoded, and 2) If any are compatible. */
rv = tls13_DecodeEchConfigs(data, &parsedConfigs);
@ -1219,11 +1225,11 @@ tls13_ClientHandleEchXtn(const sslSocket *ss, TLSExtensionData *xtnData,
PORT_SetError(SSL_ERROR_RX_MALFORMED_ECH_CONFIG);
return SECFailure;
}
/* Don't mark ECH negotiated on retry. Save the the raw
* configs so the application can retry. If we sent GREASE
* ECH (no echHpkeCtx), don't apply returned retry_configs. */
/* Don't mark ECH negotiated on rejection with retry_config.
* Save the the raw configs so the application can retry. If
* we sent GREASE ECH (no echHpkeCtx), don't apply retry_configs. */
if (ss->ssl3.hs.echHpkeCtx && !PR_CLIST_IS_EMPTY(&parsedConfigs)) {
rv = SECITEM_CopyItem(NULL, &xtnData->echRetryConfigs, data);
rv = SECITEM_CopyItem(NULL, &xtnData->ech->retryConfigs, data);
}
tls13_DestroyEchConfigs(&parsedConfigs);
@ -1465,14 +1471,22 @@ tls13_ServerHandleEchXtn(const sslSocket *ss, TLSExtensionData *xtnData,
return SECSuccess;
}
/* On CHInner, the extension must be empty. */
if (ss->ssl3.hs.echAccepted && data->len > 0) {
if (ss->ssl3.hs.echAccepted) {
ssl3_ExtSendAlert(ss, alert_fatal, illegal_parameter);
PORT_SetError(SSL_ERROR_RX_MALFORMED_ECH_EXTENSION);
PORT_SetError(SSL_ERROR_RX_UNEXPECTED_EXTENSION);
return SECFailure;
}
if (ssl3_FindExtension(CONST_CAST(sslSocket, ss), ssl_tls13_ech_is_inner_xtn)) {
ssl3_ExtSendAlert(ss, alert_fatal, illegal_parameter);
PORT_SetError(SSL_ERROR_RX_UNEXPECTED_EXTENSION);
return SECFailure;
}
PORT_Assert(!xtnData->ech);
xtnData->ech = PORT_ZNew(sslEchXtnState);
if (!xtnData->ech) {
return SECFailure;
} else if (ss->ssl3.hs.echAccepted) {
xtnData->negotiated[xtnData->numNegotiated++] = ssl_tls13_encrypted_client_hello_xtn;
return SECSuccess;
}
/* Parse the KDF and AEAD. */
@ -1503,37 +1517,40 @@ tls13_ServerHandleEchXtn(const sslSocket *ss, TLSExtensionData *xtnData,
goto alert_loser;
}
/* payload */
/* payload, which must be final and non-empty. */
rv = ssl3_ExtConsumeHandshakeVariable(ss, &encryptedCh, 2,
&data->data, &data->len);
if (rv != SECSuccess) {
goto alert_loser;
}
if (data->len) {
if (data->len || !encryptedCh.len) {
goto alert_loser;
}
/* All fields required. */
if (!configId.len || !senderPubKey.len || !encryptedCh.len) {
goto alert_loser;
if (!ss->ssl3.hs.helloRetry) {
/* In the real ECH HRR case, config_id and enc should be empty. This
* is checked after acceptance, because it might be GREASE ECH. */
if (!configId.len || !senderPubKey.len) {
goto alert_loser;
}
rv = SECITEM_CopyItem(NULL, &xtnData->ech->senderPubKey, &senderPubKey);
if (rv == SECFailure) {
return SECFailure;
}
rv = SECITEM_CopyItem(NULL, &xtnData->ech->configId, &configId);
if (rv == SECFailure) {
return SECFailure;
}
}
rv = SECITEM_CopyItem(NULL, &xtnData->echSenderPubKey, &senderPubKey);
rv = SECITEM_CopyItem(NULL, &xtnData->ech->innerCh, &encryptedCh);
if (rv == SECFailure) {
return SECFailure;
}
rv = SECITEM_CopyItem(NULL, &xtnData->innerCh, &encryptedCh);
if (rv == SECFailure) {
return SECFailure;
}
rv = SECITEM_CopyItem(NULL, &xtnData->echConfigId, &configId);
if (rv == SECFailure) {
return SECFailure;
}
xtnData->echCipherSuite = (aead & 0xFFFF) << 16 | (kdf & 0xFFFF);
xtnData->ech->kdfId = kdf;
xtnData->ech->aeadId = aead;
/* Not negotiated until tls13_MaybeAcceptEch. */
return SECSuccess;
@ -1543,3 +1560,36 @@ alert_loser:
PORT_SetError(SSL_ERROR_RX_MALFORMED_ECH_EXTENSION);
return SECFailure;
}
SECStatus
tls13_ServerHandleEchIsInnerXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
SECItem *data)
{
SSL_TRC(3, ("%d: TLS13[%d]: handle ech_is_inner extension",
SSL_GETPID(), ss->fd));
if (data->len) {
PORT_SetError(SSL_ERROR_RX_MALFORMED_ECH_EXTENSION);
return SECFailure;
}
if (ssl3_FindExtension(CONST_CAST(sslSocket, ss), ssl_tls13_encrypted_client_hello_xtn)) {
ssl3_ExtSendAlert(ss, alert_fatal, illegal_parameter);
PORT_SetError(SSL_ERROR_RX_UNEXPECTED_EXTENSION);
return SECFailure;
}
/* Consider encrypted_client_hello_xtn negotiated if we performed the
* CHOuter decryption. This is only supported in shared mode, so we'll also
* handle ech_is_inner in that case. We might, however, receive a CHInner
* that was forwarded by a different client-facing server. In this case,
* mark ech_is_inner as negotiated, which triggers sending of the ECH
* acceptance signal. ech_is_inner_xtn being negotiated does not imply
* that any other ECH state actually exists. */
if (ss->ssl3.hs.echAccepted) {
xtnData->negotiated[xtnData->numNegotiated++] = ssl_tls13_encrypted_client_hello_xtn;
}
xtnData->negotiated[xtnData->numNegotiated++] = ssl_tls13_ech_is_inner_xtn;
return SECSuccess;
}

Просмотреть файл

@ -94,6 +94,9 @@ SECStatus tls13_ServerSendEchXtn(const sslSocket *ss, TLSExtensionData *xtnData,
sslBuffer *buf, PRBool *added);
SECStatus tls13_ClientHandleEchXtn(const sslSocket *ss, TLSExtensionData *xtnData,
SECItem *data);
SECStatus tls13_ServerHandleEchIsInnerXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
SECItem *data);
SECStatus tls13_ClientSendPostHandshakeAuthXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
sslBuffer *buf, PRBool *added);

Просмотреть файл

@ -24,9 +24,11 @@
* uint8 indicator = 0xff; // To disambiguate from tickets.
* uint16 cipherSuite; // Selected cipher suite.
* uint16 keyShare; // Requested key share group (0=none)
* HpkeKdfId kdfId; // ECH KDF (uint16)
* HpkeAeadId aeadId; // ECH AEAD (uint16)
* opaque echConfigId<0..255>; // ECH config_id
* opaque echHpkeCtx<0..65535>; // ECH serialized HPKE context
* opaque applicationToken<0..65535>; // Application token
* echConfigId<0..255>; // Encrypted Client Hello config_id
* echHrrPsk<0..255>; // Encrypted Client Hello HRR PSK
* opaque ch_hash[rest_of_buffer]; // H(ClientHello)
* } CookieInner;
*
@ -43,10 +45,7 @@ tls13_MakeHrrCookie(sslSocket *ss, const sslNamedGroupDef *selectedGroup,
PRUint8 cookie[1024];
sslBuffer cookieBuf = SSL_BUFFER(cookie);
static const PRUint8 indicator = 0xff;
SECItem hrrNonceInfoItem = { siBuffer, (unsigned char *)kHpkeInfoEchHrr,
strlen(kHpkeInfoEchHrr) };
PK11SymKey *echHrrPsk = NULL;
SECItem *rawEchPsk = NULL;
SECItem *echHpkeCtx = NULL;
/* Encode header. */
rv = sslBuffer_Append(&cookieBuf, &indicator, 1);
@ -63,54 +62,53 @@ tls13_MakeHrrCookie(sslSocket *ss, const sslNamedGroupDef *selectedGroup,
return SECFailure;
}
if (ss->xtnData.ech) {
rv = sslBuffer_AppendNumber(&cookieBuf, ss->xtnData.ech->kdfId, 2);
if (rv != SECSuccess) {
return SECFailure;
}
rv = sslBuffer_AppendNumber(&cookieBuf, ss->xtnData.ech->aeadId, 2);
if (rv != SECSuccess) {
return SECFailure;
}
/* Received ECH config_id, regardless of acceptance or possession
* of a matching ECHConfig. */
PORT_Assert(ss->xtnData.ech->configId.len == 8);
rv = sslBuffer_AppendVariable(&cookieBuf, ss->xtnData.ech->configId.data,
ss->xtnData.ech->configId.len, 1);
if (rv != SECSuccess) {
return SECFailure;
}
/* There might be no HPKE Context, e.g. when we lack a matching ECHConfig. */
if (ss->ssl3.hs.echHpkeCtx) {
rv = PK11_HPKE_ExportContext(ss->ssl3.hs.echHpkeCtx, NULL, &echHpkeCtx);
if (rv != SECSuccess) {
return SECFailure;
}
rv = sslBuffer_AppendVariable(&cookieBuf, echHpkeCtx->data, echHpkeCtx->len, 2);
SECITEM_ZfreeItem(echHpkeCtx, PR_TRUE);
} else {
/* Zero length HPKE context. */
rv = sslBuffer_AppendNumber(&cookieBuf, 0, 2);
}
if (rv != SECSuccess) {
return SECFailure;
}
} else {
rv = sslBuffer_AppendNumber(&cookieBuf, 0, 7);
if (rv != SECSuccess) {
return SECFailure;
}
}
/* Application token. */
rv = sslBuffer_AppendVariable(&cookieBuf, appToken, appTokenLen, 2);
if (rv != SECSuccess) {
return SECFailure;
}
/* Received ECH config_id, regardless of acceptance or possession
* of a matching ECHConfig. If rejecting ECH, this is essentially a boolean
* indicating that ECH was offered in CH1. If accepting ECH, this config_id
* will be used for the ECH decryption in CH2. */
if (ss->xtnData.echConfigId.len) {
rv = sslBuffer_AppendVariable(&cookieBuf, ss->xtnData.echConfigId.data,
ss->xtnData.echConfigId.len, 1);
} else {
PORT_Assert(!ssl3_FindExtension(ss, ssl_tls13_encrypted_client_hello_xtn));
rv = sslBuffer_AppendNumber(&cookieBuf, 0, 1);
}
if (rv != SECSuccess) {
return SECFailure;
}
/* Extract and encode the ech-hrr-key, if ECH was accepted
* (i.e. an Open() succeeded. */
if (ss->ssl3.hs.echAccepted) {
rv = PK11_HPKE_ExportSecret(ss->ssl3.hs.echHpkeCtx, &hrrNonceInfoItem, 32, &echHrrPsk);
if (rv != SECSuccess) {
return SECFailure;
}
rv = PK11_ExtractKeyValue(echHrrPsk);
if (rv != SECSuccess) {
PK11_FreeSymKey(echHrrPsk);
return SECFailure;
}
rawEchPsk = PK11_GetKeyData(echHrrPsk);
if (!rawEchPsk) {
PK11_FreeSymKey(echHrrPsk);
return SECFailure;
}
rv = sslBuffer_AppendVariable(&cookieBuf, rawEchPsk->data, rawEchPsk->len, 1);
PK11_FreeSymKey(echHrrPsk);
} else {
/* Zero length ech_hrr_key. */
rv = sslBuffer_AppendNumber(&cookieBuf, 0, 1);
}
if (rv != SECSuccess) {
return SECFailure;
}
/* Compute and encode hashes. */
rv = tls13_ComputeHandshakeHashes(ss, &hashes);
if (rv != SECSuccess) {
@ -131,23 +129,34 @@ tls13_MakeHrrCookie(sslSocket *ss, const sslNamedGroupDef *selectedGroup,
return SECSuccess;
}
/* Recover the hash state from the cookie. */
/* Given a cookie and cookieLen, decrypt and parse, returning
* any values that were requested via the "previous_" params. If
* recoverHashState is true, the transcript state is recovered */
SECStatus
tls13_RecoverHashState(sslSocket *ss,
unsigned char *cookie, unsigned int cookieLen,
ssl3CipherSuite *previousCipherSuite,
const sslNamedGroupDef **previousGroup,
PRBool *previousEchOffered)
tls13_HandleHrrCookie(sslSocket *ss,
unsigned char *cookie, unsigned int cookieLen,
ssl3CipherSuite *previousCipherSuite,
const sslNamedGroupDef **previousGroup,
PRBool *previousEchOffered,
HpkeKdfId *previousEchKdfId,
HpkeAeadId *previousEchAeadId,
SECItem *previousEchConfigId,
HpkeContext **previousEchHpkeCtx,
PRBool recoverHashState)
{
SECStatus rv;
unsigned char plaintext[1024];
unsigned int plaintextLen = 0;
sslBuffer messageBuf = SSL_BUFFER_EMPTY;
sslReadBuffer echPskBuf;
sslReadBuffer echConfigIdBuf;
sslReadBuffer echHpkeBuf = { 0 };
sslReadBuffer echConfigIdBuf = { 0 };
PRUint64 sentinel;
PRUint64 cipherSuite;
HpkeContext *hpkeContext = NULL;
HpkeKdfId echKdfId;
HpkeAeadId echAeadId;
PRUint64 group;
PRUint64 tmp64;
const sslNamedGroupDef *selectedGroup;
PRUint64 appTokenLen;
@ -180,6 +189,33 @@ tls13_RecoverHashState(sslSocket *ss,
}
selectedGroup = ssl_LookupNamedGroup(group);
/* ECH Ciphersuite */
rv = sslRead_ReadNumber(&reader, 2, &tmp64);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
return SECFailure;
}
echKdfId = (HpkeKdfId)tmp64;
rv = sslRead_ReadNumber(&reader, 2, &tmp64);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
return SECFailure;
}
echAeadId = (HpkeAeadId)tmp64;
/* ECH Config ID and HPKE context may be empty. */
rv = sslRead_ReadVariable(&reader, 1, &echConfigIdBuf);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
return SECFailure;
}
rv = sslRead_ReadVariable(&reader, 2, &echHpkeBuf);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
return SECFailure;
}
/* Application token. */
PORT_Assert(ss->xtnData.applicationToken.len == 0);
rv = sslRead_ReadNumber(&reader, 2, &appTokenLen);
@ -202,55 +238,80 @@ tls13_RecoverHashState(sslSocket *ss,
PORT_Assert(appTokenReader.len == appTokenLen);
PORT_Memcpy(ss->xtnData.applicationToken.data, appTokenReader.buf, appTokenLen);
/* ECH Config ID, which may be empty. */
rv = sslRead_ReadVariable(&reader, 1, &echConfigIdBuf);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
return SECFailure;
}
/* ECH HRR PSK, if present, is already used by tls13_GetEchInfoFromCookie */
rv = sslRead_ReadVariable(&reader, 1, &echPskBuf);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
return SECFailure;
}
/* The remainder is the hash. */
unsigned int hashLen = SSL_READER_REMAINING(&reader);
if (hashLen != tls13_GetHashSize(ss)) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
return SECFailure;
if (recoverHashState) {
unsigned int hashLen = SSL_READER_REMAINING(&reader);
if (hashLen != tls13_GetHashSize(ss)) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
return SECFailure;
}
/* Now reinject the message. */
SSL_ASSERT_HASHES_EMPTY(ss);
rv = ssl_HashHandshakeMessageInt(ss, ssl_hs_message_hash, 0,
SSL_READER_CURRENT(&reader), hashLen,
ssl3_UpdateHandshakeHashes);
if (rv != SECSuccess) {
return SECFailure;
}
/* And finally reinject the HRR. */
rv = tls13_ConstructHelloRetryRequest(ss, cipherSuite,
selectedGroup,
cookie, cookieLen,
&messageBuf);
if (rv != SECSuccess) {
return SECFailure;
}
rv = ssl_HashHandshakeMessageInt(ss, ssl_hs_server_hello, 0,
SSL_BUFFER_BASE(&messageBuf),
SSL_BUFFER_LEN(&messageBuf),
ssl3_UpdateHandshakeHashes);
sslBuffer_Clear(&messageBuf);
if (rv != SECSuccess) {
return SECFailure;
}
}
/* Now reinject the message. */
SSL_ASSERT_HASHES_EMPTY(ss);
rv = ssl_HashHandshakeMessageInt(ss, ssl_hs_message_hash, 0,
SSL_READER_CURRENT(&reader), hashLen,
ssl3_UpdateHandshakeHashes);
if (rv != SECSuccess) {
return SECFailure;
if (previousEchHpkeCtx && echHpkeBuf.len) {
const SECItem hpkeItem = { siBuffer, CONST_CAST(unsigned char, echHpkeBuf.buf),
echHpkeBuf.len };
hpkeContext = PK11_HPKE_ImportContext(&hpkeItem, NULL);
if (!hpkeContext) {
FATAL_ERROR(ss, PORT_GetError(), internal_error);
return SECFailure;
}
}
/* And finally reinject the HRR. */
rv = tls13_ConstructHelloRetryRequest(ss, cipherSuite,
selectedGroup,
cookie, cookieLen,
&messageBuf);
if (rv != SECSuccess) {
return SECFailure;
if (previousEchConfigId && echConfigIdBuf.len) {
SECItem tmp = { siBuffer, NULL, 0 };
rv = SECITEM_MakeItem(NULL, &tmp, echConfigIdBuf.buf, echConfigIdBuf.len);
if (rv != SECSuccess) {
PK11_HPKE_DestroyContext(hpkeContext, PR_TRUE);
FATAL_ERROR(ss, PORT_GetError(), internal_error);
return SECFailure;
}
*previousEchConfigId = tmp;
}
rv = ssl_HashHandshakeMessageInt(ss, ssl_hs_server_hello, 0,
SSL_BUFFER_BASE(&messageBuf),
SSL_BUFFER_LEN(&messageBuf),
ssl3_UpdateHandshakeHashes);
sslBuffer_Clear(&messageBuf);
if (rv != SECSuccess) {
return SECFailure;
if (previousEchKdfId) {
*previousEchKdfId = echKdfId;
}
if (previousEchAeadId) {
*previousEchAeadId = echAeadId;
}
if (previousEchHpkeCtx) {
*previousEchHpkeCtx = hpkeContext;
}
if (previousCipherSuite) {
*previousCipherSuite = cipherSuite;
}
if (previousGroup) {
*previousGroup = selectedGroup;
}
if (previousEchOffered) {
*previousEchOffered = echConfigIdBuf.len > 0;
}
*previousCipherSuite = cipherSuite;
*previousGroup = selectedGroup;
*previousEchOffered = echConfigIdBuf.len > 0;
return SECSuccess;
}

Просмотреть файл

@ -17,9 +17,14 @@ SECStatus tls13_MakeHrrCookie(sslSocket *ss, const sslNamedGroupDef *selectedGro
const PRUint8 *appToken, unsigned int appTokenLen,
PRUint8 *buf, unsigned int *len, unsigned int maxlen);
SECStatus tls13_GetHrrCookieLength(sslSocket *ss, unsigned int *length);
SECStatus tls13_RecoverHashState(sslSocket *ss,
unsigned char *cookie, unsigned int cookieLen,
ssl3CipherSuite *previousCipherSuite,
const sslNamedGroupDef **previousGroup,
PRBool *previousEchOffered);
SECStatus tls13_HandleHrrCookie(sslSocket *ss,
unsigned char *cookie, unsigned int cookieLen,
ssl3CipherSuite *previousCipherSuite,
const sslNamedGroupDef **previousGroup,
PRBool *previousEchOffered,
HpkeKdfId *previousEchKdfId,
HpkeAeadId *previousEchAeadId,
SECItem *previousEchConfigId,
HpkeContext **previousEchHpkeCtx,
PRBool recoverHashState);
#endif

Просмотреть файл

@ -19,12 +19,12 @@
* The format of the version string should be
* "<major version>.<minor version>[.<patch level>[.<build number>]][ <Beta>]"
*/
#define NSSUTIL_VERSION "3.61"
#define NSSUTIL_VERSION "3.62 Beta"
#define NSSUTIL_VMAJOR 3
#define NSSUTIL_VMINOR 61
#define NSSUTIL_VMINOR 62
#define NSSUTIL_VPATCH 0
#define NSSUTIL_VBUILD 0
#define NSSUTIL_BETA PR_FALSE
#define NSSUTIL_BETA PR_TRUE
SEC_BEGIN_PROTOS

Просмотреть файл

@ -159,12 +159,20 @@ verify NameConstraints.dcissblocked:x
verify NameConstraints.dcissallowed:x
result pass
# Subject: "O = IPA.LOCAL 201901211552, CN = OCSP Subsystem"
# Subject: "O = IPA.LOCAL 20200120, CN = OCSP and IPSEC"
# EKUs: OCSPSigning,ipsecUser
#
# This tests that a non server certificate (i.e. id-kp-serverAuth
# not present in EKU) does *NOT* have CN treated as dnsName for
# purposes of Name Constraints validation
# purposes of Name Constraints validation (certificateUsageStatusResponder)
# https://hg.mozilla.org/projects/nss/rev/0b30eb1c3650
verify NameConstraints.ocsp1:x
usage 10
result pass
# This tests that a non server certificate (i.e. id-kp-serverAuth
# not present in EKU) does *NOT* have CN treated as dnsName for
# purposes of Name Constraints validation (certificateUsageIPsec)
verify NameConstraints.ocsp1:x
usage 12
result pass

Двоичный файл не отображается.

Двоичный файл не отображается.