]> git.saurik.com Git - apple/security.git/blob - AppleX509TP/tpCredRequest.cpp
1aeaf4cd001821c093190f73d36b90544f505ac8
[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 sint32 &EstimatedTime, // RETURNED
428 CssmData &ReferenceIdentifier) // RETURNED
429 {
430 CSSM_DATA_PTR csrPtr = NULL;
431 CSSM_CC_HANDLE sigHand = 0;
432 CSSM_APPLE_CL_CSR_REQUEST csrReq;
433
434 memset(&csrReq, 0, sizeof(csrReq));
435
436 /* for now we're using the same struct for input as the the normal
437 * X509 cert request. */
438 CSSM_APPLE_TP_CERT_REQUEST *certReq =
439 (CSSM_APPLE_TP_CERT_REQUEST *)RequestInput.Requests;
440 if((certReq->cspHand == 0) ||
441 (certReq->clHand == 0) ||
442 (certReq->certPublicKey == NULL) ||
443 (certReq->issuerPrivateKey == NULL) ||
444 (certReq->signatureOid.Data == NULL)) {
445 CssmError::throwMe(CSSMERR_TP_INVALID_REQUEST_INPUTS);
446 }
447 if((certReq->subjectNames == NULL) ||
448 (certReq->numSubjectNames == 0)) {
449 CssmError::throwMe(CSSMERR_TP_INVALID_NAME);
450 }
451
452 /* convert ref public key to raw per CL requirements */
453 const CSSM_KEY *subjectPubKey = certReq->certPublicKey;
454 const CSSM_KEY *actPubKey = NULL;
455 CSSM_BOOL freeRawKey = CSSM_FALSE;
456 CSSM_KEY rawPubKey;
457
458 switch(subjectPubKey->KeyHeader.BlobType) {
459 case CSSM_KEYBLOB_RAW:
460 actPubKey = subjectPubKey;
461 break;
462 case CSSM_KEYBLOB_REFERENCE:
463 refKeyToRaw(certReq->cspHand, subjectPubKey, &rawPubKey);
464 actPubKey = &rawPubKey;
465 freeRawKey = CSSM_TRUE;
466 break;
467 default:
468 tpCredDebug("SubmitCsrRequest: bad key blob type (%u)",
469 (unsigned)subjectPubKey->KeyHeader.BlobType);
470 CssmError::throwMe(CSSMERR_TP_INVALID_REQUEST_INPUTS);
471 }
472
473 /* cook up a CL-passthrough-specific request */
474 csrReq.subjectNameX509 = buildX509Name(certReq->subjectNames,
475 certReq->numSubjectNames);
476 csrReq.signatureAlg = certReq->signatureAlg;
477 csrReq.signatureOid = certReq->signatureOid;
478 csrReq.cspHand = certReq->cspHand;
479 csrReq.subjectPublicKey = actPubKey;
480 csrReq.subjectPrivateKey = certReq->issuerPrivateKey;
481 csrReq.challengeString = certReq->challengeString;
482
483 /* A crypto handle to pass to the CL */
484 CSSM_RETURN crtn;
485 crtn = CSSM_CSP_CreateSignatureContext(certReq->cspHand,
486 certReq->signatureAlg,
487 NULL, // AccessCred
488 certReq->issuerPrivateKey,
489 &sigHand);
490 if(crtn) {
491 tpCredDebug("CSSM_CSP_CreateSignatureContext returned %s",
492 cssmErrorString(crtn).c_str());
493 goto abort;
494 }
495
496 /* down to the CL to do the actual work */
497 crtn = CSSM_CL_PassThrough(certReq->clHand,
498 sigHand,
499 CSSM_APPLEX509CL_OBTAIN_CSR,
500 &csrReq,
501 (void **)&csrPtr);
502 if(crtn) {
503 tpCredDebug("CSSM_CSP_CreateSignatureContext returned %s",
504 cssmErrorString(crtn).c_str());
505 goto abort;
506 }
507
508 /* save it for retrieval by RetrieveCredResult */
509 addCertToMap(csrPtr, &ReferenceIdentifier);
510 EstimatedTime = 0;
511
512 abort:
513 /* free local resources */
514 if(csrReq.subjectNameX509) {
515 freeX509Name(csrReq.subjectNameX509);
516 }
517 if(sigHand) {
518 CSSM_DeleteContext(sigHand);
519 }
520 if(freeRawKey) {
521 tpFreeCssmData(*this, &rawPubKey.KeyData, CSSM_FALSE);
522 }
523 if(crtn) {
524 CssmError::throwMe(crtn);
525 }
526 }
527
528 /*
529 * Submit cred (cert) request. Currently the only form of request we
530 * handle is the basis "sign this cert with key right now", with policy OI
531 * CSSMOID_APPLE_TP_LOCAL_CERT_GEN.
532 */
533 void AppleTPSession::SubmitCredRequest(
534 const CSSM_TP_AUTHORITY_ID *PreferredAuthority,
535 CSSM_TP_AUTHORITY_REQUEST_TYPE RequestType,
536 const CSSM_TP_REQUEST_SET &RequestInput,
537 const CSSM_TP_CALLERAUTH_CONTEXT *CallerAuthContext,
538 sint32 &EstimatedTime,
539 CssmData &ReferenceIdentifier)
540 {
541 /* free all of these on return if non-NULL */
542 CSSM_DATA_PTR certTemplate = NULL;
543 CSSM_X509_TIME_PTR notBeforeX509 = NULL;
544 CSSM_X509_TIME_PTR notAfterX509 = NULL;
545 CSSM_X509_NAME_PTR subjectX509 = NULL;
546 CSSM_X509_NAME_PTR issuerX509 = NULL;
547 CSSM_X509_EXTENSION_PTR extens509 = NULL;
548 CSSM_CC_HANDLE sigContext = 0;
549
550 /* this gets saved on success */
551 CSSM_DATA_PTR signedCert = NULL;
552
553 /* validate rather limited set of input args */
554 if(PreferredAuthority != NULL) {
555 CssmError::throwMe(CSSMERR_TP_INVALID_AUTHORITY);
556 }
557 if(RequestType != CSSM_TP_AUTHORITY_REQUEST_CERTISSUE) {
558 CssmError::throwMe(CSSMERR_TP_UNSUPPORTED_SERVICE);
559 }
560 if(CallerAuthContext == NULL) {
561 CssmError::throwMe(CSSMERR_TP_INVALID_CALLERAUTH_CONTEXT_POINTER);
562 }
563 if((RequestInput.NumberOfRequests != 1) ||
564 (RequestInput.Requests == NULL)) {
565 CssmError::throwMe(CSSMERR_TP_INVALID_REQUEST_INPUTS);
566 }
567
568 /* Apple-specific args */
569 const CSSM_TP_POLICYINFO *tpPolicy = &CallerAuthContext->Policy;
570 if((tpPolicy->NumberOfPolicyIds != 1) ||
571 (tpPolicy->PolicyIds == NULL)) {
572 CssmError::throwMe(CSSMERR_TP_INVALID_CALLERAUTH_CONTEXT_POINTER);
573 }
574 if(tpCompareCssmData(&tpPolicy->PolicyIds->FieldOid,
575 &CSSMOID_APPLE_TP_CSR_GEN)) {
576 /* break out to CSR-specific code */
577 SubmitCsrRequest(RequestInput, EstimatedTime, ReferenceIdentifier);
578 return;
579 }
580 else if(!tpCompareCssmData(&tpPolicy->PolicyIds->FieldOid,
581 &CSSMOID_APPLE_TP_LOCAL_CERT_GEN)) {
582 CssmError::throwMe(CSSMERR_TP_INVALID_POLICY_IDENTIFIERS);
583 }
584
585 CSSM_APPLE_TP_CERT_REQUEST *certReq =
586 (CSSM_APPLE_TP_CERT_REQUEST *)RequestInput.Requests;
587 if((certReq->cspHand == 0) ||
588 (certReq->clHand == 0) ||
589 (certReq->certPublicKey == NULL) ||
590 (certReq->issuerPrivateKey == NULL)) {
591 CssmError::throwMe(CSSMERR_TP_INVALID_REQUEST_INPUTS);
592 }
593 if((certReq->subjectNames == NULL) ||
594 (certReq->numSubjectNames == 0)) {
595 CssmError::throwMe(CSSMERR_TP_INVALID_NAME);
596 }
597 if((certReq->numExtensions != 0) & (certReq->extensions == NULL)) {
598 CssmError::throwMe(CSSMERR_TP_INVALID_POINTER);
599 }
600
601 CSSM_RETURN ourRtn = CSSM_OK;
602
603 try {
604 /* convert caller's friendly names and times to CDSA style */
605 subjectX509 = buildX509Name(certReq->subjectNames, certReq->numSubjectNames);
606 if(certReq->issuerNames != NULL) {
607 issuerX509 = buildX509Name(certReq->issuerNames, certReq->numIssuerNames);
608 }
609 else if(certReq->issuerNameX509) {
610 /* caller obtained this from an existing signer's cert */
611 issuerX509 = certReq->issuerNameX509;
612 }
613 else {
614 /* self-signed */
615 issuerX509 = subjectX509;
616 }
617 notBeforeX509 = buildX509Time(certReq->notBefore);
618 notAfterX509 = buildX509Time(certReq->notAfter);
619
620 if(certReq->numExtensions != 0) {
621 /* convert extensions array from CE_DataAndType to CSSM_X509_EXTENSION */
622 extens509 = (CSSM_X509_EXTENSION *)malloc(sizeof(CSSM_X509_EXTENSION) *
623 certReq->numExtensions);
624 memset(extens509, 0, sizeof(CSSM_X509_EXTENSION) *
625 certReq->numExtensions);
626 for(unsigned dex=0; dex<certReq->numExtensions; dex++) {
627 CSSM_X509_EXTENSION *extn = &extens509[dex];
628 CE_DataAndType *cdt = &certReq->extensions[dex];
629 void *parsedValue;
630 CSSM_OID extnId;
631
632 switch(cdt->type) {
633 case DT_AuthorityKeyID:
634 parsedValue = &cdt->extension.authorityKeyID;
635 extnId = CSSMOID_AuthorityKeyIdentifier;
636 break;
637 case DT_SubjectKeyID:
638 parsedValue = &cdt->extension.subjectKeyID;
639 extnId = CSSMOID_SubjectKeyIdentifier;
640 break;
641 case DT_KeyUsage:
642 parsedValue = &cdt->extension.keyUsage;
643 extnId = CSSMOID_KeyUsage;
644 break;
645 case DT_SubjectAltName:
646 parsedValue = &cdt->extension.subjectAltName;
647 extnId = CSSMOID_SubjectAltName;
648 break;
649 case DT_ExtendedKeyUsage:
650 parsedValue = &cdt->extension.extendedKeyUsage;
651 extnId = CSSMOID_ExtendedKeyUsage;
652 break;
653 case DT_BasicConstraints:
654 parsedValue = &cdt->extension.basicConstraints;
655 extnId = CSSMOID_BasicConstraints;
656 break;
657 case DT_CertPolicies:
658 parsedValue = &cdt->extension.certPolicies;
659 extnId = CSSMOID_CertificatePolicies;
660 break;
661 case DT_NetscapeCertType:
662 parsedValue = &cdt->extension.netscapeCertType;
663 extnId = CSSMOID_NetscapeCertType;
664 break;
665 case DT_Other:
666 default:
667 tpCredDebug("SubmitCredRequest: DT_Other not supported");
668 CssmError::throwMe(CSSMERR_TP_UNKNOWN_TAG);
669 // NOT REACHED
670 }
671 extn->extnId = extnId;
672 extn->critical = cdt->critical;
673 extn->format = CSSM_X509_DATAFORMAT_PARSED;
674 extn->value.parsedValue = parsedValue;
675 extn->BERvalue.Data = NULL;
676 extn->BERvalue.Length = 0;
677 } /* for each extension */
678 } /* converting extensions */
679
680 /* cook up the unsigned template */
681 makeCertTemplate(certReq->clHand,
682 certReq->cspHand,
683 certReq->serialNumber,
684 issuerX509,
685 subjectX509,
686 notBeforeX509,
687 notAfterX509,
688 certReq->certPublicKey,
689 certReq->signatureOid,
690 NULL, // subjectUniqueID, not used here (yet)
691 NULL, // issuerUniqueId
692 extens509,
693 certReq->numExtensions,
694 certTemplate);
695
696 /* create signature context */
697 ourRtn = CSSM_CSP_CreateSignatureContext(certReq->cspHand,
698 certReq->signatureAlg,
699 (CallerAuthContext ? CallerAuthContext->CallerCredentials : NULL),
700 certReq->issuerPrivateKey,
701 &sigContext);
702 if(ourRtn) {
703 tpCredDebug("CSSM_CSP_CreateSignatureContext returned %s",
704 cssmErrorString(ourRtn).c_str());
705 CssmError::throwMe(ourRtn);
706 }
707
708 signedCert = (CSSM_DATA_PTR)malloc(sizeof(CSSM_DATA));
709 signedCert->Data = NULL;
710 signedCert->Length = 0;
711 ourRtn = CSSM_CL_CertSign(certReq->clHand,
712 sigContext,
713 certTemplate, // CertToBeSigned
714 NULL, // SignScope
715 0, // ScopeSize,
716 signedCert);
717 if(ourRtn) {
718 tpCredDebug("CSSM_CL_CertSign returned %s",
719 cssmErrorString(ourRtn).c_str());
720 CssmError::throwMe(ourRtn);
721 }
722
723 /* save it for retrieval by RetrieveCredResult */
724 addCertToMap(signedCert, &ReferenceIdentifier);
725 EstimatedTime = 0;
726 }
727 catch (const CssmError &cerr) {
728 tpCredDebug("SubmitCredRequest: CSSM error %s",
729 cssmErrorString(cerr).c_str());
730 ourRtn = cerr.cssmError();
731 }
732 catch(...) {
733 tpCredDebug("SubmitCredRequest: unknown exception");
734 ourRtn = CSSMERR_TP_INTERNAL_ERROR; // ??
735 }
736
737 /* free reources */
738 tpFreeCssmData(*this, certTemplate, CSSM_TRUE);
739 freeX509Name(subjectX509);
740 if(certReq->issuerNames) {
741 freeX509Name(issuerX509);
742 }
743 /* else same as subject */
744 freeX509Time(notBeforeX509);
745 freeX509Time(notAfterX509);
746 if(extens509) {
747 free(extens509);
748 }
749 if(sigContext != 0) {
750 CSSM_DeleteContext(sigContext);
751 }
752 if(ourRtn) {
753 CssmError::throwMe(ourRtn);
754 }
755 }
756
757 void AppleTPSession::RetrieveCredResult(
758 const CssmData &ReferenceIdentifier,
759 const CSSM_TP_CALLERAUTH_CONTEXT *CallerAuthCredentials,
760 sint32 &EstimatedTime,
761 CSSM_BOOL &ConfirmationRequired,
762 CSSM_TP_RESULT_SET_PTR &RetrieveOutput)
763 {
764 const CSSM_DATA *cert = getCertFromMap(&ReferenceIdentifier);
765
766 if(cert == NULL) {
767 tpCredDebug("RetrieveCredResult: refId not found");
768 CssmError::throwMe(CSSMERR_TP_INVALID_IDENTIFIER);
769 }
770
771 /* CSSM_TP_RESULT_SET.Results points to a CSSM_ENCODED_CERT */
772 CSSM_ENCODED_CERT *encCert = (CSSM_ENCODED_CERT *)malloc(sizeof(CSSM_ENCODED_CERT));
773 encCert->CertType = CSSM_CERT_X_509v3;
774 encCert->CertEncoding = CSSM_CERT_ENCODING_DER;
775
776 /*
777 * caller must free all three:
778 * CSSM_TP_RESULT_SET_PTR RetrieveOutput
779 * RetrieveOutput->Results (CSSM_ENCODED_CERT *encCert)
780 * encCert->CertBlob.Data (the actual cert)
781 */
782 encCert->CertBlob = *cert;
783 RetrieveOutput = (CSSM_TP_RESULT_SET_PTR)malloc(
784 sizeof(CSSM_TP_RESULT_SET));
785 RetrieveOutput->Results = encCert;
786 RetrieveOutput->NumberOfResults = 1;
787 ConfirmationRequired = CSSM_FALSE;
788 EstimatedTime = 0;
789 }