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