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