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