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