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