/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * SSL3 Protocol * * 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 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* TLS extension code moved here from ssl3ecc.c */ #include "nssrenam.h" #include "nss.h" #include "pk11pub.h" #include "ssl.h" #include "sslimpl.h" #include "sslproto.h" #include "ssl3exthandle.h" #include "tls13ech.h" #include "tls13err.h" #include "tls13exthandle.h" #include "tls13subcerts.h" /* Callback function that handles a received extension. */ typedef SECStatus (*ssl3ExtensionHandlerFunc)(const sslSocket *ss, TLSExtensionData *xtnData, SECItem *data); /* Row in a table of hello extension handlers. */ typedef struct { SSLExtensionType ex_type; ssl3ExtensionHandlerFunc ex_handler; } ssl3ExtensionHandler; /* Table of handlers for received TLS hello extensions, one per extension. * In the second generation, this table will be dynamic, and functions * will be registered here. */ /* This table is used by the server, to handle client hello extensions. */ static const ssl3ExtensionHandler clientHelloHandlers[] = { { ssl_server_name_xtn, &ssl3_HandleServerNameXtn }, { ssl_supported_groups_xtn, &ssl_HandleSupportedGroupsXtn }, { ssl_ec_point_formats_xtn, &ssl3_HandleSupportedPointFormatsXtn }, { ssl_session_ticket_xtn, &ssl3_ServerHandleSessionTicketXtn }, { ssl_renegotiation_info_xtn, &ssl3_HandleRenegotiationInfoXtn }, { ssl_app_layer_protocol_xtn, &ssl3_ServerHandleAppProtoXtn }, { ssl_use_srtp_xtn, &ssl3_ServerHandleUseSRTPXtn }, { ssl_cert_status_xtn, &ssl3_ServerHandleStatusRequestXtn }, { ssl_tls13_certificate_authorities_xtn, &tls13_ServerHandleCertAuthoritiesXtn }, { ssl_signature_algorithms_xtn, &ssl3_HandleSigAlgsXtn }, { ssl_extended_master_secret_xtn, &ssl3_HandleExtendedMasterSecretXtn }, { ssl_signed_cert_timestamp_xtn, &ssl3_ServerHandleSignedCertTimestampXtn }, { ssl_delegated_credentials_xtn, &tls13_ServerHandleDelegatedCredentialsXtn }, { ssl_tls13_key_share_xtn, &tls13_ServerHandleKeyShareXtn }, { ssl_tls13_pre_shared_key_xtn, &tls13_ServerHandlePreSharedKeyXtn }, { ssl_tls13_early_data_xtn, &tls13_ServerHandleEarlyDataXtn }, { ssl_tls13_psk_key_exchange_modes_xtn, &tls13_ServerHandlePskModesXtn }, { ssl_tls13_cookie_xtn, &tls13_ServerHandleCookieXtn }, { ssl_tls13_post_handshake_auth_xtn, &tls13_ServerHandlePostHandshakeAuthXtn }, { ssl_record_size_limit_xtn, &ssl_HandleRecordSizeLimitXtn }, { ssl_certificate_compression_xtn, &ssl3_HandleCertificateCompressionXtn }, { 0, NULL } }; /* These two tables are used by the client, to handle server hello * extensions. */ static const ssl3ExtensionHandler serverHelloHandlersTLS[] = { { ssl_server_name_xtn, &ssl3_HandleServerNameXtn }, /* TODO: add a handler for ssl_ec_point_formats_xtn */ { ssl_session_ticket_xtn, &ssl3_ClientHandleSessionTicketXtn }, { ssl_renegotiation_info_xtn, &ssl3_HandleRenegotiationInfoXtn }, { ssl_app_layer_protocol_xtn, &ssl3_ClientHandleAppProtoXtn }, { ssl_use_srtp_xtn, &ssl3_ClientHandleUseSRTPXtn }, { ssl_cert_status_xtn, &ssl3_ClientHandleStatusRequestXtn }, { ssl_extended_master_secret_xtn, &ssl3_HandleExtendedMasterSecretXtn }, { ssl_signed_cert_timestamp_xtn, &ssl3_ClientHandleSignedCertTimestampXtn }, { ssl_tls13_key_share_xtn, &tls13_ClientHandleKeyShareXtn }, { ssl_tls13_pre_shared_key_xtn, &tls13_ClientHandlePreSharedKeyXtn }, { ssl_tls13_early_data_xtn, &tls13_ClientHandleEarlyDataXtn }, { ssl_tls13_encrypted_client_hello_xtn, &tls13_ClientHandleEchXtn }, { ssl_record_size_limit_xtn, &ssl_HandleRecordSizeLimitXtn }, { 0, NULL } }; static const ssl3ExtensionHandler helloRetryRequestHandlers[] = { { ssl_tls13_key_share_xtn, tls13_ClientHandleKeyShareXtnHrr }, { ssl_tls13_cookie_xtn, tls13_ClientHandleHrrCookie }, { ssl_tls13_encrypted_client_hello_xtn, tls13_ClientHandleHrrEchXtn }, { 0, NULL } }; static const ssl3ExtensionHandler serverHelloHandlersSSL3[] = { { ssl_renegotiation_info_xtn, &ssl3_HandleRenegotiationInfoXtn }, { 0, NULL } }; static const ssl3ExtensionHandler newSessionTicketHandlers[] = { { ssl_tls13_early_data_xtn, &tls13_ClientHandleTicketEarlyDataXtn }, { 0, NULL } }; /* This table is used by the client to handle server certificates in TLS 1.3 */ static const ssl3ExtensionHandler serverCertificateHandlers[] = { { ssl_signed_cert_timestamp_xtn, &ssl3_ClientHandleSignedCertTimestampXtn }, { ssl_cert_status_xtn, &ssl3_ClientHandleStatusRequestXtn }, { ssl_delegated_credentials_xtn, &tls13_ClientHandleDelegatedCredentialsXtn }, { 0, NULL } }; static const ssl3ExtensionHandler certificateRequestHandlers[] = { { ssl_signature_algorithms_xtn, &ssl3_HandleSigAlgsXtn }, { ssl_tls13_certificate_authorities_xtn, &tls13_ClientHandleCertAuthoritiesXtn }, { ssl_certificate_compression_xtn, &ssl3_HandleCertificateCompressionXtn }, { 0, NULL } }; /* Tables of functions to format TLS hello extensions, one function per * extension. * These static tables are for the formatting of client hello extensions. * The server's table of hello senders is dynamic, in the socket struct, * and sender functions are registered there. * NB: the order of these extensions can have an impact on compatibility. Some * servers (e.g. Tomcat) will terminate the connection if the last extension in * the client hello is empty (for example, the extended master secret * 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 }, { ssl_supported_groups_xtn, &ssl_SendSupportedGroupsXtn }, { ssl_ec_point_formats_xtn, &ssl3_SendSupportedPointFormatsXtn }, { ssl_session_ticket_xtn, &ssl3_ClientSendSessionTicketXtn }, { ssl_app_layer_protocol_xtn, &ssl3_ClientSendAppProtoXtn }, { ssl_use_srtp_xtn, &ssl3_ClientSendUseSRTPXtn }, { ssl_cert_status_xtn, &ssl3_ClientSendStatusRequestXtn }, { ssl_delegated_credentials_xtn, &tls13_ClientSendDelegatedCredentialsXtn }, { ssl_signed_cert_timestamp_xtn, &ssl3_ClientSendSignedCertTimestampXtn }, { ssl_tls13_key_share_xtn, &tls13_ClientSendKeyShareXtn }, { ssl_tls13_early_data_xtn, &tls13_ClientSendEarlyDataXtn }, /* Some servers (e.g. WebSphere Application Server 7.0 and Tomcat) will * time out or terminate the connection if the last extension in the * client hello is empty. They are not intolerant of TLS 1.2, so list * signature_algorithms at the end. See bug 1243641. */ { ssl_tls13_supported_versions_xtn, &tls13_ClientSendSupportedVersionsXtn }, { ssl_signature_algorithms_xtn, &ssl3_SendSigAlgsXtn }, { ssl_tls13_cookie_xtn, &tls13_ClientSendHrrCookieXtn }, { ssl_tls13_psk_key_exchange_modes_xtn, &tls13_ClientSendPskModesXtn }, { ssl_tls13_post_handshake_auth_xtn, &tls13_ClientSendPostHandshakeAuthXtn }, { ssl_record_size_limit_xtn, &ssl_SendRecordSizeLimitXtn }, { ssl_certificate_compression_xtn, &ssl3_SendCertificateCompressionXtn }, /* 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 } }; static const sslExtensionBuilder clientHelloSendersSSL3[] = { { ssl_renegotiation_info_xtn, &ssl3_SendRenegotiationInfoXtn }, { 0, NULL } }; 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 }, { ssl_certificate_compression_xtn, &ssl3_SendCertificateCompressionXtn }, { 0, NULL } }; static const sslExtensionBuilder tls13_hrr_senders[] = { { ssl_tls13_key_share_xtn, &tls13_ServerSendHrrKeyShareXtn }, { ssl_tls13_cookie_xtn, &tls13_ServerSendHrrCookieXtn }, { ssl_tls13_supported_versions_xtn, &tls13_ServerSendSupportedVersionsXtn }, { ssl_tls13_encrypted_client_hello_xtn, &tls13_ServerSendHrrEchXtn }, { 0, NULL } }; static const struct { SSLExtensionType type; SSLExtensionSupport support; } ssl_supported_extensions[] = { { ssl_server_name_xtn, ssl_ext_native_only }, { ssl_cert_status_xtn, ssl_ext_native }, { ssl_delegated_credentials_xtn, ssl_ext_native }, { ssl_supported_groups_xtn, ssl_ext_native_only }, { ssl_ec_point_formats_xtn, ssl_ext_native }, { ssl_signature_algorithms_xtn, ssl_ext_native_only }, { ssl_use_srtp_xtn, ssl_ext_native }, { ssl_app_layer_protocol_xtn, ssl_ext_native_only }, { ssl_signed_cert_timestamp_xtn, ssl_ext_native }, { ssl_padding_xtn, ssl_ext_native }, { ssl_extended_master_secret_xtn, ssl_ext_native_only }, { ssl_session_ticket_xtn, ssl_ext_native_only }, { ssl_tls13_key_share_xtn, ssl_ext_native_only }, { ssl_tls13_pre_shared_key_xtn, ssl_ext_native_only }, { ssl_tls13_early_data_xtn, ssl_ext_native_only }, { ssl_tls13_supported_versions_xtn, ssl_ext_native_only }, { ssl_tls13_cookie_xtn, ssl_ext_native_only }, { ssl_tls13_psk_key_exchange_modes_xtn, ssl_ext_native_only }, { ssl_tls13_ticket_early_data_info_xtn, ssl_ext_native_only }, { ssl_tls13_certificate_authorities_xtn, ssl_ext_native }, { ssl_renegotiation_info_xtn, ssl_ext_native }, { ssl_tls13_encrypted_client_hello_xtn, ssl_ext_native_only }, { ssl_certificate_compression_xtn, ssl_ext_native }, }; static SSLExtensionSupport ssl_GetExtensionSupport(PRUint16 type) { unsigned int i; for (i = 0; i < PR_ARRAY_SIZE(ssl_supported_extensions); ++i) { if (type == ssl_supported_extensions[i].type) { return ssl_supported_extensions[i].support; } } return ssl_ext_none; } SECStatus SSLExp_GetExtensionSupport(PRUint16 type, SSLExtensionSupport *support) { *support = ssl_GetExtensionSupport(type); return SECSuccess; } SECStatus SSLExp_InstallExtensionHooks(PRFileDesc *fd, PRUint16 extension, SSLExtensionWriter writer, void *writerArg, SSLExtensionHandler handler, void *handlerArg) { sslSocket *ss = ssl_FindSocket(fd); PRCList *cursor; sslCustomExtensionHooks *hook; if (!ss) { return SECFailure; /* Code already set. */ } /* Need to specify both or neither, but not just one. */ if ((writer && !handler) || (!writer && handler)) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } if (ssl_GetExtensionSupport(extension) == ssl_ext_native_only) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } if (ss->firstHsDone || ((ss->ssl3.hs.ws != idle_handshake) && (ss->ssl3.hs.ws != wait_client_hello))) { PORT_SetError(PR_INVALID_STATE_ERROR); return SECFailure; } /* Remove any old handler. */ for (cursor = PR_NEXT_LINK(&ss->extensionHooks); cursor != &ss->extensionHooks; cursor = PR_NEXT_LINK(cursor)) { hook = (sslCustomExtensionHooks *)cursor; if (hook->type == extension) { PR_REMOVE_LINK(&hook->link); PORT_Free(hook); break; } } if (!writer && !handler) { return SECSuccess; } hook = PORT_ZNew(sslCustomExtensionHooks); if (!hook) { return SECFailure; /* This removed the old one, oh well. */ } hook->type = extension; hook->writer = writer; hook->writerArg = writerArg; hook->handler = handler; hook->handlerArg = handlerArg; PR_APPEND_LINK(&hook->link, &ss->extensionHooks); return SECSuccess; } sslCustomExtensionHooks * ssl_FindCustomExtensionHooks(sslSocket *ss, PRUint16 extension) { PRCList *cursor; for (cursor = PR_NEXT_LINK(&ss->extensionHooks); cursor != &ss->extensionHooks; cursor = PR_NEXT_LINK(cursor)) { sslCustomExtensionHooks *hook = (sslCustomExtensionHooks *)cursor; if (hook->type == extension) { return hook; } } return NULL; } static PRBool arrayContainsExtension(const PRUint16 *array, PRUint32 len, PRUint16 ex_type) { unsigned int i; for (i = 0; i < len; i++) { if (ex_type == array[i]) return PR_TRUE; } return PR_FALSE; } PRBool ssl3_ExtensionNegotiated(const sslSocket *ss, PRUint16 ex_type) { const TLSExtensionData *xtnData = &ss->xtnData; return arrayContainsExtension(xtnData->negotiated, xtnData->numNegotiated, ex_type); } /* This checks for whether an extension was advertised. On the client, this * covers extensions that are sent in ClientHello; on the server, extensions * sent in CertificateRequest (TLS 1.3 only). */ PRBool ssl3_ExtensionAdvertised(const sslSocket *ss, PRUint16 ex_type) { const TLSExtensionData *xtnData = &ss->xtnData; return arrayContainsExtension(xtnData->advertised, xtnData->numAdvertised, ex_type); } PRBool ssl3_ExtensionAdvertisedClientHelloInner(const sslSocket *ss, PRUint16 ex_type) { const TLSExtensionData *xtnData = &ss->xtnData; return arrayContainsExtension(xtnData->echAdvertised, xtnData->echNumAdvertised, ex_type); } /* Go through hello extensions in |b| and deserialize * them into the list in |ss->ssl3.hs.remoteExtensions|. * The only checking we do in this point is for duplicates. * * IMPORTANT: This list just contains pointers to the incoming * buffer so they can only be used during ClientHello processing. */ SECStatus ssl3_ParseExtensions(sslSocket *ss, PRUint8 **b, PRUint32 *length) { /* Clean out the extensions list. */ ssl3_DestroyRemoteExtensions(&ss->ssl3.hs.remoteExtensions); while (*length) { SECStatus rv; PRUint32 extension_type; SECItem extension_data = { siBuffer, NULL, 0 }; TLSExtension *extension; PRCList *cursor; /* Get the extension's type field */ rv = ssl3_ConsumeHandshakeNumber(ss, &extension_type, 2, b, length); if (rv != SECSuccess) { return SECFailure; /* alert already sent */ } /* Check whether an extension has been sent multiple times. */ for (cursor = PR_NEXT_LINK(&ss->ssl3.hs.remoteExtensions); cursor != &ss->ssl3.hs.remoteExtensions; cursor = PR_NEXT_LINK(cursor)) { if (((TLSExtension *)cursor)->type == extension_type) { (void)SSL3_SendAlert(ss, alert_fatal, illegal_parameter); PORT_SetError(SSL_ERROR_RX_UNEXPECTED_EXTENSION); return SECFailure; } } /* Get the data for this extension, so we can pass it or skip it. */ rv = ssl3_ConsumeHandshakeVariable(ss, &extension_data, 2, b, length); if (rv != SECSuccess) { return rv; /* alert already sent */ } SSL_TRC(10, ("%d: SSL3[%d]: parsed extension %d len=%u", SSL_GETPID(), ss->fd, extension_type, extension_data.len)); extension = PORT_ZNew(TLSExtension); if (!extension) { return SECFailure; } extension->type = (PRUint16)extension_type; extension->data = extension_data; PR_APPEND_LINK(&extension->link, &ss->ssl3.hs.remoteExtensions); } return SECSuccess; } TLSExtension * ssl3_FindExtension(sslSocket *ss, SSLExtensionType extension_type) { PRCList *cursor; for (cursor = PR_NEXT_LINK(&ss->ssl3.hs.remoteExtensions); cursor != &ss->ssl3.hs.remoteExtensions; cursor = PR_NEXT_LINK(cursor)) { TLSExtension *extension = (TLSExtension *)cursor; if (extension->type == extension_type) { return extension; } } return NULL; } static SECStatus ssl_CallExtensionHandler(sslSocket *ss, SSLHandshakeType handshakeMessage, TLSExtension *extension, const ssl3ExtensionHandler *handler) { SECStatus rv = SECSuccess; SSLAlertDescription alert = handshake_failure; sslCustomExtensionHooks *customHooks; customHooks = ssl_FindCustomExtensionHooks(ss, extension->type); if (customHooks) { if (customHooks->handler) { rv = customHooks->handler(ss->fd, handshakeMessage, extension->data.data, extension->data.len, &alert, customHooks->handlerArg); } } else { /* Find extension_type in table of Hello Extension Handlers. */ for (; handler->ex_handler != NULL; ++handler) { if (handler->ex_type == extension->type) { SECItem tmp = extension->data; rv = (*handler->ex_handler)(ss, &ss->xtnData, &tmp); break; } } } if (rv != SECSuccess) { if (!ss->ssl3.fatalAlertSent) { /* Send an alert if the handler didn't already. */ (void)SSL3_SendAlert(ss, alert_fatal, alert); } return SECFailure; } return SECSuccess; } /* Go through the hello extensions in |ss->ssl3.hs.remoteExtensions|. * For each one, find the extension handler in the table, and * if present, invoke that handler. * Servers ignore any extensions with unknown extension types. * Clients reject any extensions with unadvertised extension types * * In TLS >= 1.3, the client checks that extensions appear in the * right phase. */ SECStatus ssl3_HandleParsedExtensions(sslSocket *ss, SSLHandshakeType message) { const ssl3ExtensionHandler *handlers; /* HelloRetryRequest doesn't set ss->version. It might be safe to * do so, but we weren't entirely sure. TODO(ekr@rtfm.com). */ PRBool isTLS13 = (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) || (message == ssl_hs_hello_retry_request); /* The following messages can include extensions that were not included in * the original ClientHello. */ PRBool allowNotOffered = (message == ssl_hs_client_hello) || (message == ssl_hs_certificate_request) || (message == ssl_hs_new_session_ticket); PRCList *cursor; switch (message) { case ssl_hs_client_hello: handlers = clientHelloHandlers; break; case ssl_hs_new_session_ticket: PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3); handlers = newSessionTicketHandlers; break; case ssl_hs_hello_retry_request: handlers = helloRetryRequestHandlers; break; case ssl_hs_encrypted_extensions: PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3); /* fall through */ case ssl_hs_server_hello: if (ss->version > SSL_LIBRARY_VERSION_3_0) { handlers = serverHelloHandlersTLS; } else { handlers = serverHelloHandlersSSL3; } break; case ssl_hs_certificate: PORT_Assert(!ss->sec.isServer); handlers = serverCertificateHandlers; break; case ssl_hs_certificate_request: PORT_Assert(!ss->sec.isServer); handlers = certificateRequestHandlers; break; default: PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); PORT_Assert(0); return SECFailure; } for (cursor = PR_NEXT_LINK(&ss->ssl3.hs.remoteExtensions); cursor != &ss->ssl3.hs.remoteExtensions; cursor = PR_NEXT_LINK(cursor)) { TLSExtension *extension = (TLSExtension *)cursor; SECStatus rv; /* Check whether the server sent an extension which was not advertised * in the ClientHello. * * Note that a TLS 1.3 server should check if CertificateRequest * extensions were sent. But the extensions used for CertificateRequest * do not have any response, so we rely on * ssl3_ExtensionAdvertised to return false on the server. That * results in the server only rejecting any extension. */ if (!allowNotOffered && (extension->type != ssl_tls13_cookie_xtn)) { if (!ssl3_ExtensionAdvertised(ss, extension->type)) { SSL_TRC(10, ("Server sent xtn type=%d which is invalid for the CHO", extension->type)); (void)SSL3_SendAlert(ss, alert_fatal, unsupported_extension); PORT_SetError(SSL_ERROR_RX_UNEXPECTED_EXTENSION); return SECFailure; } /* If we offered ECH, we also check whether the extension is compatible with * the Client Hello Inner. We don't yet know whether the server accepted ECH, * so we only store this for now. If we later accept, we check this boolean * and reject with an unsupported_extension alert if it is set. */ if (ss->ssl3.hs.echHpkeCtx && !ssl3_ExtensionAdvertisedClientHelloInner(ss, extension->type)) { SSL_TRC(10, ("Server sent xtn type=%d which is invalid for the CHI", extension->type)); ss->ssl3.hs.echInvalidExtension = PR_TRUE; } } /* Check that this is a legal extension in TLS 1.3 */ if (isTLS13 && !ssl_FindCustomExtensionHooks(ss, extension->type)) { switch (tls13_ExtensionStatus(extension->type, message)) { case tls13_extension_allowed: break; case tls13_extension_unknown: if (allowNotOffered) { continue; /* Skip over unknown extensions. */ } /* RFC8446 Section 4.2 - Implementations MUST NOT send extension responses if * the remote endpoint did not send the corresponding extension request ... * Upon receiving such an extension, an endpoint MUST abort the handshake with * an "unsupported_extension" alert. */ SSL_TRC(3, ("%d: TLS13: unknown extension %d in message %d", SSL_GETPID(), extension, message)); tls13_FatalError(ss, SSL_ERROR_RX_UNEXPECTED_EXTENSION, unsupported_extension); return SECFailure; case tls13_extension_disallowed: /* RFC8446 Section 4.2 - If an implementation receives an extension which it * recognizes and which is not specified for the message in which it appears, * it MUST abort the handshake with an "illegal_parameter" alert. */ SSL_TRC(3, ("%d: TLS13: disallowed extension %d in message %d", SSL_GETPID(), extension, message)); tls13_FatalError(ss, SSL_ERROR_EXTENSION_DISALLOWED_FOR_VERSION, illegal_parameter); return SECFailure; } } /* Special check for this being the last extension if it's * PreSharedKey */ if (ss->sec.isServer && isTLS13 && (extension->type == ssl_tls13_pre_shared_key_xtn) && (PR_NEXT_LINK(cursor) != &ss->ssl3.hs.remoteExtensions)) { tls13_FatalError(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter); return SECFailure; } rv = ssl_CallExtensionHandler(ss, message, extension, handlers); if (rv != SECSuccess) { return SECFailure; } } return SECSuccess; } /* Syntactic sugar around ssl3_ParseExtensions and * ssl3_HandleParsedExtensions. */ SECStatus ssl3_HandleExtensions(sslSocket *ss, PRUint8 **b, PRUint32 *length, SSLHandshakeType handshakeMessage) { SECStatus rv; rv = ssl3_ParseExtensions(ss, b, length); if (rv != SECSuccess) return rv; rv = ssl3_HandleParsedExtensions(ss, handshakeMessage); if (rv != SECSuccess) return rv; ssl3_DestroyRemoteExtensions(&ss->ssl3.hs.remoteExtensions); return SECSuccess; } /* Add a callback function to the table of senders of server hello extensions. */ SECStatus ssl3_RegisterExtensionSender(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, sslExtensionBuilderFunc cb) { int i; sslExtensionBuilder *sender; if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { sender = &xtnData->serverHelloSenders[0]; } else { if (tls13_ExtensionStatus(ex_type, ssl_hs_server_hello) == tls13_extension_allowed) { PORT_Assert(tls13_ExtensionStatus(ex_type, ssl_hs_encrypted_extensions) == tls13_extension_disallowed); sender = &xtnData->serverHelloSenders[0]; } else if (tls13_ExtensionStatus(ex_type, ssl_hs_encrypted_extensions) == tls13_extension_allowed) { sender = &xtnData->encryptedExtensionsSenders[0]; } else if (tls13_ExtensionStatus(ex_type, ssl_hs_certificate) == tls13_extension_allowed) { sender = &xtnData->certificateSenders[0]; } else { PORT_Assert(0); PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure; } } for (i = 0; i < SSL_MAX_EXTENSIONS; ++i, ++sender) { if (!sender->ex_sender) { sender->ex_type = ex_type; sender->ex_sender = cb; return SECSuccess; } /* detect duplicate senders */ PORT_Assert(sender->ex_type != ex_type); if (sender->ex_type == ex_type) { /* duplicate */ break; } } PORT_Assert(i < SSL_MAX_EXTENSIONS); /* table needs to grow */ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure; } SECStatus ssl_CallCustomExtensionSenders(sslSocket *ss, sslBuffer *buf, SSLHandshakeType message) { sslBuffer tail = SSL_BUFFER_EMPTY; SECStatus rv; PRCList *cursor; /* Save any extensions that want to be last. */ if (ss->xtnData.lastXtnOffset) { rv = sslBuffer_Append(&tail, buf->buf + ss->xtnData.lastXtnOffset, buf->len - ss->xtnData.lastXtnOffset); if (rv != SECSuccess) { return SECFailure; } buf->len = ss->xtnData.lastXtnOffset; } /* Reserve the maximum amount of space possible. */ rv = sslBuffer_Grow(buf, 65535); if (rv != SECSuccess) { return SECFailure; } for (cursor = PR_NEXT_LINK(&ss->extensionHooks); cursor != &ss->extensionHooks; cursor = PR_NEXT_LINK(cursor)) { sslCustomExtensionHooks *hook = (sslCustomExtensionHooks *)cursor; PRBool append = PR_FALSE; unsigned int len = 0; if (hook->writer) { /* The writer writes directly into |buf|. Provide space that allows * for the existing extensions, any tail, plus type and length. */ unsigned int space = buf->space - (buf->len + tail.len + 4); append = (*hook->writer)(ss->fd, message, buf->buf + buf->len + 4, &len, space, hook->writerArg); if (len > space) { PORT_SetError(SEC_ERROR_APPLICATION_CALLBACK_ERROR); goto loser; } } if (!append) { continue; } rv = sslBuffer_AppendNumber(buf, hook->type, 2); if (rv != SECSuccess) { goto loser; /* Code already set. */ } rv = sslBuffer_AppendNumber(buf, len, 2); if (rv != SECSuccess) { goto loser; /* Code already set. */ } buf->len += len; if (message == ssl_hs_client_hello || message == ssl_hs_ech_outer_client_hello || message == ssl_hs_certificate_request) { ss->xtnData.advertised[ss->xtnData.numAdvertised++] = hook->type; } } rv = sslBuffer_Append(buf, tail.buf, tail.len); if (rv != SECSuccess) { goto loser; /* Code already set. */ } sslBuffer_Clear(&tail); return SECSuccess; loser: sslBuffer_Clear(&tail); return SECFailure; } /* Call extension handlers for the given message. */ SECStatus ssl_ConstructExtensions(sslSocket *ss, sslBuffer *buf, SSLHandshakeType message) { const sslExtensionBuilder *sender; SECStatus rv; PORT_Assert(buf->len == 0); /* Clear out any extensions previously advertised */ ss->xtnData.numAdvertised = 0; ss->xtnData.echNumAdvertised = 0; switch (message) { case ssl_hs_client_hello: if (ss->vrange.max > SSL_LIBRARY_VERSION_3_0) { /* Use TLS ClientHello Extension Permutation? */ if (ss->opt.enableChXtnPermutation) { sender = ss->ssl3.hs.chExtensionPermutation; } else { sender = clientHelloSendersTLS; } } else { sender = clientHelloSendersSSL3; } break; case ssl_hs_server_hello: sender = ss->xtnData.serverHelloSenders; break; case ssl_hs_certificate_request: PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3); sender = tls13_cert_req_senders; break; case ssl_hs_certificate: PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3); sender = ss->xtnData.certificateSenders; break; case ssl_hs_encrypted_extensions: PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3); sender = ss->xtnData.encryptedExtensionsSenders; break; case ssl_hs_hello_retry_request: PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3); sender = tls13_hrr_senders; break; default: PORT_Assert(0); PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure; } for (; sender->ex_sender != NULL; ++sender) { PRUint16 ex_type = sender->ex_type; PRBool append = PR_FALSE; unsigned int start = buf->len; unsigned int length; if (ssl_FindCustomExtensionHooks(ss, sender->ex_type)) { continue; } /* Save space for the extension type and length. Note that we don't grow * the buffer now; rely on sslBuffer_Append* to do that. */ buf->len += 4; rv = (*sender->ex_sender)(ss, &ss->xtnData, buf, &append); if (rv != SECSuccess) { goto loser; } /* Save the length and go back to the start. */ length = buf->len - start - 4; buf->len = start; if (!append) { continue; } /* 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. */ } rv = sslBuffer_AppendNumber(buf, length, 2); if (rv != SECSuccess) { goto loser; /* Code already set. */ } /* Skip over the extension body. */ buf->len += length; if (message == ssl_hs_client_hello || message == ssl_hs_certificate_request) { ss->xtnData.advertised[ss->xtnData.numAdvertised++] = ex_type; } } if (!PR_CLIST_IS_EMPTY(&ss->extensionHooks)) { if (message == ssl_hs_client_hello && ss->opt.callExtensionWriterOnEchInner) { message = ssl_hs_ech_outer_client_hello; } rv = ssl_CallCustomExtensionSenders(ss, buf, message); if (rv != SECSuccess) { goto loser; } } if (buf->len > 0xffff) { PORT_SetError(SSL_ERROR_TX_RECORD_TOO_LONG); goto loser; } return SECSuccess; loser: sslBuffer_Clear(buf); return SECFailure; } /* This extension sender can be used anywhere that an always empty extension is * needed. Mostly that is for ServerHello where sender registration is dynamic; * ClientHello senders are usually conditional in some way. */ SECStatus ssl_SendEmptyExtension(const sslSocket *ss, TLSExtensionData *xtnData, sslBuffer *buf, PRBool *append) { *append = PR_TRUE; return SECSuccess; } /* Takes the size of the ClientHello, less the record header, and determines how * much padding is required. */ static unsigned int ssl_CalculatePaddingExtLen(const sslSocket *ss, unsigned int clientHelloLength) { unsigned int extensionLen; /* Don't pad for DTLS, for SSLv3, or for renegotiation. */ if (IS_DTLS(ss) || ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_0 || ss->firstHsDone) { return 0; } /* A padding extension may be included to ensure that the record containing * the ClientHello doesn't have a length between 256 and 511 bytes * (inclusive). Initial ClientHello records with such lengths trigger bugs * in F5 devices. */ if (clientHelloLength < 256 || clientHelloLength >= 512) { return 0; } extensionLen = 512 - clientHelloLength; /* Extensions take at least four bytes to encode. Always include at least * one byte of data if we are padding. Some servers will time out or * terminate the connection if the last ClientHello extension is empty. */ if (extensionLen < 5) { extensionLen = 5; } return extensionLen - 4; } /* Manually insert an extension, retaining the position of the PSK * extension, if present. */ SECStatus ssl3_EmplaceExtension(sslSocket *ss, sslBuffer *buf, PRUint16 exType, const PRUint8 *data, unsigned int len, PRBool advertise) { SECStatus rv; unsigned int tailLen; /* Move the tail if there is one. This only happens if we are sending the * TLS 1.3 PSK extension, which needs to be at the end. */ if (ss->xtnData.lastXtnOffset) { PORT_Assert(buf->len > ss->xtnData.lastXtnOffset); tailLen = buf->len - ss->xtnData.lastXtnOffset; rv = sslBuffer_Grow(buf, buf->len + 4 + len); if (rv != SECSuccess) { return SECFailure; } PORT_Memmove(buf->buf + ss->xtnData.lastXtnOffset + 4 + len, buf->buf + ss->xtnData.lastXtnOffset, tailLen); buf->len = ss->xtnData.lastXtnOffset; } else { tailLen = 0; } if (exType == ssl_tls13_encrypted_client_hello_xtn) { ss->xtnData.echXtnOffset = buf->len; } rv = sslBuffer_AppendNumber(buf, exType, 2); if (rv != SECSuccess) { return SECFailure; /* Code already set. */ } rv = sslBuffer_AppendVariable(buf, data, len, 2); if (rv != SECSuccess) { return SECFailure; /* Code already set. */ } if (ss->xtnData.lastXtnOffset) { ss->xtnData.lastXtnOffset += 4 + len; } buf->len += tailLen; /* False only to retain behavior with padding_xtn. Maybe * we can just mark that advertised as well? TODO */ if (advertise) { ss->xtnData.advertised[ss->xtnData.numAdvertised++] = exType; } return SECSuccess; } /* ssl3_SendPaddingExtension possibly adds an extension which ensures that a * ClientHello record is either < 256 bytes or is >= 512 bytes. This ensures * that we don't trigger bugs in F5 products. * * This takes an existing extension buffer, |buf|, and the length of the * remainder of the ClientHello, |prefixLen|. It modifies the extension buffer * to insert padding at the right place. */ SECStatus ssl_InsertPaddingExtension(sslSocket *ss, unsigned int prefixLen, sslBuffer *buf) { static unsigned char padding[252] = { 0 }; unsigned int paddingLen; /* Exit early if an application-provided extension hook * already added padding. */ if (ssl3_ExtensionAdvertised(ss, ssl_padding_xtn)) { return SECSuccess; } /* Account for the size of the header, the length field of the extensions * block and the size of the existing extensions. */ paddingLen = ssl_CalculatePaddingExtLen(ss, prefixLen + 2 + buf->len); if (!paddingLen) { return SECSuccess; } return ssl3_EmplaceExtension(ss, buf, ssl_padding_xtn, padding, paddingLen, PR_FALSE); } void ssl3_MoveRemoteExtensions(PRCList *dst, PRCList *src) { PRCList *cur_p; while (!PR_CLIST_IS_EMPTY(src)) { cur_p = PR_LIST_TAIL(src); PR_REMOVE_LINK(cur_p); PR_INSERT_LINK(cur_p, dst); } } void ssl3_DestroyRemoteExtensions(PRCList *list) { PRCList *cur_p; while (!PR_CLIST_IS_EMPTY(list)) { cur_p = PR_LIST_TAIL(list); PR_REMOVE_LINK(cur_p); PORT_Free(cur_p); } } /* Initialize the extension data block. */ void ssl3_InitExtensionData(TLSExtensionData *xtnData, const sslSocket *ss) { unsigned int advertisedMax; PRCList *cursor; /* Set things up to the right starting state. */ PORT_Memset(xtnData, 0, sizeof(*xtnData)); xtnData->peerSupportsFfdheGroups = PR_FALSE; PR_INIT_CLIST(&xtnData->remoteKeyShares); /* Allocate enough to allow for native extensions, plus any custom ones. */ if (ss->sec.isServer) { advertisedMax = PR_MAX(PR_ARRAY_SIZE(certificateRequestHandlers), PR_ARRAY_SIZE(tls13_cert_req_senders)); } else { advertisedMax = PR_MAX(PR_ARRAY_SIZE(clientHelloHandlers), PR_ARRAY_SIZE(clientHelloSendersTLS)); ++advertisedMax; /* For the RI SCSV, which we also track. */ } for (cursor = PR_NEXT_LINK(&ss->extensionHooks); cursor != &ss->extensionHooks; cursor = PR_NEXT_LINK(cursor)) { ++advertisedMax; } xtnData->advertised = PORT_ZNewArray(PRUint16, advertisedMax); xtnData->echAdvertised = PORT_ZNewArray(PRUint16, advertisedMax); xtnData->peerDelegCred = NULL; xtnData->peerRequestedDelegCred = PR_FALSE; xtnData->sendingDelegCredToPeer = PR_FALSE; xtnData->selectedPsk = NULL; } void ssl3_DestroyExtensionData(TLSExtensionData *xtnData) { ssl3_FreeSniNameArray(xtnData); PORT_Free(xtnData->sigSchemes); PORT_Free(xtnData->delegCredSigSchemes); PORT_Free(xtnData->delegCredSigSchemesAdvertised); SECITEM_FreeItem(&xtnData->nextProto, PR_FALSE); tls13_DestroyKeyShares(&xtnData->remoteKeyShares); SECITEM_FreeItem(&xtnData->certReqContext, PR_FALSE); SECITEM_FreeItem(&xtnData->applicationToken, PR_FALSE); if (xtnData->certReqAuthorities.arena) { PORT_FreeArena(xtnData->certReqAuthorities.arena, PR_FALSE); xtnData->certReqAuthorities.arena = NULL; } PORT_Free(xtnData->advertised); PORT_Free(xtnData->echAdvertised); tls13_DestroyDelegatedCredential(xtnData->peerDelegCred); tls13_DestroyEchXtnState(xtnData->ech); xtnData->ech = NULL; } /* Free everything that has been allocated and then reset back to * the starting state. */ void ssl3_ResetExtensionData(TLSExtensionData *xtnData, const sslSocket *ss) { ssl3_DestroyExtensionData(xtnData); ssl3_InitExtensionData(xtnData, ss); } /* Thunks to let extension handlers operate on const sslSocket* objects. */ void ssl3_ExtSendAlert(const sslSocket *ss, SSL3AlertLevel level, SSL3AlertDescription desc) { (void)SSL3_SendAlert((sslSocket *)ss, level, desc); } void ssl3_ExtDecodeError(const sslSocket *ss) { (void)ssl3_DecodeError((sslSocket *)ss); } SECStatus ssl3_ExtConsumeHandshake(const sslSocket *ss, void *v, PRUint32 bytes, PRUint8 **b, PRUint32 *length) { return ssl3_ConsumeHandshake((sslSocket *)ss, v, bytes, b, length); } SECStatus ssl3_ExtConsumeHandshakeNumber(const sslSocket *ss, PRUint32 *num, PRUint32 bytes, PRUint8 **b, PRUint32 *length) { return ssl3_ConsumeHandshakeNumber((sslSocket *)ss, num, bytes, b, length); } SECStatus ssl3_ExtConsumeHandshakeVariable(const sslSocket *ss, SECItem *i, PRUint32 bytes, PRUint8 **b, PRUint32 *length) { return ssl3_ConsumeHandshakeVariable((sslSocket *)ss, i, bytes, b, length); } SECStatus tls_ClientHelloExtensionPermutationSetup(sslSocket *ss) { size_t buildersLen = PR_ARRAY_SIZE(clientHelloSendersTLS); const size_t buildersSize = (sizeof(sslExtensionBuilder) * buildersLen); /* Psk Extension and then NULL entry MUST be last. */ const size_t permutationLen = buildersLen - 2; /* There shouldn't already be a stored permutation. */ PR_ASSERT(!ss->ssl3.hs.chExtensionPermutation); /* This shuffle handles up to 256 extensions. */ PR_ASSERT(buildersLen < 256); uint8_t permutation[256] = { 0 }; sslExtensionBuilder *builders = PORT_ZAlloc(buildersSize); if (!builders) { return SECFailure; } /* Get a working copy of default builders. */ PORT_Memcpy(builders, clientHelloSendersTLS, buildersSize); /* Get permutation randoms. */ if (PK11_GenerateRandom(permutation, permutationLen) != SECSuccess) { PORT_Free(builders); return SECFailure; } /* Fisher-Yates Shuffle */ for (size_t i = permutationLen - 1; i > 0; i--) { size_t idx = permutation[i - 1] % (i + 1); sslExtensionBuilder tmp = builders[i]; builders[i] = builders[idx]; builders[idx] = tmp; } /* Make sure that Psk extension is penultimate (before NULL entry). */ PR_ASSERT(builders[buildersLen - 2].ex_type == ssl_tls13_pre_shared_key_xtn); PR_ASSERT(builders[buildersLen - 2].ex_sender == clientHelloSendersTLS[buildersLen - 2].ex_sender); ss->ssl3.hs.chExtensionPermutation = builders; return SECSuccess; } void tls_ClientHelloExtensionPermutationDestroy(sslSocket *ss) { if (ss->ssl3.hs.chExtensionPermutation) { PORT_Free(ss->ssl3.hs.chExtensionPermutation); ss->ssl3.hs.chExtensionPermutation = NULL; } }