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