]> git.saurik.com Git - apple/security.git/blob - SecurityTests/clxutils/sslServer/sslServer.cpp
Security-57031.1.35.tar.gz
[apple/security.git] / SecurityTests / clxutils / sslServer / sslServer.cpp
1 /*
2 * Trivial SSL server example, SecureTransport / OS X version.
3 *
4 * Written by Doug Mitchell.
5 */
6 #include <Security/SecureTransport.h>
7 #include <Security/SecureTransportPriv.h>
8 #include <clAppUtils/sslAppUtils.h>
9 #include <clAppUtils/ioSock.h>
10 #include <clAppUtils/identPicker.h>
11 #include <utilLib/fileIo.h>
12 #include <utilLib/common.h>
13 #include <security_cdsa_utils/cuPrintCert.h>
14
15 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <time.h>
20 #include <ctype.h>
21 #include <sys/param.h>
22
23 #include <Security/Security.h>
24
25 /* Set true when PR-3074739 is merged to TOT */
26 #define SET_DH_PARAMS_ENABLE 1
27
28 /* true when using SSLCopyPeerCertificates() per Radar 3311892 */
29 #define USE_COPY_PEER_CERTS 1
30
31 /*
32 * Defaults, overridable by user.
33 */
34 #define SERVER_MESSAGE "HTTP/1.0 200 OK\015\012Content-Type: text/html\015\012\015\012" \
35 "<HTML><HEAD><TITLE>SecureTransport Test Server</TITLE></HEAD>" \
36 "<BODY><H2>Secure connection established.</H2>" \
37 "Message from the 'sslServer' sample application.\015\012</BODY>" \
38 "</HTML>\015\012"
39
40 /* For ease of debugging, pick a non-privileged port */
41 #define DEFAULT_PORT 1200
42 // #define DEFAULT_PORT 443
43
44 #define DEFAULT_HOST "localhost"
45
46 #define DEFAULT_KC "certkc"
47
48 /*
49 * IE (5.0 on OS9, 5.1.3 on OS X) have an interesting way of handling unrecognized
50 * server certs. Upon receipt of the server cert msg with an unrecognized cert,
51 * IE immediately closes the connection, asks the user of they want to proceed
52 * after the usual dire warning, and retries the whole op from scratch if
53 * so authorized. Unfortunately this is often seen at this end as a broken
54 * pipe when writing either the server cert or the server hello done msg which follows
55 * it. We really have to handle the sigpipe so the lower-level I/O code
56 * (in ioSock.c) can see the error on the write and cleanup. If we don't handle
57 * the signal our process dies.
58 */
59 #define IGNORE_SIGPIPE 1
60 #if IGNORE_SIGPIPE
61 #include <signal.h>
62
63 void sigpipe(int sig)
64 {
65 fflush(stdin);
66 printf("***SIGPIPE***\n");
67 }
68 #endif
69
70 static void usage(char **argv)
71 {
72 printf("Usage: %s [option ...]\n", argv[0]);
73 printf("Options:\n");
74 printf(" P=port Port to listen on; default is %d\n", DEFAULT_PORT);
75 printf(" k=keychain Contains server cert and keys.\n");
76 printf(" y=keychain Encryption-only cert and keys.\n");
77 printf(" e Allow Expired Certs\n");
78 printf(" r Allow any root cert\n");
79 printf(" E Allow Expired Roots\n");
80 printf(" x Disable Cert Verification\n");
81 printf(" f=fileBase Write Peer Certs to fileBase*\n");
82 printf(" c Display peer certs\n");
83 printf(" d Display received data\n");
84 printf(" C=cipherSuite (e=40-bit d=DES D=40-bit DES 3=3DES 4=RC4 $=40-bit RC4\n"
85 " 2=RC2 a=AES128 A=AES256 h=DH H=Anon DH r=DHE/RSA s=DH/DSS\n"
86 " n=RSA/NULL\n");
87 printf(" 2 SSLv2 only (default is best fit)\n");
88 printf(" 3 SSLv3 only (default is best fit)\n");
89 printf(" t TLSv1 only (default is best fit)\n");
90 printf(" o TLSv1, SSLv3 use kSSLProtocol__X__Only\n");
91 printf(" g={prot...} Specify legal protocols; prot = any combo of [23t]\n");
92 printf(" T=[nrsj] Verify client cert state = "
93 "none/requested/sent/rejected\n");
94 printf(" R Disable resumable session support\n");
95 printf(" i=timeout Session cache timeout\n");
96 printf(" u=[nat] Authentication: n=never; a=always; t=try\n");
97 printf(" b Non-blocking I/O\n");
98 printf(" a fileNmae Add fileName to list of trusted roots\n");
99 printf(" A fileName fileName is ONLY trusted root\n");
100 printf(" U filename Add filename to acceptable DNList (multiple times OK)\n");
101 printf(" D filename Diffie-Hellman parameters from filename\n");
102 printf(" z=password Unlock server keychain with password.\n");
103 printf(" H Do SecIndentityRef search instead of specific keychain\n");
104 printf(" M Complete cert chain (default assumes that our identity is root)\n");
105 printf(" 4 Disable anonymous ciphers\n");
106 printf(" p Pause after each phase\n");
107 printf(" l[=loops] Loop, performing multiple transactions\n");
108 printf(" q Quiet/diagnostic mode (site names and errors only)\n");
109 printf(" h Help\n");
110 exit(1);
111 }
112
113 /* snag a copy of current connection's peer certs so we can
114 * examine them later after the connection is closed */
115 static OSStatus copyPeerCerts(
116 SSLContext *ctx,
117 CFArrayRef *peerCerts) // mallocd & RETURNED
118 {
119 #if USE_COPY_PEER_CERTS
120 OSStatus ortn = SSLCopyPeerCertificates(ctx, peerCerts);
121 #else
122 OSStatus ortn = SSLGetPeerCertificates(ctx, peerCerts);
123 #endif
124 if(ortn) {
125 printf("***Error obtaining peer certs: %s\n",
126 sslGetSSLErrString(ortn));
127 }
128 return ortn;
129 }
130
131 /* free the cert array obtained via SSLGetPeerCertificates() */
132 static void freePeerCerts(
133 CFArrayRef peerCerts)
134 {
135 if(peerCerts == NULL) {
136 return;
137 }
138
139 #if USE_COPY_PEER_CERTS
140
141 /* Voila! Problem fixed. */
142 CFRelease(peerCerts);
143 return;
144
145 #else
146
147 CFIndex numCerts;
148 SecCertificateRef certData;
149 CFIndex i;
150
151 numCerts = CFArrayGetCount(peerCerts);
152 for(i=0; i<numCerts; i++) {
153 certData = (SecCertificateRef)CFArrayGetValueAtIndex(peerCerts, i);
154 CFRelease(certData);
155 }
156 CFRelease(peerCerts);
157 #endif
158 }
159
160 /* print reply received from server */
161 static void dumpAscii(
162 uint8 *rcvBuf,
163 uint32 len)
164 {
165 char *cp = (char *)rcvBuf;
166 uint32 i;
167 char c;
168
169 for(i=0; i<len; i++) {
170 c = *cp++;
171 if(c == '\0') {
172 break;
173 }
174 switch(c) {
175 case '\n':
176 printf("\\n");
177 break;
178 case '\r':
179 printf("\\r");
180 break;
181 default:
182 if(isprint(c) && (c != '\n')) {
183 printf("%c", c);
184 }
185 else {
186 printf("<%02X>", ((unsigned)c) & 0xff);
187 }
188 break;
189 }
190
191 }
192 printf("\n");
193 }
194
195 static void doPause(const char *prompt) {
196 if(prompt) {
197 printf("%s. ", prompt);
198 }
199 fpurge(stdin);
200 printf("Continue (n/anything)? ");
201 char c = getchar();
202 if(c == 'n') {
203 exit(0);
204 }
205 }
206
207 /*
208 * Perform one SSL diagnostic server-side session. Returns nonzero on error.
209 * Normally no output to stdout except initial "waiting for connection" message,
210 * unless there is a really screwed up error (i.e., something not directly related
211 * to the SSL connection).
212 */
213 #define RCV_BUF_SIZE 256
214
215 static OSStatus sslServe(
216 otSocket listenSock,
217 unsigned short portNum,
218 SSLProtocol tryVersion, // only used if acceptedProts NULL
219 const char *acceptedProts,
220 CFArrayRef serverCerts, // required
221 char *password, // optional
222 CFArrayRef encryptServerCerts, // optional
223 CSSM_BOOL allowExpired,
224 CSSM_BOOL allowAnyRoot,
225 CSSM_BOOL allowExpiredRoot,
226 CSSM_BOOL disableCertVerify,
227 char *anchorFile,
228 CSSM_BOOL replaceAnchors,
229 char cipherRestrict, // '2', 'd'. etc...'\0' for no
230 // restriction
231 SSLAuthenticate authenticate,
232 unsigned char *dhParams, // optional D-H parameters
233 unsigned dhParamsLen,
234 CFArrayRef acceptableDNList, // optional
235 CSSM_BOOL resumableEnable,
236 uint32 sessionCacheTimeout,// optional
237 CSSM_BOOL disableAnonCiphers,
238 CSSM_BOOL silent, // no stdout
239 CSSM_BOOL pause,
240 SSLProtocol *negVersion, // RETURNED
241 SSLCipherSuite *negCipher, // RETURNED
242 SSLClientCertificateState *certState, // RETURNED
243 Boolean *sessionWasResumed, // RETURNED
244 unsigned char *sessionID, // mallocd by caller, RETURNED
245 size_t *sessionIDLength, // RETURNED
246 CFArrayRef *peerCerts, // mallocd & RETURNED
247 char **argv)
248 {
249 otSocket acceptSock;
250 PeerSpec peerId;
251 OSStatus ortn;
252 SSLContextRef ctx = NULL;
253 size_t length;
254 uint8 rcvBuf[RCV_BUF_SIZE];
255 char *outMsg = (char *)SERVER_MESSAGE;
256
257 *negVersion = kSSLProtocolUnknown;
258 *negCipher = SSL_NULL_WITH_NULL_NULL;
259 *peerCerts = NULL;
260
261 #if IGNORE_SIGPIPE
262 signal(SIGPIPE, sigpipe);
263 #endif
264
265 /* first wait for a connection */
266 if(!silent) {
267 printf("Waiting for client connection on port %u...", portNum);
268 fflush(stdout);
269 }
270 ortn = AcceptClientConnection(listenSock, &acceptSock, &peerId);
271 if(ortn) {
272 printf("AcceptClientConnection returned %d; aborting\n", (int)ortn);
273 return ortn;
274 }
275
276 /*
277 * Set up a SecureTransport session.
278 * First the standard calls.
279 */
280 ortn = SSLNewContext(true, &ctx);
281 if(ortn) {
282 printSslErrStr("SSLNewContext", ortn);
283 goto cleanup;
284 }
285 ortn = SSLSetIOFuncs(ctx, SocketRead, SocketWrite);
286 if(ortn) {
287 printSslErrStr("SSLSetIOFuncs", ortn);
288 goto cleanup;
289 }
290 ortn = SSLSetConnection(ctx, (SSLConnectionRef)acceptSock);
291 if(ortn) {
292 printSslErrStr("SSLSetConnection", ortn);
293 goto cleanup;
294 }
295
296 /* have to do these options befor setting server certs */
297 if(allowExpired) {
298 ortn = SSLSetAllowsExpiredCerts(ctx, true);
299 if(ortn) {
300 printSslErrStr("SSLSetAllowExpiredCerts", ortn);
301 goto cleanup;
302 }
303 }
304 if(allowAnyRoot) {
305 ortn = SSLSetAllowsAnyRoot(ctx, true);
306 if(ortn) {
307 printSslErrStr("SSLSetAllowAnyRoot", ortn);
308 goto cleanup;
309 }
310 }
311
312 if(anchorFile) {
313 ortn = sslAddTrustedRoot(ctx, anchorFile, replaceAnchors);
314 if(ortn) {
315 printf("***Error obtaining anchor file %s\n", anchorFile);
316 goto cleanup;
317 }
318 }
319 if(serverCerts != NULL) {
320 if(anchorFile == NULL) {
321 /* no specific anchors, so assume we want to trust this one */
322 ortn = addIdentityAsTrustedRoot(ctx, serverCerts);
323 if(ortn) {
324 goto cleanup;
325 }
326 }
327 ortn = SSLSetCertificate(ctx, serverCerts);
328 if(ortn) {
329 printSslErrStr("SSLSetCertificate", ortn);
330 goto cleanup;
331 }
332 }
333 if(encryptServerCerts) {
334 ortn = SSLSetEncryptionCertificate(ctx, encryptServerCerts);
335 if(ortn) {
336 printSslErrStr("SSLSetEncryptionCertificate", ortn);
337 goto cleanup;
338 }
339 }
340 if(allowExpiredRoot) {
341 ortn = SSLSetAllowsExpiredRoots(ctx, true);
342 if(ortn) {
343 printSslErrStr("SSLSetAllowsExpiredRoots", ortn);
344 goto cleanup;
345 }
346 }
347 if(disableCertVerify) {
348 ortn = SSLSetEnableCertVerify(ctx, false);
349 if(ortn) {
350 printSslErrStr("SSLSetEnableCertVerify", ortn);
351 goto cleanup;
352 }
353 }
354
355 /*
356 * SecureTransport options.
357 */
358 if(acceptedProts) {
359 ortn = SSLSetProtocolVersionEnabled(ctx, kSSLProtocolAll, false);
360 if(ortn) {
361 printSslErrStr("SSLSetProtocolVersionEnabled(all off)", ortn);
362 goto cleanup;
363 }
364 for(const char *cp = acceptedProts; *cp; cp++) {
365 SSLProtocol prot;
366 switch(*cp) {
367 case '2':
368 prot = kSSLProtocol2;
369 break;
370 case '3':
371 prot = kSSLProtocol3;
372 break;
373 case 't':
374 prot = kTLSProtocol1;
375 break;
376 default:
377 usage(argv);
378 }
379 ortn = SSLSetProtocolVersionEnabled(ctx, prot, true);
380 if(ortn) {
381 printSslErrStr("SSLSetProtocolVersionEnabled", ortn);
382 goto cleanup;
383 }
384 }
385 }
386 else {
387 ortn = SSLSetProtocolVersion(ctx, tryVersion);
388 if(ortn) {
389 printSslErrStr("SSLSetProtocolVersion", ortn);
390 goto cleanup;
391 }
392 }
393 if(resumableEnable) {
394 ortn = SSLSetPeerID(ctx, &peerId, sizeof(PeerSpec));
395 if(ortn) {
396 printSslErrStr("SSLSetPeerID", ortn);
397 goto cleanup;
398 }
399 }
400 if(cipherRestrict != '\0') {
401 ortn = sslSetCipherRestrictions(ctx, cipherRestrict);
402 if(ortn) {
403 goto cleanup;
404 }
405 }
406 if(authenticate != kNeverAuthenticate) {
407 ortn = SSLSetClientSideAuthenticate(ctx, authenticate);
408 if(ortn) {
409 printSslErrStr("SSLSetClientSideAuthenticate", ortn);
410 goto cleanup;
411 }
412 }
413 if(dhParams) {
414 ortn = SSLSetDiffieHellmanParams(ctx, dhParams, dhParamsLen);
415 if(ortn) {
416 printSslErrStr("SSLSetDiffieHellmanParams", ortn);
417 goto cleanup;
418 }
419 }
420 if(sessionCacheTimeout) {
421 ortn = SSLSetSessionCacheTimeout(ctx, sessionCacheTimeout);
422 if(ortn) {
423 printSslErrStr("SSLSetSessionCacheTimeout", ortn);
424 goto cleanup;
425 }
426 }
427 if(disableAnonCiphers) {
428 ortn = SSLSetAllowAnonymousCiphers(ctx, false);
429 if(ortn) {
430 printSslErrStr("SSLSetAllowAnonymousCiphers", ortn);
431 goto cleanup;
432 }
433 /* quickie test of the getter */
434 Boolean e;
435 ortn = SSLGetAllowAnonymousCiphers(ctx, &e);
436 if(ortn) {
437 printSslErrStr("SSLGetAllowAnonymousCiphers", ortn);
438 goto cleanup;
439 }
440 if(e) {
441 printf("***SSLGetAllowAnonymousCiphers() returned true; expected false\n");
442 ortn = ioErr;
443 goto cleanup;
444 }
445 }
446 if(acceptableDNList) {
447 ortn = SSLSetCertificateAuthorities(ctx, acceptableDNList, TRUE);
448 if(ortn) {
449 printSslErrStr("SSLSetCertificateAuthorities", ortn);
450 goto cleanup;
451 }
452 }
453
454 /* end options */
455
456 if(pause) {
457 doPause("SSLContext initialized");
458 }
459
460 /* Perform SSL/TLS handshake */
461 do
462 { ortn = SSLHandshake(ctx);
463 if((ortn == errSSLWouldBlock) && !silent) {
464 /* keep UI responsive */
465 sslOutputDot();
466 }
467 } while (ortn == errSSLWouldBlock);
468
469 /* this works even if handshake failed due to cert chain invalid */
470 copyPeerCerts(ctx, peerCerts);
471
472 SSLGetClientCertificateState(ctx, certState);
473 SSLGetNegotiatedCipher(ctx, negCipher);
474 SSLGetNegotiatedProtocolVersion(ctx, negVersion);
475 *sessionIDLength = MAX_SESSION_ID_LENGTH;
476 SSLGetResumableSessionInfo(ctx, sessionWasResumed, sessionID,
477 sessionIDLength);
478
479 if(!silent) {
480 printf("\n");
481 }
482 if(ortn) {
483 goto cleanup;
484 }
485 if(pause) {
486 doPause("SSLContext handshake complete");
487 }
488
489 /* wait for one complete line or user says they've had enough */
490 while(ortn == noErr) {
491 length = sizeof(rcvBuf);
492 ortn = SSLRead(ctx, rcvBuf, length, &length);
493 if(length == 0) {
494 /* keep UI responsive */
495 sslOutputDot();
496 }
497 else {
498 /* print what we have */
499 printf("client request: ");
500 dumpAscii(rcvBuf, length);
501 }
502 if(pause) {
503 /* allow user to bail */
504 char resp;
505
506 fpurge(stdin);
507 printf("\nMore client request (y/anything): ");
508 resp = getchar();
509 if(resp != 'y') {
510 break;
511 }
512 }
513
514 /* poor person's line completion scan */
515 for(unsigned i=0; i<length; i++) {
516 if((rcvBuf[i] == '\n') || (rcvBuf[i] == '\r')) {
517 /* a labelled break would be nice here.... */
518 goto serverResp;
519 }
520 }
521 if (ortn == errSSLWouldBlock) {
522 ortn = noErr;
523 }
524 }
525
526 serverResp:
527 if(pause) {
528 doPause("Client GET msg received");
529 }
530
531 /* send out canned response */
532 length = strlen(outMsg);
533 ortn = SSLWrite(ctx, outMsg, length, &length);
534 if(ortn) {
535 printSslErrStr("SSLWrite", ortn);
536 }
537 if(pause) {
538 doPause("Server response sent");
539 }
540 cleanup:
541 /*
542 * always do close, even on error - to flush outgoing write queue
543 */
544 OSStatus cerr = SSLClose(ctx);
545 if(ortn == noErr) {
546 ortn = cerr;
547 }
548 if(acceptSock) {
549 endpointShutdown(acceptSock);
550 }
551 if(ctx) {
552 SSLDisposeContext(ctx);
553 }
554 /* FIXME - dispose of serverCerts */
555 return ortn;
556 }
557
558 static void showPeerCerts(
559 CFArrayRef peerCerts,
560 CSSM_BOOL verbose)
561 {
562 CFIndex numCerts;
563 SecCertificateRef certRef;
564 OSStatus ortn;
565 CSSM_DATA certData;
566 CFIndex i;
567
568 if(peerCerts == NULL) {
569 return;
570 }
571 numCerts = CFArrayGetCount(peerCerts);
572 for(i=0; i<numCerts; i++) {
573 certRef = (SecCertificateRef)CFArrayGetValueAtIndex(peerCerts, i);
574 ortn = SecCertificateGetData(certRef, &certData);
575 if(ortn) {
576 printf("***SecCertificateGetData returned %d\n", (int)ortn);
577 continue;
578 }
579 printf("\n================== Peer Cert %lu ===================\n\n", i);
580 printCert(certData.Data, certData.Length, verbose);
581 printf("\n=============== End of Peer Cert %lu ===============\n", i);
582 }
583 }
584
585 static void writePeerCerts(
586 CFArrayRef peerCerts,
587 const char *fileBase)
588 {
589 CFIndex numCerts;
590 SecCertificateRef certRef;
591 OSStatus ortn;
592 CSSM_DATA certData;
593 CFIndex i;
594 char fileName[100];
595
596 if(peerCerts == NULL) {
597 return;
598 }
599 numCerts = CFArrayGetCount(peerCerts);
600 for(i=0; i<numCerts; i++) {
601 sprintf(fileName, "%s%02d.cer", fileBase, (int)i);
602 certRef = (SecCertificateRef)CFArrayGetValueAtIndex(peerCerts, i);
603 ortn = SecCertificateGetData(certRef, &certData);
604 if(ortn) {
605 printf("***SecCertificateGetData returned %d\n", (int)ortn);
606 continue;
607 }
608 cspWriteFile(fileName, certData.Data, certData.Length);
609 }
610 printf("...wrote %lu certs to fileBase %s\n", numCerts, fileBase);
611 }
612
613 static void showSSLResult(
614 SSLProtocol tryVersion,
615 char *acceptedProts,
616 OSStatus err,
617 SSLProtocol negVersion,
618 SSLCipherSuite negCipher,
619 Boolean sessionWasResumed,
620 unsigned char *sessionID,
621 size_t sessionIDLength,
622 CFArrayRef peerCerts,
623 CSSM_BOOL displayPeerCerts,
624 SSLClientCertificateState certState,
625 char *fileBase) // non-NULL: write certs to file
626 {
627 CFIndex numPeerCerts;
628
629 printf("\n");
630 if(acceptedProts) {
631 printf(" Allowed SSL versions : %s\n", acceptedProts);
632 }
633 else {
634 printf(" Attempted SSL version : %s\n",
635 sslGetProtocolVersionString(tryVersion));
636 }
637 printf(" Result : %s\n", sslGetSSLErrString(err));
638 printf(" Negotiated SSL version : %s\n",
639 sslGetProtocolVersionString(negVersion));
640 printf(" Negotiated CipherSuite : %s\n",
641 sslGetCipherSuiteString(negCipher));
642 if(certState != kSSLClientCertNone) {
643 printf(" Client Cert State : %s\n",
644 sslGetClientCertStateString(certState));
645 }
646 printf(" Resumed Session : ");
647 if(sessionWasResumed) {
648 for(unsigned dex=0; dex<sessionIDLength; dex++) {
649 printf("%02X ", sessionID[dex]);
650 if(((dex % 8) == 7) && (dex != (sessionIDLength - 1))) {
651 printf("\n ");
652 }
653 }
654 printf("\n");
655 }
656 else {
657 printf("NOT RESUMED\n");
658 }
659 if(peerCerts == NULL) {
660 numPeerCerts = 0;
661 }
662 else {
663 numPeerCerts = CFArrayGetCount(peerCerts);
664 }
665 printf(" Number of peer certs : %lu\n", numPeerCerts);
666 if(numPeerCerts != 0) {
667 if(displayPeerCerts) {
668 showPeerCerts(peerCerts, CSSM_FALSE);
669 }
670 if(fileBase != NULL) {
671 writePeerCerts(peerCerts, fileBase);
672 }
673 }
674 printf("\n");
675 }
676
677 static int verifyClientCertState(
678 CSSM_BOOL verifyCertState,
679 SSLClientCertificateState expectState,
680 SSLClientCertificateState gotState)
681 {
682 if(!verifyCertState) {
683 return 0;
684 }
685 if(expectState == gotState) {
686 return 0;
687 }
688 printf("***Expected clientCertState %s; got %s\n",
689 sslGetClientCertStateString(expectState),
690 sslGetClientCertStateString(gotState));
691 return 1;
692 }
693
694 int main(int argc, char **argv)
695 {
696 OSStatus err;
697 int arg;
698 char fullFileBase[100];
699 SSLProtocol negVersion;
700 SSLCipherSuite negCipher;
701 Boolean sessionWasResumed;
702 unsigned char sessionID[MAX_SESSION_ID_LENGTH];
703 size_t sessionIDLength;
704 CFArrayRef peerCerts = NULL;
705 char *argp;
706 otSocket listenSock;
707 CFArrayRef serverCerts = nil; // required
708 CFArrayRef encryptCerts = nil; // optional
709 SecKeychainRef serverKc = nil;
710 SecKeychainRef encryptKc = nil;
711 int loopNum;
712 int errCount = 0;
713 SSLClientCertificateState certState; // obtained from sslServe
714 unsigned char *caCert;
715 unsigned caCertLen;
716 SecCertificateRef secCert;
717 CSSM_DATA certData;
718 OSStatus ortn;
719
720 /* user-spec'd parameters */
721 unsigned short portNum = DEFAULT_PORT;
722 CSSM_BOOL allowExpired = CSSM_FALSE;
723 CSSM_BOOL allowAnyRoot = CSSM_FALSE;
724 char *fileBase = NULL;
725 CSSM_BOOL displayRxData = CSSM_FALSE;
726 CSSM_BOOL displayCerts = CSSM_FALSE;
727 char cipherRestrict = '\0';
728 SSLProtocol attemptProt = kTLSProtocol1;
729 CSSM_BOOL protXOnly = CSSM_FALSE; // kSSLProtocol3Only,
730 // kTLSProtocol1Only
731 char *acceptedProts = NULL; // "23t" ==> SSLSetProtocolVersionEnabled
732 CSSM_BOOL quiet = CSSM_FALSE;
733 CSSM_BOOL resumableEnable = CSSM_TRUE;
734 CSSM_BOOL pause = CSSM_FALSE;
735 char *keyChainName = NULL;
736 char *encryptKeyChainName = NULL;
737 int loops = 1;
738 SSLAuthenticate authenticate = kNeverAuthenticate;
739 CSSM_BOOL nonBlocking = CSSM_FALSE;
740 CSSM_BOOL allowExpiredRoot = CSSM_FALSE;
741 CSSM_BOOL disableCertVerify = CSSM_FALSE;
742 char *anchorFile = NULL;
743 CSSM_BOOL replaceAnchors = CSSM_FALSE;
744 CSSM_BOOL vfyCertState = CSSM_FALSE;
745 SSLClientCertificateState expectCertState;
746 char *password = NULL;
747 char *dhParamsFile = NULL;
748 unsigned char *dhParams = NULL;
749 unsigned dhParamsLen = 0;
750 CSSM_BOOL doIdSearch = CSSM_FALSE;
751 CSSM_BOOL completeCertChain = CSSM_FALSE;
752 uint32 sessionCacheTimeout = 0;
753 CSSM_BOOL disableAnonCiphers = CSSM_FALSE;
754 CFMutableArrayRef acceptableDNList = NULL;
755
756 for(arg=1; arg<argc; arg++) {
757 argp = argv[arg];
758 switch(argp[0]) {
759 case 'P':
760 portNum = atoi(&argp[2]);
761 break;
762 case 'k':
763 keyChainName = &argp[2];
764 break;
765 case 'y':
766 encryptKeyChainName = &argp[2];
767 break;
768 case 'e':
769 allowExpired = CSSM_TRUE;
770 break;
771 case 'E':
772 allowExpiredRoot = CSSM_TRUE;
773 break;
774 case 'x':
775 disableCertVerify = CSSM_TRUE;
776 break;
777 case 'a':
778 if(++arg == argc) {
779 /* requires another arg */
780 usage(argv);
781 }
782 anchorFile = argv[arg];
783 break;
784 case 'A':
785 if(++arg == argc) {
786 /* requires another arg */
787 usage(argv);
788 }
789 anchorFile = argv[arg];
790 replaceAnchors = CSSM_TRUE;
791 break;
792 case 'T':
793 if(argp[1] != '=') {
794 usage(argv);
795 }
796 vfyCertState = CSSM_TRUE;
797 switch(argp[2]) {
798 case 'n':
799 expectCertState = kSSLClientCertNone;
800 break;
801 case 'r':
802 expectCertState = kSSLClientCertRequested;
803 break;
804 case 's':
805 expectCertState = kSSLClientCertSent;
806 break;
807 case 'j':
808 expectCertState = kSSLClientCertRejected;
809 break;
810 default:
811 usage(argv);
812 }
813 break;
814 case 'r':
815 allowAnyRoot = CSSM_TRUE;
816 break;
817 case 'd':
818 displayRxData = CSSM_TRUE;
819 break;
820 case 'c':
821 displayCerts = CSSM_TRUE;
822 break;
823 case 'f':
824 fileBase = &argp[2];
825 break;
826 case 'C':
827 cipherRestrict = argp[2];
828 break;
829 case '2':
830 attemptProt = kSSLProtocol2;
831 break;
832 case '3':
833 attemptProt = kSSLProtocol3;
834 break;
835 case 't':
836 attemptProt = kTLSProtocol1;
837 break;
838 case 'o':
839 protXOnly = CSSM_TRUE;
840 break;
841 case 'g':
842 if(argp[1] != '=') {
843 usage(argv);
844 }
845 acceptedProts = &argp[2];
846 break;
847 case 'R':
848 resumableEnable = CSSM_FALSE;
849 break;
850 case 'b':
851 nonBlocking = CSSM_TRUE;
852 break;
853 case 'u':
854 if(argp[1] != '=') {
855 usage(argv);
856 }
857 switch(argp[2]) {
858 case 'a': authenticate = kAlwaysAuthenticate; break;
859 case 'n': authenticate = kNeverAuthenticate; break;
860 case 't': authenticate = kTryAuthenticate; break;
861 default: usage(argv);
862 }
863 break;
864 case 'D':
865 if(++arg == argc) {
866 /* requires another arg */
867 usage(argv);
868 }
869 dhParamsFile = argv[arg];
870 break;
871 case 'z':
872 password = &argp[2];
873 break;
874 case 'H':
875 doIdSearch = CSSM_TRUE;
876 break;
877 case 'M':
878 completeCertChain = CSSM_TRUE;
879 break;
880 case 'i':
881 sessionCacheTimeout = atoi(&argp[2]);
882 break;
883 case '4':
884 disableAnonCiphers = CSSM_TRUE;
885 break;
886 case 'p':
887 pause = CSSM_TRUE;
888 break;
889 case 'q':
890 quiet = CSSM_TRUE;
891 break;
892 case 'U':
893 if(++arg == argc) {
894 /* requires another arg */
895 usage(argv);
896 }
897 if(cspReadFile(argv[arg], &caCert, &caCertLen)) {
898 printf("***Error reading file %s. Aborting.\n", argv[arg]);
899 exit(1);
900 }
901 if(acceptableDNList == NULL) {
902 acceptableDNList = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
903 }
904 certData.Data = caCert;
905 certData.Length = caCertLen;
906 ortn = SecCertificateCreateFromData(&certData,
907 CSSM_CERT_X_509v3,
908 CSSM_CERT_ENCODING_DER,
909 &secCert);
910 if(ortn) {
911 cssmPerror("SecCertificateCreateFromData", ortn);
912 exit(1);
913 }
914 CFArrayAppendValue(acceptableDNList, secCert);
915 CFRelease(secCert);
916 break;
917
918 case 'l':
919 if(argp[1] == '\0') {
920 /* no loop count --> loop forever */
921 loops = 0;
922 break;
923 }
924 else if(argp[1] != '=') {
925 usage(argv);
926 }
927 loops = atoi(&argp[2]);
928 break;
929 default:
930 usage(argv);
931 }
932 }
933
934 /* get server cert and optional encryption cert as CFArrayRef */
935 if(keyChainName) {
936 serverCerts = getSslCerts(keyChainName, CSSM_FALSE, completeCertChain,
937 anchorFile, &serverKc);
938 if(serverCerts == nil) {
939 exit(1);
940 }
941 }
942 else if(doIdSearch) {
943 OSStatus ortn = sslIdentityPicker(NULL, anchorFile, true, NULL, &serverCerts);
944 if(ortn) {
945 printf("***IdentitySearch failure; aborting.\n");
946 exit(1);
947 }
948 }
949 if(password) {
950 OSStatus ortn = SecKeychainUnlock(serverKc, strlen(password), password, true);
951 if(ortn) {
952 printf("SecKeychainUnlock returned %d\n", (int)ortn);
953 /* oh well */
954 }
955 }
956 if(encryptKeyChainName) {
957 encryptCerts = getSslCerts(encryptKeyChainName, CSSM_TRUE, completeCertChain,
958 anchorFile, &encryptKc);
959 if(encryptCerts == nil) {
960 exit(1);
961 }
962 }
963 if(protXOnly) {
964 switch(attemptProt) {
965 case kTLSProtocol1:
966 attemptProt = kTLSProtocol1Only;
967 break;
968 case kSSLProtocol3:
969 attemptProt = kSSLProtocol3Only;
970 break;
971 default:
972 break;
973 }
974 }
975 if(dhParamsFile) {
976 int r = cspReadFile(dhParamsFile, &dhParams, &dhParamsLen);
977 if(r) {
978 printf("***Error reading diffie-hellman params from %s; aborting\n",
979 dhParamsFile);
980 }
981 }
982
983 /* one-time only server port setup */
984 err = ListenForClients(portNum, nonBlocking, &listenSock);
985 if(err) {
986 printf("ListenForClients returned %d; aborting\n", (int)err);
987 exit(1);
988 }
989
990 for(loopNum=1; ; loopNum++) {
991 err = sslServe(listenSock,
992 portNum,
993 attemptProt,
994 acceptedProts,
995 serverCerts,
996 password,
997 encryptCerts,
998 allowExpired,
999 allowAnyRoot,
1000 allowExpiredRoot,
1001 disableCertVerify,
1002 anchorFile,
1003 replaceAnchors,
1004 cipherRestrict,
1005 authenticate,
1006 dhParams,
1007 dhParamsLen,
1008 acceptableDNList,
1009 resumableEnable,
1010 sessionCacheTimeout,
1011 disableAnonCiphers,
1012 quiet,
1013 pause,
1014 &negVersion,
1015 &negCipher,
1016 &certState,
1017 &sessionWasResumed,
1018 sessionID,
1019 &sessionIDLength,
1020 &peerCerts,
1021 argv);
1022 if(err) {
1023 errCount++;
1024 }
1025 if(!quiet) {
1026 SSLProtocol tryProt = attemptProt;
1027 showSSLResult(tryProt,
1028 acceptedProts,
1029 err,
1030 negVersion,
1031 negCipher,
1032 sessionWasResumed,
1033 sessionID,
1034 sessionIDLength,
1035 peerCerts,
1036 displayCerts,
1037 certState,
1038 fileBase ? fullFileBase : NULL);
1039 }
1040 errCount += verifyClientCertState(vfyCertState, expectCertState,
1041 certState);
1042 freePeerCerts(peerCerts);
1043 if(loops && (loopNum == loops)) {
1044 break;
1045 }
1046 };
1047
1048 endpointShutdown(listenSock);
1049 printCertShutdown();
1050 if(serverKc) {
1051 CFRelease(serverKc);
1052 }
1053 if(encryptKc) {
1054 CFRelease(encryptKc);
1055 }
1056 return errCount;
1057
1058 }
1059
1060