diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c
index ab32505..80ab5c0 100644
--- a/ssl/s3_srvr.c
+++ b/ssl/s3_srvr.c
@@ -126,6 +126,7 @@
 #define NETSCAPE_HANG_BUG
 
 #include <stdio.h>
+#include <stdint.h>
 #include "ssl_locl.h"
 #include "kssl_lcl.h"
 #include <openssl/buffer.h>
@@ -148,6 +149,39 @@ static SSL_METHOD *ssl3_get_server_method(int ver);
 static int nid2curve_id(int nid);
 #endif
 
+typedef uint64_t FNV1A64;
+
+/* http://www.isthe.com/chongo/tech/comp/fnv/index.html#FNV-param */
+static const FNV1A64 FNV1A64_OFFSET_BASIS = 14695981039346656037ull;
+static const FNV1A64 FNV1A64_PRIME = 1099511628211ull;
+
+static void fnv1a64_init(FNV1A64* digest)
+	{
+	*digest = FNV1A64_OFFSET_BASIS;
+	}
+
+static void fnv1a64_update(FNV1A64* 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;
+		}
+	}
+
+static void fnv1a64_final(FNV1A64 *digest)
+	{
+	const FNV1A64 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(FNV1A64) - i - 1)));
+	}
+
 static SSL_METHOD *ssl3_get_server_method(int ver)
 	{
 	if (ver == SSL3_VERSION)
@@ -2973,6 +3007,36 @@ int ssl3_send_server_certificate(SSL *s)
 			}
 
 		l=ssl3_output_cert_chain(s,x);
+
+		if (s->cert_predicted && l >= 8 + sizeof(FNV1A64))
+			{
+			static const unsigned int prelude_len =
+				1 /* handshake type */ +
+				3 /* handshake length */ +
+				3 /* certificate list length */;
+			FNV1A64 digest;
+
+			fnv1a64_init(&digest);
+			fnv1a64_update(&digest, s->init_buf->data + prelude_len, l - prelude_len);
+			fnv1a64_final(&digest);
+
+			if (memcmp(&digest, s->predicted_cert_hash, sizeof(digest)) == 0)
+				{
+				/* The client correctly predicted the certificate chain. */
+				s->init_buf->data[1] = 0;
+				s->init_buf->data[2] = 0;
+				s->init_buf->data[3] = 3 /* certificate chain length */ +
+					               1 /* hash length */ +
+						       sizeof(digest);
+				s->init_buf->data[4] = 0;
+				s->init_buf->data[5] = 0;
+				s->init_buf->data[6] = 1 /* hash length */ + sizeof(digest);
+				s->init_buf->data[7] = sizeof(digest);
+				memcpy(s->init_buf->data + 8, &digest, sizeof(digest));
+				l = 8 + sizeof(digest);
+				}
+			}
+
 		s->state=SSL3_ST_SW_CERT_B;
 		s->init_num=(int)l;
 		s->init_off=0;
diff --git a/ssl/ssl.h b/ssl/ssl.h
index 20fbd98..5f06187 100644
--- a/ssl/ssl.h
+++ b/ssl/ssl.h
@@ -1098,6 +1098,10 @@ struct ssl_st
 	 * before the Finished message. */
 	unsigned char *next_proto_negotiated;
 	unsigned char next_proto_negotiated_len;
+
+	/* Cached info support */
+	char cert_predicted; /* non-zero if the client predicted a cert */
+	unsigned char predicted_cert_hash[8];
 #define session_ctx initial_ctx
 #else
 #define session_ctx ctx
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index fd35b18..11d22d2 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -368,6 +368,16 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha
 			}
 		}
 
+	if (s->cert_predicted)
+		{
+		if ((long)(limit - ret - 8) < 0) return NULL;
+		s2n(TLSEXT_TYPE_cached_info,ret);
+		s2n(4,ret); /* extension length */
+		s2n(2,ret); /* CachedObjects length */
+		*ret++ = TLS_CACHED_INFO_CERTIFICATE_CHAIN;
+		*ret++ = 0; /* hash length */;
+		}
+
 	if ((extdatalen = ret-p-2)== 0) 
 		return p;
 
@@ -375,6 +385,58 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha
 	return ret;
 	}
 
+/* ssl_parse_serverhello_tlsext parses a TLS cached info extension. data and
+ * len describe the contents of the extension that the peer sent to us. Returns
+ * non-zero on success. */
+static char ssl_parse_cached_info_tlsext(SSL *s, unsigned char **d, unsigned short *len)
+	{
+	/* for each CachedObject */
+	unsigned int co_len;
+
+	if (*len < 2)
+		return 0;
+
+	co_len = ((unsigned int) (*d)[0]) << 8 |
+		                 (*d)[1];
+
+	*d += 2;
+	*len -= 2;
+
+	if (co_len != *len)
+		return 0;
+
+	while (co_len)
+		{
+		/* for each CachedObject */
+		unsigned char type;
+		unsigned char hashlen;
+
+		if (co_len < 2)
+			return 0;
+		type = **d;
+		(*d)++;
+		hashlen = **d;
+		(*d)++;
+		co_len -= 2;
+
+		if (hashlen > co_len ||
+		    hashlen != sizeof(s->predicted_cert_hash))
+			return 0;
+
+		if (type == TLS_CACHED_INFO_CERTIFICATE_CHAIN &&
+		    !s->cert_predicted)
+			{
+			s->cert_predicted = 1;
+			memcpy(s->predicted_cert_hash, *d,
+			       sizeof(s->predicted_cert_hash));
+			*d += sizeof(s->predicted_cert_hash);
+			co_len -= sizeof(s->predicted_cert_hash);
+			}
+		}
+
+	return 1;
+	}
+
 int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, int n, int *al)
 	{
 	unsigned short type;
@@ -627,6 +689,12 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
 			s->s3->next_proto_neg_seen = 1;
 			}
 
+		else if (type == TLSEXT_TYPE_cached_info)
+			{
+				if (ssl_parse_cached_info_tlsext(s, &data, &size) == 0)
+					return 0;
+			}
+
 		/* session ticket processed earlier */
 
 		data+=size;		
diff --git a/ssl/tls1.h b/ssl/tls1.h
index 71d76de..47c28af 100644
--- a/ssl/tls1.h
+++ b/ssl/tls1.h
@@ -104,6 +104,9 @@ extern "C" {
 #define TLS1_AD_BAD_CERTIFICATE_HASH_VALUE 114
 #define TLS1_AD_UNKNOWN_PSK_IDENTITY	115	/* fatal */
 
+/* CachedInformationType from RFC XXXX */
+#define TLS_CACHED_INFO_CERTIFICATE_CHAIN	1
+
 /* ExtensionType values from RFC 3546 */
 #define TLSEXT_TYPE_server_name			0
 #define TLSEXT_TYPE_max_fragment_length		1
@@ -114,6 +117,7 @@ extern "C" {
 #define TLSEXT_TYPE_elliptic_curves		10
 #define TLSEXT_TYPE_ec_point_formats		11
 #define TLSEXT_TYPE_session_ticket		35
+#define TLSEXT_TYPE_cached_info			13173
 
 /* Temporary extension type */
 #define TLSEXT_TYPE_renegotiate                 0xff01
