]> git.saurik.com Git - apple/security.git/blob - SecurityTests/clxutils/dotMacRequest/dotMacRequest.cpp
Security-57031.1.35.tar.gz
[apple/security.git] / SecurityTests / clxutils / dotMacRequest / dotMacRequest.cpp
1 /*
2 * dotMacRequest.cpp - simple illustration of using SecCertificateRequestCreate() and
3 * SecCertificateRequestSubmit to post a request for a .mac cert.
4 */
5 #include <Security/Security.h>
6 #include <Security/SecCertificateRequest.h>
7 #include <security_dotmac_tp/dotMacTp.h>
8 #include <clAppUtils/keyPicker.h>
9 #include <unistd.h>
10 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
11
12 /*
13 * Defaults for the test setup du jour
14 */
15 #define USER_DEFAULT "dmitch10"
16 #define PWD_DEFAULT "password"
17 #define HOST_DEFAULT "certmgmt.mac.com"
18
19 /*
20 * Type of cert to request
21 */
22 typedef enum {
23 CRT_Identity, /* actually, now "iChat encryption", not "identity" */
24 CRT_EmailSign,
25 CRT_EmailEncrypt
26 } CertRequestType;
27
28 static void usage(char **argv)
29 {
30 printf("usage: %s op [options]\n", argv[0]);
31 printf("Op:\n");
32 printf(" i -- generate iChat encryption cert\n");
33 printf(" s -- generate email signing cert\n");
34 printf(" e -- generate email encrypting cert\n");
35 printf(" I -- search/retrieve request for iChat encryption cert\n");
36 printf(" S -- search/retrieve request for signing cert\n");
37 printf(" E -- search/retrieve request for encrypting cert\n");
38 printf(" p -- pending request poll (via -u)\n");
39 printf("Options:\n");
40 printf(" -u username -- Default is %s\n", USER_DEFAULT);
41 printf(" -Z password -- default is %s\n", PWD_DEFAULT);
42 printf(" -p -- pick key pair from existing (default is generate)\n");
43 printf(" -k keychain -- Source/destination of keys\n");
44 printf(" -r -- Renew (default is new)\n");
45 printf(" -a -- async (default is synchronous)\n");
46 printf(" -H hostname -- Alternate .mac server host name (default %s)\n",
47 HOST_DEFAULT);
48 printf(" -M -- Pause for MallocDebug\n");
49 printf(" -l -- loop\n");
50 exit(1);
51 }
52
53 /* print a string int he form of a CSSM_DATA */
54 static void printString(
55 const CSSM_DATA *str)
56 {
57 for(unsigned dex=0; dex<str->Length; dex++) {
58 printf("%c", str->Data[dex]);
59 }
60 }
61
62 /* basic "generate keypair" routine */
63 static OSStatus genKeyPair(
64 SecKeychainRef kcRef, // optional, NULL means the default list
65 SecKeyRef *pubKey, // RETURNED
66 SecKeyRef *privKey) // RETURNED
67 {
68 OSStatus ortn;
69
70 ortn = SecKeyCreatePair(kcRef,
71 DOT_MAC_KEY_ALG,
72 DOT_MAC_KEY_SIZE,
73 0, // context handle
74 /* public key usage and attrs */
75 CSSM_KEYUSE_ANY,
76 CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_PERMANENT | CSSM_KEYATTR_EXTRACTABLE,
77 /* private key usage and attrs */
78 CSSM_KEYUSE_ANY,
79 CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_PERMANENT | CSSM_KEYATTR_EXTRACTABLE |
80 CSSM_KEYATTR_SENSITIVE,
81 NULL, // initial access
82 pubKey,
83 privKey);
84 if(ortn) {
85 cssmPerror("SecKeyCreatePair", ortn);
86 }
87 return ortn;
88 }
89
90 /* max number of oid/value pairs */
91 #define MAX_ATTRS 5
92
93 /*
94 * search for a pending .mac cert request, get current status.
95 */
96 static OSStatus dotMacGetPendingRequest(
97 /* required fields */
98 const char *userName, // REQUIRED, C string
99 const char *password, // REQUIRED, C string
100 CertRequestType requestType,
101
102 /* optional fields */
103 const char *hostName, // C string
104 SecKeychainRef keychain) // destination of created cert (if !async)
105 {
106 SecCertificateRequestAttribute attrs[MAX_ATTRS];
107 SecCertificateRequestAttribute *attrp = attrs;
108 SecCertificateRequestAttributeList attrList;
109
110 attrList.count = 0;
111 attrList.attr = attrs;
112
113 /* user name */
114 attrp->oid = CSSMOID_DOTMAC_CERT_REQ_VALUE_USERNAME;
115 attrp->value.Data = (uint8 *)userName;
116 attrp->value.Length = strlen(userName);
117 attrp++;
118 attrList.count++;
119
120 /* password */
121 attrp->oid = CSSMOID_DOTMAC_CERT_REQ_VALUE_PASSWORD;
122 attrp->value.Data = (uint8 *)password;
123 attrp->value.Length = strlen(password);
124 attrp++;
125 attrList.count++;
126
127 /* options */
128
129 if(hostName) {
130 attrp->oid = CSSMOID_DOTMAC_CERT_REQ_VALUE_HOSTNAME;
131 attrp->value.Data = (uint8 *)hostName;
132 attrp->value.Length = strlen(hostName);
133 attrp++;
134 attrList.count++;
135 }
136
137 /* map CertRequestType to a policy OID */
138 const CSSM_OID *policy;
139 switch(requestType) {
140 case CRT_Identity:
141 policy = &CSSMOID_DOTMAC_CERT_REQ_IDENTITY;
142 break;
143 case CRT_EmailSign:
144 policy = &CSSMOID_DOTMAC_CERT_REQ_EMAIL_SIGN;
145 break;
146 case CRT_EmailEncrypt:
147 policy = &CSSMOID_DOTMAC_CERT_REQ_EMAIL_ENCRYPT;
148 break;
149 default:
150 printf("GAK! Bad cert type.\n");
151 return -1;
152 }
153 OSStatus ortn;
154 SecCertificateRequestRef certReq = NULL;
155 SecCertificateRef certRef = NULL;
156 sint32 estTime;
157
158 printf("...calling SecCertificateFindRequest\n");
159 ortn = SecCertificateFindRequest(policy,
160 CSSM_CERT_X_509v3,
161 CSSM_TP_AUTHORITY_REQUEST_CERTISSUE,
162 NULL, NULL, // no keys needed
163 &attrList,
164 &certReq);
165 if(ortn) {
166 cssmPerror("SecCertificateFindRequest", ortn);
167 return ortn;
168 }
169
170 printf("...calling SecCertificateRequestGetResult\n");
171 ortn = SecCertificateRequestGetResult(certReq, keychain, &estTime, &certRef);
172 if(ortn) {
173 cssmPerror("SecCertificateRequestGetResult", ortn);
174 }
175 else {
176 printf("...SecCertificateRequestGetResult succeeded; estTime %d; cert %s\n",
177 (int)estTime, certRef ? "OBTAINED" : "NOT OBTAINED");
178 }
179 if(certRef) {
180 CFRelease(certRef);
181 }
182 if(certReq) {
183 CFRelease(certReq);
184 }
185 return ortn;
186 }
187
188 /*
189 * Do an "is there a pending request for this user?" poll.
190 * That function - via SecCertificateFindRequest() always returns an error;
191 * *we* only return an error if the result is something other than the
192 * expected two results:
193 * CSSMERR_APPLE_DOTMAC_REQ_IS_PENDING
194 * CSSMERR_APPLE_DOTMAC_NO_REQ_PENDING
195 */
196 static OSStatus dotMacPostPendingReqPoll(
197 const char *userName,
198 const char *password,
199 const char *hostName)
200 {
201 SecCertificateRequestAttribute attrs[MAX_ATTRS];
202 SecCertificateRequestAttribute *attrp = attrs;
203 SecCertificateRequestAttributeList attrList;
204 uint8 oneBit = 1;
205
206 attrList.count = 0;
207 attrList.attr = attrs;
208
209 /* user name, required */
210 attrp->oid = CSSMOID_DOTMAC_CERT_REQ_VALUE_USERNAME;
211 attrp->value.Data = (uint8 *)userName;
212 attrp->value.Length = strlen(userName);
213 attrp++;
214 attrList.count++;
215
216 /* password, required */
217 attrp->oid = CSSMOID_DOTMAC_CERT_REQ_VALUE_PASSWORD;
218 attrp->value.Data = (uint8 *)password;
219 attrp->value.Length = strlen(password);
220 attrp++;
221 attrList.count++;
222
223 /* the "poll the server" indicator */
224 attrp->oid = CSSMOID_DOTMAC_CERT_REQ_VALUE_IS_PENDING;
225 /* true ::= any nonzero data */
226 attrp->value.Data = &oneBit;
227 attrp->value.Length = 1;
228 attrp++;
229 attrList.count++;
230
231 /* options */
232
233 if(hostName) {
234 attrp->oid = CSSMOID_DOTMAC_CERT_REQ_VALUE_HOSTNAME;
235 attrp->value.Data = (uint8 *)hostName;
236 attrp->value.Length = strlen(hostName);
237 attrp++;
238 attrList.count++;
239 }
240
241 /* policy, not technically needed; use this one by convention */
242 const CSSM_OID *policy = &CSSMOID_DOTMAC_CERT_REQ_IDENTITY;
243
244 OSStatus ortn;
245 SecCertificateRequestRef certReq = NULL;
246
247 printf("...calling SecCertificateFindRequest\n");
248 ortn = SecCertificateFindRequest(policy,
249 CSSM_CERT_X_509v3,
250 CSSM_TP_AUTHORITY_REQUEST_CERTISSUE,
251 NULL, NULL, // no keys needed
252 &attrList,
253 &certReq);
254
255 switch(ortn) {
256 case CSSMERR_APPLE_DOTMAC_REQ_IS_PENDING:
257 printf("...result: REQ_IS_PENDING\n");
258 ortn = noErr;
259 break;
260 case CSSMERR_APPLE_DOTMAC_NO_REQ_PENDING:
261 printf("...result: NO_REQ_PENDING\n");
262 ortn = noErr;
263 break;
264 case noErr:
265 /* should never happen */
266 printf("...UNEXPECTED SUCCESS on SecCertificateFindRequest\n");
267 ortn = internalComponentErr;
268 if(certReq != NULL) {
269 /* Somehow, it got created */
270 CFRelease(certReq);
271 }
272 break;
273 default:
274 cssmPerror("SecCertificateFindRequest", ortn);
275 break;
276 }
277 return ortn;
278 }
279
280 /*
281 * Post a .mac cert request, with a small number of options.
282 */
283 static OSStatus dotMacPostCertRequest(
284 /* required fields */
285 const char *userName, // REQUIRED, C string
286 const char *password, // REQUIRED, C string
287 SecKeyRef privKey, // REQUIRED
288 SecKeyRef pubKey,
289 CertRequestType requestType,
290 bool renew, // false: new cert
291 // true : renew existing
292 bool async, // false: wait for result
293 // true : just post request and return
294 /* optional fields */
295 const char *hostName, // C string
296 SecKeychainRef keychain) // destination of created cert (if !async)
297 {
298
299 /* the main job here is bundling up the arguments in an array of OID/value pairs */
300 SecCertificateRequestAttribute attrs[MAX_ATTRS];
301 SecCertificateRequestAttribute *attrp = attrs;
302 SecCertificateRequestAttributeList attrList;
303 uint8 oneBit = 1;
304
305 attrList.count = 0;
306 attrList.attr = attrs;
307
308 /* user name */
309 attrp->oid = CSSMOID_DOTMAC_CERT_REQ_VALUE_USERNAME;
310 attrp->value.Data = (uint8 *)userName;
311 attrp->value.Length = strlen(userName);
312 attrp++;
313 attrList.count++;
314
315 /* password */
316 attrp->oid = CSSMOID_DOTMAC_CERT_REQ_VALUE_PASSWORD;
317 attrp->value.Data = (uint8 *)password;
318 attrp->value.Length = strlen(password);
319 attrp++;
320 attrList.count++;
321
322 /* options */
323
324 if(hostName) {
325 attrp->oid = CSSMOID_DOTMAC_CERT_REQ_VALUE_HOSTNAME;
326 attrp->value.Data = (uint8 *)hostName;
327 attrp->value.Length = strlen(hostName);
328 attrp++;
329 attrList.count++;
330 }
331
332 if(renew) {
333 attrp->oid = CSSMOID_DOTMAC_CERT_REQ_VALUE_RENEW;
334 /* true ::= any nonzero data */
335 attrp->value.Data = &oneBit;
336 attrp->value.Length = 1;
337 attrp++;
338 attrList.count++;
339 }
340
341 if(async) {
342 attrp->oid = CSSMOID_DOTMAC_CERT_REQ_VALUE_ASYNC;
343 /* true ::= any nonzero data */
344 attrp->value.Data = &oneBit;
345 attrp->value.Length = 1;
346 attrp++;
347 attrList.count++;
348 }
349
350 /* map CertRequestType to a policy OID */
351 const CSSM_OID *policy;
352 switch(requestType) {
353 case CRT_Identity:
354 policy = &CSSMOID_DOTMAC_CERT_REQ_IDENTITY;
355 break;
356 case CRT_EmailSign:
357 policy = &CSSMOID_DOTMAC_CERT_REQ_EMAIL_SIGN;
358 break;
359 case CRT_EmailEncrypt:
360 policy = &CSSMOID_DOTMAC_CERT_REQ_EMAIL_ENCRYPT;
361 break;
362 default:
363 printf("GAK! Bad cert type.\n");
364 return -1;
365 }
366 OSStatus ortn;
367 SecCertificateRequestRef certReq = NULL;
368
369 ortn = SecCertificateRequestCreate(policy,
370 CSSM_CERT_X_509v3,
371 CSSM_TP_AUTHORITY_REQUEST_CERTISSUE,
372 privKey,
373 pubKey,
374 &attrList,
375 &certReq);
376 if(ortn) {
377 cssmPerror("SecCertificateRequestCreate", ortn);
378 return ortn;
379 }
380
381 printf("...submitting request to .mac server\n");
382 sint32 estTime = 0;
383 ortn = SecCertificateRequestSubmit(certReq, &estTime);
384 switch(ortn) {
385 case CSSMERR_APPLE_DOTMAC_REQ_REDIRECT:
386 {
387 /*
388 * A special case; the server is redirecting the calling app to
389 * a URL which we fetch and report like so:
390 */
391 CSSM_DATA url = {0, NULL};
392 ortn = SecCertificateRequestGetData(certReq, &url);
393 if(ortn) {
394 cssmPerror("SecCertificateRequestGetData", ortn);
395 printf("***APPLE_DOTMAC_REQ_REDIRECT obtained but no URL availalble.\n");
396 }
397 else {
398 printf("***APPLE_DOTMAC_REQ_REDIRECT obtained; redirect URL is: ");
399 printString(&url);
400 printf("\n");
401 }
402 break;
403 }
404
405 case CSSM_OK:
406 printf("...cert request submitted; estimatedTime %d.\n", (int)estTime);
407 break;
408 default:
409 cssmPerror("SecCertificateRequestSubmit", ortn);
410 break;
411 }
412 if(ortn || async) {
413 /* we're done */
414 CFRelease(certReq);
415 return ortn;
416 }
417
418 /*
419 * Running synchronously, and the submit succeeded. Try to get a result.
420 * In the real world this would be polled, every so often....
421 */
422 SecCertificateRef certRef = NULL;
423 printf("...attempting to get result of cert request...\n");
424 ortn = SecCertificateRequestGetResult(certReq, keychain, &estTime, &certRef);
425 if(ortn) {
426 cssmPerror("SecCertificateRequestGetResult", ortn);
427 }
428 else {
429 printf("...SecCertificateRequestGetResult succeeded; estTime %d; cert %s\n",
430 (int)estTime, certRef ? "OBTAINED" : "NOT OBTAINED");
431 }
432 if(certRef) {
433 CFRelease(certRef);
434 CFRelease(certReq);
435 }
436 return ortn;
437 }
438
439 #define ALWAYS_DO_SUBMIT 0
440
441
442 int main(int argc, char **argv)
443 {
444 SecKeyRef pubKeyRef = NULL;
445 SecKeyRef privKeyRef = NULL;
446 SecKeychainRef kcRef = NULL;
447 OSStatus ortn;
448
449 /* user-spec'd variables */
450 bool genKeys = true; /* true: generate; false: pick 'em */
451 char *keychainName = NULL;
452 char *userName = USER_DEFAULT;
453 char *password = PWD_DEFAULT;
454 char *hostName = NULL; /* leave as the default! = HOST_DEFAULT; */
455 /*
456 * WARNING: doing a renew operation requires that you delete your *current*
457 * .mac cert from the destination keychain. The DB attrs of the old and new certs
458 * are the same!
459 */
460 bool doRenew = false;
461 CertRequestType reqType = CRT_Identity;
462 bool doPause = false;
463 bool async = false;
464 bool doSearch = false; /* false: post cert request
465 * true : search for existing request, get
466 * status for it */
467 bool loop = false;
468 bool doPendingReqPoll = false;
469
470 if(argc < 2) {
471 usage(argv);
472 }
473 switch(argv[1][0]) {
474 case 'i':
475 reqType = CRT_Identity;
476 break;
477 case 's':
478 reqType = CRT_EmailSign;
479 break;
480 case 'e':
481 reqType = CRT_EmailEncrypt;
482 break;
483 case 'I':
484 doSearch = true;
485 reqType = CRT_Identity;
486 break;
487 case 'S':
488 doSearch = true;
489 reqType = CRT_EmailSign;
490 break;
491 case 'E':
492 doSearch = true;
493 reqType = CRT_EmailEncrypt;
494 break;
495 case 'p':
496 doPendingReqPoll = true;
497 break;
498 default:
499 usage(argv);
500 }
501
502 extern char *optarg;
503 extern int optind;
504 optind = 2;
505 int arg;
506 while ((arg = getopt(argc, argv, "u:Z:pk:rMH:al")) != -1) {
507 switch (arg) {
508 case 'u':
509 userName = optarg;
510 break;
511 case 'Z':
512 password = optarg;
513 break;
514 case 'p':
515 genKeys = false;
516 break;
517 case 'k':
518 keychainName = optarg;
519 break;
520 case 'r':
521 doRenew = true;
522 break;
523 case 'M':
524 doPause = true;
525 break;
526 case 'H':
527 hostName = optarg;
528 break;
529 case 'a':
530 async = true;
531 break;
532 case 'l':
533 loop = true;
534 break;
535 case 'h':
536 default:
537 usage(argv);
538 }
539 }
540 if(optind != argc) {
541 usage(argv);
542 }
543
544 if(doPause) {
545 fpurge(stdin);
546 printf("Pausing for MallocDebug attach; CR to continue: ");
547 getchar();
548 }
549
550 if(keychainName != NULL) {
551 /* pick a keychain (optional) */
552 ortn = SecKeychainOpen(keychainName, &kcRef);
553 if(ortn) {
554 cssmPerror("SecKeychainOpen", ortn);
555 exit(1);
556 }
557
558 /* make sure it's there since a successful SecKeychainOpen proves nothing */
559 SecKeychainStatus kcStat;
560 ortn = SecKeychainGetStatus(kcRef, &kcStat);
561 if(ortn) {
562 cssmPerror("SecKeychainGetStatus", ortn);
563 exit(1);
564 }
565 }
566
567 if((!doSearch || ALWAYS_DO_SUBMIT) && !doPendingReqPoll) {
568 /* get a key pair, somehow */
569 if(genKeys) {
570 ortn = genKeyPair(kcRef, &pubKeyRef, &privKeyRef);
571 }
572 else {
573 ortn = keyPicker(kcRef, &pubKeyRef, &privKeyRef);
574 }
575 if(ortn) {
576 printf("Can't proceed without a keypair. Aborting.\n");
577 exit(1);
578 }
579 }
580
581 /* go */
582 do {
583 if(doSearch) {
584 #if ALWAYS_DO_SUBMIT
585 /* debug only */
586 dotMacPostCertRequest(userName, password, privKeyRef, pubKeyRef,
587 reqType, doRenew, async, hostName, kcRef);
588 #endif
589
590 /* end */
591 ortn = dotMacGetPendingRequest(userName, password, reqType, hostName, kcRef);
592 }
593 else if(doPendingReqPoll) {
594 ortn = dotMacPostPendingReqPoll(userName, password, hostName);
595 }
596 else {
597 ortn = dotMacPostCertRequest(userName, password, privKeyRef, pubKeyRef,
598 reqType, doRenew, async, hostName, kcRef);
599 }
600 if(doPause) {
601 fpurge(stdin);
602 printf("Pausing for MallocDebug attach; CR to continue: ");
603 getchar();
604 }
605 } while(loop);
606 if(privKeyRef) {
607 CFRelease(privKeyRef);
608 }
609 if(pubKeyRef) {
610 CFRelease(pubKeyRef);
611 }
612 if(kcRef) {
613 CFRelease(kcRef);
614 }
615
616 if(doPause) {
617 fpurge(stdin);
618 printf("Pausing at end of test for MallocDebug attach; CR to continue: ");
619 getchar();
620 }
621
622 return ortn;
623 }
624