security/nss/cmd/dbck/dbrecover.c

branch
TOR_BUG_9701
changeset 3
141e0f1194b1
equal deleted inserted replaced
-1:000000000000 0:bb117a278f4a
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 enum {
6 dbInvalidCert = 0,
7 dbNoSMimeProfile,
8 dbOlderCert,
9 dbBadCertificate,
10 dbCertNotWrittenToDB
11 };
12
13 typedef struct dbRestoreInfoStr
14 {
15 NSSLOWCERTCertDBHandle *handle;
16 PRBool verbose;
17 PRFileDesc *out;
18 int nCerts;
19 int nOldCerts;
20 int dbErrors[5];
21 PRBool removeType[3];
22 PRBool promptUser[3];
23 } dbRestoreInfo;
24
25 char *
26 IsEmailCert(CERTCertificate *cert)
27 {
28 char *email, *tmp1, *tmp2;
29 PRBool isCA;
30 int len;
31
32 if (!cert->subjectName) {
33 return NULL;
34 }
35
36 tmp1 = PORT_Strstr(cert->subjectName, "E=");
37 tmp2 = PORT_Strstr(cert->subjectName, "MAIL=");
38 /* XXX Nelson has cert for KTrilli which does not have either
39 * of above but is email cert (has cert->emailAddr).
40 */
41 if (!tmp1 && !tmp2 && !(cert->emailAddr && cert->emailAddr[0])) {
42 return NULL;
43 }
44
45 /* Server or CA cert, not personal email. */
46 isCA = CERT_IsCACert(cert, NULL);
47 if (isCA)
48 return NULL;
49
50 /* XXX CERT_IsCACert advertises checking the key usage ext.,
51 but doesn't appear to. */
52 /* Check the key usage extension. */
53 if (cert->keyUsagePresent) {
54 /* Must at least be able to sign or encrypt (not neccesarily
55 * both if it is one of a dual cert).
56 */
57 if (!((cert->rawKeyUsage & KU_DIGITAL_SIGNATURE) ||
58 (cert->rawKeyUsage & KU_KEY_ENCIPHERMENT)))
59 return NULL;
60
61 /* CA cert, not personal email. */
62 if (cert->rawKeyUsage & (KU_KEY_CERT_SIGN | KU_CRL_SIGN))
63 return NULL;
64 }
65
66 if (cert->emailAddr && cert->emailAddr[0]) {
67 email = PORT_Strdup(cert->emailAddr);
68 } else {
69 if (tmp1)
70 tmp1 += 2; /* "E=" */
71 else
72 tmp1 = tmp2 + 5; /* "MAIL=" */
73 len = strcspn(tmp1, ", ");
74 email = (char*)PORT_Alloc(len+1);
75 PORT_Strncpy(email, tmp1, len);
76 email[len] = '\0';
77 }
78
79 return email;
80 }
81
82 SECStatus
83 deleteit(CERTCertificate *cert, void *arg)
84 {
85 return SEC_DeletePermCertificate(cert);
86 }
87
88 /* Different than DeleteCertificate - has the added bonus of removing
89 * all certs with the same DN.
90 */
91 SECStatus
92 deleteAllEntriesForCert(NSSLOWCERTCertDBHandle *handle, CERTCertificate *cert,
93 PRFileDesc *outfile)
94 {
95 #if 0
96 certDBEntrySubject *subjectEntry;
97 certDBEntryNickname *nicknameEntry;
98 certDBEntrySMime *smimeEntry;
99 int i;
100 #endif
101
102 if (outfile) {
103 PR_fprintf(outfile, "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n\n");
104 PR_fprintf(outfile, "Deleting redundant certificate:\n");
105 dumpCertificate(cert, -1, outfile);
106 }
107
108 CERT_TraverseCertsForSubject(handle, cert->subjectList, deleteit, NULL);
109 #if 0
110 CERT_LockDB(handle);
111 subjectEntry = ReadDBSubjectEntry(handle, &cert->derSubject);
112 /* It had better be there, or created a bad db. */
113 PORT_Assert(subjectEntry);
114 for (i=0; i<subjectEntry->ncerts; i++) {
115 DeleteDBCertEntry(handle, &subjectEntry->certKeys[i]);
116 }
117 DeleteDBSubjectEntry(handle, &cert->derSubject);
118 if (subjectEntry->emailAddr && subjectEntry->emailAddr[0]) {
119 smimeEntry = ReadDBSMimeEntry(handle, subjectEntry->emailAddr);
120 if (smimeEntry) {
121 if (SECITEM_ItemsAreEqual(&subjectEntry->derSubject,
122 &smimeEntry->subjectName))
123 /* Only delete it if it's for this subject! */
124 DeleteDBSMimeEntry(handle, subjectEntry->emailAddr);
125 SEC_DestroyDBEntry((certDBEntry*)smimeEntry);
126 }
127 }
128 if (subjectEntry->nickname) {
129 nicknameEntry = ReadDBNicknameEntry(handle, subjectEntry->nickname);
130 if (nicknameEntry) {
131 if (SECITEM_ItemsAreEqual(&subjectEntry->derSubject,
132 &nicknameEntry->subjectName))
133 /* Only delete it if it's for this subject! */
134 DeleteDBNicknameEntry(handle, subjectEntry->nickname);
135 SEC_DestroyDBEntry((certDBEntry*)nicknameEntry);
136 }
137 }
138 SEC_DestroyDBEntry((certDBEntry*)subjectEntry);
139 CERT_UnlockDB(handle);
140 #endif
141 return SECSuccess;
142 }
143
144 void
145 getCertsToDelete(char *numlist, int len, int *certNums, int nCerts)
146 {
147 int j, num;
148 char *numstr, *numend, *end;
149
150 numstr = numlist;
151 end = numstr + len - 1;
152 while (numstr != end) {
153 numend = strpbrk(numstr, ", \n");
154 *numend = '\0';
155 if (PORT_Strlen(numstr) == 0)
156 return;
157 num = PORT_Atoi(numstr);
158 if (numstr == numlist)
159 certNums[0] = num;
160 for (j=1; j<nCerts+1; j++) {
161 if (num == certNums[j]) {
162 certNums[j] = -1;
163 break;
164 }
165 }
166 if (numend == end)
167 break;
168 numstr = strpbrk(numend+1, "0123456789");
169 }
170 }
171
172 PRBool
173 userSaysDeleteCert(CERTCertificate **certs, int nCerts,
174 int errtype, dbRestoreInfo *info, int *certNums)
175 {
176 char response[32];
177 PRInt32 nb;
178 int i;
179 /* User wants to remove cert without prompting. */
180 if (info->promptUser[errtype] == PR_FALSE)
181 return (info->removeType[errtype]);
182 switch (errtype) {
183 case dbInvalidCert:
184 PR_fprintf(PR_STDOUT, "******** Expired ********\n");
185 PR_fprintf(PR_STDOUT, "Cert has expired.\n\n");
186 dumpCertificate(certs[0], -1, PR_STDOUT);
187 PR_fprintf(PR_STDOUT,
188 "Keep it? (y/n - this one, Y/N - all expired certs) [n] ");
189 break;
190 case dbNoSMimeProfile:
191 PR_fprintf(PR_STDOUT, "******** No Profile ********\n");
192 PR_fprintf(PR_STDOUT, "S/MIME cert has no profile.\n\n");
193 dumpCertificate(certs[0], -1, PR_STDOUT);
194 PR_fprintf(PR_STDOUT,
195 "Keep it? (y/n - this one, Y/N - all S/MIME w/o profile) [n] ");
196 break;
197 case dbOlderCert:
198 PR_fprintf(PR_STDOUT, "******* Redundant nickname/email *******\n\n");
199 PR_fprintf(PR_STDOUT, "These certs have the same nickname/email:\n");
200 for (i=0; i<nCerts; i++)
201 dumpCertificate(certs[i], i, PR_STDOUT);
202 PR_fprintf(PR_STDOUT,
203 "Enter the certs you would like to keep from those listed above.\n");
204 PR_fprintf(PR_STDOUT,
205 "Use a comma-separated list of the cert numbers (ex. 0, 8, 12).\n");
206 PR_fprintf(PR_STDOUT,
207 "The first cert in the list will be the primary cert\n");
208 PR_fprintf(PR_STDOUT,
209 " accessed by the nickname/email handle.\n");
210 PR_fprintf(PR_STDOUT,
211 "List cert numbers to keep here, or hit enter\n");
212 PR_fprintf(PR_STDOUT,
213 " to always keep only the newest cert: ");
214 break;
215 default:
216 }
217 nb = PR_Read(PR_STDIN, response, sizeof(response));
218 PR_fprintf(PR_STDOUT, "\n\n");
219 if (errtype == dbOlderCert) {
220 if (!isdigit(response[0])) {
221 info->promptUser[errtype] = PR_FALSE;
222 info->removeType[errtype] = PR_TRUE;
223 return PR_TRUE;
224 }
225 getCertsToDelete(response, nb, certNums, nCerts);
226 return PR_TRUE;
227 }
228 /* User doesn't want to be prompted for this type anymore. */
229 if (response[0] == 'Y') {
230 info->promptUser[errtype] = PR_FALSE;
231 info->removeType[errtype] = PR_FALSE;
232 return PR_FALSE;
233 } else if (response[0] == 'N') {
234 info->promptUser[errtype] = PR_FALSE;
235 info->removeType[errtype] = PR_TRUE;
236 return PR_TRUE;
237 }
238 return (response[0] != 'y') ? PR_TRUE : PR_FALSE;
239 }
240
241 SECStatus
242 addCertToDB(certDBEntryCert *certEntry, dbRestoreInfo *info,
243 NSSLOWCERTCertDBHandle *oldhandle)
244 {
245 SECStatus rv = SECSuccess;
246 PRBool allowOverride;
247 PRBool userCert;
248 SECCertTimeValidity validity;
249 CERTCertificate *oldCert = NULL;
250 CERTCertificate *dbCert = NULL;
251 CERTCertificate *newCert = NULL;
252 CERTCertTrust *trust;
253 certDBEntrySMime *smimeEntry = NULL;
254 char *email = NULL;
255 char *nickname = NULL;
256 int nCertsForSubject = 1;
257
258 oldCert = CERT_DecodeDERCertificate(&certEntry->derCert, PR_FALSE,
259 certEntry->nickname);
260 if (!oldCert) {
261 info->dbErrors[dbBadCertificate]++;
262 SEC_DestroyDBEntry((certDBEntry*)certEntry);
263 return SECSuccess;
264 }
265
266 oldCert->dbEntry = certEntry;
267 oldCert->trust = &certEntry->trust;
268 oldCert->dbhandle = oldhandle;
269
270 trust = oldCert->trust;
271
272 info->nOldCerts++;
273
274 if (info->verbose)
275 PR_fprintf(info->out, "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n\n");
276
277 if (oldCert->nickname)
278 nickname = PORT_Strdup(oldCert->nickname);
279
280 /* Always keep user certs. Skip ahead. */
281 /* XXX if someone sends themselves a signed message, it is possible
282 for their cert to be imported as an "other" cert, not a user cert.
283 this mucks with smime entries... */
284 userCert = (SEC_GET_TRUST_FLAGS(trust, trustSSL) & CERTDB_USER) ||
285 (SEC_GET_TRUST_FLAGS(trust, trustEmail) & CERTDB_USER) ||
286 (SEC_GET_TRUST_FLAGS(trust, trustObjectSigning) & CERTDB_USER);
287 if (userCert)
288 goto createcert;
289
290 /* If user chooses so, ignore expired certificates. */
291 allowOverride = (PRBool)((oldCert->keyUsage == certUsageSSLServer) ||
292 (oldCert->keyUsage == certUsageSSLServerWithStepUp));
293 validity = CERT_CheckCertValidTimes(oldCert, PR_Now(), allowOverride);
294 /* If cert expired and user wants to delete it, ignore it. */
295 if ((validity != secCertTimeValid) &&
296 userSaysDeleteCert(&oldCert, 1, dbInvalidCert, info, 0)) {
297 info->dbErrors[dbInvalidCert]++;
298 if (info->verbose) {
299 PR_fprintf(info->out, "Deleting expired certificate:\n");
300 dumpCertificate(oldCert, -1, info->out);
301 }
302 goto cleanup;
303 }
304
305 /* New database will already have default certs, don't attempt
306 to overwrite them. */
307 dbCert = CERT_FindCertByDERCert(info->handle, &oldCert->derCert);
308 if (dbCert) {
309 info->nCerts++;
310 if (info->verbose) {
311 PR_fprintf(info->out, "Added certificate to database:\n");
312 dumpCertificate(oldCert, -1, info->out);
313 }
314 goto cleanup;
315 }
316
317 /* Determine if cert is S/MIME and get its email if so. */
318 email = IsEmailCert(oldCert);
319
320 /*
321 XXX Just create empty profiles?
322 if (email) {
323 SECItem *profile = CERT_FindSMimeProfile(oldCert);
324 if (!profile &&
325 userSaysDeleteCert(&oldCert, 1, dbNoSMimeProfile, info, 0)) {
326 info->dbErrors[dbNoSMimeProfile]++;
327 if (info->verbose) {
328 PR_fprintf(info->out,
329 "Deleted cert missing S/MIME profile.\n");
330 dumpCertificate(oldCert, -1, info->out);
331 }
332 goto cleanup;
333 } else {
334 SECITEM_FreeItem(profile);
335 }
336 }
337 */
338
339 createcert:
340
341 /* Sometimes happens... */
342 if (!nickname && userCert)
343 nickname = PORT_Strdup(oldCert->subjectName);
344
345 /* Create a new certificate, copy of the old one. */
346 newCert = CERT_NewTempCertificate(info->handle, &oldCert->derCert,
347 nickname, PR_FALSE, PR_TRUE);
348 if (!newCert) {
349 PR_fprintf(PR_STDERR, "Unable to create new certificate.\n");
350 dumpCertificate(oldCert, -1, PR_STDERR);
351 info->dbErrors[dbBadCertificate]++;
352 goto cleanup;
353 }
354
355 /* Add the cert to the new database. */
356 rv = CERT_AddTempCertToPerm(newCert, nickname, oldCert->trust);
357 if (rv) {
358 PR_fprintf(PR_STDERR, "Failed to write temp cert to perm database.\n");
359 dumpCertificate(oldCert, -1, PR_STDERR);
360 info->dbErrors[dbCertNotWrittenToDB]++;
361 goto cleanup;
362 }
363
364 if (info->verbose) {
365 PR_fprintf(info->out, "Added certificate to database:\n");
366 dumpCertificate(oldCert, -1, info->out);
367 }
368
369 /* If the cert is an S/MIME cert, and the first with it's subject,
370 * modify the subject entry to include the email address,
371 * CERT_AddTempCertToPerm does not do email addresses and S/MIME entries.
372 */
373 if (smimeEntry) { /*&& !userCert && nCertsForSubject == 1) { */
374 #if 0
375 UpdateSubjectWithEmailAddr(newCert, email);
376 #endif
377 SECItem emailProfile, profileTime;
378 rv = CERT_FindFullSMimeProfile(oldCert, &emailProfile, &profileTime);
379 /* calls UpdateSubjectWithEmailAddr */
380 if (rv == SECSuccess)
381 rv = CERT_SaveSMimeProfile(newCert, &emailProfile, &profileTime);
382 }
383
384 info->nCerts++;
385
386 cleanup:
387
388 if (nickname)
389 PORT_Free(nickname);
390 if (email)
391 PORT_Free(email);
392 if (oldCert)
393 CERT_DestroyCertificate(oldCert);
394 if (dbCert)
395 CERT_DestroyCertificate(dbCert);
396 if (newCert)
397 CERT_DestroyCertificate(newCert);
398 if (smimeEntry)
399 SEC_DestroyDBEntry((certDBEntry*)smimeEntry);
400 return SECSuccess;
401 }
402
403 #if 0
404 SECStatus
405 copyDBEntry(SECItem *data, SECItem *key, certDBEntryType type, void *pdata)
406 {
407 SECStatus rv;
408 NSSLOWCERTCertDBHandle *newdb = (NSSLOWCERTCertDBHandle *)pdata;
409 certDBEntryCommon common;
410 SECItem dbkey;
411
412 common.type = type;
413 common.version = CERT_DB_FILE_VERSION;
414 common.flags = data->data[2];
415 common.arena = NULL;
416
417 dbkey.len = key->len + SEC_DB_KEY_HEADER_LEN;
418 dbkey.data = (unsigned char *)PORT_Alloc(dbkey.len*sizeof(unsigned char));
419 PORT_Memcpy(&dbkey.data[SEC_DB_KEY_HEADER_LEN], key->data, key->len);
420 dbkey.data[0] = type;
421
422 rv = WriteDBEntry(newdb, &common, &dbkey, data);
423
424 PORT_Free(dbkey.data);
425 return rv;
426 }
427 #endif
428
429 int
430 certIsOlder(CERTCertificate **cert1, CERTCertificate** cert2)
431 {
432 return !CERT_IsNewer(*cert1, *cert2);
433 }
434
435 int
436 findNewestSubjectForEmail(NSSLOWCERTCertDBHandle *handle, int subjectNum,
437 certDBArray *dbArray, dbRestoreInfo *info,
438 int *subjectWithSMime, int *smimeForSubject)
439 {
440 int newestSubject;
441 int subjectsForEmail[50];
442 int i, j, ns, sNum;
443 certDBEntryListNode *subjects = &dbArray->subjects;
444 certDBEntryListNode *smime = &dbArray->smime;
445 certDBEntrySubject *subjectEntry1, *subjectEntry2;
446 certDBEntrySMime *smimeEntry;
447 CERTCertificate **certs;
448 CERTCertificate *cert;
449 CERTCertTrust *trust;
450 PRBool userCert;
451 int *certNums;
452
453 ns = 0;
454 subjectEntry1 = (certDBEntrySubject*)&subjects.entries[subjectNum];
455 subjectsForEmail[ns++] = subjectNum;
456
457 *subjectWithSMime = -1;
458 *smimeForSubject = -1;
459 newestSubject = subjectNum;
460
461 cert = CERT_FindCertByKey(handle, &subjectEntry1->certKeys[0]);
462 if (cert) {
463 trust = cert->trust;
464 userCert = (SEC_GET_TRUST_FLAGS(trust, trustSSL) & CERTDB_USER) ||
465 (SEC_GET_TRUST_FLAGS(trust, trustEmail) & CERTDB_USER) ||
466 (SEC_GET_TRUST_FLAGS(trust, trustObjectSigning) & CERTDB_USER);
467 CERT_DestroyCertificate(cert);
468 }
469
470 /*
471 * XXX Should we make sure that subjectEntry1->emailAddr is not
472 * a null pointer or an empty string before going into the next
473 * two for loops, which pass it to PORT_Strcmp?
474 */
475
476 /* Loop over the remaining subjects. */
477 for (i=subjectNum+1; i<subjects.numEntries; i++) {
478 subjectEntry2 = (certDBEntrySubject*)&subjects.entries[i];
479 if (!subjectEntry2)
480 continue;
481 if (subjectEntry2->emailAddr && subjectEntry2->emailAddr[0] &&
482 PORT_Strcmp(subjectEntry1->emailAddr,
483 subjectEntry2->emailAddr) == 0) {
484 /* Found a subject using the same email address. */
485 subjectsForEmail[ns++] = i;
486 }
487 }
488
489 /* Find the S/MIME entry for this email address. */
490 for (i=0; i<smime.numEntries; i++) {
491 smimeEntry = (certDBEntrySMime*)&smime.entries[i];
492 if (smimeEntry->common.arena == NULL)
493 continue;
494 if (smimeEntry->emailAddr && smimeEntry->emailAddr[0] &&
495 PORT_Strcmp(subjectEntry1->emailAddr, smimeEntry->emailAddr) == 0) {
496 /* Find which of the subjects uses this S/MIME entry. */
497 for (j=0; j<ns && *subjectWithSMime < 0; j++) {
498 sNum = subjectsForEmail[j];
499 subjectEntry2 = (certDBEntrySubject*)&subjects.entries[sNum];
500 if (SECITEM_ItemsAreEqual(&smimeEntry->subjectName,
501 &subjectEntry2->derSubject)) {
502 /* Found the subject corresponding to the S/MIME entry. */
503 *subjectWithSMime = sNum;
504 *smimeForSubject = i;
505 }
506 }
507 SEC_DestroyDBEntry((certDBEntry*)smimeEntry);
508 PORT_Memset(smimeEntry, 0, sizeof(certDBEntry));
509 break;
510 }
511 }
512
513 if (ns <= 1)
514 return subjectNum;
515
516 if (userCert)
517 return *subjectWithSMime;
518
519 /* Now find which of the subjects has the newest cert. */
520 certs = (CERTCertificate**)PORT_Alloc(ns*sizeof(CERTCertificate*));
521 certNums = (int*)PORT_Alloc((ns+1)*sizeof(int));
522 certNums[0] = 0;
523 for (i=0; i<ns; i++) {
524 sNum = subjectsForEmail[i];
525 subjectEntry1 = (certDBEntrySubject*)&subjects.entries[sNum];
526 certs[i] = CERT_FindCertByKey(handle, &subjectEntry1->certKeys[0]);
527 certNums[i+1] = i;
528 }
529 /* Sort the array by validity. */
530 qsort(certs, ns, sizeof(CERTCertificate*),
531 (int (*)(const void *, const void *))certIsOlder);
532 newestSubject = -1;
533 for (i=0; i<ns; i++) {
534 sNum = subjectsForEmail[i];
535 subjectEntry1 = (certDBEntrySubject*)&subjects.entries[sNum];
536 if (SECITEM_ItemsAreEqual(&subjectEntry1->derSubject,
537 &certs[0]->derSubject))
538 newestSubject = sNum;
539 else
540 SEC_DestroyDBEntry((certDBEntry*)subjectEntry1);
541 }
542 if (info && userSaysDeleteCert(certs, ns, dbOlderCert, info, certNums)) {
543 for (i=1; i<ns+1; i++) {
544 if (certNums[i] >= 0 && certNums[i] != certNums[0]) {
545 deleteAllEntriesForCert(handle, certs[certNums[i]], info->out);
546 info->dbErrors[dbOlderCert]++;
547 }
548 }
549 }
550 CERT_DestroyCertArray(certs, ns);
551 return newestSubject;
552 }
553
554 NSSLOWCERTCertDBHandle *
555 DBCK_ReconstructDBFromCerts(NSSLOWCERTCertDBHandle *oldhandle, char *newdbname,
556 PRFileDesc *outfile, PRBool removeExpired,
557 PRBool requireProfile, PRBool singleEntry,
558 PRBool promptUser)
559 {
560 SECStatus rv;
561 dbRestoreInfo info;
562 certDBEntryContentVersion *oldContentVersion;
563 certDBArray dbArray;
564 int i;
565
566 PORT_Memset(&dbArray, 0, sizeof(dbArray));
567 PORT_Memset(&info, 0, sizeof(info));
568 info.verbose = (outfile) ? PR_TRUE : PR_FALSE;
569 info.out = (outfile) ? outfile : PR_STDOUT;
570 info.removeType[dbInvalidCert] = removeExpired;
571 info.removeType[dbNoSMimeProfile] = requireProfile;
572 info.removeType[dbOlderCert] = singleEntry;
573 info.promptUser[dbInvalidCert] = promptUser;
574 info.promptUser[dbNoSMimeProfile] = promptUser;
575 info.promptUser[dbOlderCert] = promptUser;
576
577 /* Allocate a handle to fill with CERT_OpenCertDB below. */
578 info.handle = PORT_ZNew(NSSLOWCERTCertDBHandle);
579 if (!info.handle) {
580 fprintf(stderr, "unable to get database handle");
581 return NULL;
582 }
583
584 /* Create a certdb with the most recent set of roots. */
585 rv = CERT_OpenCertDBFilename(info.handle, newdbname, PR_FALSE);
586
587 if (rv) {
588 fprintf(stderr, "could not open certificate database");
589 goto loser;
590 }
591
592 /* Create certificate, subject, nickname, and email records.
593 * mcom_db seems to have a sequential access bug. Though reads and writes
594 * should be allowed during traversal, they seem to screw up the sequence.
595 * So, stuff all the cert entries into an array, and loop over the array
596 * doing read/writes in the db.
597 */
598 fillDBEntryArray(oldhandle, certDBEntryTypeCert, &dbArray.certs);
599 for (elem = PR_LIST_HEAD(&dbArray->certs.link);
600 elem != &dbArray->certs.link; elem = PR_NEXT_LINK(elem)) {
601 node = LISTNODE_CAST(elem);
602 addCertToDB((certDBEntryCert*)&node->entry, &info, oldhandle);
603 /* entries get destroyed in addCertToDB */
604 }
605 #if 0
606 rv = nsslowcert_TraverseDBEntries(oldhandle, certDBEntryTypeSMimeProfile,
607 copyDBEntry, info.handle);
608 #endif
609
610 /* Fix up the pointers between (nickname|S/MIME) --> (subject).
611 * Create S/MIME entries for S/MIME certs.
612 * Have the S/MIME entry point to the last-expiring cert using
613 * an email address.
614 */
615 #if 0
616 CERT_RedoHandlesForSubjects(info.handle, singleEntry, &info);
617 #endif
618
619 freeDBEntryList(&dbArray.certs.link);
620
621 /* Copy over the version record. */
622 /* XXX Already exists - and _must_ be correct... */
623 /*
624 versionEntry = ReadDBVersionEntry(oldhandle);
625 rv = WriteDBVersionEntry(info.handle, versionEntry);
626 */
627
628 /* Copy over the content version record. */
629 /* XXX Can probably get useful info from old content version?
630 * Was this db created before/after this tool? etc.
631 */
632 #if 0
633 oldContentVersion = ReadDBContentVersionEntry(oldhandle);
634 CERT_SetDBContentVersion(oldContentVersion->contentVersion, info.handle);
635 #endif
636
637 #if 0
638 /* Copy over the CRL & KRL records. */
639 rv = nsslowcert_TraverseDBEntries(oldhandle, certDBEntryTypeRevocation,
640 copyDBEntry, info.handle);
641 /* XXX Only one KRL, just do db->get? */
642 rv = nsslowcert_TraverseDBEntries(oldhandle, certDBEntryTypeKeyRevocation,
643 copyDBEntry, info.handle);
644 #endif
645
646 PR_fprintf(info.out, "Database had %d certificates.\n", info.nOldCerts);
647
648 PR_fprintf(info.out, "Reconstructed %d certificates.\n", info.nCerts);
649 PR_fprintf(info.out, "(ax) Rejected %d expired certificates.\n",
650 info.dbErrors[dbInvalidCert]);
651 PR_fprintf(info.out, "(as) Rejected %d S/MIME certificates missing a profile.\n",
652 info.dbErrors[dbNoSMimeProfile]);
653 PR_fprintf(info.out, "(ar) Rejected %d certificates for which a newer certificate was found.\n",
654 info.dbErrors[dbOlderCert]);
655 PR_fprintf(info.out, " Rejected %d corrupt certificates.\n",
656 info.dbErrors[dbBadCertificate]);
657 PR_fprintf(info.out, " Rejected %d certificates which did not write to the DB.\n",
658 info.dbErrors[dbCertNotWrittenToDB]);
659
660 if (rv)
661 goto loser;
662
663 return info.handle;
664
665 loser:
666 if (info.handle)
667 PORT_Free(info.handle);
668 return NULL;
669 }
670

mercurial