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