Bug Summary

File:security/nss/lib/softoken/legacydb/pcertdb.c
Location:line 3703, column 4
Description:Value stored to 'rv' is never read

Annotated Source Code

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