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