Index: net/third_party/nss/ssl/ssl3ext.c |
=================================================================== |
--- net/third_party/nss/ssl/ssl3ext.c (revision 86360) |
+++ net/third_party/nss/ssl/ssl3ext.c (working copy) |
@@ -247,6 +247,7 @@ |
{ ssl_session_ticket_xtn, &ssl3_ClientHandleSessionTicketXtn }, |
{ ssl_renegotiation_info_xtn, &ssl3_HandleRenegotiationInfoXtn }, |
{ ssl_next_proto_neg_xtn, &ssl3_ClientHandleNextProtoNegoXtn }, |
+ { ssl_cached_info_xtn, &ssl3_ClientHandleCachedInfoXtn }, |
{ ssl_cert_status_xtn, &ssl3_ClientHandleStatusRequestXtn }, |
{ ssl_snap_start_xtn, &ssl3_ClientHandleSnapStartXtn }, |
{ -1, NULL } |
@@ -273,6 +274,7 @@ |
#endif |
{ ssl_session_ticket_xtn, &ssl3_SendSessionTicketXtn }, |
{ ssl_next_proto_neg_xtn, &ssl3_ClientSendNextProtoNegoXtn }, |
+ { ssl_cached_info_xtn, &ssl3_ClientSendCachedInfoXtn }, |
{ ssl_cert_status_xtn, &ssl3_ClientSendStatusRequestXtn }, |
{ ssl_snap_start_xtn, &ssl3_SendSnapStartXtn } |
/* NOTE: The Snap Start sender MUST be the last extension in the list. */ |
@@ -681,6 +683,141 @@ |
return SECSuccess; |
} |
+/* ssl3_ClientSendCachedInfoXtn builds the cached_info extension on the |
+ * client side. */ |
+PRInt32 |
+ssl3_ClientSendCachedInfoXtn(sslSocket * ss, PRBool append, |
+ PRUint32 maxBytes) |
+{ |
+ PRInt32 extension_length; |
+ PRBool send_empty; |
+ |
+ if (!ss->opt.enableCachedInfo) |
+ return 0; |
+ |
+ CERTCertificate ** predictedCertChain = ss->ssl3.predictedCertChain; |
+ //send_empty = (predictedCertChain == NULL || predictedCertChain[0] == NULL) |
+ // ? PR_TRUE : PR_FALSE; |
+ send_empty = (predictedCertChain == NULL) ? PR_TRUE : PR_FALSE; |
+ |
+ /* minimum extension: |
+ * extension_type (2-bytes) + |
+ * length(extension_data) (2-bytes) + |
+ * length(cached_info) (2-bytes) + |
+ */ |
+ extension_length = send_empty ? 6 : 16; |
+ |
+ if (append && maxBytes >= extension_length) { |
+ SECStatus rv; |
+ TLSExtensionData *xtnData; |
+ |
+ /* ExtensionType */ |
+ rv = ssl3_AppendHandshakeNumber(ss, ssl_cached_info_xtn, 2); |
+ if (rv != SECSuccess) |
+ return -1; |
+ /* Extension Length */ |
+ rv = ssl3_AppendHandshakeNumber(ss, extension_length - 4, 2); |
+ if (rv != SECSuccess) |
+ return -1; |
+ if (send_empty) { |
+ /* Cached Information Length */ |
+ rv = ssl3_AppendHandshakeNumber(ss, 0, 2); |
+ if (rv != SECSuccess) |
+ return -1; |
+ } else { |
+ /* Cached Information Length */ |
+ rv = ssl3_AppendHandshakeNumber(ss, 10, 2); |
+ if (rv != SECSuccess) |
+ return -1; |
+ /* Cached Information Type */ |
+ rv = ssl3_AppendHandshakeNumber(ss, 1 /* certificate_chain */, 1); |
+ if (rv != SECSuccess) |
+ return -1; |
+ /* hash length */ |
+ rv = ssl3_AppendHandshakeNumber(ss, 8, 1); |
+ if (rv != SECSuccess) |
+ return -1; |
+ /* hash */ |
+ PRUint64 certChainHash; |
+ FNV1A64_Init(&certChainHash); |
+ int i; |
+ for (i = 0; predictedCertChain[i] != NULL; i++) { |
+ unsigned int certLen = predictedCertChain[i]->derCert.len; |
+ unsigned char certLenArray[3] = |
+ {(certLen & 0xff0000) >> 16, (certLen & 0xff00) >> 8, certLen & 0xff}; |
+ FNV1A64_Update(&certChainHash, certLenArray, 3); |
+ FNV1A64_Update(&certChainHash, predictedCertChain[i]->derCert.data, certLen); |
+ } |
wtc
2011/06/03 22:56:55
Fold these long lines.
rkn
2011/06/04 20:50:19
Done.
|
+ FNV1A64_Final(&certChainHash); |
+ rv = ssl3_AppendHandshake(ss, &certChainHash, 8); |
+ if (rv != SECSuccess) |
+ return -1; |
+ } |
+ |
+ } else if (maxBytes < extension_length) { |
+ PORT_Assert(0); |
+ return 0; |
+ } |
+ ss->xtnData.advertised[ss->xtnData.numAdvertised++] = |
+ ssl_cached_info_xtn; |
+ return extension_length; |
+} |
+ |
+SECStatus |
+ssl3_ClientHandleCachedInfoXtn(sslSocket *ss, PRUint16 ex_type, |
+ SECItem *data) |
+{ |
+ /* If we didn't request this extension, then the server may not echo it. */ |
+ if (!ss->opt.enableCachedInfo) |
+ return SECFailure; |
+ |
+ if (data->len == 0) { |
+ /* The server supports information caching, but provides no information |
+ * about what information types it supports */ |
+ ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type; |
+ return SECSuccess; |
+ } |
+ |
+ if (data->len < 2) |
+ return SECFailure; |
+ unsigned char * cached_info = data->data; |
+ unsigned int remaining_cached_info_length = |
+ (cached_info[0] << 8) | cached_info[1]; |
+ if (remaining_cached_info_length != data->len - 2) |
+ return SECFailure; |
+ cached_info += 2; |
+ PRBool has_certificate_chain = PR_FALSE; |
+ while (remaining_cached_info_length >= 2) { |
+ /* The server supports only those CachedInformationType types that are |
+ * identified by a present CachedObject */ |
+ unsigned char cached_object_type; |
+ unsigned int cached_object_length; |
+ cached_object_type = *cached_info++; |
+ cached_object_length = *cached_info++; |
+ remaining_cached_info_length -= 2; |
+ if (remaining_cached_info_length < cached_object_length) |
+ return SECFailure; |
+ if (cached_object_length != 0 && cached_object_length != 8) |
+ return SECFailure; |
+ remaining_cached_info_length -= cached_object_length; |
+ if (cached_object_type == cached_info_certificate_chain) { |
+ has_certificate_chain = PR_TRUE; |
+ //TODO(rkn): Should also check that the hash matches our cached |
+ //hash. So we need to store the hash. |
+ } |
+ } |
+ |
+ if (remaining_cached_info_length != 0) |
+ return SECFailure; |
+ |
+ if (has_certificate_chain) { |
+ ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type; |
+ return SECSuccess; |
+ } |
+ |
+ return SECFailure; |
+} |
+ |
/* ssl3_ClientSendStatusRequestXtn builds the status_request extension on the |
* client side. See RFC 4366 section 3.6. */ |
PRInt32 |