]> git.saurik.com Git - apple/security.git/blob - sslViewer/sslServer.cpp
Security-57740.1.18.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 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 == errSecSuccess) {
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 = errSecSuccess;
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 == errSecSuccess) {
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 bool verbose)
561 {
562 CFIndex numCerts;
563 SecCertificateRef certRef;
564 CFIndex i;
565
566 if(peerCerts == NULL) {
567 return;
568 }
569 numCerts = CFArrayGetCount(peerCerts);
570 for(i=0; i<numCerts; i++) {
571 certRef = (SecCertificateRef)CFArrayGetValueAtIndex(peerCerts, i);
572 printf("\n================== Server Cert %lu ===================\n\n", i);
573 print_cert(certRef, verbose);
574 printf("\n=============== End of Server Cert %lu ===============\n", i);
575 }
576 }
577
578 static void writePeerCerts(
579 CFArrayRef peerCerts,
580 const char *fileBase)
581 {
582 CFIndex numCerts;
583 SecCertificateRef certRef;
584 CFIndex i;
585 char fileName[100];
586
587 if(peerCerts == NULL) {
588 return;
589 }
590 numCerts = CFArrayGetCount(peerCerts);
591 for(i=0; i<numCerts; i++) {
592 sprintf(fileName, "%s%02d.cer", fileBase, (int)i);
593 certRef = (SecCertificateRef)CFArrayGetValueAtIndex(peerCerts, i);
594 writeFileSizet(fileName, SecCertificateGetBytePtr(certRef),
595 SecCertificateGetLength(certRef));
596 }
597 printf("...wrote %lu certs to fileBase %s\n", numCerts, fileBase);
598 }
599
600 static void showSSLResult(
601 SSLProtocol tryVersion,
602 char *acceptedProts,
603 OSStatus err,
604 SSLProtocol negVersion,
605 SSLCipherSuite negCipher,
606 Boolean sessionWasResumed,
607 unsigned char *sessionID,
608 size_t sessionIDLength,
609 CFArrayRef peerCerts,
610 bool displayPeerCerts,
611 SSLClientCertificateState certState,
612 char *fileBase) // non-NULL: write certs to file
613 {
614 CFIndex numPeerCerts;
615
616 printf("\n");
617 if(acceptedProts) {
618 printf(" Allowed SSL versions : %s\n", acceptedProts);
619 }
620 else {
621 printf(" Attempted SSL version : %s\n",
622 sslGetProtocolVersionString(tryVersion));
623 }
624 printf(" Result : %s\n", sslGetSSLErrString(err));
625 printf(" Negotiated SSL version : %s\n",
626 sslGetProtocolVersionString(negVersion));
627 printf(" Negotiated CipherSuite : %s\n",
628 sslGetCipherSuiteString(negCipher));
629 if(certState != kSSLClientCertNone) {
630 printf(" Client Cert State : %s\n",
631 sslGetClientCertStateString(certState));
632 }
633 printf(" Resumed Session : ");
634 if(sessionWasResumed) {
635 for(unsigned dex=0; dex<sessionIDLength; dex++) {
636 printf("%02X ", sessionID[dex]);
637 if(((dex % 8) == 7) && (dex != (sessionIDLength - 1))) {
638 printf("\n ");
639 }
640 }
641 printf("\n");
642 }
643 else {
644 printf("NOT RESUMED\n");
645 }
646 if(peerCerts == NULL) {
647 numPeerCerts = 0;
648 }
649 else {
650 numPeerCerts = CFArrayGetCount(peerCerts);
651 }
652 printf(" Number of peer certs : %lu\n", numPeerCerts);
653 if(numPeerCerts != 0) {
654 if(displayPeerCerts) {
655 showPeerCerts(peerCerts, false);
656 }
657 if(fileBase != NULL) {
658 writePeerCerts(peerCerts, fileBase);
659 }
660 }
661 printf("\n");
662 }
663
664 static int verifyClientCertState(
665 bool verifyCertState,
666 SSLClientCertificateState expectState,
667 SSLClientCertificateState gotState)
668 {
669 if(!verifyCertState) {
670 return 0;
671 }
672 if(expectState == gotState) {
673 return 0;
674 }
675 printf("***Expected clientCertState %s; got %s\n",
676 sslGetClientCertStateString(expectState),
677 sslGetClientCertStateString(gotState));
678 return 1;
679 }
680
681 int main(int argc, char **argv)
682 {
683 OSStatus err;
684 int arg;
685 char fullFileBase[100];
686 SSLProtocol negVersion;
687 SSLCipherSuite negCipher;
688 Boolean sessionWasResumed;
689 unsigned char sessionID[MAX_SESSION_ID_LENGTH];
690 size_t sessionIDLength;
691 CFArrayRef peerCerts = NULL;
692 char *argp;
693 otSocket listenSock;
694 CFArrayRef serverCerts = nil; // required
695 SecKeychainRef serverKc = nil;
696 int loopNum;
697 int errCount = 0;
698 SSLClientCertificateState certState; // obtained from sslServe
699
700 /* user-spec'd parameters */
701 unsigned short portNum = DEFAULT_PORT;
702 bool allowExpired = false;
703 bool allowAnyRoot = false;
704 char *fileBase = NULL;
705 bool displayCerts = false;
706 char cipherRestrict = '\0';
707 SSLProtocol attemptProt = kTLSProtocol1;
708 bool protXOnly = false; // kSSLProtocol3Only,
709 // kTLSProtocol1Only
710 char *acceptedProts = NULL; // "23t" ==> SSLSetProtocolVersionEnabled
711 bool quiet = false;
712 bool resumableEnable = true;
713 bool pause = false;
714 char *keyChainName = NULL;
715 int loops = 1;
716 SSLAuthenticate authenticate = kNeverAuthenticate;
717 bool nonBlocking = false;
718 bool allowExpiredRoot = false;
719 bool disableCertVerify = false;
720 char *anchorFile = NULL;
721 bool replaceAnchors = false;
722 bool vfyCertState = false;
723 SSLClientCertificateState expectCertState = kSSLClientCertNone;
724 char *password = NULL;
725 char *dhParamsFile = NULL;
726 unsigned char *dhParams = NULL;
727 unsigned dhParamsLen = 0;
728 bool doIdSearch = false;
729 bool completeCertChain = false;
730 uint32_t sessionCacheTimeout = 0;
731 bool disableAnonCiphers = false;
732 CFMutableArrayRef acceptableDNList = NULL;
733
734 for(arg=1; arg<argc; arg++) {
735 argp = argv[arg];
736 switch(argp[0]) {
737 case 'P':
738 portNum = atoi(&argp[2]);
739 break;
740 case 'k':
741 keyChainName = &argp[2];
742 break;
743 case 'e':
744 allowExpired = true;
745 break;
746 case 'E':
747 allowExpiredRoot = true;
748 break;
749 case 'x':
750 disableCertVerify = true;
751 break;
752 case 'a':
753 if(++arg == argc) {
754 /* requires another arg */
755 usage(argv);
756 }
757 anchorFile = argv[arg];
758 break;
759 case 'A':
760 if(++arg == argc) {
761 /* requires another arg */
762 usage(argv);
763 }
764 anchorFile = argv[arg];
765 replaceAnchors = true;
766 break;
767 case 'T':
768 if(argp[1] != '=') {
769 usage(argv);
770 }
771 vfyCertState = true;
772 switch(argp[2]) {
773 case 'n':
774 expectCertState = kSSLClientCertNone;
775 break;
776 case 'r':
777 expectCertState = kSSLClientCertRequested;
778 break;
779 case 's':
780 expectCertState = kSSLClientCertSent;
781 break;
782 case 'j':
783 expectCertState = kSSLClientCertRejected;
784 break;
785 default:
786 usage(argv);
787 }
788 break;
789 case 'r':
790 allowAnyRoot = true;
791 break;
792 case 'd':
793 break;
794 case 'c':
795 displayCerts = true;
796 break;
797 case 'f':
798 fileBase = &argp[2];
799 break;
800 case 'C':
801 cipherRestrict = argp[2];
802 break;
803 case '2':
804 attemptProt = kSSLProtocol2;
805 break;
806 case '3':
807 attemptProt = kSSLProtocol3;
808 break;
809 case 't':
810 attemptProt = kTLSProtocol1;
811 break;
812 case 'o':
813 protXOnly = true;
814 break;
815 case 'g':
816 if(argp[1] != '=') {
817 usage(argv);
818 }
819 acceptedProts = &argp[2];
820 break;
821 case 'R':
822 resumableEnable = false;
823 break;
824 case 'b':
825 nonBlocking = true;
826 break;
827 case 'u':
828 if(argp[1] != '=') {
829 usage(argv);
830 }
831 switch(argp[2]) {
832 case 'a': authenticate = kAlwaysAuthenticate; break;
833 case 'n': authenticate = kNeverAuthenticate; break;
834 case 't': authenticate = kTryAuthenticate; break;
835 default: usage(argv);
836 }
837 break;
838 case 'D':
839 if(++arg == argc) {
840 /* requires another arg */
841 usage(argv);
842 }
843 dhParamsFile = argv[arg];
844 break;
845 case 'z':
846 password = &argp[2];
847 break;
848 case 'H':
849 doIdSearch = true;
850 break;
851 case 'M':
852 completeCertChain = true;
853 break;
854 case 'i':
855 sessionCacheTimeout = atoi(&argp[2]);
856 break;
857 case '4':
858 disableAnonCiphers = true;
859 break;
860 case 'p':
861 pause = true;
862 break;
863 case 'q':
864 quiet = true;
865 break;
866 #if 0
867 case 'U':
868 if(++arg == argc) {
869 /* requires another arg */
870 usage(argv);
871 }
872 if(cspReadFile(argv[arg], &caCert, &caCertLen)) {
873 printf("***Error reading file %s. Aborting.\n", argv[arg]);
874 exit(1);
875 }
876 if(acceptableDNList == NULL) {
877 acceptableDNList = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
878 }
879 certData.Data = caCert;
880 certData.Length = caCertLen;
881 ortn = SecCertificateCreateFromData(&certData,
882 CSSM_CERT_X_509v3,
883 CSSM_CERT_ENCODING_DER,
884 &secCert);
885 if(ortn) {
886 cssmPerror("SecCertificateCreateFromData", ortn);
887 exit(1);
888 }
889 CFArrayAppendValue(acceptableDNList, secCert);
890 CFRelease(secCert);
891 break;
892 #endif
893 case 'l':
894 if(argp[1] == '\0') {
895 /* no loop count --> loop forever */
896 loops = 0;
897 break;
898 }
899 else if(argp[1] != '=') {
900 usage(argv);
901 }
902 loops = atoi(&argp[2]);
903 break;
904 default:
905 usage(argv);
906 }
907 }
908
909 #if NO_SERVER
910 # if DEBUG
911 securityd_init(NULL);
912 # endif
913 #endif
914
915 /* get server cert and optional encryption cert as CFArrayRef */
916 if(keyChainName) {
917 serverCerts = getSslCerts(keyChainName, false, completeCertChain,
918 anchorFile, &serverKc);
919 if(serverCerts == nil) {
920 exit(1);
921 }
922 }
923 else
924 #if 0
925 if(doIdSearch) {
926 OSStatus ortn = sslIdentityPicker(NULL, anchorFile, true, NULL, &serverCerts);
927 if(ortn) {
928 printf("***IdentitySearch failure; aborting.\n");
929 exit(1);
930 }
931 }
932 if(password) {
933 OSStatus ortn = SecKeychainUnlock(serverKc, strlen(password), password, true);
934 if(ortn) {
935 printf("SecKeychainUnlock returned %d\n", (int)ortn);
936 /* oh well */
937 }
938 }
939 #else
940 (void) doIdSearch;
941 #endif
942 if(protXOnly) {
943 switch(attemptProt) {
944 case kTLSProtocol1:
945 attemptProt = kTLSProtocol1Only;
946 break;
947 case kSSLProtocol3:
948 attemptProt = kSSLProtocol3Only;
949 break;
950 default:
951 break;
952 }
953 }
954 #if 0
955 if(dhParamsFile) {
956 int r = cspReadFile(dhParamsFile, &dhParams, &dhParamsLen);
957 if(r) {
958 printf("***Error reading diffie-hellman params from %s; aborting\n",
959 dhParamsFile);
960 }
961 }
962 #else
963 (void) dhParamsFile;
964 #endif
965
966 /* one-time only server port setup */
967 err = ListenForClients(portNum, nonBlocking, &listenSock);
968 if(err) {
969 printf("ListenForClients returned %d; aborting\n", (int)err);
970 exit(1);
971 }
972
973 for(loopNum=1; ; loopNum++) {
974 err = sslServe(listenSock,
975 portNum,
976 attemptProt,
977 acceptedProts,
978 serverCerts,
979 password,
980 allowExpired,
981 allowAnyRoot,
982 allowExpiredRoot,
983 disableCertVerify,
984 anchorFile,
985 replaceAnchors,
986 cipherRestrict,
987 authenticate,
988 dhParams,
989 dhParamsLen,
990 acceptableDNList,
991 resumableEnable,
992 sessionCacheTimeout,
993 disableAnonCiphers,
994 quiet,
995 pause,
996 &negVersion,
997 &negCipher,
998 &certState,
999 &sessionWasResumed,
1000 sessionID,
1001 &sessionIDLength,
1002 &peerCerts,
1003 argv);
1004 if(err) {
1005 errCount++;
1006 }
1007 if(!quiet) {
1008 SSLProtocol tryProt = attemptProt;
1009 showSSLResult(tryProt,
1010 acceptedProts,
1011 err,
1012 negVersion,
1013 negCipher,
1014 sessionWasResumed,
1015 sessionID,
1016 sessionIDLength,
1017 peerCerts,
1018 displayCerts,
1019 certState,
1020 fileBase ? fullFileBase : NULL);
1021 }
1022 errCount += verifyClientCertState(vfyCertState, expectCertState,
1023 certState);
1024 freePeerCerts(peerCerts);
1025 if(loops && (loopNum == loops)) {
1026 break;
1027 }
1028 };
1029
1030 endpointShutdown(listenSock);
1031
1032 if(serverKc) {
1033 CFRelease(serverKc);
1034 }
1035 return errCount;
1036
1037 }
1038
1039