security/nss/lib/pki/pkibase.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial