/src/nss-nspr/nss/lib/pki/pki3hack.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
2 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
3 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
4 | | |
5 | | /* |
6 | | * Hacks to integrate NSS 3.4 and NSS 4.0 certificates. |
7 | | */ |
8 | | |
9 | | #ifndef NSSPKI_H |
10 | | #include "nsspki.h" |
11 | | #endif /* NSSPKI_H */ |
12 | | |
13 | | #ifndef PKI_H |
14 | | #include "pki.h" |
15 | | #endif /* PKI_H */ |
16 | | |
17 | | #ifndef PKIM_H |
18 | | #include "pkim.h" |
19 | | #endif /* PKIM_H */ |
20 | | |
21 | | #ifndef DEV_H |
22 | | #include "dev.h" |
23 | | #endif /* DEV_H */ |
24 | | |
25 | | #ifndef DEVNSS3HACK_H |
26 | | #include "dev3hack.h" |
27 | | #endif /* DEVNSS3HACK_H */ |
28 | | |
29 | | #ifndef PKINSS3HACK_H |
30 | | #include "pki3hack.h" |
31 | | #endif /* PKINSS3HACK_H */ |
32 | | |
33 | | #include "secitem.h" |
34 | | #include "certdb.h" |
35 | | #include "certt.h" |
36 | | #include "cert.h" |
37 | | #include "certi.h" |
38 | | #include "pk11func.h" |
39 | | #include "pkistore.h" |
40 | | #include "secmod.h" |
41 | | #include "nssrwlk.h" |
42 | | |
43 | | NSSTrustDomain *g_default_trust_domain = NULL; |
44 | | |
45 | | NSSCryptoContext *g_default_crypto_context = NULL; |
46 | | |
47 | | NSSTrustDomain * |
48 | | STAN_GetDefaultTrustDomain() |
49 | 2 | { |
50 | 2 | return g_default_trust_domain; |
51 | 2 | } |
52 | | |
53 | | NSSCryptoContext * |
54 | | STAN_GetDefaultCryptoContext() |
55 | 0 | { |
56 | 0 | return g_default_crypto_context; |
57 | 0 | } |
58 | | |
59 | | extern const NSSError NSS_ERROR_ALREADY_INITIALIZED; |
60 | | extern const NSSError NSS_ERROR_INTERNAL_ERROR; |
61 | | |
62 | | NSS_IMPLEMENT PRStatus |
63 | | STAN_InitTokenForSlotInfo(NSSTrustDomain *td, PK11SlotInfo *slot) |
64 | 4 | { |
65 | 4 | NSSToken *token; |
66 | 4 | if (!td) { |
67 | 0 | td = g_default_trust_domain; |
68 | 0 | if (!td) { |
69 | | /* we're called while still initting. slot will get added |
70 | | * appropriately through normal init processes */ |
71 | 0 | return PR_SUCCESS; |
72 | 0 | } |
73 | 0 | } |
74 | 4 | token = nssToken_CreateFromPK11SlotInfo(td, slot); |
75 | 4 | if (token) { |
76 | | /* PK11Slot_SetNSSToken increments the refcount on |token| to 2 */ |
77 | 4 | PK11Slot_SetNSSToken(slot, token); |
78 | | |
79 | | /* we give our reference to |td->tokenList| */ |
80 | 4 | NSSRWLock_LockWrite(td->tokensLock); |
81 | 4 | nssList_Add(td->tokenList, token); |
82 | 4 | NSSRWLock_UnlockWrite(td->tokensLock); |
83 | 4 | } else { |
84 | 0 | PK11Slot_SetNSSToken(slot, NULL); |
85 | 0 | } |
86 | 4 | return PR_SUCCESS; |
87 | 4 | } |
88 | | |
89 | | NSS_IMPLEMENT PRStatus |
90 | | STAN_ResetTokenInterator(NSSTrustDomain *td) |
91 | 0 | { |
92 | 0 | if (!td) { |
93 | 0 | td = g_default_trust_domain; |
94 | 0 | if (!td) { |
95 | | /* we're called while still initting. slot will get added |
96 | | * appropriately through normal init processes */ |
97 | 0 | return PR_SUCCESS; |
98 | 0 | } |
99 | 0 | } |
100 | 0 | NSSRWLock_LockWrite(td->tokensLock); |
101 | 0 | nssListIterator_Destroy(td->tokens); |
102 | 0 | td->tokens = nssList_CreateIterator(td->tokenList); |
103 | 0 | NSSRWLock_UnlockWrite(td->tokensLock); |
104 | 0 | return PR_SUCCESS; |
105 | 0 | } |
106 | | |
107 | | NSS_IMPLEMENT PRStatus |
108 | | STAN_LoadDefaultNSS3TrustDomain( |
109 | | void) |
110 | 2 | { |
111 | 2 | NSSTrustDomain *td; |
112 | 2 | SECMODModuleList *mlp; |
113 | 2 | SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock(); |
114 | 2 | int i; |
115 | | |
116 | 2 | if (g_default_trust_domain || g_default_crypto_context) { |
117 | | /* Stan is already initialized or a previous shutdown failed. */ |
118 | 0 | nss_SetError(NSS_ERROR_ALREADY_INITIALIZED); |
119 | 0 | return PR_FAILURE; |
120 | 0 | } |
121 | 2 | td = NSSTrustDomain_Create(NULL, NULL, NULL, NULL); |
122 | 2 | if (!td) { |
123 | 0 | return PR_FAILURE; |
124 | 0 | } |
125 | | /* |
126 | | * Deadlock warning: we should never acquire the moduleLock while |
127 | | * we hold the tokensLock. We can use the NSSRWLock Rank feature to |
128 | | * guarrentee this. tokensLock have a higher rank than module lock. |
129 | | */ |
130 | 2 | td->tokenList = nssList_Create(td->arena, PR_TRUE); |
131 | 2 | if (!td->tokenList) { |
132 | 0 | goto loser; |
133 | 0 | } |
134 | 2 | SECMOD_GetReadLock(moduleLock); |
135 | 2 | NSSRWLock_LockWrite(td->tokensLock); |
136 | 4 | for (mlp = SECMOD_GetDefaultModuleList(); mlp != NULL; mlp = mlp->next) { |
137 | 6 | for (i = 0; i < mlp->module->slotCount; i++) { |
138 | 4 | STAN_InitTokenForSlotInfo(td, mlp->module->slots[i]); |
139 | 4 | } |
140 | 2 | } |
141 | 2 | td->tokens = nssList_CreateIterator(td->tokenList); |
142 | 2 | NSSRWLock_UnlockWrite(td->tokensLock); |
143 | 2 | SECMOD_ReleaseReadLock(moduleLock); |
144 | 2 | if (!td->tokens) { |
145 | 0 | goto loser; |
146 | 0 | } |
147 | 2 | g_default_crypto_context = NSSTrustDomain_CreateCryptoContext(td, NULL); |
148 | 2 | if (!g_default_crypto_context) { |
149 | 0 | goto loser; |
150 | 0 | } |
151 | 2 | g_default_trust_domain = td; |
152 | 2 | return PR_SUCCESS; |
153 | | |
154 | 0 | loser: |
155 | 0 | NSSTrustDomain_Destroy(td); |
156 | 0 | return PR_FAILURE; |
157 | 2 | } |
158 | | |
159 | | /* |
160 | | * must be called holding the ModuleListLock (either read or write). |
161 | | */ |
162 | | NSS_IMPLEMENT SECStatus |
163 | | STAN_AddModuleToDefaultTrustDomain( |
164 | | SECMODModule *module) |
165 | 0 | { |
166 | 0 | NSSTrustDomain *td; |
167 | 0 | int i; |
168 | 0 | td = STAN_GetDefaultTrustDomain(); |
169 | 0 | for (i = 0; i < module->slotCount; i++) { |
170 | 0 | STAN_InitTokenForSlotInfo(td, module->slots[i]); |
171 | 0 | } |
172 | 0 | STAN_ResetTokenInterator(td); |
173 | 0 | return SECSuccess; |
174 | 0 | } |
175 | | |
176 | | /* |
177 | | * must be called holding the ModuleListLock (either read or write). |
178 | | */ |
179 | | NSS_IMPLEMENT SECStatus |
180 | | STAN_RemoveModuleFromDefaultTrustDomain( |
181 | | SECMODModule *module) |
182 | 0 | { |
183 | 0 | NSSToken *token; |
184 | 0 | NSSTrustDomain *td; |
185 | 0 | int i; |
186 | 0 | td = STAN_GetDefaultTrustDomain(); |
187 | 0 | for (i = 0; i < module->slotCount; i++) { |
188 | 0 | token = PK11Slot_GetNSSToken(module->slots[i]); |
189 | 0 | if (token) { |
190 | 0 | nssToken_NotifyCertsNotVisible(token); |
191 | 0 | NSSRWLock_LockWrite(td->tokensLock); |
192 | 0 | nssList_Remove(td->tokenList, token); |
193 | 0 | NSSRWLock_UnlockWrite(td->tokensLock); |
194 | 0 | PK11Slot_SetNSSToken(module->slots[i], NULL); |
195 | 0 | (void)nssToken_Destroy(token); /* for the |td->tokenList| reference */ |
196 | 0 | (void)nssToken_Destroy(token); /* for our PK11Slot_GetNSSToken reference */ |
197 | 0 | } |
198 | 0 | } |
199 | 0 | NSSRWLock_LockWrite(td->tokensLock); |
200 | 0 | nssListIterator_Destroy(td->tokens); |
201 | 0 | td->tokens = nssList_CreateIterator(td->tokenList); |
202 | 0 | NSSRWLock_UnlockWrite(td->tokensLock); |
203 | 0 | return SECSuccess; |
204 | 0 | } |
205 | | |
206 | | NSS_IMPLEMENT PRStatus |
207 | | STAN_Shutdown() |
208 | 0 | { |
209 | 0 | PRStatus status = PR_SUCCESS; |
210 | 0 | if (g_default_trust_domain) { |
211 | 0 | if (NSSTrustDomain_Destroy(g_default_trust_domain) == PR_SUCCESS) { |
212 | 0 | g_default_trust_domain = NULL; |
213 | 0 | } else { |
214 | 0 | status = PR_FAILURE; |
215 | 0 | } |
216 | 0 | } |
217 | 0 | if (g_default_crypto_context) { |
218 | 0 | if (NSSCryptoContext_Destroy(g_default_crypto_context) == PR_SUCCESS) { |
219 | 0 | g_default_crypto_context = NULL; |
220 | 0 | } else { |
221 | 0 | status = PR_FAILURE; |
222 | 0 | } |
223 | 0 | } |
224 | 0 | return status; |
225 | 0 | } |
226 | | |
227 | | /* this function should not be a hack; it will be needed in 4.0 (rename) */ |
228 | | NSS_IMPLEMENT NSSItem * |
229 | | STAN_GetCertIdentifierFromDER(NSSArena *arenaOpt, NSSDER *der) |
230 | 0 | { |
231 | 0 | NSSItem *rvKey; |
232 | 0 | SECItem secDER; |
233 | 0 | SECItem secKey = { 0 }; |
234 | 0 | SECStatus secrv; |
235 | 0 | PLArenaPool *arena; |
236 | |
|
237 | 0 | SECITEM_FROM_NSSITEM(&secDER, der); |
238 | | |
239 | | /* nss3 call uses nss3 arena's */ |
240 | 0 | arena = PORT_NewArena(256); |
241 | 0 | if (!arena) { |
242 | 0 | return NULL; |
243 | 0 | } |
244 | 0 | secrv = CERT_KeyFromDERCert(arena, &secDER, &secKey); |
245 | 0 | if (secrv != SECSuccess) { |
246 | 0 | PORT_FreeArena(arena, PR_FALSE); |
247 | 0 | return NULL; |
248 | 0 | } |
249 | 0 | rvKey = nssItem_Create(arenaOpt, NULL, secKey.len, (void *)secKey.data); |
250 | 0 | PORT_FreeArena(arena, PR_FALSE); |
251 | 0 | return rvKey; |
252 | 0 | } |
253 | | |
254 | | NSS_IMPLEMENT PRStatus |
255 | | nssPKIX509_GetIssuerAndSerialFromDER(NSSDER *der, |
256 | | NSSDER *issuer, NSSDER *serial) |
257 | 0 | { |
258 | 0 | SECItem derCert = { 0 }; |
259 | 0 | SECItem derIssuer = { 0 }; |
260 | 0 | SECItem derSerial = { 0 }; |
261 | 0 | SECStatus secrv; |
262 | 0 | derCert.data = (unsigned char *)der->data; |
263 | 0 | derCert.len = der->size; |
264 | 0 | secrv = CERT_IssuerNameFromDERCert(&derCert, &derIssuer); |
265 | 0 | if (secrv != SECSuccess) { |
266 | 0 | return PR_FAILURE; |
267 | 0 | } |
268 | 0 | secrv = CERT_SerialNumberFromDERCert(&derCert, &derSerial); |
269 | 0 | if (secrv != SECSuccess) { |
270 | 0 | PORT_Free(derSerial.data); |
271 | 0 | return PR_FAILURE; |
272 | 0 | } |
273 | 0 | issuer->data = derIssuer.data; |
274 | 0 | issuer->size = derIssuer.len; |
275 | 0 | serial->data = derSerial.data; |
276 | 0 | serial->size = derSerial.len; |
277 | 0 | return PR_SUCCESS; |
278 | 0 | } |
279 | | |
280 | | static NSSItem * |
281 | | nss3certificate_getIdentifier(nssDecodedCert *dc) |
282 | 0 | { |
283 | 0 | NSSItem *rvID; |
284 | 0 | CERTCertificate *c = (CERTCertificate *)dc->data; |
285 | 0 | rvID = nssItem_Create(NULL, NULL, c->certKey.len, c->certKey.data); |
286 | 0 | return rvID; |
287 | 0 | } |
288 | | |
289 | | static void * |
290 | | nss3certificate_getIssuerIdentifier(nssDecodedCert *dc) |
291 | 0 | { |
292 | 0 | CERTCertificate *c = (CERTCertificate *)dc->data; |
293 | 0 | return (void *)c->authKeyID; |
294 | 0 | } |
295 | | |
296 | | static nssCertIDMatch |
297 | | nss3certificate_matchIdentifier(nssDecodedCert *dc, void *id) |
298 | 0 | { |
299 | 0 | CERTCertificate *c = (CERTCertificate *)dc->data; |
300 | 0 | CERTAuthKeyID *authKeyID = (CERTAuthKeyID *)id; |
301 | 0 | SECItem skid; |
302 | 0 | nssCertIDMatch match = nssCertIDMatch_Unknown; |
303 | | |
304 | | /* keyIdentifier */ |
305 | 0 | if (authKeyID->keyID.len > 0 && |
306 | 0 | CERT_FindSubjectKeyIDExtension(c, &skid) == SECSuccess) { |
307 | 0 | PRBool skiEqual; |
308 | 0 | skiEqual = SECITEM_ItemsAreEqual(&authKeyID->keyID, &skid); |
309 | 0 | PORT_Free(skid.data); |
310 | 0 | if (skiEqual) { |
311 | | /* change the state to positive match, but keep going */ |
312 | 0 | match = nssCertIDMatch_Yes; |
313 | 0 | } else { |
314 | | /* exit immediately on failure */ |
315 | 0 | return nssCertIDMatch_No; |
316 | 0 | } |
317 | 0 | } |
318 | | |
319 | | /* issuer/serial (treated as pair) */ |
320 | 0 | if (authKeyID->authCertIssuer) { |
321 | 0 | SECItem *caName = NULL; |
322 | 0 | SECItem *caSN = &authKeyID->authCertSerialNumber; |
323 | |
|
324 | 0 | caName = (SECItem *)CERT_GetGeneralNameByType( |
325 | 0 | authKeyID->authCertIssuer, |
326 | 0 | certDirectoryName, PR_TRUE); |
327 | 0 | if (caName != NULL && |
328 | 0 | SECITEM_ItemsAreEqual(&c->derIssuer, caName) && |
329 | 0 | SECITEM_ItemsAreEqual(&c->serialNumber, caSN)) { |
330 | 0 | match = nssCertIDMatch_Yes; |
331 | 0 | } else { |
332 | 0 | match = nssCertIDMatch_Unknown; |
333 | 0 | } |
334 | 0 | } |
335 | 0 | return match; |
336 | 0 | } |
337 | | |
338 | | static PRBool |
339 | | nss3certificate_isValidIssuer(nssDecodedCert *dc) |
340 | 0 | { |
341 | 0 | CERTCertificate *c = (CERTCertificate *)dc->data; |
342 | 0 | unsigned int ignore; |
343 | 0 | return CERT_IsCACert(c, &ignore); |
344 | 0 | } |
345 | | |
346 | | static NSSUsage * |
347 | | nss3certificate_getUsage(nssDecodedCert *dc) |
348 | 0 | { |
349 | | /* CERTCertificate *c = (CERTCertificate *)dc->data; */ |
350 | 0 | return NULL; |
351 | 0 | } |
352 | | |
353 | | static PRBool |
354 | | nss3certificate_isValidAtTime(nssDecodedCert *dc, NSSTime *time) |
355 | 0 | { |
356 | 0 | SECCertTimeValidity validity; |
357 | 0 | CERTCertificate *c = (CERTCertificate *)dc->data; |
358 | 0 | validity = CERT_CheckCertValidTimes(c, NSSTime_GetPRTime(time), PR_TRUE); |
359 | 0 | if (validity == secCertTimeValid) { |
360 | 0 | return PR_TRUE; |
361 | 0 | } |
362 | 0 | return PR_FALSE; |
363 | 0 | } |
364 | | |
365 | | static PRBool |
366 | | nss3certificate_isNewerThan(nssDecodedCert *dc, nssDecodedCert *cmpdc) |
367 | 0 | { |
368 | | /* I know this isn't right, but this is glue code anyway */ |
369 | 0 | if (cmpdc->type == dc->type) { |
370 | 0 | CERTCertificate *certa = (CERTCertificate *)dc->data; |
371 | 0 | CERTCertificate *certb = (CERTCertificate *)cmpdc->data; |
372 | 0 | return CERT_IsNewer(certa, certb); |
373 | 0 | } |
374 | 0 | return PR_FALSE; |
375 | 0 | } |
376 | | |
377 | | /* CERT_FilterCertListByUsage */ |
378 | | static PRBool |
379 | | nss3certificate_matchUsage(nssDecodedCert *dc, const NSSUsage *usage) |
380 | 0 | { |
381 | 0 | CERTCertificate *cc; |
382 | 0 | unsigned int requiredKeyUsage = 0; |
383 | 0 | unsigned int requiredCertType = 0; |
384 | 0 | SECStatus secrv; |
385 | 0 | PRBool match; |
386 | 0 | PRBool ca; |
387 | | |
388 | | /* This is for NSS 3.3 functions that do not specify a usage */ |
389 | 0 | if (usage->anyUsage) { |
390 | 0 | return PR_TRUE; |
391 | 0 | } |
392 | 0 | ca = usage->nss3lookingForCA; |
393 | 0 | secrv = CERT_KeyUsageAndTypeForCertUsage(usage->nss3usage, ca, |
394 | 0 | &requiredKeyUsage, |
395 | 0 | &requiredCertType); |
396 | 0 | if (secrv != SECSuccess) { |
397 | 0 | return PR_FALSE; |
398 | 0 | } |
399 | 0 | cc = (CERTCertificate *)dc->data; |
400 | 0 | secrv = CERT_CheckKeyUsage(cc, requiredKeyUsage); |
401 | 0 | match = (PRBool)(secrv == SECSuccess); |
402 | 0 | if (match) { |
403 | 0 | unsigned int certType = 0; |
404 | 0 | if (ca) { |
405 | 0 | (void)CERT_IsCACert(cc, &certType); |
406 | 0 | } else { |
407 | 0 | certType = cc->nsCertType; |
408 | 0 | } |
409 | 0 | if (!(certType & requiredCertType)) { |
410 | 0 | match = PR_FALSE; |
411 | 0 | } |
412 | 0 | } |
413 | 0 | return match; |
414 | 0 | } |
415 | | |
416 | | static PRBool |
417 | | nss3certificate_isTrustedForUsage(nssDecodedCert *dc, const NSSUsage *usage) |
418 | 0 | { |
419 | 0 | CERTCertificate *cc; |
420 | 0 | PRBool ca; |
421 | 0 | SECStatus secrv; |
422 | 0 | unsigned int requiredFlags; |
423 | 0 | unsigned int trustFlags; |
424 | 0 | SECTrustType trustType; |
425 | 0 | CERTCertTrust trust; |
426 | | |
427 | | /* This is for NSS 3.3 functions that do not specify a usage */ |
428 | 0 | if (usage->anyUsage) { |
429 | 0 | return PR_FALSE; /* XXX is this right? */ |
430 | 0 | } |
431 | 0 | cc = (CERTCertificate *)dc->data; |
432 | 0 | ca = usage->nss3lookingForCA; |
433 | 0 | if (!ca) { |
434 | 0 | PRBool trusted; |
435 | 0 | unsigned int failedFlags; |
436 | 0 | secrv = cert_CheckLeafTrust(cc, usage->nss3usage, |
437 | 0 | &failedFlags, &trusted); |
438 | 0 | return secrv == SECSuccess && trusted; |
439 | 0 | } |
440 | 0 | secrv = CERT_TrustFlagsForCACertUsage(usage->nss3usage, &requiredFlags, |
441 | 0 | &trustType); |
442 | 0 | if (secrv != SECSuccess) { |
443 | 0 | return PR_FALSE; |
444 | 0 | } |
445 | 0 | secrv = CERT_GetCertTrust(cc, &trust); |
446 | 0 | if (secrv != SECSuccess) { |
447 | 0 | return PR_FALSE; |
448 | 0 | } |
449 | 0 | if (trustType == trustTypeNone) { |
450 | | /* normally trustTypeNone usages accept any of the given trust bits |
451 | | * being on as acceptable. */ |
452 | 0 | trustFlags = trust.sslFlags | trust.emailFlags | |
453 | 0 | trust.objectSigningFlags; |
454 | 0 | } else { |
455 | 0 | trustFlags = SEC_GET_TRUST_FLAGS(&trust, trustType); |
456 | 0 | } |
457 | 0 | return (trustFlags & requiredFlags) == requiredFlags; |
458 | 0 | } |
459 | | |
460 | | static NSSASCII7 * |
461 | | nss3certificate_getEmailAddress(nssDecodedCert *dc) |
462 | 0 | { |
463 | 0 | CERTCertificate *cc = (CERTCertificate *)dc->data; |
464 | 0 | return (cc && cc->emailAddr && cc->emailAddr[0]) |
465 | 0 | ? (NSSASCII7 *)cc->emailAddr |
466 | 0 | : NULL; |
467 | 0 | } |
468 | | |
469 | | static PRStatus |
470 | | nss3certificate_getDERSerialNumber(nssDecodedCert *dc, |
471 | | NSSDER *serial, NSSArena *arena) |
472 | 0 | { |
473 | 0 | CERTCertificate *cc = (CERTCertificate *)dc->data; |
474 | 0 | SECItem derSerial = { 0 }; |
475 | 0 | SECStatus secrv; |
476 | 0 | secrv = CERT_SerialNumberFromDERCert(&cc->derCert, &derSerial); |
477 | 0 | if (secrv == SECSuccess) { |
478 | 0 | (void)nssItem_Create(arena, serial, derSerial.len, derSerial.data); |
479 | 0 | PORT_Free(derSerial.data); |
480 | 0 | return PR_SUCCESS; |
481 | 0 | } |
482 | 0 | return PR_FAILURE; |
483 | 0 | } |
484 | | |
485 | | /* Returns NULL if "encoding" cannot be decoded. */ |
486 | | NSS_IMPLEMENT nssDecodedCert * |
487 | | nssDecodedPKIXCertificate_Create( |
488 | | NSSArena *arenaOpt, |
489 | | NSSDER *encoding) |
490 | 0 | { |
491 | 0 | nssDecodedCert *rvDC = NULL; |
492 | 0 | CERTCertificate *cert; |
493 | 0 | SECItem secDER; |
494 | |
|
495 | 0 | SECITEM_FROM_NSSITEM(&secDER, encoding); |
496 | 0 | cert = CERT_DecodeDERCertificate(&secDER, PR_TRUE, NULL); |
497 | 0 | if (cert) { |
498 | 0 | rvDC = nss_ZNEW(arenaOpt, nssDecodedCert); |
499 | 0 | if (rvDC) { |
500 | 0 | rvDC->type = NSSCertificateType_PKIX; |
501 | 0 | rvDC->data = (void *)cert; |
502 | 0 | rvDC->getIdentifier = nss3certificate_getIdentifier; |
503 | 0 | rvDC->getIssuerIdentifier = nss3certificate_getIssuerIdentifier; |
504 | 0 | rvDC->matchIdentifier = nss3certificate_matchIdentifier; |
505 | 0 | rvDC->isValidIssuer = nss3certificate_isValidIssuer; |
506 | 0 | rvDC->getUsage = nss3certificate_getUsage; |
507 | 0 | rvDC->isValidAtTime = nss3certificate_isValidAtTime; |
508 | 0 | rvDC->isNewerThan = nss3certificate_isNewerThan; |
509 | 0 | rvDC->matchUsage = nss3certificate_matchUsage; |
510 | 0 | rvDC->isTrustedForUsage = nss3certificate_isTrustedForUsage; |
511 | 0 | rvDC->getEmailAddress = nss3certificate_getEmailAddress; |
512 | 0 | rvDC->getDERSerialNumber = nss3certificate_getDERSerialNumber; |
513 | 0 | } else { |
514 | 0 | CERT_DestroyCertificate(cert); |
515 | 0 | } |
516 | 0 | } |
517 | 0 | return rvDC; |
518 | 0 | } |
519 | | |
520 | | static nssDecodedCert * |
521 | | create_decoded_pkix_cert_from_nss3cert( |
522 | | NSSArena *arenaOpt, |
523 | | CERTCertificate *cc) |
524 | 0 | { |
525 | 0 | nssDecodedCert *rvDC = nss_ZNEW(arenaOpt, nssDecodedCert); |
526 | 0 | if (rvDC) { |
527 | 0 | rvDC->type = NSSCertificateType_PKIX; |
528 | 0 | rvDC->data = (void *)cc; |
529 | 0 | rvDC->getIdentifier = nss3certificate_getIdentifier; |
530 | 0 | rvDC->getIssuerIdentifier = nss3certificate_getIssuerIdentifier; |
531 | 0 | rvDC->matchIdentifier = nss3certificate_matchIdentifier; |
532 | 0 | rvDC->isValidIssuer = nss3certificate_isValidIssuer; |
533 | 0 | rvDC->getUsage = nss3certificate_getUsage; |
534 | 0 | rvDC->isValidAtTime = nss3certificate_isValidAtTime; |
535 | 0 | rvDC->isNewerThan = nss3certificate_isNewerThan; |
536 | 0 | rvDC->matchUsage = nss3certificate_matchUsage; |
537 | 0 | rvDC->isTrustedForUsage = nss3certificate_isTrustedForUsage; |
538 | 0 | rvDC->getEmailAddress = nss3certificate_getEmailAddress; |
539 | 0 | rvDC->getDERSerialNumber = nss3certificate_getDERSerialNumber; |
540 | 0 | } |
541 | 0 | return rvDC; |
542 | 0 | } |
543 | | |
544 | | NSS_IMPLEMENT PRStatus |
545 | | nssDecodedPKIXCertificate_Destroy(nssDecodedCert *dc) |
546 | 0 | { |
547 | 0 | CERTCertificate *cert = (CERTCertificate *)dc->data; |
548 | | |
549 | | /* The decoder may only be half initialized (the case where we find we |
550 | | * could not decode the certificate). In this case, there is not cert to |
551 | | * free, just free the dc structure. */ |
552 | 0 | if (cert) { |
553 | 0 | PRBool freeSlot = cert->ownSlot; |
554 | 0 | PK11SlotInfo *slot = cert->slot; |
555 | 0 | PLArenaPool *arena = cert->arena; |
556 | | /* zero cert before freeing. Any stale references to this cert |
557 | | * after this point will probably cause an exception. */ |
558 | 0 | PORT_Memset(cert, 0, sizeof *cert); |
559 | | /* free the arena that contains the cert. */ |
560 | 0 | PORT_FreeArena(arena, PR_FALSE); |
561 | 0 | if (slot && freeSlot) { |
562 | 0 | PK11_FreeSlot(slot); |
563 | 0 | } |
564 | 0 | } |
565 | 0 | nss_ZFreeIf(dc); |
566 | 0 | return PR_SUCCESS; |
567 | 0 | } |
568 | | |
569 | | /* see pk11cert.c:pk11_HandleTrustObject */ |
570 | | static unsigned int |
571 | | get_nss3trust_from_nss4trust(nssTrustLevel t) |
572 | 0 | { |
573 | 0 | unsigned int rt = 0; |
574 | 0 | if (t == nssTrustLevel_Trusted) { |
575 | 0 | rt |= CERTDB_TERMINAL_RECORD | CERTDB_TRUSTED; |
576 | 0 | } |
577 | 0 | if (t == nssTrustLevel_TrustedDelegator) { |
578 | 0 | rt |= CERTDB_VALID_CA | CERTDB_TRUSTED_CA; |
579 | 0 | } |
580 | 0 | if (t == nssTrustLevel_NotTrusted) { |
581 | 0 | rt |= CERTDB_TERMINAL_RECORD; |
582 | 0 | } |
583 | 0 | if (t == nssTrustLevel_ValidDelegator) { |
584 | 0 | rt |= CERTDB_VALID_CA; |
585 | 0 | } |
586 | 0 | return rt; |
587 | 0 | } |
588 | | |
589 | | static CERTCertTrust * |
590 | | cert_trust_from_stan_trust(NSSTrust *t, PLArenaPool *arena) |
591 | 0 | { |
592 | 0 | CERTCertTrust *rvTrust; |
593 | 0 | unsigned int client; |
594 | 0 | if (!t) { |
595 | 0 | return NULL; |
596 | 0 | } |
597 | 0 | rvTrust = PORT_ArenaAlloc(arena, sizeof(CERTCertTrust)); |
598 | 0 | if (!rvTrust) |
599 | 0 | return NULL; |
600 | 0 | rvTrust->sslFlags = get_nss3trust_from_nss4trust(t->serverAuth); |
601 | 0 | client = get_nss3trust_from_nss4trust(t->clientAuth); |
602 | 0 | if (client & (CERTDB_TRUSTED_CA | CERTDB_NS_TRUSTED_CA)) { |
603 | 0 | client &= ~(CERTDB_TRUSTED_CA | CERTDB_NS_TRUSTED_CA); |
604 | 0 | rvTrust->sslFlags |= CERTDB_TRUSTED_CLIENT_CA; |
605 | 0 | } |
606 | 0 | rvTrust->sslFlags |= client; |
607 | 0 | rvTrust->emailFlags = get_nss3trust_from_nss4trust(t->emailProtection); |
608 | 0 | rvTrust->objectSigningFlags = get_nss3trust_from_nss4trust(t->codeSigning); |
609 | 0 | return rvTrust; |
610 | 0 | } |
611 | | |
612 | | CERTCertTrust * |
613 | | nssTrust_GetCERTCertTrustForCert(NSSCertificate *c, CERTCertificate *cc) |
614 | 0 | { |
615 | 0 | CERTCertTrust *rvTrust = NULL; |
616 | 0 | NSSTrustDomain *td = STAN_GetDefaultTrustDomain(); |
617 | 0 | NSSTrust *t; |
618 | 0 | t = nssTrustDomain_FindTrustForCertificate(td, c); |
619 | 0 | if (t) { |
620 | 0 | rvTrust = cert_trust_from_stan_trust(t, cc->arena); |
621 | 0 | if (!rvTrust) { |
622 | 0 | nssTrust_Destroy(t); |
623 | 0 | return NULL; |
624 | 0 | } |
625 | 0 | nssTrust_Destroy(t); |
626 | 0 | } else { |
627 | 0 | rvTrust = PORT_ArenaAlloc(cc->arena, sizeof(CERTCertTrust)); |
628 | 0 | if (!rvTrust) { |
629 | 0 | return NULL; |
630 | 0 | } |
631 | 0 | memset(rvTrust, 0, sizeof(*rvTrust)); |
632 | 0 | } |
633 | 0 | if (NSSCertificate_IsPrivateKeyAvailable(c, NULL, NULL)) { |
634 | 0 | rvTrust->sslFlags |= CERTDB_USER; |
635 | 0 | rvTrust->emailFlags |= CERTDB_USER; |
636 | 0 | rvTrust->objectSigningFlags |= CERTDB_USER; |
637 | 0 | } |
638 | 0 | return rvTrust; |
639 | 0 | } |
640 | | |
641 | | static nssCryptokiInstance * |
642 | | get_cert_instance(NSSCertificate *c) |
643 | 0 | { |
644 | 0 | nssCryptokiObject *instance, **ci; |
645 | 0 | nssCryptokiObject **instances = nssPKIObject_GetInstances(&c->object); |
646 | 0 | if (!instances) { |
647 | 0 | return NULL; |
648 | 0 | } |
649 | 0 | instance = NULL; |
650 | 0 | for (ci = instances; *ci; ci++) { |
651 | 0 | if (!instance) { |
652 | 0 | instance = nssCryptokiObject_Clone(*ci); |
653 | 0 | } else { |
654 | | /* This only really works for two instances... But 3.4 can't |
655 | | * handle more anyway. The logic is, if there are multiple |
656 | | * instances, prefer the one that is not internal (e.g., on |
657 | | * a hardware device. |
658 | | */ |
659 | 0 | if (PK11_IsInternal(instance->token->pk11slot)) { |
660 | 0 | nssCryptokiObject_Destroy(instance); |
661 | 0 | instance = nssCryptokiObject_Clone(*ci); |
662 | 0 | } |
663 | 0 | } |
664 | 0 | } |
665 | 0 | nssCryptokiObjectArray_Destroy(instances); |
666 | 0 | return instance; |
667 | 0 | } |
668 | | |
669 | | char * |
670 | | STAN_GetCERTCertificateNameForInstance( |
671 | | PLArenaPool *arenaOpt, |
672 | | NSSCertificate *c, |
673 | | nssCryptokiInstance *instance) |
674 | 0 | { |
675 | 0 | NSSCryptoContext *context = c->object.cryptoContext; |
676 | 0 | PRStatus nssrv; |
677 | 0 | int nicklen, tokenlen, len; |
678 | 0 | NSSUTF8 *tokenName = NULL; |
679 | 0 | NSSUTF8 *stanNick = NULL; |
680 | 0 | char *nickname = NULL; |
681 | 0 | char *nick; |
682 | |
|
683 | 0 | if (instance) { |
684 | 0 | stanNick = instance->label; |
685 | 0 | } else if (context) { |
686 | 0 | stanNick = c->object.tempName; |
687 | 0 | } |
688 | 0 | if (stanNick) { |
689 | | /* fill other fields needed by NSS3 functions using CERTCertificate */ |
690 | 0 | if (instance && (!PK11_IsInternalKeySlot(instance->token->pk11slot) || |
691 | 0 | PORT_Strchr(stanNick, ':') != NULL)) { |
692 | 0 | tokenName = nssToken_GetName(instance->token); |
693 | 0 | tokenlen = nssUTF8_Size(tokenName, &nssrv); |
694 | 0 | } else { |
695 | | /* don't use token name for internal slot; 3.3 didn't */ |
696 | 0 | tokenlen = 0; |
697 | 0 | } |
698 | 0 | nicklen = nssUTF8_Size(stanNick, &nssrv); |
699 | 0 | len = tokenlen + nicklen; |
700 | 0 | if (arenaOpt) { |
701 | 0 | nickname = PORT_ArenaAlloc(arenaOpt, len); |
702 | 0 | } else { |
703 | 0 | nickname = PORT_Alloc(len); |
704 | 0 | } |
705 | 0 | nick = nickname; |
706 | 0 | if (tokenName) { |
707 | 0 | memcpy(nick, tokenName, tokenlen - 1); |
708 | 0 | nick += tokenlen - 1; |
709 | 0 | *nick++ = ':'; |
710 | 0 | } |
711 | 0 | memcpy(nick, stanNick, nicklen - 1); |
712 | 0 | nickname[len - 1] = '\0'; |
713 | 0 | } |
714 | 0 | return nickname; |
715 | 0 | } |
716 | | |
717 | | char * |
718 | | STAN_GetCERTCertificateName(PLArenaPool *arenaOpt, NSSCertificate *c) |
719 | 0 | { |
720 | 0 | char *result; |
721 | 0 | nssCryptokiInstance *instance = get_cert_instance(c); |
722 | | /* It's OK to call this function, even if instance is NULL */ |
723 | 0 | result = STAN_GetCERTCertificateNameForInstance(arenaOpt, c, instance); |
724 | 0 | if (instance) |
725 | 0 | nssCryptokiObject_Destroy(instance); |
726 | 0 | return result; |
727 | 0 | } |
728 | | |
729 | | static void |
730 | | fill_CERTCertificateFields(NSSCertificate *c, CERTCertificate *cc, PRBool forced) |
731 | 0 | { |
732 | 0 | CERTCertTrust *trust = NULL; |
733 | 0 | NSSTrust *nssTrust; |
734 | 0 | NSSCryptoContext *context = c->object.cryptoContext; |
735 | 0 | nssCryptokiInstance *instance; |
736 | 0 | NSSUTF8 *stanNick = NULL; |
737 | | |
738 | | /* We are holding the base class object's lock on entry of this function |
739 | | * This lock protects writes to fields of the CERTCertificate . |
740 | | * It is also needed by some functions to compute values such as trust. |
741 | | */ |
742 | 0 | instance = get_cert_instance(c); |
743 | |
|
744 | 0 | if (instance) { |
745 | 0 | stanNick = instance->label; |
746 | 0 | } else if (context) { |
747 | 0 | stanNick = c->object.tempName; |
748 | 0 | } |
749 | | /* fill other fields needed by NSS3 functions using CERTCertificate */ |
750 | 0 | if ((!cc->nickname && stanNick) || forced) { |
751 | 0 | PRStatus nssrv; |
752 | 0 | int nicklen, tokenlen, len; |
753 | 0 | NSSUTF8 *tokenName = NULL; |
754 | 0 | char *nick; |
755 | 0 | if (instance && |
756 | 0 | (!PK11_IsInternalKeySlot(instance->token->pk11slot) || |
757 | 0 | (stanNick && PORT_Strchr(stanNick, ':') != NULL))) { |
758 | 0 | tokenName = nssToken_GetName(instance->token); |
759 | 0 | tokenlen = nssUTF8_Size(tokenName, &nssrv); |
760 | 0 | } else { |
761 | | /* don't use token name for internal slot; 3.3 didn't */ |
762 | 0 | tokenlen = 0; |
763 | 0 | } |
764 | 0 | if (stanNick) { |
765 | 0 | nicklen = nssUTF8_Size(stanNick, &nssrv); |
766 | 0 | len = tokenlen + nicklen; |
767 | 0 | nick = PORT_ArenaAlloc(cc->arena, len); |
768 | 0 | if (tokenName) { |
769 | 0 | memcpy(nick, tokenName, tokenlen - 1); |
770 | 0 | nick[tokenlen - 1] = ':'; |
771 | 0 | memcpy(nick + tokenlen, stanNick, nicklen - 1); |
772 | 0 | } else { |
773 | 0 | memcpy(nick, stanNick, nicklen - 1); |
774 | 0 | } |
775 | 0 | nick[len - 1] = '\0'; |
776 | 0 | cc->nickname = nick; |
777 | 0 | } else { |
778 | 0 | cc->nickname = NULL; |
779 | 0 | } |
780 | 0 | } |
781 | 0 | if (context) { |
782 | | /* trust */ |
783 | 0 | nssTrust = nssCryptoContext_FindTrustForCertificate(context, c); |
784 | 0 | if (!nssTrust) { |
785 | | /* chicken and egg issue: |
786 | | * |
787 | | * c->issuer and c->serial are empty at this point, but |
788 | | * nssTrustDomain_FindTrustForCertificate use them to look up |
789 | | * up the trust object, so we point them to cc->derIssuer and |
790 | | * cc->serialNumber. |
791 | | * |
792 | | * Our caller will fill these in with proper arena copies when we |
793 | | * return. */ |
794 | 0 | c->issuer.data = cc->derIssuer.data; |
795 | 0 | c->issuer.size = cc->derIssuer.len; |
796 | 0 | c->serial.data = cc->serialNumber.data; |
797 | 0 | c->serial.size = cc->serialNumber.len; |
798 | 0 | nssTrust = nssTrustDomain_FindTrustForCertificate(context->td, c); |
799 | 0 | } |
800 | 0 | if (nssTrust) { |
801 | 0 | trust = cert_trust_from_stan_trust(nssTrust, cc->arena); |
802 | 0 | if (trust) { |
803 | | /* we should destroy cc->trust before replacing it, but it's |
804 | | allocated in cc->arena, so memory growth will occur on each |
805 | | refresh */ |
806 | 0 | CERT_LockCertTrust(cc); |
807 | 0 | cc->trust = trust; |
808 | 0 | CERT_UnlockCertTrust(cc); |
809 | 0 | } |
810 | 0 | nssTrust_Destroy(nssTrust); |
811 | 0 | } |
812 | 0 | } else if (instance) { |
813 | | /* slot */ |
814 | 0 | if (cc->slot != instance->token->pk11slot) { |
815 | 0 | if (cc->slot) { |
816 | 0 | PK11_FreeSlot(cc->slot); |
817 | 0 | } |
818 | 0 | cc->slot = PK11_ReferenceSlot(instance->token->pk11slot); |
819 | 0 | } |
820 | 0 | cc->ownSlot = PR_TRUE; |
821 | | /* pkcs11ID */ |
822 | 0 | cc->pkcs11ID = instance->handle; |
823 | | /* trust */ |
824 | 0 | trust = nssTrust_GetCERTCertTrustForCert(c, cc); |
825 | 0 | if (trust) { |
826 | | /* we should destroy cc->trust before replacing it, but it's |
827 | | allocated in cc->arena, so memory growth will occur on each |
828 | | refresh */ |
829 | 0 | CERT_LockCertTrust(cc); |
830 | 0 | cc->trust = trust; |
831 | 0 | CERT_UnlockCertTrust(cc); |
832 | 0 | } |
833 | | /* Read the distrust fields from a nssckbi/builtins certificate and |
834 | | * fill the fields in CERTCertificate structure when any valid date |
835 | | * is found. */ |
836 | 0 | if (PK11_IsReadOnly(cc->slot) && PK11_HasRootCerts(cc->slot)) { |
837 | | /* The values are hard-coded and readonly. Read just once. */ |
838 | 0 | if (cc->distrust == NULL) { |
839 | 0 | CERTCertDistrust distrustModel; |
840 | 0 | SECItem model = { siUTCTime, NULL, 0 }; |
841 | 0 | distrustModel.serverDistrustAfter = model; |
842 | 0 | distrustModel.emailDistrustAfter = model; |
843 | 0 | SECStatus rServer = PK11_ReadAttribute( |
844 | 0 | cc->slot, cc->pkcs11ID, CKA_NSS_SERVER_DISTRUST_AFTER, |
845 | 0 | cc->arena, &distrustModel.serverDistrustAfter); |
846 | 0 | SECStatus rEmail = PK11_ReadAttribute( |
847 | 0 | cc->slot, cc->pkcs11ID, CKA_NSS_EMAIL_DISTRUST_AFTER, |
848 | 0 | cc->arena, &distrustModel.emailDistrustAfter); |
849 | | /* Only allocate the Distrust structure if a valid date is found. |
850 | | * The result length of a encoded valid timestamp is exactly 13 */ |
851 | 0 | const unsigned int kDistrustFieldSize = 13; |
852 | 0 | if ((rServer == SECSuccess && rEmail == SECSuccess) && |
853 | 0 | (distrustModel.serverDistrustAfter.len == kDistrustFieldSize || |
854 | 0 | distrustModel.emailDistrustAfter.len == kDistrustFieldSize)) { |
855 | 0 | CERTCertDistrust *tmpPtr = PORT_ArenaAlloc( |
856 | 0 | cc->arena, sizeof(CERTCertDistrust)); |
857 | 0 | PORT_Memcpy(tmpPtr, &distrustModel, |
858 | 0 | sizeof(CERTCertDistrust)); |
859 | 0 | cc->distrust = tmpPtr; |
860 | 0 | } |
861 | 0 | } |
862 | 0 | } |
863 | 0 | } |
864 | 0 | if (instance) { |
865 | 0 | nssCryptokiObject_Destroy(instance); |
866 | 0 | } |
867 | | /* database handle is now the trust domain */ |
868 | 0 | cc->dbhandle = c->object.trustDomain; |
869 | | /* subjectList ? */ |
870 | | /* istemp and isperm are supported in NSS 3.4 */ |
871 | 0 | CERT_LockCertTempPerm(cc); |
872 | 0 | cc->istemp = PR_FALSE; /* CERT_NewTemp will override this */ |
873 | 0 | cc->isperm = PR_TRUE; /* by default */ |
874 | | /* pointer back */ |
875 | 0 | cc->nssCertificate = c; |
876 | 0 | CERT_UnlockCertTempPerm(cc); |
877 | 0 | if (trust) { |
878 | | /* force the cert type to be recomputed to include trust info */ |
879 | 0 | PRUint32 nsCertType = cert_ComputeCertType(cc); |
880 | | |
881 | | /* Assert that it is safe to cast &cc->nsCertType to "PRInt32 *" */ |
882 | 0 | PORT_Assert(sizeof(cc->nsCertType) == sizeof(PRInt32)); |
883 | 0 | PR_ATOMIC_SET((PRInt32 *)&cc->nsCertType, nsCertType); |
884 | 0 | } |
885 | 0 | } |
886 | | |
887 | | static CERTCertificate * |
888 | | stan_GetCERTCertificate(NSSCertificate *c, PRBool forceUpdate) |
889 | 0 | { |
890 | 0 | nssDecodedCert *dc = NULL; |
891 | 0 | CERTCertificate *cc = NULL; |
892 | 0 | CERTCertTrust certTrust; |
893 | | |
894 | | /* make sure object does not go away until we finish */ |
895 | 0 | nssPKIObject_AddRef(&c->object); |
896 | 0 | nssPKIObject_Lock(&c->object); |
897 | |
|
898 | 0 | dc = c->decoding; |
899 | 0 | if (!dc) { |
900 | 0 | dc = nssDecodedPKIXCertificate_Create(NULL, &c->encoding); |
901 | 0 | if (!dc) { |
902 | 0 | goto loser; |
903 | 0 | } |
904 | 0 | cc = (CERTCertificate *)dc->data; |
905 | 0 | PORT_Assert(cc); /* software error */ |
906 | 0 | if (!cc) { |
907 | 0 | nssDecodedPKIXCertificate_Destroy(dc); |
908 | 0 | nss_SetError(NSS_ERROR_INTERNAL_ERROR); |
909 | 0 | goto loser; |
910 | 0 | } |
911 | 0 | PORT_Assert(!c->decoding); |
912 | 0 | if (!c->decoding) { |
913 | 0 | c->decoding = dc; |
914 | 0 | } else { |
915 | | /* this should never happen. Fail. */ |
916 | 0 | nssDecodedPKIXCertificate_Destroy(dc); |
917 | 0 | nss_SetError(NSS_ERROR_INTERNAL_ERROR); |
918 | 0 | goto loser; |
919 | 0 | } |
920 | 0 | } |
921 | 0 | cc = (CERTCertificate *)dc->data; |
922 | 0 | PORT_Assert(cc); |
923 | 0 | if (!cc) { |
924 | 0 | nss_SetError(NSS_ERROR_INTERNAL_ERROR); |
925 | 0 | goto loser; |
926 | 0 | } |
927 | 0 | CERT_LockCertTempPerm(cc); |
928 | 0 | NSSCertificate *nssCert = cc->nssCertificate; |
929 | 0 | CERT_UnlockCertTempPerm(cc); |
930 | 0 | if (!nssCert || forceUpdate) { |
931 | 0 | fill_CERTCertificateFields(c, cc, forceUpdate); |
932 | 0 | } else if (CERT_GetCertTrust(cc, &certTrust) != SECSuccess) { |
933 | 0 | CERTCertTrust *trust; |
934 | 0 | if (!c->object.cryptoContext) { |
935 | | /* If it's a perm cert, it might have been stored before the |
936 | | * trust, so look for the trust again. |
937 | | */ |
938 | 0 | trust = nssTrust_GetCERTCertTrustForCert(c, cc); |
939 | 0 | } else { |
940 | | /* If it's a temp cert, it might have been stored before the |
941 | | * builtin trust module is loaded, so look for the trust |
942 | | * again, but don't set the empty trust if it is not found. |
943 | | */ |
944 | 0 | NSSTrust *t = nssTrustDomain_FindTrustForCertificate(c->object.cryptoContext->td, c); |
945 | 0 | if (!t) { |
946 | 0 | goto loser; |
947 | 0 | } |
948 | 0 | trust = cert_trust_from_stan_trust(t, cc->arena); |
949 | 0 | nssTrust_Destroy(t); |
950 | 0 | if (!trust) { |
951 | 0 | goto loser; |
952 | 0 | } |
953 | 0 | } |
954 | | |
955 | 0 | CERT_LockCertTrust(cc); |
956 | 0 | cc->trust = trust; |
957 | 0 | CERT_UnlockCertTrust(cc); |
958 | 0 | } |
959 | | |
960 | 0 | loser: |
961 | 0 | nssPKIObject_Unlock(&c->object); |
962 | 0 | nssPKIObject_Destroy(&c->object); |
963 | 0 | return cc; |
964 | 0 | } |
965 | | |
966 | | NSS_IMPLEMENT CERTCertificate * |
967 | | STAN_ForceCERTCertificateUpdate(NSSCertificate *c) |
968 | 0 | { |
969 | 0 | if (c->decoding) { |
970 | 0 | return stan_GetCERTCertificate(c, PR_TRUE); |
971 | 0 | } |
972 | 0 | return NULL; |
973 | 0 | } |
974 | | |
975 | | NSS_IMPLEMENT CERTCertificate * |
976 | | STAN_GetCERTCertificate(NSSCertificate *c) |
977 | 0 | { |
978 | 0 | return stan_GetCERTCertificate(c, PR_FALSE); |
979 | 0 | } |
980 | | /* |
981 | | * many callers of STAN_GetCERTCertificate() intend that |
982 | | * the CERTCertificate returned inherits the reference to the |
983 | | * NSSCertificate. For these callers it's convenient to have |
984 | | * this function 'own' the reference and either return a valid |
985 | | * CERTCertificate structure which inherits the reference or |
986 | | * destroy the reference to NSSCertificate and returns NULL. |
987 | | */ |
988 | | NSS_IMPLEMENT CERTCertificate * |
989 | | STAN_GetCERTCertificateOrRelease(NSSCertificate *c) |
990 | 0 | { |
991 | 0 | CERTCertificate *nss3cert = stan_GetCERTCertificate(c, PR_FALSE); |
992 | 0 | if (!nss3cert) { |
993 | 0 | nssCertificate_Destroy(c); |
994 | 0 | } |
995 | 0 | return nss3cert; |
996 | 0 | } |
997 | | |
998 | | static nssTrustLevel |
999 | | get_stan_trust(unsigned int t, PRBool isClientAuth) |
1000 | 0 | { |
1001 | 0 | if (isClientAuth) { |
1002 | 0 | if (t & CERTDB_TRUSTED_CLIENT_CA) { |
1003 | 0 | return nssTrustLevel_TrustedDelegator; |
1004 | 0 | } |
1005 | 0 | } else { |
1006 | 0 | if (t & CERTDB_TRUSTED_CA || t & CERTDB_NS_TRUSTED_CA) { |
1007 | 0 | return nssTrustLevel_TrustedDelegator; |
1008 | 0 | } |
1009 | 0 | } |
1010 | 0 | if (t & CERTDB_TRUSTED) { |
1011 | 0 | return nssTrustLevel_Trusted; |
1012 | 0 | } |
1013 | 0 | if (t & CERTDB_TERMINAL_RECORD) { |
1014 | 0 | return nssTrustLevel_NotTrusted; |
1015 | 0 | } |
1016 | 0 | if (t & CERTDB_VALID_CA) { |
1017 | 0 | return nssTrustLevel_ValidDelegator; |
1018 | 0 | } |
1019 | 0 | return nssTrustLevel_MustVerify; |
1020 | 0 | } |
1021 | | |
1022 | | NSS_EXTERN NSSCertificate * |
1023 | | STAN_GetNSSCertificate(CERTCertificate *cc) |
1024 | 0 | { |
1025 | 0 | NSSCertificate *c; |
1026 | 0 | nssCryptokiInstance *instance; |
1027 | 0 | nssPKIObject *pkiob; |
1028 | 0 | NSSArena *arena; |
1029 | 0 | CERT_LockCertTempPerm(cc); |
1030 | 0 | c = cc->nssCertificate; |
1031 | 0 | CERT_UnlockCertTempPerm(cc); |
1032 | 0 | if (c) { |
1033 | 0 | return c; |
1034 | 0 | } |
1035 | | /* i don't think this should happen. but if it can, need to create |
1036 | | * NSSCertificate from CERTCertificate values here. */ |
1037 | | /* Yup, it can happen. */ |
1038 | 0 | arena = NSSArena_Create(); |
1039 | 0 | if (!arena) { |
1040 | 0 | return NULL; |
1041 | 0 | } |
1042 | 0 | c = nss_ZNEW(arena, NSSCertificate); |
1043 | 0 | if (!c) { |
1044 | 0 | nssArena_Destroy(arena); |
1045 | 0 | return NULL; |
1046 | 0 | } |
1047 | 0 | NSSITEM_FROM_SECITEM(&c->encoding, &cc->derCert); |
1048 | 0 | c->type = NSSCertificateType_PKIX; |
1049 | 0 | pkiob = nssPKIObject_Create(arena, NULL, cc->dbhandle, NULL, nssPKIMonitor); |
1050 | 0 | if (!pkiob) { |
1051 | 0 | nssArena_Destroy(arena); |
1052 | 0 | return NULL; |
1053 | 0 | } |
1054 | 0 | c->object = *pkiob; |
1055 | 0 | nssItem_Create(arena, |
1056 | 0 | &c->issuer, cc->derIssuer.len, cc->derIssuer.data); |
1057 | 0 | nssItem_Create(arena, |
1058 | 0 | &c->subject, cc->derSubject.len, cc->derSubject.data); |
1059 | | /* CERTCertificate stores serial numbers decoded. I need the DER |
1060 | | * here. sigh. |
1061 | | */ |
1062 | 0 | SECItem derSerial; |
1063 | 0 | SECStatus secrv; |
1064 | 0 | secrv = CERT_SerialNumberFromDERCert(&cc->derCert, &derSerial); |
1065 | 0 | if (secrv == SECFailure) { |
1066 | 0 | nssArena_Destroy(arena); |
1067 | 0 | return NULL; |
1068 | 0 | } |
1069 | 0 | nssItem_Create(arena, &c->serial, derSerial.len, derSerial.data); |
1070 | 0 | PORT_Free(derSerial.data); |
1071 | |
|
1072 | 0 | if (cc->emailAddr && cc->emailAddr[0]) { |
1073 | 0 | c->email = nssUTF8_Create(arena, |
1074 | 0 | nssStringType_PrintableString, |
1075 | 0 | (NSSUTF8 *)cc->emailAddr, |
1076 | 0 | PORT_Strlen(cc->emailAddr)); |
1077 | 0 | } |
1078 | 0 | if (cc->slot) { |
1079 | 0 | instance = nss_ZNEW(arena, nssCryptokiInstance); |
1080 | 0 | if (!instance) { |
1081 | 0 | nssArena_Destroy(arena); |
1082 | 0 | return NULL; |
1083 | 0 | } |
1084 | 0 | instance->token = PK11Slot_GetNSSToken(cc->slot); |
1085 | 0 | if (!instance->token) { |
1086 | 0 | nssArena_Destroy(arena); |
1087 | 0 | return NULL; |
1088 | 0 | } |
1089 | 0 | instance->handle = cc->pkcs11ID; |
1090 | 0 | instance->isTokenObject = PR_TRUE; |
1091 | 0 | if (cc->nickname) { |
1092 | 0 | instance->label = nssUTF8_Create(arena, |
1093 | 0 | nssStringType_UTF8String, |
1094 | 0 | (NSSUTF8 *)cc->nickname, |
1095 | 0 | PORT_Strlen(cc->nickname)); |
1096 | 0 | } |
1097 | 0 | nssPKIObject_AddInstance(&c->object, instance); |
1098 | 0 | } |
1099 | 0 | c->decoding = create_decoded_pkix_cert_from_nss3cert(NULL, cc); |
1100 | 0 | CERT_LockCertTempPerm(cc); |
1101 | 0 | cc->nssCertificate = c; |
1102 | 0 | CERT_UnlockCertTempPerm(cc); |
1103 | 0 | return c; |
1104 | 0 | } |
1105 | | |
1106 | | static NSSToken * |
1107 | | stan_GetTrustToken( |
1108 | | NSSCertificate *c) |
1109 | 0 | { |
1110 | 0 | NSSToken *ttok = NULL; |
1111 | 0 | NSSToken *rtok = NULL; |
1112 | 0 | NSSToken *tok = NULL; |
1113 | 0 | nssCryptokiObject **ip; |
1114 | 0 | nssCryptokiObject **instances = nssPKIObject_GetInstances(&c->object); |
1115 | 0 | if (!instances) { |
1116 | 0 | return PR_FALSE; |
1117 | 0 | } |
1118 | 0 | for (ip = instances; *ip; ip++) { |
1119 | 0 | nssCryptokiObject *instance = *ip; |
1120 | 0 | nssCryptokiObject *to = |
1121 | 0 | nssToken_FindTrustForCertificate(instance->token, NULL, |
1122 | 0 | &c->encoding, &c->issuer, &c->serial, |
1123 | 0 | nssTokenSearchType_TokenOnly); |
1124 | 0 | NSSToken *ctok = instance->token; |
1125 | 0 | PRBool ro = PK11_IsReadOnly(ctok->pk11slot); |
1126 | |
|
1127 | 0 | if (to) { |
1128 | 0 | nssCryptokiObject_Destroy(to); |
1129 | 0 | ttok = ctok; |
1130 | 0 | if (!ro) { |
1131 | 0 | break; |
1132 | 0 | } |
1133 | 0 | } else { |
1134 | 0 | if (!rtok && ro) { |
1135 | 0 | rtok = ctok; |
1136 | 0 | } |
1137 | 0 | if (!tok && !ro) { |
1138 | 0 | tok = ctok; |
1139 | 0 | } |
1140 | 0 | } |
1141 | 0 | } |
1142 | 0 | nssCryptokiObjectArray_Destroy(instances); |
1143 | 0 | return ttok ? ttok : (tok ? tok : rtok); |
1144 | 0 | } |
1145 | | |
1146 | | NSS_EXTERN PRStatus |
1147 | | STAN_ChangeCertTrust(CERTCertificate *cc, CERTCertTrust *trust) |
1148 | 0 | { |
1149 | 0 | PRStatus nssrv; |
1150 | 0 | NSSCertificate *c = STAN_GetNSSCertificate(cc); |
1151 | 0 | NSSToken *tok; |
1152 | 0 | NSSTrustDomain *td; |
1153 | 0 | NSSTrust *nssTrust; |
1154 | 0 | NSSArena *arena; |
1155 | 0 | CERTCertTrust *oldTrust; |
1156 | 0 | CERTCertTrust *newTrust; |
1157 | 0 | nssListIterator *tokens; |
1158 | 0 | PRBool moving_object; |
1159 | 0 | nssCryptokiObject *newInstance; |
1160 | 0 | nssPKIObject *pkiob; |
1161 | |
|
1162 | 0 | if (c == NULL) { |
1163 | 0 | return PR_FAILURE; |
1164 | 0 | } |
1165 | 0 | oldTrust = nssTrust_GetCERTCertTrustForCert(c, cc); |
1166 | 0 | if (oldTrust) { |
1167 | 0 | if (memcmp(oldTrust, trust, sizeof(CERTCertTrust)) == 0) { |
1168 | | /* ... and the new trust is no different, done) */ |
1169 | 0 | return PR_SUCCESS; |
1170 | 0 | } else { |
1171 | | /* take over memory already allocated in cc's arena */ |
1172 | 0 | newTrust = oldTrust; |
1173 | 0 | } |
1174 | 0 | } else { |
1175 | 0 | newTrust = PORT_ArenaAlloc(cc->arena, sizeof(CERTCertTrust)); |
1176 | 0 | } |
1177 | 0 | memcpy(newTrust, trust, sizeof(CERTCertTrust)); |
1178 | 0 | CERT_LockCertTrust(cc); |
1179 | 0 | cc->trust = newTrust; |
1180 | 0 | CERT_UnlockCertTrust(cc); |
1181 | | /* Set the NSSCerticate's trust */ |
1182 | 0 | arena = nssArena_Create(); |
1183 | 0 | if (!arena) |
1184 | 0 | return PR_FAILURE; |
1185 | 0 | nssTrust = nss_ZNEW(arena, NSSTrust); |
1186 | 0 | if (!nssTrust) { |
1187 | 0 | nssArena_Destroy(arena); |
1188 | 0 | return PR_FAILURE; |
1189 | 0 | } |
1190 | 0 | pkiob = nssPKIObject_Create(arena, NULL, cc->dbhandle, NULL, nssPKILock); |
1191 | 0 | if (!pkiob) { |
1192 | 0 | nssArena_Destroy(arena); |
1193 | 0 | return PR_FAILURE; |
1194 | 0 | } |
1195 | 0 | nssTrust->object = *pkiob; |
1196 | 0 | nssTrust->certificate = c; |
1197 | 0 | nssTrust->serverAuth = get_stan_trust(trust->sslFlags, PR_FALSE); |
1198 | 0 | nssTrust->clientAuth = get_stan_trust(trust->sslFlags, PR_TRUE); |
1199 | 0 | nssTrust->emailProtection = get_stan_trust(trust->emailFlags, PR_FALSE); |
1200 | 0 | nssTrust->codeSigning = get_stan_trust(trust->objectSigningFlags, PR_FALSE); |
1201 | 0 | nssTrust->stepUpApproved = |
1202 | 0 | (PRBool)(trust->sslFlags & CERTDB_GOVT_APPROVED_CA); |
1203 | 0 | if (c->object.cryptoContext != NULL) { |
1204 | | /* The cert is in a context, set the trust there */ |
1205 | 0 | NSSCryptoContext *cctx = c->object.cryptoContext; |
1206 | 0 | nssrv = nssCryptoContext_ImportTrust(cctx, nssTrust); |
1207 | 0 | if (nssrv != PR_SUCCESS) { |
1208 | 0 | goto done; |
1209 | 0 | } |
1210 | 0 | if (c->object.numInstances == 0) { |
1211 | | /* The context is the only instance, finished */ |
1212 | 0 | goto done; |
1213 | 0 | } |
1214 | 0 | } |
1215 | 0 | td = STAN_GetDefaultTrustDomain(); |
1216 | 0 | tok = stan_GetTrustToken(c); |
1217 | 0 | moving_object = PR_FALSE; |
1218 | 0 | if (tok && PK11_IsReadOnly(tok->pk11slot)) { |
1219 | 0 | NSSRWLock_LockRead(td->tokensLock); |
1220 | 0 | tokens = nssList_CreateIterator(td->tokenList); |
1221 | 0 | if (!tokens) { |
1222 | 0 | nssrv = PR_FAILURE; |
1223 | 0 | NSSRWLock_UnlockRead(td->tokensLock); |
1224 | 0 | goto done; |
1225 | 0 | } |
1226 | 0 | for (tok = (NSSToken *)nssListIterator_Start(tokens); |
1227 | 0 | tok != (NSSToken *)NULL; |
1228 | 0 | tok = (NSSToken *)nssListIterator_Next(tokens)) { |
1229 | 0 | if (!PK11_IsReadOnly(tok->pk11slot)) |
1230 | 0 | break; |
1231 | 0 | } |
1232 | 0 | nssListIterator_Finish(tokens); |
1233 | 0 | nssListIterator_Destroy(tokens); |
1234 | 0 | NSSRWLock_UnlockRead(td->tokensLock); |
1235 | 0 | moving_object = PR_TRUE; |
1236 | 0 | } |
1237 | 0 | if (tok) { |
1238 | 0 | if (moving_object) { |
1239 | | /* this is kind of hacky. the softoken needs the cert |
1240 | | * object in order to store trust. forcing it to be perm |
1241 | | */ |
1242 | 0 | NSSUTF8 *nickname = nssCertificate_GetNickname(c, NULL); |
1243 | 0 | NSSASCII7 *email = NULL; |
1244 | |
|
1245 | 0 | if (PK11_IsInternal(tok->pk11slot)) { |
1246 | 0 | email = c->email; |
1247 | 0 | } |
1248 | 0 | newInstance = nssToken_ImportCertificate(tok, NULL, |
1249 | 0 | NSSCertificateType_PKIX, |
1250 | 0 | &c->id, |
1251 | 0 | nickname, |
1252 | 0 | &c->encoding, |
1253 | 0 | &c->issuer, |
1254 | 0 | &c->subject, |
1255 | 0 | &c->serial, |
1256 | 0 | email, |
1257 | 0 | PR_TRUE); |
1258 | 0 | nss_ZFreeIf(nickname); |
1259 | 0 | nickname = NULL; |
1260 | 0 | if (!newInstance) { |
1261 | 0 | nssrv = PR_FAILURE; |
1262 | 0 | goto done; |
1263 | 0 | } |
1264 | 0 | nssPKIObject_AddInstance(&c->object, newInstance); |
1265 | 0 | } |
1266 | 0 | newInstance = nssToken_ImportTrust(tok, NULL, &c->encoding, |
1267 | 0 | &c->issuer, &c->serial, |
1268 | 0 | nssTrust->serverAuth, |
1269 | 0 | nssTrust->clientAuth, |
1270 | 0 | nssTrust->codeSigning, |
1271 | 0 | nssTrust->emailProtection, |
1272 | 0 | nssTrust->stepUpApproved, PR_TRUE); |
1273 | | /* If the selected token can't handle trust, dump the trust on |
1274 | | * the internal token */ |
1275 | 0 | if (!newInstance && !PK11_IsInternalKeySlot(tok->pk11slot)) { |
1276 | 0 | PK11SlotInfo *slot = PK11_GetInternalKeySlot(); |
1277 | 0 | NSSUTF8 *nickname = nssCertificate_GetNickname(c, NULL); |
1278 | 0 | NSSASCII7 *email = c->email; |
1279 | 0 | tok = PK11Slot_GetNSSToken(slot); |
1280 | 0 | PK11_FreeSlot(slot); |
1281 | 0 | if (!tok) { |
1282 | 0 | nssrv = PR_FAILURE; |
1283 | 0 | goto done; |
1284 | 0 | } |
1285 | | |
1286 | 0 | newInstance = nssToken_ImportCertificate(tok, NULL, |
1287 | 0 | NSSCertificateType_PKIX, |
1288 | 0 | &c->id, |
1289 | 0 | nickname, |
1290 | 0 | &c->encoding, |
1291 | 0 | &c->issuer, |
1292 | 0 | &c->subject, |
1293 | 0 | &c->serial, |
1294 | 0 | email, |
1295 | 0 | PR_TRUE); |
1296 | 0 | nss_ZFreeIf(nickname); |
1297 | 0 | nickname = NULL; |
1298 | 0 | if (!newInstance) { |
1299 | 0 | (void)nssToken_Destroy(tok); |
1300 | 0 | nssrv = PR_FAILURE; |
1301 | 0 | goto done; |
1302 | 0 | } |
1303 | 0 | nssPKIObject_AddInstance(&c->object, newInstance); |
1304 | 0 | newInstance = nssToken_ImportTrust(tok, NULL, &c->encoding, |
1305 | 0 | &c->issuer, &c->serial, |
1306 | 0 | nssTrust->serverAuth, |
1307 | 0 | nssTrust->clientAuth, |
1308 | 0 | nssTrust->codeSigning, |
1309 | 0 | nssTrust->emailProtection, |
1310 | 0 | nssTrust->stepUpApproved, PR_TRUE); |
1311 | 0 | (void)nssToken_Destroy(tok); |
1312 | 0 | } |
1313 | 0 | if (newInstance) { |
1314 | 0 | nssCryptokiObject_Destroy(newInstance); |
1315 | 0 | nssrv = PR_SUCCESS; |
1316 | 0 | } else { |
1317 | 0 | nssrv = PR_FAILURE; |
1318 | 0 | } |
1319 | 0 | } else { |
1320 | 0 | nssrv = PR_FAILURE; |
1321 | 0 | } |
1322 | 0 | done: |
1323 | 0 | (void)nssTrust_Destroy(nssTrust); |
1324 | 0 | return nssrv; |
1325 | 0 | } |
1326 | | |
1327 | | /* |
1328 | | ** Delete trust objects matching the given slot. |
1329 | | ** Returns error if a device fails to delete. |
1330 | | ** |
1331 | | ** This function has the side effect of moving the |
1332 | | ** surviving entries to the front of the object list |
1333 | | ** and nullifying the rest. |
1334 | | */ |
1335 | | static PRStatus |
1336 | | DeleteCertTrustMatchingSlot(PK11SlotInfo *pk11slot, nssPKIObject *tObject) |
1337 | 0 | { |
1338 | 0 | int numNotDestroyed = 0; /* the ones skipped plus the failures */ |
1339 | 0 | int failureCount = 0; /* actual deletion failures by devices */ |
1340 | 0 | unsigned int index; |
1341 | |
|
1342 | 0 | nssPKIObject_AddRef(tObject); |
1343 | 0 | nssPKIObject_Lock(tObject); |
1344 | | /* Keep going even if a module fails to delete. */ |
1345 | 0 | for (index = 0; index < tObject->numInstances; index++) { |
1346 | 0 | nssCryptokiObject *instance = tObject->instances[index]; |
1347 | 0 | if (!instance) { |
1348 | 0 | continue; |
1349 | 0 | } |
1350 | | |
1351 | | /* ReadOnly and not matched treated the same */ |
1352 | 0 | if (PK11_IsReadOnly(instance->token->pk11slot) || |
1353 | 0 | pk11slot != instance->token->pk11slot) { |
1354 | 0 | tObject->instances[numNotDestroyed++] = instance; |
1355 | 0 | continue; |
1356 | 0 | } |
1357 | | |
1358 | | /* Here we have found a matching one */ |
1359 | 0 | tObject->instances[index] = NULL; |
1360 | 0 | if (nssToken_DeleteStoredObject(instance) == PR_SUCCESS) { |
1361 | 0 | nssCryptokiObject_Destroy(instance); |
1362 | 0 | } else { |
1363 | 0 | tObject->instances[numNotDestroyed++] = instance; |
1364 | 0 | failureCount++; |
1365 | 0 | } |
1366 | 0 | } |
1367 | 0 | if (numNotDestroyed == 0) { |
1368 | 0 | nss_ZFreeIf(tObject->instances); |
1369 | 0 | tObject->numInstances = 0; |
1370 | 0 | } else { |
1371 | 0 | tObject->numInstances = numNotDestroyed; |
1372 | 0 | } |
1373 | |
|
1374 | 0 | nssPKIObject_Unlock(tObject); |
1375 | 0 | nssPKIObject_Destroy(tObject); |
1376 | |
|
1377 | 0 | return failureCount == 0 ? PR_SUCCESS : PR_FAILURE; |
1378 | 0 | } |
1379 | | |
1380 | | /* |
1381 | | ** Delete trust objects matching the slot of the given certificate. |
1382 | | ** Returns an error if any device fails to delete. |
1383 | | */ |
1384 | | NSS_EXTERN PRStatus |
1385 | | STAN_DeleteCertTrustMatchingSlot(NSSCertificate *c) |
1386 | 0 | { |
1387 | 0 | PRStatus nssrv = PR_SUCCESS; |
1388 | |
|
1389 | 0 | unsigned int i; |
1390 | 0 | nssPKIObject *tobject = NULL; |
1391 | 0 | nssPKIObject *cobject = &c->object; |
1392 | |
|
1393 | 0 | NSSTrustDomain *td = STAN_GetDefaultTrustDomain(); |
1394 | 0 | NSSTrust *nssTrust = nssTrustDomain_FindTrustForCertificate(td, c); |
1395 | 0 | if (!nssTrust) { |
1396 | 0 | return PR_FAILURE; |
1397 | 0 | } |
1398 | | |
1399 | 0 | tobject = &nssTrust->object; |
1400 | | |
1401 | | /* Iterate through the cert and trust object instances looking for |
1402 | | * those with matching pk11 slots to delete. Even if some device |
1403 | | * can't delete we keep going. Keeping a status variable for the |
1404 | | * loop so that once it's failed the other gets set. |
1405 | | */ |
1406 | 0 | NSSRWLock_LockRead(td->tokensLock); |
1407 | 0 | nssPKIObject_AddRef(cobject); |
1408 | 0 | nssPKIObject_Lock(cobject); |
1409 | 0 | for (i = 0; i < cobject->numInstances; i++) { |
1410 | 0 | nssCryptokiObject *cInstance = cobject->instances[i]; |
1411 | 0 | if (cInstance && !PK11_IsReadOnly(cInstance->token->pk11slot)) { |
1412 | 0 | PRStatus status; |
1413 | 0 | if (!tobject->numInstances || !tobject->instances) |
1414 | 0 | continue; |
1415 | 0 | status = DeleteCertTrustMatchingSlot(cInstance->token->pk11slot, tobject); |
1416 | 0 | if (status == PR_FAILURE) { |
1417 | | /* set the outer one but keep going */ |
1418 | 0 | nssrv = PR_FAILURE; |
1419 | 0 | } |
1420 | 0 | } |
1421 | 0 | } |
1422 | 0 | nssTrust_Destroy(nssTrust); |
1423 | 0 | nssPKIObject_Unlock(cobject); |
1424 | 0 | nssPKIObject_Destroy(cobject); |
1425 | 0 | NSSRWLock_UnlockRead(td->tokensLock); |
1426 | 0 | return nssrv; |
1427 | 0 | } |
1428 | | |
1429 | | /* CERT_TraversePermCertsForSubject */ |
1430 | | NSS_IMPLEMENT PRStatus |
1431 | | nssTrustDomain_TraverseCertificatesBySubject( |
1432 | | NSSTrustDomain *td, |
1433 | | NSSDER *subject, |
1434 | | PRStatus (*callback)(NSSCertificate *c, void *arg), |
1435 | | void *arg) |
1436 | 0 | { |
1437 | 0 | PRStatus nssrv = PR_SUCCESS; |
1438 | 0 | NSSArena *tmpArena; |
1439 | 0 | NSSCertificate **subjectCerts; |
1440 | 0 | NSSCertificate *c; |
1441 | 0 | PRIntn i; |
1442 | 0 | tmpArena = NSSArena_Create(); |
1443 | 0 | if (!tmpArena) { |
1444 | 0 | return PR_FAILURE; |
1445 | 0 | } |
1446 | 0 | subjectCerts = NSSTrustDomain_FindCertificatesBySubject(td, subject, NULL, |
1447 | 0 | 0, tmpArena); |
1448 | 0 | if (subjectCerts) { |
1449 | 0 | for (i = 0, c = subjectCerts[i]; c; i++) { |
1450 | 0 | nssrv = callback(c, arg); |
1451 | 0 | if (nssrv != PR_SUCCESS) |
1452 | 0 | break; |
1453 | 0 | } |
1454 | 0 | } |
1455 | 0 | nssArena_Destroy(tmpArena); |
1456 | 0 | return nssrv; |
1457 | 0 | } |
1458 | | |
1459 | | /* CERT_TraversePermCertsForNickname */ |
1460 | | NSS_IMPLEMENT PRStatus |
1461 | | nssTrustDomain_TraverseCertificatesByNickname( |
1462 | | NSSTrustDomain *td, |
1463 | | NSSUTF8 *nickname, |
1464 | | PRStatus (*callback)(NSSCertificate *c, void *arg), |
1465 | | void *arg) |
1466 | 0 | { |
1467 | 0 | PRStatus nssrv = PR_SUCCESS; |
1468 | 0 | NSSArena *tmpArena; |
1469 | 0 | NSSCertificate **nickCerts; |
1470 | 0 | NSSCertificate *c; |
1471 | 0 | PRIntn i; |
1472 | 0 | tmpArena = NSSArena_Create(); |
1473 | 0 | if (!tmpArena) { |
1474 | 0 | return PR_FAILURE; |
1475 | 0 | } |
1476 | 0 | nickCerts = NSSTrustDomain_FindCertificatesByNickname(td, nickname, NULL, |
1477 | 0 | 0, tmpArena); |
1478 | 0 | if (nickCerts) { |
1479 | 0 | for (i = 0, c = nickCerts[i]; c; i++) { |
1480 | 0 | nssrv = callback(c, arg); |
1481 | 0 | if (nssrv != PR_SUCCESS) |
1482 | 0 | break; |
1483 | 0 | } |
1484 | 0 | } |
1485 | 0 | nssArena_Destroy(tmpArena); |
1486 | 0 | return nssrv; |
1487 | 0 | } |
1488 | | |
1489 | | static void |
1490 | | cert_dump_iter(const void *k, void *v, void *a) |
1491 | 0 | { |
1492 | 0 | NSSCertificate *c = (NSSCertificate *)k; |
1493 | 0 | CERTCertificate *cert = STAN_GetCERTCertificate(c); |
1494 | 0 | printf("[%2d] \"%s\"\n", c->object.refCount, cert->subjectName); |
1495 | 0 | } |
1496 | | |
1497 | | void |
1498 | | nss_DumpCertificateCacheInfo() |
1499 | 0 | { |
1500 | 0 | NSSTrustDomain *td; |
1501 | 0 | NSSCryptoContext *cc; |
1502 | 0 | td = STAN_GetDefaultTrustDomain(); |
1503 | 0 | cc = STAN_GetDefaultCryptoContext(); |
1504 | 0 | printf("\n\nCertificates in the cache:\n"); |
1505 | 0 | nssTrustDomain_DumpCacheInfo(td, cert_dump_iter, NULL); |
1506 | 0 | printf("\n\nCertificates in the temporary store:\n"); |
1507 | 0 | if (cc->certStore) { |
1508 | 0 | nssCertificateStore_DumpStoreInfo(cc->certStore, cert_dump_iter, NULL); |
1509 | 0 | } |
1510 | 0 | } |