diff options
author | wolfbeast <mcwerewolf@gmail.com> | 2018-06-06 21:27:04 +0200 |
---|---|---|
committer | wolfbeast <mcwerewolf@gmail.com> | 2018-06-06 21:27:04 +0200 |
commit | 4a71b30364a4b6d1eaf16fcfdc8e873e6697f293 (patch) | |
tree | a47014077c14579249859ad34afcc5a8f2f0730a /security/nss/lib/ssl/ssl3exthandle.c | |
parent | d7da72799521386c110dbba73b1e483b00a0a56a (diff) | |
parent | 2dad0ec41d0b69c0a815012e6ea4bdde81b2875b (diff) | |
download | UXP-4a71b30364a4b6d1eaf16fcfdc8e873e6697f293.tar UXP-4a71b30364a4b6d1eaf16fcfdc8e873e6697f293.tar.gz UXP-4a71b30364a4b6d1eaf16fcfdc8e873e6697f293.tar.lz UXP-4a71b30364a4b6d1eaf16fcfdc8e873e6697f293.tar.xz UXP-4a71b30364a4b6d1eaf16fcfdc8e873e6697f293.zip |
Merge branch 'NSS-335'
Diffstat (limited to 'security/nss/lib/ssl/ssl3exthandle.c')
-rw-r--r-- | security/nss/lib/ssl/ssl3exthandle.c | 1311 |
1 files changed, 495 insertions, 816 deletions
diff --git a/security/nss/lib/ssl/ssl3exthandle.c b/security/nss/lib/ssl/ssl3exthandle.c index 370bd8b3e..c0fbda7ab 100644 --- a/security/nss/lib/ssl/ssl3exthandle.c +++ b/security/nss/lib/ssl/ssl3exthandle.c @@ -13,7 +13,6 @@ #include "blapit.h" #include "prinit.h" #include "selfencrypt.h" -#include "ssl3encode.h" #include "ssl3ext.h" #include "ssl3exthandle.h" #include "tls13exthandle.h" /* For tls13_ServerSendStatusRequestXtn. */ @@ -22,70 +21,48 @@ * unless that name is a dotted decimal string. * Used by client and server. */ -PRInt32 -ssl3_SendServerNameXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, - PRUint32 maxBytes) +SECStatus +ssl3_ClientSendServerNameXtn(const sslSocket *ss, TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added) { + unsigned int len; + PRNetAddr netAddr; SECStatus rv; - 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; + + /* must have a hostname */ + if (!ss->url || !ss->url[0]) { + return SECSuccess; } - /* 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; + /* 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; + } + /* HostName (length and value) */ + rv = sslBuffer_AppendVariable(buf, (const PRUint8 *)ss->url, len, 2); + if (rv != SECSuccess) { + return SECFailure; } - return 4; + + *added = PR_TRUE; + return SECSuccess; } /* Handle an incoming SNI extension. */ SECStatus -ssl3_HandleServerNameXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) +ssl3_HandleServerNameXtn(const sslSocket *ss, TLSExtensionData *xtnData, + SECItem *data) { SECItem *names = NULL; PRUint32 listLenBytes = 0; @@ -194,88 +171,54 @@ ssl3_FreeSniNameArray(TLSExtensionData *xtnData) * sends an empty ticket. Servers always send empty tickets. */ PRInt32 -ssl3_SendSessionTicketXtn( - const sslSocket *ss, - TLSExtensionData *xtnData, - PRBool append, - PRUint32 maxBytes) +ssl3_ClientSendSessionTicketXtn(const sslSocket *ss, TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added) { - 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 0; + return SECSuccess; } /* Ignore the SessionTicket extension if processing is disabled. */ - if (!ss->opt.enableSessionTickets) - return 0; - - /* Empty extension length = extension_type (2-bytes) + - * length(extension_data) (2-bytes) - */ - extension_length = 4; + if (!ss->opt.enableSessionTickets) { + return SECSuccess; + } - /* 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. + /* 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. */ - 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. - */ + session_ticket = &sid->u.ssl3.locked.sessionTicket; + if (session_ticket->ticket.data && + (xtnData->ticketTimestampVerified || + ssl_TicketTimeValid(session_ticket))) { - 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->ticketTimestampVerified = PR_FALSE; - 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); + rv = sslBuffer_Append(buf, session_ticket->ticket.data, + session_ticket->ticket.len); + if (rv != SECSuccess) { + return SECFailure; } - if (rv != SECSuccess) - goto loser; - if (!ss->sec.isServer) { - xtnData->advertised[xtnData->numAdvertised++] = - ssl_session_ticket_xtn; - } + xtnData->sentSessionTicketInClientHello = PR_TRUE; } - return extension_length; -loser: - xtnData->ticketTimestampVerified = PR_FALSE; - return -1; + *added = PR_TRUE; + return SECSuccess; } PRBool @@ -301,16 +244,18 @@ ssl_AlpnTagAllowed(const sslSocket *ss, const SECItem *tag) /* handle an incoming Next Protocol Negotiation extension. */ SECStatus -ssl3_ServerHandleNextProtoNegoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, +ssl3_ServerHandleNextProtoNegoXtn(const sslSocket *ss, TLSExtensionData *xtnData, 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++] = ex_type; + xtnData->negotiated[xtnData->numNegotiated++] = ssl_next_proto_nego_xtn; /* TODO: server side NPN support would require calling * ssl3_RegisterServerHelloExtensionSender here in order to echo the @@ -344,7 +289,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 ex_type, SECItem *data) + PRUint16 extension, SECItem *data) { SECStatus rv; unsigned char resultBuffer[255]; @@ -381,7 +326,7 @@ ssl3_SelectAppProtocol(const sslSocket *ss, TLSExtensionData *xtnData, SECITEM_FreeItem(&xtnData->nextProto, PR_FALSE); - if (ex_type == ssl_app_layer_protocol_xtn && + if (extension == 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. */ @@ -390,13 +335,14 @@ ssl3_SelectAppProtocol(const sslSocket *ss, TLSExtensionData *xtnData, return SECFailure; } - xtnData->negotiated[xtnData->numNegotiated++] = ex_type; + xtnData->negotiated[xtnData->numNegotiated++] = extension; return SECITEM_CopyItem(NULL, &xtnData->nextProto, &result); } /* handle an incoming ALPN extension at the server */ SECStatus -ssl3_ServerHandleAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) +ssl3_ServerHandleAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, + SECItem *data) { PRUint32 count; SECStatus rv; @@ -423,15 +369,16 @@ ssl3_ServerHandleAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRU return SECSuccess; } - rv = ssl3_SelectAppProtocol(ss, xtnData, ex_type, data); + rv = ssl3_SelectAppProtocol(ss, xtnData, ssl_app_layer_protocol_xtn, 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, ex_type, ssl3_ServerSendAppProtoXtn); + rv = ssl3_RegisterExtensionSender(ss, xtnData, + ssl_app_layer_protocol_xtn, + ssl3_ServerSendAppProtoXtn); if (rv != SECSuccess) { ssl3_ExtSendAlert(ss, alert_fatal, internal_error); PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); @@ -442,9 +389,10 @@ ssl3_ServerHandleAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRU } SECStatus -ssl3_ClientHandleNextProtoNegoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, +ssl3_ClientHandleNextProtoNegoXtn(const sslSocket *ss, TLSExtensionData *xtnData, 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)) { @@ -470,11 +418,12 @@ ssl3_ClientHandleNextProtoNegoXtn(const sslSocket *ss, TLSExtensionData *xtnData return SECFailure; } - return ssl3_SelectAppProtocol(ss, xtnData, ex_type, data); + return ssl3_SelectAppProtocol(ss, xtnData, ssl_next_proto_nego_xtn, data); } SECStatus -ssl3_ClientHandleAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) +ssl3_ClientHandleAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, + SECItem *data) { SECStatus rv; PRUint32 list_len; @@ -521,265 +470,168 @@ ssl3_ClientHandleAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRU SECITEM_FreeItem(&xtnData->nextProto, PR_FALSE); xtnData->nextProtoState = SSL_NEXT_PROTO_SELECTED; - xtnData->negotiated[xtnData->numNegotiated++] = ex_type; + xtnData->negotiated[xtnData->numNegotiated++] = ssl_app_layer_protocol_xtn; return SECITEM_CopyItem(NULL, &xtnData->nextProto, &protocol_name); } -PRInt32 -ssl3_ClientSendNextProtoNegoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, - PRUint32 maxBytes) +SECStatus +ssl3_ClientSendNextProtoNegoXtn(const sslSocket *ss, TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added) { - PRInt32 extension_length; - /* Renegotiations do not send this extension. */ if (!ss->opt.enableNPN || !ss->nextProtoCallback || ss->firstHsDone) { - return 0; - } - - 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 SECSuccess; } - return extension_length; - -loser: - return -1; + *added = PR_TRUE; + return SECSuccess; } -PRInt32 -ssl3_ClientSendAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, PRUint32 maxBytes) +SECStatus +ssl3_ClientSendAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added) { - PRInt32 extension_length; - unsigned char *alpn_protos = NULL; + SECStatus rv; + const unsigned int len = ss->opt.nextProtoNego.len; /* Renegotiations do not send this extension. */ if (!ss->opt.enableALPN || !ss->opt.nextProtoNego.data || ss->firstHsDone) { - return 0; + return SECSuccess; } - extension_length = 2 /* extension type */ + 2 /* extension length */ + - 2 /* protocol name list length */ + - ss->opt.nextProtoNego.len; + /* 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. */ - 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; + if (len > 0) { + /* Each protocol string is prefixed with a single byte length. */ + unsigned int i; - alpn_protos = PORT_Alloc(len); - if (alpn_protos == NULL) { + rv = sslBuffer_AppendNumber(buf, len, 2); + 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; + 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; + } } - xtnData->advertised[xtnData->numAdvertised++] = - ssl_app_layer_protocol_xtn; } - return extension_length; - -loser: - if (alpn_protos) { - PORT_Free(alpn_protos); - } - return -1; + *added = PR_TRUE; + return SECSuccess; } -PRInt32 -ssl3_ServerSendAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, PRUint32 maxBytes) +SECStatus +ssl3_ServerSendAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added) { - PRInt32 extension_length; + SECStatus rv; - /* 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); - 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_AppendNumber(buf, xtnData->nextProto.len + 1, 2); + 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; - } + rv = sslBuffer_AppendVariable(buf, xtnData->nextProto.data, + xtnData->nextProto.len, 1); + if (rv != SECSuccess) { + return SECFailure; } - return extension_length; + *added = PR_TRUE; + return SECSuccess; } SECStatus -ssl3_ServerHandleStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, +ssl3_ServerHandleStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData, SECItem *data) { - ssl3HelloExtensionSenderFunc sender; + sslExtensionBuilderFunc sender; PORT_Assert(ss->sec.isServer); /* remember that we got this extension. */ - xtnData->negotiated[xtnData->numNegotiated++] = ex_type; + xtnData->negotiated[xtnData->numNegotiated++] = ssl_cert_status_xtn; if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) { sender = tls13_ServerSendStatusRequestXtn; } else { sender = ssl3_ServerSendStatusRequestXtn; } - return ssl3_RegisterExtensionSender(ss, xtnData, ex_type, sender); + return ssl3_RegisterExtensionSender(ss, xtnData, ssl_cert_status_xtn, sender); } -PRInt32 -ssl3_ServerSendStatusRequestXtn( - const sslSocket *ss, - TLSExtensionData *xtnData, - PRBool append, - PRUint32 maxBytes) +SECStatus +ssl3_ServerSendStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added) { - PRInt32 extension_length; const sslServerCert *serverCert = ss->sec.serverCert; - SECStatus rv; if (!serverCert->certStatusArray || !serverCert->certStatusArray->len) { - return 0; - } - - 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 SECSuccess; } - return extension_length; + *added = PR_TRUE; + return SECSuccess; } /* ssl3_ClientSendStatusRequestXtn builds the status_request extension on the * client side. See RFC 6066 section 8. */ -PRInt32 -ssl3_ClientSendStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, - PRUint32 maxBytes) +SECStatus +ssl3_ClientSendStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added) { - PRInt32 extension_length; - - if (!ss->opt.enableOCSPStapling) - return 0; - - /* extension_type (2-bytes) + - * length(extension_data) (2-bytes) + - * status_type (1) + - * responder_id_list length (2) + - * request_extensions length (2) - */ - extension_length = 9; + SECStatus rv; - if (maxBytes < (PRUint32)extension_length) { - PORT_Assert(0); - return 0; + if (!ss->opt.enableOCSPStapling) { + return SECSuccess; } - if (append) { - SECStatus rv; - /* 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; + rv = sslBuffer_AppendNumber(buf, 1 /* status_type ocsp */, 1); + if (rv != SECSuccess) { + return SECFailure; } - return extension_length; + /* 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; + } + + *added = PR_TRUE; + return SECSuccess; } SECStatus -ssl3_ClientHandleStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, +ssl3_ClientHandleStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData, SECItem *data) { /* In TLS 1.3, the extension carries the OCSP response. */ @@ -797,36 +649,32 @@ ssl3_ClientHandleStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData } /* Keep track of negotiated extensions. */ - xtnData->negotiated[xtnData->numNegotiated++] = ex_type; + xtnData->negotiated[xtnData->numNegotiated++] = ssl_cert_status_xtn; return SECSuccess; } PRUint32 ssl_ticket_lifetime = 2 * 24 * 60 * 60; /* 2 days in seconds */ -#define TLS_EX_SESS_TICKET_VERSION (0x0105) +#define TLS_EX_SESS_TICKET_VERSION (0x010a) /* * Called from ssl3_SendNewSessionTicket, tls13_SendNewSessionTicket */ SECStatus -ssl3_EncodeSessionTicket(sslSocket *ss, - const NewSessionTicket *ticket, - SECItem *ticket_data) +ssl3_EncodeSessionTicket(sslSocket *ss, const NewSessionTicket *ticket, + const PRUint8 *appToken, unsigned int appTokenLen, + PK11SymKey *secret, SECItem *ticket_data) { SECStatus rv; - SECItem plaintext; - SECItem plaintext_item = { 0, NULL, 0 }; - PRUint32 plaintext_length; + sslBuffer plaintext = SSL_BUFFER_EMPTY; SECItem ticket_buf = { 0, NULL, 0 }; - PRBool ms_is_wrapped; + sslSessionID sid; unsigned char wrapped_ms[SSL3_MASTER_SECRET_LENGTH]; SECItem ms_item = { 0, NULL, 0 }; - PRUint32 cert_length = 0; - PRUint32 now; + PRTime now; SECItem *srvName = NULL; - CK_MECHANISM_TYPE msWrapMech = 0; /* dummy default value, - * must be >= 0 */ - ssl3CipherSpec *spec; + CK_MECHANISM_TYPE msWrapMech; SECItem *alpnSelection = NULL; + PRUint32 ticketAgeBaseline; SSL_TRC(3, ("%d: SSL3[%d]: send session_ticket handshake", SSL_GETPID(), ss->fd)); @@ -834,107 +682,69 @@ ssl3_EncodeSessionTicket(sslSocket *ss, PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - if (ss->opt.requestCertificate && ss->sec.ci.sid->peerCert) { - cert_length = 2 + ss->sec.ci.sid->peerCert->derCert.len; - } + /* Extract the master secret wrapped. */ - 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_Memset(&sid, 0, sizeof(sslSessionID)); - 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. */ + PORT_Assert(secret); + rv = ssl3_CacheWrappedSecret(ss, &sid, secret); + if (rv == SECSuccess) { + if (sid.u.ssl3.keys.wrapped_master_secret_len > sizeof(wrapped_ms)) goto loser; - } - ms_is_wrapped = PR_TRUE; + 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; } /* 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 = ssl3_AppendNumberToItem(&plaintext, TLS_EX_SESS_TICKET_VERSION, - sizeof(PRUint16)); + rv = sslBuffer_AppendNumber(&plaintext, TLS_EX_SESS_TICKET_VERSION, + sizeof(PRUint16)); if (rv != SECSuccess) goto loser; /* ssl_version */ - rv = ssl3_AppendNumberToItem(&plaintext, ss->version, - sizeof(SSL3ProtocolVersion)); + rv = sslBuffer_AppendNumber(&plaintext, ss->version, + sizeof(SSL3ProtocolVersion)); if (rv != SECSuccess) goto loser; /* ciphersuite */ - rv = ssl3_AppendNumberToItem(&plaintext, ss->ssl3.hs.cipher_suite, - sizeof(ssl3CipherSuite)); + rv = sslBuffer_AppendNumber(&plaintext, ss->ssl3.hs.cipher_suite, + sizeof(ssl3CipherSuite)); if (rv != SECSuccess) goto loser; - /* compression */ - rv = ssl3_AppendNumberToItem(&plaintext, ss->ssl3.hs.compression, 1); + /* cipher spec parameters */ + rv = sslBuffer_AppendNumber(&plaintext, ss->sec.authType, 1); if (rv != SECSuccess) goto loser; - - /* cipher spec parameters */ - rv = ssl3_AppendNumberToItem(&plaintext, ss->sec.authType, 1); + rv = sslBuffer_AppendNumber(&plaintext, ss->sec.authKeyBits, 4); if (rv != SECSuccess) goto loser; - rv = ssl3_AppendNumberToItem(&plaintext, ss->sec.authKeyBits, 4); + rv = sslBuffer_AppendNumber(&plaintext, ss->sec.keaType, 1); if (rv != SECSuccess) goto loser; - rv = ssl3_AppendNumberToItem(&plaintext, ss->sec.keaType, 1); + rv = sslBuffer_AppendNumber(&plaintext, ss->sec.keaKeyBits, 4); if (rv != SECSuccess) goto loser; - rv = ssl3_AppendNumberToItem(&plaintext, ss->sec.keaKeyBits, 4); + 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); if (rv != SECSuccess) goto loser; @@ -945,102 +755,120 @@ ssl3_EncodeSessionTicket(sslSocket *ss, PORT_Assert(cert->namedCurve); /* EC curves only use the second of the two bytes. */ PORT_Assert(cert->namedCurve->name < 256); - rv = ssl3_AppendNumberToItem(&plaintext, cert->namedCurve->name, 1); + rv = sslBuffer_AppendNumber(&plaintext, cert->namedCurve->name, 1); } else { - rv = ssl3_AppendNumberToItem(&plaintext, 0, 1); + rv = sslBuffer_AppendNumber(&plaintext, 0, 1); } if (rv != SECSuccess) goto loser; /* master_secret */ - rv = ssl3_AppendNumberToItem(&plaintext, ms_is_wrapped, 1); - if (rv != SECSuccess) - goto loser; - rv = ssl3_AppendNumberToItem(&plaintext, msWrapMech, 4); + rv = sslBuffer_AppendNumber(&plaintext, msWrapMech, 4); if (rv != SECSuccess) goto loser; - rv = ssl3_AppendNumberToItem(&plaintext, ms_item.len, 2); - if (rv != SECSuccess) - goto loser; - rv = ssl3_AppendToItem(&plaintext, ms_item.data, ms_item.len); + rv = sslBuffer_AppendVariable(&plaintext, ms_item.data, ms_item.len, 2); if (rv != SECSuccess) goto loser; /* client identity */ if (ss->opt.requestCertificate && ss->sec.ci.sid->peerCert) { - 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); + rv = sslBuffer_AppendNumber(&plaintext, CLIENT_AUTH_CERTIFICATE, 1); if (rv != SECSuccess) goto loser; - rv = ssl3_AppendToItem(&plaintext, - ss->sec.ci.sid->peerCert->derCert.data, - ss->sec.ci.sid->peerCert->derCert.len); + rv = sslBuffer_AppendVariable(&plaintext, + ss->sec.ci.sid->peerCert->derCert.data, + ss->sec.ci.sid->peerCert->derCert.len, 2); if (rv != SECSuccess) goto loser; } else { - rv = ssl3_AppendNumberToItem(&plaintext, 0, 1); + rv = sslBuffer_AppendNumber(&plaintext, 0, 1); if (rv != SECSuccess) goto loser; } /* timestamp */ - now = ssl_Time(); - rv = ssl3_AppendNumberToItem(&plaintext, now, - sizeof(ticket->ticket_lifetime_hint)); + now = ssl_TimeUsec(); + PORT_Assert(sizeof(now) == 8); + rv = sslBuffer_AppendNumber(&plaintext, now, 8); if (rv != SECSuccess) goto loser; /* HostName (length and value) */ - rv = ssl3_AppendNumberToItem(&plaintext, srvName->len, 2); + rv = sslBuffer_AppendVariable(&plaintext, srvName->data, 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 = ssl3_AppendNumberToItem( + rv = sslBuffer_AppendNumber( &plaintext, ss->sec.ci.sid->u.ssl3.keys.extendedMasterSecretUsed, 1); if (rv != SECSuccess) goto loser; /* Flags */ - rv = ssl3_AppendNumberToItem(&plaintext, ticket->flags, - sizeof(ticket->flags)); + rv = sslBuffer_AppendNumber(&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 = ssl3_AppendNumberToItem(&plaintext, alpnSelection->len, 1); + rv = sslBuffer_AppendVariable(&plaintext, alpnSelection->data, + alpnSelection->len, 1); if (rv != SECSuccess) goto loser; - if (alpnSelection->len) { - rv = ssl3_AppendToItem(&plaintext, alpnSelection->data, - alpnSelection->len); - if (rv != SECSuccess) - goto loser; - } - rv = ssl3_AppendNumberToItem(&plaintext, ssl_max_early_data_size, 4); + rv = sslBuffer_AppendNumber(&plaintext, ssl_max_early_data_size, 4); if (rv != SECSuccess) goto loser; - /* Check that we are totally full. */ - PORT_Assert(plaintext.len == 0); + /* + * 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); + if (rv != SECSuccess) + goto loser; + + /* Application token */ + rv = sslBuffer_AppendVariable(&plaintext, appToken, appTokenLen, 2); + 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; + } - /* 128 just gives us enough room for overhead. */ - if (SECITEM_AllocItem(NULL, &ticket_buf, plaintext_length + 128) == NULL) { + 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) { goto loser; } /* Finally, encrypt the ticket. */ - rv = ssl_SelfEncryptProtect(ss, plaintext_item.data, plaintext_item.len, + rv = ssl_SelfEncryptProtect(ss, SSL_BUFFER_BASE(&plaintext), + SSL_BUFFER_LEN(&plaintext), ticket_buf.data, &ticket_buf.len, ticket_buf.len); if (rv != SECSuccess) { goto loser; @@ -1049,13 +877,11 @@ ssl3_EncodeSessionTicket(sslSocket *ss, /* Give ownership of memory to caller. */ *ticket_data = ticket_buf; - SECITEM_FreeItem(&plaintext_item, PR_FALSE); + sslBuffer_Clear(&plaintext); return SECSuccess; loser: - if (plaintext_item.data) { - SECITEM_FreeItem(&plaintext_item, PR_FALSE); - } + sslBuffer_Clear(&plaintext); if (ticket_buf.data) { SECITEM_FreeItem(&ticket_buf, PR_FALSE); } @@ -1067,18 +893,22 @@ loser: * message is expected during the handshake. */ SECStatus -ssl3_ClientHandleSessionTicketXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, +ssl3_ClientHandleSessionTicketXtn(const sslSocket *ss, TLSExtensionData *xtnData, 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++] = ex_type; + xtnData->negotiated[xtnData->numNegotiated++] = ssl_session_ticket_xtn; return SECSuccess; } +PR_STATIC_ASSERT((TLS_EX_SESS_TICKET_VERSION >> 8) == 1); + static SECStatus ssl_ParseSessionTicket(sslSocket *ss, const SECItem *decryptedTicket, SessionTicket *parsedTicket) @@ -1105,6 +935,12 @@ 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) { @@ -1132,14 +968,6 @@ 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) { @@ -1165,6 +993,18 @@ 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); @@ -1185,14 +1025,6 @@ 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); @@ -1240,13 +1072,21 @@ ssl_ParseSessionTicket(sslSocket *ss, const SECItem *decryptedTicket, PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure; } - /* Read timestamp. */ + + /* 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; rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 4, &buffer, &len); if (rv != SECSuccess) { PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure; } - parsedTicket->timestamp = temp; + parsedTicket->timestamp |= (PRTime)temp; /* Read server name */ rv = ssl3_ExtConsumeHandshakeVariable(ss, &parsedTicket->srvName, 2, @@ -1287,6 +1127,20 @@ 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) { @@ -1313,13 +1167,15 @@ 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); @@ -1338,7 +1194,6 @@ 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; @@ -1381,10 +1236,12 @@ loser: /* Generic ticket processing code, common to all TLS versions. */ SECStatus -ssl3_ProcessSessionTicketCommon(sslSocket *ss, SECItem *data) +ssl3_ProcessSessionTicketCommon(sslSocket *ss, const SECItem *ticket, + SECItem *appToken) { SECItem decryptedTicket = { siBuffer, NULL, 0 }; SessionTicket parsedTicket; + sslSessionID *sid = NULL; SECStatus rv; if (ss->sec.ci.sid != NULL) { @@ -1393,12 +1250,12 @@ ssl3_ProcessSessionTicketCommon(sslSocket *ss, SECItem *data) ss->sec.ci.sid = NULL; } - if (!SECITEM_AllocItem(NULL, &decryptedTicket, data->len)) { + if (!SECITEM_AllocItem(NULL, &decryptedTicket, ticket->len)) { return SECFailure; } /* Decrypt the ticket. */ - rv = ssl_SelfEncryptUnprotect(ss, data->data, data->len, + rv = ssl_SelfEncryptUnprotect(ss, ticket->data, ticket->len, decryptedTicket.data, &decryptedTicket.len, decryptedTicket.len); @@ -1428,16 +1285,28 @@ ssl3_ProcessSessionTicketCommon(sslSocket *ss, SECItem *data) } /* Use the ticket if it is valid and unexpired. */ - if (parsedTicket.valid && - parsedTicket.timestamp + ssl_ticket_lifetime > ssl_Time()) { - sslSessionID *sid; + if (parsedTicket.timestamp + ssl_ticket_lifetime * PR_USEC_PER_SEC > + ssl_TimeUsec()) { - rv = ssl_CreateSIDFromTicket(ss, data, &parsedTicket, &sid); + rv = ssl_CreateSIDFromTicket(ss, ticket, &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); @@ -1445,15 +1314,19 @@ ssl3_ProcessSessionTicketCommon(sslSocket *ss, SECItem *data) 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, PRUint16 ex_type, +ssl3_ServerHandleSessionTicketXtn(const sslSocket *ss, TLSExtensionData *xtnData, SECItem *data) { + PORT_Assert(ss->version < SSL_LIBRARY_VERSION_TLS_1_3); /* Ignore the SessionTicket extension if processing is disabled. */ if (!ss->opt.enableSessionTickets) { @@ -1466,7 +1339,7 @@ ssl3_ServerHandleSessionTicketXtn(const sslSocket *ss, TLSExtensionData *xtnData } /* Keep track of negotiated extensions. */ - xtnData->negotiated[xtnData->numNegotiated++] = ex_type; + xtnData->negotiated[xtnData->numNegotiated++] = ssl_session_ticket_xtn; /* Parse the received ticket sent in by the client. We are * lenient about some parse errors, falling back to a fullshake @@ -1477,7 +1350,8 @@ ssl3_ServerHandleSessionTicketXtn(const sslSocket *ss, TLSExtensionData *xtnData return SECSuccess; } - return ssl3_ProcessSessionTicketCommon(CONST_CAST(sslSocket, ss), data); + return ssl3_ProcessSessionTicketCommon(CONST_CAST(sslSocket, ss), data, + NULL); } /* Extension format: @@ -1487,60 +1361,45 @@ 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) */ -PRInt32 -ssl3_SendRenegotiationInfoXtn( - const sslSocket *ss, - TLSExtensionData *xtnData, - PRBool append, - PRUint32 maxBytes) +SECStatus +ssl3_SendRenegotiationInfoXtn(const sslSocket *ss, TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added) { PRInt32 len = 0; - PRInt32 needed; + SECStatus rv; - /* 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. + /* 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. */ - if (!ss || ss->ssl3.hs.sendingSCSV) + if (ss->ssl3.hs.sendingSCSV) { return 0; + } if (ss->firstHsDone) { len = ss->sec.isServer ? ss->ssl3.hs.finishedBytes * 2 : ss->ssl3.hs.finishedBytes; } - needed = 5 + len; - if (maxBytes < (PRUint32)needed) { - return 0; - } - 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; - } + + /* verify_Data from previous Finished message(s) */ + rv = sslBuffer_AppendVariable(buf, + ss->ssl3.hs.finishedMsgs.data, len, 1); + if (rv != SECSuccess) { + return SECFailure; } - return needed; + + *added = PR_TRUE; + return SECSuccess; } /* This function runs in both the client and server. */ SECStatus -ssl3_HandleRenegotiationInfoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) +ssl3_HandleRenegotiationInfoXtn(const sslSocket *ss, TLSExtensionData *xtnData, + 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; @@ -1558,97 +1417,78 @@ 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++] = ex_type; + xtnData->negotiated[xtnData->numNegotiated++] = ssl_renegotiation_info_xtn; if (ss->sec.isServer) { /* prepare to send back the appropriate response */ - rv = ssl3_RegisterExtensionSender(ss, xtnData, ex_type, + rv = ssl3_RegisterExtensionSender(ss, xtnData, + ssl_renegotiation_info_xtn, ssl3_SendRenegotiationInfoXtn); } return rv; } -PRInt32 -ssl3_ClientSendUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, PRUint32 maxBytes) +SECStatus +ssl3_ClientSendUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added) { - PRUint32 ext_data_len; - PRInt16 i; + unsigned int i; SECStatus rv; - if (!ss) - return 0; - - if (!IS_DTLS(ss) || !ss->ssl3.dtlsSRTPCipherCount) - return 0; /* Not relevant */ - - ext_data_len = 2 + 2 * ss->ssl3.dtlsSRTPCipherCount + 1; + if (!IS_DTLS(ss) || !ss->ssl3.dtlsSRTPCipherCount) { + return SECSuccess; /* Not relevant */ + } - 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; + /* 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; } - /* Empty MKI value */ - ssl3_ExtAppendHandshakeVariable(ss, NULL, 0, 1); - - xtnData->advertised[xtnData->numAdvertised++] = - ssl_use_srtp_xtn; + } + /* Empty MKI value */ + rv = sslBuffer_AppendNumber(buf, 0, 1); + if (rv != SECSuccess) { + return SECFailure; } - return 4 + ext_data_len; + *added = PR_TRUE; + return SECSuccess; } -PRInt32 -ssl3_ServerSendUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, PRUint32 maxBytes) +SECStatus +ssl3_ServerSendUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added) { SECStatus rv; - /* 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; + rv = sslBuffer_AppendNumber(buf, 2, 2); + if (rv != SECSuccess) { + return SECFailure; + } /* The selected cipher */ - rv = ssl3_ExtAppendHandshakeNumber(ss, xtnData->dtlsSRTPCipherSuite, 2); - if (rv != SECSuccess) - return -1; + rv = sslBuffer_AppendNumber(buf, xtnData->dtlsSRTPCipherSuite, 2); + if (rv != SECSuccess) { + return SECFailure; + } /* Empty MKI value */ - ssl3_ExtAppendHandshakeVariable(ss, NULL, 0, 1); + rv = sslBuffer_AppendNumber(buf, 0, 1); + if (rv != SECSuccess) { + return SECFailure; + } - return 9; + *added = PR_TRUE; + return SECSuccess; } SECStatus -ssl3_ClientHandleUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) +ssl3_ClientHandleUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, + SECItem *data) { SECStatus rv; SECItem ciphers = { siBuffer, NULL, 0 }; @@ -1718,7 +1558,8 @@ ssl3_ClientHandleUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUi } SECStatus -ssl3_ServerHandleUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) +ssl3_ServerHandleUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, + SECItem *data) { SECStatus rv; SECItem ciphers = { siBuffer, NULL, 0 }; @@ -1789,11 +1630,12 @@ ssl3_ServerHandleUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUi ssl3_ServerSendUseSRTPXtn); } -/* ssl3_ServerHandleSigAlgsXtn handles the signature_algorithms extension - * from a client. - * See https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */ +/* 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 */ SECStatus -ssl3_ServerHandleSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) +ssl3_HandleSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData, + SECItem *data) { SECStatus rv; @@ -1802,15 +1644,15 @@ ssl3_ServerHandleSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUi return SECSuccess; } - if (xtnData->clientSigSchemes) { - PORT_Free(xtnData->clientSigSchemes); - xtnData->clientSigSchemes = NULL; + if (xtnData->sigSchemes) { + PORT_Free(xtnData->sigSchemes); + xtnData->sigSchemes = NULL; } rv = ssl_ParseSignatureSchemes(ss, NULL, - &xtnData->clientSigSchemes, - &xtnData->numClientSigScheme, + &xtnData->sigSchemes, + &xtnData->numSigSchemes, &data->data, &data->len); - if (rv != SECSuccess || xtnData->numClientSigScheme == 0) { + if (rv != SECSuccess || xtnData->numSigSchemes == 0) { ssl3_ExtSendAlert(ss, alert_fatal, decode_error); PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO); return SECFailure; @@ -1823,177 +1665,52 @@ ssl3_ServerHandleSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUi } /* Keep track of negotiated extensions. */ - xtnData->negotiated[xtnData->numNegotiated++] = ex_type; + xtnData->negotiated[xtnData->numNegotiated++] = ssl_signature_algorithms_xtn; return SECSuccess; } /* ssl3_ClientSendSigAlgsXtn sends the signature_algorithm extension for TLS * 1.2 ClientHellos. */ -PRInt32 -ssl3_ClientSendSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, PRUint32 maxBytes) +SECStatus +ssl3_SendSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added) { - PRInt32 extension_length; - PRUint8 buf[MAX_SIGNATURE_SCHEMES * 2]; - PRUint32 len; SECStatus rv; if (ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_2) { - return 0; - } - - rv = ssl3_EncodeSigAlgs(ss, buf, sizeof(buf), &len); - if (rv != SECSuccess) { - return -1; - } - - 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; -} - -/* 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; + return SECSuccess; } - rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_padding_xtn, 2); - if (rv != SECSuccess) { - return -1; - } - rv = ssl3_ExtAppendHandshakeVariable(ss, padding, xtnData->paddingLen, 2); + rv = ssl3_EncodeSigAlgs(ss, buf); if (rv != SECSuccess) { - return -1; + return SECFailure; } - return extensionLen; + *added = PR_TRUE; + return SECSuccess; } -PRInt32 -ssl3_SendExtendedMasterSecretXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, - PRUint32 maxBytes) +SECStatus +ssl3_SendExtendedMasterSecretXtn(const sslSocket *ss, TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added) { - PRInt32 extension_length; - if (!ss->opt.enableExtendedMS) { - return 0; + return SECSuccess; } /* 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. */ - 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; + *added = PR_TRUE; + return SECSuccess; } SECStatus -ssl3_HandleExtendedMasterSecretXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, +ssl3_HandleExtendedMasterSecretXtn(const sslSocket *ss, TLSExtensionData *xtnData, SECItem *data) { + PORT_Assert(ss->version < SSL_LIBRARY_VERSION_TLS_1_3); + if (ss->version < SSL_LIBRARY_VERSION_TLS_1_0) { return SECSuccess; } @@ -2013,54 +1730,34 @@ ssl3_HandleExtendedMasterSecretXtn(const sslSocket *ss, TLSExtensionData *xtnDat SSL_GETPID(), ss->fd)); /* Keep track of negotiated extensions. */ - xtnData->negotiated[xtnData->numNegotiated++] = ex_type; + xtnData->negotiated[xtnData->numNegotiated++] = ssl_extended_master_secret_xtn; if (ss->sec.isServer) { - return ssl3_RegisterExtensionSender( - ss, xtnData, ex_type, ssl3_SendExtendedMasterSecretXtn); + return ssl3_RegisterExtensionSender(ss, xtnData, + ssl_extended_master_secret_xtn, + ssl_SendEmptyExtension); } return SECSuccess; } /* ssl3_ClientSendSignedCertTimestampXtn sends the signed_certificate_timestamp * extension for TLS ClientHellos. */ -PRInt32 -ssl3_ClientSendSignedCertTimestampXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, - PRUint32 maxBytes) +SECStatus +ssl3_ClientSendSignedCertTimestampXtn(const sslSocket *ss, + TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added) { - PRInt32 extension_length = 2 /* extension_type */ + - 2 /* length(extension_data) */; - /* Only send the extension if processing is enabled. */ - 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; + if (!ss->opt.enableSignedCertTimestamps) { + return SECSuccess; } - return extension_length; -loser: - return -1; + *added = PR_TRUE; + return SECSuccess; } SECStatus -ssl3_ClientHandleSignedCertTimestampXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, +ssl3_ClientHandleSignedCertTimestampXtn(const sslSocket *ss, TLSExtensionData *xtnData, SECItem *data) { /* We do not yet know whether we'll be resuming a session or creating @@ -2080,54 +1777,34 @@ ssl3_ClientHandleSignedCertTimestampXtn(const sslSocket *ss, TLSExtensionData *x } *scts = *data; /* Keep track of negotiated extensions. */ - xtnData->negotiated[xtnData->numNegotiated++] = ex_type; + xtnData->negotiated[xtnData->numNegotiated++] = ssl_signed_cert_timestamp_xtn; return SECSuccess; } -PRInt32 +SECStatus ssl3_ServerSendSignedCertTimestampXtn(const sslSocket *ss, TLSExtensionData *xtnData, - PRBool append, - PRUint32 maxBytes) + sslBuffer *buf, PRBool *added) { - PRInt32 extension_length; const SECItem *scts = &ss->sec.serverCert->signedCertTimestamps; + SECStatus rv; if (!scts->len) { /* No timestamps to send */ - return 0; + return SECSuccess; } - 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; - } + rv = sslBuffer_Append(buf, scts->data, scts->len); + if (rv != SECSuccess) { + return SECFailure; } - return extension_length; + *added = PR_TRUE; + return SECSuccess; } SECStatus ssl3_ServerHandleSignedCertTimestampXtn(const sslSocket *ss, TLSExtensionData *xtnData, - PRUint16 ex_type, SECItem *data) { if (data->len != 0) { @@ -2136,22 +1813,25 @@ ssl3_ServerHandleSignedCertTimestampXtn(const sslSocket *ss, return SECFailure; } - xtnData->negotiated[xtnData->numNegotiated++] = ex_type; + xtnData->negotiated[xtnData->numNegotiated++] = ssl_signed_cert_timestamp_xtn; PORT_Assert(ss->sec.isServer); - return ssl3_RegisterExtensionSender( - ss, xtnData, ex_type, ssl3_ServerSendSignedCertTimestampXtn); + return ssl3_RegisterExtensionSender(ss, xtnData, + ssl_signed_cert_timestamp_xtn, + 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, - PRUint16 ex_type, +ssl3_HandleSupportedPointFormatsXtn(const sslSocket *ss, + TLSExtensionData *xtnData, 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); @@ -2160,10 +1840,9 @@ ssl3_HandleSupportedPointFormatsXtn(const sslSocket *ss, TLSExtensionData *xtnDa for (i = data->len; --i > 0;) { if (data->data[i] == 0) { /* indicate that we should send a reply */ - SECStatus rv; - rv = ssl3_RegisterExtensionSender(ss, xtnData, ex_type, - &ssl3_SendSupportedPointFormatsXtn); - return rv; + return ssl3_RegisterExtensionSender( + ss, xtnData, ssl_ec_point_formats_xtn, + &ssl3_SendSupportedPointFormatsXtn); } } @@ -2248,7 +1927,7 @@ ssl_UpdateSupportedGroups(sslSocket *ss, SECItem *data) */ SECStatus ssl_HandleSupportedGroupsXtn(const sslSocket *ss, TLSExtensionData *xtnData, - PRUint16 ex_type, SECItem *data) + SECItem *data) { SECStatus rv; @@ -2258,7 +1937,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, ex_type, + rv = ssl3_RegisterExtensionSender(ss, xtnData, ssl_supported_groups_xtn, &ssl_SendSupportedGroupsXtn); if (rv != SECSuccess) { return SECFailure; /* error already set. */ @@ -2266,7 +1945,7 @@ ssl_HandleSupportedGroupsXtn(const sslSocket *ss, TLSExtensionData *xtnData, } /* Remember that we negotiated this extension. */ - xtnData->negotiated[xtnData->numNegotiated++] = ex_type; + xtnData->negotiated[xtnData->numNegotiated++] = ssl_supported_groups_xtn; return SECSuccess; } |