security/nss/lib/pki/pkibase.c

changeset 0
6474c204b198
     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 +

mercurial