From 4c1e6ff0d8911b11b607eabcafb9f2b52888481c Mon Sep 17 00:00:00 2001 From: Leander Schwarz Date: Wed, 15 Feb 2023 10:45:12 +0000 Subject: Bug 1570615: TLS GREASE (RFC8701) r=djackson Differential Revision: https://phabricator.services.mozilla.com/D161806 --- lib/ssl/ssl.h | 27 ++++++++ lib/ssl/ssl3con.c | 53 +++++++++++++-- lib/ssl/ssl3ecc.c | 14 ++++ lib/ssl/ssl3ext.c | 19 +++++- lib/ssl/ssl3exthandle.c | 28 +++++++- lib/ssl/sslimpl.h | 26 +++++++- lib/ssl/sslsecur.c | 2 + lib/ssl/sslsock.c | 5 ++ lib/ssl/sslt.h | 2 + lib/ssl/tls13con.c | 166 ++++++++++++++++++++++++++++++++++++++++++++--- lib/ssl/tls13con.h | 6 ++ lib/ssl/tls13ech.c | 17 ++++- lib/ssl/tls13exthandle.c | 82 ++++++++++++++++++++++- lib/ssl/tls13exthandle.h | 6 ++ 14 files changed, 428 insertions(+), 25 deletions(-) (limited to 'lib') diff --git a/lib/ssl/ssl.h b/lib/ssl/ssl.h index 8b6aab20b..d2e92b170 100644 --- a/lib/ssl/ssl.h +++ b/lib/ssl/ssl.h @@ -346,6 +346,33 @@ SSL_IMPORT PRFileDesc *DTLS_ImportFD(PRFileDesc *model, PRFileDesc *fd); */ #define SSL_SUPPRESS_END_OF_EARLY_DATA 41 +/* Enables TLS GREASE (specified in RFC8701, following Chrome 55 implementation + * decisions). + * + * If enabled and the client's ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_3 or + * the server's ss->version >= SSL_LIBRARY_VERSION_TLS_1_3, this adds random + * GREASE values to: + * - ClientHello (Client): + * - A cipher_suite value to the cipher_suites field. + * - An empty and a 1B zeroed payload extension. + * - A named group value to the supported_groups extension and a + * KeyShareEntry value for the added named group. + * - A signature algorithm value to the signature_algorithms extension. + * - A version value to the supported_versions extension. + * - A PskKeyExchangeMode value to the psk_key_exchange_modes extension. + * - A alpn value to the application_layer_protocol_negotiation extension. + * + * - CertificateRequest (Server): + * - An empty extension. + * - A signature algorithm value to the signature_algorithms extension. + * + * - NewSessionTicket (Server): + * - An empty extension. + * + * GREASE values MUST nerver be negotiated but ignored. + */ +#define SSL_ENABLE_GREASE 42 + #ifdef SSL_DEPRECATED_FUNCTION /* Old deprecated function names */ SSL_IMPORT SECStatus SSL_Enable(PRFileDesc *fd, int option, PRIntn on); diff --git a/lib/ssl/ssl3con.c b/lib/ssl/ssl3con.c index 8e418a458..982d8587b 100644 --- a/lib/ssl/ssl3con.c +++ b/lib/ssl/ssl3con.c @@ -5099,6 +5099,18 @@ ssl3_AppendCipherSuites(sslSocket *ss, PRBool fallbackSCSV, sslBuffer *buf) } } } + + /* GREASE CipherSuites: + * A client MAY select one or more GREASE cipher suite values and advertise + * them in the "cipher_suites" field [RFC8701, Section 3.1]. */ + if (ss->opt.enableGrease && ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_3) { + rv = sslBuffer_AppendNumber(buf, ss->ssl3.hs.grease->idx[grease_cipher], + sizeof(ssl3CipherSuite)); + if (rv != SECSuccess) { + return SECFailure; + } + } + if (SSL_ALL_VERSIONS_DISABLED(&ss->vrange) || (SSL_BUFFER_LEN(buf) - saveLen) == 0) { PORT_SetError(SSL_ERROR_SSL_DISABLED); @@ -10200,7 +10212,7 @@ ssl3_SendServerKeyExchange(sslSocket *ss) SECStatus ssl3_EncodeSigAlgs(const sslSocket *ss, PRUint16 minVersion, PRBool forCert, - sslBuffer *buf) + PRBool grease, sslBuffer *buf) { SSLSignatureScheme filtered[MAX_SIGNATURE_SCHEMES] = { 0 }; unsigned int filteredCount = 0; @@ -10211,12 +10223,12 @@ ssl3_EncodeSigAlgs(const sslSocket *ss, PRUint16 minVersion, PRBool forCert, if (rv != SECSuccess) { return SECFailure; } - return ssl3_EncodeFilteredSigAlgs(ss, filtered, filteredCount, buf); + return ssl3_EncodeFilteredSigAlgs(ss, filtered, filteredCount, grease, buf); } SECStatus ssl3_EncodeFilteredSigAlgs(const sslSocket *ss, const SSLSignatureScheme *schemes, - PRUint32 numSchemes, sslBuffer *buf) + PRUint32 numSchemes, PRBool grease, sslBuffer *buf) { if (!numSchemes) { PORT_SetError(SSL_ERROR_NO_SUPPORTED_SIGNATURE_ALGORITHM); @@ -10237,6 +10249,35 @@ ssl3_EncodeFilteredSigAlgs(const sslSocket *ss, const SSLSignatureScheme *scheme return SECFailure; } } + + /* GREASE SignatureAlgorithms: + * A client MAY select one or more GREASE signature algorithm values and + * advertise them in the "signature_algorithms" or + * "signature_algorithms_cert" extensions, if sent [RFC8701, Section 3.1]. + * + * When sending a CertificateRequest in TLS 1.3, a server MAY behave as + * follows: [...] A server MAY select one or more GREASE signature + * algorithm values and advertise them in the "signature_algorithms" or + * "signature_algorithms_cert" extensions, if present + * [RFC8701, Section 4.1]. */ + if (grease && + ((!ss->sec.isServer && ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_3) || + (ss->sec.isServer && ss->version >= SSL_LIBRARY_VERSION_TLS_1_3))) { + PRUint16 value; + if (ss->sec.isServer) { + rv = tls13_RandomGreaseValue(&value); + if (rv != SECSuccess) { + return SECFailure; + } + } else { + value = ss->ssl3.hs.grease->idx[grease_sigalg]; + } + rv = sslBuffer_AppendNumber(buf, value, 2); + if (rv != SECSuccess) { + return SECFailure; + } + } + return sslBuffer_InsertLength(buf, lengthOffset, 2); } @@ -10328,7 +10369,8 @@ ssl3_SendCertificateRequest(sslSocket *ss) length = 1 + certTypesLength + 2 + calen; if (isTLS12) { - rv = ssl3_EncodeSigAlgs(ss, ss->version, PR_TRUE /* forCert */, &sigAlgsBuf); + rv = ssl3_EncodeSigAlgs(ss, ss->version, PR_TRUE /* forCert */, + PR_FALSE /* GREASE */, &sigAlgsBuf); if (rv != SECSuccess) { return rv; } @@ -14089,6 +14131,9 @@ ssl3_DestroySSL3Info(sslSocket *ss) PK11_HPKE_DestroyContext(ss->ssl3.hs.echHpkeCtx, PR_TRUE); PORT_Free((void *)ss->ssl3.hs.echPublicName); /* CONST */ sslBuffer_Clear(&ss->ssl3.hs.greaseEchBuf); + + /* TLS 1.3 GREASE (client) state. */ + tls13_ClientGreaseDestroy(ss); } /* check if the current cipher spec is FIPS. We only need to diff --git a/lib/ssl/ssl3ecc.c b/lib/ssl/ssl3ecc.c index d5ad372e5..168ec59bf 100644 --- a/lib/ssl/ssl3ecc.c +++ b/lib/ssl/ssl3ecc.c @@ -906,6 +906,20 @@ ssl_SendSupportedGroupsXtn(const sslSocket *ss, TLSExtensionData *xtnData, } } + /* GREASE SupportedGroups: + * A client MAY select one or more GREASE named group values and advertise + * them in the "supported_groups" extension, if sent [RFC8701, Section 3.1]. + */ + if (!ss->sec.isServer && + ss->opt.enableGrease && + ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_3) { + rv = sslBuffer_AppendNumber(buf, ss->ssl3.hs.grease->idx[grease_group], 2); + if (rv != SECSuccess) { + return SECFailure; + } + found = PR_TRUE; + } + if (!found) { /* We added nothing, don't send the extension. */ return SECSuccess; diff --git a/lib/ssl/ssl3ext.c b/lib/ssl/ssl3ext.c index afb9d3dfb..04731115f 100644 --- a/lib/ssl/ssl3ext.c +++ b/lib/ssl/ssl3ext.c @@ -123,6 +123,8 @@ static const ssl3ExtensionHandler certificateRequestHandlers[] = { * extension, if it were listed last). See bug 1243641. */ static const sslExtensionBuilder clientHelloSendersTLS[] = { + /* TLS 1.3 GREASE extensions - empty. */ + { ssl_tls13_grease_xtn, &tls13_SendEmptyGreaseXtn }, { ssl_server_name_xtn, &ssl3_ClientSendServerNameXtn }, { ssl_extended_master_secret_xtn, &ssl3_SendExtendedMasterSecretXtn }, { ssl_renegotiation_info_xtn, &ssl3_SendRenegotiationInfoXtn }, @@ -146,6 +148,8 @@ static const sslExtensionBuilder clientHelloSendersTLS[] = { { ssl_tls13_psk_key_exchange_modes_xtn, &tls13_ClientSendPskModesXtn }, { ssl_tls13_post_handshake_auth_xtn, &tls13_ClientSendPostHandshakeAuthXtn }, { ssl_record_size_limit_xtn, &ssl_SendRecordSizeLimitXtn }, + /* TLS 1.3 GREASE extensions - 1 zero byte. */ + { ssl_tls13_grease_xtn, &tls13_SendGreaseXtn }, /* The pre_shared_key extension MUST be last. */ { ssl_tls13_pre_shared_key_xtn, &tls13_ClientSendPreSharedKeyXtn }, { 0, NULL } @@ -159,6 +163,8 @@ static const sslExtensionBuilder clientHelloSendersSSL3[] = { static const sslExtensionBuilder tls13_cert_req_senders[] = { { ssl_signature_algorithms_xtn, &ssl3_SendSigAlgsXtn }, { ssl_tls13_certificate_authorities_xtn, &tls13_SendCertAuthoritiesXtn }, + /* TLS 1.3 GREASE extension. */ + { ssl_tls13_grease_xtn, &tls13_SendEmptyGreaseXtn }, { 0, NULL } }; @@ -791,6 +797,7 @@ ssl_ConstructExtensions(sslSocket *ss, sslBuffer *buf, SSLHandshakeType message) } for (; sender->ex_sender != NULL; ++sender) { + PRUint16 ex_type = sender->ex_type; PRBool append = PR_FALSE; unsigned int start = buf->len; unsigned int length; @@ -814,8 +821,14 @@ ssl_ConstructExtensions(sslSocket *ss, sslBuffer *buf, SSLHandshakeType message) continue; } - buf->len = start; - rv = sslBuffer_AppendNumber(buf, sender->ex_type, 2); + /* If TLS 1.3 GREASE is enabled, replace ssl_tls13_grease_xtn dummy + * GREASE extension types with randomly generated GREASE value. */ + rv = tls13_MaybeGreaseExtensionType(ss, message, &ex_type); + if (rv != SECSuccess) { + goto loser; /* Code already set. */ + } + + rv = sslBuffer_AppendNumber(buf, ex_type, 2); if (rv != SECSuccess) { goto loser; /* Code already set. */ } @@ -829,7 +842,7 @@ ssl_ConstructExtensions(sslSocket *ss, sslBuffer *buf, SSLHandshakeType message) if (message == ssl_hs_client_hello || message == ssl_hs_certificate_request) { ss->xtnData.advertised[ss->xtnData.numAdvertised++] = - sender->ex_type; + ex_type; } } diff --git a/lib/ssl/ssl3exthandle.c b/lib/ssl/ssl3exthandle.c index 7134447bf..9dd4fba51 100644 --- a/lib/ssl/ssl3exthandle.c +++ b/lib/ssl/ssl3exthandle.c @@ -464,7 +464,10 @@ ssl3_ClientSendAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, } if (len > 0) { - /* Each protocol string is prefixed with a single byte length. */ + /* Each protocol string is prefixed with a single byte length. + * + * The comment correctly states that this should be a 1 byte length, + * see bug 1804688! */ rv = sslBuffer_AppendNumber(buf, len, 2); if (rv != SECSuccess) { return SECFailure; @@ -475,6 +478,26 @@ ssl3_ClientSendAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, } } + /* GREASE ALPN: + * A client MAY select one or more GREASE ALPN identifiers and advertise + * them in the "application_layer_protocol_negotiation" extension, if sent + * [RFC8701, Section 3.1]. */ + if (ss->opt.enableGrease && ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_3) { + /* Each protocol string is prefixed with a single byte length. + * + * The comment correctly states that this should be a 1 byte length, + * see bug 1804688! We send a GREASE extension with incorrect length + * field for consistency with (incorrect) non-GREASE extensions. */ + rv = sslBuffer_AppendNumber(buf, 2, 2); + if (rv != SECSuccess) { + return SECFailure; + } + rv = sslBuffer_AppendNumber(buf, ss->ssl3.hs.grease->idx[grease_alpn], 2); + if (rv != SECSuccess) { + return SECFailure; + } + } + *added = PR_TRUE; return SECSuccess; } @@ -1648,7 +1671,8 @@ ssl3_SendSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData, minVersion = ss->vrange.min; /* ClientHello */ } - SECStatus rv = ssl3_EncodeSigAlgs(ss, minVersion, PR_TRUE /* forCert */, buf); + SECStatus rv = ssl3_EncodeSigAlgs(ss, minVersion, PR_TRUE /* forCert */, + ss->opt.enableGrease, buf); if (rv != SECSuccess) { return SECFailure; } diff --git a/lib/ssl/sslimpl.h b/lib/ssl/sslimpl.h index af61823c1..64c657788 100644 --- a/lib/ssl/sslimpl.h +++ b/lib/ssl/sslimpl.h @@ -290,6 +290,7 @@ typedef struct sslOptionsStr { unsigned int enableTls13GreaseEch : 1; unsigned int enableTls13BackendEch : 1; unsigned int callExtensionWriterOnEchInner : 1; + unsigned int enableGrease : 1; } sslOptions; typedef enum { sslHandshakingUndetermined = 0, @@ -610,6 +611,24 @@ typedef struct { PRUint32 timeout; } dtlsTimer; +/* TLS 1.3 client GREASE entry indices. */ +typedef enum { + grease_cipher, + grease_extension1, + grease_extension2, + grease_group, + grease_sigalg, + grease_version, + grease_alpn, + grease_entries +} tls13ClientGreaseEntry; + +/* TLS 1.3 client GREASE values struct. */ +typedef struct tls13ClientGreaseStr { + PRUint16 idx[grease_entries]; + PRUint8 pskKem; +} tls13ClientGrease; + /* ** This is the "hs" member of the "ssl3" struct. ** This entire struct is protected by ssl3HandshakeLock @@ -762,6 +781,9 @@ typedef struct SSL3HandshakeStateStr { sslBuffer greaseEchBuf; /* Client: Remember GREASE ECH, as advertised, for CH2 (HRR case). Server: Remember HRR Grease Value, for transcript calculations */ PRBool echInvalidExtension; /* Client: True if the server offered an invalid extension for the ClientHelloInner */ + + /* TLS 1.3 GREASE state. */ + tls13ClientGrease *grease; } SSL3HandshakeState; #define SSL_ASSERT_HASHES_EMPTY(ss) \ @@ -1740,10 +1762,10 @@ SECStatus ssl3_AuthCertificate(sslSocket *ss); SECStatus ssl_ReadCertificateStatus(sslSocket *ss, PRUint8 *b, PRUint32 length); SECStatus ssl3_EncodeSigAlgs(const sslSocket *ss, PRUint16 minVersion, PRBool forCert, - sslBuffer *buf); + PRBool grease, sslBuffer *buf); SECStatus ssl3_EncodeFilteredSigAlgs(const sslSocket *ss, const SSLSignatureScheme *schemes, - PRUint32 numSchemes, sslBuffer *buf); + PRUint32 numSchemes, PRBool grease, sslBuffer *buf); SECStatus ssl3_FilterSigAlgs(const sslSocket *ss, PRUint16 minVersion, PRBool disableRsae, PRBool forCert, unsigned int maxSchemes, SSLSignatureScheme *filteredSchemes, unsigned int *numFilteredSchemes); diff --git a/lib/ssl/sslsecur.c b/lib/ssl/sslsecur.c index e1f53108c..37affd36a 100644 --- a/lib/ssl/sslsecur.c +++ b/lib/ssl/sslsecur.c @@ -217,6 +217,8 @@ SSL_ResetHandshake(PRFileDesc *s, PRBool asServer) sslBuffer_Clear(&ss->ssl3.hs.greaseEchBuf); } + tls13_ClientGreaseDestroy(ss); + if (!ss->TCPconnected) ss->TCPconnected = (PR_SUCCESS == ssl_DefGetpeername(ss, &addr)); diff --git a/lib/ssl/sslsock.c b/lib/ssl/sslsock.c index 4843b990e..3d1603d92 100644 --- a/lib/ssl/sslsock.c +++ b/lib/ssl/sslsock.c @@ -96,6 +96,7 @@ static sslOptions ssl_defaults = { .enableTls13GreaseEch = PR_FALSE, .enableTls13BackendEch = PR_FALSE, .callExtensionWriterOnEchInner = PR_FALSE, + .enableGrease = PR_FALSE, }; /* @@ -891,6 +892,10 @@ SSL_OptionSet(PRFileDesc *fd, PRInt32 which, PRIntn val) ss->opt.suppressEndOfEarlyData = val; break; + case SSL_ENABLE_GREASE: + ss->opt.enableGrease = val; + break; + default: PORT_SetError(SEC_ERROR_INVALID_ARGS); rv = SECFailure; diff --git a/lib/ssl/sslt.h b/lib/ssl/sslt.h index 95f4d744a..d12b3c91f 100644 --- a/lib/ssl/sslt.h +++ b/lib/ssl/sslt.h @@ -551,6 +551,8 @@ typedef enum { ssl_tls13_post_handshake_auth_xtn = 49, ssl_signature_algorithms_cert_xtn = 50, ssl_tls13_key_share_xtn = 51, + /* TLS 1.3 GREASE extension dummy type for builders. */ + ssl_tls13_grease_xtn = 0x0a0a, ssl_next_proto_nego_xtn = 13172, /* Deprecated. */ ssl_renegotiation_info_xtn = 0xff01, ssl_tls13_short_header_xtn = 0xff03, /* Deprecated. */ diff --git a/lib/ssl/tls13con.c b/lib/ssl/tls13con.c index 4cfb6c360..144731982 100644 --- a/lib/ssl/tls13con.c +++ b/lib/ssl/tls13con.c @@ -454,6 +454,11 @@ tls13_SetupClientHello(sslSocket *ss, sslClientHelloType chType) return SECSuccess; } + rv = tls13_ClientGreaseSetup(ss); + if (rv != SECSuccess) { + return SECFailure; + } + /* Select the first enabled group. * TODO(ekr@rtfm.com): be smarter about offering the group * that the other side negotiated if we are resuming. */ @@ -1563,6 +1568,9 @@ tls13_NegotiateKeyExchange(sslSocket *ss, missing_extension); return SECFailure; } + /* Since the server insists on DHE to provide forward secracy, for + * every other PskKem value but DHE stateless resumption is disabled, + * this includes other specified and GREASE values. */ if (!memchr(ss->xtnData.psk_ke_modes.data, tls13_psk_dh_ke, ss->xtnData.psk_ke_modes.len)) { SSL_TRC(3, ("%d: TLS13[%d]: client offered PSK without DH", @@ -5294,6 +5302,7 @@ tls13_SendNewSessionTicket(sslSocket *ss, const PRUint8 *appToken, SECStatus rv; NewSessionTicket ticket = { 0 }; PRUint32 max_early_data_size_len = 0; + PRUint32 greaseLen = 0; PRUint8 ticketNonce[sizeof(ss->ssl3.hs.ticketNonce)]; sslBuffer ticketNonceBuf = SSL_BUFFER(ticketNonce); @@ -5307,6 +5316,10 @@ tls13_SendNewSessionTicket(sslSocket *ss, const PRUint8 *appToken, } ticket.ticket_lifetime_hint = ssl_ticket_lifetime; + if (ss->opt.enableGrease) { + greaseLen = 4; /* type + len + 0 (empty) */ + } + /* The ticket age obfuscator. */ rv = PK11_GenerateRandom((PRUint8 *)&ticket.ticket_age_add, sizeof(ticket.ticket_age_add)); @@ -5338,11 +5351,13 @@ tls13_SendNewSessionTicket(sslSocket *ss, const PRUint8 *appToken, goto loser; message_length = - 4 + /* lifetime */ - 4 + /* ticket_age_add */ - 1 + sizeof(ticketNonce) + /* ticket_nonce */ - 2 + max_early_data_size_len + /* max_early_data_size_len */ - 2 + /* ticket length */ + 4 + /* lifetime */ + 4 + /* ticket_age_add */ + 1 + sizeof(ticketNonce) + /* ticket_nonce */ + 2 + /* extensions lentgh */ + max_early_data_size_len + /* max_early_data_size extension length */ + greaseLen + /* GREASE extension length */ + 2 + /* ticket length */ ticket_data.len; rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_new_session_ticket, @@ -5370,11 +5385,33 @@ tls13_SendNewSessionTicket(sslSocket *ss, const PRUint8 *appToken, if (rv != SECSuccess) goto loser; - /* Extensions. */ - rv = ssl3_AppendHandshakeNumber(ss, max_early_data_size_len, 2); + /* Extensions */ + rv = ssl3_AppendHandshakeNumber(ss, max_early_data_size_len + greaseLen, 2); if (rv != SECSuccess) goto loser; + /* GREASE NewSessionTicket: + * When sending a NewSessionTicket message in TLS 1.3, a server MAY select + * one or more GREASE extension values and advertise them as extensions + * with varying length and contents [RFC8701, SEction 4.1]. */ + if (ss->opt.enableGrease) { + PR_ASSERT(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3); + + PRUint16 grease; + rv = tls13_RandomGreaseValue(&grease); + if (rv != SECSuccess) + goto loser; + /* Extension type */ + rv = ssl3_AppendHandshakeNumber(ss, grease, 2); + if (rv != SECSuccess) + goto loser; + /* Extension length */ + rv = ssl3_AppendHandshakeNumber(ss, 0, 2); + if (rv != SECSuccess) + goto loser; + } + + /* Max early data size extension. */ if (max_early_data_size_len) { rv = ssl3_AppendHandshakeNumber( ss, ssl_tls13_early_data_xtn, 2); @@ -6415,4 +6452,117 @@ tls13_MaybeTls13(sslSocket *ss) } return PR_FALSE; -} \ No newline at end of file +} + +/* Setup random client GREASE values according to RFC8701. State must be kept + * so an equal ClientHello might be send on HelloRetryRequest. */ +SECStatus +tls13_ClientGreaseSetup(sslSocket *ss) +{ + if (!ss->opt.enableGrease) { + return SECSuccess; + } + + PORT_Assert(ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_3); + + if (ss->ssl3.hs.grease) { + return SECFailure; + } + ss->ssl3.hs.grease = PORT_Alloc(sizeof(tls13ClientGrease)); + if (!ss->ssl3.hs.grease) { + return SECFailure; + } + + tls13ClientGrease *grease = ss->ssl3.hs.grease; + /* We require eight GREASE values and randoms. */ + PRUint8 random[8]; + + /* Generate random GREASE values. */ + if (PK11_GenerateRandom(random, sizeof(random)) != SECSuccess) { + return SECFailure; + } + for (size_t i = 0; i < PR_ARRAY_SIZE(grease->idx); i++) { + random[i] = ((random[i] & 0xf0) | 0x0a); + grease->idx[i] = ((random[i] << 8) | random[i]); + } + /* Specific PskKeyExchangeMode GREASE value. */ + grease->pskKem = 0x0b + ((random[8 - 1] >> 5) * 0x1f); + + /* Duplicate extensions are not allowed. */ + if (grease->idx[grease_extension1] == grease->idx[grease_extension2]) { + grease->idx[grease_extension2] ^= 0x1010; + } + + return SECSuccess; +} + +/* Destroy client GREASE state. */ +void +tls13_ClientGreaseDestroy(sslSocket *ss) +{ + if (ss->ssl3.hs.grease) { + PORT_Free(ss->ssl3.hs.grease); + ss->ssl3.hs.grease = NULL; + } +} + +/* Generate a random GREASE value according to RFC8701. + * This function does not provide valid PskKeyExchangeMode GREASE values! */ +SECStatus +tls13_RandomGreaseValue(PRUint16 *out) +{ + PRUint8 random; + + if (PK11_GenerateRandom(&random, sizeof(random)) != SECSuccess) { + return SECFailure; + } + + random = ((random & 0xf0) | 0x0a); + *out = ((random << 8) | random); + + return SECSuccess; +} + +/* Set TLS 1.3 GREASE Extension random GREASE type. */ +SECStatus +tls13_MaybeGreaseExtensionType(const sslSocket *ss, + const SSLHandshakeType message, + PRUint16 *exType) +{ + if (*exType != ssl_tls13_grease_xtn) { + return SECSuccess; + } + + PR_ASSERT(ss->opt.enableGrease); + PR_ASSERT(message == ssl_hs_client_hello || + message == ssl_hs_certificate_request); + + /* GREASE ClientHello: + * A client MAY select one or more GREASE extension values and + * advertise them as extensions with varying length and contents + * [RFC8701, Section 3.1]. */ + if (message == ssl_hs_client_hello) { + PR_ASSERT(ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_3); + /* Check if the first GREASE extension was already added. */ + if (!ssl3_ExtensionAdvertised(ss, ss->ssl3.hs.grease->idx[grease_extension1])) { + *exType = ss->ssl3.hs.grease->idx[grease_extension1]; + } else { + *exType = ss->ssl3.hs.grease->idx[grease_extension2]; + } + } + /* GREASE CertificateRequest: + * When sending a CertificateRequest in TLS 1.3, a server MAY behave as + * follows: A server MAY select one or more GREASE extension values and + * advertise them as extensions with varying length and contents + * [RFC8701, Section 4.1]. */ + else if (message == ssl_hs_certificate_request) { + PR_ASSERT(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3); + /* Get random grease extension type. */ + SECStatus rv = tls13_RandomGreaseValue(exType); + if (rv != SECSuccess) { + return SECFailure; + } + } + + return SECSuccess; +} diff --git a/lib/ssl/tls13con.h b/lib/ssl/tls13con.h index a635dbd86..1e082d639 100644 --- a/lib/ssl/tls13con.h +++ b/lib/ssl/tls13con.h @@ -152,6 +152,12 @@ SECStatus tls13_AEAD(PK11Context *context, PRBool decrypt, const unsigned char *in, unsigned int inLen); void tls13_SetSpecRecordVersion(sslSocket *ss, ssl3CipherSpec *spec); SECStatus SSLExp_SendCertificateRequest(PRFileDesc *fd); +SECStatus tls13_ClientGreaseSetup(sslSocket *ss); +void tls13_ClientGreaseDestroy(sslSocket *ss); +SECStatus tls13_RandomGreaseValue(PRUint16 *out); +SECStatus tls13_MaybeGreaseExtensionType(const sslSocket *ss, + const SSLHandshakeType message, + PRUint16 *exType); /* Use this instead of FATAL_ERROR when no alert shall be sent. */ #define LOG_ERROR(ss, prError) \ diff --git a/lib/ssl/tls13ech.c b/lib/ssl/tls13ech.c index 7b485720c..9808a9fe2 100644 --- a/lib/ssl/tls13ech.c +++ b/lib/ssl/tls13ech.c @@ -1420,23 +1420,34 @@ tls13_ConstructInnerExtensionsFromOuter(sslSocket *ss, sslBuffer *chOuterXtnsBuf } break; case ssl_tls13_supported_versions_xtn: - /* Only TLS 1.3 on CHInner. */ + /* Only TLS 1.3 and GREASE on CHInner. */ rv = sslBuffer_AppendNumber(chInnerXtns, extensionType, 2); if (rv != SECSuccess) { goto loser; } - rv = sslBuffer_AppendNumber(chInnerXtns, 3, 2); + /* Extension length. */ + tmpLen = (ss->opt.enableGrease) ? 5 : 3; + rv = sslBuffer_AppendNumber(chInnerXtns, tmpLen, 2); if (rv != SECSuccess) { goto loser; } - rv = sslBuffer_AppendNumber(chInnerXtns, 2, 1); + /* ProtocolVersion length */ + rv = sslBuffer_AppendNumber(chInnerXtns, tmpLen - 1, 1); if (rv != SECSuccess) { goto loser; } + /* ProtocolVersion TLS 1.3 */ rv = sslBuffer_AppendNumber(chInnerXtns, SSL_LIBRARY_VERSION_TLS_1_3, 2); if (rv != SECSuccess) { goto loser; } + /* ProtocolVersion GREASE */ + if (ss->opt.enableGrease) { + rv = sslBuffer_AppendNumber(chInnerXtns, ss->ssl3.hs.grease->idx[grease_version], 2); + if (rv != SECSuccess) { + goto loser; + } + } /* Only update state on second invocation of this function */ if (shouldCompress) { ss->xtnData.echAdvertised[ss->xtnData.echNumAdvertised++] = extensionType; diff --git a/lib/ssl/tls13exthandle.c b/lib/ssl/tls13exthandle.c index 91f96b933..4d24b37d6 100644 --- a/lib/ssl/tls13exthandle.c +++ b/lib/ssl/tls13exthandle.c @@ -154,6 +154,29 @@ tls13_ClientSendKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, return SECFailure; } } + + /* GREASE KeyShareEntry: + * [The client] MAY also send KeyShareEntry values for a subset of those + * selected in the "key_share" extension. For each of these, the + * "key_exchange" field MAY be any value [RFC8701, Section 3.1]. + * + * By default we do not send KeyShares for every NamedGroup so the + * ServerKeyShare handshake message / additional round-trip is not + * triggered by sending GREASE KeyShareEntries. */ + if (ss->opt.enableGrease) { + rv = sslBuffer_AppendNumber(buf, ss->ssl3.hs.grease->idx[grease_group], 2); + if (rv != SECSuccess) + return rv; + /* Entry length */ + rv = sslBuffer_AppendNumber(buf, 2, 2); + if (rv != SECSuccess) + return rv; + /* Entry value */ + rv = sslBuffer_AppendNumber(buf, 0xCD, 2); + if (rv != SECSuccess) + return rv; + } + rv = sslBuffer_InsertLength(buf, lengthOffset, 2); if (rv != SECSuccess) { return SECFailure; @@ -877,6 +900,16 @@ tls13_ClientSendSupportedVersionsXtn(const sslSocket *ss, TLSExtensionData *xtnD } } + /* GREASE SupportedVersions: + * A client MAY select one or more GREASE version values and advertise them + * in the "supported_versions" extension, if sent [RFC8701, Section 3.1]. */ + if (ss->opt.enableGrease) { + rv = sslBuffer_AppendNumber(buf, ss->ssl3.hs.grease->idx[grease_version], 2); + if (rv != SECSuccess) { + return SECFailure; + } + } + rv = sslBuffer_InsertLength(buf, lengthOffset, 1); if (rv != SECSuccess) { return SECFailure; @@ -1045,7 +1078,6 @@ SECStatus tls13_ClientSendPskModesXtn(const sslSocket *ss, TLSExtensionData *xtnData, sslBuffer *buf, PRBool *added) { - static const PRUint8 ke_modes[] = { tls13_psk_dh_ke }; SECStatus rv; if (ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_3 || @@ -1056,7 +1088,15 @@ tls13_ClientSendPskModesXtn(const sslSocket *ss, TLSExtensionData *xtnData, SSL_TRC(3, ("%d: TLS13[%d]: send psk key exchange modes extension", SSL_GETPID(), ss->fd)); - rv = sslBuffer_AppendVariable(buf, ke_modes, sizeof(ke_modes), 1); + /* GREASE PskKeyExchangeMode: + * A client MAY select one or more GREASE PskKeyExchangeMode values and + * advertise them in the "psk_key_exchange_modes" extension, if sent + * [RFC8701, Section 3.1]. */ + if (ss->opt.enableGrease) { + rv = sslBuffer_AppendVariable(buf, (PRUint8[]){ tls13_psk_dh_ke, ss->ssl3.hs.grease->pskKem }, 2, 1); + } else { + rv = sslBuffer_AppendVariable(buf, (PRUint8[]){ tls13_psk_dh_ke }, 1, 1); + } if (rv != SECSuccess) { return SECFailure; } @@ -1341,7 +1381,8 @@ tls13_ClientSendDelegatedCredentialsXtn(const sslSocket *ss, return SECSuccess; } - rv = ssl3_EncodeFilteredSigAlgs(ss, filtered, filteredCount, buf); + rv = ssl3_EncodeFilteredSigAlgs(ss, filtered, filteredCount, + PR_FALSE /* GREASE */, buf); if (rv != SECSuccess) { return SECFailure; } @@ -1715,3 +1756,38 @@ alert_loser: PORT_SetError(SSL_ERROR_RX_MALFORMED_ECH_EXTENSION); return SECFailure; } + +SECStatus +tls13_SendEmptyGreaseXtn(const sslSocket *ss, + TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added) +{ + if (!ss->opt.enableGrease || + (!ss->sec.isServer && ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_3) || + (ss->sec.isServer && ss->version < SSL_LIBRARY_VERSION_TLS_1_3)) { + return SECSuccess; + } + + *added = PR_TRUE; + return SECSuccess; +} + +SECStatus +tls13_SendGreaseXtn(const sslSocket *ss, + TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added) +{ + if (!ss->opt.enableGrease || + (!ss->sec.isServer && ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_3) || + (ss->sec.isServer && ss->version < SSL_LIBRARY_VERSION_TLS_1_3)) { + return SECSuccess; + } + + SECStatus rv = sslBuffer_AppendVariable(buf, (PRUint8[]){ 0x00 }, 1, 2); + if (rv != SECSuccess) { + return SECFailure; + } + + *added = PR_TRUE; + return SECSuccess; +} diff --git a/lib/ssl/tls13exthandle.h b/lib/ssl/tls13exthandle.h index d9bc3530d..fb4a18965 100644 --- a/lib/ssl/tls13exthandle.h +++ b/lib/ssl/tls13exthandle.h @@ -115,5 +115,11 @@ SECStatus tls13_ClientSendDelegatedCredentialsXtn(const sslSocket *ss, SECStatus tls13_ServerHandleDelegatedCredentialsXtn(const sslSocket *ss, TLSExtensionData *xtnData, SECItem *data); +SECStatus tls13_SendEmptyGreaseXtn(const sslSocket *ss, + TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added); +SECStatus tls13_SendGreaseXtn(const sslSocket *ss, + TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added); #endif -- cgit v1.2.1