diff options
Diffstat (limited to 'security/nss/lib/ssl/ssl3exthandle.c')
-rw-r--r-- | security/nss/lib/ssl/ssl3exthandle.c | 1311 |
1 files changed, 816 insertions, 495 deletions
diff --git a/security/nss/lib/ssl/ssl3exthandle.c b/security/nss/lib/ssl/ssl3exthandle.c index c0fbda7ab8..370bd8b3e4 100644 --- a/security/nss/lib/ssl/ssl3exthandle.c +++ b/security/nss/lib/ssl/ssl3exthandle.c @@ -13,6 +13,7 @@ #include "blapit.h" #include "prinit.h" #include "selfencrypt.h" +#include "ssl3encode.h" #include "ssl3ext.h" #include "ssl3exthandle.h" #include "tls13exthandle.h" /* For tls13_ServerSendStatusRequestXtn. */ @@ -21,48 +22,70 @@ * unless that name is a dotted decimal string. * Used by client and server. */ -SECStatus -ssl3_ClientSendServerNameXtn(const sslSocket *ss, TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added) +PRInt32 +ssl3_SendServerNameXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, + PRUint32 maxBytes) { - unsigned int len; - PRNetAddr netAddr; SECStatus rv; - - /* must have a hostname */ - if (!ss->url || !ss->url[0]) { - return SECSuccess; - } - /* must not be an IPv4 or IPv6 address */ - if (PR_SUCCESS == PR_StringToNetAddr(ss->url, &netAddr)) { - /* is an IP address (v4 or v6) */ - return SECSuccess; - } - len = PORT_Strlen(ss->url); - /* length of server_name_list */ - rv = sslBuffer_AppendNumber(buf, len + 3, 2); - if (rv != SECSuccess) { - return SECFailure; - } - /* Name Type (sni_host_name) */ - rv = sslBuffer_AppendNumber(buf, 0, 1); - if (rv != SECSuccess) { - return SECFailure; + if (!ss) + return 0; + if (!ss->sec.isServer) { + PRUint32 len; + PRNetAddr netAddr; + + /* must have a hostname */ + if (!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_ExtAppendHandshakeNumber(ss, ssl_server_name_xtn, 2); + if (rv != SECSuccess) + return -1; + /* length of extension_data */ + rv = ssl3_ExtAppendHandshakeNumber(ss, len + 5, 2); + if (rv != SECSuccess) + return -1; + /* length of server_name_list */ + rv = ssl3_ExtAppendHandshakeNumber(ss, len + 3, 2); + if (rv != SECSuccess) + return -1; + /* Name Type (sni_host_name) */ + rv = ssl3_ExtAppendHandshake(ss, "\0", 1); + if (rv != SECSuccess) + return -1; + /* HostName (length and value) */ + rv = ssl3_ExtAppendHandshakeVariable(ss, (PRUint8 *)ss->url, len, 2); + if (rv != SECSuccess) + return -1; + if (!ss->sec.isServer) { + xtnData->advertised[xtnData->numAdvertised++] = + ssl_server_name_xtn; + } + } + return len + 9; } - /* HostName (length and value) */ - rv = sslBuffer_AppendVariable(buf, (const PRUint8 *)ss->url, len, 2); - if (rv != SECSuccess) { - return SECFailure; + /* Server side */ + if (append && maxBytes >= 4) { + rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_server_name_xtn, 2); + if (rv != SECSuccess) + return -1; + /* length of extension_data */ + rv = ssl3_ExtAppendHandshakeNumber(ss, 0, 2); + if (rv != SECSuccess) + return -1; } - - *added = PR_TRUE; - return SECSuccess; + return 4; } /* Handle an incoming SNI extension. */ SECStatus -ssl3_HandleServerNameXtn(const sslSocket *ss, TLSExtensionData *xtnData, - SECItem *data) +ssl3_HandleServerNameXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) { SECItem *names = NULL; PRUint32 listLenBytes = 0; @@ -171,54 +194,88 @@ ssl3_FreeSniNameArray(TLSExtensionData *xtnData) * sends an empty ticket. Servers always send empty tickets. */ PRInt32 -ssl3_ClientSendSessionTicketXtn(const sslSocket *ss, TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added) +ssl3_SendSessionTicketXtn( + const sslSocket *ss, + TLSExtensionData *xtnData, + PRBool append, + PRUint32 maxBytes) { + PRInt32 extension_length; NewSessionTicket *session_ticket = NULL; sslSessionID *sid = ss->sec.ci.sid; - SECStatus rv; - - PORT_Assert(!ss->sec.isServer); /* Never send an extension with a ticket for TLS 1.3, but * OK to send the empty one in case the server does 1.2. */ if (sid->cached == in_client_cache && sid->version >= SSL_LIBRARY_VERSION_TLS_1_3) { - return SECSuccess; + return 0; } /* Ignore the SessionTicket extension if processing is disabled. */ - if (!ss->opt.enableSessionTickets) { - return SECSuccess; - } + if (!ss->opt.enableSessionTickets) + return 0; - /* Send a session ticket if one is available. - * - * The caller must be holding sid->u.ssl3.lock for reading. We cannot - * just acquire and release the lock within this function because the - * caller will call this function twice, and we need the inputs to be - * consistent between the two calls. Note that currently the caller - * will only be holding the lock when we are the client and when we're - * attempting to resume an existing session. + /* Empty extension length = extension_type (2-bytes) + + * length(extension_data) (2-bytes) */ - session_ticket = &sid->u.ssl3.locked.sessionTicket; - if (session_ticket->ticket.data && - (xtnData->ticketTimestampVerified || - ssl_TicketTimeValid(session_ticket))) { + extension_length = 4; - xtnData->ticketTimestampVerified = PR_FALSE; + /* If we are a client then send a session ticket if one is availble. + * Servers that support the extension and are willing to negotiate the + * the extension always respond with an empty extension. + */ + if (!ss->sec.isServer) { + /* The caller must be holding sid->u.ssl3.lock for reading. We cannot + * just acquire and release the lock within this function because the + * caller will call this function twice, and we need the inputs to be + * consistent between the two calls. Note that currently the caller + * will only be holding the lock when we are the client and when we're + * attempting to resume an existing session. + */ - rv = sslBuffer_Append(buf, session_ticket->ticket.data, - session_ticket->ticket.len); - if (rv != SECSuccess) { - return SECFailure; + session_ticket = &sid->u.ssl3.locked.sessionTicket; + if (session_ticket->ticket.data) { + if (xtnData->ticketTimestampVerified) { + extension_length += session_ticket->ticket.len; + } else if (!append && ssl_TicketTimeValid(session_ticket)) { + extension_length += session_ticket->ticket.len; + xtnData->ticketTimestampVerified = PR_TRUE; + } } + } - xtnData->sentSessionTicketInClientHello = PR_TRUE; + if (maxBytes < (PRUint32)extension_length) { + PORT_Assert(0); + return 0; } + if (append) { + SECStatus rv; + /* extension_type */ + rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_session_ticket_xtn, 2); + if (rv != SECSuccess) + goto loser; + if (session_ticket && session_ticket->ticket.data && + xtnData->ticketTimestampVerified) { + rv = ssl3_ExtAppendHandshakeVariable(ss, session_ticket->ticket.data, + session_ticket->ticket.len, 2); + xtnData->ticketTimestampVerified = PR_FALSE; + xtnData->sentSessionTicketInClientHello = PR_TRUE; + } else { + rv = ssl3_ExtAppendHandshakeNumber(ss, 0, 2); + } + if (rv != SECSuccess) + goto loser; - *added = PR_TRUE; - return SECSuccess; + if (!ss->sec.isServer) { + xtnData->advertised[xtnData->numAdvertised++] = + ssl_session_ticket_xtn; + } + } + return extension_length; + +loser: + xtnData->ticketTimestampVerified = PR_FALSE; + return -1; } PRBool @@ -244,18 +301,16 @@ ssl_AlpnTagAllowed(const sslSocket *ss, const SECItem *tag) /* handle an incoming Next Protocol Negotiation extension. */ SECStatus -ssl3_ServerHandleNextProtoNegoXtn(const sslSocket *ss, TLSExtensionData *xtnData, +ssl3_ServerHandleNextProtoNegoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) { - PORT_Assert(ss->version < SSL_LIBRARY_VERSION_TLS_1_3); - if (ss->firstHsDone || data->len != 0) { /* Clients MUST send an empty NPN extension, if any. */ PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID); return SECFailure; } - xtnData->negotiated[xtnData->numNegotiated++] = ssl_next_proto_nego_xtn; + xtnData->negotiated[xtnData->numNegotiated++] = ex_type; /* TODO: server side NPN support would require calling * ssl3_RegisterServerHelloExtensionSender here in order to echo the @@ -289,7 +344,7 @@ ssl3_ValidateNextProtoNego(const unsigned char *data, unsigned int length) /* protocol selection handler for ALPN (server side) and NPN (client side) */ static SECStatus ssl3_SelectAppProtocol(const sslSocket *ss, TLSExtensionData *xtnData, - PRUint16 extension, SECItem *data) + PRUint16 ex_type, SECItem *data) { SECStatus rv; unsigned char resultBuffer[255]; @@ -326,7 +381,7 @@ ssl3_SelectAppProtocol(const sslSocket *ss, TLSExtensionData *xtnData, SECITEM_FreeItem(&xtnData->nextProto, PR_FALSE); - if (extension == ssl_app_layer_protocol_xtn && + if (ex_type == ssl_app_layer_protocol_xtn && xtnData->nextProtoState != SSL_NEXT_PROTO_NEGOTIATED) { /* The callback might say OK, but then it picks a default value - one * that was not listed. That's OK for NPN, but not ALPN. */ @@ -335,14 +390,13 @@ ssl3_SelectAppProtocol(const sslSocket *ss, TLSExtensionData *xtnData, return SECFailure; } - xtnData->negotiated[xtnData->numNegotiated++] = extension; + xtnData->negotiated[xtnData->numNegotiated++] = ex_type; return SECITEM_CopyItem(NULL, &xtnData->nextProto, &result); } /* handle an incoming ALPN extension at the server */ SECStatus -ssl3_ServerHandleAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, - SECItem *data) +ssl3_ServerHandleAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) { PRUint32 count; SECStatus rv; @@ -369,16 +423,15 @@ ssl3_ServerHandleAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, return SECSuccess; } - rv = ssl3_SelectAppProtocol(ss, xtnData, ssl_app_layer_protocol_xtn, data); + rv = ssl3_SelectAppProtocol(ss, xtnData, ex_type, data); if (rv != SECSuccess) { return rv; } /* prepare to send back a response, if we negotiated */ if (xtnData->nextProtoState == SSL_NEXT_PROTO_NEGOTIATED) { - rv = ssl3_RegisterExtensionSender(ss, xtnData, - ssl_app_layer_protocol_xtn, - ssl3_ServerSendAppProtoXtn); + rv = ssl3_RegisterExtensionSender( + ss, xtnData, ex_type, ssl3_ServerSendAppProtoXtn); if (rv != SECSuccess) { ssl3_ExtSendAlert(ss, alert_fatal, internal_error); PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); @@ -389,10 +442,9 @@ ssl3_ServerHandleAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, } SECStatus -ssl3_ClientHandleNextProtoNegoXtn(const sslSocket *ss, TLSExtensionData *xtnData, +ssl3_ClientHandleNextProtoNegoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) { - PORT_Assert(ss->version < SSL_LIBRARY_VERSION_TLS_1_3); PORT_Assert(!ss->firstHsDone); if (ssl3_ExtensionNegotiated(ss, ssl_app_layer_protocol_xtn)) { @@ -418,12 +470,11 @@ ssl3_ClientHandleNextProtoNegoXtn(const sslSocket *ss, TLSExtensionData *xtnData return SECFailure; } - return ssl3_SelectAppProtocol(ss, xtnData, ssl_next_proto_nego_xtn, data); + return ssl3_SelectAppProtocol(ss, xtnData, ex_type, data); } SECStatus -ssl3_ClientHandleAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, - SECItem *data) +ssl3_ClientHandleAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) { SECStatus rv; PRUint32 list_len; @@ -470,168 +521,265 @@ ssl3_ClientHandleAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, SECITEM_FreeItem(&xtnData->nextProto, PR_FALSE); xtnData->nextProtoState = SSL_NEXT_PROTO_SELECTED; - xtnData->negotiated[xtnData->numNegotiated++] = ssl_app_layer_protocol_xtn; + xtnData->negotiated[xtnData->numNegotiated++] = ex_type; return SECITEM_CopyItem(NULL, &xtnData->nextProto, &protocol_name); } -SECStatus -ssl3_ClientSendNextProtoNegoXtn(const sslSocket *ss, TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added) +PRInt32 +ssl3_ClientSendNextProtoNegoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, + PRUint32 maxBytes) { + PRInt32 extension_length; + /* Renegotiations do not send this extension. */ if (!ss->opt.enableNPN || !ss->nextProtoCallback || ss->firstHsDone) { - return SECSuccess; + return 0; } - *added = PR_TRUE; - return SECSuccess; + extension_length = 4; + + if (maxBytes < (PRUint32)extension_length) { + return 0; + } + if (append) { + SECStatus rv; + rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_next_proto_nego_xtn, 2); + if (rv != SECSuccess) + goto loser; + rv = ssl3_ExtAppendHandshakeNumber(ss, 0, 2); + if (rv != SECSuccess) + goto loser; + xtnData->advertised[xtnData->numAdvertised++] = + ssl_next_proto_nego_xtn; + } + + return extension_length; + +loser: + return -1; } -SECStatus -ssl3_ClientSendAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added) +PRInt32 +ssl3_ClientSendAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, PRUint32 maxBytes) { - SECStatus rv; - const unsigned int len = ss->opt.nextProtoNego.len; + PRInt32 extension_length; + unsigned char *alpn_protos = NULL; /* Renegotiations do not send this extension. */ if (!ss->opt.enableALPN || !ss->opt.nextProtoNego.data || ss->firstHsDone) { - return SECSuccess; + return 0; } - /* NPN requires that the client's fallback protocol is first in the - * list. However, ALPN sends protocols in preference order. So move the - * first protocol to the end of the list. */ + extension_length = 2 /* extension type */ + 2 /* extension length */ + + 2 /* protocol name list length */ + + ss->opt.nextProtoNego.len; - if (len > 0) { - /* Each protocol string is prefixed with a single byte length. */ - unsigned int i; + if (maxBytes < (PRUint32)extension_length) { + return 0; + } + if (append) { + /* NPN requires that the client's fallback protocol is first in the + * list. However, ALPN sends protocols in preference order. So we + * allocate a buffer and move the first protocol to the end of the + * list. */ + SECStatus rv; + const unsigned int len = ss->opt.nextProtoNego.len; - rv = sslBuffer_AppendNumber(buf, len, 2); - if (rv != SECSuccess) { + alpn_protos = PORT_Alloc(len); + if (alpn_protos == NULL) { return SECFailure; } - - i = ss->opt.nextProtoNego.data[0] + 1; - if (i <= len) { - rv = sslBuffer_Append(buf, &ss->opt.nextProtoNego.data[i], len - i); - if (rv != SECSuccess) { - return SECFailure; - } - rv = sslBuffer_Append(buf, ss->opt.nextProtoNego.data, i); - if (rv != SECSuccess) { - return SECFailure; - } - } else { - /* This seems to be invalid data so we'll send as-is. */ - rv = sslBuffer_Append(buf, ss->opt.nextProtoNego.data, len); - if (rv != SECSuccess) { - return SECFailure; + if (len > 0) { + /* Each protocol string is prefixed with a single byte length. */ + unsigned int i = ss->opt.nextProtoNego.data[0] + 1; + if (i <= len) { + memcpy(alpn_protos, &ss->opt.nextProtoNego.data[i], len - i); + memcpy(alpn_protos + len - i, ss->opt.nextProtoNego.data, i); + } else { + /* This seems to be invalid data so we'll send as-is. */ + memcpy(alpn_protos, ss->opt.nextProtoNego.data, len); } } + + rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_app_layer_protocol_xtn, 2); + if (rv != SECSuccess) { + goto loser; + } + rv = ssl3_ExtAppendHandshakeNumber(ss, extension_length - 4, 2); + if (rv != SECSuccess) { + goto loser; + } + rv = ssl3_ExtAppendHandshakeVariable(ss, alpn_protos, len, 2); + PORT_Free(alpn_protos); + alpn_protos = NULL; + if (rv != SECSuccess) { + goto loser; + } + xtnData->advertised[xtnData->numAdvertised++] = + ssl_app_layer_protocol_xtn; } - *added = PR_TRUE; - return SECSuccess; + return extension_length; + +loser: + if (alpn_protos) { + PORT_Free(alpn_protos); + } + return -1; } -SECStatus -ssl3_ServerSendAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added) +PRInt32 +ssl3_ServerSendAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, PRUint32 maxBytes) { - SECStatus rv; + PRInt32 extension_length; - /* We're in over our heads if any of these fail */ + /* we're in over our heads if any of these fail */ PORT_Assert(ss->opt.enableALPN); PORT_Assert(xtnData->nextProto.data); PORT_Assert(xtnData->nextProto.len > 0); PORT_Assert(xtnData->nextProtoState == SSL_NEXT_PROTO_NEGOTIATED); PORT_Assert(!ss->firstHsDone); - rv = sslBuffer_AppendNumber(buf, xtnData->nextProto.len + 1, 2); - if (rv != SECSuccess) { - return SECFailure; + extension_length = 2 /* extension type */ + 2 /* extension length */ + + 2 /* protocol name list */ + 1 /* name length */ + + xtnData->nextProto.len; + + if (maxBytes < (PRUint32)extension_length) { + return 0; } - rv = sslBuffer_AppendVariable(buf, xtnData->nextProto.data, - xtnData->nextProto.len, 1); - if (rv != SECSuccess) { - return SECFailure; + if (append) { + SECStatus rv; + rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_app_layer_protocol_xtn, 2); + if (rv != SECSuccess) { + return -1; + } + rv = ssl3_ExtAppendHandshakeNumber(ss, extension_length - 4, 2); + if (rv != SECSuccess) { + return -1; + } + rv = ssl3_ExtAppendHandshakeNumber(ss, xtnData->nextProto.len + 1, 2); + if (rv != SECSuccess) { + return -1; + } + rv = ssl3_ExtAppendHandshakeVariable(ss, xtnData->nextProto.data, + xtnData->nextProto.len, 1); + if (rv != SECSuccess) { + return -1; + } } - *added = PR_TRUE; - return SECSuccess; + return extension_length; } SECStatus -ssl3_ServerHandleStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData, +ssl3_ServerHandleStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) { - sslExtensionBuilderFunc sender; + ssl3HelloExtensionSenderFunc sender; PORT_Assert(ss->sec.isServer); /* remember that we got this extension. */ - xtnData->negotiated[xtnData->numNegotiated++] = ssl_cert_status_xtn; + xtnData->negotiated[xtnData->numNegotiated++] = ex_type; if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) { sender = tls13_ServerSendStatusRequestXtn; } else { sender = ssl3_ServerSendStatusRequestXtn; } - return ssl3_RegisterExtensionSender(ss, xtnData, ssl_cert_status_xtn, sender); + return ssl3_RegisterExtensionSender(ss, xtnData, ex_type, sender); } -SECStatus -ssl3_ServerSendStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added) +PRInt32 +ssl3_ServerSendStatusRequestXtn( + const sslSocket *ss, + TLSExtensionData *xtnData, + PRBool append, + PRUint32 maxBytes) { + PRInt32 extension_length; const sslServerCert *serverCert = ss->sec.serverCert; + SECStatus rv; if (!serverCert->certStatusArray || !serverCert->certStatusArray->len) { - return SECSuccess; + return 0; } - *added = PR_TRUE; - return SECSuccess; + extension_length = 2 + 2; + if (maxBytes < (PRUint32)extension_length) { + return 0; + } + if (append) { + /* extension_type */ + rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_cert_status_xtn, 2); + if (rv != SECSuccess) + return -1; + /* length of extension_data */ + rv = ssl3_ExtAppendHandshakeNumber(ss, 0, 2); + if (rv != SECSuccess) + return -1; + /* The certificate status data is sent in ssl3_SendCertificateStatus. */ + } + + return extension_length; } /* ssl3_ClientSendStatusRequestXtn builds the status_request extension on the * client side. See RFC 6066 section 8. */ -SECStatus -ssl3_ClientSendStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added) +PRInt32 +ssl3_ClientSendStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, + PRUint32 maxBytes) { - SECStatus rv; + PRInt32 extension_length; - if (!ss->opt.enableOCSPStapling) { - return SECSuccess; - } + if (!ss->opt.enableOCSPStapling) + return 0; - rv = sslBuffer_AppendNumber(buf, 1 /* status_type ocsp */, 1); - if (rv != SECSuccess) { - return SECFailure; - } - /* A zero length responder_id_list means that the responders are - * implicitly known to the server. */ - rv = sslBuffer_AppendNumber(buf, 0, 2); - if (rv != SECSuccess) { - return SECFailure; - } - /* A zero length request_extensions means that there are no extensions. - * Specifically, we don't set the id-pkix-ocsp-nonce extension. This - * means that the server can replay a cached OCSP response to us. */ - rv = sslBuffer_AppendNumber(buf, 0, 2); - if (rv != SECSuccess) { - return SECFailure; + /* extension_type (2-bytes) + + * length(extension_data) (2-bytes) + + * status_type (1) + + * responder_id_list length (2) + + * request_extensions length (2) + */ + extension_length = 9; + + if (maxBytes < (PRUint32)extension_length) { + PORT_Assert(0); + return 0; } + if (append) { + SECStatus rv; - *added = PR_TRUE; - return SECSuccess; + /* extension_type */ + rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_cert_status_xtn, 2); + if (rv != SECSuccess) + return -1; + rv = ssl3_ExtAppendHandshakeNumber(ss, extension_length - 4, 2); + if (rv != SECSuccess) + return -1; + rv = ssl3_ExtAppendHandshakeNumber(ss, 1 /* status_type ocsp */, 1); + if (rv != SECSuccess) + return -1; + /* A zero length responder_id_list means that the responders are + * implicitly known to the server. */ + rv = ssl3_ExtAppendHandshakeNumber(ss, 0, 2); + if (rv != SECSuccess) + return -1; + /* A zero length request_extensions means that there are no extensions. + * Specifically, we don't set the id-pkix-ocsp-nonce extension. This + * means that the server can replay a cached OCSP response to us. */ + rv = ssl3_ExtAppendHandshakeNumber(ss, 0, 2); + if (rv != SECSuccess) + return -1; + + xtnData->advertised[xtnData->numAdvertised++] = ssl_cert_status_xtn; + } + return extension_length; } SECStatus -ssl3_ClientHandleStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData, +ssl3_ClientHandleStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) { /* In TLS 1.3, the extension carries the OCSP response. */ @@ -649,32 +797,36 @@ ssl3_ClientHandleStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData } /* Keep track of negotiated extensions. */ - xtnData->negotiated[xtnData->numNegotiated++] = ssl_cert_status_xtn; + xtnData->negotiated[xtnData->numNegotiated++] = ex_type; return SECSuccess; } PRUint32 ssl_ticket_lifetime = 2 * 24 * 60 * 60; /* 2 days in seconds */ -#define TLS_EX_SESS_TICKET_VERSION (0x010a) +#define TLS_EX_SESS_TICKET_VERSION (0x0105) /* * Called from ssl3_SendNewSessionTicket, tls13_SendNewSessionTicket */ SECStatus -ssl3_EncodeSessionTicket(sslSocket *ss, const NewSessionTicket *ticket, - const PRUint8 *appToken, unsigned int appTokenLen, - PK11SymKey *secret, SECItem *ticket_data) +ssl3_EncodeSessionTicket(sslSocket *ss, + const NewSessionTicket *ticket, + SECItem *ticket_data) { SECStatus rv; - sslBuffer plaintext = SSL_BUFFER_EMPTY; + SECItem plaintext; + SECItem plaintext_item = { 0, NULL, 0 }; + PRUint32 plaintext_length; SECItem ticket_buf = { 0, NULL, 0 }; - sslSessionID sid; + PRBool ms_is_wrapped; unsigned char wrapped_ms[SSL3_MASTER_SECRET_LENGTH]; SECItem ms_item = { 0, NULL, 0 }; - PRTime now; + PRUint32 cert_length = 0; + PRUint32 now; SECItem *srvName = NULL; - CK_MECHANISM_TYPE msWrapMech; + CK_MECHANISM_TYPE msWrapMech = 0; /* dummy default value, + * must be >= 0 */ + ssl3CipherSpec *spec; SECItem *alpnSelection = NULL; - PRUint32 ticketAgeBaseline; SSL_TRC(3, ("%d: SSL3[%d]: send session_ticket handshake", SSL_GETPID(), ss->fd)); @@ -682,69 +834,107 @@ ssl3_EncodeSessionTicket(sslSocket *ss, const NewSessionTicket *ticket, PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - /* Extract the master secret wrapped. */ + if (ss->opt.requestCertificate && ss->sec.ci.sid->peerCert) { + cert_length = 2 + ss->sec.ci.sid->peerCert->derCert.len; + } - PORT_Memset(&sid, 0, sizeof(sslSessionID)); + if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) { + spec = ss->ssl3.cwSpec; + } else { + spec = ss->ssl3.pwSpec; + } + if (spec->msItem.len && spec->msItem.data) { + /* The master secret is available unwrapped. */ + ms_item.data = spec->msItem.data; + ms_item.len = spec->msItem.len; + ms_is_wrapped = PR_FALSE; + } else { + /* Extract the master secret wrapped. */ + sslSessionID sid; + PORT_Memset(&sid, 0, sizeof(sslSessionID)); - PORT_Assert(secret); - rv = ssl3_CacheWrappedSecret(ss, &sid, secret); - if (rv == SECSuccess) { - if (sid.u.ssl3.keys.wrapped_master_secret_len > sizeof(wrapped_ms)) + rv = ssl3_CacheWrappedMasterSecret(ss, &sid, spec); + if (rv == SECSuccess) { + if (sid.u.ssl3.keys.wrapped_master_secret_len > sizeof(wrapped_ms)) + goto loser; + memcpy(wrapped_ms, sid.u.ssl3.keys.wrapped_master_secret, + sid.u.ssl3.keys.wrapped_master_secret_len); + ms_item.data = wrapped_ms; + ms_item.len = sid.u.ssl3.keys.wrapped_master_secret_len; + msWrapMech = sid.u.ssl3.masterWrapMech; + } else { + /* TODO: else send an empty ticket. */ goto loser; - memcpy(wrapped_ms, sid.u.ssl3.keys.wrapped_master_secret, - sid.u.ssl3.keys.wrapped_master_secret_len); - ms_item.data = wrapped_ms; - ms_item.len = sid.u.ssl3.keys.wrapped_master_secret_len; - msWrapMech = sid.u.ssl3.masterWrapMech; - } else { - /* TODO: else send an empty ticket. */ - goto loser; + } + ms_is_wrapped = PR_TRUE; } /* Prep to send negotiated name */ srvName = &ss->sec.ci.sid->u.ssl3.srvName; + PORT_Assert(ss->xtnData.nextProtoState == SSL_NEXT_PROTO_SELECTED || + ss->xtnData.nextProtoState == SSL_NEXT_PROTO_NEGOTIATED || + ss->xtnData.nextProto.len == 0); + alpnSelection = &ss->xtnData.nextProto; + + plaintext_length = + sizeof(PRUint16) /* ticket version */ + + sizeof(SSL3ProtocolVersion) /* ssl_version */ + + sizeof(ssl3CipherSuite) /* ciphersuite */ + + 1 /* compression */ + + 10 /* cipher spec parameters */ + + 1 /* certType arguments */ + + 1 /* SessionTicket.ms_is_wrapped */ + + 4 /* msWrapMech */ + + 2 /* master_secret.length */ + + ms_item.len /* master_secret */ + + 1 /* client_auth_type */ + + cert_length /* cert */ + + 2 + srvName->len /* name len + length field */ + + 1 /* extendedMasterSecretUsed */ + + sizeof(ticket->ticket_lifetime_hint) /* ticket lifetime hint */ + + sizeof(ticket->flags) /* ticket flags */ + + 1 + alpnSelection->len /* alpn value + length field */ + + 4; /* maxEarlyData */ + + if (SECITEM_AllocItem(NULL, &plaintext_item, plaintext_length) == NULL) + goto loser; + + plaintext = plaintext_item; + /* ticket version */ - rv = sslBuffer_AppendNumber(&plaintext, TLS_EX_SESS_TICKET_VERSION, - sizeof(PRUint16)); + rv = ssl3_AppendNumberToItem(&plaintext, TLS_EX_SESS_TICKET_VERSION, + sizeof(PRUint16)); if (rv != SECSuccess) goto loser; /* ssl_version */ - rv = sslBuffer_AppendNumber(&plaintext, ss->version, - sizeof(SSL3ProtocolVersion)); + rv = ssl3_AppendNumberToItem(&plaintext, ss->version, + sizeof(SSL3ProtocolVersion)); if (rv != SECSuccess) goto loser; /* ciphersuite */ - rv = sslBuffer_AppendNumber(&plaintext, ss->ssl3.hs.cipher_suite, - sizeof(ssl3CipherSuite)); + rv = ssl3_AppendNumberToItem(&plaintext, ss->ssl3.hs.cipher_suite, + sizeof(ssl3CipherSuite)); if (rv != SECSuccess) goto loser; - /* cipher spec parameters */ - rv = sslBuffer_AppendNumber(&plaintext, ss->sec.authType, 1); + /* compression */ + rv = ssl3_AppendNumberToItem(&plaintext, ss->ssl3.hs.compression, 1); if (rv != SECSuccess) goto loser; - rv = sslBuffer_AppendNumber(&plaintext, ss->sec.authKeyBits, 4); + + /* cipher spec parameters */ + rv = ssl3_AppendNumberToItem(&plaintext, ss->sec.authType, 1); if (rv != SECSuccess) goto loser; - rv = sslBuffer_AppendNumber(&plaintext, ss->sec.keaType, 1); + rv = ssl3_AppendNumberToItem(&plaintext, ss->sec.authKeyBits, 4); if (rv != SECSuccess) goto loser; - rv = sslBuffer_AppendNumber(&plaintext, ss->sec.keaKeyBits, 4); + rv = ssl3_AppendNumberToItem(&plaintext, ss->sec.keaType, 1); if (rv != SECSuccess) goto loser; - if (ss->sec.keaGroup) { - rv = sslBuffer_AppendNumber(&plaintext, ss->sec.keaGroup->name, 4); - if (rv != SECSuccess) - goto loser; - } else { - /* No kea group. Write 0 as invalid value. */ - rv = sslBuffer_AppendNumber(&plaintext, 0, 4); - if (rv != SECSuccess) - goto loser; - } - rv = sslBuffer_AppendNumber(&plaintext, ss->sec.signatureScheme, 4); + rv = ssl3_AppendNumberToItem(&plaintext, ss->sec.keaKeyBits, 4); if (rv != SECSuccess) goto loser; @@ -755,120 +945,102 @@ ssl3_EncodeSessionTicket(sslSocket *ss, const NewSessionTicket *ticket, PORT_Assert(cert->namedCurve); /* EC curves only use the second of the two bytes. */ PORT_Assert(cert->namedCurve->name < 256); - rv = sslBuffer_AppendNumber(&plaintext, cert->namedCurve->name, 1); + rv = ssl3_AppendNumberToItem(&plaintext, cert->namedCurve->name, 1); } else { - rv = sslBuffer_AppendNumber(&plaintext, 0, 1); + rv = ssl3_AppendNumberToItem(&plaintext, 0, 1); } if (rv != SECSuccess) goto loser; /* master_secret */ - rv = sslBuffer_AppendNumber(&plaintext, msWrapMech, 4); + rv = ssl3_AppendNumberToItem(&plaintext, ms_is_wrapped, 1); + if (rv != SECSuccess) + goto loser; + rv = ssl3_AppendNumberToItem(&plaintext, msWrapMech, 4); if (rv != SECSuccess) goto loser; - rv = sslBuffer_AppendVariable(&plaintext, ms_item.data, ms_item.len, 2); + rv = ssl3_AppendNumberToItem(&plaintext, ms_item.len, 2); + if (rv != SECSuccess) + goto loser; + rv = ssl3_AppendToItem(&plaintext, ms_item.data, ms_item.len); if (rv != SECSuccess) goto loser; /* client identity */ if (ss->opt.requestCertificate && ss->sec.ci.sid->peerCert) { - rv = sslBuffer_AppendNumber(&plaintext, CLIENT_AUTH_CERTIFICATE, 1); + rv = ssl3_AppendNumberToItem(&plaintext, CLIENT_AUTH_CERTIFICATE, 1); + if (rv != SECSuccess) + goto loser; + rv = ssl3_AppendNumberToItem(&plaintext, + ss->sec.ci.sid->peerCert->derCert.len, 2); if (rv != SECSuccess) goto loser; - rv = sslBuffer_AppendVariable(&plaintext, - ss->sec.ci.sid->peerCert->derCert.data, - ss->sec.ci.sid->peerCert->derCert.len, 2); + rv = ssl3_AppendToItem(&plaintext, + ss->sec.ci.sid->peerCert->derCert.data, + ss->sec.ci.sid->peerCert->derCert.len); if (rv != SECSuccess) goto loser; } else { - rv = sslBuffer_AppendNumber(&plaintext, 0, 1); + rv = ssl3_AppendNumberToItem(&plaintext, 0, 1); if (rv != SECSuccess) goto loser; } /* timestamp */ - now = ssl_TimeUsec(); - PORT_Assert(sizeof(now) == 8); - rv = sslBuffer_AppendNumber(&plaintext, now, 8); + now = ssl_Time(); + rv = ssl3_AppendNumberToItem(&plaintext, now, + sizeof(ticket->ticket_lifetime_hint)); if (rv != SECSuccess) goto loser; /* HostName (length and value) */ - rv = sslBuffer_AppendVariable(&plaintext, srvName->data, srvName->len, 2); + rv = ssl3_AppendNumberToItem(&plaintext, srvName->len, 2); if (rv != SECSuccess) goto loser; + if (srvName->len) { + rv = ssl3_AppendToItem(&plaintext, srvName->data, srvName->len); + if (rv != SECSuccess) + goto loser; + } /* extendedMasterSecretUsed */ - rv = sslBuffer_AppendNumber( + rv = ssl3_AppendNumberToItem( &plaintext, ss->sec.ci.sid->u.ssl3.keys.extendedMasterSecretUsed, 1); if (rv != SECSuccess) goto loser; /* Flags */ - rv = sslBuffer_AppendNumber(&plaintext, ticket->flags, - sizeof(ticket->flags)); + rv = ssl3_AppendNumberToItem(&plaintext, ticket->flags, + sizeof(ticket->flags)); if (rv != SECSuccess) goto loser; /* ALPN value. */ - PORT_Assert(ss->xtnData.nextProtoState == SSL_NEXT_PROTO_SELECTED || - ss->xtnData.nextProtoState == SSL_NEXT_PROTO_NEGOTIATED || - ss->xtnData.nextProto.len == 0); - alpnSelection = &ss->xtnData.nextProto; PORT_Assert(alpnSelection->len < 256); - rv = sslBuffer_AppendVariable(&plaintext, alpnSelection->data, - alpnSelection->len, 1); - if (rv != SECSuccess) - goto loser; - - rv = sslBuffer_AppendNumber(&plaintext, ssl_max_early_data_size, 4); - if (rv != SECSuccess) - goto loser; - - /* - * We store this in the ticket: - * ticket_age_baseline = 1rtt - ticket_age_add - * - * When the client resumes, it will provide: - * obfuscated_age = ticket_age_client + ticket_age_add - * - * We expect to receive the ticket at: - * ticket_create + 1rtt + ticket_age_server - * - * We calculate the client's estimate of this as: - * ticket_create + ticket_age_baseline + obfuscated_age - * = ticket_create + 1rtt + ticket_age_client - * - * This is compared to the expected time, which should differ only as a - * result of clock errors or errors in the RTT estimate. - */ - ticketAgeBaseline = (ssl_TimeUsec() - ss->ssl3.hs.serverHelloTime) / PR_USEC_PER_MSEC; - ticketAgeBaseline -= ticket->ticket_age_add; - rv = sslBuffer_AppendNumber(&plaintext, ticketAgeBaseline, 4); + rv = ssl3_AppendNumberToItem(&plaintext, alpnSelection->len, 1); if (rv != SECSuccess) goto loser; + if (alpnSelection->len) { + rv = ssl3_AppendToItem(&plaintext, alpnSelection->data, + alpnSelection->len); + if (rv != SECSuccess) + goto loser; + } - /* Application token */ - rv = sslBuffer_AppendVariable(&plaintext, appToken, appTokenLen, 2); + rv = ssl3_AppendNumberToItem(&plaintext, ssl_max_early_data_size, 4); if (rv != SECSuccess) goto loser; - /* This really only happens if appTokenLen is too much, and that always - * comes from the using application. */ - if (SSL_BUFFER_LEN(&plaintext) > 0xffff) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - goto loser; - } + /* Check that we are totally full. */ + PORT_Assert(plaintext.len == 0); - ticket_buf.len = ssl_SelfEncryptGetProtectedSize(SSL_BUFFER_LEN(&plaintext)); - PORT_Assert(ticket_buf.len > 0); - if (SECITEM_AllocItem(NULL, &ticket_buf, ticket_buf.len) == NULL) { + /* 128 just gives us enough room for overhead. */ + if (SECITEM_AllocItem(NULL, &ticket_buf, plaintext_length + 128) == NULL) { goto loser; } /* Finally, encrypt the ticket. */ - rv = ssl_SelfEncryptProtect(ss, SSL_BUFFER_BASE(&plaintext), - SSL_BUFFER_LEN(&plaintext), + rv = ssl_SelfEncryptProtect(ss, plaintext_item.data, plaintext_item.len, ticket_buf.data, &ticket_buf.len, ticket_buf.len); if (rv != SECSuccess) { goto loser; @@ -877,11 +1049,13 @@ ssl3_EncodeSessionTicket(sslSocket *ss, const NewSessionTicket *ticket, /* Give ownership of memory to caller. */ *ticket_data = ticket_buf; - sslBuffer_Clear(&plaintext); + SECITEM_FreeItem(&plaintext_item, PR_FALSE); return SECSuccess; loser: - sslBuffer_Clear(&plaintext); + if (plaintext_item.data) { + SECITEM_FreeItem(&plaintext_item, PR_FALSE); + } if (ticket_buf.data) { SECITEM_FreeItem(&ticket_buf, PR_FALSE); } @@ -893,22 +1067,18 @@ loser: * message is expected during the handshake. */ SECStatus -ssl3_ClientHandleSessionTicketXtn(const sslSocket *ss, TLSExtensionData *xtnData, +ssl3_ClientHandleSessionTicketXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) { - PORT_Assert(ss->version < SSL_LIBRARY_VERSION_TLS_1_3); - if (data->len != 0) { return SECSuccess; /* Ignore the extension. */ } /* Keep track of negotiated extensions. */ - xtnData->negotiated[xtnData->numNegotiated++] = ssl_session_ticket_xtn; + xtnData->negotiated[xtnData->numNegotiated++] = ex_type; return SECSuccess; } -PR_STATIC_ASSERT((TLS_EX_SESS_TICKET_VERSION >> 8) == 1); - static SECStatus ssl_ParseSessionTicket(sslSocket *ss, const SECItem *decryptedTicket, SessionTicket *parsedTicket) @@ -935,12 +1105,6 @@ ssl_ParseSessionTicket(sslSocket *ss, const SECItem *decryptedTicket, return SECFailure; } - /* All ticket versions start with 0x01, so check to see if this - * is a ticket or some other self-encrypted thing. */ - if ((temp >> 8) != 1) { - PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO); - return SECFailure; - } /* Skip the ticket if the version is wrong. This won't result in a * handshake failure, just a failure to resume. */ if (temp != TLS_EX_SESS_TICKET_VERSION) { @@ -968,6 +1132,14 @@ ssl_ParseSessionTicket(sslSocket *ss, const SECItem *decryptedTicket, } parsedTicket->cipher_suite = (ssl3CipherSuite)temp; + /* Read compression_method. */ + rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 1, &buffer, &len); + if (rv != SECSuccess) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + parsedTicket->compression_method = (SSLCompressionMethod)temp; + /* Read cipher spec parameters. */ rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 1, &buffer, &len); if (rv != SECSuccess) { @@ -993,18 +1165,6 @@ ssl_ParseSessionTicket(sslSocket *ss, const SECItem *decryptedTicket, return SECFailure; } parsedTicket->keaKeyBits = temp; - rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 4, &buffer, &len); - if (rv != SECSuccess) { - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; - } - parsedTicket->originalKeaGroup = temp; - rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 4, &buffer, &len); - if (rv != SECSuccess) { - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; - } - parsedTicket->signatureScheme = (SSLSignatureScheme)temp; /* Read the optional named curve. */ rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 1, &buffer, &len); @@ -1025,6 +1185,14 @@ ssl_ParseSessionTicket(sslSocket *ss, const SECItem *decryptedTicket, } /* Read the master secret (and how it is wrapped). */ + rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 1, &buffer, &len); + if (rv != SECSuccess) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + PORT_Assert(temp == PR_TRUE || temp == PR_FALSE); + parsedTicket->ms_is_wrapped = (PRBool)temp; + rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 4, &buffer, &len); if (rv != SECSuccess) { PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); @@ -1072,21 +1240,13 @@ ssl_ParseSessionTicket(sslSocket *ss, const SECItem *decryptedTicket, PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure; } - - /* Read timestamp. This is a 64-bit value and - * ssl3_ExtConsumeHandshakeNumber only reads 32-bits at a time. */ - rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 4, &buffer, &len); - if (rv != SECSuccess) { - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; - } - parsedTicket->timestamp = (PRTime)temp << 32; + /* Read timestamp. */ rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 4, &buffer, &len); if (rv != SECSuccess) { PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure; } - parsedTicket->timestamp |= (PRTime)temp; + parsedTicket->timestamp = temp; /* Read server name */ rv = ssl3_ExtConsumeHandshakeVariable(ss, &parsedTicket->srvName, 2, @@ -1127,20 +1287,6 @@ ssl_ParseSessionTicket(sslSocket *ss, const SECItem *decryptedTicket, } parsedTicket->maxEarlyData = temp; - rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 4, &buffer, &len); - if (rv != SECSuccess) { - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; - } - parsedTicket->ticketAgeBaseline = temp; - - rv = ssl3_ExtConsumeHandshakeVariable(ss, &parsedTicket->applicationToken, - 2, &buffer, &len); - if (rv != SECSuccess) { - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; - } - #ifndef UNSAFE_FUZZER_MODE /* Done parsing. Check that all bytes have been consumed. */ if (len != 0) { @@ -1167,15 +1313,13 @@ ssl_CreateSIDFromTicket(sslSocket *ss, const SECItem *rawTicket, /* Copy over parameters. */ sid->version = parsedTicket->ssl_version; - sid->creationTime = parsedTicket->timestamp; sid->u.ssl3.cipherSuite = parsedTicket->cipher_suite; + sid->u.ssl3.compression = parsedTicket->compression_method; sid->authType = parsedTicket->authType; sid->authKeyBits = parsedTicket->authKeyBits; sid->keaType = parsedTicket->keaType; sid->keaKeyBits = parsedTicket->keaKeyBits; - sid->keaGroup = parsedTicket->originalKeaGroup; sid->namedCurve = parsedTicket->namedCurve; - sid->sigScheme = parsedTicket->signatureScheme; rv = SECITEM_CopyItem(NULL, &sid->u.ssl3.locked.sessionTicket.ticket, rawTicket); @@ -1194,6 +1338,7 @@ ssl_CreateSIDFromTicket(sslSocket *ss, const SECItem *rawTicket, parsedTicket->master_secret, parsedTicket->ms_length); sid->u.ssl3.keys.wrapped_master_secret_len = parsedTicket->ms_length; sid->u.ssl3.masterWrapMech = parsedTicket->msWrapMech; + sid->u.ssl3.keys.msIsWrapped = parsedTicket->ms_is_wrapped; sid->u.ssl3.masterValid = PR_TRUE; sid->u.ssl3.keys.resumable = PR_TRUE; sid->u.ssl3.keys.extendedMasterSecretUsed = parsedTicket->extendedMasterSecretUsed; @@ -1236,12 +1381,10 @@ loser: /* Generic ticket processing code, common to all TLS versions. */ SECStatus -ssl3_ProcessSessionTicketCommon(sslSocket *ss, const SECItem *ticket, - SECItem *appToken) +ssl3_ProcessSessionTicketCommon(sslSocket *ss, SECItem *data) { SECItem decryptedTicket = { siBuffer, NULL, 0 }; SessionTicket parsedTicket; - sslSessionID *sid = NULL; SECStatus rv; if (ss->sec.ci.sid != NULL) { @@ -1250,12 +1393,12 @@ ssl3_ProcessSessionTicketCommon(sslSocket *ss, const SECItem *ticket, ss->sec.ci.sid = NULL; } - if (!SECITEM_AllocItem(NULL, &decryptedTicket, ticket->len)) { + if (!SECITEM_AllocItem(NULL, &decryptedTicket, data->len)) { return SECFailure; } /* Decrypt the ticket. */ - rv = ssl_SelfEncryptUnprotect(ss, ticket->data, ticket->len, + rv = ssl_SelfEncryptUnprotect(ss, data->data, data->len, decryptedTicket.data, &decryptedTicket.len, decryptedTicket.len); @@ -1285,28 +1428,16 @@ ssl3_ProcessSessionTicketCommon(sslSocket *ss, const SECItem *ticket, } /* Use the ticket if it is valid and unexpired. */ - if (parsedTicket.timestamp + ssl_ticket_lifetime * PR_USEC_PER_SEC > - ssl_TimeUsec()) { + if (parsedTicket.valid && + parsedTicket.timestamp + ssl_ticket_lifetime > ssl_Time()) { + sslSessionID *sid; - rv = ssl_CreateSIDFromTicket(ss, ticket, &parsedTicket, &sid); + rv = ssl_CreateSIDFromTicket(ss, data, &parsedTicket, &sid); if (rv != SECSuccess) { goto loser; /* code already set */ } - if (appToken && parsedTicket.applicationToken.len) { - rv = SECITEM_CopyItem(NULL, appToken, - &parsedTicket.applicationToken); - if (rv != SECSuccess) { - goto loser; /* code already set */ - } - } - ss->statelessResume = PR_TRUE; ss->sec.ci.sid = sid; - - /* We have the baseline value for the obfuscated ticket age here. Save - * that in xtnData temporarily. This value is updated in - * tls13_ServerHandlePreSharedKeyXtn with the final estimate. */ - ss->xtnData.ticketAge = parsedTicket.ticketAgeBaseline; } SECITEM_ZfreeItem(&decryptedTicket, PR_FALSE); @@ -1314,19 +1445,15 @@ ssl3_ProcessSessionTicketCommon(sslSocket *ss, const SECItem *ticket, return SECSuccess; loser: - if (sid) { - ssl_FreeSID(sid); - } SECITEM_ZfreeItem(&decryptedTicket, PR_FALSE); PORT_Memset(&parsedTicket, 0, sizeof(parsedTicket)); return SECFailure; } SECStatus -ssl3_ServerHandleSessionTicketXtn(const sslSocket *ss, TLSExtensionData *xtnData, +ssl3_ServerHandleSessionTicketXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) { - PORT_Assert(ss->version < SSL_LIBRARY_VERSION_TLS_1_3); /* Ignore the SessionTicket extension if processing is disabled. */ if (!ss->opt.enableSessionTickets) { @@ -1339,7 +1466,7 @@ ssl3_ServerHandleSessionTicketXtn(const sslSocket *ss, TLSExtensionData *xtnData } /* Keep track of negotiated extensions. */ - xtnData->negotiated[xtnData->numNegotiated++] = ssl_session_ticket_xtn; + xtnData->negotiated[xtnData->numNegotiated++] = ex_type; /* Parse the received ticket sent in by the client. We are * lenient about some parse errors, falling back to a fullshake @@ -1350,8 +1477,7 @@ ssl3_ServerHandleSessionTicketXtn(const sslSocket *ss, TLSExtensionData *xtnData return SECSuccess; } - return ssl3_ProcessSessionTicketCommon(CONST_CAST(sslSocket, ss), data, - NULL); + return ssl3_ProcessSessionTicketCommon(CONST_CAST(sslSocket, ss), data); } /* Extension format: @@ -1361,45 +1487,60 @@ ssl3_ServerHandleSessionTicketXtn(const sslSocket *ss, TLSExtensionData *xtnData * Verify Data (TLS): 12 bytes (client) or 24 bytes (server) * Verify Data (SSL): 36 bytes (client) or 72 bytes (server) */ -SECStatus -ssl3_SendRenegotiationInfoXtn(const sslSocket *ss, TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added) +PRInt32 +ssl3_SendRenegotiationInfoXtn( + const sslSocket *ss, + TLSExtensionData *xtnData, + PRBool append, + PRUint32 maxBytes) { PRInt32 len = 0; - SECStatus rv; + PRInt32 needed; - /* In RFC 5746, 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. + /* 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->ssl3.hs.sendingSCSV) { + if (!ss || ss->ssl3.hs.sendingSCSV) return 0; - } if (ss->firstHsDone) { len = ss->sec.isServer ? ss->ssl3.hs.finishedBytes * 2 : ss->ssl3.hs.finishedBytes; } - - /* verify_Data from previous Finished message(s) */ - rv = sslBuffer_AppendVariable(buf, - ss->ssl3.hs.finishedMsgs.data, len, 1); - if (rv != SECSuccess) { - return SECFailure; + needed = 5 + len; + if (maxBytes < (PRUint32)needed) { + return 0; } - - *added = PR_TRUE; - return SECSuccess; + if (append) { + SECStatus rv; + /* extension_type */ + rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_renegotiation_info_xtn, 2); + if (rv != SECSuccess) + return -1; + /* length of extension_data */ + rv = ssl3_ExtAppendHandshakeNumber(ss, len + 1, 2); + if (rv != SECSuccess) + return -1; + /* verify_Data from previous Finished message(s) */ + rv = ssl3_ExtAppendHandshakeVariable(ss, + ss->ssl3.hs.finishedMsgs.data, len, 1); + if (rv != SECSuccess) + return -1; + if (!ss->sec.isServer) { + xtnData->advertised[xtnData->numAdvertised++] = + ssl_renegotiation_info_xtn; + } + } + return needed; } /* This function runs in both the client and server. */ SECStatus -ssl3_HandleRenegotiationInfoXtn(const sslSocket *ss, TLSExtensionData *xtnData, - SECItem *data) +ssl3_HandleRenegotiationInfoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) { SECStatus rv = SECSuccess; PRUint32 len = 0; - PORT_Assert(ss->version < SSL_LIBRARY_VERSION_TLS_1_3); - if (ss->firstHsDone) { len = ss->sec.isServer ? ss->ssl3.hs.finishedBytes : ss->ssl3.hs.finishedBytes * 2; @@ -1417,78 +1558,97 @@ ssl3_HandleRenegotiationInfoXtn(const sslSocket *ss, TLSExtensionData *xtnData, /* remember that we got this extension and it was correct. */ CONST_CAST(sslSocket, ss) ->peerRequestedProtection = 1; - xtnData->negotiated[xtnData->numNegotiated++] = ssl_renegotiation_info_xtn; + xtnData->negotiated[xtnData->numNegotiated++] = ex_type; if (ss->sec.isServer) { /* prepare to send back the appropriate response */ - rv = ssl3_RegisterExtensionSender(ss, xtnData, - ssl_renegotiation_info_xtn, + rv = ssl3_RegisterExtensionSender(ss, xtnData, ex_type, ssl3_SendRenegotiationInfoXtn); } return rv; } -SECStatus -ssl3_ClientSendUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added) +PRInt32 +ssl3_ClientSendUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, PRUint32 maxBytes) { - unsigned int i; + PRUint32 ext_data_len; + PRInt16 i; SECStatus rv; - if (!IS_DTLS(ss) || !ss->ssl3.dtlsSRTPCipherCount) { - return SECSuccess; /* Not relevant */ - } + if (!ss) + return 0; - /* Length of the SRTP cipher list */ - rv = sslBuffer_AppendNumber(buf, 2 * ss->ssl3.dtlsSRTPCipherCount, 2); - if (rv != SECSuccess) { - return SECFailure; - } - /* The SRTP ciphers */ - for (i = 0; i < ss->ssl3.dtlsSRTPCipherCount; i++) { - rv = sslBuffer_AppendNumber(buf, ss->ssl3.dtlsSRTPCiphers[i], 2); - if (rv != SECSuccess) { - return SECFailure; + if (!IS_DTLS(ss) || !ss->ssl3.dtlsSRTPCipherCount) + return 0; /* Not relevant */ + + ext_data_len = 2 + 2 * ss->ssl3.dtlsSRTPCipherCount + 1; + + if (append && maxBytes >= 4 + ext_data_len) { + /* Extension type */ + rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_use_srtp_xtn, 2); + if (rv != SECSuccess) + return -1; + /* Length of extension data */ + rv = ssl3_ExtAppendHandshakeNumber(ss, ext_data_len, 2); + if (rv != SECSuccess) + return -1; + /* Length of the SRTP cipher list */ + rv = ssl3_ExtAppendHandshakeNumber(ss, + 2 * ss->ssl3.dtlsSRTPCipherCount, + 2); + if (rv != SECSuccess) + return -1; + /* The SRTP ciphers */ + for (i = 0; i < ss->ssl3.dtlsSRTPCipherCount; i++) { + rv = ssl3_ExtAppendHandshakeNumber(ss, + ss->ssl3.dtlsSRTPCiphers[i], + 2); + if (rv != SECSuccess) + return -1; } - } - /* Empty MKI value */ - rv = sslBuffer_AppendNumber(buf, 0, 1); - if (rv != SECSuccess) { - return SECFailure; + /* Empty MKI value */ + ssl3_ExtAppendHandshakeVariable(ss, NULL, 0, 1); + + xtnData->advertised[xtnData->numAdvertised++] = + ssl_use_srtp_xtn; } - *added = PR_TRUE; - return SECSuccess; + return 4 + ext_data_len; } -SECStatus -ssl3_ServerSendUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added) +PRInt32 +ssl3_ServerSendUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, PRUint32 maxBytes) { SECStatus rv; - /* Length of the SRTP cipher list */ - rv = sslBuffer_AppendNumber(buf, 2, 2); - if (rv != SECSuccess) { - return SECFailure; + /* Server side */ + if (!append || maxBytes < 9) { + return 9; } + + /* Extension type */ + rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_use_srtp_xtn, 2); + if (rv != SECSuccess) + return -1; + /* Length of extension data */ + rv = ssl3_ExtAppendHandshakeNumber(ss, 5, 2); + if (rv != SECSuccess) + return -1; + /* Length of the SRTP cipher list */ + rv = ssl3_ExtAppendHandshakeNumber(ss, 2, 2); + if (rv != SECSuccess) + return -1; /* The selected cipher */ - rv = sslBuffer_AppendNumber(buf, xtnData->dtlsSRTPCipherSuite, 2); - if (rv != SECSuccess) { - return SECFailure; - } + rv = ssl3_ExtAppendHandshakeNumber(ss, xtnData->dtlsSRTPCipherSuite, 2); + if (rv != SECSuccess) + return -1; /* Empty MKI value */ - rv = sslBuffer_AppendNumber(buf, 0, 1); - if (rv != SECSuccess) { - return SECFailure; - } + ssl3_ExtAppendHandshakeVariable(ss, NULL, 0, 1); - *added = PR_TRUE; - return SECSuccess; + return 9; } SECStatus -ssl3_ClientHandleUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, - SECItem *data) +ssl3_ClientHandleUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) { SECStatus rv; SECItem ciphers = { siBuffer, NULL, 0 }; @@ -1558,8 +1718,7 @@ ssl3_ClientHandleUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, } SECStatus -ssl3_ServerHandleUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, - SECItem *data) +ssl3_ServerHandleUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) { SECStatus rv; SECItem ciphers = { siBuffer, NULL, 0 }; @@ -1630,12 +1789,11 @@ ssl3_ServerHandleUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, ssl3_ServerSendUseSRTPXtn); } -/* ssl3_HandleSigAlgsXtn handles the signature_algorithms extension from a - * client. In TLS 1.3, the client uses this to parse CertificateRequest - * extensions. See https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */ +/* ssl3_ServerHandleSigAlgsXtn handles the signature_algorithms extension + * from a client. + * See https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */ SECStatus -ssl3_HandleSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData, - SECItem *data) +ssl3_ServerHandleSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) { SECStatus rv; @@ -1644,15 +1802,15 @@ ssl3_HandleSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData, return SECSuccess; } - if (xtnData->sigSchemes) { - PORT_Free(xtnData->sigSchemes); - xtnData->sigSchemes = NULL; + if (xtnData->clientSigSchemes) { + PORT_Free(xtnData->clientSigSchemes); + xtnData->clientSigSchemes = NULL; } rv = ssl_ParseSignatureSchemes(ss, NULL, - &xtnData->sigSchemes, - &xtnData->numSigSchemes, + &xtnData->clientSigSchemes, + &xtnData->numClientSigScheme, &data->data, &data->len); - if (rv != SECSuccess || xtnData->numSigSchemes == 0) { + if (rv != SECSuccess || xtnData->numClientSigScheme == 0) { ssl3_ExtSendAlert(ss, alert_fatal, decode_error); PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO); return SECFailure; @@ -1665,52 +1823,177 @@ ssl3_HandleSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData, } /* Keep track of negotiated extensions. */ - xtnData->negotiated[xtnData->numNegotiated++] = ssl_signature_algorithms_xtn; + xtnData->negotiated[xtnData->numNegotiated++] = ex_type; return SECSuccess; } /* ssl3_ClientSendSigAlgsXtn sends the signature_algorithm extension for TLS * 1.2 ClientHellos. */ -SECStatus -ssl3_SendSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added) +PRInt32 +ssl3_ClientSendSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, PRUint32 maxBytes) { + PRInt32 extension_length; + PRUint8 buf[MAX_SIGNATURE_SCHEMES * 2]; + PRUint32 len; SECStatus rv; if (ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_2) { - return SECSuccess; + return 0; } - rv = ssl3_EncodeSigAlgs(ss, buf); + rv = ssl3_EncodeSigAlgs(ss, buf, sizeof(buf), &len); if (rv != SECSuccess) { - return SECFailure; + return -1; } - *added = PR_TRUE; - return SECSuccess; + extension_length = + 2 /* extension type */ + + 2 /* extension length */ + + 2 /* supported_signature_algorithms length */ + + len; + + if (maxBytes < extension_length) { + PORT_Assert(0); + return 0; + } + + if (append) { + SECStatus rv; + rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_signature_algorithms_xtn, 2); + if (rv != SECSuccess) { + return -1; + } + rv = ssl3_ExtAppendHandshakeNumber(ss, len + 2, 2); + if (rv != SECSuccess) { + return -1; + } + + rv = ssl3_ExtAppendHandshakeVariable(ss, buf, len, 2); + if (rv != SECSuccess) { + return -1; + } + + xtnData->advertised[xtnData->numAdvertised++] = + ssl_signature_algorithms_xtn; + } + + return extension_length; } -SECStatus -ssl3_SendExtendedMasterSecretXtn(const sslSocket *ss, TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added) +/* Takes the size of the ClientHello, less the record header, and determines how + * much padding is required. */ +void +ssl3_CalculatePaddingExtLen(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; + } + + /* 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; + } + + 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 < 4 + 1) { + extensionLen = 4 + 1; + } + + ss->xtnData.paddingLen = 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. */ +PRInt32 +ssl3_ClientSendPaddingExtension(const sslSocket *ss, TLSExtensionData *xtnData, + PRBool append, PRUint32 maxBytes) +{ + static unsigned char padding[252] = { 0 }; + unsigned int extensionLen; + SECStatus rv; + + /* On the length-calculation pass, report zero total length. The record + * will be larger on the second pass if needed. */ + if (!append || !xtnData->paddingLen) { + return 0; + } + + extensionLen = xtnData->paddingLen + 4; + if (extensionLen > maxBytes || + xtnData->paddingLen > sizeof(padding)) { + PORT_Assert(0); + return -1; + } + + rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_padding_xtn, 2); + if (rv != SECSuccess) { + return -1; + } + rv = ssl3_ExtAppendHandshakeVariable(ss, padding, xtnData->paddingLen, 2); + if (rv != SECSuccess) { + return -1; + } + + return extensionLen; +} + +PRInt32 +ssl3_SendExtendedMasterSecretXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, + PRUint32 maxBytes) { + PRInt32 extension_length; + if (!ss->opt.enableExtendedMS) { - return SECSuccess; + return 0; } /* Always send the extension in this function, since the * client always sends it and this function is only called on * the server if we negotiated the extension. */ - *added = PR_TRUE; - return SECSuccess; + extension_length = 4; /* Type + length (0) */ + if (maxBytes < extension_length) { + PORT_Assert(0); + return 0; + } + + if (append) { + SECStatus rv; + rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_extended_master_secret_xtn, 2); + if (rv != SECSuccess) + goto loser; + rv = ssl3_ExtAppendHandshakeNumber(ss, 0, 2); + if (rv != SECSuccess) + goto loser; + xtnData->advertised[xtnData->numAdvertised++] = + ssl_extended_master_secret_xtn; + } + + return extension_length; + +loser: + return -1; } SECStatus -ssl3_HandleExtendedMasterSecretXtn(const sslSocket *ss, TLSExtensionData *xtnData, +ssl3_HandleExtendedMasterSecretXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) { - PORT_Assert(ss->version < SSL_LIBRARY_VERSION_TLS_1_3); - if (ss->version < SSL_LIBRARY_VERSION_TLS_1_0) { return SECSuccess; } @@ -1730,34 +2013,54 @@ ssl3_HandleExtendedMasterSecretXtn(const sslSocket *ss, TLSExtensionData *xtnDat SSL_GETPID(), ss->fd)); /* Keep track of negotiated extensions. */ - xtnData->negotiated[xtnData->numNegotiated++] = ssl_extended_master_secret_xtn; + xtnData->negotiated[xtnData->numNegotiated++] = ex_type; if (ss->sec.isServer) { - return ssl3_RegisterExtensionSender(ss, xtnData, - ssl_extended_master_secret_xtn, - ssl_SendEmptyExtension); + return ssl3_RegisterExtensionSender( + ss, xtnData, ex_type, ssl3_SendExtendedMasterSecretXtn); } return SECSuccess; } /* ssl3_ClientSendSignedCertTimestampXtn sends the signed_certificate_timestamp * extension for TLS ClientHellos. */ -SECStatus -ssl3_ClientSendSignedCertTimestampXtn(const sslSocket *ss, - TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added) +PRInt32 +ssl3_ClientSendSignedCertTimestampXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, + PRUint32 maxBytes) { + PRInt32 extension_length = 2 /* extension_type */ + + 2 /* length(extension_data) */; + /* Only send the extension if processing is enabled. */ - if (!ss->opt.enableSignedCertTimestamps) { - return SECSuccess; + if (!ss->opt.enableSignedCertTimestamps) + return 0; + + if (append && maxBytes >= extension_length) { + SECStatus rv; + /* extension_type */ + rv = ssl3_ExtAppendHandshakeNumber(ss, + ssl_signed_cert_timestamp_xtn, + 2); + if (rv != SECSuccess) + goto loser; + /* zero length */ + rv = ssl3_ExtAppendHandshakeNumber(ss, 0, 2); + if (rv != SECSuccess) + goto loser; + xtnData->advertised[xtnData->numAdvertised++] = + ssl_signed_cert_timestamp_xtn; + } else if (maxBytes < extension_length) { + PORT_Assert(0); + return 0; } - *added = PR_TRUE; - return SECSuccess; + return extension_length; +loser: + return -1; } SECStatus -ssl3_ClientHandleSignedCertTimestampXtn(const sslSocket *ss, TLSExtensionData *xtnData, +ssl3_ClientHandleSignedCertTimestampXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) { /* We do not yet know whether we'll be resuming a session or creating @@ -1777,34 +2080,54 @@ ssl3_ClientHandleSignedCertTimestampXtn(const sslSocket *ss, TLSExtensionData *x } *scts = *data; /* Keep track of negotiated extensions. */ - xtnData->negotiated[xtnData->numNegotiated++] = ssl_signed_cert_timestamp_xtn; + xtnData->negotiated[xtnData->numNegotiated++] = ex_type; return SECSuccess; } -SECStatus +PRInt32 ssl3_ServerSendSignedCertTimestampXtn(const sslSocket *ss, TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added) + PRBool append, + PRUint32 maxBytes) { + PRInt32 extension_length; const SECItem *scts = &ss->sec.serverCert->signedCertTimestamps; - SECStatus rv; if (!scts->len) { /* No timestamps to send */ - return SECSuccess; + return 0; } - rv = sslBuffer_Append(buf, scts->data, scts->len); - if (rv != SECSuccess) { - return SECFailure; + extension_length = 2 /* extension_type */ + + 2 /* length(extension_data) */ + + scts->len; + + if (maxBytes < extension_length) { + PORT_Assert(0); + return 0; + } + if (append) { + SECStatus rv; + /* extension_type */ + rv = ssl3_ExtAppendHandshakeNumber(ss, + ssl_signed_cert_timestamp_xtn, + 2); + if (rv != SECSuccess) { + return -1; + } + /* extension_data */ + rv = ssl3_ExtAppendHandshakeVariable(ss, scts->data, scts->len, 2); + if (rv != SECSuccess) { + return -1; + } } - *added = PR_TRUE; - return SECSuccess; + return extension_length; } SECStatus ssl3_ServerHandleSignedCertTimestampXtn(const sslSocket *ss, TLSExtensionData *xtnData, + PRUint16 ex_type, SECItem *data) { if (data->len != 0) { @@ -1813,25 +2136,22 @@ ssl3_ServerHandleSignedCertTimestampXtn(const sslSocket *ss, return SECFailure; } - xtnData->negotiated[xtnData->numNegotiated++] = ssl_signed_cert_timestamp_xtn; + xtnData->negotiated[xtnData->numNegotiated++] = ex_type; PORT_Assert(ss->sec.isServer); - return ssl3_RegisterExtensionSender(ss, xtnData, - ssl_signed_cert_timestamp_xtn, - ssl3_ServerSendSignedCertTimestampXtn); + return ssl3_RegisterExtensionSender( + ss, xtnData, ex_type, ssl3_ServerSendSignedCertTimestampXtn); } /* Just make sure that the remote client supports uncompressed points, * Since that is all we support. Disable ECC cipher suites if it doesn't. */ SECStatus -ssl3_HandleSupportedPointFormatsXtn(const sslSocket *ss, - TLSExtensionData *xtnData, +ssl3_HandleSupportedPointFormatsXtn(const sslSocket *ss, TLSExtensionData *xtnData, + PRUint16 ex_type, SECItem *data) { int i; - PORT_Assert(ss->version < SSL_LIBRARY_VERSION_TLS_1_3); - if (data->len < 2 || data->len > 255 || !data->data || data->len != (unsigned int)data->data[0] + 1) { ssl3_ExtDecodeError(ss); @@ -1840,9 +2160,10 @@ ssl3_HandleSupportedPointFormatsXtn(const sslSocket *ss, for (i = data->len; --i > 0;) { if (data->data[i] == 0) { /* indicate that we should send a reply */ - return ssl3_RegisterExtensionSender( - ss, xtnData, ssl_ec_point_formats_xtn, - &ssl3_SendSupportedPointFormatsXtn); + SECStatus rv; + rv = ssl3_RegisterExtensionSender(ss, xtnData, ex_type, + &ssl3_SendSupportedPointFormatsXtn); + return rv; } } @@ -1927,7 +2248,7 @@ ssl_UpdateSupportedGroups(sslSocket *ss, SECItem *data) */ SECStatus ssl_HandleSupportedGroupsXtn(const sslSocket *ss, TLSExtensionData *xtnData, - SECItem *data) + PRUint16 ex_type, SECItem *data) { SECStatus rv; @@ -1937,7 +2258,7 @@ ssl_HandleSupportedGroupsXtn(const sslSocket *ss, TLSExtensionData *xtnData, /* TLS 1.3 permits the server to send this extension so make it so. */ if (ss->sec.isServer && ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) { - rv = ssl3_RegisterExtensionSender(ss, xtnData, ssl_supported_groups_xtn, + rv = ssl3_RegisterExtensionSender(ss, xtnData, ex_type, &ssl_SendSupportedGroupsXtn); if (rv != SECSuccess) { return SECFailure; /* error already set. */ @@ -1945,7 +2266,7 @@ ssl_HandleSupportedGroupsXtn(const sslSocket *ss, TLSExtensionData *xtnData, } /* Remember that we negotiated this extension. */ - xtnData->negotiated[xtnData->numNegotiated++] = ssl_supported_groups_xtn; + xtnData->negotiated[xtnData->numNegotiated++] = ex_type; return SECSuccess; } |