1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/softoken/legacydb/pcertdb.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,5357 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +/* 1.9 + * Permanent Certificate database handling code 1.10 + */ 1.11 +#include "lowkeyti.h" 1.12 +#include "pcert.h" 1.13 +#include "mcom_db.h" 1.14 +#include "pcert.h" 1.15 +#include "secitem.h" 1.16 +#include "secder.h" 1.17 + 1.18 +#include "secerr.h" 1.19 +#include "lgdb.h" 1.20 + 1.21 +/* forward declaration */ 1.22 +NSSLOWCERTCertificate * 1.23 +nsslowcert_FindCertByDERCertNoLocking(NSSLOWCERTCertDBHandle *handle, SECItem *derCert); 1.24 +static SECStatus 1.25 +nsslowcert_UpdateSMimeProfile(NSSLOWCERTCertDBHandle *dbhandle, 1.26 + char *emailAddr, SECItem *derSubject, SECItem *emailProfile, 1.27 + SECItem *profileTime); 1.28 +static SECStatus 1.29 +nsslowcert_UpdatePermCert(NSSLOWCERTCertDBHandle *dbhandle, 1.30 + NSSLOWCERTCertificate *cert, char *nickname, NSSLOWCERTCertTrust *trust); 1.31 +static SECStatus 1.32 +nsslowcert_UpdateCrl(NSSLOWCERTCertDBHandle *handle, SECItem *derCrl, 1.33 + SECItem *crlKey, char *url, PRBool isKRL); 1.34 + 1.35 +static NSSLOWCERTCertificate *certListHead = NULL; 1.36 +static NSSLOWCERTTrust *trustListHead = NULL; 1.37 +static certDBEntryCert *entryListHead = NULL; 1.38 +static int certListCount = 0; 1.39 +static int trustListCount = 0; 1.40 +static int entryListCount = 0; 1.41 +#define MAX_CERT_LIST_COUNT 10 1.42 +#define MAX_TRUST_LIST_COUNT 10 1.43 +#define MAX_ENTRY_LIST_COUNT 10 1.44 + 1.45 +/* 1.46 + * the following functions are wrappers for the db library that implement 1.47 + * a global lock to make the database thread safe. 1.48 + */ 1.49 +static PZLock *dbLock = NULL; 1.50 +static PZLock *certRefCountLock = NULL; 1.51 +static PZLock *certTrustLock = NULL; 1.52 +static PZLock *freeListLock = NULL; 1.53 + 1.54 +void 1.55 +certdb_InitDBLock(NSSLOWCERTCertDBHandle *handle) 1.56 +{ 1.57 + if (dbLock == NULL) { 1.58 + dbLock = PZ_NewLock(nssILockCertDB); 1.59 + PORT_Assert(dbLock != NULL); 1.60 + } 1.61 +} 1.62 + 1.63 +SECStatus 1.64 +nsslowcert_InitLocks(void) 1.65 +{ 1.66 + if (freeListLock == NULL) { 1.67 + freeListLock = PZ_NewLock(nssILockRefLock); 1.68 + if (freeListLock == NULL) { 1.69 + return SECFailure; 1.70 + } 1.71 + } 1.72 + if (certRefCountLock == NULL) { 1.73 + certRefCountLock = PZ_NewLock(nssILockRefLock); 1.74 + if (certRefCountLock == NULL) { 1.75 + return SECFailure; 1.76 + } 1.77 + } 1.78 + if (certTrustLock == NULL ) { 1.79 + certTrustLock = PZ_NewLock(nssILockCertDB); 1.80 + if (certTrustLock == NULL) { 1.81 + return SECFailure; 1.82 + } 1.83 + } 1.84 + 1.85 + return SECSuccess; 1.86 +} 1.87 + 1.88 +/* 1.89 + * Acquire the global lock on the cert database. 1.90 + * This lock is currently used for the following operations: 1.91 + * adding or deleting a cert to either the temp or perm databases 1.92 + * converting a temp to perm or perm to temp 1.93 + * changing (maybe just adding!?) the trust of a cert 1.94 + * chaning the DB status checking Configuration 1.95 + */ 1.96 +static void 1.97 +nsslowcert_LockDB(NSSLOWCERTCertDBHandle *handle) 1.98 +{ 1.99 + PZ_EnterMonitor(handle->dbMon); 1.100 + return; 1.101 +} 1.102 + 1.103 +/* 1.104 + * Free the global cert database lock. 1.105 + */ 1.106 +static void 1.107 +nsslowcert_UnlockDB(NSSLOWCERTCertDBHandle *handle) 1.108 +{ 1.109 + PRStatus prstat; 1.110 + 1.111 + prstat = PZ_ExitMonitor(handle->dbMon); 1.112 + 1.113 + PORT_Assert(prstat == PR_SUCCESS); 1.114 + 1.115 + return; 1.116 +} 1.117 + 1.118 + 1.119 +/* 1.120 + * Acquire the cert reference count lock 1.121 + * There is currently one global lock for all certs, but I'm putting a cert 1.122 + * arg here so that it will be easy to make it per-cert in the future if 1.123 + * that turns out to be necessary. 1.124 + */ 1.125 +static void 1.126 +nsslowcert_LockCertRefCount(NSSLOWCERTCertificate *cert) 1.127 +{ 1.128 + PORT_Assert(certRefCountLock != NULL); 1.129 + 1.130 + PZ_Lock(certRefCountLock); 1.131 + return; 1.132 +} 1.133 + 1.134 +/* 1.135 + * Free the cert reference count lock 1.136 + */ 1.137 +static void 1.138 +nsslowcert_UnlockCertRefCount(NSSLOWCERTCertificate *cert) 1.139 +{ 1.140 + PRStatus prstat; 1.141 + 1.142 + PORT_Assert(certRefCountLock != NULL); 1.143 + 1.144 + prstat = PZ_Unlock(certRefCountLock); 1.145 + 1.146 + PORT_Assert(prstat == PR_SUCCESS); 1.147 + 1.148 + return; 1.149 +} 1.150 + 1.151 +/* 1.152 + * Acquire the cert trust lock 1.153 + * There is currently one global lock for all certs, but I'm putting a cert 1.154 + * arg here so that it will be easy to make it per-cert in the future if 1.155 + * that turns out to be necessary. 1.156 + */ 1.157 +static void 1.158 +nsslowcert_LockCertTrust(NSSLOWCERTCertificate *cert) 1.159 +{ 1.160 + PORT_Assert(certTrustLock != NULL); 1.161 + 1.162 + PZ_Lock(certTrustLock); 1.163 + return; 1.164 +} 1.165 + 1.166 +/* 1.167 + * Free the cert trust lock 1.168 + */ 1.169 +static void 1.170 +nsslowcert_UnlockCertTrust(NSSLOWCERTCertificate *cert) 1.171 +{ 1.172 + PRStatus prstat; 1.173 + 1.174 + PORT_Assert(certTrustLock != NULL); 1.175 + 1.176 + prstat = PZ_Unlock(certTrustLock); 1.177 + 1.178 + PORT_Assert(prstat == PR_SUCCESS); 1.179 + 1.180 + return; 1.181 +} 1.182 + 1.183 + 1.184 +/* 1.185 + * Acquire the cert reference count lock 1.186 + * There is currently one global lock for all certs, but I'm putting a cert 1.187 + * arg here so that it will be easy to make it per-cert in the future if 1.188 + * that turns out to be necessary. 1.189 + */ 1.190 +static void 1.191 +nsslowcert_LockFreeList(void) 1.192 +{ 1.193 + PORT_Assert(freeListLock != NULL); 1.194 + 1.195 + SKIP_AFTER_FORK(PZ_Lock(freeListLock)); 1.196 + return; 1.197 +} 1.198 + 1.199 +/* 1.200 + * Free the cert reference count lock 1.201 + */ 1.202 +static void 1.203 +nsslowcert_UnlockFreeList(void) 1.204 +{ 1.205 + PRStatus prstat = PR_SUCCESS; 1.206 + 1.207 + PORT_Assert(freeListLock != NULL); 1.208 + 1.209 + SKIP_AFTER_FORK(prstat = PZ_Unlock(freeListLock)); 1.210 + 1.211 + PORT_Assert(prstat == PR_SUCCESS); 1.212 + 1.213 + return; 1.214 +} 1.215 + 1.216 +NSSLOWCERTCertificate * 1.217 +nsslowcert_DupCertificate(NSSLOWCERTCertificate *c) 1.218 +{ 1.219 + if (c) { 1.220 + nsslowcert_LockCertRefCount(c); 1.221 + ++c->referenceCount; 1.222 + nsslowcert_UnlockCertRefCount(c); 1.223 + } 1.224 + return c; 1.225 +} 1.226 + 1.227 +static int 1.228 +certdb_Get(DB *db, DBT *key, DBT *data, unsigned int flags) 1.229 +{ 1.230 + PRStatus prstat; 1.231 + int ret; 1.232 + 1.233 + PORT_Assert(dbLock != NULL); 1.234 + PZ_Lock(dbLock); 1.235 + 1.236 + ret = (* db->get)(db, key, data, flags); 1.237 + 1.238 + prstat = PZ_Unlock(dbLock); 1.239 + 1.240 + return(ret); 1.241 +} 1.242 + 1.243 +static int 1.244 +certdb_Put(DB *db, DBT *key, DBT *data, unsigned int flags) 1.245 +{ 1.246 + PRStatus prstat; 1.247 + int ret = 0; 1.248 + 1.249 + PORT_Assert(dbLock != NULL); 1.250 + PZ_Lock(dbLock); 1.251 + 1.252 + ret = (* db->put)(db, key, data, flags); 1.253 + 1.254 + prstat = PZ_Unlock(dbLock); 1.255 + 1.256 + return(ret); 1.257 +} 1.258 + 1.259 +static int 1.260 +certdb_Sync(DB *db, unsigned int flags) 1.261 +{ 1.262 + PRStatus prstat; 1.263 + int ret; 1.264 + 1.265 + PORT_Assert(dbLock != NULL); 1.266 + PZ_Lock(dbLock); 1.267 + 1.268 + ret = (* db->sync)(db, flags); 1.269 + 1.270 + prstat = PZ_Unlock(dbLock); 1.271 + 1.272 + return(ret); 1.273 +} 1.274 + 1.275 +#define DB_NOT_FOUND -30991 /* from DBM 3.2 */ 1.276 +static int 1.277 +certdb_Del(DB *db, DBT *key, unsigned int flags) 1.278 +{ 1.279 + PRStatus prstat; 1.280 + int ret; 1.281 + 1.282 + PORT_Assert(dbLock != NULL); 1.283 + PZ_Lock(dbLock); 1.284 + 1.285 + ret = (* db->del)(db, key, flags); 1.286 + 1.287 + prstat = PZ_Unlock(dbLock); 1.288 + 1.289 + /* don't fail if the record is already deleted */ 1.290 + if (ret == DB_NOT_FOUND) { 1.291 + ret = 0; 1.292 + } 1.293 + 1.294 + return(ret); 1.295 +} 1.296 + 1.297 +static int 1.298 +certdb_Seq(DB *db, DBT *key, DBT *data, unsigned int flags) 1.299 +{ 1.300 + PRStatus prstat; 1.301 + int ret; 1.302 + 1.303 + PORT_Assert(dbLock != NULL); 1.304 + PZ_Lock(dbLock); 1.305 + 1.306 + ret = (* db->seq)(db, key, data, flags); 1.307 + 1.308 + prstat = PZ_Unlock(dbLock); 1.309 + 1.310 + return(ret); 1.311 +} 1.312 + 1.313 +static void 1.314 +certdb_Close(DB *db) 1.315 +{ 1.316 + PRStatus prstat = PR_SUCCESS; 1.317 + 1.318 + PORT_Assert(dbLock != NULL); 1.319 + SKIP_AFTER_FORK(PZ_Lock(dbLock)); 1.320 + 1.321 + (* db->close)(db); 1.322 + 1.323 + SKIP_AFTER_FORK(prstat = PZ_Unlock(dbLock)); 1.324 + 1.325 + return; 1.326 +} 1.327 + 1.328 +void 1.329 +pkcs11_freeNickname(char *nickname, char *space) 1.330 +{ 1.331 + if (nickname && nickname != space) { 1.332 + PORT_Free(nickname); 1.333 + } 1.334 +} 1.335 + 1.336 +char * 1.337 +pkcs11_copyNickname(char *nickname,char *space, int spaceLen) 1.338 +{ 1.339 + int len; 1.340 + char *copy = NULL; 1.341 + 1.342 + len = PORT_Strlen(nickname)+1; 1.343 + if (len <= spaceLen) { 1.344 + copy = space; 1.345 + PORT_Memcpy(copy,nickname,len); 1.346 + } else { 1.347 + copy = PORT_Strdup(nickname); 1.348 + } 1.349 + 1.350 + return copy; 1.351 +} 1.352 + 1.353 +void 1.354 +pkcs11_freeStaticData (unsigned char *data, unsigned char *space) 1.355 +{ 1.356 + if (data && data != space) { 1.357 + PORT_Free(data); 1.358 + } 1.359 +} 1.360 + 1.361 +unsigned char * 1.362 +pkcs11_allocStaticData(int len, unsigned char *space, int spaceLen) 1.363 +{ 1.364 + unsigned char *data = NULL; 1.365 + 1.366 + if (len <= spaceLen) { 1.367 + data = space; 1.368 + } else { 1.369 + data = (unsigned char *) PORT_Alloc(len); 1.370 + } 1.371 + 1.372 + return data; 1.373 +} 1.374 + 1.375 +unsigned char * 1.376 +pkcs11_copyStaticData(unsigned char *data, int len, 1.377 + unsigned char *space, int spaceLen) 1.378 +{ 1.379 + unsigned char *copy = pkcs11_allocStaticData(len, space, spaceLen); 1.380 + if (copy) { 1.381 + PORT_Memcpy(copy,data,len); 1.382 + } 1.383 + 1.384 + return copy; 1.385 +} 1.386 + 1.387 +/* 1.388 + * destroy a database entry 1.389 + */ 1.390 +static void 1.391 +DestroyDBEntry(certDBEntry *entry) 1.392 +{ 1.393 + PLArenaPool *arena = entry->common.arena; 1.394 + 1.395 + /* must be one of our certDBEntry from the free list */ 1.396 + if (arena == NULL) { 1.397 + certDBEntryCert *certEntry; 1.398 + if ( entry->common.type != certDBEntryTypeCert) { 1.399 + return; 1.400 + } 1.401 + certEntry = (certDBEntryCert *)entry; 1.402 + 1.403 + pkcs11_freeStaticData(certEntry->derCert.data, certEntry->derCertSpace); 1.404 + pkcs11_freeNickname(certEntry->nickname, certEntry->nicknameSpace); 1.405 + 1.406 + nsslowcert_LockFreeList(); 1.407 + if (entryListCount > MAX_ENTRY_LIST_COUNT) { 1.408 + PORT_Free(certEntry); 1.409 + } else { 1.410 + entryListCount++; 1.411 + PORT_Memset(certEntry, 0, sizeof( *certEntry)); 1.412 + certEntry->next = entryListHead; 1.413 + entryListHead = certEntry; 1.414 + } 1.415 + nsslowcert_UnlockFreeList(); 1.416 + return; 1.417 + } 1.418 + 1.419 + 1.420 + /* Zero out the entry struct, so that any further attempts to use it 1.421 + * will cause an exception (e.g. null pointer reference). */ 1.422 + PORT_Memset(&entry->common, 0, sizeof entry->common); 1.423 + PORT_FreeArena(arena, PR_FALSE); 1.424 + 1.425 + return; 1.426 +} 1.427 + 1.428 +/* forward references */ 1.429 +static void nsslowcert_DestroyCertificateNoLocking(NSSLOWCERTCertificate *cert); 1.430 + 1.431 +static SECStatus 1.432 +DeleteDBEntry(NSSLOWCERTCertDBHandle *handle, certDBEntryType type, SECItem *dbkey) 1.433 +{ 1.434 + DBT key; 1.435 + int ret; 1.436 + 1.437 + /* init the database key */ 1.438 + key.data = dbkey->data; 1.439 + key.size = dbkey->len; 1.440 + 1.441 + dbkey->data[0] = (unsigned char)type; 1.442 + 1.443 + /* delete entry from database */ 1.444 + ret = certdb_Del(handle->permCertDB, &key, 0 ); 1.445 + if ( ret != 0 ) { 1.446 + PORT_SetError(SEC_ERROR_BAD_DATABASE); 1.447 + goto loser; 1.448 + } 1.449 + 1.450 + ret = certdb_Sync(handle->permCertDB, 0); 1.451 + if ( ret ) { 1.452 + PORT_SetError(SEC_ERROR_BAD_DATABASE); 1.453 + goto loser; 1.454 + } 1.455 + 1.456 + return(SECSuccess); 1.457 + 1.458 +loser: 1.459 + return(SECFailure); 1.460 +} 1.461 + 1.462 +static SECStatus 1.463 +ReadDBEntry(NSSLOWCERTCertDBHandle *handle, certDBEntryCommon *entry, 1.464 + SECItem *dbkey, SECItem *dbentry, PLArenaPool *arena) 1.465 +{ 1.466 + DBT data, key; 1.467 + int ret; 1.468 + unsigned char *buf; 1.469 + 1.470 + /* init the database key */ 1.471 + key.data = dbkey->data; 1.472 + key.size = dbkey->len; 1.473 + 1.474 + dbkey->data[0] = (unsigned char)entry->type; 1.475 + 1.476 + /* read entry from database */ 1.477 + ret = certdb_Get(handle->permCertDB, &key, &data, 0 ); 1.478 + if ( ret != 0 ) { 1.479 + PORT_SetError(SEC_ERROR_BAD_DATABASE); 1.480 + goto loser; 1.481 + } 1.482 + 1.483 + /* validate the entry */ 1.484 + if ( data.size < SEC_DB_ENTRY_HEADER_LEN ) { 1.485 + PORT_SetError(SEC_ERROR_BAD_DATABASE); 1.486 + goto loser; 1.487 + } 1.488 + buf = (unsigned char *)data.data; 1.489 + /* version 7 has the same schema, we may be using a v7 db if we openned 1.490 + * the databases readonly. */ 1.491 + if (!((buf[0] == (unsigned char)CERT_DB_FILE_VERSION) 1.492 + || (buf[0] == (unsigned char) CERT_DB_V7_FILE_VERSION))) { 1.493 + PORT_SetError(SEC_ERROR_BAD_DATABASE); 1.494 + goto loser; 1.495 + } 1.496 + if ( buf[1] != (unsigned char)entry->type ) { 1.497 + PORT_SetError(SEC_ERROR_BAD_DATABASE); 1.498 + goto loser; 1.499 + } 1.500 + 1.501 + /* copy out header information */ 1.502 + entry->version = (unsigned int)buf[0]; 1.503 + entry->type = (certDBEntryType)buf[1]; 1.504 + entry->flags = (unsigned int)buf[2]; 1.505 + 1.506 + /* format body of entry for return to caller */ 1.507 + dbentry->len = data.size - SEC_DB_ENTRY_HEADER_LEN; 1.508 + if ( dbentry->len ) { 1.509 + if (arena) { 1.510 + dbentry->data = (unsigned char *) 1.511 + PORT_ArenaAlloc(arena, dbentry->len); 1.512 + if ( dbentry->data == NULL ) { 1.513 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.514 + goto loser; 1.515 + } 1.516 + 1.517 + PORT_Memcpy(dbentry->data, &buf[SEC_DB_ENTRY_HEADER_LEN], 1.518 + dbentry->len); 1.519 + } else { 1.520 + dbentry->data = &buf[SEC_DB_ENTRY_HEADER_LEN]; 1.521 + } 1.522 + } else { 1.523 + dbentry->data = NULL; 1.524 + } 1.525 + 1.526 + return(SECSuccess); 1.527 + 1.528 +loser: 1.529 + return(SECFailure); 1.530 +} 1.531 + 1.532 +/** 1.533 + ** Implement low level database access 1.534 + **/ 1.535 +static SECStatus 1.536 +WriteDBEntry(NSSLOWCERTCertDBHandle *handle, certDBEntryCommon *entry, 1.537 + SECItem *dbkey, SECItem *dbentry) 1.538 +{ 1.539 + int ret; 1.540 + DBT data, key; 1.541 + unsigned char *buf; 1.542 + 1.543 + data.data = dbentry->data; 1.544 + data.size = dbentry->len; 1.545 + 1.546 + buf = (unsigned char*)data.data; 1.547 + 1.548 + buf[0] = (unsigned char)entry->version; 1.549 + buf[1] = (unsigned char)entry->type; 1.550 + buf[2] = (unsigned char)entry->flags; 1.551 + 1.552 + key.data = dbkey->data; 1.553 + key.size = dbkey->len; 1.554 + 1.555 + dbkey->data[0] = (unsigned char)entry->type; 1.556 + 1.557 + /* put the record into the database now */ 1.558 + ret = certdb_Put(handle->permCertDB, &key, &data, 0); 1.559 + 1.560 + if ( ret != 0 ) { 1.561 + goto loser; 1.562 + } 1.563 + 1.564 + ret = certdb_Sync( handle->permCertDB, 0 ); 1.565 + 1.566 + if ( ret ) { 1.567 + goto loser; 1.568 + } 1.569 + 1.570 + return(SECSuccess); 1.571 + 1.572 +loser: 1.573 + return(SECFailure); 1.574 +} 1.575 + 1.576 +/* 1.577 + * encode a database cert record 1.578 + */ 1.579 +static SECStatus 1.580 +EncodeDBCertEntry(certDBEntryCert *entry, PLArenaPool *arena, SECItem *dbitem) 1.581 +{ 1.582 + unsigned int nnlen; 1.583 + unsigned char *buf; 1.584 + char *nn; 1.585 + char zbuf = 0; 1.586 + 1.587 + if ( entry->nickname ) { 1.588 + nn = entry->nickname; 1.589 + } else { 1.590 + nn = &zbuf; 1.591 + } 1.592 + nnlen = PORT_Strlen(nn) + 1; 1.593 + 1.594 + /* allocate space for encoded database record, including space 1.595 + * for low level header 1.596 + */ 1.597 + dbitem->len = entry->derCert.len + nnlen + DB_CERT_ENTRY_HEADER_LEN + 1.598 + SEC_DB_ENTRY_HEADER_LEN; 1.599 + 1.600 + dbitem->data = (unsigned char *)PORT_ArenaAlloc(arena, dbitem->len); 1.601 + if ( dbitem->data == NULL) { 1.602 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.603 + goto loser; 1.604 + } 1.605 + 1.606 + /* fill in database record */ 1.607 + buf = &dbitem->data[SEC_DB_ENTRY_HEADER_LEN]; 1.608 + 1.609 + buf[0] = (PRUint8)( entry->trust.sslFlags >> 8 ); 1.610 + buf[1] = (PRUint8)( entry->trust.sslFlags ); 1.611 + buf[2] = (PRUint8)( entry->trust.emailFlags >> 8 ); 1.612 + buf[3] = (PRUint8)( entry->trust.emailFlags ); 1.613 + buf[4] = (PRUint8)( entry->trust.objectSigningFlags >> 8 ); 1.614 + buf[5] = (PRUint8)( entry->trust.objectSigningFlags ); 1.615 + buf[6] = (PRUint8)( entry->derCert.len >> 8 ); 1.616 + buf[7] = (PRUint8)( entry->derCert.len ); 1.617 + buf[8] = (PRUint8)( nnlen >> 8 ); 1.618 + buf[9] = (PRUint8)( nnlen ); 1.619 + 1.620 + PORT_Memcpy(&buf[DB_CERT_ENTRY_HEADER_LEN], entry->derCert.data, 1.621 + entry->derCert.len); 1.622 + 1.623 + PORT_Memcpy(&buf[DB_CERT_ENTRY_HEADER_LEN + entry->derCert.len], 1.624 + nn, nnlen); 1.625 + 1.626 + return(SECSuccess); 1.627 + 1.628 +loser: 1.629 + return(SECFailure); 1.630 +} 1.631 + 1.632 +/* 1.633 + * encode a database key for a cert record 1.634 + */ 1.635 +static SECStatus 1.636 +EncodeDBCertKey(const SECItem *certKey, PLArenaPool *arena, SECItem *dbkey) 1.637 +{ 1.638 + unsigned int len = certKey->len + SEC_DB_KEY_HEADER_LEN; 1.639 + if (len > NSS_MAX_LEGACY_DB_KEY_SIZE) 1.640 + goto loser; 1.641 + if (arena) { 1.642 + dbkey->data = (unsigned char *)PORT_ArenaAlloc(arena, len); 1.643 + } else { 1.644 + if (dbkey->len < len) { 1.645 + dbkey->data = (unsigned char *)PORT_Alloc(len); 1.646 + } 1.647 + } 1.648 + dbkey->len = len; 1.649 + if ( dbkey->data == NULL ) { 1.650 + goto loser; 1.651 + } 1.652 + PORT_Memcpy(&dbkey->data[SEC_DB_KEY_HEADER_LEN], 1.653 + certKey->data, certKey->len); 1.654 + dbkey->data[0] = certDBEntryTypeCert; 1.655 + 1.656 + return(SECSuccess); 1.657 +loser: 1.658 + return(SECFailure); 1.659 +} 1.660 + 1.661 +static SECStatus 1.662 +EncodeDBGenericKey(const SECItem *certKey, PLArenaPool *arena, SECItem *dbkey, 1.663 + certDBEntryType entryType) 1.664 +{ 1.665 + /* 1.666 + * we only allow _one_ KRL key! 1.667 + */ 1.668 + if (entryType == certDBEntryTypeKeyRevocation) { 1.669 + dbkey->len = SEC_DB_KEY_HEADER_LEN; 1.670 + dbkey->data = (unsigned char *)PORT_ArenaAlloc(arena, dbkey->len); 1.671 + if ( dbkey->data == NULL ) { 1.672 + goto loser; 1.673 + } 1.674 + dbkey->data[0] = (unsigned char) entryType; 1.675 + return(SECSuccess); 1.676 + } 1.677 + 1.678 + 1.679 + dbkey->len = certKey->len + SEC_DB_KEY_HEADER_LEN; 1.680 + if (dbkey->len > NSS_MAX_LEGACY_DB_KEY_SIZE) 1.681 + goto loser; 1.682 + dbkey->data = (unsigned char *)PORT_ArenaAlloc(arena, dbkey->len); 1.683 + if ( dbkey->data == NULL ) { 1.684 + goto loser; 1.685 + } 1.686 + PORT_Memcpy(&dbkey->data[SEC_DB_KEY_HEADER_LEN], 1.687 + certKey->data, certKey->len); 1.688 + dbkey->data[0] = (unsigned char) entryType; 1.689 + 1.690 + return(SECSuccess); 1.691 +loser: 1.692 + return(SECFailure); 1.693 +} 1.694 + 1.695 +static SECStatus 1.696 +DecodeDBCertEntry(certDBEntryCert *entry, SECItem *dbentry) 1.697 +{ 1.698 + unsigned int nnlen; 1.699 + unsigned int headerlen; 1.700 + int lenoff; 1.701 + 1.702 + /* allow updates of old versions of the database */ 1.703 + switch ( entry->common.version ) { 1.704 + case 5: 1.705 + headerlen = DB_CERT_V5_ENTRY_HEADER_LEN; 1.706 + lenoff = 3; 1.707 + break; 1.708 + case 6: 1.709 + /* should not get here */ 1.710 + PORT_Assert(0); 1.711 + headerlen = DB_CERT_V6_ENTRY_HEADER_LEN; 1.712 + lenoff = 3; 1.713 + break; 1.714 + case 7: 1.715 + case 8: 1.716 + headerlen = DB_CERT_ENTRY_HEADER_LEN; 1.717 + lenoff = 6; 1.718 + break; 1.719 + default: 1.720 + /* better not get here */ 1.721 + PORT_Assert(0); 1.722 + headerlen = DB_CERT_V5_ENTRY_HEADER_LEN; 1.723 + lenoff = 3; 1.724 + break; 1.725 + } 1.726 + 1.727 + /* is record long enough for header? */ 1.728 + if ( dbentry->len < headerlen ) { 1.729 + PORT_SetError(SEC_ERROR_BAD_DATABASE); 1.730 + goto loser; 1.731 + } 1.732 + 1.733 + /* is database entry correct length? */ 1.734 + entry->derCert.len = ( ( dbentry->data[lenoff] << 8 ) | 1.735 + dbentry->data[lenoff+1] ); 1.736 + nnlen = ( ( dbentry->data[lenoff+2] << 8 ) | dbentry->data[lenoff+3] ); 1.737 + lenoff = dbentry->len - ( entry->derCert.len + nnlen + headerlen ); 1.738 + if ( lenoff ) { 1.739 + if ( lenoff < 0 || (lenoff & 0xffff) != 0 ) { 1.740 + PORT_SetError(SEC_ERROR_BAD_DATABASE); 1.741 + goto loser; 1.742 + } 1.743 + /* The cert size exceeded 64KB. Reconstruct the correct length. */ 1.744 + entry->derCert.len += lenoff; 1.745 + } 1.746 + 1.747 + /* copy the dercert */ 1.748 + entry->derCert.data = pkcs11_copyStaticData(&dbentry->data[headerlen], 1.749 + entry->derCert.len,entry->derCertSpace,sizeof(entry->derCertSpace)); 1.750 + if ( entry->derCert.data == NULL ) { 1.751 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.752 + goto loser; 1.753 + } 1.754 + 1.755 + /* copy the nickname */ 1.756 + if ( nnlen > 1 ) { 1.757 + entry->nickname = (char *)pkcs11_copyStaticData( 1.758 + &dbentry->data[headerlen+entry->derCert.len], nnlen, 1.759 + (unsigned char *)entry->nicknameSpace, 1.760 + sizeof(entry->nicknameSpace)); 1.761 + if ( entry->nickname == NULL ) { 1.762 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.763 + goto loser; 1.764 + } 1.765 + } else { 1.766 + entry->nickname = NULL; 1.767 + } 1.768 + 1.769 + if ( entry->common.version < 7 ) { 1.770 + /* allow updates of v5 db */ 1.771 + entry->trust.sslFlags = dbentry->data[0]; 1.772 + entry->trust.emailFlags = dbentry->data[1]; 1.773 + entry->trust.objectSigningFlags = dbentry->data[2]; 1.774 + } else { 1.775 + entry->trust.sslFlags = ( dbentry->data[0] << 8 ) | dbentry->data[1]; 1.776 + entry->trust.emailFlags = ( dbentry->data[2] << 8 ) | dbentry->data[3]; 1.777 + entry->trust.objectSigningFlags = 1.778 + ( dbentry->data[4] << 8 ) | dbentry->data[5]; 1.779 + } 1.780 + 1.781 + return(SECSuccess); 1.782 +loser: 1.783 + return(SECFailure); 1.784 +} 1.785 + 1.786 + 1.787 +/* 1.788 + * Create a new certDBEntryCert from existing data 1.789 + */ 1.790 +static certDBEntryCert * 1.791 +NewDBCertEntry(SECItem *derCert, char *nickname, 1.792 + NSSLOWCERTCertTrust *trust, int flags) 1.793 +{ 1.794 + certDBEntryCert *entry; 1.795 + PLArenaPool *arena = NULL; 1.796 + int nnlen; 1.797 + 1.798 + arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE ); 1.799 + 1.800 + if ( !arena ) { 1.801 + goto loser; 1.802 + } 1.803 + 1.804 + entry = PORT_ArenaZNew(arena, certDBEntryCert); 1.805 + if ( entry == NULL ) { 1.806 + goto loser; 1.807 + } 1.808 + 1.809 + /* fill in the dbCert */ 1.810 + entry->common.arena = arena; 1.811 + entry->common.type = certDBEntryTypeCert; 1.812 + entry->common.version = CERT_DB_FILE_VERSION; 1.813 + entry->common.flags = flags; 1.814 + 1.815 + if ( trust ) { 1.816 + entry->trust = *trust; 1.817 + } 1.818 + 1.819 + entry->derCert.data = (unsigned char *)PORT_ArenaAlloc(arena, derCert->len); 1.820 + if ( !entry->derCert.data ) { 1.821 + goto loser; 1.822 + } 1.823 + entry->derCert.len = derCert->len; 1.824 + PORT_Memcpy(entry->derCert.data, derCert->data, derCert->len); 1.825 + 1.826 + nnlen = ( nickname ? strlen(nickname) + 1 : 0 ); 1.827 + 1.828 + if ( nnlen ) { 1.829 + entry->nickname = (char *)PORT_ArenaAlloc(arena, nnlen); 1.830 + if ( !entry->nickname ) { 1.831 + goto loser; 1.832 + } 1.833 + PORT_Memcpy(entry->nickname, nickname, nnlen); 1.834 + 1.835 + } else { 1.836 + entry->nickname = 0; 1.837 + } 1.838 + 1.839 + return(entry); 1.840 + 1.841 +loser: 1.842 + 1.843 + /* allocation error, free arena and return */ 1.844 + if ( arena ) { 1.845 + PORT_FreeArena(arena, PR_FALSE); 1.846 + } 1.847 + 1.848 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.849 + return(0); 1.850 +} 1.851 + 1.852 +/* 1.853 + * Decode a version 4 DBCert from the byte stream database format 1.854 + * and construct a current database entry struct 1.855 + */ 1.856 +static certDBEntryCert * 1.857 +DecodeV4DBCertEntry(unsigned char *buf, int len) 1.858 +{ 1.859 + certDBEntryCert *entry; 1.860 + int certlen; 1.861 + int nnlen; 1.862 + PLArenaPool *arena; 1.863 + 1.864 + /* make sure length is at least long enough for the header */ 1.865 + if ( len < DBCERT_V4_HEADER_LEN ) { 1.866 + PORT_SetError(SEC_ERROR_BAD_DATABASE); 1.867 + return(0); 1.868 + } 1.869 + 1.870 + /* get other lengths */ 1.871 + certlen = buf[3] << 8 | buf[4]; 1.872 + nnlen = buf[5] << 8 | buf[6]; 1.873 + 1.874 + /* make sure DB entry is the right size */ 1.875 + if ( ( certlen + nnlen + DBCERT_V4_HEADER_LEN ) != len ) { 1.876 + PORT_SetError(SEC_ERROR_BAD_DATABASE); 1.877 + return(0); 1.878 + } 1.879 + 1.880 + /* allocate arena */ 1.881 + arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE ); 1.882 + 1.883 + if ( !arena ) { 1.884 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.885 + return(0); 1.886 + } 1.887 + 1.888 + /* allocate structure and members */ 1.889 + entry = (certDBEntryCert *) PORT_ArenaAlloc(arena, sizeof(certDBEntryCert)); 1.890 + 1.891 + if ( !entry ) { 1.892 + goto loser; 1.893 + } 1.894 + 1.895 + entry->common.arena = arena; 1.896 + entry->common.version = CERT_DB_FILE_VERSION; 1.897 + entry->common.type = certDBEntryTypeCert; 1.898 + entry->common.flags = 0; 1.899 + entry->trust.sslFlags = buf[0]; 1.900 + entry->trust.emailFlags = buf[1]; 1.901 + entry->trust.objectSigningFlags = buf[2]; 1.902 + 1.903 + entry->derCert.data = (unsigned char *)PORT_ArenaAlloc(arena, certlen); 1.904 + if ( !entry->derCert.data ) { 1.905 + goto loser; 1.906 + } 1.907 + entry->derCert.len = certlen; 1.908 + PORT_Memcpy(entry->derCert.data, &buf[DBCERT_V4_HEADER_LEN], certlen); 1.909 + 1.910 + if ( nnlen ) { 1.911 + entry->nickname = (char *) PORT_ArenaAlloc(arena, nnlen); 1.912 + if ( !entry->nickname ) { 1.913 + goto loser; 1.914 + } 1.915 + PORT_Memcpy(entry->nickname, &buf[DBCERT_V4_HEADER_LEN + certlen], nnlen); 1.916 + 1.917 + if (PORT_Strcmp(entry->nickname, "Server-Cert") == 0) { 1.918 + entry->trust.sslFlags |= CERTDB_USER; 1.919 + } 1.920 + } else { 1.921 + entry->nickname = 0; 1.922 + } 1.923 + 1.924 + return(entry); 1.925 + 1.926 +loser: 1.927 + PORT_FreeArena(arena, PR_FALSE); 1.928 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.929 + return(0); 1.930 +} 1.931 + 1.932 +/* 1.933 + * Encode a Certificate database entry into byte stream suitable for 1.934 + * the database 1.935 + */ 1.936 +static SECStatus 1.937 +WriteDBCertEntry(NSSLOWCERTCertDBHandle *handle, certDBEntryCert *entry) 1.938 +{ 1.939 + SECItem dbitem, dbkey; 1.940 + PLArenaPool *tmparena = NULL; 1.941 + SECItem tmpitem; 1.942 + SECStatus rv; 1.943 + 1.944 + tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.945 + if ( tmparena == NULL ) { 1.946 + goto loser; 1.947 + } 1.948 + 1.949 + rv = EncodeDBCertEntry(entry, tmparena, &dbitem); 1.950 + if ( rv != SECSuccess ) { 1.951 + goto loser; 1.952 + } 1.953 + 1.954 + /* get the database key and format it */ 1.955 + rv = nsslowcert_KeyFromDERCert(tmparena, &entry->derCert, &tmpitem); 1.956 + if ( rv == SECFailure ) { 1.957 + goto loser; 1.958 + } 1.959 + 1.960 + rv = EncodeDBCertKey(&tmpitem, tmparena, &dbkey); 1.961 + if ( rv == SECFailure ) { 1.962 + goto loser; 1.963 + } 1.964 + 1.965 + /* now write it to the database */ 1.966 + rv = WriteDBEntry(handle, &entry->common, &dbkey, &dbitem); 1.967 + if ( rv != SECSuccess ) { 1.968 + goto loser; 1.969 + } 1.970 + 1.971 + PORT_FreeArena(tmparena, PR_FALSE); 1.972 + return(SECSuccess); 1.973 + 1.974 +loser: 1.975 + if ( tmparena ) { 1.976 + PORT_FreeArena(tmparena, PR_FALSE); 1.977 + } 1.978 + return(SECFailure); 1.979 +} 1.980 + 1.981 + 1.982 +/* 1.983 + * delete a certificate entry 1.984 + */ 1.985 +static SECStatus 1.986 +DeleteDBCertEntry(NSSLOWCERTCertDBHandle *handle, SECItem *certKey) 1.987 +{ 1.988 + SECItem dbkey; 1.989 + SECStatus rv; 1.990 + 1.991 + dbkey.data= NULL; 1.992 + dbkey.len = 0; 1.993 + 1.994 + rv = EncodeDBCertKey(certKey, NULL, &dbkey); 1.995 + if ( rv != SECSuccess ) { 1.996 + goto loser; 1.997 + } 1.998 + 1.999 + rv = DeleteDBEntry(handle, certDBEntryTypeCert, &dbkey); 1.1000 + if ( rv == SECFailure ) { 1.1001 + goto loser; 1.1002 + } 1.1003 + 1.1004 + PORT_Free(dbkey.data); 1.1005 + 1.1006 + return(SECSuccess); 1.1007 + 1.1008 +loser: 1.1009 + if (dbkey.data) { 1.1010 + PORT_Free(dbkey.data); 1.1011 + } 1.1012 + return(SECFailure); 1.1013 +} 1.1014 + 1.1015 +static certDBEntryCert * 1.1016 +CreateCertEntry(void) 1.1017 +{ 1.1018 + certDBEntryCert *entry; 1.1019 + 1.1020 + nsslowcert_LockFreeList(); 1.1021 + entry = entryListHead; 1.1022 + if (entry) { 1.1023 + entryListCount--; 1.1024 + entryListHead = entry->next; 1.1025 + } 1.1026 + PORT_Assert(entryListCount >= 0); 1.1027 + nsslowcert_UnlockFreeList(); 1.1028 + if (entry) { 1.1029 + return entry; 1.1030 + } 1.1031 + 1.1032 + return PORT_ZNew(certDBEntryCert); 1.1033 +} 1.1034 + 1.1035 +static void 1.1036 +DestroyCertEntryFreeList(void) 1.1037 +{ 1.1038 + certDBEntryCert *entry; 1.1039 + 1.1040 + nsslowcert_LockFreeList(); 1.1041 + while (NULL != (entry = entryListHead)) { 1.1042 + entryListCount--; 1.1043 + entryListHead = entry->next; 1.1044 + PORT_Free(entry); 1.1045 + } 1.1046 + PORT_Assert(!entryListCount); 1.1047 + entryListCount = 0; 1.1048 + nsslowcert_UnlockFreeList(); 1.1049 +} 1.1050 + 1.1051 +/* 1.1052 + * Read a certificate entry 1.1053 + */ 1.1054 +static certDBEntryCert * 1.1055 +ReadDBCertEntry(NSSLOWCERTCertDBHandle *handle, const SECItem *certKey) 1.1056 +{ 1.1057 + certDBEntryCert *entry; 1.1058 + SECItem dbkey; 1.1059 + SECItem dbentry; 1.1060 + SECStatus rv; 1.1061 + unsigned char buf[512]; 1.1062 + 1.1063 + dbkey.data = buf; 1.1064 + dbkey.len = sizeof(buf); 1.1065 + 1.1066 + entry = CreateCertEntry(); 1.1067 + if ( entry == NULL ) { 1.1068 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.1069 + goto loser; 1.1070 + } 1.1071 + entry->common.arena = NULL; 1.1072 + entry->common.type = certDBEntryTypeCert; 1.1073 + 1.1074 + rv = EncodeDBCertKey(certKey, NULL, &dbkey); 1.1075 + if ( rv != SECSuccess ) { 1.1076 + goto loser; 1.1077 + } 1.1078 + 1.1079 + rv = ReadDBEntry(handle, &entry->common, &dbkey, &dbentry, NULL); 1.1080 + if ( rv == SECFailure ) { 1.1081 + goto loser; 1.1082 + } 1.1083 + 1.1084 + rv = DecodeDBCertEntry(entry, &dbentry); 1.1085 + if ( rv != SECSuccess ) { 1.1086 + goto loser; 1.1087 + } 1.1088 + 1.1089 + pkcs11_freeStaticData(dbkey.data,buf); 1.1090 + dbkey.data = NULL; 1.1091 + return(entry); 1.1092 + 1.1093 +loser: 1.1094 + pkcs11_freeStaticData(dbkey.data,buf); 1.1095 + dbkey.data = NULL; 1.1096 + if ( entry ) { 1.1097 + DestroyDBEntry((certDBEntry *)entry); 1.1098 + } 1.1099 + 1.1100 + return(NULL); 1.1101 +} 1.1102 + 1.1103 +/* 1.1104 + * encode a database cert record 1.1105 + */ 1.1106 +static SECStatus 1.1107 +EncodeDBCrlEntry(certDBEntryRevocation *entry, PLArenaPool *arena, SECItem *dbitem) 1.1108 +{ 1.1109 + unsigned int nnlen = 0; 1.1110 + unsigned char *buf; 1.1111 + 1.1112 + if (entry->url) { 1.1113 + nnlen = PORT_Strlen(entry->url) + 1; 1.1114 + } 1.1115 + 1.1116 + /* allocate space for encoded database record, including space 1.1117 + * for low level header 1.1118 + */ 1.1119 + dbitem->len = entry->derCrl.len + nnlen 1.1120 + + SEC_DB_ENTRY_HEADER_LEN + DB_CRL_ENTRY_HEADER_LEN; 1.1121 + 1.1122 + dbitem->data = (unsigned char *)PORT_ArenaAlloc(arena, dbitem->len); 1.1123 + if ( dbitem->data == NULL) { 1.1124 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.1125 + goto loser; 1.1126 + } 1.1127 + 1.1128 + /* fill in database record */ 1.1129 + buf = &dbitem->data[SEC_DB_ENTRY_HEADER_LEN]; 1.1130 + 1.1131 + buf[0] = (PRUint8)( entry->derCrl.len >> 8 ); 1.1132 + buf[1] = (PRUint8)( entry->derCrl.len ); 1.1133 + buf[2] = (PRUint8)( nnlen >> 8 ); 1.1134 + buf[3] = (PRUint8)( nnlen ); 1.1135 + 1.1136 + PORT_Memcpy(&buf[DB_CRL_ENTRY_HEADER_LEN], entry->derCrl.data, 1.1137 + entry->derCrl.len); 1.1138 + 1.1139 + if (nnlen != 0) { 1.1140 + PORT_Memcpy(&buf[DB_CRL_ENTRY_HEADER_LEN + entry->derCrl.len], 1.1141 + entry->url, nnlen); 1.1142 + } 1.1143 + 1.1144 + return(SECSuccess); 1.1145 + 1.1146 +loser: 1.1147 + return(SECFailure); 1.1148 +} 1.1149 + 1.1150 +static SECStatus 1.1151 +DecodeDBCrlEntry(certDBEntryRevocation *entry, SECItem *dbentry) 1.1152 +{ 1.1153 + unsigned int urlLen; 1.1154 + int lenDiff; 1.1155 + 1.1156 + /* is record long enough for header? */ 1.1157 + if ( dbentry->len < DB_CRL_ENTRY_HEADER_LEN ) { 1.1158 + PORT_SetError(SEC_ERROR_BAD_DATABASE); 1.1159 + goto loser; 1.1160 + } 1.1161 + 1.1162 + /* is database entry correct length? */ 1.1163 + entry->derCrl.len = ( ( dbentry->data[0] << 8 ) | dbentry->data[1] ); 1.1164 + urlLen = ( ( dbentry->data[2] << 8 ) | dbentry->data[3] ); 1.1165 + lenDiff = dbentry->len - 1.1166 + (entry->derCrl.len + urlLen + DB_CRL_ENTRY_HEADER_LEN); 1.1167 + if (lenDiff) { 1.1168 + if (lenDiff < 0 || (lenDiff & 0xffff) != 0) { 1.1169 + PORT_SetError(SEC_ERROR_BAD_DATABASE); 1.1170 + goto loser; 1.1171 + } 1.1172 + /* CRL entry is greater than 64 K. Hack to make this continue to work */ 1.1173 + entry->derCrl.len += lenDiff; 1.1174 + } 1.1175 + 1.1176 + /* copy the der CRL */ 1.1177 + entry->derCrl.data = (unsigned char *)PORT_ArenaAlloc(entry->common.arena, 1.1178 + entry->derCrl.len); 1.1179 + if ( entry->derCrl.data == NULL ) { 1.1180 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.1181 + goto loser; 1.1182 + } 1.1183 + PORT_Memcpy(entry->derCrl.data, &dbentry->data[DB_CRL_ENTRY_HEADER_LEN], 1.1184 + entry->derCrl.len); 1.1185 + 1.1186 + /* copy the url */ 1.1187 + entry->url = NULL; 1.1188 + if (urlLen != 0) { 1.1189 + entry->url = (char *)PORT_ArenaAlloc(entry->common.arena, urlLen); 1.1190 + if ( entry->url == NULL ) { 1.1191 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.1192 + goto loser; 1.1193 + } 1.1194 + PORT_Memcpy(entry->url, 1.1195 + &dbentry->data[DB_CRL_ENTRY_HEADER_LEN + entry->derCrl.len], 1.1196 + urlLen); 1.1197 + } 1.1198 + 1.1199 + return(SECSuccess); 1.1200 +loser: 1.1201 + return(SECFailure); 1.1202 +} 1.1203 + 1.1204 +/* 1.1205 + * Create a new certDBEntryRevocation from existing data 1.1206 + */ 1.1207 +static certDBEntryRevocation * 1.1208 +NewDBCrlEntry(SECItem *derCrl, char * url, certDBEntryType crlType, int flags) 1.1209 +{ 1.1210 + certDBEntryRevocation *entry; 1.1211 + PLArenaPool *arena = NULL; 1.1212 + int nnlen; 1.1213 + 1.1214 + arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE ); 1.1215 + 1.1216 + if ( !arena ) { 1.1217 + goto loser; 1.1218 + } 1.1219 + 1.1220 + entry = PORT_ArenaZNew(arena, certDBEntryRevocation); 1.1221 + if ( entry == NULL ) { 1.1222 + goto loser; 1.1223 + } 1.1224 + 1.1225 + /* fill in the dbRevolcation */ 1.1226 + entry->common.arena = arena; 1.1227 + entry->common.type = crlType; 1.1228 + entry->common.version = CERT_DB_FILE_VERSION; 1.1229 + entry->common.flags = flags; 1.1230 + 1.1231 + 1.1232 + entry->derCrl.data = (unsigned char *)PORT_ArenaAlloc(arena, derCrl->len); 1.1233 + if ( !entry->derCrl.data ) { 1.1234 + goto loser; 1.1235 + } 1.1236 + 1.1237 + if (url) { 1.1238 + nnlen = PORT_Strlen(url) + 1; 1.1239 + entry->url = (char *)PORT_ArenaAlloc(arena, nnlen); 1.1240 + if ( !entry->url ) { 1.1241 + goto loser; 1.1242 + } 1.1243 + PORT_Memcpy(entry->url, url, nnlen); 1.1244 + } else { 1.1245 + entry->url = NULL; 1.1246 + } 1.1247 + 1.1248 + 1.1249 + entry->derCrl.len = derCrl->len; 1.1250 + PORT_Memcpy(entry->derCrl.data, derCrl->data, derCrl->len); 1.1251 + 1.1252 + return(entry); 1.1253 + 1.1254 +loser: 1.1255 + 1.1256 + /* allocation error, free arena and return */ 1.1257 + if ( arena ) { 1.1258 + PORT_FreeArena(arena, PR_FALSE); 1.1259 + } 1.1260 + 1.1261 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.1262 + return(0); 1.1263 +} 1.1264 + 1.1265 + 1.1266 +static SECStatus 1.1267 +WriteDBCrlEntry(NSSLOWCERTCertDBHandle *handle, certDBEntryRevocation *entry, 1.1268 + SECItem *crlKey ) 1.1269 +{ 1.1270 + SECItem dbkey; 1.1271 + PLArenaPool *tmparena = NULL; 1.1272 + SECItem encodedEntry; 1.1273 + SECStatus rv; 1.1274 + 1.1275 + tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.1276 + if ( tmparena == NULL ) { 1.1277 + goto loser; 1.1278 + } 1.1279 + 1.1280 + rv = EncodeDBCrlEntry(entry, tmparena, &encodedEntry); 1.1281 + if ( rv == SECFailure ) { 1.1282 + goto loser; 1.1283 + } 1.1284 + 1.1285 + rv = EncodeDBGenericKey(crlKey, tmparena, &dbkey, entry->common.type); 1.1286 + if ( rv == SECFailure ) { 1.1287 + goto loser; 1.1288 + } 1.1289 + 1.1290 + /* now write it to the database */ 1.1291 + rv = WriteDBEntry(handle, &entry->common, &dbkey, &encodedEntry); 1.1292 + if ( rv != SECSuccess ) { 1.1293 + goto loser; 1.1294 + } 1.1295 + 1.1296 + PORT_FreeArena(tmparena, PR_FALSE); 1.1297 + return(SECSuccess); 1.1298 + 1.1299 +loser: 1.1300 + if ( tmparena ) { 1.1301 + PORT_FreeArena(tmparena, PR_FALSE); 1.1302 + } 1.1303 + return(SECFailure); 1.1304 +} 1.1305 +/* 1.1306 + * delete a crl entry 1.1307 + */ 1.1308 +static SECStatus 1.1309 +DeleteDBCrlEntry(NSSLOWCERTCertDBHandle *handle, const SECItem *crlKey, 1.1310 + certDBEntryType crlType) 1.1311 +{ 1.1312 + SECItem dbkey; 1.1313 + PLArenaPool *arena = NULL; 1.1314 + SECStatus rv; 1.1315 + 1.1316 + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.1317 + if ( arena == NULL ) { 1.1318 + goto loser; 1.1319 + } 1.1320 + 1.1321 + rv = EncodeDBGenericKey(crlKey, arena, &dbkey, crlType); 1.1322 + if ( rv != SECSuccess ) { 1.1323 + goto loser; 1.1324 + } 1.1325 + 1.1326 + rv = DeleteDBEntry(handle, crlType, &dbkey); 1.1327 + if ( rv == SECFailure ) { 1.1328 + goto loser; 1.1329 + } 1.1330 + 1.1331 + PORT_FreeArena(arena, PR_FALSE); 1.1332 + return(SECSuccess); 1.1333 + 1.1334 +loser: 1.1335 + if ( arena ) { 1.1336 + PORT_FreeArena(arena, PR_FALSE); 1.1337 + } 1.1338 + 1.1339 + return(SECFailure); 1.1340 +} 1.1341 + 1.1342 +/* 1.1343 + * Read a certificate entry 1.1344 + */ 1.1345 +static certDBEntryRevocation * 1.1346 +ReadDBCrlEntry(NSSLOWCERTCertDBHandle *handle, SECItem *certKey, 1.1347 + certDBEntryType crlType) 1.1348 +{ 1.1349 + PLArenaPool *arena = NULL; 1.1350 + PLArenaPool *tmparena = NULL; 1.1351 + certDBEntryRevocation *entry; 1.1352 + SECItem dbkey; 1.1353 + SECItem dbentry; 1.1354 + SECStatus rv; 1.1355 + 1.1356 + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.1357 + if ( arena == NULL ) { 1.1358 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.1359 + goto loser; 1.1360 + } 1.1361 + 1.1362 + tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.1363 + if ( tmparena == NULL ) { 1.1364 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.1365 + goto loser; 1.1366 + } 1.1367 + 1.1368 + entry = (certDBEntryRevocation *) 1.1369 + PORT_ArenaAlloc(arena, sizeof(certDBEntryRevocation)); 1.1370 + if ( entry == NULL ) { 1.1371 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.1372 + goto loser; 1.1373 + } 1.1374 + entry->common.arena = arena; 1.1375 + entry->common.type = crlType; 1.1376 + 1.1377 + rv = EncodeDBGenericKey(certKey, tmparena, &dbkey, crlType); 1.1378 + if ( rv != SECSuccess ) { 1.1379 + goto loser; 1.1380 + } 1.1381 + 1.1382 + rv = ReadDBEntry(handle, &entry->common, &dbkey, &dbentry, NULL); 1.1383 + if ( rv == SECFailure ) { 1.1384 + goto loser; 1.1385 + } 1.1386 + 1.1387 + rv = DecodeDBCrlEntry(entry, &dbentry); 1.1388 + if ( rv != SECSuccess ) { 1.1389 + goto loser; 1.1390 + } 1.1391 + 1.1392 + PORT_FreeArena(tmparena, PR_FALSE); 1.1393 + return(entry); 1.1394 + 1.1395 +loser: 1.1396 + if ( tmparena ) { 1.1397 + PORT_FreeArena(tmparena, PR_FALSE); 1.1398 + } 1.1399 + if ( arena ) { 1.1400 + PORT_FreeArena(arena, PR_FALSE); 1.1401 + } 1.1402 + 1.1403 + return(NULL); 1.1404 +} 1.1405 + 1.1406 +void 1.1407 +nsslowcert_DestroyDBEntry(certDBEntry *entry) 1.1408 +{ 1.1409 + DestroyDBEntry(entry); 1.1410 + return; 1.1411 +} 1.1412 + 1.1413 +/* 1.1414 + * Encode a database nickname record 1.1415 + */ 1.1416 +static SECStatus 1.1417 +EncodeDBNicknameEntry(certDBEntryNickname *entry, PLArenaPool *arena, 1.1418 + SECItem *dbitem) 1.1419 +{ 1.1420 + unsigned char *buf; 1.1421 + 1.1422 + /* allocate space for encoded database record, including space 1.1423 + * for low level header 1.1424 + */ 1.1425 + dbitem->len = entry->subjectName.len + DB_NICKNAME_ENTRY_HEADER_LEN + 1.1426 + SEC_DB_ENTRY_HEADER_LEN; 1.1427 + dbitem->data = (unsigned char *)PORT_ArenaAlloc(arena, dbitem->len); 1.1428 + if ( dbitem->data == NULL) { 1.1429 + goto loser; 1.1430 + } 1.1431 + 1.1432 + /* fill in database record */ 1.1433 + buf = &dbitem->data[SEC_DB_ENTRY_HEADER_LEN]; 1.1434 + buf[0] = (PRUint8)( entry->subjectName.len >> 8 ); 1.1435 + buf[1] = (PRUint8)( entry->subjectName.len ); 1.1436 + PORT_Memcpy(&buf[DB_NICKNAME_ENTRY_HEADER_LEN], entry->subjectName.data, 1.1437 + entry->subjectName.len); 1.1438 + 1.1439 + return(SECSuccess); 1.1440 + 1.1441 +loser: 1.1442 + return(SECFailure); 1.1443 +} 1.1444 + 1.1445 +/* 1.1446 + * Encode a database key for a nickname record 1.1447 + */ 1.1448 +static SECStatus 1.1449 +EncodeDBNicknameKey(char *nickname, PLArenaPool *arena, 1.1450 + SECItem *dbkey) 1.1451 +{ 1.1452 + unsigned int nnlen; 1.1453 + 1.1454 + nnlen = PORT_Strlen(nickname) + 1; /* includes null */ 1.1455 + 1.1456 + /* now get the database key and format it */ 1.1457 + dbkey->len = nnlen + SEC_DB_KEY_HEADER_LEN; 1.1458 + if (dbkey->len > NSS_MAX_LEGACY_DB_KEY_SIZE) 1.1459 + goto loser; 1.1460 + dbkey->data = (unsigned char *)PORT_ArenaAlloc(arena, dbkey->len); 1.1461 + if ( dbkey->data == NULL ) { 1.1462 + goto loser; 1.1463 + } 1.1464 + PORT_Memcpy(&dbkey->data[SEC_DB_KEY_HEADER_LEN], nickname, nnlen); 1.1465 + dbkey->data[0] = certDBEntryTypeNickname; 1.1466 + 1.1467 + return(SECSuccess); 1.1468 + 1.1469 +loser: 1.1470 + return(SECFailure); 1.1471 +} 1.1472 + 1.1473 +static SECStatus 1.1474 +DecodeDBNicknameEntry(certDBEntryNickname *entry, SECItem *dbentry, 1.1475 + char *nickname) 1.1476 +{ 1.1477 + int lenDiff; 1.1478 + 1.1479 + /* is record long enough for header? */ 1.1480 + if ( dbentry->len < DB_NICKNAME_ENTRY_HEADER_LEN ) { 1.1481 + PORT_SetError(SEC_ERROR_BAD_DATABASE); 1.1482 + goto loser; 1.1483 + } 1.1484 + 1.1485 + /* is database entry correct length? */ 1.1486 + entry->subjectName.len = ( ( dbentry->data[0] << 8 ) | dbentry->data[1] ); 1.1487 + lenDiff = dbentry->len - 1.1488 + (entry->subjectName.len + DB_NICKNAME_ENTRY_HEADER_LEN); 1.1489 + if (lenDiff) { 1.1490 + if (lenDiff < 0 || (lenDiff & 0xffff) != 0 ) { 1.1491 + PORT_SetError(SEC_ERROR_BAD_DATABASE); 1.1492 + goto loser; 1.1493 + } 1.1494 + /* The entry size exceeded 64KB. Reconstruct the correct length. */ 1.1495 + entry->subjectName.len += lenDiff; 1.1496 + } 1.1497 + 1.1498 + /* copy the certkey */ 1.1499 + entry->subjectName.data = 1.1500 + (unsigned char *)PORT_ArenaAlloc(entry->common.arena, 1.1501 + entry->subjectName.len); 1.1502 + if ( entry->subjectName.data == NULL ) { 1.1503 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.1504 + goto loser; 1.1505 + } 1.1506 + PORT_Memcpy(entry->subjectName.data, 1.1507 + &dbentry->data[DB_NICKNAME_ENTRY_HEADER_LEN], 1.1508 + entry->subjectName.len); 1.1509 + entry->subjectName.type = siBuffer; 1.1510 + 1.1511 + entry->nickname = (char *)PORT_ArenaAlloc(entry->common.arena, 1.1512 + PORT_Strlen(nickname)+1); 1.1513 + if ( entry->nickname ) { 1.1514 + PORT_Strcpy(entry->nickname, nickname); 1.1515 + } 1.1516 + 1.1517 + return(SECSuccess); 1.1518 + 1.1519 +loser: 1.1520 + return(SECFailure); 1.1521 +} 1.1522 + 1.1523 +/* 1.1524 + * create a new nickname entry 1.1525 + */ 1.1526 +static certDBEntryNickname * 1.1527 +NewDBNicknameEntry(char *nickname, SECItem *subjectName, unsigned int flags) 1.1528 +{ 1.1529 + PLArenaPool *arena = NULL; 1.1530 + certDBEntryNickname *entry; 1.1531 + int nnlen; 1.1532 + SECStatus rv; 1.1533 + 1.1534 + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.1535 + if ( arena == NULL ) { 1.1536 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.1537 + goto loser; 1.1538 + } 1.1539 + 1.1540 + entry = (certDBEntryNickname *)PORT_ArenaAlloc(arena, 1.1541 + sizeof(certDBEntryNickname)); 1.1542 + if ( entry == NULL ) { 1.1543 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.1544 + goto loser; 1.1545 + } 1.1546 + 1.1547 + /* init common fields */ 1.1548 + entry->common.arena = arena; 1.1549 + entry->common.type = certDBEntryTypeNickname; 1.1550 + entry->common.version = CERT_DB_FILE_VERSION; 1.1551 + entry->common.flags = flags; 1.1552 + 1.1553 + /* copy the nickname */ 1.1554 + nnlen = PORT_Strlen(nickname) + 1; 1.1555 + 1.1556 + entry->nickname = (char*)PORT_ArenaAlloc(arena, nnlen); 1.1557 + if ( entry->nickname == NULL ) { 1.1558 + goto loser; 1.1559 + } 1.1560 + 1.1561 + PORT_Memcpy(entry->nickname, nickname, nnlen); 1.1562 + 1.1563 + rv = SECITEM_CopyItem(arena, &entry->subjectName, subjectName); 1.1564 + if ( rv != SECSuccess ) { 1.1565 + goto loser; 1.1566 + } 1.1567 + 1.1568 + return(entry); 1.1569 +loser: 1.1570 + if ( arena ) { 1.1571 + PORT_FreeArena(arena, PR_FALSE); 1.1572 + } 1.1573 + 1.1574 + return(NULL); 1.1575 +} 1.1576 + 1.1577 +/* 1.1578 + * delete a nickname entry 1.1579 + */ 1.1580 +static SECStatus 1.1581 +DeleteDBNicknameEntry(NSSLOWCERTCertDBHandle *handle, char *nickname) 1.1582 +{ 1.1583 + PLArenaPool *arena = NULL; 1.1584 + SECStatus rv; 1.1585 + SECItem dbkey; 1.1586 + 1.1587 + if ( nickname == NULL ) { 1.1588 + return(SECSuccess); 1.1589 + } 1.1590 + 1.1591 + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.1592 + if ( arena == NULL ) { 1.1593 + goto loser; 1.1594 + } 1.1595 + 1.1596 + rv = EncodeDBNicknameKey(nickname, arena, &dbkey); 1.1597 + if ( rv != SECSuccess ) { 1.1598 + goto loser; 1.1599 + } 1.1600 + 1.1601 + rv = DeleteDBEntry(handle, certDBEntryTypeNickname, &dbkey); 1.1602 + if ( rv == SECFailure ) { 1.1603 + goto loser; 1.1604 + } 1.1605 + 1.1606 + PORT_FreeArena(arena, PR_FALSE); 1.1607 + return(SECSuccess); 1.1608 + 1.1609 +loser: 1.1610 + if ( arena ) { 1.1611 + PORT_FreeArena(arena, PR_FALSE); 1.1612 + } 1.1613 + 1.1614 + return(SECFailure); 1.1615 +} 1.1616 + 1.1617 +/* 1.1618 + * Read a nickname entry 1.1619 + */ 1.1620 +static certDBEntryNickname * 1.1621 +ReadDBNicknameEntry(NSSLOWCERTCertDBHandle *handle, char *nickname) 1.1622 +{ 1.1623 + PLArenaPool *arena = NULL; 1.1624 + PLArenaPool *tmparena = NULL; 1.1625 + certDBEntryNickname *entry; 1.1626 + SECItem dbkey; 1.1627 + SECItem dbentry; 1.1628 + SECStatus rv; 1.1629 + 1.1630 + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.1631 + if ( arena == NULL ) { 1.1632 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.1633 + goto loser; 1.1634 + } 1.1635 + 1.1636 + tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.1637 + if ( tmparena == NULL ) { 1.1638 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.1639 + goto loser; 1.1640 + } 1.1641 + 1.1642 + entry = (certDBEntryNickname *)PORT_ArenaAlloc(arena, 1.1643 + sizeof(certDBEntryNickname)); 1.1644 + if ( entry == NULL ) { 1.1645 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.1646 + goto loser; 1.1647 + } 1.1648 + entry->common.arena = arena; 1.1649 + entry->common.type = certDBEntryTypeNickname; 1.1650 + 1.1651 + rv = EncodeDBNicknameKey(nickname, tmparena, &dbkey); 1.1652 + if ( rv != SECSuccess ) { 1.1653 + goto loser; 1.1654 + } 1.1655 + 1.1656 + rv = ReadDBEntry(handle, &entry->common, &dbkey, &dbentry, tmparena); 1.1657 + if ( rv == SECFailure ) { 1.1658 + goto loser; 1.1659 + } 1.1660 + 1.1661 + /* is record long enough for header? */ 1.1662 + if ( dbentry.len < DB_NICKNAME_ENTRY_HEADER_LEN ) { 1.1663 + PORT_SetError(SEC_ERROR_BAD_DATABASE); 1.1664 + goto loser; 1.1665 + } 1.1666 + 1.1667 + rv = DecodeDBNicknameEntry(entry, &dbentry, nickname); 1.1668 + if ( rv != SECSuccess ) { 1.1669 + goto loser; 1.1670 + } 1.1671 + 1.1672 + PORT_FreeArena(tmparena, PR_FALSE); 1.1673 + return(entry); 1.1674 + 1.1675 +loser: 1.1676 + if ( tmparena ) { 1.1677 + PORT_FreeArena(tmparena, PR_FALSE); 1.1678 + } 1.1679 + if ( arena ) { 1.1680 + PORT_FreeArena(arena, PR_FALSE); 1.1681 + } 1.1682 + 1.1683 + return(NULL); 1.1684 +} 1.1685 + 1.1686 +/* 1.1687 + * Encode a nickname entry into byte stream suitable for 1.1688 + * the database 1.1689 + */ 1.1690 +static SECStatus 1.1691 +WriteDBNicknameEntry(NSSLOWCERTCertDBHandle *handle, certDBEntryNickname *entry) 1.1692 +{ 1.1693 + SECItem dbitem, dbkey; 1.1694 + PLArenaPool *tmparena = NULL; 1.1695 + SECStatus rv; 1.1696 + 1.1697 + tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.1698 + if ( tmparena == NULL ) { 1.1699 + goto loser; 1.1700 + } 1.1701 + 1.1702 + rv = EncodeDBNicknameEntry(entry, tmparena, &dbitem); 1.1703 + if ( rv != SECSuccess ) { 1.1704 + goto loser; 1.1705 + } 1.1706 + 1.1707 + rv = EncodeDBNicknameKey(entry->nickname, tmparena, &dbkey); 1.1708 + if ( rv != SECSuccess ) { 1.1709 + goto loser; 1.1710 + } 1.1711 + 1.1712 + /* now write it to the database */ 1.1713 + rv = WriteDBEntry(handle, &entry->common, &dbkey, &dbitem); 1.1714 + if ( rv != SECSuccess ) { 1.1715 + goto loser; 1.1716 + } 1.1717 + 1.1718 + PORT_FreeArena(tmparena, PR_FALSE); 1.1719 + return(SECSuccess); 1.1720 + 1.1721 +loser: 1.1722 + if ( tmparena ) { 1.1723 + PORT_FreeArena(tmparena, PR_FALSE); 1.1724 + } 1.1725 + return(SECFailure); 1.1726 + 1.1727 +} 1.1728 + 1.1729 +static SECStatus 1.1730 +EncodeDBSMimeEntry(certDBEntrySMime *entry, PLArenaPool *arena, 1.1731 + SECItem *dbitem) 1.1732 +{ 1.1733 + unsigned char *buf; 1.1734 + 1.1735 + /* allocate space for encoded database record, including space 1.1736 + * for low level header 1.1737 + */ 1.1738 + dbitem->len = entry->subjectName.len + entry->smimeOptions.len + 1.1739 + entry->optionsDate.len + 1.1740 + DB_SMIME_ENTRY_HEADER_LEN + SEC_DB_ENTRY_HEADER_LEN; 1.1741 + 1.1742 + dbitem->data = (unsigned char *)PORT_ArenaAlloc(arena, dbitem->len); 1.1743 + if ( dbitem->data == NULL) { 1.1744 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.1745 + goto loser; 1.1746 + } 1.1747 + 1.1748 + /* fill in database record */ 1.1749 + buf = &dbitem->data[SEC_DB_ENTRY_HEADER_LEN]; 1.1750 + 1.1751 + buf[0] = (PRUint8)( entry->subjectName.len >> 8 ); 1.1752 + buf[1] = (PRUint8)( entry->subjectName.len ); 1.1753 + buf[2] = (PRUint8)( entry->smimeOptions.len >> 8 ); 1.1754 + buf[3] = (PRUint8)( entry->smimeOptions.len ); 1.1755 + buf[4] = (PRUint8)( entry->optionsDate.len >> 8 ); 1.1756 + buf[5] = (PRUint8)( entry->optionsDate.len ); 1.1757 + 1.1758 + /* if no smime options, then there should not be an options date either */ 1.1759 + PORT_Assert( ! ( ( entry->smimeOptions.len == 0 ) && 1.1760 + ( entry->optionsDate.len != 0 ) ) ); 1.1761 + 1.1762 + PORT_Memcpy(&buf[DB_SMIME_ENTRY_HEADER_LEN], entry->subjectName.data, 1.1763 + entry->subjectName.len); 1.1764 + if ( entry->smimeOptions.len ) { 1.1765 + PORT_Memcpy(&buf[DB_SMIME_ENTRY_HEADER_LEN+entry->subjectName.len], 1.1766 + entry->smimeOptions.data, 1.1767 + entry->smimeOptions.len); 1.1768 + PORT_Memcpy(&buf[DB_SMIME_ENTRY_HEADER_LEN + entry->subjectName.len + 1.1769 + entry->smimeOptions.len], 1.1770 + entry->optionsDate.data, 1.1771 + entry->optionsDate.len); 1.1772 + } 1.1773 + 1.1774 + return(SECSuccess); 1.1775 + 1.1776 +loser: 1.1777 + return(SECFailure); 1.1778 +} 1.1779 + 1.1780 +/* 1.1781 + * Encode a database key for a SMIME record 1.1782 + */ 1.1783 +static SECStatus 1.1784 +EncodeDBSMimeKey(char *emailAddr, PLArenaPool *arena, 1.1785 + SECItem *dbkey) 1.1786 +{ 1.1787 + unsigned int addrlen; 1.1788 + 1.1789 + addrlen = PORT_Strlen(emailAddr) + 1; /* includes null */ 1.1790 + 1.1791 + /* now get the database key and format it */ 1.1792 + dbkey->len = addrlen + SEC_DB_KEY_HEADER_LEN; 1.1793 + if (dbkey->len > NSS_MAX_LEGACY_DB_KEY_SIZE) 1.1794 + goto loser; 1.1795 + dbkey->data = (unsigned char *)PORT_ArenaAlloc(arena, dbkey->len); 1.1796 + if ( dbkey->data == NULL ) { 1.1797 + goto loser; 1.1798 + } 1.1799 + PORT_Memcpy(&dbkey->data[SEC_DB_KEY_HEADER_LEN], emailAddr, addrlen); 1.1800 + dbkey->data[0] = certDBEntryTypeSMimeProfile; 1.1801 + 1.1802 + return(SECSuccess); 1.1803 + 1.1804 +loser: 1.1805 + return(SECFailure); 1.1806 +} 1.1807 + 1.1808 +/* 1.1809 + * Decode a database SMIME record 1.1810 + */ 1.1811 +static SECStatus 1.1812 +DecodeDBSMimeEntry(certDBEntrySMime *entry, SECItem *dbentry, char *emailAddr) 1.1813 +{ 1.1814 + int lenDiff; 1.1815 + 1.1816 + /* is record long enough for header? */ 1.1817 + if ( dbentry->len < DB_SMIME_ENTRY_HEADER_LEN ) { 1.1818 + PORT_SetError(SEC_ERROR_BAD_DATABASE); 1.1819 + goto loser; 1.1820 + } 1.1821 + 1.1822 + /* is database entry correct length? */ 1.1823 + entry->subjectName.len = (( dbentry->data[0] << 8 ) | dbentry->data[1] ); 1.1824 + entry->smimeOptions.len = (( dbentry->data[2] << 8 ) | dbentry->data[3] ); 1.1825 + entry->optionsDate.len = (( dbentry->data[4] << 8 ) | dbentry->data[5] ); 1.1826 + lenDiff = dbentry->len - (entry->subjectName.len + 1.1827 + entry->smimeOptions.len + 1.1828 + entry->optionsDate.len + 1.1829 + DB_SMIME_ENTRY_HEADER_LEN); 1.1830 + if (lenDiff) { 1.1831 + if (lenDiff < 0 || (lenDiff & 0xffff) != 0 ) { 1.1832 + PORT_SetError(SEC_ERROR_BAD_DATABASE); 1.1833 + goto loser; 1.1834 + } 1.1835 + /* The entry size exceeded 64KB. Reconstruct the correct length. */ 1.1836 + entry->subjectName.len += lenDiff; 1.1837 + } 1.1838 + 1.1839 + /* copy the subject name */ 1.1840 + entry->subjectName.data = 1.1841 + (unsigned char *)PORT_ArenaAlloc(entry->common.arena, 1.1842 + entry->subjectName.len); 1.1843 + if ( entry->subjectName.data == NULL ) { 1.1844 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.1845 + goto loser; 1.1846 + } 1.1847 + PORT_Memcpy(entry->subjectName.data, 1.1848 + &dbentry->data[DB_SMIME_ENTRY_HEADER_LEN], 1.1849 + entry->subjectName.len); 1.1850 + 1.1851 + /* copy the smime options */ 1.1852 + if ( entry->smimeOptions.len ) { 1.1853 + entry->smimeOptions.data = 1.1854 + (unsigned char *)PORT_ArenaAlloc(entry->common.arena, 1.1855 + entry->smimeOptions.len); 1.1856 + if ( entry->smimeOptions.data == NULL ) { 1.1857 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.1858 + goto loser; 1.1859 + } 1.1860 + PORT_Memcpy(entry->smimeOptions.data, 1.1861 + &dbentry->data[DB_SMIME_ENTRY_HEADER_LEN + 1.1862 + entry->subjectName.len], 1.1863 + entry->smimeOptions.len); 1.1864 + } 1.1865 + if ( entry->optionsDate.len ) { 1.1866 + entry->optionsDate.data = 1.1867 + (unsigned char *)PORT_ArenaAlloc(entry->common.arena, 1.1868 + entry->optionsDate.len); 1.1869 + if ( entry->optionsDate.data == NULL ) { 1.1870 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.1871 + goto loser; 1.1872 + } 1.1873 + PORT_Memcpy(entry->optionsDate.data, 1.1874 + &dbentry->data[DB_SMIME_ENTRY_HEADER_LEN + 1.1875 + entry->subjectName.len + 1.1876 + entry->smimeOptions.len], 1.1877 + entry->optionsDate.len); 1.1878 + } 1.1879 + 1.1880 + /* both options and options date must either exist or not exist */ 1.1881 + if ( ( ( entry->optionsDate.len == 0 ) || 1.1882 + ( entry->smimeOptions.len == 0 ) ) && 1.1883 + entry->smimeOptions.len != entry->optionsDate.len ) { 1.1884 + PORT_SetError(SEC_ERROR_BAD_DATABASE); 1.1885 + goto loser; 1.1886 + } 1.1887 + 1.1888 + entry->emailAddr = (char *)PORT_ArenaAlloc(entry->common.arena, 1.1889 + PORT_Strlen(emailAddr)+1); 1.1890 + if ( entry->emailAddr ) { 1.1891 + PORT_Strcpy(entry->emailAddr, emailAddr); 1.1892 + } 1.1893 + 1.1894 + return(SECSuccess); 1.1895 + 1.1896 +loser: 1.1897 + return(SECFailure); 1.1898 +} 1.1899 + 1.1900 +/* 1.1901 + * create a new SMIME entry 1.1902 + */ 1.1903 +static certDBEntrySMime * 1.1904 +NewDBSMimeEntry(char *emailAddr, SECItem *subjectName, SECItem *smimeOptions, 1.1905 + SECItem *optionsDate, unsigned int flags) 1.1906 +{ 1.1907 + PLArenaPool *arena = NULL; 1.1908 + certDBEntrySMime *entry; 1.1909 + int addrlen; 1.1910 + SECStatus rv; 1.1911 + 1.1912 + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.1913 + if ( arena == NULL ) { 1.1914 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.1915 + goto loser; 1.1916 + } 1.1917 + 1.1918 + entry = (certDBEntrySMime *)PORT_ArenaAlloc(arena, 1.1919 + sizeof(certDBEntrySMime)); 1.1920 + if ( entry == NULL ) { 1.1921 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.1922 + goto loser; 1.1923 + } 1.1924 + 1.1925 + /* init common fields */ 1.1926 + entry->common.arena = arena; 1.1927 + entry->common.type = certDBEntryTypeSMimeProfile; 1.1928 + entry->common.version = CERT_DB_FILE_VERSION; 1.1929 + entry->common.flags = flags; 1.1930 + 1.1931 + /* copy the email addr */ 1.1932 + addrlen = PORT_Strlen(emailAddr) + 1; 1.1933 + 1.1934 + entry->emailAddr = (char*)PORT_ArenaAlloc(arena, addrlen); 1.1935 + if ( entry->emailAddr == NULL ) { 1.1936 + goto loser; 1.1937 + } 1.1938 + 1.1939 + PORT_Memcpy(entry->emailAddr, emailAddr, addrlen); 1.1940 + 1.1941 + /* copy the subject name */ 1.1942 + rv = SECITEM_CopyItem(arena, &entry->subjectName, subjectName); 1.1943 + if ( rv != SECSuccess ) { 1.1944 + goto loser; 1.1945 + } 1.1946 + 1.1947 + /* copy the smime options */ 1.1948 + if ( smimeOptions ) { 1.1949 + rv = SECITEM_CopyItem(arena, &entry->smimeOptions, smimeOptions); 1.1950 + if ( rv != SECSuccess ) { 1.1951 + goto loser; 1.1952 + } 1.1953 + } else { 1.1954 + PORT_Assert(optionsDate == NULL); 1.1955 + entry->smimeOptions.data = NULL; 1.1956 + entry->smimeOptions.len = 0; 1.1957 + } 1.1958 + 1.1959 + /* copy the options date */ 1.1960 + if ( optionsDate ) { 1.1961 + rv = SECITEM_CopyItem(arena, &entry->optionsDate, optionsDate); 1.1962 + if ( rv != SECSuccess ) { 1.1963 + goto loser; 1.1964 + } 1.1965 + } else { 1.1966 + PORT_Assert(smimeOptions == NULL); 1.1967 + entry->optionsDate.data = NULL; 1.1968 + entry->optionsDate.len = 0; 1.1969 + } 1.1970 + 1.1971 + return(entry); 1.1972 +loser: 1.1973 + if ( arena ) { 1.1974 + PORT_FreeArena(arena, PR_FALSE); 1.1975 + } 1.1976 + 1.1977 + return(NULL); 1.1978 +} 1.1979 + 1.1980 +/* 1.1981 + * delete a SMIME entry 1.1982 + */ 1.1983 +static SECStatus 1.1984 +DeleteDBSMimeEntry(NSSLOWCERTCertDBHandle *handle, char *emailAddr) 1.1985 +{ 1.1986 + PLArenaPool *arena = NULL; 1.1987 + SECStatus rv; 1.1988 + SECItem dbkey; 1.1989 + 1.1990 + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.1991 + if ( arena == NULL ) { 1.1992 + goto loser; 1.1993 + } 1.1994 + 1.1995 + rv = EncodeDBSMimeKey(emailAddr, arena, &dbkey); 1.1996 + if ( rv != SECSuccess ) { 1.1997 + goto loser; 1.1998 + } 1.1999 + 1.2000 + rv = DeleteDBEntry(handle, certDBEntryTypeSMimeProfile, &dbkey); 1.2001 + if ( rv == SECFailure ) { 1.2002 + goto loser; 1.2003 + } 1.2004 + 1.2005 + PORT_FreeArena(arena, PR_FALSE); 1.2006 + return(SECSuccess); 1.2007 + 1.2008 +loser: 1.2009 + if ( arena ) { 1.2010 + PORT_FreeArena(arena, PR_FALSE); 1.2011 + } 1.2012 + 1.2013 + return(SECFailure); 1.2014 +} 1.2015 + 1.2016 +/* 1.2017 + * Read a SMIME entry 1.2018 + */ 1.2019 +certDBEntrySMime * 1.2020 +nsslowcert_ReadDBSMimeEntry(NSSLOWCERTCertDBHandle *handle, char *emailAddr) 1.2021 +{ 1.2022 + PLArenaPool *arena = NULL; 1.2023 + PLArenaPool *tmparena = NULL; 1.2024 + certDBEntrySMime *entry; 1.2025 + SECItem dbkey; 1.2026 + SECItem dbentry; 1.2027 + SECStatus rv; 1.2028 + 1.2029 + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.2030 + if ( arena == NULL ) { 1.2031 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.2032 + goto loser; 1.2033 + } 1.2034 + 1.2035 + tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.2036 + if ( tmparena == NULL ) { 1.2037 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.2038 + goto loser; 1.2039 + } 1.2040 + 1.2041 + entry = (certDBEntrySMime *)PORT_ArenaAlloc(arena, 1.2042 + sizeof(certDBEntrySMime)); 1.2043 + if ( entry == NULL ) { 1.2044 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.2045 + goto loser; 1.2046 + } 1.2047 + entry->common.arena = arena; 1.2048 + entry->common.type = certDBEntryTypeSMimeProfile; 1.2049 + 1.2050 + rv = EncodeDBSMimeKey(emailAddr, tmparena, &dbkey); 1.2051 + if ( rv != SECSuccess ) { 1.2052 + goto loser; 1.2053 + } 1.2054 + 1.2055 + rv = ReadDBEntry(handle, &entry->common, &dbkey, &dbentry, tmparena); 1.2056 + if ( rv == SECFailure ) { 1.2057 + goto loser; 1.2058 + } 1.2059 + 1.2060 + /* is record long enough for header? */ 1.2061 + if ( dbentry.len < DB_SMIME_ENTRY_HEADER_LEN ) { 1.2062 + PORT_SetError(SEC_ERROR_BAD_DATABASE); 1.2063 + goto loser; 1.2064 + } 1.2065 + 1.2066 + rv = DecodeDBSMimeEntry(entry, &dbentry, emailAddr); 1.2067 + if ( rv != SECSuccess ) { 1.2068 + goto loser; 1.2069 + } 1.2070 + 1.2071 + PORT_FreeArena(tmparena, PR_FALSE); 1.2072 + return(entry); 1.2073 + 1.2074 +loser: 1.2075 + if ( tmparena ) { 1.2076 + PORT_FreeArena(tmparena, PR_FALSE); 1.2077 + } 1.2078 + if ( arena ) { 1.2079 + PORT_FreeArena(arena, PR_FALSE); 1.2080 + } 1.2081 + 1.2082 + return(NULL); 1.2083 +} 1.2084 + 1.2085 +/* 1.2086 + * Encode a SMIME entry into byte stream suitable for 1.2087 + * the database 1.2088 + */ 1.2089 +static SECStatus 1.2090 +WriteDBSMimeEntry(NSSLOWCERTCertDBHandle *handle, certDBEntrySMime *entry) 1.2091 +{ 1.2092 + SECItem dbitem, dbkey; 1.2093 + PLArenaPool *tmparena = NULL; 1.2094 + SECStatus rv; 1.2095 + 1.2096 + tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.2097 + if ( tmparena == NULL ) { 1.2098 + goto loser; 1.2099 + } 1.2100 + 1.2101 + rv = EncodeDBSMimeEntry(entry, tmparena, &dbitem); 1.2102 + if ( rv != SECSuccess ) { 1.2103 + goto loser; 1.2104 + } 1.2105 + 1.2106 + rv = EncodeDBSMimeKey(entry->emailAddr, tmparena, &dbkey); 1.2107 + if ( rv != SECSuccess ) { 1.2108 + goto loser; 1.2109 + } 1.2110 + 1.2111 + /* now write it to the database */ 1.2112 + rv = WriteDBEntry(handle, &entry->common, &dbkey, &dbitem); 1.2113 + if ( rv != SECSuccess ) { 1.2114 + goto loser; 1.2115 + } 1.2116 + 1.2117 + PORT_FreeArena(tmparena, PR_FALSE); 1.2118 + return(SECSuccess); 1.2119 + 1.2120 +loser: 1.2121 + if ( tmparena ) { 1.2122 + PORT_FreeArena(tmparena, PR_FALSE); 1.2123 + } 1.2124 + return(SECFailure); 1.2125 + 1.2126 +} 1.2127 + 1.2128 +/* 1.2129 + * Encode a database subject record 1.2130 + */ 1.2131 +static SECStatus 1.2132 +EncodeDBSubjectEntry(certDBEntrySubject *entry, PLArenaPool *arena, 1.2133 + SECItem *dbitem) 1.2134 +{ 1.2135 + unsigned char *buf; 1.2136 + int len; 1.2137 + unsigned int ncerts; 1.2138 + unsigned int i; 1.2139 + unsigned char *tmpbuf; 1.2140 + unsigned int nnlen = 0; 1.2141 + unsigned int eaddrslen = 0; 1.2142 + int keyidoff; 1.2143 + SECItem *certKeys = entry->certKeys; 1.2144 + SECItem *keyIDs = entry->keyIDs;; 1.2145 + 1.2146 + if ( entry->nickname ) { 1.2147 + nnlen = PORT_Strlen(entry->nickname) + 1; 1.2148 + } 1.2149 + if ( entry->emailAddrs ) { 1.2150 + eaddrslen = 2; 1.2151 + for (i=0; i < entry->nemailAddrs; i++) { 1.2152 + eaddrslen += PORT_Strlen(entry->emailAddrs[i]) + 1 + 2; 1.2153 + } 1.2154 + } 1.2155 + 1.2156 + ncerts = entry->ncerts; 1.2157 + 1.2158 + /* compute the length of the entry */ 1.2159 + keyidoff = DB_SUBJECT_ENTRY_HEADER_LEN + nnlen ; 1.2160 + len = keyidoff + (4 * ncerts) + eaddrslen; 1.2161 + for ( i = 0; i < ncerts; i++ ) { 1.2162 + if (keyIDs[i].len > 0xffff || 1.2163 + (certKeys[i].len > 0xffff)) { 1.2164 + PORT_SetError(SEC_ERROR_INPUT_LEN); 1.2165 + goto loser; 1.2166 + } 1.2167 + len += certKeys[i].len; 1.2168 + len += keyIDs[i].len; 1.2169 + } 1.2170 + 1.2171 + /* allocate space for encoded database record, including space 1.2172 + * for low level header 1.2173 + */ 1.2174 + dbitem->len = len + SEC_DB_ENTRY_HEADER_LEN; 1.2175 + 1.2176 + dbitem->data = (unsigned char *)PORT_ArenaAlloc(arena, dbitem->len); 1.2177 + if ( dbitem->data == NULL) { 1.2178 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.2179 + goto loser; 1.2180 + } 1.2181 + 1.2182 + /* fill in database record */ 1.2183 + buf = &dbitem->data[SEC_DB_ENTRY_HEADER_LEN]; 1.2184 + 1.2185 + buf[0] = (PRUint8)( ncerts >> 8 ); 1.2186 + buf[1] = (PRUint8)( ncerts ); 1.2187 + buf[2] = (PRUint8)( nnlen >> 8 ); 1.2188 + buf[3] = (PRUint8)( nnlen ); 1.2189 + /* v7 email field is NULL in v8 */ 1.2190 + buf[4] = 0; 1.2191 + buf[5] = 0; 1.2192 + 1.2193 + PORT_Memcpy(&buf[DB_SUBJECT_ENTRY_HEADER_LEN], entry->nickname, nnlen); 1.2194 + tmpbuf = &buf[keyidoff]; 1.2195 + for ( i = 0; i < ncerts; i++ ) { 1.2196 + tmpbuf[0] = (PRUint8)( certKeys[i].len >> 8 ); 1.2197 + tmpbuf[1] = (PRUint8)( certKeys[i].len ); 1.2198 + tmpbuf += 2; 1.2199 + } 1.2200 + for ( i = 0; i < ncerts; i++ ) { 1.2201 + tmpbuf[0] = (PRUint8)( keyIDs[i].len >> 8 ); 1.2202 + tmpbuf[1] = (PRUint8)( keyIDs[i].len ); 1.2203 + tmpbuf += 2; 1.2204 + } 1.2205 + 1.2206 + for ( i = 0; i < ncerts; i++ ) { 1.2207 + PORT_Memcpy(tmpbuf, certKeys[i].data, certKeys[i].len); 1.2208 + tmpbuf += certKeys[i].len; 1.2209 + } 1.2210 + for ( i = 0; i < ncerts; i++ ) { 1.2211 + PORT_Memcpy(tmpbuf, keyIDs[i].data, keyIDs[i].len); 1.2212 + tmpbuf += keyIDs[i].len; 1.2213 + } 1.2214 + 1.2215 + if (entry->emailAddrs) { 1.2216 + tmpbuf[0] = (PRUint8)( entry->nemailAddrs >> 8 ); 1.2217 + tmpbuf[1] = (PRUint8)( entry->nemailAddrs ); 1.2218 + tmpbuf += 2; 1.2219 + for (i=0; i < entry->nemailAddrs; i++) { 1.2220 + int nameLen = PORT_Strlen(entry->emailAddrs[i]) + 1; 1.2221 + tmpbuf[0] = (PRUint8)( nameLen >> 8 ); 1.2222 + tmpbuf[1] = (PRUint8)( nameLen ); 1.2223 + tmpbuf += 2; 1.2224 + PORT_Memcpy(tmpbuf,entry->emailAddrs[i],nameLen); 1.2225 + tmpbuf +=nameLen; 1.2226 + } 1.2227 + } 1.2228 + 1.2229 + PORT_Assert(tmpbuf == &buf[len]); 1.2230 + 1.2231 + return(SECSuccess); 1.2232 + 1.2233 +loser: 1.2234 + return(SECFailure); 1.2235 +} 1.2236 + 1.2237 +/* 1.2238 + * Encode a database key for a subject record 1.2239 + */ 1.2240 +static SECStatus 1.2241 +EncodeDBSubjectKey(SECItem *derSubject, PLArenaPool *arena, 1.2242 + SECItem *dbkey) 1.2243 +{ 1.2244 + dbkey->len = derSubject->len + SEC_DB_KEY_HEADER_LEN; 1.2245 + if (dbkey->len > NSS_MAX_LEGACY_DB_KEY_SIZE) 1.2246 + goto loser; 1.2247 + dbkey->data = (unsigned char *)PORT_ArenaAlloc(arena, dbkey->len); 1.2248 + if ( dbkey->data == NULL ) { 1.2249 + goto loser; 1.2250 + } 1.2251 + PORT_Memcpy(&dbkey->data[SEC_DB_KEY_HEADER_LEN], derSubject->data, 1.2252 + derSubject->len); 1.2253 + dbkey->data[0] = certDBEntryTypeSubject; 1.2254 + 1.2255 + return(SECSuccess); 1.2256 + 1.2257 +loser: 1.2258 + return(SECFailure); 1.2259 +} 1.2260 + 1.2261 +static SECStatus 1.2262 +DecodeDBSubjectEntry(certDBEntrySubject *entry, SECItem *dbentry, 1.2263 + const SECItem *derSubject) 1.2264 +{ 1.2265 + PLArenaPool *arena = entry->common.arena; 1.2266 + unsigned char *tmpbuf; 1.2267 + unsigned char *end; 1.2268 + void *mark = PORT_ArenaMark(arena); 1.2269 + unsigned int eaddrlen; 1.2270 + unsigned int i; 1.2271 + unsigned int keyidoff; 1.2272 + unsigned int len; 1.2273 + unsigned int ncerts = 0; 1.2274 + unsigned int nnlen; 1.2275 + SECStatus rv; 1.2276 + 1.2277 + rv = SECITEM_CopyItem(arena, &entry->derSubject, derSubject); 1.2278 + if ( rv != SECSuccess ) { 1.2279 + goto loser; 1.2280 + } 1.2281 + 1.2282 + /* is record long enough for header? */ 1.2283 + if ( dbentry->len < DB_SUBJECT_ENTRY_HEADER_LEN ) { 1.2284 + PORT_SetError(SEC_ERROR_BAD_DATABASE); 1.2285 + goto loser; 1.2286 + } 1.2287 + 1.2288 + entry->ncerts = ncerts = (( dbentry->data[0] << 8 ) | dbentry->data[1] ); 1.2289 + nnlen = (( dbentry->data[2] << 8 ) | dbentry->data[3] ); 1.2290 + eaddrlen = (( dbentry->data[4] << 8 ) | dbentry->data[5] ); 1.2291 + keyidoff = DB_SUBJECT_ENTRY_HEADER_LEN + nnlen + eaddrlen; 1.2292 + len = keyidoff + (4 * ncerts); 1.2293 + if ( dbentry->len < len) { 1.2294 + PORT_SetError(SEC_ERROR_BAD_DATABASE); 1.2295 + goto loser; 1.2296 + } 1.2297 + 1.2298 + entry->certKeys = PORT_ArenaNewArray(arena, SECItem, ncerts); 1.2299 + entry->keyIDs = PORT_ArenaNewArray(arena, SECItem, ncerts); 1.2300 + if ( ( entry->certKeys == NULL ) || ( entry->keyIDs == NULL ) ) { 1.2301 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.2302 + goto loser; 1.2303 + } 1.2304 + 1.2305 + if ( nnlen > 1 ) { /* null terminator is stored */ 1.2306 + entry->nickname = (char *)PORT_ArenaAlloc(arena, nnlen); 1.2307 + if ( entry->nickname == NULL ) { 1.2308 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.2309 + goto loser; 1.2310 + } 1.2311 + PORT_Memcpy(entry->nickname, 1.2312 + &dbentry->data[DB_SUBJECT_ENTRY_HEADER_LEN], 1.2313 + nnlen); 1.2314 + } else { 1.2315 + entry->nickname = NULL; 1.2316 + } 1.2317 + 1.2318 + /* if we have an old style email entry, there is only one */ 1.2319 + entry->nemailAddrs = 0; 1.2320 + if ( eaddrlen > 1 ) { /* null terminator is stored */ 1.2321 + entry->emailAddrs = PORT_ArenaNewArray(arena, char *, 2); 1.2322 + if ( entry->emailAddrs == NULL ) { 1.2323 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.2324 + goto loser; 1.2325 + } 1.2326 + entry->emailAddrs[0] = (char *)PORT_ArenaAlloc(arena, eaddrlen); 1.2327 + if ( entry->emailAddrs[0] == NULL ) { 1.2328 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.2329 + goto loser; 1.2330 + } 1.2331 + PORT_Memcpy(entry->emailAddrs[0], 1.2332 + &dbentry->data[DB_SUBJECT_ENTRY_HEADER_LEN+nnlen], 1.2333 + eaddrlen); 1.2334 + entry->nemailAddrs = 1; 1.2335 + } else { 1.2336 + entry->emailAddrs = NULL; 1.2337 + } 1.2338 + 1.2339 + /* collect the lengths of the certKeys and keyIDs, and total the 1.2340 + * overall length. 1.2341 + */ 1.2342 + tmpbuf = &dbentry->data[keyidoff]; 1.2343 + for ( i = 0; i < ncerts; i++ ) { 1.2344 + unsigned int itemlen = ( tmpbuf[0] << 8 ) | tmpbuf[1]; 1.2345 + entry->certKeys[i].len = itemlen; 1.2346 + len += itemlen; 1.2347 + tmpbuf += 2; 1.2348 + } 1.2349 + for ( i = 0; i < ncerts; i++ ) { 1.2350 + unsigned int itemlen = ( tmpbuf[0] << 8 ) | tmpbuf[1] ; 1.2351 + entry->keyIDs[i].len = itemlen; 1.2352 + len += itemlen; 1.2353 + tmpbuf += 2; 1.2354 + } 1.2355 + 1.2356 + /* is encoded entry large enough ? */ 1.2357 + if ( len > dbentry->len ){ 1.2358 + PORT_SetError(SEC_ERROR_BAD_DATABASE); 1.2359 + goto loser; 1.2360 + } 1.2361 + 1.2362 + for ( i = 0; i < ncerts; i++ ) { 1.2363 + unsigned int kLen = entry->certKeys[i].len; 1.2364 + entry->certKeys[i].data = (unsigned char *)PORT_ArenaAlloc(arena, kLen); 1.2365 + if ( entry->certKeys[i].data == NULL ) { 1.2366 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.2367 + goto loser; 1.2368 + } 1.2369 + PORT_Memcpy(entry->certKeys[i].data, tmpbuf, kLen); 1.2370 + tmpbuf += kLen; 1.2371 + } 1.2372 + for ( i = 0; i < ncerts; i++ ) { 1.2373 + unsigned int iLen = entry->keyIDs[i].len; 1.2374 + entry->keyIDs[i].data = (unsigned char *)PORT_ArenaAlloc(arena, iLen); 1.2375 + if ( entry->keyIDs[i].data == NULL ) { 1.2376 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.2377 + goto loser; 1.2378 + } 1.2379 + PORT_Memcpy(entry->keyIDs[i].data, tmpbuf, iLen); 1.2380 + tmpbuf += iLen; 1.2381 + } 1.2382 + 1.2383 + end = dbentry->data + dbentry->len; 1.2384 + if ((eaddrlen == 0) && (end - tmpbuf > 1)) { 1.2385 + /* read in the additional email addresses */ 1.2386 + entry->nemailAddrs = (((unsigned int)tmpbuf[0]) << 8) | tmpbuf[1]; 1.2387 + tmpbuf += 2; 1.2388 + if (end - tmpbuf < 2 * (int)entry->nemailAddrs) 1.2389 + goto loser; 1.2390 + entry->emailAddrs = PORT_ArenaNewArray(arena, char *, entry->nemailAddrs); 1.2391 + if (entry->emailAddrs == NULL) { 1.2392 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.2393 + goto loser; 1.2394 + } 1.2395 + for (i=0; i < entry->nemailAddrs; i++) { 1.2396 + int nameLen; 1.2397 + if (end - tmpbuf < 2) { 1.2398 + goto loser; 1.2399 + } 1.2400 + nameLen = (((int)tmpbuf[0]) << 8) | tmpbuf[1]; 1.2401 + tmpbuf += 2; 1.2402 + if (end - tmpbuf < nameLen) { 1.2403 + goto loser; 1.2404 + } 1.2405 + entry->emailAddrs[i] = PORT_ArenaAlloc(arena,nameLen); 1.2406 + if (entry->emailAddrs == NULL) { 1.2407 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.2408 + goto loser; 1.2409 + } 1.2410 + PORT_Memcpy(entry->emailAddrs[i], tmpbuf, nameLen); 1.2411 + tmpbuf += nameLen; 1.2412 + } 1.2413 + if (tmpbuf != end) 1.2414 + goto loser; 1.2415 + } 1.2416 + PORT_ArenaUnmark(arena, mark); 1.2417 + return(SECSuccess); 1.2418 + 1.2419 +loser: 1.2420 + PORT_ArenaRelease(arena, mark); /* discard above allocations */ 1.2421 + return(SECFailure); 1.2422 +} 1.2423 + 1.2424 +/* 1.2425 + * create a new subject entry with a single cert 1.2426 + */ 1.2427 +static certDBEntrySubject * 1.2428 +NewDBSubjectEntry(SECItem *derSubject, SECItem *certKey, 1.2429 + SECItem *keyID, char *nickname, char *emailAddr, 1.2430 + unsigned int flags) 1.2431 +{ 1.2432 + PLArenaPool *arena = NULL; 1.2433 + certDBEntrySubject *entry; 1.2434 + SECStatus rv; 1.2435 + unsigned int nnlen; 1.2436 + unsigned int eaddrlen; 1.2437 + 1.2438 + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.2439 + if ( arena == NULL ) { 1.2440 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.2441 + goto loser; 1.2442 + } 1.2443 + 1.2444 + entry = (certDBEntrySubject *)PORT_ArenaAlloc(arena, 1.2445 + sizeof(certDBEntrySubject)); 1.2446 + if ( entry == NULL ) { 1.2447 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.2448 + goto loser; 1.2449 + } 1.2450 + 1.2451 + /* init common fields */ 1.2452 + entry->common.arena = arena; 1.2453 + entry->common.type = certDBEntryTypeSubject; 1.2454 + entry->common.version = CERT_DB_FILE_VERSION; 1.2455 + entry->common.flags = flags; 1.2456 + 1.2457 + /* copy the subject */ 1.2458 + rv = SECITEM_CopyItem(arena, &entry->derSubject, derSubject); 1.2459 + if ( rv != SECSuccess ) { 1.2460 + goto loser; 1.2461 + } 1.2462 + 1.2463 + entry->ncerts = 1; 1.2464 + entry->nemailAddrs = 0; 1.2465 + /* copy nickname */ 1.2466 + if ( nickname && ( *nickname != '\0' ) ) { 1.2467 + nnlen = PORT_Strlen(nickname) + 1; 1.2468 + entry->nickname = (char *)PORT_ArenaAlloc(arena, nnlen); 1.2469 + if ( entry->nickname == NULL ) { 1.2470 + goto loser; 1.2471 + } 1.2472 + 1.2473 + PORT_Memcpy(entry->nickname, nickname, nnlen); 1.2474 + } else { 1.2475 + entry->nickname = NULL; 1.2476 + } 1.2477 + 1.2478 + /* copy email addr */ 1.2479 + if ( emailAddr && ( *emailAddr != '\0' ) ) { 1.2480 + emailAddr = nsslowcert_FixupEmailAddr(emailAddr); 1.2481 + if ( emailAddr == NULL ) { 1.2482 + entry->emailAddrs = NULL; 1.2483 + goto loser; 1.2484 + } 1.2485 + 1.2486 + eaddrlen = PORT_Strlen(emailAddr) + 1; 1.2487 + entry->emailAddrs = (char **)PORT_ArenaAlloc(arena, sizeof(char *)); 1.2488 + if ( entry->emailAddrs == NULL ) { 1.2489 + PORT_Free(emailAddr); 1.2490 + goto loser; 1.2491 + } 1.2492 + entry->emailAddrs[0] = PORT_ArenaStrdup(arena,emailAddr); 1.2493 + if (entry->emailAddrs[0]) { 1.2494 + entry->nemailAddrs = 1; 1.2495 + } 1.2496 + 1.2497 + PORT_Free(emailAddr); 1.2498 + } else { 1.2499 + entry->emailAddrs = NULL; 1.2500 + } 1.2501 + 1.2502 + /* allocate space for certKeys and keyIDs */ 1.2503 + entry->certKeys = (SECItem *)PORT_ArenaAlloc(arena, sizeof(SECItem)); 1.2504 + entry->keyIDs = (SECItem *)PORT_ArenaAlloc(arena, sizeof(SECItem)); 1.2505 + if ( ( entry->certKeys == NULL ) || ( entry->keyIDs == NULL ) ) { 1.2506 + goto loser; 1.2507 + } 1.2508 + 1.2509 + /* copy the certKey and keyID */ 1.2510 + rv = SECITEM_CopyItem(arena, &entry->certKeys[0], certKey); 1.2511 + if ( rv != SECSuccess ) { 1.2512 + goto loser; 1.2513 + } 1.2514 + rv = SECITEM_CopyItem(arena, &entry->keyIDs[0], keyID); 1.2515 + if ( rv != SECSuccess ) { 1.2516 + goto loser; 1.2517 + } 1.2518 + 1.2519 + return(entry); 1.2520 +loser: 1.2521 + if ( arena ) { 1.2522 + PORT_FreeArena(arena, PR_FALSE); 1.2523 + } 1.2524 + 1.2525 + return(NULL); 1.2526 +} 1.2527 + 1.2528 +/* 1.2529 + * delete a subject entry 1.2530 + */ 1.2531 +static SECStatus 1.2532 +DeleteDBSubjectEntry(NSSLOWCERTCertDBHandle *handle, SECItem *derSubject) 1.2533 +{ 1.2534 + SECItem dbkey; 1.2535 + PLArenaPool *arena = NULL; 1.2536 + SECStatus rv; 1.2537 + 1.2538 + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.2539 + if ( arena == NULL ) { 1.2540 + goto loser; 1.2541 + } 1.2542 + 1.2543 + rv = EncodeDBSubjectKey(derSubject, arena, &dbkey); 1.2544 + if ( rv != SECSuccess ) { 1.2545 + goto loser; 1.2546 + } 1.2547 + 1.2548 + rv = DeleteDBEntry(handle, certDBEntryTypeSubject, &dbkey); 1.2549 + if ( rv == SECFailure ) { 1.2550 + goto loser; 1.2551 + } 1.2552 + 1.2553 + PORT_FreeArena(arena, PR_FALSE); 1.2554 + return(SECSuccess); 1.2555 + 1.2556 +loser: 1.2557 + if ( arena ) { 1.2558 + PORT_FreeArena(arena, PR_FALSE); 1.2559 + } 1.2560 + 1.2561 + return(SECFailure); 1.2562 +} 1.2563 + 1.2564 +/* 1.2565 + * Read the subject entry 1.2566 + */ 1.2567 +static certDBEntrySubject * 1.2568 +ReadDBSubjectEntry(NSSLOWCERTCertDBHandle *handle, SECItem *derSubject) 1.2569 +{ 1.2570 + PLArenaPool *arena = NULL; 1.2571 + PLArenaPool *tmparena = NULL; 1.2572 + certDBEntrySubject *entry; 1.2573 + SECItem dbkey; 1.2574 + SECItem dbentry; 1.2575 + SECStatus rv; 1.2576 + 1.2577 + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.2578 + if ( arena == NULL ) { 1.2579 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.2580 + goto loser; 1.2581 + } 1.2582 + 1.2583 + tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.2584 + if ( tmparena == NULL ) { 1.2585 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.2586 + goto loser; 1.2587 + } 1.2588 + 1.2589 + entry = (certDBEntrySubject *)PORT_ArenaAlloc(arena, 1.2590 + sizeof(certDBEntrySubject)); 1.2591 + if ( entry == NULL ) { 1.2592 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.2593 + goto loser; 1.2594 + } 1.2595 + entry->common.arena = arena; 1.2596 + entry->common.type = certDBEntryTypeSubject; 1.2597 + 1.2598 + rv = EncodeDBSubjectKey(derSubject, tmparena, &dbkey); 1.2599 + if ( rv != SECSuccess ) { 1.2600 + goto loser; 1.2601 + } 1.2602 + 1.2603 + rv = ReadDBEntry(handle, &entry->common, &dbkey, &dbentry, tmparena); 1.2604 + if ( rv == SECFailure ) { 1.2605 + goto loser; 1.2606 + } 1.2607 + 1.2608 + rv = DecodeDBSubjectEntry(entry, &dbentry, derSubject); 1.2609 + if ( rv == SECFailure ) { 1.2610 + goto loser; 1.2611 + } 1.2612 + 1.2613 + PORT_FreeArena(tmparena, PR_FALSE); 1.2614 + return(entry); 1.2615 + 1.2616 +loser: 1.2617 + if ( tmparena ) { 1.2618 + PORT_FreeArena(tmparena, PR_FALSE); 1.2619 + } 1.2620 + if ( arena ) { 1.2621 + PORT_FreeArena(arena, PR_FALSE); 1.2622 + } 1.2623 + 1.2624 + return(NULL); 1.2625 +} 1.2626 + 1.2627 +/* 1.2628 + * Encode a subject name entry into byte stream suitable for 1.2629 + * the database 1.2630 + */ 1.2631 +static SECStatus 1.2632 +WriteDBSubjectEntry(NSSLOWCERTCertDBHandle *handle, certDBEntrySubject *entry) 1.2633 +{ 1.2634 + SECItem dbitem, dbkey; 1.2635 + PLArenaPool *tmparena = NULL; 1.2636 + SECStatus rv; 1.2637 + 1.2638 + tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.2639 + if ( tmparena == NULL ) { 1.2640 + goto loser; 1.2641 + } 1.2642 + 1.2643 + rv = EncodeDBSubjectEntry(entry, tmparena, &dbitem); 1.2644 + if ( rv != SECSuccess ) { 1.2645 + goto loser; 1.2646 + } 1.2647 + 1.2648 + rv = EncodeDBSubjectKey(&entry->derSubject, tmparena, &dbkey); 1.2649 + if ( rv != SECSuccess ) { 1.2650 + goto loser; 1.2651 + } 1.2652 + 1.2653 + /* now write it to the database */ 1.2654 + rv = WriteDBEntry(handle, &entry->common, &dbkey, &dbitem); 1.2655 + if ( rv != SECSuccess ) { 1.2656 + goto loser; 1.2657 + } 1.2658 + 1.2659 + PORT_FreeArena(tmparena, PR_FALSE); 1.2660 + return(SECSuccess); 1.2661 + 1.2662 +loser: 1.2663 + if ( tmparena ) { 1.2664 + PORT_FreeArena(tmparena, PR_FALSE); 1.2665 + } 1.2666 + return(SECFailure); 1.2667 + 1.2668 +} 1.2669 + 1.2670 +typedef enum { nsslowcert_remove, nsslowcert_add } nsslowcertUpdateType; 1.2671 + 1.2672 +static SECStatus 1.2673 +nsslowcert_UpdateSubjectEmailAddr(NSSLOWCERTCertDBHandle *dbhandle, 1.2674 + SECItem *derSubject, char *emailAddr, nsslowcertUpdateType updateType) 1.2675 +{ 1.2676 + certDBEntrySubject *entry = NULL; 1.2677 + int index = -1, i; 1.2678 + SECStatus rv; 1.2679 + 1.2680 + if (emailAddr) { 1.2681 + emailAddr = nsslowcert_FixupEmailAddr(emailAddr); 1.2682 + if (emailAddr == NULL) { 1.2683 + return SECFailure; 1.2684 + } 1.2685 + } else { 1.2686 + return SECSuccess; 1.2687 + } 1.2688 + 1.2689 + entry = ReadDBSubjectEntry(dbhandle,derSubject); 1.2690 + if (entry == NULL) { 1.2691 + rv = SECFailure; 1.2692 + goto done; 1.2693 + } 1.2694 + 1.2695 + for (i=0; i < (int)(entry->nemailAddrs); i++) { 1.2696 + if (PORT_Strcmp(entry->emailAddrs[i],emailAddr) == 0) { 1.2697 + index = i; 1.2698 + } 1.2699 + } 1.2700 + 1.2701 + if (updateType == nsslowcert_remove) { 1.2702 + if (index == -1) { 1.2703 + rv = SECSuccess; 1.2704 + goto done; 1.2705 + } 1.2706 + entry->nemailAddrs--; 1.2707 + for (i=index; i < (int)(entry->nemailAddrs); i++) { 1.2708 + entry->emailAddrs[i] = entry->emailAddrs[i+1]; 1.2709 + } 1.2710 + } else { 1.2711 + char **newAddrs = NULL; 1.2712 + 1.2713 + if (index != -1) { 1.2714 + rv = SECSuccess; 1.2715 + goto done; 1.2716 + } 1.2717 + newAddrs = (char **)PORT_ArenaAlloc(entry->common.arena, 1.2718 + (entry->nemailAddrs+1)* sizeof(char *)); 1.2719 + if (!newAddrs) { 1.2720 + rv = SECFailure; 1.2721 + goto done; 1.2722 + } 1.2723 + for (i=0; i < (int)(entry->nemailAddrs); i++) { 1.2724 + newAddrs[i] = entry->emailAddrs[i]; 1.2725 + } 1.2726 + newAddrs[entry->nemailAddrs] = 1.2727 + PORT_ArenaStrdup(entry->common.arena,emailAddr); 1.2728 + if (!newAddrs[entry->nemailAddrs]) { 1.2729 + rv = SECFailure; 1.2730 + goto done; 1.2731 + } 1.2732 + entry->emailAddrs = newAddrs; 1.2733 + entry->nemailAddrs++; 1.2734 + } 1.2735 + 1.2736 + /* delete the subject entry */ 1.2737 + DeleteDBSubjectEntry(dbhandle, derSubject); 1.2738 + 1.2739 + /* write the new one */ 1.2740 + rv = WriteDBSubjectEntry(dbhandle, entry); 1.2741 + 1.2742 + done: 1.2743 + if (entry) DestroyDBEntry((certDBEntry *)entry); 1.2744 + if (emailAddr) PORT_Free(emailAddr); 1.2745 + return rv; 1.2746 +} 1.2747 + 1.2748 +/* 1.2749 + * writes a nickname to an existing subject entry that does not currently 1.2750 + * have one 1.2751 + */ 1.2752 +static SECStatus 1.2753 +AddNicknameToSubject(NSSLOWCERTCertDBHandle *dbhandle, 1.2754 + NSSLOWCERTCertificate *cert, char *nickname) 1.2755 +{ 1.2756 + certDBEntrySubject *entry; 1.2757 + SECStatus rv; 1.2758 + 1.2759 + if ( nickname == NULL ) { 1.2760 + return(SECFailure); 1.2761 + } 1.2762 + 1.2763 + entry = ReadDBSubjectEntry(dbhandle,&cert->derSubject); 1.2764 + PORT_Assert(entry != NULL); 1.2765 + if ( entry == NULL ) { 1.2766 + goto loser; 1.2767 + } 1.2768 + 1.2769 + PORT_Assert(entry->nickname == NULL); 1.2770 + if ( entry->nickname != NULL ) { 1.2771 + goto loser; 1.2772 + } 1.2773 + 1.2774 + entry->nickname = PORT_ArenaStrdup(entry->common.arena, nickname); 1.2775 + 1.2776 + if ( entry->nickname == NULL ) { 1.2777 + goto loser; 1.2778 + } 1.2779 + 1.2780 + /* delete the subject entry */ 1.2781 + DeleteDBSubjectEntry(dbhandle, &cert->derSubject); 1.2782 + 1.2783 + /* write the new one */ 1.2784 + rv = WriteDBSubjectEntry(dbhandle, entry); 1.2785 + if ( rv != SECSuccess ) { 1.2786 + goto loser; 1.2787 + } 1.2788 + 1.2789 + return(SECSuccess); 1.2790 + 1.2791 +loser: 1.2792 + return(SECFailure); 1.2793 +} 1.2794 + 1.2795 +/* 1.2796 + * create a new version entry 1.2797 + */ 1.2798 +static certDBEntryVersion * 1.2799 +NewDBVersionEntry(unsigned int flags) 1.2800 +{ 1.2801 + PLArenaPool *arena = NULL; 1.2802 + certDBEntryVersion *entry; 1.2803 + 1.2804 + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.2805 + if ( arena == NULL ) { 1.2806 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.2807 + goto loser; 1.2808 + } 1.2809 + 1.2810 + entry = (certDBEntryVersion *)PORT_ArenaAlloc(arena, 1.2811 + sizeof(certDBEntryVersion)); 1.2812 + if ( entry == NULL ) { 1.2813 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.2814 + goto loser; 1.2815 + } 1.2816 + entry->common.arena = arena; 1.2817 + entry->common.type = certDBEntryTypeVersion; 1.2818 + entry->common.version = CERT_DB_FILE_VERSION; 1.2819 + entry->common.flags = flags; 1.2820 + 1.2821 + return(entry); 1.2822 +loser: 1.2823 + if ( arena ) { 1.2824 + PORT_FreeArena(arena, PR_FALSE); 1.2825 + } 1.2826 + 1.2827 + return(NULL); 1.2828 +} 1.2829 + 1.2830 +/* 1.2831 + * Read the version entry 1.2832 + */ 1.2833 +static certDBEntryVersion * 1.2834 +ReadDBVersionEntry(NSSLOWCERTCertDBHandle *handle) 1.2835 +{ 1.2836 + PLArenaPool *arena = NULL; 1.2837 + PLArenaPool *tmparena = NULL; 1.2838 + certDBEntryVersion *entry; 1.2839 + SECItem dbkey; 1.2840 + SECItem dbentry; 1.2841 + SECStatus rv; 1.2842 + 1.2843 + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.2844 + if ( arena == NULL ) { 1.2845 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.2846 + goto loser; 1.2847 + } 1.2848 + 1.2849 + tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.2850 + if ( tmparena == NULL ) { 1.2851 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.2852 + goto loser; 1.2853 + } 1.2854 + 1.2855 + entry = PORT_ArenaZNew(arena, certDBEntryVersion); 1.2856 + if ( entry == NULL ) { 1.2857 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.2858 + goto loser; 1.2859 + } 1.2860 + entry->common.arena = arena; 1.2861 + entry->common.type = certDBEntryTypeVersion; 1.2862 + 1.2863 + /* now get the database key and format it */ 1.2864 + dbkey.len = SEC_DB_VERSION_KEY_LEN + SEC_DB_KEY_HEADER_LEN; 1.2865 + dbkey.data = (unsigned char *)PORT_ArenaAlloc(tmparena, dbkey.len); 1.2866 + if ( dbkey.data == NULL ) { 1.2867 + goto loser; 1.2868 + } 1.2869 + PORT_Memcpy(&dbkey.data[SEC_DB_KEY_HEADER_LEN], SEC_DB_VERSION_KEY, 1.2870 + SEC_DB_VERSION_KEY_LEN); 1.2871 + 1.2872 + rv = ReadDBEntry(handle, &entry->common, &dbkey, &dbentry, tmparena); 1.2873 + if (rv != SECSuccess) { 1.2874 + goto loser; 1.2875 + } 1.2876 + 1.2877 + PORT_FreeArena(tmparena, PR_FALSE); 1.2878 + return(entry); 1.2879 + 1.2880 +loser: 1.2881 + if ( tmparena ) { 1.2882 + PORT_FreeArena(tmparena, PR_FALSE); 1.2883 + } 1.2884 + if ( arena ) { 1.2885 + PORT_FreeArena(arena, PR_FALSE); 1.2886 + } 1.2887 + 1.2888 + return(NULL); 1.2889 +} 1.2890 + 1.2891 + 1.2892 +/* 1.2893 + * Encode a version entry into byte stream suitable for 1.2894 + * the database 1.2895 + */ 1.2896 +static SECStatus 1.2897 +WriteDBVersionEntry(NSSLOWCERTCertDBHandle *handle, certDBEntryVersion *entry) 1.2898 +{ 1.2899 + SECItem dbitem, dbkey; 1.2900 + PLArenaPool *tmparena = NULL; 1.2901 + SECStatus rv; 1.2902 + 1.2903 + tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.2904 + if ( tmparena == NULL ) { 1.2905 + goto loser; 1.2906 + } 1.2907 + 1.2908 + /* allocate space for encoded database record, including space 1.2909 + * for low level header 1.2910 + */ 1.2911 + dbitem.len = SEC_DB_ENTRY_HEADER_LEN; 1.2912 + 1.2913 + dbitem.data = (unsigned char *)PORT_ArenaAlloc(tmparena, dbitem.len); 1.2914 + if ( dbitem.data == NULL) { 1.2915 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.2916 + goto loser; 1.2917 + } 1.2918 + 1.2919 + /* now get the database key and format it */ 1.2920 + dbkey.len = SEC_DB_VERSION_KEY_LEN + SEC_DB_KEY_HEADER_LEN; 1.2921 + dbkey.data = (unsigned char *)PORT_ArenaAlloc(tmparena, dbkey.len); 1.2922 + if ( dbkey.data == NULL ) { 1.2923 + goto loser; 1.2924 + } 1.2925 + PORT_Memcpy(&dbkey.data[SEC_DB_KEY_HEADER_LEN], SEC_DB_VERSION_KEY, 1.2926 + SEC_DB_VERSION_KEY_LEN); 1.2927 + 1.2928 + /* now write it to the database */ 1.2929 + rv = WriteDBEntry(handle, &entry->common, &dbkey, &dbitem); 1.2930 + if ( rv != SECSuccess ) { 1.2931 + goto loser; 1.2932 + } 1.2933 + 1.2934 + PORT_FreeArena(tmparena, PR_FALSE); 1.2935 + return(SECSuccess); 1.2936 + 1.2937 +loser: 1.2938 + if ( tmparena ) { 1.2939 + PORT_FreeArena(tmparena, PR_FALSE); 1.2940 + } 1.2941 + return(SECFailure); 1.2942 +} 1.2943 + 1.2944 +/* 1.2945 + * cert is no longer a perm cert, but will remain a temp cert 1.2946 + */ 1.2947 +static SECStatus 1.2948 +RemovePermSubjectNode(NSSLOWCERTCertificate *cert) 1.2949 +{ 1.2950 + certDBEntrySubject *entry; 1.2951 + unsigned int i; 1.2952 + SECStatus rv; 1.2953 + 1.2954 + entry = ReadDBSubjectEntry(cert->dbhandle,&cert->derSubject); 1.2955 + if ( entry == NULL ) { 1.2956 + return(SECFailure); 1.2957 + } 1.2958 + 1.2959 + PORT_Assert(entry->ncerts); 1.2960 + rv = SECFailure; 1.2961 + 1.2962 + if ( entry->ncerts > 1 ) { 1.2963 + for ( i = 0; i < entry->ncerts; i++ ) { 1.2964 + if ( SECITEM_CompareItem(&entry->certKeys[i], &cert->certKey) == 1.2965 + SECEqual ) { 1.2966 + /* copy rest of list forward one entry */ 1.2967 + for ( i = i + 1; i < entry->ncerts; i++ ) { 1.2968 + entry->certKeys[i-1] = entry->certKeys[i]; 1.2969 + entry->keyIDs[i-1] = entry->keyIDs[i]; 1.2970 + } 1.2971 + entry->ncerts--; 1.2972 + DeleteDBSubjectEntry(cert->dbhandle, &cert->derSubject); 1.2973 + rv = WriteDBSubjectEntry(cert->dbhandle, entry); 1.2974 + break; 1.2975 + } 1.2976 + } 1.2977 + } else { 1.2978 + /* no entries left, delete the perm entry in the DB */ 1.2979 + if ( entry->emailAddrs ) { 1.2980 + /* if the subject had an email record, then delete it too */ 1.2981 + for (i=0; i < entry->nemailAddrs; i++) { 1.2982 + DeleteDBSMimeEntry(cert->dbhandle, entry->emailAddrs[i]); 1.2983 + } 1.2984 + } 1.2985 + if ( entry->nickname ) { 1.2986 + DeleteDBNicknameEntry(cert->dbhandle, entry->nickname); 1.2987 + } 1.2988 + 1.2989 + DeleteDBSubjectEntry(cert->dbhandle, &cert->derSubject); 1.2990 + } 1.2991 + DestroyDBEntry((certDBEntry *)entry); 1.2992 + 1.2993 + return(rv); 1.2994 +} 1.2995 + 1.2996 +/* 1.2997 + * add a cert to the perm subject list 1.2998 + */ 1.2999 +static SECStatus 1.3000 +AddPermSubjectNode(certDBEntrySubject *entry, NSSLOWCERTCertificate *cert, 1.3001 + char *nickname) 1.3002 +{ 1.3003 + SECItem *newCertKeys, *newKeyIDs; 1.3004 + unsigned int i, new_i; 1.3005 + SECStatus rv; 1.3006 + unsigned int ncerts; 1.3007 + 1.3008 + PORT_Assert(entry); 1.3009 + ncerts = entry->ncerts; 1.3010 + 1.3011 + if ( nickname && entry->nickname ) { 1.3012 + /* nicknames must be the same */ 1.3013 + PORT_Assert(PORT_Strcmp(nickname, entry->nickname) == 0); 1.3014 + } 1.3015 + 1.3016 + if ( ( entry->nickname == NULL ) && ( nickname != NULL ) ) { 1.3017 + /* copy nickname into the entry */ 1.3018 + entry->nickname = PORT_ArenaStrdup(entry->common.arena, nickname); 1.3019 + if ( entry->nickname == NULL ) { 1.3020 + return(SECFailure); 1.3021 + } 1.3022 + } 1.3023 + 1.3024 + /* a DB entry already exists, so add this cert */ 1.3025 + newCertKeys = PORT_ArenaZNewArray(entry->common.arena, SECItem, ncerts + 1); 1.3026 + newKeyIDs = PORT_ArenaZNewArray(entry->common.arena, SECItem, ncerts + 1); 1.3027 + 1.3028 + if ( ( newCertKeys == NULL ) || ( newKeyIDs == NULL ) ) { 1.3029 + return(SECFailure); 1.3030 + } 1.3031 + 1.3032 + /* Step 1: copy certs older than "cert" into new entry. */ 1.3033 + for ( i = 0, new_i=0; i < ncerts; i++ ) { 1.3034 + NSSLOWCERTCertificate *cmpcert; 1.3035 + PRBool isNewer; 1.3036 + cmpcert = nsslowcert_FindCertByKey(cert->dbhandle, 1.3037 + &entry->certKeys[i]); 1.3038 + /* The entry has been corrupted, remove it from the list */ 1.3039 + if (!cmpcert) { 1.3040 + continue; 1.3041 + } 1.3042 + 1.3043 + isNewer = nsslowcert_IsNewer(cert, cmpcert); 1.3044 + nsslowcert_DestroyCertificate(cmpcert); 1.3045 + if ( isNewer ) 1.3046 + break; 1.3047 + /* copy this cert entry */ 1.3048 + newCertKeys[new_i] = entry->certKeys[i]; 1.3049 + newKeyIDs[new_i] = entry->keyIDs[i]; 1.3050 + new_i++; 1.3051 + } 1.3052 + 1.3053 + /* Step 2: Add "cert" to the entry. */ 1.3054 + rv = SECITEM_CopyItem(entry->common.arena, &newCertKeys[new_i], 1.3055 + &cert->certKey); 1.3056 + if ( rv != SECSuccess ) { 1.3057 + return(SECFailure); 1.3058 + } 1.3059 + rv = SECITEM_CopyItem(entry->common.arena, &newKeyIDs[new_i], 1.3060 + &cert->subjectKeyID); 1.3061 + if ( rv != SECSuccess ) { 1.3062 + return(SECFailure); 1.3063 + } 1.3064 + new_i++; 1.3065 + 1.3066 + /* Step 3: copy remaining certs (if any) from old entry to new. */ 1.3067 + for ( ; i < ncerts; i++ ,new_i++) { 1.3068 + newCertKeys[new_i] = entry->certKeys[i]; 1.3069 + newKeyIDs[new_i] = entry->keyIDs[i]; 1.3070 + } 1.3071 + 1.3072 + /* update certKeys and keyIDs */ 1.3073 + entry->certKeys = newCertKeys; 1.3074 + entry->keyIDs = newKeyIDs; 1.3075 + 1.3076 + /* set new count value */ 1.3077 + entry->ncerts = new_i; 1.3078 + 1.3079 + DeleteDBSubjectEntry(cert->dbhandle, &cert->derSubject); 1.3080 + rv = WriteDBSubjectEntry(cert->dbhandle, entry); 1.3081 + return(rv); 1.3082 +} 1.3083 + 1.3084 + 1.3085 +SECStatus 1.3086 +nsslowcert_TraversePermCertsForSubject(NSSLOWCERTCertDBHandle *handle, 1.3087 + SECItem *derSubject, 1.3088 + NSSLOWCERTCertCallback cb, void *cbarg) 1.3089 +{ 1.3090 + certDBEntrySubject *entry; 1.3091 + unsigned int i; 1.3092 + NSSLOWCERTCertificate *cert; 1.3093 + SECStatus rv = SECSuccess; 1.3094 + 1.3095 + entry = ReadDBSubjectEntry(handle, derSubject); 1.3096 + 1.3097 + if ( entry == NULL ) { 1.3098 + return(SECFailure); 1.3099 + } 1.3100 + 1.3101 + for( i = 0; i < entry->ncerts; i++ ) { 1.3102 + cert = nsslowcert_FindCertByKey(handle, &entry->certKeys[i]); 1.3103 + if (!cert) { 1.3104 + continue; 1.3105 + } 1.3106 + rv = (* cb)(cert, cbarg); 1.3107 + nsslowcert_DestroyCertificate(cert); 1.3108 + if ( rv == SECFailure ) { 1.3109 + break; 1.3110 + } 1.3111 + } 1.3112 + 1.3113 + DestroyDBEntry((certDBEntry *)entry); 1.3114 + 1.3115 + return(rv); 1.3116 +} 1.3117 + 1.3118 +int 1.3119 +nsslowcert_NumPermCertsForSubject(NSSLOWCERTCertDBHandle *handle, 1.3120 + SECItem *derSubject) 1.3121 +{ 1.3122 + certDBEntrySubject *entry; 1.3123 + int ret; 1.3124 + 1.3125 + entry = ReadDBSubjectEntry(handle, derSubject); 1.3126 + 1.3127 + if ( entry == NULL ) { 1.3128 + return(SECFailure); 1.3129 + } 1.3130 + 1.3131 + ret = entry->ncerts; 1.3132 + 1.3133 + DestroyDBEntry((certDBEntry *)entry); 1.3134 + 1.3135 + return(ret); 1.3136 +} 1.3137 + 1.3138 +SECStatus 1.3139 +nsslowcert_TraversePermCertsForNickname(NSSLOWCERTCertDBHandle *handle, 1.3140 + char *nickname, NSSLOWCERTCertCallback cb, void *cbarg) 1.3141 +{ 1.3142 + certDBEntryNickname *nnentry = NULL; 1.3143 + certDBEntrySMime *smentry = NULL; 1.3144 + SECStatus rv; 1.3145 + SECItem *derSubject = NULL; 1.3146 + 1.3147 + nnentry = ReadDBNicknameEntry(handle, nickname); 1.3148 + if ( nnentry ) { 1.3149 + derSubject = &nnentry->subjectName; 1.3150 + } else { 1.3151 + smentry = nsslowcert_ReadDBSMimeEntry(handle, nickname); 1.3152 + if ( smentry ) { 1.3153 + derSubject = &smentry->subjectName; 1.3154 + } 1.3155 + } 1.3156 + 1.3157 + if ( derSubject ) { 1.3158 + rv = nsslowcert_TraversePermCertsForSubject(handle, derSubject, 1.3159 + cb, cbarg); 1.3160 + } else { 1.3161 + rv = SECFailure; 1.3162 + } 1.3163 + 1.3164 + if ( nnentry ) { 1.3165 + DestroyDBEntry((certDBEntry *)nnentry); 1.3166 + } 1.3167 + if ( smentry ) { 1.3168 + DestroyDBEntry((certDBEntry *)smentry); 1.3169 + } 1.3170 + 1.3171 + return(rv); 1.3172 +} 1.3173 + 1.3174 +int 1.3175 +nsslowcert_NumPermCertsForNickname(NSSLOWCERTCertDBHandle *handle, 1.3176 + char *nickname) 1.3177 +{ 1.3178 + certDBEntryNickname *entry; 1.3179 + int ret; 1.3180 + 1.3181 + entry = ReadDBNicknameEntry(handle, nickname); 1.3182 + 1.3183 + if ( entry ) { 1.3184 + ret = nsslowcert_NumPermCertsForSubject(handle, &entry->subjectName); 1.3185 + DestroyDBEntry((certDBEntry *)entry); 1.3186 + } else { 1.3187 + ret = 0; 1.3188 + } 1.3189 + return(ret); 1.3190 +} 1.3191 + 1.3192 +/* 1.3193 + * add a nickname to a cert that doesn't have one 1.3194 + */ 1.3195 +static SECStatus 1.3196 +AddNicknameToPermCert(NSSLOWCERTCertDBHandle *dbhandle, 1.3197 + NSSLOWCERTCertificate *cert, char *nickname) 1.3198 +{ 1.3199 + certDBEntryCert *entry; 1.3200 + int rv; 1.3201 + 1.3202 + entry = cert->dbEntry; 1.3203 + PORT_Assert(entry != NULL); 1.3204 + if ( entry == NULL ) { 1.3205 + goto loser; 1.3206 + } 1.3207 + 1.3208 + pkcs11_freeNickname(entry->nickname,entry->nicknameSpace); 1.3209 + entry->nickname = NULL; 1.3210 + entry->nickname = pkcs11_copyNickname(nickname,entry->nicknameSpace, 1.3211 + sizeof(entry->nicknameSpace)); 1.3212 + 1.3213 + rv = WriteDBCertEntry(dbhandle, entry); 1.3214 + if ( rv ) { 1.3215 + goto loser; 1.3216 + } 1.3217 + 1.3218 + pkcs11_freeNickname(cert->nickname,cert->nicknameSpace); 1.3219 + cert->nickname = NULL; 1.3220 + cert->nickname = pkcs11_copyNickname(nickname,cert->nicknameSpace, 1.3221 + sizeof(cert->nicknameSpace)); 1.3222 + 1.3223 + return(SECSuccess); 1.3224 + 1.3225 +loser: 1.3226 + return(SECFailure); 1.3227 +} 1.3228 + 1.3229 +/* 1.3230 + * add a nickname to a cert that is already in the perm database, but doesn't 1.3231 + * have one yet (it is probably an e-mail cert). 1.3232 + */ 1.3233 +SECStatus 1.3234 +nsslowcert_AddPermNickname(NSSLOWCERTCertDBHandle *dbhandle, 1.3235 + NSSLOWCERTCertificate *cert, char *nickname) 1.3236 +{ 1.3237 + SECStatus rv = SECFailure; 1.3238 + certDBEntrySubject *entry = NULL; 1.3239 + certDBEntryNickname *nicknameEntry = NULL; 1.3240 + 1.3241 + nsslowcert_LockDB(dbhandle); 1.3242 + 1.3243 + entry = ReadDBSubjectEntry(dbhandle, &cert->derSubject); 1.3244 + if (entry == NULL) goto loser; 1.3245 + 1.3246 + if ( entry->nickname == NULL ) { 1.3247 + 1.3248 + /* no nickname for subject */ 1.3249 + rv = AddNicknameToSubject(dbhandle, cert, nickname); 1.3250 + if ( rv != SECSuccess ) { 1.3251 + goto loser; 1.3252 + } 1.3253 + rv = AddNicknameToPermCert(dbhandle, cert, nickname); 1.3254 + if ( rv != SECSuccess ) { 1.3255 + goto loser; 1.3256 + } 1.3257 + nicknameEntry = NewDBNicknameEntry(nickname, &cert->derSubject, 0); 1.3258 + if ( nicknameEntry == NULL ) { 1.3259 + goto loser; 1.3260 + } 1.3261 + 1.3262 + rv = WriteDBNicknameEntry(dbhandle, nicknameEntry); 1.3263 + if ( rv != SECSuccess ) { 1.3264 + goto loser; 1.3265 + } 1.3266 + } else { 1.3267 + /* subject already has a nickname */ 1.3268 + rv = AddNicknameToPermCert(dbhandle, cert, entry->nickname); 1.3269 + if ( rv != SECSuccess ) { 1.3270 + goto loser; 1.3271 + } 1.3272 + /* make sure nickname entry exists. If the database was corrupted, 1.3273 + * we may have lost the nickname entry. Add it back now */ 1.3274 + nicknameEntry = ReadDBNicknameEntry(dbhandle, entry->nickname); 1.3275 + if (nicknameEntry == NULL ) { 1.3276 + nicknameEntry = NewDBNicknameEntry(entry->nickname, 1.3277 + &cert->derSubject, 0); 1.3278 + if ( nicknameEntry == NULL ) { 1.3279 + goto loser; 1.3280 + } 1.3281 + 1.3282 + rv = WriteDBNicknameEntry(dbhandle, nicknameEntry); 1.3283 + if ( rv != SECSuccess ) { 1.3284 + goto loser; 1.3285 + } 1.3286 + } 1.3287 + } 1.3288 + rv = SECSuccess; 1.3289 + 1.3290 +loser: 1.3291 + if (entry) { 1.3292 + DestroyDBEntry((certDBEntry *)entry); 1.3293 + } 1.3294 + if (nicknameEntry) { 1.3295 + DestroyDBEntry((certDBEntry *)nicknameEntry); 1.3296 + } 1.3297 + nsslowcert_UnlockDB(dbhandle); 1.3298 + return(rv); 1.3299 +} 1.3300 + 1.3301 +static certDBEntryCert * 1.3302 +AddCertToPermDB(NSSLOWCERTCertDBHandle *handle, NSSLOWCERTCertificate *cert, 1.3303 + char *nickname, NSSLOWCERTCertTrust *trust) 1.3304 +{ 1.3305 + certDBEntryCert *certEntry = NULL; 1.3306 + certDBEntryNickname *nicknameEntry = NULL; 1.3307 + certDBEntrySubject *subjectEntry = NULL; 1.3308 + int state = 0; 1.3309 + SECStatus rv; 1.3310 + PRBool donnentry = PR_FALSE; 1.3311 + 1.3312 + if ( nickname ) { 1.3313 + donnentry = PR_TRUE; 1.3314 + } 1.3315 + 1.3316 + subjectEntry = ReadDBSubjectEntry(handle, &cert->derSubject); 1.3317 + 1.3318 + if ( subjectEntry && subjectEntry->nickname ) { 1.3319 + donnentry = PR_FALSE; 1.3320 + nickname = subjectEntry->nickname; 1.3321 + } 1.3322 + 1.3323 + certEntry = NewDBCertEntry(&cert->derCert, nickname, trust, 0); 1.3324 + if ( certEntry == NULL ) { 1.3325 + goto loser; 1.3326 + } 1.3327 + 1.3328 + if ( donnentry ) { 1.3329 + nicknameEntry = NewDBNicknameEntry(nickname, &cert->derSubject, 0); 1.3330 + if ( nicknameEntry == NULL ) { 1.3331 + goto loser; 1.3332 + } 1.3333 + } 1.3334 + 1.3335 + rv = WriteDBCertEntry(handle, certEntry); 1.3336 + if ( rv != SECSuccess ) { 1.3337 + goto loser; 1.3338 + } 1.3339 + state = 1; 1.3340 + 1.3341 + if ( nicknameEntry ) { 1.3342 + rv = WriteDBNicknameEntry(handle, nicknameEntry); 1.3343 + if ( rv != SECSuccess ) { 1.3344 + goto loser; 1.3345 + } 1.3346 + } 1.3347 + 1.3348 + state = 2; 1.3349 + 1.3350 + /* "Change" handles if necessary */ 1.3351 + cert->dbhandle = handle; 1.3352 + 1.3353 + /* add to or create new subject entry */ 1.3354 + if ( subjectEntry ) { 1.3355 + /* REWRITE BASED ON SUBJECT ENTRY */ 1.3356 + rv = AddPermSubjectNode(subjectEntry, cert, nickname); 1.3357 + if ( rv != SECSuccess ) { 1.3358 + goto loser; 1.3359 + } 1.3360 + } else { 1.3361 + /* make a new subject entry - this case is only used when updating 1.3362 + * an old version of the database. This is OK because the oldnickname 1.3363 + * db format didn't allow multiple certs with the same subject. 1.3364 + */ 1.3365 + /* where does subjectKeyID and certKey come from? */ 1.3366 + subjectEntry = NewDBSubjectEntry(&cert->derSubject, &cert->certKey, 1.3367 + &cert->subjectKeyID, nickname, 1.3368 + NULL, 0); 1.3369 + if ( subjectEntry == NULL ) { 1.3370 + goto loser; 1.3371 + } 1.3372 + rv = WriteDBSubjectEntry(handle, subjectEntry); 1.3373 + if ( rv != SECSuccess ) { 1.3374 + goto loser; 1.3375 + } 1.3376 + } 1.3377 + 1.3378 + state = 3; 1.3379 + 1.3380 + if ( nicknameEntry ) { 1.3381 + DestroyDBEntry((certDBEntry *)nicknameEntry); 1.3382 + } 1.3383 + 1.3384 + if ( subjectEntry ) { 1.3385 + DestroyDBEntry((certDBEntry *)subjectEntry); 1.3386 + } 1.3387 + 1.3388 + return(certEntry); 1.3389 + 1.3390 +loser: 1.3391 + /* don't leave partial entry in the database */ 1.3392 + if ( state > 0 ) { 1.3393 + rv = DeleteDBCertEntry(handle, &cert->certKey); 1.3394 + } 1.3395 + if ( ( state > 1 ) && donnentry ) { 1.3396 + rv = DeleteDBNicknameEntry(handle, nickname); 1.3397 + } 1.3398 + if ( state > 2 ) { 1.3399 + rv = DeleteDBSubjectEntry(handle, &cert->derSubject); 1.3400 + } 1.3401 + if ( certEntry ) { 1.3402 + DestroyDBEntry((certDBEntry *)certEntry); 1.3403 + } 1.3404 + if ( nicknameEntry ) { 1.3405 + DestroyDBEntry((certDBEntry *)nicknameEntry); 1.3406 + } 1.3407 + if ( subjectEntry ) { 1.3408 + DestroyDBEntry((certDBEntry *)subjectEntry); 1.3409 + } 1.3410 + 1.3411 + return(NULL); 1.3412 +} 1.3413 + 1.3414 +/* forward declaration */ 1.3415 +static SECStatus 1.3416 +UpdateV7DB(NSSLOWCERTCertDBHandle *handle, DB *updatedb); 1.3417 + 1.3418 +/* 1.3419 + * version 8 uses the same schema as version 7. The only differences are 1.3420 + * 1) version 8 db uses the blob shim to store data entries > 32k. 1.3421 + * 2) version 8 db sets the db block size to 32k. 1.3422 + * both of these are dealt with by the handle. 1.3423 + */ 1.3424 + 1.3425 +static SECStatus 1.3426 +UpdateV8DB(NSSLOWCERTCertDBHandle *handle, DB *updatedb) 1.3427 +{ 1.3428 + return UpdateV7DB(handle,updatedb); 1.3429 +} 1.3430 + 1.3431 + 1.3432 +/* 1.3433 + * we could just blindly sequence through reading key data pairs and writing 1.3434 + * them back out, but some cert.db's have gotten quite large and may have some 1.3435 + * subtle corruption problems, so instead we cycle through the certs and 1.3436 + * CRL's and S/MIME profiles and rebuild our subject lists from those records. 1.3437 + */ 1.3438 +static SECStatus 1.3439 +UpdateV7DB(NSSLOWCERTCertDBHandle *handle, DB *updatedb) 1.3440 +{ 1.3441 + DBT key, data; 1.3442 + int ret; 1.3443 + NSSLOWCERTCertificate *cert; 1.3444 + PRBool isKRL = PR_FALSE; 1.3445 + certDBEntryType entryType; 1.3446 + SECItem dbEntry, dbKey; 1.3447 + certDBEntryRevocation crlEntry; 1.3448 + certDBEntryCert certEntry; 1.3449 + certDBEntrySMime smimeEntry; 1.3450 + SECStatus rv; 1.3451 + 1.3452 + ret = (* updatedb->seq)(updatedb, &key, &data, R_FIRST); 1.3453 + 1.3454 + if ( ret ) { 1.3455 + return(SECFailure); 1.3456 + } 1.3457 + 1.3458 + do { 1.3459 + unsigned char *dataBuf = (unsigned char *)data.data; 1.3460 + unsigned char *keyBuf = (unsigned char *)key.data; 1.3461 + dbEntry.data = &dataBuf[SEC_DB_ENTRY_HEADER_LEN]; 1.3462 + dbEntry.len = data.size - SEC_DB_ENTRY_HEADER_LEN; 1.3463 + entryType = (certDBEntryType) keyBuf[0]; 1.3464 + dbKey.data = &keyBuf[SEC_DB_KEY_HEADER_LEN]; 1.3465 + dbKey.len = key.size - SEC_DB_KEY_HEADER_LEN; 1.3466 + if ((dbEntry.len <= 0) || (dbKey.len <= 0)) { 1.3467 + continue; 1.3468 + } 1.3469 + 1.3470 + switch (entryType) { 1.3471 + /* these entries will get regenerated as we read the 1.3472 + * rest of the data from the database */ 1.3473 + case certDBEntryTypeVersion: 1.3474 + case certDBEntryTypeSubject: 1.3475 + case certDBEntryTypeContentVersion: 1.3476 + case certDBEntryTypeNickname: 1.3477 + /* smime profiles need entries created after the certs have 1.3478 + * been imported, loop over them in a second run */ 1.3479 + case certDBEntryTypeSMimeProfile: 1.3480 + break; 1.3481 + 1.3482 + case certDBEntryTypeCert: 1.3483 + /* decode Entry */ 1.3484 + certEntry.common.version = (unsigned int)dataBuf[0]; 1.3485 + certEntry.common.type = entryType; 1.3486 + certEntry.common.flags = (unsigned int)dataBuf[2]; 1.3487 + rv = DecodeDBCertEntry(&certEntry,&dbEntry); 1.3488 + if (rv != SECSuccess) { 1.3489 + break; 1.3490 + } 1.3491 + /* should we check for existing duplicates? */ 1.3492 + cert = nsslowcert_DecodeDERCertificate(&certEntry.derCert, 1.3493 + certEntry.nickname); 1.3494 + if (cert) { 1.3495 + nsslowcert_UpdatePermCert(handle, cert, certEntry.nickname, 1.3496 + &certEntry.trust); 1.3497 + nsslowcert_DestroyCertificate(cert); 1.3498 + } 1.3499 + /* free any data the decode may have allocated. */ 1.3500 + pkcs11_freeStaticData(certEntry.derCert.data, 1.3501 + certEntry.derCertSpace); 1.3502 + pkcs11_freeNickname(certEntry.nickname, certEntry.nicknameSpace); 1.3503 + break; 1.3504 + 1.3505 + case certDBEntryTypeKeyRevocation: 1.3506 + isKRL = PR_TRUE; 1.3507 + /* fall through */ 1.3508 + case certDBEntryTypeRevocation: 1.3509 + crlEntry.common.version = (unsigned int)dataBuf[0]; 1.3510 + crlEntry.common.type = entryType; 1.3511 + crlEntry.common.flags = (unsigned int)dataBuf[2]; 1.3512 + crlEntry.common.arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.3513 + if (crlEntry.common.arena == NULL) { 1.3514 + break; 1.3515 + } 1.3516 + rv = DecodeDBCrlEntry(&crlEntry,&dbEntry); 1.3517 + if (rv != SECSuccess) { 1.3518 + break; 1.3519 + } 1.3520 + nsslowcert_UpdateCrl(handle, &crlEntry.derCrl, &dbKey, 1.3521 + crlEntry.url, isKRL); 1.3522 + /* free data allocated by the decode */ 1.3523 + PORT_FreeArena(crlEntry.common.arena, PR_FALSE); 1.3524 + crlEntry.common.arena = NULL; 1.3525 + break; 1.3526 + 1.3527 + default: 1.3528 + break; 1.3529 + } 1.3530 + } while ( (* updatedb->seq)(updatedb, &key, &data, R_NEXT) == 0 ); 1.3531 + 1.3532 + /* now loop again updating just the SMimeProfile. */ 1.3533 + ret = (* updatedb->seq)(updatedb, &key, &data, R_FIRST); 1.3534 + 1.3535 + if ( ret ) { 1.3536 + return(SECFailure); 1.3537 + } 1.3538 + 1.3539 + do { 1.3540 + unsigned char *dataBuf = (unsigned char *)data.data; 1.3541 + unsigned char *keyBuf = (unsigned char *)key.data; 1.3542 + dbEntry.data = &dataBuf[SEC_DB_ENTRY_HEADER_LEN]; 1.3543 + dbEntry.len = data.size - SEC_DB_ENTRY_HEADER_LEN; 1.3544 + entryType = (certDBEntryType) keyBuf[0]; 1.3545 + if (entryType != certDBEntryTypeSMimeProfile) { 1.3546 + continue; 1.3547 + } 1.3548 + dbKey.data = &keyBuf[SEC_DB_KEY_HEADER_LEN]; 1.3549 + dbKey.len = key.size - SEC_DB_KEY_HEADER_LEN; 1.3550 + if ((dbEntry.len <= 0) || (dbKey.len <= 0)) { 1.3551 + continue; 1.3552 + } 1.3553 + smimeEntry.common.version = (unsigned int)dataBuf[0]; 1.3554 + smimeEntry.common.type = entryType; 1.3555 + smimeEntry.common.flags = (unsigned int)dataBuf[2]; 1.3556 + smimeEntry.common.arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.3557 + /* decode entry */ 1.3558 + rv = DecodeDBSMimeEntry(&smimeEntry,&dbEntry,(char *)dbKey.data); 1.3559 + if (rv == SECSuccess) { 1.3560 + nsslowcert_UpdateSMimeProfile(handle, smimeEntry.emailAddr, 1.3561 + &smimeEntry.subjectName, &smimeEntry.smimeOptions, 1.3562 + &smimeEntry.optionsDate); 1.3563 + } 1.3564 + PORT_FreeArena(smimeEntry.common.arena, PR_FALSE); 1.3565 + smimeEntry.common.arena = NULL; 1.3566 + } while ( (* updatedb->seq)(updatedb, &key, &data, R_NEXT) == 0 ); 1.3567 + 1.3568 + (* updatedb->close)(updatedb); 1.3569 + 1.3570 + /* a database update is a good time to go back and verify the integrity of 1.3571 + * the keys and certs */ 1.3572 + handle->dbVerify = PR_TRUE; 1.3573 + return(SECSuccess); 1.3574 +} 1.3575 + 1.3576 +/* 1.3577 + * NOTE - Version 6 DB did not go out to the real world in a release, 1.3578 + * so we can remove this function in a later release. 1.3579 + */ 1.3580 +static SECStatus 1.3581 +UpdateV6DB(NSSLOWCERTCertDBHandle *handle, DB *updatedb) 1.3582 +{ 1.3583 + int ret; 1.3584 + DBT key, data; 1.3585 + unsigned char *buf, *tmpbuf = NULL; 1.3586 + certDBEntryType type; 1.3587 + certDBEntryNickname *nnEntry = NULL; 1.3588 + certDBEntrySubject *subjectEntry = NULL; 1.3589 + certDBEntrySMime *emailEntry = NULL; 1.3590 + char *nickname; 1.3591 + char *emailAddr; 1.3592 + SECStatus rv; 1.3593 + 1.3594 + /* 1.3595 + * Sequence through the old database and copy all of the entries 1.3596 + * to the new database. Subject name entries will have the new 1.3597 + * fields inserted into them (with zero length). 1.3598 + */ 1.3599 + ret = (* updatedb->seq)(updatedb, &key, &data, R_FIRST); 1.3600 + if ( ret ) { 1.3601 + return(SECFailure); 1.3602 + } 1.3603 + 1.3604 + do { 1.3605 + buf = (unsigned char *)data.data; 1.3606 + 1.3607 + if ( data.size >= 3 ) { 1.3608 + if ( buf[0] == 6 ) { /* version number */ 1.3609 + type = (certDBEntryType)buf[1]; 1.3610 + if ( type == certDBEntryTypeSubject ) { 1.3611 + /* expando subjecto entrieo */ 1.3612 + tmpbuf = (unsigned char *)PORT_Alloc(data.size + 4); 1.3613 + if ( tmpbuf ) { 1.3614 + /* copy header stuff */ 1.3615 + PORT_Memcpy(tmpbuf, buf, SEC_DB_ENTRY_HEADER_LEN + 2); 1.3616 + /* insert 4 more bytes of zero'd header */ 1.3617 + PORT_Memset(&tmpbuf[SEC_DB_ENTRY_HEADER_LEN + 2], 1.3618 + 0, 4); 1.3619 + /* copy rest of the data */ 1.3620 + PORT_Memcpy(&tmpbuf[SEC_DB_ENTRY_HEADER_LEN + 6], 1.3621 + &buf[SEC_DB_ENTRY_HEADER_LEN + 2], 1.3622 + data.size - (SEC_DB_ENTRY_HEADER_LEN + 2)); 1.3623 + 1.3624 + data.data = (void *)tmpbuf; 1.3625 + data.size += 4; 1.3626 + buf = tmpbuf; 1.3627 + } 1.3628 + } else if ( type == certDBEntryTypeCert ) { 1.3629 + /* expando certo entrieo */ 1.3630 + tmpbuf = (unsigned char *)PORT_Alloc(data.size + 3); 1.3631 + if ( tmpbuf ) { 1.3632 + /* copy header stuff */ 1.3633 + PORT_Memcpy(tmpbuf, buf, SEC_DB_ENTRY_HEADER_LEN); 1.3634 + 1.3635 + /* copy trust flage, setting msb's to 0 */ 1.3636 + tmpbuf[SEC_DB_ENTRY_HEADER_LEN] = 0; 1.3637 + tmpbuf[SEC_DB_ENTRY_HEADER_LEN+1] = 1.3638 + buf[SEC_DB_ENTRY_HEADER_LEN]; 1.3639 + tmpbuf[SEC_DB_ENTRY_HEADER_LEN+2] = 0; 1.3640 + tmpbuf[SEC_DB_ENTRY_HEADER_LEN+3] = 1.3641 + buf[SEC_DB_ENTRY_HEADER_LEN+1]; 1.3642 + tmpbuf[SEC_DB_ENTRY_HEADER_LEN+4] = 0; 1.3643 + tmpbuf[SEC_DB_ENTRY_HEADER_LEN+5] = 1.3644 + buf[SEC_DB_ENTRY_HEADER_LEN+2]; 1.3645 + 1.3646 + /* copy rest of the data */ 1.3647 + PORT_Memcpy(&tmpbuf[SEC_DB_ENTRY_HEADER_LEN + 6], 1.3648 + &buf[SEC_DB_ENTRY_HEADER_LEN + 3], 1.3649 + data.size - (SEC_DB_ENTRY_HEADER_LEN + 3)); 1.3650 + 1.3651 + data.data = (void *)tmpbuf; 1.3652 + data.size += 3; 1.3653 + buf = tmpbuf; 1.3654 + } 1.3655 + 1.3656 + } 1.3657 + 1.3658 + /* update the record version number */ 1.3659 + buf[0] = CERT_DB_FILE_VERSION; 1.3660 + 1.3661 + /* copy to the new database */ 1.3662 + ret = certdb_Put(handle->permCertDB, &key, &data, 0); 1.3663 + if ( tmpbuf ) { 1.3664 + PORT_Free(tmpbuf); 1.3665 + tmpbuf = NULL; 1.3666 + } 1.3667 + } 1.3668 + } 1.3669 + } while ( (* updatedb->seq)(updatedb, &key, &data, R_NEXT) == 0 ); 1.3670 + 1.3671 + ret = certdb_Sync(handle->permCertDB, 0); 1.3672 + 1.3673 + ret = (* updatedb->seq)(updatedb, &key, &data, R_FIRST); 1.3674 + if ( ret ) { 1.3675 + return(SECFailure); 1.3676 + } 1.3677 + 1.3678 + do { 1.3679 + buf = (unsigned char *)data.data; 1.3680 + 1.3681 + if ( data.size >= 3 ) { 1.3682 + if ( buf[0] == CERT_DB_FILE_VERSION ) { /* version number */ 1.3683 + type = (certDBEntryType)buf[1]; 1.3684 + if ( type == certDBEntryTypeNickname ) { 1.3685 + nickname = &((char *)key.data)[1]; 1.3686 + 1.3687 + /* get the matching nickname entry in the new DB */ 1.3688 + nnEntry = ReadDBNicknameEntry(handle, nickname); 1.3689 + if ( nnEntry == NULL ) { 1.3690 + goto endloop; 1.3691 + } 1.3692 + 1.3693 + /* find the subject entry pointed to by nickname */ 1.3694 + subjectEntry = ReadDBSubjectEntry(handle, 1.3695 + &nnEntry->subjectName); 1.3696 + if ( subjectEntry == NULL ) { 1.3697 + goto endloop; 1.3698 + } 1.3699 + 1.3700 + subjectEntry->nickname = 1.3701 + (char *)PORT_ArenaAlloc(subjectEntry->common.arena, 1.3702 + key.size - 1); 1.3703 + if ( subjectEntry->nickname ) { 1.3704 + PORT_Memcpy(subjectEntry->nickname, nickname, 1.3705 + key.size - 1); 1.3706 + rv = WriteDBSubjectEntry(handle, subjectEntry); 1.3707 + } 1.3708 + } else if ( type == certDBEntryTypeSMimeProfile ) { 1.3709 + emailAddr = &((char *)key.data)[1]; 1.3710 + 1.3711 + /* get the matching smime entry in the new DB */ 1.3712 + emailEntry = nsslowcert_ReadDBSMimeEntry(handle, emailAddr); 1.3713 + if ( emailEntry == NULL ) { 1.3714 + goto endloop; 1.3715 + } 1.3716 + 1.3717 + /* find the subject entry pointed to by nickname */ 1.3718 + subjectEntry = ReadDBSubjectEntry(handle, 1.3719 + &emailEntry->subjectName); 1.3720 + if ( subjectEntry == NULL ) { 1.3721 + goto endloop; 1.3722 + } 1.3723 + 1.3724 + subjectEntry->emailAddrs = (char **) 1.3725 + PORT_ArenaAlloc(subjectEntry->common.arena, 1.3726 + sizeof(char *)); 1.3727 + if ( subjectEntry->emailAddrs ) { 1.3728 + subjectEntry->emailAddrs[0] = 1.3729 + (char *)PORT_ArenaAlloc(subjectEntry->common.arena, 1.3730 + key.size - 1); 1.3731 + if ( subjectEntry->emailAddrs[0] ) { 1.3732 + PORT_Memcpy(subjectEntry->emailAddrs[0], emailAddr, 1.3733 + key.size - 1); 1.3734 + subjectEntry->nemailAddrs = 1; 1.3735 + rv = WriteDBSubjectEntry(handle, subjectEntry); 1.3736 + } 1.3737 + } 1.3738 + } 1.3739 + 1.3740 +endloop: 1.3741 + if ( subjectEntry ) { 1.3742 + DestroyDBEntry((certDBEntry *)subjectEntry); 1.3743 + subjectEntry = NULL; 1.3744 + } 1.3745 + if ( nnEntry ) { 1.3746 + DestroyDBEntry((certDBEntry *)nnEntry); 1.3747 + nnEntry = NULL; 1.3748 + } 1.3749 + if ( emailEntry ) { 1.3750 + DestroyDBEntry((certDBEntry *)emailEntry); 1.3751 + emailEntry = NULL; 1.3752 + } 1.3753 + } 1.3754 + } 1.3755 + } while ( (* updatedb->seq)(updatedb, &key, &data, R_NEXT) == 0 ); 1.3756 + 1.3757 + ret = certdb_Sync(handle->permCertDB, 0); 1.3758 + 1.3759 + (* updatedb->close)(updatedb); 1.3760 + return(SECSuccess); 1.3761 +} 1.3762 + 1.3763 + 1.3764 +static SECStatus 1.3765 +updateV5Callback(NSSLOWCERTCertificate *cert, SECItem *k, void *pdata) 1.3766 +{ 1.3767 + NSSLOWCERTCertDBHandle *handle; 1.3768 + certDBEntryCert *entry; 1.3769 + NSSLOWCERTCertTrust *trust; 1.3770 + 1.3771 + handle = (NSSLOWCERTCertDBHandle *)pdata; 1.3772 + trust = &cert->dbEntry->trust; 1.3773 + 1.3774 + /* SSL user certs can be used for email if they have an email addr */ 1.3775 + if ( cert->emailAddr && ( trust->sslFlags & CERTDB_USER ) && 1.3776 + ( trust->emailFlags == 0 ) ) { 1.3777 + trust->emailFlags = CERTDB_USER; 1.3778 + } 1.3779 + /* servers didn't set the user flags on the server cert.. */ 1.3780 + if (PORT_Strcmp(cert->dbEntry->nickname,"Server-Cert") == 0) { 1.3781 + trust->sslFlags |= CERTDB_USER; 1.3782 + } 1.3783 + 1.3784 + entry = AddCertToPermDB(handle, cert, cert->dbEntry->nickname, 1.3785 + &cert->dbEntry->trust); 1.3786 + if ( entry ) { 1.3787 + DestroyDBEntry((certDBEntry *)entry); 1.3788 + } 1.3789 + 1.3790 + return(SECSuccess); 1.3791 +} 1.3792 + 1.3793 +static SECStatus 1.3794 +UpdateV5DB(NSSLOWCERTCertDBHandle *handle, DB *updatedb) 1.3795 +{ 1.3796 + NSSLOWCERTCertDBHandle updatehandle; 1.3797 + SECStatus rv; 1.3798 + 1.3799 + updatehandle.permCertDB = updatedb; 1.3800 + updatehandle.dbMon = PZ_NewMonitor(nssILockCertDB); 1.3801 + updatehandle.dbVerify = 0; 1.3802 + updatehandle.ref = 1; /* prevent premature close */ 1.3803 + 1.3804 + rv = nsslowcert_TraversePermCerts(&updatehandle, updateV5Callback, 1.3805 + (void *)handle); 1.3806 + 1.3807 + PZ_DestroyMonitor(updatehandle.dbMon); 1.3808 + 1.3809 + (* updatedb->close)(updatedb); 1.3810 + return(SECSuccess); 1.3811 +} 1.3812 + 1.3813 +static PRBool 1.3814 +isV4DB(DB *db) { 1.3815 + DBT key,data; 1.3816 + int ret; 1.3817 + 1.3818 + key.data = "Version"; 1.3819 + key.size = 7; 1.3820 + 1.3821 + ret = (*db->get)(db, &key, &data, 0); 1.3822 + if (ret) { 1.3823 + return PR_FALSE; 1.3824 + } 1.3825 + 1.3826 + if ((data.size == 1) && (*(unsigned char *)data.data <= 4)) { 1.3827 + return PR_TRUE; 1.3828 + } 1.3829 + 1.3830 + return PR_FALSE; 1.3831 +} 1.3832 + 1.3833 +static SECStatus 1.3834 +UpdateV4DB(NSSLOWCERTCertDBHandle *handle, DB *updatedb) 1.3835 +{ 1.3836 + DBT key, data; 1.3837 + certDBEntryCert *entry, *entry2; 1.3838 + int ret; 1.3839 + PLArenaPool *arena = NULL; 1.3840 + NSSLOWCERTCertificate *cert; 1.3841 + 1.3842 + ret = (* updatedb->seq)(updatedb, &key, &data, R_FIRST); 1.3843 + 1.3844 + if ( ret ) { 1.3845 + return(SECFailure); 1.3846 + } 1.3847 + 1.3848 + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.3849 + if (arena == NULL) { 1.3850 + return(SECFailure); 1.3851 + } 1.3852 + 1.3853 + do { 1.3854 + if ( data.size != 1 ) { /* skip version number */ 1.3855 + 1.3856 + /* decode the old DB entry */ 1.3857 + entry = (certDBEntryCert *) 1.3858 + DecodeV4DBCertEntry((unsigned char*)data.data, data.size); 1.3859 + 1.3860 + if ( entry ) { 1.3861 + cert = nsslowcert_DecodeDERCertificate(&entry->derCert, 1.3862 + entry->nickname); 1.3863 + 1.3864 + if ( cert != NULL ) { 1.3865 + /* add to new database */ 1.3866 + entry2 = AddCertToPermDB(handle, cert, entry->nickname, 1.3867 + &entry->trust); 1.3868 + 1.3869 + nsslowcert_DestroyCertificate(cert); 1.3870 + if ( entry2 ) { 1.3871 + DestroyDBEntry((certDBEntry *)entry2); 1.3872 + } 1.3873 + } 1.3874 + DestroyDBEntry((certDBEntry *)entry); 1.3875 + } 1.3876 + } 1.3877 + } while ( (* updatedb->seq)(updatedb, &key, &data, R_NEXT) == 0 ); 1.3878 + 1.3879 + PORT_FreeArena(arena, PR_FALSE); 1.3880 + (* updatedb->close)(updatedb); 1.3881 + return(SECSuccess); 1.3882 +} 1.3883 + 1.3884 + 1.3885 +/* 1.3886 + * return true if a database key conflict exists 1.3887 + */ 1.3888 +PRBool 1.3889 +nsslowcert_CertDBKeyConflict(SECItem *derCert, NSSLOWCERTCertDBHandle *handle) 1.3890 +{ 1.3891 + SECStatus rv; 1.3892 + DBT tmpdata; 1.3893 + DBT namekey; 1.3894 + int ret; 1.3895 + SECItem keyitem; 1.3896 + PLArenaPool *arena = NULL; 1.3897 + SECItem derKey; 1.3898 + 1.3899 + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.3900 + if ( arena == NULL ) { 1.3901 + goto loser; 1.3902 + } 1.3903 + 1.3904 + /* get the db key of the cert */ 1.3905 + rv = nsslowcert_KeyFromDERCert(arena, derCert, &derKey); 1.3906 + if ( rv != SECSuccess ) { 1.3907 + goto loser; 1.3908 + } 1.3909 + 1.3910 + rv = EncodeDBCertKey(&derKey, arena, &keyitem); 1.3911 + if ( rv != SECSuccess ) { 1.3912 + goto loser; 1.3913 + } 1.3914 + 1.3915 + namekey.data = keyitem.data; 1.3916 + namekey.size = keyitem.len; 1.3917 + 1.3918 + ret = certdb_Get(handle->permCertDB, &namekey, &tmpdata, 0); 1.3919 + if ( ret == 0 ) { 1.3920 + goto loser; 1.3921 + } 1.3922 + 1.3923 + PORT_FreeArena(arena, PR_FALSE); 1.3924 + 1.3925 + return(PR_FALSE); 1.3926 +loser: 1.3927 + if ( arena ) { 1.3928 + PORT_FreeArena(arena, PR_FALSE); 1.3929 + } 1.3930 + 1.3931 + return(PR_TRUE); 1.3932 +} 1.3933 + 1.3934 +/* 1.3935 + * return true if a nickname conflict exists 1.3936 + * NOTE: caller must have already made sure that this exact cert 1.3937 + * doesn't exist in the DB 1.3938 + */ 1.3939 +static PRBool 1.3940 +nsslowcert_CertNicknameConflict(char *nickname, SECItem *derSubject, 1.3941 + NSSLOWCERTCertDBHandle *handle) 1.3942 +{ 1.3943 + PRBool rv; 1.3944 + certDBEntryNickname *entry; 1.3945 + 1.3946 + if ( nickname == NULL ) { 1.3947 + return(PR_FALSE); 1.3948 + } 1.3949 + 1.3950 + entry = ReadDBNicknameEntry(handle, nickname); 1.3951 + 1.3952 + if ( entry == NULL ) { 1.3953 + /* no entry for this nickname, so no conflict */ 1.3954 + return(PR_FALSE); 1.3955 + } 1.3956 + 1.3957 + rv = PR_TRUE; 1.3958 + if ( SECITEM_CompareItem(derSubject, &entry->subjectName) == SECEqual ) { 1.3959 + /* if subject names are the same, then no conflict */ 1.3960 + rv = PR_FALSE; 1.3961 + } 1.3962 + 1.3963 + DestroyDBEntry((certDBEntry *)entry); 1.3964 + return(rv); 1.3965 +} 1.3966 + 1.3967 +#ifdef DBM_USING_NSPR 1.3968 +#define NO_RDONLY PR_RDONLY 1.3969 +#define NO_RDWR PR_RDWR 1.3970 +#define NO_CREATE (PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE) 1.3971 +#else 1.3972 +#define NO_RDONLY O_RDONLY 1.3973 +#define NO_RDWR O_RDWR 1.3974 +#define NO_CREATE (O_RDWR | O_CREAT | O_TRUNC) 1.3975 +#endif 1.3976 + 1.3977 +/* 1.3978 + * open an old database that needs to be updated 1.3979 + */ 1.3980 +static DB * 1.3981 +nsslowcert_openolddb(NSSLOWCERTDBNameFunc namecb, void *cbarg, int version) 1.3982 +{ 1.3983 + char * tmpname; 1.3984 + DB *updatedb = NULL; 1.3985 + 1.3986 + tmpname = (* namecb)(cbarg, version); /* get v6 db name */ 1.3987 + if ( tmpname ) { 1.3988 + updatedb = dbopen( tmpname, NO_RDONLY, 0600, DB_HASH, 0 ); 1.3989 + PORT_Free(tmpname); 1.3990 + } 1.3991 + return updatedb; 1.3992 +} 1.3993 + 1.3994 +static SECStatus 1.3995 +openNewCertDB(const char *appName, const char *prefix, const char *certdbname, 1.3996 + NSSLOWCERTCertDBHandle *handle, NSSLOWCERTDBNameFunc namecb, void *cbarg) 1.3997 +{ 1.3998 + SECStatus rv; 1.3999 + certDBEntryVersion *versionEntry = NULL; 1.4000 + DB *updatedb = NULL; 1.4001 + int status = RDB_FAIL; 1.4002 + 1.4003 + if (appName) { 1.4004 + handle->permCertDB=rdbopen( appName, prefix, "cert", NO_CREATE, &status); 1.4005 + } else { 1.4006 + handle->permCertDB=dbsopen(certdbname, NO_CREATE, 0600, DB_HASH, 0); 1.4007 + } 1.4008 + 1.4009 + /* if create fails then we lose */ 1.4010 + if ( handle->permCertDB == 0 ) { 1.4011 + return status == RDB_RETRY ? SECWouldBlock : SECFailure; 1.4012 + } 1.4013 + 1.4014 + /* Verify version number; */ 1.4015 + versionEntry = NewDBVersionEntry(0); 1.4016 + if ( versionEntry == NULL ) { 1.4017 + rv = SECFailure; 1.4018 + goto loser; 1.4019 + } 1.4020 + 1.4021 + rv = WriteDBVersionEntry(handle, versionEntry); 1.4022 + 1.4023 + DestroyDBEntry((certDBEntry *)versionEntry); 1.4024 + 1.4025 + if ( rv != SECSuccess ) { 1.4026 + goto loser; 1.4027 + } 1.4028 + 1.4029 + /* rv must already be Success here because of previous if statement */ 1.4030 + /* try to upgrade old db here */ 1.4031 + if (appName && 1.4032 + (updatedb = dbsopen(certdbname, NO_RDONLY, 0600, DB_HASH, 0)) != NULL) { 1.4033 + rv = UpdateV8DB(handle, updatedb); 1.4034 + } else if ((updatedb = nsslowcert_openolddb(namecb,cbarg,7)) != NULL) { 1.4035 + rv = UpdateV7DB(handle, updatedb); 1.4036 + } else if ((updatedb = nsslowcert_openolddb(namecb,cbarg,6)) != NULL) { 1.4037 + rv = UpdateV6DB(handle, updatedb); 1.4038 + } else if ((updatedb = nsslowcert_openolddb(namecb,cbarg,5)) != NULL) { 1.4039 + rv = UpdateV5DB(handle, updatedb); 1.4040 + } else if ((updatedb = nsslowcert_openolddb(namecb,cbarg,4)) != NULL) { 1.4041 + /* NES has v5 format db's with v4 db names! */ 1.4042 + if (isV4DB(updatedb)) { 1.4043 + rv = UpdateV4DB(handle,updatedb); 1.4044 + } else { 1.4045 + rv = UpdateV5DB(handle,updatedb); 1.4046 + } 1.4047 + } 1.4048 + 1.4049 + 1.4050 +loser: 1.4051 + db_InitComplete(handle->permCertDB); 1.4052 + return rv; 1.4053 +} 1.4054 + 1.4055 +static int 1.4056 +nsslowcert_GetVersionNumber( NSSLOWCERTCertDBHandle *handle) 1.4057 +{ 1.4058 + certDBEntryVersion *versionEntry = NULL; 1.4059 + int version = 0; 1.4060 + 1.4061 + versionEntry = ReadDBVersionEntry(handle); 1.4062 + if ( versionEntry == NULL ) { 1.4063 + return 0; 1.4064 + } 1.4065 + version = versionEntry->common.version; 1.4066 + DestroyDBEntry((certDBEntry *)versionEntry); 1.4067 + return version; 1.4068 +} 1.4069 + 1.4070 +/* 1.4071 + * Open the certificate database and index databases. Create them if 1.4072 + * they are not there or bad. 1.4073 + */ 1.4074 +static SECStatus 1.4075 +nsslowcert_OpenPermCertDB(NSSLOWCERTCertDBHandle *handle, PRBool readOnly, 1.4076 + const char *appName, const char *prefix, 1.4077 + NSSLOWCERTDBNameFunc namecb, void *cbarg) 1.4078 +{ 1.4079 + SECStatus rv; 1.4080 + int openflags; 1.4081 + char *certdbname; 1.4082 + int version = 0; 1.4083 + 1.4084 + certdbname = (* namecb)(cbarg, CERT_DB_FILE_VERSION); 1.4085 + if ( certdbname == NULL ) { 1.4086 + return(SECFailure); 1.4087 + } 1.4088 + 1.4089 + openflags = readOnly ? NO_RDONLY : NO_RDWR; 1.4090 + 1.4091 + /* 1.4092 + * first open the permanent file based database. 1.4093 + */ 1.4094 + if (appName) { 1.4095 + handle->permCertDB = rdbopen( appName, prefix, "cert", openflags, NULL); 1.4096 + } else { 1.4097 + handle->permCertDB = dbsopen( certdbname, openflags, 0600, DB_HASH, 0 ); 1.4098 + } 1.4099 + 1.4100 + /* check for correct version number */ 1.4101 + if ( handle->permCertDB ) { 1.4102 + version = nsslowcert_GetVersionNumber(handle); 1.4103 + if ((version != CERT_DB_FILE_VERSION) && 1.4104 + !(appName && version == CERT_DB_V7_FILE_VERSION)) { 1.4105 + goto loser; 1.4106 + } 1.4107 + } else if ( readOnly ) { 1.4108 + /* don't create if readonly */ 1.4109 + /* Try openning a version 7 database */ 1.4110 + handle->permCertDB = nsslowcert_openolddb(namecb,cbarg, 7); 1.4111 + if (!handle->permCertDB) { 1.4112 + goto loser; 1.4113 + } 1.4114 + if (nsslowcert_GetVersionNumber(handle) != 7) { 1.4115 + goto loser; 1.4116 + } 1.4117 + } else { 1.4118 + /* if first open fails, try to create a new DB */ 1.4119 + rv = openNewCertDB(appName,prefix,certdbname,handle,namecb,cbarg); 1.4120 + if (rv == SECWouldBlock) { 1.4121 + /* only the rdb version can fail with wouldblock */ 1.4122 + handle->permCertDB = 1.4123 + rdbopen( appName, prefix, "cert", openflags, NULL); 1.4124 + 1.4125 + /* check for correct version number */ 1.4126 + if ( !handle->permCertDB ) { 1.4127 + goto loser; 1.4128 + } 1.4129 + version = nsslowcert_GetVersionNumber(handle); 1.4130 + if ((version != CERT_DB_FILE_VERSION) && 1.4131 + !(appName && version == CERT_DB_V7_FILE_VERSION)) { 1.4132 + goto loser; 1.4133 + } 1.4134 + } else if (rv != SECSuccess) { 1.4135 + goto loser; 1.4136 + } 1.4137 + } 1.4138 + 1.4139 + PORT_Free(certdbname); 1.4140 + 1.4141 + return (SECSuccess); 1.4142 + 1.4143 +loser: 1.4144 + 1.4145 + PORT_SetError(SEC_ERROR_BAD_DATABASE); 1.4146 + 1.4147 + if ( handle->permCertDB ) { 1.4148 + certdb_Close(handle->permCertDB); 1.4149 + handle->permCertDB = 0; 1.4150 + } 1.4151 + 1.4152 + PORT_Free(certdbname); 1.4153 + 1.4154 + return(SECFailure); 1.4155 +} 1.4156 + 1.4157 +/* 1.4158 + * delete all DB records associated with a particular certificate 1.4159 + */ 1.4160 +static SECStatus 1.4161 +DeletePermCert(NSSLOWCERTCertificate *cert) 1.4162 +{ 1.4163 + SECStatus rv; 1.4164 + SECStatus ret; 1.4165 + 1.4166 + ret = SECSuccess; 1.4167 + 1.4168 + rv = DeleteDBCertEntry(cert->dbhandle, &cert->certKey); 1.4169 + if ( rv != SECSuccess ) { 1.4170 + ret = SECFailure; 1.4171 + } 1.4172 + 1.4173 + rv = RemovePermSubjectNode(cert); 1.4174 + 1.4175 + 1.4176 + return(ret); 1.4177 +} 1.4178 + 1.4179 +/* 1.4180 + * Delete a certificate from the permanent database. 1.4181 + */ 1.4182 +SECStatus 1.4183 +nsslowcert_DeletePermCertificate(NSSLOWCERTCertificate *cert) 1.4184 +{ 1.4185 + SECStatus rv; 1.4186 + 1.4187 + nsslowcert_LockDB(cert->dbhandle); 1.4188 + 1.4189 + /* delete the records from the permanent database */ 1.4190 + rv = DeletePermCert(cert); 1.4191 + 1.4192 + /* get rid of dbcert and stuff pointing to it */ 1.4193 + DestroyDBEntry((certDBEntry *)cert->dbEntry); 1.4194 + cert->dbEntry = NULL; 1.4195 + cert->trust = NULL; 1.4196 + 1.4197 + nsslowcert_UnlockDB(cert->dbhandle); 1.4198 + return(rv); 1.4199 +} 1.4200 + 1.4201 +/* 1.4202 + * Traverse all of the entries in the database of a particular type 1.4203 + * call the given function for each one. 1.4204 + */ 1.4205 +SECStatus 1.4206 +nsslowcert_TraverseDBEntries(NSSLOWCERTCertDBHandle *handle, 1.4207 + certDBEntryType type, 1.4208 + SECStatus (* callback)(SECItem *data, SECItem *key, 1.4209 + certDBEntryType type, void *pdata), 1.4210 + void *udata ) 1.4211 +{ 1.4212 + DBT data; 1.4213 + DBT key; 1.4214 + SECStatus rv = SECSuccess; 1.4215 + int ret; 1.4216 + SECItem dataitem; 1.4217 + SECItem keyitem; 1.4218 + unsigned char *buf; 1.4219 + unsigned char *keybuf; 1.4220 + 1.4221 + ret = certdb_Seq(handle->permCertDB, &key, &data, R_FIRST); 1.4222 + if ( ret ) { 1.4223 + return(SECFailure); 1.4224 + } 1.4225 + /* here, ret is zero and rv is SECSuccess. 1.4226 + * Below here, ret is a count of successful calls to the callback function. 1.4227 + */ 1.4228 + do { 1.4229 + buf = (unsigned char *)data.data; 1.4230 + 1.4231 + if ( buf[1] == (unsigned char)type ) { 1.4232 + dataitem.len = data.size; 1.4233 + dataitem.data = buf; 1.4234 + dataitem.type = siBuffer; 1.4235 + keyitem.len = key.size - SEC_DB_KEY_HEADER_LEN; 1.4236 + keybuf = (unsigned char *)key.data; 1.4237 + keyitem.data = &keybuf[SEC_DB_KEY_HEADER_LEN]; 1.4238 + keyitem.type = siBuffer; 1.4239 + /* type should equal keybuf[0]. */ 1.4240 + 1.4241 + rv = (* callback)(&dataitem, &keyitem, type, udata); 1.4242 + if ( rv == SECSuccess ) { 1.4243 + ++ret; 1.4244 + } 1.4245 + } 1.4246 + } while ( certdb_Seq(handle->permCertDB, &key, &data, R_NEXT) == 0 ); 1.4247 + /* If any callbacks succeeded, or no calls to callbacks were made, 1.4248 + * then report success. Otherwise, report failure. 1.4249 + */ 1.4250 + return (ret ? SECSuccess : rv); 1.4251 +} 1.4252 +/* 1.4253 + * Decode a certificate and enter it into the temporary certificate database. 1.4254 + * Deal with nicknames correctly 1.4255 + * 1.4256 + * This is the private entry point. 1.4257 + */ 1.4258 +static NSSLOWCERTCertificate * 1.4259 +DecodeACert(NSSLOWCERTCertDBHandle *handle, certDBEntryCert *entry) 1.4260 +{ 1.4261 + NSSLOWCERTCertificate *cert = NULL; 1.4262 + 1.4263 + cert = nsslowcert_DecodeDERCertificate(&entry->derCert, entry->nickname ); 1.4264 + 1.4265 + if ( cert == NULL ) { 1.4266 + goto loser; 1.4267 + } 1.4268 + 1.4269 + cert->dbhandle = handle; 1.4270 + cert->dbEntry = entry; 1.4271 + cert->trust = &entry->trust; 1.4272 + 1.4273 + return(cert); 1.4274 + 1.4275 +loser: 1.4276 + return(0); 1.4277 +} 1.4278 + 1.4279 +static NSSLOWCERTTrust * 1.4280 +CreateTrust(void) 1.4281 +{ 1.4282 + NSSLOWCERTTrust *trust = NULL; 1.4283 + 1.4284 + nsslowcert_LockFreeList(); 1.4285 + trust = trustListHead; 1.4286 + if (trust) { 1.4287 + trustListCount--; 1.4288 + trustListHead = trust->next; 1.4289 + } 1.4290 + PORT_Assert(trustListCount >= 0); 1.4291 + nsslowcert_UnlockFreeList(); 1.4292 + if (trust) { 1.4293 + return trust; 1.4294 + } 1.4295 + 1.4296 + return PORT_ZNew(NSSLOWCERTTrust); 1.4297 +} 1.4298 + 1.4299 +static void 1.4300 +DestroyTrustFreeList(void) 1.4301 +{ 1.4302 + NSSLOWCERTTrust *trust; 1.4303 + 1.4304 + nsslowcert_LockFreeList(); 1.4305 + while (NULL != (trust = trustListHead)) { 1.4306 + trustListCount--; 1.4307 + trustListHead = trust->next; 1.4308 + PORT_Free(trust); 1.4309 + } 1.4310 + PORT_Assert(!trustListCount); 1.4311 + trustListCount = 0; 1.4312 + nsslowcert_UnlockFreeList(); 1.4313 +} 1.4314 + 1.4315 +static NSSLOWCERTTrust * 1.4316 +DecodeTrustEntry(NSSLOWCERTCertDBHandle *handle, certDBEntryCert *entry, 1.4317 + const SECItem *dbKey) 1.4318 +{ 1.4319 + NSSLOWCERTTrust *trust = CreateTrust(); 1.4320 + if (trust == NULL) { 1.4321 + return trust; 1.4322 + } 1.4323 + trust->dbhandle = handle; 1.4324 + trust->dbEntry = entry; 1.4325 + trust->dbKey.data = pkcs11_copyStaticData(dbKey->data,dbKey->len, 1.4326 + trust->dbKeySpace, sizeof(trust->dbKeySpace)); 1.4327 + if (!trust->dbKey.data) { 1.4328 + PORT_Free(trust); 1.4329 + return NULL; 1.4330 + } 1.4331 + trust->dbKey.len = dbKey->len; 1.4332 + 1.4333 + trust->trust = &entry->trust; 1.4334 + trust->derCert = &entry->derCert; 1.4335 + 1.4336 + return(trust); 1.4337 +} 1.4338 + 1.4339 +typedef struct { 1.4340 + PermCertCallback certfunc; 1.4341 + NSSLOWCERTCertDBHandle *handle; 1.4342 + void *data; 1.4343 +} PermCertCallbackState; 1.4344 + 1.4345 +/* 1.4346 + * traversal callback to decode certs and call callers callback 1.4347 + */ 1.4348 +static SECStatus 1.4349 +certcallback(SECItem *dbdata, SECItem *dbkey, certDBEntryType type, void *data) 1.4350 +{ 1.4351 + PermCertCallbackState *mystate; 1.4352 + SECStatus rv; 1.4353 + certDBEntryCert *entry; 1.4354 + SECItem entryitem; 1.4355 + NSSLOWCERTCertificate *cert; 1.4356 + PLArenaPool *arena = NULL; 1.4357 + 1.4358 + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.4359 + if ( arena == NULL ) { 1.4360 + goto loser; 1.4361 + } 1.4362 + 1.4363 + entry = (certDBEntryCert *)PORT_ArenaAlloc(arena, sizeof(certDBEntryCert)); 1.4364 + mystate = (PermCertCallbackState *)data; 1.4365 + entry->common.version = (unsigned int)dbdata->data[0]; 1.4366 + entry->common.type = (certDBEntryType)dbdata->data[1]; 1.4367 + entry->common.flags = (unsigned int)dbdata->data[2]; 1.4368 + entry->common.arena = arena; 1.4369 + 1.4370 + entryitem.len = dbdata->len - SEC_DB_ENTRY_HEADER_LEN; 1.4371 + entryitem.data = &dbdata->data[SEC_DB_ENTRY_HEADER_LEN]; 1.4372 + 1.4373 + rv = DecodeDBCertEntry(entry, &entryitem); 1.4374 + if (rv != SECSuccess ) { 1.4375 + goto loser; 1.4376 + } 1.4377 + entry->derCert.type = siBuffer; 1.4378 + 1.4379 + /* note: Entry is 'inheritted'. */ 1.4380 + cert = DecodeACert(mystate->handle, entry); 1.4381 + 1.4382 + rv = (* mystate->certfunc)(cert, dbkey, mystate->data); 1.4383 + 1.4384 + /* arena stored in entry destroyed by nsslowcert_DestroyCertificate */ 1.4385 + nsslowcert_DestroyCertificateNoLocking(cert); 1.4386 + 1.4387 + return(rv); 1.4388 + 1.4389 +loser: 1.4390 + if ( arena ) { 1.4391 + PORT_FreeArena(arena, PR_FALSE); 1.4392 + } 1.4393 + return(SECFailure); 1.4394 +} 1.4395 + 1.4396 +/* 1.4397 + * Traverse all of the certificates in the permanent database and 1.4398 + * call the given function for each one; expect the caller to have lock. 1.4399 + */ 1.4400 +static SECStatus 1.4401 +TraversePermCertsNoLocking(NSSLOWCERTCertDBHandle *handle, 1.4402 + SECStatus (* certfunc)(NSSLOWCERTCertificate *cert, 1.4403 + SECItem *k, 1.4404 + void *pdata), 1.4405 + void *udata ) 1.4406 +{ 1.4407 + SECStatus rv; 1.4408 + PermCertCallbackState mystate; 1.4409 + 1.4410 + mystate.certfunc = certfunc; 1.4411 + mystate.handle = handle; 1.4412 + mystate.data = udata; 1.4413 + rv = nsslowcert_TraverseDBEntries(handle, certDBEntryTypeCert, certcallback, 1.4414 + (void *)&mystate); 1.4415 + 1.4416 + return(rv); 1.4417 +} 1.4418 + 1.4419 +/* 1.4420 + * Traverse all of the certificates in the permanent database and 1.4421 + * call the given function for each one. 1.4422 + */ 1.4423 +SECStatus 1.4424 +nsslowcert_TraversePermCerts(NSSLOWCERTCertDBHandle *handle, 1.4425 + SECStatus (* certfunc)(NSSLOWCERTCertificate *cert, SECItem *k, 1.4426 + void *pdata), 1.4427 + void *udata ) 1.4428 +{ 1.4429 + SECStatus rv; 1.4430 + 1.4431 + nsslowcert_LockDB(handle); 1.4432 + rv = TraversePermCertsNoLocking(handle, certfunc, udata); 1.4433 + nsslowcert_UnlockDB(handle); 1.4434 + 1.4435 + return(rv); 1.4436 +} 1.4437 + 1.4438 + 1.4439 + 1.4440 +/* 1.4441 + * Close the database 1.4442 + */ 1.4443 +void 1.4444 +nsslowcert_ClosePermCertDB(NSSLOWCERTCertDBHandle *handle) 1.4445 +{ 1.4446 + if ( handle ) { 1.4447 + if ( handle->permCertDB ) { 1.4448 + certdb_Close( handle->permCertDB ); 1.4449 + handle->permCertDB = NULL; 1.4450 + } 1.4451 + if (handle->dbMon) { 1.4452 + PZ_DestroyMonitor(handle->dbMon); 1.4453 + handle->dbMon = NULL; 1.4454 + } 1.4455 + PORT_Free(handle); 1.4456 + } 1.4457 + return; 1.4458 +} 1.4459 + 1.4460 +/* 1.4461 + * Get the trust attributes from a certificate 1.4462 + */ 1.4463 +SECStatus 1.4464 +nsslowcert_GetCertTrust(NSSLOWCERTCertificate *cert, NSSLOWCERTCertTrust *trust) 1.4465 +{ 1.4466 + SECStatus rv; 1.4467 + 1.4468 + nsslowcert_LockCertTrust(cert); 1.4469 + 1.4470 + if ( cert->trust == NULL ) { 1.4471 + rv = SECFailure; 1.4472 + } else { 1.4473 + *trust = *cert->trust; 1.4474 + rv = SECSuccess; 1.4475 + } 1.4476 + 1.4477 + nsslowcert_UnlockCertTrust(cert); 1.4478 + return(rv); 1.4479 +} 1.4480 + 1.4481 +/* 1.4482 + * Change the trust attributes of a certificate and make them permanent 1.4483 + * in the database. 1.4484 + */ 1.4485 +SECStatus 1.4486 +nsslowcert_ChangeCertTrust(NSSLOWCERTCertDBHandle *handle, 1.4487 + NSSLOWCERTCertificate *cert, NSSLOWCERTCertTrust *trust) 1.4488 +{ 1.4489 + certDBEntryCert *entry; 1.4490 + int rv; 1.4491 + SECStatus ret; 1.4492 + 1.4493 + nsslowcert_LockDB(handle); 1.4494 + nsslowcert_LockCertTrust(cert); 1.4495 + /* only set the trust on permanent certs */ 1.4496 + if ( cert->trust == NULL ) { 1.4497 + ret = SECFailure; 1.4498 + goto done; 1.4499 + } 1.4500 + 1.4501 + *cert->trust = *trust; 1.4502 + if ( cert->dbEntry == NULL ) { 1.4503 + ret = SECSuccess; /* not in permanent database */ 1.4504 + goto done; 1.4505 + } 1.4506 + 1.4507 + entry = cert->dbEntry; 1.4508 + entry->trust = *trust; 1.4509 + 1.4510 + rv = WriteDBCertEntry(handle, entry); 1.4511 + if ( rv ) { 1.4512 + ret = SECFailure; 1.4513 + goto done; 1.4514 + } 1.4515 + 1.4516 + ret = SECSuccess; 1.4517 + 1.4518 +done: 1.4519 + nsslowcert_UnlockCertTrust(cert); 1.4520 + nsslowcert_UnlockDB(handle); 1.4521 + return(ret); 1.4522 +} 1.4523 + 1.4524 + 1.4525 +static SECStatus 1.4526 +nsslowcert_UpdatePermCert(NSSLOWCERTCertDBHandle *dbhandle, 1.4527 + NSSLOWCERTCertificate *cert, char *nickname, NSSLOWCERTCertTrust *trust) 1.4528 +{ 1.4529 + char *oldnn; 1.4530 + certDBEntryCert *entry; 1.4531 + PRBool conflict; 1.4532 + SECStatus ret; 1.4533 + 1.4534 + PORT_Assert(!cert->dbEntry); 1.4535 + 1.4536 + /* don't add a conflicting nickname */ 1.4537 + conflict = nsslowcert_CertNicknameConflict(nickname, &cert->derSubject, 1.4538 + dbhandle); 1.4539 + if ( conflict ) { 1.4540 + ret = SECFailure; 1.4541 + goto done; 1.4542 + } 1.4543 + 1.4544 + /* save old nickname so that we can delete it */ 1.4545 + oldnn = cert->nickname; 1.4546 + 1.4547 + entry = AddCertToPermDB(dbhandle, cert, nickname, trust); 1.4548 + 1.4549 + if ( entry == NULL ) { 1.4550 + ret = SECFailure; 1.4551 + goto done; 1.4552 + } 1.4553 + 1.4554 + pkcs11_freeNickname(oldnn,cert->nicknameSpace); 1.4555 + 1.4556 + cert->nickname = (entry->nickname) ? pkcs11_copyNickname(entry->nickname, 1.4557 + cert->nicknameSpace, sizeof(cert->nicknameSpace)) : NULL; 1.4558 + cert->trust = &entry->trust; 1.4559 + cert->dbEntry = entry; 1.4560 + 1.4561 + ret = SECSuccess; 1.4562 +done: 1.4563 + return(ret); 1.4564 +} 1.4565 + 1.4566 +SECStatus 1.4567 +nsslowcert_AddPermCert(NSSLOWCERTCertDBHandle *dbhandle, 1.4568 + NSSLOWCERTCertificate *cert, char *nickname, NSSLOWCERTCertTrust *trust) 1.4569 +{ 1.4570 + SECStatus ret; 1.4571 + 1.4572 + nsslowcert_LockDB(dbhandle); 1.4573 + 1.4574 + ret = nsslowcert_UpdatePermCert(dbhandle, cert, nickname, trust); 1.4575 + 1.4576 + nsslowcert_UnlockDB(dbhandle); 1.4577 + return(ret); 1.4578 +} 1.4579 + 1.4580 +/* 1.4581 + * Open the certificate database and index databases. Create them if 1.4582 + * they are not there or bad. 1.4583 + */ 1.4584 +SECStatus 1.4585 +nsslowcert_OpenCertDB(NSSLOWCERTCertDBHandle *handle, PRBool readOnly, 1.4586 + const char *appName, const char *prefix, 1.4587 + NSSLOWCERTDBNameFunc namecb, void *cbarg, PRBool openVolatile) 1.4588 +{ 1.4589 + int rv; 1.4590 + 1.4591 + certdb_InitDBLock(handle); 1.4592 + 1.4593 + handle->dbMon = PZ_NewMonitor(nssILockCertDB); 1.4594 + PORT_Assert(handle->dbMon != NULL); 1.4595 + handle->dbVerify = PR_FALSE; 1.4596 + 1.4597 + rv = nsslowcert_OpenPermCertDB(handle, readOnly, appName, prefix, 1.4598 + namecb, cbarg); 1.4599 + if ( rv ) { 1.4600 + goto loser; 1.4601 + } 1.4602 + 1.4603 + return (SECSuccess); 1.4604 + 1.4605 +loser: 1.4606 + if (handle->dbMon) { 1.4607 + PZ_DestroyMonitor(handle->dbMon); 1.4608 + handle->dbMon = NULL; 1.4609 + } 1.4610 + PORT_SetError(SEC_ERROR_BAD_DATABASE); 1.4611 + return(SECFailure); 1.4612 +} 1.4613 + 1.4614 +PRBool 1.4615 +nsslowcert_needDBVerify(NSSLOWCERTCertDBHandle *handle) 1.4616 +{ 1.4617 + if (!handle) return PR_FALSE; 1.4618 + return handle->dbVerify; 1.4619 +} 1.4620 + 1.4621 +void 1.4622 +nsslowcert_setDBVerify(NSSLOWCERTCertDBHandle *handle, PRBool value) 1.4623 +{ 1.4624 + handle->dbVerify = value; 1.4625 +} 1.4626 + 1.4627 + 1.4628 +/* 1.4629 + * Lookup a certificate in the databases. 1.4630 + */ 1.4631 +static NSSLOWCERTCertificate * 1.4632 +FindCertByKey(NSSLOWCERTCertDBHandle *handle, const SECItem *certKey, PRBool lockdb) 1.4633 +{ 1.4634 + NSSLOWCERTCertificate *cert = NULL; 1.4635 + certDBEntryCert *entry; 1.4636 + PRBool locked = PR_FALSE; 1.4637 + 1.4638 + if ( lockdb ) { 1.4639 + locked = PR_TRUE; 1.4640 + nsslowcert_LockDB(handle); 1.4641 + } 1.4642 + 1.4643 + /* find in perm database */ 1.4644 + entry = ReadDBCertEntry(handle, certKey); 1.4645 + 1.4646 + if ( entry == NULL ) { 1.4647 + goto loser; 1.4648 + } 1.4649 + 1.4650 + /* inherit entry */ 1.4651 + cert = DecodeACert(handle, entry); 1.4652 + 1.4653 +loser: 1.4654 + if (cert == NULL) { 1.4655 + if (entry) { 1.4656 + DestroyDBEntry((certDBEntry *)entry); 1.4657 + } 1.4658 + } 1.4659 + 1.4660 + if ( locked ) { 1.4661 + nsslowcert_UnlockDB(handle); 1.4662 + } 1.4663 + 1.4664 + return(cert); 1.4665 +} 1.4666 + 1.4667 +/* 1.4668 + * Lookup a certificate in the databases. 1.4669 + */ 1.4670 +static NSSLOWCERTTrust * 1.4671 +FindTrustByKey(NSSLOWCERTCertDBHandle *handle, const SECItem *certKey, PRBool lockdb) 1.4672 +{ 1.4673 + NSSLOWCERTTrust *trust = NULL; 1.4674 + certDBEntryCert *entry; 1.4675 + PRBool locked = PR_FALSE; 1.4676 + 1.4677 + if ( lockdb ) { 1.4678 + locked = PR_TRUE; 1.4679 + nsslowcert_LockDB(handle); 1.4680 + } 1.4681 + 1.4682 + /* find in perm database */ 1.4683 + entry = ReadDBCertEntry(handle, certKey); 1.4684 + 1.4685 + if ( entry == NULL ) { 1.4686 + goto loser; 1.4687 + } 1.4688 + 1.4689 + if (!nsslowcert_hasTrust(&entry->trust)) { 1.4690 + goto loser; 1.4691 + } 1.4692 + 1.4693 + /* inherit entry */ 1.4694 + trust = DecodeTrustEntry(handle, entry, certKey); 1.4695 + 1.4696 +loser: 1.4697 + if (trust == NULL) { 1.4698 + if (entry) { 1.4699 + DestroyDBEntry((certDBEntry *)entry); 1.4700 + } 1.4701 + } 1.4702 + 1.4703 + if ( locked ) { 1.4704 + nsslowcert_UnlockDB(handle); 1.4705 + } 1.4706 + 1.4707 + return(trust); 1.4708 +} 1.4709 + 1.4710 +/* 1.4711 + * Lookup a certificate in the databases without locking 1.4712 + */ 1.4713 +NSSLOWCERTCertificate * 1.4714 +nsslowcert_FindCertByKey(NSSLOWCERTCertDBHandle *handle, const SECItem *certKey) 1.4715 +{ 1.4716 + return(FindCertByKey(handle, certKey, PR_FALSE)); 1.4717 +} 1.4718 + 1.4719 +/* 1.4720 + * Lookup a trust object in the databases without locking 1.4721 + */ 1.4722 +NSSLOWCERTTrust * 1.4723 +nsslowcert_FindTrustByKey(NSSLOWCERTCertDBHandle *handle, const SECItem *certKey) 1.4724 +{ 1.4725 + return(FindTrustByKey(handle, certKey, PR_FALSE)); 1.4726 +} 1.4727 + 1.4728 +/* 1.4729 + * Generate a key from an issuerAndSerialNumber, and find the 1.4730 + * associated cert in the database. 1.4731 + */ 1.4732 +NSSLOWCERTCertificate * 1.4733 +nsslowcert_FindCertByIssuerAndSN(NSSLOWCERTCertDBHandle *handle, NSSLOWCERTIssuerAndSN *issuerAndSN) 1.4734 +{ 1.4735 + SECItem certKey; 1.4736 + SECItem *sn = &issuerAndSN->serialNumber; 1.4737 + SECItem *issuer = &issuerAndSN->derIssuer; 1.4738 + NSSLOWCERTCertificate *cert; 1.4739 + int data_left = sn->len-1; 1.4740 + int data_len = sn->len; 1.4741 + int index = 0; 1.4742 + 1.4743 + /* automatically detect DER encoded serial numbers and remove the der 1.4744 + * encoding since the database expects unencoded data. 1.4745 + * if it's DER encoded, there must be at least 3 bytes, tag, len, data */ 1.4746 + if ((sn->len >= 3) && (sn->data[0] == 0x2)) { 1.4747 + /* remove the der encoding of the serial number before generating the 1.4748 + * key.. */ 1.4749 + data_left = sn->len-2; 1.4750 + data_len = sn->data[1]; 1.4751 + index = 2; 1.4752 + 1.4753 + /* extended length ? (not very likely for a serial number) */ 1.4754 + if (data_len & 0x80) { 1.4755 + int len_count = data_len & 0x7f; 1.4756 + 1.4757 + data_len = 0; 1.4758 + data_left -= len_count; 1.4759 + if (data_left > 0) { 1.4760 + while (len_count --) { 1.4761 + data_len = (data_len << 8) | sn->data[index++]; 1.4762 + } 1.4763 + } 1.4764 + } 1.4765 + /* XXX leaving any leading zeros on the serial number for backwards 1.4766 + * compatibility 1.4767 + */ 1.4768 + /* not a valid der, must be just an unlucky serial number value */ 1.4769 + if (data_len != data_left) { 1.4770 + data_len = sn->len; 1.4771 + index = 0; 1.4772 + } 1.4773 + } 1.4774 + 1.4775 + certKey.type = 0; 1.4776 + certKey.data = (unsigned char*)PORT_Alloc(sn->len + issuer->len); 1.4777 + certKey.len = data_len + issuer->len; 1.4778 + 1.4779 + if ( certKey.data == NULL ) { 1.4780 + return(0); 1.4781 + } 1.4782 + 1.4783 + /* first try the serial number as hand-decoded above*/ 1.4784 + /* copy the serialNumber */ 1.4785 + PORT_Memcpy(certKey.data, &sn->data[index], data_len); 1.4786 + 1.4787 + /* copy the issuer */ 1.4788 + PORT_Memcpy( &certKey.data[data_len],issuer->data,issuer->len); 1.4789 + 1.4790 + cert = nsslowcert_FindCertByKey(handle, &certKey); 1.4791 + if (cert) { 1.4792 + PORT_Free(certKey.data); 1.4793 + return (cert); 1.4794 + } 1.4795 + 1.4796 + /* didn't find it, try by der encoded serial number */ 1.4797 + /* copy the serialNumber */ 1.4798 + PORT_Memcpy(certKey.data, sn->data, sn->len); 1.4799 + 1.4800 + /* copy the issuer */ 1.4801 + PORT_Memcpy( &certKey.data[sn->len], issuer->data, issuer->len); 1.4802 + certKey.len = sn->len + issuer->len; 1.4803 + 1.4804 + cert = nsslowcert_FindCertByKey(handle, &certKey); 1.4805 + 1.4806 + PORT_Free(certKey.data); 1.4807 + 1.4808 + return(cert); 1.4809 +} 1.4810 + 1.4811 +/* 1.4812 + * Generate a key from an issuerAndSerialNumber, and find the 1.4813 + * associated cert in the database. 1.4814 + */ 1.4815 +NSSLOWCERTTrust * 1.4816 +nsslowcert_FindTrustByIssuerAndSN(NSSLOWCERTCertDBHandle *handle, 1.4817 + NSSLOWCERTIssuerAndSN *issuerAndSN) 1.4818 +{ 1.4819 + SECItem certKey; 1.4820 + SECItem *sn = &issuerAndSN->serialNumber; 1.4821 + SECItem *issuer = &issuerAndSN->derIssuer; 1.4822 + NSSLOWCERTTrust *trust; 1.4823 + unsigned char keyBuf[512]; 1.4824 + int data_left = sn->len-1; 1.4825 + int data_len = sn->len; 1.4826 + int index = 0; 1.4827 + int len; 1.4828 + 1.4829 + /* automatically detect DER encoded serial numbers and remove the der 1.4830 + * encoding since the database expects unencoded data. 1.4831 + * if it's DER encoded, there must be at least 3 bytes, tag, len, data */ 1.4832 + if ((sn->len >= 3) && (sn->data[0] == 0x2)) { 1.4833 + /* remove the der encoding of the serial number before generating the 1.4834 + * key.. */ 1.4835 + data_left = sn->len-2; 1.4836 + data_len = sn->data[1]; 1.4837 + index = 2; 1.4838 + 1.4839 + /* extended length ? (not very likely for a serial number) */ 1.4840 + if (data_len & 0x80) { 1.4841 + int len_count = data_len & 0x7f; 1.4842 + 1.4843 + data_len = 0; 1.4844 + data_left -= len_count; 1.4845 + if (data_left > 0) { 1.4846 + while (len_count --) { 1.4847 + data_len = (data_len << 8) | sn->data[index++]; 1.4848 + } 1.4849 + } 1.4850 + } 1.4851 + /* XXX leaving any leading zeros on the serial number for backwards 1.4852 + * compatibility 1.4853 + */ 1.4854 + /* not a valid der, must be just an unlucky serial number value */ 1.4855 + if (data_len != data_left) { 1.4856 + data_len = sn->len; 1.4857 + index = 0; 1.4858 + } 1.4859 + } 1.4860 + 1.4861 + certKey.type = 0; 1.4862 + certKey.len = data_len + issuer->len; 1.4863 + len = sn->len + issuer->len; 1.4864 + if (len > sizeof (keyBuf)) { 1.4865 + certKey.data = (unsigned char*)PORT_Alloc(len); 1.4866 + } else { 1.4867 + certKey.data = keyBuf; 1.4868 + } 1.4869 + 1.4870 + if ( certKey.data == NULL ) { 1.4871 + return(0); 1.4872 + } 1.4873 + 1.4874 + /* first try the serial number as hand-decoded above*/ 1.4875 + /* copy the serialNumber */ 1.4876 + PORT_Memcpy(certKey.data, &sn->data[index], data_len); 1.4877 + 1.4878 + /* copy the issuer */ 1.4879 + PORT_Memcpy( &certKey.data[data_len],issuer->data,issuer->len); 1.4880 + 1.4881 + trust = nsslowcert_FindTrustByKey(handle, &certKey); 1.4882 + if (trust) { 1.4883 + pkcs11_freeStaticData(certKey.data, keyBuf); 1.4884 + return (trust); 1.4885 + } 1.4886 + 1.4887 + if (index == 0) { 1.4888 + pkcs11_freeStaticData(certKey.data, keyBuf); 1.4889 + return NULL; 1.4890 + } 1.4891 + 1.4892 + /* didn't find it, try by der encoded serial number */ 1.4893 + /* copy the serialNumber */ 1.4894 + PORT_Memcpy(certKey.data, sn->data, sn->len); 1.4895 + 1.4896 + /* copy the issuer */ 1.4897 + PORT_Memcpy( &certKey.data[sn->len], issuer->data, issuer->len); 1.4898 + certKey.len = sn->len + issuer->len; 1.4899 + 1.4900 + trust = nsslowcert_FindTrustByKey(handle, &certKey); 1.4901 + 1.4902 + pkcs11_freeStaticData(certKey.data, keyBuf); 1.4903 + 1.4904 + return(trust); 1.4905 +} 1.4906 + 1.4907 +/* 1.4908 + * look for the given DER certificate in the database 1.4909 + */ 1.4910 +NSSLOWCERTCertificate * 1.4911 +nsslowcert_FindCertByDERCert(NSSLOWCERTCertDBHandle *handle, SECItem *derCert) 1.4912 +{ 1.4913 + PLArenaPool *arena; 1.4914 + SECItem certKey; 1.4915 + SECStatus rv; 1.4916 + NSSLOWCERTCertificate *cert = NULL; 1.4917 + 1.4918 + /* create a scratch arena */ 1.4919 + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.4920 + if ( arena == NULL ) { 1.4921 + return(NULL); 1.4922 + } 1.4923 + 1.4924 + /* extract the database key from the cert */ 1.4925 + rv = nsslowcert_KeyFromDERCert(arena, derCert, &certKey); 1.4926 + if ( rv != SECSuccess ) { 1.4927 + goto loser; 1.4928 + } 1.4929 + 1.4930 + /* find the certificate */ 1.4931 + cert = nsslowcert_FindCertByKey(handle, &certKey); 1.4932 + 1.4933 +loser: 1.4934 + PORT_FreeArena(arena, PR_FALSE); 1.4935 + return(cert); 1.4936 +} 1.4937 + 1.4938 +static void 1.4939 +DestroyCertificate(NSSLOWCERTCertificate *cert, PRBool lockdb) 1.4940 +{ 1.4941 + int refCount; 1.4942 + NSSLOWCERTCertDBHandle *handle; 1.4943 + 1.4944 + if ( cert ) { 1.4945 + 1.4946 + handle = cert->dbhandle; 1.4947 + 1.4948 + /* 1.4949 + * handle may be NULL, for example if the cert was created with 1.4950 + * nsslowcert_DecodeDERCertificate. 1.4951 + */ 1.4952 + if ( lockdb && handle ) { 1.4953 + nsslowcert_LockDB(handle); 1.4954 + } 1.4955 + 1.4956 + nsslowcert_LockCertRefCount(cert); 1.4957 + PORT_Assert(cert->referenceCount > 0); 1.4958 + refCount = --cert->referenceCount; 1.4959 + nsslowcert_UnlockCertRefCount(cert); 1.4960 + 1.4961 + if ( refCount == 0 ) { 1.4962 + certDBEntryCert *entry = cert->dbEntry; 1.4963 + 1.4964 + if ( entry ) { 1.4965 + DestroyDBEntry((certDBEntry *)entry); 1.4966 + } 1.4967 + 1.4968 + pkcs11_freeNickname(cert->nickname,cert->nicknameSpace); 1.4969 + pkcs11_freeNickname(cert->emailAddr,cert->emailAddrSpace); 1.4970 + pkcs11_freeStaticData(cert->certKey.data,cert->certKeySpace); 1.4971 + cert->certKey.data = NULL; 1.4972 + cert->nickname = NULL; 1.4973 + 1.4974 + /* zero cert before freeing. Any stale references to this cert 1.4975 + * after this point will probably cause an exception. */ 1.4976 + PORT_Memset(cert, 0, sizeof *cert); 1.4977 + 1.4978 + /* use reflock to protect the free list */ 1.4979 + nsslowcert_LockFreeList(); 1.4980 + if (certListCount > MAX_CERT_LIST_COUNT) { 1.4981 + PORT_Free(cert); 1.4982 + } else { 1.4983 + certListCount++; 1.4984 + cert->next = certListHead; 1.4985 + certListHead = cert; 1.4986 + } 1.4987 + nsslowcert_UnlockFreeList(); 1.4988 + cert = NULL; 1.4989 + } 1.4990 + if ( lockdb && handle ) { 1.4991 + nsslowcert_UnlockDB(handle); 1.4992 + } 1.4993 + } 1.4994 + 1.4995 + return; 1.4996 +} 1.4997 + 1.4998 +NSSLOWCERTCertificate * 1.4999 +nsslowcert_CreateCert(void) 1.5000 +{ 1.5001 + NSSLOWCERTCertificate *cert; 1.5002 + nsslowcert_LockFreeList(); 1.5003 + cert = certListHead; 1.5004 + if (cert) { 1.5005 + certListHead = cert->next; 1.5006 + certListCount--; 1.5007 + } 1.5008 + PORT_Assert(certListCount >= 0); 1.5009 + nsslowcert_UnlockFreeList(); 1.5010 + if (cert) { 1.5011 + return cert; 1.5012 + } 1.5013 + return PORT_ZNew(NSSLOWCERTCertificate); 1.5014 +} 1.5015 + 1.5016 +static void 1.5017 +DestroyCertFreeList(void) 1.5018 +{ 1.5019 + NSSLOWCERTCertificate *cert; 1.5020 + 1.5021 + nsslowcert_LockFreeList(); 1.5022 + while (NULL != (cert = certListHead)) { 1.5023 + certListCount--; 1.5024 + certListHead = cert->next; 1.5025 + PORT_Free(cert); 1.5026 + } 1.5027 + PORT_Assert(!certListCount); 1.5028 + certListCount = 0; 1.5029 + nsslowcert_UnlockFreeList(); 1.5030 +} 1.5031 + 1.5032 +void 1.5033 +nsslowcert_DestroyTrust(NSSLOWCERTTrust *trust) 1.5034 +{ 1.5035 + certDBEntryCert *entry = trust->dbEntry; 1.5036 + 1.5037 + if ( entry ) { 1.5038 + DestroyDBEntry((certDBEntry *)entry); 1.5039 + } 1.5040 + pkcs11_freeStaticData(trust->dbKey.data,trust->dbKeySpace); 1.5041 + PORT_Memset(trust, 0, sizeof(*trust)); 1.5042 + 1.5043 + nsslowcert_LockFreeList(); 1.5044 + if (trustListCount > MAX_TRUST_LIST_COUNT) { 1.5045 + PORT_Free(trust); 1.5046 + } else { 1.5047 + trustListCount++; 1.5048 + trust->next = trustListHead; 1.5049 + trustListHead = trust; 1.5050 + } 1.5051 + nsslowcert_UnlockFreeList(); 1.5052 + 1.5053 + return; 1.5054 +} 1.5055 + 1.5056 +void 1.5057 +nsslowcert_DestroyCertificate(NSSLOWCERTCertificate *cert) 1.5058 +{ 1.5059 + DestroyCertificate(cert, PR_TRUE); 1.5060 + return; 1.5061 +} 1.5062 + 1.5063 +static void 1.5064 +nsslowcert_DestroyCertificateNoLocking(NSSLOWCERTCertificate *cert) 1.5065 +{ 1.5066 + DestroyCertificate(cert, PR_FALSE); 1.5067 + return; 1.5068 +} 1.5069 + 1.5070 +/* 1.5071 + * Lookup a CRL in the databases. We mirror the same fast caching data base 1.5072 + * caching stuff used by certificates....? 1.5073 + */ 1.5074 +certDBEntryRevocation * 1.5075 +nsslowcert_FindCrlByKey(NSSLOWCERTCertDBHandle *handle, 1.5076 + SECItem *crlKey, PRBool isKRL) 1.5077 +{ 1.5078 + SECItem keyitem; 1.5079 + DBT key; 1.5080 + SECStatus rv; 1.5081 + PLArenaPool *arena = NULL; 1.5082 + certDBEntryRevocation *entry = NULL; 1.5083 + certDBEntryType crlType = isKRL ? certDBEntryTypeKeyRevocation 1.5084 + : certDBEntryTypeRevocation; 1.5085 + 1.5086 + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.5087 + if ( arena == NULL ) { 1.5088 + goto loser; 1.5089 + } 1.5090 + 1.5091 + rv = EncodeDBGenericKey(crlKey, arena, &keyitem, crlType); 1.5092 + if ( rv != SECSuccess ) { 1.5093 + goto loser; 1.5094 + } 1.5095 + 1.5096 + key.data = keyitem.data; 1.5097 + key.size = keyitem.len; 1.5098 + 1.5099 + /* find in perm database */ 1.5100 + entry = ReadDBCrlEntry(handle, crlKey, crlType); 1.5101 + 1.5102 + if ( entry == NULL ) { 1.5103 + goto loser; 1.5104 + } 1.5105 + 1.5106 +loser: 1.5107 + if ( arena ) { 1.5108 + PORT_FreeArena(arena, PR_FALSE); 1.5109 + } 1.5110 + 1.5111 + return entry; 1.5112 +} 1.5113 + 1.5114 +/* 1.5115 + * replace the existing URL in the data base with a new one 1.5116 + */ 1.5117 +static SECStatus 1.5118 +nsslowcert_UpdateCrl(NSSLOWCERTCertDBHandle *handle, SECItem *derCrl, 1.5119 + SECItem *crlKey, char *url, PRBool isKRL) 1.5120 +{ 1.5121 + SECStatus rv = SECFailure; 1.5122 + certDBEntryRevocation *entry = NULL; 1.5123 + certDBEntryType crlType = isKRL ? certDBEntryTypeKeyRevocation 1.5124 + : certDBEntryTypeRevocation; 1.5125 + DeleteDBCrlEntry(handle, crlKey, crlType); 1.5126 + 1.5127 + /* Write the new entry into the data base */ 1.5128 + entry = NewDBCrlEntry(derCrl, url, crlType, 0); 1.5129 + if (entry == NULL) goto done; 1.5130 + 1.5131 + rv = WriteDBCrlEntry(handle, entry, crlKey); 1.5132 + if (rv != SECSuccess) goto done; 1.5133 + 1.5134 +done: 1.5135 + if (entry) { 1.5136 + DestroyDBEntry((certDBEntry *)entry); 1.5137 + } 1.5138 + return rv; 1.5139 +} 1.5140 + 1.5141 +SECStatus 1.5142 +nsslowcert_AddCrl(NSSLOWCERTCertDBHandle *handle, SECItem *derCrl, 1.5143 + SECItem *crlKey, char *url, PRBool isKRL) 1.5144 +{ 1.5145 + SECStatus rv; 1.5146 + 1.5147 + rv = nsslowcert_UpdateCrl(handle, derCrl, crlKey, url, isKRL); 1.5148 + 1.5149 + return rv; 1.5150 +} 1.5151 + 1.5152 +SECStatus 1.5153 +nsslowcert_DeletePermCRL(NSSLOWCERTCertDBHandle *handle, const SECItem *derName, 1.5154 + PRBool isKRL) 1.5155 +{ 1.5156 + SECStatus rv; 1.5157 + certDBEntryType crlType = isKRL ? certDBEntryTypeKeyRevocation 1.5158 + : certDBEntryTypeRevocation; 1.5159 + 1.5160 + rv = DeleteDBCrlEntry(handle, derName, crlType); 1.5161 + if (rv != SECSuccess) goto done; 1.5162 + 1.5163 +done: 1.5164 + return rv; 1.5165 +} 1.5166 + 1.5167 + 1.5168 +PRBool 1.5169 +nsslowcert_hasTrust(NSSLOWCERTCertTrust *trust) 1.5170 +{ 1.5171 + if (trust == NULL) { 1.5172 + return PR_FALSE; 1.5173 + } 1.5174 + return !((trust->sslFlags & CERTDB_TRUSTED_UNKNOWN) && 1.5175 + (trust->emailFlags & CERTDB_TRUSTED_UNKNOWN) && 1.5176 + (trust->objectSigningFlags & CERTDB_TRUSTED_UNKNOWN)); 1.5177 +} 1.5178 + 1.5179 +/* 1.5180 + * This function has the logic that decides if another person's cert and 1.5181 + * email profile from an S/MIME message should be saved. It can deal with 1.5182 + * the case when there is no profile. 1.5183 + */ 1.5184 +static SECStatus 1.5185 +nsslowcert_UpdateSMimeProfile(NSSLOWCERTCertDBHandle *dbhandle, 1.5186 + char *emailAddr, SECItem *derSubject, SECItem *emailProfile, 1.5187 + SECItem *profileTime) 1.5188 +{ 1.5189 + certDBEntrySMime *entry = NULL; 1.5190 + SECStatus rv = SECFailure;; 1.5191 + 1.5192 + 1.5193 + /* find our existing entry */ 1.5194 + entry = nsslowcert_ReadDBSMimeEntry(dbhandle, emailAddr); 1.5195 + 1.5196 + if ( entry ) { 1.5197 + /* keep our old db entry consistant for old applications. */ 1.5198 + if (!SECITEM_ItemsAreEqual(derSubject, &entry->subjectName)) { 1.5199 + nsslowcert_UpdateSubjectEmailAddr(dbhandle, &entry->subjectName, 1.5200 + emailAddr, nsslowcert_remove); 1.5201 + } 1.5202 + DestroyDBEntry((certDBEntry *)entry); 1.5203 + entry = NULL; 1.5204 + } 1.5205 + 1.5206 + /* now save the entry */ 1.5207 + entry = NewDBSMimeEntry(emailAddr, derSubject, emailProfile, 1.5208 + profileTime, 0); 1.5209 + if ( entry == NULL ) { 1.5210 + rv = SECFailure; 1.5211 + goto loser; 1.5212 + } 1.5213 + 1.5214 + nsslowcert_LockDB(dbhandle); 1.5215 + 1.5216 + rv = DeleteDBSMimeEntry(dbhandle, emailAddr); 1.5217 + /* if delete fails, try to write new entry anyway... */ 1.5218 + 1.5219 + /* link subject entry back here */ 1.5220 + rv = nsslowcert_UpdateSubjectEmailAddr(dbhandle, derSubject, emailAddr, 1.5221 + nsslowcert_add); 1.5222 + if ( rv != SECSuccess ) { 1.5223 + nsslowcert_UnlockDB(dbhandle); 1.5224 + goto loser; 1.5225 + } 1.5226 + 1.5227 + rv = WriteDBSMimeEntry(dbhandle, entry); 1.5228 + if ( rv != SECSuccess ) { 1.5229 + nsslowcert_UnlockDB(dbhandle); 1.5230 + goto loser; 1.5231 + } 1.5232 + 1.5233 + nsslowcert_UnlockDB(dbhandle); 1.5234 + 1.5235 + rv = SECSuccess; 1.5236 + 1.5237 +loser: 1.5238 + if ( entry ) { 1.5239 + DestroyDBEntry((certDBEntry *)entry); 1.5240 + } 1.5241 + return(rv); 1.5242 +} 1.5243 + 1.5244 +SECStatus 1.5245 +nsslowcert_SaveSMimeProfile(NSSLOWCERTCertDBHandle *dbhandle, char *emailAddr, 1.5246 + SECItem *derSubject, SECItem *emailProfile, SECItem *profileTime) 1.5247 +{ 1.5248 + SECStatus rv = SECFailure;; 1.5249 + 1.5250 + 1.5251 + rv = nsslowcert_UpdateSMimeProfile(dbhandle, emailAddr, 1.5252 + derSubject, emailProfile, profileTime); 1.5253 + 1.5254 + return(rv); 1.5255 +} 1.5256 + 1.5257 +void 1.5258 +nsslowcert_DestroyFreeLists(void) 1.5259 +{ 1.5260 + if (freeListLock == NULL) { 1.5261 + return; 1.5262 + } 1.5263 + DestroyCertEntryFreeList(); 1.5264 + DestroyTrustFreeList(); 1.5265 + DestroyCertFreeList(); 1.5266 + SKIP_AFTER_FORK(PZ_DestroyLock(freeListLock)); 1.5267 + freeListLock = NULL; 1.5268 +} 1.5269 + 1.5270 +void 1.5271 +nsslowcert_DestroyGlobalLocks(void) 1.5272 +{ 1.5273 + if (dbLock) { 1.5274 + SKIP_AFTER_FORK(PZ_DestroyLock(dbLock)); 1.5275 + dbLock = NULL; 1.5276 + } 1.5277 + if (certRefCountLock) { 1.5278 + SKIP_AFTER_FORK(PZ_DestroyLock(certRefCountLock)); 1.5279 + certRefCountLock = NULL; 1.5280 + } 1.5281 + if (certTrustLock) { 1.5282 + SKIP_AFTER_FORK(PZ_DestroyLock(certTrustLock)); 1.5283 + certTrustLock = NULL; 1.5284 + } 1.5285 +} 1.5286 + 1.5287 +certDBEntry * 1.5288 +nsslowcert_DecodeAnyDBEntry(SECItem *dbData, const SECItem *dbKey, 1.5289 + certDBEntryType entryType, void *pdata) 1.5290 +{ 1.5291 + PLArenaPool *arena = NULL; 1.5292 + certDBEntry *entry; 1.5293 + SECStatus rv; 1.5294 + SECItem dbEntry; 1.5295 + 1.5296 + 1.5297 + if ((dbData->len < SEC_DB_ENTRY_HEADER_LEN) || (dbKey->len == 0)) { 1.5298 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.5299 + goto loser; 1.5300 + } 1.5301 + dbEntry.data = &dbData->data[SEC_DB_ENTRY_HEADER_LEN]; 1.5302 + dbEntry.len = dbData->len - SEC_DB_ENTRY_HEADER_LEN; 1.5303 + 1.5304 + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.5305 + if (arena == NULL) { 1.5306 + goto loser; 1.5307 + } 1.5308 + entry = PORT_ArenaZNew(arena, certDBEntry); 1.5309 + if (!entry) 1.5310 + goto loser; 1.5311 + 1.5312 + entry->common.version = (unsigned int)dbData->data[0]; 1.5313 + entry->common.flags = (unsigned int)dbData->data[2]; 1.5314 + entry->common.type = entryType; 1.5315 + entry->common.arena = arena; 1.5316 + 1.5317 + switch (entryType) { 1.5318 + case certDBEntryTypeContentVersion: /* This type appears to be unused */ 1.5319 + case certDBEntryTypeVersion: /* This type has only the common hdr */ 1.5320 + rv = SECSuccess; 1.5321 + break; 1.5322 + 1.5323 + case certDBEntryTypeSubject: 1.5324 + rv = DecodeDBSubjectEntry(&entry->subject, &dbEntry, dbKey); 1.5325 + break; 1.5326 + 1.5327 + case certDBEntryTypeNickname: 1.5328 + rv = DecodeDBNicknameEntry(&entry->nickname, &dbEntry, 1.5329 + (char *)dbKey->data); 1.5330 + break; 1.5331 + 1.5332 + /* smime profiles need entries created after the certs have 1.5333 + * been imported, loop over them in a second run */ 1.5334 + case certDBEntryTypeSMimeProfile: 1.5335 + rv = DecodeDBSMimeEntry(&entry->smime, &dbEntry, (char *)dbKey->data); 1.5336 + break; 1.5337 + 1.5338 + case certDBEntryTypeCert: 1.5339 + rv = DecodeDBCertEntry(&entry->cert, &dbEntry); 1.5340 + break; 1.5341 + 1.5342 + case certDBEntryTypeKeyRevocation: 1.5343 + case certDBEntryTypeRevocation: 1.5344 + rv = DecodeDBCrlEntry(&entry->revocation, &dbEntry); 1.5345 + break; 1.5346 + 1.5347 + default: 1.5348 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.5349 + rv = SECFailure; 1.5350 + } 1.5351 + 1.5352 + if (rv == SECSuccess) 1.5353 + return entry; 1.5354 + 1.5355 +loser: 1.5356 + if (arena) 1.5357 + PORT_FreeArena(arena, PR_FALSE); 1.5358 + return NULL; 1.5359 +} 1.5360 +