From ce2943e83c291d50e9a2acc3f14e80dd8ab27d2c Mon Sep 17 00:00:00 2001 From: "nelson%bolyard.com" Date: Wed, 15 Apr 2009 08:36:58 +0000 Subject: Bug 488241: Fix cert7/cert8.db issues with large issuer names in NSS_3_11_BRANCH as well Patch contributed by Kaspar Brand --- security/nss/lib/softoken/lowcert.c | 4 + security/nss/lib/softoken/pcertdb.c | 335 +++++++++++++++++++----------------- security/nss/lib/softoken/pcertt.h | 2 + 3 files changed, 185 insertions(+), 156 deletions(-) diff --git a/security/nss/lib/softoken/lowcert.c b/security/nss/lib/softoken/lowcert.c index 008687e52..629cfe3ce 100644 --- a/security/nss/lib/softoken/lowcert.c +++ b/security/nss/lib/softoken/lowcert.c @@ -369,6 +369,10 @@ nsslowcert_KeyFromIssuerAndSN(PRArenaPool *arena, PORT_SetError(SEC_ERROR_INVALID_ARGS); goto loser; } + if (len > NSS_MAX_LEGACY_DB_KEY_SIZE) { + PORT_SetError(SEC_ERROR_INPUT_LEN); + goto loser; + } key->data = (unsigned char*)PORT_ArenaAlloc(arena, len); if ( !key->data ) { goto loser; diff --git a/security/nss/lib/softoken/pcertdb.c b/security/nss/lib/softoken/pcertdb.c index 6630b6134..ad8fd0b23 100644 --- a/security/nss/lib/softoken/pcertdb.c +++ b/security/nss/lib/softoken/pcertdb.c @@ -649,16 +649,16 @@ EncodeDBCertEntry(certDBEntryCert *entry, PRArenaPool *arena, SECItem *dbitem) /* fill in database record */ buf = &dbitem->data[SEC_DB_ENTRY_HEADER_LEN]; - buf[0] = ( entry->trust.sslFlags >> 8 ) & 0xff; - buf[1] = entry->trust.sslFlags & 0xff; - buf[2] = ( entry->trust.emailFlags >> 8 ) & 0xff; - buf[3] = entry->trust.emailFlags & 0xff; - buf[4] = ( entry->trust.objectSigningFlags >> 8 ) & 0xff; - buf[5] = entry->trust.objectSigningFlags & 0xff; - buf[6] = ( entry->derCert.len >> 8 ) & 0xff; - buf[7] = entry->derCert.len & 0xff; - buf[8] = ( nnlen >> 8 ) & 0xff; - buf[9] = nnlen & 0xff; + buf[0] = (PRUint8)( entry->trust.sslFlags >> 8 ); + buf[1] = (PRUint8)( entry->trust.sslFlags ); + buf[2] = (PRUint8)( entry->trust.emailFlags >> 8 ); + buf[3] = (PRUint8)( entry->trust.emailFlags ); + buf[4] = (PRUint8)( entry->trust.objectSigningFlags >> 8 ); + buf[5] = (PRUint8)( entry->trust.objectSigningFlags ); + buf[6] = (PRUint8)( entry->derCert.len >> 8 ); + buf[7] = (PRUint8)( entry->derCert.len ); + buf[8] = (PRUint8)( nnlen >> 8 ); + buf[9] = (PRUint8)( nnlen ); PORT_Memcpy(&buf[DB_CERT_ENTRY_HEADER_LEN], entry->derCert.data, entry->derCert.len); @@ -679,6 +679,8 @@ static SECStatus EncodeDBCertKey(SECItem *certKey, PRArenaPool *arena, SECItem *dbkey) { unsigned int len = certKey->len + SEC_DB_KEY_HEADER_LEN; + if (len > NSS_MAX_LEGACY_DB_KEY_SIZE) + goto loser; if (arena) { dbkey->data = (unsigned char *)PORT_ArenaAlloc(arena, len); } else { @@ -718,12 +720,14 @@ EncodeDBGenericKey(SECItem *certKey, PRArenaPool *arena, SECItem *dbkey, dbkey->len = certKey->len + SEC_DB_KEY_HEADER_LEN; + if (dbkey->len > NSS_MAX_LEGACY_DB_KEY_SIZE) + goto loser; dbkey->data = (unsigned char *)PORT_ArenaAlloc(arena, dbkey->len); if ( dbkey->data == NULL ) { goto loser; } PORT_Memcpy(&dbkey->data[SEC_DB_KEY_HEADER_LEN], - certKey->data, certKey->len); + certKey->data, certKey->len); dbkey->data[0] = (unsigned char) entryType; return(SECSuccess); @@ -773,14 +777,17 @@ DecodeDBCertEntry(certDBEntryCert *entry, SECItem *dbentry) entry->derCert.len = ( ( dbentry->data[lenoff] << 8 ) | dbentry->data[lenoff+1] ); nnlen = ( ( dbentry->data[lenoff+2] << 8 ) | dbentry->data[lenoff+3] ); - if ( ( entry->derCert.len + nnlen + headerlen ) - != dbentry->len) { - PORT_SetError(SEC_ERROR_BAD_DATABASE); - goto loser; + lenoff = dbentry->len - ( entry->derCert.len + nnlen + headerlen ); + if ( lenoff ) { + if ( lenoff < 0 || (lenoff & 0xffff) != 0 ) { + PORT_SetError(SEC_ERROR_BAD_DATABASE); + goto loser; + } + /* The cert size exceeded 64KB. Reconstruct the correct length. */ + entry->derCert.len += lenoff; } /* copy the dercert */ - entry->derCert.data = pkcs11_copyStaticData(&dbentry->data[headerlen], entry->derCert.len,entry->derCertSpace,sizeof(entry->derCertSpace)); if ( entry->derCert.data == NULL ) { @@ -1165,10 +1172,10 @@ EncodeDBCrlEntry(certDBEntryRevocation *entry, PRArenaPool *arena, SECItem *dbit /* fill in database record */ buf = &dbitem->data[SEC_DB_ENTRY_HEADER_LEN]; - buf[0] = ( entry->derCrl.len >> 8 ) & 0xff; - buf[1] = entry->derCrl.len & 0xff; - buf[2] = ( nnlen >> 8 ) & 0xff; - buf[3] = nnlen & 0xff; + buf[0] = (PRUint8)( entry->derCrl.len >> 8 ); + buf[1] = (PRUint8)( entry->derCrl.len ); + buf[2] = (PRUint8)( nnlen >> 8 ); + buf[3] = (PRUint8)( nnlen ); PORT_Memcpy(&buf[DB_CRL_ENTRY_HEADER_LEN], entry->derCrl.data, entry->derCrl.len); @@ -1187,8 +1194,9 @@ loser: static SECStatus DecodeDBCrlEntry(certDBEntryRevocation *entry, SECItem *dbentry) { - unsigned int nnlen; - + unsigned int urlLen; + int lenDiff; + /* is record long enough for header? */ if ( dbentry->len < DB_CRL_ENTRY_HEADER_LEN ) { PORT_SetError(SEC_ERROR_BAD_DATABASE); @@ -1197,20 +1205,19 @@ DecodeDBCrlEntry(certDBEntryRevocation *entry, SECItem *dbentry) /* is database entry correct length? */ entry->derCrl.len = ( ( dbentry->data[0] << 8 ) | dbentry->data[1] ); - nnlen = ( ( dbentry->data[2] << 8 ) | dbentry->data[3] ); - if ( ( entry->derCrl.len + nnlen + DB_CRL_ENTRY_HEADER_LEN ) - != dbentry->len) { - /* CRL entry is greater than 64 K. Hack to make this continue to work */ - if (dbentry->len >= (0xffff - DB_CRL_ENTRY_HEADER_LEN) - nnlen) { - entry->derCrl.len = - (dbentry->len - DB_CRL_ENTRY_HEADER_LEN) - nnlen; - } else { - PORT_SetError(SEC_ERROR_BAD_DATABASE); - goto loser; - } + urlLen = ( ( dbentry->data[2] << 8 ) | dbentry->data[3] ); + lenDiff = dbentry->len - + (entry->derCrl.len + urlLen + DB_CRL_ENTRY_HEADER_LEN); + if (lenDiff) { + if (lenDiff < 0 || (lenDiff & 0xffff) != 0) { + PORT_SetError(SEC_ERROR_BAD_DATABASE); + goto loser; + } + /* CRL entry is greater than 64 K. Hack to make this continue to work */ + entry->derCrl.len += lenDiff; } - /* copy the dercert */ + /* copy the der CRL */ entry->derCrl.data = (unsigned char *)PORT_ArenaAlloc(entry->common.arena, entry->derCrl.len); if ( entry->derCrl.data == NULL ) { @@ -1222,15 +1229,15 @@ DecodeDBCrlEntry(certDBEntryRevocation *entry, SECItem *dbentry) /* copy the url */ entry->url = NULL; - if (nnlen != 0) { - entry->url = (char *)PORT_ArenaAlloc(entry->common.arena, nnlen); + if (urlLen != 0) { + entry->url = (char *)PORT_ArenaAlloc(entry->common.arena, urlLen); if ( entry->url == NULL ) { PORT_SetError(SEC_ERROR_NO_MEMORY); goto loser; } PORT_Memcpy(entry->url, &dbentry->data[DB_CRL_ENTRY_HEADER_LEN + entry->derCrl.len], - nnlen); + urlLen); } return(SECSuccess); @@ -1461,7 +1468,6 @@ EncodeDBNicknameEntry(certDBEntryNickname *entry, PRArenaPool *arena, */ dbitem->len = entry->subjectName.len + DB_NICKNAME_ENTRY_HEADER_LEN + SEC_DB_ENTRY_HEADER_LEN; - dbitem->data = (unsigned char *)PORT_ArenaAlloc(arena, dbitem->len); if ( dbitem->data == NULL) { goto loser; @@ -1469,10 +1475,8 @@ EncodeDBNicknameEntry(certDBEntryNickname *entry, PRArenaPool *arena, /* fill in database record */ buf = &dbitem->data[SEC_DB_ENTRY_HEADER_LEN]; - - buf[0] = ( entry->subjectName.len >> 8 ) & 0xff; - buf[1] = entry->subjectName.len & 0xff; - + buf[0] = (PRUint8)( entry->subjectName.len >> 8 ); + buf[1] = (PRUint8)( entry->subjectName.len ); PORT_Memcpy(&buf[DB_NICKNAME_ENTRY_HEADER_LEN], entry->subjectName.data, entry->subjectName.len); @@ -1495,6 +1499,8 @@ EncodeDBNicknameKey(char *nickname, PRArenaPool *arena, /* now get the database key and format it */ dbkey->len = nnlen + SEC_DB_KEY_HEADER_LEN; + if (dbkey->len > NSS_MAX_LEGACY_DB_KEY_SIZE) + goto loser; dbkey->data = (unsigned char *)PORT_ArenaAlloc(arena, dbkey->len); if ( dbkey->data == NULL ) { goto loser; @@ -1512,6 +1518,8 @@ static SECStatus DecodeDBNicknameEntry(certDBEntryNickname *entry, SECItem *dbentry, char *nickname) { + int lenDiff; + /* is record long enough for header? */ if ( dbentry->len < DB_NICKNAME_ENTRY_HEADER_LEN ) { PORT_SetError(SEC_ERROR_BAD_DATABASE); @@ -1520,12 +1528,17 @@ DecodeDBNicknameEntry(certDBEntryNickname *entry, SECItem *dbentry, /* is database entry correct length? */ entry->subjectName.len = ( ( dbentry->data[0] << 8 ) | dbentry->data[1] ); - if (( entry->subjectName.len + DB_NICKNAME_ENTRY_HEADER_LEN ) != - dbentry->len ){ - PORT_SetError(SEC_ERROR_BAD_DATABASE); - goto loser; + lenDiff = dbentry->len - + (entry->subjectName.len + DB_NICKNAME_ENTRY_HEADER_LEN); + if (lenDiff) { + if (lenDiff < 0 || (lenDiff & 0xffff) != 0 ) { + PORT_SetError(SEC_ERROR_BAD_DATABASE); + goto loser; + } + /* The entry size exceeded 64KB. Reconstruct the correct length. */ + entry->subjectName.len += lenDiff; } - + /* copy the certkey */ entry->subjectName.data = (unsigned char *)PORT_ArenaAlloc(entry->common.arena, @@ -1779,12 +1792,12 @@ EncodeDBSMimeEntry(certDBEntrySMime *entry, PRArenaPool *arena, /* fill in database record */ buf = &dbitem->data[SEC_DB_ENTRY_HEADER_LEN]; - buf[0] = ( entry->subjectName.len >> 8 ) & 0xff; - buf[1] = entry->subjectName.len & 0xff; - buf[2] = ( entry->smimeOptions.len >> 8 ) & 0xff; - buf[3] = entry->smimeOptions.len & 0xff; - buf[4] = ( entry->optionsDate.len >> 8 ) & 0xff; - buf[5] = entry->optionsDate.len & 0xff; + buf[0] = (PRUint8)( entry->subjectName.len >> 8 ); + buf[1] = (PRUint8)( entry->subjectName.len ); + buf[2] = (PRUint8)( entry->smimeOptions.len >> 8 ); + buf[3] = (PRUint8)( entry->smimeOptions.len ); + buf[4] = (PRUint8)( entry->optionsDate.len >> 8 ); + buf[5] = (PRUint8)( entry->optionsDate.len ); /* if no smime options, then there should not be an options date either */ PORT_Assert( ! ( ( entry->smimeOptions.len == 0 ) && @@ -1821,6 +1834,8 @@ EncodeDBSMimeKey(char *emailAddr, PRArenaPool *arena, /* now get the database key and format it */ dbkey->len = addrlen + SEC_DB_KEY_HEADER_LEN; + if (dbkey->len > NSS_MAX_LEGACY_DB_KEY_SIZE) + goto loser; dbkey->data = (unsigned char *)PORT_ArenaAlloc(arena, dbkey->len); if ( dbkey->data == NULL ) { goto loser; @@ -1840,6 +1855,8 @@ loser: static SECStatus DecodeDBSMimeEntry(certDBEntrySMime *entry, SECItem *dbentry, char *emailAddr) { + int lenDiff; + /* is record long enough for header? */ if ( dbentry->len < DB_SMIME_ENTRY_HEADER_LEN ) { PORT_SetError(SEC_ERROR_BAD_DATABASE); @@ -1847,15 +1864,22 @@ DecodeDBSMimeEntry(certDBEntrySMime *entry, SECItem *dbentry, char *emailAddr) } /* is database entry correct length? */ - entry->subjectName.len = ( ( dbentry->data[0] << 8 ) | dbentry->data[1] ); - entry->smimeOptions.len = ( ( dbentry->data[2] << 8 ) | dbentry->data[3] ); - entry->optionsDate.len = ( ( dbentry->data[4] << 8 ) | dbentry->data[5] ); - if (( entry->subjectName.len + entry->smimeOptions.len + - entry->optionsDate.len + DB_SMIME_ENTRY_HEADER_LEN ) != dbentry->len){ - PORT_SetError(SEC_ERROR_BAD_DATABASE); - goto loser; + entry->subjectName.len = (( dbentry->data[0] << 8 ) | dbentry->data[1] ); + entry->smimeOptions.len = (( dbentry->data[2] << 8 ) | dbentry->data[3] ); + entry->optionsDate.len = (( dbentry->data[4] << 8 ) | dbentry->data[5] ); + lenDiff = dbentry->len - (entry->subjectName.len + + entry->smimeOptions.len + + entry->optionsDate.len + + DB_SMIME_ENTRY_HEADER_LEN); + if (lenDiff) { + if (lenDiff < 0 || (lenDiff & 0xffff) != 0 ) { + PORT_SetError(SEC_ERROR_BAD_DATABASE); + goto loser; + } + /* The entry size exceeded 64KB. Reconstruct the correct length. */ + entry->subjectName.len += lenDiff; } - + /* copy the subject name */ entry->subjectName.data = (unsigned char *)PORT_ArenaAlloc(entry->common.arena, @@ -2160,8 +2184,8 @@ EncodeDBSubjectEntry(certDBEntrySubject *entry, PRArenaPool *arena, unsigned int nnlen = 0; unsigned int eaddrslen = 0; int keyidoff; - SECItem *certKeys; - SECItem *keyIDs; + SECItem *certKeys = entry->certKeys; + SECItem *keyIDs = entry->keyIDs;; if ( entry->nickname ) { nnlen = PORT_Strlen(entry->nickname) + 1; @@ -2177,10 +2201,15 @@ EncodeDBSubjectEntry(certDBEntrySubject *entry, PRArenaPool *arena, /* compute the length of the entry */ keyidoff = DB_SUBJECT_ENTRY_HEADER_LEN + nnlen ; - len = keyidoff + 4 * ncerts + eaddrslen; + len = keyidoff + (4 * ncerts) + eaddrslen; for ( i = 0; i < ncerts; i++ ) { - len += entry->certKeys[i].len; - len += entry->keyIDs[i].len; + if (keyIDs[i].len > 0xffff || + (certKeys[i].len > 0xffff)) { + PORT_SetError(SEC_ERROR_INPUT_LEN); + goto loser; + } + len += certKeys[i].len; + len += keyIDs[i].len; } /* allocate space for encoded database record, including space @@ -2197,50 +2226,44 @@ EncodeDBSubjectEntry(certDBEntrySubject *entry, PRArenaPool *arena, /* fill in database record */ buf = &dbitem->data[SEC_DB_ENTRY_HEADER_LEN]; - buf[0] = ( ncerts >> 8 ) & 0xff; - buf[1] = ncerts & 0xff; - buf[2] = ( nnlen >> 8 ) & 0xff; - buf[3] = nnlen & 0xff; + buf[0] = (PRUint8)( ncerts >> 8 ); + buf[1] = (PRUint8)( ncerts ); + buf[2] = (PRUint8)( nnlen >> 8 ); + buf[3] = (PRUint8)( nnlen ); /* v7 email field is NULL in v8 */ buf[4] = 0; buf[5] = 0; PORT_Memcpy(&buf[DB_SUBJECT_ENTRY_HEADER_LEN], entry->nickname, nnlen); - + tmpbuf = &buf[keyidoff]; for ( i = 0; i < ncerts; i++ ) { - - certKeys = entry->certKeys; - keyIDs = entry->keyIDs; - - buf[keyidoff+i*2] = ( certKeys[i].len >> 8 ) & 0xff; - buf[keyidoff+1+i*2] = certKeys[i].len & 0xff; - buf[keyidoff+ncerts*2+i*2] = ( keyIDs[i].len >> 8 ) & 0xff; - buf[keyidoff+1+ncerts*2+i*2] = keyIDs[i].len & 0xff; + tmpbuf[0] = (PRUint8)( certKeys[i].len >> 8 ); + tmpbuf[1] = (PRUint8)( certKeys[i].len ); + tmpbuf += 2; + } + for ( i = 0; i < ncerts; i++ ) { + tmpbuf[0] = (PRUint8)( keyIDs[i].len >> 8 ); + tmpbuf[1] = (PRUint8)( keyIDs[i].len ); + tmpbuf += 2; } - /* temp pointer used to stuff certkeys and keyids into the buffer */ - tmpbuf = &buf[keyidoff+ncerts*4]; - for ( i = 0; i < ncerts; i++ ) { - certKeys = entry->certKeys; PORT_Memcpy(tmpbuf, certKeys[i].data, certKeys[i].len); - tmpbuf = tmpbuf + certKeys[i].len; + tmpbuf += certKeys[i].len; } - for ( i = 0; i < ncerts; i++ ) { - keyIDs = entry->keyIDs; PORT_Memcpy(tmpbuf, keyIDs[i].data, keyIDs[i].len); - tmpbuf = tmpbuf + keyIDs[i].len; + tmpbuf += keyIDs[i].len; } if (entry->emailAddrs) { - tmpbuf[0] = (entry->nemailAddrs >> 8) & 0xff; - tmpbuf[1] = entry->nemailAddrs & 0xff; + tmpbuf[0] = (PRUint8)( entry->nemailAddrs >> 8 ); + tmpbuf[1] = (PRUint8)( entry->nemailAddrs ); tmpbuf += 2; for (i=0; i < entry->nemailAddrs; i++) { int nameLen = PORT_Strlen(entry->emailAddrs[i]) + 1; - tmpbuf[0] = (nameLen >> 8) & 0xff; - tmpbuf[1] = nameLen & 0xff; + tmpbuf[0] = (PRUint8)( nameLen >> 8 ); + tmpbuf[1] = (PRUint8)( nameLen ); tmpbuf += 2; PORT_Memcpy(tmpbuf,entry->emailAddrs[i],nameLen); tmpbuf +=nameLen; @@ -2263,6 +2286,8 @@ EncodeDBSubjectKey(SECItem *derSubject, PRArenaPool *arena, SECItem *dbkey) { dbkey->len = derSubject->len + SEC_DB_KEY_HEADER_LEN; + if (dbkey->len > NSS_MAX_LEGACY_DB_KEY_SIZE) + goto loser; dbkey->data = (unsigned char *)PORT_ArenaAlloc(arena, dbkey->len); if ( dbkey->data == NULL ) { goto loser; @@ -2281,18 +2306,17 @@ static SECStatus DecodeDBSubjectEntry(certDBEntrySubject *entry, SECItem *dbentry, SECItem *derSubject) { - unsigned int ncerts; - PRArenaPool *arena; - unsigned int len, itemlen; + PRArenaPool *arena = entry->common.arena; unsigned char *tmpbuf; unsigned char *end; + void *mark = PORT_ArenaMark(arena); + unsigned int eaddrlen; unsigned int i; - SECStatus rv; unsigned int keyidoff; - unsigned int nnlen, eaddrlen; - unsigned int stdlen; - - arena = entry->common.arena; + unsigned int len; + unsigned int ncerts = 0; + unsigned int nnlen; + SECStatus rv; rv = SECITEM_CopyItem(arena, &entry->derSubject, derSubject); if ( rv != SECSuccess ) { @@ -2305,20 +2329,18 @@ DecodeDBSubjectEntry(certDBEntrySubject *entry, SECItem *dbentry, goto loser; } - entry->ncerts = ncerts = ( ( dbentry->data[0] << 8 ) | dbentry->data[1] ); - nnlen = ( ( dbentry->data[2] << 8 ) | dbentry->data[3] ); - eaddrlen = ( ( dbentry->data[4] << 8 ) | dbentry->data[5] ); - stdlen = ncerts * 4 + DB_SUBJECT_ENTRY_HEADER_LEN + nnlen + eaddrlen; - if ( dbentry->len < stdlen) { + entry->ncerts = ncerts = (( dbentry->data[0] << 8 ) | dbentry->data[1] ); + nnlen = (( dbentry->data[2] << 8 ) | dbentry->data[3] ); + eaddrlen = (( dbentry->data[4] << 8 ) | dbentry->data[5] ); + keyidoff = DB_SUBJECT_ENTRY_HEADER_LEN + nnlen + eaddrlen; + len = keyidoff + (4 * ncerts); + if ( dbentry->len < len) { PORT_SetError(SEC_ERROR_BAD_DATABASE); goto loser; } - entry->certKeys = (SECItem *)PORT_ArenaAlloc(arena, - sizeof(SECItem) * ncerts); - entry->keyIDs = (SECItem *)PORT_ArenaAlloc(arena, - sizeof(SECItem) * ncerts); - + entry->certKeys = PORT_ArenaNewArray(arena, SECItem, ncerts); + entry->keyIDs = PORT_ArenaNewArray(arena, SECItem, ncerts); if ( ( entry->certKeys == NULL ) || ( entry->keyIDs == NULL ) ) { PORT_SetError(SEC_ERROR_NO_MEMORY); goto loser; @@ -2340,7 +2362,7 @@ DecodeDBSubjectEntry(certDBEntrySubject *entry, SECItem *dbentry, /* if we have an old style email entry, there is only one */ entry->nemailAddrs = 0; if ( eaddrlen > 1 ) { /* null terminator is stored */ - entry->emailAddrs = (char **)PORT_ArenaAlloc(arena, sizeof(char *)); + entry->emailAddrs = PORT_ArenaNewArray(arena, char *, 2); if ( entry->emailAddrs == NULL ) { PORT_SetError(SEC_ERROR_NO_MEMORY); goto loser; @@ -2361,87 +2383,85 @@ DecodeDBSubjectEntry(certDBEntrySubject *entry, SECItem *dbentry, /* collect the lengths of the certKeys and keyIDs, and total the * overall length. */ - keyidoff = DB_SUBJECT_ENTRY_HEADER_LEN + nnlen + eaddrlen; - len = keyidoff + 4 * ncerts; - - tmpbuf = &dbentry->data[0]; - + tmpbuf = &dbentry->data[keyidoff]; for ( i = 0; i < ncerts; i++ ) { - - itemlen = ( tmpbuf[keyidoff + 2*i] << 8 ) | tmpbuf[keyidoff + 1 + 2*i] ; - len += itemlen; - entry->certKeys[i].len = itemlen; - - itemlen = ( tmpbuf[keyidoff + 2*ncerts + 2*i] << 8 ) | - tmpbuf[keyidoff + 1 + 2*ncerts + 2*i] ; - len += itemlen; - entry->keyIDs[i].len = itemlen; + unsigned int itemlen = ( tmpbuf[0] << 8 ) | tmpbuf[1]; + entry->certKeys[i].len = itemlen; + len += itemlen; + tmpbuf += 2; } - - /* is database entry correct length? */ + for ( i = 0; i < ncerts; i++ ) { + unsigned int itemlen = ( tmpbuf[0] << 8 ) | tmpbuf[1] ; + entry->keyIDs[i].len = itemlen; + len += itemlen; + tmpbuf += 2; + } + + /* is encoded entry large enough ? */ if ( len > dbentry->len ){ PORT_SetError(SEC_ERROR_BAD_DATABASE); goto loser; } - - tmpbuf = &tmpbuf[keyidoff + 4*ncerts]; + for ( i = 0; i < ncerts; i++ ) { - entry->certKeys[i].data = - (unsigned char *)PORT_ArenaAlloc(arena, entry->certKeys[i].len); + unsigned int kLen = entry->certKeys[i].len; + entry->certKeys[i].data = (unsigned char *)PORT_ArenaAlloc(arena, kLen); if ( entry->certKeys[i].data == NULL ) { PORT_SetError(SEC_ERROR_NO_MEMORY); goto loser; } - PORT_Memcpy(entry->certKeys[i].data, tmpbuf, entry->certKeys[i].len); - tmpbuf = &tmpbuf[entry->certKeys[i].len]; + PORT_Memcpy(entry->certKeys[i].data, tmpbuf, kLen); + tmpbuf += kLen; } - for ( i = 0; i < ncerts; i++ ) { - entry->keyIDs[i].data = - (unsigned char *)PORT_ArenaAlloc(arena, entry->keyIDs[i].len); + unsigned int iLen = entry->keyIDs[i].len; + entry->keyIDs[i].data = (unsigned char *)PORT_ArenaAlloc(arena, iLen); if ( entry->keyIDs[i].data == NULL ) { PORT_SetError(SEC_ERROR_NO_MEMORY); goto loser; } - PORT_Memcpy(entry->keyIDs[i].data, tmpbuf, entry->keyIDs[i].len); - tmpbuf = &tmpbuf[entry->keyIDs[i].len]; + PORT_Memcpy(entry->keyIDs[i].data, tmpbuf, iLen); + tmpbuf += iLen; } - end = &dbentry->data[dbentry->len]; - if ((eaddrlen == 0) && (tmpbuf+1 < end)) { + end = dbentry->data + dbentry->len; + if ((eaddrlen == 0) && (end - tmpbuf > 1)) { /* read in the additional email addresses */ - entry->nemailAddrs = tmpbuf[0] << 8 | tmpbuf[1]; + entry->nemailAddrs = (((unsigned int)tmpbuf[0]) << 8) | tmpbuf[1]; tmpbuf += 2; - entry->emailAddrs = (char **) - PORT_ArenaAlloc(arena, entry->nemailAddrs * sizeof(char *)); + if (end - tmpbuf < 2 * (int)entry->nemailAddrs) + goto loser; + entry->emailAddrs = PORT_ArenaNewArray(arena, char *, entry->nemailAddrs); if (entry->emailAddrs == NULL) { PORT_SetError(SEC_ERROR_NO_MEMORY); goto loser; } for (i=0; i < entry->nemailAddrs; i++) { int nameLen; - if (tmpbuf + 2 > end) { + if (end - tmpbuf < 2) { + goto loser; + } + nameLen = (((int)tmpbuf[0]) << 8) | tmpbuf[1]; + tmpbuf += 2; + if (end - tmpbuf < nameLen) { goto loser; } - - nameLen = tmpbuf[0] << 8 | tmpbuf[1]; entry->emailAddrs[i] = PORT_ArenaAlloc(arena,nameLen); if (entry->emailAddrs == NULL) { PORT_SetError(SEC_ERROR_NO_MEMORY); goto loser; } - if (tmpbuf + (nameLen+2) > end) { - goto loser; - } - PORT_Memcpy(entry->emailAddrs[i],&tmpbuf[2],nameLen); - tmpbuf += 2 + nameLen; + PORT_Memcpy(entry->emailAddrs[i], tmpbuf, nameLen); + tmpbuf += nameLen; } + if (tmpbuf != end) + goto loser; } - - + PORT_ArenaUnmark(arena, mark); return(SECSuccess); loser: + PORT_ArenaRelease(arena, mark); /* discard above allocations */ return(SECFailure); } @@ -4277,7 +4297,7 @@ nsslowcert_TraverseDBEntries(NSSLOWCERTCertDBHandle *handle, { DBT data; DBT key; - SECStatus rv; + SECStatus rv = SECSuccess; int ret; SECItem dataitem; SECItem keyitem; @@ -4304,13 +4324,16 @@ nsslowcert_TraverseDBEntries(NSSLOWCERTCertDBHandle *handle, /* type should equal keybuf[0]. */ rv = (* callback)(&dataitem, &keyitem, type, udata); - if ( rv != SECSuccess ) { - return(rv); + if ( rv == SECSuccess ) { + ++ret; } } } while ( certdb_Seq(handle->permCertDB, &key, &data, R_NEXT) == 0 ); - return(SECSuccess); + /* If any callbacks succeeded, or no calls to callbacks were made, + * then report success. Otherwise, report failure. + */ + return (ret ? SECSuccess : rv); } /* * Decode a certificate and enter it into the temporary certificate database. diff --git a/security/nss/lib/softoken/pcertt.h b/security/nss/lib/softoken/pcertt.h index 848fe69e9..38a152414 100644 --- a/security/nss/lib/softoken/pcertt.h +++ b/security/nss/lib/softoken/pcertt.h @@ -166,6 +166,8 @@ struct NSSLOWCERTCertificateStr { #define SEC_CRL_VERSION_1 0 /* default */ #define SEC_CRL_VERSION_2 1 /* v2 extensions */ +#define NSS_MAX_LEGACY_DB_KEY_SIZE (60 * 1024) + struct NSSLOWCERTIssuerAndSNStr { SECItem derIssuer; SECItem serialNumber; -- cgit v1.2.1