diff -pu a/nss/lib/ssl/ssl3con.c b/nss/lib/ssl/ssl3con.c --- a/nss/lib/ssl/ssl3con.c 2014-01-17 17:49:26.062517203 -0800 +++ b/nss/lib/ssl/ssl3con.c 2014-01-17 17:51:23.974478249 -0800 @@ -43,6 +43,7 @@ static SECStatus ssl3_AuthCertificate(sslSocket *ss); static void ssl3_CleanupPeerCerts(sslSocket *ss); +static void ssl3_CopyPeerCertsFromSID(sslSocket *ss, sslSessionID *sid); static PK11SymKey *ssl3_GenerateRSAPMS(sslSocket *ss, ssl3CipherSpec *spec, PK11SlotInfo * serverKeySlot); static SECStatus ssl3_DeriveMasterSecret(sslSocket *ss, PK11SymKey *pms); @@ -6474,6 +6475,7 @@ ssl3_HandleServerHello(sslSocket *ss, SS /* copy the peer cert from the SID */ if (sid->peerCert != NULL) { ss->sec.peerCert = CERT_DupCertificate(sid->peerCert); + ssl3_CopyPeerCertsFromSID(ss, sid); } /* NULL value for PMS signifies re-use of the old MS */ @@ -8048,6 +8050,7 @@ compression_found: ss->sec.ci.sid = sid; if (sid->peerCert != NULL) { ss->sec.peerCert = CERT_DupCertificate(sid->peerCert); + ssl3_CopyPeerCertsFromSID(ss, sid); } /* @@ -9662,6 +9665,44 @@ ssl3_CleanupPeerCerts(sslSocket *ss) ss->ssl3.peerCertChain = NULL; } +static void +ssl3_CopyPeerCertsFromSID(sslSocket *ss, sslSessionID *sid) +{ + PLArenaPool *arena; + ssl3CertNode *lastCert = NULL; + ssl3CertNode *certs = NULL; + int i; + + if (!sid->peerCertChain[0]) + return; + PORT_Assert(!ss->ssl3.peerCertArena); + PORT_Assert(!ss->ssl3.peerCertChain); + ss->ssl3.peerCertArena = arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + for (i = 0; i < MAX_PEER_CERT_CHAIN_SIZE && sid->peerCertChain[i]; i++) { + ssl3CertNode *c = PORT_ArenaNew(arena, ssl3CertNode); + c->cert = CERT_DupCertificate(sid->peerCertChain[i]); + c->next = NULL; + if (lastCert) { + lastCert->next = c; + } else { + certs = c; + } + lastCert = c; + } + ss->ssl3.peerCertChain = certs; +} + +static void +ssl3_CopyPeerCertsToSID(ssl3CertNode *certs, sslSessionID *sid) +{ + int i = 0; + ssl3CertNode *c = certs; + for (; i < MAX_PEER_CERT_CHAIN_SIZE && c; i++, c = c->next) { + PORT_Assert(!sid->peerCertChain[i]); + sid->peerCertChain[i] = CERT_DupCertificate(c->cert); + } +} + /* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete * ssl3 CertificateStatus message. * Caller must hold Handshake and RecvBuf locks. @@ -9940,6 +9981,7 @@ ssl3_AuthCertificate(sslSocket *ss) } ss->sec.ci.sid->peerCert = CERT_DupCertificate(ss->sec.peerCert); + ssl3_CopyPeerCertsToSID(ss->ssl3.peerCertChain, ss->sec.ci.sid); if (!ss->sec.isServer) { CERTCertificate *cert = ss->sec.peerCert; diff -pu a/nss/lib/ssl/sslimpl.h b/nss/lib/ssl/sslimpl.h --- a/nss/lib/ssl/sslimpl.h 2014-01-17 17:49:26.072517368 -0800 +++ b/nss/lib/ssl/sslimpl.h 2014-01-17 17:51:23.984478418 -0800 @@ -595,6 +595,8 @@ typedef enum { never_cached, invalid_cache /* no longer in any cache. */ } Cached; +#define MAX_PEER_CERT_CHAIN_SIZE 8 + struct sslSessionIDStr { /* The global cache lock must be held when accessing these members when the * sid is in any cache. @@ -609,6 +611,7 @@ struct sslSessionIDStr { */ CERTCertificate * peerCert; + CERTCertificate * peerCertChain[MAX_PEER_CERT_CHAIN_SIZE]; SECItemArray peerCertStatus; /* client only */ const char * peerID; /* client only */ const char * urlSvrName; /* client only */ diff -pu a/nss/lib/ssl/sslnonce.c b/nss/lib/ssl/sslnonce.c --- a/nss/lib/ssl/sslnonce.c 2014-01-17 17:49:26.072517368 -0800 +++ b/nss/lib/ssl/sslnonce.c 2014-01-17 17:51:23.984478418 -0800 @@ -164,6 +164,7 @@ lock_cache(void) static void ssl_DestroySID(sslSessionID *sid) { + int i; SSL_TRC(8, ("SSL: destroy sid: sid=0x%x cached=%d", sid, sid->cached)); PORT_Assert(sid->references == 0); PORT_Assert(sid->cached != in_client_cache); @@ -194,6 +195,9 @@ ssl_DestroySID(sslSessionID *sid) if ( sid->peerCert ) { CERT_DestroyCertificate(sid->peerCert); } + for (i = 0; i < MAX_PEER_CERT_CHAIN_SIZE && sid->peerCertChain[i]; i++) { + CERT_DestroyCertificate(sid->peerCertChain[i]); + } if (sid->peerCertStatus.items) { SECITEM_FreeArray(&sid->peerCertStatus, PR_FALSE); }