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