Bug 858231: Update NSS to NSS 3.15 Beta 6, with the local patch
authorWan-Teh Chang <wtc@google.com>
Wed, 22 May 2013 16:32:02 -0700
changeset 132705 84985c77b141503e555f8e3aa06086ac0b48c59d
parent 132704 88016f09b0f4be66698780ec36d2b4e5ba7f0f8a
child 132706 f8c8be5a9f4aef89d041e5913362f8b73e535c0d
push id28406
push userwtc@google.com
push dateWed, 22 May 2013 23:32:10 +0000
treeherdermozilla-inbound@84985c77b141 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs858231, 808217, 868694, 868678, 873673, 783579
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 6, with the local patch revert-bug-808217.patch. r=wtc. Reduces revert-bug-808217.patch to just avoid using the new SECITEM_ReallocItemV2 function. Inclues fixes for bug 868694, bug 868678, bug 873673, bug 783579, bug 808217.
security/nss/TAG-INFO
security/nss/cmd/certutil/certutil.c
security/nss/cmd/certutil/certutil.h
security/nss/cmd/certutil/keystuff.c
security/nss/cmd/lib/secutil.c
security/nss/coreconf/coreconf.dep
security/nss/lib/certhigh/ocsp.c
security/nss/lib/dbm/src/config.mk
security/nss/lib/ssl/ssl3con.c
security/nss/lib/util/nssutil.def
security/nss/lib/util/secitem.c
security/nss/lib/util/secitem.h
security/patches/revert-bug-808217.patch
--- a/security/nss/TAG-INFO
+++ b/security/nss/TAG-INFO
@@ -1,1 +1,1 @@
-NSS_3_15_BETA5
+NSS_3_15_BETA6
--- a/security/nss/cmd/certutil/certutil.c
+++ b/security/nss/cmd/certutil/certutil.c
@@ -1197,16 +1197,29 @@ static void luG(enum usage_level ul, con
     FPS "%-20s secp112r2, secp128r1, secp128r2, sect113r1, sect113r2\n", "");
     FPS "%-20s sect131r1, sect131r2\n", "");
 #endif /* NSS_ECC_MORE_THAN_SUITE_B */
 #endif
     FPS "%-20s Key database directory (default is ~/.netscape)\n",
         "   -d keydir");
     FPS "%-20s Cert & Key database prefix\n",
         "   -P dbprefix");
+    FPS "%-20s PKCS #11 key Attributes\n",
+        "   --keyAttrFlags attrflags.");
+    FPS "%-20s Comma separated list of key attribute attribute flags,\n", "");
+    FPS "%-20s selected from the following list of choices:\n", "");
+    FPS "%-20s {token | session} {public | private} {sensitive | insensitive}\n", "");
+    FPS "%-20s {modifiable | unmodifiable} {extractable | unextractable}\n", "");
+    FPS "%-20s PKCS #11 key Operation Flags\n",
+        "   --keyOpFlagsOn opflags.");
+    FPS "%-20s PKCS #11 key Operation Flags\n",
+        "   --keyOpFlagsOff opflags.");
+    FPS "%-20s Comma separated list of one or more of the following:\n", "");
+    FPS "%-20s encrypt, decrypt, sign, sign_recover, verify,\n", "");
+    FPS "%-20s verify_recover, wrap, unwrap, derive\n", "");
     FPS "\n");
 }
 
 static void luD(enum usage_level ul, const char *command)
 {
     int is_my_command = (command && 0 == strcmp(command, "D"));
     if (ul == usage_all || !command || is_my_command)
     FPS "%-15s Delete a certificate from the database\n",
@@ -1428,16 +1441,18 @@ static void luR(enum usage_level ul, con
     FPS "%-20s Cert & Key database prefix\n",
         "   -P dbprefix");
     FPS "%-20s Specify the contact phone number (\"123-456-7890\")\n",
         "   -p phone");
     FPS "%-20s Output the cert request in ASCII (RFC1113); default is binary\n",
         "   -a");
     FPS "%-20s \n",
         "   See -S for available extension options");
