comparison nss/lib/softoken/legacydb/pcertdb.c @ 3:150b72113545

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