diff options
Diffstat (limited to 'security/nss/lib/ssl/ssl3ext.c')
-rw-r--r-- | security/nss/lib/ssl/ssl3ext.c | 709 |
1 files changed, 124 insertions, 585 deletions
diff --git a/security/nss/lib/ssl/ssl3ext.c b/security/nss/lib/ssl/ssl3ext.c index ade2809036..271084cf73 100644 --- a/security/nss/lib/ssl/ssl3ext.c +++ b/security/nss/lib/ssl/ssl3ext.c @@ -14,20 +14,8 @@ #include "sslimpl.h" #include "sslproto.h" #include "ssl3exthandle.h" -#include "tls13err.h" #include "tls13exthandle.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. @@ -43,15 +31,16 @@ static const ssl3ExtensionHandler clientHelloHandlers[] = { { ssl_app_layer_protocol_xtn, &ssl3_ServerHandleAppProtoXtn }, { ssl_use_srtp_xtn, &ssl3_ServerHandleUseSRTPXtn }, { ssl_cert_status_xtn, &ssl3_ServerHandleStatusRequestXtn }, - { ssl_signature_algorithms_xtn, &ssl3_HandleSigAlgsXtn }, + { ssl_signature_algorithms_xtn, &ssl3_ServerHandleSigAlgsXtn }, { ssl_extended_master_secret_xtn, &ssl3_HandleExtendedMasterSecretXtn }, { ssl_signed_cert_timestamp_xtn, &ssl3_ServerHandleSignedCertTimestampXtn }, { 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 }, - { 0, NULL } + { ssl_tls13_psk_key_exchange_modes_xtn, + &tls13_ServerHandlePskKeyExchangeModesXtn }, + { ssl_tls13_short_header_xtn, &tls13_HandleShortHeaderXtn }, + { -1, NULL } }; /* These two tables are used by the client, to handle server hello @@ -70,38 +59,36 @@ static const ssl3ExtensionHandler serverHelloHandlersTLS[] = { { ssl_tls13_key_share_xtn, &tls13_ClientHandleKeyShareXtn }, { ssl_tls13_pre_shared_key_xtn, &tls13_ClientHandlePreSharedKeyXtn }, { ssl_tls13_early_data_xtn, &tls13_ClientHandleEarlyDataXtn }, - { 0, NULL } + { ssl_tls13_short_header_xtn, &tls13_HandleShortHeaderXtn }, + { -1, NULL } }; static const ssl3ExtensionHandler helloRetryRequestHandlers[] = { { ssl_tls13_key_share_xtn, tls13_ClientHandleKeyShareXtnHrr }, { ssl_tls13_cookie_xtn, tls13_ClientHandleHrrCookie }, - { 0, NULL } + { -1, NULL } }; static const ssl3ExtensionHandler serverHelloHandlersSSL3[] = { { ssl_renegotiation_info_xtn, &ssl3_HandleRenegotiationInfoXtn }, - { 0, NULL } + { -1, NULL } }; static const ssl3ExtensionHandler newSessionTicketHandlers[] = { - { ssl_tls13_early_data_xtn, - &tls13_ClientHandleTicketEarlyDataXtn }, - { 0, NULL } + { ssl_tls13_ticket_early_data_info_xtn, + &tls13_ClientHandleTicketEarlyDataInfoXtn }, + { -1, 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 }, - { 0, NULL } + { -1, NULL } }; static const ssl3ExtensionHandler certificateRequestHandlers[] = { - { ssl_signature_algorithms_xtn, &ssl3_HandleSigAlgsXtn }, - { ssl_tls13_certificate_authorities_xtn, - &tls13_ClientHandleCertAuthoritiesXtn }, - { 0, NULL } + { -1, NULL } }; /* Tables of functions to format TLS hello extensions, one function per @@ -114,14 +101,14 @@ static const ssl3ExtensionHandler certificateRequestHandlers[] = { * the client hello is empty (for example, the extended master secret * extension, if it were listed last). See bug 1243641. */ -static const sslExtensionBuilder clientHelloSendersTLS[] = +static const ssl3HelloExtensionSender clientHelloSendersTLS[SSL_MAX_EXTENSIONS] = { - { ssl_server_name_xtn, &ssl3_ClientSendServerNameXtn }, + { ssl_server_name_xtn, &ssl3_SendServerNameXtn }, { 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_session_ticket_xtn, &ssl3_SendSessionTicketXtn }, { ssl_next_proto_nego_xtn, &ssl3_ClientSendNextProtoNegoXtn }, { ssl_app_layer_protocol_xtn, &ssl3_ClientSendAppProtoXtn }, { ssl_use_srtp_xtn, &ssl3_ClientSendUseSRTPXtn }, @@ -134,155 +121,22 @@ static const sslExtensionBuilder clientHelloSendersTLS[] = * 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_short_header_xtn, &tls13_SendShortHeaderXtn }, + { ssl_signature_algorithms_xtn, &ssl3_ClientSendSigAlgsXtn }, { ssl_tls13_cookie_xtn, &tls13_ClientSendHrrCookieXtn }, - { ssl_tls13_psk_key_exchange_modes_xtn, &tls13_ClientSendPskModesXtn }, + { ssl_tls13_psk_key_exchange_modes_xtn, + &tls13_ClientSendPskKeyExchangeModesXtn }, + { ssl_padding_xtn, &ssl3_ClientSendPaddingExtension }, /* The pre_shared_key extension MUST be last. */ { ssl_tls13_pre_shared_key_xtn, &tls13_ClientSendPreSharedKeyXtn }, - { 0, NULL } + /* any extra entries will appear as { 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 }, - { 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 }, - { 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_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_next_proto_nego_xtn, ssl_ext_none }, - { ssl_renegotiation_info_xtn, ssl_ext_native } +static const ssl3HelloExtensionSender clientHelloSendersSSL3[SSL_MAX_EXTENSIONS] = { + { ssl_renegotiation_info_xtn, &ssl3_SendRenegotiationInfoXtn } + /* any extra entries will appear as { 0, NULL } */ }; -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; -} - -static 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) { @@ -302,11 +156,8 @@ ssl3_ExtensionNegotiated(const sslSocket *ss, PRUint16 ex_type) 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) +ssl3_ClientExtensionAdvertised(const sslSocket *ss, PRUint16 ex_type) { const TLSExtensionData *xtnData = &ss->xtnData; return arrayContainsExtension(xtnData->advertised, @@ -389,44 +240,6 @@ ssl3_FindExtension(sslSocket *ss, SSLExtensionType extension_type) 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) { - rv = (*handler->ex_handler)(ss, &ss->xtnData, &extension->data); - 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. @@ -437,46 +250,42 @@ ssl_CallExtensionHandler(sslSocket *ss, SSLHandshakeType handshakeMessage, * right phase. */ SECStatus -ssl3_HandleParsedExtensions(sslSocket *ss, SSLHandshakeType message) +ssl3_HandleParsedExtensions(sslSocket *ss, + SSL3HandshakeType handshakeMessage) { 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); + (handshakeMessage == hello_retry_request); PRCList *cursor; - switch (message) { - case ssl_hs_client_hello: + switch (handshakeMessage) { + case client_hello: handlers = clientHelloHandlers; break; - case ssl_hs_new_session_ticket: + case new_session_ticket: PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3); handlers = newSessionTicketHandlers; break; - case ssl_hs_hello_retry_request: + case hello_retry_request: handlers = helloRetryRequestHandlers; break; - case ssl_hs_encrypted_extensions: + case encrypted_extensions: PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3); /* fall through */ - case ssl_hs_server_hello: + case server_hello: if (ss->version > SSL_LIBRARY_VERSION_3_0) { handlers = serverHelloHandlersTLS; } else { handlers = serverHelloHandlersSSL3; } break; - case ssl_hs_certificate: + case certificate: PORT_Assert(!ss->sec.isServer); handlers = serverCertificateHandlers; break; - case ssl_hs_certificate_request: + case certificate_request: PORT_Assert(!ss->sec.isServer); handlers = certificateRequestHandlers; break; @@ -490,39 +299,28 @@ ssl3_HandleParsedExtensions(sslSocket *ss, SSLHandshakeType message) cursor != &ss->ssl3.hs.remoteExtensions; cursor = PR_NEXT_LINK(cursor)) { TLSExtension *extension = (TLSExtension *)cursor; - SECStatus rv; + const ssl3ExtensionHandler *handler; /* 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) && - !ssl3_ExtensionAdvertised(ss, extension->type)) { + * in the ClientHello */ + if (!ss->sec.isServer && + !ssl3_ClientExtensionAdvertised(ss, extension->type) && + (handshakeMessage != new_session_ticket) && + (extension->type != ssl_tls13_cookie_xtn)) { (void)SSL3_SendAlert(ss, alert_fatal, unsupported_extension); PORT_SetError(SSL_ERROR_RX_UNEXPECTED_EXTENSION); return SECFailure; } /* 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. */ - } - /* Fall through. */ - case tls13_extension_disallowed: - tls13_FatalError(ss, SSL_ERROR_EXTENSION_DISALLOWED_FOR_VERSION, - unsupported_extension); - return SECFailure; + if (isTLS13 && !tls13_ExtensionAllowed(extension->type, handshakeMessage)) { + if (handshakeMessage == client_hello) { + /* Skip extensions not used in TLS 1.3 */ + continue; } + tls13_FatalError(ss, SSL_ERROR_EXTENSION_DISALLOWED_FOR_VERSION, + unsupported_extension); + return SECFailure; } /* Special check for this being the last extension if it's @@ -536,9 +334,23 @@ ssl3_HandleParsedExtensions(sslSocket *ss, SSLHandshakeType message) return SECFailure; } - rv = ssl_CallExtensionHandler(ss, message, extension, handlers); - if (rv != SECSuccess) { - return SECFailure; + /* find extension_type in table of Hello Extension Handlers */ + for (handler = handlers; handler->ex_type >= 0; handler++) { + /* if found, call this handler */ + if (handler->ex_type == extension->type) { + SECStatus rv; + + rv = (*handler->ex_handler)(ss, &ss->xtnData, + (PRUint16)extension->type, + &extension->data); + if (rv != SECSuccess) { + if (!ss->ssl3.fatalAlertSent) { + /* send a generic alert if the handler didn't already */ + (void)SSL3_SendAlert(ss, alert_fatal, handshake_failure); + } + return SECFailure; + } + } } } return SECSuccess; @@ -549,7 +361,7 @@ ssl3_HandleParsedExtensions(sslSocket *ss, SSLHandshakeType message) SECStatus ssl3_HandleExtensions(sslSocket *ss, PRUint8 **b, PRUint32 *length, - SSLHandshakeType handshakeMessage) + SSL3HandshakeType handshakeMessage) { SECStatus rv; @@ -571,30 +383,21 @@ SECStatus ssl3_RegisterExtensionSender(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, - sslExtensionBuilderFunc cb) + ssl3HelloExtensionSenderFunc cb) { int i; - sslExtensionBuilder *sender; + ssl3HelloExtensionSender *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); + if (tls13_ExtensionAllowed(ex_type, server_hello)) { + PORT_Assert(!tls13_ExtensionAllowed(ex_type, encrypted_extensions)); 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) { + } else if (tls13_ExtensionAllowed(ex_type, certificate)) { sender = &xtnData->certificateSenders[0]; } else { - PORT_Assert(0); - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; + PORT_Assert(tls13_ExtensionAllowed(ex_type, encrypted_extensions)); + sender = &xtnData->encryptedExtensionsSenders[0]; } } for (i = 0; i < SSL_MAX_EXTENSIONS; ++i, ++sender) { @@ -615,289 +418,32 @@ ssl3_RegisterExtensionSender(const sslSocket *ss, return SECFailure; } -static SECStatus -ssl_CallCustomExtensionSenders(sslSocket *ss, sslBuffer *buf, - SSLHandshakeType message) +/* call each of the extension senders and return the accumulated length */ +PRInt32 +ssl3_CallHelloExtensionSenders(sslSocket *ss, PRBool append, PRUint32 maxBytes, + const ssl3HelloExtensionSender *sender) { - 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_certificate_request) { - ss->xtnData.advertised[ss->xtnData.numAdvertised++] = hook->type; - } - } - - sslBuffer_Append(buf, tail.buf, tail.len); - 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); - - switch (message) { - case ssl_hs_client_hello: - if (ss->vrange.max > SSL_LIBRARY_VERSION_3_0) { - 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) { - 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; - } - - buf->len = start; - rv = sslBuffer_AppendNumber(buf, sender->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++] = - sender->ex_type; - } - } + PRInt32 total_exten_len = 0; + int i; - if (!PR_CLIST_IS_EMPTY(&ss->extensionHooks)) { - rv = ssl_CallCustomExtensionSenders(ss, buf, message); - if (rv != SECSuccess) { - goto loser; + if (!sender) { + if (ss->vrange.max > SSL_LIBRARY_VERSION_3_0) { + sender = &clientHelloSendersTLS[0]; + } else { + sender = &clientHelloSendersSSL3[0]; } } - 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 recordLength = 1 /* handshake message type */ + - 3 /* handshake message length */ + - 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 (recordLength < 256 || recordLength >= 512) { - return 0; - } - - extensionLen = 512 - recordLength; - /* 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; -} - -/* 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(const sslSocket *ss, unsigned int prefixLen, - sslBuffer *buf) -{ - static unsigned char padding[252] = { 0 }; - unsigned int paddingLen; - unsigned int tailLen; - SECStatus rv; - - /* 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; - } - - /* 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 + paddingLen); - if (rv != SECSuccess) { - return SECFailure; + for (i = 0; i < SSL_MAX_EXTENSIONS; ++i, ++sender) { + if (sender->ex_sender) { + PRInt32 extLen = (*sender->ex_sender)(ss, &ss->xtnData, append, maxBytes); + if (extLen < 0) + return -1; + maxBytes -= extLen; + total_exten_len += extLen; } - PORT_Memmove(buf->buf + ss->xtnData.lastXtnOffset + 4 + paddingLen, - buf->buf + ss->xtnData.lastXtnOffset, - tailLen); - buf->len = ss->xtnData.lastXtnOffset; - } else { - tailLen = 0; } - - rv = sslBuffer_AppendNumber(buf, ssl_padding_xtn, 2); - if (rv != SECSuccess) { - return SECFailure; /* Code already set. */ - } - rv = sslBuffer_AppendVariable(buf, padding, paddingLen, 2); - if (rv != SECSuccess) { - return SECFailure; /* Code already set. */ - } - - buf->len += tailLen; - - return SECSuccess; + return total_exten_len; } void @@ -914,59 +460,52 @@ ssl3_DestroyRemoteExtensions(PRCList *list) /* Initialize the extension data block. */ void -ssl3_InitExtensionData(TLSExtensionData *xtnData, const sslSocket *ss) +ssl3_InitExtensionData(TLSExtensionData *xtnData) { - 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); } +/* Free everything that has been allocated and then reset back to + * the starting state. */ void -ssl3_DestroyExtensionData(TLSExtensionData *xtnData) +ssl3_ResetExtensionData(TLSExtensionData *xtnData) { + /* Clean up. */ ssl3_FreeSniNameArray(xtnData); - PORT_Free(xtnData->sigSchemes); + PORT_Free(xtnData->clientSigSchemes); 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); + + /* Now reinit. */ + ssl3_InitExtensionData(xtnData); } -/* Free everything that has been allocated and then reset back to - * the starting state. */ -void -ssl3_ResetExtensionData(TLSExtensionData *xtnData, const sslSocket *ss) +/* Thunks to let extension handlers operate on const sslSocket* objects. */ +SECStatus +ssl3_ExtAppendHandshake(const sslSocket *ss, const void *void_src, + PRInt32 bytes) { - ssl3_DestroyExtensionData(xtnData); - ssl3_InitExtensionData(xtnData, ss); + return ssl3_AppendHandshake((sslSocket *)ss, void_src, bytes); +} + +SECStatus +ssl3_ExtAppendHandshakeNumber(const sslSocket *ss, PRInt32 num, + PRInt32 lenSize) +{ + return ssl3_AppendHandshakeNumber((sslSocket *)ss, num, lenSize); +} + +SECStatus +ssl3_ExtAppendHandshakeVariable(const sslSocket *ss, + const PRUint8 *src, PRInt32 bytes, + PRInt32 lenSize) +{ + return ssl3_AppendHandshakeVariable((sslSocket *)ss, src, bytes, lenSize); } -/* Thunks to let extension handlers operate on const sslSocket* objects. */ void ssl3_ExtSendAlert(const sslSocket *ss, SSL3AlertLevel level, SSL3AlertDescription desc) |