]> git.saurik.com Git - apple/security.git/blob - sslViewer/sslServer.cpp
Security-57031.1.35.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 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)(intptr_t)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 = errSecIO;
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 == errSecSuccess) {
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 = errSecSuccess;
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 == errSecSuccess) {
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 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 break;
808 case 'c':
809 displayCerts = true;
810 break;
811 case 'f':
812 fileBase = &argp[2];
813 break;
814 case 'C':
815 cipherRestrict = argp[2];
816 break;
817 case '2':
818 attemptProt = kSSLProtocol2;
819 break;
820 case '3':
821 attemptProt = kSSLProtocol3;
822 break;
823 case 't':
824 attemptProt = kTLSProtocol1;
825 break;
826 case 'o':
827 protXOnly = true;
828 break;
829 case 'g':
830 if(argp[1] != '=') {
831 usage(argv);
832 }
833 acceptedProts = &argp[2];
834 break;
835 case 'R':
836 resumableEnable = false;
837 break;
838 case 'b':
839 nonBlocking = true;
840 break;
841 case 'u':
842 if(argp[1] != '=') {
843 usage(argv);
844 }
845 switch(argp[2]) {
846 case 'a': authenticate = kAlwaysAuthenticate; break;
847 case 'n': authenticate = kNeverAuthenticate; break;
848 case 't': authenticate = kTryAuthenticate; break;
849 default: usage(argv);
850 }
851 break;
852 case 'D':
853 if(++arg == argc) {
854 /* requires another arg */
855 usage(argv);
856 }
857 dhParamsFile = argv[arg];
858 break;
859 case 'z':
860 password = &argp[2];
861 break;
862 case 'H':
863 doIdSearch = true;
864 break;
865 case 'M':
866 completeCertChain = true;
867 break;
868 case 'i':
869 sessionCacheTimeout = atoi(&argp[2]);
870 break;
871 case '4':
872 disableAnonCiphers = true;
873 break;
874 case 'p':
875 pause = true;
876 break;
877 case 'q':
878 quiet = true;
879 break;
880 #if 0
881 case 'U':
882 if(++arg == argc) {
883 /* requires another arg */
884 usage(argv);
885 }
886 if(cspReadFile(argv[arg], &caCert, &caCertLen)) {
887 printf("***Error reading file %s. Aborting.\n", argv[arg]);
888 exit(1);
889 }
890 if(acceptableDNList == NULL) {
891 acceptableDNList = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
892 }
893 certData.Data = caCert;
894 certData.Length = caCertLen;
895 ortn = SecCertificateCreateFromData(&certData,
896 CSSM_CERT_X_509v3,
897 CSSM_CERT_ENCODING_DER,
898 &secCert);
899 if(ortn) {
900 cssmPerror("SecCertificateCreateFromData", ortn);
901 exit(1);
902 }
903 CFArrayAppendValue(acceptableDNList, secCert);
904 CFRelease(secCert);
905 break;
906 #endif
907 case 'l':
908 if(argp[1] == '\0') {
909 /* no loop count --> loop forever */
910 loops = 0;
911 break;
912 }
913 else if(argp[1] != '=') {
914 usage(argv);
915 }
916 loops = atoi(&argp[2]);
917 break;
918 default:
919 usage(argv);
920 }
921 }
922
923 #if NO_SERVER
924 # if DEBUG
925 securityd_init(NULL);
926 # endif
927 #endif
928
929 /* get server cert and optional encryption cert as CFArrayRef */
930 if(keyChainName) {
931 serverCerts = getSslCerts(keyChainName, false, completeCertChain,
932 anchorFile, &serverKc);
933 if(serverCerts == nil) {
934 exit(1);
935 }
936 }
937 else
938 #if 0
939 if(doIdSearch) {
940 OSStatus ortn = sslIdentityPicker(NULL, anchorFile, true, NULL, &serverCerts);
941 if(ortn) {
942 printf("***IdentitySearch failure; aborting.\n");
943 exit(1);
944 }
945 }
946 if(password) {
947 OSStatus ortn = SecKeychainUnlock(serverKc, strlen(password), password, true);
948 if(ortn) {
949 printf("SecKeychainUnlock returned %d\n", (int)ortn);
950 /* oh well */
951 }
952 }
953 if(encryptKeyChainName) {
954 encryptCerts = getSslCerts(encryptKeyChainName, true, completeCertChain,
955 anchorFile, &encryptKc);
956 if(encryptCerts == nil) {
957 exit(1);
958 }
959 }
960 #else
961 (void) doIdSearch;
962 (void) encryptKeyChainName;
963 #endif
964 if(protXOnly) {
965 switch(attemptProt) {
966 case kTLSProtocol1:
967 attemptProt = kTLSProtocol1Only;
968 break;
969 case kSSLProtocol3:
970 attemptProt = kSSLProtocol3Only;
971 break;
972 default:
973 break;
974 }
975 }
976 #if 0
977 if(dhParamsFile) {
978 int r = cspReadFile(dhParamsFile, &dhParams, &dhParamsLen);
979 if(r) {
980 printf("***Error reading diffie-hellman params from %s; aborting\n",
981 dhParamsFile);
982 }
983 }
984 #else
985 (void) dhParamsFile;
986 #endif
987
988 /* one-time only server port setup */
989 err = ListenForClients(portNum, nonBlocking, &listenSock);
990 if(err) {
991 printf("ListenForClients returned %d; aborting\n", (int)err);
992 exit(1);
993 }
994
995 for(loopNum=1; ; loopNum++) {
996 err = sslServe(listenSock,
997 portNum,
998 attemptProt,
999 acceptedProts,
1000 serverCerts,
1001 password,
1002 encryptCerts,
1003 allowExpired,
1004 allowAnyRoot,
1005 allowExpiredRoot,
1006 disableCertVerify,
1007 anchorFile,
1008 replaceAnchors,
1009 cipherRestrict,
1010 authenticate,
1011 dhParams,
1012 dhParamsLen,
1013 acceptableDNList,
1014 resumableEnable,
1015 sessionCacheTimeout,
1016 disableAnonCiphers,
1017 quiet,
1018 pause,
1019 &negVersion,
1020 &negCipher,
1021 &certState,
1022 &sessionWasResumed,
1023 sessionID,
1024 &sessionIDLength,
1025 &peerCerts,
1026 argv);
1027 if(err) {
1028 errCount++;
1029 }
1030 if(!quiet) {
1031 SSLProtocol tryProt = attemptProt;
1032 showSSLResult(tryProt,
1033 acceptedProts,
1034 err,
1035 negVersion,
1036 negCipher,
1037 sessionWasResumed,
1038 sessionID,
1039 sessionIDLength,
1040 peerCerts,
1041 displayCerts,
1042 certState,
1043 fileBase ? fullFileBase : NULL);
1044 }
1045 errCount += verifyClientCertState(vfyCertState, expectCertState,
1046 certState);
1047 freePeerCerts(peerCerts);
1048 if(loops && (loopNum == loops)) {
1049 break;
1050 }
1051 };
1052
1053 endpointShutdown(listenSock);
1054
1055 if(serverKc) {
1056 CFRelease(serverKc);
1057 }
1058 if(encryptKc) {
1059 CFRelease(encryptKc);
1060 }
1061 return errCount;
1062
1063 }
1064
1065