1/* 2 * Copyright (c) 2002 Apple Computer, Inc. All Rights Reserved. 3 * 4 * The contents of this file constitute Original Code as defined in and are 5 * subject to the Apple Public Source License Version 1.2 (the 'License'). 6 * You may not use this file except in compliance with the License. Please obtain 7 * a copy of the License at http://www.apple.com/publicsource and read it before 8 * using this file. 9 * 10 * This Original Code and all software distributed under the License are 11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS 12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT 13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the 15 * specific language governing rights and limitations under the License. 16 */ 17 18 19/* 20 * tpCredRequest.cpp - credential request functions SubmitCredRequest, 21 * RetrieveCredResult 22 * 23 * Created 1/24/2002 by Doug Mitchell. 24 */ 25 26#include "AppleTPSession.h" 27#include "certGroupUtils.h" 28#include "tpdebugging.h" 29#include "tpTime.h" 30#include <Security/oidsalg.h> 31#include <Security/oidsattr.h> 32#include <Security/oidscert.h> 33#include <Security/cssmapple.h> 34#include <security_utilities/debugging.h> 35#include <Security/cssmapple.h> 36#include <assert.h> 37 38#define tpCredDebug(args...) secdebug("tpCred", ## args) 39 40/* 41 * Build up a CSSM_X509_NAME from an arbitrary list of name/OID pairs. 42 * We do one a/v pair per RDN. 43 */ 44CSSM_X509_NAME * AppleTPSession::buildX509Name( 45 const CSSM_APPLE_TP_NAME_OID *nameArray, 46 unsigned numNames) 47{ 48 CSSM_X509_NAME *top = (CSSM_X509_NAME *)malloc(sizeof(CSSM_X509_NAME)); 49 top->numberOfRDNs = numNames; 50 if(numNames == 0) { 51 /* legal! */ 52 top->RelativeDistinguishedName = NULL; 53 return top; 54 } 55 top->RelativeDistinguishedName = 56 (CSSM_X509_RDN_PTR)malloc(sizeof(CSSM_X509_RDN) * numNames); 57 CSSM_X509_RDN_PTR rdn; 58 const CSSM_APPLE_TP_NAME_OID *nameOid; 59 unsigned nameDex; 60 for(nameDex=0; nameDex<numNames; nameDex++) { 61 rdn = &top->RelativeDistinguishedName[nameDex]; 62 nameOid = &nameArray[nameDex]; 63 rdn->numberOfPairs = 1; 64 rdn->AttributeTypeAndValue = (CSSM_X509_TYPE_VALUE_PAIR_PTR) 65 malloc(sizeof(CSSM_X509_TYPE_VALUE_PAIR)); 66 CSSM_X509_TYPE_VALUE_PAIR_PTR atvp = rdn->AttributeTypeAndValue; 67 tpCopyCssmData(*this, nameOid->oid, &atvp->type); 68 atvp->value.Length = strlen(nameOid->string); 69 if(tpCompareOids(&CSSMOID_CountryName, nameOid->oid)) { 70 /* 71 * Country handled differently per RFC 3280 - must be printable, 72 * max of two characters in length 73 */ 74 if(atvp->value.Length > 2) { 75 CssmError::throwMe(CSSMERR_TP_INVALID_DATA); 76 } 77 for(unsigned dex=0; dex<atvp->value.Length; dex++) { 78 int c = nameOid->string[dex]; 79 if(!isprint(c) || (c == EOF)) { 80 CssmError::throwMe(CSSMERR_TP_INVALID_DATA); 81 } 82 } 83 atvp->valueType = BER_TAG_PRINTABLE_STRING; 84 } 85 /* other special cases per RFC 3280 */ 86 else if(tpCompareOids(&CSSMOID_DNQualifier, nameOid->oid)) { 87 atvp->valueType = BER_TAG_PRINTABLE_STRING; 88 } 89 else if(tpCompareOids(&CSSMOID_SerialNumber, nameOid->oid)) { 90 atvp->valueType = BER_TAG_PRINTABLE_STRING; 91 } 92 else if(tpCompareOids(&CSSMOID_EmailAddress, nameOid->oid)) { 93 atvp->valueType = BER_TAG_IA5_STRING; 94 } 95 else { 96 /* Default type */ 97 atvp->valueType = BER_TAG_PKIX_UTF8_STRING; 98 } 99 atvp->value.Data = (uint8 *)malloc(atvp->value.Length); 100 memmove(atvp->value.Data, nameOid->string, atvp->value.Length); 101 } 102 return top; 103} 104 105/* free the CSSM_X509_NAME obtained from buildX509Name */ 106void AppleTPSession::freeX509Name( 107 CSSM_X509_NAME *top) 108{ 109 if(top == NULL) { 110 return; 111 } 112 unsigned nameDex; 113 CSSM_X509_RDN_PTR rdn; 114 for(nameDex=0; nameDex<top->numberOfRDNs; nameDex++) { 115 rdn = &top->RelativeDistinguishedName[nameDex]; 116 if(rdn->AttributeTypeAndValue) { 117 for(unsigned aDex=0; aDex<rdn->numberOfPairs; aDex++) { 118 CSSM_X509_TYPE_VALUE_PAIR_PTR atvp = 119 &rdn->AttributeTypeAndValue[aDex]; 120 free(atvp->type.Data); 121 free(atvp->value.Data); 122 } 123 free(rdn->AttributeTypeAndValue); 124 } 125 } 126 free(top->RelativeDistinguishedName); 127 free(top); 128} 129 130/* Obtain a CSSM_X509_TIME representing "now" plus specified seconds */ 131 132/* 133 * Although RFC 2459, *the* spec for X509 certs, allows for not before/after 134 * times to be expressed in ther generalized (4-digit year) or UTC (2-digit year 135 * with implied century rollover), IE 5 on Mac will not accept the generalized 136 * format. 137 */ 138#define TP_FOUR_DIGIT_YEAR 0 139#if TP_FOUR_DIGIT_YEAR 140#define TP_TIME_FORMAT TIME_GEN 141#define TP_TIME_TAG BER_TAG_GENERALIZED_TIME 142#else 143#define TP_TIME_FORMAT TIME_UTC 144#define TP_TIME_TAG BER_TAG_UTC_TIME 145#endif /* TP_FOUR_DIGIT_YEAR */ 146 147CSSM_X509_TIME * AppleTPSession::buildX509Time( 148 unsigned secondsFromNow) 149{ 150 CSSM_X509_TIME *xtime = (CSSM_X509_TIME *)malloc(sizeof(CSSM_X509_TIME)); 151 xtime->timeType = TP_TIME_TAG; 152 char *ts = (char *)malloc(GENERALIZED_TIME_STRLEN + 1); 153 { 154 StLock<Mutex> _(tpTimeLock()); 155 timeAtNowPlus(secondsFromNow, TP_TIME_FORMAT, ts); 156 } 157 xtime->time.Data = (uint8 *)ts; 158 xtime->time.Length = strlen(ts); 159 return xtime; 160} 161 162/* Free CSSM_X509_TIME obtained in buildX509Time */ 163void AppleTPSession::freeX509Time( 164 CSSM_X509_TIME *xtime) 165{ 166 if(xtime == NULL) { 167 return; 168 } 169 free((char *)xtime->time.Data); 170 free(xtime); 171} 172 173/* 174 * Cook up a CSSM_DATA with specified integer, DER style (minimum number of 175 * bytes, big-endian). 176 */ 177static void intToDER( 178 CSSM_INTPTR theInt, 179 CSSM_DATA &DER_Data, 180 Allocator &alloc) 181{ 182 /* 183 * Calculate length in bytes of encoded integer, minimum length of 1. 184 */ 185 DER_Data.Length = 1; 186 uintptr_t unsignedInt = (uintptr_t)theInt; 187 while(unsignedInt > 0xff) { 188 DER_Data.Length++; 189 unsignedInt >>= 8; 190 } 191 192 /* 193 * DER encoding requires top bit to be zero, else it's a negative number. 194 * Even though we're passing around integers as CSSM_INTPTR, they really are 195 * always unsigned. 196 * unsignedInt contains the m.s. byte of theInt in its l.s. byte. 197 */ 198 if(unsignedInt & 0x80) { 199 DER_Data.Length++; 200 } 201 202 DER_Data.Data = (uint8 *)alloc.malloc(DER_Data.Length); 203 uint8 *dst = DER_Data.Data + DER_Data.Length - 1; 204 unsignedInt = (uintptr_t)theInt; 205 for(unsigned dex=0; dex<DER_Data.Length; dex++) { 206 *dst-- = unsignedInt & 0xff; 207 /* this shifts off to zero if we're adding a zero at the top */ 208 unsignedInt >>= 8; 209 } 210} 211 212/* The reverse of the above. */ 213static CSSM_INTPTR DERToInt( 214 const CSSM_DATA &DER_Data) 215{ 216 CSSM_INTPTR rtn = 0; 217 uint8 *bp = DER_Data.Data; 218 for(unsigned dex=0; dex<DER_Data.Length; dex++) { 219 rtn <<= 8; 220 rtn |= *bp++; 221 } 222 return rtn; 223} 224 225/* Convert a reference key to a raw key. */ 226void AppleTPSession::refKeyToRaw( 227 CSSM_CSP_HANDLE cspHand, 228 const CSSM_KEY *refKey, 229 CSSM_KEY_PTR rawKey) // RETURNED 230{ 231 CSSM_CC_HANDLE ccHand; 232 CSSM_RETURN crtn; 233 CSSM_ACCESS_CREDENTIALS creds; 234 235 memset(rawKey, 0, sizeof(CSSM_KEY)); 236 memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS)); 237 crtn = CSSM_CSP_CreateSymmetricContext(cspHand, 238 CSSM_ALGID_NONE, 239 CSSM_ALGMODE_NONE, 240 &creds, // passPhrase 241 NULL, // wrapping key 242 NULL, // init vector 243 CSSM_PADDING_NONE, // Padding 244 0, // Params 245 &ccHand); 246 if(crtn) { 247 tpCredDebug("AppleTPSession::refKeyToRaw: context err"); 248 CssmError::throwMe(crtn); 249 } 250 251 crtn = CSSM_WrapKey(ccHand, 252 &creds, 253 refKey, 254 NULL, // DescriptiveData 255 rawKey); 256 if(crtn != CSSM_OK) { 257 tpCredDebug("AppleTPSession::refKeyToRaw: wrapKey err"); 258 CssmError::throwMe(crtn); 259 } 260 CSSM_DeleteContext(ccHand); 261} 262 263 264/* 265 * Cook up an unsigned cert. 266 * This is just a wrapper for CSSM_CL_CertCreateTemplate(). 267 */ 268void AppleTPSession::makeCertTemplate( 269 /* required */ 270 CSSM_CL_HANDLE clHand, 271 CSSM_CSP_HANDLE cspHand, // for converting ref to raw key 272 uint32 serialNumber, 273 const CSSM_X509_NAME *issuerName, 274 const CSSM_X509_NAME *subjectName, 275 const CSSM_X509_TIME *notBefore, 276 const CSSM_X509_TIME *notAfter, 277 const CSSM_KEY *subjectPubKey, 278 const CSSM_OID &sigOid, // e.g., CSSMOID_SHA1WithRSA 279 /* optional */ 280 const CSSM_DATA *subjectUniqueId, 281 const CSSM_DATA *issuerUniqueId, 282 CSSM_X509_EXTENSION *extensions, 283 unsigned numExtensions, 284 CSSM_DATA_PTR &rawCert) 285{ 286 CSSM_FIELD *certTemp; 287 unsigned fieldDex = 0; // index into certTemp 288 CSSM_DATA serialDER = {0, NULL}; // serial number, DER format 289 CSSM_DATA versionDER = {0, NULL}; 290 unsigned extNum; 291 CSSM_X509_ALGORITHM_IDENTIFIER algId; 292 const CSSM_KEY *actPubKey; 293 CSSM_KEY rawPubKey; 294 CSSM_BOOL freeRawKey = CSSM_FALSE; 295 296 rawCert = NULL; 297 algId.algorithm = sigOid; 298 algId.parameters.Data = NULL; 299 algId.parameters.Length = 0; 300 301 /* 302 * Convert possible ref public key to raw format as required by CL. 303 */ 304 switch(subjectPubKey->KeyHeader.BlobType) { 305 case CSSM_KEYBLOB_RAW: 306 actPubKey = subjectPubKey; 307 break; 308 case CSSM_KEYBLOB_REFERENCE: 309 refKeyToRaw(cspHand, subjectPubKey, &rawPubKey); 310 actPubKey = &rawPubKey; 311 freeRawKey = CSSM_TRUE; 312 break; 313 default: 314 tpCredDebug("CSSM_CL_CertCreateTemplate: bad key blob type (%u)", 315 (unsigned)subjectPubKey->KeyHeader.BlobType); 316 CssmError::throwMe(CSSMERR_TP_INVALID_REQUEST_INPUTS); 317 } 318 319 320 /* 321 * version, always 2 (X509v3) 322 * serialNumber thru subjectPubKey 323 */ 324 unsigned numFields = 8 + numExtensions; 325 if(subjectUniqueId) { 326 numFields++; 327 } 328 if(issuerUniqueId) { 329 numFields++; 330 } 331 332 certTemp = (CSSM_FIELD *)malloc(sizeof(CSSM_FIELD) * numFields); 333 334 335 /* version */ 336 intToDER(2, versionDER, *this); 337 certTemp[fieldDex].FieldOid = CSSMOID_X509V1Version; 338 certTemp[fieldDex++].FieldValue = versionDER; 339 340 /* serial number */ 341 intToDER(serialNumber, serialDER, *this); 342 certTemp[fieldDex].FieldOid = CSSMOID_X509V1SerialNumber; 343 certTemp[fieldDex++].FieldValue = serialDER; 344 345 /* subject and issuer name */ 346 certTemp[fieldDex].FieldOid = CSSMOID_X509V1IssuerNameCStruct; 347 certTemp[fieldDex].FieldValue.Data = (uint8 *)issuerName; 348 certTemp[fieldDex++].FieldValue.Length = sizeof(CSSM_X509_NAME); 349 350 certTemp[fieldDex].FieldOid = CSSMOID_X509V1SubjectNameCStruct; 351 certTemp[fieldDex].FieldValue.Data = (uint8 *)subjectName; 352 certTemp[fieldDex++].FieldValue.Length = sizeof(CSSM_X509_NAME); 353 354 /* not before/after */ 355 certTemp[fieldDex].FieldOid = CSSMOID_X509V1ValidityNotBefore; 356 certTemp[fieldDex].FieldValue.Data = (uint8 *)notBefore; 357 certTemp[fieldDex++].FieldValue.Length = sizeof(CSSM_X509_TIME); 358 359 certTemp[fieldDex].FieldOid = CSSMOID_X509V1ValidityNotAfter; 360 certTemp[fieldDex].FieldValue.Data = (uint8 *)notAfter; 361 certTemp[fieldDex++].FieldValue.Length = sizeof(CSSM_X509_TIME); 362 363 /* the subject key */ 364 certTemp[fieldDex].FieldOid = CSSMOID_CSSMKeyStruct; 365 certTemp[fieldDex].FieldValue.Data = (uint8 *)actPubKey; 366 certTemp[fieldDex++].FieldValue.Length = sizeof(CSSM_KEY); 367 368 /* signature algorithm */ 369 certTemp[fieldDex].FieldOid = CSSMOID_X509V1SignatureAlgorithmTBS; 370 certTemp[fieldDex].FieldValue.Data = (uint8 *)&algId; 371 certTemp[fieldDex++].FieldValue.Length = sizeof(CSSM_X509_ALGORITHM_IDENTIFIER); 372 373 /* subject/issuer unique IDs */ 374 if(subjectUniqueId != 0) { 375 certTemp[fieldDex].FieldOid = CSSMOID_X509V1CertificateSubjectUniqueId; 376 certTemp[fieldDex++].FieldValue = *subjectUniqueId; 377 } 378 if(issuerUniqueId != 0) { 379 certTemp[fieldDex].FieldOid = CSSMOID_X509V1CertificateIssuerUniqueId; 380 certTemp[fieldDex++].FieldValue = *issuerUniqueId; 381 } 382 383 for(extNum=0; extNum<numExtensions; extNum++) { 384 CSSM_X509_EXTENSION_PTR ext = &extensions[extNum]; 385 if(ext->format == CSSM_X509_DATAFORMAT_PARSED) { 386 certTemp[fieldDex].FieldOid = ext->extnId; 387 } 388 else { 389 certTemp[fieldDex].FieldOid = CSSMOID_X509V3CertificateExtensionCStruct; 390 } 391 certTemp[fieldDex].FieldValue.Data = (uint8 *)ext; 392 certTemp[fieldDex++].FieldValue.Length = sizeof(CSSM_X509_EXTENSION); 393 } 394 assert(fieldDex == numFields); 395 396 /* 397 * OK, here we go 398 */ 399 rawCert = (CSSM_DATA_PTR)malloc(sizeof(CSSM_DATA)); 400 rawCert->Data = NULL; 401 rawCert->Length = 0; 402 CSSM_RETURN crtn = CSSM_CL_CertCreateTemplate(clHand, 403 fieldDex, 404 certTemp, 405 rawCert); 406 if(crtn) { 407 tpCredDebug("CSSM_CL_CertCreateTemplate returned %ld", (long)crtn); 408 free(rawCert->Data); 409 free(rawCert); 410 rawCert = NULL; 411 } 412 413 /* free the stuff we mallocd to get here */ 414 free(serialDER.Data); 415 free(versionDER.Data); 416 free(certTemp); 417 if(freeRawKey) { 418 tpFreeCssmData(*this, &rawPubKey.KeyData, CSSM_FALSE); 419 } 420 if(crtn) { 421 CssmError::throwMe(crtn); 422 } 423} 424 425/* given a cert and a ReferenceIdentifier, fill in ReferenceIdentifier and 426 * add it and the cert to tpCredMap. */ 427void AppleTPSession::addCertToMap( 428 const CSSM_DATA *cert, 429 CSSM_DATA_PTR refId) 430{ 431 StLock<Mutex> _(tpCredMapLock); 432 433 TpCredHandle hand = reinterpret_cast<TpCredHandle>(cert); 434 intToDER(hand, *refId, *this); 435 tpCredMap[hand] = cert; 436} 437 438/* given a ReferenceIdentifier, obtain associated cert and remove from the map */ 439CSSM_DATA_PTR AppleTPSession::getCertFromMap( 440 const CSSM_DATA *refId) 441{ 442 StLock<Mutex> _(tpCredMapLock); 443 CSSM_DATA_PTR rtn = NULL; 444 445 if((refId == NULL) || (refId->Data == NULL)) { 446 return NULL; 447 } 448 TpCredHandle hand = DERToInt(*refId); 449 credMap::iterator it = tpCredMap.find(hand); 450 if(it == tpCredMap.end()) { 451 return NULL; 452 } 453 rtn = const_cast<CSSM_DATA *>(it->second); 454 tpCredMap.erase(hand); 455 return rtn; 456} 457 458/* 459 * SubmitCredRequest, CSR form. 460 */ 461void AppleTPSession::SubmitCsrRequest( 462 const CSSM_TP_REQUEST_SET &RequestInput, 463 const CSSM_TP_CALLERAUTH_CONTEXT *CallerAuthContext, 464 sint32 &EstimatedTime, // RETURNED 465 CssmData &ReferenceIdentifier) // RETURNED 466{ 467 CSSM_DATA_PTR csrPtr = NULL; 468 CSSM_CC_HANDLE sigHand = 0; 469 CSSM_APPLE_CL_CSR_REQUEST csrReq; 470 471 memset(&csrReq, 0, sizeof(csrReq)); 472 473 /* for now we're using the same struct for input as the the normal 474 * X509 cert request. */ 475 CSSM_APPLE_TP_CERT_REQUEST *certReq = 476 (CSSM_APPLE_TP_CERT_REQUEST *)RequestInput.Requests; 477 if((certReq->cspHand == 0) || 478 (certReq->clHand == 0) || 479 (certReq->certPublicKey == NULL) || 480 (certReq->issuerPrivateKey == NULL) || 481 (certReq->signatureOid.Data == NULL)) { 482 CssmError::throwMe(CSSMERR_TP_INVALID_REQUEST_INPUTS); 483 } 484 485 /* convert ref public key to raw per CL requirements */ 486 const CSSM_KEY *subjectPubKey = certReq->certPublicKey; 487 const CSSM_KEY *actPubKey = NULL; 488 CSSM_BOOL freeRawKey = CSSM_FALSE; 489 CSSM_KEY rawPubKey; 490 491 switch(subjectPubKey->KeyHeader.BlobType) { 492 case CSSM_KEYBLOB_RAW: 493 actPubKey = subjectPubKey; 494 break; 495 case CSSM_KEYBLOB_REFERENCE: 496 refKeyToRaw(certReq->cspHand, subjectPubKey, &rawPubKey); 497 actPubKey = &rawPubKey; 498 freeRawKey = CSSM_TRUE; 499 break; 500 default: 501 tpCredDebug("SubmitCsrRequest: bad key blob type (%u)", 502 (unsigned)subjectPubKey->KeyHeader.BlobType); 503 CssmError::throwMe(CSSMERR_TP_INVALID_REQUEST_INPUTS); 504 } 505 506 /* cook up a CL-passthrough-specific request */ 507 csrReq.subjectNameX509 = buildX509Name(certReq->subjectNames, 508 certReq->numSubjectNames); 509 csrReq.signatureAlg = certReq->signatureAlg; 510 csrReq.signatureOid = certReq->signatureOid; 511 csrReq.cspHand = certReq->cspHand; 512 csrReq.subjectPublicKey = actPubKey; 513 csrReq.subjectPrivateKey = certReq->issuerPrivateKey; 514 csrReq.challengeString = certReq->challengeString; 515 516 /* A crypto handle to pass to the CL */ 517 CSSM_RETURN crtn; 518 crtn = CSSM_CSP_CreateSignatureContext(certReq->cspHand, 519 certReq->signatureAlg, 520 (CallerAuthContext ? CallerAuthContext->CallerCredentials : NULL), 521 certReq->issuerPrivateKey, 522 &sigHand); 523 if(crtn) { 524 tpCredDebug("CSSM_CSP_CreateSignatureContext returned %ld", (long)crtn); 525 goto abort; 526 } 527 528 /* down to the CL to do the actual work */ 529 crtn = CSSM_CL_PassThrough(certReq->clHand, 530 sigHand, 531 CSSM_APPLEX509CL_OBTAIN_CSR, 532 &csrReq, 533 (void **)&csrPtr); 534 if(crtn) { 535 tpCredDebug("CSSM_CL_PassThrough returned %ld", (long)crtn); 536 goto abort; 537 } 538 539 /* save it for retrieval by RetrieveCredResult */ 540 addCertToMap(csrPtr, &ReferenceIdentifier); 541 EstimatedTime = 0; 542 543abort: 544 /* free local resources */ 545 if(csrReq.subjectNameX509) { 546 freeX509Name(csrReq.subjectNameX509); 547 } 548 if(sigHand) { 549 CSSM_DeleteContext(sigHand); 550 } 551 if(freeRawKey) { 552 tpFreeCssmData(*this, &rawPubKey.KeyData, CSSM_FALSE); 553 } 554 if(crtn) { 555 CssmError::throwMe(crtn); 556 } 557} 558 559/* 560 * Submit cred (cert) request. Currently the only form of request we 561 * handle is the basis "sign this cert with key right now", with policy OI 562 * CSSMOID_APPLE_TP_LOCAL_CERT_GEN. 563 */ 564void AppleTPSession::SubmitCredRequest( 565 const CSSM_TP_AUTHORITY_ID *PreferredAuthority, 566 CSSM_TP_AUTHORITY_REQUEST_TYPE RequestType, 567 const CSSM_TP_REQUEST_SET &RequestInput, 568 const CSSM_TP_CALLERAUTH_CONTEXT *CallerAuthContext, 569 sint32 &EstimatedTime, 570 CssmData &ReferenceIdentifier) 571{ 572 /* free all of these on return if non-NULL */ 573 CSSM_DATA_PTR certTemplate = NULL; 574 CSSM_X509_TIME_PTR notBeforeX509 = NULL; 575 CSSM_X509_TIME_PTR notAfterX509 = NULL; 576 CSSM_X509_NAME_PTR subjectX509 = NULL; 577 CSSM_X509_NAME_PTR issuerX509 = NULL; 578 CSSM_X509_EXTENSION_PTR extens509 = NULL; 579 CSSM_CC_HANDLE sigContext = 0; 580 581 /* this gets saved on success */ 582 CSSM_DATA_PTR signedCert = NULL; 583 584 /* validate rather limited set of input args */ 585 if(PreferredAuthority != NULL) { 586 CssmError::throwMe(CSSMERR_TP_INVALID_AUTHORITY); 587 } 588 if(RequestType != CSSM_TP_AUTHORITY_REQUEST_CERTISSUE) { 589 CssmError::throwMe(CSSMERR_TP_UNSUPPORTED_SERVICE); 590 } 591 if(CallerAuthContext == NULL) { 592 CssmError::throwMe(CSSMERR_TP_INVALID_CALLERAUTH_CONTEXT_POINTER); 593 } 594 if((RequestInput.NumberOfRequests != 1) || 595 (RequestInput.Requests == NULL)) { 596 CssmError::throwMe(CSSMERR_TP_INVALID_REQUEST_INPUTS); 597 } 598 599 /* Apple-specific args */ 600 const CSSM_TP_POLICYINFO *tpPolicy = &CallerAuthContext->Policy; 601 if((tpPolicy->NumberOfPolicyIds != 1) || 602 (tpPolicy->PolicyIds == NULL)) { 603 CssmError::throwMe(CSSMERR_TP_INVALID_CALLERAUTH_CONTEXT_POINTER); 604 } 605 if(tpCompareCssmData(&tpPolicy->PolicyIds->FieldOid, 606 &CSSMOID_APPLE_TP_CSR_GEN)) { 607 /* break out to CSR-specific code */ 608 SubmitCsrRequest(RequestInput, CallerAuthContext, EstimatedTime, ReferenceIdentifier); 609 return; 610 } 611 else if(!tpCompareCssmData(&tpPolicy->PolicyIds->FieldOid, 612 &CSSMOID_APPLE_TP_LOCAL_CERT_GEN)) { 613 CssmError::throwMe(CSSMERR_TP_INVALID_POLICY_IDENTIFIERS); 614 } 615 616 CSSM_APPLE_TP_CERT_REQUEST *certReq = 617 (CSSM_APPLE_TP_CERT_REQUEST *)RequestInput.Requests; 618 if((certReq->cspHand == 0) || 619 (certReq->clHand == 0) || 620 (certReq->certPublicKey == NULL) || 621 (certReq->issuerPrivateKey == NULL)) { 622 CssmError::throwMe(CSSMERR_TP_INVALID_REQUEST_INPUTS); 623 } 624 if((certReq->numExtensions != 0) & (certReq->extensions == NULL)) { 625 CssmError::throwMe(CSSMERR_TP_INVALID_POINTER); 626 } 627 628 CSSM_RETURN ourRtn = CSSM_OK; 629 630 try { 631 /* convert caller's friendly names and times to CDSA style */ 632 subjectX509 = buildX509Name(certReq->subjectNames, certReq->numSubjectNames); 633 if(certReq->issuerNames != NULL) { 634 issuerX509 = buildX509Name(certReq->issuerNames, certReq->numIssuerNames); 635 } 636 else if(certReq->issuerNameX509) { 637 /* caller obtained this from an existing signer's cert */ 638 issuerX509 = certReq->issuerNameX509; 639 } 640 else { 641 /* self-signed */ 642 issuerX509 = subjectX509; 643 } 644 notBeforeX509 = buildX509Time(certReq->notBefore); 645 notAfterX509 = buildX509Time(certReq->notAfter); 646 647 if(certReq->numExtensions != 0) { 648 /* convert extensions array from CE_DataAndType to CSSM_X509_EXTENSION */ 649 extens509 = (CSSM_X509_EXTENSION *)malloc(sizeof(CSSM_X509_EXTENSION) * 650 certReq->numExtensions); 651 memset(extens509, 0, sizeof(CSSM_X509_EXTENSION) * 652 certReq->numExtensions); 653 for(unsigned dex=0; dex<certReq->numExtensions; dex++) { 654 CSSM_X509_EXTENSION *extn = &extens509[dex]; 655 CE_DataAndType *cdt = &certReq->extensions[dex]; 656 void *parsedValue; 657 CSSM_OID extnId; 658 659 switch(cdt->type) { 660 case DT_AuthorityKeyID: 661 parsedValue = &cdt->extension.authorityKeyID; 662 extnId = CSSMOID_AuthorityKeyIdentifier; 663 break; 664 case DT_SubjectKeyID: 665 parsedValue = &cdt->extension.subjectKeyID; 666 extnId = CSSMOID_SubjectKeyIdentifier; 667 break; 668 case DT_KeyUsage: 669 parsedValue = &cdt->extension.keyUsage; 670 extnId = CSSMOID_KeyUsage; 671 break; 672 case DT_SubjectAltName: 673 parsedValue = &cdt->extension.subjectAltName; 674 extnId = CSSMOID_SubjectAltName; 675 break; 676 case DT_IssuerAltName: 677 parsedValue = &cdt->extension.issuerAltName; 678 extnId = CSSMOID_IssuerAltName; 679 break; 680 case DT_ExtendedKeyUsage: 681 parsedValue = &cdt->extension.extendedKeyUsage; 682 extnId = CSSMOID_ExtendedKeyUsage; 683 break; 684 case DT_BasicConstraints: 685 parsedValue = &cdt->extension.basicConstraints; 686 extnId = CSSMOID_BasicConstraints; 687 break; 688 case DT_CertPolicies: 689 parsedValue = &cdt->extension.certPolicies; 690 extnId = CSSMOID_CertificatePolicies; 691 break; 692 case DT_NetscapeCertType: 693 parsedValue = &cdt->extension.netscapeCertType; 694 extnId = CSSMOID_NetscapeCertType; 695 break; 696 case DT_CrlDistributionPoints: 697 parsedValue = &cdt->extension.crlDistPoints; 698 extnId = CSSMOID_CrlDistributionPoints; 699 break; 700 case DT_AuthorityInfoAccess: 701 parsedValue = &cdt->extension.authorityInfoAccess; 702 extnId = CSSMOID_AuthorityInfoAccess; 703 break; 704 case DT_Other: 705 default: 706 tpCredDebug("SubmitCredRequest: DT_Other not supported"); 707 CssmError::throwMe(CSSMERR_TP_UNKNOWN_TAG); 708 // NOT REACHED 709 } 710 extn->extnId = extnId; 711 extn->critical = cdt->critical; 712 extn->format = CSSM_X509_DATAFORMAT_PARSED; 713 extn->value.parsedValue = parsedValue; 714 extn->BERvalue.Data = NULL; 715 extn->BERvalue.Length = 0; 716 } /* for each extension */ 717 } /* converting extensions */ 718 719 /* cook up the unsigned template */ 720 makeCertTemplate(certReq->clHand, 721 certReq->cspHand, 722 certReq->serialNumber, 723 issuerX509, 724 subjectX509, 725 notBeforeX509, 726 notAfterX509, 727 certReq->certPublicKey, 728 certReq->signatureOid, 729 NULL, // subjectUniqueID, not used here (yet) 730 NULL, // issuerUniqueId 731 extens509, 732 certReq->numExtensions, 733 certTemplate); 734 735 /* create signature context */ 736 ourRtn = CSSM_CSP_CreateSignatureContext(certReq->cspHand, 737 certReq->signatureAlg, 738 (CallerAuthContext ? CallerAuthContext->CallerCredentials : NULL), 739 certReq->issuerPrivateKey, 740 &sigContext); 741 if(ourRtn) { 742 tpCredDebug("CSSM_CSP_CreateSignatureContext returned %ld", (long)ourRtn); 743 CssmError::throwMe(ourRtn); 744 } 745 746 signedCert = (CSSM_DATA_PTR)malloc(sizeof(CSSM_DATA)); 747 signedCert->Data = NULL; 748 signedCert->Length = 0; 749 ourRtn = CSSM_CL_CertSign(certReq->clHand, 750 sigContext, 751 certTemplate, // CertToBeSigned 752 NULL, // SignScope 753 0, // ScopeSize, 754 signedCert); 755 if(ourRtn) { 756 tpCredDebug("CSSM_CL_CertSign returned %ld", (long)ourRtn); 757 CssmError::throwMe(ourRtn); 758 } 759 760 /* save it for retrieval by RetrieveCredResult */ 761 addCertToMap(signedCert, &ReferenceIdentifier); 762 EstimatedTime = 0; 763 } 764 catch (const CssmError &cerr) { 765 tpCredDebug("SubmitCredRequest: CSSM error %ld", (long)cerr.error); 766 ourRtn = cerr.error; 767 } 768 catch(...) { 769 tpCredDebug("SubmitCredRequest: unknown exception"); 770 ourRtn = CSSMERR_TP_INTERNAL_ERROR; // ?? 771 } 772 773 /* free reources */ 774 tpFreeCssmData(*this, certTemplate, CSSM_TRUE); 775 freeX509Name(subjectX509); 776 if(certReq->issuerNames) { 777 freeX509Name(issuerX509); 778 } 779 /* else same as subject */ 780 freeX509Time(notBeforeX509); 781 freeX509Time(notAfterX509); 782 if(extens509) { 783 free(extens509); 784 } 785 if(sigContext != 0) { 786 CSSM_DeleteContext(sigContext); 787 } 788 if(ourRtn) { 789 CssmError::throwMe(ourRtn); 790 } 791} 792 793void AppleTPSession::RetrieveCredResult( 794 const CssmData &ReferenceIdentifier, 795 const CSSM_TP_CALLERAUTH_CONTEXT *CallerAuthCredentials, 796 sint32 &EstimatedTime, 797 CSSM_BOOL &ConfirmationRequired, 798 CSSM_TP_RESULT_SET_PTR &RetrieveOutput) 799{ 800 CSSM_DATA *cert = getCertFromMap(&ReferenceIdentifier); 801 802 if(cert == NULL) { 803 tpCredDebug("RetrieveCredResult: refId not found"); 804 CssmError::throwMe(CSSMERR_TP_INVALID_IDENTIFIER); 805 } 806 807 /* CSSM_TP_RESULT_SET.Results points to a CSSM_ENCODED_CERT */ 808 CSSM_ENCODED_CERT *encCert = (CSSM_ENCODED_CERT *)malloc(sizeof(CSSM_ENCODED_CERT)); 809 encCert->CertType = CSSM_CERT_X_509v3; 810 encCert->CertEncoding = CSSM_CERT_ENCODING_DER; 811 812 /* 813 * caller must free all three: 814 * CSSM_TP_RESULT_SET_PTR RetrieveOutput 815 * RetrieveOutput->Results (CSSM_ENCODED_CERT *encCert) 816 * encCert->CertBlob.Data (the actual cert) 817 * We free: 818 * cert -- mallocd in SubmitCredRequest 819 */ 820 encCert->CertBlob = *cert; 821 RetrieveOutput = (CSSM_TP_RESULT_SET_PTR)malloc( 822 sizeof(CSSM_TP_RESULT_SET)); 823 RetrieveOutput->Results = encCert; 824 RetrieveOutput->NumberOfResults = 1; 825 ConfirmationRequired = CSSM_FALSE; 826 free(cert); 827 EstimatedTime = 0; 828} 829