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