OLD | NEW |
| (Empty) |
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 #include "prtime.h" | |
6 | |
7 #include "cert.h" | |
8 #include "certi.h" | |
9 #include "certdb.h" | |
10 #include "secitem.h" | |
11 #include "secder.h" | |
12 | |
13 /* Call to PK11_FreeSlot below */ | |
14 | |
15 #include "secasn1.h" | |
16 #include "secerr.h" | |
17 #include "nssilock.h" | |
18 #include "prmon.h" | |
19 #include "base64.h" | |
20 #include "sechash.h" | |
21 #include "plhash.h" | |
22 #include "pk11func.h" /* sigh */ | |
23 | |
24 #include "nsspki.h" | |
25 #include "pki.h" | |
26 #include "pkim.h" | |
27 #include "pki3hack.h" | |
28 #include "ckhelper.h" | |
29 #include "base.h" | |
30 #include "pkistore.h" | |
31 #include "dev3hack.h" | |
32 #include "dev.h" | |
33 | |
34 PRBool | |
35 SEC_CertNicknameConflict(const char *nickname, const SECItem *derSubject, | |
36 CERTCertDBHandle *handle) | |
37 { | |
38 CERTCertificate *cert; | |
39 PRBool conflict = PR_FALSE; | |
40 | |
41 cert = CERT_FindCertByNickname(handle, nickname); | |
42 | |
43 if (!cert) { | |
44 return conflict; | |
45 } | |
46 | |
47 conflict = !SECITEM_ItemsAreEqual(derSubject, &cert->derSubject); | |
48 CERT_DestroyCertificate(cert); | |
49 return conflict; | |
50 } | |
51 | |
52 SECStatus | |
53 SEC_DeletePermCertificate(CERTCertificate *cert) | |
54 { | |
55 PRStatus nssrv; | |
56 NSSTrustDomain *td = STAN_GetDefaultTrustDomain(); | |
57 NSSCertificate *c = STAN_GetNSSCertificate(cert); | |
58 CERTCertTrust *certTrust; | |
59 | |
60 if (c == NULL) { | |
61 /* error code is set */ | |
62 return SECFailure; | |
63 } | |
64 | |
65 certTrust = nssTrust_GetCERTCertTrustForCert(c, cert); | |
66 if (certTrust) { | |
67 NSSTrust *nssTrust = nssTrustDomain_FindTrustForCertificate(td, c); | |
68 if (nssTrust) { | |
69 nssrv = STAN_DeleteCertTrustMatchingSlot(c); | |
70 if (nssrv != PR_SUCCESS) { | |
71 CERT_MapStanError(); | |
72 } | |
73 /* This call always returns PR_SUCCESS! */ | |
74 (void)nssTrust_Destroy(nssTrust); | |
75 } | |
76 } | |
77 | |
78 /* get rid of the token instances */ | |
79 nssrv = NSSCertificate_DeleteStoredObject(c, NULL); | |
80 | |
81 /* get rid of the cache entry */ | |
82 nssTrustDomain_LockCertCache(td); | |
83 nssTrustDomain_RemoveCertFromCacheLOCKED(td, c); | |
84 nssTrustDomain_UnlockCertCache(td); | |
85 | |
86 return (nssrv == PR_SUCCESS) ? SECSuccess : SECFailure; | |
87 } | |
88 | |
89 SECStatus | |
90 CERT_GetCertTrust(const CERTCertificate *cert, CERTCertTrust *trust) | |
91 { | |
92 SECStatus rv; | |
93 CERT_LockCertTrust(cert); | |
94 if (cert->trust == NULL) { | |
95 rv = SECFailure; | |
96 } else { | |
97 *trust = *cert->trust; | |
98 rv = SECSuccess; | |
99 } | |
100 CERT_UnlockCertTrust(cert); | |
101 return (rv); | |
102 } | |
103 | |
104 extern const NSSError NSS_ERROR_NO_ERROR; | |
105 extern const NSSError NSS_ERROR_INTERNAL_ERROR; | |
106 extern const NSSError NSS_ERROR_NO_MEMORY; | |
107 extern const NSSError NSS_ERROR_INVALID_POINTER; | |
108 extern const NSSError NSS_ERROR_INVALID_ARENA; | |
109 extern const NSSError NSS_ERROR_INVALID_ARENA_MARK; | |
110 extern const NSSError NSS_ERROR_DUPLICATE_POINTER; | |
111 extern const NSSError NSS_ERROR_POINTER_NOT_REGISTERED; | |
112 extern const NSSError NSS_ERROR_TRACKER_NOT_EMPTY; | |
113 extern const NSSError NSS_ERROR_TRACKER_NOT_INITIALIZED; | |
114 extern const NSSError NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD; | |
115 extern const NSSError NSS_ERROR_VALUE_TOO_LARGE; | |
116 extern const NSSError NSS_ERROR_UNSUPPORTED_TYPE; | |
117 extern const NSSError NSS_ERROR_BUFFER_TOO_SHORT; | |
118 extern const NSSError NSS_ERROR_INVALID_ATOB_CONTEXT; | |
119 extern const NSSError NSS_ERROR_INVALID_BASE64; | |
120 extern const NSSError NSS_ERROR_INVALID_BTOA_CONTEXT; | |
121 extern const NSSError NSS_ERROR_INVALID_ITEM; | |
122 extern const NSSError NSS_ERROR_INVALID_STRING; | |
123 extern const NSSError NSS_ERROR_INVALID_ASN1ENCODER; | |
124 extern const NSSError NSS_ERROR_INVALID_ASN1DECODER; | |
125 extern const NSSError NSS_ERROR_INVALID_BER; | |
126 extern const NSSError NSS_ERROR_INVALID_ATAV; | |
127 extern const NSSError NSS_ERROR_INVALID_ARGUMENT; | |
128 extern const NSSError NSS_ERROR_INVALID_UTF8; | |
129 extern const NSSError NSS_ERROR_INVALID_NSSOID; | |
130 extern const NSSError NSS_ERROR_UNKNOWN_ATTRIBUTE; | |
131 extern const NSSError NSS_ERROR_NOT_FOUND; | |
132 extern const NSSError NSS_ERROR_INVALID_PASSWORD; | |
133 extern const NSSError NSS_ERROR_USER_CANCELED; | |
134 extern const NSSError NSS_ERROR_MAXIMUM_FOUND; | |
135 extern const NSSError NSS_ERROR_CERTIFICATE_ISSUER_NOT_FOUND; | |
136 extern const NSSError NSS_ERROR_CERTIFICATE_IN_CACHE; | |
137 extern const NSSError NSS_ERROR_HASH_COLLISION; | |
138 extern const NSSError NSS_ERROR_DEVICE_ERROR; | |
139 extern const NSSError NSS_ERROR_INVALID_CERTIFICATE; | |
140 extern const NSSError NSS_ERROR_BUSY; | |
141 extern const NSSError NSS_ERROR_ALREADY_INITIALIZED; | |
142 extern const NSSError NSS_ERROR_PKCS11; | |
143 | |
144 /* Look at the stan error stack and map it to NSS 3 errors */ | |
145 #define STAN_MAP_ERROR(x, y) \ | |
146 else if (error == (x)) { secError = y; } | |
147 | |
148 /* | |
149 * map Stan errors into NSS errors | |
150 * This function examines the stan error stack and automatically sets | |
151 * PORT_SetError(); to the appropriate SEC_ERROR value. | |
152 */ | |
153 void | |
154 CERT_MapStanError() | |
155 { | |
156 PRInt32 *errorStack; | |
157 NSSError error, prevError; | |
158 int secError; | |
159 int i; | |
160 | |
161 error = 0; | |
162 | |
163 errorStack = NSS_GetErrorStack(); | |
164 if (errorStack == 0) { | |
165 PORT_SetError(0); | |
166 return; | |
167 } | |
168 error = prevError = CKR_GENERAL_ERROR; | |
169 /* get the 'top 2' error codes from the stack */ | |
170 for (i = 0; errorStack[i]; i++) { | |
171 prevError = error; | |
172 error = errorStack[i]; | |
173 } | |
174 if (error == NSS_ERROR_PKCS11) { | |
175 /* map it */ | |
176 secError = PK11_MapError(prevError); | |
177 } | |
178 STAN_MAP_ERROR(NSS_ERROR_NO_ERROR, 0) | |
179 STAN_MAP_ERROR(NSS_ERROR_NO_MEMORY, SEC_ERROR_NO_MEMORY) | |
180 STAN_MAP_ERROR(NSS_ERROR_INVALID_BASE64, SEC_ERROR_BAD_DATA) | |
181 STAN_MAP_ERROR(NSS_ERROR_INVALID_BER, SEC_ERROR_BAD_DER) | |
182 STAN_MAP_ERROR(NSS_ERROR_INVALID_ATAV, SEC_ERROR_INVALID_AVA) | |
183 STAN_MAP_ERROR(NSS_ERROR_INVALID_PASSWORD, SEC_ERROR_BAD_PASSWORD) | |
184 STAN_MAP_ERROR(NSS_ERROR_BUSY, SEC_ERROR_BUSY) | |
185 STAN_MAP_ERROR(NSS_ERROR_DEVICE_ERROR, SEC_ERROR_IO) | |
186 STAN_MAP_ERROR(NSS_ERROR_CERTIFICATE_ISSUER_NOT_FOUND, | |
187 SEC_ERROR_UNKNOWN_ISSUER) | |
188 STAN_MAP_ERROR(NSS_ERROR_INVALID_CERTIFICATE, SEC_ERROR_CERT_NOT_VALID) | |
189 STAN_MAP_ERROR(NSS_ERROR_INVALID_UTF8, SEC_ERROR_BAD_DATA) | |
190 STAN_MAP_ERROR(NSS_ERROR_INVALID_NSSOID, SEC_ERROR_BAD_DATA) | |
191 | |
192 /* these are library failure for lack of a better error code */ | |
193 STAN_MAP_ERROR(NSS_ERROR_NOT_FOUND, SEC_ERROR_LIBRARY_FAILURE) | |
194 STAN_MAP_ERROR(NSS_ERROR_CERTIFICATE_IN_CACHE, SEC_ERROR_LIBRARY_FAILURE) | |
195 STAN_MAP_ERROR(NSS_ERROR_MAXIMUM_FOUND, SEC_ERROR_LIBRARY_FAILURE) | |
196 STAN_MAP_ERROR(NSS_ERROR_USER_CANCELED, SEC_ERROR_LIBRARY_FAILURE) | |
197 STAN_MAP_ERROR(NSS_ERROR_TRACKER_NOT_INITIALIZED, SEC_ERROR_LIBRARY_FAILURE) | |
198 STAN_MAP_ERROR(NSS_ERROR_ALREADY_INITIALIZED, SEC_ERROR_LIBRARY_FAILURE) | |
199 STAN_MAP_ERROR(NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD, | |
200 SEC_ERROR_LIBRARY_FAILURE) | |
201 STAN_MAP_ERROR(NSS_ERROR_HASH_COLLISION, SEC_ERROR_LIBRARY_FAILURE) | |
202 | |
203 STAN_MAP_ERROR(NSS_ERROR_INTERNAL_ERROR, SEC_ERROR_LIBRARY_FAILURE) | |
204 | |
205 /* these are all invalid arguments */ | |
206 STAN_MAP_ERROR(NSS_ERROR_INVALID_ARGUMENT, SEC_ERROR_INVALID_ARGS) | |
207 STAN_MAP_ERROR(NSS_ERROR_INVALID_POINTER, SEC_ERROR_INVALID_ARGS) | |
208 STAN_MAP_ERROR(NSS_ERROR_INVALID_ARENA, SEC_ERROR_INVALID_ARGS) | |
209 STAN_MAP_ERROR(NSS_ERROR_INVALID_ARENA_MARK, SEC_ERROR_INVALID_ARGS) | |
210 STAN_MAP_ERROR(NSS_ERROR_DUPLICATE_POINTER, SEC_ERROR_INVALID_ARGS) | |
211 STAN_MAP_ERROR(NSS_ERROR_POINTER_NOT_REGISTERED, SEC_ERROR_INVALID_ARGS) | |
212 STAN_MAP_ERROR(NSS_ERROR_TRACKER_NOT_EMPTY, SEC_ERROR_INVALID_ARGS) | |
213 STAN_MAP_ERROR(NSS_ERROR_VALUE_TOO_LARGE, SEC_ERROR_INVALID_ARGS) | |
214 STAN_MAP_ERROR(NSS_ERROR_UNSUPPORTED_TYPE, SEC_ERROR_INVALID_ARGS) | |
215 STAN_MAP_ERROR(NSS_ERROR_BUFFER_TOO_SHORT, SEC_ERROR_INVALID_ARGS) | |
216 STAN_MAP_ERROR(NSS_ERROR_INVALID_ATOB_CONTEXT, SEC_ERROR_INVALID_ARGS) | |
217 STAN_MAP_ERROR(NSS_ERROR_INVALID_BTOA_CONTEXT, SEC_ERROR_INVALID_ARGS) | |
218 STAN_MAP_ERROR(NSS_ERROR_INVALID_ITEM, SEC_ERROR_INVALID_ARGS) | |
219 STAN_MAP_ERROR(NSS_ERROR_INVALID_STRING, SEC_ERROR_INVALID_ARGS) | |
220 STAN_MAP_ERROR(NSS_ERROR_INVALID_ASN1ENCODER, SEC_ERROR_INVALID_ARGS) | |
221 STAN_MAP_ERROR(NSS_ERROR_INVALID_ASN1DECODER, SEC_ERROR_INVALID_ARGS) | |
222 STAN_MAP_ERROR(NSS_ERROR_UNKNOWN_ATTRIBUTE, SEC_ERROR_INVALID_ARGS) | |
223 else { secError = SEC_ERROR_LIBRARY_FAILURE; } | |
224 PORT_SetError(secError); | |
225 } | |
226 | |
227 SECStatus | |
228 CERT_ChangeCertTrust(CERTCertDBHandle *handle, CERTCertificate *cert, | |
229 CERTCertTrust *trust) | |
230 { | |
231 SECStatus rv = SECSuccess; | |
232 PRStatus ret; | |
233 | |
234 ret = STAN_ChangeCertTrust(cert, trust); | |
235 if (ret != PR_SUCCESS) { | |
236 rv = SECFailure; | |
237 CERT_MapStanError(); | |
238 } | |
239 return rv; | |
240 } | |
241 | |
242 extern const NSSError NSS_ERROR_INVALID_CERTIFICATE; | |
243 | |
244 SECStatus | |
245 __CERT_AddTempCertToPerm(CERTCertificate *cert, char *nickname, | |
246 CERTCertTrust *trust) | |
247 { | |
248 NSSUTF8 *stanNick; | |
249 PK11SlotInfo *slot; | |
250 NSSToken *internal; | |
251 NSSCryptoContext *context; | |
252 nssCryptokiObject *permInstance; | |
253 NSSCertificate *c = STAN_GetNSSCertificate(cert); | |
254 nssCertificateStoreTrace lockTrace = { NULL, NULL, PR_FALSE, PR_FALSE }; | |
255 nssCertificateStoreTrace unlockTrace = { NULL, NULL, PR_FALSE, PR_FALSE }; | |
256 SECStatus rv; | |
257 PRStatus ret; | |
258 | |
259 if (c == NULL) { | |
260 CERT_MapStanError(); | |
261 return SECFailure; | |
262 } | |
263 | |
264 context = c->object.cryptoContext; | |
265 if (!context) { | |
266 PORT_SetError(SEC_ERROR_ADDING_CERT); | |
267 return SECFailure; /* wasn't a temp cert */ | |
268 } | |
269 stanNick = nssCertificate_GetNickname(c, NULL); | |
270 if (stanNick && nickname && strcmp(nickname, stanNick) != 0) { | |
271 /* different: take the new nickname */ | |
272 cert->nickname = NULL; | |
273 nss_ZFreeIf(stanNick); | |
274 stanNick = NULL; | |
275 } | |
276 if (!stanNick && nickname) { | |
277 /* Either there was no nickname yet, or we have a new nickname */ | |
278 stanNick = nssUTF8_Duplicate((NSSUTF8 *)nickname, NULL); | |
279 } /* else: old stanNick is identical to new nickname */ | |
280 /* Delete the temp instance */ | |
281 nssCertificateStore_Lock(context->certStore, &lockTrace); | |
282 nssCertificateStore_RemoveCertLOCKED(context->certStore, c); | |
283 nssCertificateStore_Unlock(context->certStore, &lockTrace, &unlockTrace); | |
284 c->object.cryptoContext = NULL; | |
285 /* Import the perm instance onto the internal token */ | |
286 slot = PK11_GetInternalKeySlot(); | |
287 internal = PK11Slot_GetNSSToken(slot); | |
288 permInstance = nssToken_ImportCertificate( | |
289 internal, NULL, NSSCertificateType_PKIX, &c->id, stanNick, &c->encoding, | |
290 &c->issuer, &c->subject, &c->serial, cert->emailAddr, PR_TRUE); | |
291 nss_ZFreeIf(stanNick); | |
292 stanNick = NULL; | |
293 PK11_FreeSlot(slot); | |
294 if (!permInstance) { | |
295 if (NSS_GetError() == NSS_ERROR_INVALID_CERTIFICATE) { | |
296 PORT_SetError(SEC_ERROR_REUSED_ISSUER_AND_SERIAL); | |
297 } | |
298 return SECFailure; | |
299 } | |
300 nssPKIObject_AddInstance(&c->object, permInstance); | |
301 nssTrustDomain_AddCertsToCache(STAN_GetDefaultTrustDomain(), &c, 1); | |
302 /* reset the CERTCertificate fields */ | |
303 cert->nssCertificate = NULL; | |
304 cert = STAN_GetCERTCertificateOrRelease(c); /* should return same pointer */ | |
305 if (!cert) { | |
306 CERT_MapStanError(); | |
307 return SECFailure; | |
308 } | |
309 cert->istemp = PR_FALSE; | |
310 cert->isperm = PR_TRUE; | |
311 if (!trust) { | |
312 return SECSuccess; | |
313 } | |
314 ret = STAN_ChangeCertTrust(cert, trust); | |
315 rv = SECSuccess; | |
316 if (ret != PR_SUCCESS) { | |
317 rv = SECFailure; | |
318 CERT_MapStanError(); | |
319 } | |
320 return rv; | |
321 } | |
322 | |
323 SECStatus | |
324 CERT_AddTempCertToPerm(CERTCertificate *cert, char *nickname, | |
325 CERTCertTrust *trust) | |
326 { | |
327 return __CERT_AddTempCertToPerm(cert, nickname, trust); | |
328 } | |
329 | |
330 CERTCertificate * | |
331 CERT_NewTempCertificate(CERTCertDBHandle *handle, SECItem *derCert, | |
332 char *nickname, PRBool isperm, PRBool copyDER) | |
333 { | |
334 NSSCertificate *c; | |
335 CERTCertificate *cc; | |
336 NSSCertificate *tempCert = NULL; | |
337 nssPKIObject *pkio; | |
338 NSSCryptoContext *gCC = STAN_GetDefaultCryptoContext(); | |
339 NSSTrustDomain *gTD = STAN_GetDefaultTrustDomain(); | |
340 if (!isperm) { | |
341 NSSDER encoding; | |
342 NSSITEM_FROM_SECITEM(&encoding, derCert); | |
343 /* First, see if it is already a temp cert */ | |
344 c = NSSCryptoContext_FindCertificateByEncodedCertificate(gCC, | |
345 &encoding); | |
346 if (!c) { | |
347 /* Then, see if it is already a perm cert */ | |
348 c = NSSTrustDomain_FindCertificateByEncodedCertificate(handle, | |
349 &encoding); | |
350 } | |
351 if (c) { | |
352 /* actually, that search ends up going by issuer/serial, | |
353 * so it is still possible to return a cert with the same | |
354 * issuer/serial but a different encoding, and we're | |
355 * going to reject that | |
356 */ | |
357 if (!nssItem_Equal(&c->encoding, &encoding, NULL)) { | |
358 nssCertificate_Destroy(c); | |
359 PORT_SetError(SEC_ERROR_REUSED_ISSUER_AND_SERIAL); | |
360 cc = NULL; | |
361 } else { | |
362 cc = STAN_GetCERTCertificateOrRelease(c); | |
363 if (cc == NULL) { | |
364 CERT_MapStanError(); | |
365 } | |
366 } | |
367 return cc; | |
368 } | |
369 } | |
370 pkio = nssPKIObject_Create(NULL, NULL, gTD, gCC, nssPKIMonitor); | |
371 if (!pkio) { | |
372 CERT_MapStanError(); | |
373 return NULL; | |
374 } | |
375 c = nss_ZNEW(pkio->arena, NSSCertificate); | |
376 if (!c) { | |
377 CERT_MapStanError(); | |
378 nssPKIObject_Destroy(pkio); | |
379 return NULL; | |
380 } | |
381 c->object = *pkio; | |
382 if (copyDER) { | |
383 nssItem_Create(c->object.arena, &c->encoding, derCert->len, | |
384 derCert->data); | |
385 } else { | |
386 NSSITEM_FROM_SECITEM(&c->encoding, derCert); | |
387 } | |
388 /* Forces a decoding of the cert in order to obtain the parts used | |
389 * below | |
390 */ | |
391 /* 'c' is not adopted here, if we fail loser frees what has been | |
392 * allocated so far for 'c' */ | |
393 cc = STAN_GetCERTCertificate(c); | |
394 if (!cc) { | |
395 CERT_MapStanError(); | |
396 goto loser; | |
397 } | |
398 nssItem_Create(c->object.arena, &c->issuer, cc->derIssuer.len, | |
399 cc->derIssuer.data); | |
400 nssItem_Create(c->object.arena, &c->subject, cc->derSubject.len, | |
401 cc->derSubject.data); | |
402 if (PR_TRUE) { | |
403 /* CERTCertificate stores serial numbers decoded. I need the DER | |
404 * here. sigh. | |
405 */ | |
406 SECItem derSerial = { 0 }; | |
407 CERT_SerialNumberFromDERCert(&cc->derCert, &derSerial); | |
408 if (!derSerial.data) | |
409 goto loser; | |
410 nssItem_Create(c->object.arena, &c->serial, derSerial.len, | |
411 derSerial.data); | |
412 PORT_Free(derSerial.data); | |
413 } | |
414 if (nickname) { | |
415 c->object.tempName = | |
416 nssUTF8_Create(c->object.arena, nssStringType_UTF8String, | |
417 (NSSUTF8 *)nickname, PORT_Strlen(nickname)); | |
418 } | |
419 if (cc->emailAddr && cc->emailAddr[0]) { | |
420 c->email = nssUTF8_Create( | |
421 c->object.arena, nssStringType_PrintableString, | |
422 (NSSUTF8 *)cc->emailAddr, PORT_Strlen(cc->emailAddr)); | |
423 } | |
424 | |
425 tempCert = NSSCryptoContext_FindOrImportCertificate(gCC, c); | |
426 if (!tempCert) { | |
427 CERT_MapStanError(); | |
428 goto loser; | |
429 } | |
430 /* destroy our copy */ | |
431 NSSCertificate_Destroy(c); | |
432 /* and use the stored entry */ | |
433 c = tempCert; | |
434 cc = STAN_GetCERTCertificateOrRelease(c); | |
435 if (!cc) { | |
436 /* STAN_GetCERTCertificateOrRelease destroys c on failure. */ | |
437 CERT_MapStanError(); | |
438 return NULL; | |
439 } | |
440 | |
441 cc->istemp = PR_TRUE; | |
442 cc->isperm = PR_FALSE; | |
443 return cc; | |
444 loser: | |
445 /* Perhaps this should be nssCertificate_Destroy(c) */ | |
446 nssPKIObject_Destroy(&c->object); | |
447 return NULL; | |
448 } | |
449 | |
450 /* This symbol is exported for backward compatibility. */ | |
451 CERTCertificate * | |
452 __CERT_NewTempCertificate(CERTCertDBHandle *handle, SECItem *derCert, | |
453 char *nickname, PRBool isperm, PRBool copyDER) | |
454 { | |
455 return CERT_NewTempCertificate(handle, derCert, nickname, isperm, copyDER); | |
456 } | |
457 | |
458 /* maybe all the wincx's should be some const for internal token login? */ | |
459 CERTCertificate * | |
460 CERT_FindCertByIssuerAndSN(CERTCertDBHandle *handle, | |
461 CERTIssuerAndSN *issuerAndSN) | |
462 { | |
463 PK11SlotInfo *slot; | |
464 CERTCertificate *cert; | |
465 | |
466 cert = PK11_FindCertByIssuerAndSN(&slot, issuerAndSN, NULL); | |
467 if (cert && slot) { | |
468 PK11_FreeSlot(slot); | |
469 } | |
470 | |
471 return cert; | |
472 } | |
473 | |
474 static NSSCertificate * | |
475 get_best_temp_or_perm(NSSCertificate *ct, NSSCertificate *cp) | |
476 { | |
477 NSSUsage usage; | |
478 NSSCertificate *arr[3]; | |
479 if (!ct) { | |
480 return nssCertificate_AddRef(cp); | |
481 } else if (!cp) { | |
482 return nssCertificate_AddRef(ct); | |
483 } | |
484 arr[0] = ct; | |
485 arr[1] = cp; | |
486 arr[2] = NULL; | |
487 usage.anyUsage = PR_TRUE; | |
488 return nssCertificateArray_FindBestCertificate(arr, NULL, &usage, NULL); | |
489 } | |
490 | |
491 CERTCertificate * | |
492 CERT_FindCertByName(CERTCertDBHandle *handle, SECItem *name) | |
493 { | |
494 NSSCertificate *cp, *ct, *c; | |
495 NSSDER subject; | |
496 NSSUsage usage; | |
497 NSSCryptoContext *cc; | |
498 NSSITEM_FROM_SECITEM(&subject, name); | |
499 usage.anyUsage = PR_TRUE; | |
500 cc = STAN_GetDefaultCryptoContext(); | |
501 ct = NSSCryptoContext_FindBestCertificateBySubject(cc, &subject, NULL, | |
502 &usage, NULL); | |
503 cp = NSSTrustDomain_FindBestCertificateBySubject(handle, &subject, NULL, | |
504 &usage, NULL); | |
505 c = get_best_temp_or_perm(ct, cp); | |
506 if (ct) { | |
507 CERT_DestroyCertificate(STAN_GetCERTCertificateOrRelease(ct)); | |
508 } | |
509 if (cp) { | |
510 CERT_DestroyCertificate(STAN_GetCERTCertificateOrRelease(cp)); | |
511 } | |
512 return c ? STAN_GetCERTCertificateOrRelease(c) : NULL; | |
513 } | |
514 | |
515 CERTCertificate * | |
516 CERT_FindCertByKeyID(CERTCertDBHandle *handle, SECItem *name, SECItem *keyID) | |
517 { | |
518 CERTCertList *list; | |
519 CERTCertificate *cert = NULL; | |
520 CERTCertListNode *node, *head; | |
521 | |
522 list = CERT_CreateSubjectCertList(NULL, handle, name, 0, PR_FALSE); | |
523 if (list == NULL) | |
524 return NULL; | |
525 | |
526 node = head = CERT_LIST_HEAD(list); | |
527 if (head) { | |
528 do { | |
529 if (node->cert && | |
530 SECITEM_ItemsAreEqual(&node->cert->subjectKeyID, keyID)) { | |
531 cert = CERT_DupCertificate(node->cert); | |
532 goto done; | |
533 } | |
534 node = CERT_LIST_NEXT(node); | |
535 } while (node && head != node); | |
536 } | |
537 PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER); | |
538 done: | |
539 if (list) { | |
540 CERT_DestroyCertList(list); | |
541 } | |
542 return cert; | |
543 } | |
544 | |
545 CERTCertificate * | |
546 CERT_FindCertByNickname(CERTCertDBHandle *handle, const char *nickname) | |
547 { | |
548 NSSCryptoContext *cc; | |
549 NSSCertificate *c, *ct; | |
550 CERTCertificate *cert; | |
551 NSSUsage usage; | |
552 usage.anyUsage = PR_TRUE; | |
553 cc = STAN_GetDefaultCryptoContext(); | |
554 ct = NSSCryptoContext_FindBestCertificateByNickname(cc, nickname, NULL, | |
555 &usage, NULL); | |
556 cert = PK11_FindCertFromNickname(nickname, NULL); | |
557 c = NULL; | |
558 if (cert) { | |
559 c = get_best_temp_or_perm(ct, STAN_GetNSSCertificate(cert)); | |
560 CERT_DestroyCertificate(cert); | |
561 if (ct) { | |
562 CERT_DestroyCertificate(STAN_GetCERTCertificateOrRelease(ct)); | |
563 } | |
564 } else { | |
565 c = ct; | |
566 } | |
567 return c ? STAN_GetCERTCertificateOrRelease(c) : NULL; | |
568 } | |
569 | |
570 CERTCertificate * | |
571 CERT_FindCertByDERCert(CERTCertDBHandle *handle, SECItem *derCert) | |
572 { | |
573 NSSCryptoContext *cc; | |
574 NSSCertificate *c; | |
575 NSSDER encoding; | |
576 NSSITEM_FROM_SECITEM(&encoding, derCert); | |
577 cc = STAN_GetDefaultCryptoContext(); | |
578 c = NSSCryptoContext_FindCertificateByEncodedCertificate(cc, &encoding); | |
579 if (!c) { | |
580 c = NSSTrustDomain_FindCertificateByEncodedCertificate(handle, | |
581 &encoding); | |
582 if (!c) | |
583 return NULL; | |
584 } | |
585 return STAN_GetCERTCertificateOrRelease(c); | |
586 } | |
587 | |
588 static CERTCertificate * | |
589 common_FindCertByNicknameOrEmailAddrForUsage(CERTCertDBHandle *handle, | |
590 const char *name, PRBool anyUsage, | |
591 SECCertUsage lookingForUsage) | |
592 { | |
593 NSSCryptoContext *cc; | |
594 NSSCertificate *c, *ct; | |
595 CERTCertificate *cert = NULL; | |
596 NSSUsage usage; | |
597 CERTCertList *certlist; | |
598 | |
599 if (NULL == name) { | |
600 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
601 return NULL; | |
602 } | |
603 | |
604 usage.anyUsage = anyUsage; | |
605 | |
606 if (!anyUsage) { | |
607 usage.nss3lookingForCA = PR_FALSE; | |
608 usage.nss3usage = lookingForUsage; | |
609 } | |
610 | |
611 cc = STAN_GetDefaultCryptoContext(); | |
612 ct = NSSCryptoContext_FindBestCertificateByNickname(cc, name, NULL, &usage, | |
613 NULL); | |
614 if (!ct && PORT_Strchr(name, '@') != NULL) { | |
615 char *lowercaseName = CERT_FixupEmailAddr(name); | |
616 if (lowercaseName) { | |
617 ct = NSSCryptoContext_FindBestCertificateByEmail( | |
618 cc, lowercaseName, NULL, &usage, NULL); | |
619 PORT_Free(lowercaseName); | |
620 } | |
621 } | |
622 | |
623 if (anyUsage) { | |
624 cert = PK11_FindCertFromNickname(name, NULL); | |
625 } else { | |
626 if (ct) { | |
627 /* Does ct really have the required usage? */ | |
628 nssDecodedCert *dc; | |
629 dc = nssCertificate_GetDecoding(ct); | |
630 if (!dc->matchUsage(dc, &usage)) { | |
631 CERT_DestroyCertificate(STAN_GetCERTCertificateOrRelease(ct)); | |
632 ct = NULL; | |
633 } | |
634 } | |
635 | |
636 certlist = PK11_FindCertsFromNickname(name, NULL); | |
637 if (certlist) { | |
638 SECStatus rv = | |
639 CERT_FilterCertListByUsage(certlist, lookingForUsage, PR_FALSE); | |
640 if (SECSuccess == rv && | |
641 !CERT_LIST_END(CERT_LIST_HEAD(certlist), certlist)) { | |
642 cert = CERT_DupCertificate(CERT_LIST_HEAD(certlist)->cert); | |
643 } | |
644 CERT_DestroyCertList(certlist); | |
645 } | |
646 } | |
647 | |
648 if (cert) { | |
649 c = get_best_temp_or_perm(ct, STAN_GetNSSCertificate(cert)); | |
650 CERT_DestroyCertificate(cert); | |
651 if (ct) { | |
652 CERT_DestroyCertificate(STAN_GetCERTCertificateOrRelease(ct)); | |
653 } | |
654 } else { | |
655 c = ct; | |
656 } | |
657 return c ? STAN_GetCERTCertificateOrRelease(c) : NULL; | |
658 } | |
659 | |
660 CERTCertificate * | |
661 CERT_FindCertByNicknameOrEmailAddr(CERTCertDBHandle *handle, const char *name) | |
662 { | |
663 return common_FindCertByNicknameOrEmailAddrForUsage(handle, name, PR_TRUE, | |
664 0); | |
665 } | |
666 | |
667 CERTCertificate * | |
668 CERT_FindCertByNicknameOrEmailAddrForUsage(CERTCertDBHandle *handle, | |
669 const char *name, | |
670 SECCertUsage lookingForUsage) | |
671 { | |
672 return common_FindCertByNicknameOrEmailAddrForUsage(handle, name, PR_FALSE, | |
673 lookingForUsage); | |
674 } | |
675 | |
676 static void | |
677 add_to_subject_list(CERTCertList *certList, CERTCertificate *cert, | |
678 PRBool validOnly, PRTime sorttime) | |
679 { | |
680 SECStatus secrv; | |
681 if (!validOnly || | |
682 CERT_CheckCertValidTimes(cert, sorttime, PR_FALSE) == | |
683 secCertTimeValid) { | |
684 secrv = CERT_AddCertToListSorted(certList, cert, CERT_SortCBValidity, | |
685 (void *)&sorttime); | |
686 if (secrv != SECSuccess) { | |
687 CERT_DestroyCertificate(cert); | |
688 } | |
689 } else { | |
690 CERT_DestroyCertificate(cert); | |
691 } | |
692 } | |
693 | |
694 CERTCertList * | |
695 CERT_CreateSubjectCertList(CERTCertList *certList, CERTCertDBHandle *handle, | |
696 const SECItem *name, PRTime sorttime, | |
697 PRBool validOnly) | |
698 { | |
699 NSSCryptoContext *cc; | |
700 NSSCertificate **tSubjectCerts, **pSubjectCerts; | |
701 NSSCertificate **ci; | |
702 CERTCertificate *cert; | |
703 NSSDER subject; | |
704 PRBool myList = PR_FALSE; | |
705 cc = STAN_GetDefaultCryptoContext(); | |
706 NSSITEM_FROM_SECITEM(&subject, name); | |
707 /* Collect both temp and perm certs for the subject */ | |
708 tSubjectCerts = | |
709 NSSCryptoContext_FindCertificatesBySubject(cc, &subject, NULL, 0, NULL); | |
710 pSubjectCerts = NSSTrustDomain_FindCertificatesBySubject(handle, &subject, | |
711 NULL, 0, NULL); | |
712 if (!tSubjectCerts && !pSubjectCerts) { | |
713 return NULL; | |
714 } | |
715 if (certList == NULL) { | |
716 certList = CERT_NewCertList(); | |
717 myList = PR_TRUE; | |
718 if (!certList) | |
719 goto loser; | |
720 } | |
721 /* Iterate over the matching temp certs. Add them to the list */ | |
722 ci = tSubjectCerts; | |
723 while (ci && *ci) { | |
724 cert = STAN_GetCERTCertificateOrRelease(*ci); | |
725 /* *ci may be invalid at this point, don't reference it again */ | |
726 if (cert) { | |
727 /* NOTE: add_to_subject_list adopts the incoming cert. */ | |
728 add_to_subject_list(certList, cert, validOnly, sorttime); | |
729 } | |
730 ci++; | |
731 } | |
732 /* Iterate over the matching perm certs. Add them to the list */ | |
733 ci = pSubjectCerts; | |
734 while (ci && *ci) { | |
735 cert = STAN_GetCERTCertificateOrRelease(*ci); | |
736 /* *ci may be invalid at this point, don't reference it again */ | |
737 if (cert) { | |
738 /* NOTE: add_to_subject_list adopts the incoming cert. */ | |
739 add_to_subject_list(certList, cert, validOnly, sorttime); | |
740 } | |
741 ci++; | |
742 } | |
743 /* all the references have been adopted or freed at this point, just | |
744 * free the arrays now */ | |
745 nss_ZFreeIf(tSubjectCerts); | |
746 nss_ZFreeIf(pSubjectCerts); | |
747 return certList; | |
748 loser: | |
749 /* need to free the references in tSubjectCerts and pSubjectCerts! */ | |
750 nssCertificateArray_Destroy(tSubjectCerts); | |
751 nssCertificateArray_Destroy(pSubjectCerts); | |
752 if (myList && certList != NULL) { | |
753 CERT_DestroyCertList(certList); | |
754 } | |
755 return NULL; | |
756 } | |
757 | |
758 void | |
759 CERT_DestroyCertificate(CERTCertificate *cert) | |
760 { | |
761 if (cert) { | |
762 /* don't use STAN_GetNSSCertificate because we don't want to | |
763 * go to the trouble of translating the CERTCertificate into | |
764 * an NSSCertificate just to destroy it. If it hasn't been done | |
765 * yet, don't do it at all. | |
766 */ | |
767 NSSCertificate *tmp = cert->nssCertificate; | |
768 if (tmp) { | |
769 /* delete the NSSCertificate */ | |
770 NSSCertificate_Destroy(tmp); | |
771 } else if (cert->arena) { | |
772 PORT_FreeArena(cert->arena, PR_FALSE); | |
773 } | |
774 } | |
775 return; | |
776 } | |
777 | |
778 int | |
779 CERT_GetDBContentVersion(CERTCertDBHandle *handle) | |
780 { | |
781 /* should read the DB content version from the pkcs #11 device */ | |
782 return 0; | |
783 } | |
784 | |
785 SECStatus | |
786 certdb_SaveSingleProfile(CERTCertificate *cert, const char *emailAddr, | |
787 SECItem *emailProfile, SECItem *profileTime) | |
788 { | |
789 PRTime oldtime; | |
790 PRTime newtime; | |
791 SECStatus rv = SECFailure; | |
792 PRBool saveit; | |
793 SECItem oldprof, oldproftime; | |
794 SECItem *oldProfile = NULL; | |
795 SECItem *oldProfileTime = NULL; | |
796 PK11SlotInfo *slot = NULL; | |
797 NSSCertificate *c; | |
798 NSSCryptoContext *cc; | |
799 nssSMIMEProfile *stanProfile = NULL; | |
800 PRBool freeOldProfile = PR_FALSE; | |
801 | |
802 c = STAN_GetNSSCertificate(cert); | |
803 if (!c) | |
804 return SECFailure; | |
805 cc = c->object.cryptoContext; | |
806 if (cc != NULL) { | |
807 stanProfile = nssCryptoContext_FindSMIMEProfileForCertificate(cc, c); | |
808 if (stanProfile) { | |
809 PORT_Assert(stanProfile->profileData); | |
810 SECITEM_FROM_NSSITEM(&oldprof, stanProfile->profileData); | |
811 oldProfile = &oldprof; | |
812 SECITEM_FROM_NSSITEM(&oldproftime, stanProfile->profileTime); | |
813 oldProfileTime = &oldproftime; | |
814 } | |
815 } else { | |
816 oldProfile = PK11_FindSMimeProfile(&slot, (char *)emailAddr, | |
817 &cert->derSubject, &oldProfileTime); | |
818 freeOldProfile = PR_TRUE; | |
819 } | |
820 | |
821 saveit = PR_FALSE; | |
822 | |
823 /* both profileTime and emailProfile have to exist or not exist */ | |
824 if (emailProfile == NULL) { | |
825 profileTime = NULL; | |
826 } else if (profileTime == NULL) { | |
827 emailProfile = NULL; | |
828 } | |
829 | |
830 if (oldProfileTime == NULL) { | |
831 saveit = PR_TRUE; | |
832 } else { | |
833 /* there was already a profile for this email addr */ | |
834 if (profileTime) { | |
835 /* we have an old and new profile - save whichever is more recent*/ | |
836 if (oldProfileTime->len == 0) { | |
837 /* always replace if old entry doesn't have a time */ | |
838 oldtime = LL_MININT; | |
839 } else { | |
840 rv = DER_UTCTimeToTime(&oldtime, oldProfileTime); | |
841 if (rv != SECSuccess) { | |
842 goto loser; | |
843 } | |
844 } | |
845 | |
846 rv = DER_UTCTimeToTime(&newtime, profileTime); | |
847 if (rv != SECSuccess) { | |
848 goto loser; | |
849 } | |
850 | |
851 if (LL_CMP(newtime, >, oldtime)) { | |
852 /* this is a newer profile, save it and cert */ | |
853 saveit = PR_TRUE; | |
854 } | |
855 } else { | |
856 saveit = PR_TRUE; | |
857 } | |
858 } | |
859 | |
860 if (saveit) { | |
861 if (cc) { | |
862 if (stanProfile) { | |
863 /* stanProfile is already stored in the crypto context, | |
864 * overwrite the data | |
865 */ | |
866 NSSArena *arena = stanProfile->object.arena; | |
867 stanProfile->profileTime = nssItem_Create( | |
868 arena, NULL, profileTime->len, profileTime->data); | |
869 stanProfile->profileData = nssItem_Create( | |
870 arena, NULL, emailProfile->len, emailProfile->data); | |
871 } else if (profileTime && emailProfile) { | |
872 PRStatus nssrv; | |
873 NSSItem profTime, profData; | |
874 NSSITEM_FROM_SECITEM(&profTime, profileTime); | |
875 NSSITEM_FROM_SECITEM(&profData, emailProfile); | |
876 stanProfile = nssSMIMEProfile_Create(c, &profTime, &profData); | |
877 if (!stanProfile) | |
878 goto loser; | |
879 nssrv = nssCryptoContext_ImportSMIMEProfile(cc, stanProfile); | |
880 rv = (nssrv == PR_SUCCESS) ? SECSuccess : SECFailure; | |
881 } | |
882 } else { | |
883 rv = PK11_SaveSMimeProfile(slot, (char *)emailAddr, | |
884 &cert->derSubject, emailProfile, | |
885 profileTime); | |
886 } | |
887 } else { | |
888 rv = SECSuccess; | |
889 } | |
890 | |
891 loser: | |
892 if (oldProfile && freeOldProfile) { | |
893 SECITEM_FreeItem(oldProfile, PR_TRUE); | |
894 } | |
895 if (oldProfileTime && freeOldProfile) { | |
896 SECITEM_FreeItem(oldProfileTime, PR_TRUE); | |
897 } | |
898 if (stanProfile) { | |
899 nssSMIMEProfile_Destroy(stanProfile); | |
900 } | |
901 if (slot) { | |
902 PK11_FreeSlot(slot); | |
903 } | |
904 | |
905 return (rv); | |
906 } | |
907 | |
908 /* | |
909 * | |
910 * Manage S/MIME profiles | |
911 * | |
912 */ | |
913 | |
914 SECStatus | |
915 CERT_SaveSMimeProfile(CERTCertificate *cert, SECItem *emailProfile, | |
916 SECItem *profileTime) | |
917 { | |
918 const char *emailAddr; | |
919 SECStatus rv; | |
920 | |
921 if (!cert) { | |
922 return SECFailure; | |
923 } | |
924 | |
925 if (cert->slot && !PK11_IsInternal(cert->slot)) { | |
926 /* this cert comes from an external source, we need to add it | |
927 to the cert db before creating an S/MIME profile */ | |
928 PK11SlotInfo *internalslot = PK11_GetInternalKeySlot(); | |
929 if (!internalslot) { | |
930 return SECFailure; | |
931 } | |
932 rv = PK11_ImportCert(internalslot, cert, CK_INVALID_HANDLE, NULL, | |
933 PR_FALSE); | |
934 | |
935 PK11_FreeSlot(internalslot); | |
936 if (rv != SECSuccess) { | |
937 return SECFailure; | |
938 } | |
939 } | |
940 | |
941 if (cert->slot && cert->isperm && CERT_IsUserCert(cert) && | |
942 (!emailProfile || !emailProfile->len)) { | |
943 /* Don't clobber emailProfile for user certs. */ | |
944 return SECSuccess; | |
945 } | |
946 | |
947 for (emailAddr = CERT_GetFirstEmailAddress(cert); emailAddr != NULL; | |
948 emailAddr = CERT_GetNextEmailAddress(cert, emailAddr)) { | |
949 rv = certdb_SaveSingleProfile(cert, emailAddr, emailProfile, | |
950 profileTime); | |
951 if (rv != SECSuccess) { | |
952 return SECFailure; | |
953 } | |
954 } | |
955 return SECSuccess; | |
956 } | |
957 | |
958 SECItem * | |
959 CERT_FindSMimeProfile(CERTCertificate *cert) | |
960 { | |
961 PK11SlotInfo *slot = NULL; | |
962 NSSCertificate *c; | |
963 NSSCryptoContext *cc; | |
964 SECItem *rvItem = NULL; | |
965 | |
966 if (!cert || !cert->emailAddr || !cert->emailAddr[0]) { | |
967 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
968 return NULL; | |
969 } | |
970 c = STAN_GetNSSCertificate(cert); | |
971 if (!c) | |
972 return NULL; | |
973 cc = c->object.cryptoContext; | |
974 if (cc != NULL) { | |
975 nssSMIMEProfile *stanProfile; | |
976 stanProfile = nssCryptoContext_FindSMIMEProfileForCertificate(cc, c); | |
977 if (stanProfile) { | |
978 rvItem = | |
979 SECITEM_AllocItem(NULL, NULL, stanProfile->profileData->size); | |
980 if (rvItem) { | |
981 rvItem->data = stanProfile->profileData->data; | |
982 } | |
983 nssSMIMEProfile_Destroy(stanProfile); | |
984 } | |
985 return rvItem; | |
986 } | |
987 rvItem = | |
988 PK11_FindSMimeProfile(&slot, cert->emailAddr, &cert->derSubject, NULL); | |
989 if (slot) { | |
990 PK11_FreeSlot(slot); | |
991 } | |
992 return rvItem; | |
993 } | |
994 | |
995 /* | |
996 * deprecated functions that are now just stubs. | |
997 */ | |
998 /* | |
999 * Close the database | |
1000 */ | |
1001 void | |
1002 __CERT_ClosePermCertDB(CERTCertDBHandle *handle) | |
1003 { | |
1004 PORT_Assert("CERT_ClosePermCertDB is Deprecated" == NULL); | |
1005 return; | |
1006 } | |
1007 | |
1008 SECStatus | |
1009 CERT_OpenCertDBFilename(CERTCertDBHandle *handle, char *certdbname, | |
1010 PRBool readOnly) | |
1011 { | |
1012 PORT_Assert("CERT_OpenCertDBFilename is Deprecated" == NULL); | |
1013 PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); | |
1014 return SECFailure; | |
1015 } | |
1016 | |
1017 SECItem * | |
1018 SECKEY_HashPassword(char *pw, SECItem *salt) | |
1019 { | |
1020 PORT_Assert("SECKEY_HashPassword is Deprecated" == NULL); | |
1021 PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); | |
1022 return NULL; | |
1023 } | |
1024 | |
1025 SECStatus | |
1026 __CERT_TraversePermCertsForSubject(CERTCertDBHandle *handle, | |
1027 SECItem *derSubject, void *cb, void *cbarg) | |
1028 { | |
1029 PORT_Assert("CERT_TraversePermCertsForSubject is Deprecated" == NULL); | |
1030 PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); | |
1031 return SECFailure; | |
1032 } | |
1033 | |
1034 SECStatus | |
1035 __CERT_TraversePermCertsForNickname(CERTCertDBHandle *handle, char *nickname, | |
1036 void *cb, void *cbarg) | |
1037 { | |
1038 PORT_Assert("CERT_TraversePermCertsForNickname is Deprecated" == NULL); | |
1039 PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); | |
1040 return SECFailure; | |
1041 } | |
OLD | NEW |