+    FPS "%-20s \n",
+        "   See -G for available key flag  options");
     FPS "\n");
 }
 
 static void luV(enum usage_level ul, const char *command)
 {
     int is_my_command = (command && 0 == strcmp(command, "V"));
     if (ul == usage_all || !command || is_my_command)
     FPS "%-15s Validate a certificate\n",
@@ -1610,16 +1625,18 @@ static void luS(enum usage_level ul, con
     FPS "%-20s Create a Policy Mappings extension\n",
         "   --extPM ");
     FPS "%-20s Create a Policy Constraints extension\n",
         "   --extPC ");
     FPS "%-20s Create an Inhibit Any Policy extension\n",
         "   --extIA ");
     FPS "%-20s Create a subject key ID extension\n",
         "   --extSKID ");
+    FPS "%-20s \n",
+        "   See -G for available key flag  options");
     FPS "%-20s Create a name constraints extension\n",
         "   --extNC ");
     FPS "\n");
 }
 
 static void LongUsage(char *progName, enum usage_level ul, const char *command)
 {
     luA(ul, command);
@@ -1930,16 +1947,113 @@ getObjectClass(CK_ULONG classType)
     }
     if (classType >= CKO_NSS && classType <= CKO_NSS_BUILTIN_ROOT_LIST) {
 	return objNSSClassArray[classType - CKO_NSS];
     }
     sprintf(buf, "0x%lx", classType);
     return buf;
 }
 
