diff --git a/mozilla/security/nss/cmd/selfserv/selfserv.c b/mozilla/security/nss/cmd/selfserv/selfserv.c
index cef9e91..c64e1dc 100644
--- a/mozilla/security/nss/cmd/selfserv/selfserv.c
+++ b/mozilla/security/nss/cmd/selfserv/selfserv.c
@@ -801,6 +801,7 @@ PRBool disableLocking  = PR_FALSE;
 PRBool testbypass      = PR_FALSE;
 PRBool enableSessionTickets = PR_FALSE;
 PRBool enableCompression    = PR_FALSE;
+PRBool enableCachedInfo     = PR_FALSE;
 PRBool failedToNegotiateName  = PR_FALSE;
 static char  *virtServerNameArray[MAX_VIRT_SERVER_NAME_ARRAY_INDEX];
 
@@ -1706,6 +1707,12 @@ server_main(
 	}
     }
 
+    if (enableCachedInfo) {
+	rv = SSL_OptionSet(model_sock, SSL_ENABLE_CACHED_INFO, PR_TRUE);
+	if (rv != SECSuccess)
+	    errExit("error enabling cached info extension");
+    }
+
     rv = SSL_SNISocketConfigHook(model_sock, mySSLSNISocketConfig,
                                  (void*)&virtServerNameArray);
     if (rv != SECSuccess) {
@@ -1949,7 +1956,7 @@ main(int argc, char **argv)
     ** numbers, then capital letters, then lower case, alphabetical. 
     */
     optstate = PL_CreateOptState(argc, argv, 
-        "2:3BC:DEL:M:NP:RSTa:bc:d:e:f:g:hi:jk:lmn:op:qrst:uvw:xyz");
+        "2:3BC:DEIL:M:NP:RSTa:bc:d:e:f:g:hi:jk:lmn:op:qrst:uvw:xyz");
     while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
 	++optionsFound;
 	switch(optstate->option) {
@@ -1964,6 +1971,8 @@ main(int argc, char **argv)
 	case 'D': noDelay = PR_TRUE; break;
 	case 'E': disableStepDown = PR_TRUE; break;
 
+	case 'I': enableCachedInfo = PR_TRUE; break;
+
         case 'L':
             logStats = PR_TRUE;
 	    if (optstate->value == NULL) {
diff --git a/mozilla/security/nss/cmd/tstclnt/tstclnt.c b/mozilla/security/nss/cmd/tstclnt/tstclnt.c
index c15a0ad..b88d931 100644
--- a/mozilla/security/nss/cmd/tstclnt/tstclnt.c
+++ b/mozilla/security/nss/cmd/tstclnt/tstclnt.c
@@ -225,6 +225,7 @@ static void Usage(const char *progName)
     fprintf(stderr, "%-20s Renegotiate N times (resuming session if N>1).\n", "-r N");
     fprintf(stderr, "%-20s Enable the session ticket extension.\n", "-u");
     fprintf(stderr, "%-20s Enable compression.\n", "-z");
+    fprintf(stderr, "%-20s Enable cached info.\n", "-I pemfile");
     fprintf(stderr, "%-20s Letter(s) chosen from the following list\n", 
                     "-c ciphers");
     fprintf(stderr, 
@@ -521,6 +522,7 @@ int main(int argc, char **argv)
     int                useExportPolicy = 0;
     int                enableSessionTickets = 0;
     int                enableCompression = 0;
+    const char *       predictedCert = NULL;
     PRSocketOptionData opt;
     PRNetAddr          addr;
     PRPollDesc         pollset[2];
@@ -551,7 +553,7 @@ int main(int argc, char **argv)
     }
 
     optstate = PL_CreateOptState(argc, argv,
-                                 "23BSTW:a:c:d:fh:m:n:op:qr:suvw:xz");
+                                 "23BI:STW:a:c:d:fh:m:n:op:qr:suvw:xz");
     while ((optstatus = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
 	switch (optstate->option) {
 	  case '?':
@@ -563,6 +565,8 @@ int main(int argc, char **argv)
 
           case 'B': bypassPKCS11 = 1; 			break;
 
+          case 'I': predictedCert = optstate->value;	break;
+
           case 'S': skipProtoHeader = PR_TRUE;                 break;
 
           case 'T': disableTLS  = 1; 			break;
@@ -863,7 +867,55 @@ int main(int argc, char **argv)
 	SECU_PrintError(progName, "error enabling compression");
 	return 1;
     }
-               
+
+    /* enable cached info. */
+    rv = SSL_OptionSet(s, SSL_ENABLE_CACHED_INFO, predictedCert != NULL);
+    if (rv != SECSuccess) {
+	SECU_PrintError(progName, "error enabling cached info");
+	return 1;
+    }
+
+    if (predictedCert) {
+	FILE *f = fopen(predictedCert, "r");
+	long filelen;
+	char *contents;
+	CERTCertificate *cert;
+
+	if (!f) {
+	    fprintf(stderr, "%s: error reading predicted certificate", progName);
+	    return 1;
+	}
+
+	fseek(f, 0, SEEK_END);
+	filelen = ftell(f);
+	fseek(f, 0, SEEK_SET);
+	contents = PORT_Alloc(filelen);
+	if (!contents) {
+	    fclose(f);
+	    SECU_PrintError(progName, "predicted certificate too large");
+	    return 1;
+	}
+
+	if (1 != fread(contents, filelen, 1, f)) {
+	    fclose(f);
+	    PORT_Free(contents);
+	    printf(stderr, "%s: I/O error reading predicted certificate", progName);
+	    return 1;
+	}
+	fclose(f);
+
+	cert = CERT_DecodeCertFromPackage(contents, filelen);
+	if (!cert) {
+	    PORT_Free(contents);
+	    SECU_PrintError(progName, "failed to parse predicted certificate");
+	    return 1;
+	}
+
+	SSL_SetPredictedPeerCertificate(s, &cert, 1);
+	CERT_DestroyCertificate(cert);
+	PORT_Free(contents);
+    }
+
     SSL_SetPKCS11PinArg(s, &pwdata);
 
     SSL_AuthCertificateHook(s, SSL_AuthCertificate, (void *)handle);
diff --git a/mozilla/security/nss/lib/ssl/ssl.def b/mozilla/security/nss/lib/ssl/ssl.def
index d3f455c..dd8032d 100644
--- a/mozilla/security/nss/lib/ssl/ssl.def
+++ b/mozilla/security/nss/lib/ssl/ssl.def
@@ -152,3 +152,9 @@ SSL_SNISocketConfigHook;
 ;+    local:
 ;+*;
 ;+};
+;+NSS_3.12.7 {      # NSS 3.12.7 release
+;+    global:
+SSL_SetPredictedPeerCertificate;
+;+    local:
+;+*;
+;+};
diff --git a/mozilla/security/nss/lib/ssl/ssl.h b/mozilla/security/nss/lib/ssl/ssl.h
index d60a73c..9aebc24 100644
--- a/mozilla/security/nss/lib/ssl/ssl.h
+++ b/mozilla/security/nss/lib/ssl/ssl.h
@@ -128,6 +128,7 @@ SSL_IMPORT PRFileDesc *SSL_ImportFD(PRFileDesc *model, PRFileDesc *fd);
                                           /* Renegotiation  Info (RI)       */
 					  /* extension in ALL handshakes.   */
                                           /* default: off                   */
+#define SSL_ENABLE_CACHED_INFO         22 /* Enable TLS cached info extn   */
 
 #ifdef SSL_DEPRECATED_FUNCTION 
 /* Old deprecated function names */
@@ -353,6 +354,18 @@ SSL_IMPORT SECStatus SSL_BadCertHook(PRFileDesc *fd, SSLBadCertHandler f,
 				     void *arg);
 
 /*
+ * Set the predicted chain of certificates for the peer. This is used for the
+ * TLS cached-info extension to save the peer from retransmitting its full
+ * chain for each (non-resumption) handshake. Note that the
+ * SSL_ENABLE_CACHED_INFO option must be set for this to occur.
+ *
+ * This function takes a reference to each of the given certificates.
+ */
+SSL_IMPORT SECStatus SSL_SetPredictedPeerCertificate(
+				PRFileDesc *fd, CERTCertificate **certs,
+				unsigned int len);
+
+/*
 ** Configure SSL socket for running a secure server. Needs the
 ** certificate for the server and the servers private key. The arguments
 ** are copied.
diff --git a/mozilla/security/nss/lib/ssl/ssl3con.c b/mozilla/security/nss/lib/ssl/ssl3con.c
index 083248d..0cf66a5 100644
--- a/mozilla/security/nss/lib/ssl/ssl3con.c
+++ b/mozilla/security/nss/lib/ssl/ssl3con.c
@@ -7616,6 +7616,7 @@ ssl3_SendCertificate(sslSocket *ss)
     int                  len 		= 0;
     int                  i;
     SSL3KEAType          certIndex;
+    PRBool               predictionCorrect = PR_FALSE;
 #ifdef NISCC_TEST
     SECItem              fakeCert;
     int                  ndex           = -1;
@@ -7632,7 +7633,7 @@ ssl3_SendCertificate(sslSocket *ss)
     if (ss->sec.isServer) {
 	sslServerCerts * sc = NULL;
 
-	/* XXX SSLKEAType isn't really a good choice for 
+	/* XXX SSLKEAType isn't really a good choice for
 	 * indexing certificates (it breaks when we deal
 	 * with (EC)DHE-* cipher suites. This hack ensures
 	 * the RSA cert is picked for (EC)DHE-RSA.
@@ -7660,7 +7661,31 @@ ssl3_SendCertificate(sslSocket *ss)
     rv = get_fake_cert(&fakeCert, &ndex);
 #endif
 
-    if (certChain) {
+    /* If the client predicted a certificate we'll calculate the hash of the
+     * certificate which we were about to send. */
+    if (ss->ssl3.hs.certPredicted && certChain) {
+	PRUint64 digest;
+
+	FNV1A64_Init(&digest);
+	for (i = 0; i < certChain->len; i++) {
+	    unsigned char clen[3];
+
+	    clen[0] = certChain->certs[i].len >> 16;
+	    clen[1] = certChain->certs[i].len >> 8;
+	    clen[2] = certChain->certs[i].len;
+	    FNV1A64_Update(&digest, clen, sizeof(clen));
+	    FNV1A64_Update(&digest, certChain->certs[i].data,
+			 certChain->certs[i].len);
+	}
+	FNV1A64_Final(&digest);
+
+	if (digest == ss->ssl3.hs.predictedCertHash) {
+	    predictionCorrect = PR_TRUE;
+	    len = FNV1A64_LENGTH + 1;
+	}
+    }
+
+    if (certChain && !predictionCorrect) {
 	for (i = 0; i < certChain->len; i++) {
 #ifdef NISCC_TEST
 	    if (fakeCert.len > 0 && i == ndex) {
@@ -7682,6 +7707,12 @@ ssl3_SendCertificate(sslSocket *ss)
     if (rv != SECSuccess) {
 	return rv; 		/* err set by AppendHandshake. */
     }
+    if (predictionCorrect) {
+	rv = ssl3_AppendHandshakeVariable(
+            ss, (const SSL3Opaque*) &ss->ssl3.hs.predictedCertHash,
+            FNV1A64_LENGTH, 1);
+	return rv; 		/* err set by AppendHandshake. */
+    }
     if (certChain) {
         for (i = 0; i < certChain->len; i++) {
 #ifdef NISCC_TEST
@@ -7723,6 +7754,20 @@ ssl3_CleanupPeerCerts(sslSocket *ss)
     ss->ssl3.peerCertChain = NULL;
 }
 
+void
+ssl3_CleanupPredictedCerts(sslSocket *ss) {
+    ssl3CertNode *certs = (ssl3CertNode *)ss->ssl3.peerCertChain;
+    ssl3CertNode *next;
+
+    for (; certs; certs = next) {
+	CERT_DestroyCertificate(certs->cert);
+	next = certs->next;
+	PORT_Free(certs);
+    }
+
+    ss->ssl3.predictedCertChain = NULL;
+}
+
 /* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete
  * ssl3 Certificate message.
  * Caller must hold Handshake and RecvBuf locks.
@@ -7768,65 +7813,72 @@ ssl3_HandleCertificate(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
     ssl3_CleanupPeerCerts(ss);
     isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0);
 
-    /* It is reported that some TLS client sends a Certificate message
-    ** with a zero-length message body.  We'll treat that case like a
-    ** normal no_certificates message to maximize interoperability.
-    */
-    if (length) {
-	remaining = ssl3_ConsumeHandshakeNumber(ss, 3, &b, &length);
-	if (remaining < 0)
-	    goto loser;	/* fatal alert already sent by ConsumeHandshake. */
-	if ((PRUint32)remaining > length)
-	    goto decode_loser;
-    }
-
-    if (!remaining) {
-	if (!(isTLS && isServer))
-	    goto alert_loser;
-    	/* This is TLS's version of a no_certificate alert. */
-    	/* I'm a server. I've requested a client cert. He hasn't got one. */
-	rv = ssl3_HandleNoCertificate(ss);
-	if (rv != SECSuccess) {
-	    errCode = PORT_GetError();
-	    goto loser;
-	}
-	goto cert_block;
-    }
-
     ss->ssl3.peerCertArena = arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
     if ( arena == NULL ) {
 	goto loser;	/* don't send alerts on memory errors */
     }
 
-    /* First get the peer cert. */
-    remaining -= 3;
-    if (remaining < 0)
-	goto decode_loser;
+    /* Cached info handling */
+    if (length == 3 + 1 + FNV1A64_LENGTH &&
+	ss->ssl3.hs.certPredicted &&
+	ssl3_ExtensionNegotiated(ss, ssl_cached_info_xtn) &&
+	ss->ssl3.predictedCertChain != NULL &&
+	b[0] == 0 &&
+	b[1] == 0 &&
+	b[2] == FNV1A64_LENGTH + 1 &&
+	b[3] == FNV1A64_LENGTH &&
+	PORT_Memcmp(&ss->ssl3.hs.predictedCertHash, b + 4, FNV1A64_LENGTH) == 0) {
+	/* We correctly predicted the certificate chain. */
+	ssl3CertNode *node;
 
-    size = ssl3_ConsumeHandshakeNumber(ss, 3, &b, &length);
-    if (size <= 0)
-	goto loser;	/* fatal alert already sent by ConsumeHandshake. */
+	remaining = 0;
+	length -= FNV1A64_LENGTH + 4;
+	b += FNV1A64_LENGTH + 4;
 
-    if (remaining < size)
-	goto decode_loser;
+	node = (ssl3CertNode*) ss->ssl3.predictedCertChain;
+	ss->sec.peerCert = CERT_DupCertificate(node->cert);
 
-    certItem.data = b;
-    certItem.len = size;
-    b      += size;
-    length -= size;
-    remaining -= size;
+	certs = NULL;
 
-    ss->sec.peerCert = CERT_NewTempCertificate(ss->dbHandle, &certItem, NULL,
-                                            PR_FALSE, PR_TRUE);
-    if (ss->sec.peerCert == NULL) {
-	/* We should report an alert if the cert was bad, but not if the
-	 * problem was just some local problem, like memory error.
-	 */
-	goto ambiguous_err;
-    }
+	for (node = node->next; node; node = node->next) {
+	    c = PORT_ArenaNew(arena, ssl3CertNode);
+	    if (c == NULL)
+		goto loser;
+	    c->cert = CERT_DupCertificate(node->cert);
 
-    /* Now get all of the CA certs. */
-    while (remaining > 0) {
+	    if (c->cert->trust)
+		trusted = PR_TRUE;
+
+	    c->next = certs;
+	    certs = c;
+	}
+    } else {
+	/* It is reported that some TLS client sends a Certificate message
+	** with a zero-length message body.  We'll treat that case like a
+	** normal no_certificates message to maximize interoperability.
+	*/
+	if (length) {
+	    remaining = ssl3_ConsumeHandshakeNumber(ss, 3, &b, &length);
+	    if (remaining < 0)
+		goto loser;	/* fatal alert already sent by ConsumeHandshake. */
+	    if ((PRUint32)remaining > length)
+		goto decode_loser;
+	}
+
+	if (!remaining) {
+	    if (!(isTLS && isServer))
+		goto alert_loser;
+	    /* This is TLS's version of a no_certificate alert. */
+	    /* I'm a server. I've requested a client cert. He hasn't got one. */
+	    rv = ssl3_HandleNoCertificate(ss);
+	    if (rv != SECSuccess) {
+		errCode = PORT_GetError();
+		goto loser;
+	    }
+	    goto cert_block;
+	}
+
+	/* First get the peer cert. */
 	remaining -= 3;
 	if (remaining < 0)
 	    goto decode_loser;
@@ -7844,22 +7896,51 @@ ssl3_HandleCertificate(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
 	length -= size;
 	remaining -= size;
 
-	c = PORT_ArenaNew(arena, ssl3CertNode);
-	if (c == NULL) {
-	    goto loser;	/* don't send alerts on memory errors */
-	}
-
-	c->cert = CERT_NewTempCertificate(ss->dbHandle, &certItem, NULL,
-	                                  PR_FALSE, PR_TRUE);
-	if (c->cert == NULL) {
+	ss->sec.peerCert = CERT_NewTempCertificate(ss->dbHandle, &certItem, NULL,
+						PR_FALSE, PR_TRUE);
+	if (ss->sec.peerCert == NULL) {
+	    /* We should report an alert if the cert was bad, but not if the
+	     * problem was just some local problem, like memory error.
+	     */
 	    goto ambiguous_err;
 	}
 
-	if (c->cert->trust)
-	    trusted = PR_TRUE;
+	/* Now get all of the CA certs. */
+	while (remaining > 0) {
+	    remaining -= 3;
+	    if (remaining < 0)
+		goto decode_loser;
+
+	    size = ssl3_ConsumeHandshakeNumber(ss, 3, &b, &length);
+	    if (size <= 0)
+		goto loser;	/* fatal alert already sent by ConsumeHandshake. */
+
+	    if (remaining < size)
+		goto decode_loser;
 
-	c->next = certs;
-	certs = c;
+	    certItem.data = b;
+	    certItem.len = size;
+	    b      += size;
+	    length -= size;
+	    remaining -= size;
+
+	    c = PORT_ArenaNew(arena, ssl3CertNode);
+	    if (c == NULL) {
+		goto loser;	/* don't send alerts on memory errors */
+	    }
+
+	    c->cert = CERT_NewTempCertificate(ss->dbHandle, &certItem, NULL,
+					      PR_FALSE, PR_TRUE);
+	    if (c->cert == NULL) {
+		goto ambiguous_err;
+	    }
+
+	    if (c->cert->trust)
+		trusted = PR_TRUE;
+
+	    c->next = certs;
+	    certs = c;
+	}
     }
 
     if (remaining != 0)
@@ -9122,6 +9203,7 @@ ssl3_InitState(sslSocket *ss)
     ss->ssl3.crSpec = ss->ssl3.cwSpec = &ss->ssl3.specs[0];
     ss->ssl3.prSpec = ss->ssl3.pwSpec = &ss->ssl3.specs[1];
     ss->ssl3.hs.rehandshake = PR_FALSE;
+    ss->ssl3.hs.certPredicted = PR_FALSE;
     ss->ssl3.hs.sendingSCSV = PR_FALSE;
     ssl3_InitCipherSpec(ss, ss->ssl3.crSpec);
     ssl3_InitCipherSpec(ss, ss->ssl3.prSpec);
@@ -9424,6 +9506,9 @@ ssl3_DestroySSL3Info(sslSocket *ss)
     if (ss->ssl3.peerCertArena != NULL)
 	ssl3_CleanupPeerCerts(ss);
 
+    if (ss->ssl3.predictedCertChain != NULL)
+	ssl3_CleanupPredictedCerts(ss);
+
     if (ss->ssl3.clientCertChain != NULL) {
        CERT_DestroyCertificateList(ss->ssl3.clientCertChain);
        ss->ssl3.clientCertChain = NULL;
diff --git a/mozilla/security/nss/lib/ssl/ssl3ext.c b/mozilla/security/nss/lib/ssl/ssl3ext.c
index ac2b067..83d57a0 100644
--- a/mozilla/security/nss/lib/ssl/ssl3ext.c
+++ b/mozilla/security/nss/lib/ssl/ssl3ext.c
@@ -235,6 +235,7 @@ static const ssl3HelloExtensionHandler clientHelloHandlers[] = {
 #endif
     { ssl_session_ticket_xtn,     &ssl3_ServerHandleSessionTicketXtn },
     { ssl_renegotiation_info_xtn, &ssl3_HandleRenegotiationInfoXtn },
+    { ssl_cached_info_xtn,        &ssl3_ServerHandleCachedInfoXtn },
     { -1, NULL }
 };
 
@@ -245,6 +246,7 @@ static const ssl3HelloExtensionHandler serverHelloHandlersTLS[] = {
     /* TODO: add a handler for ssl_ec_point_formats_xtn */
     { ssl_session_ticket_xtn,     &ssl3_ClientHandleSessionTicketXtn },
     { ssl_renegotiation_info_xtn, &ssl3_HandleRenegotiationInfoXtn },
+    { ssl_cached_info_xtn,        &ssl3_ClientHandleCachedInfoXtn },
     { -1, NULL }
 };
 
@@ -267,7 +269,8 @@ ssl3HelloExtensionSender clientHelloSendersTLS[SSL_MAX_EXTENSIONS] = {
     { ssl_elliptic_curves_xtn,    &ssl3_SendSupportedCurvesXtn },
     { ssl_ec_point_formats_xtn,   &ssl3_SendSupportedPointFormatsXtn },
 #endif
-    { ssl_session_ticket_xtn,     &ssl3_SendSessionTicketXtn }
+    { ssl_session_ticket_xtn,     &ssl3_SendSessionTicketXtn },
+    { ssl_cached_info_xtn,        &ssl3_SendCachedInfoXtn }
     /* any extra entries will appear as { 0, NULL }    */
 };
 
@@ -532,6 +535,97 @@ ssl3_SendSessionTicketXtn(
     return -1;
 }
 
+SECStatus
+ssl3_SendCachedInfoXtn(
+			sslSocket * ss,
+			PRBool      append,
+			PRUint32    maxBytes)
+{
+    PRUint32 len;
+
+    /* In order to send this extension, the option must be enabled and a
+     * predicted certificate chain must have been set. */
+    if (!ss || !ss->opt.enableCachedInfo || !ss->ssl3.predictedCertChain)
+	return 0;
+
+    len = 2 /* extension number */ +
+	  2 /* extension length */ +
+	  2 /* cached_info length */ +
+	  1 /* CachedInformationType */ +
+	  1 /* hash value length */ +
+	  FNV1A64_LENGTH;
+
+    if (append && maxBytes >= len) {
+	PRUint64 digest;
+	SECStatus rv;
+	ssl3CertNode *cert;
+
+	FNV1A64_Init(&digest);
+	for (cert = ss->ssl3.predictedCertChain; cert; cert = cert->next) {
+	    unsigned char clen[3];
+
+	    clen[0] = cert->cert->derCert.len >> 16;
+	    clen[1] = cert->cert->derCert.len >> 8;
+	    clen[2] = cert->cert->derCert.len;
+	    FNV1A64_Update(&digest, clen, sizeof(clen));
+	    FNV1A64_Update(&digest, cert->cert->derCert.data,
+			 cert->cert->derCert.len);
+	}
+	FNV1A64_Final(&digest);
+
+	ss->ssl3.hs.certPredicted = PR_TRUE;
+	ss->ssl3.hs.predictedCertHash = digest;
+
+	rv = ssl3_AppendHandshakeNumber(ss, ssl_cached_info_xtn, 2);
+	if (rv != SECSuccess) return -1;
+	rv = ssl3_AppendHandshakeNumber(ss, len - 4, 2);
+	if (rv != SECSuccess) return -1;
+	rv = ssl3_AppendHandshakeNumber(ss, len - 6, 2);
+	if (rv != SECSuccess) return -1;
+	rv = ssl3_AppendHandshakeNumber(ss, ssl_cached_info_certificate_chain, 1);
+	if (rv != SECSuccess) return -1;
+	rv = ssl3_AppendHandshakeNumber(ss, FNV1A64_LENGTH, 1);
+	if (rv != SECSuccess) return -1;
+	rv = ssl3_AppendHandshake(ss, &digest, sizeof(digest));
+	if (rv != SECSuccess) return -1;
+
+	ss->xtnData.advertised[ss->xtnData.numAdvertised++] = ssl_cached_info_xtn;
+    }
+
+    return len;
+}
+
+static PRInt32
+ssl3_ServerSendCachedInfoXtn(
+			sslSocket * ss,
+			PRBool      append,
+			PRUint32    maxBytes)
+{
+    PRUint32 len;
+    SECStatus rv;
+
+    len = 2 /* extension number */ +
+	  2 /* extension length */ +
+	  2 /* cached_info length */ +
+	  1 /* CachedInformationType */ +
+	  1 /* hash value length (0) */;
+
+    if (append && maxBytes >= len) {
+	rv = ssl3_AppendHandshakeNumber(ss, ssl_cached_info_xtn, 2);
+	if (rv != SECSuccess) return -1;
+	rv = ssl3_AppendHandshakeNumber(ss, len - 4, 2);
+	if (rv != SECSuccess) return -1;
+	rv = ssl3_AppendHandshakeNumber(ss, len - 6, 2);
+	if (rv != SECSuccess) return -1;
+	rv = ssl3_AppendHandshakeNumber(ss, ssl_cached_info_certificate_chain, 1);
+	if (rv != SECSuccess) return -1;
+	rv = ssl3_AppendHandshakeNumber(ss, 0, 1);
+	if (rv != SECSuccess) return -1;
+    }
+
+    return len;
+}
+
 /*
  * NewSessionTicket
  * Called from ssl3_HandleFinished
@@ -1287,6 +1381,124 @@ loser:
     return rv;
 }
 
+SECStatus
+ssl3_ClientHandleCachedInfoXtn(sslSocket *ss, PRUint16 ex_type,
+                               SECItem *data)
+{
+    unsigned char *d;
+    unsigned int len;
+
+    d = data->data;
+    len = data->len;
+
+    if (!len) {
+	/* An empty extension is permitted. We assume that the server supports
+	 * certificate caching in this case. */
+	ss->xtnData.serverSupportsCertificateCaching = PR_TRUE;
+    } else {
+	unsigned int coLen;
+
+	if (len < 2)
+	    return SECFailure;
+	coLen = ((unsigned int) d[0]) << 8 |
+		((unsigned int) d[1]);
+	d += 2;
+	len -= 2;
+
+	if (coLen != len)
+	    return SECFailure;
+
+	while (coLen) {
+	    /* for each CachedObject */
+	    SSLCachedInformationType type;
+	    unsigned int hashlen;
+
+	    if (coLen < 2)
+		return SECFailure;
+	    type = (SSLCachedInformationType) d[0];
+	    hashlen = (unsigned int) d[1];
+
+	    d += 2;
+	    coLen -= 2;
+
+	    if (hashlen > coLen ||
+		(hashlen != FNV1A64_LENGTH && hashlen != 0)) {
+		return SECFailure;
+	    }
+
+	    if (type == ssl_cached_info_certificate_chain)
+		ss->xtnData.serverSupportsCertificateCaching = PR_TRUE;
+	    coLen -= hashlen;
+	}
+    }
+
+    ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type;
+    return SECSuccess;
+}
+
+SECStatus
+ssl3_ServerHandleCachedInfoXtn(sslSocket *ss, PRUint16 ex_type,
+                               SECItem *data)
+{
+    unsigned char *d;
+    unsigned int len;
+    unsigned int coLen;
+    SECStatus rv;
+
+    if (!ss->opt.enableCachedInfo)
+	return SECSuccess;
+
+    d = data->data;
+    len = data->len;
+
+    if (len < 2)
+	return SECFailure;
+
+    coLen = ((unsigned int) d[0]) << 8 |
+	    ((unsigned int) d[1]);
+
+    d += 2;
+    len -= 2;
+
+    if (coLen != len)
+	return SECFailure;
+
+    while (coLen) {
+	/* for each CachedObject */
+	SSLCachedInformationType type;
+	unsigned int hashlen;
+
+	if (coLen < 2)
+	    return SECFailure;
+	type = (SSLCachedInformationType) d[0];
+	hashlen = (unsigned int) d[1];
+
+	d += 2;
+	coLen -= 2;
+
+	if (hashlen > coLen ||
+	    hashlen != FNV1A64_LENGTH) {
+	    return SECFailure;
+	}
+
+	if (type == ssl_cached_info_certificate_chain &&
+	    !ss->ssl3.hs.certPredicted) {
+	    /* We're interested in this hash */
+	    ss->ssl3.hs.certPredicted = PR_TRUE;
+	    PORT_Memcpy(&ss->ssl3.hs.predictedCertHash, d, FNV1A64_LENGTH);
+	    ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type;
+	    rv = ssl3_RegisterServerHelloExtensionSender(
+		    ss, ssl_cached_info_xtn, ssl3_ServerSendCachedInfoXtn);
+	    if (rv != SECSuccess)
+		return rv;
+	}
+
+	coLen -= hashlen;
+    }
+
+    return SECSuccess;
+}
+
 /*
  * Read bytes.  Using this function means the SECItem structure
  * cannot be freed.  The caller is expected to call this function
@@ -1517,3 +1729,29 @@ ssl3_HandleRenegotiationInfoXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data)
     return rv;
 }
 
+/* http://www.isthe.com/chongo/tech/comp/fnv/index.html#FNV-param */
+static const PRUint64 FNV1A64_OFFSET_BASIS = 14695981039346656037ull;
+static const PRUint64 FNV1A64_PRIME = 1099511628211ull;
+
+void FNV1A64_Init(PRUint64* digest) {
+  *digest = FNV1A64_OFFSET_BASIS;
+}
+
+void FNV1A64_Update(PRUint64* digest, void* voiddata, unsigned int length) {
+  unsigned char *data = voiddata;
+  unsigned int i;
+
+  for (i = 0; i < length; i++) {
+    *digest ^= data[i];
+    *digest *= FNV1A64_PRIME;
+  }
+}
+
+void FNV1A64_Final(PRUint64 *digest) {
+  const PRUint64 native_endian_result = *digest;
+  unsigned char *out = (unsigned char *) digest;
+  unsigned int i;
+
+  for (i = 0; i < 8; i++)
+    out[i] = (native_endian_result >> (8 * (sizeof(*digest) - i - 1)));
+}
diff --git a/mozilla/security/nss/lib/ssl/sslimpl.h b/mozilla/security/nss/lib/ssl/sslimpl.h
index 7581b98..ce3d86b 100644
--- a/mozilla/security/nss/lib/ssl/sslimpl.h
+++ b/mozilla/security/nss/lib/ssl/sslimpl.h
@@ -333,6 +333,7 @@ typedef struct sslOptionsStr {
     unsigned int enableDeflate          : 1;  /* 19 */
     unsigned int enableRenegotiation    : 2;  /* 20-21 */
     unsigned int requireSafeNegotiation : 1;  /* 22 */
+    unsigned int enableCachedInfo       : 1;  /* 23 */
 } sslOptions;
 
 typedef enum { sslHandshakingUndetermined = 0,
@@ -742,6 +743,9 @@ struct TLSExtensionDataStr {
      * is beyond ssl3_HandleClientHello function. */
     SECItem *sniNameArr;
     PRUint32 sniNameArrSize;
+
+    /* Cached info related data */
+    PRBool serverSupportsCertificateCaching;
 };
 
 /*
@@ -776,6 +780,15 @@ const ssl3CipherSuiteDef *suite_def;
     sslBuffer             msgState;    /* current state for handshake messages*/
                                        /* protected by recvBufLock */
     sslBuffer             messages;    /* Accumulated handshake messages */
+    PRBool                certPredicted;
+                               /* For a server: */
+			       /*   If true, then the peer predicted a */
+			       /* certificate */
+			       /* For a client: */
+			       /*   If true, then we predicted a certificate */
+    uint64_t              predictedCertHash;
+                               /* If cert_predicted is set, then this contains the */
+                               /* FNV1A64 hash of the predicted cert chain. */
     PRUint16              finishedBytes; /* size of single finished below */
     union {
 	TLSFinished       tFinished[2]; /* client, then server */
@@ -813,6 +826,10 @@ struct ssl3StateStr {
     CERTCertificateList *clientCertChain;    /* used by client */
     PRBool               sendEmptyCert;      /* used by client */
 
+    void *               predictedCertChain;
+			    /* for the TLS cached-info extension. Points to an
+			     * ssl3CertNode. */
+
     int                  policy;
 			/* This says what cipher suites we can do, and should 
 			 * be either SSL_ALLOWED or SSL_RESTRICTED 
@@ -1481,6 +1498,7 @@ extern SECStatus ssl3_VerifySignedHashes(SSL3Hashes *hash,
 extern SECStatus ssl3_CacheWrappedMasterSecret(sslSocket *ss,
 			sslSessionID *sid, ssl3CipherSpec *spec,
 			SSL3KEAType effectiveExchKeyType);
+extern void ssl3_CleanupPredictedCerts(sslSocket *ss);
 
 /* Functions that handle ClientHello and ServerHello extensions. */
 extern SECStatus ssl3_HandleServerNameXtn(sslSocket * ss,
@@ -1493,6 +1511,10 @@ extern SECStatus ssl3_ClientHandleSessionTicketXtn(sslSocket *ss,
 			PRUint16 ex_type, SECItem *data);
 extern SECStatus ssl3_ServerHandleSessionTicketXtn(sslSocket *ss,
 			PRUint16 ex_type, SECItem *data);
+extern SECStatus ssl3_ServerHandleCachedInfoXtn(sslSocket *ss,
+			PRUint16 ex_type, SECItem *data);
+extern SECStatus ssl3_ClientHandleCachedInfoXtn(sslSocket *ss, PRUint16 ex_type,
+			SECItem *data);
 
 /* ClientHello and ServerHello extension senders.
  * Note that not all extension senders are exposed here; only those that
@@ -1506,6 +1528,8 @@ extern PRInt32 ssl3_SendSessionTicketXtn(sslSocket *ss, PRBool append,
  */
 extern PRInt32 ssl3_SendServerNameXtn(sslSocket *ss, PRBool append,
                      PRUint32 maxBytes);
+extern SECStatus ssl3_SendCachedInfoXtn(sslSocket * ss, PRBool append,
+                                        PRUint32 maxBytes);
 
 /* Assigns new cert, cert chain and keys to ss->serverCerts
  * struct. If certChain is NULL, tries to find one. Aborts if
@@ -1605,6 +1629,12 @@ SECStatus SSL_DisableDefaultExportCipherSuites(void);
 SECStatus SSL_DisableExportCipherSuites(PRFileDesc * fd);
 PRBool    SSL_IsExportCipherSuite(PRUint16 cipherSuite);
 
+/********************** FNV hash  *********************/
+
+#define FNV1A64_LENGTH 8
+void FNV1A64_Init(PRUint64* digest);
+void FNV1A64_Update(PRUint64* digest, void* data, unsigned length);
+void FNV1A64_Final(PRUint64* digest);
 
 #ifdef TRACE
 #define SSL_TRACE(msg) ssl_Trace msg
diff --git a/mozilla/security/nss/lib/ssl/sslsecur.c b/mozilla/security/nss/lib/ssl/sslsecur.c
index 8f79135..353732b 100644
--- a/mozilla/security/nss/lib/ssl/sslsecur.c
+++ b/mozilla/security/nss/lib/ssl/sslsecur.c
@@ -1267,6 +1267,36 @@ SSL_BadCertHook(PRFileDesc *fd, SSLBadCertHandler f, void *arg)
     return SECSuccess;
 }
 
+SECStatus
+SSL_SetPredictedPeerCertificate(PRFileDesc *fd, CERTCertificate **certs,
+				unsigned int len)
+{
+    sslSocket *ss;
+    unsigned int i;
+
+    ss = ssl_FindSocket(fd);
+    if (!ss) {
+	SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetPredictedPeerCertificate",
+		 SSL_GETPID(), fd));
+	return SECFailure;
+    }
+
+    for (i = 0; i < len; i++) {
+	ssl3CertNode *c = PORT_Alloc(sizeof(ssl3CertNode));
+	if (!c)
+	    goto failed;	/* error code was set */
+	c->cert = CERT_DupCertificate(certs[i]);
+	c->next = (ssl3CertNode *)ss->ssl3.predictedCertChain;
+	ss->ssl3.predictedCertChain = c;
+    }
+
+    return SECSuccess;
+
+failed:
+    ssl3_CleanupPredictedCerts(ss);
+    return SECFailure;
+}
+
 /*
  * Allow the application to pass the url or hostname into the SSL library
  * so that we can do some checking on it. It will be used for the value in
diff --git a/mozilla/security/nss/lib/ssl/sslsock.c b/mozilla/security/nss/lib/ssl/sslsock.c
index f1d1921..627d6af 100644
--- a/mozilla/security/nss/lib/ssl/sslsock.c
+++ b/mozilla/security/nss/lib/ssl/sslsock.c
@@ -728,6 +728,10 @@ SSL_OptionSet(PRFileDesc *fd, PRInt32 which, PRBool on)
 	ss->opt.requireSafeNegotiation = on;
 	break;
 
+      case SSL_ENABLE_CACHED_INFO:
+	ss->opt.enableCachedInfo = on;
+	break;
+
       default:
 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
 	rv = SECFailure;
@@ -791,6 +795,7 @@ SSL_OptionGet(PRFileDesc *fd, PRInt32 which, PRBool *pOn)
                                   on = ss->opt.enableRenegotiation; break;
     case SSL_REQUIRE_SAFE_NEGOTIATION: 
                                   on = ss->opt.requireSafeNegotiation; break;
+    case SSL_ENABLE_CACHED_INFO:  on = ss->opt.enableCachedInfo;   break;
 
     default:
 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
@@ -841,6 +846,7 @@ SSL_OptionGetDefault(PRInt32 which, PRBool *pOn)
     case SSL_REQUIRE_SAFE_NEGOTIATION: 
                                   on = ssl_defaults.requireSafeNegotiation; 
 				  break;
+    case SSL_ENABLE_CACHED_INFO:  on = ssl_defaults.enableCachedInfo;   break;
 
     default:
 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
@@ -984,6 +990,10 @@ SSL_OptionSetDefault(PRInt32 which, PRBool on)
 	ssl_defaults.requireSafeNegotiation = on;
 	break;
 
+      case SSL_ENABLE_CACHED_INFO:
+	ssl_defaults.enableCachedInfo = on;
+	break;
+
       default:
 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
 	return SECFailure;
diff --git a/mozilla/security/nss/lib/ssl/sslt.h b/mozilla/security/nss/lib/ssl/sslt.h
index c7d4553..7b092f7 100644
--- a/mozilla/security/nss/lib/ssl/sslt.h
+++ b/mozilla/security/nss/lib/ssl/sslt.h
@@ -203,9 +203,14 @@ typedef enum {
     ssl_ec_point_formats_xtn         = 11,
 #endif
     ssl_session_ticket_xtn           = 35,
+    ssl_cached_info_xtn              = 13173,	/* not an IANA allocation */
     ssl_renegotiation_info_xtn       = 0xff01	/* experimental number */
 } SSLExtensionType;
 
-#define SSL_MAX_EXTENSIONS             5
+typedef enum {
+  ssl_cached_info_certificate_chain = 1,
+} SSLCachedInformationType;
+
+#define SSL_MAX_EXTENSIONS             6
 
 #endif /* __sslt_h_ */
