diff options
Diffstat (limited to 'net/third_party/nss/ssl/ssl3ext.c')
-rw-r--r-- | net/third_party/nss/ssl/ssl3ext.c | 408 |
1 files changed, 329 insertions, 79 deletions
diff --git a/net/third_party/nss/ssl/ssl3ext.c b/net/third_party/nss/ssl/ssl3ext.c index 1eaf47c..ead0cfd 100644 --- a/net/third_party/nss/ssl/ssl3ext.c +++ b/net/third_party/nss/ssl/ssl3ext.c @@ -41,11 +41,12 @@ * ***** END LICENSE BLOCK ***** */ /* TLS extension code moved here from ssl3ecc.c */ -/* $Id: ssl3ext.c,v 1.5 2009/11/07 18:23:06 wtc%google.com Exp $ */ +/* $Id: ssl3ext.c,v 1.11 2010/02/03 02:38:20 wtc%google.com Exp $ */ #include "nssrenam.h" #include "nss.h" #include "ssl.h" +#include "sslproto.h" #include "sslimpl.h" #include "pk11pub.h" #include "blapi.h" @@ -61,8 +62,7 @@ static unsigned char session_ticket_mac_key[SHA256_LENGTH]; static PRBool session_ticket_keys_initialized = PR_FALSE; static PRCallOnceType generate_session_keys_once; -static PRInt32 ssl3_SendServerNameXtn(sslSocket * ss, - PRBool append, PRUint32 maxBytes); +/* forward static function declarations */ static SECStatus ssl3_ParseEncryptedSessionTicket(sslSocket *ss, SECItem *data, EncryptedSessionTicket *enc_session_ticket); static SECStatus ssl3_AppendToItem(SECItem *item, const unsigned char *buf, @@ -74,6 +74,10 @@ static SECStatus ssl3_GetSessionTicketKeysPKCS11(sslSocket *ss, static SECStatus ssl3_GetSessionTicketKeys(const unsigned char **aes_key, PRUint32 *aes_key_length, const unsigned char **mac_key, PRUint32 *mac_key_length); +static PRInt32 ssl3_SendRenegotiationInfoXtn(sslSocket * ss, + PRBool append, PRUint32 maxBytes); +static SECStatus ssl3_HandleRenegotiationInfoXtn(sslSocket *ss, + PRUint16 ex_type, SECItem *data); /* * Write bytes. Using this function means the SECItem structure @@ -222,42 +226,58 @@ ssl3_GetSessionTicketKeys(const unsigned char **aes_key, * 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 ssl3HelloExtensionHandler clientHelloHandlers[] = { - { server_name_xtn, &ssl3_HandleServerNameXtn }, + { ssl_server_name_xtn, &ssl3_HandleServerNameXtn }, #ifdef NSS_ENABLE_ECC - { elliptic_curves_xtn, &ssl3_HandleSupportedCurvesXtn }, - { ec_point_formats_xtn, &ssl3_HandleSupportedPointFormatsXtn }, + { ssl_elliptic_curves_xtn, &ssl3_HandleSupportedCurvesXtn }, + { ssl_ec_point_formats_xtn, &ssl3_HandleSupportedPointFormatsXtn }, #endif - { session_ticket_xtn, &ssl3_ServerHandleSessionTicketXtn }, - { next_proto_neg_xtn, &ssl3_ServerHandleNextProtoNegoXtn }, + { ssl_session_ticket_xtn, &ssl3_ServerHandleSessionTicketXtn }, + { ssl_renegotiation_info_xtn, &ssl3_HandleRenegotiationInfoXtn }, + { ssl_next_proto_neg_xtn, &ssl3_ServerHandleNextProtoNegoXtn }, + { -1, NULL } +}; + +/* These two tables are used by the client, to handle server hello + * extensions. */ +static const ssl3HelloExtensionHandler 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_next_proto_neg_xtn, &ssl3_ClientHandleNextProtoNegoXtn }, { -1, NULL } }; -static const ssl3HelloExtensionHandler serverHelloHandlers[] = { - { server_name_xtn, &ssl3_HandleServerNameXtn }, - /* TODO: add a handler for ec_point_formats_xtn */ - { session_ticket_xtn, &ssl3_ClientHandleSessionTicketXtn }, - { next_proto_neg_xtn, &ssl3_ClientHandleNextProtoNegoXtn }, +static const ssl3HelloExtensionHandler serverHelloHandlersSSL3[] = { + { ssl_renegotiation_info_xtn, &ssl3_HandleRenegotiationInfoXtn }, { -1, NULL } }; -/* Table of functions to format TLS hello extensions, one per extension. - * This static table is for the formatting of client hello extensions. +/* 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. */ static const -ssl3HelloExtensionSender clientHelloSenders[MAX_EXTENSIONS] = { - { server_name_xtn, &ssl3_SendServerNameXtn }, +ssl3HelloExtensionSender clientHelloSendersTLS[SSL_MAX_EXTENSIONS] = { + { ssl_server_name_xtn, &ssl3_SendServerNameXtn }, + { ssl_renegotiation_info_xtn, &ssl3_SendRenegotiationInfoXtn }, #ifdef NSS_ENABLE_ECC - { elliptic_curves_xtn, &ssl3_SendSupportedCurvesXtn }, - { ec_point_formats_xtn, &ssl3_SendSupportedPointFormatsXtn }, -#else - { -1, NULL }, - { -1, NULL }, + { ssl_elliptic_curves_xtn, &ssl3_SendSupportedCurvesXtn }, + { ssl_ec_point_formats_xtn, &ssl3_SendSupportedPointFormatsXtn }, #endif - { session_ticket_xtn, ssl3_SendSessionTicketXtn }, - { next_proto_neg_xtn, ssl3_ClientSendNextProtoNegoXtn } + { ssl_session_ticket_xtn, &ssl3_SendSessionTicketXtn }, + { ssl_next_proto_neg_xtn, &ssl3_ClientSendNextProtoNegoXtn } + /* any extra entries will appear as { 0, NULL } */ +}; + +static const +ssl3HelloExtensionSender clientHelloSendersSSL3[SSL_MAX_EXTENSIONS] = { + { ssl_renegotiation_info_xtn, &ssl3_SendRenegotiationInfoXtn } + /* any extra entries will appear as { 0, NULL } */ }; static PRBool @@ -287,60 +307,159 @@ ssl3_ClientExtensionAdvertised(sslSocket *ss, PRUint16 ex_type) { /* Format an SNI extension, using the name from the socket's URL, * unless that name is a dotted decimal string. + * Used by client and server. */ -static PRInt32 -ssl3_SendServerNameXtn( - sslSocket * ss, - PRBool append, - PRUint32 maxBytes) +PRInt32 +ssl3_SendServerNameXtn(sslSocket * ss, PRBool append, + PRUint32 maxBytes) { - PRUint32 len; - PRNetAddr netAddr; - - /* must have a hostname */ - if (!ss || !ss->url || !ss->url[0]) - return 0; - /* must not be an IPv4 or IPv6 address */ - if (PR_SUCCESS == PR_StringToNetAddr(ss->url, &netAddr)) { - /* is an IP address (v4 or v6) */ - return 0; + SECStatus rv; + if (!ss->sec.isServer) { + PRUint32 len; + PRNetAddr netAddr; + + /* must have a hostname */ + if (!ss || !ss->url || !ss->url[0]) + return 0; + /* must not be an IPv4 or IPv6 address */ + if (PR_SUCCESS == PR_StringToNetAddr(ss->url, &netAddr)) { + /* is an IP address (v4 or v6) */ + return 0; + } + len = PORT_Strlen(ss->url); + if (append && maxBytes >= len + 9) { + /* extension_type */ + rv = ssl3_AppendHandshakeNumber(ss, ssl_server_name_xtn, 2); + if (rv != SECSuccess) return -1; + /* length of extension_data */ + rv = ssl3_AppendHandshakeNumber(ss, len + 5, 2); + if (rv != SECSuccess) return -1; + /* length of server_name_list */ + rv = ssl3_AppendHandshakeNumber(ss, len + 3, 2); + if (rv != SECSuccess) return -1; + /* Name Type (sni_host_name) */ + rv = ssl3_AppendHandshake(ss, "\0", 1); + if (rv != SECSuccess) return -1; + /* HostName (length and value) */ + rv = ssl3_AppendHandshakeVariable(ss, (PRUint8 *)ss->url, len, 2); + if (rv != SECSuccess) return -1; + if (!ss->sec.isServer) { + TLSExtensionData *xtnData = &ss->xtnData; + xtnData->advertised[xtnData->numAdvertised++] = + ssl_server_name_xtn; + } + } + return len + 9; } - len = PORT_Strlen(ss->url); - if (append && maxBytes >= len + 9) { - SECStatus rv; - /* extension_type */ - rv = ssl3_AppendHandshakeNumber(ss, server_name_xtn, 2); - if (rv != SECSuccess) return -1; - /* length of extension_data */ - rv = ssl3_AppendHandshakeNumber(ss, len + 5, 2); - if (rv != SECSuccess) return -1; - /* length of server_name_list */ - rv = ssl3_AppendHandshakeNumber(ss, len + 3, 2); - if (rv != SECSuccess) return -1; - /* Name Type (host_name) */ - rv = ssl3_AppendHandshake(ss, "\0", 1); - if (rv != SECSuccess) return -1; - /* HostName (length and value) */ - rv = ssl3_AppendHandshakeVariable(ss, (unsigned char *)ss->url, len, 2); - if (rv != SECSuccess) return -1; - if (!ss->sec.isServer) { - TLSExtensionData *xtnData = &ss->xtnData; - xtnData->advertised[xtnData->numAdvertised++] = server_name_xtn; - } + /* Server side */ + if (append && maxBytes >= 4) { + rv = ssl3_AppendHandshakeNumber(ss, ssl_server_name_xtn, 2); + if (rv != SECSuccess) return -1; + /* length of extension_data */ + rv = ssl3_AppendHandshakeNumber(ss, 0, 2); + if (rv != SECSuccess) return -1; } - return len + 9; + return 4; } /* handle an incoming SNI extension, by ignoring it. */ SECStatus ssl3_HandleServerNameXtn(sslSocket * ss, PRUint16 ex_type, SECItem *data) { - /* TODO: if client, should verify extension_data is empty. */ - /* TODO: if server, should send empty extension_data. */ - /* For now, we ignore this, as if we didn't understand it. :-) */ + SECItem *names = NULL; + PRUint32 listCount = 0, namesPos = 0, i; + TLSExtensionData *xtnData = &ss->xtnData; + SECItem ldata; + PRInt32 listLenBytes = 0; + + if (!ss->sec.isServer) { + /* Verify extension_data is empty. */ + if (data->data || data->len || + !ssl3_ExtensionNegotiated(ss, ssl_server_name_xtn)) { + /* malformed or was not initiated by the client.*/ + return SECFailure; + } + return SECSuccess; + } + + /* Server side - consume client data and register server sender. */ + /* do not parse the data if don't have user extension handling function. */ + if (!ss->sniSocketConfig) { + return SECSuccess; + } + /* length of server_name_list */ + listLenBytes = ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, &data->len); + if (listLenBytes == 0 || listLenBytes != data->len) { + return SECFailure; + } + ldata = *data; + /* Calculate the size of the array.*/ + while (listLenBytes > 0) { + SECItem litem; + SECStatus rv; + PRInt32 type; + /* Name Type (sni_host_name) */ + type = ssl3_ConsumeHandshakeNumber(ss, 1, &ldata.data, &ldata.len); + if (!ldata.len) { + return SECFailure; + } + rv = ssl3_ConsumeHandshakeVariable(ss, &litem, 2, &ldata.data, &ldata.len); + if (rv != SECSuccess) { + return SECFailure; + } + /* Adjust total length for cunsumed item, item len and type.*/ + listLenBytes -= litem.len + 3; + if (listLenBytes > 0 && !ldata.len) { + return SECFailure; + } + listCount += 1; + } + if (!listCount) { + return SECFailure; + } + names = PORT_ZNewArray(SECItem, listCount); + if (!names) { + return SECFailure; + } + for (i = 0;i < listCount;i++) { + int j; + PRInt32 type; + SECStatus rv; + PRBool nametypePresent = PR_FALSE; + /* Name Type (sni_host_name) */ + type = ssl3_ConsumeHandshakeNumber(ss, 1, &data->data, &data->len); + /* Check if we have such type in the list */ + for (j = 0;j < listCount && names[j].data;j++) { + if (names[j].type == type) { + nametypePresent = PR_TRUE; + break; + } + } + /* HostName (length and value) */ + rv = ssl3_ConsumeHandshakeVariable(ss, &names[namesPos], 2, + &data->data, &data->len); + if (rv != SECSuccess) { + goto loser; + } + if (nametypePresent == PR_FALSE) { + namesPos += 1; + } + } + /* Free old and set the new data. */ + if (xtnData->sniNameArr) { + PORT_Free(ss->xtnData.sniNameArr); + } + xtnData->sniNameArr = names; + xtnData->sniNameArrSize = namesPos; + xtnData->negotiated[xtnData->numNegotiated++] = ssl_server_name_xtn; + return SECSuccess; -} +loser: + PORT_Free(names); + return SECFailure; +} + /* Called by both clients and servers. * Clients sends a filled in session ticket if one is available, and otherwise * sends an empty ticket. Servers always send empty tickets. @@ -386,7 +505,7 @@ ssl3_SendSessionTicketXtn( if (append && maxBytes >= extension_length) { SECStatus rv; /* extension_type */ - rv = ssl3_AppendHandshakeNumber(ss, session_ticket_xtn, 2); + rv = ssl3_AppendHandshakeNumber(ss, ssl_session_ticket_xtn, 2); if (rv != SECSuccess) goto loser; if (session_ticket && session_ticket->ticket.data && @@ -402,7 +521,8 @@ ssl3_SendSessionTicketXtn( if (!ss->sec.isServer) { TLSExtensionData *xtnData = &ss->xtnData; - xtnData->advertised[xtnData->numAdvertised++] = session_ticket_xtn; + xtnData->advertised[xtnData->numAdvertised++] = + ssl_session_ticket_xtn; } } else if (maxBytes < extension_length) { PORT_Assert(0); @@ -514,15 +634,14 @@ ssl3_ClientSendNextProtoNegoXtn(sslSocket * ss, if (append && maxBytes >= extension_length) { SECStatus rv; - TLSExtensionData *xtnData; - rv = ssl3_AppendHandshakeNumber(ss, next_proto_neg_xtn, 2); + rv = ssl3_AppendHandshakeNumber(ss, ssl_next_proto_neg_xtn, 2); if (rv != SECSuccess) goto loser; rv = ssl3_AppendHandshakeNumber(ss, 0, 2); if (rv != SECSuccess) goto loser; - xtnData = &ss->xtnData; - xtnData->advertised[xtnData->numAdvertised++] = next_proto_neg_xtn; + ss->xtnData.advertised[ss->xtnData.numAdvertised++] = + ssl_next_proto_neg_xtn; } else if (maxBytes < extension_length) { return 0; } @@ -575,6 +694,8 @@ ssl3_SendNewSessionTicket(sslSocket *ss) unsigned int computed_mac_length; unsigned char iv[AES_BLOCK_SIZE]; SECItem ivItem; + SECItem *srvName = NULL; + PRUint32 srvNameLen = 0; CK_MECHANISM_TYPE msWrapMech = 0; /* dummy default value, * must be >= 0 */ @@ -635,6 +756,11 @@ ssl3_SendNewSessionTicket(sslSocket *ss) } ms_is_wrapped = PR_TRUE; } + /* Prep to send negotiated name */ + srvName = &ss->ssl3.pwSpec->srvVirtName; + if (srvName->data && srvName->len) { + srvNameLen = 2 + srvName->len; /* len bytes + name len */ + } ciphertext_length = sizeof(PRUint16) /* ticket_version */ @@ -649,6 +775,8 @@ ssl3_SendNewSessionTicket(sslSocket *ss) + ms_item.len /* master_secret */ + 1 /* client_auth_type */ + cert_length /* cert */ + + 1 /* server name type */ + + srvNameLen /* name len + length field */ + sizeof(ticket.ticket_lifetime_hint); padding_length = AES_BLOCK_SIZE - (ciphertext_length % AES_BLOCK_SIZE); @@ -731,6 +859,22 @@ ssl3_SendNewSessionTicket(sslSocket *ss) sizeof(ticket.ticket_lifetime_hint)); if (rv != SECSuccess) goto loser; + if (srvNameLen) { + /* Name Type (sni_host_name) */ + rv = ssl3_AppendNumberToItem(&plaintext, srvName->type, 1); + if (rv != SECSuccess) goto loser; + /* HostName (length and value) */ + rv = ssl3_AppendNumberToItem(&plaintext, srvName->len, 2); + if (rv != SECSuccess) goto loser; + rv = ssl3_AppendToItem(&plaintext, srvName->data, srvName->len); + if (rv != SECSuccess) goto loser; + } else { + /* No Name */ + rv = ssl3_AppendNumberToItem(&plaintext, (char)TLS_STE_NO_SERVER_NAME, + 1); + if (rv != SECSuccess) goto loser; + } + PORT_Assert(plaintext.len == padding_length); for (i = 0; i < padding_length; i++) plaintext.data[i] = (unsigned char)padding_length; @@ -903,6 +1047,7 @@ ssl3_ServerHandleSessionTicketXtn(sslSocket *ss, PRUint16 ex_type, unsigned int buffer_len; PRInt32 temp; SECItem cert_item; + PRInt8 nameType = TLS_STE_NO_SERVER_NAME; /* Turn off stateless session resumption if the client sends a * SessionTicket extension, even if the extension turns out to be @@ -1155,6 +1300,20 @@ ssl3_ServerHandleSessionTicketXtn(sslSocket *ss, PRUint16 ex_type, goto no_ticket; parsed_session_ticket->timestamp = (PRUint32)temp; + /* Read server name */ + nameType = + ssl3_ConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len); + if (nameType != TLS_STE_NO_SERVER_NAME) { + SECItem name_item; + rv = ssl3_ConsumeHandshakeVariable(ss, &name_item, 2, &buffer, + &buffer_len); + if (rv != SECSuccess) goto no_ticket; + rv = SECITEM_CopyItem(NULL, &parsed_session_ticket->srvName, + &name_item); + if (rv != SECSuccess) goto no_ticket; + parsed_session_ticket->srvName.type = nameType; + } + /* Done parsing. Check that all bytes have been consumed. */ if (buffer_len != padding_length) goto no_ticket; @@ -1211,6 +1370,9 @@ ssl3_ServerHandleSessionTicketXtn(sslSocket *ss, PRUint16 ex_type, goto loser; } } + if (parsed_session_ticket->srvName.data != NULL) { + sid->u.ssl3.srvName = parsed_session_ticket->srvName; + } ss->statelessResume = PR_TRUE; ss->sec.ci.sid = sid; } @@ -1293,8 +1455,15 @@ ssl3_ParseEncryptedSessionTicket(sslSocket *ss, SECItem *data, SECStatus ssl3_HandleHelloExtensions(sslSocket *ss, SSL3Opaque **b, PRUint32 *length) { - const ssl3HelloExtensionHandler * handlers = - ss->sec.isServer ? clientHelloHandlers : serverHelloHandlers; + const ssl3HelloExtensionHandler * handlers; + + if (ss->sec.isServer) { + handlers = clientHelloHandlers; + } else if (ss->version > SSL_LIBRARY_VERSION_3_0) { + handlers = serverHelloHandlersTLS; + } else { + handlers = serverHelloHandlersSSL3; + } while (*length) { const ssl3HelloExtensionHandler * handler; @@ -1347,7 +1516,7 @@ ssl3_RegisterServerHelloExtensionSender(sslSocket *ss, PRUint16 ex_type, int i; ssl3HelloExtensionSender *sender = &ss->xtnData.serverSenders[0]; - for (i = 0; i < MAX_EXTENSIONS; ++i, ++sender) { + for (i = 0; i < SSL_MAX_EXTENSIONS; ++i, ++sender) { if (!sender->ex_sender) { sender->ex_type = ex_type; sender->ex_sender = cb; @@ -1360,7 +1529,7 @@ ssl3_RegisterServerHelloExtensionSender(sslSocket *ss, PRUint16 ex_type, break; } } - PORT_Assert(i < MAX_EXTENSIONS); /* table needs to grow */ + PORT_Assert(i < SSL_MAX_EXTENSIONS); /* table needs to grow */ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure; } @@ -1373,10 +1542,12 @@ ssl3_CallHelloExtensionSenders(sslSocket *ss, PRBool append, PRUint32 maxBytes, PRInt32 total_exten_len = 0; int i; - if (!sender) - sender = &clientHelloSenders[0]; + if (!sender) { + sender = ss->version > SSL_LIBRARY_VERSION_3_0 ? + &clientHelloSendersTLS[0] : &clientHelloSendersSSL3[0]; + } - for (i = 0; i < MAX_EXTENSIONS; ++i, ++sender) { + for (i = 0; i < SSL_MAX_EXTENSIONS; ++i, ++sender) { if (sender->ex_sender) { PRInt32 extLen = (*sender->ex_sender)(ss, append, maxBytes); if (extLen < 0) @@ -1387,3 +1558,82 @@ ssl3_CallHelloExtensionSenders(sslSocket *ss, PRBool append, PRUint32 maxBytes, } return total_exten_len; } + + +/* Extension format: + * Extension number: 2 bytes + * Extension length: 2 bytes + * Verify Data Length: 1 byte + * Verify Data (TLS): 12 bytes (client) or 24 bytes (server) + * Verify Data (SSL): 36 bytes (client) or 72 bytes (server) + */ +static PRInt32 +ssl3_SendRenegotiationInfoXtn( + sslSocket * ss, + PRBool append, + PRUint32 maxBytes) +{ + PRInt32 len, needed; + + /* In draft-ietf-tls-renegotiation-03, it is NOT RECOMMENDED to send + * both the SCSV and the empty RI, so when we send SCSV in + * the initial handshake, we don't also send RI. + */ + if (!ss || ss->ssl3.hs.sendingSCSV) + return 0; + len = !ss->firstHsDone ? 0 : + (ss->sec.isServer ? ss->ssl3.hs.finishedBytes * 2 + : ss->ssl3.hs.finishedBytes); + needed = 5 + len; + if (append && maxBytes >= needed) { + SECStatus rv; + /* extension_type */ + rv = ssl3_AppendHandshakeNumber(ss, ssl_renegotiation_info_xtn, 2); + if (rv != SECSuccess) return -1; + /* length of extension_data */ + rv = ssl3_AppendHandshakeNumber(ss, len + 1, 2); + if (rv != SECSuccess) return -1; + /* verify_Data from previous Finished message(s) */ + rv = ssl3_AppendHandshakeVariable(ss, + ss->ssl3.hs.finishedMsgs.data, len, 1); + if (rv != SECSuccess) return -1; + if (!ss->sec.isServer) { + TLSExtensionData *xtnData = &ss->xtnData; + xtnData->advertised[xtnData->numAdvertised++] = + ssl_renegotiation_info_xtn; + } + } + return needed; +} + +/* This function runs in both the client and server. */ +static SECStatus +ssl3_HandleRenegotiationInfoXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data) +{ + SECStatus rv = SECSuccess; + PRUint32 len = 0; + + if (ss->firstHsDone) { + len = ss->sec.isServer ? ss->ssl3.hs.finishedBytes + : ss->ssl3.hs.finishedBytes * 2; + } + if (data->len != 1 + len || + data->data[0] != len || (len && + NSS_SecureMemcmp(ss->ssl3.hs.finishedMsgs.data, + data->data + 1, len))) { + /* Can we do this here? Or, must we arrange for the caller to do it? */ + (void)SSL3_SendAlert(ss, alert_fatal, handshake_failure); + PORT_SetError(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE); + return SECFailure; + } + /* remember that we got this extension and it was correct. */ + ss->peerRequestedProtection = 1; + ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type; + if (ss->sec.isServer) { + /* prepare to send back the appropriate response */ + rv = ssl3_RegisterServerHelloExtensionSender(ss, ex_type, + ssl3_SendRenegotiationInfoXtn); + } + return rv; +} + |