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/. */
6
* Permanent Certificate database handling code
8
* $Id: pcertdb.c,v 1.14 2012/12/12 19:25:36 wtc%google.com Exp $
20
/* forward declaration */
21
NSSLOWCERTCertificate *
22
nsslowcert_FindCertByDERCertNoLocking(NSSLOWCERTCertDBHandle *handle, SECItem *derCert);
24
nsslowcert_UpdateSMimeProfile(NSSLOWCERTCertDBHandle *dbhandle,
25
char *emailAddr, SECItem *derSubject, SECItem *emailProfile,
26
SECItem *profileTime);
28
nsslowcert_UpdatePermCert(NSSLOWCERTCertDBHandle *dbhandle,
29
NSSLOWCERTCertificate *cert, char *nickname, NSSLOWCERTCertTrust *trust);
31
nsslowcert_UpdateCrl(NSSLOWCERTCertDBHandle *handle, SECItem *derCrl,
32
SECItem *crlKey, char *url, PRBool isKRL);
34
static NSSLOWCERTCertificate *certListHead = NULL;
35
static NSSLOWCERTTrust *trustListHead = NULL;
36
static certDBEntryCert *entryListHead = NULL;
37
static int certListCount = 0;
38
static int trustListCount = 0;
39
static int entryListCount = 0;
40
#define MAX_CERT_LIST_COUNT 10
41
#define MAX_TRUST_LIST_COUNT 10
42
#define MAX_ENTRY_LIST_COUNT 10
45
* the following functions are wrappers for the db library that implement
46
* a global lock to make the database thread safe.
48
static PZLock *dbLock = NULL;
49
static PZLock *certRefCountLock = NULL;
50
static PZLock *certTrustLock = NULL;
51
static PZLock *freeListLock = NULL;
54
certdb_InitDBLock(NSSLOWCERTCertDBHandle *handle)
57
dbLock = PZ_NewLock(nssILockCertDB);
58
PORT_Assert(dbLock != NULL);
63
nsslowcert_InitLocks(void)
65
if (freeListLock == NULL) {
66
freeListLock = PZ_NewLock(nssILockRefLock);
67
if (freeListLock == NULL) {
71
if (certRefCountLock == NULL) {
72
certRefCountLock = PZ_NewLock(nssILockRefLock);
73
if (certRefCountLock == NULL) {
77
if (certTrustLock == NULL ) {
78
certTrustLock = PZ_NewLock(nssILockCertDB);
79
if (certTrustLock == NULL) {
88
* Acquire the global lock on the cert database.
89
* This lock is currently used for the following operations:
90
* adding or deleting a cert to either the temp or perm databases
91
* converting a temp to perm or perm to temp
92
* changing (maybe just adding!?) the trust of a cert
93
* chaning the DB status checking Configuration
96
nsslowcert_LockDB(NSSLOWCERTCertDBHandle *handle)
98
PZ_EnterMonitor(handle->dbMon);
103
* Free the global cert database lock.
106
nsslowcert_UnlockDB(NSSLOWCERTCertDBHandle *handle)
110
prstat = PZ_ExitMonitor(handle->dbMon);
112
PORT_Assert(prstat == PR_SUCCESS);
119
* Acquire the cert reference count lock
120
* There is currently one global lock for all certs, but I'm putting a cert
121
* arg here so that it will be easy to make it per-cert in the future if
122
* that turns out to be necessary.
125
nsslowcert_LockCertRefCount(NSSLOWCERTCertificate *cert)
127
PORT_Assert(certRefCountLock != NULL);
129
PZ_Lock(certRefCountLock);
134
* Free the cert reference count lock
137
nsslowcert_UnlockCertRefCount(NSSLOWCERTCertificate *cert)
141
PORT_Assert(certRefCountLock != NULL);
143
prstat = PZ_Unlock(certRefCountLock);
145
PORT_Assert(prstat == PR_SUCCESS);
151
* Acquire the cert trust lock
152
* There is currently one global lock for all certs, but I'm putting a cert
153
* arg here so that it will be easy to make it per-cert in the future if
154
* that turns out to be necessary.
157
nsslowcert_LockCertTrust(NSSLOWCERTCertificate *cert)
159
PORT_Assert(certTrustLock != NULL);
161
PZ_Lock(certTrustLock);
166
* Free the cert trust lock
169
nsslowcert_UnlockCertTrust(NSSLOWCERTCertificate *cert)
173
PORT_Assert(certTrustLock != NULL);
175
prstat = PZ_Unlock(certTrustLock);
177
PORT_Assert(prstat == PR_SUCCESS);
184
* Acquire the cert reference count lock
185
* There is currently one global lock for all certs, but I'm putting a cert
186
* arg here so that it will be easy to make it per-cert in the future if
187
* that turns out to be necessary.
190
nsslowcert_LockFreeList(void)
192
PORT_Assert(freeListLock != NULL);
194
SKIP_AFTER_FORK(PZ_Lock(freeListLock));
199
* Free the cert reference count lock
202
nsslowcert_UnlockFreeList(void)
204
PRStatus prstat = PR_SUCCESS;
206
PORT_Assert(freeListLock != NULL);
208
SKIP_AFTER_FORK(prstat = PZ_Unlock(freeListLock));
210
PORT_Assert(prstat == PR_SUCCESS);
215
NSSLOWCERTCertificate *
216
nsslowcert_DupCertificate(NSSLOWCERTCertificate *c)
219
nsslowcert_LockCertRefCount(c);
221
nsslowcert_UnlockCertRefCount(c);
227
certdb_Get(DB *db, DBT *key, DBT *data, unsigned int flags)
232
PORT_Assert(dbLock != NULL);
235
ret = (* db->get)(db, key, data, flags);
237
prstat = PZ_Unlock(dbLock);
243
certdb_Put(DB *db, DBT *key, DBT *data, unsigned int flags)
248
PORT_Assert(dbLock != NULL);
251
ret = (* db->put)(db, key, data, flags);
253
prstat = PZ_Unlock(dbLock);
259
certdb_Sync(DB *db, unsigned int flags)
264
PORT_Assert(dbLock != NULL);
267
ret = (* db->sync)(db, flags);
269
prstat = PZ_Unlock(dbLock);
274
#define DB_NOT_FOUND -30991 /* from DBM 3.2 */
276
certdb_Del(DB *db, DBT *key, unsigned int flags)
281
PORT_Assert(dbLock != NULL);
284
ret = (* db->del)(db, key, flags);
286
prstat = PZ_Unlock(dbLock);
288
/* don't fail if the record is already deleted */
289
if (ret == DB_NOT_FOUND) {
297
certdb_Seq(DB *db, DBT *key, DBT *data, unsigned int flags)
302
PORT_Assert(dbLock != NULL);
305
ret = (* db->seq)(db, key, data, flags);
307
prstat = PZ_Unlock(dbLock);
315
PRStatus prstat = PR_SUCCESS;
317
PORT_Assert(dbLock != NULL);
318
SKIP_AFTER_FORK(PZ_Lock(dbLock));
322
SKIP_AFTER_FORK(prstat = PZ_Unlock(dbLock));
328
pkcs11_freeNickname(char *nickname, char *space)
330
if (nickname && nickname != space) {
336
pkcs11_copyNickname(char *nickname,char *space, int spaceLen)
341
len = PORT_Strlen(nickname)+1;
342
if (len <= spaceLen) {
344
PORT_Memcpy(copy,nickname,len);
346
copy = PORT_Strdup(nickname);
353
pkcs11_freeStaticData (unsigned char *data, unsigned char *space)
355
if (data && data != space) {
361
pkcs11_allocStaticData(int len, unsigned char *space, int spaceLen)
363
unsigned char *data = NULL;
365
if (len <= spaceLen) {
368
data = (unsigned char *) PORT_Alloc(len);
375
pkcs11_copyStaticData(unsigned char *data, int len,
376
unsigned char *space, int spaceLen)
378
unsigned char *copy = pkcs11_allocStaticData(len, space, spaceLen);
380
PORT_Memcpy(copy,data,len);
387
* destroy a database entry
390
DestroyDBEntry(certDBEntry *entry)
392
PRArenaPool *arena = entry->common.arena;
394
/* must be one of our certDBEntry from the free list */
396
certDBEntryCert *certEntry;
397
if ( entry->common.type != certDBEntryTypeCert) {
400
certEntry = (certDBEntryCert *)entry;
402
pkcs11_freeStaticData(certEntry->derCert.data, certEntry->derCertSpace);
403
pkcs11_freeNickname(certEntry->nickname, certEntry->nicknameSpace);
405
nsslowcert_LockFreeList();
406
if (entryListCount > MAX_ENTRY_LIST_COUNT) {
407
PORT_Free(certEntry);
410
PORT_Memset(certEntry, 0, sizeof( *certEntry));
411
certEntry->next = entryListHead;
412
entryListHead = certEntry;
414
nsslowcert_UnlockFreeList();
419
/* Zero out the entry struct, so that any further attempts to use it
420
* will cause an exception (e.g. null pointer reference). */
421
PORT_Memset(&entry->common, 0, sizeof entry->common);
422
PORT_FreeArena(arena, PR_FALSE);
427
/* forward references */
428
static void nsslowcert_DestroyCertificateNoLocking(NSSLOWCERTCertificate *cert);
431
DeleteDBEntry(NSSLOWCERTCertDBHandle *handle, certDBEntryType type, SECItem *dbkey)
436
/* init the database key */
437
key.data = dbkey->data;
438
key.size = dbkey->len;
440
dbkey->data[0] = (unsigned char)type;
442
/* delete entry from database */
443
ret = certdb_Del(handle->permCertDB, &key, 0 );
445
PORT_SetError(SEC_ERROR_BAD_DATABASE);
449
ret = certdb_Sync(handle->permCertDB, 0);
451
PORT_SetError(SEC_ERROR_BAD_DATABASE);
462
ReadDBEntry(NSSLOWCERTCertDBHandle *handle, certDBEntryCommon *entry,
463
SECItem *dbkey, SECItem *dbentry, PRArenaPool *arena)
469
/* init the database key */
470
key.data = dbkey->data;
471
key.size = dbkey->len;
473
dbkey->data[0] = (unsigned char)entry->type;
475
/* read entry from database */
476
ret = certdb_Get(handle->permCertDB, &key, &data, 0 );
478
PORT_SetError(SEC_ERROR_BAD_DATABASE);
482
/* validate the entry */
483
if ( data.size < SEC_DB_ENTRY_HEADER_LEN ) {
484
PORT_SetError(SEC_ERROR_BAD_DATABASE);
487
buf = (unsigned char *)data.data;
488
/* version 7 has the same schema, we may be using a v7 db if we openned
489
* the databases readonly. */
490
if (!((buf[0] == (unsigned char)CERT_DB_FILE_VERSION)
491
|| (buf[0] == (unsigned char) CERT_DB_V7_FILE_VERSION))) {
492
PORT_SetError(SEC_ERROR_BAD_DATABASE);
495
if ( buf[1] != (unsigned char)entry->type ) {
496
PORT_SetError(SEC_ERROR_BAD_DATABASE);
500
/* copy out header information */
501
entry->version = (unsigned int)buf[0];
502
entry->type = (certDBEntryType)buf[1];
503
entry->flags = (unsigned int)buf[2];
505
/* format body of entry for return to caller */
506
dbentry->len = data.size - SEC_DB_ENTRY_HEADER_LEN;
507
if ( dbentry->len ) {
509
dbentry->data = (unsigned char *)
510
PORT_ArenaAlloc(arena, dbentry->len);
511
if ( dbentry->data == NULL ) {
512
PORT_SetError(SEC_ERROR_NO_MEMORY);
516
PORT_Memcpy(dbentry->data, &buf[SEC_DB_ENTRY_HEADER_LEN],
519
dbentry->data = &buf[SEC_DB_ENTRY_HEADER_LEN];
522
dbentry->data = NULL;
532
** Implement low level database access
535
WriteDBEntry(NSSLOWCERTCertDBHandle *handle, certDBEntryCommon *entry,
536
SECItem *dbkey, SECItem *dbentry)
542
data.data = dbentry->data;
543
data.size = dbentry->len;
545
buf = (unsigned char*)data.data;
547
buf[0] = (unsigned char)entry->version;
548
buf[1] = (unsigned char)entry->type;
549
buf[2] = (unsigned char)entry->flags;
551
key.data = dbkey->data;
552
key.size = dbkey->len;
554
dbkey->data[0] = (unsigned char)entry->type;
556
/* put the record into the database now */
557
ret = certdb_Put(handle->permCertDB, &key, &data, 0);
563
ret = certdb_Sync( handle->permCertDB, 0 );
576
* encode a database cert record
579
EncodeDBCertEntry(certDBEntryCert *entry, PRArenaPool *arena, SECItem *dbitem)
586
if ( entry->nickname ) {
587
nn = entry->nickname;
591
nnlen = PORT_Strlen(nn) + 1;
593
/* allocate space for encoded database record, including space
594
* for low level header
596
dbitem->len = entry->derCert.len + nnlen + DB_CERT_ENTRY_HEADER_LEN +
597
SEC_DB_ENTRY_HEADER_LEN;
599
dbitem->data = (unsigned char *)PORT_ArenaAlloc(arena, dbitem->len);
600
if ( dbitem->data == NULL) {
601
PORT_SetError(SEC_ERROR_NO_MEMORY);
605
/* fill in database record */
606
buf = &dbitem->data[SEC_DB_ENTRY_HEADER_LEN];
608
buf[0] = (PRUint8)( entry->trust.sslFlags >> 8 );
609
buf[1] = (PRUint8)( entry->trust.sslFlags );
610
buf[2] = (PRUint8)( entry->trust.emailFlags >> 8 );
611
buf[3] = (PRUint8)( entry->trust.emailFlags );
612
buf[4] = (PRUint8)( entry->trust.objectSigningFlags >> 8 );
613
buf[5] = (PRUint8)( entry->trust.objectSigningFlags );
614
buf[6] = (PRUint8)( entry->derCert.len >> 8 );
615
buf[7] = (PRUint8)( entry->derCert.len );
616
buf[8] = (PRUint8)( nnlen >> 8 );
617
buf[9] = (PRUint8)( nnlen );
619
PORT_Memcpy(&buf[DB_CERT_ENTRY_HEADER_LEN], entry->derCert.data,
622
PORT_Memcpy(&buf[DB_CERT_ENTRY_HEADER_LEN + entry->derCert.len],
632
* encode a database key for a cert record
635
EncodeDBCertKey(const SECItem *certKey, PRArenaPool *arena, SECItem *dbkey)
637
unsigned int len = certKey->len + SEC_DB_KEY_HEADER_LEN;
638
if (len > NSS_MAX_LEGACY_DB_KEY_SIZE)
641
dbkey->data = (unsigned char *)PORT_ArenaAlloc(arena, len);
643
if (dbkey->len < len) {
644
dbkey->data = (unsigned char *)PORT_Alloc(len);
648
if ( dbkey->data == NULL ) {
651
PORT_Memcpy(&dbkey->data[SEC_DB_KEY_HEADER_LEN],
652
certKey->data, certKey->len);
653
dbkey->data[0] = certDBEntryTypeCert;
661
EncodeDBGenericKey(const SECItem *certKey, PRArenaPool *arena, SECItem *dbkey,
662
certDBEntryType entryType)
665
* we only allow _one_ KRL key!
667
if (entryType == certDBEntryTypeKeyRevocation) {
668
dbkey->len = SEC_DB_KEY_HEADER_LEN;
669
dbkey->data = (unsigned char *)PORT_ArenaAlloc(arena, dbkey->len);
670
if ( dbkey->data == NULL ) {
673
dbkey->data[0] = (unsigned char) entryType;
678
dbkey->len = certKey->len + SEC_DB_KEY_HEADER_LEN;
679
if (dbkey->len > NSS_MAX_LEGACY_DB_KEY_SIZE)
681
dbkey->data = (unsigned char *)PORT_ArenaAlloc(arena, dbkey->len);
682
if ( dbkey->data == NULL ) {
685
PORT_Memcpy(&dbkey->data[SEC_DB_KEY_HEADER_LEN],
686
certKey->data, certKey->len);
687
dbkey->data[0] = (unsigned char) entryType;
695
DecodeDBCertEntry(certDBEntryCert *entry, SECItem *dbentry)
698
unsigned int headerlen;
701
/* allow updates of old versions of the database */
702
switch ( entry->common.version ) {
704
headerlen = DB_CERT_V5_ENTRY_HEADER_LEN;
708
/* should not get here */
710
headerlen = DB_CERT_V6_ENTRY_HEADER_LEN;
715
headerlen = DB_CERT_ENTRY_HEADER_LEN;
719
/* better not get here */
721
headerlen = DB_CERT_V5_ENTRY_HEADER_LEN;
726
/* is record long enough for header? */
727
if ( dbentry->len < headerlen ) {
728
PORT_SetError(SEC_ERROR_BAD_DATABASE);
732
/* is database entry correct length? */
733
entry->derCert.len = ( ( dbentry->data[lenoff] << 8 ) |
734
dbentry->data[lenoff+1] );
735
nnlen = ( ( dbentry->data[lenoff+2] << 8 ) | dbentry->data[lenoff+3] );
736
lenoff = dbentry->len - ( entry->derCert.len + nnlen + headerlen );
738
if ( lenoff < 0 || (lenoff & 0xffff) != 0 ) {
739
PORT_SetError(SEC_ERROR_BAD_DATABASE);
742
/* The cert size exceeded 64KB. Reconstruct the correct length. */
743
entry->derCert.len += lenoff;
746
/* copy the dercert */
747
entry->derCert.data = pkcs11_copyStaticData(&dbentry->data[headerlen],
748
entry->derCert.len,entry->derCertSpace,sizeof(entry->derCertSpace));
749
if ( entry->derCert.data == NULL ) {
750
PORT_SetError(SEC_ERROR_NO_MEMORY);
754
/* copy the nickname */
756
entry->nickname = (char *)pkcs11_copyStaticData(
757
&dbentry->data[headerlen+entry->derCert.len], nnlen,
758
(unsigned char *)entry->nicknameSpace,
759
sizeof(entry->nicknameSpace));
760
if ( entry->nickname == NULL ) {
761
PORT_SetError(SEC_ERROR_NO_MEMORY);
765
entry->nickname = NULL;
768
if ( entry->common.version < 7 ) {
769
/* allow updates of v5 db */
770
entry->trust.sslFlags = dbentry->data[0];
771
entry->trust.emailFlags = dbentry->data[1];
772
entry->trust.objectSigningFlags = dbentry->data[2];
774
entry->trust.sslFlags = ( dbentry->data[0] << 8 ) | dbentry->data[1];
775
entry->trust.emailFlags = ( dbentry->data[2] << 8 ) | dbentry->data[3];
776
entry->trust.objectSigningFlags =
777
( dbentry->data[4] << 8 ) | dbentry->data[5];
787
* Create a new certDBEntryCert from existing data
789
static certDBEntryCert *
790
NewDBCertEntry(SECItem *derCert, char *nickname,
791
NSSLOWCERTCertTrust *trust, int flags)
793
certDBEntryCert *entry;
794
PRArenaPool *arena = NULL;
797
arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE );
803
entry = PORT_ArenaZNew(arena, certDBEntryCert);
804
if ( entry == NULL ) {
808
/* fill in the dbCert */
809
entry->common.arena = arena;
810
entry->common.type = certDBEntryTypeCert;
811
entry->common.version = CERT_DB_FILE_VERSION;
812
entry->common.flags = flags;
815
entry->trust = *trust;
818
entry->derCert.data = (unsigned char *)PORT_ArenaAlloc(arena, derCert->len);
819
if ( !entry->derCert.data ) {
822
entry->derCert.len = derCert->len;
823
PORT_Memcpy(entry->derCert.data, derCert->data, derCert->len);
825
nnlen = ( nickname ? strlen(nickname) + 1 : 0 );
828
entry->nickname = (char *)PORT_ArenaAlloc(arena, nnlen);
829
if ( !entry->nickname ) {
832
PORT_Memcpy(entry->nickname, nickname, nnlen);
842
/* allocation error, free arena and return */
844
PORT_FreeArena(arena, PR_FALSE);
847
PORT_SetError(SEC_ERROR_NO_MEMORY);
852
* Decode a version 4 DBCert from the byte stream database format
853
* and construct a current database entry struct
855
static certDBEntryCert *
856
DecodeV4DBCertEntry(unsigned char *buf, int len)
858
certDBEntryCert *entry;
863
/* make sure length is at least long enough for the header */
864
if ( len < DBCERT_V4_HEADER_LEN ) {
865
PORT_SetError(SEC_ERROR_BAD_DATABASE);
869
/* get other lengths */
870
certlen = buf[3] << 8 | buf[4];
871
nnlen = buf[5] << 8 | buf[6];
873
/* make sure DB entry is the right size */
874
if ( ( certlen + nnlen + DBCERT_V4_HEADER_LEN ) != len ) {
875
PORT_SetError(SEC_ERROR_BAD_DATABASE);
880
arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE );
883
PORT_SetError(SEC_ERROR_NO_MEMORY);
887
/* allocate structure and members */
888
entry = (certDBEntryCert *) PORT_ArenaAlloc(arena, sizeof(certDBEntryCert));
894
entry->common.arena = arena;
895
entry->common.version = CERT_DB_FILE_VERSION;
896
entry->common.type = certDBEntryTypeCert;
897
entry->common.flags = 0;
898
entry->trust.sslFlags = buf[0];
899
entry->trust.emailFlags = buf[1];
900
entry->trust.objectSigningFlags = buf[2];
902
entry->derCert.data = (unsigned char *)PORT_ArenaAlloc(arena, certlen);
903
if ( !entry->derCert.data ) {
906
entry->derCert.len = certlen;
907
PORT_Memcpy(entry->derCert.data, &buf[DBCERT_V4_HEADER_LEN], certlen);
910
entry->nickname = (char *) PORT_ArenaAlloc(arena, nnlen);
911
if ( !entry->nickname ) {
914
PORT_Memcpy(entry->nickname, &buf[DBCERT_V4_HEADER_LEN + certlen], nnlen);
916
if (PORT_Strcmp(entry->nickname, "Server-Cert") == 0) {
917
entry->trust.sslFlags |= CERTDB_USER;
926
PORT_FreeArena(arena, PR_FALSE);
927
PORT_SetError(SEC_ERROR_NO_MEMORY);
932
* Encode a Certificate database entry into byte stream suitable for
936
WriteDBCertEntry(NSSLOWCERTCertDBHandle *handle, certDBEntryCert *entry)
938
SECItem dbitem, dbkey;
939
PRArenaPool *tmparena = NULL;
943
tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
944
if ( tmparena == NULL ) {
948
rv = EncodeDBCertEntry(entry, tmparena, &dbitem);
949
if ( rv != SECSuccess ) {
953
/* get the database key and format it */
954
rv = nsslowcert_KeyFromDERCert(tmparena, &entry->derCert, &tmpitem);
955
if ( rv == SECFailure ) {
959
rv = EncodeDBCertKey(&tmpitem, tmparena, &dbkey);
960
if ( rv == SECFailure ) {
964
/* now write it to the database */
965
rv = WriteDBEntry(handle, &entry->common, &dbkey, &dbitem);
966
if ( rv != SECSuccess ) {
970
PORT_FreeArena(tmparena, PR_FALSE);
975
PORT_FreeArena(tmparena, PR_FALSE);
982
* delete a certificate entry
985
DeleteDBCertEntry(NSSLOWCERTCertDBHandle *handle, SECItem *certKey)
993
rv = EncodeDBCertKey(certKey, NULL, &dbkey);
994
if ( rv != SECSuccess ) {
998
rv = DeleteDBEntry(handle, certDBEntryTypeCert, &dbkey);
999
if ( rv == SECFailure ) {
1003
PORT_Free(dbkey.data);
1009
PORT_Free(dbkey.data);
1014
static certDBEntryCert *
1015
CreateCertEntry(void)
1017
certDBEntryCert *entry;
1019
nsslowcert_LockFreeList();
1020
entry = entryListHead;
1023
entryListHead = entry->next;
1025
PORT_Assert(entryListCount >= 0);
1026
nsslowcert_UnlockFreeList();
1031
return PORT_ZNew(certDBEntryCert);
1035
DestroyCertEntryFreeList(void)
1037
certDBEntryCert *entry;
1039
nsslowcert_LockFreeList();
1040
while (NULL != (entry = entryListHead)) {
1042
entryListHead = entry->next;
1045
PORT_Assert(!entryListCount);
1047
nsslowcert_UnlockFreeList();
1051
* Read a certificate entry
1053
static certDBEntryCert *
1054
ReadDBCertEntry(NSSLOWCERTCertDBHandle *handle, const SECItem *certKey)
1056
certDBEntryCert *entry;
1060
unsigned char buf[512];
1063
dbkey.len = sizeof(buf);
1065
entry = CreateCertEntry();
1066
if ( entry == NULL ) {
1067
PORT_SetError(SEC_ERROR_NO_MEMORY);
1070
entry->common.arena = NULL;
1071
entry->common.type = certDBEntryTypeCert;
1073
rv = EncodeDBCertKey(certKey, NULL, &dbkey);
1074
if ( rv != SECSuccess ) {
1078
rv = ReadDBEntry(handle, &entry->common, &dbkey, &dbentry, NULL);
1079
if ( rv == SECFailure ) {
1083
rv = DecodeDBCertEntry(entry, &dbentry);
1084
if ( rv != SECSuccess ) {
1088
pkcs11_freeStaticData(dbkey.data,buf);
1093
pkcs11_freeStaticData(dbkey.data,buf);
1096
DestroyDBEntry((certDBEntry *)entry);
1103
* encode a database cert record
1106
EncodeDBCrlEntry(certDBEntryRevocation *entry, PRArenaPool *arena, SECItem *dbitem)
1108
unsigned int nnlen = 0;
1112
nnlen = PORT_Strlen(entry->url) + 1;
1115
/* allocate space for encoded database record, including space
1116
* for low level header
1118
dbitem->len = entry->derCrl.len + nnlen
1119
+ SEC_DB_ENTRY_HEADER_LEN + DB_CRL_ENTRY_HEADER_LEN;
1121
dbitem->data = (unsigned char *)PORT_ArenaAlloc(arena, dbitem->len);
1122
if ( dbitem->data == NULL) {
1123
PORT_SetError(SEC_ERROR_NO_MEMORY);
1127
/* fill in database record */
1128
buf = &dbitem->data[SEC_DB_ENTRY_HEADER_LEN];
1130
buf[0] = (PRUint8)( entry->derCrl.len >> 8 );
1131
buf[1] = (PRUint8)( entry->derCrl.len );
1132
buf[2] = (PRUint8)( nnlen >> 8 );
1133
buf[3] = (PRUint8)( nnlen );
1135
PORT_Memcpy(&buf[DB_CRL_ENTRY_HEADER_LEN], entry->derCrl.data,
1139
PORT_Memcpy(&buf[DB_CRL_ENTRY_HEADER_LEN + entry->derCrl.len],
1150
DecodeDBCrlEntry(certDBEntryRevocation *entry, SECItem *dbentry)
1152
unsigned int urlLen;
1155
/* is record long enough for header? */
1156
if ( dbentry->len < DB_CRL_ENTRY_HEADER_LEN ) {
1157
PORT_SetError(SEC_ERROR_BAD_DATABASE);
1161
/* is database entry correct length? */
1162
entry->derCrl.len = ( ( dbentry->data[0] << 8 ) | dbentry->data[1] );
1163
urlLen = ( ( dbentry->data[2] << 8 ) | dbentry->data[3] );
1164
lenDiff = dbentry->len -
1165
(entry->derCrl.len + urlLen + DB_CRL_ENTRY_HEADER_LEN);
1167
if (lenDiff < 0 || (lenDiff & 0xffff) != 0) {
1168
PORT_SetError(SEC_ERROR_BAD_DATABASE);
1171
/* CRL entry is greater than 64 K. Hack to make this continue to work */
1172
entry->derCrl.len += lenDiff;
1175
/* copy the der CRL */
1176
entry->derCrl.data = (unsigned char *)PORT_ArenaAlloc(entry->common.arena,
1178
if ( entry->derCrl.data == NULL ) {
1179
PORT_SetError(SEC_ERROR_NO_MEMORY);
1182
PORT_Memcpy(entry->derCrl.data, &dbentry->data[DB_CRL_ENTRY_HEADER_LEN],
1188
entry->url = (char *)PORT_ArenaAlloc(entry->common.arena, urlLen);
1189
if ( entry->url == NULL ) {
1190
PORT_SetError(SEC_ERROR_NO_MEMORY);
1193
PORT_Memcpy(entry->url,
1194
&dbentry->data[DB_CRL_ENTRY_HEADER_LEN + entry->derCrl.len],
1204
* Create a new certDBEntryRevocation from existing data
1206
static certDBEntryRevocation *
1207
NewDBCrlEntry(SECItem *derCrl, char * url, certDBEntryType crlType, int flags)
1209
certDBEntryRevocation *entry;
1210
PRArenaPool *arena = NULL;
1213
arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE );
1219
entry = PORT_ArenaZNew(arena, certDBEntryRevocation);
1220
if ( entry == NULL ) {
1224
/* fill in the dbRevolcation */
1225
entry->common.arena = arena;
1226
entry->common.type = crlType;
1227
entry->common.version = CERT_DB_FILE_VERSION;
1228
entry->common.flags = flags;
1231
entry->derCrl.data = (unsigned char *)PORT_ArenaAlloc(arena, derCrl->len);
1232
if ( !entry->derCrl.data ) {
1237
nnlen = PORT_Strlen(url) + 1;
1238
entry->url = (char *)PORT_ArenaAlloc(arena, nnlen);
1239
if ( !entry->url ) {
1242
PORT_Memcpy(entry->url, url, nnlen);
1248
entry->derCrl.len = derCrl->len;
1249
PORT_Memcpy(entry->derCrl.data, derCrl->data, derCrl->len);
1255
/* allocation error, free arena and return */
1257
PORT_FreeArena(arena, PR_FALSE);
1260
PORT_SetError(SEC_ERROR_NO_MEMORY);
1266
WriteDBCrlEntry(NSSLOWCERTCertDBHandle *handle, certDBEntryRevocation *entry,
1270
PRArenaPool *tmparena = NULL;
1271
SECItem encodedEntry;
1274
tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1275
if ( tmparena == NULL ) {
1279
rv = EncodeDBCrlEntry(entry, tmparena, &encodedEntry);
1280
if ( rv == SECFailure ) {
1284
rv = EncodeDBGenericKey(crlKey, tmparena, &dbkey, entry->common.type);
1285
if ( rv == SECFailure ) {
1289
/* now write it to the database */
1290
rv = WriteDBEntry(handle, &entry->common, &dbkey, &encodedEntry);
1291
if ( rv != SECSuccess ) {
1295
PORT_FreeArena(tmparena, PR_FALSE);
1300
PORT_FreeArena(tmparena, PR_FALSE);
1305
* delete a crl entry
1308
DeleteDBCrlEntry(NSSLOWCERTCertDBHandle *handle, const SECItem *crlKey,
1309
certDBEntryType crlType)
1312
PRArenaPool *arena = NULL;
1315
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1316
if ( arena == NULL ) {
1320
rv = EncodeDBGenericKey(crlKey, arena, &dbkey, crlType);
1321
if ( rv != SECSuccess ) {
1325
rv = DeleteDBEntry(handle, crlType, &dbkey);
1326
if ( rv == SECFailure ) {
1330
PORT_FreeArena(arena, PR_FALSE);
1335
PORT_FreeArena(arena, PR_FALSE);
1342
* Read a certificate entry
1344
static certDBEntryRevocation *
1345
ReadDBCrlEntry(NSSLOWCERTCertDBHandle *handle, SECItem *certKey,
1346
certDBEntryType crlType)
1348
PRArenaPool *arena = NULL;
1349
PRArenaPool *tmparena = NULL;
1350
certDBEntryRevocation *entry;
1355
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1356
if ( arena == NULL ) {
1357
PORT_SetError(SEC_ERROR_NO_MEMORY);
1361
tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1362
if ( tmparena == NULL ) {
1363
PORT_SetError(SEC_ERROR_NO_MEMORY);
1367
entry = (certDBEntryRevocation *)
1368
PORT_ArenaAlloc(arena, sizeof(certDBEntryRevocation));
1369
if ( entry == NULL ) {
1370
PORT_SetError(SEC_ERROR_NO_MEMORY);
1373
entry->common.arena = arena;
1374
entry->common.type = crlType;
1376
rv = EncodeDBGenericKey(certKey, tmparena, &dbkey, crlType);
1377
if ( rv != SECSuccess ) {
1381
rv = ReadDBEntry(handle, &entry->common, &dbkey, &dbentry, NULL);
1382
if ( rv == SECFailure ) {
1386
rv = DecodeDBCrlEntry(entry, &dbentry);
1387
if ( rv != SECSuccess ) {
1391
PORT_FreeArena(tmparena, PR_FALSE);
1396
PORT_FreeArena(tmparena, PR_FALSE);
1399
PORT_FreeArena(arena, PR_FALSE);
1406
nsslowcert_DestroyDBEntry(certDBEntry *entry)
1408
DestroyDBEntry(entry);
1413
* Encode a database nickname record
1416
EncodeDBNicknameEntry(certDBEntryNickname *entry, PRArenaPool *arena,
1421
/* allocate space for encoded database record, including space
1422
* for low level header
1424
dbitem->len = entry->subjectName.len + DB_NICKNAME_ENTRY_HEADER_LEN +
1425
SEC_DB_ENTRY_HEADER_LEN;
1426
dbitem->data = (unsigned char *)PORT_ArenaAlloc(arena, dbitem->len);
1427
if ( dbitem->data == NULL) {
1431
/* fill in database record */
1432
buf = &dbitem->data[SEC_DB_ENTRY_HEADER_LEN];
1433
buf[0] = (PRUint8)( entry->subjectName.len >> 8 );
1434
buf[1] = (PRUint8)( entry->subjectName.len );
1435
PORT_Memcpy(&buf[DB_NICKNAME_ENTRY_HEADER_LEN], entry->subjectName.data,
1436
entry->subjectName.len);
1445
* Encode a database key for a nickname record
1448
EncodeDBNicknameKey(char *nickname, PRArenaPool *arena,
1453
nnlen = PORT_Strlen(nickname) + 1; /* includes null */
1455
/* now get the database key and format it */
1456
dbkey->len = nnlen + SEC_DB_KEY_HEADER_LEN;
1457
if (dbkey->len > NSS_MAX_LEGACY_DB_KEY_SIZE)
1459
dbkey->data = (unsigned char *)PORT_ArenaAlloc(arena, dbkey->len);
1460
if ( dbkey->data == NULL ) {
1463
PORT_Memcpy(&dbkey->data[SEC_DB_KEY_HEADER_LEN], nickname, nnlen);
1464
dbkey->data[0] = certDBEntryTypeNickname;
1473
DecodeDBNicknameEntry(certDBEntryNickname *entry, SECItem *dbentry,
1478
/* is record long enough for header? */
1479
if ( dbentry->len < DB_NICKNAME_ENTRY_HEADER_LEN ) {
1480
PORT_SetError(SEC_ERROR_BAD_DATABASE);
1484
/* is database entry correct length? */
1485
entry->subjectName.len = ( ( dbentry->data[0] << 8 ) | dbentry->data[1] );
1486
lenDiff = dbentry->len -
1487
(entry->subjectName.len + DB_NICKNAME_ENTRY_HEADER_LEN);
1489
if (lenDiff < 0 || (lenDiff & 0xffff) != 0 ) {
1490
PORT_SetError(SEC_ERROR_BAD_DATABASE);
1493
/* The entry size exceeded 64KB. Reconstruct the correct length. */
1494
entry->subjectName.len += lenDiff;
1497
/* copy the certkey */
1498
entry->subjectName.data =
1499
(unsigned char *)PORT_ArenaAlloc(entry->common.arena,
1500
entry->subjectName.len);
1501
if ( entry->subjectName.data == NULL ) {
1502
PORT_SetError(SEC_ERROR_NO_MEMORY);
1505
PORT_Memcpy(entry->subjectName.data,
1506
&dbentry->data[DB_NICKNAME_ENTRY_HEADER_LEN],
1507
entry->subjectName.len);
1508
entry->subjectName.type = siBuffer;
1510
entry->nickname = (char *)PORT_ArenaAlloc(entry->common.arena,
1511
PORT_Strlen(nickname)+1);
1512
if ( entry->nickname ) {
1513
PORT_Strcpy(entry->nickname, nickname);
1523
* create a new nickname entry
1525
static certDBEntryNickname *
1526
NewDBNicknameEntry(char *nickname, SECItem *subjectName, unsigned int flags)
1528
PRArenaPool *arena = NULL;
1529
certDBEntryNickname *entry;
1533
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1534
if ( arena == NULL ) {
1535
PORT_SetError(SEC_ERROR_NO_MEMORY);
1539
entry = (certDBEntryNickname *)PORT_ArenaAlloc(arena,
1540
sizeof(certDBEntryNickname));
1541
if ( entry == NULL ) {
1542
PORT_SetError(SEC_ERROR_NO_MEMORY);
1546
/* init common fields */
1547
entry->common.arena = arena;
1548
entry->common.type = certDBEntryTypeNickname;
1549
entry->common.version = CERT_DB_FILE_VERSION;
1550
entry->common.flags = flags;
1552
/* copy the nickname */
1553
nnlen = PORT_Strlen(nickname) + 1;
1555
entry->nickname = (char*)PORT_ArenaAlloc(arena, nnlen);
1556
if ( entry->nickname == NULL ) {
1560
PORT_Memcpy(entry->nickname, nickname, nnlen);
1562
rv = SECITEM_CopyItem(arena, &entry->subjectName, subjectName);
1563
if ( rv != SECSuccess ) {
1570
PORT_FreeArena(arena, PR_FALSE);
1577
* delete a nickname entry
1580
DeleteDBNicknameEntry(NSSLOWCERTCertDBHandle *handle, char *nickname)
1582
PRArenaPool *arena = NULL;
1586
if ( nickname == NULL ) {
1590
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1591
if ( arena == NULL ) {
1595
rv = EncodeDBNicknameKey(nickname, arena, &dbkey);
1596
if ( rv != SECSuccess ) {
1600
rv = DeleteDBEntry(handle, certDBEntryTypeNickname, &dbkey);
1601
if ( rv == SECFailure ) {
1605
PORT_FreeArena(arena, PR_FALSE);
1610
PORT_FreeArena(arena, PR_FALSE);
1617
* Read a nickname entry
1619
static certDBEntryNickname *
1620
ReadDBNicknameEntry(NSSLOWCERTCertDBHandle *handle, char *nickname)
1622
PRArenaPool *arena = NULL;
1623
PRArenaPool *tmparena = NULL;
1624
certDBEntryNickname *entry;
1629
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1630
if ( arena == NULL ) {
1631
PORT_SetError(SEC_ERROR_NO_MEMORY);
1635
tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1636
if ( tmparena == NULL ) {
1637
PORT_SetError(SEC_ERROR_NO_MEMORY);
1641
entry = (certDBEntryNickname *)PORT_ArenaAlloc(arena,
1642
sizeof(certDBEntryNickname));
1643
if ( entry == NULL ) {
1644
PORT_SetError(SEC_ERROR_NO_MEMORY);
1647
entry->common.arena = arena;
1648
entry->common.type = certDBEntryTypeNickname;
1650
rv = EncodeDBNicknameKey(nickname, tmparena, &dbkey);
1651
if ( rv != SECSuccess ) {
1655
rv = ReadDBEntry(handle, &entry->common, &dbkey, &dbentry, tmparena);
1656
if ( rv == SECFailure ) {
1660
/* is record long enough for header? */
1661
if ( dbentry.len < DB_NICKNAME_ENTRY_HEADER_LEN ) {
1662
PORT_SetError(SEC_ERROR_BAD_DATABASE);
1666
rv = DecodeDBNicknameEntry(entry, &dbentry, nickname);
1667
if ( rv != SECSuccess ) {
1671
PORT_FreeArena(tmparena, PR_FALSE);
1676
PORT_FreeArena(tmparena, PR_FALSE);
1679
PORT_FreeArena(arena, PR_FALSE);
1686
* Encode a nickname entry into byte stream suitable for
1690
WriteDBNicknameEntry(NSSLOWCERTCertDBHandle *handle, certDBEntryNickname *entry)
1692
SECItem dbitem, dbkey;
1693
PRArenaPool *tmparena = NULL;
1696
tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1697
if ( tmparena == NULL ) {
1701
rv = EncodeDBNicknameEntry(entry, tmparena, &dbitem);
1702
if ( rv != SECSuccess ) {
1706
rv = EncodeDBNicknameKey(entry->nickname, tmparena, &dbkey);
1707
if ( rv != SECSuccess ) {
1711
/* now write it to the database */
1712
rv = WriteDBEntry(handle, &entry->common, &dbkey, &dbitem);
1713
if ( rv != SECSuccess ) {
1717
PORT_FreeArena(tmparena, PR_FALSE);
1722
PORT_FreeArena(tmparena, PR_FALSE);
1729
EncodeDBSMimeEntry(certDBEntrySMime *entry, PRArenaPool *arena,
1734
/* allocate space for encoded database record, including space
1735
* for low level header
1737
dbitem->len = entry->subjectName.len + entry->smimeOptions.len +
1738
entry->optionsDate.len +
1739
DB_SMIME_ENTRY_HEADER_LEN + SEC_DB_ENTRY_HEADER_LEN;
1741
dbitem->data = (unsigned char *)PORT_ArenaAlloc(arena, dbitem->len);
1742
if ( dbitem->data == NULL) {
1743
PORT_SetError(SEC_ERROR_NO_MEMORY);
1747
/* fill in database record */
1748
buf = &dbitem->data[SEC_DB_ENTRY_HEADER_LEN];
1750
buf[0] = (PRUint8)( entry->subjectName.len >> 8 );
1751
buf[1] = (PRUint8)( entry->subjectName.len );
1752
buf[2] = (PRUint8)( entry->smimeOptions.len >> 8 );
1753
buf[3] = (PRUint8)( entry->smimeOptions.len );
1754
buf[4] = (PRUint8)( entry->optionsDate.len >> 8 );
1755
buf[5] = (PRUint8)( entry->optionsDate.len );
1757
/* if no smime options, then there should not be an options date either */
1758
PORT_Assert( ! ( ( entry->smimeOptions.len == 0 ) &&
1759
( entry->optionsDate.len != 0 ) ) );
1761
PORT_Memcpy(&buf[DB_SMIME_ENTRY_HEADER_LEN], entry->subjectName.data,
1762
entry->subjectName.len);
1763
if ( entry->smimeOptions.len ) {
1764
PORT_Memcpy(&buf[DB_SMIME_ENTRY_HEADER_LEN+entry->subjectName.len],
1765
entry->smimeOptions.data,
1766
entry->smimeOptions.len);
1767
PORT_Memcpy(&buf[DB_SMIME_ENTRY_HEADER_LEN + entry->subjectName.len +
1768
entry->smimeOptions.len],
1769
entry->optionsDate.data,
1770
entry->optionsDate.len);
1780
* Encode a database key for a SMIME record
1783
EncodeDBSMimeKey(char *emailAddr, PRArenaPool *arena,
1786
unsigned int addrlen;
1788
addrlen = PORT_Strlen(emailAddr) + 1; /* includes null */
1790
/* now get the database key and format it */
1791
dbkey->len = addrlen + SEC_DB_KEY_HEADER_LEN;
1792
if (dbkey->len > NSS_MAX_LEGACY_DB_KEY_SIZE)
1794
dbkey->data = (unsigned char *)PORT_ArenaAlloc(arena, dbkey->len);
1795
if ( dbkey->data == NULL ) {
1798
PORT_Memcpy(&dbkey->data[SEC_DB_KEY_HEADER_LEN], emailAddr, addrlen);
1799
dbkey->data[0] = certDBEntryTypeSMimeProfile;
1808
* Decode a database SMIME record
1811
DecodeDBSMimeEntry(certDBEntrySMime *entry, SECItem *dbentry, char *emailAddr)
1815
/* is record long enough for header? */
1816
if ( dbentry->len < DB_SMIME_ENTRY_HEADER_LEN ) {
1817
PORT_SetError(SEC_ERROR_BAD_DATABASE);
1821
/* is database entry correct length? */
1822
entry->subjectName.len = (( dbentry->data[0] << 8 ) | dbentry->data[1] );
1823
entry->smimeOptions.len = (( dbentry->data[2] << 8 ) | dbentry->data[3] );
1824
entry->optionsDate.len = (( dbentry->data[4] << 8 ) | dbentry->data[5] );
1825
lenDiff = dbentry->len - (entry->subjectName.len +
1826
entry->smimeOptions.len +
1827
entry->optionsDate.len +
1828
DB_SMIME_ENTRY_HEADER_LEN);
1830
if (lenDiff < 0 || (lenDiff & 0xffff) != 0 ) {
1831
PORT_SetError(SEC_ERROR_BAD_DATABASE);
1834
/* The entry size exceeded 64KB. Reconstruct the correct length. */
1835
entry->subjectName.len += lenDiff;
1838
/* copy the subject name */
1839
entry->subjectName.data =
1840
(unsigned char *)PORT_ArenaAlloc(entry->common.arena,
1841
entry->subjectName.len);
1842
if ( entry->subjectName.data == NULL ) {
1843
PORT_SetError(SEC_ERROR_NO_MEMORY);
1846
PORT_Memcpy(entry->subjectName.data,
1847
&dbentry->data[DB_SMIME_ENTRY_HEADER_LEN],
1848
entry->subjectName.len);
1850
/* copy the smime options */
1851
if ( entry->smimeOptions.len ) {
1852
entry->smimeOptions.data =
1853
(unsigned char *)PORT_ArenaAlloc(entry->common.arena,
1854
entry->smimeOptions.len);
1855
if ( entry->smimeOptions.data == NULL ) {
1856
PORT_SetError(SEC_ERROR_NO_MEMORY);
1859
PORT_Memcpy(entry->smimeOptions.data,
1860
&dbentry->data[DB_SMIME_ENTRY_HEADER_LEN +
1861
entry->subjectName.len],
1862
entry->smimeOptions.len);
1864
if ( entry->optionsDate.len ) {
1865
entry->optionsDate.data =
1866
(unsigned char *)PORT_ArenaAlloc(entry->common.arena,
1867
entry->optionsDate.len);
1868
if ( entry->optionsDate.data == NULL ) {
1869
PORT_SetError(SEC_ERROR_NO_MEMORY);
1872
PORT_Memcpy(entry->optionsDate.data,
1873
&dbentry->data[DB_SMIME_ENTRY_HEADER_LEN +
1874
entry->subjectName.len +
1875
entry->smimeOptions.len],
1876
entry->optionsDate.len);
1879
/* both options and options date must either exist or not exist */
1880
if ( ( ( entry->optionsDate.len == 0 ) ||
1881
( entry->smimeOptions.len == 0 ) ) &&
1882
entry->smimeOptions.len != entry->optionsDate.len ) {
1883
PORT_SetError(SEC_ERROR_BAD_DATABASE);
1887
entry->emailAddr = (char *)PORT_ArenaAlloc(entry->common.arena,
1888
PORT_Strlen(emailAddr)+1);
1889
if ( entry->emailAddr ) {
1890
PORT_Strcpy(entry->emailAddr, emailAddr);
1900
* create a new SMIME entry
1902
static certDBEntrySMime *
1903
NewDBSMimeEntry(char *emailAddr, SECItem *subjectName, SECItem *smimeOptions,
1904
SECItem *optionsDate, unsigned int flags)
1906
PRArenaPool *arena = NULL;
1907
certDBEntrySMime *entry;
1911
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1912
if ( arena == NULL ) {
1913
PORT_SetError(SEC_ERROR_NO_MEMORY);
1917
entry = (certDBEntrySMime *)PORT_ArenaAlloc(arena,
1918
sizeof(certDBEntrySMime));
1919
if ( entry == NULL ) {
1920
PORT_SetError(SEC_ERROR_NO_MEMORY);
1924
/* init common fields */
1925
entry->common.arena = arena;
1926
entry->common.type = certDBEntryTypeSMimeProfile;
1927
entry->common.version = CERT_DB_FILE_VERSION;
1928
entry->common.flags = flags;
1930
/* copy the email addr */
1931
addrlen = PORT_Strlen(emailAddr) + 1;
1933
entry->emailAddr = (char*)PORT_ArenaAlloc(arena, addrlen);
1934
if ( entry->emailAddr == NULL ) {
1938
PORT_Memcpy(entry->emailAddr, emailAddr, addrlen);
1940
/* copy the subject name */
1941
rv = SECITEM_CopyItem(arena, &entry->subjectName, subjectName);
1942
if ( rv != SECSuccess ) {
1946
/* copy the smime options */
1947
if ( smimeOptions ) {
1948
rv = SECITEM_CopyItem(arena, &entry->smimeOptions, smimeOptions);
1949
if ( rv != SECSuccess ) {
1953
PORT_Assert(optionsDate == NULL);
1954
entry->smimeOptions.data = NULL;
1955
entry->smimeOptions.len = 0;
1958
/* copy the options date */
1959
if ( optionsDate ) {
1960
rv = SECITEM_CopyItem(arena, &entry->optionsDate, optionsDate);
1961
if ( rv != SECSuccess ) {
1965
PORT_Assert(smimeOptions == NULL);
1966
entry->optionsDate.data = NULL;
1967
entry->optionsDate.len = 0;
1973
PORT_FreeArena(arena, PR_FALSE);
1980
* delete a SMIME entry
1983
DeleteDBSMimeEntry(NSSLOWCERTCertDBHandle *handle, char *emailAddr)
1985
PRArenaPool *arena = NULL;
1989
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1990
if ( arena == NULL ) {
1994
rv = EncodeDBSMimeKey(emailAddr, arena, &dbkey);
1995
if ( rv != SECSuccess ) {
1999
rv = DeleteDBEntry(handle, certDBEntryTypeSMimeProfile, &dbkey);
2000
if ( rv == SECFailure ) {
2004
PORT_FreeArena(arena, PR_FALSE);
2009
PORT_FreeArena(arena, PR_FALSE);
2016
* Read a SMIME entry
2019
nsslowcert_ReadDBSMimeEntry(NSSLOWCERTCertDBHandle *handle, char *emailAddr)
2021
PRArenaPool *arena = NULL;
2022
PRArenaPool *tmparena = NULL;
2023
certDBEntrySMime *entry;
2028
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
2029
if ( arena == NULL ) {
2030
PORT_SetError(SEC_ERROR_NO_MEMORY);
2034
tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
2035
if ( tmparena == NULL ) {
2036
PORT_SetError(SEC_ERROR_NO_MEMORY);
2040
entry = (certDBEntrySMime *)PORT_ArenaAlloc(arena,
2041
sizeof(certDBEntrySMime));
2042
if ( entry == NULL ) {
2043
PORT_SetError(SEC_ERROR_NO_MEMORY);
2046
entry->common.arena = arena;
2047
entry->common.type = certDBEntryTypeSMimeProfile;
2049
rv = EncodeDBSMimeKey(emailAddr, tmparena, &dbkey);
2050
if ( rv != SECSuccess ) {
2054
rv = ReadDBEntry(handle, &entry->common, &dbkey, &dbentry, tmparena);
2055
if ( rv == SECFailure ) {
2059
/* is record long enough for header? */
2060
if ( dbentry.len < DB_SMIME_ENTRY_HEADER_LEN ) {
2061
PORT_SetError(SEC_ERROR_BAD_DATABASE);
2065
rv = DecodeDBSMimeEntry(entry, &dbentry, emailAddr);
2066
if ( rv != SECSuccess ) {
2070
PORT_FreeArena(tmparena, PR_FALSE);
2075
PORT_FreeArena(tmparena, PR_FALSE);
2078
PORT_FreeArena(arena, PR_FALSE);
2085
* Encode a SMIME entry into byte stream suitable for
2089
WriteDBSMimeEntry(NSSLOWCERTCertDBHandle *handle, certDBEntrySMime *entry)
2091
SECItem dbitem, dbkey;
2092
PRArenaPool *tmparena = NULL;
2095
tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
2096
if ( tmparena == NULL ) {
2100
rv = EncodeDBSMimeEntry(entry, tmparena, &dbitem);
2101
if ( rv != SECSuccess ) {
2105
rv = EncodeDBSMimeKey(entry->emailAddr, tmparena, &dbkey);
2106
if ( rv != SECSuccess ) {
2110
/* now write it to the database */
2111
rv = WriteDBEntry(handle, &entry->common, &dbkey, &dbitem);
2112
if ( rv != SECSuccess ) {
2116
PORT_FreeArena(tmparena, PR_FALSE);
2121
PORT_FreeArena(tmparena, PR_FALSE);
2128
* Encode a database subject record
2131
EncodeDBSubjectEntry(certDBEntrySubject *entry, PRArenaPool *arena,
2136
unsigned int ncerts;
2138
unsigned char *tmpbuf;
2139
unsigned int nnlen = 0;
2140
unsigned int eaddrslen = 0;
2142
SECItem *certKeys = entry->certKeys;
2143
SECItem *keyIDs = entry->keyIDs;;
2145
if ( entry->nickname ) {
2146
nnlen = PORT_Strlen(entry->nickname) + 1;
2148
if ( entry->emailAddrs ) {
2150
for (i=0; i < entry->nemailAddrs; i++) {
2151
eaddrslen += PORT_Strlen(entry->emailAddrs[i]) + 1 + 2;
2155
ncerts = entry->ncerts;
2157
/* compute the length of the entry */
2158
keyidoff = DB_SUBJECT_ENTRY_HEADER_LEN + nnlen ;
2159
len = keyidoff + (4 * ncerts) + eaddrslen;
2160
for ( i = 0; i < ncerts; i++ ) {
2161
if (keyIDs[i].len > 0xffff ||
2162
(certKeys[i].len > 0xffff)) {
2163
PORT_SetError(SEC_ERROR_INPUT_LEN);
2166
len += certKeys[i].len;
2167
len += keyIDs[i].len;
2170
/* allocate space for encoded database record, including space
2171
* for low level header
2173
dbitem->len = len + SEC_DB_ENTRY_HEADER_LEN;
2175
dbitem->data = (unsigned char *)PORT_ArenaAlloc(arena, dbitem->len);
2176
if ( dbitem->data == NULL) {
2177
PORT_SetError(SEC_ERROR_NO_MEMORY);
2181
/* fill in database record */
2182
buf = &dbitem->data[SEC_DB_ENTRY_HEADER_LEN];
2184
buf[0] = (PRUint8)( ncerts >> 8 );
2185
buf[1] = (PRUint8)( ncerts );
2186
buf[2] = (PRUint8)( nnlen >> 8 );
2187
buf[3] = (PRUint8)( nnlen );
2188
/* v7 email field is NULL in v8 */
2192
PORT_Memcpy(&buf[DB_SUBJECT_ENTRY_HEADER_LEN], entry->nickname, nnlen);
2193
tmpbuf = &buf[keyidoff];
2194
for ( i = 0; i < ncerts; i++ ) {
2195
tmpbuf[0] = (PRUint8)( certKeys[i].len >> 8 );
2196
tmpbuf[1] = (PRUint8)( certKeys[i].len );
2199
for ( i = 0; i < ncerts; i++ ) {
2200
tmpbuf[0] = (PRUint8)( keyIDs[i].len >> 8 );
2201
tmpbuf[1] = (PRUint8)( keyIDs[i].len );
2205
for ( i = 0; i < ncerts; i++ ) {
2206
PORT_Memcpy(tmpbuf, certKeys[i].data, certKeys[i].len);
2207
tmpbuf += certKeys[i].len;
2209
for ( i = 0; i < ncerts; i++ ) {
2210
PORT_Memcpy(tmpbuf, keyIDs[i].data, keyIDs[i].len);
2211
tmpbuf += keyIDs[i].len;
2214
if (entry->emailAddrs) {
2215
tmpbuf[0] = (PRUint8)( entry->nemailAddrs >> 8 );
2216
tmpbuf[1] = (PRUint8)( entry->nemailAddrs );
2218
for (i=0; i < entry->nemailAddrs; i++) {
2219
int nameLen = PORT_Strlen(entry->emailAddrs[i]) + 1;
2220
tmpbuf[0] = (PRUint8)( nameLen >> 8 );
2221
tmpbuf[1] = (PRUint8)( nameLen );
2223
PORT_Memcpy(tmpbuf,entry->emailAddrs[i],nameLen);
2228
PORT_Assert(tmpbuf == &buf[len]);
2237
* Encode a database key for a subject record
2240
EncodeDBSubjectKey(SECItem *derSubject, PRArenaPool *arena,
2243
dbkey->len = derSubject->len + SEC_DB_KEY_HEADER_LEN;
2244
if (dbkey->len > NSS_MAX_LEGACY_DB_KEY_SIZE)
2246
dbkey->data = (unsigned char *)PORT_ArenaAlloc(arena, dbkey->len);
2247
if ( dbkey->data == NULL ) {
2250
PORT_Memcpy(&dbkey->data[SEC_DB_KEY_HEADER_LEN], derSubject->data,
2252
dbkey->data[0] = certDBEntryTypeSubject;
2261
DecodeDBSubjectEntry(certDBEntrySubject *entry, SECItem *dbentry,
2262
const SECItem *derSubject)
2264
PRArenaPool *arena = entry->common.arena;
2265
unsigned char *tmpbuf;
2267
void *mark = PORT_ArenaMark(arena);
2268
unsigned int eaddrlen;
2270
unsigned int keyidoff;
2272
unsigned int ncerts = 0;
2276
rv = SECITEM_CopyItem(arena, &entry->derSubject, derSubject);
2277
if ( rv != SECSuccess ) {
2281
/* is record long enough for header? */
2282
if ( dbentry->len < DB_SUBJECT_ENTRY_HEADER_LEN ) {
2283
PORT_SetError(SEC_ERROR_BAD_DATABASE);
2287
entry->ncerts = ncerts = (( dbentry->data[0] << 8 ) | dbentry->data[1] );
2288
nnlen = (( dbentry->data[2] << 8 ) | dbentry->data[3] );
2289
eaddrlen = (( dbentry->data[4] << 8 ) | dbentry->data[5] );
2290
keyidoff = DB_SUBJECT_ENTRY_HEADER_LEN + nnlen + eaddrlen;
2291
len = keyidoff + (4 * ncerts);
2292
if ( dbentry->len < len) {
2293
PORT_SetError(SEC_ERROR_BAD_DATABASE);
2297
entry->certKeys = PORT_ArenaNewArray(arena, SECItem, ncerts);
2298
entry->keyIDs = PORT_ArenaNewArray(arena, SECItem, ncerts);
2299
if ( ( entry->certKeys == NULL ) || ( entry->keyIDs == NULL ) ) {
2300
PORT_SetError(SEC_ERROR_NO_MEMORY);
2304
if ( nnlen > 1 ) { /* null terminator is stored */
2305
entry->nickname = (char *)PORT_ArenaAlloc(arena, nnlen);
2306
if ( entry->nickname == NULL ) {
2307
PORT_SetError(SEC_ERROR_NO_MEMORY);
2310
PORT_Memcpy(entry->nickname,
2311
&dbentry->data[DB_SUBJECT_ENTRY_HEADER_LEN],
2314
entry->nickname = NULL;
2317
/* if we have an old style email entry, there is only one */
2318
entry->nemailAddrs = 0;
2319
if ( eaddrlen > 1 ) { /* null terminator is stored */
2320
entry->emailAddrs = PORT_ArenaNewArray(arena, char *, 2);
2321
if ( entry->emailAddrs == NULL ) {
2322
PORT_SetError(SEC_ERROR_NO_MEMORY);
2325
entry->emailAddrs[0] = (char *)PORT_ArenaAlloc(arena, eaddrlen);
2326
if ( entry->emailAddrs[0] == NULL ) {
2327
PORT_SetError(SEC_ERROR_NO_MEMORY);
2330
PORT_Memcpy(entry->emailAddrs[0],
2331
&dbentry->data[DB_SUBJECT_ENTRY_HEADER_LEN+nnlen],
2333
entry->nemailAddrs = 1;
2335
entry->emailAddrs = NULL;
2338
/* collect the lengths of the certKeys and keyIDs, and total the
2341
tmpbuf = &dbentry->data[keyidoff];
2342
for ( i = 0; i < ncerts; i++ ) {
2343
unsigned int itemlen = ( tmpbuf[0] << 8 ) | tmpbuf[1];
2344
entry->certKeys[i].len = itemlen;
2348
for ( i = 0; i < ncerts; i++ ) {
2349
unsigned int itemlen = ( tmpbuf[0] << 8 ) | tmpbuf[1] ;
2350
entry->keyIDs[i].len = itemlen;
2355
/* is encoded entry large enough ? */
2356
if ( len > dbentry->len ){
2357
PORT_SetError(SEC_ERROR_BAD_DATABASE);
2361
for ( i = 0; i < ncerts; i++ ) {
2362
unsigned int kLen = entry->certKeys[i].len;
2363
entry->certKeys[i].data = (unsigned char *)PORT_ArenaAlloc(arena, kLen);
2364
if ( entry->certKeys[i].data == NULL ) {
2365
PORT_SetError(SEC_ERROR_NO_MEMORY);
2368
PORT_Memcpy(entry->certKeys[i].data, tmpbuf, kLen);
2371
for ( i = 0; i < ncerts; i++ ) {
2372
unsigned int iLen = entry->keyIDs[i].len;
2373
entry->keyIDs[i].data = (unsigned char *)PORT_ArenaAlloc(arena, iLen);
2374
if ( entry->keyIDs[i].data == NULL ) {
2375
PORT_SetError(SEC_ERROR_NO_MEMORY);
2378
PORT_Memcpy(entry->keyIDs[i].data, tmpbuf, iLen);
2382
end = dbentry->data + dbentry->len;
2383
if ((eaddrlen == 0) && (end - tmpbuf > 1)) {
2384
/* read in the additional email addresses */
2385
entry->nemailAddrs = (((unsigned int)tmpbuf[0]) << 8) | tmpbuf[1];
2387
if (end - tmpbuf < 2 * (int)entry->nemailAddrs)
2389
entry->emailAddrs = PORT_ArenaNewArray(arena, char *, entry->nemailAddrs);
2390
if (entry->emailAddrs == NULL) {
2391
PORT_SetError(SEC_ERROR_NO_MEMORY);
2394
for (i=0; i < entry->nemailAddrs; i++) {
2396
if (end - tmpbuf < 2) {
2399
nameLen = (((int)tmpbuf[0]) << 8) | tmpbuf[1];
2401
if (end - tmpbuf < nameLen) {
2404
entry->emailAddrs[i] = PORT_ArenaAlloc(arena,nameLen);
2405
if (entry->emailAddrs == NULL) {
2406
PORT_SetError(SEC_ERROR_NO_MEMORY);
2409
PORT_Memcpy(entry->emailAddrs[i], tmpbuf, nameLen);
2415
PORT_ArenaUnmark(arena, mark);
2419
PORT_ArenaRelease(arena, mark); /* discard above allocations */
2424
* create a new subject entry with a single cert
2426
static certDBEntrySubject *
2427
NewDBSubjectEntry(SECItem *derSubject, SECItem *certKey,
2428
SECItem *keyID, char *nickname, char *emailAddr,
2431
PRArenaPool *arena = NULL;
2432
certDBEntrySubject *entry;
2435
unsigned int eaddrlen;
2437
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
2438
if ( arena == NULL ) {
2439
PORT_SetError(SEC_ERROR_NO_MEMORY);
2443
entry = (certDBEntrySubject *)PORT_ArenaAlloc(arena,
2444
sizeof(certDBEntrySubject));
2445
if ( entry == NULL ) {
2446
PORT_SetError(SEC_ERROR_NO_MEMORY);
2450
/* init common fields */
2451
entry->common.arena = arena;
2452
entry->common.type = certDBEntryTypeSubject;
2453
entry->common.version = CERT_DB_FILE_VERSION;
2454
entry->common.flags = flags;
2456
/* copy the subject */
2457
rv = SECITEM_CopyItem(arena, &entry->derSubject, derSubject);
2458
if ( rv != SECSuccess ) {
2463
entry->nemailAddrs = 0;
2465
if ( nickname && ( *nickname != '\0' ) ) {
2466
nnlen = PORT_Strlen(nickname) + 1;
2467
entry->nickname = (char *)PORT_ArenaAlloc(arena, nnlen);
2468
if ( entry->nickname == NULL ) {
2472
PORT_Memcpy(entry->nickname, nickname, nnlen);
2474
entry->nickname = NULL;
2477
/* copy email addr */
2478
if ( emailAddr && ( *emailAddr != '\0' ) ) {
2479
emailAddr = nsslowcert_FixupEmailAddr(emailAddr);
2480
if ( emailAddr == NULL ) {
2481
entry->emailAddrs = NULL;
2485
eaddrlen = PORT_Strlen(emailAddr) + 1;
2486
entry->emailAddrs = (char **)PORT_ArenaAlloc(arena, sizeof(char *));
2487
if ( entry->emailAddrs == NULL ) {
2488
PORT_Free(emailAddr);
2491
entry->emailAddrs[0] = PORT_ArenaStrdup(arena,emailAddr);
2492
if (entry->emailAddrs[0]) {
2493
entry->nemailAddrs = 1;
2496
PORT_Free(emailAddr);
2498
entry->emailAddrs = NULL;
2501
/* allocate space for certKeys and keyIDs */
2502
entry->certKeys = (SECItem *)PORT_ArenaAlloc(arena, sizeof(SECItem));
2503
entry->keyIDs = (SECItem *)PORT_ArenaAlloc(arena, sizeof(SECItem));
2504
if ( ( entry->certKeys == NULL ) || ( entry->keyIDs == NULL ) ) {
2508
/* copy the certKey and keyID */
2509
rv = SECITEM_CopyItem(arena, &entry->certKeys[0], certKey);
2510
if ( rv != SECSuccess ) {
2513
rv = SECITEM_CopyItem(arena, &entry->keyIDs[0], keyID);
2514
if ( rv != SECSuccess ) {
2521
PORT_FreeArena(arena, PR_FALSE);
2528
* delete a subject entry
2531
DeleteDBSubjectEntry(NSSLOWCERTCertDBHandle *handle, SECItem *derSubject)
2534
PRArenaPool *arena = NULL;
2537
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
2538
if ( arena == NULL ) {
2542
rv = EncodeDBSubjectKey(derSubject, arena, &dbkey);
2543
if ( rv != SECSuccess ) {
2547
rv = DeleteDBEntry(handle, certDBEntryTypeSubject, &dbkey);
2548
if ( rv == SECFailure ) {
2552
PORT_FreeArena(arena, PR_FALSE);
2557
PORT_FreeArena(arena, PR_FALSE);
2564
* Read the subject entry
2566
static certDBEntrySubject *
2567
ReadDBSubjectEntry(NSSLOWCERTCertDBHandle *handle, SECItem *derSubject)
2569
PRArenaPool *arena = NULL;
2570
PRArenaPool *tmparena = NULL;
2571
certDBEntrySubject *entry;
2576
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
2577
if ( arena == NULL ) {
2578
PORT_SetError(SEC_ERROR_NO_MEMORY);
2582
tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
2583
if ( tmparena == NULL ) {
2584
PORT_SetError(SEC_ERROR_NO_MEMORY);
2588
entry = (certDBEntrySubject *)PORT_ArenaAlloc(arena,
2589
sizeof(certDBEntrySubject));
2590
if ( entry == NULL ) {
2591
PORT_SetError(SEC_ERROR_NO_MEMORY);
2594
entry->common.arena = arena;
2595
entry->common.type = certDBEntryTypeSubject;
2597
rv = EncodeDBSubjectKey(derSubject, tmparena, &dbkey);
2598
if ( rv != SECSuccess ) {
2602
rv = ReadDBEntry(handle, &entry->common, &dbkey, &dbentry, tmparena);
2603
if ( rv == SECFailure ) {
2607
rv = DecodeDBSubjectEntry(entry, &dbentry, derSubject);
2608
if ( rv == SECFailure ) {
2612
PORT_FreeArena(tmparena, PR_FALSE);
2617
PORT_FreeArena(tmparena, PR_FALSE);
2620
PORT_FreeArena(arena, PR_FALSE);
2627
* Encode a subject name entry into byte stream suitable for
2631
WriteDBSubjectEntry(NSSLOWCERTCertDBHandle *handle, certDBEntrySubject *entry)
2633
SECItem dbitem, dbkey;
2634
PRArenaPool *tmparena = NULL;
2637
tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
2638
if ( tmparena == NULL ) {
2642
rv = EncodeDBSubjectEntry(entry, tmparena, &dbitem);
2643
if ( rv != SECSuccess ) {
2647
rv = EncodeDBSubjectKey(&entry->derSubject, tmparena, &dbkey);
2648
if ( rv != SECSuccess ) {
2652
/* now write it to the database */
2653
rv = WriteDBEntry(handle, &entry->common, &dbkey, &dbitem);
2654
if ( rv != SECSuccess ) {
2658
PORT_FreeArena(tmparena, PR_FALSE);
2663
PORT_FreeArena(tmparena, PR_FALSE);
2669
typedef enum { nsslowcert_remove, nsslowcert_add } nsslowcertUpdateType;
2672
nsslowcert_UpdateSubjectEmailAddr(NSSLOWCERTCertDBHandle *dbhandle,
2673
SECItem *derSubject, char *emailAddr, nsslowcertUpdateType updateType)
2675
certDBEntrySubject *entry = NULL;
2680
emailAddr = nsslowcert_FixupEmailAddr(emailAddr);
2681
if (emailAddr == NULL) {
2688
entry = ReadDBSubjectEntry(dbhandle,derSubject);
2689
if (entry == NULL) {
2694
for (i=0; i < (int)(entry->nemailAddrs); i++) {
2695
if (PORT_Strcmp(entry->emailAddrs[i],emailAddr) == 0) {
2700
if (updateType == nsslowcert_remove) {
2705
entry->nemailAddrs--;
2706
for (i=index; i < (int)(entry->nemailAddrs); i++) {
2707
entry->emailAddrs[i] = entry->emailAddrs[i+1];
2710
char **newAddrs = NULL;
2716
newAddrs = (char **)PORT_ArenaAlloc(entry->common.arena,
2717
(entry->nemailAddrs+1)* sizeof(char *));
2722
for (i=0; i < (int)(entry->nemailAddrs); i++) {
2723
newAddrs[i] = entry->emailAddrs[i];
2725
newAddrs[entry->nemailAddrs] =
2726
PORT_ArenaStrdup(entry->common.arena,emailAddr);
2727
if (!newAddrs[entry->nemailAddrs]) {
2731
entry->emailAddrs = newAddrs;
2732
entry->nemailAddrs++;
2735
/* delete the subject entry */
2736
DeleteDBSubjectEntry(dbhandle, derSubject);
2738
/* write the new one */
2739
rv = WriteDBSubjectEntry(dbhandle, entry);
2742
if (entry) DestroyDBEntry((certDBEntry *)entry);
2743
if (emailAddr) PORT_Free(emailAddr);
2748
* writes a nickname to an existing subject entry that does not currently
2752
AddNicknameToSubject(NSSLOWCERTCertDBHandle *dbhandle,
2753
NSSLOWCERTCertificate *cert, char *nickname)
2755
certDBEntrySubject *entry;
2758
if ( nickname == NULL ) {
2762
entry = ReadDBSubjectEntry(dbhandle,&cert->derSubject);
2763
PORT_Assert(entry != NULL);
2764
if ( entry == NULL ) {
2768
PORT_Assert(entry->nickname == NULL);
2769
if ( entry->nickname != NULL ) {
2773
entry->nickname = PORT_ArenaStrdup(entry->common.arena, nickname);
2775
if ( entry->nickname == NULL ) {
2779
/* delete the subject entry */
2780
DeleteDBSubjectEntry(dbhandle, &cert->derSubject);
2782
/* write the new one */
2783
rv = WriteDBSubjectEntry(dbhandle, entry);
2784
if ( rv != SECSuccess ) {
2795
* create a new version entry
2797
static certDBEntryVersion *
2798
NewDBVersionEntry(unsigned int flags)
2800
PRArenaPool *arena = NULL;
2801
certDBEntryVersion *entry;
2803
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
2804
if ( arena == NULL ) {
2805
PORT_SetError(SEC_ERROR_NO_MEMORY);
2809
entry = (certDBEntryVersion *)PORT_ArenaAlloc(arena,
2810
sizeof(certDBEntryVersion));
2811
if ( entry == NULL ) {
2812
PORT_SetError(SEC_ERROR_NO_MEMORY);
2815
entry->common.arena = arena;
2816
entry->common.type = certDBEntryTypeVersion;
2817
entry->common.version = CERT_DB_FILE_VERSION;
2818
entry->common.flags = flags;
2823
PORT_FreeArena(arena, PR_FALSE);
2830
* Read the version entry
2832
static certDBEntryVersion *
2833
ReadDBVersionEntry(NSSLOWCERTCertDBHandle *handle)
2835
PRArenaPool *arena = NULL;
2836
PRArenaPool *tmparena = NULL;
2837
certDBEntryVersion *entry;
2842
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
2843
if ( arena == NULL ) {
2844
PORT_SetError(SEC_ERROR_NO_MEMORY);
2848
tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
2849
if ( tmparena == NULL ) {
2850
PORT_SetError(SEC_ERROR_NO_MEMORY);
2854
entry = PORT_ArenaZNew(arena, certDBEntryVersion);
2855
if ( entry == NULL ) {
2856
PORT_SetError(SEC_ERROR_NO_MEMORY);
2859
entry->common.arena = arena;
2860
entry->common.type = certDBEntryTypeVersion;
2862
/* now get the database key and format it */
2863
dbkey.len = SEC_DB_VERSION_KEY_LEN + SEC_DB_KEY_HEADER_LEN;
2864
dbkey.data = (unsigned char *)PORT_ArenaAlloc(tmparena, dbkey.len);
2865
if ( dbkey.data == NULL ) {
2868
PORT_Memcpy(&dbkey.data[SEC_DB_KEY_HEADER_LEN], SEC_DB_VERSION_KEY,
2869
SEC_DB_VERSION_KEY_LEN);
2871
rv = ReadDBEntry(handle, &entry->common, &dbkey, &dbentry, tmparena);
2872
if (rv != SECSuccess) {
2876
PORT_FreeArena(tmparena, PR_FALSE);
2881
PORT_FreeArena(tmparena, PR_FALSE);
2884
PORT_FreeArena(arena, PR_FALSE);
2892
* Encode a version entry into byte stream suitable for
2896
WriteDBVersionEntry(NSSLOWCERTCertDBHandle *handle, certDBEntryVersion *entry)
2898
SECItem dbitem, dbkey;
2899
PRArenaPool *tmparena = NULL;
2902
tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
2903
if ( tmparena == NULL ) {
2907
/* allocate space for encoded database record, including space
2908
* for low level header
2910
dbitem.len = SEC_DB_ENTRY_HEADER_LEN;
2912
dbitem.data = (unsigned char *)PORT_ArenaAlloc(tmparena, dbitem.len);
2913
if ( dbitem.data == NULL) {
2914
PORT_SetError(SEC_ERROR_NO_MEMORY);
2918
/* now get the database key and format it */
2919
dbkey.len = SEC_DB_VERSION_KEY_LEN + SEC_DB_KEY_HEADER_LEN;
2920
dbkey.data = (unsigned char *)PORT_ArenaAlloc(tmparena, dbkey.len);
2921
if ( dbkey.data == NULL ) {
2924
PORT_Memcpy(&dbkey.data[SEC_DB_KEY_HEADER_LEN], SEC_DB_VERSION_KEY,
2925
SEC_DB_VERSION_KEY_LEN);
2927
/* now write it to the database */
2928
rv = WriteDBEntry(handle, &entry->common, &dbkey, &dbitem);
2929
if ( rv != SECSuccess ) {
2933
PORT_FreeArena(tmparena, PR_FALSE);
2938
PORT_FreeArena(tmparena, PR_FALSE);
2944
* cert is no longer a perm cert, but will remain a temp cert
2947
RemovePermSubjectNode(NSSLOWCERTCertificate *cert)
2949
certDBEntrySubject *entry;
2953
entry = ReadDBSubjectEntry(cert->dbhandle,&cert->derSubject);
2954
if ( entry == NULL ) {
2958
PORT_Assert(entry->ncerts);
2961
if ( entry->ncerts > 1 ) {
2962
for ( i = 0; i < entry->ncerts; i++ ) {
2963
if ( SECITEM_CompareItem(&entry->certKeys[i], &cert->certKey) ==
2965
/* copy rest of list forward one entry */
2966
for ( i = i + 1; i < entry->ncerts; i++ ) {
2967
entry->certKeys[i-1] = entry->certKeys[i];
2968
entry->keyIDs[i-1] = entry->keyIDs[i];
2971
DeleteDBSubjectEntry(cert->dbhandle, &cert->derSubject);
2972
rv = WriteDBSubjectEntry(cert->dbhandle, entry);
2977
/* no entries left, delete the perm entry in the DB */
2978
if ( entry->emailAddrs ) {
2979
/* if the subject had an email record, then delete it too */
2980
for (i=0; i < entry->nemailAddrs; i++) {
2981
DeleteDBSMimeEntry(cert->dbhandle, entry->emailAddrs[i]);
2984
if ( entry->nickname ) {
2985
DeleteDBNicknameEntry(cert->dbhandle, entry->nickname);
2988
DeleteDBSubjectEntry(cert->dbhandle, &cert->derSubject);
2990
DestroyDBEntry((certDBEntry *)entry);
2996
* add a cert to the perm subject list
2999
AddPermSubjectNode(certDBEntrySubject *entry, NSSLOWCERTCertificate *cert,
3002
SECItem *newCertKeys, *newKeyIDs;
3003
unsigned int i, new_i;
3005
unsigned int ncerts;
3008
ncerts = entry->ncerts;
3010
if ( nickname && entry->nickname ) {
3011
/* nicknames must be the same */
3012
PORT_Assert(PORT_Strcmp(nickname, entry->nickname) == 0);
3015
if ( ( entry->nickname == NULL ) && ( nickname != NULL ) ) {
3016
/* copy nickname into the entry */
3017
entry->nickname = PORT_ArenaStrdup(entry->common.arena, nickname);
3018
if ( entry->nickname == NULL ) {
3023
/* a DB entry already exists, so add this cert */
3024
newCertKeys = PORT_ArenaZNewArray(entry->common.arena, SECItem, ncerts + 1);
3025
newKeyIDs = PORT_ArenaZNewArray(entry->common.arena, SECItem, ncerts + 1);
3027
if ( ( newCertKeys == NULL ) || ( newKeyIDs == NULL ) ) {
3031
/* Step 1: copy certs older than "cert" into new entry. */
3032
for ( i = 0, new_i=0; i < ncerts; i++ ) {
3033
NSSLOWCERTCertificate *cmpcert;
3035
cmpcert = nsslowcert_FindCertByKey(cert->dbhandle,
3036
&entry->certKeys[i]);
3037
/* The entry has been corrupted, remove it from the list */
3042
isNewer = nsslowcert_IsNewer(cert, cmpcert);
3043
nsslowcert_DestroyCertificate(cmpcert);
3046
/* copy this cert entry */
3047
newCertKeys[new_i] = entry->certKeys[i];
3048
newKeyIDs[new_i] = entry->keyIDs[i];
3052
/* Step 2: Add "cert" to the entry. */
3053
rv = SECITEM_CopyItem(entry->common.arena, &newCertKeys[new_i],
3055
if ( rv != SECSuccess ) {
3058
rv = SECITEM_CopyItem(entry->common.arena, &newKeyIDs[new_i],
3059
&cert->subjectKeyID);
3060
if ( rv != SECSuccess ) {
3065
/* Step 3: copy remaining certs (if any) from old entry to new. */
3066
for ( ; i < ncerts; i++ ,new_i++) {
3067
newCertKeys[new_i] = entry->certKeys[i];
3068
newKeyIDs[new_i] = entry->keyIDs[i];
3071
/* update certKeys and keyIDs */
3072
entry->certKeys = newCertKeys;
3073
entry->keyIDs = newKeyIDs;
3075
/* set new count value */
3076
entry->ncerts = new_i;
3078
DeleteDBSubjectEntry(cert->dbhandle, &cert->derSubject);
3079
rv = WriteDBSubjectEntry(cert->dbhandle, entry);
3085
nsslowcert_TraversePermCertsForSubject(NSSLOWCERTCertDBHandle *handle,
3086
SECItem *derSubject,
3087
NSSLOWCERTCertCallback cb, void *cbarg)
3089
certDBEntrySubject *entry;
3091
NSSLOWCERTCertificate *cert;
3092
SECStatus rv = SECSuccess;
3094
entry = ReadDBSubjectEntry(handle, derSubject);
3096
if ( entry == NULL ) {
3100
for( i = 0; i < entry->ncerts; i++ ) {
3101
cert = nsslowcert_FindCertByKey(handle, &entry->certKeys[i]);
3105
rv = (* cb)(cert, cbarg);
3106
nsslowcert_DestroyCertificate(cert);
3107
if ( rv == SECFailure ) {
3112
DestroyDBEntry((certDBEntry *)entry);
3118
nsslowcert_NumPermCertsForSubject(NSSLOWCERTCertDBHandle *handle,
3119
SECItem *derSubject)
3121
certDBEntrySubject *entry;
3124
entry = ReadDBSubjectEntry(handle, derSubject);
3126
if ( entry == NULL ) {
3130
ret = entry->ncerts;
3132
DestroyDBEntry((certDBEntry *)entry);
3138
nsslowcert_TraversePermCertsForNickname(NSSLOWCERTCertDBHandle *handle,
3139
char *nickname, NSSLOWCERTCertCallback cb, void *cbarg)
3141
certDBEntryNickname *nnentry = NULL;
3142
certDBEntrySMime *smentry = NULL;
3144
SECItem *derSubject = NULL;
3146
nnentry = ReadDBNicknameEntry(handle, nickname);
3148
derSubject = &nnentry->subjectName;
3150
smentry = nsslowcert_ReadDBSMimeEntry(handle, nickname);
3152
derSubject = &smentry->subjectName;
3157
rv = nsslowcert_TraversePermCertsForSubject(handle, derSubject,
3164
DestroyDBEntry((certDBEntry *)nnentry);
3167
DestroyDBEntry((certDBEntry *)smentry);
3174
nsslowcert_NumPermCertsForNickname(NSSLOWCERTCertDBHandle *handle,
3177
certDBEntryNickname *entry;
3180
entry = ReadDBNicknameEntry(handle, nickname);
3183
ret = nsslowcert_NumPermCertsForSubject(handle, &entry->subjectName);
3184
DestroyDBEntry((certDBEntry *)entry);
3192
* add a nickname to a cert that doesn't have one
3195
AddNicknameToPermCert(NSSLOWCERTCertDBHandle *dbhandle,
3196
NSSLOWCERTCertificate *cert, char *nickname)
3198
certDBEntryCert *entry;
3201
entry = cert->dbEntry;
3202
PORT_Assert(entry != NULL);
3203
if ( entry == NULL ) {
3207
pkcs11_freeNickname(entry->nickname,entry->nicknameSpace);
3208
entry->nickname = NULL;
3209
entry->nickname = pkcs11_copyNickname(nickname,entry->nicknameSpace,
3210
sizeof(entry->nicknameSpace));
3212
rv = WriteDBCertEntry(dbhandle, entry);
3217
pkcs11_freeNickname(cert->nickname,cert->nicknameSpace);
3218
cert->nickname = NULL;
3219
cert->nickname = pkcs11_copyNickname(nickname,cert->nicknameSpace,
3220
sizeof(cert->nicknameSpace));
3229
* add a nickname to a cert that is already in the perm database, but doesn't
3230
* have one yet (it is probably an e-mail cert).
3233
nsslowcert_AddPermNickname(NSSLOWCERTCertDBHandle *dbhandle,
3234
NSSLOWCERTCertificate *cert, char *nickname)
3236
SECStatus rv = SECFailure;
3237
certDBEntrySubject *entry = NULL;
3238
certDBEntryNickname *nicknameEntry = NULL;
3240
nsslowcert_LockDB(dbhandle);
3242
entry = ReadDBSubjectEntry(dbhandle, &cert->derSubject);
3243
if (entry == NULL) goto loser;
3245
if ( entry->nickname == NULL ) {
3247
/* no nickname for subject */
3248
rv = AddNicknameToSubject(dbhandle, cert, nickname);
3249
if ( rv != SECSuccess ) {
3252
rv = AddNicknameToPermCert(dbhandle, cert, nickname);
3253
if ( rv != SECSuccess ) {
3256
nicknameEntry = NewDBNicknameEntry(nickname, &cert->derSubject, 0);
3257
if ( nicknameEntry == NULL ) {
3261
rv = WriteDBNicknameEntry(dbhandle, nicknameEntry);
3262
if ( rv != SECSuccess ) {
3266
/* subject already has a nickname */
3267
rv = AddNicknameToPermCert(dbhandle, cert, entry->nickname);
3268
if ( rv != SECSuccess ) {
3271
/* make sure nickname entry exists. If the database was corrupted,
3272
* we may have lost the nickname entry. Add it back now */
3273
nicknameEntry = ReadDBNicknameEntry(dbhandle, entry->nickname);
3274
if (nicknameEntry == NULL ) {
3275
nicknameEntry = NewDBNicknameEntry(entry->nickname,
3276
&cert->derSubject, 0);
3277
if ( nicknameEntry == NULL ) {
3281
rv = WriteDBNicknameEntry(dbhandle, nicknameEntry);
3282
if ( rv != SECSuccess ) {
3291
DestroyDBEntry((certDBEntry *)entry);
3293
if (nicknameEntry) {
3294
DestroyDBEntry((certDBEntry *)nicknameEntry);
3296
nsslowcert_UnlockDB(dbhandle);
3300
static certDBEntryCert *
3301
AddCertToPermDB(NSSLOWCERTCertDBHandle *handle, NSSLOWCERTCertificate *cert,
3302
char *nickname, NSSLOWCERTCertTrust *trust)
3304
certDBEntryCert *certEntry = NULL;
3305
certDBEntryNickname *nicknameEntry = NULL;
3306
certDBEntrySubject *subjectEntry = NULL;
3309
PRBool donnentry = PR_FALSE;
3312
donnentry = PR_TRUE;
3315
subjectEntry = ReadDBSubjectEntry(handle, &cert->derSubject);
3317
if ( subjectEntry && subjectEntry->nickname ) {
3318
donnentry = PR_FALSE;
3319
nickname = subjectEntry->nickname;
3322
certEntry = NewDBCertEntry(&cert->derCert, nickname, trust, 0);
3323
if ( certEntry == NULL ) {
3328
nicknameEntry = NewDBNicknameEntry(nickname, &cert->derSubject, 0);
3329
if ( nicknameEntry == NULL ) {
3334
rv = WriteDBCertEntry(handle, certEntry);
3335
if ( rv != SECSuccess ) {
3340
if ( nicknameEntry ) {
3341
rv = WriteDBNicknameEntry(handle, nicknameEntry);
3342
if ( rv != SECSuccess ) {
3349
/* "Change" handles if necessary */
3350
cert->dbhandle = handle;
3352
/* add to or create new subject entry */
3353
if ( subjectEntry ) {
3354
/* REWRITE BASED ON SUBJECT ENTRY */
3355
rv = AddPermSubjectNode(subjectEntry, cert, nickname);
3356
if ( rv != SECSuccess ) {
3360
/* make a new subject entry - this case is only used when updating
3361
* an old version of the database. This is OK because the oldnickname
3362
* db format didn't allow multiple certs with the same subject.
3364
/* where does subjectKeyID and certKey come from? */
3365
subjectEntry = NewDBSubjectEntry(&cert->derSubject, &cert->certKey,
3366
&cert->subjectKeyID, nickname,
3368
if ( subjectEntry == NULL ) {
3371
rv = WriteDBSubjectEntry(handle, subjectEntry);
3372
if ( rv != SECSuccess ) {
3379
if ( nicknameEntry ) {
3380
DestroyDBEntry((certDBEntry *)nicknameEntry);
3383
if ( subjectEntry ) {
3384
DestroyDBEntry((certDBEntry *)subjectEntry);
3390
/* don't leave partial entry in the database */
3392
rv = DeleteDBCertEntry(handle, &cert->certKey);
3394
if ( ( state > 1 ) && donnentry ) {
3395
rv = DeleteDBNicknameEntry(handle, nickname);
3398
rv = DeleteDBSubjectEntry(handle, &cert->derSubject);
3401
DestroyDBEntry((certDBEntry *)certEntry);
3403
if ( nicknameEntry ) {
3404
DestroyDBEntry((certDBEntry *)nicknameEntry);
3406
if ( subjectEntry ) {
3407
DestroyDBEntry((certDBEntry *)subjectEntry);
3413
/* forward declaration */
3415
UpdateV7DB(NSSLOWCERTCertDBHandle *handle, DB *updatedb);
3418
* version 8 uses the same schema as version 7. The only differences are
3419
* 1) version 8 db uses the blob shim to store data entries > 32k.
3420
* 2) version 8 db sets the db block size to 32k.
3421
* both of these are dealt with by the handle.
3425
UpdateV8DB(NSSLOWCERTCertDBHandle *handle, DB *updatedb)
3427
return UpdateV7DB(handle,updatedb);
3432
* we could just blindly sequence through reading key data pairs and writing
3433
* them back out, but some cert.db's have gotten quite large and may have some
3434
* subtle corruption problems, so instead we cycle through the certs and
3435
* CRL's and S/MIME profiles and rebuild our subject lists from those records.
3438
UpdateV7DB(NSSLOWCERTCertDBHandle *handle, DB *updatedb)
3442
NSSLOWCERTCertificate *cert;
3443
PRBool isKRL = PR_FALSE;
3444
certDBEntryType entryType;
3445
SECItem dbEntry, dbKey;
3446
certDBEntryRevocation crlEntry;
3447
certDBEntryCert certEntry;
3448
certDBEntrySMime smimeEntry;
3451
ret = (* updatedb->seq)(updatedb, &key, &data, R_FIRST);
3458
unsigned char *dataBuf = (unsigned char *)data.data;
3459
unsigned char *keyBuf = (unsigned char *)key.data;
3460
dbEntry.data = &dataBuf[SEC_DB_ENTRY_HEADER_LEN];
3461
dbEntry.len = data.size - SEC_DB_ENTRY_HEADER_LEN;
3462
entryType = (certDBEntryType) keyBuf[0];
3463
dbKey.data = &keyBuf[SEC_DB_KEY_HEADER_LEN];
3464
dbKey.len = key.size - SEC_DB_KEY_HEADER_LEN;
3465
if ((dbEntry.len <= 0) || (dbKey.len <= 0)) {
3469
switch (entryType) {
3470
/* these entries will get regenerated as we read the
3471
* rest of the data from the database */
3472
case certDBEntryTypeVersion:
3473
case certDBEntryTypeSubject:
3474
case certDBEntryTypeContentVersion:
3475
case certDBEntryTypeNickname:
3476
/* smime profiles need entries created after the certs have
3477
* been imported, loop over them in a second run */
3478
case certDBEntryTypeSMimeProfile:
3481
case certDBEntryTypeCert:
3483
certEntry.common.version = (unsigned int)dataBuf[0];
3484
certEntry.common.type = entryType;
3485
certEntry.common.flags = (unsigned int)dataBuf[2];
3486
rv = DecodeDBCertEntry(&certEntry,&dbEntry);
3487
if (rv != SECSuccess) {
3490
/* should we check for existing duplicates? */
3491
cert = nsslowcert_DecodeDERCertificate(&certEntry.derCert,
3492
certEntry.nickname);
3494
nsslowcert_UpdatePermCert(handle, cert, certEntry.nickname,
3496
nsslowcert_DestroyCertificate(cert);
3498
/* free any data the decode may have allocated. */
3499
pkcs11_freeStaticData(certEntry.derCert.data,
3500
certEntry.derCertSpace);
3501
pkcs11_freeNickname(certEntry.nickname, certEntry.nicknameSpace);
3504
case certDBEntryTypeKeyRevocation:
3507
case certDBEntryTypeRevocation:
3508
crlEntry.common.version = (unsigned int)dataBuf[0];
3509
crlEntry.common.type = entryType;
3510
crlEntry.common.flags = (unsigned int)dataBuf[2];
3511
crlEntry.common.arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
3512
if (crlEntry.common.arena == NULL) {
3515
rv = DecodeDBCrlEntry(&crlEntry,&dbEntry);
3516
if (rv != SECSuccess) {
3519
nsslowcert_UpdateCrl(handle, &crlEntry.derCrl, &dbKey,
3520
crlEntry.url, isKRL);
3521
/* free data allocated by the decode */
3522
PORT_FreeArena(crlEntry.common.arena, PR_FALSE);
3523
crlEntry.common.arena = NULL;
3529
} while ( (* updatedb->seq)(updatedb, &key, &data, R_NEXT) == 0 );
3531
/* now loop again updating just the SMimeProfile. */
3532
ret = (* updatedb->seq)(updatedb, &key, &data, R_FIRST);
3539
unsigned char *dataBuf = (unsigned char *)data.data;
3540
unsigned char *keyBuf = (unsigned char *)key.data;
3541
dbEntry.data = &dataBuf[SEC_DB_ENTRY_HEADER_LEN];
3542
dbEntry.len = data.size - SEC_DB_ENTRY_HEADER_LEN;
3543
entryType = (certDBEntryType) keyBuf[0];
3544
if (entryType != certDBEntryTypeSMimeProfile) {
3547
dbKey.data = &keyBuf[SEC_DB_KEY_HEADER_LEN];
3548
dbKey.len = key.size - SEC_DB_KEY_HEADER_LEN;
3549
if ((dbEntry.len <= 0) || (dbKey.len <= 0)) {
3552
smimeEntry.common.version = (unsigned int)dataBuf[0];
3553
smimeEntry.common.type = entryType;
3554
smimeEntry.common.flags = (unsigned int)dataBuf[2];
3555
smimeEntry.common.arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
3557
rv = DecodeDBSMimeEntry(&smimeEntry,&dbEntry,(char *)dbKey.data);
3558
if (rv == SECSuccess) {
3559
nsslowcert_UpdateSMimeProfile(handle, smimeEntry.emailAddr,
3560
&smimeEntry.subjectName, &smimeEntry.smimeOptions,
3561
&smimeEntry.optionsDate);
3563
PORT_FreeArena(smimeEntry.common.arena, PR_FALSE);
3564
smimeEntry.common.arena = NULL;
3565
} while ( (* updatedb->seq)(updatedb, &key, &data, R_NEXT) == 0 );
3567
(* updatedb->close)(updatedb);
3569
/* a database update is a good time to go back and verify the integrity of
3570
* the keys and certs */
3571
handle->dbVerify = PR_TRUE;
3576
* NOTE - Version 6 DB did not go out to the real world in a release,
3577
* so we can remove this function in a later release.
3580
UpdateV6DB(NSSLOWCERTCertDBHandle *handle, DB *updatedb)
3584
unsigned char *buf, *tmpbuf = NULL;
3585
certDBEntryType type;
3586
certDBEntryNickname *nnEntry = NULL;
3587
certDBEntrySubject *subjectEntry = NULL;
3588
certDBEntrySMime *emailEntry = NULL;
3594
* Sequence through the old database and copy all of the entries
3595
* to the new database. Subject name entries will have the new
3596
* fields inserted into them (with zero length).
3598
ret = (* updatedb->seq)(updatedb, &key, &data, R_FIRST);
3604
buf = (unsigned char *)data.data;
3606
if ( data.size >= 3 ) {
3607
if ( buf[0] == 6 ) { /* version number */
3608
type = (certDBEntryType)buf[1];
3609
if ( type == certDBEntryTypeSubject ) {
3610
/* expando subjecto entrieo */
3611
tmpbuf = (unsigned char *)PORT_Alloc(data.size + 4);
3613
/* copy header stuff */
3614
PORT_Memcpy(tmpbuf, buf, SEC_DB_ENTRY_HEADER_LEN + 2);
3615
/* insert 4 more bytes of zero'd header */
3616
PORT_Memset(&tmpbuf[SEC_DB_ENTRY_HEADER_LEN + 2],
3618
/* copy rest of the data */
3619
PORT_Memcpy(&tmpbuf[SEC_DB_ENTRY_HEADER_LEN + 6],
3620
&buf[SEC_DB_ENTRY_HEADER_LEN + 2],
3621
data.size - (SEC_DB_ENTRY_HEADER_LEN + 2));
3623
data.data = (void *)tmpbuf;
3627
} else if ( type == certDBEntryTypeCert ) {
3628
/* expando certo entrieo */
3629
tmpbuf = (unsigned char *)PORT_Alloc(data.size + 3);
3631
/* copy header stuff */
3632
PORT_Memcpy(tmpbuf, buf, SEC_DB_ENTRY_HEADER_LEN);
3634
/* copy trust flage, setting msb's to 0 */
3635
tmpbuf[SEC_DB_ENTRY_HEADER_LEN] = 0;
3636
tmpbuf[SEC_DB_ENTRY_HEADER_LEN+1] =
3637
buf[SEC_DB_ENTRY_HEADER_LEN];
3638
tmpbuf[SEC_DB_ENTRY_HEADER_LEN+2] = 0;
3639
tmpbuf[SEC_DB_ENTRY_HEADER_LEN+3] =
3640
buf[SEC_DB_ENTRY_HEADER_LEN+1];
3641
tmpbuf[SEC_DB_ENTRY_HEADER_LEN+4] = 0;
3642
tmpbuf[SEC_DB_ENTRY_HEADER_LEN+5] =
3643
buf[SEC_DB_ENTRY_HEADER_LEN+2];
3645
/* copy rest of the data */
3646
PORT_Memcpy(&tmpbuf[SEC_DB_ENTRY_HEADER_LEN + 6],
3647
&buf[SEC_DB_ENTRY_HEADER_LEN + 3],
3648
data.size - (SEC_DB_ENTRY_HEADER_LEN + 3));
3650
data.data = (void *)tmpbuf;
3657
/* update the record version number */
3658
buf[0] = CERT_DB_FILE_VERSION;
3660
/* copy to the new database */
3661
ret = certdb_Put(handle->permCertDB, &key, &data, 0);
3668
} while ( (* updatedb->seq)(updatedb, &key, &data, R_NEXT) == 0 );
3670
ret = certdb_Sync(handle->permCertDB, 0);
3672
ret = (* updatedb->seq)(updatedb, &key, &data, R_FIRST);
3678
buf = (unsigned char *)data.data;
3680
if ( data.size >= 3 ) {
3681
if ( buf[0] == CERT_DB_FILE_VERSION ) { /* version number */
3682
type = (certDBEntryType)buf[1];
3683
if ( type == certDBEntryTypeNickname ) {
3684
nickname = &((char *)key.data)[1];
3686
/* get the matching nickname entry in the new DB */
3687
nnEntry = ReadDBNicknameEntry(handle, nickname);
3688
if ( nnEntry == NULL ) {
3692
/* find the subject entry pointed to by nickname */
3693
subjectEntry = ReadDBSubjectEntry(handle,
3694
&nnEntry->subjectName);
3695
if ( subjectEntry == NULL ) {
3699
subjectEntry->nickname =
3700
(char *)PORT_ArenaAlloc(subjectEntry->common.arena,
3702
if ( subjectEntry->nickname ) {
3703
PORT_Memcpy(subjectEntry->nickname, nickname,
3705
rv = WriteDBSubjectEntry(handle, subjectEntry);
3707
} else if ( type == certDBEntryTypeSMimeProfile ) {
3708
emailAddr = &((char *)key.data)[1];
3710
/* get the matching smime entry in the new DB */
3711
emailEntry = nsslowcert_ReadDBSMimeEntry(handle, emailAddr);
3712
if ( emailEntry == NULL ) {
3716
/* find the subject entry pointed to by nickname */
3717
subjectEntry = ReadDBSubjectEntry(handle,
3718
&emailEntry->subjectName);
3719
if ( subjectEntry == NULL ) {
3723
subjectEntry->emailAddrs = (char **)
3724
PORT_ArenaAlloc(subjectEntry->common.arena,
3726
if ( subjectEntry->emailAddrs ) {
3727
subjectEntry->emailAddrs[0] =
3728
(char *)PORT_ArenaAlloc(subjectEntry->common.arena,
3730
if ( subjectEntry->emailAddrs[0] ) {
3731
PORT_Memcpy(subjectEntry->emailAddrs[0], emailAddr,
3733
subjectEntry->nemailAddrs = 1;
3734
rv = WriteDBSubjectEntry(handle, subjectEntry);
3740
if ( subjectEntry ) {
3741
DestroyDBEntry((certDBEntry *)subjectEntry);
3742
subjectEntry = NULL;
3745
DestroyDBEntry((certDBEntry *)nnEntry);
3749
DestroyDBEntry((certDBEntry *)emailEntry);
3754
} while ( (* updatedb->seq)(updatedb, &key, &data, R_NEXT) == 0 );
3756
ret = certdb_Sync(handle->permCertDB, 0);
3758
(* updatedb->close)(updatedb);
3764
updateV5Callback(NSSLOWCERTCertificate *cert, SECItem *k, void *pdata)
3766
NSSLOWCERTCertDBHandle *handle;
3767
certDBEntryCert *entry;
3768
NSSLOWCERTCertTrust *trust;
3770
handle = (NSSLOWCERTCertDBHandle *)pdata;
3771
trust = &cert->dbEntry->trust;
3773
/* SSL user certs can be used for email if they have an email addr */
3774
if ( cert->emailAddr && ( trust->sslFlags & CERTDB_USER ) &&
3775
( trust->emailFlags == 0 ) ) {
3776
trust->emailFlags = CERTDB_USER;
3778
/* servers didn't set the user flags on the server cert.. */
3779
if (PORT_Strcmp(cert->dbEntry->nickname,"Server-Cert") == 0) {
3780
trust->sslFlags |= CERTDB_USER;
3783
entry = AddCertToPermDB(handle, cert, cert->dbEntry->nickname,
3784
&cert->dbEntry->trust);
3786
DestroyDBEntry((certDBEntry *)entry);
3793
UpdateV5DB(NSSLOWCERTCertDBHandle *handle, DB *updatedb)
3795
NSSLOWCERTCertDBHandle updatehandle;
3798
updatehandle.permCertDB = updatedb;
3799
updatehandle.dbMon = PZ_NewMonitor(nssILockCertDB);
3800
updatehandle.dbVerify = 0;
3801
updatehandle.ref = 1; /* prevent premature close */
3803
rv = nsslowcert_TraversePermCerts(&updatehandle, updateV5Callback,
3806
PZ_DestroyMonitor(updatehandle.dbMon);
3808
(* updatedb->close)(updatedb);
3817
key.data = "Version";
3820
ret = (*db->get)(db, &key, &data, 0);
3825
if ((data.size == 1) && (*(unsigned char *)data.data <= 4)) {
3833
UpdateV4DB(NSSLOWCERTCertDBHandle *handle, DB *updatedb)
3836
certDBEntryCert *entry, *entry2;
3838
PRArenaPool *arena = NULL;
3839
NSSLOWCERTCertificate *cert;
3841
ret = (* updatedb->seq)(updatedb, &key, &data, R_FIRST);
3847
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
3848
if (arena == NULL) {
3853
if ( data.size != 1 ) { /* skip version number */
3855
/* decode the old DB entry */
3856
entry = (certDBEntryCert *)
3857
DecodeV4DBCertEntry((unsigned char*)data.data, data.size);
3860
cert = nsslowcert_DecodeDERCertificate(&entry->derCert,
3863
if ( cert != NULL ) {
3864
/* add to new database */
3865
entry2 = AddCertToPermDB(handle, cert, entry->nickname,
3868
nsslowcert_DestroyCertificate(cert);
3870
DestroyDBEntry((certDBEntry *)entry2);
3873
DestroyDBEntry((certDBEntry *)entry);
3876
} while ( (* updatedb->seq)(updatedb, &key, &data, R_NEXT) == 0 );
3878
PORT_FreeArena(arena, PR_FALSE);
3879
(* updatedb->close)(updatedb);
3885
* return true if a database key conflict exists
3888
nsslowcert_CertDBKeyConflict(SECItem *derCert, NSSLOWCERTCertDBHandle *handle)
3895
PRArenaPool *arena = NULL;
3898
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
3899
if ( arena == NULL ) {
3903
/* get the db key of the cert */
3904
rv = nsslowcert_KeyFromDERCert(arena, derCert, &derKey);
3905
if ( rv != SECSuccess ) {
3909
rv = EncodeDBCertKey(&derKey, arena, &keyitem);
3910
if ( rv != SECSuccess ) {
3914
namekey.data = keyitem.data;
3915
namekey.size = keyitem.len;
3917
ret = certdb_Get(handle->permCertDB, &namekey, &tmpdata, 0);
3922
PORT_FreeArena(arena, PR_FALSE);
3927
PORT_FreeArena(arena, PR_FALSE);
3934
* return true if a nickname conflict exists
3935
* NOTE: caller must have already made sure that this exact cert
3936
* doesn't exist in the DB
3939
nsslowcert_CertNicknameConflict(char *nickname, SECItem *derSubject,
3940
NSSLOWCERTCertDBHandle *handle)
3943
certDBEntryNickname *entry;
3945
if ( nickname == NULL ) {
3949
entry = ReadDBNicknameEntry(handle, nickname);
3951
if ( entry == NULL ) {
3952
/* no entry for this nickname, so no conflict */
3957
if ( SECITEM_CompareItem(derSubject, &entry->subjectName) == SECEqual ) {
3958
/* if subject names are the same, then no conflict */
3962
DestroyDBEntry((certDBEntry *)entry);
3966
#ifdef DBM_USING_NSPR
3967
#define NO_RDONLY PR_RDONLY
3968
#define NO_RDWR PR_RDWR
3969
#define NO_CREATE (PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE)
3971
#define NO_RDONLY O_RDONLY
3972
#define NO_RDWR O_RDWR
3973
#define NO_CREATE (O_RDWR | O_CREAT | O_TRUNC)
3977
* open an old database that needs to be updated
3980
nsslowcert_openolddb(NSSLOWCERTDBNameFunc namecb, void *cbarg, int version)
3983
DB *updatedb = NULL;
3985
tmpname = (* namecb)(cbarg, version); /* get v6 db name */
3987
updatedb = dbopen( tmpname, NO_RDONLY, 0600, DB_HASH, 0 );
3994
openNewCertDB(const char *appName, const char *prefix, const char *certdbname,
3995
NSSLOWCERTCertDBHandle *handle, NSSLOWCERTDBNameFunc namecb, void *cbarg)
3998
certDBEntryVersion *versionEntry = NULL;
3999
DB *updatedb = NULL;
4000
int status = RDB_FAIL;
4003
handle->permCertDB=rdbopen( appName, prefix, "cert", NO_CREATE, &status);
4005
handle->permCertDB=dbsopen(certdbname, NO_CREATE, 0600, DB_HASH, 0);
4008
/* if create fails then we lose */
4009
if ( handle->permCertDB == 0 ) {
4010
return status == RDB_RETRY ? SECWouldBlock : SECFailure;
4013
/* Verify version number; */
4014
versionEntry = NewDBVersionEntry(0);
4015
if ( versionEntry == NULL ) {
4020
rv = WriteDBVersionEntry(handle, versionEntry);
4022
DestroyDBEntry((certDBEntry *)versionEntry);
4024
if ( rv != SECSuccess ) {
4028
/* rv must already be Success here because of previous if statement */
4029
/* try to upgrade old db here */
4031
(updatedb = dbsopen(certdbname, NO_RDONLY, 0600, DB_HASH, 0)) != NULL) {
4032
rv = UpdateV8DB(handle, updatedb);
4033
} else if ((updatedb = nsslowcert_openolddb(namecb,cbarg,7)) != NULL) {
4034
rv = UpdateV7DB(handle, updatedb);
4035
} else if ((updatedb = nsslowcert_openolddb(namecb,cbarg,6)) != NULL) {
4036
rv = UpdateV6DB(handle, updatedb);
4037
} else if ((updatedb = nsslowcert_openolddb(namecb,cbarg,5)) != NULL) {
4038
rv = UpdateV5DB(handle, updatedb);
4039
} else if ((updatedb = nsslowcert_openolddb(namecb,cbarg,4)) != NULL) {
4040
/* NES has v5 format db's with v4 db names! */
4041
if (isV4DB(updatedb)) {
4042
rv = UpdateV4DB(handle,updatedb);
4044
rv = UpdateV5DB(handle,updatedb);
4050
db_InitComplete(handle->permCertDB);
4055
nsslowcert_GetVersionNumber( NSSLOWCERTCertDBHandle *handle)
4057
certDBEntryVersion *versionEntry = NULL;
4060
versionEntry = ReadDBVersionEntry(handle);
4061
if ( versionEntry == NULL ) {
4064
version = versionEntry->common.version;
4065
DestroyDBEntry((certDBEntry *)versionEntry);
4070
* Open the certificate database and index databases. Create them if
4071
* they are not there or bad.
4074
nsslowcert_OpenPermCertDB(NSSLOWCERTCertDBHandle *handle, PRBool readOnly,
4075
const char *appName, const char *prefix,
4076
NSSLOWCERTDBNameFunc namecb, void *cbarg)
4083
certdbname = (* namecb)(cbarg, CERT_DB_FILE_VERSION);
4084
if ( certdbname == NULL ) {
4088
openflags = readOnly ? NO_RDONLY : NO_RDWR;
4091
* first open the permanent file based database.
4094
handle->permCertDB = rdbopen( appName, prefix, "cert", openflags, NULL);
4096
handle->permCertDB = dbsopen( certdbname, openflags, 0600, DB_HASH, 0 );
4099
/* check for correct version number */
4100
if ( handle->permCertDB ) {
4101
version = nsslowcert_GetVersionNumber(handle);
4102
if ((version != CERT_DB_FILE_VERSION) &&
4103
!(appName && version == CERT_DB_V7_FILE_VERSION)) {
4106
} else if ( readOnly ) {
4107
/* don't create if readonly */
4108
/* Try openning a version 7 database */
4109
handle->permCertDB = nsslowcert_openolddb(namecb,cbarg, 7);
4110
if (!handle->permCertDB) {
4113
if (nsslowcert_GetVersionNumber(handle) != 7) {
4117
/* if first open fails, try to create a new DB */
4118
rv = openNewCertDB(appName,prefix,certdbname,handle,namecb,cbarg);
4119
if (rv == SECWouldBlock) {
4120
/* only the rdb version can fail with wouldblock */
4121
handle->permCertDB =
4122
rdbopen( appName, prefix, "cert", openflags, NULL);
4124
/* check for correct version number */
4125
if ( !handle->permCertDB ) {
4128
version = nsslowcert_GetVersionNumber(handle);
4129
if ((version != CERT_DB_FILE_VERSION) &&
4130
!(appName && version == CERT_DB_V7_FILE_VERSION)) {
4133
} else if (rv != SECSuccess) {
4138
PORT_Free(certdbname);
4140
return (SECSuccess);
4144
PORT_SetError(SEC_ERROR_BAD_DATABASE);
4146
if ( handle->permCertDB ) {
4147
certdb_Close(handle->permCertDB);
4148
handle->permCertDB = 0;
4151
PORT_Free(certdbname);
4157
* delete all DB records associated with a particular certificate
4160
DeletePermCert(NSSLOWCERTCertificate *cert)
4167
rv = DeleteDBCertEntry(cert->dbhandle, &cert->certKey);
4168
if ( rv != SECSuccess ) {
4172
rv = RemovePermSubjectNode(cert);
4179
* Delete a certificate from the permanent database.
4182
nsslowcert_DeletePermCertificate(NSSLOWCERTCertificate *cert)
4186
nsslowcert_LockDB(cert->dbhandle);
4188
/* delete the records from the permanent database */
4189
rv = DeletePermCert(cert);
4191
/* get rid of dbcert and stuff pointing to it */
4192
DestroyDBEntry((certDBEntry *)cert->dbEntry);
4193
cert->dbEntry = NULL;
4196
nsslowcert_UnlockDB(cert->dbhandle);
4201
* Traverse all of the entries in the database of a particular type
4202
* call the given function for each one.
4205
nsslowcert_TraverseDBEntries(NSSLOWCERTCertDBHandle *handle,
4206
certDBEntryType type,
4207
SECStatus (* callback)(SECItem *data, SECItem *key,
4208
certDBEntryType type, void *pdata),
4213
SECStatus rv = SECSuccess;
4218
unsigned char *keybuf;
4220
ret = certdb_Seq(handle->permCertDB, &key, &data, R_FIRST);
4224
/* here, ret is zero and rv is SECSuccess.
4225
* Below here, ret is a count of successful calls to the callback function.
4228
buf = (unsigned char *)data.data;
4230
if ( buf[1] == (unsigned char)type ) {
4231
dataitem.len = data.size;
4232
dataitem.data = buf;
4233
dataitem.type = siBuffer;
4234
keyitem.len = key.size - SEC_DB_KEY_HEADER_LEN;
4235
keybuf = (unsigned char *)key.data;
4236
keyitem.data = &keybuf[SEC_DB_KEY_HEADER_LEN];
4237
keyitem.type = siBuffer;
4238
/* type should equal keybuf[0]. */
4240
rv = (* callback)(&dataitem, &keyitem, type, udata);
4241
if ( rv == SECSuccess ) {
4245
} while ( certdb_Seq(handle->permCertDB, &key, &data, R_NEXT) == 0 );
4246
/* If any callbacks succeeded, or no calls to callbacks were made,
4247
* then report success. Otherwise, report failure.
4249
return (ret ? SECSuccess : rv);
4252
* Decode a certificate and enter it into the temporary certificate database.
4253
* Deal with nicknames correctly
4255
* This is the private entry point.
4257
static NSSLOWCERTCertificate *
4258
DecodeACert(NSSLOWCERTCertDBHandle *handle, certDBEntryCert *entry)
4260
NSSLOWCERTCertificate *cert = NULL;
4262
cert = nsslowcert_DecodeDERCertificate(&entry->derCert, entry->nickname );
4264
if ( cert == NULL ) {
4268
cert->dbhandle = handle;
4269
cert->dbEntry = entry;
4270
cert->trust = &entry->trust;
4278
static NSSLOWCERTTrust *
4281
NSSLOWCERTTrust *trust = NULL;
4283
nsslowcert_LockFreeList();
4284
trust = trustListHead;
4287
trustListHead = trust->next;
4289
PORT_Assert(trustListCount >= 0);
4290
nsslowcert_UnlockFreeList();
4295
return PORT_ZNew(NSSLOWCERTTrust);
4299
DestroyTrustFreeList(void)
4301
NSSLOWCERTTrust *trust;
4303
nsslowcert_LockFreeList();
4304
while (NULL != (trust = trustListHead)) {
4306
trustListHead = trust->next;
4309
PORT_Assert(!trustListCount);
4311
nsslowcert_UnlockFreeList();
4314
static NSSLOWCERTTrust *
4315
DecodeTrustEntry(NSSLOWCERTCertDBHandle *handle, certDBEntryCert *entry,
4316
const SECItem *dbKey)
4318
NSSLOWCERTTrust *trust = CreateTrust();
4319
if (trust == NULL) {
4322
trust->dbhandle = handle;
4323
trust->dbEntry = entry;
4324
trust->dbKey.data = pkcs11_copyStaticData(dbKey->data,dbKey->len,
4325
trust->dbKeySpace, sizeof(trust->dbKeySpace));
4326
if (!trust->dbKey.data) {
4330
trust->dbKey.len = dbKey->len;
4332
trust->trust = &entry->trust;
4333
trust->derCert = &entry->derCert;
4339
PermCertCallback certfunc;
4340
NSSLOWCERTCertDBHandle *handle;
4342
} PermCertCallbackState;
4345
* traversal callback to decode certs and call callers callback
4348
certcallback(SECItem *dbdata, SECItem *dbkey, certDBEntryType type, void *data)
4350
PermCertCallbackState *mystate;
4352
certDBEntryCert *entry;
4354
NSSLOWCERTCertificate *cert;
4355
PRArenaPool *arena = NULL;
4357
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
4358
if ( arena == NULL ) {
4362
entry = (certDBEntryCert *)PORT_ArenaAlloc(arena, sizeof(certDBEntryCert));
4363
mystate = (PermCertCallbackState *)data;
4364
entry->common.version = (unsigned int)dbdata->data[0];
4365
entry->common.type = (certDBEntryType)dbdata->data[1];
4366
entry->common.flags = (unsigned int)dbdata->data[2];
4367
entry->common.arena = arena;
4369
entryitem.len = dbdata->len - SEC_DB_ENTRY_HEADER_LEN;
4370
entryitem.data = &dbdata->data[SEC_DB_ENTRY_HEADER_LEN];
4372
rv = DecodeDBCertEntry(entry, &entryitem);
4373
if (rv != SECSuccess ) {
4376
entry->derCert.type = siBuffer;
4378
/* note: Entry is 'inheritted'. */
4379
cert = DecodeACert(mystate->handle, entry);
4381
rv = (* mystate->certfunc)(cert, dbkey, mystate->data);
4383
/* arena stored in entry destroyed by nsslowcert_DestroyCertificate */
4384
nsslowcert_DestroyCertificateNoLocking(cert);
4390
PORT_FreeArena(arena, PR_FALSE);
4396
* Traverse all of the certificates in the permanent database and
4397
* call the given function for each one; expect the caller to have lock.
4400
TraversePermCertsNoLocking(NSSLOWCERTCertDBHandle *handle,
4401
SECStatus (* certfunc)(NSSLOWCERTCertificate *cert,
4407
PermCertCallbackState mystate;
4409
mystate.certfunc = certfunc;
4410
mystate.handle = handle;
4411
mystate.data = udata;
4412
rv = nsslowcert_TraverseDBEntries(handle, certDBEntryTypeCert, certcallback,
4419
* Traverse all of the certificates in the permanent database and
4420
* call the given function for each one.
4423
nsslowcert_TraversePermCerts(NSSLOWCERTCertDBHandle *handle,
4424
SECStatus (* certfunc)(NSSLOWCERTCertificate *cert, SECItem *k,
4430
nsslowcert_LockDB(handle);
4431
rv = TraversePermCertsNoLocking(handle, certfunc, udata);
4432
nsslowcert_UnlockDB(handle);
4440
* Close the database
4443
nsslowcert_ClosePermCertDB(NSSLOWCERTCertDBHandle *handle)
4446
if ( handle->permCertDB ) {
4447
certdb_Close( handle->permCertDB );
4448
handle->permCertDB = NULL;
4450
if (handle->dbMon) {
4451
PZ_DestroyMonitor(handle->dbMon);
4452
handle->dbMon = NULL;
4460
* Get the trust attributes from a certificate
4463
nsslowcert_GetCertTrust(NSSLOWCERTCertificate *cert, NSSLOWCERTCertTrust *trust)
4467
nsslowcert_LockCertTrust(cert);
4469
if ( cert->trust == NULL ) {
4472
*trust = *cert->trust;
4476
nsslowcert_UnlockCertTrust(cert);
4481
* Change the trust attributes of a certificate and make them permanent
4485
nsslowcert_ChangeCertTrust(NSSLOWCERTCertDBHandle *handle,
4486
NSSLOWCERTCertificate *cert, NSSLOWCERTCertTrust *trust)
4488
certDBEntryCert *entry;
4492
nsslowcert_LockDB(handle);
4493
nsslowcert_LockCertTrust(cert);
4494
/* only set the trust on permanent certs */
4495
if ( cert->trust == NULL ) {
4500
*cert->trust = *trust;
4501
if ( cert->dbEntry == NULL ) {
4502
ret = SECSuccess; /* not in permanent database */
4506
entry = cert->dbEntry;
4507
entry->trust = *trust;
4509
rv = WriteDBCertEntry(handle, entry);
4518
nsslowcert_UnlockCertTrust(cert);
4519
nsslowcert_UnlockDB(handle);
4525
nsslowcert_UpdatePermCert(NSSLOWCERTCertDBHandle *dbhandle,
4526
NSSLOWCERTCertificate *cert, char *nickname, NSSLOWCERTCertTrust *trust)
4529
certDBEntryCert *entry;
4533
PORT_Assert(!cert->dbEntry);
4535
/* don't add a conflicting nickname */
4536
conflict = nsslowcert_CertNicknameConflict(nickname, &cert->derSubject,
4543
/* save old nickname so that we can delete it */
4544
oldnn = cert->nickname;
4546
entry = AddCertToPermDB(dbhandle, cert, nickname, trust);
4548
if ( entry == NULL ) {
4553
pkcs11_freeNickname(oldnn,cert->nicknameSpace);
4555
cert->nickname = (entry->nickname) ? pkcs11_copyNickname(entry->nickname,
4556
cert->nicknameSpace, sizeof(cert->nicknameSpace)) : NULL;
4557
cert->trust = &entry->trust;
4558
cert->dbEntry = entry;
4566
nsslowcert_AddPermCert(NSSLOWCERTCertDBHandle *dbhandle,
4567
NSSLOWCERTCertificate *cert, char *nickname, NSSLOWCERTCertTrust *trust)
4571
nsslowcert_LockDB(dbhandle);
4573
ret = nsslowcert_UpdatePermCert(dbhandle, cert, nickname, trust);
4575
nsslowcert_UnlockDB(dbhandle);
4580
* Open the certificate database and index databases. Create them if
4581
* they are not there or bad.
4584
nsslowcert_OpenCertDB(NSSLOWCERTCertDBHandle *handle, PRBool readOnly,
4585
const char *appName, const char *prefix,
4586
NSSLOWCERTDBNameFunc namecb, void *cbarg, PRBool openVolatile)
4590
certdb_InitDBLock(handle);
4592
handle->dbMon = PZ_NewMonitor(nssILockCertDB);
4593
PORT_Assert(handle->dbMon != NULL);
4594
handle->dbVerify = PR_FALSE;
4596
rv = nsslowcert_OpenPermCertDB(handle, readOnly, appName, prefix,
4602
return (SECSuccess);
4606
PORT_SetError(SEC_ERROR_BAD_DATABASE);
4611
nsslowcert_needDBVerify(NSSLOWCERTCertDBHandle *handle)
4613
if (!handle) return PR_FALSE;
4614
return handle->dbVerify;
4618
nsslowcert_setDBVerify(NSSLOWCERTCertDBHandle *handle, PRBool value)
4620
handle->dbVerify = value;
4625
* Lookup a certificate in the databases.
4627
static NSSLOWCERTCertificate *
4628
FindCertByKey(NSSLOWCERTCertDBHandle *handle, const SECItem *certKey, PRBool lockdb)
4630
NSSLOWCERTCertificate *cert = NULL;
4631
certDBEntryCert *entry;
4632
PRBool locked = PR_FALSE;
4636
nsslowcert_LockDB(handle);
4639
/* find in perm database */
4640
entry = ReadDBCertEntry(handle, certKey);
4642
if ( entry == NULL ) {
4647
cert = DecodeACert(handle, entry);
4652
DestroyDBEntry((certDBEntry *)entry);
4657
nsslowcert_UnlockDB(handle);
4664
* Lookup a certificate in the databases.
4666
static NSSLOWCERTTrust *
4667
FindTrustByKey(NSSLOWCERTCertDBHandle *handle, const SECItem *certKey, PRBool lockdb)
4669
NSSLOWCERTTrust *trust = NULL;
4670
certDBEntryCert *entry;
4671
PRBool locked = PR_FALSE;
4675
nsslowcert_LockDB(handle);
4678
/* find in perm database */
4679
entry = ReadDBCertEntry(handle, certKey);
4681
if ( entry == NULL ) {
4685
if (!nsslowcert_hasTrust(&entry->trust)) {
4690
trust = DecodeTrustEntry(handle, entry, certKey);
4693
if (trust == NULL) {
4695
DestroyDBEntry((certDBEntry *)entry);
4700
nsslowcert_UnlockDB(handle);
4707
* Lookup a certificate in the databases without locking
4709
NSSLOWCERTCertificate *
4710
nsslowcert_FindCertByKey(NSSLOWCERTCertDBHandle *handle, const SECItem *certKey)
4712
return(FindCertByKey(handle, certKey, PR_FALSE));
4716
* Lookup a trust object in the databases without locking
4719
nsslowcert_FindTrustByKey(NSSLOWCERTCertDBHandle *handle, const SECItem *certKey)
4721
return(FindTrustByKey(handle, certKey, PR_FALSE));
4725
* Generate a key from an issuerAndSerialNumber, and find the
4726
* associated cert in the database.
4728
NSSLOWCERTCertificate *
4729
nsslowcert_FindCertByIssuerAndSN(NSSLOWCERTCertDBHandle *handle, NSSLOWCERTIssuerAndSN *issuerAndSN)
4732
SECItem *sn = &issuerAndSN->serialNumber;
4733
SECItem *issuer = &issuerAndSN->derIssuer;
4734
NSSLOWCERTCertificate *cert;
4735
int data_left = sn->len-1;
4736
int data_len = sn->len;
4739
/* automatically detect DER encoded serial numbers and remove the der
4740
* encoding since the database expects unencoded data.
4741
* if it's DER encoded, there must be at least 3 bytes, tag, len, data */
4742
if ((sn->len >= 3) && (sn->data[0] == 0x2)) {
4743
/* remove the der encoding of the serial number before generating the
4745
data_left = sn->len-2;
4746
data_len = sn->data[1];
4749
/* extended length ? (not very likely for a serial number) */
4750
if (data_len & 0x80) {
4751
int len_count = data_len & 0x7f;
4754
data_left -= len_count;
4755
if (data_left > 0) {
4756
while (len_count --) {
4757
data_len = (data_len << 8) | sn->data[index++];
4761
/* XXX leaving any leading zeros on the serial number for backwards
4764
/* not a valid der, must be just an unlucky serial number value */
4765
if (data_len != data_left) {
4772
certKey.data = (unsigned char*)PORT_Alloc(sn->len + issuer->len);
4773
certKey.len = data_len + issuer->len;
4775
if ( certKey.data == NULL ) {
4779
/* first try the serial number as hand-decoded above*/
4780
/* copy the serialNumber */
4781
PORT_Memcpy(certKey.data, &sn->data[index], data_len);
4783
/* copy the issuer */
4784
PORT_Memcpy( &certKey.data[data_len],issuer->data,issuer->len);
4786
cert = nsslowcert_FindCertByKey(handle, &certKey);
4788
PORT_Free(certKey.data);
4792
/* didn't find it, try by der encoded serial number */
4793
/* copy the serialNumber */
4794
PORT_Memcpy(certKey.data, sn->data, sn->len);
4796
/* copy the issuer */
4797
PORT_Memcpy( &certKey.data[sn->len], issuer->data, issuer->len);
4798
certKey.len = sn->len + issuer->len;
4800
cert = nsslowcert_FindCertByKey(handle, &certKey);
4802
PORT_Free(certKey.data);
4808
* Generate a key from an issuerAndSerialNumber, and find the
4809
* associated cert in the database.
4812
nsslowcert_FindTrustByIssuerAndSN(NSSLOWCERTCertDBHandle *handle,
4813
NSSLOWCERTIssuerAndSN *issuerAndSN)
4816
SECItem *sn = &issuerAndSN->serialNumber;
4817
SECItem *issuer = &issuerAndSN->derIssuer;
4818
NSSLOWCERTTrust *trust;
4819
unsigned char keyBuf[512];
4820
int data_left = sn->len-1;
4821
int data_len = sn->len;
4825
/* automatically detect DER encoded serial numbers and remove the der
4826
* encoding since the database expects unencoded data.
4827
* if it's DER encoded, there must be at least 3 bytes, tag, len, data */
4828
if ((sn->len >= 3) && (sn->data[0] == 0x2)) {
4829
/* remove the der encoding of the serial number before generating the
4831
data_left = sn->len-2;
4832
data_len = sn->data[1];
4835
/* extended length ? (not very likely for a serial number) */
4836
if (data_len & 0x80) {
4837
int len_count = data_len & 0x7f;
4840
data_left -= len_count;
4841
if (data_left > 0) {
4842
while (len_count --) {
4843
data_len = (data_len << 8) | sn->data[index++];
4847
/* XXX leaving any leading zeros on the serial number for backwards
4850
/* not a valid der, must be just an unlucky serial number value */
4851
if (data_len != data_left) {
4858
certKey.len = data_len + issuer->len;
4859
len = sn->len + issuer->len;
4860
if (len > sizeof (keyBuf)) {
4861
certKey.data = (unsigned char*)PORT_Alloc(len);
4863
certKey.data = keyBuf;
4866
if ( certKey.data == NULL ) {
4870
/* first try the serial number as hand-decoded above*/
4871
/* copy the serialNumber */
4872
PORT_Memcpy(certKey.data, &sn->data[index], data_len);
4874
/* copy the issuer */
4875
PORT_Memcpy( &certKey.data[data_len],issuer->data,issuer->len);
4877
trust = nsslowcert_FindTrustByKey(handle, &certKey);
4879
pkcs11_freeStaticData(certKey.data, keyBuf);
4884
pkcs11_freeStaticData(certKey.data, keyBuf);
4888
/* didn't find it, try by der encoded serial number */
4889
/* copy the serialNumber */
4890
PORT_Memcpy(certKey.data, sn->data, sn->len);
4892
/* copy the issuer */
4893
PORT_Memcpy( &certKey.data[sn->len], issuer->data, issuer->len);
4894
certKey.len = sn->len + issuer->len;
4896
trust = nsslowcert_FindTrustByKey(handle, &certKey);
4898
pkcs11_freeStaticData(certKey.data, keyBuf);
4904
* look for the given DER certificate in the database
4906
NSSLOWCERTCertificate *
4907
nsslowcert_FindCertByDERCert(NSSLOWCERTCertDBHandle *handle, SECItem *derCert)
4912
NSSLOWCERTCertificate *cert = NULL;
4914
/* create a scratch arena */
4915
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
4916
if ( arena == NULL ) {
4920
/* extract the database key from the cert */
4921
rv = nsslowcert_KeyFromDERCert(arena, derCert, &certKey);
4922
if ( rv != SECSuccess ) {
4926
/* find the certificate */
4927
cert = nsslowcert_FindCertByKey(handle, &certKey);
4930
PORT_FreeArena(arena, PR_FALSE);
4935
DestroyCertificate(NSSLOWCERTCertificate *cert, PRBool lockdb)
4938
NSSLOWCERTCertDBHandle *handle;
4942
handle = cert->dbhandle;
4945
* handle may be NULL, for example if the cert was created with
4946
* nsslowcert_DecodeDERCertificate.
4948
if ( lockdb && handle ) {
4949
nsslowcert_LockDB(handle);
4952
nsslowcert_LockCertRefCount(cert);
4953
PORT_Assert(cert->referenceCount > 0);
4954
refCount = --cert->referenceCount;
4955
nsslowcert_UnlockCertRefCount(cert);
4957
if ( refCount == 0 ) {
4958
certDBEntryCert *entry = cert->dbEntry;
4961
DestroyDBEntry((certDBEntry *)entry);
4964
pkcs11_freeNickname(cert->nickname,cert->nicknameSpace);
4965
pkcs11_freeNickname(cert->emailAddr,cert->emailAddrSpace);
4966
pkcs11_freeStaticData(cert->certKey.data,cert->certKeySpace);
4967
cert->certKey.data = NULL;
4968
cert->nickname = NULL;
4970
/* zero cert before freeing. Any stale references to this cert
4971
* after this point will probably cause an exception. */
4972
PORT_Memset(cert, 0, sizeof *cert);
4974
/* use reflock to protect the free list */
4975
nsslowcert_LockFreeList();
4976
if (certListCount > MAX_CERT_LIST_COUNT) {
4980
cert->next = certListHead;
4981
certListHead = cert;
4983
nsslowcert_UnlockFreeList();
4986
if ( lockdb && handle ) {
4987
nsslowcert_UnlockDB(handle);
4994
NSSLOWCERTCertificate *
4995
nsslowcert_CreateCert(void)
4997
NSSLOWCERTCertificate *cert;
4998
nsslowcert_LockFreeList();
4999
cert = certListHead;
5001
certListHead = cert->next;
5004
PORT_Assert(certListCount >= 0);
5005
nsslowcert_UnlockFreeList();
5009
return PORT_ZNew(NSSLOWCERTCertificate);
5013
DestroyCertFreeList(void)
5015
NSSLOWCERTCertificate *cert;
5017
nsslowcert_LockFreeList();
5018
while (NULL != (cert = certListHead)) {
5020
certListHead = cert->next;
5023
PORT_Assert(!certListCount);
5025
nsslowcert_UnlockFreeList();
5029
nsslowcert_DestroyTrust(NSSLOWCERTTrust *trust)
5031
certDBEntryCert *entry = trust->dbEntry;
5034
DestroyDBEntry((certDBEntry *)entry);
5036
pkcs11_freeStaticData(trust->dbKey.data,trust->dbKeySpace);
5037
PORT_Memset(trust, 0, sizeof(*trust));
5039
nsslowcert_LockFreeList();
5040
if (trustListCount > MAX_TRUST_LIST_COUNT) {
5044
trust->next = trustListHead;
5045
trustListHead = trust;
5047
nsslowcert_UnlockFreeList();
5053
nsslowcert_DestroyCertificate(NSSLOWCERTCertificate *cert)
5055
DestroyCertificate(cert, PR_TRUE);
5060
nsslowcert_DestroyCertificateNoLocking(NSSLOWCERTCertificate *cert)
5062
DestroyCertificate(cert, PR_FALSE);
5067
* Lookup a CRL in the databases. We mirror the same fast caching data base
5068
* caching stuff used by certificates....?
5070
certDBEntryRevocation *
5071
nsslowcert_FindCrlByKey(NSSLOWCERTCertDBHandle *handle,
5072
SECItem *crlKey, PRBool isKRL)
5077
PRArenaPool *arena = NULL;
5078
certDBEntryRevocation *entry = NULL;
5079
certDBEntryType crlType = isKRL ? certDBEntryTypeKeyRevocation
5080
: certDBEntryTypeRevocation;
5082
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
5083
if ( arena == NULL ) {
5087
rv = EncodeDBGenericKey(crlKey, arena, &keyitem, crlType);
5088
if ( rv != SECSuccess ) {
5092
key.data = keyitem.data;
5093
key.size = keyitem.len;
5095
/* find in perm database */
5096
entry = ReadDBCrlEntry(handle, crlKey, crlType);
5098
if ( entry == NULL ) {
5104
PORT_FreeArena(arena, PR_FALSE);
5111
* replace the existing URL in the data base with a new one
5114
nsslowcert_UpdateCrl(NSSLOWCERTCertDBHandle *handle, SECItem *derCrl,
5115
SECItem *crlKey, char *url, PRBool isKRL)
5117
SECStatus rv = SECFailure;
5118
certDBEntryRevocation *entry = NULL;
5119
certDBEntryType crlType = isKRL ? certDBEntryTypeKeyRevocation
5120
: certDBEntryTypeRevocation;
5121
DeleteDBCrlEntry(handle, crlKey, crlType);
5123
/* Write the new entry into the data base */
5124
entry = NewDBCrlEntry(derCrl, url, crlType, 0);
5125
if (entry == NULL) goto done;
5127
rv = WriteDBCrlEntry(handle, entry, crlKey);
5128
if (rv != SECSuccess) goto done;
5132
DestroyDBEntry((certDBEntry *)entry);
5138
nsslowcert_AddCrl(NSSLOWCERTCertDBHandle *handle, SECItem *derCrl,
5139
SECItem *crlKey, char *url, PRBool isKRL)
5143
rv = nsslowcert_UpdateCrl(handle, derCrl, crlKey, url, isKRL);
5149
nsslowcert_DeletePermCRL(NSSLOWCERTCertDBHandle *handle, const SECItem *derName,
5153
certDBEntryType crlType = isKRL ? certDBEntryTypeKeyRevocation
5154
: certDBEntryTypeRevocation;
5156
rv = DeleteDBCrlEntry(handle, derName, crlType);
5157
if (rv != SECSuccess) goto done;
5165
nsslowcert_hasTrust(NSSLOWCERTCertTrust *trust)
5167
if (trust == NULL) {
5170
return !((trust->sslFlags & CERTDB_TRUSTED_UNKNOWN) &&
5171
(trust->emailFlags & CERTDB_TRUSTED_UNKNOWN) &&
5172
(trust->objectSigningFlags & CERTDB_TRUSTED_UNKNOWN));
5176
* This function has the logic that decides if another person's cert and
5177
* email profile from an S/MIME message should be saved. It can deal with
5178
* the case when there is no profile.
5181
nsslowcert_UpdateSMimeProfile(NSSLOWCERTCertDBHandle *dbhandle,
5182
char *emailAddr, SECItem *derSubject, SECItem *emailProfile,
5183
SECItem *profileTime)
5185
certDBEntrySMime *entry = NULL;
5186
SECStatus rv = SECFailure;;
5189
/* find our existing entry */
5190
entry = nsslowcert_ReadDBSMimeEntry(dbhandle, emailAddr);
5193
/* keep our old db entry consistant for old applications. */
5194
if (!SECITEM_ItemsAreEqual(derSubject, &entry->subjectName)) {
5195
nsslowcert_UpdateSubjectEmailAddr(dbhandle, &entry->subjectName,
5196
emailAddr, nsslowcert_remove);
5198
DestroyDBEntry((certDBEntry *)entry);
5202
/* now save the entry */
5203
entry = NewDBSMimeEntry(emailAddr, derSubject, emailProfile,
5205
if ( entry == NULL ) {
5210
nsslowcert_LockDB(dbhandle);
5212
rv = DeleteDBSMimeEntry(dbhandle, emailAddr);
5213
/* if delete fails, try to write new entry anyway... */
5215
/* link subject entry back here */
5216
rv = nsslowcert_UpdateSubjectEmailAddr(dbhandle, derSubject, emailAddr,
5218
if ( rv != SECSuccess ) {
5219
nsslowcert_UnlockDB(dbhandle);
5223
rv = WriteDBSMimeEntry(dbhandle, entry);
5224
if ( rv != SECSuccess ) {
5225
nsslowcert_UnlockDB(dbhandle);
5229
nsslowcert_UnlockDB(dbhandle);
5235
DestroyDBEntry((certDBEntry *)entry);
5241
nsslowcert_SaveSMimeProfile(NSSLOWCERTCertDBHandle *dbhandle, char *emailAddr,
5242
SECItem *derSubject, SECItem *emailProfile, SECItem *profileTime)
5244
SECStatus rv = SECFailure;;
5247
rv = nsslowcert_UpdateSMimeProfile(dbhandle, emailAddr,
5248
derSubject, emailProfile, profileTime);
5254
nsslowcert_DestroyFreeLists(void)
5256
if (freeListLock == NULL) {
5259
DestroyCertEntryFreeList();
5260
DestroyTrustFreeList();
5261
DestroyCertFreeList();
5262
SKIP_AFTER_FORK(PZ_DestroyLock(freeListLock));
5263
freeListLock = NULL;
5267
nsslowcert_DestroyGlobalLocks(void)
5270
SKIP_AFTER_FORK(PZ_DestroyLock(dbLock));
5273
if (certRefCountLock) {
5274
SKIP_AFTER_FORK(PZ_DestroyLock(certRefCountLock));
5275
certRefCountLock = NULL;
5277
if (certTrustLock) {
5278
SKIP_AFTER_FORK(PZ_DestroyLock(certTrustLock));
5279
certTrustLock = NULL;
5284
nsslowcert_DecodeAnyDBEntry(SECItem *dbData, const SECItem *dbKey,
5285
certDBEntryType entryType, void *pdata)
5287
PLArenaPool *arena = NULL;
5293
if ((dbData->len < SEC_DB_ENTRY_HEADER_LEN) || (dbKey->len == 0)) {
5294
PORT_SetError(SEC_ERROR_INVALID_ARGS);
5297
dbEntry.data = &dbData->data[SEC_DB_ENTRY_HEADER_LEN];
5298
dbEntry.len = dbData->len - SEC_DB_ENTRY_HEADER_LEN;
5300
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
5301
if (arena == NULL) {
5304
entry = PORT_ArenaZNew(arena, certDBEntry);
5308
entry->common.version = (unsigned int)dbData->data[0];
5309
entry->common.flags = (unsigned int)dbData->data[2];
5310
entry->common.type = entryType;
5311
entry->common.arena = arena;
5313
switch (entryType) {
5314
case certDBEntryTypeContentVersion: /* This type appears to be unused */
5315
case certDBEntryTypeVersion: /* This type has only the common hdr */
5319
case certDBEntryTypeSubject:
5320
rv = DecodeDBSubjectEntry(&entry->subject, &dbEntry, dbKey);
5323
case certDBEntryTypeNickname:
5324
rv = DecodeDBNicknameEntry(&entry->nickname, &dbEntry,
5325
(char *)dbKey->data);
5328
/* smime profiles need entries created after the certs have
5329
* been imported, loop over them in a second run */
5330
case certDBEntryTypeSMimeProfile:
5331
rv = DecodeDBSMimeEntry(&entry->smime, &dbEntry, (char *)dbKey->data);
5334
case certDBEntryTypeCert:
5335
rv = DecodeDBCertEntry(&entry->cert, &dbEntry);
5338
case certDBEntryTypeKeyRevocation:
5339
case certDBEntryTypeRevocation:
5340
rv = DecodeDBCrlEntry(&entry->revocation, &dbEntry);
5344
PORT_SetError(SEC_ERROR_INVALID_ARGS);
5348
if (rv == SECSuccess)
5353
PORT_FreeArena(arena, PR_FALSE);