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