summaryrefslogtreecommitdiff
path: root/lib/ssl/tls13hashstate.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ssl/tls13hashstate.c')
-rw-r--r--lib/ssl/tls13hashstate.c241
1 files changed, 151 insertions, 90 deletions
diff --git a/lib/ssl/tls13hashstate.c b/lib/ssl/tls13hashstate.c
index 011b4838e..f2f55ba0f 100644
--- a/lib/ssl/tls13hashstate.c
+++ b/lib/ssl/tls13hashstate.c
@@ -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,50 +62,49 @@ tls13_MakeHrrCookie(sslSocket *ss, const sslNamedGroupDef *selectedGroup,
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 (ss->xtnData.ech) {
+ rv = sslBuffer_AppendNumber(&cookieBuf, ss->xtnData.ech->kdfId, 2);
if (rv != SECSuccess) {
return SECFailure;
}
- rv = PK11_ExtractKeyValue(echHrrPsk);
+ rv = sslBuffer_AppendNumber(&cookieBuf, ss->xtnData.ech->aeadId, 2);
if (rv != SECSuccess) {
- PK11_FreeSymKey(echHrrPsk);
return SECFailure;
}
- rawEchPsk = PK11_GetKeyData(echHrrPsk);
- if (!rawEchPsk) {
- PK11_FreeSymKey(echHrrPsk);
+
+ /* 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;
}
- rv = sslBuffer_AppendVariable(&cookieBuf, rawEchPsk->data, rawEchPsk->len, 1);
- PK11_FreeSymKey(echHrrPsk);
} else {
- /* Zero length ech_hrr_key. */
- rv = sslBuffer_AppendNumber(&cookieBuf, 0, 1);
+ 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;
}
@@ -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,77 +189,129 @@ tls13_RecoverHashState(sslSocket *ss,
}
selectedGroup = ssl_LookupNamedGroup(group);
- /* Application token. */
- PORT_Assert(ss->xtnData.applicationToken.len == 0);
- rv = sslRead_ReadNumber(&reader, 2, &appTokenLen);
+ /* ECH Ciphersuite */
+ rv = sslRead_ReadNumber(&reader, 2, &tmp64);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
return SECFailure;
}
- if (SECITEM_AllocItem(NULL, &ss->xtnData.applicationToken,
- appTokenLen) == NULL) {
- FATAL_ERROR(ss, PORT_GetError(), internal_error);
- return SECFailure;
- }
- ss->xtnData.applicationToken.len = appTokenLen;
- sslReadBuffer appTokenReader = { 0 };
- rv = sslRead_Read(&reader, appTokenLen, &appTokenReader);
+ 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;
}
- PORT_Assert(appTokenReader.len == appTokenLen);
- PORT_Memcpy(ss->xtnData.applicationToken.data, appTokenReader.buf, appTokenLen);
+ echAeadId = (HpkeAeadId)tmp64;
- /* ECH Config ID, which may be empty. */
+ /* 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;
}
- /* ECH HRR PSK, if present, is already used by tls13_GetEchInfoFromCookie */
- rv = sslRead_ReadVariable(&reader, 1, &echPskBuf);
+ rv = sslRead_ReadVariable(&reader, 2, &echHpkeBuf);
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)) {
+ /* Application token. */
+ PORT_Assert(ss->xtnData.applicationToken.len == 0);
+ rv = sslRead_ReadNumber(&reader, 2, &appTokenLen);
+ if (rv != SECSuccess) {
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) {
+ if (SECITEM_AllocItem(NULL, &ss->xtnData.applicationToken,
+ appTokenLen) == NULL) {
+ FATAL_ERROR(ss, PORT_GetError(), internal_error);
return SECFailure;
}
-
- /* And finally reinject the HRR. */
- rv = tls13_ConstructHelloRetryRequest(ss, cipherSuite,
- selectedGroup,
- cookie, cookieLen,
- &messageBuf);
+ ss->xtnData.applicationToken.len = appTokenLen;
+ sslReadBuffer appTokenReader = { 0 };
+ rv = sslRead_Read(&reader, appTokenLen, &appTokenReader);
if (rv != SECSuccess) {
+ FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
return SECFailure;
}
+ PORT_Assert(appTokenReader.len == appTokenLen);
+ PORT_Memcpy(ss->xtnData.applicationToken.data, appTokenReader.buf, appTokenLen);
- 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;
+ /* The remainder is the hash. */
+ 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;
+ }
+ }
+
+ 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;
+ }
}
- *previousCipherSuite = cipherSuite;
- *previousGroup = selectedGroup;
- *previousEchOffered = echConfigIdBuf.len > 0;
+ 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;
+ }
+
+ 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;
+ }
return SECSuccess;
}