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