crmfreq.c (19271B)
1 /* -*- Mode: C; tab-width: 8 -*-*/ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 #include "crmf.h" 7 #include "crmfi.h" 8 #include "keyhi.h" 9 #include "secder.h" 10 11 /* 12 * Macro that returns PR_TRUE if the pointer is not NULL. 13 * If the pointer is NULL, then the macro will return PR_FALSE. 14 */ 15 #define IS_NOT_NULL(ptr) ((ptr) == NULL) ? PR_FALSE : PR_TRUE 16 17 const unsigned char hexTrue = 0xff; 18 const unsigned char hexFalse = 0x00; 19 20 SECStatus 21 crmf_encode_integer(PLArenaPool *poolp, SECItem *dest, long value) 22 { 23 SECItem *dummy; 24 25 dummy = SEC_ASN1EncodeInteger(poolp, dest, value); 26 PORT_Assert(dummy == dest); 27 if (dummy == NULL) { 28 return SECFailure; 29 } 30 return SECSuccess; 31 } 32 33 SECStatus 34 crmf_encode_unsigned_integer(PLArenaPool *poolp, SECItem *dest, 35 unsigned long value) 36 { 37 SECItem *dummy; 38 39 dummy = SEC_ASN1EncodeUnsignedInteger(poolp, dest, value); 40 PORT_Assert(dummy == dest); 41 if (dummy != dest) { 42 return SECFailure; 43 } 44 return SECSuccess; 45 } 46 47 static SECStatus 48 crmf_copy_secitem(PLArenaPool *poolp, SECItem *dest, SECItem *src) 49 { 50 return SECITEM_CopyItem(poolp, dest, src); 51 } 52 53 PRBool 54 CRMF_DoesRequestHaveField(CRMFCertRequest *inCertReq, 55 CRMFCertTemplateField inField) 56 { 57 58 PORT_Assert(inCertReq != NULL); 59 if (inCertReq == NULL) { 60 return PR_FALSE; 61 } 62 switch (inField) { 63 case crmfVersion: 64 return inCertReq->certTemplate.version.data != NULL; 65 case crmfSerialNumber: 66 return inCertReq->certTemplate.serialNumber.data != NULL; 67 case crmfSigningAlg: 68 return inCertReq->certTemplate.signingAlg != NULL; 69 case crmfIssuer: 70 return inCertReq->certTemplate.issuer != NULL; 71 case crmfValidity: 72 return inCertReq->certTemplate.validity != NULL; 73 case crmfSubject: 74 return inCertReq->certTemplate.subject != NULL; 75 case crmfPublicKey: 76 return inCertReq->certTemplate.publicKey != NULL; 77 case crmfIssuerUID: 78 return inCertReq->certTemplate.issuerUID.data != NULL; 79 case crmfSubjectUID: 80 return inCertReq->certTemplate.subjectUID.data != NULL; 81 case crmfExtension: 82 return CRMF_CertRequestGetNumberOfExtensions(inCertReq) != 0; 83 } 84 return PR_FALSE; 85 } 86 87 CRMFCertRequest * 88 CRMF_CreateCertRequest(PRUint32 inRequestID) 89 { 90 PLArenaPool *poolp; 91 CRMFCertRequest *certReq; 92 SECStatus rv; 93 94 poolp = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE); 95 if (poolp == NULL) { 96 goto loser; 97 } 98 99 certReq = PORT_ArenaZNew(poolp, CRMFCertRequest); 100 if (certReq == NULL) { 101 goto loser; 102 } 103 104 certReq->poolp = poolp; 105 certReq->requestID = inRequestID; 106 107 rv = crmf_encode_unsigned_integer(poolp, &(certReq->certReqId), 108 inRequestID); 109 if (rv != SECSuccess) { 110 goto loser; 111 } 112 113 return certReq; 114 loser: 115 if (poolp) { 116 PORT_FreeArena(poolp, PR_FALSE); 117 } 118 return NULL; 119 } 120 121 SECStatus 122 CRMF_DestroyCertRequest(CRMFCertRequest *inCertReq) 123 { 124 PORT_Assert(inCertReq != NULL); 125 if (inCertReq != NULL) { 126 if (inCertReq->certTemplate.extensions) { 127 PORT_Free(inCertReq->certTemplate.extensions); 128 } 129 if (inCertReq->controls) { 130 /* Right now we don't support EnveloppedData option, 131 * so we won't go through and delete each occurrence of 132 * an EnveloppedData in the control. 133 */ 134 PORT_Free(inCertReq->controls); 135 } 136 if (inCertReq->poolp) { 137 PORT_FreeArena(inCertReq->poolp, PR_TRUE); 138 } 139 } 140 return SECSuccess; 141 } 142 143 static SECStatus 144 crmf_template_add_version(PLArenaPool *poolp, SECItem *dest, long version) 145 { 146 return (crmf_encode_integer(poolp, dest, version)); 147 } 148 149 static SECStatus 150 crmf_template_add_serialnumber(PLArenaPool *poolp, SECItem *dest, long serial) 151 { 152 return (crmf_encode_integer(poolp, dest, serial)); 153 } 154 155 SECStatus 156 crmf_template_copy_secalg(PLArenaPool *poolp, SECAlgorithmID **dest, 157 SECAlgorithmID *src) 158 { 159 SECStatus rv; 160 void *mark = NULL; 161 SECAlgorithmID *mySecAlg; 162 163 if (!poolp) { 164 PORT_SetError(SEC_ERROR_INVALID_ARGS); 165 return SECFailure; 166 } 167 168 mark = PORT_ArenaMark(poolp); 169 *dest = mySecAlg = PORT_ArenaZNew(poolp, SECAlgorithmID); 170 if (mySecAlg == NULL) { 171 goto loser; 172 } 173 rv = SECOID_CopyAlgorithmID(poolp, mySecAlg, src); 174 if (rv != SECSuccess) { 175 goto loser; 176 } 177 if (mark) { 178 PORT_ArenaUnmark(poolp, mark); 179 } 180 return SECSuccess; 181 182 loser: 183 *dest = NULL; 184 if (mark) { 185 PORT_ArenaRelease(poolp, mark); 186 } 187 return SECFailure; 188 } 189 190 SECStatus 191 crmf_copy_cert_name(PLArenaPool *poolp, CERTName **dest, 192 CERTName *src) 193 { 194 CERTName *newName; 195 SECStatus rv; 196 void *mark; 197 198 mark = PORT_ArenaMark(poolp); 199 *dest = newName = PORT_ArenaZNew(poolp, CERTName); 200 if (newName == NULL) { 201 goto loser; 202 } 203 204 rv = CERT_CopyName(poolp, newName, src); 205 if (rv != SECSuccess) { 206 goto loser; 207 } 208 PORT_ArenaUnmark(poolp, mark); 209 return SECSuccess; 210 loser: 211 PORT_ArenaRelease(poolp, mark); 212 *dest = NULL; 213 return SECFailure; 214 } 215 216 static SECStatus 217 crmf_template_add_issuer(PLArenaPool *poolp, CERTName **dest, 218 CERTName *issuerName) 219 { 220 return crmf_copy_cert_name(poolp, dest, issuerName); 221 } 222 223 static SECStatus 224 crmf_template_add_validity(PLArenaPool *poolp, CRMFOptionalValidity **dest, 225 CRMFValidityCreationInfo *info) 226 { 227 SECStatus rv; 228 void *mark; 229 CRMFOptionalValidity *myValidity; 230 231 /*First off, let's make sure at least one of the two fields is present*/ 232 if (!info || (!info->notBefore && !info->notAfter)) { 233 return SECFailure; 234 } 235 mark = PORT_ArenaMark(poolp); 236 *dest = myValidity = PORT_ArenaZNew(poolp, CRMFOptionalValidity); 237 if (myValidity == NULL) { 238 goto loser; 239 } 240 241 if (info->notBefore) { 242 rv = DER_EncodeTimeChoice(poolp, &myValidity->notBefore, 243 *info->notBefore); 244 if (rv != SECSuccess) { 245 goto loser; 246 } 247 } 248 if (info->notAfter) { 249 rv = DER_EncodeTimeChoice(poolp, &myValidity->notAfter, 250 *info->notAfter); 251 if (rv != SECSuccess) { 252 goto loser; 253 } 254 } 255 PORT_ArenaUnmark(poolp, mark); 256 return SECSuccess; 257 loser: 258 PORT_ArenaRelease(poolp, mark); 259 *dest = NULL; 260 return SECFailure; 261 } 262 263 static SECStatus 264 crmf_template_add_subject(PLArenaPool *poolp, CERTName **dest, 265 CERTName *subject) 266 { 267 return crmf_copy_cert_name(poolp, dest, subject); 268 } 269 270 SECStatus 271 crmf_template_add_public_key(PLArenaPool *poolp, 272 CERTSubjectPublicKeyInfo **dest, 273 CERTSubjectPublicKeyInfo *pubKey) 274 { 275 CERTSubjectPublicKeyInfo *spki; 276 SECStatus rv; 277 278 *dest = spki = (poolp == NULL) ? PORT_ZNew(CERTSubjectPublicKeyInfo) : PORT_ArenaZNew(poolp, CERTSubjectPublicKeyInfo); 279 if (spki == NULL) { 280 goto loser; 281 } 282 rv = SECKEY_CopySubjectPublicKeyInfo(poolp, spki, pubKey); 283 if (rv != SECSuccess) { 284 goto loser; 285 } 286 return SECSuccess; 287 loser: 288 if (poolp == NULL && spki != NULL) { 289 SECKEY_DestroySubjectPublicKeyInfo(spki); 290 } 291 *dest = NULL; 292 return SECFailure; 293 } 294 295 static SECStatus 296 crmf_copy_bitstring(PLArenaPool *poolp, SECItem *dest, const SECItem *src) 297 { 298 SECStatus rv; 299 SECItem byteSrc; 300 301 byteSrc = *src; 302 byteSrc.len = CRMF_BITS_TO_BYTES(byteSrc.len); 303 rv = crmf_copy_secitem(poolp, dest, &byteSrc); 304 dest->len = src->len; 305 return rv; 306 } 307 308 static SECStatus 309 crmf_template_add_issuer_uid(PLArenaPool *poolp, SECItem *dest, 310 const SECItem *issuerUID) 311 { 312 return crmf_copy_bitstring(poolp, dest, issuerUID); 313 } 314 315 static SECStatus 316 crmf_template_add_subject_uid(PLArenaPool *poolp, SECItem *dest, 317 const SECItem *subjectUID) 318 { 319 return crmf_copy_bitstring(poolp, dest, subjectUID); 320 } 321 322 static void 323 crmf_zeroize_new_extensions(CRMFCertExtension **extensions, 324 int numToZeroize) 325 { 326 PORT_Memset((void *)extensions, 0, sizeof(CERTCertExtension *) * numToZeroize); 327 } 328 329 /* 330 * The strategy for adding templates will differ from all the other 331 * attributes in the template. First, we want to allow the client 332 * of this API to set extensions more than just once. So we will 333 * need the ability grow the array of extensions. Since arenas don't 334 * give us the realloc function, we'll use the generic PORT_* functions 335 * to allocate the array of pointers *ONLY*. Then we will allocate each 336 * individual extension from the arena that comes along with the certReq 337 * structure that owns this template. 338 */ 339 static SECStatus 340 crmf_template_add_extensions(PLArenaPool *poolp, CRMFCertTemplate *inTemplate, 341 CRMFCertExtCreationInfo *extensions) 342 { 343 void *mark; 344 int newSize, oldSize, i; 345 SECStatus rv; 346 CRMFCertExtension **extArray; 347 CRMFCertExtension *newExt, *currExt; 348 349 mark = PORT_ArenaMark(poolp); 350 if (inTemplate->extensions == NULL) { 351 newSize = extensions->numExtensions; 352 extArray = PORT_ZNewArray(CRMFCertExtension *, newSize + 1); 353 } else { 354 newSize = inTemplate->numExtensions + extensions->numExtensions; 355 extArray = PORT_Realloc(inTemplate->extensions, 356 sizeof(CRMFCertExtension *) * (newSize + 1)); 357 } 358 if (extArray == NULL) { 359 goto loser; 360 } 361 oldSize = inTemplate->numExtensions; 362 inTemplate->extensions = extArray; 363 inTemplate->numExtensions = newSize; 364 for (i = oldSize; i < newSize; i++) { 365 newExt = PORT_ArenaZNew(poolp, CRMFCertExtension); 366 if (newExt == NULL) { 367 goto loser2; 368 } 369 currExt = extensions->extensions[i - oldSize]; 370 rv = crmf_copy_secitem(poolp, &(newExt->id), &(currExt->id)); 371 if (rv != SECSuccess) { 372 goto loser2; 373 } 374 rv = crmf_copy_secitem(poolp, &(newExt->critical), 375 &(currExt->critical)); 376 if (rv != SECSuccess) { 377 goto loser2; 378 } 379 rv = crmf_copy_secitem(poolp, &(newExt->value), &(currExt->value)); 380 if (rv != SECSuccess) { 381 goto loser2; 382 } 383 extArray[i] = newExt; 384 } 385 extArray[newSize] = NULL; 386 PORT_ArenaUnmark(poolp, mark); 387 return SECSuccess; 388 loser2: 389 crmf_zeroize_new_extensions(&(inTemplate->extensions[oldSize]), 390 extensions->numExtensions); 391 inTemplate->numExtensions = oldSize; 392 loser: 393 PORT_ArenaRelease(poolp, mark); 394 return SECFailure; 395 } 396 397 SECStatus 398 CRMF_CertRequestSetTemplateField(CRMFCertRequest *inCertReq, 399 CRMFCertTemplateField inTemplateField, 400 void *data) 401 { 402 CRMFCertTemplate *certTemplate; 403 PLArenaPool *poolp; 404 SECStatus rv = SECFailure; 405 void *mark; 406 407 if (inCertReq == NULL) { 408 return SECFailure; 409 } 410 411 certTemplate = &(inCertReq->certTemplate); 412 413 poolp = inCertReq->poolp; 414 mark = PORT_ArenaMark(poolp); 415 switch (inTemplateField) { 416 case crmfVersion: 417 rv = crmf_template_add_version(poolp, &(certTemplate->version), 418 *(long *)data); 419 break; 420 case crmfSerialNumber: 421 rv = crmf_template_add_serialnumber(poolp, 422 &(certTemplate->serialNumber), 423 *(long *)data); 424 break; 425 case crmfSigningAlg: 426 rv = crmf_template_copy_secalg(poolp, &(certTemplate->signingAlg), 427 (SECAlgorithmID *)data); 428 break; 429 case crmfIssuer: 430 rv = crmf_template_add_issuer(poolp, &(certTemplate->issuer), 431 (CERTName *)data); 432 break; 433 case crmfValidity: 434 rv = crmf_template_add_validity(poolp, &(certTemplate->validity), 435 (CRMFValidityCreationInfo *)data); 436 break; 437 case crmfSubject: 438 rv = crmf_template_add_subject(poolp, &(certTemplate->subject), 439 (CERTName *)data); 440 break; 441 case crmfPublicKey: 442 rv = crmf_template_add_public_key(poolp, &(certTemplate->publicKey), 443 (CERTSubjectPublicKeyInfo *)data); 444 break; 445 case crmfIssuerUID: 446 rv = crmf_template_add_issuer_uid(poolp, &(certTemplate->issuerUID), 447 (SECItem *)data); 448 break; 449 case crmfSubjectUID: 450 rv = crmf_template_add_subject_uid(poolp, &(certTemplate->subjectUID), 451 (SECItem *)data); 452 break; 453 case crmfExtension: 454 rv = crmf_template_add_extensions(poolp, certTemplate, 455 (CRMFCertExtCreationInfo *)data); 456 break; 457 } 458 if (rv != SECSuccess) { 459 PORT_ArenaRelease(poolp, mark); 460 } else { 461 PORT_ArenaUnmark(poolp, mark); 462 } 463 return rv; 464 } 465 466 SECStatus 467 CRMF_CertReqMsgSetCertRequest(CRMFCertReqMsg *inCertReqMsg, 468 CRMFCertRequest *inCertReq) 469 { 470 PORT_Assert(inCertReqMsg != NULL && inCertReq != NULL); 471 if (inCertReqMsg == NULL || inCertReq == NULL) { 472 return SECFailure; 473 } 474 inCertReqMsg->certReq = crmf_copy_cert_request(inCertReqMsg->poolp, 475 inCertReq); 476 return (inCertReqMsg->certReq == NULL) ? SECFailure : SECSuccess; 477 } 478 479 CRMFCertReqMsg * 480 CRMF_CreateCertReqMsg(void) 481 { 482 PLArenaPool *poolp; 483 CRMFCertReqMsg *reqMsg; 484 485 poolp = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE); 486 if (poolp == NULL) { 487 goto loser; 488 } 489 reqMsg = PORT_ArenaZNew(poolp, CRMFCertReqMsg); 490 if (reqMsg == NULL) { 491 goto loser; 492 } 493 reqMsg->poolp = poolp; 494 return reqMsg; 495 496 loser: 497 if (poolp) { 498 PORT_FreeArena(poolp, PR_FALSE); 499 } 500 return NULL; 501 } 502 503 SECStatus 504 CRMF_DestroyCertReqMsg(CRMFCertReqMsg *inCertReqMsg) 505 { 506 PORT_Assert(inCertReqMsg != NULL && inCertReqMsg->poolp != NULL); 507 if (!inCertReqMsg->isDecoded) { 508 if (inCertReqMsg->certReq->certTemplate.extensions != NULL) { 509 PORT_Free(inCertReqMsg->certReq->certTemplate.extensions); 510 } 511 if (inCertReqMsg->certReq->controls != NULL) { 512 PORT_Free(inCertReqMsg->certReq->controls); 513 } 514 } 515 PORT_FreeArena(inCertReqMsg->poolp, PR_TRUE); 516 return SECSuccess; 517 } 518 519 CRMFCertExtension * 520 crmf_create_cert_extension(PLArenaPool *poolp, 521 SECOidTag id, 522 PRBool isCritical, 523 SECItem *data) 524 { 525 CRMFCertExtension *newExt; 526 SECOidData *oidData; 527 SECStatus rv; 528 529 newExt = (poolp == NULL) ? PORT_ZNew(CRMFCertExtension) : PORT_ArenaZNew(poolp, CRMFCertExtension); 530 if (newExt == NULL) { 531 goto loser; 532 } 533 oidData = SECOID_FindOIDByTag(id); 534 if (oidData == NULL || 535 oidData->supportedExtension != SUPPORTED_CERT_EXTENSION) { 536 goto loser; 537 } 538 539 rv = SECITEM_CopyItem(poolp, &(newExt->id), &(oidData->oid)); 540 if (rv != SECSuccess) { 541 goto loser; 542 } 543 544 rv = SECITEM_CopyItem(poolp, &(newExt->value), data); 545 if (rv != SECSuccess) { 546 goto loser; 547 } 548 549 if (isCritical) { 550 newExt->critical.data = (poolp == NULL) ? PORT_New(unsigned char) 551 : PORT_ArenaNew(poolp, unsigned char); 552 if (newExt->critical.data == NULL) { 553 goto loser; 554 } 555 newExt->critical.data[0] = hexTrue; 556 newExt->critical.len = 1; 557 } 558 return newExt; 559 loser: 560 if (newExt != NULL && poolp == NULL) { 561 CRMF_DestroyCertExtension(newExt); 562 } 563 return NULL; 564 } 565 566 CRMFCertExtension * 567 CRMF_CreateCertExtension(SECOidTag id, 568 PRBool isCritical, 569 SECItem *data) 570 { 571 return crmf_create_cert_extension(NULL, id, isCritical, data); 572 } 573 574 static SECStatus 575 crmf_destroy_cert_extension(CRMFCertExtension *inExtension, PRBool freeit) 576 { 577 if (inExtension != NULL) { 578 SECITEM_FreeItem(&(inExtension->id), PR_FALSE); 579 SECITEM_FreeItem(&(inExtension->value), PR_FALSE); 580 SECITEM_FreeItem(&(inExtension->critical), PR_FALSE); 581 if (freeit) { 582 PORT_Free(inExtension); 583 } 584 } 585 return SECSuccess; 586 } 587 588 SECStatus 589 CRMF_DestroyCertExtension(CRMFCertExtension *inExtension) 590 { 591 return crmf_destroy_cert_extension(inExtension, PR_TRUE); 592 } 593 594 SECStatus 595 CRMF_DestroyCertReqMessages(CRMFCertReqMessages *inCertReqMsgs) 596 { 597 PORT_Assert(inCertReqMsgs != NULL); 598 if (inCertReqMsgs != NULL) { 599 PORT_FreeArena(inCertReqMsgs->poolp, PR_TRUE); 600 } 601 return SECSuccess; 602 } 603 604 static PRBool 605 crmf_item_has_data(SECItem *item) 606 { 607 if (item != NULL && item->data != NULL) { 608 return PR_TRUE; 609 } 610 return PR_FALSE; 611 } 612 613 PRBool 614 CRMF_CertRequestIsFieldPresent(CRMFCertRequest *inCertReq, 615 CRMFCertTemplateField inTemplateField) 616 { 617 PRBool retVal; 618 CRMFCertTemplate *certTemplate; 619 620 PORT_Assert(inCertReq != NULL); 621 if (inCertReq == NULL) { 622 /* This is probably some kind of error, but this is 623 * the safest return value for this function. 624 */ 625 return PR_FALSE; 626 } 627 certTemplate = &inCertReq->certTemplate; 628 switch (inTemplateField) { 629 case crmfVersion: 630 retVal = crmf_item_has_data(&certTemplate->version); 631 break; 632 case crmfSerialNumber: 633 retVal = crmf_item_has_data(&certTemplate->serialNumber); 634 break; 635 case crmfSigningAlg: 636 retVal = IS_NOT_NULL(certTemplate->signingAlg); 637 break; 638 case crmfIssuer: 639 retVal = IS_NOT_NULL(certTemplate->issuer); 640 break; 641 case crmfValidity: 642 retVal = IS_NOT_NULL(certTemplate->validity); 643 break; 644 case crmfSubject: 645 retVal = IS_NOT_NULL(certTemplate->subject); 646 break; 647 case crmfPublicKey: 648 retVal = IS_NOT_NULL(certTemplate->publicKey); 649 break; 650 case crmfIssuerUID: 651 retVal = crmf_item_has_data(&certTemplate->issuerUID); 652 break; 653 case crmfSubjectUID: 654 retVal = crmf_item_has_data(&certTemplate->subjectUID); 655 break; 656 case crmfExtension: 657 retVal = IS_NOT_NULL(certTemplate->extensions); 658 break; 659 default: 660 retVal = PR_FALSE; 661 } 662 return retVal; 663 }