+typedef struct {
+    char *name;
+    int  nameSize;
+    CK_ULONG value;
+} flagArray;
+
+#define NAME_SIZE(x) #x,sizeof(#x)-1
+
+flagArray opFlagsArray[] =
+{
+    {NAME_SIZE(encrypt), CKF_ENCRYPT},
+    {NAME_SIZE(decrypt), CKF_DECRYPT},
+    {NAME_SIZE(sign), CKF_SIGN},
+    {NAME_SIZE(sign_recover), CKF_SIGN_RECOVER},
+    {NAME_SIZE(verify), CKF_VERIFY},
+    {NAME_SIZE(verify_recover), CKF_VERIFY_RECOVER},
+    {NAME_SIZE(wrap), CKF_WRAP},
+    {NAME_SIZE(unwrap), CKF_UNWRAP},
+    {NAME_SIZE(derive), CKF_DERIVE},
+};
+
+int opFlagsCount = sizeof(opFlagsArray)/sizeof(flagArray);
+
+flagArray attrFlagsArray[] =
+{
+    {NAME_SIZE(token), PK11_ATTR_TOKEN},
+    {NAME_SIZE(session), PK11_ATTR_SESSION},
+    {NAME_SIZE(private), PK11_ATTR_PRIVATE},
+    {NAME_SIZE(public), PK11_ATTR_PUBLIC},
+    {NAME_SIZE(modifiable), PK11_ATTR_MODIFIABLE},
+    {NAME_SIZE(unmodifiable), PK11_ATTR_UNMODIFIABLE},
+    {NAME_SIZE(sensitive), PK11_ATTR_SENSITIVE},
+    {NAME_SIZE(insensitive), PK11_ATTR_INSENSITIVE},
+    {NAME_SIZE(extractable), PK11_ATTR_EXTRACTABLE},
+    {NAME_SIZE(unextractable), PK11_ATTR_EXTRACTABLE}
+
+};
+
+int attrFlagsCount = sizeof(attrFlagsArray)/sizeof(flagArray);
+
+#define MAX_STRING 30
+CK_ULONG
+GetFlags(char *flagsString, flagArray *flagArray, int count)
+{
+   CK_ULONG flagsValue = strtol(flagsString, NULL, 0);
+   int i;
+
+fprintf(stderr, "parsing flags <%s>\n", flagsString);
+
+   if ((flagsValue != 0) || (*flagsString == 0)) {
+	return flagsValue;
+   }
+   while (*flagsString) {
+	for (i=0; i < count; i++) {
+	    if (strncmp(flagsString, flagArray[i].name, flagArray[i].nameSize) 
+								== 0) {
+		flagsValue |= flagArray[i].value;
+		flagsString += flagArray[i].nameSize;
+		if (*flagsString != 0) {
+		    flagsString++;
+		}
+		break;
+	    }
+	}
+	if (i == count) {
+	    char name[MAX_STRING];
+	    char *tok;
+
+	    strncpy(name,flagsString, MAX_STRING);
+	    name[MAX_STRING-1] = 0;
+	    tok = strchr(name, ',');
+	    if (tok) {
+		*tok = 0;
+	    }
+	    fprintf(stderr,"Unknown flag (%s)\n",name);
+	    tok = strchr(flagsString, ',');
+	    if (tok == NULL)  {
+		break;
+	    }
+	    flagsString = tok+1;
+	}
+    }
+    return flagsValue;
+}
+
+CK_FLAGS
+GetOpFlags(char *flags)
+{
+    return GetFlags(flags, opFlagsArray, opFlagsCount);
+}
+
+PK11AttrFlags
+GetAttrFlags(char *flags)
+{
+    return GetFlags(flags, attrFlagsArray, attrFlagsCount);
+}
+
 char *mkNickname(unsigned char *data, int len)
 {
    char *nick = PORT_Alloc(len+1);
    if (!nick) {
 	return nick;
    }
    PORT_Memcpy(nick, data, len);
    nick[len] = 0;
@@ -2069,16 +2183,19 @@ enum certutilOpts {
     opt_AddSubjectKeyIDExt,
     opt_AddCmdKeyUsageExt,
     opt_AddCmdNSCertTypeExt,
     opt_AddCmdExtKeyUsageExt,
     opt_SourceDir,
     opt_SourcePrefix,
     opt_UpgradeID,
     opt_UpgradeTokenName,
+    opt_KeyOpFlagsOn,
+    opt_KeyOpFlagsOff,
+    opt_KeyAttrFlags,
     opt_Help
 };
 
 static const
 secuCommandFlag commands_init[] =
 {
 	{ /* cmd_AddCert             */  'A', PR_FALSE, 0, PR_FALSE },
 	{ /* cmd_CreateNewCert       */  'C', PR_FALSE, 0, PR_FALSE },
@@ -2170,16 +2287,22 @@ secuCommandFlag options_init[] =
 	{ /* opt_SourceDir           */  0,   PR_TRUE,  0, PR_FALSE,
                                                    "source-dir"},
 	{ /* opt_SourcePrefix        */  0,   PR_TRUE,  0, PR_FALSE, 
 						   "source-prefix"},
 	{ /* opt_UpgradeID           */  0,   PR_TRUE,  0, PR_FALSE, 
                                                    "upgrade-id"},
 	{ /* opt_UpgradeTokenName    */  0,   PR_TRUE,  0, PR_FALSE, 
                                                    "upgrade-token-name"},
+	{ /* opt_KeyOpFlagsOn        */  0,   PR_TRUE, 0, PR_FALSE, 
+                                                   "keyOpFlagsOn"},
+	{ /* opt_KeyOpFlagsOff       */  0,   PR_TRUE, 0, PR_FALSE, 
+                                                   "keyOpFlagsOff"},
+	{ /* opt_KeyAttrFlags        */  0,   PR_TRUE, 0, PR_FALSE, 
+                                                   "keyAttrFlags"},
 };
 #define NUM_OPTIONS ((sizeof options_init)  / (sizeof options_init[0]))
 
 static secuCommandFlag certutil_commands[NUM_COMMANDS];
 static secuCommandFlag certutil_options [NUM_OPTIONS ];
 
 static const secuCommand certutil = {
     NUM_COMMANDS, 
@@ -2217,16 +2340,20 @@ certutil_main(int argc, char **argv, PRB
     int         warpmonths      = 0;
     int         validityMonths  = 3;
     int         commandsEntered = 0;
     char        commandToRun    = '\0';
     secuPWData  pwdata          = { PW_NONE, 0 };
     secuPWData  pwdata2         = { PW_NONE, 0 };
     PRBool      readOnly        = PR_FALSE;
     PRBool      initialized     = PR_FALSE;
+    CK_FLAGS    keyOpFlagsOn = 0;
+    CK_FLAGS    keyOpFlagsOff = 0;
+    PK11AttrFlags    keyAttrFlags = 
+		PK11_ATTR_TOKEN | PK11_ATTR_SENSITIVE | PK11_ATTR_PRIVATE;
 
     SECKEYPrivateKey *privkey = NULL;
     SECKEYPublicKey *pubkey = NULL;
 
     int i;
     SECStatus rv;
 
     progName = PORT_Strrchr(argv[0], '/');
@@ -2339,16 +2466,27 @@ certutil_main(int argc, char **argv, PRB
 	} else {
 	    /* use an existing private/public key pair */
 	    keysource = arg;
 	}
     } else if (certutil.commands[cmd_ListKeys].activated) {
 	keytype = nullKey;
     }
 
+    if (certutil.options[opt_KeyOpFlagsOn].activated) {
+	keyOpFlagsOn = GetOpFlags(certutil.options[opt_KeyOpFlagsOn].arg);
+    }
+    if (certutil.options[opt_KeyOpFlagsOff].activated) {
+	keyOpFlagsOff = GetOpFlags(certutil.options[opt_KeyOpFlagsOff].arg);
+	keyOpFlagsOn &=~keyOpFlagsOff; /* make off override on */
+    }
+    if (certutil.options[opt_KeyAttrFlags].activated) {
+	keyAttrFlags = GetAttrFlags(certutil.options[opt_KeyAttrFlags].arg);
+    }
+
     /*  -m serial number */
     if (certutil.options[opt_SerialNumber].activated) {
 	int sn = PORT_Atoi(certutil.options[opt_SerialNumber].arg);
 	if (sn < 0) {
 	    PR_fprintf(PR_STDERR, "%s -m:  %s is not a valid serial number.\n",
 	               progName, certutil.options[opt_SerialNumber].arg);
 	    return 255;
 	}
@@ -2932,16 +3070,19 @@ merge_fail:
 	    CERT_DestroyCertificate(keycert);
 	} else {
 	    privkey = 
 		CERTUTIL_GeneratePrivateKey(keytype, slot, keysize,
 					    publicExponent, 
 					    certutil.options[opt_NoiseFile].arg,
 					    &pubkey, 
 					    certutil.options[opt_PQGFile].arg,
+					    keyAttrFlags,
+					    keyOpFlagsOn,
+					    keyOpFlagsOff,
 					    &pwdata);
 	    if (privkey == NULL) {
 		SECU_PrintError(progName, "unable to generate key(s)\n");
 		rv = SECFailure;
 		goto shutdown;
 	    }
 	}
 	privkey->wincx = &pwdata;
--- a/security/nss/cmd/certutil/certutil.h
+++ b/security/nss/cmd/certutil/certutil.h
@@ -8,16 +8,19 @@
 extern SECKEYPrivateKey *
 CERTUTIL_GeneratePrivateKey(KeyType keytype,
                             PK11SlotInfo *slot, 
                             int rsasize,
                             int publicExponent,
                             char *noise,
                             SECKEYPublicKey **pubkeyp,
                             char *pqgFile,
+                            PK11AttrFlags attrFlags,
+                            CK_FLAGS opFlagsOn,
+                            CK_FLAGS opFlagsOff,
                             secuPWData *pwdata);
 
 extern char *progName;
 
 enum certutilExtns {
     ext_keyUsage = 0,
     ext_basicConstraint,
     ext_authorityKeyID,
--- a/security/nss/cmd/certutil/keystuff.c
+++ b/security/nss/cmd/certutil/keystuff.c
@@ -485,17 +485,18 @@ getECParams(const char *curve)
     return ecparams;
 }
 #endif /* NSS_ENABLE_ECC */
 
 SECKEYPrivateKey *
 CERTUTIL_GeneratePrivateKey(KeyType keytype, PK11SlotInfo *slot, int size,
 			    int publicExponent, const char *noise, 
 			    SECKEYPublicKey **pubkeyp, const char *pqgFile,
-                            secuPWData *pwdata)
+			    PK11AttrFlags attrFlags, CK_FLAGS opFlagsOn,
+			    CK_FLAGS opFlagsOff, secuPWData *pwdata)
 {
     CK_MECHANISM_TYPE  mechanism;
     SECOidTag          algtag;
     PK11RSAGenParams   rsaparams;
     SECKEYPQGParams  * dsaparams = NULL;
     void             * params;
     SECKEYPrivateKey * privKey = NULL;
 
@@ -554,18 +555,18 @@ CERTUTIL_GeneratePrivateKey(KeyType keyt
 #endif /* NSS_ENABLE_ECC */
     default:
 	return NULL;
     }
 
     fprintf(stderr, "\n\n");
     fprintf(stderr, "Generating key.  This may take a few moments...\n\n");
 
-    privKey = PK11_GenerateKeyPair(slot, mechanism, params, pubkeyp,
-				PR_TRUE /*isPerm*/, PR_TRUE /*isSensitive*/, 
+    privKey = PK11_GenerateKeyPairWithOpFlags(slot, mechanism, params, pubkeyp,
+				attrFlags, opFlagsOn, opFlagsOn|opFlagsOff,
 				pwdata /*wincx*/);
     /* free up the params */
     switch (keytype) {
     case dsaKey: if (dsaparams) CERTUTIL_DestroyParamsPQG(dsaparams); 
 	                                                      break;
 #ifdef NSS_ENABLE_ECC
     case ecKey: SECITEM_FreeItem((SECItem *)params, PR_TRUE); break;
 #endif
--- a/security/nss/cmd/lib/secutil.c
+++ b/security/nss/cmd/lib/secutil.c
@@ -516,19 +516,19 @@ SECU_ReadDERFromFile(SECItem *der, PRFil
 	if ((body = strstr(asc, "-----BEGIN")) != NULL) {
 	    char *trailer = NULL;
 	    asc = body;
 	    body = PORT_Strchr(body, '\n');
 	    if (!body)
 		body = PORT_Strchr(asc, '\r'); /* maybe this is a MAC file */
 	    if (body)
 		trailer = strstr(++body, "-----END");
-	    if (trailer != NULL)
+	    if (trailer != NULL) {
 		*trailer = '\0';
-	    if (!body || !trailer) {
+	    } else {
 		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);
 	    if (rv != SECSuccess) {
--- 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/certhigh/ocsp.c
+++ b/security/nss/lib/certhigh/ocsp.c
@@ -134,17 +134,17 @@ ocsp_GetVerifiedSingleResponseForCertID(
                                         CERTCertificate  *signerCert,
                                         PRTime            time,
                                         CERTOCSPSingleResponse **pSingleResponse);
 
 static SECStatus
 ocsp_CertRevokedAfter(ocspRevokedInfo *revokedInfo, PRTime time);
 
 static CERTOCSPCertID *
-cert_DupOCSPCertID(CERTOCSPCertID *src);
+cert_DupOCSPCertID(const CERTOCSPCertID *src);
 
 #ifndef DEBUG
 #define OCSP_TRACE(msg)
 #define OCSP_TRACE_TIME(msg, time)
 #define OCSP_TRACE_CERT(cert)
 #define OCSP_TRACE_CERTID(certid)
 #else
 #define OCSP_TRACE(msg) ocsp_Trace msg
@@ -777,17 +777,17 @@ ocsp_CreateOrUpdateCacheEntry(OCSPCacheD
                               CERTOCSPSingleResponse *single,
                               PRBool *certIDWasConsumed)
 {
     SECStatus rv;
     OCSPCacheItem *cacheItem;
     OCSP_TRACE(("OCSP ocsp_CreateOrUpdateCacheEntry\n"));
   
     if (certIDWasConsumed)
-    *certIDWasConsumed = PR_FALSE;
+        *certIDWasConsumed = PR_FALSE;
   
     PR_EnterMonitor(OCSP_Global.monitor);
     PORT_Assert(OCSP_Global.maxCacheEntries >= 0);
   
     cacheItem = ocsp_FindCacheEntry(cache, certID);
     if (!cacheItem) {
         CERTOCSPCertID *myCertID;
         if (certIDWasConsumed) {
@@ -817,17 +817,18 @@ ocsp_CreateOrUpdateCacheEntry(OCSPCacheD
             (rv == SECSuccess && cacheItem->thisUpdate < thisUpdate)) {
             rv = ocsp_SetCacheItemResponse(cacheItem, single);
             if (rv != SECSuccess) {
                 ocsp_RemoveCacheItem(cache, cacheItem);
                 PR_ExitMonitor(OCSP_Global.monitor);
                 return rv;
             }
         } else {
-            OCSP_TRACE(("Not caching response because the response is not newer than the cache"));
+            OCSP_TRACE(("Not caching response because the response is not "
+                        "newer than the cache"));
         }
     } else {
         cacheItem->missingResponseError = PORT_GetError();
         if (cacheItem->certStatusArena) {
             PORT_FreeArena(cacheItem->certStatusArena, PR_FALSE);
             cacheItem->certStatusArena = NULL;
         }
     }
@@ -1773,39 +1774,39 @@ CERT_CreateOCSPCertID(CERTCertificate *c
 	PORT_FreeArena(arena, PR_FALSE);
 	return NULL;
     }
     certID->poolp = arena;
     return certID;
 }
 
 static CERTOCSPCertID *
-cert_DupOCSPCertID(CERTOCSPCertID *src)
+cert_DupOCSPCertID(const CERTOCSPCertID *src)
 {
     CERTOCSPCertID *dest;
     PLArenaPool *arena = NULL;
 
     if (!src) {
         PORT_SetError(SEC_ERROR_INVALID_ARGS);
         return NULL;
     }
 
     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
     if (!arena)
         goto loser;
 
     dest = PORT_ArenaZNew(arena, CERTOCSPCertID);
-      if (!dest)
+    if (!dest)
         goto loser;
 
 #define DUPHELP(element) \
-    if (src->element.data) {  \
-        if (SECITEM_CopyItem(arena, &dest->element, &src->element) \
-            != SECSuccess) \
-            goto loser;     \
+    if (src->element.data && \
+        SECITEM_CopyItem(arena, &dest->element, &src->element) \
+        != SECSuccess) { \
+        goto loser; \
     }
 
     DUPHELP(hashAlgorithm.algorithm)
     DUPHELP(hashAlgorithm.parameters)
     DUPHELP(issuerNameHash)
     DUPHELP(issuerKeyHash)
     DUPHELP(serialNumber)
     DUPHELP(issuerSHA1NameHash)
--- a/security/nss/lib/dbm/src/config.mk
+++ b/security/nss/lib/dbm/src/config.mk
@@ -1,15 +1,15 @@
 #! gmake
 #
 # 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/.
 
-DEFINES += -DMEMMOVE -D__DBINTERFACE_PRIVATE $(SECURITY_FLAG)
+DEFINES += -DMEMMOVE -D__DBINTERFACE_PRIVATE
 
 #
 #  Currently, override TARGETS variable so that only static libraries
 #  are specifed as dependencies within rules.mk.
 #
 
 TARGETS        = $(LIBRARY)
 SHARED_LIBRARY =
--- a/security/nss/lib/ssl/ssl3con.c
+++ b/security/nss/lib/ssl/ssl3con.c
@@ -35,16 +35,17 @@
 #include "zlib.h"
 #endif
 
 #ifndef PK11_SETATTRS
 #define PK11_SETATTRS(x,id,v,l) (x)->type = (id); \
 		(x)->pValue=(v); (x)->ulValueLen = (l);
 #endif
 
+static SECStatus ssl3_AuthCertificate(sslSocket *ss);
 static void      ssl3_CleanupPeerCerts(sslSocket *ss);
 static PK11SymKey *ssl3_GenerateRSAPMS(sslSocket *ss, ssl3CipherSpec *spec,
                                        PK11SlotInfo * serverKeySlot);
 static SECStatus ssl3_DeriveMasterSecret(sslSocket *ss, PK11SymKey *pms);
 static SECStatus ssl3_DeriveConnectionKeysPKCS11(sslSocket *ss);
 static SECStatus ssl3_HandshakeFailure(      sslSocket *ss);
 static SECStatus ssl3_InitState(             sslSocket *ss);
 static SECStatus ssl3_SendCertificate(       sslSocket *ss);
@@ -8515,17 +8516,24 @@ ssl3_CleanupPeerCerts(sslSocket *ss)
  * Caller must hold Handshake and RecvBuf locks.
  * This is always called before ssl3_HandleCertificate, even if the Certificate
  * message is sent first.
  */
 static SECStatus
 ssl3_HandleCertificateStatus(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
 {
     PRInt32 status, len;
-    PORT_Assert(ss->ssl3.hs.ws == wait_certificate_status);
+
+    if (ss->ssl3.hs.ws != wait_certificate_status) {
+        (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message);
+        PORT_SetError(SSL_ERROR_RX_UNEXPECTED_CERT_STATUS);
+        return SECFailure;
+    }
+
+    PORT_Assert(!ss->sec.isServer);
 
     /* Consume the CertificateStatusType enum */
     status = ssl3_ConsumeHandshakeNumber(ss, 1, &b, &length);
     if (status != 1 /* ocsp */) {
        goto format_loser;
     }
 
     len = ssl3_ConsumeHandshakeNumber(ss, 3, &b, &length);
@@ -8548,24 +8556,23 @@ ssl3_HandleCertificateStatus(sslSocket *
     if (!ss->sec.ci.sid->peerCertStatus.items[0].data) {
         SECITEM_FreeArray(&ss->sec.ci.sid->peerCertStatus, PR_FALSE);
         return SECFailure;
     }
 
     PORT_Memcpy(ss->sec.ci.sid->peerCertStatus.items[0].data, b, length);
     ss->sec.ci.sid->peerCertStatus.items[0].len = length;
     ss->sec.ci.sid->peerCertStatus.items[0].type = siBuffer;
-    return SECSuccess;
+
+    return ssl3_AuthCertificate(ss);
 
 format_loser:
     return ssl3_DecodeError(ss);
 }
 
-static SECStatus ssl3_AuthCertificate(sslSocket *ss);
-
 /* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete
  * ssl3 Certificate message.
  * Caller must hold Handshake and RecvBuf locks.
  */
 static SECStatus
 ssl3_HandleCertificate(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
 {
     ssl3CertNode *   c;
@@ -9542,40 +9549,28 @@ ssl3_HandleHandshakeMessage(sslSocket *s
 
 	/* The message body */
 	rv = ssl3_UpdateHandshakeHashes(ss, b, length);
 	if (rv != SECSuccess) return rv;	/* err code already set. */
     }
 
     PORT_SetError(0);	/* each message starts with no error. */
 
-    /* The CertificateStatus message is optional. We process the message if we
-     * get one when it is allowed, but otherwise we just carry on.
-     */
-    if (ss->ssl3.hs.ws == wait_certificate_status) {
-        /* We must process any CertificateStatus message before we call
-         * ssl3_AuthCertificate, as ssl3_AuthCertificate needs any stapled
-         * OCSP response we get.
-         */
-        if (ss->ssl3.hs.msg_type == certificate_status) {
-            rv = ssl3_HandleCertificateStatus(ss, b, length);
-            if (rv != SECSuccess)
-                return rv;
-            if (IS_DTLS(ss)) {
-                /* Increment the expected sequence number */
-                ss->ssl3.hs.recvMessageSeq++;
-            }
-        }
-
-        /* Regardless of whether we got a CertificateStatus message, we must
-         * authenticate the cert before we handle any more handshake messages.
+    if (ss->ssl3.hs.ws == wait_certificate_status &&
+        ss->ssl3.hs.msg_type != certificate_status) {
+        /* If we negotiated the certificate_status extension then we deferred
+         * certificate validation until we get the CertificateStatus messsage.
+         * But the CertificateStatus message is optional. If the server did
+         * not send it then we need to validate the certificate now. If the
+         * server does send the CertificateStatus message then we will
+         * authenticate the certificate in ssl3_HandleCertificateStatus.
          */
         rv = ssl3_AuthCertificate(ss); /* sets ss->ssl3.hs.ws */
         PORT_Assert(rv != SECWouldBlock);
-        if (rv != SECSuccess || ss->ssl3.hs.msg_type == certificate_status) {
+        if (rv != SECSuccess) {
             return rv;
         }
     }
 
     switch (ss->ssl3.hs.msg_type) {
     case hello_request:
 	if (length != 0) {
 	    (void)ssl3_DecodeError(ss);
@@ -9612,20 +9607,18 @@ ssl3_HandleHandshakeMessage(sslSocket *s
 	    return SECFailure;
 	}
 	rv = dtls_HandleHelloVerifyRequest(ss, b, length);
 	break;
     case certificate:
 	rv = ssl3_HandleCertificate(ss, b, length);
 	break;
     case certificate_status:
-	/* The good case is handled above */
-	(void)SSL3_SendAlert(ss, alert_fatal, unexpected_message);
-	PORT_SetError(SSL_ERROR_RX_UNEXPECTED_CERT_STATUS);
-	return SECFailure;
+	rv = ssl3_HandleCertificateStatus(ss, b, length);
+	break;
     case server_key_exchange:
 	if (ss->sec.isServer) {
 	    (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message);
 	    PORT_SetError(SSL_ERROR_RX_UNEXPECTED_SERVER_KEY_EXCH);
 	    return SECFailure;
 	}
 	rv = ssl3_HandleServerKeyExchange(ss, b, length);
 	break;
--- 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,76 @@ 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) {
+	if (!arena) {
+	    PORT_Free(item->data);
+	}
+	item->data = NULL;
+	item->len = 0;
+	return SECSuccess;
+    }
+    
+    if (!item->data) {
+	/* allocate fresh block of memory */
+	PORT_Assert(!item->len);
+	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;
+	    }
+	    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;
@@ -361,17 +421,17 @@ loser:
 static void
 secitem_FreeArray(SECItemArray *array, PRBool zero_items, PRBool freeit)
 {
     unsigned int i;
 
     if (!array || !array->len || !array->items)
         return;
 
-    for (i=0; i<array->len; ++i) {
+    for (i = 0; i < array->len; ++i) {
         SECItem *item = &array->items[i];
 
         if (item->data) {
             if (zero_items) {
                 SECITEM_ZfreeItem(item, PR_FALSE);
             } else {
                 SECITEM_FreeItem(item, PR_FALSE);
             }
@@ -396,24 +456,28 @@ void SECITEM_ZfreeArray(SECItemArray *ar
 }
 
 SECItemArray *
 SECITEM_DupArray(PLArenaPool *arena, const SECItemArray *from)
 {
     SECItemArray *result;
     unsigned int i;
 
-    if (!from || !from->items || !from->len)
+    /* Require a "from" array.
+     * Reject an inconsistent "from" array with NULL data and nonzero length.
+     * However, allow a "from" array of zero length.
+     */
+    if (!from || (!from->items && from->len))
         return NULL;
 
     result = SECITEM_AllocArray(arena, NULL, from->len);
     if (!result)
         return NULL;
 
-    for (i=0; i<from->len; ++i) {
+    for (i = 0; i < from->len; ++i) {
         SECStatus rv = SECITEM_CopyItem(arena,
                                         &result->items[i], &from->items[i]);
         if (rv != SECSuccess) {
             SECITEM_ZfreeArray(result, PR_TRUE);
             return NULL;
         }
     }
 
--- a/security/nss/lib/util/secitem.h
+++ b/security/nss/lib/util/secitem.h
@@ -31,27 +31,44 @@ 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 item->data is NULL, 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, 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);
@@ -86,15 +103,16 @@ extern void SECITEM_ZfreeItem(SECItem *z
 
 PLHashNumber PR_CALLBACK SECITEM_Hash ( const void *key);
 
 PRIntn PR_CALLBACK SECITEM_HashCompare ( const void *k1, const void *k2);
 
 extern SECItemArray *SECITEM_AllocArray(PLArenaPool *arena,
                                         SECItemArray *array,
                                         unsigned int len);
-extern SECItemArray *SECITEM_DupArray(PLArenaPool *arena, const SECItemArray *from);
+extern SECItemArray *SECITEM_DupArray(PLArenaPool *arena,
+                                      const SECItemArray *from);
 extern void SECITEM_FreeArray(SECItemArray *array, PRBool freeit);
 extern void SECITEM_ZfreeArray(SECItemArray *array, PRBool freeit);
 
 SEC_END_PROTOS
 
 #endif /* _SECITEM_H_ */
--- a/security/patches/revert-bug-808217.patch
+++ b/security/patches/revert-bug-808217.patch
@@ -38,152 +38,8 @@ diff --git a/cmd/lib/secutil.c b/cmd/lib
  	    if (rv != SECSuccess) {
  		PORT_Free(filedata.data);
  		return rv;
  	    }
  	    body = (char*)filedata.data;
  	    body[filedata.len-1] = '\0';
  	}
       
-diff --git a/lib/util/nssutil.def b/lib/util/nssutil.def
---- a/lib/util/nssutil.def
-+++ b/lib/util/nssutil.def
-@@ -261,13 +261,12 @@ NSSUTIL_QuoteSize;
- ;+    local:
- ;+       *;
- ;+};
- ;+NSSUTIL_3.15 {         # NSS Utilities 3.15 release
- ;+    global:
- SECITEM_AllocArray;
- SECITEM_DupArray;
- SECITEM_FreeArray;
--SECITEM_ReallocItemV2;
- SECITEM_ZfreeArray;
- ;+    local:
- ;+       *;
- ;+};
-diff --git a/lib/util/secitem.c b/lib/util/secitem.c
---- a/lib/util/secitem.c
-+++ b/lib/util/secitem.c
-@@ -110,73 +110,16 @@ 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;
-diff --git a/lib/util/secitem.h b/lib/util/secitem.h
---- a/lib/util/secitem.h
-+++ b/lib/util/secitem.h
-@@ -31,45 +31,27 @@ 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( /* deprecated function */
--				     PLArenaPool *arena, SECItem *item,
-+extern SECStatus SECITEM_ReallocItem(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);