Index: nss/mozilla/security/nss/lib/softoken/legacydb/keydb.c
===================================================================
--- nss.orig/mozilla/security/nss/lib/softoken/legacydb/keydb.c	2012-06-02 09:40:33.313201758 +0200
+++ nss/mozilla/security/nss/lib/softoken/legacydb/keydb.c	2012-06-02 09:44:24.107462120 +0200
@@ -1790,6 +1790,35 @@
 		rv = SEC_QuickDERDecodeItem(permarena, pk,
 					nsslowkey_RSAPrivateKeyTemplate,
 					&newPrivateKey);
+		if (rv == SECSuccess) {
+		    break;
+		}
+		/* Try decoding with the alternative template, but only allow
+		 * a zero-length modulus for a secret key object.
+		 * See bug 715073.
+		 */
+		rv = SEC_QuickDERDecodeItem(permarena, pk,
+					nsslowkey_RSAPrivateKeyTemplate2,
+					&newPrivateKey);
+		/* A publicExponent of 0 is the defining property of a secret
+		 * key disguised as an RSA key. When decoding with the
+		 * alternative template, only accept a secret key with an
+		 * improperly encoded modulus and a publicExponent of 0.
+		 */
+		if (rv == SECSuccess) {
+		    if (pk->u.rsa.modulus.len == 2 &&
+			pk->u.rsa.modulus.data[0] == SEC_ASN1_INTEGER &&
+			pk->u.rsa.modulus.data[1] == 0 &&
+			pk->u.rsa.publicExponent.len == 1 &&
+			pk->u.rsa.publicExponent.data[0] == 0) {
+			/* Fix the zero-length integer by setting it to 0. */
+			pk->u.rsa.modulus.data = pk->u.rsa.publicExponent.data;
+			pk->u.rsa.modulus.len = pk->u.rsa.publicExponent.len;
+		    } else {
+			PORT_SetError(SEC_ERROR_BAD_DER);
+			rv = SECFailure;
+		    }
+		}
 		break;
 	      case SEC_OID_ANSIX9_DSA_SIGNATURE:
 		pk->keyType = NSSLOWKEYDSAKey;
Index: nss/mozilla/security/nss/lib/softoken/legacydb/lgcreate.c
===================================================================
--- nss.orig/mozilla/security/nss/lib/softoken/legacydb/lgcreate.c	2012-06-02 09:40:33.313201758 +0200
+++ nss/mozilla/security/nss/lib/softoken/legacydb/lgcreate.c	2012-06-02 09:42:35.354166672 +0200
@@ -818,11 +818,16 @@
     privKey->keyType = NSSLOWKEYRSAKey;
 
     /* The modulus is set to the key id of the symmetric key */
-    crv = lg_Attribute2SecItem(arena, CKA_ID, templ, count, 
-				&privKey->u.rsa.modulus);
-    if (crv != CKR_OK) goto loser;
+    privKey->u.rsa.modulus.data =
+		(unsigned char *) PORT_ArenaAlloc(arena, pubkey->len);
+    if (privKey->u.rsa.modulus.data == NULL) {
+	crv = CKR_HOST_MEMORY;
+	goto loser;
+    }
+    privKey->u.rsa.modulus.len = pubkey->len;
+    PORT_Memcpy(privKey->u.rsa.modulus.data, pubkey->data, pubkey->len);
 
-    /* The public exponent is set to 0 length to indicate a special key */
+    /* The public exponent is set to 0 to indicate a special key */
     privKey->u.rsa.publicExponent.len = sizeof derZero;
     privKey->u.rsa.publicExponent.data = derZero;
 
Index: nss/mozilla/security/nss/lib/softoken/legacydb/lowkey.c
===================================================================
--- nss.orig/mozilla/security/nss/lib/softoken/legacydb/lowkey.c	2012-06-02 09:40:33.317201659 +0200
+++ nss/mozilla/security/nss/lib/softoken/legacydb/lowkey.c	2012-06-02 09:45:10.962296923 +0200
@@ -97,6 +97,24 @@
     { 0 }                                                                     
 };                                                                            
 
+/*
+ * Allows u.rsa.modulus to be zero length for secret keys with an empty
+ * CKA_ID incorrectly generated in NSS 3.13.3 or earlier.  Only used for
+ * decoding.  See bug 715073.
+ */
+const SEC_ASN1Template nsslowkey_RSAPrivateKeyTemplate2[] = {
+    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSLOWKEYPrivateKey) },
+    { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.rsa.version) },
+    { SEC_ASN1_ANY, offsetof(NSSLOWKEYPrivateKey,u.rsa.modulus) },
+    { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.rsa.publicExponent) },
+    { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.rsa.privateExponent) },
+    { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.rsa.prime1) },
+    { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.rsa.prime2) },
+    { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.rsa.exponent1) },
+    { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.rsa.exponent2) },
+    { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.rsa.coefficient) },
+    { 0 }
+};
 
 const SEC_ASN1Template nsslowkey_DSAPrivateKeyTemplate[] = {
     { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSLOWKEYPrivateKey) },
