]> git.saurik.com Git - apple/security.git/blob - SecurityTests/clxutils/signerAndSubjTp/signerAndSubjTp.cpp
Security-57031.1.35.tar.gz
[apple/security.git] / SecurityTests / clxutils / signerAndSubjTp / signerAndSubjTp.cpp
1 /* Copyright (c) 1998-2003,2005-2006,2008 Apple Inc.
2 *
3 * signerAndSubjTp.c
4 *
5 * Create two certs - a root, and a subject cert signed by the root. Includes
6 * extension construction. Verify certs every which way, including various expected
7 * failures. This version uses CSSM_TP_SubmitCredRequest to create the certs.
8 *
9 */
10
11 #include <utilLib/common.h>
12 #include <utilLib/cspwrap.h>
13 #include <security_cdsa_utils/cuFileIo.h>
14 #include <clAppUtils/clutils.h>
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <string.h>
18 #include <Security/cssm.h>
19 #include <Security/x509defs.h>
20 #include <Security/oidsattr.h>
21 #include <Security/oidscert.h>
22 #include <Security/oidsalg.h>
23 #include <Security/certextensions.h>
24 #include <Security/cssmapple.h>
25 #include <string.h>
26
27 #define SUBJ_KEY_LABEL "subjectKey"
28 #define ROOT_KEY_LABEL "rootKey"
29 /* default key and signature algorithm */
30 #define SIG_ALG_DEFAULT CSSM_ALGID_SHA1WithRSA
31 #define SIG_OID_DEFAULT CSSMOID_SHA1WithRSA
32 #define KEY_ALG_DEFAULT CSSM_ALGID_RSA
33
34 /* for write certs/keys option */
35 #define ROOT_CERT_FILE_NAME "ssRootCert.cer"
36 #define SUBJ_CERT_FILE_NAME "ssSubjCert.cer"
37 #define ROOT_KEY_FILE_NAME "ssRootKey.der"
38 #define SUBJ_KEY_FILE_NAME "ssSubjKey.der"
39
40 /* public key in ref form, TP supports this as of 1/30/02 */
41 #define PUB_KEY_IS_REF CSSM_TRUE
42
43 #define SERIAL_DEFAULT 0x12345678
44
45 static void usage(char **argv)
46 {
47 printf("Usage: %s [options]\n", argv[0]);
48 printf("Options:\n");
49 printf(" w[rite certs and keys]\n");
50 printf(" a=alg where alg is s(RSA/SHA1), m(RSA/MD5), f(FEE/MD5), F(FEE/SHA1),\n");
51 printf(" 2(RSA/SHA224), 6(RSA/SHA256), 3(RSA/SHA384) 5=RSA/SHA512,\n");
52 printf(" e(ECDSA), E(ANSI/ECDSA), 7(ECDSA/SHA256), 8(ECDSA/SHA384), 9(ECDSA/SHA512)\n");
53 printf(" k=keySizeInBits\n");
54 printf(" c=commonName (for SSL compatible subject name)\n");
55 printf(" P (loop and pause for malloc debug)\n");
56 printf("Extension options:\n");
57 printf(" t=authorityKeyName -- AuthorityKeyID, generalNames, DNSName plus s/n variant\n");
58 printf(" s -- SubjectKey, data = aabbccddeeff\n");
59 printf(" e=emailAddress -- subjectAltName, RFC822Name variant\n");
60 printf(" i=issuerAltName -- DNSName variant\n");
61 printf(" r=crlDistributionPoint -- dpn, URI variant\n");
62 printf(" u=authorityInfoAccess -- OCSP, DNSName variant\n");
63 printf(" p=certPolicyString -- CertPolicies, id_cps variant\n");
64 printf(" n=netscapeCertType -- NetscapeCertType, specify an integer\n");
65 printf(" N=serialNumber -- in decimal, default is 0x%x\n", SERIAL_DEFAULT);
66 exit(1);
67 }
68
69 /*
70 * RDN components for root, subject
71 */
72 static CSSM_APPLE_TP_NAME_OID rootRdn[] =
73 {
74 { "Apple Computer", &CSSMOID_OrganizationName },
75 { "The Big Cheesy Debug Root", &CSSMOID_CommonName }
76 };
77 #define NUM_ROOT_NAMES (sizeof(rootRdn) / sizeof(CSSM_APPLE_TP_NAME_OID))
78
79 static CSSM_APPLE_TP_NAME_OID subjRdn[] =
80 {
81 /* note extra space for normalize test */
82 { "Apple Computer", &CSSMOID_OrganizationName },
83 /* this can get overridden by cmd line */
84 { "Doug Mitchell", &CSSMOID_CommonName }
85 };
86 #define NUM_SUBJ_NAMES (sizeof(subjRdn) / sizeof(CSSM_APPLE_TP_NAME_OID))
87
88 static CSSM_BOOL compareKeyData(const CSSM_KEY *key1, const CSSM_KEY *key2);
89 static CSSM_RETURN verifyCert(CSSM_CL_HANDLE clHand,
90 CSSM_CSP_HANDLE cspHand,
91 CSSM_DATA_PTR cert,
92 CSSM_DATA_PTR signerCert,
93 CSSM_KEY_PTR key,
94 CSSM_ALGORITHMS sigAlg,
95 CSSM_RETURN expectResult,
96 const char *opString);
97
98 /*
99 * Cook up trivial CE_GeneralName, one component of specified NameType.
100 */
101 static void makeGeneralName(
102 CE_GeneralName *genName, /* locally declared, persistent */
103 char *str,
104 CE_GeneralNameType nameType) /* GNT_RFC822Name, etc. */
105 {
106 genName->nameType = nameType;
107 genName->berEncoded = CSSM_FALSE;
108 genName->name.Data = (uint8 *)str;
109 genName->name.Length = strlen(str);
110 }
111
112 /*
113 * Cook up a trivial CE_GeneralNames, one component of specified NameType.
114 */
115 static void makeGeneralNames(
116 CE_GeneralNames *genNames, /* pointer from CE_DataAndType */
117 CE_GeneralName *genName, /* locally declared, persistent */
118 char *str,
119 CE_GeneralNameType nameType) /* GNT_RFC822Name, etc. */
120 {
121 genNames->numNames = 1;
122 genNames->generalName = genName;
123 makeGeneralName(genName, str, nameType);
124 }
125
126 int main(int argc, char **argv)
127 {
128 CSSM_CL_HANDLE clHand; // CL handle
129 CSSM_CSP_HANDLE cspHand; // CSP handle
130 CSSM_TP_HANDLE tpHand; // TP handle
131 CSSM_DATA signedRootCert; // from CSSM_CL_CertSign
132 CSSM_DATA signedSubjCert; // from CSSM_CL_CertSign
133 CSSM_KEY subjPubKey; // subject's RSA public key blob
134 CSSM_KEY subjPrivKey; // subject's RSA private key - ref format
135 CSSM_KEY rootPubKey; // root's RSA public key blob
136 CSSM_KEY rootPrivKey; // root's RSA private key - ref format
137 CSSM_RETURN crtn;
138 CSSM_KEY_PTR extractRootKey; // from CSSM_CL_CertGetKeyInfo()
139 CSSM_KEY_PTR extractSubjKey; // ditto
140 unsigned badByte;
141 int arg;
142 unsigned errorCount = 0;
143 CSSM_DATA refId; // mallocd by CSSM_TP_SubmitCredRequest
144 CSSM_APPLE_TP_CERT_REQUEST certReq;
145 CSSM_TP_REQUEST_SET reqSet;
146 sint32 estTime;
147 CSSM_BOOL confirmRequired;
148 CSSM_TP_RESULT_SET_PTR rootResultSet;
149 CSSM_TP_RESULT_SET_PTR subjResultSet;
150 CSSM_ENCODED_CERT *rootEncCert;
151 CSSM_ENCODED_CERT *subjEncCert;
152 CSSM_TP_CALLERAUTH_CONTEXT CallerAuthContext;
153 CSSM_FIELD policyId;
154
155 /* extension support */
156 CE_GeneralName sanGenName; /* subjectAltName */
157 CE_GeneralName ianGenName; /* issuerAltName */
158 CE_DistributionPointName distPointName;
159 CE_GeneralName crlGenName;
160 CE_GeneralNames crlGenNames;
161 CE_CRLDistributionPoint cdp;
162 CE_AccessDescription accessDescr;
163 CE_GeneralNames authKeyIdGenNames;
164 CE_GeneralName authKeyIdGenName;
165 uint8 authKeyIdSerial[4] = {0x22, 0x33, 0x44, 0x55 };
166 uint8 subjKeyIdData[6] = {0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff};
167 CE_PolicyQualifierInfo polQualInfo;
168 CE_PolicyInformation polInfo;
169
170 /* user-spec'd variables */
171 CSSM_BOOL writeBlobs = CSSM_FALSE;
172 CSSM_ALGORITHMS keyAlg = KEY_ALG_DEFAULT;
173 CSSM_ALGORITHMS sigAlg = SIG_ALG_DEFAULT;
174 CSSM_OID sigOid = SIG_OID_DEFAULT;
175 uint32 keySizeInBits = CSP_KEY_SIZE_DEFAULT;
176 char *subjectEmail = NULL; // for S/MIME subjectAltName
177 char *issuerAltName = NULL;
178 char *crlDistPoint = NULL;
179 char *authorityInfoAccess = NULL;
180 char *authKeyIdName = NULL;
181 bool subjectKeyId = false;
182 char *certPoliciesStr = NULL;
183 bool netscapeTypeSpec = false;
184 uint16 netscapeType = 0;
185 uint32 serialNumber = SERIAL_DEFAULT;
186 bool loopPause = false;
187
188 /*
189 * Extensions. Subject at least one (KeyUsage).
190 * Root has KeyUsage and BasicConstraints.
191 */
192 CE_DataAndType exts[8];
193 CE_DataAndType *extp = &exts[0];
194
195 for(arg=1; arg<argc; arg++) {
196 switch(argv[arg][0]) {
197 case 'w':
198 writeBlobs = CSSM_TRUE;
199 break;
200 case 'a':
201 if((argv[arg][1] == '\0') || (argv[arg][2] == '\0')) {
202 usage(argv);
203 }
204 switch(argv[arg][2]) {
205 case 's':
206 keyAlg = CSSM_ALGID_RSA;
207 sigAlg = CSSM_ALGID_SHA1WithRSA;
208 sigOid = CSSMOID_SHA1WithRSA;
209 break;
210 case 'm':
211 keyAlg = CSSM_ALGID_RSA;
212 sigAlg = CSSM_ALGID_MD5WithRSA;
213 sigOid = CSSMOID_MD5WithRSA;
214 break;
215 case '2':
216 keyAlg = CSSM_ALGID_RSA;
217 sigAlg = CSSM_ALGID_SHA224WithRSA;
218 sigOid = CSSMOID_SHA224WithRSA;
219 break;
220 case '6':
221 keyAlg = CSSM_ALGID_RSA;
222 sigAlg = CSSM_ALGID_SHA256WithRSA;
223 sigOid = CSSMOID_SHA256WithRSA;
224 break;
225 case '3':
226 keyAlg = CSSM_ALGID_RSA;
227 sigAlg = CSSM_ALGID_SHA384WithRSA;
228 sigOid = CSSMOID_SHA384WithRSA;
229 break;
230 case '5':
231 keyAlg = CSSM_ALGID_RSA;
232 sigAlg = CSSM_ALGID_SHA512WithRSA;
233 sigOid = CSSMOID_SHA512WithRSA;
234 break;
235 case 'f':
236 keyAlg = CSSM_ALGID_FEE;
237 sigAlg = CSSM_ALGID_FEE_MD5;
238 sigOid = CSSMOID_APPLE_FEE_MD5;
239 break;
240 case 'F':
241 keyAlg = CSSM_ALGID_FEE;
242 sigAlg = CSSM_ALGID_FEE_SHA1;
243 sigOid = CSSMOID_APPLE_FEE_SHA1;
244 break;
245 case 'e':
246 keyAlg = CSSM_ALGID_FEE;
247 sigAlg = CSSM_ALGID_SHA1WithECDSA;
248 sigOid = CSSMOID_APPLE_ECDSA;
249 break;
250 case 'E':
251 keyAlg = CSSM_ALGID_ECDSA;
252 sigAlg = CSSM_ALGID_SHA1WithECDSA;
253 sigOid = CSSMOID_ECDSA_WithSHA1;
254 break;
255 case '7':
256 keyAlg = CSSM_ALGID_ECDSA;
257 sigAlg = CSSM_ALGID_SHA256WithECDSA;
258 sigOid = CSSMOID_ECDSA_WithSHA256;
259 break;
260 case '8':
261 keyAlg = CSSM_ALGID_ECDSA;
262 sigAlg = CSSM_ALGID_SHA384WithECDSA;
263 sigOid = CSSMOID_ECDSA_WithSHA384;
264 break;
265 case '9':
266 keyAlg = CSSM_ALGID_ECDSA;
267 sigAlg = CSSM_ALGID_SHA512WithECDSA;
268 sigOid = CSSMOID_ECDSA_WithSHA512;
269 break;
270 default:
271 usage(argv);
272 }
273 break;
274 case 'k':
275 keySizeInBits = atoi(&argv[arg][2]);
276 break;
277 case 'e':
278 subjectEmail = &argv[arg][2];
279 break;
280 case 'i':
281 issuerAltName = &argv[arg][2];
282 break;
283 case 'r':
284 crlDistPoint = &argv[arg][2];
285 break;
286 case 'u':
287 authorityInfoAccess = &argv[arg][2];
288 break;
289 case 't':
290 authKeyIdName = &argv[arg][2];
291 break;
292 case 's':
293 subjectKeyId = true;
294 break;
295 case 'p':
296 certPoliciesStr = &argv[arg][2];
297 break;
298 case 'n':
299 netscapeTypeSpec = true;
300 netscapeType = atoi(&argv[arg][2]);
301 break;
302 case 'c':
303 subjRdn[NUM_SUBJ_NAMES-1].string = &argv[arg][2];
304 break;
305 case 'N':
306 serialNumber = atoi(&argv[arg][2]);
307 break;
308 case 'P':
309 loopPause = true;
310 break;
311 default:
312 usage(argv);
313 }
314 }
315
316 /* connect to CL, TP, and CSP */
317 clHand = clStartup();
318 if(clHand == 0) {
319 return 0;
320 }
321 tpHand = tpStartup();
322 if(tpHand == 0) {
323 return 0;
324 }
325 cspHand = cspStartup();
326 if(cspHand == 0) {
327 return 0;
328 }
329
330 /* subsequent errors to abort: to detach */
331
332 /* cook up an RSA key pair for the subject */
333 crtn = cspGenKeyPair(cspHand,
334 keyAlg,
335 SUBJ_KEY_LABEL,
336 strlen(SUBJ_KEY_LABEL),
337 keySizeInBits,
338 &subjPubKey,
339 #if PUB_KEY_IS_REF
340 CSSM_TRUE,
341 #else
342 CSSM_FALSE, // pubIsRef
343 #endif
344 CSSM_KEYUSE_VERIFY | CSSM_KEYUSE_ENCRYPT,
345 CSSM_KEYBLOB_RAW_FORMAT_NONE,
346 &subjPrivKey,
347 writeBlobs ? CSSM_FALSE : CSSM_TRUE, // privIsRef
348 CSSM_KEYUSE_SIGN | CSSM_KEYUSE_DECRYPT,
349 CSSM_KEYBLOB_RAW_FORMAT_NONE,
350 CSSM_FALSE);
351 if(crtn) {
352 errorCount++;
353 goto abort;
354 }
355
356 /* and the root */
357 crtn = cspGenKeyPair(cspHand,
358 keyAlg,
359 ROOT_KEY_LABEL,
360 strlen(ROOT_KEY_LABEL),
361 keySizeInBits,
362 &rootPubKey,
363 CSSM_FALSE, // pubIsRef - should work both ways, but not yet
364 CSSM_KEYUSE_VERIFY,
365 CSSM_KEYBLOB_RAW_FORMAT_NONE,
366 &rootPrivKey,
367 writeBlobs ? CSSM_FALSE : CSSM_TRUE, // privIsRef
368 CSSM_KEYUSE_SIGN,
369 CSSM_KEYBLOB_RAW_FORMAT_NONE,
370 CSSM_FALSE);
371 if(crtn) {
372 errorCount++;
373 goto abort;
374 }
375
376 if(compareKeyData(&rootPubKey, &subjPubKey)) {
377 printf("**WARNING: Identical root and subj keys!\n");
378 }
379
380 if(writeBlobs) {
381 writeFile(ROOT_KEY_FILE_NAME, rootPrivKey.KeyData.Data,
382 rootPrivKey.KeyData.Length);
383 printf("...wrote %lu bytes to %s\n", rootPrivKey.KeyData.Length,
384 ROOT_KEY_FILE_NAME);
385 writeFile(SUBJ_KEY_FILE_NAME, subjPrivKey.KeyData.Data,
386 subjPrivKey.KeyData.Length);
387 printf("...wrote %lu bytes to %s\n", subjPrivKey.KeyData.Length,
388 SUBJ_KEY_FILE_NAME);
389 }
390
391 if(loopPause) {
392 fpurge(stdin);
393 printf("pausing before root CSSM_TP_SubmitCredRequest; CR to continue:");
394 getchar();
395 }
396 loopTop:
397
398 /* A KeyUsage extension for both certs */
399 exts[0].type = DT_KeyUsage;
400 exts[0].critical = CSSM_FALSE;
401 exts[0].extension.keyUsage = CE_KU_DigitalSignature | CE_KU_KeyCertSign;
402
403 /* root - BasicConstraints extensions */
404 exts[1].type = DT_BasicConstraints;
405 exts[1].critical = CSSM_TRUE;
406 exts[1].extension.basicConstraints.cA = CSSM_TRUE;
407 exts[1].extension.basicConstraints.pathLenConstraintPresent = CSSM_TRUE;
408 exts[1].extension.basicConstraints.pathLenConstraint = 2;
409
410 /* certReq for root */
411 memset(&certReq, 0, sizeof(CSSM_APPLE_TP_CERT_REQUEST));
412 certReq.cspHand = cspHand;
413 certReq.clHand = clHand;
414 certReq.serialNumber = serialNumber;
415 certReq.numSubjectNames = NUM_ROOT_NAMES;
416 certReq.subjectNames = rootRdn;
417 certReq.numIssuerNames = 0;
418 certReq.issuerNames = NULL;
419 certReq.certPublicKey = &rootPubKey;
420 certReq.issuerPrivateKey = &rootPrivKey;
421 certReq.signatureAlg = sigAlg;
422 certReq.signatureOid = sigOid;
423 certReq.notBefore = 0; // now
424 certReq.notAfter = 10000; // seconds from now
425 certReq.numExtensions = 2;
426 certReq.extensions = exts;
427
428 reqSet.NumberOfRequests = 1;
429 reqSet.Requests = &certReq;
430
431 /* a big CSSM_TP_CALLERAUTH_CONTEXT just to specify an OID */
432 memset(&CallerAuthContext, 0, sizeof(CSSM_TP_CALLERAUTH_CONTEXT));
433 memset(&policyId, 0, sizeof(CSSM_FIELD));
434 policyId.FieldOid = CSSMOID_APPLE_TP_LOCAL_CERT_GEN;
435 CallerAuthContext.Policy.NumberOfPolicyIds = 1;
436 CallerAuthContext.Policy.PolicyIds = &policyId;
437
438 /* generate root cert */
439 printf("Creating root cert...\n");
440 crtn = CSSM_TP_SubmitCredRequest(tpHand,
441 NULL, // PreferredAuthority
442 CSSM_TP_AUTHORITY_REQUEST_CERTISSUE,
443 &reqSet,
444 &CallerAuthContext,
445 &estTime,
446 &refId);
447 if(crtn) {
448 printError("CSSM_TP_SubmitCredRequest", crtn);
449 errorCount++;
450 goto abort;
451 }
452 crtn = CSSM_TP_RetrieveCredResult(tpHand,
453 &refId,
454 NULL, // CallerAuthCredentials
455 &estTime,
456 &confirmRequired,
457 &rootResultSet);
458 if(crtn) {
459 printError("CSSM_TP_RetrieveCredResult", crtn);
460 errorCount++;
461 goto abort;
462 }
463 CSSM_FREE(refId.Data);
464 if(rootResultSet == NULL) {
465 printf("***CSSM_TP_RetrieveCredResult returned NULL result set.\n");
466 errorCount++;
467 goto abort;
468 }
469 rootEncCert = (CSSM_ENCODED_CERT *)rootResultSet->Results;
470 signedRootCert = rootEncCert->CertBlob;
471 if(writeBlobs) {
472 writeFile(ROOT_CERT_FILE_NAME, signedRootCert.Data, signedRootCert.Length);
473 printf("...wrote %lu bytes to %s\n", signedRootCert.Length,
474 ROOT_CERT_FILE_NAME);
475 }
476
477 if(loopPause) {
478 fpurge(stdin);
479 printf("pausing before subject CSSM_TP_SubmitCredRequest; CR to continue:");
480 getchar();
481 }
482
483 /* now a subject cert signed by the root cert */
484 printf("Creating subject cert...\n");
485 certReq.serialNumber = serialNumber + 1;
486 certReq.numSubjectNames = NUM_SUBJ_NAMES;
487 certReq.subjectNames = subjRdn;
488 certReq.numIssuerNames = NUM_ROOT_NAMES;
489 certReq.issuerNames = rootRdn;
490 certReq.certPublicKey = &subjPubKey;
491 certReq.issuerPrivateKey = &rootPrivKey;
492 certReq.numExtensions = 1;
493 certReq.extensions = exts;
494
495 /* subject cert extensions - at least KeyUsage, maybe more */
496 exts[0].type = DT_KeyUsage;
497 exts[0].critical = CSSM_FALSE;
498 exts[0].extension.keyUsage =
499 CE_KU_DigitalSignature | CE_KU_DataEncipherment | CE_KU_KeyAgreement;
500 extp = &exts[1];
501
502 if(subjectEmail) {
503 /* subjectAltName extension */
504 makeGeneralNames(&extp->extension.subjectAltName, &sanGenName,
505 subjectEmail, GNT_RFC822Name);
506 extp->type = DT_SubjectAltName;
507 extp->critical = CSSM_FALSE;
508 certReq.numExtensions++;
509 extp++;
510 }
511
512 if(authKeyIdName) {
513 /* AuthorityKeyID extension */
514 makeGeneralNames(&authKeyIdGenNames, &authKeyIdGenName,
515 authKeyIdName, GNT_DNSName);
516 CE_AuthorityKeyID *akid = &extp->extension.authorityKeyID;
517 memset(akid, 0, sizeof(*akid));
518 akid->generalNamesPresent = CSSM_TRUE;
519 akid->generalNames = &authKeyIdGenNames;
520 akid->serialNumberPresent = CSSM_TRUE;
521 akid->serialNumber.Data = authKeyIdSerial;
522 akid->serialNumber.Length = sizeof(authKeyIdSerial);
523
524 extp->type = DT_AuthorityKeyID;
525 extp->critical = CSSM_FALSE;
526 certReq.numExtensions++;
527 extp++;
528 }
529
530 if(subjectKeyId) {
531 /* SubjectKeyID extension */
532 CSSM_DATA *skid = &extp->extension.subjectKeyID;
533 skid->Data = subjKeyIdData;
534 skid->Length = sizeof(subjKeyIdData);
535
536 extp->type = DT_SubjectKeyID;
537 extp->critical = CSSM_FALSE;
538 certReq.numExtensions++;
539 extp++;
540 }
541
542 if(issuerAltName) {
543 /* issuerAltName extension */
544 makeGeneralNames(&extp->extension.issuerAltName, &ianGenName,
545 issuerAltName, GNT_DNSName);
546 extp->type = DT_IssuerAltName;
547 extp->critical = CSSM_FALSE;
548 certReq.numExtensions++;
549 extp++;
550 }
551
552 if(crlDistPoint) {
553 /* CRLDistributionPoints extension */
554 memset(&distPointName, 0, sizeof(distPointName));
555 makeGeneralNames(&crlGenNames, &crlGenName,
556 crlDistPoint, GNT_URI);
557 distPointName.nameType = CE_CDNT_FullName;
558 distPointName.dpn.fullName = &crlGenNames;
559
560 cdp.distPointName = &distPointName;
561 cdp.reasonsPresent = CSSM_FALSE;
562 cdp.reasons = 0;
563 cdp.crlIssuer = NULL;
564
565 CE_CRLDistPointsSyntax *dps = &extp->extension.crlDistPoints;
566 dps->numDistPoints = 1;
567 dps->distPoints = &cdp;
568 extp->type = DT_CrlDistributionPoints;
569 extp->critical = CSSM_FALSE;
570
571 certReq.numExtensions++;
572 extp++;
573 }
574
575 if(authorityInfoAccess) {
576 /* AuthorityInfoAccess extension */
577 CE_AuthorityInfoAccess *cad = &extp->extension.authorityInfoAccess;
578 cad->numAccessDescriptions = 1;
579 cad->accessDescriptions = &accessDescr;
580 makeGeneralName(&accessDescr.accessLocation, authorityInfoAccess,
581 GNT_DNSName);
582 accessDescr.accessMethod = CSSMOID_AD_OCSP;
583 extp->type = DT_AuthorityInfoAccess;
584 extp->critical = CSSM_FALSE;
585 certReq.numExtensions++;
586 extp++;
587 }
588
589 if(certPoliciesStr) {
590 /* Cert Policies extension */
591 CE_CertPolicies *cp = &extp->extension.certPolicies;
592 cp->numPolicies = 1;
593 cp->policies = &polInfo;
594 /* just make this policy OID up */
595 polInfo.certPolicyId = CSSMOID_APPLE_TP_PKINIT_CLIENT;
596 polInfo.numPolicyQualifiers = 1;
597 polInfo.policyQualifiers = &polQualInfo;
598 polQualInfo.policyQualifierId = CSSMOID_QT_CPS;
599 polQualInfo.qualifier.Data = (uint8 *)certPoliciesStr;
600 polQualInfo.qualifier.Length = strlen(certPoliciesStr);
601
602 extp->type = DT_CertPolicies;
603 extp->critical = CSSM_FALSE;
604 certReq.numExtensions++;
605 extp++;
606 }
607
608 if(netscapeTypeSpec) {
609 /* NetscapeCertType extension */
610 extp->extension.netscapeCertType = netscapeType;
611 extp->type = DT_NetscapeCertType;
612 extp->critical = CSSM_FALSE;
613 certReq.numExtensions++;
614 extp++;
615 }
616
617 crtn = CSSM_TP_SubmitCredRequest(tpHand,
618 NULL, // PreferredAuthority
619 CSSM_TP_AUTHORITY_REQUEST_CERTISSUE,
620 &reqSet,
621 &CallerAuthContext,
622 &estTime,
623 &refId);
624 if(crtn) {
625 printError("CSSM_TP_SubmitCredRequest (2)", crtn);
626 errorCount++;
627 goto abort;
628 }
629 crtn = CSSM_TP_RetrieveCredResult(tpHand,
630 &refId,
631 NULL, // CallerAuthCredentials
632 &estTime,
633 &confirmRequired,
634 &subjResultSet);
635 if(crtn) {
636 printError("CSSM_TP_RetrieveCredResult (2)", crtn);
637 errorCount++;
638 goto abort;
639 }
640 CSSM_FREE(refId.Data);
641 if(subjResultSet == NULL) {
642 printf("***CSSM_TP_RetrieveCredResult (2) returned NULL result set.\n");
643 errorCount++;
644 goto abort;
645 }
646 subjEncCert = (CSSM_ENCODED_CERT *)subjResultSet->Results;
647 signedSubjCert = subjEncCert->CertBlob;
648
649 if(writeBlobs) {
650 writeFile(SUBJ_CERT_FILE_NAME, signedSubjCert.Data, signedSubjCert.Length);
651 printf("...wrote %lu bytes to %s\n", signedSubjCert.Length,
652 SUBJ_CERT_FILE_NAME);
653 }
654
655 /*
656 * Extract public keys from the two certs, verify.
657 */
658 crtn = CSSM_CL_CertGetKeyInfo(clHand, &signedSubjCert, &extractSubjKey);
659 if(crtn) {
660 printError("CSSM_CL_CertGetKeyInfo", crtn);
661 }
662 else {
663 /* compare key data - header is different.
664 * Known header differences:
665 * -- CspID - CSSM_CL_CertGetKeyInfo returns a key with NULL for
666 * this field
667 * -- Format. rootPubKey : 6 (CSSM_KEYBLOB_RAW_FORMAT_BSAFE)
668 * extractRootKey : 1 (CSSM_KEYBLOB_RAW_FORMAT_PKCS1)
669 * -- KeyAttr. rootPubKey : 0x20 (CSSM_KEYATTR_EXTRACTABLE)
670 * extractRootKey : 0x0
671 */
672 if(!compareKeyData(extractSubjKey, &subjPubKey)) {
673 printf("***CSSM_CL_CertGetKeyInfo(signedSubjCert) returned bad key data\n");
674 }
675 if(extractSubjKey->KeyHeader.LogicalKeySizeInBits !=
676 subjPubKey.KeyHeader.LogicalKeySizeInBits) {
677 printf("***EffectiveKeySizeInBits mismatch: extract %u subj %u\n",
678 (unsigned)extractSubjKey->KeyHeader.LogicalKeySizeInBits,
679 (unsigned)subjPubKey.KeyHeader.LogicalKeySizeInBits);
680 }
681 }
682 crtn = CSSM_CL_CertGetKeyInfo(clHand, &signedRootCert, &extractRootKey);
683 if(crtn) {
684 printError("CSSM_CL_CertGetKeyInfo", crtn);
685 }
686 else {
687 if(!compareKeyData(extractRootKey, &rootPubKey)) {
688 printf("***CSSM_CL_CertGetKeyInfo(signedRootCert) returned bad key data\n");
689 }
690 }
691
692 /*
693 * Verify:
694 */
695 printf("Verifying certificates...\n");
696
697 /*
698 * Verify root cert by root pub key, should succeed.
699 */
700 if(verifyCert(clHand,
701 cspHand,
702 &signedRootCert,
703 NULL,
704 &rootPubKey,
705 sigAlg,
706 CSSM_OK,
707 "Verify(root by root key)")) {
708 errorCount++;
709 /* continue */
710 }
711
712 /*
713 * Verify root cert by root cert, should succeed.
714 */
715 if(verifyCert(clHand,
716 cspHand,
717 &signedRootCert,
718 &signedRootCert,
719 NULL,
720 CSSM_ALGID_NONE, // sigAlg not used here
721 CSSM_OK,
722 "Verify(root by root cert)")) {
723 errorCount++;
724 /* continue */
725 }
726
727
728 /*
729 * Verify subject cert by root pub key, should succeed.
730 */
731 if(verifyCert(clHand,
732 cspHand,
733 &signedSubjCert,
734 NULL,
735 &rootPubKey,
736 sigAlg,
737 CSSM_OK,
738 "Verify(subj by root key)")) {
739 errorCount++;
740 /* continue */
741 }
742
743 /*
744 * Verify subject cert by root cert, should succeed.
745 */
746 if(verifyCert(clHand,
747 cspHand,
748 &signedSubjCert,
749 &signedRootCert,
750 NULL,
751 CSSM_ALGID_NONE, // sigAlg not used here
752 CSSM_OK,
753 "Verify(subj by root cert)")) {
754 errorCount++;
755 /* continue */
756 }
757
758 /*
759 * Verify subject cert by root cert AND key, should succeed.
760 */
761 if(verifyCert(clHand,
762 cspHand,
763 &signedSubjCert,
764 &signedRootCert,
765 &rootPubKey,
766 sigAlg,
767 CSSM_OK,
768 "Verify(subj by root cert and key)")) {
769 errorCount++;
770 /* continue */
771 }
772
773 /*
774 * Verify subject cert by extracted root pub key, should succeed.
775 */
776 if(verifyCert(clHand,
777 cspHand,
778 &signedSubjCert,
779 NULL,
780 extractRootKey,
781 sigAlg,
782 CSSM_OK,
783 "Verify(subj by extracted root key)")) {
784 errorCount++;
785 /* continue */
786 }
787
788 /*
789 * Verify subject cert by subject pub key, should fail.
790 */
791 if(verifyCert(clHand,
792 cspHand,
793 &signedSubjCert,
794 NULL,
795 &subjPubKey,
796 sigAlg,
797 CSSMERR_CL_VERIFICATION_FAILURE,
798 "Verify(subj by subj key)")) {
799 errorCount++;
800 /* continue */
801 }
802
803 /*
804 * Verify subject cert by subject cert, should fail.
805 */
806 if(verifyCert(clHand,
807 cspHand,
808 &signedSubjCert,
809 &signedSubjCert,
810 NULL,
811 CSSM_ALGID_NONE, // sigAlg not used here
812 CSSMERR_CL_VERIFICATION_FAILURE,
813 "Verify(subj by subj cert)")) {
814 errorCount++;
815 /* continue */
816 }
817
818 /*
819 * Verify erroneous subject cert by root pub key, should fail.
820 */
821 badByte = genRand(1, signedSubjCert.Length - 1);
822 signedSubjCert.Data[badByte] ^= 0x55;
823 if(verifyCert(clHand,
824 cspHand,
825 &signedSubjCert,
826 NULL,
827 &rootPubKey,
828 sigAlg,
829 CSSMERR_CL_VERIFICATION_FAILURE,
830 "Verify(bad subj by root key)")) {
831 errorCount++;
832 /* continue */
833 }
834
835
836 /* free/delete certs and keys */
837 CSSM_FREE(signedSubjCert.Data);
838 CSSM_FREE(signedRootCert.Data);
839 CSSM_FREE(rootEncCert);
840 CSSM_FREE(subjEncCert);
841 CSSM_FREE(rootResultSet);
842 CSSM_FREE(subjResultSet);
843
844 /* These don't work because CSSM_CL_CertGetKeyInfo() gives keys with
845 * a bogus GUID. This may be a problem with the Apple CSP...
846 *
847 cspFreeKey(cspHand, extractRootKey);
848 cspFreeKey(cspHand, extractSubjKey);
849 *
850 * do it this way instead...*/
851 CSSM_FREE(extractRootKey->KeyData.Data);
852 CSSM_FREE(extractSubjKey->KeyData.Data);
853
854 /* need to do this regardless...*/
855 CSSM_FREE(extractRootKey);
856 CSSM_FREE(extractSubjKey);
857
858 if(loopPause) {
859 fpurge(stdin);
860 printf("pausing at end of loop; CR to continue:");
861 getchar();
862 goto loopTop;
863 }
864
865 abort:
866 cspFreeKey(cspHand, &rootPubKey);
867 cspFreeKey(cspHand, &subjPubKey);
868
869 if(cspHand != 0) {
870 CSSM_ModuleDetach(cspHand);
871 }
872 if(clHand != 0) {
873 CSSM_ModuleDetach(clHand);
874 }
875 if(tpHand != 0) {
876 CSSM_ModuleDetach(tpHand);
877 }
878
879 if(errorCount) {
880 printf("Signer/Subject test failed with %d errors\n", errorCount);
881 }
882 else {
883 printf("Signer/Subject test succeeded\n");
884 }
885 return 0;
886 }
887
888
889 /* compare KeyData for two keys. */
890 static CSSM_BOOL compareKeyData(const CSSM_KEY *key1, const CSSM_KEY *key2)
891 {
892 if(key1->KeyData.Length != key2->KeyData.Length) {
893 return CSSM_FALSE;
894 }
895 if(memcmp(key1->KeyData.Data,
896 key2->KeyData.Data,
897 key1->KeyData.Length)) {
898 return CSSM_FALSE;
899 }
900 return CSSM_TRUE;
901 }
902
903 /* verify a cert using specified key and/or signerCert */
904 static CSSM_RETURN verifyCert(CSSM_CL_HANDLE clHand,
905 CSSM_CSP_HANDLE cspHand,
906 CSSM_DATA_PTR cert,
907 CSSM_DATA_PTR signerCert, // optional
908 CSSM_KEY_PTR key, // ditto, to work spec one, other, or both
909 CSSM_ALGORITHMS sigAlg, // CSSM_ALGID_SHA1WithRSA, etc.
910 CSSM_RETURN expectResult,
911 const char *opString)
912 {
913 CSSM_RETURN crtn;
914 CSSM_CC_HANDLE signContext = CSSM_INVALID_HANDLE;
915
916 if(key) {
917 crtn = CSSM_CSP_CreateSignatureContext(cspHand,
918 sigAlg,
919 NULL, // AccessCred
920 key,
921 &signContext);
922 if(crtn) {
923 printf("Failure during %s\n", opString);
924 printError("CSSM_CSP_CreateSignatureContext", crtn);
925 return crtn;
926 }
927 }
928 crtn = CSSM_CL_CertVerify(clHand,
929 signContext,
930 cert, // CertToBeVerified
931 signerCert, // SignerCert
932 NULL, // VerifyScope
933 0); // ScopeSize
934
935 /* Hack to accomodate ECDSA returning CSSMERR_CSP_INVALID_SIGNATURE - a more detailed */
936 if(crtn != expectResult) {
937 printf("Failure during %s\n", opString);
938 if(crtn == CSSM_OK) {
939 printf("Unexpected CSSM_CL_CertVerify success\n");
940 }
941 else if(expectResult == CSSM_OK) {
942 printError("CSSM_CL_CertVerify", crtn);
943 }
944 else {
945 printError("CSSM_CL_CertVerify: expected", expectResult);
946 printError("CSSM_CL_CertVerify: got ", crtn);
947 }
948 return CSSMERR_CL_VERIFICATION_FAILURE;
949 }
950 if(signContext != CSSM_INVALID_HANDLE) {
951 crtn = CSSM_DeleteContext(signContext);
952 if(crtn) {
953 printf("Failure during %s\n", opString);
954 printError("CSSM_DeleteContext", crtn);
955 return crtn;
956 }
957 }
958 return CSSM_OK;
959 }