]> git.saurik.com Git - apple/security.git/blob - sslViewer/sslServer.cpp
Security-58286.70.7.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/print_cert.h"
49
50 #if NO_SERVER
51 #include <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 *negVersion = kSSLProtocolUnknown;
264 *negCipher = SSL_NULL_WITH_NULL_NULL;
265 *peerCerts = NULL;
266
267 #if IGNORE_SIGPIPE
268 signal(SIGPIPE, sigpipe);
269 #endif
270
271 /* first wait for a connection */
272 if(!silent) {
273 printf("Waiting for client connection on port %u...", portNum);
274 fflush(stdout);
275 }
276 ortn = AcceptClientConnection(listenSock, &acceptSock, &peerId);
277 if(ortn) {
278 printf("AcceptClientConnection returned %d; aborting\n", (int)ortn);
279 return ortn;
280 }
281
282 /*
283 * Set up a SecureTransport session.
284 * First the standard calls.
285 */
286 ortn = SSLNewContext(true, &ctx);
287 if(ortn) {
288 printSslErrStr("SSLNewContext", ortn);
289 goto cleanup;
290 }
291 ortn = SSLSetIOFuncs(ctx, SocketRead, SocketWrite);
292 if(ortn) {
293 printSslErrStr("SSLSetIOFuncs", ortn);
294 goto cleanup;
295 }
296 ortn = SSLSetConnection(ctx, (SSLConnectionRef)(intptr_t)acceptSock);
297 if(ortn) {
298 printSslErrStr("SSLSetConnection", ortn);
299 goto cleanup;
300 }
301
302 /* have to do these options befor setting server certs */
303 if(allowExpired) {
304 ortn = SSLSetAllowsExpiredCerts(ctx, true);
305 if(ortn) {
306 printSslErrStr("SSLSetAllowExpiredCerts", ortn);
307 goto cleanup;
308 }
309 }
310 if(allowAnyRoot) {
311 ortn = SSLSetAllowsAnyRoot(ctx, true);
312 if(ortn) {
313 printSslErrStr("SSLSetAllowAnyRoot", ortn);
314 goto cleanup;
315 }
316 }
317
318 if(anchorFile) {
319 ortn = sslAddTrustedRoot(ctx, anchorFile, replaceAnchors);
320 if(ortn) {
321 printf("***Error obtaining anchor file %s\n", anchorFile);
322 goto cleanup;
323 }
324 }
325 if(serverCerts != NULL) {
326 if(anchorFile == NULL) {
327 /* no specific anchors, so assume we want to trust this one */
328 ortn = addIdentityAsTrustedRoot(ctx, serverCerts);
329 if(ortn) {
330 goto cleanup;
331 }
332 }
333 ortn = SSLSetCertificate(ctx, serverCerts);
334 if(ortn) {
335 printSslErrStr("SSLSetCertificate", ortn);
336 goto cleanup;
337 }
338 }
339 if(allowExpiredRoot) {
340 ortn = SSLSetAllowsExpiredRoots(ctx, true);
341 if(ortn) {
342 printSslErrStr("SSLSetAllowsExpiredRoots", ortn);
343 goto cleanup;
344 }
345 }
346 if(disableCertVerify) {
347 ortn = SSLSetEnableCertVerify(ctx, false);
348 if(ortn) {
349 printSslErrStr("SSLSetEnableCertVerify", ortn);
350 goto cleanup;
351 }
352 }
353
354 /*
355 * SecureTransport options.
356 */
357 if(acceptedProts) {
358 ortn = SSLSetProtocolVersionEnabled(ctx, kSSLProtocolAll, false);
359 if(ortn) {
360 printSslErrStr("SSLSetProtocolVersionEnabled(all off)", ortn);
361 goto cleanup;
362 }
363 for(const char *cp = acceptedProts; *cp; cp++) {
364 SSLProtocol prot = kSSLProtocolUnknown;
365 switch(*cp) {
366 case '2':
367 prot = kSSLProtocol2;
368 break;
369 case '3':
370 prot = kSSLProtocol3;
371 break;
372 case 't':
373 prot = kTLSProtocol1;
374 break;
375 default:
376 usage(argv);
377 }
378 ortn = SSLSetProtocolVersionEnabled(ctx, prot, true);
379 if(ortn) {
380 printSslErrStr("SSLSetProtocolVersionEnabled", ortn);
381 goto cleanup;
382 }
383 }
384 }
385 else {
386 ortn = SSLSetProtocolVersion(ctx, tryVersion);
387 if(ortn) {
388 printSslErrStr("SSLSetProtocolVersion", ortn);
389 goto cleanup;
390 }
391 }
392 if(resumableEnable) {
393 ortn = SSLSetPeerID(ctx, &peerId, sizeof(PeerSpec));
394 if(ortn) {
395 printSslErrStr("SSLSetPeerID", ortn);
396 goto cleanup;
397 }
398 }
399 if(cipherRestrict != '\0') {
400 ortn = sslSetCipherRestrictions(ctx, cipherRestrict);
401 if(ortn) {
402 goto cleanup;
403 }
404 }
405 if(authenticate != kNeverAuthenticate) {
406 ortn = SSLSetClientSideAuthenticate(ctx, authenticate);
407 if(ortn) {
408 printSslErrStr("SSLSetClientSideAuthenticate", ortn);
409 goto cleanup;
410 }
411 }
412 if(dhParams) {
413 ortn = SSLSetDiffieHellmanParams(ctx, dhParams, dhParamsLen);
414 if(ortn) {
415 printSslErrStr("SSLSetDiffieHellmanParams", ortn);
416 goto cleanup;
417 }
418 }
419 if(sessionCacheTimeout) {
420 ortn = SSLSetSessionCacheTimeout(ctx, sessionCacheTimeout);
421 if(ortn) {
422 printSslErrStr("SSLSetSessionCacheTimeout", ortn);
423 goto cleanup;
424 }
425 }
426 if(disableAnonCiphers) {
427 ortn = SSLSetAllowAnonymousCiphers(ctx, false);
428 if(ortn) {
429 printSslErrStr("SSLSetAllowAnonymousCiphers", ortn);
430 goto cleanup;
431 }
432 /* quickie test of the getter */
433 Boolean e;
434 ortn = SSLGetAllowAnonymousCiphers(ctx, &e);
435 if(ortn) {
436 printSslErrStr("SSLGetAllowAnonymousCiphers", ortn);
437 goto cleanup;
438 }
439 if(e) {
440 printf("***SSLGetAllowAnonymousCiphers() returned true; expected false\n");
441 ortn = errSecIO;
442 goto cleanup;
443 }
444 }
445 /* XXX/cs
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 ortn = SSLGetResumableSessionInfo(ctx, sessionWasResumed, sessionID, sessionIDLength);
477
478 if(!silent) {
479 printf("\n");
480 }
481 if(ortn) {
482 goto cleanup;
483 }
484 if(pause) {
485 doPause("SSLContext handshake complete");
486 }
487
488 /* wait for one complete line or user says they've had enough */
489 while(ortn == errSecSuccess) {
490 length = sizeof(rcvBuf);
491 ortn = SSLRead(ctx, rcvBuf, length, &length);
492 if(length == 0) {
493 /* keep UI responsive */
494 sslOutputDot();
495 }
496 else {
497 /* print what we have */
498 printf("client request: ");
499 dumpAscii(rcvBuf, length);
500 }
501 if(pause) {
502 /* allow user to bail */
503 char resp;
504
505 fpurge(stdin);
506 printf("\nMore client request (y/anything): ");
507 resp = getchar();
508 if(resp != 'y') {
509 break;
510 }
511 }
512
513 /* poor person's line completion scan */
514 for(unsigned i=0; i<length; i++) {
515 if((rcvBuf[i] == '\n') || (rcvBuf[i] == '\r')) {
516 /* a labelled break would be nice here.... */
517 goto serverResp;
518 }
519 }
520 if (ortn == errSSLWouldBlock) {
521 ortn = errSecSuccess;
522 }
523 }
524
525 serverResp:
526 if(pause) {
527 doPause("Client GET msg received");
528 }
529
530 /* send out canned response */
531 length = strlen(outMsg);
532 ortn = SSLWrite(ctx, outMsg, length, &length);
533 if(ortn) {
534 printSslErrStr("SSLWrite", ortn);
535 }
536 if(pause) {
537 doPause("Server response sent");
538 }
539 cleanup:
540 /*
541 * always do close, even on error - to flush outgoing write queue
542 */
543 OSStatus cerr = SSLClose(ctx);
544 if(ortn == errSecSuccess) {
545 ortn = cerr;
546 }
547 if(acceptSock) {
548 endpointShutdown(acceptSock);
549 }
550 if(ctx) {
551 SSLDisposeContext(ctx);
552 }
553 /* FIXME - dispose of serverCerts */
554 return ortn;
555 }
556
557 static void showPeerCerts(
558 CFArrayRef peerCerts,
559 bool verbose)
560 {
561 CFIndex numCerts;
562 SecCertificateRef certRef;
563 CFIndex i;
564
565 if(peerCerts == NULL) {
566 return;
567 }
568 numCerts = CFArrayGetCount(peerCerts);
569 for(i=0; i<numCerts; i++) {
570 certRef = (SecCertificateRef)CFArrayGetValueAtIndex(peerCerts, i);
571 printf("\n================== Server Cert %lu ===================\n\n", i);
572 print_cert(certRef, verbose);
573 printf("\n=============== End of Server Cert %lu ===============\n", i);
574 }
575 }
576
577 static void writePeerCerts(
578 CFArrayRef peerCerts,
579 const char *fileBase)
580 {
581 CFIndex numCerts;
582 SecCertificateRef certRef;
583 CFIndex i;
584 char fileName[100];
585
586 if(peerCerts == NULL) {
587 return;
588 }
589 numCerts = CFArrayGetCount(peerCerts);
590 for(i=0; i<numCerts; i++) {
591 sprintf(fileName, "%s%02d.cer", fileBase, (int)i);
592 certRef = (SecCertificateRef)CFArrayGetValueAtIndex(peerCerts, i);
593 writeFileSizet(fileName, SecCertificateGetBytePtr(certRef),
594 SecCertificateGetLength(certRef));
595 }
596 printf("...wrote %lu certs to fileBase %s\n", numCerts, fileBase);
597 }
598
599 static void showSSLResult(
600 SSLProtocol tryVersion,
601 char *acceptedProts,
602 OSStatus err,
603 SSLProtocol negVersion,
604 SSLCipherSuite negCipher,
605 Boolean sessionWasResumed,
606 unsigned char *sessionID,
607 size_t sessionIDLength,
608 CFArrayRef peerCerts,
609 bool displayPeerCerts,
610 SSLClientCertificateState certState,
611 char *fileBase) // non-NULL: write certs to file
612 {
613 CFIndex numPeerCerts;
614
615 printf("\n");
616 if(acceptedProts) {
617 printf(" Allowed SSL versions : %s\n", acceptedProts);
618 }
619 else {
620 printf(" Attempted SSL version : %s\n",
621 sslGetProtocolVersionString(tryVersion));
622 }
623 printf(" Result : %s\n", sslGetSSLErrString(err));
624 printf(" Negotiated SSL version : %s\n",
625 sslGetProtocolVersionString(negVersion));
626 printf(" Negotiated CipherSuite : %s\n",
627 sslGetCipherSuiteString(negCipher));
628 if(certState != kSSLClientCertNone) {
629 printf(" Client Cert State : %s\n",
630 sslGetClientCertStateString(certState));
631 }
632 printf(" Resumed Session : ");
633 if(sessionWasResumed) {
634 for(unsigned dex=0; dex<sessionIDLength; dex++) {
635 printf("%02X ", sessionID[dex]);
636 if(((dex % 8) == 7) && (dex != (sessionIDLength - 1))) {
637 printf("\n ");
638 }
639 }
640 printf("\n");
641 }
642 else {
643 printf("NOT RESUMED\n");
644 }
645 if(peerCerts == NULL) {
646 numPeerCerts = 0;
647 }
648 else {
649 numPeerCerts = CFArrayGetCount(peerCerts);
650 }
651 printf(" Number of peer certs : %lu\n", numPeerCerts);
652 if(numPeerCerts != 0) {
653 if(displayPeerCerts) {
654 showPeerCerts(peerCerts, false);
655 }
656 if(fileBase != NULL) {
657 writePeerCerts(peerCerts, fileBase);
658 }
659 }
660 printf("\n");
661 }
662
663 static int verifyClientCertState(
664 bool verifyCertState,
665 SSLClientCertificateState expectState,
666 SSLClientCertificateState gotState)
667 {
668 if(!verifyCertState) {
669 return 0;
670 }
671 if(expectState == gotState) {
672 return 0;
673 }
674 printf("***Expected clientCertState %s; got %s\n",
675 sslGetClientCertStateString(expectState),
676 sslGetClientCertStateString(gotState));
677 return 1;
678 }
679
680 int main(int argc, char **argv)
681 {
682 OSStatus err;
683 int arg;
684 char fullFileBase[100];
685 SSLProtocol negVersion;
686 SSLCipherSuite negCipher;
687 Boolean sessionWasResumed;
688 unsigned char sessionID[MAX_SESSION_ID_LENGTH];
689 size_t sessionIDLength;
690 CFArrayRef peerCerts = NULL;
691 char *argp;
692 otSocket listenSock;
693 CFArrayRef serverCerts = nil; // required
694 SecKeychainRef serverKc = nil;
695 int loopNum;
696 int errCount = 0;
697 SSLClientCertificateState certState; // obtained from sslServe
698
699 /* user-spec'd parameters */
700 unsigned short portNum = DEFAULT_PORT;
701 bool allowExpired = false;
702 bool allowAnyRoot = false;
703 char *fileBase = NULL;
704 bool displayCerts = false;
705 char cipherRestrict = '\0';
706 SSLProtocol attemptProt = kTLSProtocol1;
707 bool protXOnly = false; // kSSLProtocol3Only,
708 // kTLSProtocol1Only
709 char *acceptedProts = NULL; // "23t" ==> SSLSetProtocolVersionEnabled
710 bool quiet = false;
711 bool resumableEnable = true;
712 bool pause = false;
713 char *keyChainName = NULL;
714 int loops = 1;
715 SSLAuthenticate authenticate = kNeverAuthenticate;
716 bool nonBlocking = false;
717 bool allowExpiredRoot = false;
718 bool disableCertVerify = false;
719 char *anchorFile = NULL;
720 bool replaceAnchors = false;
721 bool vfyCertState = false;
722 SSLClientCertificateState expectCertState = kSSLClientCertNone;
723 char *password = NULL;
724 char *dhParamsFile = NULL;
725 unsigned char *dhParams = NULL;
726 unsigned dhParamsLen = 0;
727 bool doIdSearch = false;
728 bool completeCertChain = false;
729 uint32_t sessionCacheTimeout = 0;
730 bool disableAnonCiphers = false;
731 CFMutableArrayRef acceptableDNList = NULL;
732
733 for(arg=1; arg<argc; arg++) {
734 argp = argv[arg];
735 switch(argp[0]) {
736 case 'P':
737 portNum = atoi(&argp[2]);
738 break;
739 case 'k':
740 keyChainName = &argp[2];
741 break;
742 case 'e':
743 allowExpired = true;
744 break;
745 case 'E':
746 allowExpiredRoot = true;
747 break;
748 case 'x':
749 disableCertVerify = true;
750 break;
751 case 'a':
752 if(++arg == argc) {
753 /* requires another arg */
754 usage(argv);
755 }
756 anchorFile = argv[arg];
757 break;
758 case 'A':
759 if(++arg == argc) {
760 /* requires another arg */
761 usage(argv);
762 }
763 anchorFile = argv[arg];
764 replaceAnchors = true;
765 break;
766 case 'T':
767 if(argp[1] != '=') {
768 usage(argv);
769 }
770 vfyCertState = true;
771 switch(argp[2]) {
772 case 'n':
773 expectCertState = kSSLClientCertNone;
774 break;
775 case 'r':
776 expectCertState = kSSLClientCertRequested;
777 break;
778 case 's':
779 expectCertState = kSSLClientCertSent;
780 break;
781 case 'j':
782 expectCertState = kSSLClientCertRejected;
783 break;
784 default:
785 usage(argv);
786 }
787 break;
788 case 'r':
789 allowAnyRoot = true;
790 break;
791 case 'd':
792 break;
793 case 'c':
794 displayCerts = true;
795 break;
796 case 'f':
797 fileBase = &argp[2];
798 break;
799 case 'C':
800 cipherRestrict = argp[2];
801 break;
802 case '2':
803 attemptProt = kSSLProtocol2;
804 break;
805 case '3':
806 attemptProt = kSSLProtocol3;
807 break;
808 case 't':
809 attemptProt = kTLSProtocol1;
810 break;
811 case 'o':
812 protXOnly = true;
813 break;
814 case 'g':
815 if(argp[1] != '=') {
816 usage(argv);
817 }
818 acceptedProts = &argp[2];
819 break;
820 case 'R':
821 resumableEnable = false;
822 break;
823 case 'b':
824 nonBlocking = true;
825 break;
826 case 'u':
827 if(argp[1] != '=') {
828 usage(argv);
829 }
830 switch(argp[2]) {
831 case 'a': authenticate = kAlwaysAuthenticate; break;
832 case 'n': authenticate = kNeverAuthenticate; break;
833 case 't': authenticate = kTryAuthenticate; break;
834 default: usage(argv);
835 }
836 break;
837 case 'D':
838 if(++arg == argc) {
839 /* requires another arg */
840 usage(argv);
841 }
842 dhParamsFile = argv[arg];
843 break;
844 case 'z':
845 password = &argp[2];
846 break;
847 case 'H':
848 doIdSearch = true;
849 break;
850 case 'M':
851 completeCertChain = true;
852 break;
853 case 'i':
854 sessionCacheTimeout = atoi(&argp[2]);
855 break;
856 case '4':
857 disableAnonCiphers = true;
858 break;
859 case 'p':
860 pause = true;
861 break;
862 case 'q':
863 quiet = true;
864 break;
865 #if 0
866 case 'U':
867 if(++arg == argc) {
868 /* requires another arg */
869 usage(argv);
870 }
871 if(cspReadFile(argv[arg], &caCert, &caCertLen)) {
872 printf("***Error reading file %s. Aborting.\n", argv[arg]);
873 exit(1);
874 }
875 if(acceptableDNList == NULL) {
876 acceptableDNList = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
877 }
878 certData.Data = caCert;
879 certData.Length = caCertLen;
880 ortn = SecCertificateCreateFromData(&certData,
881 CSSM_CERT_X_509v3,
882 CSSM_CERT_ENCODING_DER,
883 &secCert);
884 if(ortn) {
885 cssmPerror("SecCertificateCreateFromData", ortn);
886 exit(1);
887 }
888 CFArrayAppendValue(acceptableDNList, secCert);
889 CFRelease(secCert);
890 break;
891 #endif
892 case 'l':
893 if(argp[1] == '\0') {
894 /* no loop count --> loop forever */
895 loops = 0;
896 break;
897 }
898 else if(argp[1] != '=') {
899 usage(argv);
900 }
901 loops = atoi(&argp[2]);
902 break;
903 default:
904 usage(argv);
905 }
906 }
907
908 #if NO_SERVER
909 # if DEBUG
910 securityd_init(NULL);
911 # endif
912 #endif
913
914 /* get server cert and optional encryption cert as CFArrayRef */
915 if(keyChainName) {
916 serverCerts = getSslCerts(keyChainName, false, completeCertChain,
917 anchorFile, &serverKc);
918 if(serverCerts == nil) {
919 exit(1);
920 }
921 }
922 else
923 #if 0
924 if(doIdSearch) {
925 OSStatus ortn = sslIdentityPicker(NULL, anchorFile, true, NULL, &serverCerts);
926 if(ortn) {
927 printf("***IdentitySearch failure; aborting.\n");
928 exit(1);
929 }
930 }
931 if(password) {
932 OSStatus ortn = SecKeychainUnlock(serverKc, strlen(password), password, true);
933 if(ortn) {
934 printf("SecKeychainUnlock returned %d\n", (int)ortn);
935 /* oh well */
936 }
937 }
938 #else
939 (void) doIdSearch;
940 #endif
941 if(protXOnly) {
942 switch(attemptProt) {
943 case kTLSProtocol1:
944 attemptProt = kTLSProtocol1Only;
945 break;
946 case kSSLProtocol3:
947 attemptProt = kSSLProtocol3Only;
948 break;
949 default:
950 break;
951 }
952 }
953 #if 0
954 if(dhParamsFile) {
955 int r = cspReadFile(dhParamsFile, &dhParams, &dhParamsLen);
956 if(r) {
957 printf("***Error reading diffie-hellman params from %s; aborting\n",
958 dhParamsFile);
959 }
960 }
961 #else
962 (void) dhParamsFile;
963 #endif
964
965 /* one-time only server port setup */
966 err = ListenForClients(portNum, nonBlocking, &listenSock);
967 if(err) {
968 printf("ListenForClients returned %d; aborting\n", (int)err);
969 exit(1);
970 }
971
972 for(loopNum=1; ; loopNum++) {
973 err = sslServe(listenSock,
974 portNum,
975 attemptProt,
976 acceptedProts,
977 serverCerts,
978 password,
979 allowExpired,
980 allowAnyRoot,
981 allowExpiredRoot,
982 disableCertVerify,
983 anchorFile,
984 replaceAnchors,
985 cipherRestrict,
986 authenticate,
987 dhParams,
988 dhParamsLen,
989 acceptableDNList,
990 resumableEnable,
991 sessionCacheTimeout,
992 disableAnonCiphers,
993 quiet,
994 pause,
995 &negVersion,
996 &negCipher,
997 &certState,
998 &sessionWasResumed,
999 sessionID,
1000 &sessionIDLength,
1001 &peerCerts,
1002 argv);
1003 if(err) {
1004 errCount++;
1005 }
1006 if(!quiet) {
1007 SSLProtocol tryProt = attemptProt;
1008 showSSLResult(tryProt,
1009 acceptedProts,
1010 err,
1011 negVersion,
1012 negCipher,
1013 sessionWasResumed,
1014 sessionID,
1015 sessionIDLength,
1016 peerCerts,
1017 displayCerts,
1018 certState,
1019 fileBase ? fullFileBase : NULL);
1020 }
1021 errCount += verifyClientCertState(vfyCertState, expectCertState,
1022 certState);
1023 freePeerCerts(peerCerts);
1024 if(loops && (loopNum == loops)) {
1025 break;
1026 }
1027 };
1028
1029 endpointShutdown(listenSock);
1030
1031 if(serverKc) {
1032 CFRelease(serverKc);
1033 }
1034 return errCount;
1035
1036 }
1037
1038