]>
Commit | Line | Data |
---|---|---|
d8f41ccd A |
1 | /* Copyright (c) 1998,2003,2005-2006,2008 Apple Inc. |
2 | * | |
3 | * signerAndSubj.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. | |
8 | * | |
9 | * Revision History | |
10 | * ---------------- | |
11 | * 31 Aug 2000 Doug Mitchell at Apple | |
12 | * Ported to X/CDSA2. | |
13 | * 20 Jul 1998 Doug Mitchell at NeXT | |
14 | * Created. | |
15 | */ | |
16 | ||
17 | #include <utilLib/common.h> | |
18 | #include <utilLib/cspwrap.h> | |
19 | #include <security_cdsa_utils/cuFileIo.h> | |
20 | #include <clAppUtils/CertBuilderApp.h> | |
21 | #include <clAppUtils/clutils.h> | |
22 | #include <stdlib.h> | |
23 | #include <stdio.h> | |
24 | #include <string.h> | |
25 | #include <Security/cssm.h> | |
26 | #include <Security/x509defs.h> | |
27 | #include <Security/oidsattr.h> | |
28 | #include <Security/oidscert.h> | |
29 | #include <Security/oidsalg.h> | |
30 | #include <Security/certextensions.h> | |
31 | #include <Security/cssmapple.h> | |
32 | #include <string.h> | |
33 | ||
34 | #define SUBJ_KEY_LABEL "subjectKey" | |
35 | #define ROOT_KEY_LABEL "rootKey" | |
36 | /* default key and signature algorithm */ | |
37 | #define SIG_ALG_DEFAULT CSSM_ALGID_SHA1WithRSA | |
38 | #define KEY_ALG_DEFAULT CSSM_ALGID_RSA | |
39 | ||
40 | /* for write certs/components option */ | |
41 | #define ROOT_CERT_FILE_NAME "ssRootCert.der" | |
42 | #define ROOT_TBS_FILE_NAME "ssRootTBS.der" | |
43 | #define SUBJ_CERT_FILE_NAME "ssSubjCert.der" | |
44 | #define SUBJ_TBS_FILE_NAME "ssSubjTBS.der" | |
45 | #define ROOT_PRIV_KEY_FILE "ssRootPriv.der" | |
46 | #define SUBJ_PRIV_KEY_FILE "ssSubjPriv.der" | |
47 | ||
48 | static void usage(char **argv) | |
49 | { | |
50 | printf("Usage: %s [options]\n", argv[0]); | |
51 | printf("Options:\n"); | |
52 | printf(" w[rite certs and components]\n"); | |
53 | printf(" a=alg where alg is s(RSA/SHA1), m(RSA/MD5), f(FEE/MD5), F(FEE/SHA1),\n"); | |
54 | printf(" 2(RSA/SHA224), 6(RSA/SHA256), 3(RSA/SHA384) 5=RSA/SHA512,\n"); | |
55 | printf(" e(ECDSA), E(ANSI/ECDSA), 7(ECDSA/SHA256), 8(ECDSA/SHA384), 9(ECDSA/SHA512)\n"); | |
56 | printf(" k=keySizeInBits\n"); | |
57 | exit(1); | |
58 | } | |
59 | ||
60 | /* | |
61 | * RDN components for root, subject | |
62 | */ | |
63 | CB_NameOid rootRdn[] = | |
64 | { | |
65 | { "Apple Computer", &CSSMOID_OrganizationName }, | |
66 | { "The Big Cheese", &CSSMOID_Title } | |
67 | }; | |
68 | #define NUM_ROOT_NAMES (sizeof(rootRdn) / sizeof(CB_NameOid)) | |
69 | ||
70 | CB_NameOid subjRdn[] = | |
71 | { | |
72 | /* note extra space for normalize test */ | |
73 | { "Apple Computer", &CSSMOID_OrganizationName }, | |
74 | { "Doug Mitchell", &CSSMOID_CommonName } | |
75 | }; | |
76 | #define NUM_SUBJ_NAMES (sizeof(subjRdn) / sizeof(CB_NameOid)) | |
77 | ||
78 | static CSSM_BOOL compareKeyData(const CSSM_KEY *key1, const CSSM_KEY *key2); | |
79 | static CSSM_RETURN verifyCert(CSSM_CL_HANDLE clHand, | |
80 | CSSM_CSP_HANDLE cspHand, | |
81 | CSSM_DATA_PTR cert, | |
82 | CSSM_DATA_PTR signerCert, | |
83 | CSSM_KEY_PTR key, | |
84 | CSSM_ALGORITHMS sigAlg, | |
85 | CSSM_RETURN expectResult, | |
86 | const char *opString); | |
87 | ||
88 | ||
89 | int main(int argc, char **argv) | |
90 | { | |
91 | CSSM_CL_HANDLE clHand; // CL handle | |
92 | CSSM_X509_NAME *subjName; | |
93 | CSSM_X509_NAME *rootName; | |
94 | CSSM_X509_TIME *notBefore; // UTC-style "not before" time | |
95 | CSSM_X509_TIME *notAfter; // UTC-style "not after" time | |
96 | CSSM_DATA_PTR rawCert; // from CSSM_CL_CertCreateTemplate | |
97 | CSSM_DATA signedRootCert; // from CSSM_CL_CertSign | |
98 | CSSM_DATA signedSubjCert; // from CSSM_CL_CertSign | |
99 | CSSM_CSP_HANDLE cspHand; // CSP handle | |
100 | CSSM_KEY subjPubKey; // subject's RSA public key blob | |
101 | CSSM_KEY subjPrivKey; // subject's RSA private key - ref format | |
102 | CSSM_KEY rootPubKey; // root's RSA public key blob | |
103 | CSSM_KEY rootPrivKey; // root's RSA private key - ref format | |
104 | CSSM_RETURN crtn; | |
105 | CSSM_KEY_PTR extractRootKey; // from CSSM_CL_CertGetKeyInfo() | |
106 | CSSM_KEY_PTR extractSubjKey; // ditto | |
107 | CSSM_CC_HANDLE signContext; // for signing/verifying the cert | |
108 | unsigned badByte; | |
109 | int arg; | |
110 | unsigned errorCount = 0; | |
111 | ||
112 | /* user-spec'd variables */ | |
113 | CSSM_BOOL writeBlobs = CSSM_FALSE; | |
114 | CSSM_ALGORITHMS keyAlg = KEY_ALG_DEFAULT; | |
115 | CSSM_ALGORITHMS sigAlg = SIG_ALG_DEFAULT; | |
116 | uint32 keySizeInBits = CSP_KEY_SIZE_DEFAULT; | |
117 | ||
118 | /* | |
119 | * Two extensions. Subject has one (KeyUsage); root has KeyUsage and | |
120 | * BasicConstraints. | |
121 | */ | |
122 | CSSM_X509_EXTENSION exts[2]; | |
123 | CE_KeyUsage keyUsage; | |
124 | CE_BasicConstraints bc; | |
125 | ||
126 | for(arg=1; arg<argc; arg++) { | |
127 | switch(argv[arg][0]) { | |
128 | case 'w': | |
129 | writeBlobs = CSSM_TRUE; | |
130 | break; | |
131 | case 'a': | |
132 | if((argv[arg][1] == '\0') || (argv[arg][2] == '\0')) { | |
133 | usage(argv); | |
134 | } | |
135 | switch(argv[arg][2]) { | |
136 | case 's': | |
137 | keyAlg = CSSM_ALGID_RSA; | |
138 | sigAlg = CSSM_ALGID_SHA1WithRSA; | |
139 | break; | |
140 | case 'm': | |
141 | keyAlg = CSSM_ALGID_RSA; | |
142 | sigAlg = CSSM_ALGID_MD5WithRSA; | |
143 | break; | |
144 | case 'f': | |
145 | keyAlg = CSSM_ALGID_FEE; | |
146 | sigAlg = CSSM_ALGID_FEE_MD5; | |
147 | break; | |
148 | case 'F': | |
149 | keyAlg = CSSM_ALGID_FEE; | |
150 | sigAlg = CSSM_ALGID_FEE_SHA1; | |
151 | break; | |
152 | case 'e': | |
153 | keyAlg = CSSM_ALGID_FEE; | |
154 | sigAlg = CSSM_ALGID_SHA1WithECDSA; | |
155 | break; | |
156 | case 'E': | |
157 | keyAlg = CSSM_ALGID_ECDSA; | |
158 | sigAlg = CSSM_ALGID_SHA1WithECDSA; | |
159 | break; | |
160 | case '7': | |
161 | keyAlg = CSSM_ALGID_ECDSA; | |
162 | sigAlg = CSSM_ALGID_SHA256WithECDSA; | |
163 | break; | |
164 | case '8': | |
165 | keyAlg = CSSM_ALGID_ECDSA; | |
166 | sigAlg = CSSM_ALGID_SHA384WithECDSA; | |
167 | break; | |
168 | case '9': | |
169 | keyAlg = CSSM_ALGID_ECDSA; | |
170 | sigAlg = CSSM_ALGID_SHA512WithECDSA; | |
171 | break; | |
172 | case '2': | |
173 | keyAlg = CSSM_ALGID_RSA; | |
174 | sigAlg = CSSM_ALGID_SHA224WithRSA; | |
175 | break; | |
176 | case '6': | |
177 | keyAlg = CSSM_ALGID_RSA; | |
178 | sigAlg = CSSM_ALGID_SHA256WithRSA; | |
179 | break; | |
180 | case '3': | |
181 | keyAlg = CSSM_ALGID_RSA; | |
182 | sigAlg = CSSM_ALGID_SHA384WithRSA; | |
183 | break; | |
184 | case '5': | |
185 | keyAlg = CSSM_ALGID_RSA; | |
186 | sigAlg = CSSM_ALGID_SHA512WithRSA; | |
187 | break; | |
188 | default: | |
189 | usage(argv); | |
190 | } | |
191 | break; | |
192 | case 'k': | |
193 | keySizeInBits = atoi(&argv[arg][2]); | |
194 | break; | |
195 | default: | |
196 | usage(argv); | |
197 | } | |
198 | } | |
199 | ||
200 | /* connect to CL and CSP */ | |
201 | clHand = clStartup(); | |
202 | if(clHand == 0) { | |
203 | return 0; | |
204 | } | |
205 | cspHand = cspStartup(); | |
206 | if(cspHand == 0) { | |
207 | return 0; | |
208 | } | |
209 | ||
210 | /* subsequent errors to abort: to detach */ | |
211 | ||
212 | /* cook up an RSA key pair for the subject */ | |
213 | crtn = cspGenKeyPair(cspHand, | |
214 | keyAlg, | |
215 | SUBJ_KEY_LABEL, | |
216 | strlen(SUBJ_KEY_LABEL), | |
217 | keySizeInBits, | |
218 | &subjPubKey, | |
219 | CSSM_FALSE, // pubIsRef - should work both ways, but not yet | |
220 | CSSM_KEYUSE_VERIFY, | |
221 | CSSM_KEYBLOB_RAW_FORMAT_NONE, | |
222 | &subjPrivKey, | |
223 | CSSM_FALSE, // privIsRef | |
224 | CSSM_KEYUSE_SIGN, | |
225 | CSSM_KEYBLOB_RAW_FORMAT_NONE, | |
226 | CSSM_FALSE); | |
227 | if(crtn) { | |
228 | errorCount++; | |
229 | goto abort; | |
230 | } | |
231 | if(writeBlobs) { | |
232 | writeFile(SUBJ_PRIV_KEY_FILE, subjPrivKey.KeyData.Data, | |
233 | subjPrivKey.KeyData.Length); | |
234 | printf("...wrote %lu bytes to %s\n", subjPrivKey.KeyData.Length, | |
235 | SUBJ_PRIV_KEY_FILE); | |
236 | } | |
237 | ||
238 | /* and the root */ | |
239 | crtn = cspGenKeyPair(cspHand, | |
240 | keyAlg, | |
241 | ROOT_KEY_LABEL, | |
242 | strlen(ROOT_KEY_LABEL), | |
243 | keySizeInBits, | |
244 | &rootPubKey, | |
245 | CSSM_FALSE, // pubIsRef - should work both ways, but not yet | |
246 | CSSM_KEYUSE_VERIFY, | |
247 | CSSM_KEYBLOB_RAW_FORMAT_NONE, | |
248 | &rootPrivKey, | |
249 | CSSM_FALSE, // privIsRef | |
250 | CSSM_KEYUSE_SIGN, | |
251 | CSSM_KEYBLOB_RAW_FORMAT_NONE, | |
252 | CSSM_FALSE); | |
253 | if(crtn) { | |
254 | errorCount++; | |
255 | goto abort; | |
256 | } | |
257 | if(writeBlobs) { | |
258 | writeFile(ROOT_PRIV_KEY_FILE, rootPrivKey.KeyData.Data, | |
259 | rootPrivKey.KeyData.Length); | |
260 | printf("...wrote %lu bytes to %s\n", rootPrivKey.KeyData.Length, | |
261 | ROOT_PRIV_KEY_FILE); | |
262 | } | |
263 | ||
264 | if(compareKeyData(&rootPubKey, &subjPubKey)) { | |
265 | printf("**WARNING: Identical root and subj keys!\n"); | |
266 | } | |
267 | ||
268 | /* | |
269 | * Cook up various cert fields. | |
270 | * First, the RDNs for subject and issuer. | |
271 | */ | |
272 | rootName = CB_BuildX509Name(rootRdn, NUM_ROOT_NAMES); | |
273 | subjName = CB_BuildX509Name(subjRdn, NUM_SUBJ_NAMES); | |
274 | if((rootName == NULL) || (subjName == NULL)) { | |
275 | printf("CB_BuildX509Name failure"); | |
276 | errorCount++; | |
277 | goto abort; | |
278 | } | |
279 | ||
280 | /* not before/after in generalized time format */ | |
281 | notBefore = CB_BuildX509Time(0); | |
282 | notAfter = CB_BuildX509Time(10000); | |
283 | ||
284 | /* A KeyUsage extension for both certs */ | |
285 | exts[0].extnId = CSSMOID_KeyUsage; | |
286 | exts[0].critical = CSSM_FALSE; | |
287 | exts[0].format = CSSM_X509_DATAFORMAT_PARSED; | |
288 | keyUsage = CE_KU_DigitalSignature | CE_KU_KeyCertSign | | |
289 | CE_KU_KeyEncipherment | CE_KU_DataEncipherment; | |
290 | exts[0].value.parsedValue = &keyUsage; | |
291 | exts[0].BERvalue.Data = NULL; | |
292 | exts[0].BERvalue.Length = 0; | |
293 | ||
294 | /* BasicConstraints for root only */ | |
295 | exts[1].extnId = CSSMOID_BasicConstraints; | |
296 | exts[1].critical = CSSM_TRUE; | |
297 | exts[1].format = CSSM_X509_DATAFORMAT_PARSED; | |
298 | bc.cA = CSSM_TRUE; | |
299 | bc.pathLenConstraintPresent = CSSM_TRUE; | |
300 | bc.pathLenConstraint = 2; | |
301 | exts[1].value.parsedValue = &bc; | |
302 | exts[1].BERvalue.Data = NULL; | |
303 | exts[1].BERvalue.Length = 0; | |
304 | ||
305 | /* cook up root cert */ | |
306 | printf("Creating root cert...\n"); | |
307 | rawCert = CB_MakeCertTemplate(clHand, | |
308 | 0x12345678, // serial number | |
309 | rootName, | |
310 | rootName, | |
311 | notBefore, | |
312 | notAfter, | |
313 | &rootPubKey, | |
314 | sigAlg, | |
315 | NULL, // subjUniqueId | |
316 | NULL, // issuerUniqueId | |
317 | exts, // extensions | |
318 | 2); // numExtensions | |
319 | ||
320 | if(rawCert == NULL) { | |
321 | errorCount++; | |
322 | goto abort; | |
323 | } | |
324 | if(writeBlobs) { | |
325 | writeFile(ROOT_TBS_FILE_NAME, rawCert->Data, rawCert->Length); | |
326 | printf("...wrote %lu bytes to %s\n", rawCert->Length, ROOT_TBS_FILE_NAME); | |
327 | } | |
328 | ||
329 | /* Self-sign; this is a root cert */ | |
330 | crtn = CSSM_CSP_CreateSignatureContext(cspHand, | |
331 | sigAlg, | |
332 | NULL, // AccessCred | |
333 | &rootPrivKey, | |
334 | &signContext); | |
335 | if(crtn) { | |
336 | printError("CSSM_CSP_CreateSignatureContext", crtn); | |
337 | errorCount++; | |
338 | goto abort; | |
339 | } | |
340 | signedRootCert.Data = NULL; | |
341 | signedRootCert.Length = 0; | |
342 | crtn = CSSM_CL_CertSign(clHand, | |
343 | signContext, | |
344 | rawCert, // CertToBeSigned | |
345 | NULL, // SignScope | |
346 | 0, // ScopeSize, | |
347 | &signedRootCert); | |
348 | if(crtn) { | |
349 | printError("CSSM_CL_CertSign", crtn); | |
350 | errorCount++; | |
351 | goto abort; | |
352 | } | |
353 | crtn = CSSM_DeleteContext(signContext); | |
354 | if(crtn) { | |
355 | printError("CSSM_DeleteContext", crtn); | |
356 | errorCount++; | |
357 | goto abort; | |
358 | } | |
359 | appFreeCssmData(rawCert, CSSM_TRUE); | |
360 | if(writeBlobs) { | |
361 | writeFile(ROOT_CERT_FILE_NAME, signedRootCert.Data, signedRootCert.Length); | |
362 | printf("...wrote %lu bytes to %s\n", signedRootCert.Length, | |
363 | ROOT_CERT_FILE_NAME); | |
364 | } | |
365 | ||
366 | /* now a subject cert signed by the root cert */ | |
367 | printf("Creating subject cert...\n"); | |
368 | rawCert = CB_MakeCertTemplate(clHand, | |
369 | 0x8765, // serial number | |
370 | rootName, | |
371 | subjName, | |
372 | notBefore, | |
373 | notAfter, | |
374 | &subjPubKey, | |
375 | sigAlg, | |
376 | NULL, // subjUniqueId | |
377 | NULL, // issuerUniqueId | |
378 | exts, // extensions | |
379 | 1); // numExtensions | |
380 | if(rawCert == NULL) { | |
381 | errorCount++; | |
382 | goto abort; | |
383 | } | |
384 | if(writeBlobs) { | |
385 | writeFile(SUBJ_TBS_FILE_NAME, rawCert->Data, rawCert->Length); | |
386 | printf("...wrote %lu bytes to %s\n", rawCert->Length, SUBJ_TBS_FILE_NAME); | |
387 | } | |
388 | ||
389 | /* sign by root */ | |
390 | crtn = CSSM_CSP_CreateSignatureContext(cspHand, | |
391 | sigAlg, | |
392 | NULL, // AccessCred | |
393 | &rootPrivKey, | |
394 | &signContext); | |
395 | if(crtn) { | |
396 | printError("CSSM_CSP_CreateSignatureContext", crtn); | |
397 | errorCount++; | |
398 | goto abort; | |
399 | } | |
400 | signedSubjCert.Data = NULL; | |
401 | signedSubjCert.Length = 0; | |
402 | crtn = CSSM_CL_CertSign(clHand, | |
403 | signContext, | |
404 | rawCert, // CertToBeSigned | |
405 | NULL, // SignScope | |
406 | 0, // ScopeSize, | |
407 | &signedSubjCert); | |
408 | if(crtn) { | |
409 | printError("CSSM_CL_CertSign", crtn); | |
410 | errorCount++; | |
411 | goto abort; | |
412 | } | |
413 | crtn = CSSM_DeleteContext(signContext); | |
414 | if(crtn) { | |
415 | printError("CSSM_DeleteContext", crtn); | |
416 | errorCount++; | |
417 | goto abort; | |
418 | } | |
419 | appFreeCssmData(rawCert, CSSM_TRUE); | |
420 | if(writeBlobs) { | |
421 | writeFile(SUBJ_CERT_FILE_NAME, signedSubjCert.Data, signedSubjCert.Length); | |
422 | printf("...wrote %lu bytes to %s\n", signedSubjCert.Length, | |
423 | SUBJ_CERT_FILE_NAME); | |
424 | } | |
425 | ||
426 | /* Free the stuff we allocd to get here */ | |
427 | CB_FreeX509Name(rootName); | |
428 | CB_FreeX509Name(subjName); | |
429 | CB_FreeX509Time(notBefore); | |
430 | CB_FreeX509Time(notAfter); | |
431 | ||
432 | /* | |
433 | * Extract public keys from the two certs, verify. | |
434 | */ | |
435 | crtn = CSSM_CL_CertGetKeyInfo(clHand, &signedSubjCert, &extractSubjKey); | |
436 | if(crtn) { | |
437 | printError("CSSM_CL_CertGetKeyInfo", crtn); | |
438 | } | |
439 | else { | |
440 | /* compare key data - header is different. | |
441 | * Known header differences: | |
442 | * -- CspID - CSSM_CL_CertGetKeyInfo returns a key with NULL for | |
443 | * this field | |
444 | * -- Format. rootPubKey : 6 (CSSM_KEYBLOB_RAW_FORMAT_BSAFE) | |
445 | * extractRootKey : 1 (CSSM_KEYBLOB_RAW_FORMAT_PKCS1) | |
446 | * -- KeyAttr. rootPubKey : 0x20 (CSSM_KEYATTR_EXTRACTABLE) | |
447 | * extractRootKey : 0x0 | |
448 | */ | |
449 | if(!compareKeyData(extractSubjKey, &subjPubKey)) { | |
450 | printf("***CSSM_CL_CertGetKeyInfo(signedSubjCert) returned bad key data\n"); | |
451 | } | |
452 | if(extractSubjKey->KeyHeader.LogicalKeySizeInBits != | |
453 | subjPubKey.KeyHeader.LogicalKeySizeInBits) { | |
454 | printf("***EffectiveKeySizeInBits mismatch: extract %u subj %u\n", | |
455 | (unsigned)extractSubjKey->KeyHeader.LogicalKeySizeInBits, | |
456 | (unsigned)subjPubKey.KeyHeader.LogicalKeySizeInBits); | |
457 | } | |
458 | } | |
459 | crtn = CSSM_CL_CertGetKeyInfo(clHand, &signedRootCert, &extractRootKey); | |
460 | if(crtn) { | |
461 | printError("CSSM_CL_CertGetKeyInfo", crtn); | |
462 | } | |
463 | else { | |
464 | if(!compareKeyData(extractRootKey, &rootPubKey)) { | |
465 | printf("***CSSM_CL_CertGetKeyInfo(signedRootCert) returned bad key data\n"); | |
466 | } | |
467 | } | |
468 | ||
469 | /* | |
470 | * Verify: | |
471 | */ | |
472 | printf("Verifying certificates...\n"); | |
473 | ||
474 | /* | |
475 | * Verify root cert by root pub key, should succeed. | |
476 | */ | |
477 | if(verifyCert(clHand, | |
478 | cspHand, | |
479 | &signedRootCert, | |
480 | NULL, | |
481 | &rootPubKey, | |
482 | sigAlg, | |
483 | CSSM_OK, | |
484 | "Verify(root by root key)")) { | |
485 | errorCount++; | |
486 | /* continue */ | |
487 | } | |
488 | ||
489 | /* | |
490 | * Verify root cert by root cert, should succeed. | |
491 | */ | |
492 | if(verifyCert(clHand, | |
493 | cspHand, | |
494 | &signedRootCert, | |
495 | &signedRootCert, | |
496 | NULL, | |
497 | CSSM_ALGID_NONE, // sigAlg not used here | |
498 | CSSM_OK, | |
499 | "Verify(root by root cert)")) { | |
500 | errorCount++; | |
501 | /* continue */ | |
502 | } | |
503 | ||
504 | ||
505 | /* | |
506 | * Verify subject cert by root pub key, should succeed. | |
507 | */ | |
508 | if(verifyCert(clHand, | |
509 | cspHand, | |
510 | &signedSubjCert, | |
511 | NULL, | |
512 | &rootPubKey, | |
513 | sigAlg, | |
514 | CSSM_OK, | |
515 | "Verify(subj by root key)")) { | |
516 | errorCount++; | |
517 | /* continue */ | |
518 | } | |
519 | ||
520 | /* | |
521 | * Verify subject cert by root cert, should succeed. | |
522 | */ | |
523 | if(verifyCert(clHand, | |
524 | cspHand, | |
525 | &signedSubjCert, | |
526 | &signedRootCert, | |
527 | NULL, | |
528 | CSSM_ALGID_NONE, // sigAlg not used here | |
529 | CSSM_OK, | |
530 | "Verify(subj by root cert)")) { | |
531 | errorCount++; | |
532 | /* continue */ | |
533 | } | |
534 | ||
535 | /* | |
536 | * Verify subject cert by root cert AND key, should succeed. | |
537 | */ | |
538 | if(verifyCert(clHand, | |
539 | cspHand, | |
540 | &signedSubjCert, | |
541 | &signedRootCert, | |
542 | &rootPubKey, | |
543 | sigAlg, | |
544 | CSSM_OK, | |
545 | "Verify(subj by root cert and key)")) { | |
546 | errorCount++; | |
547 | /* continue */ | |
548 | } | |
549 | ||
550 | /* | |
551 | * Verify subject cert by extracted root pub key, should succeed. | |
552 | */ | |
553 | if(verifyCert(clHand, | |
554 | cspHand, | |
555 | &signedSubjCert, | |
556 | NULL, | |
557 | extractRootKey, | |
558 | sigAlg, | |
559 | CSSM_OK, | |
560 | "Verify(subj by extracted root key)")) { | |
561 | errorCount++; | |
562 | /* continue */ | |
563 | } | |
564 | ||
565 | /* | |
566 | * Verify subject cert by subject pub key, should fail. | |
567 | */ | |
568 | if(verifyCert(clHand, | |
569 | cspHand, | |
570 | &signedSubjCert, | |
571 | NULL, | |
572 | &subjPubKey, | |
573 | sigAlg, | |
574 | CSSMERR_CL_VERIFICATION_FAILURE, | |
575 | "Verify(subj by subj key)")) { | |
576 | errorCount++; | |
577 | /* continue */ | |
578 | } | |
579 | ||
580 | /* | |
581 | * Verify subject cert by subject cert, should fail. | |
582 | */ | |
583 | if(verifyCert(clHand, | |
584 | cspHand, | |
585 | &signedSubjCert, | |
586 | &signedSubjCert, | |
587 | NULL, | |
588 | CSSM_ALGID_NONE, // sigAlg not used here | |
589 | CSSMERR_CL_VERIFICATION_FAILURE, | |
590 | "Verify(subj by subj cert)")) { | |
591 | errorCount++; | |
592 | /* continue */ | |
593 | } | |
594 | ||
595 | /* | |
596 | * Verify erroneous subject cert by root pub key, should fail. | |
597 | */ | |
598 | badByte = genRand(1, signedSubjCert.Length - 1); | |
599 | signedSubjCert.Data[badByte] ^= 0x55; | |
600 | if(verifyCert(clHand, | |
601 | cspHand, | |
602 | &signedSubjCert, | |
603 | NULL, | |
604 | &rootPubKey, | |
605 | sigAlg, | |
606 | CSSMERR_CL_VERIFICATION_FAILURE, | |
607 | "Verify(bad subj by root key)")) { | |
608 | errorCount++; | |
609 | /* continue */ | |
610 | } | |
611 | ||
612 | ||
613 | /* free/delete certs and keys */ | |
614 | appFreeCssmData(&signedSubjCert, CSSM_FALSE); | |
615 | appFreeCssmData(&signedRootCert, CSSM_FALSE); | |
616 | ||
617 | cspFreeKey(cspHand, &rootPubKey); | |
618 | cspFreeKey(cspHand, &subjPubKey); | |
619 | ||
620 | /* These don't work because CSSM_CL_CertGetKeyInfo() gives keys with | |
621 | * a bogus GUID. This may be a problem with the Apple CSP... | |
622 | * | |
623 | cspFreeKey(cspHand, extractRootKey); | |
624 | cspFreeKey(cspHand, extractSubjKey); | |
625 | * | |
626 | * do it this way instead...*/ | |
627 | CSSM_FREE(extractRootKey->KeyData.Data); | |
628 | CSSM_FREE(extractSubjKey->KeyData.Data); | |
629 | ||
630 | /* need to do this regardless...*/ | |
631 | CSSM_FREE(extractRootKey); | |
632 | CSSM_FREE(extractSubjKey); | |
633 | ||
634 | abort: | |
635 | if(cspHand != 0) { | |
636 | CSSM_ModuleDetach(cspHand); | |
637 | } | |
638 | ||
639 | if(errorCount) { | |
640 | printf("Signer/Subject test failed with %d errors\n", errorCount); | |
641 | } | |
642 | else { | |
643 | printf("Signer/Subject test succeeded\n"); | |
644 | } | |
645 | return 0; | |
646 | } | |
647 | ||
648 | ||
649 | /* compare KeyData for two keys. */ | |
650 | static CSSM_BOOL compareKeyData(const CSSM_KEY *key1, const CSSM_KEY *key2) | |
651 | { | |
652 | if(key1->KeyData.Length != key2->KeyData.Length) { | |
653 | return CSSM_FALSE; | |
654 | } | |
655 | if(memcmp(key1->KeyData.Data, | |
656 | key2->KeyData.Data, | |
657 | key1->KeyData.Length)) { | |
658 | return CSSM_FALSE; | |
659 | } | |
660 | return CSSM_TRUE; | |
661 | } | |
662 | ||
663 | /* verify a cert using specified key and/or signerCert */ | |
664 | static CSSM_RETURN verifyCert(CSSM_CL_HANDLE clHand, | |
665 | CSSM_CSP_HANDLE cspHand, | |
666 | CSSM_DATA_PTR cert, | |
667 | CSSM_DATA_PTR signerCert, // optional | |
668 | CSSM_KEY_PTR key, // ditto, to work spec one, other, or both | |
669 | CSSM_ALGORITHMS sigAlg, // CSSM_ALGID_SHA1WithRSA, etc. | |
670 | CSSM_RETURN expectResult, | |
671 | const char *opString) | |
672 | { | |
673 | CSSM_RETURN crtn; | |
674 | CSSM_CC_HANDLE signContext = CSSM_INVALID_HANDLE; | |
675 | ||
676 | if(key) { | |
677 | crtn = CSSM_CSP_CreateSignatureContext(cspHand, | |
678 | sigAlg, | |
679 | NULL, // AccessCred | |
680 | key, | |
681 | &signContext); | |
682 | if(crtn) { | |
683 | printf("Failure during %s\n", opString); | |
684 | printError("CSSM_CSP_CreateSignatureContext", crtn); | |
685 | return crtn; | |
686 | } | |
687 | } | |
688 | crtn = CSSM_CL_CertVerify(clHand, | |
689 | signContext, | |
690 | cert, // CertToBeVerified | |
691 | signerCert, // SignerCert | |
692 | NULL, // VerifyScope | |
693 | 0); // ScopeSize | |
694 | if(crtn != expectResult) { | |
695 | printf("Failure during %s\n", opString); | |
696 | if(crtn == CSSM_OK) { | |
697 | printf("Unexpected CSSM_CL_CertVerify success\n"); | |
698 | } | |
699 | else if(expectResult == CSSM_OK) { | |
700 | printError("CSSM_CL_CertVerify", crtn); | |
701 | } | |
702 | else { | |
703 | printError("CSSM_CL_CertVerify: expected", expectResult); | |
704 | printError("CSSM_CL_CertVerify: got ", crtn); | |
705 | } | |
706 | return CSSMERR_CL_VERIFICATION_FAILURE; | |
707 | } | |
708 | if(signContext != CSSM_INVALID_HANDLE) { | |
709 | crtn = CSSM_DeleteContext(signContext); | |
710 | if(crtn) { | |
711 | printf("Failure during %s\n", opString); | |
712 | printError("CSSM_DeleteContext", crtn); | |
713 | return crtn; | |
714 | } | |
715 | } | |
716 | return CSSM_OK; | |
717 | } |