~ubuntu-branches/ubuntu/quantal/nss/quantal-updates

« back to all changes in this revision

Viewing changes to mozilla/security/nss/lib/softoken/legacydb/pcertdb.c

  • Committer: Package Import Robot
  • Author(s): Marc Deslauriers
  • Date: 2013-11-14 14:58:07 UTC
  • mfrom: (1.1.19)
  • Revision ID: package-import@ubuntu.com-20131114145807-vj6v4erz8xj6kwz3
Tags: 3.15.3-0ubuntu0.12.10.1
* SECURITY UPDATE: New upstream release to fix multiple security issues
  and add TLSv1.2 support.
  - CVE-2013-1739
  - CVE-2013-1741
  - CVE-2013-5605
  - CVE-2013-5606
* Adjusted packaging for 3.15.3:
  - debian/patches/*: refreshed.
  - debian/patches/lower-dhe-priority.patch: removed, no longer needed,
    was a workaround for an old version of firefox.
  - debian/libnss3.symbols: added new symbols.
  - debian/rules: updated for new source layout.

Show diffs side-by-side

added added

removed removed

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