diff options
Diffstat (limited to 'lib/ssl/tls13hashstate.c')
-rw-r--r-- | lib/ssl/tls13hashstate.c | 241 |
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; } |