|
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 #ifndef DEV_H |
|
6 #include "dev.h" |
|
7 #endif /* DEV_H */ |
|
8 |
|
9 #ifndef PKIM_H |
|
10 #include "pkim.h" |
|
11 #endif /* PKIM_H */ |
|
12 |
|
13 #include "pki3hack.h" |
|
14 |
|
15 extern const NSSError NSS_ERROR_NOT_FOUND; |
|
16 |
|
17 NSS_IMPLEMENT void |
|
18 nssPKIObject_Lock(nssPKIObject * object) |
|
19 { |
|
20 switch (object->lockType) { |
|
21 case nssPKIMonitor: |
|
22 PZ_EnterMonitor(object->sync.mlock); |
|
23 break; |
|
24 case nssPKILock: |
|
25 PZ_Lock(object->sync.lock); |
|
26 break; |
|
27 default: |
|
28 PORT_Assert(0); |
|
29 } |
|
30 } |
|
31 |
|
32 NSS_IMPLEMENT void |
|
33 nssPKIObject_Unlock(nssPKIObject * object) |
|
34 { |
|
35 switch (object->lockType) { |
|
36 case nssPKIMonitor: |
|
37 PZ_ExitMonitor(object->sync.mlock); |
|
38 break; |
|
39 case nssPKILock: |
|
40 PZ_Unlock(object->sync.lock); |
|
41 break; |
|
42 default: |
|
43 PORT_Assert(0); |
|
44 } |
|
45 } |
|
46 |
|
47 NSS_IMPLEMENT PRStatus |
|
48 nssPKIObject_NewLock(nssPKIObject * object, nssPKILockType lockType) |
|
49 { |
|
50 object->lockType = lockType; |
|
51 switch (lockType) { |
|
52 case nssPKIMonitor: |
|
53 object->sync.mlock = PZ_NewMonitor(nssILockSSL); |
|
54 return (object->sync.mlock ? PR_SUCCESS : PR_FAILURE); |
|
55 case nssPKILock: |
|
56 object->sync.lock = PZ_NewLock(nssILockSSL); |
|
57 return (object->sync.lock ? PR_SUCCESS : PR_FAILURE); |
|
58 default: |
|
59 PORT_Assert(0); |
|
60 return PR_FAILURE; |
|
61 } |
|
62 } |
|
63 |
|
64 NSS_IMPLEMENT void |
|
65 nssPKIObject_DestroyLock(nssPKIObject * object) |
|
66 { |
|
67 switch (object->lockType) { |
|
68 case nssPKIMonitor: |
|
69 PZ_DestroyMonitor(object->sync.mlock); |
|
70 object->sync.mlock = NULL; |
|
71 break; |
|
72 case nssPKILock: |
|
73 PZ_DestroyLock(object->sync.lock); |
|
74 object->sync.lock = NULL; |
|
75 break; |
|
76 default: |
|
77 PORT_Assert(0); |
|
78 } |
|
79 } |
|
80 |
|
81 |
|
82 |
|
83 NSS_IMPLEMENT nssPKIObject * |
|
84 nssPKIObject_Create ( |
|
85 NSSArena *arenaOpt, |
|
86 nssCryptokiObject *instanceOpt, |
|
87 NSSTrustDomain *td, |
|
88 NSSCryptoContext *cc, |
|
89 nssPKILockType lockType |
|
90 ) |
|
91 { |
|
92 NSSArena *arena; |
|
93 nssArenaMark *mark = NULL; |
|
94 nssPKIObject *object; |
|
95 if (arenaOpt) { |
|
96 arena = arenaOpt; |
|
97 mark = nssArena_Mark(arena); |
|
98 } else { |
|
99 arena = nssArena_Create(); |
|
100 if (!arena) { |
|
101 return (nssPKIObject *)NULL; |
|
102 } |
|
103 } |
|
104 object = nss_ZNEW(arena, nssPKIObject); |
|
105 if (!object) { |
|
106 goto loser; |
|
107 } |
|
108 object->arena = arena; |
|
109 object->trustDomain = td; /* XXX */ |
|
110 object->cryptoContext = cc; |
|
111 if (PR_SUCCESS != nssPKIObject_NewLock(object, lockType)) { |
|
112 goto loser; |
|
113 } |
|
114 if (instanceOpt) { |
|
115 if (nssPKIObject_AddInstance(object, instanceOpt) != PR_SUCCESS) { |
|
116 goto loser; |
|
117 } |
|
118 } |
|
119 PR_ATOMIC_INCREMENT(&object->refCount); |
|
120 if (mark) { |
|
121 nssArena_Unmark(arena, mark); |
|
122 } |
|
123 return object; |
|
124 loser: |
|
125 if (mark) { |
|
126 nssArena_Release(arena, mark); |
|
127 } else { |
|
128 nssArena_Destroy(arena); |
|
129 } |
|
130 return (nssPKIObject *)NULL; |
|
131 } |
|
132 |
|
133 NSS_IMPLEMENT PRBool |
|
134 nssPKIObject_Destroy ( |
|
135 nssPKIObject *object |
|
136 ) |
|
137 { |
|
138 PRUint32 i; |
|
139 PR_ASSERT(object->refCount > 0); |
|
140 if (PR_ATOMIC_DECREMENT(&object->refCount) == 0) { |
|
141 for (i=0; i<object->numInstances; i++) { |
|
142 nssCryptokiObject_Destroy(object->instances[i]); |
|
143 } |
|
144 nssPKIObject_DestroyLock(object); |
|
145 nssArena_Destroy(object->arena); |
|
146 return PR_TRUE; |
|
147 } |
|
148 return PR_FALSE; |
|
149 } |
|
150 |
|
151 NSS_IMPLEMENT nssPKIObject * |
|
152 nssPKIObject_AddRef ( |
|
153 nssPKIObject *object |
|
154 ) |
|
155 { |
|
156 PR_ATOMIC_INCREMENT(&object->refCount); |
|
157 return object; |
|
158 } |
|
159 |
|
160 NSS_IMPLEMENT PRStatus |
|
161 nssPKIObject_AddInstance ( |
|
162 nssPKIObject *object, |
|
163 nssCryptokiObject *instance |
|
164 ) |
|
165 { |
|
166 nssCryptokiObject **newInstances = NULL; |
|
167 |
|
168 nssPKIObject_Lock(object); |
|
169 if (object->numInstances == 0) { |
|
170 newInstances = nss_ZNEWARRAY(object->arena, |
|
171 nssCryptokiObject *, |
|
172 object->numInstances + 1); |
|
173 } else { |
|
174 PRBool found = PR_FALSE; |
|
175 PRUint32 i; |
|
176 for (i=0; i<object->numInstances; i++) { |
|
177 if (nssCryptokiObject_Equal(object->instances[i], instance)) { |
|
178 found = PR_TRUE; |
|
179 break; |
|
180 } |
|
181 } |
|
182 if (found) { |
|
183 /* The new instance is identical to one in the array, except |
|
184 * perhaps that the label may be different. So replace |
|
185 * the label in the array instance with the label from the |
|
186 * new instance, and discard the new instance. |
|
187 */ |
|
188 nss_ZFreeIf(object->instances[i]->label); |
|
189 object->instances[i]->label = instance->label; |
|
190 nssPKIObject_Unlock(object); |
|
191 instance->label = NULL; |
|
192 nssCryptokiObject_Destroy(instance); |
|
193 return PR_SUCCESS; |
|
194 } |
|
195 newInstances = nss_ZREALLOCARRAY(object->instances, |
|
196 nssCryptokiObject *, |
|
197 object->numInstances + 1); |
|
198 } |
|
199 if (newInstances) { |
|
200 object->instances = newInstances; |
|
201 newInstances[object->numInstances++] = instance; |
|
202 } |
|
203 nssPKIObject_Unlock(object); |
|
204 return (newInstances ? PR_SUCCESS : PR_FAILURE); |
|
205 } |
|
206 |
|
207 NSS_IMPLEMENT PRBool |
|
208 nssPKIObject_HasInstance ( |
|
209 nssPKIObject *object, |
|
210 nssCryptokiObject *instance |
|
211 ) |
|
212 { |
|
213 PRUint32 i; |
|
214 PRBool hasIt = PR_FALSE;; |
|
215 nssPKIObject_Lock(object); |
|
216 for (i=0; i<object->numInstances; i++) { |
|
217 if (nssCryptokiObject_Equal(object->instances[i], instance)) { |
|
218 hasIt = PR_TRUE; |
|
219 break; |
|
220 } |
|
221 } |
|
222 nssPKIObject_Unlock(object); |
|
223 return hasIt; |
|
224 } |
|
225 |
|
226 NSS_IMPLEMENT PRStatus |
|
227 nssPKIObject_RemoveInstanceForToken ( |
|
228 nssPKIObject *object, |
|
229 NSSToken *token |
|
230 ) |
|
231 { |
|
232 PRUint32 i; |
|
233 nssCryptokiObject *instanceToRemove = NULL; |
|
234 nssPKIObject_Lock(object); |
|
235 if (object->numInstances == 0) { |
|
236 nssPKIObject_Unlock(object); |
|
237 return PR_SUCCESS; |
|
238 } |
|
239 for (i=0; i<object->numInstances; i++) { |
|
240 if (object->instances[i]->token == token) { |
|
241 instanceToRemove = object->instances[i]; |
|
242 object->instances[i] = object->instances[object->numInstances-1]; |
|
243 object->instances[object->numInstances-1] = NULL; |
|
244 break; |
|
245 } |
|
246 } |
|
247 if (--object->numInstances > 0) { |
|
248 nssCryptokiObject **instances = nss_ZREALLOCARRAY(object->instances, |
|
249 nssCryptokiObject *, |
|
250 object->numInstances); |
|
251 if (instances) { |
|
252 object->instances = instances; |
|
253 } |
|
254 } else { |
|
255 nss_ZFreeIf(object->instances); |
|
256 } |
|
257 nssCryptokiObject_Destroy(instanceToRemove); |
|
258 nssPKIObject_Unlock(object); |
|
259 return PR_SUCCESS; |
|
260 } |
|
261 |
|
262 /* this needs more thought on what will happen when there are multiple |
|
263 * instances |
|
264 */ |
|
265 NSS_IMPLEMENT PRStatus |
|
266 nssPKIObject_DeleteStoredObject ( |
|
267 nssPKIObject *object, |
|
268 NSSCallback *uhh, |
|
269 PRBool isFriendly |
|
270 ) |
|
271 { |
|
272 PRUint32 i, numNotDestroyed; |
|
273 PRStatus status = PR_SUCCESS; |
|
274 numNotDestroyed = 0; |
|
275 nssPKIObject_Lock(object); |
|
276 for (i=0; i<object->numInstances; i++) { |
|
277 nssCryptokiObject *instance = object->instances[i]; |
|
278 status = nssToken_DeleteStoredObject(instance); |
|
279 object->instances[i] = NULL; |
|
280 if (status == PR_SUCCESS) { |
|
281 nssCryptokiObject_Destroy(instance); |
|
282 } else { |
|
283 object->instances[numNotDestroyed++] = instance; |
|
284 } |
|
285 } |
|
286 if (numNotDestroyed == 0) { |
|
287 nss_ZFreeIf(object->instances); |
|
288 object->numInstances = 0; |
|
289 } else { |
|
290 object->numInstances = numNotDestroyed; |
|
291 } |
|
292 nssPKIObject_Unlock(object); |
|
293 return status; |
|
294 } |
|
295 |
|
296 NSS_IMPLEMENT NSSToken ** |
|
297 nssPKIObject_GetTokens ( |
|
298 nssPKIObject *object, |
|
299 PRStatus *statusOpt |
|
300 ) |
|
301 { |
|
302 NSSToken **tokens = NULL; |
|
303 nssPKIObject_Lock(object); |
|
304 if (object->numInstances > 0) { |
|
305 tokens = nss_ZNEWARRAY(NULL, NSSToken *, object->numInstances + 1); |
|
306 if (tokens) { |
|
307 PRUint32 i; |
|
308 for (i=0; i<object->numInstances; i++) { |
|
309 tokens[i] = nssToken_AddRef(object->instances[i]->token); |
|
310 } |
|
311 } |
|
312 } |
|
313 nssPKIObject_Unlock(object); |
|
314 if (statusOpt) *statusOpt = PR_SUCCESS; /* until more logic here */ |
|
315 return tokens; |
|
316 } |
|
317 |
|
318 NSS_IMPLEMENT NSSUTF8 * |
|
319 nssPKIObject_GetNicknameForToken ( |
|
320 nssPKIObject *object, |
|
321 NSSToken *tokenOpt |
|
322 ) |
|
323 { |
|
324 PRUint32 i; |
|
325 NSSUTF8 *nickname = NULL; |
|
326 nssPKIObject_Lock(object); |
|
327 for (i=0; i<object->numInstances; i++) { |
|
328 if ((!tokenOpt && object->instances[i]->label) || |
|
329 (object->instances[i]->token == tokenOpt)) |
|
330 { |
|
331 /* Must copy, see bug 745548 */ |
|
332 nickname = nssUTF8_Duplicate(object->instances[i]->label, NULL); |
|
333 break; |
|
334 } |
|
335 } |
|
336 nssPKIObject_Unlock(object); |
|
337 return nickname; |
|
338 } |
|
339 |
|
340 NSS_IMPLEMENT nssCryptokiObject ** |
|
341 nssPKIObject_GetInstances ( |
|
342 nssPKIObject *object |
|
343 ) |
|
344 { |
|
345 nssCryptokiObject **instances = NULL; |
|
346 PRUint32 i; |
|
347 if (object->numInstances == 0) { |
|
348 return (nssCryptokiObject **)NULL; |
|
349 } |
|
350 nssPKIObject_Lock(object); |
|
351 instances = nss_ZNEWARRAY(NULL, nssCryptokiObject *, |
|
352 object->numInstances + 1); |
|
353 if (instances) { |
|
354 for (i=0; i<object->numInstances; i++) { |
|
355 instances[i] = nssCryptokiObject_Clone(object->instances[i]); |
|
356 } |
|
357 } |
|
358 nssPKIObject_Unlock(object); |
|
359 return instances; |
|
360 } |
|
361 |
|
362 NSS_IMPLEMENT void |
|
363 nssCertificateArray_Destroy ( |
|
364 NSSCertificate **certs |
|
365 ) |
|
366 { |
|
367 if (certs) { |
|
368 NSSCertificate **certp; |
|
369 for (certp = certs; *certp; certp++) { |
|
370 if ((*certp)->decoding) { |
|
371 CERTCertificate *cc = STAN_GetCERTCertificate(*certp); |
|
372 if (cc) { |
|
373 CERT_DestroyCertificate(cc); |
|
374 } |
|
375 continue; |
|
376 } |
|
377 nssCertificate_Destroy(*certp); |
|
378 } |
|
379 nss_ZFreeIf(certs); |
|
380 } |
|
381 } |
|
382 |
|
383 NSS_IMPLEMENT void |
|
384 NSSCertificateArray_Destroy ( |
|
385 NSSCertificate **certs |
|
386 ) |
|
387 { |
|
388 nssCertificateArray_Destroy(certs); |
|
389 } |
|
390 |
|
391 NSS_IMPLEMENT NSSCertificate ** |
|
392 nssCertificateArray_Join ( |
|
393 NSSCertificate **certs1, |
|
394 NSSCertificate **certs2 |
|
395 ) |
|
396 { |
|
397 if (certs1 && certs2) { |
|
398 NSSCertificate **certs, **cp; |
|
399 PRUint32 count = 0; |
|
400 PRUint32 count1 = 0; |
|
401 cp = certs1; |
|
402 while (*cp++) count1++; |
|
403 count = count1; |
|
404 cp = certs2; |
|
405 while (*cp++) count++; |
|
406 certs = nss_ZREALLOCARRAY(certs1, NSSCertificate *, count + 1); |
|
407 if (!certs) { |
|
408 nss_ZFreeIf(certs1); |
|
409 nss_ZFreeIf(certs2); |
|
410 return (NSSCertificate **)NULL; |
|
411 } |
|
412 for (cp = certs2; *cp; cp++, count1++) { |
|
413 certs[count1] = *cp; |
|
414 } |
|
415 nss_ZFreeIf(certs2); |
|
416 return certs; |
|
417 } else if (certs1) { |
|
418 return certs1; |
|
419 } else { |
|
420 return certs2; |
|
421 } |
|
422 } |
|
423 |
|
424 NSS_IMPLEMENT NSSCertificate * |
|
425 nssCertificateArray_FindBestCertificate ( |
|
426 NSSCertificate **certs, |
|
427 NSSTime *timeOpt, |
|
428 const NSSUsage *usage, |
|
429 NSSPolicies *policiesOpt |
|
430 ) |
|
431 { |
|
432 NSSCertificate *bestCert = NULL; |
|
433 nssDecodedCert *bestdc = NULL; |
|
434 NSSTime *time, sTime; |
|
435 PRBool bestCertMatches = PR_FALSE; |
|
436 PRBool thisCertMatches; |
|
437 PRBool bestCertIsValidAtTime = PR_FALSE; |
|
438 PRBool bestCertIsTrusted = PR_FALSE; |
|
439 |
|
440 if (timeOpt) { |
|
441 time = timeOpt; |
|
442 } else { |
|
443 NSSTime_Now(&sTime); |
|
444 time = &sTime; |
|
445 } |
|
446 if (!certs) { |
|
447 return (NSSCertificate *)NULL; |
|
448 } |
|
449 for (; *certs; certs++) { |
|
450 nssDecodedCert *dc; |
|
451 NSSCertificate *c = *certs; |
|
452 dc = nssCertificate_GetDecoding(c); |
|
453 if (!dc) continue; |
|
454 thisCertMatches = dc->matchUsage(dc, usage); |
|
455 if (!bestCert) { |
|
456 /* always take the first cert, but remember whether or not |
|
457 * the usage matched |
|
458 */ |
|
459 bestCert = nssCertificate_AddRef(c); |
|
460 bestCertMatches = thisCertMatches; |
|
461 bestdc = dc; |
|
462 continue; |
|
463 } else { |
|
464 if (bestCertMatches && !thisCertMatches) { |
|
465 /* if already have a cert for this usage, and if this cert |
|
466 * doesn't have the correct usage, continue |
|
467 */ |
|
468 continue; |
|
469 } else if (!bestCertMatches && thisCertMatches) { |
|
470 /* this one does match usage, replace the other */ |
|
471 nssCertificate_Destroy(bestCert); |
|
472 bestCert = nssCertificate_AddRef(c); |
|
473 bestCertMatches = thisCertMatches; |
|
474 bestdc = dc; |
|
475 continue; |
|
476 } |
|
477 /* this cert match as well as any cert we've found so far, |
|
478 * defer to time/policies |
|
479 * */ |
|
480 } |
|
481 /* time */ |
|
482 if (bestCertIsValidAtTime || bestdc->isValidAtTime(bestdc, time)) { |
|
483 /* The current best cert is valid at time */ |
|
484 bestCertIsValidAtTime = PR_TRUE; |
|
485 if (!dc->isValidAtTime(dc, time)) { |
|
486 /* If the new cert isn't valid at time, it's not better */ |
|
487 continue; |
|
488 } |
|
489 } else { |
|
490 /* The current best cert is not valid at time */ |
|
491 if (dc->isValidAtTime(dc, time)) { |
|
492 /* If the new cert is valid at time, it's better */ |
|
493 nssCertificate_Destroy(bestCert); |
|
494 bestCert = nssCertificate_AddRef(c); |
|
495 bestdc = dc; |
|
496 bestCertIsValidAtTime = PR_TRUE; |
|
497 continue; |
|
498 } |
|
499 } |
|
500 /* Either they are both valid at time, or neither valid. |
|
501 * If only one is trusted for this usage, take it. |
|
502 */ |
|
503 if (bestCertIsTrusted || bestdc->isTrustedForUsage(bestdc, usage)) { |
|
504 bestCertIsTrusted = PR_TRUE; |
|
505 if (!dc->isTrustedForUsage(dc, usage)) { |
|
506 continue; |
|
507 } |
|
508 } else { |
|
509 /* The current best cert is not trusted */ |
|
510 if (dc->isTrustedForUsage(dc, usage)) { |
|
511 /* If the new cert is trusted, it's better */ |
|
512 nssCertificate_Destroy(bestCert); |
|
513 bestCert = nssCertificate_AddRef(c); |
|
514 bestdc = dc; |
|
515 bestCertIsTrusted = PR_TRUE; |
|
516 continue; |
|
517 } |
|
518 } |
|
519 /* Otherwise, take the newer one. */ |
|
520 if (!bestdc->isNewerThan(bestdc, dc)) { |
|
521 nssCertificate_Destroy(bestCert); |
|
522 bestCert = nssCertificate_AddRef(c); |
|
523 bestdc = dc; |
|
524 continue; |
|
525 } |
|
526 /* policies */ |
|
527 /* XXX later -- defer to policies */ |
|
528 } |
|
529 return bestCert; |
|
530 } |
|
531 |
|
532 NSS_IMPLEMENT PRStatus |
|
533 nssCertificateArray_Traverse ( |
|
534 NSSCertificate **certs, |
|
535 PRStatus (* callback)(NSSCertificate *c, void *arg), |
|
536 void *arg |
|
537 ) |
|
538 { |
|
539 PRStatus status = PR_SUCCESS; |
|
540 if (certs) { |
|
541 NSSCertificate **certp; |
|
542 for (certp = certs; *certp; certp++) { |
|
543 status = (*callback)(*certp, arg); |
|
544 if (status != PR_SUCCESS) { |
|
545 break; |
|
546 } |
|
547 } |
|
548 } |
|
549 return status; |
|
550 } |
|
551 |
|
552 |
|
553 NSS_IMPLEMENT void |
|
554 nssCRLArray_Destroy ( |
|
555 NSSCRL **crls |
|
556 ) |
|
557 { |
|
558 if (crls) { |
|
559 NSSCRL **crlp; |
|
560 for (crlp = crls; *crlp; crlp++) { |
|
561 nssCRL_Destroy(*crlp); |
|
562 } |
|
563 nss_ZFreeIf(crls); |
|
564 } |
|
565 } |
|
566 |
|
567 /* |
|
568 * Object collections |
|
569 */ |
|
570 |
|
571 typedef enum |
|
572 { |
|
573 pkiObjectType_Certificate = 0, |
|
574 pkiObjectType_CRL = 1, |
|
575 pkiObjectType_PrivateKey = 2, |
|
576 pkiObjectType_PublicKey = 3 |
|
577 } pkiObjectType; |
|
578 |
|
579 /* Each object is defined by a set of items that uniquely identify it. |
|
580 * Here are the uid sets: |
|
581 * |
|
582 * NSSCertificate ==> { issuer, serial } |
|
583 * NSSPrivateKey |
|
584 * (RSA) ==> { modulus, public exponent } |
|
585 * |
|
586 */ |
|
587 #define MAX_ITEMS_FOR_UID 2 |
|
588 |
|
589 /* pkiObjectCollectionNode |
|
590 * |
|
591 * A node in the collection is the set of unique identifiers for a single |
|
592 * object, along with either the actual object or a proto-object. |
|
593 */ |
|
594 typedef struct |
|
595 { |
|
596 PRCList link; |
|
597 PRBool haveObject; |
|
598 nssPKIObject *object; |
|
599 NSSItem uid[MAX_ITEMS_FOR_UID]; |
|
600 } |
|
601 pkiObjectCollectionNode; |
|
602 |
|
603 /* nssPKIObjectCollection |
|
604 * |
|
605 * The collection is the set of all objects, plus the interfaces needed |
|
606 * to manage the objects. |
|
607 * |
|
608 */ |
|
609 struct nssPKIObjectCollectionStr |
|
610 { |
|
611 NSSArena *arena; |
|
612 NSSTrustDomain *td; |
|
613 NSSCryptoContext *cc; |
|
614 PRCList head; /* list of pkiObjectCollectionNode's */ |
|
615 PRUint32 size; |
|
616 pkiObjectType objectType; |
|
617 void (* destroyObject)(nssPKIObject *o); |
|
618 PRStatus (* getUIDFromObject)(nssPKIObject *o, NSSItem *uid); |
|
619 PRStatus (* getUIDFromInstance)(nssCryptokiObject *co, NSSItem *uid, |
|
620 NSSArena *arena); |
|
621 nssPKIObject * (* createObject)(nssPKIObject *o); |
|
622 nssPKILockType lockType; /* type of lock to use for new proto-objects */ |
|
623 }; |
|
624 |
|
625 static nssPKIObjectCollection * |
|
626 nssPKIObjectCollection_Create ( |
|
627 NSSTrustDomain *td, |
|
628 NSSCryptoContext *ccOpt, |
|
629 nssPKILockType lockType |
|
630 ) |
|
631 { |
|
632 NSSArena *arena; |
|
633 nssPKIObjectCollection *rvCollection = NULL; |
|
634 arena = nssArena_Create(); |
|
635 if (!arena) { |
|
636 return (nssPKIObjectCollection *)NULL; |
|
637 } |
|
638 rvCollection = nss_ZNEW(arena, nssPKIObjectCollection); |
|
639 if (!rvCollection) { |
|
640 goto loser; |
|
641 } |
|
642 PR_INIT_CLIST(&rvCollection->head); |
|
643 rvCollection->arena = arena; |
|
644 rvCollection->td = td; /* XXX */ |
|
645 rvCollection->cc = ccOpt; |
|
646 rvCollection->lockType = lockType; |
|
647 return rvCollection; |
|
648 loser: |
|
649 nssArena_Destroy(arena); |
|
650 return (nssPKIObjectCollection *)NULL; |
|
651 } |
|
652 |
|
653 NSS_IMPLEMENT void |
|
654 nssPKIObjectCollection_Destroy ( |
|
655 nssPKIObjectCollection *collection |
|
656 ) |
|
657 { |
|
658 if (collection) { |
|
659 PRCList *link; |
|
660 pkiObjectCollectionNode *node; |
|
661 /* first destroy any objects in the collection */ |
|
662 link = PR_NEXT_LINK(&collection->head); |
|
663 while (link != &collection->head) { |
|
664 node = (pkiObjectCollectionNode *)link; |
|
665 if (node->haveObject) { |
|
666 (*collection->destroyObject)(node->object); |
|
667 } else { |
|
668 nssPKIObject_Destroy(node->object); |
|
669 } |
|
670 link = PR_NEXT_LINK(link); |
|
671 } |
|
672 /* then destroy it */ |
|
673 nssArena_Destroy(collection->arena); |
|
674 } |
|
675 } |
|
676 |
|
677 NSS_IMPLEMENT PRUint32 |
|
678 nssPKIObjectCollection_Count ( |
|
679 nssPKIObjectCollection *collection |
|
680 ) |
|
681 { |
|
682 return collection->size; |
|
683 } |
|
684 |
|
685 NSS_IMPLEMENT PRStatus |
|
686 nssPKIObjectCollection_AddObject ( |
|
687 nssPKIObjectCollection *collection, |
|
688 nssPKIObject *object |
|
689 ) |
|
690 { |
|
691 pkiObjectCollectionNode *node; |
|
692 node = nss_ZNEW(collection->arena, pkiObjectCollectionNode); |
|
693 if (!node) { |
|
694 return PR_FAILURE; |
|
695 } |
|
696 node->haveObject = PR_TRUE; |
|
697 node->object = nssPKIObject_AddRef(object); |
|
698 (*collection->getUIDFromObject)(object, node->uid); |
|
699 PR_INIT_CLIST(&node->link); |
|
700 PR_INSERT_BEFORE(&node->link, &collection->head); |
|
701 collection->size++; |
|
702 return PR_SUCCESS; |
|
703 } |
|
704 |
|
705 static pkiObjectCollectionNode * |
|
706 find_instance_in_collection ( |
|
707 nssPKIObjectCollection *collection, |
|
708 nssCryptokiObject *instance |
|
709 ) |
|
710 { |
|
711 PRCList *link; |
|
712 pkiObjectCollectionNode *node; |
|
713 link = PR_NEXT_LINK(&collection->head); |
|
714 while (link != &collection->head) { |
|
715 node = (pkiObjectCollectionNode *)link; |
|
716 if (nssPKIObject_HasInstance(node->object, instance)) { |
|
717 return node; |
|
718 } |
|
719 link = PR_NEXT_LINK(link); |
|
720 } |
|
721 return (pkiObjectCollectionNode *)NULL; |
|
722 } |
|
723 |
|
724 static pkiObjectCollectionNode * |
|
725 find_object_in_collection ( |
|
726 nssPKIObjectCollection *collection, |
|
727 NSSItem *uid |
|
728 ) |
|
729 { |
|
730 PRUint32 i; |
|
731 PRStatus status; |
|
732 PRCList *link; |
|
733 pkiObjectCollectionNode *node; |
|
734 link = PR_NEXT_LINK(&collection->head); |
|
735 while (link != &collection->head) { |
|
736 node = (pkiObjectCollectionNode *)link; |
|
737 for (i=0; i<MAX_ITEMS_FOR_UID; i++) { |
|
738 if (!nssItem_Equal(&node->uid[i], &uid[i], &status)) { |
|
739 break; |
|
740 } |
|
741 } |
|
742 if (i == MAX_ITEMS_FOR_UID) { |
|
743 return node; |
|
744 } |
|
745 link = PR_NEXT_LINK(link); |
|
746 } |
|
747 return (pkiObjectCollectionNode *)NULL; |
|
748 } |
|
749 |
|
750 static pkiObjectCollectionNode * |
|
751 add_object_instance ( |
|
752 nssPKIObjectCollection *collection, |
|
753 nssCryptokiObject *instance, |
|
754 PRBool *foundIt |
|
755 ) |
|
756 { |
|
757 PRUint32 i; |
|
758 PRStatus status; |
|
759 pkiObjectCollectionNode *node; |
|
760 nssArenaMark *mark = NULL; |
|
761 NSSItem uid[MAX_ITEMS_FOR_UID]; |
|
762 nsslibc_memset(uid, 0, sizeof uid); |
|
763 /* The list is traversed twice, first (here) looking to match the |
|
764 * { token, handle } tuple, and if that is not found, below a search |
|
765 * for unique identifier is done. Here, a match means this exact object |
|
766 * instance is already in the collection, and we have nothing to do. |
|
767 */ |
|
768 *foundIt = PR_FALSE; |
|
769 node = find_instance_in_collection(collection, instance); |
|
770 if (node) { |
|
771 /* The collection is assumed to take over the instance. Since we |
|
772 * are not using it, it must be destroyed. |
|
773 */ |
|
774 nssCryptokiObject_Destroy(instance); |
|
775 *foundIt = PR_TRUE; |
|
776 return node; |
|
777 } |
|
778 mark = nssArena_Mark(collection->arena); |
|
779 if (!mark) { |
|
780 goto loser; |
|
781 } |
|
782 status = (*collection->getUIDFromInstance)(instance, uid, |
|
783 collection->arena); |
|
784 if (status != PR_SUCCESS) { |
|
785 goto loser; |
|
786 } |
|
787 /* Search for unique identifier. A match here means the object exists |
|
788 * in the collection, but does not have this instance, so the instance |
|
789 * needs to be added. |
|
790 */ |
|
791 node = find_object_in_collection(collection, uid); |
|
792 if (node) { |
|
793 /* This is an object with multiple instances */ |
|
794 status = nssPKIObject_AddInstance(node->object, instance); |
|
795 } else { |
|
796 /* This is a completely new object. Create a node for it. */ |
|
797 node = nss_ZNEW(collection->arena, pkiObjectCollectionNode); |
|
798 if (!node) { |
|
799 goto loser; |
|
800 } |
|
801 node->object = nssPKIObject_Create(NULL, instance, |
|
802 collection->td, collection->cc, |
|
803 collection->lockType); |
|
804 if (!node->object) { |
|
805 goto loser; |
|
806 } |
|
807 for (i=0; i<MAX_ITEMS_FOR_UID; i++) { |
|
808 node->uid[i] = uid[i]; |
|
809 } |
|
810 node->haveObject = PR_FALSE; |
|
811 PR_INIT_CLIST(&node->link); |
|
812 PR_INSERT_BEFORE(&node->link, &collection->head); |
|
813 collection->size++; |
|
814 status = PR_SUCCESS; |
|
815 } |
|
816 nssArena_Unmark(collection->arena, mark); |
|
817 return node; |
|
818 loser: |
|
819 if (mark) { |
|
820 nssArena_Release(collection->arena, mark); |
|
821 } |
|
822 nssCryptokiObject_Destroy(instance); |
|
823 return (pkiObjectCollectionNode *)NULL; |
|
824 } |
|
825 |
|
826 NSS_IMPLEMENT PRStatus |
|
827 nssPKIObjectCollection_AddInstances ( |
|
828 nssPKIObjectCollection *collection, |
|
829 nssCryptokiObject **instances, |
|
830 PRUint32 numInstances |
|
831 ) |
|
832 { |
|
833 PRStatus status = PR_SUCCESS; |
|
834 PRUint32 i = 0; |
|
835 PRBool foundIt; |
|
836 pkiObjectCollectionNode *node; |
|
837 if (instances) { |
|
838 while ((!numInstances || i < numInstances) && *instances) { |
|
839 if (status == PR_SUCCESS) { |
|
840 node = add_object_instance(collection, *instances, &foundIt); |
|
841 if (node == NULL) { |
|
842 /* add_object_instance freed the current instance */ |
|
843 /* free the remaining instances */ |
|
844 status = PR_FAILURE; |
|
845 } |
|
846 } else { |
|
847 nssCryptokiObject_Destroy(*instances); |
|
848 } |
|
849 instances++; |
|
850 i++; |
|
851 } |
|
852 } |
|
853 return status; |
|
854 } |
|
855 |
|
856 static void |
|
857 nssPKIObjectCollection_RemoveNode ( |
|
858 nssPKIObjectCollection *collection, |
|
859 pkiObjectCollectionNode *node |
|
860 ) |
|
861 { |
|
862 PR_REMOVE_LINK(&node->link); |
|
863 collection->size--; |
|
864 } |
|
865 |
|
866 static PRStatus |
|
867 nssPKIObjectCollection_GetObjects ( |
|
868 nssPKIObjectCollection *collection, |
|
869 nssPKIObject **rvObjects, |
|
870 PRUint32 rvSize |
|
871 ) |
|
872 { |
|
873 PRUint32 i = 0; |
|
874 PRCList *link = PR_NEXT_LINK(&collection->head); |
|
875 pkiObjectCollectionNode *node; |
|
876 int error=0; |
|
877 while ((i < rvSize) && (link != &collection->head)) { |
|
878 node = (pkiObjectCollectionNode *)link; |
|
879 if (!node->haveObject) { |
|
880 /* Convert the proto-object to an object */ |
|
881 node->object = (*collection->createObject)(node->object); |
|
882 if (!node->object) { |
|
883 link = PR_NEXT_LINK(link); |
|
884 /*remove bogus object from list*/ |
|
885 nssPKIObjectCollection_RemoveNode(collection,node); |
|
886 error++; |
|
887 continue; |
|
888 } |
|
889 node->haveObject = PR_TRUE; |
|
890 } |
|
891 rvObjects[i++] = nssPKIObject_AddRef(node->object); |
|
892 link = PR_NEXT_LINK(link); |
|
893 } |
|
894 if (!error && *rvObjects == NULL) { |
|
895 nss_SetError(NSS_ERROR_NOT_FOUND); |
|
896 } |
|
897 return PR_SUCCESS; |
|
898 } |
|
899 |
|
900 NSS_IMPLEMENT PRStatus |
|
901 nssPKIObjectCollection_Traverse ( |
|
902 nssPKIObjectCollection *collection, |
|
903 nssPKIObjectCallback *callback |
|
904 ) |
|
905 { |
|
906 PRStatus status; |
|
907 PRCList *link = PR_NEXT_LINK(&collection->head); |
|
908 pkiObjectCollectionNode *node; |
|
909 while (link != &collection->head) { |
|
910 node = (pkiObjectCollectionNode *)link; |
|
911 if (!node->haveObject) { |
|
912 node->object = (*collection->createObject)(node->object); |
|
913 if (!node->object) { |
|
914 link = PR_NEXT_LINK(link); |
|
915 /*remove bogus object from list*/ |
|
916 nssPKIObjectCollection_RemoveNode(collection,node); |
|
917 continue; |
|
918 } |
|
919 node->haveObject = PR_TRUE; |
|
920 } |
|
921 switch (collection->objectType) { |
|
922 case pkiObjectType_Certificate: |
|
923 status = (*callback->func.cert)((NSSCertificate *)node->object, |
|
924 callback->arg); |
|
925 break; |
|
926 case pkiObjectType_CRL: |
|
927 status = (*callback->func.crl)((NSSCRL *)node->object, |
|
928 callback->arg); |
|
929 break; |
|
930 case pkiObjectType_PrivateKey: |
|
931 status = (*callback->func.pvkey)((NSSPrivateKey *)node->object, |
|
932 callback->arg); |
|
933 break; |
|
934 case pkiObjectType_PublicKey: |
|
935 status = (*callback->func.pbkey)((NSSPublicKey *)node->object, |
|
936 callback->arg); |
|
937 break; |
|
938 } |
|
939 link = PR_NEXT_LINK(link); |
|
940 } |
|
941 return PR_SUCCESS; |
|
942 } |
|
943 |
|
944 NSS_IMPLEMENT PRStatus |
|
945 nssPKIObjectCollection_AddInstanceAsObject ( |
|
946 nssPKIObjectCollection *collection, |
|
947 nssCryptokiObject *instance |
|
948 ) |
|
949 { |
|
950 pkiObjectCollectionNode *node; |
|
951 PRBool foundIt; |
|
952 node = add_object_instance(collection, instance, &foundIt); |
|
953 if (node == NULL) { |
|
954 return PR_FAILURE; |
|
955 } |
|
956 if (!node->haveObject) { |
|
957 node->object = (*collection->createObject)(node->object); |
|
958 if (!node->object) { |
|
959 /*remove bogus object from list*/ |
|
960 nssPKIObjectCollection_RemoveNode(collection,node); |
|
961 return PR_FAILURE; |
|
962 } |
|
963 node->haveObject = PR_TRUE; |
|
964 } else if (!foundIt) { |
|
965 /* The instance was added to a pre-existing node. This |
|
966 * function is *only* being used for certificates, and having |
|
967 * multiple instances of certs in 3.X requires updating the |
|
968 * CERTCertificate. |
|
969 * But only do it if it was a new instance!!! If the same instance |
|
970 * is encountered, we set *foundIt to true. Detect that here and |
|
971 * ignore it. |
|
972 */ |
|
973 STAN_ForceCERTCertificateUpdate((NSSCertificate *)node->object); |
|
974 } |
|
975 return PR_SUCCESS; |
|
976 } |
|
977 |
|
978 /* |
|
979 * Certificate collections |
|
980 */ |
|
981 |
|
982 static void |
|
983 cert_destroyObject(nssPKIObject *o) |
|
984 { |
|
985 NSSCertificate *c = (NSSCertificate *)o; |
|
986 if (c->decoding) { |
|
987 CERTCertificate *cc = STAN_GetCERTCertificate(c); |
|
988 if (cc) { |
|
989 CERT_DestroyCertificate(cc); |
|
990 return; |
|
991 } /* else destroy it as NSSCertificate below */ |
|
992 } |
|
993 nssCertificate_Destroy(c); |
|
994 } |
|
995 |
|
996 static PRStatus |
|
997 cert_getUIDFromObject(nssPKIObject *o, NSSItem *uid) |
|
998 { |
|
999 NSSCertificate *c = (NSSCertificate *)o; |
|
1000 /* The builtins are still returning decoded serial numbers. Until |
|
1001 * this compatibility issue is resolved, use the full DER of the |
|
1002 * cert to uniquely identify it. |
|
1003 */ |
|
1004 NSSDER *derCert; |
|
1005 derCert = nssCertificate_GetEncoding(c); |
|
1006 uid[0].data = NULL; uid[0].size = 0; |
|
1007 uid[1].data = NULL; uid[1].size = 0; |
|
1008 if (derCert != NULL) { |
|
1009 uid[0] = *derCert; |
|
1010 } |
|
1011 return PR_SUCCESS; |
|
1012 } |
|
1013 |
|
1014 static PRStatus |
|
1015 cert_getUIDFromInstance(nssCryptokiObject *instance, NSSItem *uid, |
|
1016 NSSArena *arena) |
|
1017 { |
|
1018 /* The builtins are still returning decoded serial numbers. Until |
|
1019 * this compatibility issue is resolved, use the full DER of the |
|
1020 * cert to uniquely identify it. |
|
1021 */ |
|
1022 uid[1].data = NULL; uid[1].size = 0; |
|
1023 return nssCryptokiCertificate_GetAttributes(instance, |
|
1024 NULL, /* XXX sessionOpt */ |
|
1025 arena, /* arena */ |
|
1026 NULL, /* type */ |
|
1027 NULL, /* id */ |
|
1028 &uid[0], /* encoding */ |
|
1029 NULL, /* issuer */ |
|
1030 NULL, /* serial */ |
|
1031 NULL); /* subject */ |
|
1032 } |
|
1033 |
|
1034 static nssPKIObject * |
|
1035 cert_createObject(nssPKIObject *o) |
|
1036 { |
|
1037 NSSCertificate *cert; |
|
1038 cert = nssCertificate_Create(o); |
|
1039 /* if (STAN_GetCERTCertificate(cert) == NULL) { |
|
1040 nssCertificate_Destroy(cert); |
|
1041 return (nssPKIObject *)NULL; |
|
1042 } */ |
|
1043 /* In 3.4, have to maintain uniqueness of cert pointers by caching all |
|
1044 * certs. Cache the cert here, before returning. If it is already |
|
1045 * cached, take the cached entry. |
|
1046 */ |
|
1047 { |
|
1048 NSSTrustDomain *td = o->trustDomain; |
|
1049 nssTrustDomain_AddCertsToCache(td, &cert, 1); |
|
1050 } |
|
1051 return (nssPKIObject *)cert; |
|
1052 } |
|
1053 |
|
1054 NSS_IMPLEMENT nssPKIObjectCollection * |
|
1055 nssCertificateCollection_Create ( |
|
1056 NSSTrustDomain *td, |
|
1057 NSSCertificate **certsOpt |
|
1058 ) |
|
1059 { |
|
1060 PRStatus status; |
|
1061 nssPKIObjectCollection *collection; |
|
1062 collection = nssPKIObjectCollection_Create(td, NULL, nssPKIMonitor); |
|
1063 collection->objectType = pkiObjectType_Certificate; |
|
1064 collection->destroyObject = cert_destroyObject; |
|
1065 collection->getUIDFromObject = cert_getUIDFromObject; |
|
1066 collection->getUIDFromInstance = cert_getUIDFromInstance; |
|
1067 collection->createObject = cert_createObject; |
|
1068 if (certsOpt) { |
|
1069 for (; *certsOpt; certsOpt++) { |
|
1070 nssPKIObject *object = (nssPKIObject *)(*certsOpt); |
|
1071 status = nssPKIObjectCollection_AddObject(collection, object); |
|
1072 } |
|
1073 } |
|
1074 return collection; |
|
1075 } |
|
1076 |
|
1077 NSS_IMPLEMENT NSSCertificate ** |
|
1078 nssPKIObjectCollection_GetCertificates ( |
|
1079 nssPKIObjectCollection *collection, |
|
1080 NSSCertificate **rvOpt, |
|
1081 PRUint32 maximumOpt, |
|
1082 NSSArena *arenaOpt |
|
1083 ) |
|
1084 { |
|
1085 PRStatus status; |
|
1086 PRUint32 rvSize; |
|
1087 PRBool allocated = PR_FALSE; |
|
1088 if (collection->size == 0) { |
|
1089 return (NSSCertificate **)NULL; |
|
1090 } |
|
1091 if (maximumOpt == 0) { |
|
1092 rvSize = collection->size; |
|
1093 } else { |
|
1094 rvSize = PR_MIN(collection->size, maximumOpt); |
|
1095 } |
|
1096 if (!rvOpt) { |
|
1097 rvOpt = nss_ZNEWARRAY(arenaOpt, NSSCertificate *, rvSize + 1); |
|
1098 if (!rvOpt) { |
|
1099 return (NSSCertificate **)NULL; |
|
1100 } |
|
1101 allocated = PR_TRUE; |
|
1102 } |
|
1103 status = nssPKIObjectCollection_GetObjects(collection, |
|
1104 (nssPKIObject **)rvOpt, |
|
1105 rvSize); |
|
1106 if (status != PR_SUCCESS) { |
|
1107 if (allocated) { |
|
1108 nss_ZFreeIf(rvOpt); |
|
1109 } |
|
1110 return (NSSCertificate **)NULL; |
|
1111 } |
|
1112 return rvOpt; |
|
1113 } |
|
1114 |
|
1115 /* |
|
1116 * CRL/KRL collections |
|
1117 */ |
|
1118 |
|
1119 static void |
|
1120 crl_destroyObject(nssPKIObject *o) |
|
1121 { |
|
1122 NSSCRL *crl = (NSSCRL *)o; |
|
1123 nssCRL_Destroy(crl); |
|
1124 } |
|
1125 |
|
1126 static PRStatus |
|
1127 crl_getUIDFromObject(nssPKIObject *o, NSSItem *uid) |
|
1128 { |
|
1129 NSSCRL *crl = (NSSCRL *)o; |
|
1130 NSSDER *encoding; |
|
1131 encoding = nssCRL_GetEncoding(crl); |
|
1132 if (!encoding) { |
|
1133 nss_SetError(NSS_ERROR_INVALID_ARGUMENT); |
|
1134 return PR_FALSE; |
|
1135 } |
|
1136 uid[0] = *encoding; |
|
1137 uid[1].data = NULL; uid[1].size = 0; |
|
1138 return PR_SUCCESS; |
|
1139 } |
|
1140 |
|
1141 static PRStatus |
|
1142 crl_getUIDFromInstance(nssCryptokiObject *instance, NSSItem *uid, |
|
1143 NSSArena *arena) |
|
1144 { |
|
1145 return nssCryptokiCRL_GetAttributes(instance, |
|
1146 NULL, /* XXX sessionOpt */ |
|
1147 arena, /* arena */ |
|
1148 &uid[0], /* encoding */ |
|
1149 NULL, /* subject */ |
|
1150 NULL, /* class */ |
|
1151 NULL, /* url */ |
|
1152 NULL); /* isKRL */ |
|
1153 } |
|
1154 |
|
1155 static nssPKIObject * |
|
1156 crl_createObject(nssPKIObject *o) |
|
1157 { |
|
1158 return (nssPKIObject *)nssCRL_Create(o); |
|
1159 } |
|
1160 |
|
1161 NSS_IMPLEMENT nssPKIObjectCollection * |
|
1162 nssCRLCollection_Create ( |
|
1163 NSSTrustDomain *td, |
|
1164 NSSCRL **crlsOpt |
|
1165 ) |
|
1166 { |
|
1167 PRStatus status; |
|
1168 nssPKIObjectCollection *collection; |
|
1169 collection = nssPKIObjectCollection_Create(td, NULL, nssPKILock); |
|
1170 collection->objectType = pkiObjectType_CRL; |
|
1171 collection->destroyObject = crl_destroyObject; |
|
1172 collection->getUIDFromObject = crl_getUIDFromObject; |
|
1173 collection->getUIDFromInstance = crl_getUIDFromInstance; |
|
1174 collection->createObject = crl_createObject; |
|
1175 if (crlsOpt) { |
|
1176 for (; *crlsOpt; crlsOpt++) { |
|
1177 nssPKIObject *object = (nssPKIObject *)(*crlsOpt); |
|
1178 status = nssPKIObjectCollection_AddObject(collection, object); |
|
1179 } |
|
1180 } |
|
1181 return collection; |
|
1182 } |
|
1183 |
|
1184 NSS_IMPLEMENT NSSCRL ** |
|
1185 nssPKIObjectCollection_GetCRLs ( |
|
1186 nssPKIObjectCollection *collection, |
|
1187 NSSCRL **rvOpt, |
|
1188 PRUint32 maximumOpt, |
|
1189 NSSArena *arenaOpt |
|
1190 ) |
|
1191 { |
|
1192 PRStatus status; |
|
1193 PRUint32 rvSize; |
|
1194 PRBool allocated = PR_FALSE; |
|
1195 if (collection->size == 0) { |
|
1196 return (NSSCRL **)NULL; |
|
1197 } |
|
1198 if (maximumOpt == 0) { |
|
1199 rvSize = collection->size; |
|
1200 } else { |
|
1201 rvSize = PR_MIN(collection->size, maximumOpt); |
|
1202 } |
|
1203 if (!rvOpt) { |
|
1204 rvOpt = nss_ZNEWARRAY(arenaOpt, NSSCRL *, rvSize + 1); |
|
1205 if (!rvOpt) { |
|
1206 return (NSSCRL **)NULL; |
|
1207 } |
|
1208 allocated = PR_TRUE; |
|
1209 } |
|
1210 status = nssPKIObjectCollection_GetObjects(collection, |
|
1211 (nssPKIObject **)rvOpt, |
|
1212 rvSize); |
|
1213 if (status != PR_SUCCESS) { |
|
1214 if (allocated) { |
|
1215 nss_ZFreeIf(rvOpt); |
|
1216 } |
|
1217 return (NSSCRL **)NULL; |
|
1218 } |
|
1219 return rvOpt; |
|
1220 } |
|
1221 |
|
1222 /* how bad would it be to have a static now sitting around, updated whenever |
|
1223 * this was called? would avoid repeated allocs... |
|
1224 */ |
|
1225 NSS_IMPLEMENT NSSTime * |
|
1226 NSSTime_Now ( |
|
1227 NSSTime *timeOpt |
|
1228 ) |
|
1229 { |
|
1230 return NSSTime_SetPRTime(timeOpt, PR_Now()); |
|
1231 } |
|
1232 |
|
1233 NSS_IMPLEMENT NSSTime * |
|
1234 NSSTime_SetPRTime ( |
|
1235 NSSTime *timeOpt, |
|
1236 PRTime prTime |
|
1237 ) |
|
1238 { |
|
1239 NSSTime *rvTime; |
|
1240 rvTime = (timeOpt) ? timeOpt : nss_ZNEW(NULL, NSSTime); |
|
1241 if (rvTime) { |
|
1242 rvTime->prTime = prTime; |
|
1243 } |
|
1244 return rvTime; |
|
1245 } |
|
1246 |
|
1247 NSS_IMPLEMENT PRTime |
|
1248 NSSTime_GetPRTime ( |
|
1249 NSSTime *time |
|
1250 ) |
|
1251 { |
|
1252 return time->prTime; |
|
1253 } |
|
1254 |