Bug 858231: Update NSS to NSS 3.15 Beta 5. r=wtc.
authorWan-Teh Chang <wtc@google.com>
Mon, 20 May 2013 15:28:12 -0700
changeset 132439 cc8bbdd0533cce7c2c78ea4135cbc3b4a4402758
parent 132438 1d14e9de6418784fb5f9366c8f9bfc9361b6777b
child 132440 cd4d5caefa882d0f108cbfff930ec9b10252a802
push id28277
push userwtc@google.com
push dateMon, 20 May 2013 22:28:22 +0000
treeherdermozilla-inbound@cc8bbdd0533c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerswtc
bugs858231, 869262, 863947, 866362, 863871, 808217
milestone24.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 858231: Update NSS to NSS 3.15 Beta 5. r=wtc. Inclues fixes for bug 869262, bug 863947, bug 866362, bug 863871, and bug 808217.
security/nss/TAG-INFO
security/nss/cmd/bltest/blapitest.c
security/nss/cmd/lib/secutil.c
security/nss/cmd/selfserv/selfserv.c
security/nss/coreconf/coreconf.dep
security/nss/lib/certdb/alg1485.c
security/nss/lib/ckfw/builtins/certdata.perl
security/nss/lib/ckfw/builtins/certdata.txt
security/nss/lib/ckfw/ck.api
security/nss/lib/ckfw/ckapi.perl
security/nss/lib/libpkix/include/pkix_pl_pki.h
security/nss/lib/libpkix/pkix/top/pkix_build.c
security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_cert.c
security/nss/lib/ssl/ssl.h
security/nss/lib/ssl/ssl3con.c
security/nss/lib/ssl/ssl3ext.c
security/nss/lib/ssl/sslimpl.h
security/nss/lib/ssl/sslsock.c
security/nss/lib/util/nssutil.def
security/nss/lib/util/secitem.c
security/nss/lib/util/secitem.h
--- a/security/nss/TAG-INFO
+++ b/security/nss/TAG-INFO
@@ -1,1 +1,1 @@
-NSS_3_15_BETA4
+NSS_3_15_BETA5
--- a/security/nss/cmd/bltest/blapitest.c
+++ b/security/nss/cmd/bltest/blapitest.c
@@ -1028,18 +1028,17 @@ bltestCopyIO(PLArenaPool *arena, bltestI
 }
 
 void
 misalignBuffer(PLArenaPool *arena, bltestIO *io, int off)
 {
     ptrdiff_t offset = (ptrdiff_t)io->buf.data % WORDSIZE;
     int length = io->buf.len;
     if (offset != off) {
-	SECITEM_ReallocItem(arena, &io->buf, length, length + 2*WORDSIZE);
-	io->buf.len = length + 2*WORDSIZE; /* why doesn't realloc do this? */
+	SECITEM_ReallocItemV2(arena, &io->buf, length + 2*WORDSIZE);
 	/* offset may have changed? */
 	offset = (ptrdiff_t)io->buf.data % WORDSIZE;
 	if (offset != off) {
 	    memmove(io->buf.data + off, io->buf.data, length);
 	    io->pBuf.data = io->buf.data + off;
 	    io->pBuf.len = length;
 	} else {
 	    io->pBuf.data = io->buf.data;
--- a/security/nss/cmd/lib/secutil.c
+++ b/security/nss/cmd/lib/secutil.c
@@ -525,17 +525,17 @@ SECU_ReadDERFromFile(SECItem *der, PRFil
 		*trailer = '\0';
 	    if (!body || !trailer) {
 		fprintf(stderr, "input has header but no trailer\n");
 		PORT_Free(filedata.data);
 		return SECFailure;
 	    }
 	} else {
 	    /* need one additional byte for zero terminator */
-	    rv = SECITEM_ReallocItem(NULL, &filedata, filedata.len, filedata.len+1);
+	    rv = SECITEM_ReallocItemV2(NULL, &filedata, filedata.len+1);
 	    if (rv != SECSuccess) {
 		PORT_Free(filedata.data);
 		return rv;
 	    }
 	    body = (char*)filedata.data;
 	    body[filedata.len-1] = '\0';
 	}
      
--- a/security/nss/cmd/selfserv/selfserv.c
+++ b/security/nss/cmd/selfserv/selfserv.c
@@ -87,17 +87,17 @@ static enum ocspStaplingModeEnum {
     osm_badsig,    /* supply a good status response with a bad signature */
     osm_corrupted, /* supply a corrupted data block as the status */
     osm_random,    /* use a random response for each connection */
     osm_ocsp       /* retrieve ocsp status from external ocsp server,
 		      use empty status if server is unavailable */
 } ocspStaplingMode = osm_disabled;
 typedef enum ocspStaplingModeEnum ocspStaplingModeType;
 static char *ocspStaplingCA = NULL;
-CERTCertificate * certForStatusWeakReference = NULL;
+static SECItemArray *certStatus[kt_kea_size] = { NULL };
 
 const int ssl2CipherSuites[] = {
     SSL_EN_RC4_128_WITH_MD5,			/* A */
     SSL_EN_RC4_128_EXPORT40_WITH_MD5,		/* B */
     SSL_EN_RC2_128_CBC_WITH_MD5,		/* C */
     SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5,	/* D */
     SSL_EN_DES_64_CBC_WITH_MD5,			/* E */
     SSL_EN_DES_192_EDE3_CBC_WITH_MD5,		/* F */
@@ -1103,29 +1103,28 @@ makeCorruptedOCSPResponse(PLArenaPool *a
     result->items[0].data = ocspResponse->data;
     result->items[0].len = ocspResponse->len;
 
     return result;
 }
 
 SECItemArray *
 makeSignedOCSPResponse(PLArenaPool *arena, ocspStaplingModeType osm,
-		       PRFileDesc *model_sock, CERTCertificate *cert)
+		       CERTCertificate *cert, secuPWData *pwdata)
 {
     SECItemArray *result = NULL;
     SECItem *ocspResponse = NULL;
     CERTOCSPSingleResponse **singleResponses;
     CERTOCSPSingleResponse *sr;
     CERTOCSPCertID *cid = NULL;
     CERTCertificate *ca;
     PRTime now = PR_Now();
     PRTime nextUpdate;
-    secuPWData *pwdata;
 
-    PORT_Assert(model_sock != NULL && cert != NULL);
+    PORT_Assert(cert != NULL);
 
     ca = CERT_FindCertByNickname(CERT_GetDefaultCertDB(), ocspStaplingCA);
     if (!ca)
 	errExit("cannot find CA");
 
     cid = CERT_CreateOCSPCertID(cert, now);
     if (!cid)
 	errExit("cannot created cid");
@@ -1159,18 +1158,16 @@ makeSignedOCSPResponse(PLArenaPool *aren
     /* meaning of value 2: one entry + one end marker */
     singleResponses = PORT_ArenaNewArray(arena, CERTOCSPSingleResponse*, 2);
     if (singleResponses == NULL)
 	errExit("cannot allocate singleResponses");
 
     singleResponses[0] = sr;
     singleResponses[1] = NULL;
 
-    pwdata = SSL_RevealPinArg(model_sock);
-
     ocspResponse = CERT_CreateEncodedOCSPSuccessResponse(arena,
 			(osm == osm_badsig) ? NULL : ca,
 			ocspResponderID_byName, now, singleResponses,
 			&pwdata);
     if (!ocspResponse)
 	errExit("cannot created ocspResponse");
 
     CERT_DestroyCertificate(ca);
@@ -1184,16 +1181,63 @@ makeSignedOCSPResponse(PLArenaPool *aren
     result->items[0].len = ocspResponse->len;
 
     CERT_DestroyOCSPCertID(cid);
     cid = NULL;
 
     return result;
 }
 
+void
+setupCertStatus(PLArenaPool *arena, enum ocspStaplingModeEnum ocspStaplingMode,
+		CERTCertificate *cert, SSLKEAType kea, secuPWData *pwdata)
+{
+    if (ocspStaplingMode == osm_random) {
+	/* 6 different responses */
+	int r = rand() % 6;
+	switch (r) {
+	    case 0: ocspStaplingMode = osm_good; break;
+	    case 1: ocspStaplingMode = osm_revoked; break;
+	    case 2: ocspStaplingMode = osm_unknown; break;
+	    case 3: ocspStaplingMode = osm_badsig; break;
+	    case 4: ocspStaplingMode = osm_corrupted; break;
+	    case 5: ocspStaplingMode = osm_failure; break;
+	    default: PORT_Assert(0); break;
+	}
+    }
+    if (ocspStaplingMode != osm_disabled) {
+	SECItemArray *multiOcspResponses = NULL;
+	switch (ocspStaplingMode) {
+	    case osm_good:
+	    case osm_revoked:
+	    case osm_unknown:
+	    case osm_badsig:
+		multiOcspResponses =
+		    makeSignedOCSPResponse(arena, ocspStaplingMode, cert,
+					   pwdata);
+		break;
+	    case osm_corrupted:
+		multiOcspResponses = makeCorruptedOCSPResponse(arena);
+		break;
+	    case osm_failure:
+		multiOcspResponses = makeTryLaterOCSPResponse(arena);
+		break;
+	    case osm_ocsp:
+		errExit("stapling mode \"ocsp\" not implemented");
+		break;
+		break;
+	    default:
+		break;
+	}
+	if (multiOcspResponses) {
+	   certStatus[kea] = multiOcspResponses;
+	}
+   }
+}
+
 int
 handle_connection( 
     PRFileDesc *tcp_sock,
     PRFileDesc *model_sock,
     int         requestCert
     )
 {
     PRFileDesc *       ssl_sock = NULL;
@@ -1211,18 +1255,17 @@ handle_connection(
     int                numIOVs;
     PRSocketOptionData opt;
     PRIOVec            iovs[16];
     char               msgBuf[160];
     char               buf[10240];
     char               fileName[513];
     char               proto[128];
     PRDescIdentity     aboveLayer = PR_INVALID_IO_LAYER;
-    PLArenaPool *arena = NULL;
-    ocspStaplingModeType osm;
+    SSLKEAType  kea;
 
     pBuf   = buf;
     bufRem = sizeof buf;
 
     VLOG(("selfserv: handle_connection: starting"));
     opt.option             = PR_SockOpt_Nonblocking;
     opt.value.non_blocking = PR_FALSE;
     PR_SetSocketOption(tcp_sock, &opt);
@@ -1239,67 +1282,21 @@ handle_connection(
 	if (rv != SECSuccess) {
 	    errWarn("SSL_ResetHandshake");
 	    goto cleanup;
 	}
     } else {
 	ssl_sock = tcp_sock;
     }
 
-    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
-    if (!arena)
-	errExit("cannot allocate arena");
-
-    osm = ocspStaplingMode;
-    if (osm == osm_random) {
-	/* 6 different responses */
-	int r = rand() % 6;
-	switch (r) {
-	    case 0: osm = osm_good; break;
-	    case 1: osm = osm_revoked; break;
-	    case 2: osm = osm_unknown; break;
-	    case 3: osm = osm_badsig; break;
-	    case 4: osm = osm_corrupted; break;
-	    case 5: osm = osm_failure; break;
-	    default: PORT_Assert(0); break;
-	}
+    for (kea = kt_rsa; kea < kt_kea_size; kea++) {
+       if (certStatus[kea] != NULL) {
+           SSL_SetStapledOCSPResponses(ssl_sock, certStatus[kea], kea);
+       }
     }
-    if (osm != osm_disabled) {
-	SECItemArray *multiOcspResponses = NULL;
-	switch (osm) {
-	    case osm_good:
-	    case osm_revoked:
-	    case osm_unknown:
-	    case osm_badsig:
-		multiOcspResponses =
-		    makeSignedOCSPResponse(arena, osm, ssl_sock,
-					   certForStatusWeakReference);
-		break;
-	    case osm_corrupted:
-		multiOcspResponses = makeCorruptedOCSPResponse(arena);
-		break;
-	    case osm_failure:
-		multiOcspResponses = makeTryLaterOCSPResponse(arena);
-		break;
-	    case osm_ocsp:
-		errExit("stapling mode \"ocsp\" not implemented");
-		break;
-		break;
-	    default:
-		break;
-	}
-
-	if (multiOcspResponses) {
-	    SSL_SetStapledOCSPResponses(ssl_sock, multiOcspResponses,
-					PR_FALSE /* no ownership transfer */);
-	}
-    }
-
-    PORT_FreeArena(arena, PR_FALSE);
-    arena = NULL;
 
     if (loggingLayer) {
         /* find the layer where our new layer is to be pushed */
         aboveLayer = PR_GetLayersIdentity(ssl_sock->lower);
         if (aboveLayer == PR_INVALID_IO_LAYER) {
             errExit("PRGetUniqueIdentity");
         }
         /* create the new layer - this is a very cheap operation */
@@ -1905,19 +1902,16 @@ server_main(
                                      (void*)&virtServerNameArray);
         if (rv != SECSuccess) {
             errExit("error enabling SNI extension ");
         }
     }
 
     for (kea = kt_rsa; kea < kt_kea_size; kea++) {
 	if (cert[kea] != NULL) {
-	    if (!certForStatusWeakReference)
-		certForStatusWeakReference = cert[kea];
-
 	    secStatus = SSL_ConfigSecureServer(model_sock, 
 	    		cert[kea], privKey[kea], kea);
 	    if (secStatus != SECSuccess)
 		errExit("SSL_ConfigSecureServer");
 	}
     }
 
     if (bigBuf.data) { /* doing FDX */
@@ -2167,16 +2161,17 @@ main(int argc, char **argv)
     PRBool               debugCache = PR_FALSE; /* bug 90518 */
     char                 emptyString[] = { "" };
     char*                certPrefix = emptyString;
     PRUint32             protos = 0;
     SSL3Statistics      *ssl3stats;
     PRUint32             i;
     secuPWData  pwdata = { PW_NONE, 0 };
     char                *expectedHostNameVal = NULL;
+    PLArenaPool         *certStatusArena = NULL;
 
     tmp = strrchr(argv[0], '/');
     tmp = tmp ? tmp + 1 : argv[0];
     progName = strrchr(tmp, '\\');
     progName = progName ? progName + 1 : tmp;
 
     PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
     SSL_VersionRangeGetSupported(ssl_variant_stream, &enabledVersions);
@@ -2564,16 +2559,20 @@ main(int argc, char **argv)
         }
         /* TLS 1.1 has the same SSL Bypass mode requirements as TLS 1.0 */
         if (enabledVersions.min <= SSL_LIBRARY_VERSION_TLS_1_1 &&
             enabledVersions.max >= SSL_LIBRARY_VERSION_TLS_1_1) {
             protos |= SSL_CBP_TLS1_0;
         }
     }
 
+    certStatusArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+    if (!certStatusArena)
+	errExit("cannot allocate certStatusArena");
+
     if (nickName) {
 	cert[kt_rsa] = PK11_FindCertFromNickname(nickName, &pwdata);
 	if (cert[kt_rsa] == NULL) {
 	    fprintf(stderr, "selfserv: Can't find certificate %s\n", nickName);
 	    exit(10);
 	}
 	privKey[kt_rsa] = PK11_FindKeyByAnyCert(cert[kt_rsa], &pwdata);
 	if (privKey[kt_rsa] == NULL) {
@@ -2586,16 +2585,18 @@ main(int argc, char **argv)
 	    if (SSL_CanBypass(cert[kt_rsa], privKey[kt_rsa], protos, cipherlist, 
 	                      nciphers, &bypassOK, &pwdata) != SECSuccess) {
 		SECU_PrintError(progName, "Bypass test failed %s\n", nickName);
 		exit(14);
 	    }
 	    fprintf(stderr, "selfserv: %s can%s bypass\n", nickName,
 		    bypassOK ? "" : "not");
 	}
+	setupCertStatus(certStatusArena, ocspStaplingMode, cert[kt_rsa], kt_rsa,
+			&pwdata);
     }
 #ifdef NSS_ENABLE_ECC
     if (ecNickName) {
 	cert[kt_ecdh] = PK11_FindCertFromNickname(ecNickName, &pwdata);
 	if (cert[kt_ecdh] == NULL) {
 	    fprintf(stderr, "selfserv: Can't find certificate %s\n",
 		    ecNickName);
 	    exit(13);
@@ -2610,17 +2611,19 @@ main(int argc, char **argv)
 	    PRBool bypassOK;
 	    if (SSL_CanBypass(cert[kt_ecdh], privKey[kt_ecdh], protos, cipherlist,
 			      nciphers, &bypassOK, &pwdata) != SECSuccess) {
 		SECU_PrintError(progName, "Bypass test failed %s\n", ecNickName);
 		exit(15);
 	    }
 	    fprintf(stderr, "selfserv: %s can%s bypass\n", ecNickName,
 		    bypassOK ? "" : "not");
-       }
+	}
+	setupCertStatus(certStatusArena, ocspStaplingMode, cert[kt_ecdh], kt_ecdh,
+			&pwdata);
     }
 #endif /* NSS_ENABLE_ECC */
 
     if (testbypass)
 	goto cleanup;
 
 /* allocate the array of thread slots, and launch the worker threads. */
     rv = launch_threads(&jobLoop, 0, 0, requestCert, useLocalThreads);
@@ -2692,21 +2695,23 @@ cleanup:
     if (ecNickName) {
         PORT_Free(ecNickName);
     }
  #endif
 
     if (hasSidCache) {
 	SSL_ShutdownServerSessionIDCache();
     }
+    if (certStatusArena) {
+	PORT_FreeArena(certStatusArena, PR_FALSE);
+    }
     if (NSS_Shutdown() != SECSuccess) {
 	SECU_PrintError(progName, "NSS_Shutdown");
         if (loggerThread) {
             PR_JoinThread(loggerThread);
         }
 	PR_Cleanup();
 	exit(1);
     }
     PR_Cleanup();
     printf("selfserv: normal termination\n");
     return 0;
 }
-
--- a/security/nss/coreconf/coreconf.dep
+++ b/security/nss/coreconf/coreconf.dep
@@ -5,9 +5,8 @@
 
 /*
  * A dummy header file that is a dependency for all the object files.
  * Used to force a full recompilation of NSS in Mozilla's Tinderbox
  * depend builds.  See comments in rules.mk.
  */
 
 #error "Do not include this header file."
-
--- a/security/nss/lib/certdb/alg1485.c
+++ b/security/nss/lib/certdb/alg1485.c
@@ -1031,18 +1031,20 @@ AppendAVA(stringBuf *bufp, CERTAVA *ava,
 	}
 	rv = SECSuccess;
     } else if (!truncateValue) {
 	rv = escapeAndQuote(encodedAVA + nameLen, len - nameLen, 
 			    (char *)avaValue->data, avaValue->len, &mode);
     } else {
 	/* must truncate the escaped and quoted value */
 	char bigTmpBuf[TMPBUF_LEN * 3 + 3];
+	PORT_Assert(valueLen < sizeof tmpBuf);
 	rv = escapeAndQuote(bigTmpBuf, sizeof bigTmpBuf,
-			    (char *)avaValue->data, valueLen, &mode);
+			    (char *)avaValue->data,
+			    PR_MIN(avaValue->len, valueLen), &mode);
 
 	bigTmpBuf[valueLen--] = '\0'; /* hard stop here */
 	/* See if we're in the middle of a multi-byte UTF8 character */
 	while (((bigTmpBuf[valueLen] & 0xc0) == 0x80) && valueLen > 0) {
 	    bigTmpBuf[valueLen--] = '\0';
 	}
 	/* add ellipsis to signify truncation. */
 	bigTmpBuf[++valueLen] = '.';
--- a/security/nss/lib/ckfw/builtins/certdata.perl
+++ b/security/nss/lib/ckfw/builtins/certdata.perl
@@ -1,49 +1,32 @@
 #!perl -w
 # 
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
-my $cvs_id = '@(#) $RCSfile$ $Revision$ $Date$';
 use strict;
 
 my %constants;
 my $count = 0;
 my $o;
 my @objects = ();
 my @objsize;
-my $cvsid;
 
 $constants{CKO_DATA} = "static const CK_OBJECT_CLASS cko_data = CKO_DATA;\n";
 $constants{CK_TRUE} = "static const CK_BBOOL ck_true = CK_TRUE;\n";
 $constants{CK_FALSE} = "static const CK_BBOOL ck_false = CK_FALSE;\n";
 
 while(<>) {
   my @fields = ();
   my $size;
 
   s/^((?:[^"#]+|"[^"]*")*)(\s*#.*$)/$1/;
   next if (/^\s*$/);
 
-  if( /(^CVS_ID\s+)(.*)/ ) {
-    $cvsid = $2 . "\"; $cvs_id\"";
-    my $scratch = $cvsid;
-    $size = 1 + $scratch =~ s/[^"\n]//g;
-    @{$objects[0][0]} = ( "CKA_CLASS", "&cko_data", "sizeof(CK_OBJECT_CLASS)" );
-    @{$objects[0][1]} = ( "CKA_TOKEN", "&ck_true", "sizeof(CK_BBOOL)" );
-    @{$objects[0][2]} = ( "CKA_PRIVATE", "&ck_false", "sizeof(CK_BBOOL)" );
-    @{$objects[0][3]} = ( "CKA_MODIFIABLE", "&ck_false", "sizeof(CK_BBOOL)" );
-    @{$objects[0][4]} = ( "CKA_LABEL", "\"CVS ID\"", "7" );
-    @{$objects[0][5]} = ( "CKA_APPLICATION", "\"NSS\"", "4" );
-    @{$objects[0][6]} = ( "CKA_VALUE", $cvsid, "$size" );
-    $objsize[0] = 7;
-    next;
-  }
-
   # This was taken from the perl faq #4.
   my $text = $_;
   push(@fields, $+) while $text =~ m{
       "([^\"\\]*(?:\\.[^\"\\]*)*)"\s?  # groups the phrase inside the quotes
     | ([^\s]+)\s?
     | \s
   }gx;
   push(@fields, undef) if substr($text,-1,1) eq '\s';
@@ -105,17 +88,17 @@ while(<>) {
 
  # print "$fields[0] | $fields[1] | $size | $fields[2]\n";
 }
 
 doprint();
 
 sub dudump {
 my $i;
-for( $i = 0; $i <= $count; $i++ ) {
+for( $i = 1; $i <= $count; $i++ ) {
   print "\n";
   $o = $objects[$i];
   my @ob = @{$o};
   my $l;
   my $j;
   for( $j = 0; $j < @ob; $j++ ) {
     $l = $ob[$j];
     my @a = @{$l};
@@ -128,104 +111,71 @@ for( $i = 0; $i <= $count; $i++ ) {
 sub doprint {
 my $i;
 
 print <<EOD
 /* THIS IS A GENERATED FILE */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-#ifdef DEBUG
-static const char CVS_ID[] = $cvsid;
-#endif /* DEBUG */
 
 #ifndef BUILTINS_H
 #include "builtins.h"
 #endif /* BUILTINS_H */
 
 EOD
     ;
 
 foreach $b (sort values(%constants)) {
   print $b;
 }
 
-for( $i = 0; $i <= $count; $i++ ) {
-  if( 0 == $i ) {
-    print "#ifdef DEBUG\n";
-  }
-
+for( $i = 1; $i <= $count; $i++ ) {
   print "static const CK_ATTRIBUTE_TYPE nss_builtins_types_$i [] = {\n";
   $o = $objects[$i];
   my @ob = @{$o};
   my $j;
   for( $j = 0; $j < @ob; $j++ ) {
     my $l = $ob[$j];
     my @a = @{$l};
     print " $a[0]";
     if( $j+1 != @ob ) {
       print ", ";
     }
   }
   print "\n};\n";
-
-  if( 0 == $i ) {
-    print "#endif /* DEBUG */\n";
-  }
 }
 
-for( $i = 0; $i <= $count; $i++ ) {
-  if( 0 == $i ) {
-    print "#ifdef DEBUG\n";
-  }
-
+for( $i = 1; $i <= $count; $i++ ) {
   print "static const NSSItem nss_builtins_items_$i [] = {\n";
   $o = $objects[$i];
   my @ob = @{$o};
   my $j;
   for( $j = 0; $j < @ob; $j++ ) {
     my $l = $ob[$j];
     my @a = @{$l};
     print "  { (void *)$a[1], (PRUint32)$a[2] }";
     if( $j+1 != @ob ) {
       print ",\n";
     } else {
       print "\n";
     }
   }
   print "};\n";
-
-  if( 0 == $i ) {
-    print "#endif /* DEBUG */\n";
-  }
 }
 
 print "\nbuiltinsInternalObject\n";
 print "nss_builtins_data[] = {\n";
 
-for( $i = 0; $i <= $count; $i++ ) {
-
-  if( 0 == $i ) {
-    print "#ifdef DEBUG\n";
-  }
-
+for( $i = 1; $i <= $count; $i++ ) {
   print "  { $objsize[$i], nss_builtins_types_$i, nss_builtins_items_$i, {NULL} }";
-
   if( $i == $count ) {
     print "\n";
   } else {
     print ",\n";
   }
-
-  if( 0 == $i ) {
-    print "#endif /* DEBUG */\n";
-  }
 }
 
 print "};\n";
 
 print "const PRUint32\n";
-print "#ifdef DEBUG\n";
-print "  nss_builtins_nObjects = $count+1;\n";
-print "#else\n";
-print "  nss_builtins_nObjects = $count;\n";
-print "#endif /* DEBUG */\n";
+print "nss_builtins_nObjects = $count;\n";
 }
--- a/security/nss/lib/ckfw/builtins/certdata.txt
+++ b/security/nss/lib/ckfw/builtins/certdata.txt
@@ -1,13 +1,12 @@
 # 
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
-CVS_ID "@(#) $RCSfile$ $Revision$ $Date$"
 
 #
 # certdata.txt
 #
 # This file contains the object definitions for the certs and other
 # information "built into" NSS.
 #
 # Object definitions:
--- a/security/nss/lib/ckfw/ck.api
+++ b/security/nss/lib/ckfw/ck.api
@@ -1,18 +1,16 @@
 # 
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 # This file is in part derived from a file "pkcs11f.h" made available
 # by RSA Security at ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-11/pkcs11f.h
 
-CVS_ID "@(#) $RCSfile$ $Revision$ $Date$"
-
 # Fields
 #  FUNCTION introduces a Cryptoki function
 #  CK_type specifies and introduces an argument
 #
 
 # General-purpose
 
 # C_Initialize initializes the Cryptoki library.
--- a/security/nss/lib/ckfw/ckapi.perl
+++ b/security/nss/lib/ckfw/ckapi.perl
@@ -69,20 +69,16 @@ open(API, ">nssck.api") || die "Can't op
 
 select PROTOTYPE;
 
 print $copyright;
 print <<EOD
 #ifndef NSSCKG_H
 #define NSSCKG_H
 
-#ifdef DEBUG
-static const char NSSCKG_CVS_ID[] = "$g{CVS_ID} ; $cvs_id";
-#endif /* DEBUG */
-
 /*
  * nssckg.h
  *
  * This automatically-generated header file prototypes the Cryptoki
  * functions specified by PKCS#11.
  */
 
 #ifndef NSSCKT_H
@@ -113,20 +109,16 @@ EOD
 
 select TYPEDEF;
 
 print $copyright;
 print <<EOD
 #ifndef NSSCKFT_H
 #define NSSCKFT_H
 
-#ifdef DEBUG
-static const char NSSCKFT_CVS_ID[] = "$g{CVS_ID} ; $cvs_id";
-#endif /* DEBUG */
-
 /*
  * nssckft.h
  *
  * The automatically-generated header file declares a typedef
  * each of the Cryptoki functions specified by PKCS#11.
  */
 
 #ifndef NSSCKT_H
@@ -157,20 +149,16 @@ EOD
 
 select EPV;
 
 print $copyright;
 print <<EOD
 #ifndef NSSCKEPV_H
 #define NSSCKEPV_H
 
-#ifdef DEBUG
-static const char NSSCKEPV_CVS_ID[] = "$g{CVS_ID} ; $cvs_id";
-#endif /* DEBUG */
-
 /*
  * nssckepv.h
  *
  * This automatically-generated header file defines the type
  * CK_FUNCTION_LIST specified by PKCS#11.
  */
 
 #ifndef NSSCKT_H
@@ -201,20 +189,16 @@ print <<EOD
 EOD
     ;
 
 select API;
 
 print $copyright;
 print <<EOD
 
-#ifdef DEBUG
-static const char NSSCKAPI_CVS_ID[] = "$g{CVS_ID} ; $cvs_id";
-#endif /* DEBUG */
-
 /*
  * nssck.api
  *
  * This automatically-generated file is used to generate a set of
  * Cryptoki entry points within the object space of a Module using
  * the NSS Cryptoki Framework.
  *
  * The Module should have a .c file with the following:
--- a/security/nss/lib/libpkix/include/pkix_pl_pki.h
+++ b/security/nss/lib/libpkix/include/pkix_pl_pki.h
@@ -1483,16 +1483,42 @@ PKIX_PL_Cert_GetValidityNotAfter(
  *  Returns a Fatal Error if the function fails in an unrecoverable way.
  */
 PKIX_Error *
 PKIX_PL_Cert_VerifySignature(
         PKIX_PL_Cert *cert,
         PKIX_PL_PublicKey *pubKey,
         void *plContext);
 
+/* A set of flags to indicate how explicitly configured trust anchors should be
+ * handled by PKIX_PL_Cert_IsCertTrusted
+ */
+typedef enum PKIX_PL_TrustAnchorModeEnum {
+        /* Indicates trust anchors should be ignored; only the underlying
+         * platform's trust settings should be used.
+         */
+        PKIX_PL_TrustAnchorMode_Ignore,
+
+        /* Indicates that explicitly configured trust anchors may be considered
+         * trustworthy, if present.
+         * Note: If the underlying platform supports marking a certificate as
+         *       explicitly untrustworthy, explicitly configured trust anchors
+         *       MAY be ignored/rejected.
+         */
+        PKIX_PL_TrustAnchorMode_Additive,
+
+        /* Indicates that ONLY trust anchors should be considered as
+         * trustworthy.
+         * Note: If the underlying platform supports marking a certificate as
+         *       explicitly untrustworthy, explicitly configured trust anchors
+         *       MAY be ignored/rejected.
+         */
+        PKIX_PL_TrustAnchorMode_Exclusive,
+} PKIX_PL_TrustAnchorMode;
+
 /*
  * FUNCTION: PKIX_PL_Cert_IsCertTrusted
  * DESCRIPTION:
  *
  *  Checks the Cert specified by "cert" to determine, in a manner that depends
  *  on the underlying platform, whether it is trusted, and stores the result in
  *  "pTrusted". If a certificate is trusted it means that a chain built to that
  *  certificate, and satisfying all the usage, policy, validity, and other
@@ -1504,33 +1530,34 @@ PKIX_PL_Cert_VerifySignature(
  *
  *  If the Certificate is intrinsically untrustworthy, this function will return
  *  an error. 
  *
  * PARAMETERS
  *  "cert"
  *      Address of Cert whose trustworthiness is to be determined. Must be
  *      non-NULL.
- *  "trustOnlyUserAnchors"
- *      States that we can only trust explicitly defined user trust anchors.
+ *  "trustAnchorMode"
+ *      A PKIX_PL_TrustAnchorMode that indicates how explicitly defined user
+ *      trust anchors should be handled.
  *  "pTrusted"
  *      Address where the Boolean value will be stored. Must be non-NULL.
  *  "plContext"
  *      Platform-specific context pointer.
  * THREAD SAFETY:
  *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
  * RETURNS:
  *  Returns NULL if the function succeeds.
  *  Returns a CERT Error if the function fails in a non-fatal way.
  *  Returns a Fatal Error if the function fails in an unrecoverable way.
  */
 PKIX_Error *
 PKIX_PL_Cert_IsCertTrusted(
         PKIX_PL_Cert *cert,
-        PKIX_Boolean trustOnlyUserAnchors,
+        PKIX_PL_TrustAnchorMode trustAnchorMode,
         PKIX_Boolean *pTrusted,
         void *plContext);
 
 /*
  * FUNCTION: PKIX_PL_Cert_IsLeafCertTrusted
  * DESCRIPTION:
  *
  *  Checks the Leaf Cert specified by "cert" to determine, in a manner that 
--- a/security/nss/lib/libpkix/pkix/top/pkix_build.c
+++ b/security/nss/lib/libpkix/pkix/top/pkix_build.c
@@ -831,36 +831,42 @@ pkix_Build_VerifyCertificate(
         PKIX_UInt32 i = 0;
         PKIX_Boolean loopFound = PKIX_FALSE;
         PKIX_Boolean supportForwardChecking = PKIX_FALSE;
         PKIX_Boolean trusted = PKIX_FALSE;
         PKIX_PL_Cert *candidateCert = NULL;
         PKIX_PL_PublicKey *candidatePubKey = NULL;
         PKIX_CertChainChecker *userChecker = NULL;
         PKIX_CertChainChecker_CheckCallback checkerCheck = NULL;
-        PKIX_Boolean trustOnlyUserAnchors = PKIX_FALSE;
+        PKIX_PL_TrustAnchorMode trustAnchorMode =
+                PKIX_PL_TrustAnchorMode_Ignore;
         void *nbioContext = NULL;
         
         PKIX_ENTER(BUILD, "pkix_Build_VerifyCertificate");
         PKIX_NULLCHECK_THREE(state, pTrusted, pNeedsCRLChecking);
         PKIX_NULLCHECK_THREE
                 (state->candidateCerts, state->prevCert, state->trustChain);
 
         *pNeedsCRLChecking = PKIX_FALSE;
 
         PKIX_INCREF(state->candidateCert);
         candidateCert = state->candidateCert;
 
         if (state->buildConstants.numAnchors) {
-            trustOnlyUserAnchors = state->buildConstants.trustOnlyUserAnchors;
+            if (state->buildConstants.trustOnlyUserAnchors) {
+                trustAnchorMode = PKIX_PL_TrustAnchorMode_Exclusive;
+            } else {
+                trustAnchorMode = PKIX_PL_TrustAnchorMode_Additive;
+            }
+        } else {
+            trustAnchorMode = PKIX_PL_TrustAnchorMode_Ignore;
         }
 
         PKIX_CHECK(
-            PKIX_PL_Cert_IsCertTrusted(candidateCert,
-                                       trustOnlyUserAnchors,
+            PKIX_PL_Cert_IsCertTrusted(candidateCert, trustAnchorMode,
                                        &trusted, plContext),
             PKIX_CERTISCERTTRUSTEDFAILED);
 
         *pTrusted = trusted;
 
         /* check for loops */
         PKIX_CHECK(pkix_List_Contains
                 (state->trustChain,
@@ -3036,29 +3042,37 @@ pkix_Build_CheckInCache(
                    PKIX_VALIDATERESULTGETTRUSTANCHORFAILED);
         
         PKIX_DECREF(valResult);
         
         PKIX_CHECK(PKIX_TrustAnchor_GetTrustedCert
                    (matchingAnchor, &trustedCert, plContext),
                    PKIX_TRUSTANCHORGETTRUSTEDCERTFAILED);
         
-        if (state->buildConstants.anchors &&
-            state->buildConstants.anchors->length) {
+        if (anchors && state->buildConstants.numAnchors) {
             /* Check if it is one of the trust anchors */
             PKIX_CHECK(
-                pkix_List_Contains(state->buildConstants.anchors,
+                pkix_List_Contains(anchors,
                                    (PKIX_PL_Object *)matchingAnchor,
                                    &trusted,
                                    plContext),
                 PKIX_LISTCONTAINSFAILED);
-        } else {
-            PKIX_CHECK(PKIX_PL_Cert_IsCertTrusted
-                       (trustedCert, PKIX_FALSE, &trusted, plContext),
-                       PKIX_CERTISCERTTRUSTEDFAILED);
+        }
+
+        if ((!trusted && !state->buildConstants.trustOnlyUserAnchors) ||
+            !state->buildConstants.numAnchors) {
+            /* If it is not one of the trust anchors and the trust anchors
+             * are supplemental, or if there are no trust anchors, then check
+             * if the cert is trusted directly.
+             */
+            PKIX_CHECK(
+                PKIX_PL_Cert_IsCertTrusted(trustedCert,
+                                           PKIX_PL_TrustAnchorMode_Ignore,
+                                           &trusted, plContext),
+                PKIX_CERTISCERTTRUSTEDFAILED);
         }
 
         if (!trusted) {
             goto cleanup;
         }
         /*
          * Since the key usage may vary for different
          * applications, we need to verify the chain again.
--- a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_cert.c
+++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_cert.c
@@ -3289,17 +3289,17 @@ pkix_pl_Cert_GetTrusted(void *plContext,
 
 /*
  * FUNCTION: PKIX_PL_Cert_IsCertTrusted
  * (see comments in pkix_pl_pki.h)
  */
 PKIX_Error *
 PKIX_PL_Cert_IsCertTrusted(
         PKIX_PL_Cert *cert,
-        PKIX_Boolean trustOnlyUserAnchors,
+        PKIX_PL_TrustAnchorMode trustAnchorMode,
         PKIX_Boolean *pTrusted,
         void *plContext)
 {
         PKIX_CertStore_CheckTrustCallback trustCallback = NULL;
         PKIX_Boolean trusted = PKIX_FALSE;
         SECStatus rv = SECFailure;
 
         PKIX_ENTER(CERT, "PKIX_PL_Cert_IsCertTrusted");
@@ -3310,18 +3310,20 @@ PKIX_PL_Cert_IsCertTrusted(
         rv = pkix_pl_Cert_GetTrusted(plContext, cert, &trusted, PKIX_TRUE);
         if (rv != SECSuccess) {
                 /* Failure means the cert is explicitly distrusted,
                  * let the next level know not to use it. */
                 *pTrusted = PKIX_FALSE;
                 PKIX_ERROR(PKIX_CERTISCERTTRUSTEDFAILED);
         }
 
-        if (trustOnlyUserAnchors || cert->isUserTrustAnchor) {
-            /* discard our |trusted| value since we are using the anchors */
+        if (trustAnchorMode == PKIX_PL_TrustAnchorMode_Exclusive ||
+            (trustAnchorMode == PKIX_PL_TrustAnchorMode_Additive &&
+             cert->isUserTrustAnchor)) {
+            /* Use the trust anchor's |trusted| value */
             *pTrusted = cert->isUserTrustAnchor;
             goto cleanup;
         }
 
         /* no key usage information or store is not trusted */
         if (plContext == NULL || cert->store == NULL) {
                 *pTrusted = PKIX_FALSE;
                 goto cleanup;
--- a/security/nss/lib/ssl/ssl.h
+++ b/security/nss/lib/ssl/ssl.h
@@ -412,24 +412,23 @@ SSL_IMPORT CERTCertificate *SSL_PeerCert
  * authenticate certificate hook is responsible for doing so. The default
  * authenticate certificate hook, SSL_AuthCertificate, does not implement
  * any OCSP stapling funtionality, but this may change in future versions.
  */
 SSL_IMPORT const SECItemArray * SSL_PeerStapledOCSPResponses(PRFileDesc *fd);
 
 /* SSL_SetStapledOCSPResponses stores an array of one or multiple OCSP responses
  * in the fd's data, which may be sent as part of a server side cert_status
- * handshake message.
- * If takeOwnership is false, the function will duplicate the responses.
- * If takeOwnership is true, the ownership of responses is transfered into the
- * SSL library, and the caller must stop using it.
+ * handshake message. Parameter |responses| is for the server certificate of
+ * the key exchange type |kea|.
+ * The function will duplicate the responses array.
  */
 SSL_IMPORT SECStatus
-SSL_SetStapledOCSPResponses(PRFileDesc *fd, SECItemArray *responses,
-			    PRBool takeOwnership);
+SSL_SetStapledOCSPResponses(PRFileDesc *fd, const SECItemArray *responses,
+			    SSLKEAType kea);
 
 /*
 ** Authenticate certificate hook. Called when a certificate comes in
 ** (because of SSL_REQUIRE_CERTIFICATE in SSL_Enable) to authenticate the
 ** certificate.
 **
 ** The authenticate certificate hook must return SECSuccess to indicate the
 ** certificate is valid, SECFailure to indicate the certificate is invalid,
--- a/security/nss/lib/ssl/ssl3con.c
+++ b/security/nss/lib/ssl/ssl3con.c
@@ -8439,45 +8439,58 @@ ssl3_SendCertificate(sslSocket *ss)
 
 /*
  * Used by server only.
  * single-stapling, send only a single cert status
  */
 static SECStatus
 ssl3_SendCertificateStatus(sslSocket *ss)
 {
-    SECStatus            rv;
-    int                  len 		= 0;
+    SECStatus rv;
+    int len = 0;
+    SECItemArray *statusToSend = NULL;
+    SSL3KEAType certIndex;
 
     SSL_TRC(3, ("%d: SSL3[%d]: send certificate status handshake",
 		SSL_GETPID(), ss->fd));
 
     PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
     PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
+    PORT_Assert( ss->sec.isServer);
 
     if (!ssl3_ExtensionNegotiated(ss, ssl_cert_status_xtn))
 	return SECSuccess;
 
-    if (!ss->certStatusArray || !ss->certStatusArray->len)
+    /* Use certStatus based on the cert being used. */
+    if ((ss->ssl3.hs.kea_def->kea == kea_ecdhe_rsa) ||
+	(ss->ssl3.hs.kea_def->kea == kea_dhe_rsa)) {
+	certIndex = kt_rsa;
+    } else {
+	certIndex = ss->ssl3.hs.kea_def->exchKeyType;
+    }
+    if (ss->certStatusArray[certIndex] && ss->certStatusArray[certIndex]->len) {
+	statusToSend = ss->certStatusArray[certIndex];
+    }
+    if (!statusToSend)
 	return SECSuccess;
 
     /* Use the array's first item only (single stapling) */
-    len = 1 + ss->certStatusArray->items[0].len + 3;
+    len = 1 + statusToSend->items[0].len + 3;
 
     rv = ssl3_AppendHandshakeHeader(ss, certificate_status, len);
     if (rv != SECSuccess) {
 	return rv; 		/* err set by AppendHandshake. */
     }
     rv = ssl3_AppendHandshakeNumber(ss, 1 /*ocsp*/, 1);
     if (rv != SECSuccess)
 	return rv; 		/* err set by AppendHandshake. */
 
     rv = ssl3_AppendHandshakeVariable(ss,
-				      ss->certStatusArray->items[0].data,
-				      ss->certStatusArray->items[0].len,
+				      statusToSend->items[0].data,
+				      statusToSend->items[0].len,
 				      3);
     if (rv != SECSuccess)
 	return rv; 		/* err set by AppendHandshake. */
 
     return SECSuccess;
 }
 
 /* This is used to delete the CA certificates in the peer certificate chain
--- a/security/nss/lib/ssl/ssl3ext.c
+++ b/security/nss/lib/ssl/ssl3ext.c
@@ -676,18 +676,31 @@ ssl3_ClientHandleStatusRequestXtn(sslSoc
 static PRInt32
 ssl3_ServerSendStatusRequestXtn(
 			sslSocket * ss,
 			PRBool      append,
 			PRUint32    maxBytes)
 {
     PRInt32 extension_length;
     SECStatus rv;
+    int i;
+    PRBool haveStatus = PR_FALSE;
 
-    if (!ss->certStatusArray || !ss->certStatusArray->len)
+    for (i = kt_null; i < kt_kea_size; i++) {
+	/* TODO: This is a temporary workaround.
+	 *       The correct code needs to see if we have an OCSP response for
+	 *       the server certificate being used, rather than if we have any
+	 *       OCSP response. See also ssl3_SendCertificateStatus.
+	 */
+	if (ss->certStatusArray[i] && ss->certStatusArray[i]->len) {
+	    haveStatus = PR_TRUE;
+	    break;
+	}
+    }
+    if (!haveStatus)
 	return 0;
 
     extension_length = 2 + 2;
     if (append && maxBytes >= extension_length) {
 	/* extension_type */
 	rv = ssl3_AppendHandshakeNumber(ss, ssl_cert_status_xtn, 2);
 	if (rv != SECSuccess)
 	    return -1;
--- a/security/nss/lib/ssl/sslimpl.h
+++ b/security/nss/lib/ssl/sslimpl.h
@@ -1170,17 +1170,18 @@ const unsigned char *  preferredCipher;
     sslGather        gs;				/*recvBufLock*/
 
     sslBuffer        saveBuf;				/*xmitBufLock*/
     sslBuffer        pendingBuf;			/*xmitBufLock*/
 
     /* Configuration state for server sockets */
     /* server cert and key for each KEA type */
     sslServerCerts        serverCerts[kt_kea_size];
-    SECItemArray *        certStatusArray;
+    /* each cert needs its own status */
+    SECItemArray *        certStatusArray[kt_kea_size];
 
     ssl3CipherSuiteCfg cipherSuites[ssl_V3_SUITES_IMPLEMENTED];
     ssl3KeyPair *         ephemeralECDHKeyPair; /* for ECDHE-* handshake */
 
     /* SSL3 state info.  Formerly was a pointer */
     ssl3State        ssl3;
 
     /*
--- a/security/nss/lib/ssl/sslsock.c
+++ b/security/nss/lib/ssl/sslsock.c
@@ -316,23 +316,23 @@ ssl_DupSocket(sslSocket *os)
 		    sc->serverCert      = NULL;
 		    sc->serverCertChain = NULL;
 		}
 		sc->serverKeyPair = oc->serverKeyPair ?
 				ssl3_GetKeyPairRef(oc->serverKeyPair) : NULL;
 		if (oc->serverKeyPair && !sc->serverKeyPair)
 		    goto loser;
 	        sc->serverKeyBits = oc->serverKeyBits;
+		ss->certStatusArray[i] = !os->certStatusArray[i] ? NULL :
+				SECITEM_DupArray(NULL, os->certStatusArray[i]);
 	    }
 	    ss->stepDownKeyPair = !os->stepDownKeyPair ? NULL :
 		                  ssl3_GetKeyPairRef(os->stepDownKeyPair);
 	    ss->ephemeralECDHKeyPair = !os->ephemeralECDHKeyPair ? NULL :
 		                  ssl3_GetKeyPairRef(os->ephemeralECDHKeyPair);
-	    ss->certStatusArray = !os->certStatusArray ? NULL :
-				  SECITEM_DupArray(NULL, os->certStatusArray);
 /*
  * XXX the preceding CERT_ and SECKEY_ functions can fail and return NULL.
  * XXX We should detect this, and not just march on with NULL pointers.
  */
 	    ss->authCertificate       = os->authCertificate;
 	    ss->authCertificateArg    = os->authCertificateArg;
 	    ss->getClientAuthData     = os->getClientAuthData;
 	    ss->getClientAuthDataArg  = os->getClientAuthDataArg;
@@ -425,29 +425,29 @@ ssl_DestroySocketContents(sslSocket *ss)
     for (i=kt_null; i < kt_kea_size; i++) {
 	sslServerCerts * sc = ss->serverCerts + i;
 	if (sc->serverCert != NULL)
 	    CERT_DestroyCertificate(sc->serverCert);
 	if (sc->serverCertChain != NULL)
 	    CERT_DestroyCertificateList(sc->serverCertChain);
 	if (sc->serverKeyPair != NULL)
 	    ssl3_FreeKeyPair(sc->serverKeyPair);
+	if (ss->certStatusArray[i] != NULL) {
+	    SECITEM_FreeArray(ss->certStatusArray[i], PR_TRUE);
+	    ss->certStatusArray[i] = NULL;
+	}
     }
     if (ss->stepDownKeyPair) {
 	ssl3_FreeKeyPair(ss->stepDownKeyPair);
 	ss->stepDownKeyPair = NULL;
     }
     if (ss->ephemeralECDHKeyPair) {
 	ssl3_FreeKeyPair(ss->ephemeralECDHKeyPair);
 	ss->ephemeralECDHKeyPair = NULL;
     }
-    if (ss->certStatusArray) {
-	SECITEM_FreeArray(ss->certStatusArray, PR_TRUE);
-	ss->certStatusArray = NULL;
-    }
     SECITEM_FreeItem(&ss->opt.nextProtoNego, PR_FALSE);
     PORT_Assert(!ss->xtnData.sniNameArr);
     if (ss->xtnData.sniNameArr) {
         PORT_Free(ss->xtnData.sniNameArr);
         ss->xtnData.sniNameArr = NULL;
     }
 }
 
@@ -1663,16 +1663,25 @@ SSL_ReconfigFD(PRFileDesc *model, PRFile
             }
             sc->serverCert      = CERT_DupCertificate(mc->serverCert);
             if (sc->serverCertChain) {
                 CERT_DestroyCertificateList(sc->serverCertChain);
             }
             sc->serverCertChain = CERT_DupCertList(mc->serverCertChain);
             if (!sc->serverCertChain)
                 goto loser;
+	    if (sm->certStatusArray[i]) {
+		if (ss->certStatusArray[i]) {
+		    SECITEM_FreeArray(ss->certStatusArray[i], PR_TRUE);
+		    ss->certStatusArray[i] = NULL;
+		}
+		ss->certStatusArray[i] = SECITEM_DupArray(NULL, sm->certStatusArray[i]);
+		if (!ss->certStatusArray[i])
+		    goto loser;
+	    }
         }
         if (mc->serverKeyPair) {
             if (sc->serverKeyPair) {
                 ssl3_FreeKeyPair(sc->serverKeyPair);
             }
             sc->serverKeyPair = ssl3_GetKeyPairRef(mc->serverKeyPair);
             sc->serverKeyBits = mc->serverKeyBits;
         }
@@ -1685,23 +1694,16 @@ SSL_ReconfigFD(PRFileDesc *model, PRFile
     }
     if (sm->ephemeralECDHKeyPair) {
         if (ss->ephemeralECDHKeyPair) {
             ssl3_FreeKeyPair(ss->ephemeralECDHKeyPair);
         }
         ss->ephemeralECDHKeyPair =
             ssl3_GetKeyPairRef(sm->ephemeralECDHKeyPair);
     }
-    if (sm->certStatusArray) {
-	if (ss->certStatusArray) {
-	    SECITEM_FreeArray(ss->certStatusArray, PR_TRUE);
-	    ss->certStatusArray = NULL;
-	}
-	ss->certStatusArray = SECITEM_DupArray(NULL, sm->certStatusArray);
-    }
     /* copy trust anchor names */
     if (sm->ssl3.ca_list) {
         if (ss->ssl3.ca_list) {
             CERT_FreeDistNames(ss->ssl3.ca_list);
         }
         ss->ssl3.ca_list = CERT_DupDistNames(sm->ssl3.ca_list);
         if (!ss->ssl3.ca_list) {
             goto loser;
@@ -2224,41 +2226,42 @@ ssl_GetSockName(PRFileDesc *fd, PRNetAdd
     if (!ss) {
 	SSL_DBG(("%d: SSL[%d]: bad socket in getsockname", SSL_GETPID(), fd));
 	return PR_FAILURE;
     }
     return (PRStatus)(*ss->ops->getsockname)(ss, name);
 }
 
 SECStatus
-SSL_SetStapledOCSPResponses(PRFileDesc *fd, SECItemArray *responses,
-			    PRBool takeOwnership)
+SSL_SetStapledOCSPResponses(PRFileDesc *fd, const SECItemArray *responses,
+			    SSLKEAType kea)
 {
     sslSocket *ss;
 
     ss = ssl_FindSocket(fd);
     if (!ss) {
 	SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetStapledOCSPResponses",
 		 SSL_GETPID(), fd));
 	return SECFailure;
     }
 
-    if (ss->certStatusArray) {
-        SECITEM_FreeArray(ss->certStatusArray, PR_TRUE);
-        ss->certStatusArray = NULL;
+    if ( kea <= 0 || kea >= kt_kea_size) {
+	SSL_DBG(("%d: SSL[%d]: invalid key in SSL_SetStapledOCSPResponses",
+		 SSL_GETPID(), fd));
+	return SECFailure;
+    }
+
+    if (ss->certStatusArray[kea]) {
+        SECITEM_FreeArray(ss->certStatusArray[kea], PR_TRUE);
+        ss->certStatusArray[kea] = NULL;
     }
     if (responses) {
-	if (takeOwnership) {
-	    ss->certStatusArray = responses;
-	}
-	else {
-	    ss->certStatusArray = SECITEM_DupArray(NULL, responses);
-	}
+	ss->certStatusArray[kea] = SECITEM_DupArray(NULL, responses);
     }
-    return (ss->certStatusArray || !responses) ? SECSuccess : SECFailure;
+    return (ss->certStatusArray[kea] || !responses) ? SECSuccess : SECFailure;
 }
 
 SECStatus
 SSL_SetSockPeerID(PRFileDesc *fd, const char *peerID)
 {
     sslSocket *ss;
 
     ss = ssl_FindSocket(fd);
@@ -2948,20 +2951,20 @@ ssl_NewSocket(PRBool makeLocks, SSLProto
         ss->url                = NULL;
 
 	for (i=kt_null; i < kt_kea_size; i++) {
 	    sslServerCerts * sc = ss->serverCerts + i;
 	    sc->serverCert      = NULL;
 	    sc->serverCertChain = NULL;
 	    sc->serverKeyPair   = NULL;
 	    sc->serverKeyBits   = 0;
+	    ss->certStatusArray[i] = NULL;
 	}
 	ss->stepDownKeyPair    = NULL;
 	ss->dbHandle           = CERT_GetDefaultCertDB();
-	ss->certStatusArray    = NULL;
 
 	/* Provide default implementation of hooks */
 	ss->authCertificate    = SSL_AuthCertificate;
 	ss->authCertificateArg = (void *)ss->dbHandle;
         ss->sniSocketConfig    = NULL;
         ss->sniSocketConfigArg = NULL;
 	ss->getClientAuthData  = NULL;
 	ss->handleBadCert      = NULL;
--- a/security/nss/lib/util/nssutil.def
+++ b/security/nss/lib/util/nssutil.def
@@ -261,12 +261,13 @@ NSSUTIL_QuoteSize;
 ;+    local:
 ;+       *;
 ;+};
 ;+NSSUTIL_3.15 {         # NSS Utilities 3.15 release
 ;+    global:
 SECITEM_AllocArray;
 SECITEM_DupArray;
 SECITEM_FreeArray;
+SECITEM_ReallocItemV2;
 SECITEM_ZfreeArray;
 ;+    local:
 ;+       *;
 ;+};
--- a/security/nss/lib/util/secitem.c
+++ b/security/nss/lib/util/secitem.c
@@ -110,16 +110,73 @@ SECITEM_ReallocItem(PLArenaPool *arena, 
 
     if (item->data == NULL) {
 	return SECFailure;
     }
 
     return SECSuccess;
 }
 
+SECStatus
+SECITEM_ReallocItemV2(PLArenaPool *arena, SECItem *item, unsigned int newlen)
+{
+    unsigned char *newdata = NULL;
+
+    PORT_Assert(item);
+    if (!item) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+    
+    if (item->len == newlen) {
+	return SECSuccess;
+    }
+
+    if (!newlen) {
+	SECITEM_FreeItem(item, PR_FALSE);
+	return SECSuccess;
+    }
+    
+    if (!item->len) {
+	/* allocate fresh block of memory */
+	PORT_Assert(!item->data);
+	if (arena) {
+	    newdata = PORT_ArenaAlloc(arena, newlen);
+	} else {
+	    newdata = PORT_Alloc(newlen);
+	}
+    } else {
+	/* reallocate or adjust existing block of memory */
+	if (arena) {
+	    if (item->len > newlen) {
+		/* There's no need to realloc a shorter block from the arena,
+		 * because it would result in using even more memory!
+		 * Therefore we'll continue to use the old block and 
+		 * set the item to the shorter size.
+		 */
+		item->len = newlen;
+		return SECSuccess;
+	    } else {
+		newdata = PORT_ArenaGrow(arena, item->data, item->len, newlen);
+	    }
+	} else {
+	    newdata = PORT_Realloc(item->data, newlen);
+	}
+    }
+
+    if (!newdata) {
+	PORT_SetError(SEC_ERROR_NO_MEMORY);
+	return SECFailure;
+    }
+
+    item->len = newlen;
+    item->data = newdata;
+    return SECSuccess;
+}
+
 SECComparison
 SECITEM_CompareItem(const SECItem *a, const SECItem *b)
 {
     unsigned m;
     int rv;
 
     if (a == b)
     	return SECEqual;
--- a/security/nss/lib/util/secitem.h
+++ b/security/nss/lib/util/secitem.h
@@ -31,27 +31,45 @@ SEC_BEGIN_PROTOS
 **
 ** XXX This probably should take a SECItemType, but since that is mostly
 ** unused and our improved APIs (aka Stan) are looming, I left it out.
 */
 extern SECItem *SECITEM_AllocItem(PLArenaPool *arena, SECItem *item,
 				  unsigned int len);
 
 /*
+** This is a legacy function containing bugs. It doesn't update item->len,
+** and it has other issues as described in bug 298649 and bug 298938.
+** However, the function is  kept unchanged for consumers that might depend 
+** on the broken behaviour. New code should call SECITEM_ReallocItemV2.
+**
 ** Reallocate the data for the specified "item".  If "arena" is not NULL,
 ** then reallocate from there, otherwise reallocate from the heap.
 ** In the case where oldlen is 0, the data is allocated (not reallocated).
 ** In any case, "item" is expected to be a valid SECItem pointer;
 ** SECFailure is returned if it is not.  If the allocation succeeds,
 ** SECSuccess is returned.
 */
-extern SECStatus SECITEM_ReallocItem(PLArenaPool *arena, SECItem *item,
+extern SECStatus SECITEM_ReallocItem( /* deprecated function */
+				     PLArenaPool *arena, SECItem *item,
 				     unsigned int oldlen, unsigned int newlen);
 
 /*
+** Reallocate the data for the specified "item".  If "arena" is not NULL,
+** then reallocate from there, otherwise reallocate from the heap.
+** If the item already has at least the request new size,
+** then the item is kept unchanged and SECSuccess is returned.
+** In any case, "item" is expected to be a valid SECItem pointer;
+** SECFailure is returned if it is not, and the item will remain unchanged.
+** If the allocation succeeds, the item is updated and SECSuccess is returned.
+ */
+extern SECStatus SECITEM_ReallocItemV2(PLArenaPool *arena, SECItem *item,
+				       unsigned int newlen);
+
+/*
 ** Compare two items returning the difference between them.
 */
 extern SECComparison SECITEM_CompareItem(const SECItem *a, const SECItem *b);
 
 /*
 ** Compare two items -- if they are the same, return true; otherwise false.
 */
 extern PRBool SECITEM_ItemsAreEqual(const SECItem *a, const SECItem *b);