2 * dotMacRequest.cpp - simple illustration of using SecCertificateRequestCreate() and
3 * SecCertificateRequestSubmit to post a request for a .mac cert.
5 #include <Security/Security.h>
6 #include <Security/SecCertificateRequest.h>
7 #include <security_dotmac_tp/dotMacTp.h>
8 #include <clAppUtils/keyPicker.h>
10 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
13 * Defaults for the test setup du jour
15 #define USER_DEFAULT "dmitch10"
16 #define PWD_DEFAULT "password"
17 #define HOST_DEFAULT "certmgmt.mac.com"
20 * Type of cert to request
23 CRT_Identity
, /* actually, now "iChat encryption", not "identity" */
28 static void usage(char **argv
)
30 printf("usage: %s op [options]\n", argv
[0]);
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");
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",
48 printf(" -M -- Pause for MallocDebug\n");
49 printf(" -l -- loop\n");
53 /* print a string int he form of a CSSM_DATA */
54 static void printString(
57 for(unsigned dex
=0; dex
<str
->Length
; dex
++) {
58 printf("%c", str
->Data
[dex
]);
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
70 ortn
= SecKeyCreatePair(kcRef
,
74 /* public key usage and attrs */
76 CSSM_KEYATTR_RETURN_REF
| CSSM_KEYATTR_PERMANENT
| CSSM_KEYATTR_EXTRACTABLE
,
77 /* private key usage and attrs */
79 CSSM_KEYATTR_RETURN_REF
| CSSM_KEYATTR_PERMANENT
| CSSM_KEYATTR_EXTRACTABLE
|
80 CSSM_KEYATTR_SENSITIVE
,
81 NULL
, // initial access
85 cssmPerror("SecKeyCreatePair", ortn
);
90 /* max number of oid/value pairs */
94 * search for a pending .mac cert request, get current status.
96 static OSStatus
dotMacGetPendingRequest(
98 const char *userName
, // REQUIRED, C string
99 const char *password
, // REQUIRED, C string
100 CertRequestType requestType
,
102 /* optional fields */
103 const char *hostName
, // C string
104 SecKeychainRef keychain
) // destination of created cert (if !async)
106 SecCertificateRequestAttribute attrs
[MAX_ATTRS
];
107 SecCertificateRequestAttribute
*attrp
= attrs
;
108 SecCertificateRequestAttributeList attrList
;
111 attrList
.attr
= attrs
;
114 attrp
->oid
= CSSMOID_DOTMAC_CERT_REQ_VALUE_USERNAME
;
115 attrp
->value
.Data
= (uint8
*)userName
;
116 attrp
->value
.Length
= strlen(userName
);
121 attrp
->oid
= CSSMOID_DOTMAC_CERT_REQ_VALUE_PASSWORD
;
122 attrp
->value
.Data
= (uint8
*)password
;
123 attrp
->value
.Length
= strlen(password
);
130 attrp
->oid
= CSSMOID_DOTMAC_CERT_REQ_VALUE_HOSTNAME
;
131 attrp
->value
.Data
= (uint8
*)hostName
;
132 attrp
->value
.Length
= strlen(hostName
);
137 /* map CertRequestType to a policy OID */
138 const CSSM_OID
*policy
;
139 switch(requestType
) {
141 policy
= &CSSMOID_DOTMAC_CERT_REQ_IDENTITY
;
144 policy
= &CSSMOID_DOTMAC_CERT_REQ_EMAIL_SIGN
;
146 case CRT_EmailEncrypt
:
147 policy
= &CSSMOID_DOTMAC_CERT_REQ_EMAIL_ENCRYPT
;
150 printf("GAK! Bad cert type.\n");
154 SecCertificateRequestRef certReq
= NULL
;
155 SecCertificateRef certRef
= NULL
;
158 printf("...calling SecCertificateFindRequest\n");
159 ortn
= SecCertificateFindRequest(policy
,
161 CSSM_TP_AUTHORITY_REQUEST_CERTISSUE
,
162 NULL
, NULL
, // no keys needed
166 cssmPerror("SecCertificateFindRequest", ortn
);
170 printf("...calling SecCertificateRequestGetResult\n");
171 ortn
= SecCertificateRequestGetResult(certReq
, keychain
, &estTime
, &certRef
);
173 cssmPerror("SecCertificateRequestGetResult", ortn
);
176 printf("...SecCertificateRequestGetResult succeeded; estTime %d; cert %s\n",
177 (int)estTime
, certRef
? "OBTAINED" : "NOT OBTAINED");
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
196 static OSStatus
dotMacPostPendingReqPoll(
197 const char *userName
,
198 const char *password
,
199 const char *hostName
)
201 SecCertificateRequestAttribute attrs
[MAX_ATTRS
];
202 SecCertificateRequestAttribute
*attrp
= attrs
;
203 SecCertificateRequestAttributeList attrList
;
207 attrList
.attr
= attrs
;
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
);
216 /* password, required */
217 attrp
->oid
= CSSMOID_DOTMAC_CERT_REQ_VALUE_PASSWORD
;
218 attrp
->value
.Data
= (uint8
*)password
;
219 attrp
->value
.Length
= strlen(password
);
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;
234 attrp
->oid
= CSSMOID_DOTMAC_CERT_REQ_VALUE_HOSTNAME
;
235 attrp
->value
.Data
= (uint8
*)hostName
;
236 attrp
->value
.Length
= strlen(hostName
);
241 /* policy, not technically needed; use this one by convention */
242 const CSSM_OID
*policy
= &CSSMOID_DOTMAC_CERT_REQ_IDENTITY
;
245 SecCertificateRequestRef certReq
= NULL
;
247 printf("...calling SecCertificateFindRequest\n");
248 ortn
= SecCertificateFindRequest(policy
,
250 CSSM_TP_AUTHORITY_REQUEST_CERTISSUE
,
251 NULL
, NULL
, // no keys needed
256 case CSSMERR_APPLE_DOTMAC_REQ_IS_PENDING
:
257 printf("...result: REQ_IS_PENDING\n");
260 case CSSMERR_APPLE_DOTMAC_NO_REQ_PENDING
:
261 printf("...result: NO_REQ_PENDING\n");
265 /* should never happen */
266 printf("...UNEXPECTED SUCCESS on SecCertificateFindRequest\n");
267 ortn
= internalComponentErr
;
268 if(certReq
!= NULL
) {
269 /* Somehow, it got created */
274 cssmPerror("SecCertificateFindRequest", ortn
);
281 * Post a .mac cert request, with a small number of options.
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
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)
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
;
306 attrList
.attr
= attrs
;
309 attrp
->oid
= CSSMOID_DOTMAC_CERT_REQ_VALUE_USERNAME
;
310 attrp
->value
.Data
= (uint8
*)userName
;
311 attrp
->value
.Length
= strlen(userName
);
316 attrp
->oid
= CSSMOID_DOTMAC_CERT_REQ_VALUE_PASSWORD
;
317 attrp
->value
.Data
= (uint8
*)password
;
318 attrp
->value
.Length
= strlen(password
);
325 attrp
->oid
= CSSMOID_DOTMAC_CERT_REQ_VALUE_HOSTNAME
;
326 attrp
->value
.Data
= (uint8
*)hostName
;
327 attrp
->value
.Length
= strlen(hostName
);
333 attrp
->oid
= CSSMOID_DOTMAC_CERT_REQ_VALUE_RENEW
;
334 /* true ::= any nonzero data */
335 attrp
->value
.Data
= &oneBit
;
336 attrp
->value
.Length
= 1;
342 attrp
->oid
= CSSMOID_DOTMAC_CERT_REQ_VALUE_ASYNC
;
343 /* true ::= any nonzero data */
344 attrp
->value
.Data
= &oneBit
;
345 attrp
->value
.Length
= 1;
350 /* map CertRequestType to a policy OID */
351 const CSSM_OID
*policy
;
352 switch(requestType
) {
354 policy
= &CSSMOID_DOTMAC_CERT_REQ_IDENTITY
;
357 policy
= &CSSMOID_DOTMAC_CERT_REQ_EMAIL_SIGN
;
359 case CRT_EmailEncrypt
:
360 policy
= &CSSMOID_DOTMAC_CERT_REQ_EMAIL_ENCRYPT
;
363 printf("GAK! Bad cert type.\n");
367 SecCertificateRequestRef certReq
= NULL
;
369 ortn
= SecCertificateRequestCreate(policy
,
371 CSSM_TP_AUTHORITY_REQUEST_CERTISSUE
,
377 cssmPerror("SecCertificateRequestCreate", ortn
);
381 printf("...submitting request to .mac server\n");
383 ortn
= SecCertificateRequestSubmit(certReq
, &estTime
);
385 case CSSMERR_APPLE_DOTMAC_REQ_REDIRECT
:
388 * A special case; the server is redirecting the calling app to
389 * a URL which we fetch and report like so:
391 CSSM_DATA url
= {0, NULL
};
392 ortn
= SecCertificateRequestGetData(certReq
, &url
);
394 cssmPerror("SecCertificateRequestGetData", ortn
);
395 printf("***APPLE_DOTMAC_REQ_REDIRECT obtained but no URL availalble.\n");
398 printf("***APPLE_DOTMAC_REQ_REDIRECT obtained; redirect URL is: ");
406 printf("...cert request submitted; estimatedTime %d.\n", (int)estTime
);
409 cssmPerror("SecCertificateRequestSubmit", ortn
);
419 * Running synchronously, and the submit succeeded. Try to get a result.
420 * In the real world this would be polled, every so often....
422 SecCertificateRef certRef
= NULL
;
423 printf("...attempting to get result of cert request...\n");
424 ortn
= SecCertificateRequestGetResult(certReq
, keychain
, &estTime
, &certRef
);
426 cssmPerror("SecCertificateRequestGetResult", ortn
);
429 printf("...SecCertificateRequestGetResult succeeded; estTime %d; cert %s\n",
430 (int)estTime
, certRef
? "OBTAINED" : "NOT OBTAINED");
439 #define ALWAYS_DO_SUBMIT 0
442 int main(int argc
, char **argv
)
444 SecKeyRef pubKeyRef
= NULL
;
445 SecKeyRef privKeyRef
= NULL
;
446 SecKeychainRef kcRef
= NULL
;
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; */
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
460 bool doRenew
= false;
461 CertRequestType reqType
= CRT_Identity
;
462 bool doPause
= false;
464 bool doSearch
= false; /* false: post cert request
465 * true : search for existing request, get
468 bool doPendingReqPoll
= false;
475 reqType
= CRT_Identity
;
478 reqType
= CRT_EmailSign
;
481 reqType
= CRT_EmailEncrypt
;
485 reqType
= CRT_Identity
;
489 reqType
= CRT_EmailSign
;
493 reqType
= CRT_EmailEncrypt
;
496 doPendingReqPoll
= true;
506 while ((arg
= getopt(argc
, argv
, "u:Z:pk:rMH:al")) != -1) {
518 keychainName
= optarg
;
546 printf("Pausing for MallocDebug attach; CR to continue: ");
550 if(keychainName
!= NULL
) {
551 /* pick a keychain (optional) */
552 ortn
= SecKeychainOpen(keychainName
, &kcRef
);
554 cssmPerror("SecKeychainOpen", ortn
);
558 /* make sure it's there since a successful SecKeychainOpen proves nothing */
559 SecKeychainStatus kcStat
;
560 ortn
= SecKeychainGetStatus(kcRef
, &kcStat
);
562 cssmPerror("SecKeychainGetStatus", ortn
);
567 if((!doSearch
|| ALWAYS_DO_SUBMIT
) && !doPendingReqPoll
) {
568 /* get a key pair, somehow */
570 ortn
= genKeyPair(kcRef
, &pubKeyRef
, &privKeyRef
);
573 ortn
= keyPicker(kcRef
, &pubKeyRef
, &privKeyRef
);
576 printf("Can't proceed without a keypair. Aborting.\n");
586 dotMacPostCertRequest(userName
, password
, privKeyRef
, pubKeyRef
,
587 reqType
, doRenew
, async
, hostName
, kcRef
);
591 ortn
= dotMacGetPendingRequest(userName
, password
, reqType
, hostName
, kcRef
);
593 else if(doPendingReqPoll
) {
594 ortn
= dotMacPostPendingReqPoll(userName
, password
, hostName
);
597 ortn
= dotMacPostCertRequest(userName
, password
, privKeyRef
, pubKeyRef
,
598 reqType
, doRenew
, async
, hostName
, kcRef
);
602 printf("Pausing for MallocDebug attach; CR to continue: ");
607 CFRelease(privKeyRef
);
610 CFRelease(pubKeyRef
);
618 printf("Pausing at end of test for MallocDebug attach; CR to continue: ");