Index: nss/mozilla/security/nss/lib/softoken/legacydb/lowkeyti.h
===================================================================
--- nss.orig/mozilla/security/nss/lib/softoken/legacydb/lowkeyti.h	2012-06-02 09:40:33.317201659 +0200
+++ nss/mozilla/security/nss/lib/softoken/legacydb/lowkeyti.h	2012-06-02 09:43:25.700914607 +0200
@@ -72,6 +72,7 @@
 */
 extern const SEC_ASN1Template nsslowkey_PQGParamsTemplate[];
 extern const SEC_ASN1Template nsslowkey_RSAPrivateKeyTemplate[];
+extern const SEC_ASN1Template nsslowkey_RSAPrivateKeyTemplate2[];
 extern const SEC_ASN1Template nsslowkey_DSAPrivateKeyTemplate[];
 extern const SEC_ASN1Template nsslowkey_DSAPrivateKeyExportTemplate[];
 extern const SEC_ASN1Template nsslowkey_DHPrivateKeyTemplate[];
Index: nss/mozilla/security/nss/lib/util/quickder.c
===================================================================
--- nss.orig/mozilla/security/nss/lib/util/quickder.c	2012-06-02 09:40:33.341201062 +0200
+++ nss/mozilla/security/nss/lib/util/quickder.c	2012-06-02 09:42:36.418140213 +0200
@@ -815,40 +815,57 @@
             SECItem newtemp = temp;
             rv = GetItem(&newtemp, &temp, PR_FALSE);
             save = PR_TRUE;
-            if ((SECSuccess == rv) && SEC_ASN1_UNIVERSAL == (kind & SEC_ASN1_CLASS_MASK))
-            switch (kind & SEC_ASN1_TAGNUM_MASK)
+            if ((SECSuccess == rv) &&
+                SEC_ASN1_UNIVERSAL == (kind & SEC_ASN1_CLASS_MASK))
             {
-            /* special cases of primitive types */
-            case SEC_ASN1_INTEGER:
+                unsigned long tagnum = kind & SEC_ASN1_TAGNUM_MASK;
+                if ( temp.len == 0 && (tagnum == SEC_ASN1_BOOLEAN ||
+                                       tagnum == SEC_ASN1_INTEGER ||
+                                       tagnum == SEC_ASN1_BIT_STRING ||
+                                       tagnum == SEC_ASN1_OBJECT_ID ||
+                                       tagnum == SEC_ASN1_ENUMERATED ||
+                                       tagnum == SEC_ASN1_UTC_TIME ||
+                                       tagnum == SEC_ASN1_GENERALIZED_TIME) )
                 {
-                    /* remove leading zeroes if the caller requested siUnsignedInteger
-                       This is to allow RSA key operations to work */
-                    SECItem* destItem = (SECItem*) ((char*)dest + templateEntry->offset);
-                    if (destItem && (siUnsignedInteger == destItem->type))
+                    /* these types MUST have at least one content octet */
+                    PORT_SetError(SEC_ERROR_BAD_DER);
+                    rv = SECFailure;
+                }
+                else
+                switch (tagnum)
+                {
+                /* special cases of primitive types */
+                case SEC_ASN1_INTEGER:
                     {
-                        while (temp.len > 1 && temp.data[0] == 0)
-                        {              /* leading 0 */
-                            temp.data++;
-                            temp.len--;
+                        /* remove leading zeroes if the caller requested
+                           siUnsignedInteger
+                           This is to allow RSA key operations to work */
+                        SECItem* destItem = (SECItem*) ((char*)dest +
+                                            templateEntry->offset);
+                        if (destItem && (siUnsignedInteger == destItem->type))
+                        {
+                            while (temp.len > 1 && temp.data[0] == 0)
+                            {              /* leading 0 */
+                                temp.data++;
+                                temp.len--;
+                            }
                         }
+                        break;
                     }
-                    break;
-                }
 
-            case SEC_ASN1_BIT_STRING:
-                {
-                    /* change the length in the SECItem to be the number of bits */
-                    if (temp.len && temp.data)
+                case SEC_ASN1_BIT_STRING:
                     {
-                        temp.len = (temp.len-1)*8 - ((*(unsigned char*)temp.data) & 0x7);
-                        temp.data = (unsigned char*)(temp.data+1);
+                        /* change the length in the SECItem to be the number
+                           of bits */
+                        temp.len = (temp.len-1)*8 - (temp.data[0] & 0x7);
+                        temp.data++;
+                        break;
                     }
-                    break;
-                }
 
-            default:
-                {
-                    break;
+                default:
+                    {
+                        break;
+                    }
                 }
             }
         }
@@ -863,7 +880,7 @@
                If part of the destination was allocated by the decoder, in
                cases of POINTER, SET OF and SEQUENCE OF, then type is set to
                siBuffer due to the use of PORT_ArenaZAlloc*/
-            destItem->data = temp.data;
+            destItem->data = temp.len ? temp.data : NULL;
             destItem->len = temp.len;
         }
         else
