Bug Summary

File:s/lib/softoken/legacydb/pcertdb.c
Warning:line 5208, column 5
Value stored to 'rv' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name pcertdb.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/var/lib/jenkins/workspace/nss-scan-build/nss/lib/softoken/legacydb -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/var/lib/jenkins/workspace/nss-scan-build/nss/lib/softoken/legacydb -resource-dir /usr/lib/llvm-18/lib/clang/18 -D HAVE_STRERROR -D LINUX -D linux -D XP_UNIX -D XP_UNIX -D SHLIB_SUFFIX="so" -D SHLIB_PREFIX="lib" -D LG_LIB_NAME="libnssdbm3.so" -D DEBUG -U NDEBUG -D _DEFAULT_SOURCE -D _BSD_SOURCE -D _POSIX_SOURCE -D SDB_MEASURE_USE_TEMP_DIR -D _REENTRANT -D DEBUG -U NDEBUG -D _DEFAULT_SOURCE -D _BSD_SOURCE -D _POSIX_SOURCE -D SDB_MEASURE_USE_TEMP_DIR -D _REENTRANT -D NSS_DISABLE_SSE3 -D NSS_NO_INIT_SUPPORT -D USE_UTIL_DIRECTLY -D NO_NSPR_10_SUPPORT -D SSL_DISABLE_DEPRECATED_CIPHER_SUITE_NAMES -I ../../../../dist/Linux4.19_x86_64_gcc_glibc_PTH_64_DBG.OBJ/include -I ../../../../dist/public/nss -I ../../../../dist/private/nss -I ../../../../dist/public/dbm -internal-isystem /usr/lib/llvm-18/lib/clang/18/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -std=c99 -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2024-05-18-082241-28900-1 -x c pcertdb.c
1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5/*
6 * Permanent Certificate database handling code
7 */
8#include "lowkeyti.h"
9#include "pcert.h"
10#include "mcom_db.h"
11#include "pcert.h"
12#include "secitem.h"
13#include "secder.h"
14
15#include "secerr.h"
16#include "lgdb.h"
17
18/* forward declaration */
19NSSLOWCERTCertificate *
20nsslowcert_FindCertByDERCertNoLocking(NSSLOWCERTCertDBHandle *handle, SECItem *derCert);
21static SECStatus
22nsslowcert_UpdateSMimeProfile(NSSLOWCERTCertDBHandle *dbhandle,
23 char *emailAddr, SECItem *derSubject, SECItem *emailProfile,
24 SECItem *profileTime);
25static SECStatus
26nsslowcert_UpdatePermCert(NSSLOWCERTCertDBHandle *dbhandle,
27 NSSLOWCERTCertificate *cert, char *nickname, NSSLOWCERTCertTrust *trust);
28static SECStatus
29nsslowcert_UpdateCrl(NSSLOWCERTCertDBHandle *handle, SECItem *derCrl,
30 SECItem *crlKey, char *url, PRBool isKRL);
31
32static NSSLOWCERTCertificate *certListHead = NULL((void*)0);
33static NSSLOWCERTTrust *trustListHead = NULL((void*)0);
34static certDBEntryCert *entryListHead = NULL((void*)0);
35static int certListCount = 0;
36static int trustListCount = 0;
37static int entryListCount = 0;
38#define MAX_CERT_LIST_COUNT10 10
39#define MAX_TRUST_LIST_COUNT10 10
40#define MAX_ENTRY_LIST_COUNT10 10
41
42/*
43 * the following functions are wrappers for the db library that implement
44 * a global lock to make the database thread safe.
45 */
46static PZLockPRLock *dbLock = NULL((void*)0);
47static PZLockPRLock *certRefCountLock = NULL((void*)0);
48static PZLockPRLock *certTrustLock = NULL((void*)0);
49static PZLockPRLock *freeListLock = NULL((void*)0);
50
51void
52certdb_InitDBLock(NSSLOWCERTCertDBHandle *handle)
53{
54 if (dbLock == NULL((void*)0)) {
55 dbLock = PZ_NewLock(nssILockCertDB)PR_NewLock();
56 PORT_Assert(dbLock != NULL)((dbLock != ((void*)0))?((void)0):PR_Assert("dbLock != NULL",
"pcertdb.c",56))
;
57 }
58}
59
60SECStatus
61nsslowcert_InitLocks(void)
62{
63 if (freeListLock == NULL((void*)0)) {
64 freeListLock = PZ_NewLock(nssILockRefLock)PR_NewLock();
65 if (freeListLock == NULL((void*)0)) {
66 return SECFailure;
67 }
68 }
69 if (certRefCountLock == NULL((void*)0)) {
70 certRefCountLock = PZ_NewLock(nssILockRefLock)PR_NewLock();
71 if (certRefCountLock == NULL((void*)0)) {
72 return SECFailure;
73 }
74 }
75 if (certTrustLock == NULL((void*)0)) {
76 certTrustLock = PZ_NewLock(nssILockCertDB)PR_NewLock();
77 if (certTrustLock == NULL((void*)0)) {
78 return SECFailure;
79 }
80 }
81
82 return SECSuccess;
83}
84
85/*
86 * Acquire the global lock on the cert database.
87 * This lock is currently used for the following operations:
88 * adding or deleting a cert to either the temp or perm databases
89 * converting a temp to perm or perm to temp
90 * changing (maybe just adding!?) the trust of a cert
91 * chaning the DB status checking Configuration
92 */
93static void
94nsslowcert_LockDB(NSSLOWCERTCertDBHandle *handle)
95{
96 PZ_EnterMonitor(handle->dbMon)PR_EnterMonitor((handle->dbMon));
97 return;
98}
99
100/*
101 * Free the global cert database lock.
102 */
103static void
104nsslowcert_UnlockDB(NSSLOWCERTCertDBHandle *handle)
105{
106#ifdef DEBUG1
107 PRStatus prstat = PZ_ExitMonitor(handle->dbMon)PR_ExitMonitor((handle->dbMon));
108 PORT_Assert(prstat == PR_SUCCESS)((prstat == PR_SUCCESS)?((void)0):PR_Assert("prstat == PR_SUCCESS"
,"pcertdb.c",108))
;
109#else
110 PZ_ExitMonitor(handle->dbMon)PR_ExitMonitor((handle->dbMon));
111#endif
112}
113
114/*
115 * Acquire the cert reference count lock
116 * There is currently one global lock for all certs, but I'm putting a cert
117 * arg here so that it will be easy to make it per-cert in the future if
118 * that turns out to be necessary.
119 */
120static void
121nsslowcert_LockCertRefCount(NSSLOWCERTCertificate *cert)
122{
123 PORT_Assert(certRefCountLock != NULL)((certRefCountLock != ((void*)0))?((void)0):PR_Assert("certRefCountLock != NULL"
,"pcertdb.c",123))
;
124
125 PZ_Lock(certRefCountLock)PR_Lock((certRefCountLock));
126 return;
127}
128
129/*
130 * Free the cert reference count lock
131 */
132static void
133nsslowcert_UnlockCertRefCount(NSSLOWCERTCertificate *cert)
134{
135 PORT_Assert(certRefCountLock != NULL)((certRefCountLock != ((void*)0))?((void)0):PR_Assert("certRefCountLock != NULL"
,"pcertdb.c",135))
;
136
137#ifdef DEBUG1
138 {
139 PRStatus prstat = PZ_Unlock(certRefCountLock)PR_Unlock((certRefCountLock));
140 PORT_Assert(prstat == PR_SUCCESS)((prstat == PR_SUCCESS)?((void)0):PR_Assert("prstat == PR_SUCCESS"
,"pcertdb.c",140))
;
141 }
142#else
143 PZ_Unlock(certRefCountLock)PR_Unlock((certRefCountLock));
144#endif
145}
146
147/*
148 * Acquire the cert trust lock
149 * There is currently one global lock for all certs, but I'm putting a cert
150 * arg here so that it will be easy to make it per-cert in the future if
151 * that turns out to be necessary.
152 */
153static void
154nsslowcert_LockCertTrust(NSSLOWCERTCertificate *cert)
155{
156 PORT_Assert(certTrustLock != NULL)((certTrustLock != ((void*)0))?((void)0):PR_Assert("certTrustLock != NULL"
,"pcertdb.c",156))
;
157
158 PZ_Lock(certTrustLock)PR_Lock((certTrustLock));
159 return;
160}
161
162/*
163 * Free the cert trust lock
164 */
165static void
166nsslowcert_UnlockCertTrust(NSSLOWCERTCertificate *cert)
167{
168 PORT_Assert(certTrustLock != NULL)((certTrustLock != ((void*)0))?((void)0):PR_Assert("certTrustLock != NULL"
,"pcertdb.c",168))
;
169
170#ifdef DEBUG1
171 {
172 PRStatus prstat = PZ_Unlock(certTrustLock)PR_Unlock((certTrustLock));
173 PORT_Assert(prstat == PR_SUCCESS)((prstat == PR_SUCCESS)?((void)0):PR_Assert("prstat == PR_SUCCESS"
,"pcertdb.c",173))
;
174 }
175#else
176 PZ_Unlock(certTrustLock)PR_Unlock((certTrustLock));
177#endif
178}
179
180/*
181 * Acquire the cert reference count lock
182 * There is currently one global lock for all certs, but I'm putting a cert
183 * arg here so that it will be easy to make it per-cert in the future if
184 * that turns out to be necessary.
185 */
186static void
187nsslowcert_LockFreeList(void)
188{
189 PORT_Assert(freeListLock != NULL)((freeListLock != ((void*)0))?((void)0):PR_Assert("freeListLock != NULL"
,"pcertdb.c",189))
;
190
191 SKIP_AFTER_FORK(PZ_Lock(freeListLock))if (!lg_parentForkedAfterC_Initialize) PR_Lock((freeListLock)
)
;
192 return;
193}
194
195/*
196 * Free the cert reference count lock
197 */
198static void
199nsslowcert_UnlockFreeList(void)
200{
201 PORT_Assert(freeListLock != NULL)((freeListLock != ((void*)0))?((void)0):PR_Assert("freeListLock != NULL"
,"pcertdb.c",201))
;
202
203#ifdef DEBUG1
204 {
205 PRStatus prstat = PR_SUCCESS;
206 SKIP_AFTER_FORK(prstat = PZ_Unlock(freeListLock))if (!lg_parentForkedAfterC_Initialize) prstat = PR_Unlock((freeListLock
))
;
207 PORT_Assert(prstat == PR_SUCCESS)((prstat == PR_SUCCESS)?((void)0):PR_Assert("prstat == PR_SUCCESS"
,"pcertdb.c",207))
;
208 }
209#else
210 SKIP_AFTER_FORK(PZ_Unlock(freeListLock))if (!lg_parentForkedAfterC_Initialize) PR_Unlock((freeListLock
))
;
211#endif
212}
213
214NSSLOWCERTCertificate *
215nsslowcert_DupCertificate(NSSLOWCERTCertificate *c)
216{
217 if (c) {
218 nsslowcert_LockCertRefCount(c);
219 ++c->referenceCount;
220 nsslowcert_UnlockCertRefCount(c);
221 }
222 return c;
223}
224
225static int
226certdb_Get(DB *db, DBT *key, DBT *data, unsigned int flags)
227{
228 int ret;
229
230 PORT_Assert(dbLock != NULL)((dbLock != ((void*)0))?((void)0):PR_Assert("dbLock != NULL",
"pcertdb.c",230))
;
231 PZ_Lock(dbLock)PR_Lock((dbLock));
232
233 ret = (*db->get)(db, key, data, flags);
234
235 (void)PZ_Unlock(dbLock)PR_Unlock((dbLock));
236
237 return (ret);
238}
239
240static int
241certdb_Put(DB *db, DBT *key, DBT *data, unsigned int flags)
242{
243 int ret = 0;
244
245 PORT_Assert(dbLock != NULL)((dbLock != ((void*)0))?((void)0):PR_Assert("dbLock != NULL",
"pcertdb.c",245))
;
246 PZ_Lock(dbLock)PR_Lock((dbLock));
247
248 ret = (*db->put)(db, key, data, flags);
249
250 (void)PZ_Unlock(dbLock)PR_Unlock((dbLock));
251
252 return (ret);
253}
254
255static int
256certdb_Sync(DB *db, unsigned int flags)
257{
258 int ret;
259
260 PORT_Assert(dbLock != NULL)((dbLock != ((void*)0))?((void)0):PR_Assert("dbLock != NULL",
"pcertdb.c",260))
;
261 PZ_Lock(dbLock)PR_Lock((dbLock));
262
263 ret = (*db->sync)(db, flags);
264
265 (void)PZ_Unlock(dbLock)PR_Unlock((dbLock));
266
267 return (ret);
268}
269
270#define DB_NOT_FOUND-30991 -30991 /* from DBM 3.2 */
271static int
272certdb_Del(DB *db, DBT *key, unsigned int flags)
273{
274 int ret;
275
276 PORT_Assert(dbLock != NULL)((dbLock != ((void*)0))?((void)0):PR_Assert("dbLock != NULL",
"pcertdb.c",276))
;
277 PZ_Lock(dbLock)PR_Lock((dbLock));
278
279 ret = (*db->del)(db, key, flags);
280
281 (void)PZ_Unlock(dbLock)PR_Unlock((dbLock));
282
283 /* don't fail if the record is already deleted */
284 if (ret == DB_NOT_FOUND-30991) {
285 ret = 0;
286 }
287
288 return (ret);
289}
290
291static int
292certdb_Seq(DB *db, DBT *key, DBT *data, unsigned int flags)
293{
294 int ret;
295
296 PORT_Assert(dbLock != NULL)((dbLock != ((void*)0))?((void)0):PR_Assert("dbLock != NULL",
"pcertdb.c",296))
;
297 PZ_Lock(dbLock)PR_Lock((dbLock));
298
299 ret = (*db->seq)(db, key, data, flags);
300
301 (void)PZ_Unlock(dbLock)PR_Unlock((dbLock));
302
303 return (ret);
304}
305
306static void
307certdb_Close(DB *db)
308{
309 PORT_Assert(dbLock != NULL)((dbLock != ((void*)0))?((void)0):PR_Assert("dbLock != NULL",
"pcertdb.c",309))
;
310 SKIP_AFTER_FORK(PZ_Lock(dbLock))if (!lg_parentForkedAfterC_Initialize) PR_Lock((dbLock));
311
312 (*db->close)(db);
313
314 SKIP_AFTER_FORK(PZ_Unlock(dbLock))if (!lg_parentForkedAfterC_Initialize) PR_Unlock((dbLock));
315
316 return;
317}
318
319void
320pkcs11_freeNickname(char *nickname, char *space)
321{
322 if (nickname && nickname != space) {
323 PORT_FreePORT_Free_Util(nickname);
324 }
325}
326
327char *
328pkcs11_copyNickname(char *nickname, char *space, int spaceLen)
329{
330 int len;
331 char *copy = NULL((void*)0);
332
333 len = PORT_Strlen(nickname)strlen(nickname) + 1;
334 if (len <= spaceLen) {
335 copy = space;
336 PORT_Memcpymemcpy(copy, nickname, len);
337 } else {
338 copy = PORT_StrdupPORT_Strdup_Util(nickname);
339 }
340
341 return copy;
342}
343
344void
345pkcs11_freeStaticData(unsigned char *data, unsigned char *space)
346{
347 if (data && data != space) {
348 PORT_FreePORT_Free_Util(data);
349 }
350}
351
352unsigned char *
353pkcs11_allocStaticData(int len, unsigned char *space, int spaceLen)
354{
355 unsigned char *data = NULL((void*)0);
356
357 if (len <= spaceLen) {
358 data = space;
359 } else {
360 data = (unsigned char *)PORT_AllocPORT_Alloc_Util(len);
361 }
362
363 return data;
364}
365
366unsigned char *
367pkcs11_copyStaticData(unsigned char *data, int len,
368 unsigned char *space, int spaceLen)
369{
370 unsigned char *copy = pkcs11_allocStaticData(len, space, spaceLen);
371 if (copy) {
372 PORT_Memcpymemcpy(copy, data, len);
373 }
374
375 return copy;
376}
377
378/*
379 * destroy a database entry
380 */
381static void
382DestroyDBEntry(certDBEntry *entry)
383{
384 PLArenaPool *arena = entry->common.arena;
385
386 /* must be one of our certDBEntry from the free list */
387 if (arena == NULL((void*)0)) {
388 certDBEntryCert *certEntry;
389 if (entry->common.type != certDBEntryTypeCert) {
390 return;
391 }
392 certEntry = (certDBEntryCert *)entry;
393
394 pkcs11_freeStaticData(certEntry->derCert.data, certEntry->derCertSpace);
395 pkcs11_freeNickname(certEntry->nickname, certEntry->nicknameSpace);
396
397 nsslowcert_LockFreeList();
398 if (entryListCount > MAX_ENTRY_LIST_COUNT10) {
399 PORT_FreePORT_Free_Util(certEntry);
400 } else {
401 entryListCount++;
402 PORT_Memsetmemset(certEntry, 0, sizeof(*certEntry));
403 certEntry->next = entryListHead;
404 entryListHead = certEntry;
405 }
406 nsslowcert_UnlockFreeList();
407 return;
408 }
409
410 /* Zero out the entry struct, so that any further attempts to use it
411 * will cause an exception (e.g. null pointer reference). */
412 PORT_Memsetmemset(&entry->common, 0, sizeof entry->common);
413 PORT_FreeArenaPORT_FreeArena_Util(arena, PR_FALSE0);
414
415 return;
416}
417
418/* forward references */
419static void nsslowcert_DestroyCertificateNoLocking(NSSLOWCERTCertificate *cert);
420
421static SECStatus
422DeleteDBEntry(NSSLOWCERTCertDBHandle *handle, certDBEntryType type, SECItem *dbkey)
423{
424 DBT key;
425 int ret;
426
427 /* init the database key */
428 key.data = dbkey->data;
429 key.size = dbkey->len;
430
431 dbkey->data[0] = (unsigned char)type;
432
433 /* delete entry from database */
434 ret = certdb_Del(handle->permCertDB, &key, 0);
435 if (ret != 0) {
436 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_BAD_DATABASE);
437 goto loser;
438 }
439
440 ret = certdb_Sync(handle->permCertDB, 0);
441 if (ret) {
442 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_BAD_DATABASE);
443 goto loser;
444 }
445
446 return (SECSuccess);
447
448loser:
449 return (SECFailure);
450}
451
452static SECStatus
453ReadDBEntry(NSSLOWCERTCertDBHandle *handle, certDBEntryCommon *entry,
454 SECItem *dbkey, SECItem *dbentry, PLArenaPool *arena)
455{
456 DBT data, key;
457 int ret;
458 unsigned char *buf;
459
460 /* init the database key */
461 key.data = dbkey->data;
462 key.size = dbkey->len;
463
464 dbkey->data[0] = (unsigned char)entry->type;
465
466 /* read entry from database */
467 ret = certdb_Get(handle->permCertDB, &key, &data, 0);
468 if (ret != 0) {
469 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_BAD_DATABASE);
470 goto loser;
471 }
472
473 /* validate the entry */
474 if (data.size < SEC_DB_ENTRY_HEADER_LEN3) {
475 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_BAD_DATABASE);
476 goto loser;
477 }
478 buf = (unsigned char *)data.data;
479 /* version 7 has the same schema, we may be using a v7 db if we openned
480 * the databases readonly. */
481 if (!((buf[0] == (unsigned char)CERT_DB_FILE_VERSION8) ||
482 (buf[0] == (unsigned char)CERT_DB_V7_FILE_VERSION7))) {
483 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_BAD_DATABASE);
484 goto loser;
485 }
486 if (buf[1] != (unsigned char)entry->type) {
487 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_BAD_DATABASE);
488 goto loser;
489 }
490
491 /* copy out header information */
492 entry->version = (unsigned int)buf[0];
493 entry->type = (certDBEntryType)buf[1];
494 entry->flags = (unsigned int)buf[2];
495
496 /* format body of entry for return to caller */
497 dbentry->len = data.size - SEC_DB_ENTRY_HEADER_LEN3;
498 if (dbentry->len) {
499 if (arena) {
500 dbentry->data = (unsigned char *)
501 PORT_ArenaAllocPORT_ArenaAlloc_Util(arena, dbentry->len);
502 if (dbentry->data == NULL((void*)0)) {
503 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
504 goto loser;
505 }
506
507 PORT_Memcpymemcpy(dbentry->data, &buf[SEC_DB_ENTRY_HEADER_LEN3],
508 dbentry->len);
509 } else {
510 dbentry->data = &buf[SEC_DB_ENTRY_HEADER_LEN3];
511 }
512 } else {
513 dbentry->data = NULL((void*)0);
514 }
515
516 return (SECSuccess);
517
518loser:
519 return (SECFailure);
520}
521
522/**
523 ** Implement low level database access
524 **/
525static SECStatus
526WriteDBEntry(NSSLOWCERTCertDBHandle *handle, certDBEntryCommon *entry,
527 SECItem *dbkey, SECItem *dbentry)
528{
529 int ret;
530 DBT data, key;
531 unsigned char *buf;
532
533 data.data = dbentry->data;
534 data.size = dbentry->len;
535
536 buf = (unsigned char *)data.data;
537
538 buf[0] = (unsigned char)entry->version;
539 buf[1] = (unsigned char)entry->type;
540 buf[2] = (unsigned char)entry->flags;
541
542 key.data = dbkey->data;
543 key.size = dbkey->len;
544
545 dbkey->data[0] = (unsigned char)entry->type;
546
547 /* put the record into the database now */
548 ret = certdb_Put(handle->permCertDB, &key, &data, 0);
549
550 if (ret != 0) {
551 goto loser;
552 }
553
554 ret = certdb_Sync(handle->permCertDB, 0);
555
556 if (ret) {
557 goto loser;
558 }
559
560 return (SECSuccess);
561
562loser:
563 return (SECFailure);
564}
565
566/*
567 * encode a database cert record
568 */
569static SECStatus
570EncodeDBCertEntry(certDBEntryCert *entry, PLArenaPool *arena, SECItem *dbitem)
571{
572 unsigned int nnlen;
573 unsigned char *buf;
574 char *nn;
575 char zbuf = 0;
576
577 if (entry->nickname) {
578 nn = entry->nickname;
579 } else {
580 nn = &zbuf;
581 }
582 nnlen = PORT_Strlen(nn)strlen(nn) + 1;
583
584 /* allocate space for encoded database record, including space
585 * for low level header
586 */
587 dbitem->len = entry->derCert.len + nnlen + DB_CERT_ENTRY_HEADER_LEN10 +
588 SEC_DB_ENTRY_HEADER_LEN3;
589
590 dbitem->data = (unsigned char *)PORT_ArenaAllocPORT_ArenaAlloc_Util(arena, dbitem->len);
591 if (dbitem->data == NULL((void*)0)) {
592 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
593 goto loser;
594 }
595
596 /* fill in database record */
597 buf = &dbitem->data[SEC_DB_ENTRY_HEADER_LEN3];
598
599 buf[0] = (PRUint8)(entry->trust.sslFlags >> 8);
600 buf[1] = (PRUint8)(entry->trust.sslFlags);
601 buf[2] = (PRUint8)(entry->trust.emailFlags >> 8);
602 buf[3] = (PRUint8)(entry->trust.emailFlags);
603 buf[4] = (PRUint8)(entry->trust.objectSigningFlags >> 8);
604 buf[5] = (PRUint8)(entry->trust.objectSigningFlags);
605 buf[6] = (PRUint8)(entry->derCert.len >> 8);
606 buf[7] = (PRUint8)(entry->derCert.len);
607 buf[8] = (PRUint8)(nnlen >> 8);
608 buf[9] = (PRUint8)(nnlen);
609
610 PORT_Memcpymemcpy(&buf[DB_CERT_ENTRY_HEADER_LEN10], entry->derCert.data,
611 entry->derCert.len);
612
613 PORT_Memcpymemcpy(&buf[DB_CERT_ENTRY_HEADER_LEN10 + entry->derCert.len],
614 nn, nnlen);
615
616 return (SECSuccess);
617
618loser:
619 return (SECFailure);
620}
621
622/*
623 * encode a database key for a cert record
624 */
625static SECStatus
626EncodeDBCertKey(const SECItem *certKey, PLArenaPool *arena, SECItem *dbkey)
627{
628 unsigned int len = certKey->len + SEC_DB_KEY_HEADER_LEN1;
629 if (len > NSS_MAX_LEGACY_DB_KEY_SIZE(60 * 1024))
630 goto loser;
631 if (arena) {
632 dbkey->data = (unsigned char *)PORT_ArenaAllocPORT_ArenaAlloc_Util(arena, len);
633 } else {
634 if (dbkey->len < len) {
635 dbkey->data = (unsigned char *)PORT_AllocPORT_Alloc_Util(len);
636 }
637 }
638 dbkey->len = len;
639 if (dbkey->data == NULL((void*)0)) {
640 goto loser;
641 }
642 PORT_Memcpymemcpy(&dbkey->data[SEC_DB_KEY_HEADER_LEN1],
643 certKey->data, certKey->len);
644 dbkey->data[0] = certDBEntryTypeCert;
645
646 return (SECSuccess);
647loser:
648 return (SECFailure);
649}
650
651static SECStatus
652EncodeDBGenericKey(const SECItem *certKey, PLArenaPool *arena, SECItem *dbkey,
653 certDBEntryType entryType)
654{
655 /*
656 * we only allow _one_ KRL key!
657 */
658 if (entryType == certDBEntryTypeKeyRevocation) {
659 dbkey->len = SEC_DB_KEY_HEADER_LEN1;
660 dbkey->data = (unsigned char *)PORT_ArenaAllocPORT_ArenaAlloc_Util(arena, dbkey->len);
661 if (dbkey->data == NULL((void*)0)) {
662 goto loser;
663 }
664 dbkey->data[0] = (unsigned char)entryType;
665 return (SECSuccess);
666 }
667
668 dbkey->len = certKey->len + SEC_DB_KEY_HEADER_LEN1;
669 if (dbkey->len > NSS_MAX_LEGACY_DB_KEY_SIZE(60 * 1024))
670 goto loser;
671 dbkey->data = (unsigned char *)PORT_ArenaAllocPORT_ArenaAlloc_Util(arena, dbkey->len);
672 if (dbkey->data == NULL((void*)0)) {
673 goto loser;
674 }
675 PORT_Memcpymemcpy(&dbkey->data[SEC_DB_KEY_HEADER_LEN1],
676 certKey->data, certKey->len);
677 dbkey->data[0] = (unsigned char)entryType;
678
679 return (SECSuccess);
680loser:
681 return (SECFailure);
682}
683
684static SECStatus
685DecodeDBCertEntry(certDBEntryCert *entry, SECItem *dbentry)
686{
687 unsigned int nnlen;
688 unsigned int headerlen;
689 int lenoff;
690
691 /* allow updates of old versions of the database */
692 switch (entry->common.version) {
693 case 5:
694 headerlen = DB_CERT_V5_ENTRY_HEADER_LEN7;
695 lenoff = 3;
696 break;
697 case 6:
698 /* should not get here */
699 PORT_Assert(0)((0)?((void)0):PR_Assert("0","pcertdb.c",699));
700 headerlen = DB_CERT_V6_ENTRY_HEADER_LEN7;
701 lenoff = 3;
702 break;
703 case 7:
704 case 8:
705 headerlen = DB_CERT_ENTRY_HEADER_LEN10;
706 lenoff = 6;
707 break;
708 default:
709 /* better not get here */
710 PORT_Assert(0)((0)?((void)0):PR_Assert("0","pcertdb.c",710));
711 headerlen = DB_CERT_V5_ENTRY_HEADER_LEN7;
712 lenoff = 3;
713 break;
714 }
715
716 /* is record long enough for header? */
717 if (dbentry->len < headerlen) {
718 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_BAD_DATABASE);
719 goto loser;
720 }
721
722 /* is database entry correct length? */
723 entry->derCert.len = ((dbentry->data[lenoff] << 8) |
724 dbentry->data[lenoff + 1]);
725 nnlen = ((dbentry->data[lenoff + 2] << 8) | dbentry->data[lenoff + 3]);
726 lenoff = dbentry->len - (entry->derCert.len + nnlen + headerlen);
727 if (lenoff) {
728 if (lenoff < 0 || (lenoff & 0xffff) != 0) {
729 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_BAD_DATABASE);
730 goto loser;
731 }
732 /* The cert size exceeded 64KB. Reconstruct the correct length. */
733 entry->derCert.len += lenoff;
734 }
735
736 /* Is data long enough? */
737 if (dbentry->len < headerlen + entry->derCert.len) {
738 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_BAD_DATABASE);
739 goto loser;
740 }
741
742 /* copy the dercert */
743 entry->derCert.data = pkcs11_copyStaticData(&dbentry->data[headerlen],
744 entry->derCert.len, entry->derCertSpace, sizeof(entry->derCertSpace));
745 if (entry->derCert.data == NULL((void*)0)) {
746 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
747 goto loser;
748 }
749
750 /* copy the nickname */
751 if (nnlen > 1) {
752 /* Is data long enough? */
753 if (dbentry->len < headerlen + entry->derCert.len + nnlen) {
754 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_BAD_DATABASE);
755 goto loser;
756 }
757 entry->nickname = (char *)pkcs11_copyStaticData(
758 &dbentry->data[headerlen + entry->derCert.len], nnlen,
759 (unsigned char *)entry->nicknameSpace,
760 sizeof(entry->nicknameSpace));
761 if (entry->nickname == NULL((void*)0)) {
762 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
763 goto loser;
764 }
765 } else {
766 entry->nickname = NULL((void*)0);
767 }
768
769 if (entry->common.version < 7) {
770 /* allow updates of v5 db */
771 entry->trust.sslFlags = dbentry->data[0];
772 entry->trust.emailFlags = dbentry->data[1];
773 entry->trust.objectSigningFlags = dbentry->data[2];
774 } else {
775 entry->trust.sslFlags = (dbentry->data[0] << 8) | dbentry->data[1];
776 entry->trust.emailFlags = (dbentry->data[2] << 8) | dbentry->data[3];
777 entry->trust.objectSigningFlags =
778 (dbentry->data[4] << 8) | dbentry->data[5];
779 }
780
781 return (SECSuccess);
782loser:
783 return (SECFailure);
784}
785
786/*
787 * Create a new certDBEntryCert from existing data
788 */
789static certDBEntryCert *
790NewDBCertEntry(SECItem *derCert, char *nickname,
791 NSSLOWCERTCertTrust *trust, int flags)
792{
793 certDBEntryCert *entry;
794 PLArenaPool *arena = NULL((void*)0);
795 int nnlen;
796
797 arena = PORT_NewArenaPORT_NewArena_Util(DER_DEFAULT_CHUNKSIZE(2048));
798
799 if (!arena) {
800 goto loser;
801 }
802
803 entry = PORT_ArenaZNew(arena, certDBEntryCert)(certDBEntryCert *)PORT_ArenaZAlloc_Util(arena, sizeof(certDBEntryCert
))
;
804 if (entry == NULL((void*)0)) {
805 goto loser;
806 }
807
808 /* fill in the dbCert */
809 entry->common.arena = arena;
810 entry->common.type = certDBEntryTypeCert;
811 entry->common.version = CERT_DB_FILE_VERSION8;
812 entry->common.flags = flags;
813
814 if (trust) {
815 entry->trust = *trust;
816 }
817
818 entry->derCert.data = (unsigned char *)PORT_ArenaAllocPORT_ArenaAlloc_Util(arena, derCert->len);
819 if (!entry->derCert.data) {
820 goto loser;
821 }
822 entry->derCert.len = derCert->len;
823 PORT_Memcpymemcpy(entry->derCert.data, derCert->data, derCert->len);
824
825 nnlen = (nickname ? strlen(nickname) + 1 : 0);
826
827 if (nnlen) {
828 entry->nickname = (char *)PORT_ArenaAllocPORT_ArenaAlloc_Util(arena, nnlen);
829 if (!entry->nickname) {
830 goto loser;
831 }
832 PORT_Memcpymemcpy(entry->nickname, nickname, nnlen);
833
834 } else {
835 entry->nickname = 0;
836 }
837
838 return (entry);
839
840loser:
841
842 /* allocation error, free arena and return */
843 if (arena) {
844 PORT_FreeArenaPORT_FreeArena_Util(arena, PR_FALSE0);
845 }
846
847 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
848 return (0);
849}
850
851/*
852 * Decode a version 4 DBCert from the byte stream database format
853 * and construct a current database entry struct
854 */
855static certDBEntryCert *
856DecodeV4DBCertEntry(unsigned char *buf, int len)
857{
858 certDBEntryCert *entry;
859 int certlen;
860 int nnlen;
861 PLArenaPool *arena;
862
863 /* make sure length is at least long enough for the header */
864 if (len < DBCERT_V4_HEADER_LEN7) {
865 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_BAD_DATABASE);
866 return (0);
867 }
868
869 /* get other lengths */
870 certlen = buf[3] << 8 | buf[4];
871 nnlen = buf[5] << 8 | buf[6];
872
873 /* make sure DB entry is the right size */
874 if ((certlen + nnlen + DBCERT_V4_HEADER_LEN7) != len) {
875 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_BAD_DATABASE);
876 return (0);
877 }
878
879 /* allocate arena */
880 arena = PORT_NewArenaPORT_NewArena_Util(DER_DEFAULT_CHUNKSIZE(2048));
881
882 if (!arena) {
883 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
884 return (0);
885 }
886
887 /* allocate structure and members */
888 entry = (certDBEntryCert *)PORT_ArenaAllocPORT_ArenaAlloc_Util(arena, sizeof(certDBEntryCert));
889
890 if (!entry) {
891 goto loser;
892 }
893
894 entry->common.arena = arena;
895 entry->common.version = CERT_DB_FILE_VERSION8;
896 entry->common.type = certDBEntryTypeCert;
897 entry->common.flags = 0;
898 entry->trust.sslFlags = buf[0];
899 entry->trust.emailFlags = buf[1];
900 entry->trust.objectSigningFlags = buf[2];
901
902 entry->derCert.data = (unsigned char *)PORT_ArenaAllocPORT_ArenaAlloc_Util(arena, certlen);
903 if (!entry->derCert.data) {
904 goto loser;
905 }
906 entry->derCert.len = certlen;
907 PORT_Memcpymemcpy(entry->derCert.data, &buf[DBCERT_V4_HEADER_LEN7], certlen);
908
909 if (nnlen) {
910 entry->nickname = (char *)PORT_ArenaAllocPORT_ArenaAlloc_Util(arena, nnlen);
911 if (!entry->nickname) {
912 goto loser;
913 }
914 PORT_Memcpymemcpy(entry->nickname, &buf[DBCERT_V4_HEADER_LEN7 + certlen], nnlen);
915
916 if (PORT_Strcmpstrcmp(entry->nickname, "Server-Cert") == 0) {
917 entry->trust.sslFlags |= CERTDB_USER(1u << 6);
918 }
919 } else {
920 entry->nickname = 0;
921 }
922
923 return (entry);
924
925loser:
926 PORT_FreeArenaPORT_FreeArena_Util(arena, PR_FALSE0);
927 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
928 return (0);
929}
930
931/*
932 * Encode a Certificate database entry into byte stream suitable for
933 * the database
934 */
935static SECStatus
936WriteDBCertEntry(NSSLOWCERTCertDBHandle *handle, certDBEntryCert *entry)
937{
938 SECItem dbitem, dbkey;
939 PLArenaPool *tmparena = NULL((void*)0);
940 SECItem tmpitem;
941 SECStatus rv;
942
943 tmparena = PORT_NewArenaPORT_NewArena_Util(DER_DEFAULT_CHUNKSIZE(2048));
944 if (tmparena == NULL((void*)0)) {
945 goto loser;
946 }
947
948 rv = EncodeDBCertEntry(entry, tmparena, &dbitem);
949 if (rv != SECSuccess) {
950 goto loser;
951 }
952
953 /* get the database key and format it */
954 rv = nsslowcert_KeyFromDERCert(tmparena, &entry->derCert, &tmpitem);
955 if (rv == SECFailure) {
956 goto loser;
957 }
958
959 rv = EncodeDBCertKey(&tmpitem, tmparena, &dbkey);
960 if (rv == SECFailure) {
961 goto loser;
962 }
963
964 /* now write it to the database */
965 rv = WriteDBEntry(handle, &entry->common, &dbkey, &dbitem);
966 if (rv != SECSuccess) {
967 goto loser;
968 }
969
970 PORT_FreeArenaPORT_FreeArena_Util(tmparena, PR_FALSE0);
971 return (SECSuccess);
972
973loser:
974 if (tmparena) {
975 PORT_FreeArenaPORT_FreeArena_Util(tmparena, PR_FALSE0);
976 }
977 return (SECFailure);
978}
979
980/*
981 * delete a certificate entry
982 */
983static SECStatus
984DeleteDBCertEntry(NSSLOWCERTCertDBHandle *handle, SECItem *certKey)
985{
986 SECItem dbkey;
987 SECStatus rv;
988
989 dbkey.data = NULL((void*)0);
990 dbkey.len = 0;
991
992 rv = EncodeDBCertKey(certKey, NULL((void*)0), &dbkey);
993 if (rv != SECSuccess) {
994 goto loser;
995 }
996
997 rv = DeleteDBEntry(handle, certDBEntryTypeCert, &dbkey);
998 if (rv == SECFailure) {
999 goto loser;
1000 }
1001
1002 PORT_FreePORT_Free_Util(dbkey.data);
1003
1004 return (SECSuccess);
1005
1006loser:
1007 if (dbkey.data) {
1008 PORT_FreePORT_Free_Util(dbkey.data);
1009 }
1010 return (SECFailure);
1011}
1012
1013static certDBEntryCert *
1014CreateCertEntry(void)
1015{
1016 certDBEntryCert *entry;
1017
1018 nsslowcert_LockFreeList();
1019 entry = entryListHead;
1020 if (entry) {
1021 entryListCount--;
1022 entryListHead = entry->next;
1023 }
1024 PORT_Assert(entryListCount >= 0)((entryListCount >= 0)?((void)0):PR_Assert("entryListCount >= 0"
,"pcertdb.c",1024))
;
1025 nsslowcert_UnlockFreeList();
1026 if (entry) {
1027 return entry;
1028 }
1029
1030 return PORT_ZNew(certDBEntryCert)(certDBEntryCert *)PORT_ZAlloc_Util(sizeof(certDBEntryCert));
1031}
1032
1033static void
1034DestroyCertEntryFreeList(void)
1035{
1036 certDBEntryCert *entry;
1037
1038 nsslowcert_LockFreeList();
1039 while (NULL((void*)0) != (entry = entryListHead)) {
1040 entryListCount--;
1041 entryListHead = entry->next;
1042 PORT_FreePORT_Free_Util(entry);
1043 }
1044 PORT_Assert(!entryListCount)((!entryListCount)?((void)0):PR_Assert("!entryListCount","pcertdb.c"
,1044))
;
1045 entryListCount = 0;
1046 nsslowcert_UnlockFreeList();
1047}
1048
1049/*
1050 * Read a certificate entry
1051 */
1052static certDBEntryCert *
1053ReadDBCertEntry(NSSLOWCERTCertDBHandle *handle, const SECItem *certKey)
1054{
1055 certDBEntryCert *entry;
1056 SECItem dbkey;
1057 SECItem dbentry;
1058 SECStatus rv;
1059 unsigned char buf[512];
1060
1061 dbkey.data = buf;
1062 dbkey.len = sizeof(buf);
1063
1064 entry = CreateCertEntry();
1065 if (entry == NULL((void*)0)) {
1066 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
1067 goto loser;
1068 }
1069 entry->common.arena = NULL((void*)0);
1070 entry->common.type = certDBEntryTypeCert;
1071
1072 rv = EncodeDBCertKey(certKey, NULL((void*)0), &dbkey);
1073 if (rv != SECSuccess) {
1074 goto loser;
1075 }
1076
1077 rv = ReadDBEntry(handle, &entry->common, &dbkey, &dbentry, NULL((void*)0));
1078 if (rv == SECFailure) {
1079 goto loser;
1080 }
1081
1082 rv = DecodeDBCertEntry(entry, &dbentry);
1083 if (rv != SECSuccess) {
1084 goto loser;
1085 }
1086
1087 pkcs11_freeStaticData(dbkey.data, buf);
1088 dbkey.data = NULL((void*)0);
1089 return (entry);
1090
1091loser:
1092 pkcs11_freeStaticData(dbkey.data, buf);
1093 dbkey.data = NULL((void*)0);
1094 if (entry) {
1095 DestroyDBEntry((certDBEntry *)entry);
1096 }
1097
1098 return (NULL((void*)0));
1099}
1100
1101/*
1102 * encode a database cert record
1103 */
1104static SECStatus
1105EncodeDBCrlEntry(certDBEntryRevocation *entry, PLArenaPool *arena, SECItem *dbitem)
1106{
1107 unsigned int nnlen = 0;
1108 unsigned char *buf;
1109
1110 if (entry->url) {
1111 nnlen = PORT_Strlen(entry->url)strlen(entry->url) + 1;
1112 }
1113
1114 /* allocate space for encoded database record, including space
1115 * for low level header
1116 */
1117 dbitem->len = entry->derCrl.len + nnlen + SEC_DB_ENTRY_HEADER_LEN3 + DB_CRL_ENTRY_HEADER_LEN4;
1118
1119 dbitem->data = (unsigned char *)PORT_ArenaAllocPORT_ArenaAlloc_Util(arena, dbitem->len);
1120 if (dbitem->data == NULL((void*)0)) {
1121 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
1122 goto loser;
1123 }
1124
1125 /* fill in database record */
1126 buf = &dbitem->data[SEC_DB_ENTRY_HEADER_LEN3];
1127
1128 buf[0] = (PRUint8)(entry->derCrl.len >> 8);
1129 buf[1] = (PRUint8)(entry->derCrl.len);
1130 buf[2] = (PRUint8)(nnlen >> 8);
1131 buf[3] = (PRUint8)(nnlen);
1132
1133 PORT_Memcpymemcpy(&buf[DB_CRL_ENTRY_HEADER_LEN4], entry->derCrl.data,
1134 entry->derCrl.len);
1135
1136 if (nnlen != 0) {
1137 PORT_Memcpymemcpy(&buf[DB_CRL_ENTRY_HEADER_LEN4 + entry->derCrl.len],
1138 entry->url, nnlen);
1139 }
1140
1141 return (SECSuccess);
1142
1143loser:
1144 return (SECFailure);
1145}
1146
1147static SECStatus
1148DecodeDBCrlEntry(certDBEntryRevocation *entry, SECItem *dbentry)
1149{
1150 unsigned int urlLen;
1151 int lenDiff;
1152
1153 /* is record long enough for header? */
1154 if (dbentry->len < DB_CRL_ENTRY_HEADER_LEN4) {
1155 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_BAD_DATABASE);
1156 goto loser;
1157 }
1158
1159 /* is database entry correct length? */
1160 entry->derCrl.len = ((dbentry->data[0] << 8) | dbentry->data[1]);
1161 urlLen = ((dbentry->data[2] << 8) | dbentry->data[3]);
1162 lenDiff = dbentry->len -
1163 (entry->derCrl.len + urlLen + DB_CRL_ENTRY_HEADER_LEN4);
1164 if (lenDiff) {
1165 if (lenDiff < 0 || (lenDiff & 0xffff) != 0) {
1166 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_BAD_DATABASE);
1167 goto loser;
1168 }
1169 /* CRL entry is greater than 64 K. Hack to make this continue to work */
1170 entry->derCrl.len += lenDiff;
1171 }
1172
1173 /* copy the der CRL */
1174 entry->derCrl.data = (unsigned char *)PORT_ArenaAllocPORT_ArenaAlloc_Util(entry->common.arena,
1175 entry->derCrl.len);
1176 if (entry->derCrl.data == NULL((void*)0)) {
1177 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
1178 goto loser;
1179 }
1180 PORT_Memcpymemcpy(entry->derCrl.data, &dbentry->data[DB_CRL_ENTRY_HEADER_LEN4],
1181 entry->derCrl.len);
1182
1183 /* copy the url */
1184 entry->url = NULL((void*)0);
1185 if (urlLen != 0) {
1186 entry->url = (char *)PORT_ArenaAllocPORT_ArenaAlloc_Util(entry->common.arena, urlLen);
1187 if (entry->url == NULL((void*)0)) {
1188 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
1189 goto loser;
1190 }
1191 PORT_Memcpymemcpy(entry->url,
1192 &dbentry->data[DB_CRL_ENTRY_HEADER_LEN4 + entry->derCrl.len],
1193 urlLen);
1194 }
1195
1196 return (SECSuccess);
1197loser:
1198 return (SECFailure);
1199}
1200
1201/*
1202 * Create a new certDBEntryRevocation from existing data
1203 */
1204static certDBEntryRevocation *
1205NewDBCrlEntry(SECItem *derCrl, char *url, certDBEntryType crlType, int flags)
1206{
1207 certDBEntryRevocation *entry;
1208 PLArenaPool *arena = NULL((void*)0);
1209 int nnlen;
1210
1211 arena = PORT_NewArenaPORT_NewArena_Util(DER_DEFAULT_CHUNKSIZE(2048));
1212
1213 if (!arena) {
1214 goto loser;
1215 }
1216
1217 entry = PORT_ArenaZNew(arena, certDBEntryRevocation)(certDBEntryRevocation *)PORT_ArenaZAlloc_Util(arena, sizeof(
certDBEntryRevocation))
;
1218 if (entry == NULL((void*)0)) {
1219 goto loser;
1220 }
1221
1222 /* fill in the dbRevolcation */
1223 entry->common.arena = arena;
1224 entry->common.type = crlType;
1225 entry->common.version = CERT_DB_FILE_VERSION8;
1226 entry->common.flags = flags;
1227
1228 entry->derCrl.data = (unsigned char *)PORT_ArenaAllocPORT_ArenaAlloc_Util(arena, derCrl->len);
1229 if (!entry->derCrl.data) {
1230 goto loser;
1231 }
1232
1233 if (url) {
1234 nnlen = PORT_Strlen(url)strlen(url) + 1;
1235 entry->url = (char *)PORT_ArenaAllocPORT_ArenaAlloc_Util(arena, nnlen);
1236 if (!entry->url) {
1237 goto loser;
1238 }
1239 PORT_Memcpymemcpy(entry->url, url, nnlen);
1240 } else {
1241 entry->url = NULL((void*)0);
1242 }
1243
1244 entry->derCrl.len = derCrl->len;
1245 PORT_Memcpymemcpy(entry->derCrl.data, derCrl->data, derCrl->len);
1246
1247 return (entry);
1248
1249loser:
1250
1251 /* allocation error, free arena and return */
1252 if (arena) {
1253 PORT_FreeArenaPORT_FreeArena_Util(arena, PR_FALSE0);
1254 }
1255
1256 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
1257 return (0);
1258}
1259
1260static SECStatus
1261WriteDBCrlEntry(NSSLOWCERTCertDBHandle *handle, certDBEntryRevocation *entry,
1262 SECItem *crlKey)
1263{
1264 SECItem dbkey;
1265 PLArenaPool *tmparena = NULL((void*)0);
1266 SECItem encodedEntry;
1267 SECStatus rv;
1268
1269 tmparena = PORT_NewArenaPORT_NewArena_Util(DER_DEFAULT_CHUNKSIZE(2048));
1270 if (tmparena == NULL((void*)0)) {
1271 goto loser;
1272 }
1273
1274 rv = EncodeDBCrlEntry(entry, tmparena, &encodedEntry);
1275 if (rv == SECFailure) {
1276 goto loser;
1277 }
1278
1279 rv = EncodeDBGenericKey(crlKey, tmparena, &dbkey, entry->common.type);
1280 if (rv == SECFailure) {
1281 goto loser;
1282 }
1283
1284 /* now write it to the database */
1285 rv = WriteDBEntry(handle, &entry->common, &dbkey, &encodedEntry);
1286 if (rv != SECSuccess) {
1287 goto loser;
1288 }
1289
1290 PORT_FreeArenaPORT_FreeArena_Util(tmparena, PR_FALSE0);
1291 return (SECSuccess);
1292
1293loser:
1294 if (tmparena) {
1295 PORT_FreeArenaPORT_FreeArena_Util(tmparena, PR_FALSE0);
1296 }
1297 return (SECFailure);
1298}
1299/*
1300 * delete a crl entry
1301 */
1302static SECStatus
1303DeleteDBCrlEntry(NSSLOWCERTCertDBHandle *handle, const SECItem *crlKey,
1304 certDBEntryType crlType)
1305{
1306 SECItem dbkey;
1307 PLArenaPool *arena = NULL((void*)0);
1308 SECStatus rv;
1309
1310 arena = PORT_NewArenaPORT_NewArena_Util(DER_DEFAULT_CHUNKSIZE(2048));
1311 if (arena == NULL((void*)0)) {
1312 goto loser;
1313 }
1314
1315 rv = EncodeDBGenericKey(crlKey, arena, &dbkey, crlType);
1316 if (rv != SECSuccess) {
1317 goto loser;
1318 }
1319
1320 rv = DeleteDBEntry(handle, crlType, &dbkey);
1321 if (rv == SECFailure) {
1322 goto loser;
1323 }
1324
1325 PORT_FreeArenaPORT_FreeArena_Util(arena, PR_FALSE0);
1326 return (SECSuccess);
1327
1328loser:
1329 if (arena) {
1330 PORT_FreeArenaPORT_FreeArena_Util(arena, PR_FALSE0);
1331 }
1332
1333 return (SECFailure);
1334}
1335
1336/*
1337 * Read a certificate entry
1338 */
1339static certDBEntryRevocation *
1340ReadDBCrlEntry(NSSLOWCERTCertDBHandle *handle, SECItem *certKey,
1341 certDBEntryType crlType)
1342{
1343 PLArenaPool *arena = NULL((void*)0);
1344 PLArenaPool *tmparena = NULL((void*)0);
1345 certDBEntryRevocation *entry;
1346 SECItem dbkey;
1347 SECItem dbentry;
1348 SECStatus rv;
1349
1350 arena = PORT_NewArenaPORT_NewArena_Util(DER_DEFAULT_CHUNKSIZE(2048));
1351 if (arena == NULL((void*)0)) {
1352 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
1353 goto loser;
1354 }
1355
1356 tmparena = PORT_NewArenaPORT_NewArena_Util(DER_DEFAULT_CHUNKSIZE(2048));
1357 if (tmparena == NULL((void*)0)) {
1358 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
1359 goto loser;
1360 }
1361
1362 entry = (certDBEntryRevocation *)
1363 PORT_ArenaAllocPORT_ArenaAlloc_Util(arena, sizeof(certDBEntryRevocation));
1364 if (entry == NULL((void*)0)) {
1365 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
1366 goto loser;
1367 }
1368 entry->common.arena = arena;
1369 entry->common.type = crlType;
1370
1371 rv = EncodeDBGenericKey(certKey, tmparena, &dbkey, crlType);
1372 if (rv != SECSuccess) {
1373 goto loser;
1374 }
1375
1376 rv = ReadDBEntry(handle, &entry->common, &dbkey, &dbentry, NULL((void*)0));
1377 if (rv == SECFailure) {
1378 goto loser;
1379 }
1380
1381 rv = DecodeDBCrlEntry(entry, &dbentry);
1382 if (rv != SECSuccess) {
1383 goto loser;
1384 }
1385
1386 PORT_FreeArenaPORT_FreeArena_Util(tmparena, PR_FALSE0);
1387 return (entry);
1388
1389loser:
1390 if (tmparena) {
1391 PORT_FreeArenaPORT_FreeArena_Util(tmparena, PR_FALSE0);
1392 }
1393 if (arena) {
1394 PORT_FreeArenaPORT_FreeArena_Util(arena, PR_FALSE0);
1395 }
1396
1397 return (NULL((void*)0));
1398}
1399
1400void
1401nsslowcert_DestroyDBEntry(certDBEntry *entry)
1402{
1403 DestroyDBEntry(entry);
1404 return;
1405}
1406
1407/*
1408 * Encode a database nickname record
1409 */
1410static SECStatus
1411EncodeDBNicknameEntry(certDBEntryNickname *entry, PLArenaPool *arena,
1412 SECItem *dbitem)
1413{
1414 unsigned char *buf;
1415
1416 /* allocate space for encoded database record, including space
1417 * for low level header
1418 */
1419 dbitem->len = entry->subjectName.len + DB_NICKNAME_ENTRY_HEADER_LEN2 +
1420 SEC_DB_ENTRY_HEADER_LEN3;
1421 dbitem->data = (unsigned char *)PORT_ArenaAllocPORT_ArenaAlloc_Util(arena, dbitem->len);
1422 if (dbitem->data == NULL((void*)0)) {
1423 goto loser;
1424 }
1425
1426 /* fill in database record */
1427 buf = &dbitem->data[SEC_DB_ENTRY_HEADER_LEN3];
1428 buf[0] = (PRUint8)(entry->subjectName.len >> 8);
1429 buf[1] = (PRUint8)(entry->subjectName.len);
1430 PORT_Memcpymemcpy(&buf[DB_NICKNAME_ENTRY_HEADER_LEN2], entry->subjectName.data,
1431 entry->subjectName.len);
1432
1433 return (SECSuccess);
1434
1435loser:
1436 return (SECFailure);
1437}
1438
1439/*
1440 * Encode a database key for a nickname record
1441 */
1442static SECStatus
1443EncodeDBNicknameKey(char *nickname, PLArenaPool *arena,
1444 SECItem *dbkey)
1445{
1446 unsigned int nnlen;
1447
1448 nnlen = PORT_Strlen(nickname)strlen(nickname) + 1; /* includes null */
1449
1450 /* now get the database key and format it */
1451 dbkey->len = nnlen + SEC_DB_KEY_HEADER_LEN1;
1452 if (dbkey->len > NSS_MAX_LEGACY_DB_KEY_SIZE(60 * 1024))
1453 goto loser;
1454 dbkey->data = (unsigned char *)PORT_ArenaAllocPORT_ArenaAlloc_Util(arena, dbkey->len);
1455 if (dbkey->data == NULL((void*)0)) {
1456 goto loser;
1457 }
1458 PORT_Memcpymemcpy(&dbkey->data[SEC_DB_KEY_HEADER_LEN1], nickname, nnlen);
1459 dbkey->data[0] = certDBEntryTypeNickname;
1460
1461 return (SECSuccess);
1462
1463loser:
1464 return (SECFailure);
1465}
1466
1467static SECStatus
1468DecodeDBNicknameEntry(certDBEntryNickname *entry, SECItem *dbentry,
1469 char *nickname)
1470{
1471 int lenDiff;
1472
1473 /* is record long enough for header? */
1474 if (dbentry->len < DB_NICKNAME_ENTRY_HEADER_LEN2) {
1475 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_BAD_DATABASE);
1476 goto loser;
1477 }
1478
1479 /* is database entry correct length? */
1480 entry->subjectName.len = ((dbentry->data[0] << 8) | dbentry->data[1]);
1481 lenDiff = dbentry->len -
1482 (entry->subjectName.len + DB_NICKNAME_ENTRY_HEADER_LEN2);
1483 if (lenDiff) {
1484 if (lenDiff < 0 || (lenDiff & 0xffff) != 0) {
1485 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_BAD_DATABASE);
1486 goto loser;
1487 }
1488 /* The entry size exceeded 64KB. Reconstruct the correct length. */
1489 entry->subjectName.len += lenDiff;
1490 }
1491
1492 /* copy the certkey */
1493 entry->subjectName.data =
1494 (unsigned char *)PORT_ArenaAllocPORT_ArenaAlloc_Util(entry->common.arena,
1495 entry->subjectName.len);
1496 if (entry->subjectName.data == NULL((void*)0)) {
1497 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
1498 goto loser;
1499 }
1500 PORT_Memcpymemcpy(entry->subjectName.data,
1501 &dbentry->data[DB_NICKNAME_ENTRY_HEADER_LEN2],
1502 entry->subjectName.len);
1503 entry->subjectName.type = siBuffer;
1504
1505 entry->nickname = (char *)PORT_ArenaAllocPORT_ArenaAlloc_Util(entry->common.arena,
1506 PORT_Strlen(nickname)strlen(nickname) + 1);
1507 if (entry->nickname) {
1508 PORT_Strcpystrcpy(entry->nickname, nickname);
1509 }
1510
1511 return (SECSuccess);
1512
1513loser:
1514 return (SECFailure);
1515}
1516
1517/*
1518 * create a new nickname entry
1519 */
1520static certDBEntryNickname *
1521NewDBNicknameEntry(char *nickname, SECItem *subjectName, unsigned int flags)
1522{
1523 PLArenaPool *arena = NULL((void*)0);
1524 certDBEntryNickname *entry;
1525 int nnlen;
1526 SECStatus rv;
1527
1528 arena = PORT_NewArenaPORT_NewArena_Util(DER_DEFAULT_CHUNKSIZE(2048));
1529 if (arena == NULL((void*)0)) {
1530 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
1531 goto loser;
1532 }
1533
1534 entry = (certDBEntryNickname *)PORT_ArenaAllocPORT_ArenaAlloc_Util(arena,
1535 sizeof(certDBEntryNickname));
1536 if (entry == NULL((void*)0)) {
1537 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
1538 goto loser;
1539 }
1540
1541 /* init common fields */
1542 entry->common.arena = arena;
1543 entry->common.type = certDBEntryTypeNickname;
1544 entry->common.version = CERT_DB_FILE_VERSION8;
1545 entry->common.flags = flags;
1546
1547 /* copy the nickname */
1548 nnlen = PORT_Strlen(nickname)strlen(nickname) + 1;
1549
1550 entry->nickname = (char *)PORT_ArenaAllocPORT_ArenaAlloc_Util(arena, nnlen);
1551 if (entry->nickname == NULL((void*)0)) {
1552 goto loser;
1553 }
1554
1555 PORT_Memcpymemcpy(entry->nickname, nickname, nnlen);
1556
1557 rv = SECITEM_CopyItemSECITEM_CopyItem_Util(arena, &entry->subjectName, subjectName);
1558 if (rv != SECSuccess) {
1559 goto loser;
1560 }
1561
1562 return (entry);
1563loser:
1564 if (arena) {
1565 PORT_FreeArenaPORT_FreeArena_Util(arena, PR_FALSE0);
1566 }
1567
1568 return (NULL((void*)0));
1569}
1570
1571/*
1572 * delete a nickname entry
1573 */
1574static SECStatus
1575DeleteDBNicknameEntry(NSSLOWCERTCertDBHandle *handle, char *nickname)
1576{
1577 PLArenaPool *arena = NULL((void*)0);
1578 SECStatus rv;
1579 SECItem dbkey;
1580
1581 if (nickname == NULL((void*)0)) {
1582 return (SECSuccess);
1583 }
1584
1585 arena = PORT_NewArenaPORT_NewArena_Util(DER_DEFAULT_CHUNKSIZE(2048));
1586 if (arena == NULL((void*)0)) {
1587 goto loser;
1588 }
1589
1590 rv = EncodeDBNicknameKey(nickname, arena, &dbkey);
1591 if (rv != SECSuccess) {
1592 goto loser;
1593 }
1594
1595 rv = DeleteDBEntry(handle, certDBEntryTypeNickname, &dbkey);
1596 if (rv == SECFailure) {
1597 goto loser;
1598 }
1599
1600 PORT_FreeArenaPORT_FreeArena_Util(arena, PR_FALSE0);
1601 return (SECSuccess);
1602
1603loser:
1604 if (arena) {
1605 PORT_FreeArenaPORT_FreeArena_Util(arena, PR_FALSE0);
1606 }
1607
1608 return (SECFailure);
1609}
1610
1611/*
1612 * Read a nickname entry
1613 */
1614static certDBEntryNickname *
1615ReadDBNicknameEntry(NSSLOWCERTCertDBHandle *handle, char *nickname)
1616{
1617 PLArenaPool *arena = NULL((void*)0);
1618 PLArenaPool *tmparena = NULL((void*)0);
1619 certDBEntryNickname *entry;
1620 SECItem dbkey;
1621 SECItem dbentry;
1622 SECStatus rv;
1623
1624 arena = PORT_NewArenaPORT_NewArena_Util(DER_DEFAULT_CHUNKSIZE(2048));
1625 if (arena == NULL((void*)0)) {
1626 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
1627 goto loser;
1628 }
1629
1630 tmparena = PORT_NewArenaPORT_NewArena_Util(DER_DEFAULT_CHUNKSIZE(2048));
1631 if (tmparena == NULL((void*)0)) {
1632 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
1633 goto loser;
1634 }
1635
1636 entry = (certDBEntryNickname *)PORT_ArenaAllocPORT_ArenaAlloc_Util(arena,
1637 sizeof(certDBEntryNickname));
1638 if (entry == NULL((void*)0)) {
1639 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
1640 goto loser;
1641 }
1642 entry->common.arena = arena;
1643 entry->common.type = certDBEntryTypeNickname;
1644
1645 rv = EncodeDBNicknameKey(nickname, tmparena, &dbkey);
1646 if (rv != SECSuccess) {
1647 goto loser;
1648 }
1649
1650 rv = ReadDBEntry(handle, &entry->common, &dbkey, &dbentry, tmparena);
1651 if (rv == SECFailure) {
1652 goto loser;
1653 }
1654
1655 /* is record long enough for header? */
1656 if (dbentry.len < DB_NICKNAME_ENTRY_HEADER_LEN2) {
1657 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_BAD_DATABASE);
1658 goto loser;
1659 }
1660
1661 rv = DecodeDBNicknameEntry(entry, &dbentry, nickname);
1662 if (rv != SECSuccess) {
1663 goto loser;
1664 }
1665
1666 PORT_FreeArenaPORT_FreeArena_Util(tmparena, PR_FALSE0);
1667 return (entry);
1668
1669loser:
1670 if (tmparena) {
1671 PORT_FreeArenaPORT_FreeArena_Util(tmparena, PR_FALSE0);
1672 }
1673 if (arena) {
1674 PORT_FreeArenaPORT_FreeArena_Util(arena, PR_FALSE0);
1675 }
1676
1677 return (NULL((void*)0));
1678}
1679
1680/*
1681 * Encode a nickname entry into byte stream suitable for
1682 * the database
1683 */
1684static SECStatus
1685WriteDBNicknameEntry(NSSLOWCERTCertDBHandle *handle, certDBEntryNickname *entry)
1686{
1687 SECItem dbitem, dbkey;
1688 PLArenaPool *tmparena = NULL((void*)0);
1689 SECStatus rv;
1690
1691 tmparena = PORT_NewArenaPORT_NewArena_Util(DER_DEFAULT_CHUNKSIZE(2048));
1692 if (tmparena == NULL((void*)0)) {
1693 goto loser;
1694 }
1695
1696 rv = EncodeDBNicknameEntry(entry, tmparena, &dbitem);
1697 if (rv != SECSuccess) {
1698 goto loser;
1699 }
1700
1701 rv = EncodeDBNicknameKey(entry->nickname, tmparena, &dbkey);
1702 if (rv != SECSuccess) {
1703 goto loser;
1704 }
1705
1706 /* now write it to the database */
1707 rv = WriteDBEntry(handle, &entry->common, &dbkey, &dbitem);
1708 if (rv != SECSuccess) {
1709 goto loser;
1710 }
1711
1712 PORT_FreeArenaPORT_FreeArena_Util(tmparena, PR_FALSE0);
1713 return (SECSuccess);
1714
1715loser:
1716 if (tmparena) {
1717 PORT_FreeArenaPORT_FreeArena_Util(tmparena, PR_FALSE0);
1718 }
1719 return (SECFailure);
1720}
1721
1722static SECStatus
1723EncodeDBSMimeEntry(certDBEntrySMime *entry, PLArenaPool *arena,
1724 SECItem *dbitem)
1725{
1726 unsigned char *buf;
1727
1728 /* allocate space for encoded database record, including space
1729 * for low level header
1730 */
1731 dbitem->len = entry->subjectName.len + entry->smimeOptions.len +
1732 entry->optionsDate.len +
1733 DB_SMIME_ENTRY_HEADER_LEN6 + SEC_DB_ENTRY_HEADER_LEN3;
1734
1735 dbitem->data = (unsigned char *)PORT_ArenaAllocPORT_ArenaAlloc_Util(arena, dbitem->len);
1736 if (dbitem->data == NULL((void*)0)) {
1737 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
1738 goto loser;
1739 }
1740
1741 /* fill in database record */
1742 buf = &dbitem->data[SEC_DB_ENTRY_HEADER_LEN3];
1743
1744 buf[0] = (PRUint8)(entry->subjectName.len >> 8);
1745 buf[1] = (PRUint8)(entry->subjectName.len);
1746 buf[2] = (PRUint8)(entry->smimeOptions.len >> 8);
1747 buf[3] = (PRUint8)(entry->smimeOptions.len);
1748 buf[4] = (PRUint8)(entry->optionsDate.len >> 8);
1749 buf[5] = (PRUint8)(entry->optionsDate.len);
1750
1751 /* if no smime options, then there should not be an options date either */
1752 PORT_Assert(!((entry->smimeOptions.len == 0) &&((!((entry->smimeOptions.len == 0) && (entry->optionsDate
.len != 0)))?((void)0):PR_Assert("!((entry->smimeOptions.len == 0) && (entry->optionsDate.len != 0))"
,"pcertdb.c",1753))
1753 (entry->optionsDate.len != 0)))((!((entry->smimeOptions.len == 0) && (entry->optionsDate
.len != 0)))?((void)0):PR_Assert("!((entry->smimeOptions.len == 0) && (entry->optionsDate.len != 0))"
,"pcertdb.c",1753))
;
1754
1755 PORT_Memcpymemcpy(&buf[DB_SMIME_ENTRY_HEADER_LEN6], entry->subjectName.data,
1756 entry->subjectName.len);
1757 if (entry->smimeOptions.len) {
1758 PORT_Memcpymemcpy(&buf[DB_SMIME_ENTRY_HEADER_LEN6 + entry->subjectName.len],
1759 entry->smimeOptions.data,
1760 entry->smimeOptions.len);
1761 PORT_Memcpymemcpy(&buf[DB_SMIME_ENTRY_HEADER_LEN6 + entry->subjectName.len +
1762 entry->smimeOptions.len],
1763 entry->optionsDate.data,
1764 entry->optionsDate.len);
1765 }
1766
1767 return (SECSuccess);
1768
1769loser:
1770 return (SECFailure);
1771}
1772
1773/*
1774 * Encode a database key for a SMIME record
1775 */
1776static SECStatus
1777EncodeDBSMimeKey(char *emailAddr, PLArenaPool *arena,
1778 SECItem *dbkey)
1779{
1780 unsigned int addrlen;
1781
1782 addrlen = PORT_Strlen(emailAddr)strlen(emailAddr) + 1; /* includes null */
1783
1784 /* now get the database key and format it */
1785 dbkey->len = addrlen + SEC_DB_KEY_HEADER_LEN1;
1786 if (dbkey->len > NSS_MAX_LEGACY_DB_KEY_SIZE(60 * 1024))
1787 goto loser;
1788 dbkey->data = (unsigned char *)PORT_ArenaAllocPORT_ArenaAlloc_Util(arena, dbkey->len);
1789 if (dbkey->data == NULL((void*)0)) {
1790 goto loser;
1791 }
1792 PORT_Memcpymemcpy(&dbkey->data[SEC_DB_KEY_HEADER_LEN1], emailAddr, addrlen);
1793 dbkey->data[0] = certDBEntryTypeSMimeProfile;
1794
1795 return (SECSuccess);
1796
1797loser:
1798 return (SECFailure);
1799}
1800
1801/*
1802 * Decode a database SMIME record
1803 */
1804static SECStatus
1805DecodeDBSMimeEntry(certDBEntrySMime *entry, SECItem *dbentry, char *emailAddr)
1806{
1807 int lenDiff;
1808
1809 /* is record long enough for header? */
1810 if (dbentry->len < DB_SMIME_ENTRY_HEADER_LEN6) {
1811 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_BAD_DATABASE);
1812 goto loser;
1813 }
1814
1815 /* is database entry correct length? */
1816 entry->subjectName.len = ((dbentry->data[0] << 8) | dbentry->data[1]);
1817 entry->smimeOptions.len = ((dbentry->data[2] << 8) | dbentry->data[3]);
1818 entry->optionsDate.len = ((dbentry->data[4] << 8) | dbentry->data[5]);
1819 lenDiff = dbentry->len - (entry->subjectName.len +
1820 entry->smimeOptions.len +
1821 entry->optionsDate.len +
1822 DB_SMIME_ENTRY_HEADER_LEN6);
1823 if (lenDiff) {
1824 if (lenDiff < 0 || (lenDiff & 0xffff) != 0) {
1825 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_BAD_DATABASE);
1826 goto loser;
1827 }
1828 /* The entry size exceeded 64KB. Reconstruct the correct length. */
1829 entry->subjectName.len += lenDiff;
1830 }
1831
1832 /* copy the subject name */
1833 entry->subjectName.data =
1834 (unsigned char *)PORT_ArenaAllocPORT_ArenaAlloc_Util(entry->common.arena,
1835 entry->subjectName.len);
1836 if (entry->subjectName.data == NULL((void*)0)) {
1837 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
1838 goto loser;
1839 }
1840 PORT_Memcpymemcpy(entry->subjectName.data,
1841 &dbentry->data[DB_SMIME_ENTRY_HEADER_LEN6],
1842 entry->subjectName.len);
1843
1844 /* copy the smime options */
1845 if (entry->smimeOptions.len) {
1846 entry->smimeOptions.data =
1847 (unsigned char *)PORT_ArenaAllocPORT_ArenaAlloc_Util(entry->common.arena,
1848 entry->smimeOptions.len);
1849 if (entry->smimeOptions.data == NULL((void*)0)) {
1850 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
1851 goto loser;
1852 }
1853 PORT_Memcpymemcpy(entry->smimeOptions.data,
1854 &dbentry->data[DB_SMIME_ENTRY_HEADER_LEN6 +
1855 entry->subjectName.len],
1856 entry->smimeOptions.len);
1857 } else {
1858 entry->smimeOptions.data = NULL((void*)0);
1859 }
1860 if (entry->optionsDate.len) {
1861 entry->optionsDate.data =
1862 (unsigned char *)PORT_ArenaAllocPORT_ArenaAlloc_Util(entry->common.arena,
1863 entry->optionsDate.len);
1864 if (entry->optionsDate.data == NULL((void*)0)) {
1865 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
1866 goto loser;
1867 }
1868 PORT_Memcpymemcpy(entry->optionsDate.data,
1869 &dbentry->data[DB_SMIME_ENTRY_HEADER_LEN6 +
1870 entry->subjectName.len +
1871 entry->smimeOptions.len],
1872 entry->optionsDate.len);
1873 } else {
1874 entry->optionsDate.data = NULL((void*)0);
1875 }
1876
1877 /* both options and options date must either exist or not exist */
1878 if (((entry->optionsDate.len == 0) ||
1879 (entry->smimeOptions.len == 0)) &&
1880 entry->smimeOptions.len != entry->optionsDate.len) {
1881 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_BAD_DATABASE);
1882 goto loser;
1883 }
1884
1885 entry->emailAddr = (char *)PORT_ArenaAllocPORT_ArenaAlloc_Util(entry->common.arena,
1886 PORT_Strlen(emailAddr)strlen(emailAddr) + 1);
1887 if (entry->emailAddr) {
1888 PORT_Strcpystrcpy(entry->emailAddr, emailAddr);
1889 }
1890
1891 return (SECSuccess);
1892
1893loser:
1894 return (SECFailure);
1895}
1896
1897/*
1898 * create a new SMIME entry
1899 */
1900static certDBEntrySMime *
1901NewDBSMimeEntry(char *emailAddr, SECItem *subjectName, SECItem *smimeOptions,
1902 SECItem *optionsDate, unsigned int flags)
1903{
1904 PLArenaPool *arena = NULL((void*)0);
1905 certDBEntrySMime *entry;
1906 int addrlen;
1907 SECStatus rv;
1908
1909 arena = PORT_NewArenaPORT_NewArena_Util(DER_DEFAULT_CHUNKSIZE(2048));
1910 if (arena == NULL((void*)0)) {
1911 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
1912 goto loser;
1913 }
1914
1915 entry = (certDBEntrySMime *)PORT_ArenaAllocPORT_ArenaAlloc_Util(arena,
1916 sizeof(certDBEntrySMime));
1917 if (entry == NULL((void*)0)) {
1918 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
1919 goto loser;
1920 }
1921
1922 /* init common fields */
1923 entry->common.arena = arena;
1924 entry->common.type = certDBEntryTypeSMimeProfile;
1925 entry->common.version = CERT_DB_FILE_VERSION8;
1926 entry->common.flags = flags;
1927
1928 /* copy the email addr */
1929 addrlen = PORT_Strlen(emailAddr)strlen(emailAddr) + 1;
1930
1931 entry->emailAddr = (char *)PORT_ArenaAllocPORT_ArenaAlloc_Util(arena, addrlen);
1932 if (entry->emailAddr == NULL((void*)0)) {
1933 goto loser;
1934 }
1935
1936 PORT_Memcpymemcpy(entry->emailAddr, emailAddr, addrlen);
1937
1938 /* copy the subject name */
1939 rv = SECITEM_CopyItemSECITEM_CopyItem_Util(arena, &entry->subjectName, subjectName);
1940 if (rv != SECSuccess) {
1941 goto loser;
1942 }
1943
1944 /* copy the smime options */
1945 if (smimeOptions) {
1946 rv = SECITEM_CopyItemSECITEM_CopyItem_Util(arena, &entry->smimeOptions, smimeOptions);
1947 if (rv != SECSuccess) {
1948 goto loser;
1949 }
1950 } else {
1951 PORT_Assert(optionsDate == NULL)((optionsDate == ((void*)0))?((void)0):PR_Assert("optionsDate == NULL"
,"pcertdb.c",1951))
;
1952 entry->smimeOptions.data = NULL((void*)0);
1953 entry->smimeOptions.len = 0;
1954 }
1955
1956 /* copy the options date */
1957 if (optionsDate) {
1958 rv = SECITEM_CopyItemSECITEM_CopyItem_Util(arena, &entry->optionsDate, optionsDate);
1959 if (rv != SECSuccess) {
1960 goto loser;
1961 }
1962 } else {
1963 PORT_Assert(smimeOptions == NULL)((smimeOptions == ((void*)0))?((void)0):PR_Assert("smimeOptions == NULL"
,"pcertdb.c",1963))
;
1964 entry->optionsDate.data = NULL((void*)0);
1965 entry->optionsDate.len = 0;
1966 }
1967
1968 return (entry);
1969loser:
1970 if (arena) {
1971 PORT_FreeArenaPORT_FreeArena_Util(arena, PR_FALSE0);
1972 }
1973
1974 return (NULL((void*)0));
1975}
1976
1977/*
1978 * delete a SMIME entry
1979 */
1980static SECStatus
1981DeleteDBSMimeEntry(NSSLOWCERTCertDBHandle *handle, char *emailAddr)
1982{
1983 PLArenaPool *arena = NULL((void*)0);
1984 SECStatus rv;
1985 SECItem dbkey;
1986
1987 arena = PORT_NewArenaPORT_NewArena_Util(DER_DEFAULT_CHUNKSIZE(2048));
1988 if (arena == NULL((void*)0)) {
1989 goto loser;
1990 }
1991
1992 rv = EncodeDBSMimeKey(emailAddr, arena, &dbkey);
1993 if (rv != SECSuccess) {
1994 goto loser;
1995 }
1996
1997 rv = DeleteDBEntry(handle, certDBEntryTypeSMimeProfile, &dbkey);
1998 if (rv == SECFailure) {
1999 goto loser;
2000 }
2001
2002 PORT_FreeArenaPORT_FreeArena_Util(arena, PR_FALSE0);
2003 return (SECSuccess);
2004
2005loser:
2006 if (arena) {
2007 PORT_FreeArenaPORT_FreeArena_Util(arena, PR_FALSE0);
2008 }
2009
2010 return (SECFailure);
2011}
2012
2013/*
2014 * Read a SMIME entry
2015 */
2016certDBEntrySMime *
2017nsslowcert_ReadDBSMimeEntry(NSSLOWCERTCertDBHandle *handle, char *emailAddr)
2018{
2019 PLArenaPool *arena = NULL((void*)0);
2020 PLArenaPool *tmparena = NULL((void*)0);
2021 certDBEntrySMime *entry = NULL((void*)0);
2022 SECItem dbkey;
2023 SECItem dbentry;
2024 SECStatus rv;
2025
2026 arena = PORT_NewArenaPORT_NewArena_Util(DER_DEFAULT_CHUNKSIZE(2048));
2027 if (arena == NULL((void*)0)) {
2028 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
2029 goto loser;
2030 }
2031
2032 tmparena = PORT_NewArenaPORT_NewArena_Util(DER_DEFAULT_CHUNKSIZE(2048));
2033 if (tmparena == NULL((void*)0)) {
2034 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
2035 goto loser;
2036 }
2037
2038 entry = (certDBEntrySMime *)PORT_ArenaZAllocPORT_ArenaZAlloc_Util(arena,
2039 sizeof(certDBEntrySMime));
2040 if (entry == NULL((void*)0)) {
2041 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
2042 goto loser;
2043 }
2044 entry->common.arena = arena;
2045 entry->common.type = certDBEntryTypeSMimeProfile;
2046
2047 rv = EncodeDBSMimeKey(emailAddr, tmparena, &dbkey);
2048 if (rv != SECSuccess) {
2049 goto loser;
2050 }
2051
2052 rv = ReadDBEntry(handle, &entry->common, &dbkey, &dbentry, tmparena);
2053 if (rv == SECFailure) {
2054 goto loser;
2055 }
2056
2057 /* is record long enough for header? */
2058 if (dbentry.len < DB_SMIME_ENTRY_HEADER_LEN6) {
2059 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_BAD_DATABASE);
2060 goto loser;
2061 }
2062
2063 rv = DecodeDBSMimeEntry(entry, &dbentry, emailAddr);
2064 if (rv != SECSuccess) {
2065 goto loser;
2066 }
2067
2068 PORT_FreeArenaPORT_FreeArena_Util(tmparena, PR_FALSE0);
2069 return (entry);
2070
2071loser:
2072 if (tmparena) {
2073 PORT_FreeArenaPORT_FreeArena_Util(tmparena, PR_FALSE0);
2074 }
2075 if (arena) {
2076 PORT_FreeArenaPORT_FreeArena_Util(arena, PR_FALSE0);
2077 }
2078
2079 return (NULL((void*)0));
2080}
2081
2082/*
2083 * Encode a SMIME entry into byte stream suitable for
2084 * the database
2085 */
2086static SECStatus
2087WriteDBSMimeEntry(NSSLOWCERTCertDBHandle *handle, certDBEntrySMime *entry)
2088{
2089 SECItem dbitem, dbkey;
2090 PLArenaPool *tmparena = NULL((void*)0);
2091 SECStatus rv;
2092
2093 tmparena = PORT_NewArenaPORT_NewArena_Util(DER_DEFAULT_CHUNKSIZE(2048));
2094 if (tmparena == NULL((void*)0)) {
2095 goto loser;
2096 }
2097
2098 rv = EncodeDBSMimeEntry(entry, tmparena, &dbitem);
2099 if (rv != SECSuccess) {
2100 goto loser;
2101 }
2102
2103 rv = EncodeDBSMimeKey(entry->emailAddr, tmparena, &dbkey);
2104 if (rv != SECSuccess) {
2105 goto loser;
2106 }
2107
2108 /* now write it to the database */
2109 rv = WriteDBEntry(handle, &entry->common, &dbkey, &dbitem);
2110 if (rv != SECSuccess) {
2111 goto loser;
2112 }
2113
2114 PORT_FreeArenaPORT_FreeArena_Util(tmparena, PR_FALSE0);
2115 return (SECSuccess);
2116
2117loser:
2118 if (tmparena) {
2119 PORT_FreeArenaPORT_FreeArena_Util(tmparena, PR_FALSE0);
2120 }
2121 return (SECFailure);
2122}
2123
2124/*
2125 * Encode a database subject record
2126 */
2127static SECStatus
2128EncodeDBSubjectEntry(certDBEntrySubject *entry, PLArenaPool *arena,
2129 SECItem *dbitem)
2130{
2131 unsigned char *buf;
2132 int len;
2133 unsigned int ncerts;
2134 unsigned int i;
2135 unsigned char *tmpbuf;
2136 unsigned int nnlen = 0;
2137 unsigned int eaddrslen = 0;
2138 int keyidoff;
2139 SECItem *certKeys = entry->certKeys;
2140 SECItem *keyIDs = entry->keyIDs;
2141 ;
2142
2143 if (entry->nickname) {
2144 nnlen = PORT_Strlen(entry->nickname)strlen(entry->nickname) + 1;
2145 }
2146 if (entry->emailAddrs) {
2147 eaddrslen = 2;
2148 for (i = 0; i < entry->nemailAddrs; i++) {
2149 eaddrslen += PORT_Strlen(entry->emailAddrs[i])strlen(entry->emailAddrs[i]) + 1 + 2;
2150 }
2151 }
2152
2153 ncerts = entry->ncerts;
2154
2155 /* compute the length of the entry */
2156 keyidoff = DB_SUBJECT_ENTRY_HEADER_LEN6 + nnlen;
2157 len = keyidoff + (4 * ncerts) + eaddrslen;
2158 for (i = 0; i < ncerts; i++) {
2159 if (keyIDs[i].len > 0xffff ||
2160 (certKeys[i].len > 0xffff)) {
2161 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_INPUT_LEN);
2162 goto loser;
2163 }
2164 len += certKeys[i].len;
2165 len += keyIDs[i].len;
2166 }
2167
2168 /* allocate space for encoded database record, including space
2169 * for low level header
2170 */
2171 dbitem->len = len + SEC_DB_ENTRY_HEADER_LEN3;
2172
2173 dbitem->data = (unsigned char *)PORT_ArenaAllocPORT_ArenaAlloc_Util(arena, dbitem->len);
2174 if (dbitem->data == NULL((void*)0)) {
2175 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
2176 goto loser;
2177 }
2178
2179 /* fill in database record */
2180 buf = &dbitem->data[SEC_DB_ENTRY_HEADER_LEN3];
2181
2182 buf[0] = (PRUint8)(ncerts >> 8);
2183 buf[1] = (PRUint8)(ncerts);
2184 buf[2] = (PRUint8)(nnlen >> 8);
2185 buf[3] = (PRUint8)(nnlen);
2186 /* v7 email field is NULL in v8 */
2187 buf[4] = 0;
2188 buf[5] = 0;
2189
2190 PORT_Assert(DB_SUBJECT_ENTRY_HEADER_LEN == 6)((6 == 6)?((void)0):PR_Assert("DB_SUBJECT_ENTRY_HEADER_LEN == 6"
,"pcertdb.c",2190))
;
2191
2192 if (entry->nickname) {
2193 PORT_Memcpymemcpy(&buf[DB_SUBJECT_ENTRY_HEADER_LEN6], entry->nickname, nnlen);
2194 }
2195 tmpbuf = &buf[keyidoff];
2196 for (i = 0; i < ncerts; i++) {
2197 tmpbuf[0] = (PRUint8)(certKeys[i].len >> 8);
2198 tmpbuf[1] = (PRUint8)(certKeys[i].len);
2199 tmpbuf += 2;
2200 }
2201 for (i = 0; i < ncerts; i++) {
2202 tmpbuf[0] = (PRUint8)(keyIDs[i].len >> 8);
2203 tmpbuf[1] = (PRUint8)(keyIDs[i].len);
2204 tmpbuf += 2;
2205 }
2206
2207 for (i = 0; i < ncerts; i++) {
2208 PORT_Memcpymemcpy(tmpbuf, certKeys[i].data, certKeys[i].len);
2209 tmpbuf += certKeys[i].len;
2210 }
2211 for (i = 0; i < ncerts; i++) {
2212 if (keyIDs[i].len) {
2213 PORT_Memcpymemcpy(tmpbuf, keyIDs[i].data, keyIDs[i].len);
2214 tmpbuf += keyIDs[i].len;
2215 }
2216 }
2217
2218 if (entry->emailAddrs) {
2219 tmpbuf[0] = (PRUint8)(entry->nemailAddrs >> 8);
2220 tmpbuf[1] = (PRUint8)(entry->nemailAddrs);
2221 tmpbuf += 2;
2222 for (i = 0; i < entry->nemailAddrs; i++) {
2223 int nameLen = PORT_Strlen(entry->emailAddrs[i])strlen(entry->emailAddrs[i]) + 1;
2224 tmpbuf[0] = (PRUint8)(nameLen >> 8);
2225 tmpbuf[1] = (PRUint8)(nameLen);
2226 tmpbuf += 2;
2227 PORT_Memcpymemcpy(tmpbuf, entry->emailAddrs[i], nameLen);
2228 tmpbuf += nameLen;
2229 }
2230 }
2231
2232 PORT_Assert(tmpbuf == &buf[len])((tmpbuf == &buf[len])?((void)0):PR_Assert("tmpbuf == &buf[len]"
,"pcertdb.c",2232))
;
2233
2234 return (SECSuccess);
2235
2236loser:
2237 return (SECFailure);
2238}
2239
2240/*
2241 * Encode a database key for a subject record
2242 */
2243static SECStatus
2244EncodeDBSubjectKey(SECItem *derSubject, PLArenaPool *arena,
2245 SECItem *dbkey)
2246{
2247 dbkey->len = derSubject->len + SEC_DB_KEY_HEADER_LEN1;
2248 if (dbkey->len > NSS_MAX_LEGACY_DB_KEY_SIZE(60 * 1024))
2249 goto loser;
2250 dbkey->data = (unsigned char *)PORT_ArenaAllocPORT_ArenaAlloc_Util(arena, dbkey->len);
2251 if (dbkey->data == NULL((void*)0)) {
2252 goto loser;
2253 }
2254 PORT_Memcpymemcpy(&dbkey->data[SEC_DB_KEY_HEADER_LEN1], derSubject->data,
2255 derSubject->len);
2256 dbkey->data[0] = certDBEntryTypeSubject;
2257
2258 return (SECSuccess);
2259
2260loser:
2261 return (SECFailure);
2262}
2263
2264static SECStatus
2265DecodeDBSubjectEntry(certDBEntrySubject *entry, SECItem *dbentry,
2266 const SECItem *derSubject)
2267{
2268 PLArenaPool *arena = entry->common.arena;
2269 unsigned char *tmpbuf;
2270 unsigned char *end;
2271 void *mark = PORT_ArenaMarkPORT_ArenaMark_Util(arena);
2272 unsigned int eaddrlen;
2273 unsigned int i;
2274 unsigned int keyidoff;
2275 unsigned int len;
2276 unsigned int ncerts = 0;
2277 unsigned int nnlen;
2278 SECStatus rv;
2279
2280 rv = SECITEM_CopyItemSECITEM_CopyItem_Util(arena, &entry->derSubject, derSubject);
2281 if (rv != SECSuccess) {
2282 goto loser;
2283 }
2284
2285 /* is record long enough for header? */
2286 if (dbentry->len < DB_SUBJECT_ENTRY_HEADER_LEN6) {
2287 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_BAD_DATABASE);
2288 goto loser;
2289 }
2290
2291 entry->ncerts = ncerts = ((dbentry->data[0] << 8) | dbentry->data[1]);
2292 nnlen = ((dbentry->data[2] << 8) | dbentry->data[3]);
2293 eaddrlen = ((dbentry->data[4] << 8) | dbentry->data[5]);
2294 keyidoff = DB_SUBJECT_ENTRY_HEADER_LEN6 + nnlen + eaddrlen;
2295 len = keyidoff + (4 * ncerts);
2296 if (dbentry->len < len) {
2297 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_BAD_DATABASE);
2298 goto loser;
2299 }
2300
2301 entry->certKeys = PORT_ArenaNewArray(arena, SECItem, ncerts)(SECItem *)PORT_ArenaAlloc_Util(arena, sizeof(SECItem) * (ncerts
))
;
2302 entry->keyIDs = PORT_ArenaNewArray(arena, SECItem, ncerts)(SECItem *)PORT_ArenaAlloc_Util(arena, sizeof(SECItem) * (ncerts
))
;
2303 if ((entry->certKeys == NULL((void*)0)) || (entry->keyIDs == NULL((void*)0))) {
2304 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
2305 goto loser;
2306 }
2307
2308 if (nnlen > 1) { /* null terminator is stored */
2309 entry->nickname = (char *)PORT_ArenaAllocPORT_ArenaAlloc_Util(arena, nnlen);
2310 if (entry->nickname == NULL((void*)0)) {
2311 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
2312 goto loser;
2313 }
2314 PORT_Memcpymemcpy(entry->nickname,
2315 &dbentry->data[DB_SUBJECT_ENTRY_HEADER_LEN6],
2316 nnlen);
2317 } else {
2318 entry->nickname = NULL((void*)0);
2319 }
2320
2321 /* if we have an old style email entry, there is only one */
2322 entry->nemailAddrs = 0;
2323 if (eaddrlen > 1) { /* null terminator is stored */
2324 entry->emailAddrs = PORT_ArenaNewArray(arena, char *, 2)(char * *)PORT_ArenaAlloc_Util(arena, sizeof(char *) * (2));
2325 if (entry->emailAddrs == NULL((void*)0)) {
2326 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
2327 goto loser;
2328 }
2329 entry->emailAddrs[0] = (char *)PORT_ArenaAllocPORT_ArenaAlloc_Util(arena, eaddrlen);
2330 if (entry->emailAddrs[0] == NULL((void*)0)) {
2331 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
2332 goto loser;
2333 }
2334 PORT_Memcpymemcpy(entry->emailAddrs[0],
2335 &dbentry->data[DB_SUBJECT_ENTRY_HEADER_LEN6 + nnlen],
2336 eaddrlen);
2337 entry->nemailAddrs = 1;
2338 } else {
2339 entry->emailAddrs = NULL((void*)0);
2340 }
2341
2342 /* collect the lengths of the certKeys and keyIDs, and total the
2343 * overall length.
2344 */
2345 tmpbuf = &dbentry->data[keyidoff];
2346 for (i = 0; i < ncerts; i++) {
2347 unsigned int itemlen = (tmpbuf[0] << 8) | tmpbuf[1];
2348 entry->certKeys[i].len = itemlen;
2349 len += itemlen;
2350 tmpbuf += 2;
2351 }
2352 for (i = 0; i < ncerts; i++) {
2353 unsigned int itemlen = (tmpbuf[0] << 8) | tmpbuf[1];
2354 entry->keyIDs[i].len = itemlen;
2355 len += itemlen;
2356 tmpbuf += 2;
2357 }
2358
2359 /* is encoded entry large enough ? */
2360 if (len > dbentry->len) {
2361 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_BAD_DATABASE);
2362 goto loser;
2363 }
2364
2365 for (i = 0; i < ncerts; i++) {
2366 unsigned int kLen = entry->certKeys[i].len;
2367 entry->certKeys[i].data = (unsigned char *)PORT_ArenaAllocPORT_ArenaAlloc_Util(arena, kLen);
2368 if (entry->certKeys[i].data == NULL((void*)0)) {
2369 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
2370 goto loser;
2371 }
2372 PORT_Memcpymemcpy(entry->certKeys[i].data, tmpbuf, kLen);
2373 tmpbuf += kLen;
2374 }
2375 for (i = 0; i < ncerts; i++) {
2376 unsigned int iLen = entry->keyIDs[i].len;
2377 entry->keyIDs[i].data = (unsigned char *)PORT_ArenaAllocPORT_ArenaAlloc_Util(arena, iLen);
2378 if (entry->keyIDs[i].data == NULL((void*)0)) {
2379 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
2380 goto loser;
2381 }
2382 PORT_Memcpymemcpy(entry->keyIDs[i].data, tmpbuf, iLen);
2383 tmpbuf += iLen;
2384 }
2385
2386 end = dbentry->data + dbentry->len;
2387 if ((eaddrlen == 0) && (end - tmpbuf > 1)) {
2388 /* read in the additional email addresses */
2389 entry->nemailAddrs = (((unsigned int)tmpbuf[0]) << 8) | tmpbuf[1];
2390 tmpbuf += 2;
2391 if (end - tmpbuf < 2 * (int)entry->nemailAddrs)
2392 goto loser;
2393 entry->emailAddrs = PORT_ArenaNewArray(arena, char *, entry->nemailAddrs)(char * *)PORT_ArenaAlloc_Util(arena, sizeof(char *) * (entry
->nemailAddrs))
;
2394 if (entry->emailAddrs == NULL((void*)0)) {
2395 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
2396 goto loser;
2397 }
2398 for (i = 0; i < entry->nemailAddrs; i++) {
2399 int nameLen;
2400 if (end - tmpbuf < 2) {
2401 goto loser;
2402 }
2403 nameLen = (((int)tmpbuf[0]) << 8) | tmpbuf[1];
2404 tmpbuf += 2;
2405 if (end - tmpbuf < nameLen) {
2406 goto loser;
2407 }
2408 entry->emailAddrs[i] = PORT_ArenaAllocPORT_ArenaAlloc_Util(arena, nameLen);
2409 if (entry->emailAddrs == NULL((void*)0)) {
2410 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
2411 goto loser;
2412 }
2413 PORT_Memcpymemcpy(entry->emailAddrs[i], tmpbuf, nameLen);
2414 tmpbuf += nameLen;
2415 }
2416 if (tmpbuf != end)
2417 goto loser;
2418 }
2419 PORT_ArenaUnmarkPORT_ArenaUnmark_Util(arena, mark);
2420 return (SECSuccess);
2421
2422loser:
2423 PORT_ArenaReleasePORT_ArenaRelease_Util(arena, mark); /* discard above allocations */
2424 return (SECFailure);
2425}
2426
2427/*
2428 * create a new subject entry with a single cert
2429 */
2430static certDBEntrySubject *
2431NewDBSubjectEntry(SECItem *derSubject, SECItem *certKey,
2432 SECItem *keyID, char *nickname, char *emailAddr,
2433 unsigned int flags)
2434{
2435 PLArenaPool *arena = NULL((void*)0);
2436 certDBEntrySubject *entry;
2437 SECStatus rv;
2438 unsigned int nnlen;
2439
2440 arena = PORT_NewArenaPORT_NewArena_Util(DER_DEFAULT_CHUNKSIZE(2048));
2441 if (arena == NULL((void*)0)) {
2442 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
2443 goto loser;
2444 }
2445
2446 entry = (certDBEntrySubject *)PORT_ArenaAllocPORT_ArenaAlloc_Util(arena,
2447 sizeof(certDBEntrySubject));
2448 if (entry == NULL((void*)0)) {
2449 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
2450 goto loser;
2451 }
2452
2453 /* init common fields */
2454 entry->common.arena = arena;
2455 entry->common.type = certDBEntryTypeSubject;
2456 entry->common.version = CERT_DB_FILE_VERSION8;
2457 entry->common.flags = flags;
2458
2459 /* copy the subject */
2460 rv = SECITEM_CopyItemSECITEM_CopyItem_Util(arena, &entry->derSubject, derSubject);
2461 if (rv != SECSuccess) {
2462 goto loser;
2463 }
2464
2465 entry->ncerts = 1;
2466 entry->nemailAddrs = 0;
2467 /* copy nickname */
2468 if (nickname && (*nickname != '\0')) {
2469 nnlen = PORT_Strlen(nickname)strlen(nickname) + 1;
2470 entry->nickname = (char *)PORT_ArenaAllocPORT_ArenaAlloc_Util(arena, nnlen);
2471 if (entry->nickname == NULL((void*)0)) {
2472 goto loser;
2473 }
2474
2475 PORT_Memcpymemcpy(entry->nickname, nickname, nnlen);
2476 } else {
2477 entry->nickname = NULL((void*)0);
2478 }
2479
2480 /* copy email addr */
2481 if (emailAddr && (*emailAddr != '\0')) {
2482 emailAddr = nsslowcert_FixupEmailAddr(emailAddr);
2483 if (emailAddr == NULL((void*)0)) {
2484 entry->emailAddrs = NULL((void*)0);
2485 goto loser;
2486 }
2487
2488 entry->emailAddrs = (char **)PORT_ArenaAllocPORT_ArenaAlloc_Util(arena, sizeof(char *));
2489 if (entry->emailAddrs == NULL((void*)0)) {
2490 PORT_FreePORT_Free_Util(emailAddr);
2491 goto loser;
2492 }
2493 entry->emailAddrs[0] = PORT_ArenaStrdupPORT_ArenaStrdup_Util(arena, emailAddr);
2494 if (entry->emailAddrs[0]) {
2495 entry->nemailAddrs = 1;
2496 }
2497
2498 PORT_FreePORT_Free_Util(emailAddr);
2499 } else {
2500 entry->emailAddrs = NULL((void*)0);
2501 }
2502
2503 /* allocate space for certKeys and keyIDs */
2504 entry->certKeys = (SECItem *)PORT_ArenaAllocPORT_ArenaAlloc_Util(arena, sizeof(SECItem));
2505 entry->keyIDs = (SECItem *)PORT_ArenaAllocPORT_ArenaAlloc_Util(arena, sizeof(SECItem));
2506 if ((entry->certKeys == NULL((void*)0)) || (entry->keyIDs == NULL((void*)0))) {
2507 goto loser;
2508 }
2509
2510 /* copy the certKey and keyID */
2511 rv = SECITEM_CopyItemSECITEM_CopyItem_Util(arena, &entry->certKeys[0], certKey);
2512 if (rv != SECSuccess) {
2513 goto loser;
2514 }
2515 rv = SECITEM_CopyItemSECITEM_CopyItem_Util(arena, &entry->keyIDs[0], keyID);
2516 if (rv != SECSuccess) {
2517 goto loser;
2518 }
2519
2520 return (entry);
2521loser:
2522 if (arena) {
2523 PORT_FreeArenaPORT_FreeArena_Util(arena, PR_FALSE0);
2524 }
2525
2526 return (NULL((void*)0));
2527}
2528
2529/*
2530 * delete a subject entry
2531 */
2532static SECStatus
2533DeleteDBSubjectEntry(NSSLOWCERTCertDBHandle *handle, SECItem *derSubject)
2534{
2535 SECItem dbkey;
2536 PLArenaPool *arena = NULL((void*)0);
2537 SECStatus rv;
2538
2539 arena = PORT_NewArenaPORT_NewArena_Util(DER_DEFAULT_CHUNKSIZE(2048));
2540 if (arena == NULL((void*)0)) {
2541 goto loser;
2542 }
2543
2544 rv = EncodeDBSubjectKey(derSubject, arena, &dbkey);
2545 if (rv != SECSuccess) {
2546 goto loser;
2547 }
2548
2549 rv = DeleteDBEntry(handle, certDBEntryTypeSubject, &dbkey);
2550 if (rv == SECFailure) {
2551 goto loser;
2552 }
2553
2554 PORT_FreeArenaPORT_FreeArena_Util(arena, PR_FALSE0);
2555 return (SECSuccess);
2556
2557loser:
2558 if (arena) {
2559 PORT_FreeArenaPORT_FreeArena_Util(arena, PR_FALSE0);
2560 }
2561
2562 return (SECFailure);
2563}
2564
2565/*
2566 * Read the subject entry
2567 */
2568static certDBEntrySubject *
2569ReadDBSubjectEntry(NSSLOWCERTCertDBHandle *handle, SECItem *derSubject)
2570{
2571 /* |arena| isn't function-bounded, so cannot be a PORTCheapArenaPool. */
2572 PLArenaPool *arena = NULL((void*)0);
2573 PORTCheapArenaPool tmpArena;
2574
2575 certDBEntrySubject *entry;
2576 SECItem dbkey;
2577 SECItem dbentry;
2578 SECStatus rv;
2579
2580 PORT_InitCheapArena(&tmpArena, DER_DEFAULT_CHUNKSIZE(2048));
2581 arena = PORT_NewArenaPORT_NewArena_Util(DER_DEFAULT_CHUNKSIZE(2048));
2582 if (arena == NULL((void*)0)) {
2583 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
2584 goto loser;
2585 }
2586
2587 entry = (certDBEntrySubject *)PORT_ArenaAllocPORT_ArenaAlloc_Util(arena,
2588 sizeof(certDBEntrySubject));
2589 if (entry == NULL((void*)0)) {
2590 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
2591 goto loser;
2592 }
2593 entry->common.arena = arena;
2594 entry->common.type = certDBEntryTypeSubject;
2595
2596 rv = EncodeDBSubjectKey(derSubject, &tmpArena.arena, &dbkey);
2597 if (rv != SECSuccess) {
2598 goto loser;
2599 }
2600
2601 rv = ReadDBEntry(handle, &entry->common, &dbkey, &dbentry, &tmpArena.arena);
2602 if (rv == SECFailure) {
2603 goto loser;
2604 }
2605
2606 rv = DecodeDBSubjectEntry(entry, &dbentry, derSubject);
2607 if (rv == SECFailure) {
2608 goto loser;
2609 }
2610
2611 PORT_DestroyCheapArena(&tmpArena);
2612 return (entry);
2613
2614loser:
2615 PORT_DestroyCheapArena(&tmpArena);
2616 if (arena) {
2617 PORT_FreeArenaPORT_FreeArena_Util(arena, PR_FALSE0);
2618 }
2619
2620 return (NULL((void*)0));
2621}
2622
2623/*
2624 * Encode a subject name entry into byte stream suitable for
2625 * the database
2626 */
2627static SECStatus
2628WriteDBSubjectEntry(NSSLOWCERTCertDBHandle *handle, certDBEntrySubject *entry)
2629{
2630 SECItem dbitem, dbkey;
2631 PLArenaPool *tmparena = NULL((void*)0);
2632 SECStatus rv;
2633
2634 tmparena = PORT_NewArenaPORT_NewArena_Util(DER_DEFAULT_CHUNKSIZE(2048));
2635 if (tmparena == NULL((void*)0)) {
2636 goto loser;
2637 }
2638
2639 rv = EncodeDBSubjectEntry(entry, tmparena, &dbitem);
2640 if (rv != SECSuccess) {
2641 goto loser;
2642 }
2643
2644 rv = EncodeDBSubjectKey(&entry->derSubject, tmparena, &dbkey);
2645 if (rv != SECSuccess) {
2646 goto loser;
2647 }
2648
2649 /* now write it to the database */
2650 rv = WriteDBEntry(handle, &entry->common, &dbkey, &dbitem);
2651 if (rv != SECSuccess) {
2652 goto loser;
2653 }
2654
2655 PORT_FreeArenaPORT_FreeArena_Util(tmparena, PR_FALSE0);
2656 return (SECSuccess);
2657
2658loser:
2659 if (tmparena) {
2660 PORT_FreeArenaPORT_FreeArena_Util(tmparena, PR_FALSE0);
2661 }
2662 return (SECFailure);
2663}
2664
2665typedef enum { nsslowcert_remove,
2666 nsslowcert_add } nsslowcertUpdateType;
2667
2668static SECStatus
2669nsslowcert_UpdateSubjectEmailAddr(NSSLOWCERTCertDBHandle *dbhandle,
2670 SECItem *derSubject, char *emailAddr, nsslowcertUpdateType updateType)
2671{
2672 certDBEntrySubject *entry = NULL((void*)0);
2673 int index = -1, i;
2674 SECStatus rv;
2675
2676 if (emailAddr) {
2677 emailAddr = nsslowcert_FixupEmailAddr(emailAddr);
2678 if (emailAddr == NULL((void*)0)) {
2679 return SECFailure;
2680 }
2681 } else {
2682 return SECSuccess;
2683 }
2684
2685 entry = ReadDBSubjectEntry(dbhandle, derSubject);
2686 if (entry == NULL((void*)0)) {
2687 rv = SECFailure;
2688 goto done;
2689 }
2690
2691 for (i = 0; i < (int)(entry->nemailAddrs); i++) {
2692 if (PORT_Strcmpstrcmp(entry->emailAddrs[i], emailAddr) == 0) {
2693 index = i;
2694 }
2695 }
2696
2697 if (updateType == nsslowcert_remove) {
2698 if (index == -1) {
2699 rv = SECSuccess;
2700 goto done;
2701 }
2702 entry->nemailAddrs--;
2703 for (i = index; i < (int)(entry->nemailAddrs); i++) {
2704 entry->emailAddrs[i] = entry->emailAddrs[i + 1];
2705 }
2706 } else {
2707 char **newAddrs = NULL((void*)0);
2708
2709 if (index != -1) {
2710 rv = SECSuccess;
2711 goto done;
2712 }
2713 newAddrs = (char **)PORT_ArenaAllocPORT_ArenaAlloc_Util(entry->common.arena,
2714 (entry->nemailAddrs + 1) * sizeof(char *));
2715 if (!newAddrs) {
2716 rv = SECFailure;
2717 goto done;
2718 }
2719 for (i = 0; i < (int)(entry->nemailAddrs); i++) {
2720 newAddrs[i] = entry->emailAddrs[i];
2721 }
2722 newAddrs[entry->nemailAddrs] =
2723 PORT_ArenaStrdupPORT_ArenaStrdup_Util(entry->common.arena, emailAddr);
2724 if (!newAddrs[entry->nemailAddrs]) {
2725 rv = SECFailure;
2726 goto done;
2727 }
2728 entry->emailAddrs = newAddrs;
2729 entry->nemailAddrs++;
2730 }
2731
2732 /* delete the subject entry */
2733 DeleteDBSubjectEntry(dbhandle, derSubject);
2734
2735 /* write the new one */
2736 rv = WriteDBSubjectEntry(dbhandle, entry);
2737
2738done:
2739 if (entry)
2740 DestroyDBEntry((certDBEntry *)entry);
2741 if (emailAddr)
2742 PORT_FreePORT_Free_Util(emailAddr);
2743 return rv;
2744}
2745
2746/*
2747 * writes a nickname to an existing subject entry that does not currently
2748 * have one
2749 */
2750static SECStatus
2751AddNicknameToSubject(NSSLOWCERTCertDBHandle *dbhandle,
2752 NSSLOWCERTCertificate *cert, char *nickname)
2753{
2754 certDBEntrySubject *entry;
2755 SECStatus rv;
2756
2757 if (nickname == NULL((void*)0)) {
2758 return (SECFailure);
2759 }
2760
2761 entry = ReadDBSubjectEntry(dbhandle, &cert->derSubject);
2762 PORT_Assert(entry != NULL)((entry != ((void*)0))?((void)0):PR_Assert("entry != NULL","pcertdb.c"
,2762))
;
2763 if (entry == NULL((void*)0)) {
2764 goto loser;
2765 }
2766
2767 PORT_Assert(entry->nickname == NULL)((entry->nickname == ((void*)0))?((void)0):PR_Assert("entry->nickname == NULL"
,"pcertdb.c",2767))
;
2768 if (entry->nickname != NULL((void*)0)) {
2769 goto loser;
2770 }
2771
2772 entry->nickname = PORT_ArenaStrdupPORT_ArenaStrdup_Util(entry->common.arena, nickname);
2773
2774 if (entry->nickname == NULL((void*)0)) {
2775 goto loser;
2776 }
2777
2778 /* delete the subject entry */
2779 DeleteDBSubjectEntry(dbhandle, &cert->derSubject);
2780
2781 /* write the new one */
2782 rv = WriteDBSubjectEntry(dbhandle, entry);
2783 if (rv != SECSuccess) {
2784 goto loser;
2785 }
2786
2787 DestroyDBEntry((certDBEntry *)entry);
2788 return (SECSuccess);
2789
2790loser:
2791 DestroyDBEntry((certDBEntry *)entry);
2792 return (SECFailure);
2793}
2794
2795/*
2796 * create a new version entry
2797 */
2798static certDBEntryVersion *
2799NewDBVersionEntry(unsigned int flags)
2800{
2801 PLArenaPool *arena = NULL((void*)0);
2802 certDBEntryVersion *entry;
2803
2804 arena = PORT_NewArenaPORT_NewArena_Util(DER_DEFAULT_CHUNKSIZE(2048));
2805 if (arena == NULL((void*)0)) {
2806 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
2807 goto loser;
2808 }
2809
2810 entry = (certDBEntryVersion *)PORT_ArenaAllocPORT_ArenaAlloc_Util(arena,
2811 sizeof(certDBEntryVersion));
2812 if (entry == NULL((void*)0)) {
2813 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
2814 goto loser;
2815 }
2816 entry->common.arena = arena;
2817 entry->common.type = certDBEntryTypeVersion;
2818 entry->common.version = CERT_DB_FILE_VERSION8;
2819 entry->common.flags = flags;
2820
2821 return (entry);
2822loser:
2823 if (arena) {
2824 PORT_FreeArenaPORT_FreeArena_Util(arena, PR_FALSE0);
2825 }
2826
2827 return (NULL((void*)0));
2828}
2829
2830/*
2831 * Read the version entry
2832 */
2833static certDBEntryVersion *
2834ReadDBVersionEntry(NSSLOWCERTCertDBHandle *handle)
2835{
2836 PLArenaPool *arena = NULL((void*)0);
2837 PLArenaPool *tmparena = NULL((void*)0);
2838 certDBEntryVersion *entry;
2839 SECItem dbkey;
2840 SECItem dbentry;
2841 SECStatus rv;
2842
2843 arena = PORT_NewArenaPORT_NewArena_Util(DER_DEFAULT_CHUNKSIZE(2048));
2844 if (arena == NULL((void*)0)) {
2845 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
2846 goto loser;
2847 }
2848
2849 tmparena = PORT_NewArenaPORT_NewArena_Util(DER_DEFAULT_CHUNKSIZE(2048));
2850 if (tmparena == NULL((void*)0)) {
2851 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
2852 goto loser;
2853 }
2854
2855 entry = PORT_ArenaZNew(arena, certDBEntryVersion)(certDBEntryVersion *)PORT_ArenaZAlloc_Util(arena, sizeof(certDBEntryVersion
))
;
2856 if (entry == NULL((void*)0)) {
2857 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
2858 goto loser;
2859 }
2860 entry->common.arena = arena;
2861 entry->common.type = certDBEntryTypeVersion;
2862
2863 /* now get the database key and format it */
2864 dbkey.len = SEC_DB_VERSION_KEY_LENsizeof("Version") + SEC_DB_KEY_HEADER_LEN1;
2865 dbkey.data = (unsigned char *)PORT_ArenaAllocPORT_ArenaAlloc_Util(tmparena, dbkey.len);
2866 if (dbkey.data == NULL((void*)0)) {
2867 goto loser;
2868 }
2869 PORT_Memcpymemcpy(&dbkey.data[SEC_DB_KEY_HEADER_LEN1], SEC_DB_VERSION_KEY"Version",
2870 SEC_DB_VERSION_KEY_LENsizeof("Version"));
2871
2872 rv = ReadDBEntry(handle, &entry->common, &dbkey, &dbentry, tmparena);
2873 if (rv != SECSuccess) {
2874 goto loser;
2875 }
2876
2877 PORT_FreeArenaPORT_FreeArena_Util(tmparena, PR_FALSE0);
2878 return (entry);
2879
2880loser:
2881 if (tmparena) {
2882 PORT_FreeArenaPORT_FreeArena_Util(tmparena, PR_FALSE0);
2883 }
2884 if (arena) {
2885 PORT_FreeArenaPORT_FreeArena_Util(arena, PR_FALSE0);
2886 }
2887
2888 return (NULL((void*)0));
2889}
2890
2891/*
2892 * Encode a version entry into byte stream suitable for
2893 * the database
2894 */
2895static SECStatus
2896WriteDBVersionEntry(NSSLOWCERTCertDBHandle *handle, certDBEntryVersion *entry)
2897{
2898 SECItem dbitem, dbkey;
2899 PLArenaPool *tmparena = NULL((void*)0);
2900 SECStatus rv;
2901
2902 tmparena = PORT_NewArenaPORT_NewArena_Util(DER_DEFAULT_CHUNKSIZE(2048));
2903 if (tmparena == NULL((void*)0)) {
2904 goto loser;
2905 }
2906
2907 /* allocate space for encoded database record, including space
2908 * for low level header
2909 */
2910 dbitem.len = SEC_DB_ENTRY_HEADER_LEN3;
2911
2912 dbitem.data = (unsigned char *)PORT_ArenaAllocPORT_ArenaAlloc_Util(tmparena, dbitem.len);
2913 if (dbitem.data == NULL((void*)0)) {
2914 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
2915 goto loser;
2916 }
2917
2918 /* now get the database key and format it */
2919 dbkey.len = SEC_DB_VERSION_KEY_LENsizeof("Version") + SEC_DB_KEY_HEADER_LEN1;
2920 dbkey.data = (unsigned char *)PORT_ArenaAllocPORT_ArenaAlloc_Util(tmparena, dbkey.len);
2921 if (dbkey.data == NULL((void*)0)) {
2922 goto loser;
2923 }
2924 PORT_Memcpymemcpy(&dbkey.data[SEC_DB_KEY_HEADER_LEN1], SEC_DB_VERSION_KEY"Version",
2925 SEC_DB_VERSION_KEY_LENsizeof("Version"));
2926
2927 /* now write it to the database */
2928 rv = WriteDBEntry(handle, &entry->common, &dbkey, &dbitem);
2929 if (rv != SECSuccess) {
2930 goto loser;
2931 }
2932
2933 PORT_FreeArenaPORT_FreeArena_Util(tmparena, PR_FALSE0);
2934 return (SECSuccess);
2935
2936loser:
2937 if (tmparena) {
2938 PORT_FreeArenaPORT_FreeArena_Util(tmparena, PR_FALSE0);
2939 }
2940 return (SECFailure);
2941}
2942
2943/*
2944 * cert is no longer a perm cert, but will remain a temp cert
2945 */
2946static SECStatus
2947RemovePermSubjectNode(NSSLOWCERTCertificate *cert)
2948{
2949 certDBEntrySubject *entry;
2950 unsigned int i;
2951 SECStatus rv;
2952
2953 entry = ReadDBSubjectEntry(cert->dbhandle, &cert->derSubject);
2954 if (entry == NULL((void*)0)) {
2955 return (SECFailure);
2956 }
2957
2958 PORT_Assert(entry->ncerts)((entry->ncerts)?((void)0):PR_Assert("entry->ncerts","pcertdb.c"
,2958))
;
2959 rv = SECFailure;
2960
2961 if (entry->ncerts > 1) {
2962 for (i = 0; i < entry->ncerts; i++) {
2963 if (SECITEM_CompareItemSECITEM_CompareItem_Util(&entry->certKeys[i], &cert->certKey) ==
2964 SECEqual) {
2965 /* copy rest of list forward one entry */
2966 for (i = i + 1; i < entry->ncerts; i++) {
2967 entry->certKeys[i - 1] = entry->certKeys[i];
2968 entry->keyIDs[i - 1] = entry->keyIDs[i];
2969 }
2970 entry->ncerts--;
2971 DeleteDBSubjectEntry(cert->dbhandle, &cert->derSubject);
2972 rv = WriteDBSubjectEntry(cert->dbhandle, entry);
2973 break;
2974 }
2975 }
2976 } else {
2977 /* no entries left, delete the perm entry in the DB */
2978 if (entry->emailAddrs) {
2979 /* if the subject had an email record, then delete it too */
2980 for (i = 0; i < entry->nemailAddrs; i++) {
2981 DeleteDBSMimeEntry(cert->dbhandle, entry->emailAddrs[i]);
2982 }
2983 }
2984 if (entry->nickname) {
2985 DeleteDBNicknameEntry(cert->dbhandle, entry->nickname);
2986 }
2987
2988 DeleteDBSubjectEntry(cert->dbhandle, &cert->derSubject);
2989 }
2990 DestroyDBEntry((certDBEntry *)entry);
2991
2992 return (rv);
2993}
2994
2995/*
2996 * add a cert to the perm subject list
2997 */
2998static SECStatus
2999AddPermSubjectNode(certDBEntrySubject *entry, NSSLOWCERTCertificate *cert,
3000 char *nickname)
3001{
3002 SECItem *newCertKeys, *newKeyIDs;
3003 unsigned int i, new_i;
3004 SECStatus rv;
3005 unsigned int ncerts;
3006
3007 PORT_Assert(entry)((entry)?((void)0):PR_Assert("entry","pcertdb.c",3007));
3008 ncerts = entry->ncerts;
3009
3010 if (nickname && entry->nickname) {
3011 /* nicknames must be the same */
3012 PORT_Assert(PORT_Strcmp(nickname, entry->nickname) == 0)((strcmp(nickname, entry->nickname) == 0)?((void)0):PR_Assert
("PORT_Strcmp(nickname, entry->nickname) == 0","pcertdb.c"
,3012))
;
3013 }
3014
3015 if ((entry->nickname == NULL((void*)0)) && (nickname != NULL((void*)0))) {
3016 /* copy nickname into the entry */
3017 entry->nickname = PORT_ArenaStrdupPORT_ArenaStrdup_Util(entry->common.arena, nickname);
3018 if (entry->nickname == NULL((void*)0)) {
3019 return (SECFailure);
3020 }
3021 }
3022
3023 /* a DB entry already exists, so add this cert */
3024 newCertKeys = PORT_ArenaZNewArray(entry->common.arena, SECItem, ncerts + 1)(SECItem *)PORT_ArenaZAlloc_Util(entry->common.arena, sizeof
(SECItem) * (ncerts + 1))
;
3025 newKeyIDs = PORT_ArenaZNewArray(entry->common.arena, SECItem, ncerts + 1)(SECItem *)PORT_ArenaZAlloc_Util(entry->common.arena, sizeof
(SECItem) * (ncerts + 1))
;
3026
3027 if ((newCertKeys == NULL((void*)0)) || (newKeyIDs == NULL((void*)0))) {
3028 return (SECFailure);
3029 }
3030
3031 /* Step 1: copy certs older than "cert" into new entry. */
3032 for (i = 0, new_i = 0; i < ncerts; i++) {
3033 NSSLOWCERTCertificate *cmpcert;
3034 PRBool isNewer;
3035 cmpcert = nsslowcert_FindCertByKey(cert->dbhandle,
3036 &entry->certKeys[i]);
3037 /* The entry has been corrupted, remove it from the list */
3038 if (!cmpcert) {
3039 continue;
3040 }
3041
3042 isNewer = nsslowcert_IsNewer(cert, cmpcert);
3043 nsslowcert_DestroyCertificate(cmpcert);
3044 if (isNewer)
3045 break;
3046 /* copy this cert entry */
3047 newCertKeys[new_i] = entry->certKeys[i];
3048 newKeyIDs[new_i] = entry->keyIDs[i];
3049 new_i++;
3050 }
3051
3052 /* Step 2: Add "cert" to the entry. */
3053 rv = SECITEM_CopyItemSECITEM_CopyItem_Util(entry->common.arena, &newCertKeys[new_i],
3054 &cert->certKey);
3055 if (rv != SECSuccess) {
3056 return (SECFailure);
3057 }
3058 rv = SECITEM_CopyItemSECITEM_CopyItem_Util(entry->common.arena, &newKeyIDs[new_i],
3059 &cert->subjectKeyID);
3060 if (rv != SECSuccess) {
3061 return (SECFailure);
3062 }
3063 new_i++;
3064
3065 /* Step 3: copy remaining certs (if any) from old entry to new. */
3066 for (; i < ncerts; i++, new_i++) {
3067 newCertKeys[new_i] = entry->certKeys[i];
3068 newKeyIDs[new_i] = entry->keyIDs[i];
3069 }
3070
3071 /* update certKeys and keyIDs */
3072 entry->certKeys = newCertKeys;
3073 entry->keyIDs = newKeyIDs;
3074
3075 /* set new count value */
3076 entry->ncerts = new_i;
3077
3078 DeleteDBSubjectEntry(cert->dbhandle, &cert->derSubject);
3079 rv = WriteDBSubjectEntry(cert->dbhandle, entry);
3080 return (rv);
3081}
3082
3083SECStatus
3084nsslowcert_TraversePermCertsForSubject(NSSLOWCERTCertDBHandle *handle,
3085 SECItem *derSubject,
3086 NSSLOWCERTCertCallback cb, void *cbarg)
3087{
3088 certDBEntrySubject *entry;
3089 unsigned int i;
3090 NSSLOWCERTCertificate *cert;
3091 SECStatus rv = SECSuccess;
3092
3093 entry = ReadDBSubjectEntry(handle, derSubject);
3094
3095 if (entry == NULL((void*)0)) {
3096 return (SECFailure);
3097 }
3098
3099 for (i = 0; i < entry->ncerts; i++) {
3100 cert = nsslowcert_FindCertByKey(handle, &entry->certKeys[i]);
3101 if (!cert) {
3102 continue;
3103 }
3104 rv = (*cb)(cert, cbarg);
3105 nsslowcert_DestroyCertificate(cert);
3106 if (rv == SECFailure) {
3107 break;
3108 }
3109 }
3110
3111 DestroyDBEntry((certDBEntry *)entry);
3112
3113 return (rv);
3114}
3115
3116int
3117nsslowcert_NumPermCertsForSubject(NSSLOWCERTCertDBHandle *handle,
3118 SECItem *derSubject)
3119{
3120 certDBEntrySubject *entry;
3121 int ret;
3122
3123 entry = ReadDBSubjectEntry(handle, derSubject);
3124
3125 if (entry == NULL((void*)0)) {
3126 return (SECFailure);
3127 }
3128
3129 ret = entry->ncerts;
3130
3131 DestroyDBEntry((certDBEntry *)entry);
3132
3133 return (ret);
3134}
3135
3136SECStatus
3137nsslowcert_TraversePermCertsForNickname(NSSLOWCERTCertDBHandle *handle,
3138 char *nickname, NSSLOWCERTCertCallback cb, void *cbarg)
3139{
3140 certDBEntryNickname *nnentry = NULL((void*)0);
3141 certDBEntrySMime *smentry = NULL((void*)0);
3142 SECStatus rv;
3143 SECItem *derSubject = NULL((void*)0);
3144
3145 nnentry = ReadDBNicknameEntry(handle, nickname);
3146 if (nnentry) {
3147 derSubject = &nnentry->subjectName;
3148 } else {
3149 smentry = nsslowcert_ReadDBSMimeEntry(handle, nickname);
3150 if (smentry) {
3151 derSubject = &smentry->subjectName;
3152 }
3153 }
3154
3155 if (derSubject) {
3156 rv = nsslowcert_TraversePermCertsForSubject(handle, derSubject,
3157 cb, cbarg);
3158 } else {
3159 rv = SECFailure;
3160 }
3161
3162 if (nnentry) {
3163 DestroyDBEntry((certDBEntry *)nnentry);
3164 }
3165 if (smentry) {
3166 DestroyDBEntry((certDBEntry *)smentry);
3167 }
3168
3169 return (rv);
3170}
3171
3172int
3173nsslowcert_NumPermCertsForNickname(NSSLOWCERTCertDBHandle *handle,
3174 char *nickname)
3175{
3176 certDBEntryNickname *entry;
3177 int ret;
3178
3179 entry = ReadDBNicknameEntry(handle, nickname);
3180
3181 if (entry) {
3182 ret = nsslowcert_NumPermCertsForSubject(handle, &entry->subjectName);
3183 DestroyDBEntry((certDBEntry *)entry);
3184 } else {
3185 ret = 0;
3186 }
3187 return (ret);
3188}
3189
3190/*
3191 * add a nickname to a cert that doesn't have one
3192 */
3193static SECStatus
3194AddNicknameToPermCert(NSSLOWCERTCertDBHandle *dbhandle,
3195 NSSLOWCERTCertificate *cert, char *nickname)
3196{
3197 certDBEntryCert *entry;
3198 int rv;
3199
3200 entry = cert->dbEntry;
3201 PORT_Assert(entry != NULL)((entry != ((void*)0))?((void)0):PR_Assert("entry != NULL","pcertdb.c"
,3201))
;
3202 if (entry == NULL((void*)0)) {
3203 goto loser;
3204 }
3205
3206 pkcs11_freeNickname(entry->nickname, entry->nicknameSpace);
3207 entry->nickname = NULL((void*)0);
3208 entry->nickname = pkcs11_copyNickname(nickname, entry->nicknameSpace,
3209 sizeof(entry->nicknameSpace));
3210
3211 rv = WriteDBCertEntry(dbhandle, entry);
3212 if (rv) {
3213 goto loser;
3214 }
3215
3216 pkcs11_freeNickname(cert->nickname, cert->nicknameSpace);
3217 cert->nickname = NULL((void*)0);
3218 cert->nickname = pkcs11_copyNickname(nickname, cert->nicknameSpace,
3219 sizeof(cert->nicknameSpace));
3220
3221 return (SECSuccess);
3222
3223loser:
3224 return (SECFailure);
3225}
3226
3227/*
3228 * add a nickname to a cert that is already in the perm database, but doesn't
3229 * have one yet (it is probably an e-mail cert).
3230 */
3231SECStatus
3232nsslowcert_AddPermNickname(NSSLOWCERTCertDBHandle *dbhandle,
3233 NSSLOWCERTCertificate *cert, char *nickname)
3234{
3235 SECStatus rv = SECFailure;
3236 certDBEntrySubject *entry = NULL((void*)0);
3237 certDBEntryNickname *nicknameEntry = NULL((void*)0);
3238
3239 nsslowcert_LockDB(dbhandle);
3240
3241 entry = ReadDBSubjectEntry(dbhandle, &cert->derSubject);
3242 if (entry == NULL((void*)0))
3243 goto loser;
3244
3245 if (entry->nickname == NULL((void*)0)) {
3246
3247 /* no nickname for subject */
3248 rv = AddNicknameToSubject(dbhandle, cert, nickname);
3249 if (rv != SECSuccess) {
3250 goto loser;
3251 }
3252 rv = AddNicknameToPermCert(dbhandle, cert, nickname);
3253 if (rv != SECSuccess) {
3254 goto loser;
3255 }
3256 nicknameEntry = NewDBNicknameEntry(nickname, &cert->derSubject, 0);
3257 if (nicknameEntry == NULL((void*)0)) {
3258 goto loser;
3259 }
3260
3261 rv = WriteDBNicknameEntry(dbhandle, nicknameEntry);
3262 if (rv != SECSuccess) {
3263 goto loser;
3264 }
3265 } else {
3266 /* subject already has a nickname */
3267 rv = AddNicknameToPermCert(dbhandle, cert, entry->nickname);
3268 if (rv != SECSuccess) {
3269 goto loser;
3270 }
3271 /* make sure nickname entry exists. If the database was corrupted,
3272 * we may have lost the nickname entry. Add it back now */
3273 nicknameEntry = ReadDBNicknameEntry(dbhandle, entry->nickname);
3274 if (nicknameEntry == NULL((void*)0)) {
3275 nicknameEntry = NewDBNicknameEntry(entry->nickname,
3276 &cert->derSubject, 0);
3277 if (nicknameEntry == NULL((void*)0)) {
3278 goto loser;
3279 }
3280
3281 rv = WriteDBNicknameEntry(dbhandle, nicknameEntry);
3282 if (rv != SECSuccess) {
3283 goto loser;
3284 }
3285 }
3286 }
3287 rv = SECSuccess;
3288
3289loser:
3290 if (entry) {
3291 DestroyDBEntry((certDBEntry *)entry);
3292 }
3293 if (nicknameEntry) {
3294 DestroyDBEntry((certDBEntry *)nicknameEntry);
3295 }
3296 nsslowcert_UnlockDB(dbhandle);
3297 return (rv);
3298}
3299
3300static certDBEntryCert *
3301AddCertToPermDB(NSSLOWCERTCertDBHandle *handle, NSSLOWCERTCertificate *cert,
3302 char *nickname, NSSLOWCERTCertTrust *trust)
3303{
3304 certDBEntryCert *certEntry = NULL((void*)0);
3305 certDBEntryNickname *nicknameEntry = NULL((void*)0);
3306 certDBEntrySubject *subjectEntry = NULL((void*)0);
3307 int state = 0;
3308 SECStatus rv;
3309 PRBool donnentry = PR_FALSE0;
3310
3311 if (nickname) {
3312 donnentry = PR_TRUE1;
3313 }
3314
3315 subjectEntry = ReadDBSubjectEntry(handle, &cert->derSubject);
3316
3317 if (subjectEntry && subjectEntry->nickname) {
3318 donnentry = PR_FALSE0;
3319 nickname = subjectEntry->nickname;
3320 }
3321
3322 certEntry = NewDBCertEntry(&cert->derCert, nickname, trust, 0);
3323 if (certEntry == NULL((void*)0)) {
3324 goto loser;
3325 }
3326
3327 if (donnentry) {
3328 nicknameEntry = NewDBNicknameEntry(nickname, &cert->derSubject, 0);
3329 if (nicknameEntry == NULL((void*)0)) {
3330 goto loser;
3331 }
3332 }
3333
3334 rv = WriteDBCertEntry(handle, certEntry);
3335 if (rv != SECSuccess) {
3336 goto loser;
3337 }
3338 state = 1;
3339
3340 if (nicknameEntry) {
3341 rv = WriteDBNicknameEntry(handle, nicknameEntry);
3342 if (rv != SECSuccess) {
3343 goto loser;
3344 }
3345 }
3346
3347 state = 2;
3348
3349 /* "Change" handles if necessary */
3350 cert->dbhandle = handle;
3351
3352 /* add to or create new subject entry */
3353 if (subjectEntry) {
3354 /* REWRITE BASED ON SUBJECT ENTRY */
3355 rv = AddPermSubjectNode(subjectEntry, cert, nickname);
3356 if (rv != SECSuccess) {
3357 goto loser;
3358 }
3359 } else {
3360 /* make a new subject entry - this case is only used when updating
3361 * an old version of the database. This is OK because the oldnickname
3362 * db format didn't allow multiple certs with the same subject.
3363 */
3364 /* where does subjectKeyID and certKey come from? */
3365 subjectEntry = NewDBSubjectEntry(&cert->derSubject, &cert->certKey,
3366 &cert->subjectKeyID, nickname,
3367 NULL((void*)0), 0);
3368 if (subjectEntry == NULL((void*)0)) {
3369 goto loser;
3370 }
3371 rv = WriteDBSubjectEntry(handle, subjectEntry);
3372 if (rv != SECSuccess) {
3373 goto loser;
3374 }
3375 }
3376
3377 state = 3;
3378
3379 if (nicknameEntry) {
3380 DestroyDBEntry((certDBEntry *)nicknameEntry);
3381 }
3382
3383 if (subjectEntry) {
3384 DestroyDBEntry((certDBEntry *)subjectEntry);
3385 }
3386
3387 return (certEntry);
3388
3389loser:
3390 /* don't leave partial entry in the database */
3391 if (state > 0) {
3392 DeleteDBCertEntry(handle, &cert->certKey);
3393 }
3394 if ((state > 1) && donnentry) {
3395 DeleteDBNicknameEntry(handle, nickname);
3396 }
3397 if (certEntry) {
3398 DestroyDBEntry((certDBEntry *)certEntry);
3399 }
3400 if (nicknameEntry) {
3401 DestroyDBEntry((certDBEntry *)nicknameEntry);
3402 }
3403 if (subjectEntry) {
3404 DestroyDBEntry((certDBEntry *)subjectEntry);
3405 }
3406
3407 return (NULL((void*)0));
3408}
3409
3410/* forward declaration */
3411static SECStatus
3412UpdateV7DB(NSSLOWCERTCertDBHandle *handle, DB *updatedb);
3413
3414/*
3415 * version 8 uses the same schema as version 7. The only differences are
3416 * 1) version 8 db uses the blob shim to store data entries > 32k.
3417 * 2) version 8 db sets the db block size to 32k.
3418 * both of these are dealt with by the handle.
3419 */
3420
3421static SECStatus
3422UpdateV8DB(NSSLOWCERTCertDBHandle *handle, DB *updatedb)
3423{
3424 return UpdateV7DB(handle, updatedb);
3425}
3426
3427/*
3428 * we could just blindly sequence through reading key data pairs and writing
3429 * them back out, but some cert.db's have gotten quite large and may have some
3430 * subtle corruption problems, so instead we cycle through the certs and
3431 * CRL's and S/MIME profiles and rebuild our subject lists from those records.
3432 */
3433static SECStatus
3434UpdateV7DB(NSSLOWCERTCertDBHandle *handle, DB *updatedb)
3435{
3436 DBT key, data;
3437 int ret;
3438 NSSLOWCERTCertificate *cert;
3439 PRBool isKRL = PR_FALSE0;
3440 certDBEntryType entryType;
3441 SECItem dbEntry, dbKey;
3442 certDBEntryRevocation crlEntry;
3443 certDBEntryCert certEntry;
3444 certDBEntrySMime smimeEntry;
3445 SECStatus rv;
3446
3447 ret = (*updatedb->seq)(updatedb, &key, &data, R_FIRST3);
3448
3449 if (ret) {
3450 return (SECFailure);
3451 }
3452
3453 do {
3454 unsigned char *dataBuf = (unsigned char *)data.data;
3455 unsigned char *keyBuf = (unsigned char *)key.data;
3456 dbEntry.data = &dataBuf[SEC_DB_ENTRY_HEADER_LEN3];
3457 dbEntry.len = data.size - SEC_DB_ENTRY_HEADER_LEN3;
3458 entryType = (certDBEntryType)keyBuf[0];
3459 dbKey.data = &keyBuf[SEC_DB_KEY_HEADER_LEN1];
3460 dbKey.len = key.size - SEC_DB_KEY_HEADER_LEN1;
3461 if ((dbEntry.len <= 0) || (dbKey.len <= 0)) {
3462 continue;
3463 }
3464
3465 switch (entryType) {
3466 /* these entries will get regenerated as we read the
3467 * rest of the data from the database */
3468 case certDBEntryTypeVersion:
3469 case certDBEntryTypeSubject:
3470 case certDBEntryTypeContentVersion:
3471 case certDBEntryTypeNickname:
3472 /* smime profiles need entries created after the certs have
3473 * been imported, loop over them in a second run */
3474 case certDBEntryTypeSMimeProfile:
3475 break;
3476
3477 case certDBEntryTypeCert:
3478 /* decode Entry */
3479 certEntry.common.version = (unsigned int)dataBuf[0];
3480 certEntry.common.type = entryType;
3481 certEntry.common.flags = (unsigned int)dataBuf[2];
3482 rv = DecodeDBCertEntry(&certEntry, &dbEntry);
3483 if (rv != SECSuccess) {
3484 break;
3485 }
3486 /* should we check for existing duplicates? */
3487 cert = nsslowcert_DecodeDERCertificate(&certEntry.derCert,
3488 certEntry.nickname);
3489 if (cert) {
3490 nsslowcert_UpdatePermCert(handle, cert, certEntry.nickname,
3491 &certEntry.trust);
3492 nsslowcert_DestroyCertificate(cert);
3493 }
3494 /* free any data the decode may have allocated. */
3495 pkcs11_freeStaticData(certEntry.derCert.data,
3496 certEntry.derCertSpace);
3497 pkcs11_freeNickname(certEntry.nickname, certEntry.nicknameSpace);
3498 break;
3499
3500 case certDBEntryTypeKeyRevocation:
3501 isKRL = PR_TRUE1;
3502 /* fall through */
3503 case certDBEntryTypeRevocation:
3504 crlEntry.common.version = (unsigned int)dataBuf[0];
3505 crlEntry.common.type = entryType;
3506 crlEntry.common.flags = (unsigned int)dataBuf[2];
3507 crlEntry.common.arena = PORT_NewArenaPORT_NewArena_Util(DER_DEFAULT_CHUNKSIZE(2048));
3508 if (crlEntry.common.arena == NULL((void*)0)) {
3509 break;
3510 }
3511 rv = DecodeDBCrlEntry(&crlEntry, &dbEntry);
3512 if (rv != SECSuccess) {
3513 break;
3514 }
3515 nsslowcert_UpdateCrl(handle, &crlEntry.derCrl, &dbKey,
3516 crlEntry.url, isKRL);
3517 /* free data allocated by the decode */
3518 PORT_FreeArenaPORT_FreeArena_Util(crlEntry.common.arena, PR_FALSE0);
3519 crlEntry.common.arena = NULL((void*)0);
3520 break;
3521
3522 default:
3523 break;
3524 }
3525 } while ((*updatedb->seq)(updatedb, &key, &data, R_NEXT7) == 0);
3526
3527 /* now loop again updating just the SMimeProfile. */
3528 ret = (*updatedb->seq)(updatedb, &key, &data, R_FIRST3);
3529
3530 if (ret) {
3531 return (SECFailure);
3532 }
3533
3534 do {
3535 unsigned char *dataBuf = (unsigned char *)data.data;
3536 unsigned char *keyBuf = (unsigned char *)key.data;
3537 dbEntry.data = &dataBuf[SEC_DB_ENTRY_HEADER_LEN3];
3538 dbEntry.len = data.size - SEC_DB_ENTRY_HEADER_LEN3;
3539 entryType = (certDBEntryType)keyBuf[0];
3540 if (entryType != certDBEntryTypeSMimeProfile) {
3541 continue;
3542 }
3543 dbKey.data = &keyBuf[SEC_DB_KEY_HEADER_LEN1];
3544 dbKey.len = key.size - SEC_DB_KEY_HEADER_LEN1;
3545 if ((dbEntry.len <= 0) || (dbKey.len <= 0)) {
3546 continue;
3547 }
3548 smimeEntry.common.version = (unsigned int)dataBuf[0];
3549 smimeEntry.common.type = entryType;
3550 smimeEntry.common.flags = (unsigned int)dataBuf[2];
3551 smimeEntry.common.arena = PORT_NewArenaPORT_NewArena_Util(DER_DEFAULT_CHUNKSIZE(2048));
3552 /* decode entry */
3553 rv = DecodeDBSMimeEntry(&smimeEntry, &dbEntry, (char *)dbKey.data);
3554 if (rv == SECSuccess) {
3555 nsslowcert_UpdateSMimeProfile(handle, smimeEntry.emailAddr,
3556 &smimeEntry.subjectName, &smimeEntry.smimeOptions,
3557 &smimeEntry.optionsDate);
3558 }
3559 PORT_FreeArenaPORT_FreeArena_Util(smimeEntry.common.arena, PR_FALSE0);
3560 smimeEntry.common.arena = NULL((void*)0);
3561 } while ((*updatedb->seq)(updatedb, &key, &data, R_NEXT7) == 0);
3562
3563 (*updatedb->close)(updatedb);
3564
3565 /* a database update is a good time to go back and verify the integrity of
3566 * the keys and certs */
3567 handle->dbVerify = PR_TRUE1;
3568 return (SECSuccess);
3569}
3570
3571/*
3572 * NOTE - Version 6 DB did not go out to the real world in a release,
3573 * so we can remove this function in a later release.
3574 */
3575static SECStatus
3576UpdateV6DB(NSSLOWCERTCertDBHandle *handle, DB *updatedb)
3577{
3578 int ret;
3579 DBT key, data;
3580 unsigned char *buf, *tmpbuf = NULL((void*)0);
3581 certDBEntryType type;
3582 certDBEntryNickname *nnEntry = NULL((void*)0);
3583 certDBEntrySubject *subjectEntry = NULL((void*)0);
3584 certDBEntrySMime *emailEntry = NULL((void*)0);
3585 char *nickname;
3586 char *emailAddr;
3587
3588 /*
3589 * Sequence through the old database and copy all of the entries
3590 * to the new database. Subject name entries will have the new
3591 * fields inserted into them (with zero length).
3592 */
3593 ret = (*updatedb->seq)(updatedb, &key, &data, R_FIRST3);
3594 if (ret) {
3595 return (SECFailure);
3596 }
3597
3598 do {
3599 buf = (unsigned char *)data.data;
3600
3601 if (data.size >= 3) {
3602 if (buf[0] == 6) { /* version number */
3603 type = (certDBEntryType)buf[1];
3604 if (type == certDBEntryTypeSubject) {
3605 /* expando subjecto entrieo */
3606 tmpbuf = (unsigned char *)PORT_AllocPORT_Alloc_Util(data.size + 4);
3607 if (tmpbuf) {
3608 /* copy header stuff */
3609 PORT_Memcpymemcpy(tmpbuf, buf, SEC_DB_ENTRY_HEADER_LEN3 + 2);
3610 /* insert 4 more bytes of zero'd header */
3611 PORT_Memsetmemset(&tmpbuf[SEC_DB_ENTRY_HEADER_LEN3 + 2],
3612 0, 4);
3613 /* copy rest of the data */
3614 PORT_Memcpymemcpy(&tmpbuf[SEC_DB_ENTRY_HEADER_LEN3 + 6],
3615 &buf[SEC_DB_ENTRY_HEADER_LEN3 + 2],
3616 data.size - (SEC_DB_ENTRY_HEADER_LEN3 + 2));
3617
3618 data.data = (void *)tmpbuf;
3619 data.size += 4;
3620 buf = tmpbuf;
3621 }
3622 } else if (type == certDBEntryTypeCert) {
3623 /* expando certo entrieo */
3624 tmpbuf = (unsigned char *)PORT_AllocPORT_Alloc_Util(data.size + 3);
3625 if (tmpbuf) {
3626 /* copy header stuff */
3627 PORT_Memcpymemcpy(tmpbuf, buf, SEC_DB_ENTRY_HEADER_LEN3);
3628
3629 /* copy trust flage, setting msb's to 0 */
3630 tmpbuf[SEC_DB_ENTRY_HEADER_LEN3] = 0;
3631 tmpbuf[SEC_DB_ENTRY_HEADER_LEN3 + 1] =
3632 buf[SEC_DB_ENTRY_HEADER_LEN3];
3633 tmpbuf[SEC_DB_ENTRY_HEADER_LEN3 + 2] = 0;
3634 tmpbuf[SEC_DB_ENTRY_HEADER_LEN3 + 3] =
3635 buf[SEC_DB_ENTRY_HEADER_LEN3 + 1];
3636 tmpbuf[SEC_DB_ENTRY_HEADER_LEN3 + 4] = 0;
3637 tmpbuf[SEC_DB_ENTRY_HEADER_LEN3 + 5] =
3638 buf[SEC_DB_ENTRY_HEADER_LEN3 + 2];
3639
3640 /* copy rest of the data */
3641 PORT_Memcpymemcpy(&tmpbuf[SEC_DB_ENTRY_HEADER_LEN3 + 6],
3642 &buf[SEC_DB_ENTRY_HEADER_LEN3 + 3],
3643 data.size - (SEC_DB_ENTRY_HEADER_LEN3 + 3));
3644
3645 data.data = (void *)tmpbuf;
3646 data.size += 3;
3647 buf = tmpbuf;
3648 }
3649 }
3650
3651 /* update the record version number */
3652 buf[0] = CERT_DB_FILE_VERSION8;
3653
3654 /* copy to the new database */
3655 ret = certdb_Put(handle->permCertDB, &key, &data, 0);
3656 if (tmpbuf) {
3657 PORT_FreePORT_Free_Util(tmpbuf);
3658 tmpbuf = NULL((void*)0);
3659 }
3660 if (ret) {
3661 return SECFailure;
3662 }
3663 }
3664 }
3665 } while ((*updatedb->seq)(updatedb, &key, &data, R_NEXT7) == 0);
3666
3667 ret = certdb_Sync(handle->permCertDB, 0);
3668 if (ret) {
3669 return SECFailure;
3670 }
3671
3672 ret = (*updatedb->seq)(updatedb, &key, &data, R_FIRST3);
3673 if (ret) {
3674 return (SECFailure);
3675 }
3676
3677 do {
3678 buf = (unsigned char *)data.data;
3679
3680 if (data.size >= 3) {
3681 if (buf[0] == CERT_DB_FILE_VERSION8) { /* version number */
3682 type = (certDBEntryType)buf[1];
3683 if (type == certDBEntryTypeNickname) {
3684 nickname = &((char *)key.data)[1];
3685
3686 /* get the matching nickname entry in the new DB */
3687 nnEntry = ReadDBNicknameEntry(handle, nickname);
3688 if (nnEntry == NULL((void*)0)) {
3689 goto endloop;
3690 }
3691
3692 /* find the subject entry pointed to by nickname */
3693 subjectEntry = ReadDBSubjectEntry(handle,
3694 &nnEntry->subjectName);
3695 if (subjectEntry == NULL((void*)0)) {
3696 goto endloop;
3697 }
3698
3699 subjectEntry->nickname =
3700 (char *)PORT_ArenaAllocPORT_ArenaAlloc_Util(subjectEntry->common.arena,
3701 key.size - 1);
3702 if (subjectEntry->nickname) {
3703 PORT_Memcpymemcpy(subjectEntry->nickname, nickname,
3704 key.size - 1);
3705 (void)WriteDBSubjectEntry(handle, subjectEntry);
3706 }
3707 } else if (type == certDBEntryTypeSMimeProfile) {
3708 emailAddr = &((char *)key.data)[1];
3709
3710 /* get the matching smime entry in the new DB */
3711 emailEntry = nsslowcert_ReadDBSMimeEntry(handle, emailAddr);
3712 if (emailEntry == NULL((void*)0)) {
3713 goto endloop;
3714 }
3715
3716 /* find the subject entry pointed to by nickname */
3717 subjectEntry = ReadDBSubjectEntry(handle,
3718 &emailEntry->subjectName);
3719 if (subjectEntry == NULL((void*)0)) {
3720 goto endloop;
3721 }
3722
3723 subjectEntry->emailAddrs = (char **)
3724 PORT_ArenaAllocPORT_ArenaAlloc_Util(subjectEntry->common.arena,
3725 sizeof(char *));
3726 if (subjectEntry->emailAddrs) {
3727 subjectEntry->emailAddrs[0] =
3728 (char *)PORT_ArenaAllocPORT_ArenaAlloc_Util(subjectEntry->common.arena,
3729 key.size - 1);
3730 if (subjectEntry->emailAddrs[0]) {
3731 PORT_Memcpymemcpy(subjectEntry->emailAddrs[0], emailAddr,
3732 key.size - 1);
3733 subjectEntry->nemailAddrs = 1;
3734 (void)WriteDBSubjectEntry(handle, subjectEntry);
3735 }
3736 }
3737 }
3738
3739 endloop:
3740 if (subjectEntry) {
3741 DestroyDBEntry((certDBEntry *)subjectEntry);
3742 subjectEntry = NULL((void*)0);
3743 }
3744 if (nnEntry) {
3745 DestroyDBEntry((certDBEntry *)nnEntry);
3746 nnEntry = NULL((void*)0);
3747 }
3748 if (emailEntry) {
3749 DestroyDBEntry((certDBEntry *)emailEntry);
3750 emailEntry = NULL((void*)0);
3751 }
3752 }
3753 }
3754 } while ((*updatedb->seq)(updatedb, &key, &data, R_NEXT7) == 0);
3755
3756 ret = certdb_Sync(handle->permCertDB, 0);
3757 if (ret) {
3758 return SECFailure;
3759 }
3760
3761 (*updatedb->close)(updatedb);
3762 return (SECSuccess);
3763}
3764
3765static SECStatus
3766updateV5Callback(NSSLOWCERTCertificate *cert, SECItem *k, void *pdata)
3767{
3768 NSSLOWCERTCertDBHandle *handle;
3769 certDBEntryCert *entry;
3770 NSSLOWCERTCertTrust *trust;
3771
3772 handle = (NSSLOWCERTCertDBHandle *)pdata;
3773 trust = &cert->dbEntry->trust;
3774
3775 /* SSL user certs can be used for email if they have an email addr */
3776 if (cert->emailAddr && (trust->sslFlags & CERTDB_USER(1u << 6)) &&
3777 (trust->emailFlags == 0)) {
3778 trust->emailFlags = CERTDB_USER(1u << 6);
3779 }
3780 /* servers didn't set the user flags on the server cert.. */
3781 if (PORT_Strcmpstrcmp(cert->dbEntry->nickname, "Server-Cert") == 0) {
3782 trust->sslFlags |= CERTDB_USER(1u << 6);
3783 }
3784
3785 entry = AddCertToPermDB(handle, cert, cert->dbEntry->nickname,
3786 &cert->dbEntry->trust);
3787 if (entry) {
3788 DestroyDBEntry((certDBEntry *)entry);
3789 }
3790
3791 return (SECSuccess);
3792}
3793
3794static SECStatus
3795UpdateV5DB(NSSLOWCERTCertDBHandle *handle, DB *updatedb)
3796{
3797 NSSLOWCERTCertDBHandle updatehandle;
3798
3799 updatehandle.permCertDB = updatedb;
3800 updatehandle.dbMon = PZ_NewMonitor(nssILockCertDB)PR_NewMonitor();
3801 updatehandle.dbVerify = 0;
3802 updatehandle.ref = 1; /* prevent premature close */
3803
3804 (void)nsslowcert_TraversePermCerts(&updatehandle, updateV5Callback,
3805 (void *)handle);
3806
3807 PZ_DestroyMonitor(updatehandle.dbMon)PR_DestroyMonitor((updatehandle.dbMon));
3808
3809 (*updatedb->close)(updatedb);
3810 return (SECSuccess);
3811}
3812
3813static PRBool
3814isV4DB(DB *db)
3815{
3816 DBT key, data;
3817 int ret;
3818
3819 key.data = "Version";
3820 key.size = 7;
3821
3822 ret = (*db->get)(db, &key, &data, 0);
3823 if (ret) {
3824 return PR_FALSE0;
3825 }
3826
3827 if ((data.size == 1) && (*(unsigned char *)data.data <= 4)) {
3828 return PR_TRUE1;
3829 }
3830
3831 return PR_FALSE0;
3832}
3833
3834static SECStatus
3835UpdateV4DB(NSSLOWCERTCertDBHandle *handle, DB *updatedb)
3836{
3837 DBT key, data;
3838 certDBEntryCert *entry, *entry2;
3839 int ret;
3840 NSSLOWCERTCertificate *cert;
3841
3842 ret = (*updatedb->seq)(updatedb, &key, &data, R_FIRST3);
3843
3844 if (ret) {
3845 return (SECFailure);
3846 }
3847
3848 do {
3849 if (data.size != 1) { /* skip version number */
3850
3851 /* decode the old DB entry */
3852 entry = (certDBEntryCert *)
3853 DecodeV4DBCertEntry((unsigned char *)data.data, data.size);
3854
3855 if (entry) {
3856 cert = nsslowcert_DecodeDERCertificate(&entry->derCert,
3857 entry->nickname);
3858
3859 if (cert != NULL((void*)0)) {
3860 /* add to new database */
3861 entry2 = AddCertToPermDB(handle, cert, entry->nickname,
3862 &entry->trust);
3863
3864 nsslowcert_DestroyCertificate(cert);
3865 if (entry2) {
3866 DestroyDBEntry((certDBEntry *)entry2);
3867 }
3868 }
3869 DestroyDBEntry((certDBEntry *)entry);
3870 }
3871 }
3872 } while ((*updatedb->seq)(updatedb, &key, &data, R_NEXT7) == 0);
3873
3874 (*updatedb->close)(updatedb);
3875 return (SECSuccess);
3876}
3877
3878/*
3879 * return true if a database key conflict exists
3880 */
3881PRBool
3882nsslowcert_CertDBKeyConflict(SECItem *derCert, NSSLOWCERTCertDBHandle *handle)
3883{
3884 SECStatus rv;
3885 DBT tmpdata;
3886 DBT namekey;
3887 int ret;
3888 SECItem keyitem;
3889 PLArenaPool *arena = NULL((void*)0);
3890 SECItem derKey;
3891
3892 arena = PORT_NewArenaPORT_NewArena_Util(DER_DEFAULT_CHUNKSIZE(2048));
3893 if (arena == NULL((void*)0)) {
3894 goto loser;
3895 }
3896
3897 /* get the db key of the cert */
3898 rv = nsslowcert_KeyFromDERCert(arena, derCert, &derKey);
3899 if (rv != SECSuccess) {
3900 goto loser;
3901 }
3902
3903 rv = EncodeDBCertKey(&derKey, arena, &keyitem);
3904 if (rv != SECSuccess) {
3905 goto loser;
3906 }
3907
3908 namekey.data = keyitem.data;
3909 namekey.size = keyitem.len;
3910
3911 ret = certdb_Get(handle->permCertDB, &namekey, &tmpdata, 0);
3912 if (ret == 0) {
3913 goto loser;
3914 }
3915
3916 PORT_FreeArenaPORT_FreeArena_Util(arena, PR_FALSE0);
3917
3918 return (PR_FALSE0);
3919loser:
3920 if (arena) {
3921 PORT_FreeArenaPORT_FreeArena_Util(arena, PR_FALSE0);
3922 }
3923
3924 return (PR_TRUE1);
3925}
3926
3927/*
3928 * return true if a nickname conflict exists
3929 * NOTE: caller must have already made sure that this exact cert
3930 * doesn't exist in the DB
3931 */
3932static PRBool
3933nsslowcert_CertNicknameConflict(char *nickname, SECItem *derSubject,
3934 NSSLOWCERTCertDBHandle *handle)
3935{
3936 PRBool rv;
3937 certDBEntryNickname *entry;
3938
3939 if (nickname == NULL((void*)0)) {
3940 return (PR_FALSE0);
3941 }
3942
3943 entry = ReadDBNicknameEntry(handle, nickname);
3944
3945 if (entry == NULL((void*)0)) {
3946 /* no entry for this nickname, so no conflict */
3947 return (PR_FALSE0);
3948 }
3949
3950 rv = PR_TRUE1;
3951 if (SECITEM_CompareItemSECITEM_CompareItem_Util(derSubject, &entry->subjectName) == SECEqual) {
3952 /* if subject names are the same, then no conflict */
3953 rv = PR_FALSE0;
3954 }
3955
3956 DestroyDBEntry((certDBEntry *)entry);
3957 return (rv);
3958}
3959
3960#ifdef DBM_USING_NSPR
3961#define NO_RDONLY00 PR_RDONLY0x01
3962#define NO_RDWR02 PR_RDWR0x04
3963#define NO_CREATE(02 | 0100 | 01000) (PR_RDWR0x04 | PR_CREATE_FILE0x08 | PR_TRUNCATE0x20)
3964#else
3965#define NO_RDONLY00 O_RDONLY00
3966#define NO_RDWR02 O_RDWR02
3967#define NO_CREATE(02 | 0100 | 01000) (O_RDWR02 | O_CREAT0100 | O_TRUNC01000)
3968#endif
3969
3970/*
3971 * open an old database that needs to be updated
3972 */
3973static DB *
3974nsslowcert_openolddb(NSSLOWCERTDBNameFunc namecb, void *cbarg, int version)
3975{
3976 char *tmpname;
3977 DB *updatedb = NULL((void*)0);
3978
3979 tmpname = (*namecb)(cbarg, version); /* get v6 db name */
3980 if (tmpname) {
3981 updatedb = dbopen(tmpname, NO_RDONLY00, 0600, DB_HASH, 0);
3982 PORT_FreePORT_Free_Util(tmpname);
3983 }
3984 return updatedb;
3985}
3986
3987static SECStatus
3988openNewCertDB(const char *appName, const char *prefix, const char *certdbname,
3989 NSSLOWCERTCertDBHandle *handle, NSSLOWCERTDBNameFunc namecb, void *cbarg)
3990{
3991 SECStatus rv;
3992 certDBEntryVersion *versionEntry = NULL((void*)0);
3993 DB *updatedb = NULL((void*)0);
3994 int status = RDB_FAIL1;
3995
3996 if (appName) {
3997 handle->permCertDB = rdbopen(appName, prefix, "cert", NO_CREATE(02 | 0100 | 01000), &status);
3998 } else {
3999 handle->permCertDB = dbsopen(certdbname, NO_CREATE(02 | 0100 | 01000), 0600, DB_HASH, 0);
4000 }
4001
4002 /* if create fails then we lose */
4003 if (handle->permCertDB == 0) {
4004 return status == RDB_RETRY2 ? SECWouldBlock : SECFailure;
4005 }
4006
4007 /* Verify version number; */
4008 versionEntry = NewDBVersionEntry(0);
4009 if (versionEntry == NULL((void*)0)) {
4010 rv = SECFailure;
4011 goto loser;
4012 }
4013
4014 rv = WriteDBVersionEntry(handle, versionEntry);
4015
4016 DestroyDBEntry((certDBEntry *)versionEntry);
4017
4018 if (rv != SECSuccess) {
4019 goto loser;
4020 }
4021
4022 /* rv must already be Success here because of previous if statement */
4023 /* try to upgrade old db here */
4024 if (appName &&
4025 (updatedb = dbsopen(certdbname, NO_RDONLY00, 0600, DB_HASH, 0)) != NULL((void*)0)) {
4026 rv = UpdateV8DB(handle, updatedb);
4027 } else if ((updatedb = nsslowcert_openolddb(namecb, cbarg, 7)) != NULL((void*)0)) {
4028 rv = UpdateV7DB(handle, updatedb);
4029 } else if ((updatedb = nsslowcert_openolddb(namecb, cbarg, 6)) != NULL((void*)0)) {
4030 rv = UpdateV6DB(handle, updatedb);
4031 } else if ((updatedb = nsslowcert_openolddb(namecb, cbarg, 5)) != NULL((void*)0)) {
4032 rv = UpdateV5DB(handle, updatedb);
4033 } else if ((updatedb = nsslowcert_openolddb(namecb, cbarg, 4)) != NULL((void*)0)) {
4034 /* NES has v5 format db's with v4 db names! */
4035 if (isV4DB(updatedb)) {
4036 rv = UpdateV4DB(handle, updatedb);
4037 } else {
4038 rv = UpdateV5DB(handle, updatedb);
4039 }
4040 }
4041
4042loser:
4043 db_InitComplete(handle->permCertDB);
4044 return rv;
4045}
4046
4047static int
4048nsslowcert_GetVersionNumber(NSSLOWCERTCertDBHandle *handle)
4049{
4050 certDBEntryVersion *versionEntry = NULL((void*)0);
4051 int version = 0;
4052
4053 versionEntry = ReadDBVersionEntry(handle);
4054 if (versionEntry == NULL((void*)0)) {
4055 return 0;
4056 }
4057 version = versionEntry->common.version;
4058 DestroyDBEntry((certDBEntry *)versionEntry);
4059 return version;
4060}
4061
4062/*
4063 * Open the certificate database and index databases. Create them if
4064 * they are not there or bad.
4065 */
4066static SECStatus
4067nsslowcert_OpenPermCertDB(NSSLOWCERTCertDBHandle *handle, PRBool readOnly,
4068 const char *appName, const char *prefix,
4069 NSSLOWCERTDBNameFunc namecb, void *cbarg)
4070{
4071 SECStatus rv;
4072 int openflags;
4073 char *certdbname;
4074 int version = 0;
4075
4076 certdbname = (*namecb)(cbarg, CERT_DB_FILE_VERSION8);
4077 if (certdbname == NULL((void*)0)) {
4078 return (SECFailure);
4079 }
4080
4081 openflags = readOnly ? NO_RDONLY00 : NO_RDWR02;
4082
4083 /*
4084 * first open the permanent file based database.
4085 */
4086 if (appName) {
4087 handle->permCertDB = rdbopen(appName, prefix, "cert", openflags, NULL((void*)0));
4088 } else {
4089 handle->permCertDB = dbsopen(certdbname, openflags, 0600, DB_HASH, 0);
4090 }
4091
4092 /* check for correct version number */
4093 if (handle->permCertDB) {
4094 version = nsslowcert_GetVersionNumber(handle);
4095 if ((version != CERT_DB_FILE_VERSION8) &&
4096 !(appName && version == CERT_DB_V7_FILE_VERSION7)) {
4097 goto loser;
4098 }
4099 } else if (readOnly) {
4100 /* don't create if readonly */
4101 /* Try openning a version 7 database */
4102 handle->permCertDB = nsslowcert_openolddb(namecb, cbarg, 7);
4103 if (!handle->permCertDB) {
4104 goto loser;
4105 }
4106 if (nsslowcert_GetVersionNumber(handle) != 7) {
4107 goto loser;
4108 }
4109 } else {
4110 /* if first open fails, try to create a new DB */
4111 rv = openNewCertDB(appName, prefix, certdbname, handle, namecb, cbarg);
4112 if (rv == SECWouldBlock) {
4113 /* only the rdb version can fail with wouldblock */
4114 handle->permCertDB =
4115 rdbopen(appName, prefix, "cert", openflags, NULL((void*)0));
4116
4117 /* check for correct version number */
4118 if (!handle->permCertDB) {
4119 goto loser;
4120 }
4121 version = nsslowcert_GetVersionNumber(handle);
4122 if ((version != CERT_DB_FILE_VERSION8) &&
4123 !(appName && version == CERT_DB_V7_FILE_VERSION7)) {
4124 goto loser;
4125 }
4126 } else if (rv != SECSuccess) {
4127 goto loser;
4128 }
4129 }
4130
4131 PORT_FreePORT_Free_Util(certdbname);
4132
4133 return (SECSuccess);
4134
4135loser:
4136
4137 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_BAD_DATABASE);
4138
4139 if (handle->permCertDB) {
4140 certdb_Close(handle->permCertDB);
4141 handle->permCertDB = 0;
4142 }
4143
4144 PORT_FreePORT_Free_Util(certdbname);
4145
4146 return (SECFailure);
4147}
4148
4149/*
4150 * delete all DB records associated with a particular certificate
4151 */
4152static SECStatus
4153DeletePermCert(NSSLOWCERTCertificate *cert)
4154{
4155 SECStatus rv;
4156 SECStatus ret;
4157
4158 ret = SECSuccess;
4159
4160 rv = DeleteDBCertEntry(cert->dbhandle, &cert->certKey);
4161 if (rv != SECSuccess) {
4162 ret = SECFailure;
4163 }
4164
4165 rv = RemovePermSubjectNode(cert);
4166
4167 return (ret);
4168}
4169
4170/*
4171 * Delete a certificate from the permanent database.
4172 */
4173SECStatus
4174nsslowcert_DeletePermCertificate(NSSLOWCERTCertificate *cert)
4175{
4176 SECStatus rv;
4177
4178 nsslowcert_LockDB(cert->dbhandle);
4179
4180 /* delete the records from the permanent database */
4181 rv = DeletePermCert(cert);
4182
4183 /* get rid of dbcert and stuff pointing to it */
4184 DestroyDBEntry((certDBEntry *)cert->dbEntry);
4185 cert->dbEntry = NULL((void*)0);
4186 cert->trust = NULL((void*)0);
4187
4188 nsslowcert_UnlockDB(cert->dbhandle);
4189 return (rv);
4190}
4191
4192/*
4193 * Traverse all of the entries in the database of a particular type
4194 * call the given function for each one.
4195 */
4196SECStatus
4197nsslowcert_TraverseDBEntries(NSSLOWCERTCertDBHandle *handle,
4198 certDBEntryType type,
4199 SECStatus (*callback)(SECItem *data, SECItem *key,
4200 certDBEntryType type, void *pdata),
4201 void *udata)
4202{
4203 DBT data;
4204 DBT key;
4205 SECStatus rv = SECSuccess;
4206 int ret;
4207 SECItem dataitem;
4208 SECItem keyitem;
4209 unsigned char *buf;
4210 unsigned char *keybuf;
4211
4212 ret = certdb_Seq(handle->permCertDB, &key, &data, R_FIRST3);
4213 if (ret) {
4214 return (SECFailure);
4215 }
4216 /* here, ret is zero and rv is SECSuccess.
4217 * Below here, ret is a count of successful calls to the callback function.
4218 */
4219 do {
4220 buf = (unsigned char *)data.data;
4221
4222 if (buf[1] == (unsigned char)type) {
4223 dataitem.len = data.size;
4224 dataitem.data = buf;
4225 dataitem.type = siBuffer;
4226 keyitem.len = key.size - SEC_DB_KEY_HEADER_LEN1;
4227 keybuf = (unsigned char *)key.data;
4228 keyitem.data = &keybuf[SEC_DB_KEY_HEADER_LEN1];
4229 keyitem.type = siBuffer;
4230 /* type should equal keybuf[0]. */
4231
4232 rv = (*callback)(&dataitem, &keyitem, type, udata);
4233 if (rv == SECSuccess) {
4234 ++ret;
4235 }
4236 }
4237 } while (certdb_Seq(handle->permCertDB, &key, &data, R_NEXT7) == 0);
4238 /* If any callbacks succeeded, or no calls to callbacks were made,
4239 * then report success. Otherwise, report failure.
4240 */
4241 return (ret ? SECSuccess : rv);
4242}
4243/*
4244 * Decode a certificate and enter it into the temporary certificate database.
4245 * Deal with nicknames correctly
4246 *
4247 * This is the private entry point.
4248 */
4249static NSSLOWCERTCertificate *
4250DecodeACert(NSSLOWCERTCertDBHandle *handle, certDBEntryCert *entry)
4251{
4252 NSSLOWCERTCertificate *cert = NULL((void*)0);
4253
4254 cert = nsslowcert_DecodeDERCertificate(&entry->derCert, entry->nickname);
4255
4256 if (cert == NULL((void*)0)) {
4257 goto loser;
4258 }
4259
4260 cert->dbhandle = handle;
4261 cert->dbEntry = entry;
4262 cert->trust = &entry->trust;
4263
4264 return (cert);
4265
4266loser:
4267 return (0);
4268}
4269
4270static NSSLOWCERTTrust *
4271CreateTrust(void)
4272{
4273 NSSLOWCERTTrust *trust = NULL((void*)0);
4274
4275 nsslowcert_LockFreeList();
4276 trust = trustListHead;
4277 if (trust) {
4278 trustListCount--;
4279 trustListHead = trust->next;
4280 trust->next = NULL((void*)0);
4281 }
4282 PORT_Assert(trustListCount >= 0)((trustListCount >= 0)?((void)0):PR_Assert("trustListCount >= 0"
,"pcertdb.c",4282))
;
4283 nsslowcert_UnlockFreeList();
4284 if (trust) {
4285 return trust;
4286 }
4287
4288 return PORT_ZNew(NSSLOWCERTTrust)(NSSLOWCERTTrust *)PORT_ZAlloc_Util(sizeof(NSSLOWCERTTrust));
4289}
4290
4291static void
4292DestroyTrustFreeList(void)
4293{
4294 NSSLOWCERTTrust *trust;
4295
4296 nsslowcert_LockFreeList();
4297 while (NULL((void*)0) != (trust = trustListHead)) {
4298 trustListCount--;
4299 trustListHead = trust->next;
4300 PORT_FreePORT_Free_Util(trust);
4301 }
4302 PORT_Assert(!trustListCount)((!trustListCount)?((void)0):PR_Assert("!trustListCount","pcertdb.c"
,4302))
;
4303 trustListCount = 0;
4304 nsslowcert_UnlockFreeList();
4305}
4306
4307static NSSLOWCERTTrust *
4308DecodeTrustEntry(NSSLOWCERTCertDBHandle *handle, certDBEntryCert *entry,
4309 const SECItem *dbKey)
4310{
4311 NSSLOWCERTTrust *trust = CreateTrust();
4312 if (trust == NULL((void*)0)) {
4313 return trust;
4314 }
4315 trust->dbhandle = handle;
4316 trust->dbEntry = entry;
4317 trust->dbKey.data = pkcs11_copyStaticData(dbKey->data, dbKey->len,
4318 trust->dbKeySpace, sizeof(trust->dbKeySpace));
4319 if (!trust->dbKey.data) {
4320 PORT_FreePORT_Free_Util(trust);
4321 return NULL((void*)0);
4322 }
4323 trust->dbKey.len = dbKey->len;
4324
4325 trust->trust = &entry->trust;
4326 trust->derCert = &entry->derCert;
4327
4328 return (trust);
4329}
4330
4331typedef struct {
4332 PermCertCallback certfunc;
4333 NSSLOWCERTCertDBHandle *handle;
4334 void *data;
4335} PermCertCallbackState;
4336
4337/*
4338 * traversal callback to decode certs and call callers callback
4339 */
4340static SECStatus
4341certcallback(SECItem *dbdata, SECItem *dbkey, certDBEntryType type, void *data)
4342{
4343 PermCertCallbackState *mystate;
4344 SECStatus rv;
4345 certDBEntryCert *entry;
4346 SECItem entryitem;
4347 NSSLOWCERTCertificate *cert;
4348 PLArenaPool *arena = NULL((void*)0);
4349
4350 arena = PORT_NewArenaPORT_NewArena_Util(DER_DEFAULT_CHUNKSIZE(2048));
4351 if (arena == NULL((void*)0)) {
4352 goto loser;
4353 }
4354
4355 entry = (certDBEntryCert *)PORT_ArenaAllocPORT_ArenaAlloc_Util(arena, sizeof(certDBEntryCert));
4356 if (!entry) {
4357 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
4358 goto loser;
4359 }
4360 mystate = (PermCertCallbackState *)data;
4361 entry->common.version = (unsigned int)dbdata->data[0];
4362 entry->common.type = (certDBEntryType)dbdata->data[1];
4363 entry->common.flags = (unsigned int)dbdata->data[2];
4364 entry->common.arena = arena;
4365
4366 entryitem.len = dbdata->len - SEC_DB_ENTRY_HEADER_LEN3;
4367 entryitem.data = &dbdata->data[SEC_DB_ENTRY_HEADER_LEN3];
4368
4369 rv = DecodeDBCertEntry(entry, &entryitem);
4370 if (rv != SECSuccess) {
4371 goto loser;
4372 }
4373 entry->derCert.type = siBuffer;
4374
4375 /* note: Entry is 'inheritted'. */
4376 cert = DecodeACert(mystate->handle, entry);
4377
4378 rv = (*mystate->certfunc)(cert, dbkey, mystate->data);
4379
4380 /* arena stored in entry destroyed by nsslowcert_DestroyCertificate */
4381 nsslowcert_DestroyCertificateNoLocking(cert);
4382
4383 return (rv);
4384
4385loser:
4386 if (arena) {
4387 PORT_FreeArenaPORT_FreeArena_Util(arena, PR_FALSE0);
4388 }
4389 return (SECFailure);
4390}
4391
4392/*
4393 * Traverse all of the certificates in the permanent database and
4394 * call the given function for each one; expect the caller to have lock.
4395 */
4396static SECStatus
4397TraversePermCertsNoLocking(NSSLOWCERTCertDBHandle *handle,
4398 SECStatus (*certfunc)(NSSLOWCERTCertificate *cert,
4399 SECItem *k,
4400 void *pdata),
4401 void *udata)
4402{
4403 SECStatus rv;
4404 PermCertCallbackState mystate;
4405
4406 mystate.certfunc = certfunc;
4407 mystate.handle = handle;
4408 mystate.data = udata;
4409 rv = nsslowcert_TraverseDBEntries(handle, certDBEntryTypeCert, certcallback,
4410 (void *)&mystate);
4411
4412 return (rv);
4413}
4414
4415/*
4416 * Traverse all of the certificates in the permanent database and
4417 * call the given function for each one.
4418 */
4419SECStatus
4420nsslowcert_TraversePermCerts(NSSLOWCERTCertDBHandle *handle,
4421 SECStatus (*certfunc)(NSSLOWCERTCertificate *cert, SECItem *k,
4422 void *pdata),
4423 void *udata)
4424{
4425 SECStatus rv;
4426
4427 nsslowcert_LockDB(handle);
4428 rv = TraversePermCertsNoLocking(handle, certfunc, udata);
4429 nsslowcert_UnlockDB(handle);
4430
4431 return (rv);
4432}
4433
4434/*
4435 * Close the database
4436 */
4437void
4438nsslowcert_ClosePermCertDB(NSSLOWCERTCertDBHandle *handle)
4439{
4440 if (handle) {
4441 if (handle->permCertDB) {
4442 certdb_Close(handle->permCertDB);
4443 handle->permCertDB = NULL((void*)0);
4444 }
4445 if (handle->dbMon) {
4446 PZ_DestroyMonitor(handle->dbMon)PR_DestroyMonitor((handle->dbMon));
4447 handle->dbMon = NULL((void*)0);
4448 }
4449 PORT_FreePORT_Free_Util(handle);
4450 }
4451 return;
4452}
4453
4454/*
4455 * Get the trust attributes from a certificate
4456 */
4457SECStatus
4458nsslowcert_GetCertTrust(NSSLOWCERTCertificate *cert, NSSLOWCERTCertTrust *trust)
4459{
4460 SECStatus rv;
4461
4462 nsslowcert_LockCertTrust(cert);
4463
4464 if (cert->trust == NULL((void*)0)) {
4465 rv = SECFailure;
4466 } else {
4467 *trust = *cert->trust;
4468 rv = SECSuccess;
4469 }
4470
4471 nsslowcert_UnlockCertTrust(cert);
4472 return (rv);
4473}
4474
4475/*
4476 * Change the trust attributes of a certificate and make them permanent
4477 * in the database.
4478 */
4479SECStatus
4480nsslowcert_ChangeCertTrust(NSSLOWCERTCertDBHandle *handle,
4481 NSSLOWCERTCertificate *cert, NSSLOWCERTCertTrust *trust)
4482{
4483 certDBEntryCert *entry;
4484 int rv;
4485 SECStatus ret;
4486
4487 nsslowcert_LockDB(handle);
4488 nsslowcert_LockCertTrust(cert);
4489 /* only set the trust on permanent certs */
4490 if (cert->trust == NULL((void*)0)) {
4491 ret = SECFailure;
4492 goto done;
4493 }
4494
4495 *cert->trust = *trust;
4496 if (cert->dbEntry == NULL((void*)0)) {
4497 ret = SECSuccess; /* not in permanent database */
4498 goto done;
4499 }
4500
4501 entry = cert->dbEntry;
4502 entry->trust = *trust;
4503
4504 rv = WriteDBCertEntry(handle, entry);
4505 if (rv) {
4506 ret = SECFailure;
4507 goto done;
4508 }
4509
4510 ret = SECSuccess;
4511
4512done:
4513 nsslowcert_UnlockCertTrust(cert);
4514 nsslowcert_UnlockDB(handle);
4515 return (ret);
4516}
4517
4518static SECStatus
4519nsslowcert_UpdatePermCert(NSSLOWCERTCertDBHandle *dbhandle,
4520 NSSLOWCERTCertificate *cert, char *nickname, NSSLOWCERTCertTrust *trust)
4521{
4522 char *oldnn;
4523 certDBEntryCert *entry;
4524 PRBool conflict;
4525 SECStatus ret;
4526
4527 PORT_Assert(!cert->dbEntry)((!cert->dbEntry)?((void)0):PR_Assert("!cert->dbEntry",
"pcertdb.c",4527))
;
4528
4529 /* don't add a conflicting nickname */
4530 conflict = nsslowcert_CertNicknameConflict(nickname, &cert->derSubject,
4531 dbhandle);
4532 if (conflict) {
4533 ret = SECFailure;
4534 goto done;
4535 }
4536
4537 /* save old nickname so that we can delete it */
4538 oldnn = cert->nickname;
4539
4540 entry = AddCertToPermDB(dbhandle, cert, nickname, trust);
4541
4542 if (entry == NULL((void*)0)) {
4543 ret = SECFailure;
4544 goto done;
4545 }
4546
4547 pkcs11_freeNickname(oldnn, cert->nicknameSpace);
4548
4549 cert->nickname = (entry->nickname) ? pkcs11_copyNickname(entry->nickname,
4550 cert->nicknameSpace, sizeof(cert->nicknameSpace))
4551 : NULL((void*)0);
4552 cert->trust = &entry->trust;
4553 cert->dbEntry = entry;
4554
4555 ret = SECSuccess;
4556done:
4557 return (ret);
4558}
4559
4560SECStatus
4561nsslowcert_AddPermCert(NSSLOWCERTCertDBHandle *dbhandle,
4562 NSSLOWCERTCertificate *cert, char *nickname, NSSLOWCERTCertTrust *trust)
4563{
4564 SECStatus ret;
4565
4566 nsslowcert_LockDB(dbhandle);
4567
4568 ret = nsslowcert_UpdatePermCert(dbhandle, cert, nickname, trust);
4569
4570 nsslowcert_UnlockDB(dbhandle);
4571 return (ret);
4572}
4573
4574/*
4575 * Open the certificate database and index databases. Create them if
4576 * they are not there or bad.
4577 */
4578SECStatus
4579nsslowcert_OpenCertDB(NSSLOWCERTCertDBHandle *handle, PRBool readOnly,
4580 const char *appName, const char *prefix,
4581 NSSLOWCERTDBNameFunc namecb, void *cbarg, PRBool openVolatile)
4582{
4583 int rv;
4584
4585 certdb_InitDBLock(handle);
4586
4587 handle->dbMon = PZ_NewMonitor(nssILockCertDB)PR_NewMonitor();
4588 PORT_Assert(handle->dbMon != NULL)((handle->dbMon != ((void*)0))?((void)0):PR_Assert("handle->dbMon != NULL"
,"pcertdb.c",4588))
;
4589 handle->dbVerify = PR_FALSE0;
4590
4591 rv = nsslowcert_OpenPermCertDB(handle, readOnly, appName, prefix,
4592 namecb, cbarg);
4593 if (rv) {
4594 goto loser;
4595 }
4596
4597 return (SECSuccess);
4598
4599loser:
4600 if (handle->dbMon) {
4601 PZ_DestroyMonitor(handle->dbMon)PR_DestroyMonitor((handle->dbMon));
4602 handle->dbMon = NULL((void*)0);
4603 }
4604 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_BAD_DATABASE);
4605 return (SECFailure);
4606}
4607
4608PRBool
4609nsslowcert_needDBVerify(NSSLOWCERTCertDBHandle *handle)
4610{
4611 if (!handle)
4612 return PR_FALSE0;
4613 return handle->dbVerify;
4614}
4615
4616void
4617nsslowcert_setDBVerify(NSSLOWCERTCertDBHandle *handle, PRBool value)
4618{
4619 handle->dbVerify = value;
4620}
4621
4622/*
4623 * Lookup a certificate in the databases.
4624 */
4625static NSSLOWCERTCertificate *
4626FindCertByKey(NSSLOWCERTCertDBHandle *handle, const SECItem *certKey, PRBool lockdb)
4627{
4628 NSSLOWCERTCertificate *cert = NULL((void*)0);
4629 certDBEntryCert *entry;
4630 PRBool locked = PR_FALSE0;
4631
4632 if (lockdb) {
4633 locked = PR_TRUE1;
4634 nsslowcert_LockDB(handle);
4635 }
4636
4637 /* find in perm database */
4638 entry = ReadDBCertEntry(handle, certKey);
4639
4640 if (entry == NULL((void*)0)) {
4641 goto loser;
4642 }
4643
4644 /* inherit entry */
4645 cert = DecodeACert(handle, entry);
4646
4647loser:
4648 if (cert == NULL((void*)0)) {
4649 if (entry) {
4650 DestroyDBEntry((certDBEntry *)entry);
4651 }
4652 }
4653
4654 if (locked) {
4655 nsslowcert_UnlockDB(handle);
4656 }
4657
4658 return (cert);
4659}
4660
4661/*
4662 * Lookup a certificate in the databases.
4663 */
4664static NSSLOWCERTTrust *
4665FindTrustByKey(NSSLOWCERTCertDBHandle *handle, const SECItem *certKey, PRBool lockdb)
4666{
4667 NSSLOWCERTTrust *trust = NULL((void*)0);
4668 certDBEntryCert *entry;
4669 PRBool locked = PR_FALSE0;
4670
4671 if (lockdb) {
4672 locked = PR_TRUE1;
4673 nsslowcert_LockDB(handle);
4674 }
4675
4676 /* find in perm database */
4677 entry = ReadDBCertEntry(handle, certKey);
4678
4679 if (entry == NULL((void*)0)) {
4680 goto loser;
4681 }
4682
4683 if (!nsslowcert_hasTrust(&entry->trust)) {
4684 goto loser;
4685 }
4686
4687 /* inherit entry */
4688 trust = DecodeTrustEntry(handle, entry, certKey);
4689
4690loser:
4691 if (trust == NULL((void*)0)) {
4692 if (entry) {
4693 DestroyDBEntry((certDBEntry *)entry);
4694 }
4695 }
4696
4697 if (locked) {
4698 nsslowcert_UnlockDB(handle);
4699 }
4700
4701 return (trust);
4702}
4703
4704/*
4705 * Lookup a certificate in the databases without locking
4706 */
4707NSSLOWCERTCertificate *
4708nsslowcert_FindCertByKey(NSSLOWCERTCertDBHandle *handle, const SECItem *certKey)
4709{
4710 return (FindCertByKey(handle, certKey, PR_FALSE0));
4711}
4712
4713/*
4714 * Lookup a trust object in the databases without locking
4715 */
4716NSSLOWCERTTrust *
4717nsslowcert_FindTrustByKey(NSSLOWCERTCertDBHandle *handle, const SECItem *certKey)
4718{
4719 return (FindTrustByKey(handle, certKey, PR_FALSE0));
4720}
4721
4722/*
4723 * Generate a key from an issuerAndSerialNumber, and find the
4724 * associated cert in the database.
4725 */
4726NSSLOWCERTCertificate *
4727nsslowcert_FindCertByIssuerAndSN(NSSLOWCERTCertDBHandle *handle, NSSLOWCERTIssuerAndSN *issuerAndSN)
4728{
4729 SECItem certKey;
4730 SECItem *sn = &issuerAndSN->serialNumber;
4731 SECItem *issuer = &issuerAndSN->derIssuer;
4732 NSSLOWCERTCertificate *cert;
4733 int data_len = sn->len;
4734 int index = 0;
4735
4736 /* automatically detect DER encoded serial numbers and remove the der
4737 * encoding since the database expects unencoded data.
4738 * if it's DER encoded, there must be at least 3 bytes, tag, len, data */
4739 if ((sn->len >= 3) && (sn->data[0] == 0x2)) {
4740 /* remove the der encoding of the serial number before generating the
4741 * key.. */
4742 int data_left = sn->len - 2;
4743 data_len = sn->data[1];
4744 index = 2;
4745
4746 /* extended length ? (not very likely for a serial number) */
4747 if (data_len & 0x80) {
4748 int len_count = data_len & 0x7f;
4749
4750 data_len = 0;
4751 data_left -= len_count;
4752 if (data_left > 0) {
4753 while (len_count--) {
4754 data_len = (data_len << 8) | sn->data[index++];
4755 }
4756 }
4757 }
4758 /* XXX leaving any leading zeros on the serial number for backwards
4759 * compatibility
4760 */
4761 /* not a valid der, must be just an unlucky serial number value */
4762 if (data_len != data_left) {
4763 data_len = sn->len;
4764 index = 0;
4765 }
4766 }
4767
4768 certKey.type = 0;
4769 certKey.data = (unsigned char *)PORT_AllocPORT_Alloc_Util(sn->len + issuer->len);
4770 certKey.len = data_len + issuer->len;
4771
4772 if (certKey.data == NULL((void*)0)) {
4773 return (0);
4774 }
4775
4776 /* first try the serial number as hand-decoded above*/
4777 /* copy the serialNumber */
4778 PORT_Memcpymemcpy(certKey.data, &sn->data[index], data_len);
4779
4780 /* copy the issuer */
4781 PORT_Memcpymemcpy(&certKey.data[data_len], issuer->data, issuer->len);
4782
4783 cert = nsslowcert_FindCertByKey(handle, &certKey);
4784 if (cert) {
4785 PORT_FreePORT_Free_Util(certKey.data);
4786 return (cert);
4787 }
4788
4789 /* didn't find it, try by der encoded serial number */
4790 /* copy the serialNumber */
4791 PORT_Memcpymemcpy(certKey.data, sn->data, sn->len);
4792
4793 /* copy the issuer */
4794 PORT_Memcpymemcpy(&certKey.data[sn->len], issuer->data, issuer->len);
4795 certKey.len = sn->len + issuer->len;
4796
4797 cert = nsslowcert_FindCertByKey(handle, &certKey);
4798
4799 PORT_FreePORT_Free_Util(certKey.data);
4800
4801 return (cert);
4802}
4803
4804/*
4805 * Generate a key from an issuerAndSerialNumber, and find the
4806 * associated cert in the database.
4807 */
4808NSSLOWCERTTrust *
4809nsslowcert_FindTrustByIssuerAndSN(NSSLOWCERTCertDBHandle *handle,
4810 NSSLOWCERTIssuerAndSN *issuerAndSN)
4811{
4812 SECItem certKey;
4813 SECItem *sn = &issuerAndSN->serialNumber;
4814 SECItem *issuer = &issuerAndSN->derIssuer;
4815 NSSLOWCERTTrust *trust;
4816 unsigned char keyBuf[512];
4817 int data_len = sn->len;
4818 int index = 0;
4819 int len;
4820
4821 /* automatically detect DER encoded serial numbers and remove the der
4822 * encoding since the database expects unencoded data.
4823 * if it's DER encoded, there must be at least 3 bytes, tag, len, data */
4824 if ((sn->len >= 3) && (sn->data[0] == 0x2)) {
4825 /* remove the der encoding of the serial number before generating the
4826 * key.. */
4827 int data_left = sn->len - 2;
4828 data_len = sn->data[1];
4829 index = 2;
4830
4831 /* extended length ? (not very likely for a serial number) */
4832 if (data_len & 0x80) {
4833 int len_count = data_len & 0x7f;
4834
4835 data_len = 0;
4836 data_left -= len_count;
4837 if (data_left > 0) {
4838 while (len_count--) {
4839 data_len = (data_len << 8) | sn->data[index++];
4840 }
4841 }
4842 }
4843 /* XXX leaving any leading zeros on the serial number for backwards
4844 * compatibility
4845 */
4846 /* not a valid der, must be just an unlucky serial number value */
4847 if (data_len != data_left) {
4848 data_len = sn->len;
4849 index = 0;
4850 }
4851 }
4852
4853 certKey.type = 0;
4854 certKey.len = data_len + issuer->len;
4855 len = sn->len + issuer->len;
4856 if (len > sizeof(keyBuf)) {
4857 certKey.data = (unsigned char *)PORT_AllocPORT_Alloc_Util(len);
4858 } else {
4859 certKey.data = keyBuf;
4860 }
4861
4862 if (certKey.data == NULL((void*)0)) {
4863 return (0);
4864 }
4865
4866 /* first try the serial number as hand-decoded above*/
4867 /* copy the serialNumber */
4868 PORT_Memcpymemcpy(certKey.data, &sn->data[index], data_len);
4869
4870 /* copy the issuer */
4871 PORT_Memcpymemcpy(&certKey.data[data_len], issuer->data, issuer->len);
4872
4873 trust = nsslowcert_FindTrustByKey(handle, &certKey);
4874 if (trust) {
4875 pkcs11_freeStaticData(certKey.data, keyBuf);
4876 return (trust);
4877 }
4878
4879 if (index == 0) {
4880 pkcs11_freeStaticData(certKey.data, keyBuf);
4881 return NULL((void*)0);
4882 }
4883
4884 /* didn't find it, try by der encoded serial number */
4885 /* copy the serialNumber */
4886 PORT_Memcpymemcpy(certKey.data, sn->data, sn->len);
4887
4888 /* copy the issuer */
4889 PORT_Memcpymemcpy(&certKey.data[sn->len], issuer->data, issuer->len);
4890 certKey.len = sn->len + issuer->len;
4891
4892 trust = nsslowcert_FindTrustByKey(handle, &certKey);
4893
4894 pkcs11_freeStaticData(certKey.data, keyBuf);
4895
4896 return (trust);
4897}
4898
4899/*
4900 * look for the given DER certificate in the database
4901 */
4902NSSLOWCERTCertificate *
4903nsslowcert_FindCertByDERCert(NSSLOWCERTCertDBHandle *handle, SECItem *derCert)
4904{
4905 PLArenaPool *arena;
4906 SECItem certKey;
4907 SECStatus rv;
4908 NSSLOWCERTCertificate *cert = NULL((void*)0);
4909
4910 /* create a scratch arena */
4911 arena = PORT_NewArenaPORT_NewArena_Util(DER_DEFAULT_CHUNKSIZE(2048));
4912 if (arena == NULL((void*)0)) {
4913 return (NULL((void*)0));
4914 }
4915
4916 /* extract the database key from the cert */
4917 rv = nsslowcert_KeyFromDERCert(arena, derCert, &certKey);
4918 if (rv != SECSuccess) {
4919 goto loser;
4920 }
4921
4922 /* find the certificate */
4923 cert = nsslowcert_FindCertByKey(handle, &certKey);
4924
4925loser:
4926 PORT_FreeArenaPORT_FreeArena_Util(arena, PR_FALSE0);
4927 return (cert);
4928}
4929
4930static void
4931DestroyCertificate(NSSLOWCERTCertificate *cert, PRBool lockdb)
4932{
4933 int refCount;
4934 NSSLOWCERTCertDBHandle *handle;
4935
4936 if (cert) {
4937
4938 handle = cert->dbhandle;
4939
4940 /*
4941 * handle may be NULL, for example if the cert was created with
4942 * nsslowcert_DecodeDERCertificate.
4943 */
4944 if (lockdb && handle) {
4945 nsslowcert_LockDB(handle);
4946 }
4947
4948 nsslowcert_LockCertRefCount(cert);
4949 PORT_Assert(cert->referenceCount > 0)((cert->referenceCount > 0)?((void)0):PR_Assert("cert->referenceCount > 0"
,"pcertdb.c",4949))
;
4950 refCount = --cert->referenceCount;
4951 nsslowcert_UnlockCertRefCount(cert);
4952
4953 if (refCount == 0) {
4954 certDBEntryCert *entry = cert->dbEntry;
4955
4956 if (entry) {
4957 DestroyDBEntry((certDBEntry *)entry);
4958 }
4959
4960 pkcs11_freeNickname(cert->nickname, cert->nicknameSpace);
4961 pkcs11_freeNickname(cert->emailAddr, cert->emailAddrSpace);
4962 pkcs11_freeStaticData(cert->certKey.data, cert->certKeySpace);
4963 cert->certKey.data = NULL((void*)0);
4964 cert->nickname = NULL((void*)0);
4965
4966 /* zero cert before freeing. Any stale references to this cert
4967 * after this point will probably cause an exception. */
4968 PORT_Memsetmemset(cert, 0, sizeof *cert);
4969
4970 /* use reflock to protect the free list */
4971 nsslowcert_LockFreeList();
4972 if (certListCount > MAX_CERT_LIST_COUNT10) {
4973 PORT_FreePORT_Free_Util(cert);
4974 } else {
4975 certListCount++;
4976 cert->next = certListHead;
4977 certListHead = cert;
4978 }
4979 nsslowcert_UnlockFreeList();
4980 cert = NULL((void*)0);
4981 }
4982 if (lockdb && handle) {
4983 nsslowcert_UnlockDB(handle);
4984 }
4985 }
4986
4987 return;
4988}
4989
4990NSSLOWCERTCertificate *
4991nsslowcert_CreateCert(void)
4992{
4993 NSSLOWCERTCertificate *cert;
4994 nsslowcert_LockFreeList();
4995 cert = certListHead;
4996 if (cert) {
4997 certListHead = cert->next;
4998 certListCount--;
4999 }
5000 PORT_Assert(certListCount >= 0)((certListCount >= 0)?((void)0):PR_Assert("certListCount >= 0"
,"pcertdb.c",5000))
;
5001 nsslowcert_UnlockFreeList();
5002 if (cert) {
5003 return cert;
5004 }
5005 return PORT_ZNew(NSSLOWCERTCertificate)(NSSLOWCERTCertificate *)PORT_ZAlloc_Util(sizeof(NSSLOWCERTCertificate
))
;
5006}
5007
5008static void
5009DestroyCertFreeList(void)
5010{
5011 NSSLOWCERTCertificate *cert;
5012
5013 nsslowcert_LockFreeList();
5014 while (NULL((void*)0) != (cert = certListHead)) {
5015 certListCount--;
5016 certListHead = cert->next;
5017 PORT_FreePORT_Free_Util(cert);
5018 }
5019 PORT_Assert(!certListCount)((!certListCount)?((void)0):PR_Assert("!certListCount","pcertdb.c"
,5019))
;
5020 certListCount = 0;
5021 nsslowcert_UnlockFreeList();
5022}
5023
5024void
5025nsslowcert_DestroyTrust(NSSLOWCERTTrust *trust)
5026{
5027 certDBEntryCert *entry = trust->dbEntry;
5028
5029 if (entry) {
5030 DestroyDBEntry((certDBEntry *)entry);
5031 }
5032 pkcs11_freeStaticData(trust->dbKey.data, trust->dbKeySpace);
5033 PORT_Memsetmemset(trust, 0, sizeof(*trust));
5034
5035 nsslowcert_LockFreeList();
5036 if (trustListCount > MAX_TRUST_LIST_COUNT10) {
5037 PORT_FreePORT_Free_Util(trust);
5038 } else {
5039 trustListCount++;
5040 trust->next = trustListHead;
5041 trustListHead = trust;
5042 }
5043 nsslowcert_UnlockFreeList();
5044
5045 return;
5046}
5047
5048void
5049nsslowcert_DestroyCertificate(NSSLOWCERTCertificate *cert)
5050{
5051 DestroyCertificate(cert, PR_TRUE1);
5052 return;
5053}
5054
5055static void
5056nsslowcert_DestroyCertificateNoLocking(NSSLOWCERTCertificate *cert)
5057{
5058 DestroyCertificate(cert, PR_FALSE0);
5059 return;
5060}
5061
5062/*
5063 * Lookup a CRL in the databases. We mirror the same fast caching data base
5064 * caching stuff used by certificates....?
5065 */
5066certDBEntryRevocation *
5067nsslowcert_FindCrlByKey(NSSLOWCERTCertDBHandle *handle,
5068 SECItem *crlKey, PRBool isKRL)
5069{
5070 SECItem keyitem;
5071 SECStatus rv;
5072 PLArenaPool *arena = NULL((void*)0);
5073 certDBEntryRevocation *entry = NULL((void*)0);
5074 certDBEntryType crlType = isKRL ? certDBEntryTypeKeyRevocation
5075 : certDBEntryTypeRevocation;
5076
5077 arena = PORT_NewArenaPORT_NewArena_Util(DER_DEFAULT_CHUNKSIZE(2048));
5078 if (arena == NULL((void*)0)) {
5079 goto loser;
5080 }
5081
5082 rv = EncodeDBGenericKey(crlKey, arena, &keyitem, crlType);
5083 if (rv != SECSuccess) {
5084 goto loser;
5085 }
5086
5087 /* find in perm database */
5088 entry = ReadDBCrlEntry(handle, crlKey, crlType);
5089
5090 if (entry == NULL((void*)0)) {
5091 goto loser;
5092 }
5093
5094loser:
5095 if (arena) {
5096 PORT_FreeArenaPORT_FreeArena_Util(arena, PR_FALSE0);
5097 }
5098
5099 return entry;
5100}
5101
5102/*
5103 * replace the existing URL in the data base with a new one
5104 */
5105static SECStatus
5106nsslowcert_UpdateCrl(NSSLOWCERTCertDBHandle *handle, SECItem *derCrl,
5107 SECItem *crlKey, char *url, PRBool isKRL)
5108{
5109 SECStatus rv = SECFailure;
5110 certDBEntryRevocation *entry = NULL((void*)0);
5111 certDBEntryType crlType = isKRL ? certDBEntryTypeKeyRevocation
5112 : certDBEntryTypeRevocation;
5113 DeleteDBCrlEntry(handle, crlKey, crlType);
5114
5115 /* Write the new entry into the data base */
5116 entry = NewDBCrlEntry(derCrl, url, crlType, 0);
5117 if (entry == NULL((void*)0))
5118 goto done;
5119
5120 rv = WriteDBCrlEntry(handle, entry, crlKey);
5121 if (rv != SECSuccess)
5122 goto done;
5123
5124done:
5125 if (entry) {
5126 DestroyDBEntry((certDBEntry *)entry);
5127 }
5128 return rv;
5129}
5130
5131SECStatus
5132nsslowcert_AddCrl(NSSLOWCERTCertDBHandle *handle, SECItem *derCrl,
5133 SECItem *crlKey, char *url, PRBool isKRL)
5134{
5135 SECStatus rv;
5136
5137 rv = nsslowcert_UpdateCrl(handle, derCrl, crlKey, url, isKRL);
5138
5139 return rv;
5140}
5141
5142SECStatus
5143nsslowcert_DeletePermCRL(NSSLOWCERTCertDBHandle *handle, const SECItem *derName,
5144 PRBool isKRL)
5145{
5146 SECStatus rv;
5147 certDBEntryType crlType = isKRL ? certDBEntryTypeKeyRevocation
5148 : certDBEntryTypeRevocation;
5149
5150 rv = DeleteDBCrlEntry(handle, derName, crlType);
5151 if (rv != SECSuccess)
5152 goto done;
5153
5154done:
5155 return rv;
5156}
5157
5158PRBool
5159nsslowcert_hasTrust(NSSLOWCERTCertTrust *trust)
5160{
5161 if (trust == NULL((void*)0)) {
5162 return PR_FALSE0;
5163 }
5164 /* if we only have CERTDB__USER and CERTDB_TRUSTED_UNKNOWN bits, then
5165 * we don't have a trust record. */
5166 return !(((trust->sslFlags & ~(CERTDB_USER(1u << 6) | CERTDB_TRUSTED_UNKNOWN(1u << 11))) == 0) &&
5167 ((trust->emailFlags & ~(CERTDB_USER(1u << 6) | CERTDB_TRUSTED_UNKNOWN(1u << 11))) == 0) &&
5168 ((trust->objectSigningFlags & ~(CERTDB_USER(1u << 6) | CERTDB_TRUSTED_UNKNOWN(1u << 11))) == 0));
5169}
5170
5171/*
5172 * This function has the logic that decides if another person's cert and
5173 * email profile from an S/MIME message should be saved. It can deal with
5174 * the case when there is no profile.
5175 */
5176static SECStatus
5177nsslowcert_UpdateSMimeProfile(NSSLOWCERTCertDBHandle *dbhandle,
5178 char *emailAddr, SECItem *derSubject, SECItem *emailProfile,
5179 SECItem *profileTime)
5180{
5181 certDBEntrySMime *entry = NULL((void*)0);
5182 SECStatus rv = SECFailure;
5183 ;
5184
5185 /* find our existing entry */
5186 entry = nsslowcert_ReadDBSMimeEntry(dbhandle, emailAddr);
5187
5188 if (entry) {
5189 /* keep our old db entry consistant for old applications. */
5190 if (!SECITEM_ItemsAreEqualSECITEM_ItemsAreEqual_Util(derSubject, &entry->subjectName)) {
5191 nsslowcert_UpdateSubjectEmailAddr(dbhandle, &entry->subjectName,
5192 emailAddr, nsslowcert_remove);
5193 }
5194 DestroyDBEntry((certDBEntry *)entry);
5195 entry = NULL((void*)0);
5196 }
5197
5198 /* now save the entry */
5199 entry = NewDBSMimeEntry(emailAddr, derSubject, emailProfile,
5200 profileTime, 0);
5201 if (entry == NULL((void*)0)) {
5202 rv = SECFailure;
5203 goto loser;
5204 }
5205
5206 nsslowcert_LockDB(dbhandle);
5207
5208 rv = DeleteDBSMimeEntry(dbhandle, emailAddr);
Value stored to 'rv' is never read
5209 /* if delete fails, try to write new entry anyway... */
5210
5211 /* link subject entry back here */
5212 rv = nsslowcert_UpdateSubjectEmailAddr(dbhandle, derSubject, emailAddr,
5213 nsslowcert_add);
5214 if (rv != SECSuccess) {
5215 nsslowcert_UnlockDB(dbhandle);
5216 goto loser;
5217 }
5218
5219 rv = WriteDBSMimeEntry(dbhandle, entry);
5220 if (rv != SECSuccess) {
5221 nsslowcert_UnlockDB(dbhandle);
5222 goto loser;
5223 }
5224
5225 nsslowcert_UnlockDB(dbhandle);
5226
5227 rv = SECSuccess;
5228
5229loser:
5230 if (entry) {
5231 DestroyDBEntry((certDBEntry *)entry);
5232 }
5233 return (rv);
5234}
5235
5236SECStatus
5237nsslowcert_SaveSMimeProfile(NSSLOWCERTCertDBHandle *dbhandle, char *emailAddr,
5238 SECItem *derSubject, SECItem *emailProfile, SECItem *profileTime)
5239{
5240 SECStatus rv = SECFailure;
5241 ;
5242
5243 rv = nsslowcert_UpdateSMimeProfile(dbhandle, emailAddr,
5244 derSubject, emailProfile, profileTime);
5245
5246 return (rv);
5247}
5248
5249void
5250nsslowcert_DestroyFreeLists(void)
5251{
5252 if (freeListLock == NULL((void*)0)) {
5253 return;
5254 }
5255 DestroyCertEntryFreeList();
5256 DestroyTrustFreeList();
5257 DestroyCertFreeList();
5258 SKIP_AFTER_FORK(PZ_DestroyLock(freeListLock))if (!lg_parentForkedAfterC_Initialize) PR_DestroyLock((freeListLock
))
;
5259 freeListLock = NULL((void*)0);
5260}
5261
5262void
5263nsslowcert_DestroyGlobalLocks(void)
5264{
5265 if (dbLock) {
5266 SKIP_AFTER_FORK(PZ_DestroyLock(dbLock))if (!lg_parentForkedAfterC_Initialize) PR_DestroyLock((dbLock
))
;
5267 dbLock = NULL((void*)0);
5268 }
5269 if (certRefCountLock) {
5270 SKIP_AFTER_FORK(PZ_DestroyLock(certRefCountLock))if (!lg_parentForkedAfterC_Initialize) PR_DestroyLock((certRefCountLock
))
;
5271 certRefCountLock = NULL((void*)0);
5272 }
5273 if (certTrustLock) {
5274 SKIP_AFTER_FORK(PZ_DestroyLock(certTrustLock))if (!lg_parentForkedAfterC_Initialize) PR_DestroyLock((certTrustLock
))
;
5275 certTrustLock = NULL((void*)0);
5276 }
5277}
5278
5279certDBEntry *
5280nsslowcert_DecodeAnyDBEntry(SECItem *dbData, const SECItem *dbKey,
5281 certDBEntryType entryType, void *pdata)
5282{
5283 PLArenaPool *arena = NULL((void*)0);
5284 certDBEntry *entry;
5285 SECStatus rv;
5286 SECItem dbEntry;
5287
5288 if ((dbData->len < SEC_DB_ENTRY_HEADER_LEN3) || (dbKey->len == 0)) {
5289 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_INVALID_ARGS);
5290 goto loser;
5291 }
5292 dbEntry.data = &dbData->data[SEC_DB_ENTRY_HEADER_LEN3];
5293 dbEntry.len = dbData->len - SEC_DB_ENTRY_HEADER_LEN3;
5294
5295 arena = PORT_NewArenaPORT_NewArena_Util(DER_DEFAULT_CHUNKSIZE(2048));
5296 if (arena == NULL((void*)0)) {
5297 goto loser;
5298 }
5299 entry = PORT_ArenaZNew(arena, certDBEntry)(certDBEntry *)PORT_ArenaZAlloc_Util(arena, sizeof(certDBEntry
))
;
5300 if (!entry)
5301 goto loser;
5302
5303 entry->common.version = (unsigned int)dbData->data[0];
5304 entry->common.flags = (unsigned int)dbData->data[2];
5305 entry->common.type = entryType;
5306 entry->common.arena = arena;
5307
5308 switch (entryType) {
5309 case certDBEntryTypeContentVersion: /* This type appears to be unused */
5310 case certDBEntryTypeVersion: /* This type has only the common hdr */
5311 rv = SECSuccess;
5312 break;
5313
5314 case certDBEntryTypeSubject:
5315 rv = DecodeDBSubjectEntry(&entry->subject, &dbEntry, dbKey);
5316 break;
5317
5318 case certDBEntryTypeNickname:
5319 rv = DecodeDBNicknameEntry(&entry->nickname, &dbEntry,
5320 (char *)dbKey->data);
5321 break;
5322
5323 /* smime profiles need entries created after the certs have
5324 * been imported, loop over them in a second run */
5325 case certDBEntryTypeSMimeProfile:
5326 rv = DecodeDBSMimeEntry(&entry->smime, &dbEntry, (char *)dbKey->data);
5327 break;
5328
5329 case certDBEntryTypeCert:
5330 rv = DecodeDBCertEntry(&entry->cert, &dbEntry);
5331 break;
5332
5333 case certDBEntryTypeKeyRevocation:
5334 case certDBEntryTypeRevocation:
5335 rv = DecodeDBCrlEntry(&entry->revocation, &dbEntry);
5336 break;
5337
5338 default:
5339 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_INVALID_ARGS);
5340 rv = SECFailure;
5341 }
5342
5343 if (rv == SECSuccess)
5344 return entry;
5345
5346loser:
5347 if (arena)
5348 PORT_FreeArenaPORT_FreeArena_Util(arena, PR_FALSE0);
5349 return NULL((void*)0);
5350}