1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/pki/pkibase.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1254 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#ifndef DEV_H 1.9 +#include "dev.h" 1.10 +#endif /* DEV_H */ 1.11 + 1.12 +#ifndef PKIM_H 1.13 +#include "pkim.h" 1.14 +#endif /* PKIM_H */ 1.15 + 1.16 +#include "pki3hack.h" 1.17 + 1.18 +extern const NSSError NSS_ERROR_NOT_FOUND; 1.19 + 1.20 +NSS_IMPLEMENT void 1.21 +nssPKIObject_Lock(nssPKIObject * object) 1.22 +{ 1.23 + switch (object->lockType) { 1.24 + case nssPKIMonitor: 1.25 + PZ_EnterMonitor(object->sync.mlock); 1.26 + break; 1.27 + case nssPKILock: 1.28 + PZ_Lock(object->sync.lock); 1.29 + break; 1.30 + default: 1.31 + PORT_Assert(0); 1.32 + } 1.33 +} 1.34 + 1.35 +NSS_IMPLEMENT void 1.36 +nssPKIObject_Unlock(nssPKIObject * object) 1.37 +{ 1.38 + switch (object->lockType) { 1.39 + case nssPKIMonitor: 1.40 + PZ_ExitMonitor(object->sync.mlock); 1.41 + break; 1.42 + case nssPKILock: 1.43 + PZ_Unlock(object->sync.lock); 1.44 + break; 1.45 + default: 1.46 + PORT_Assert(0); 1.47 + } 1.48 +} 1.49 + 1.50 +NSS_IMPLEMENT PRStatus 1.51 +nssPKIObject_NewLock(nssPKIObject * object, nssPKILockType lockType) 1.52 +{ 1.53 + object->lockType = lockType; 1.54 + switch (lockType) { 1.55 + case nssPKIMonitor: 1.56 + object->sync.mlock = PZ_NewMonitor(nssILockSSL); 1.57 + return (object->sync.mlock ? PR_SUCCESS : PR_FAILURE); 1.58 + case nssPKILock: 1.59 + object->sync.lock = PZ_NewLock(nssILockSSL); 1.60 + return (object->sync.lock ? PR_SUCCESS : PR_FAILURE); 1.61 + default: 1.62 + PORT_Assert(0); 1.63 + return PR_FAILURE; 1.64 + } 1.65 +} 1.66 + 1.67 +NSS_IMPLEMENT void 1.68 +nssPKIObject_DestroyLock(nssPKIObject * object) 1.69 +{ 1.70 + switch (object->lockType) { 1.71 + case nssPKIMonitor: 1.72 + PZ_DestroyMonitor(object->sync.mlock); 1.73 + object->sync.mlock = NULL; 1.74 + break; 1.75 + case nssPKILock: 1.76 + PZ_DestroyLock(object->sync.lock); 1.77 + object->sync.lock = NULL; 1.78 + break; 1.79 + default: 1.80 + PORT_Assert(0); 1.81 + } 1.82 +} 1.83 + 1.84 + 1.85 + 1.86 +NSS_IMPLEMENT nssPKIObject * 1.87 +nssPKIObject_Create ( 1.88 + NSSArena *arenaOpt, 1.89 + nssCryptokiObject *instanceOpt, 1.90 + NSSTrustDomain *td, 1.91 + NSSCryptoContext *cc, 1.92 + nssPKILockType lockType 1.93 +) 1.94 +{ 1.95 + NSSArena *arena; 1.96 + nssArenaMark *mark = NULL; 1.97 + nssPKIObject *object; 1.98 + if (arenaOpt) { 1.99 + arena = arenaOpt; 1.100 + mark = nssArena_Mark(arena); 1.101 + } else { 1.102 + arena = nssArena_Create(); 1.103 + if (!arena) { 1.104 + return (nssPKIObject *)NULL; 1.105 + } 1.106 + } 1.107 + object = nss_ZNEW(arena, nssPKIObject); 1.108 + if (!object) { 1.109 + goto loser; 1.110 + } 1.111 + object->arena = arena; 1.112 + object->trustDomain = td; /* XXX */ 1.113 + object->cryptoContext = cc; 1.114 + if (PR_SUCCESS != nssPKIObject_NewLock(object, lockType)) { 1.115 + goto loser; 1.116 + } 1.117 + if (instanceOpt) { 1.118 + if (nssPKIObject_AddInstance(object, instanceOpt) != PR_SUCCESS) { 1.119 + goto loser; 1.120 + } 1.121 + } 1.122 + PR_ATOMIC_INCREMENT(&object->refCount); 1.123 + if (mark) { 1.124 + nssArena_Unmark(arena, mark); 1.125 + } 1.126 + return object; 1.127 +loser: 1.128 + if (mark) { 1.129 + nssArena_Release(arena, mark); 1.130 + } else { 1.131 + nssArena_Destroy(arena); 1.132 + } 1.133 + return (nssPKIObject *)NULL; 1.134 +} 1.135 + 1.136 +NSS_IMPLEMENT PRBool 1.137 +nssPKIObject_Destroy ( 1.138 + nssPKIObject *object 1.139 +) 1.140 +{ 1.141 + PRUint32 i; 1.142 + PR_ASSERT(object->refCount > 0); 1.143 + if (PR_ATOMIC_DECREMENT(&object->refCount) == 0) { 1.144 + for (i=0; i<object->numInstances; i++) { 1.145 + nssCryptokiObject_Destroy(object->instances[i]); 1.146 + } 1.147 + nssPKIObject_DestroyLock(object); 1.148 + nssArena_Destroy(object->arena); 1.149 + return PR_TRUE; 1.150 + } 1.151 + return PR_FALSE; 1.152 +} 1.153 + 1.154 +NSS_IMPLEMENT nssPKIObject * 1.155 +nssPKIObject_AddRef ( 1.156 + nssPKIObject *object 1.157 +) 1.158 +{ 1.159 + PR_ATOMIC_INCREMENT(&object->refCount); 1.160 + return object; 1.161 +} 1.162 + 1.163 +NSS_IMPLEMENT PRStatus 1.164 +nssPKIObject_AddInstance ( 1.165 + nssPKIObject *object, 1.166 + nssCryptokiObject *instance 1.167 +) 1.168 +{ 1.169 + nssCryptokiObject **newInstances = NULL; 1.170 + 1.171 + nssPKIObject_Lock(object); 1.172 + if (object->numInstances == 0) { 1.173 + newInstances = nss_ZNEWARRAY(object->arena, 1.174 + nssCryptokiObject *, 1.175 + object->numInstances + 1); 1.176 + } else { 1.177 + PRBool found = PR_FALSE; 1.178 + PRUint32 i; 1.179 + for (i=0; i<object->numInstances; i++) { 1.180 + if (nssCryptokiObject_Equal(object->instances[i], instance)) { 1.181 + found = PR_TRUE; 1.182 + break; 1.183 + } 1.184 + } 1.185 + if (found) { 1.186 + /* The new instance is identical to one in the array, except 1.187 + * perhaps that the label may be different. So replace 1.188 + * the label in the array instance with the label from the 1.189 + * new instance, and discard the new instance. 1.190 + */ 1.191 + nss_ZFreeIf(object->instances[i]->label); 1.192 + object->instances[i]->label = instance->label; 1.193 + nssPKIObject_Unlock(object); 1.194 + instance->label = NULL; 1.195 + nssCryptokiObject_Destroy(instance); 1.196 + return PR_SUCCESS; 1.197 + } 1.198 + newInstances = nss_ZREALLOCARRAY(object->instances, 1.199 + nssCryptokiObject *, 1.200 + object->numInstances + 1); 1.201 + } 1.202 + if (newInstances) { 1.203 + object->instances = newInstances; 1.204 + newInstances[object->numInstances++] = instance; 1.205 + } 1.206 + nssPKIObject_Unlock(object); 1.207 + return (newInstances ? PR_SUCCESS : PR_FAILURE); 1.208 +} 1.209 + 1.210 +NSS_IMPLEMENT PRBool 1.211 +nssPKIObject_HasInstance ( 1.212 + nssPKIObject *object, 1.213 + nssCryptokiObject *instance 1.214 +) 1.215 +{ 1.216 + PRUint32 i; 1.217 + PRBool hasIt = PR_FALSE;; 1.218 + nssPKIObject_Lock(object); 1.219 + for (i=0; i<object->numInstances; i++) { 1.220 + if (nssCryptokiObject_Equal(object->instances[i], instance)) { 1.221 + hasIt = PR_TRUE; 1.222 + break; 1.223 + } 1.224 + } 1.225 + nssPKIObject_Unlock(object); 1.226 + return hasIt; 1.227 +} 1.228 + 1.229 +NSS_IMPLEMENT PRStatus 1.230 +nssPKIObject_RemoveInstanceForToken ( 1.231 + nssPKIObject *object, 1.232 + NSSToken *token 1.233 +) 1.234 +{ 1.235 + PRUint32 i; 1.236 + nssCryptokiObject *instanceToRemove = NULL; 1.237 + nssPKIObject_Lock(object); 1.238 + if (object->numInstances == 0) { 1.239 + nssPKIObject_Unlock(object); 1.240 + return PR_SUCCESS; 1.241 + } 1.242 + for (i=0; i<object->numInstances; i++) { 1.243 + if (object->instances[i]->token == token) { 1.244 + instanceToRemove = object->instances[i]; 1.245 + object->instances[i] = object->instances[object->numInstances-1]; 1.246 + object->instances[object->numInstances-1] = NULL; 1.247 + break; 1.248 + } 1.249 + } 1.250 + if (--object->numInstances > 0) { 1.251 + nssCryptokiObject **instances = nss_ZREALLOCARRAY(object->instances, 1.252 + nssCryptokiObject *, 1.253 + object->numInstances); 1.254 + if (instances) { 1.255 + object->instances = instances; 1.256 + } 1.257 + } else { 1.258 + nss_ZFreeIf(object->instances); 1.259 + } 1.260 + nssCryptokiObject_Destroy(instanceToRemove); 1.261 + nssPKIObject_Unlock(object); 1.262 + return PR_SUCCESS; 1.263 +} 1.264 + 1.265 +/* this needs more thought on what will happen when there are multiple 1.266 + * instances 1.267 + */ 1.268 +NSS_IMPLEMENT PRStatus 1.269 +nssPKIObject_DeleteStoredObject ( 1.270 + nssPKIObject *object, 1.271 + NSSCallback *uhh, 1.272 + PRBool isFriendly 1.273 +) 1.274 +{ 1.275 + PRUint32 i, numNotDestroyed; 1.276 + PRStatus status = PR_SUCCESS; 1.277 + numNotDestroyed = 0; 1.278 + nssPKIObject_Lock(object); 1.279 + for (i=0; i<object->numInstances; i++) { 1.280 + nssCryptokiObject *instance = object->instances[i]; 1.281 + status = nssToken_DeleteStoredObject(instance); 1.282 + object->instances[i] = NULL; 1.283 + if (status == PR_SUCCESS) { 1.284 + nssCryptokiObject_Destroy(instance); 1.285 + } else { 1.286 + object->instances[numNotDestroyed++] = instance; 1.287 + } 1.288 + } 1.289 + if (numNotDestroyed == 0) { 1.290 + nss_ZFreeIf(object->instances); 1.291 + object->numInstances = 0; 1.292 + } else { 1.293 + object->numInstances = numNotDestroyed; 1.294 + } 1.295 + nssPKIObject_Unlock(object); 1.296 + return status; 1.297 +} 1.298 + 1.299 +NSS_IMPLEMENT NSSToken ** 1.300 +nssPKIObject_GetTokens ( 1.301 + nssPKIObject *object, 1.302 + PRStatus *statusOpt 1.303 +) 1.304 +{ 1.305 + NSSToken **tokens = NULL; 1.306 + nssPKIObject_Lock(object); 1.307 + if (object->numInstances > 0) { 1.308 + tokens = nss_ZNEWARRAY(NULL, NSSToken *, object->numInstances + 1); 1.309 + if (tokens) { 1.310 + PRUint32 i; 1.311 + for (i=0; i<object->numInstances; i++) { 1.312 + tokens[i] = nssToken_AddRef(object->instances[i]->token); 1.313 + } 1.314 + } 1.315 + } 1.316 + nssPKIObject_Unlock(object); 1.317 + if (statusOpt) *statusOpt = PR_SUCCESS; /* until more logic here */ 1.318 + return tokens; 1.319 +} 1.320 + 1.321 +NSS_IMPLEMENT NSSUTF8 * 1.322 +nssPKIObject_GetNicknameForToken ( 1.323 + nssPKIObject *object, 1.324 + NSSToken *tokenOpt 1.325 +) 1.326 +{ 1.327 + PRUint32 i; 1.328 + NSSUTF8 *nickname = NULL; 1.329 + nssPKIObject_Lock(object); 1.330 + for (i=0; i<object->numInstances; i++) { 1.331 + if ((!tokenOpt && object->instances[i]->label) || 1.332 + (object->instances[i]->token == tokenOpt)) 1.333 + { 1.334 + /* Must copy, see bug 745548 */ 1.335 + nickname = nssUTF8_Duplicate(object->instances[i]->label, NULL); 1.336 + break; 1.337 + } 1.338 + } 1.339 + nssPKIObject_Unlock(object); 1.340 + return nickname; 1.341 +} 1.342 + 1.343 +NSS_IMPLEMENT nssCryptokiObject ** 1.344 +nssPKIObject_GetInstances ( 1.345 + nssPKIObject *object 1.346 +) 1.347 +{ 1.348 + nssCryptokiObject **instances = NULL; 1.349 + PRUint32 i; 1.350 + if (object->numInstances == 0) { 1.351 + return (nssCryptokiObject **)NULL; 1.352 + } 1.353 + nssPKIObject_Lock(object); 1.354 + instances = nss_ZNEWARRAY(NULL, nssCryptokiObject *, 1.355 + object->numInstances + 1); 1.356 + if (instances) { 1.357 + for (i=0; i<object->numInstances; i++) { 1.358 + instances[i] = nssCryptokiObject_Clone(object->instances[i]); 1.359 + } 1.360 + } 1.361 + nssPKIObject_Unlock(object); 1.362 + return instances; 1.363 +} 1.364 + 1.365 +NSS_IMPLEMENT void 1.366 +nssCertificateArray_Destroy ( 1.367 + NSSCertificate **certs 1.368 +) 1.369 +{ 1.370 + if (certs) { 1.371 + NSSCertificate **certp; 1.372 + for (certp = certs; *certp; certp++) { 1.373 + if ((*certp)->decoding) { 1.374 + CERTCertificate *cc = STAN_GetCERTCertificate(*certp); 1.375 + if (cc) { 1.376 + CERT_DestroyCertificate(cc); 1.377 + } 1.378 + continue; 1.379 + } 1.380 + nssCertificate_Destroy(*certp); 1.381 + } 1.382 + nss_ZFreeIf(certs); 1.383 + } 1.384 +} 1.385 + 1.386 +NSS_IMPLEMENT void 1.387 +NSSCertificateArray_Destroy ( 1.388 + NSSCertificate **certs 1.389 +) 1.390 +{ 1.391 + nssCertificateArray_Destroy(certs); 1.392 +} 1.393 + 1.394 +NSS_IMPLEMENT NSSCertificate ** 1.395 +nssCertificateArray_Join ( 1.396 + NSSCertificate **certs1, 1.397 + NSSCertificate **certs2 1.398 +) 1.399 +{ 1.400 + if (certs1 && certs2) { 1.401 + NSSCertificate **certs, **cp; 1.402 + PRUint32 count = 0; 1.403 + PRUint32 count1 = 0; 1.404 + cp = certs1; 1.405 + while (*cp++) count1++; 1.406 + count = count1; 1.407 + cp = certs2; 1.408 + while (*cp++) count++; 1.409 + certs = nss_ZREALLOCARRAY(certs1, NSSCertificate *, count + 1); 1.410 + if (!certs) { 1.411 + nss_ZFreeIf(certs1); 1.412 + nss_ZFreeIf(certs2); 1.413 + return (NSSCertificate **)NULL; 1.414 + } 1.415 + for (cp = certs2; *cp; cp++, count1++) { 1.416 + certs[count1] = *cp; 1.417 + } 1.418 + nss_ZFreeIf(certs2); 1.419 + return certs; 1.420 + } else if (certs1) { 1.421 + return certs1; 1.422 + } else { 1.423 + return certs2; 1.424 + } 1.425 +} 1.426 + 1.427 +NSS_IMPLEMENT NSSCertificate * 1.428 +nssCertificateArray_FindBestCertificate ( 1.429 + NSSCertificate **certs, 1.430 + NSSTime *timeOpt, 1.431 + const NSSUsage *usage, 1.432 + NSSPolicies *policiesOpt 1.433 +) 1.434 +{ 1.435 + NSSCertificate *bestCert = NULL; 1.436 + nssDecodedCert *bestdc = NULL; 1.437 + NSSTime *time, sTime; 1.438 + PRBool bestCertMatches = PR_FALSE; 1.439 + PRBool thisCertMatches; 1.440 + PRBool bestCertIsValidAtTime = PR_FALSE; 1.441 + PRBool bestCertIsTrusted = PR_FALSE; 1.442 + 1.443 + if (timeOpt) { 1.444 + time = timeOpt; 1.445 + } else { 1.446 + NSSTime_Now(&sTime); 1.447 + time = &sTime; 1.448 + } 1.449 + if (!certs) { 1.450 + return (NSSCertificate *)NULL; 1.451 + } 1.452 + for (; *certs; certs++) { 1.453 + nssDecodedCert *dc; 1.454 + NSSCertificate *c = *certs; 1.455 + dc = nssCertificate_GetDecoding(c); 1.456 + if (!dc) continue; 1.457 + thisCertMatches = dc->matchUsage(dc, usage); 1.458 + if (!bestCert) { 1.459 + /* always take the first cert, but remember whether or not 1.460 + * the usage matched 1.461 + */ 1.462 + bestCert = nssCertificate_AddRef(c); 1.463 + bestCertMatches = thisCertMatches; 1.464 + bestdc = dc; 1.465 + continue; 1.466 + } else { 1.467 + if (bestCertMatches && !thisCertMatches) { 1.468 + /* if already have a cert for this usage, and if this cert 1.469 + * doesn't have the correct usage, continue 1.470 + */ 1.471 + continue; 1.472 + } else if (!bestCertMatches && thisCertMatches) { 1.473 + /* this one does match usage, replace the other */ 1.474 + nssCertificate_Destroy(bestCert); 1.475 + bestCert = nssCertificate_AddRef(c); 1.476 + bestCertMatches = thisCertMatches; 1.477 + bestdc = dc; 1.478 + continue; 1.479 + } 1.480 + /* this cert match as well as any cert we've found so far, 1.481 + * defer to time/policies 1.482 + * */ 1.483 + } 1.484 + /* time */ 1.485 + if (bestCertIsValidAtTime || bestdc->isValidAtTime(bestdc, time)) { 1.486 + /* The current best cert is valid at time */ 1.487 + bestCertIsValidAtTime = PR_TRUE; 1.488 + if (!dc->isValidAtTime(dc, time)) { 1.489 + /* If the new cert isn't valid at time, it's not better */ 1.490 + continue; 1.491 + } 1.492 + } else { 1.493 + /* The current best cert is not valid at time */ 1.494 + if (dc->isValidAtTime(dc, time)) { 1.495 + /* If the new cert is valid at time, it's better */ 1.496 + nssCertificate_Destroy(bestCert); 1.497 + bestCert = nssCertificate_AddRef(c); 1.498 + bestdc = dc; 1.499 + bestCertIsValidAtTime = PR_TRUE; 1.500 + continue; 1.501 + } 1.502 + } 1.503 + /* Either they are both valid at time, or neither valid. 1.504 + * If only one is trusted for this usage, take it. 1.505 + */ 1.506 + if (bestCertIsTrusted || bestdc->isTrustedForUsage(bestdc, usage)) { 1.507 + bestCertIsTrusted = PR_TRUE; 1.508 + if (!dc->isTrustedForUsage(dc, usage)) { 1.509 + continue; 1.510 + } 1.511 + } else { 1.512 + /* The current best cert is not trusted */ 1.513 + if (dc->isTrustedForUsage(dc, usage)) { 1.514 + /* If the new cert is trusted, it's better */ 1.515 + nssCertificate_Destroy(bestCert); 1.516 + bestCert = nssCertificate_AddRef(c); 1.517 + bestdc = dc; 1.518 + bestCertIsTrusted = PR_TRUE; 1.519 + continue; 1.520 + } 1.521 + } 1.522 + /* Otherwise, take the newer one. */ 1.523 + if (!bestdc->isNewerThan(bestdc, dc)) { 1.524 + nssCertificate_Destroy(bestCert); 1.525 + bestCert = nssCertificate_AddRef(c); 1.526 + bestdc = dc; 1.527 + continue; 1.528 + } 1.529 + /* policies */ 1.530 + /* XXX later -- defer to policies */ 1.531 + } 1.532 + return bestCert; 1.533 +} 1.534 + 1.535 +NSS_IMPLEMENT PRStatus 1.536 +nssCertificateArray_Traverse ( 1.537 + NSSCertificate **certs, 1.538 + PRStatus (* callback)(NSSCertificate *c, void *arg), 1.539 + void *arg 1.540 +) 1.541 +{ 1.542 + PRStatus status = PR_SUCCESS; 1.543 + if (certs) { 1.544 + NSSCertificate **certp; 1.545 + for (certp = certs; *certp; certp++) { 1.546 + status = (*callback)(*certp, arg); 1.547 + if (status != PR_SUCCESS) { 1.548 + break; 1.549 + } 1.550 + } 1.551 + } 1.552 + return status; 1.553 +} 1.554 + 1.555 + 1.556 +NSS_IMPLEMENT void 1.557 +nssCRLArray_Destroy ( 1.558 + NSSCRL **crls 1.559 +) 1.560 +{ 1.561 + if (crls) { 1.562 + NSSCRL **crlp; 1.563 + for (crlp = crls; *crlp; crlp++) { 1.564 + nssCRL_Destroy(*crlp); 1.565 + } 1.566 + nss_ZFreeIf(crls); 1.567 + } 1.568 +} 1.569 + 1.570 +/* 1.571 + * Object collections 1.572 + */ 1.573 + 1.574 +typedef enum 1.575 +{ 1.576 + pkiObjectType_Certificate = 0, 1.577 + pkiObjectType_CRL = 1, 1.578 + pkiObjectType_PrivateKey = 2, 1.579 + pkiObjectType_PublicKey = 3 1.580 +} pkiObjectType; 1.581 + 1.582 +/* Each object is defined by a set of items that uniquely identify it. 1.583 + * Here are the uid sets: 1.584 + * 1.585 + * NSSCertificate ==> { issuer, serial } 1.586 + * NSSPrivateKey 1.587 + * (RSA) ==> { modulus, public exponent } 1.588 + * 1.589 + */ 1.590 +#define MAX_ITEMS_FOR_UID 2 1.591 + 1.592 +/* pkiObjectCollectionNode 1.593 + * 1.594 + * A node in the collection is the set of unique identifiers for a single 1.595 + * object, along with either the actual object or a proto-object. 1.596 + */ 1.597 +typedef struct 1.598 +{ 1.599 + PRCList link; 1.600 + PRBool haveObject; 1.601 + nssPKIObject *object; 1.602 + NSSItem uid[MAX_ITEMS_FOR_UID]; 1.603 +} 1.604 +pkiObjectCollectionNode; 1.605 + 1.606 +/* nssPKIObjectCollection 1.607 + * 1.608 + * The collection is the set of all objects, plus the interfaces needed 1.609 + * to manage the objects. 1.610 + * 1.611 + */ 1.612 +struct nssPKIObjectCollectionStr 1.613 +{ 1.614 + NSSArena *arena; 1.615 + NSSTrustDomain *td; 1.616 + NSSCryptoContext *cc; 1.617 + PRCList head; /* list of pkiObjectCollectionNode's */ 1.618 + PRUint32 size; 1.619 + pkiObjectType objectType; 1.620 + void (* destroyObject)(nssPKIObject *o); 1.621 + PRStatus (* getUIDFromObject)(nssPKIObject *o, NSSItem *uid); 1.622 + PRStatus (* getUIDFromInstance)(nssCryptokiObject *co, NSSItem *uid, 1.623 + NSSArena *arena); 1.624 + nssPKIObject * (* createObject)(nssPKIObject *o); 1.625 + nssPKILockType lockType; /* type of lock to use for new proto-objects */ 1.626 +}; 1.627 + 1.628 +static nssPKIObjectCollection * 1.629 +nssPKIObjectCollection_Create ( 1.630 + NSSTrustDomain *td, 1.631 + NSSCryptoContext *ccOpt, 1.632 + nssPKILockType lockType 1.633 +) 1.634 +{ 1.635 + NSSArena *arena; 1.636 + nssPKIObjectCollection *rvCollection = NULL; 1.637 + arena = nssArena_Create(); 1.638 + if (!arena) { 1.639 + return (nssPKIObjectCollection *)NULL; 1.640 + } 1.641 + rvCollection = nss_ZNEW(arena, nssPKIObjectCollection); 1.642 + if (!rvCollection) { 1.643 + goto loser; 1.644 + } 1.645 + PR_INIT_CLIST(&rvCollection->head); 1.646 + rvCollection->arena = arena; 1.647 + rvCollection->td = td; /* XXX */ 1.648 + rvCollection->cc = ccOpt; 1.649 + rvCollection->lockType = lockType; 1.650 + return rvCollection; 1.651 +loser: 1.652 + nssArena_Destroy(arena); 1.653 + return (nssPKIObjectCollection *)NULL; 1.654 +} 1.655 + 1.656 +NSS_IMPLEMENT void 1.657 +nssPKIObjectCollection_Destroy ( 1.658 + nssPKIObjectCollection *collection 1.659 +) 1.660 +{ 1.661 + if (collection) { 1.662 + PRCList *link; 1.663 + pkiObjectCollectionNode *node; 1.664 + /* first destroy any objects in the collection */ 1.665 + link = PR_NEXT_LINK(&collection->head); 1.666 + while (link != &collection->head) { 1.667 + node = (pkiObjectCollectionNode *)link; 1.668 + if (node->haveObject) { 1.669 + (*collection->destroyObject)(node->object); 1.670 + } else { 1.671 + nssPKIObject_Destroy(node->object); 1.672 + } 1.673 + link = PR_NEXT_LINK(link); 1.674 + } 1.675 + /* then destroy it */ 1.676 + nssArena_Destroy(collection->arena); 1.677 + } 1.678 +} 1.679 + 1.680 +NSS_IMPLEMENT PRUint32 1.681 +nssPKIObjectCollection_Count ( 1.682 + nssPKIObjectCollection *collection 1.683 +) 1.684 +{ 1.685 + return collection->size; 1.686 +} 1.687 + 1.688 +NSS_IMPLEMENT PRStatus 1.689 +nssPKIObjectCollection_AddObject ( 1.690 + nssPKIObjectCollection *collection, 1.691 + nssPKIObject *object 1.692 +) 1.693 +{ 1.694 + pkiObjectCollectionNode *node; 1.695 + node = nss_ZNEW(collection->arena, pkiObjectCollectionNode); 1.696 + if (!node) { 1.697 + return PR_FAILURE; 1.698 + } 1.699 + node->haveObject = PR_TRUE; 1.700 + node->object = nssPKIObject_AddRef(object); 1.701 + (*collection->getUIDFromObject)(object, node->uid); 1.702 + PR_INIT_CLIST(&node->link); 1.703 + PR_INSERT_BEFORE(&node->link, &collection->head); 1.704 + collection->size++; 1.705 + return PR_SUCCESS; 1.706 +} 1.707 + 1.708 +static pkiObjectCollectionNode * 1.709 +find_instance_in_collection ( 1.710 + nssPKIObjectCollection *collection, 1.711 + nssCryptokiObject *instance 1.712 +) 1.713 +{ 1.714 + PRCList *link; 1.715 + pkiObjectCollectionNode *node; 1.716 + link = PR_NEXT_LINK(&collection->head); 1.717 + while (link != &collection->head) { 1.718 + node = (pkiObjectCollectionNode *)link; 1.719 + if (nssPKIObject_HasInstance(node->object, instance)) { 1.720 + return node; 1.721 + } 1.722 + link = PR_NEXT_LINK(link); 1.723 + } 1.724 + return (pkiObjectCollectionNode *)NULL; 1.725 +} 1.726 + 1.727 +static pkiObjectCollectionNode * 1.728 +find_object_in_collection ( 1.729 + nssPKIObjectCollection *collection, 1.730 + NSSItem *uid 1.731 +) 1.732 +{ 1.733 + PRUint32 i; 1.734 + PRStatus status; 1.735 + PRCList *link; 1.736 + pkiObjectCollectionNode *node; 1.737 + link = PR_NEXT_LINK(&collection->head); 1.738 + while (link != &collection->head) { 1.739 + node = (pkiObjectCollectionNode *)link; 1.740 + for (i=0; i<MAX_ITEMS_FOR_UID; i++) { 1.741 + if (!nssItem_Equal(&node->uid[i], &uid[i], &status)) { 1.742 + break; 1.743 + } 1.744 + } 1.745 + if (i == MAX_ITEMS_FOR_UID) { 1.746 + return node; 1.747 + } 1.748 + link = PR_NEXT_LINK(link); 1.749 + } 1.750 + return (pkiObjectCollectionNode *)NULL; 1.751 +} 1.752 + 1.753 +static pkiObjectCollectionNode * 1.754 +add_object_instance ( 1.755 + nssPKIObjectCollection *collection, 1.756 + nssCryptokiObject *instance, 1.757 + PRBool *foundIt 1.758 +) 1.759 +{ 1.760 + PRUint32 i; 1.761 + PRStatus status; 1.762 + pkiObjectCollectionNode *node; 1.763 + nssArenaMark *mark = NULL; 1.764 + NSSItem uid[MAX_ITEMS_FOR_UID]; 1.765 + nsslibc_memset(uid, 0, sizeof uid); 1.766 + /* The list is traversed twice, first (here) looking to match the 1.767 + * { token, handle } tuple, and if that is not found, below a search 1.768 + * for unique identifier is done. Here, a match means this exact object 1.769 + * instance is already in the collection, and we have nothing to do. 1.770 + */ 1.771 + *foundIt = PR_FALSE; 1.772 + node = find_instance_in_collection(collection, instance); 1.773 + if (node) { 1.774 + /* The collection is assumed to take over the instance. Since we 1.775 + * are not using it, it must be destroyed. 1.776 + */ 1.777 + nssCryptokiObject_Destroy(instance); 1.778 + *foundIt = PR_TRUE; 1.779 + return node; 1.780 + } 1.781 + mark = nssArena_Mark(collection->arena); 1.782 + if (!mark) { 1.783 + goto loser; 1.784 + } 1.785 + status = (*collection->getUIDFromInstance)(instance, uid, 1.786 + collection->arena); 1.787 + if (status != PR_SUCCESS) { 1.788 + goto loser; 1.789 + } 1.790 + /* Search for unique identifier. A match here means the object exists 1.791 + * in the collection, but does not have this instance, so the instance 1.792 + * needs to be added. 1.793 + */ 1.794 + node = find_object_in_collection(collection, uid); 1.795 + if (node) { 1.796 + /* This is an object with multiple instances */ 1.797 + status = nssPKIObject_AddInstance(node->object, instance); 1.798 + } else { 1.799 + /* This is a completely new object. Create a node for it. */ 1.800 + node = nss_ZNEW(collection->arena, pkiObjectCollectionNode); 1.801 + if (!node) { 1.802 + goto loser; 1.803 + } 1.804 + node->object = nssPKIObject_Create(NULL, instance, 1.805 + collection->td, collection->cc, 1.806 + collection->lockType); 1.807 + if (!node->object) { 1.808 + goto loser; 1.809 + } 1.810 + for (i=0; i<MAX_ITEMS_FOR_UID; i++) { 1.811 + node->uid[i] = uid[i]; 1.812 + } 1.813 + node->haveObject = PR_FALSE; 1.814 + PR_INIT_CLIST(&node->link); 1.815 + PR_INSERT_BEFORE(&node->link, &collection->head); 1.816 + collection->size++; 1.817 + status = PR_SUCCESS; 1.818 + } 1.819 + nssArena_Unmark(collection->arena, mark); 1.820 + return node; 1.821 +loser: 1.822 + if (mark) { 1.823 + nssArena_Release(collection->arena, mark); 1.824 + } 1.825 + nssCryptokiObject_Destroy(instance); 1.826 + return (pkiObjectCollectionNode *)NULL; 1.827 +} 1.828 + 1.829 +NSS_IMPLEMENT PRStatus 1.830 +nssPKIObjectCollection_AddInstances ( 1.831 + nssPKIObjectCollection *collection, 1.832 + nssCryptokiObject **instances, 1.833 + PRUint32 numInstances 1.834 +) 1.835 +{ 1.836 + PRStatus status = PR_SUCCESS; 1.837 + PRUint32 i = 0; 1.838 + PRBool foundIt; 1.839 + pkiObjectCollectionNode *node; 1.840 + if (instances) { 1.841 + while ((!numInstances || i < numInstances) && *instances) { 1.842 + if (status == PR_SUCCESS) { 1.843 + node = add_object_instance(collection, *instances, &foundIt); 1.844 + if (node == NULL) { 1.845 + /* add_object_instance freed the current instance */ 1.846 + /* free the remaining instances */ 1.847 + status = PR_FAILURE; 1.848 + } 1.849 + } else { 1.850 + nssCryptokiObject_Destroy(*instances); 1.851 + } 1.852 + instances++; 1.853 + i++; 1.854 + } 1.855 + } 1.856 + return status; 1.857 +} 1.858 + 1.859 +static void 1.860 +nssPKIObjectCollection_RemoveNode ( 1.861 + nssPKIObjectCollection *collection, 1.862 + pkiObjectCollectionNode *node 1.863 +) 1.864 +{ 1.865 + PR_REMOVE_LINK(&node->link); 1.866 + collection->size--; 1.867 +} 1.868 + 1.869 +static PRStatus 1.870 +nssPKIObjectCollection_GetObjects ( 1.871 + nssPKIObjectCollection *collection, 1.872 + nssPKIObject **rvObjects, 1.873 + PRUint32 rvSize 1.874 +) 1.875 +{ 1.876 + PRUint32 i = 0; 1.877 + PRCList *link = PR_NEXT_LINK(&collection->head); 1.878 + pkiObjectCollectionNode *node; 1.879 + int error=0; 1.880 + while ((i < rvSize) && (link != &collection->head)) { 1.881 + node = (pkiObjectCollectionNode *)link; 1.882 + if (!node->haveObject) { 1.883 + /* Convert the proto-object to an object */ 1.884 + node->object = (*collection->createObject)(node->object); 1.885 + if (!node->object) { 1.886 + link = PR_NEXT_LINK(link); 1.887 + /*remove bogus object from list*/ 1.888 + nssPKIObjectCollection_RemoveNode(collection,node); 1.889 + error++; 1.890 + continue; 1.891 + } 1.892 + node->haveObject = PR_TRUE; 1.893 + } 1.894 + rvObjects[i++] = nssPKIObject_AddRef(node->object); 1.895 + link = PR_NEXT_LINK(link); 1.896 + } 1.897 + if (!error && *rvObjects == NULL) { 1.898 + nss_SetError(NSS_ERROR_NOT_FOUND); 1.899 + } 1.900 + return PR_SUCCESS; 1.901 +} 1.902 + 1.903 +NSS_IMPLEMENT PRStatus 1.904 +nssPKIObjectCollection_Traverse ( 1.905 + nssPKIObjectCollection *collection, 1.906 + nssPKIObjectCallback *callback 1.907 +) 1.908 +{ 1.909 + PRStatus status; 1.910 + PRCList *link = PR_NEXT_LINK(&collection->head); 1.911 + pkiObjectCollectionNode *node; 1.912 + while (link != &collection->head) { 1.913 + node = (pkiObjectCollectionNode *)link; 1.914 + if (!node->haveObject) { 1.915 + node->object = (*collection->createObject)(node->object); 1.916 + if (!node->object) { 1.917 + link = PR_NEXT_LINK(link); 1.918 + /*remove bogus object from list*/ 1.919 + nssPKIObjectCollection_RemoveNode(collection,node); 1.920 + continue; 1.921 + } 1.922 + node->haveObject = PR_TRUE; 1.923 + } 1.924 + switch (collection->objectType) { 1.925 + case pkiObjectType_Certificate: 1.926 + status = (*callback->func.cert)((NSSCertificate *)node->object, 1.927 + callback->arg); 1.928 + break; 1.929 + case pkiObjectType_CRL: 1.930 + status = (*callback->func.crl)((NSSCRL *)node->object, 1.931 + callback->arg); 1.932 + break; 1.933 + case pkiObjectType_PrivateKey: 1.934 + status = (*callback->func.pvkey)((NSSPrivateKey *)node->object, 1.935 + callback->arg); 1.936 + break; 1.937 + case pkiObjectType_PublicKey: 1.938 + status = (*callback->func.pbkey)((NSSPublicKey *)node->object, 1.939 + callback->arg); 1.940 + break; 1.941 + } 1.942 + link = PR_NEXT_LINK(link); 1.943 + } 1.944 + return PR_SUCCESS; 1.945 +} 1.946 + 1.947 +NSS_IMPLEMENT PRStatus 1.948 +nssPKIObjectCollection_AddInstanceAsObject ( 1.949 + nssPKIObjectCollection *collection, 1.950 + nssCryptokiObject *instance 1.951 +) 1.952 +{ 1.953 + pkiObjectCollectionNode *node; 1.954 + PRBool foundIt; 1.955 + node = add_object_instance(collection, instance, &foundIt); 1.956 + if (node == NULL) { 1.957 + return PR_FAILURE; 1.958 + } 1.959 + if (!node->haveObject) { 1.960 + node->object = (*collection->createObject)(node->object); 1.961 + if (!node->object) { 1.962 + /*remove bogus object from list*/ 1.963 + nssPKIObjectCollection_RemoveNode(collection,node); 1.964 + return PR_FAILURE; 1.965 + } 1.966 + node->haveObject = PR_TRUE; 1.967 + } else if (!foundIt) { 1.968 + /* The instance was added to a pre-existing node. This 1.969 + * function is *only* being used for certificates, and having 1.970 + * multiple instances of certs in 3.X requires updating the 1.971 + * CERTCertificate. 1.972 + * But only do it if it was a new instance!!! If the same instance 1.973 + * is encountered, we set *foundIt to true. Detect that here and 1.974 + * ignore it. 1.975 + */ 1.976 + STAN_ForceCERTCertificateUpdate((NSSCertificate *)node->object); 1.977 + } 1.978 + return PR_SUCCESS; 1.979 +} 1.980 + 1.981 +/* 1.982 + * Certificate collections 1.983 + */ 1.984 + 1.985 +static void 1.986 +cert_destroyObject(nssPKIObject *o) 1.987 +{ 1.988 + NSSCertificate *c = (NSSCertificate *)o; 1.989 + if (c->decoding) { 1.990 + CERTCertificate *cc = STAN_GetCERTCertificate(c); 1.991 + if (cc) { 1.992 + CERT_DestroyCertificate(cc); 1.993 + return; 1.994 + } /* else destroy it as NSSCertificate below */ 1.995 + } 1.996 + nssCertificate_Destroy(c); 1.997 +} 1.998 + 1.999 +static PRStatus 1.1000 +cert_getUIDFromObject(nssPKIObject *o, NSSItem *uid) 1.1001 +{ 1.1002 + NSSCertificate *c = (NSSCertificate *)o; 1.1003 + /* The builtins are still returning decoded serial numbers. Until 1.1004 + * this compatibility issue is resolved, use the full DER of the 1.1005 + * cert to uniquely identify it. 1.1006 + */ 1.1007 + NSSDER *derCert; 1.1008 + derCert = nssCertificate_GetEncoding(c); 1.1009 + uid[0].data = NULL; uid[0].size = 0; 1.1010 + uid[1].data = NULL; uid[1].size = 0; 1.1011 + if (derCert != NULL) { 1.1012 + uid[0] = *derCert; 1.1013 + } 1.1014 + return PR_SUCCESS; 1.1015 +} 1.1016 + 1.1017 +static PRStatus 1.1018 +cert_getUIDFromInstance(nssCryptokiObject *instance, NSSItem *uid, 1.1019 + NSSArena *arena) 1.1020 +{ 1.1021 + /* The builtins are still returning decoded serial numbers. Until 1.1022 + * this compatibility issue is resolved, use the full DER of the 1.1023 + * cert to uniquely identify it. 1.1024 + */ 1.1025 + uid[1].data = NULL; uid[1].size = 0; 1.1026 + return nssCryptokiCertificate_GetAttributes(instance, 1.1027 + NULL, /* XXX sessionOpt */ 1.1028 + arena, /* arena */ 1.1029 + NULL, /* type */ 1.1030 + NULL, /* id */ 1.1031 + &uid[0], /* encoding */ 1.1032 + NULL, /* issuer */ 1.1033 + NULL, /* serial */ 1.1034 + NULL); /* subject */ 1.1035 +} 1.1036 + 1.1037 +static nssPKIObject * 1.1038 +cert_createObject(nssPKIObject *o) 1.1039 +{ 1.1040 + NSSCertificate *cert; 1.1041 + cert = nssCertificate_Create(o); 1.1042 +/* if (STAN_GetCERTCertificate(cert) == NULL) { 1.1043 + nssCertificate_Destroy(cert); 1.1044 + return (nssPKIObject *)NULL; 1.1045 + } */ 1.1046 + /* In 3.4, have to maintain uniqueness of cert pointers by caching all 1.1047 + * certs. Cache the cert here, before returning. If it is already 1.1048 + * cached, take the cached entry. 1.1049 + */ 1.1050 + { 1.1051 + NSSTrustDomain *td = o->trustDomain; 1.1052 + nssTrustDomain_AddCertsToCache(td, &cert, 1); 1.1053 + } 1.1054 + return (nssPKIObject *)cert; 1.1055 +} 1.1056 + 1.1057 +NSS_IMPLEMENT nssPKIObjectCollection * 1.1058 +nssCertificateCollection_Create ( 1.1059 + NSSTrustDomain *td, 1.1060 + NSSCertificate **certsOpt 1.1061 +) 1.1062 +{ 1.1063 + PRStatus status; 1.1064 + nssPKIObjectCollection *collection; 1.1065 + collection = nssPKIObjectCollection_Create(td, NULL, nssPKIMonitor); 1.1066 + collection->objectType = pkiObjectType_Certificate; 1.1067 + collection->destroyObject = cert_destroyObject; 1.1068 + collection->getUIDFromObject = cert_getUIDFromObject; 1.1069 + collection->getUIDFromInstance = cert_getUIDFromInstance; 1.1070 + collection->createObject = cert_createObject; 1.1071 + if (certsOpt) { 1.1072 + for (; *certsOpt; certsOpt++) { 1.1073 + nssPKIObject *object = (nssPKIObject *)(*certsOpt); 1.1074 + status = nssPKIObjectCollection_AddObject(collection, object); 1.1075 + } 1.1076 + } 1.1077 + return collection; 1.1078 +} 1.1079 + 1.1080 +NSS_IMPLEMENT NSSCertificate ** 1.1081 +nssPKIObjectCollection_GetCertificates ( 1.1082 + nssPKIObjectCollection *collection, 1.1083 + NSSCertificate **rvOpt, 1.1084 + PRUint32 maximumOpt, 1.1085 + NSSArena *arenaOpt 1.1086 +) 1.1087 +{ 1.1088 + PRStatus status; 1.1089 + PRUint32 rvSize; 1.1090 + PRBool allocated = PR_FALSE; 1.1091 + if (collection->size == 0) { 1.1092 + return (NSSCertificate **)NULL; 1.1093 + } 1.1094 + if (maximumOpt == 0) { 1.1095 + rvSize = collection->size; 1.1096 + } else { 1.1097 + rvSize = PR_MIN(collection->size, maximumOpt); 1.1098 + } 1.1099 + if (!rvOpt) { 1.1100 + rvOpt = nss_ZNEWARRAY(arenaOpt, NSSCertificate *, rvSize + 1); 1.1101 + if (!rvOpt) { 1.1102 + return (NSSCertificate **)NULL; 1.1103 + } 1.1104 + allocated = PR_TRUE; 1.1105 + } 1.1106 + status = nssPKIObjectCollection_GetObjects(collection, 1.1107 + (nssPKIObject **)rvOpt, 1.1108 + rvSize); 1.1109 + if (status != PR_SUCCESS) { 1.1110 + if (allocated) { 1.1111 + nss_ZFreeIf(rvOpt); 1.1112 + } 1.1113 + return (NSSCertificate **)NULL; 1.1114 + } 1.1115 + return rvOpt; 1.1116 +} 1.1117 + 1.1118 +/* 1.1119 + * CRL/KRL collections 1.1120 + */ 1.1121 + 1.1122 +static void 1.1123 +crl_destroyObject(nssPKIObject *o) 1.1124 +{ 1.1125 + NSSCRL *crl = (NSSCRL *)o; 1.1126 + nssCRL_Destroy(crl); 1.1127 +} 1.1128 + 1.1129 +static PRStatus 1.1130 +crl_getUIDFromObject(nssPKIObject *o, NSSItem *uid) 1.1131 +{ 1.1132 + NSSCRL *crl = (NSSCRL *)o; 1.1133 + NSSDER *encoding; 1.1134 + encoding = nssCRL_GetEncoding(crl); 1.1135 + if (!encoding) { 1.1136 + nss_SetError(NSS_ERROR_INVALID_ARGUMENT); 1.1137 + return PR_FALSE; 1.1138 + } 1.1139 + uid[0] = *encoding; 1.1140 + uid[1].data = NULL; uid[1].size = 0; 1.1141 + return PR_SUCCESS; 1.1142 +} 1.1143 + 1.1144 +static PRStatus 1.1145 +crl_getUIDFromInstance(nssCryptokiObject *instance, NSSItem *uid, 1.1146 + NSSArena *arena) 1.1147 +{ 1.1148 + return nssCryptokiCRL_GetAttributes(instance, 1.1149 + NULL, /* XXX sessionOpt */ 1.1150 + arena, /* arena */ 1.1151 + &uid[0], /* encoding */ 1.1152 + NULL, /* subject */ 1.1153 + NULL, /* class */ 1.1154 + NULL, /* url */ 1.1155 + NULL); /* isKRL */ 1.1156 +} 1.1157 + 1.1158 +static nssPKIObject * 1.1159 +crl_createObject(nssPKIObject *o) 1.1160 +{ 1.1161 + return (nssPKIObject *)nssCRL_Create(o); 1.1162 +} 1.1163 + 1.1164 +NSS_IMPLEMENT nssPKIObjectCollection * 1.1165 +nssCRLCollection_Create ( 1.1166 + NSSTrustDomain *td, 1.1167 + NSSCRL **crlsOpt 1.1168 +) 1.1169 +{ 1.1170 + PRStatus status; 1.1171 + nssPKIObjectCollection *collection; 1.1172 + collection = nssPKIObjectCollection_Create(td, NULL, nssPKILock); 1.1173 + collection->objectType = pkiObjectType_CRL; 1.1174 + collection->destroyObject = crl_destroyObject; 1.1175 + collection->getUIDFromObject = crl_getUIDFromObject; 1.1176 + collection->getUIDFromInstance = crl_getUIDFromInstance; 1.1177 + collection->createObject = crl_createObject; 1.1178 + if (crlsOpt) { 1.1179 + for (; *crlsOpt; crlsOpt++) { 1.1180 + nssPKIObject *object = (nssPKIObject *)(*crlsOpt); 1.1181 + status = nssPKIObjectCollection_AddObject(collection, object); 1.1182 + } 1.1183 + } 1.1184 + return collection; 1.1185 +} 1.1186 + 1.1187 +NSS_IMPLEMENT NSSCRL ** 1.1188 +nssPKIObjectCollection_GetCRLs ( 1.1189 + nssPKIObjectCollection *collection, 1.1190 + NSSCRL **rvOpt, 1.1191 + PRUint32 maximumOpt, 1.1192 + NSSArena *arenaOpt 1.1193 +) 1.1194 +{ 1.1195 + PRStatus status; 1.1196 + PRUint32 rvSize; 1.1197 + PRBool allocated = PR_FALSE; 1.1198 + if (collection->size == 0) { 1.1199 + return (NSSCRL **)NULL; 1.1200 + } 1.1201 + if (maximumOpt == 0) { 1.1202 + rvSize = collection->size; 1.1203 + } else { 1.1204 + rvSize = PR_MIN(collection->size, maximumOpt); 1.1205 + } 1.1206 + if (!rvOpt) { 1.1207 + rvOpt = nss_ZNEWARRAY(arenaOpt, NSSCRL *, rvSize + 1); 1.1208 + if (!rvOpt) { 1.1209 + return (NSSCRL **)NULL; 1.1210 + } 1.1211 + allocated = PR_TRUE; 1.1212 + } 1.1213 + status = nssPKIObjectCollection_GetObjects(collection, 1.1214 + (nssPKIObject **)rvOpt, 1.1215 + rvSize); 1.1216 + if (status != PR_SUCCESS) { 1.1217 + if (allocated) { 1.1218 + nss_ZFreeIf(rvOpt); 1.1219 + } 1.1220 + return (NSSCRL **)NULL; 1.1221 + } 1.1222 + return rvOpt; 1.1223 +} 1.1224 + 1.1225 +/* how bad would it be to have a static now sitting around, updated whenever 1.1226 + * this was called? would avoid repeated allocs... 1.1227 + */ 1.1228 +NSS_IMPLEMENT NSSTime * 1.1229 +NSSTime_Now ( 1.1230 + NSSTime *timeOpt 1.1231 +) 1.1232 +{ 1.1233 + return NSSTime_SetPRTime(timeOpt, PR_Now()); 1.1234 +} 1.1235 + 1.1236 +NSS_IMPLEMENT NSSTime * 1.1237 +NSSTime_SetPRTime ( 1.1238 + NSSTime *timeOpt, 1.1239 + PRTime prTime 1.1240 +) 1.1241 +{ 1.1242 + NSSTime *rvTime; 1.1243 + rvTime = (timeOpt) ? timeOpt : nss_ZNEW(NULL, NSSTime); 1.1244 + if (rvTime) { 1.1245 + rvTime->prTime = prTime; 1.1246 + } 1.1247 + return rvTime; 1.1248 +} 1.1249 + 1.1250 +NSS_IMPLEMENT PRTime 1.1251 +NSSTime_GetPRTime ( 1.1252 + NSSTime *time 1.1253 +) 1.1254 +{ 1.1255 + return time->prTime; 1.1256 +} 1.1257 +