darling-security/sslViewer/sslServer.cpp
2020-07-06 07:59:58 -04:00

992 lines
24 KiB
C++

/*
* Copyright (c) 2008-2013 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*
* Trivial SSL server example, using SecureTransport / OS X version.
*
* Written by Doug Mitchell.
*/
#include <Security/SecureTransport.h>
#include <Security/SecureTransportPriv.h>
#include "sslAppUtils.h"
#include "ioSock.h"
#include "utilities/fileIo.h"
#include <Security/SecBase.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
#include <sys/param.h>
#include <Security/Security.h>
#include <Security/SecCertificatePriv.h>
#include <CoreFoundation/CoreFoundation.h>
#include "SecurityTool/sharedTool/print_cert.h"
#if NO_SERVER
#include "keychain/securityd/spi.h"
#endif
/* Set true when PR-3074739 is merged to TOT */
#define SET_DH_PARAMS_ENABLE 1
/* true when using SSLCopyPeerCertificates() per Radar 3311892 */
#define USE_COPY_PEER_CERTS 1
/*
* Defaults, overridable by user.
*/
#define SERVER_MESSAGE "HTTP/1.0 200 OK\015\012Content-Type: text/html\015\012\015\012" \
"<HTML><HEAD><TITLE>SecureTransport Test Server</TITLE></HEAD>" \
"<BODY><H2>Secure connection established.</H2>" \
"Message from the 'sslServer' sample application.\015\012</BODY>" \
"</HTML>\015\012"
/* For ease of debugging, pick a non-privileged port */
#define DEFAULT_PORT 1200
// #define DEFAULT_PORT 443
#define DEFAULT_HOST "localhost"
#define DEFAULT_KC "certkc"
static void usage(char **argv)
{
printf("Usage: %s [option ...]\n", argv[0]);
printf("Options:\n");
printf(" P=port Port to listen on; default is %d\n", DEFAULT_PORT);
printf(" k=keychain Contains server cert and keys.\n");
printf(" y=keychain Encryption-only cert and keys.\n");
printf(" e Allow Expired Certs\n");
printf(" r Allow any root cert\n");
printf(" E Allow Expired Roots\n");
printf(" x Disable Cert Verification\n");
printf(" f=fileBase Write Peer Certs to fileBase*\n");
printf(" c Display peer certs\n");
printf(" d Display received data\n");
printf(" C=cipherSuite (e=40-bit d=DES D=40-bit DES 3=3DES 4=RC4 $=40-bit RC4\n"
" 2=RC2 a=AES128 A=AES256 h=DH H=Anon DH r=DHE/RSA s=DH/DSS\n"
" n=RSA/NULL\n");
printf(" 2 SSLv2 only (default is best fit)\n");
printf(" 3 SSLv3 only (default is best fit)\n");
printf(" t TLSv1 only (default is best fit)\n");
printf(" o TLSv1, SSLv3 use kSSLProtocol__X__Only\n");
printf(" g={prot...} Specify legal protocols; prot = any combo of [23t]\n");
printf(" T=[nrsj] Verify client cert state = "
"none/requested/sent/rejected\n");
printf(" R Disable resumable session support\n");
printf(" i=timeout Session cache timeout\n");
printf(" u=[nat] Authentication: n=never; a=always; t=try\n");
printf(" b Non-blocking I/O\n");
printf(" a fileNmae Add fileName to list of trusted roots\n");
printf(" A fileName fileName is ONLY trusted root\n");
printf(" U filename Add filename to acceptable DNList (multiple times OK)\n");
printf(" D filename Diffie-Hellman parameters from filename\n");
printf(" z=password Unlock server keychain with password.\n");
printf(" H Do SecIndentityRef search instead of specific keychain\n");
printf(" M Complete cert chain (default assumes that our identity is root)\n");
printf(" 4 Disable anonymous ciphers\n");
printf(" p Pause after each phase\n");
printf(" l[=loops] Loop, performing multiple transactions\n");
printf(" q Quiet/diagnostic mode (site names and errors only)\n");
printf(" h Help\n");
exit(1);
}
/* snag a copy of current connection's peer certs so we can
* examine them later after the connection is closed */
static OSStatus copyPeerCerts(
SSLContext *ctx,
CFArrayRef *peerCerts) // mallocd & RETURNED
{
#if USE_COPY_PEER_CERTS
OSStatus ortn = SSLCopyPeerCertificates(ctx, peerCerts);
#else
OSStatus ortn = SSLGetPeerCertificates(ctx, peerCerts);
#endif
if(ortn) {
printf("***Error obtaining peer certs: %s\n",
sslGetSSLErrString(ortn));
}
return ortn;
}
/* free the cert array obtained via SSLGetPeerCertificates() */
static void freePeerCerts(
CFArrayRef peerCerts)
{
if(peerCerts == NULL) {
return;
}
#if USE_COPY_PEER_CERTS
/* Voila! Problem fixed. */
CFRelease(peerCerts);
return;
#else
CFIndex numCerts;
SecCertificateRef certData;
CFIndex i;
numCerts = CFArrayGetCount(peerCerts);
for(i=0; i<numCerts; i++) {
certData = (SecCertificateRef)CFArrayGetValueAtIndex(peerCerts, i);
CFRelease(certData);
}
CFRelease(peerCerts);
#endif
}
/* print reply received from server */
static void dumpAscii(
uint8_t *rcvBuf,
size_t len)
{
char *cp = (char *)rcvBuf;
uint32_t i;
char c;
for(i=0; i<len; i++) {
c = *cp++;
if(c == '\0') {
break;
}
switch(c) {
case '\n':
printf("\\n");
break;
case '\r':
printf("\\r");
break;
default:
if(isprint(c) && (c != '\n')) {
printf("%c", c);
}
else {
printf("<%02X>", ((unsigned)c) & 0xff);
}
break;
}
}
printf("\n");
}
static void doPause(const char *prompt) {
if(prompt) {
printf("%s. ", prompt);
}
fpurge(stdin);
printf("Continue (n/anything)? ");
char c = getchar();
if(c == 'n') {
exit(0);
}
}
/*
* Perform one SSL diagnostic server-side session. Returns nonzero on error.
* Normally no output to stdout except initial "waiting for connection" message,
* unless there is a really screwed up error (i.e., something not directly related
* to the SSL connection).
*/
#define RCV_BUF_SIZE 256
static OSStatus sslServe(
otSocket listenSock,
unsigned short portNum,
SSLProtocol tryVersion, // only used if acceptedProts NULL
const char *acceptedProts,
CFArrayRef serverCerts, // required
char *password, // optional
bool allowExpired,
bool allowAnyRoot,
bool allowExpiredRoot,
bool disableCertVerify,
char *anchorFile,
bool replaceAnchors,
char cipherRestrict, // '2', 'd'. etc...'\0' for no
// restriction
SSLAuthenticate authenticate,
unsigned char *dhParams, // optional D-H parameters
unsigned dhParamsLen,
CFArrayRef acceptableDNList, // optional
bool resumableEnable,
uint32_t sessionCacheTimeout,// optional
bool disableAnonCiphers,
bool silent, // no stdout
bool pause,
SSLProtocol *negVersion, // RETURNED
SSLCipherSuite *negCipher, // RETURNED
SSLClientCertificateState *certState, // RETURNED
Boolean *sessionWasResumed, // RETURNED
unsigned char *sessionID, // mallocd by caller, RETURNED
size_t *sessionIDLength, // RETURNED
CFArrayRef *peerCerts, // mallocd & RETURNED
char **argv)
{
otSocket acceptSock;
PeerSpec peerId;
OSStatus ortn;
SSLContextRef ctx = NULL;
size_t length;
uint8_t rcvBuf[RCV_BUF_SIZE];
const char *outMsg = SERVER_MESSAGE;
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
*negVersion = kSSLProtocolUnknown;
*negCipher = SSL_NULL_WITH_NULL_NULL;
*peerCerts = NULL;
#if IGNORE_SIGPIPE
signal(SIGPIPE, sigpipe);
#endif
/* first wait for a connection */
if(!silent) {
printf("Waiting for client connection on port %u...", portNum);
fflush(stdout);
}
ortn = AcceptClientConnection(listenSock, &acceptSock, &peerId);
if(ortn) {
printf("AcceptClientConnection returned %d; aborting\n", (int)ortn);
return ortn;
}
/*
* Set up a SecureTransport session.
* First the standard calls.
*/
ortn = SSLNewContext(true, &ctx);
if(ortn) {
printSslErrStr("SSLNewContext", ortn);
goto cleanup;
}
ortn = SSLSetIOFuncs(ctx, SocketRead, SocketWrite);
if(ortn) {
printSslErrStr("SSLSetIOFuncs", ortn);
goto cleanup;
}
ortn = SSLSetConnection(ctx, (SSLConnectionRef)(intptr_t)acceptSock);
if(ortn) {
printSslErrStr("SSLSetConnection", ortn);
goto cleanup;
}
/* have to do these options befor setting server certs */
if(allowExpired) {
ortn = SSLSetAllowsExpiredCerts(ctx, true);
if(ortn) {
printSslErrStr("SSLSetAllowExpiredCerts", ortn);
goto cleanup;
}
}
if(allowAnyRoot) {
ortn = SSLSetAllowsAnyRoot(ctx, true);
if(ortn) {
printSslErrStr("SSLSetAllowAnyRoot", ortn);
goto cleanup;
}
}
if(anchorFile) {
ortn = sslAddTrustedRoot(ctx, anchorFile, replaceAnchors);
if(ortn) {
printf("***Error obtaining anchor file %s\n", anchorFile);
goto cleanup;
}
}
if(serverCerts != NULL) {
if(anchorFile == NULL) {
/* no specific anchors, so assume we want to trust this one */
ortn = addIdentityAsTrustedRoot(ctx, serverCerts);
if(ortn) {
goto cleanup;
}
}
ortn = SSLSetCertificate(ctx, serverCerts);
if(ortn) {
printSslErrStr("SSLSetCertificate", ortn);
goto cleanup;
}
}
if(allowExpiredRoot) {
ortn = SSLSetAllowsExpiredRoots(ctx, true);
if(ortn) {
printSslErrStr("SSLSetAllowsExpiredRoots", ortn);
goto cleanup;
}
}
if(disableCertVerify) {
ortn = SSLSetEnableCertVerify(ctx, false);
if(ortn) {
printSslErrStr("SSLSetEnableCertVerify", ortn);
goto cleanup;
}
}
/*
* SecureTransport options.
*/
if(acceptedProts) {
ortn = SSLSetProtocolVersionEnabled(ctx, kSSLProtocolAll, false);
if(ortn) {
printSslErrStr("SSLSetProtocolVersionEnabled(all off)", ortn);
goto cleanup;
}
for(const char *cp = acceptedProts; *cp; cp++) {
SSLProtocol prot = kSSLProtocolUnknown;
switch(*cp) {
case '2':
prot = kSSLProtocol2;
break;
case '3':
prot = kSSLProtocol3;
break;
case 't':
prot = kTLSProtocol1;
break;
default:
usage(argv);
}
ortn = SSLSetProtocolVersionEnabled(ctx, prot, true);
if(ortn) {
printSslErrStr("SSLSetProtocolVersionEnabled", ortn);
goto cleanup;
}
}
}
else {
ortn = SSLSetProtocolVersion(ctx, tryVersion);
if(ortn) {
printSslErrStr("SSLSetProtocolVersion", ortn);
goto cleanup;
}
}
if(resumableEnable) {
ortn = SSLSetPeerID(ctx, &peerId, sizeof(PeerSpec));
if(ortn) {
printSslErrStr("SSLSetPeerID", ortn);
goto cleanup;
}
}
if(cipherRestrict != '\0') {
ortn = sslSetCipherRestrictions(ctx, cipherRestrict);
if(ortn) {
goto cleanup;
}
}
if(authenticate != kNeverAuthenticate) {
ortn = SSLSetClientSideAuthenticate(ctx, authenticate);
if(ortn) {
printSslErrStr("SSLSetClientSideAuthenticate", ortn);
goto cleanup;
}
}
if(dhParams) {
ortn = SSLSetDiffieHellmanParams(ctx, dhParams, dhParamsLen);
if(ortn) {
printSslErrStr("SSLSetDiffieHellmanParams", ortn);
goto cleanup;
}
}
if(sessionCacheTimeout) {
ortn = SSLSetSessionCacheTimeout(ctx, sessionCacheTimeout);
if(ortn) {
printSslErrStr("SSLSetSessionCacheTimeout", ortn);
goto cleanup;
}
}
if(disableAnonCiphers) {
ortn = SSLSetAllowAnonymousCiphers(ctx, false);
if(ortn) {
printSslErrStr("SSLSetAllowAnonymousCiphers", ortn);
goto cleanup;
}
/* quickie test of the getter */
Boolean e;
ortn = SSLGetAllowAnonymousCiphers(ctx, &e);
if(ortn) {
printSslErrStr("SSLGetAllowAnonymousCiphers", ortn);
goto cleanup;
}
if(e) {
printf("***SSLGetAllowAnonymousCiphers() returned true; expected false\n");
ortn = errSecIO;
goto cleanup;
}
}
/* XXX/cs
if(acceptableDNList) {
ortn = SSLSetCertificateAuthorities(ctx, acceptableDNList, TRUE);
if(ortn) {
printSslErrStr("SSLSetCertificateAuthorities", ortn);
goto cleanup;
}
}
*/
/* end options */
if(pause) {
doPause("SSLContext initialized");
}
/* Perform SSL/TLS handshake */
do
{ ortn = SSLHandshake(ctx);
if((ortn == errSSLWouldBlock) && !silent) {
/* keep UI responsive */
sslOutputDot();
}
} while (ortn == errSSLWouldBlock);
/* this works even if handshake failed due to cert chain invalid */
copyPeerCerts(ctx, peerCerts);
SSLGetClientCertificateState(ctx, certState);
SSLGetNegotiatedCipher(ctx, negCipher);
SSLGetNegotiatedProtocolVersion(ctx, negVersion);
*sessionIDLength = MAX_SESSION_ID_LENGTH;
ortn = SSLGetResumableSessionInfo(ctx, sessionWasResumed, sessionID, sessionIDLength);
if(!silent) {
printf("\n");
}
if(ortn) {
goto cleanup;
}
if(pause) {
doPause("SSLContext handshake complete");
}
/* wait for one complete line or user says they've had enough */
while(ortn == errSecSuccess) {
length = sizeof(rcvBuf);
ortn = SSLRead(ctx, rcvBuf, length, &length);
if(length == 0) {
/* keep UI responsive */
sslOutputDot();
}
else {
/* print what we have */
printf("client request: ");
dumpAscii(rcvBuf, length);
}
if(pause) {
/* allow user to bail */
char resp;
fpurge(stdin);
printf("\nMore client request (y/anything): ");
resp = getchar();
if(resp != 'y') {
break;
}
}
/* poor person's line completion scan */
for(unsigned i=0; i<length; i++) {
if((rcvBuf[i] == '\n') || (rcvBuf[i] == '\r')) {
/* a labelled break would be nice here.... */
goto serverResp;
}
}
if (ortn == errSSLWouldBlock) {
ortn = errSecSuccess;
}
}
serverResp:
if(pause) {
doPause("Client GET msg received");
}
/* send out canned response */
length = strlen(outMsg);
ortn = SSLWrite(ctx, outMsg, length, &length);
if(ortn) {
printSslErrStr("SSLWrite", ortn);
}
if(pause) {
doPause("Server response sent");
}
cleanup:
/*
* always do close, even on error - to flush outgoing write queue
*/
OSStatus cerr = SSLClose(ctx);
if(ortn == errSecSuccess) {
ortn = cerr;
}
if(acceptSock) {
endpointShutdown(acceptSock);
}
if(ctx) {
SSLDisposeContext(ctx);
}
#pragma clang diagnostic pop
/* FIXME - dispose of serverCerts */
return ortn;
}
static void showPeerCerts(
CFArrayRef peerCerts,
bool verbose)
{
CFIndex numCerts;
SecCertificateRef certRef;
CFIndex i;
if(peerCerts == NULL) {
return;
}
numCerts = CFArrayGetCount(peerCerts);
for(i=0; i<numCerts; i++) {
certRef = (SecCertificateRef)CFArrayGetValueAtIndex(peerCerts, i);
printf("\n================== Server Cert %lu ===================\n\n", i);
print_cert(certRef, verbose);
printf("\n=============== End of Server Cert %lu ===============\n", i);
}
}
static void writePeerCerts(
CFArrayRef peerCerts,
const char *fileBase)
{
CFIndex numCerts;
SecCertificateRef certRef;
CFIndex i;
char fileName[100];
if(peerCerts == NULL) {
return;
}
numCerts = CFArrayGetCount(peerCerts);
for(i=0; i<numCerts; i++) {
sprintf(fileName, "%s%02d.cer", fileBase, (int)i);
certRef = (SecCertificateRef)CFArrayGetValueAtIndex(peerCerts, i);
writeFileSizet(fileName, SecCertificateGetBytePtr(certRef),
SecCertificateGetLength(certRef));
}
printf("...wrote %lu certs to fileBase %s\n", numCerts, fileBase);
}
static void showSSLResult(
SSLProtocol tryVersion,
char *acceptedProts,
OSStatus err,
SSLProtocol negVersion,
SSLCipherSuite negCipher,
Boolean sessionWasResumed,
unsigned char *sessionID,
size_t sessionIDLength,
CFArrayRef peerCerts,
bool displayPeerCerts,
SSLClientCertificateState certState,
char *fileBase) // non-NULL: write certs to file
{
CFIndex numPeerCerts;
printf("\n");
if(acceptedProts) {
printf(" Allowed SSL versions : %s\n", acceptedProts);
}
else {
printf(" Attempted SSL version : %s\n",
sslGetProtocolVersionString(tryVersion));
}
printf(" Result : %s\n", sslGetSSLErrString(err));
printf(" Negotiated SSL version : %s\n",
sslGetProtocolVersionString(negVersion));
printf(" Negotiated CipherSuite : %s\n",
sslGetCipherSuiteString(negCipher));
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
if(certState != kSSLClientCertNone) {
printf(" Client Cert State : %s\n",
sslGetClientCertStateString(certState));
}
#pragma clang diagnostic pop
printf(" Resumed Session : ");
if(sessionWasResumed) {
for(unsigned dex=0; dex<sessionIDLength; dex++) {
printf("%02X ", sessionID[dex]);
if(((dex % 8) == 7) && (dex != (sessionIDLength - 1))) {
printf("\n ");
}
}
printf("\n");
}
else {
printf("NOT RESUMED\n");
}
if(peerCerts == NULL) {
numPeerCerts = 0;
}
else {
numPeerCerts = CFArrayGetCount(peerCerts);
}
printf(" Number of peer certs : %lu\n", numPeerCerts);
if(numPeerCerts != 0) {
if(displayPeerCerts) {
showPeerCerts(peerCerts, false);
}
if(fileBase != NULL) {
writePeerCerts(peerCerts, fileBase);
}
}
printf("\n");
}
static int verifyClientCertState(
bool verifyCertState,
SSLClientCertificateState expectState,
SSLClientCertificateState gotState)
{
if(!verifyCertState) {
return 0;
}
if(expectState == gotState) {
return 0;
}
printf("***Expected clientCertState %s; got %s\n",
sslGetClientCertStateString(expectState),
sslGetClientCertStateString(gotState));
return 1;
}
int main(int argc, char **argv)
{
OSStatus err;
int arg;
char fullFileBase[100];
SSLProtocol negVersion;
SSLCipherSuite negCipher;
Boolean sessionWasResumed;
unsigned char sessionID[MAX_SESSION_ID_LENGTH];
size_t sessionIDLength;
CFArrayRef peerCerts = NULL;
char *argp;
otSocket listenSock;
CFArrayRef serverCerts = nil; // required
SecKeychainRef serverKc = nil;
int loopNum;
int errCount = 0;
SSLClientCertificateState certState; // obtained from sslServe
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
/* user-spec'd parameters */
unsigned short portNum = DEFAULT_PORT;
bool allowExpired = false;
bool allowAnyRoot = false;
char *fileBase = NULL;
bool displayCerts = false;
char cipherRestrict = '\0';
SSLProtocol attemptProt = kTLSProtocol1;
bool protXOnly = false; // kSSLProtocol3Only,
// kTLSProtocol1Only
char *acceptedProts = NULL; // "23t" ==> SSLSetProtocolVersionEnabled
bool quiet = false;
bool resumableEnable = true;
bool pause = false;
char *keyChainName = NULL;
int loops = 1;
SSLAuthenticate authenticate = kNeverAuthenticate;
bool nonBlocking = false;
bool allowExpiredRoot = false;
bool disableCertVerify = false;
char *anchorFile = NULL;
bool replaceAnchors = false;
bool vfyCertState = false;
SSLClientCertificateState expectCertState = kSSLClientCertNone;
char *password = NULL;
unsigned char *dhParams = NULL;
unsigned dhParamsLen = 0;
bool completeCertChain = false;
uint32_t sessionCacheTimeout = 0;
bool disableAnonCiphers = false;
CFMutableArrayRef acceptableDNList = NULL;
for(arg=1; arg<argc; arg++) {
argp = argv[arg];
switch(argp[0]) {
case 'P':
portNum = atoi(&argp[2]);
break;
case 'k':
keyChainName = &argp[2];
break;
case 'e':
allowExpired = true;
break;
case 'E':
allowExpiredRoot = true;
break;
case 'x':
disableCertVerify = true;
break;
case 'a':
if(++arg == argc) {
/* requires another arg */
usage(argv);
}
anchorFile = argv[arg];
break;
case 'A':
if(++arg == argc) {
/* requires another arg */
usage(argv);
}
anchorFile = argv[arg];
replaceAnchors = true;
break;
case 'T':
if(argp[1] != '=') {
usage(argv);
}
vfyCertState = true;
switch(argp[2]) {
case 'n':
expectCertState = kSSLClientCertNone;
break;
case 'r':
expectCertState = kSSLClientCertRequested;
break;
case 's':
expectCertState = kSSLClientCertSent;
break;
case 'j':
expectCertState = kSSLClientCertRejected;
break;
default:
usage(argv);
}
break;
case 'r':
allowAnyRoot = true;
break;
case 'd':
break;
case 'c':
displayCerts = true;
break;
case 'f':
fileBase = &argp[2];
break;
case 'C':
cipherRestrict = argp[2];
break;
case '2':
attemptProt = kSSLProtocol2;
break;
case '3':
attemptProt = kSSLProtocol3;
break;
case 't':
attemptProt = kTLSProtocol1;
break;
case 'o':
protXOnly = true;
break;
case 'g':
if(argp[1] != '=') {
usage(argv);
}
acceptedProts = &argp[2];
break;
case 'R':
resumableEnable = false;
break;
case 'b':
nonBlocking = true;
break;
case 'u':
if(argp[1] != '=') {
usage(argv);
}
switch(argp[2]) {
case 'a': authenticate = kAlwaysAuthenticate; break;
case 'n': authenticate = kNeverAuthenticate; break;
case 't': authenticate = kTryAuthenticate; break;
default: usage(argv);
}
break;
case 'D':
if(++arg == argc) {
/* requires another arg */
usage(argv);
}
break;
case 'z':
password = &argp[2];
break;
case 'H':
break;
case 'M':
completeCertChain = true;
break;
case 'i':
sessionCacheTimeout = atoi(&argp[2]);
break;
case '4':
disableAnonCiphers = true;
break;
case 'p':
pause = true;
break;
case 'q':
quiet = true;
break;
case 'l':
if(argp[1] == '\0') {
/* no loop count --> loop forever */
loops = 0;
break;
}
else if(argp[1] != '=') {
usage(argv);
}
loops = atoi(&argp[2]);
break;
default:
usage(argv);
}
}
#if NO_SERVER
# if DEBUG
securityd_init(NULL);
# endif
#endif
/* get server cert and optional encryption cert as CFArrayRef */
if(keyChainName) {
serverCerts = getSslCerts(keyChainName, false, completeCertChain,
anchorFile, &serverKc);
if(serverCerts == nil) {
exit(1);
}
} else if(protXOnly) {
switch(attemptProt) {
case kTLSProtocol1:
attemptProt = kTLSProtocol1Only;
break;
case kSSLProtocol3:
attemptProt = kSSLProtocol3Only;
break;
default:
break;
}
}
#pragma clang diagnostic pop
/* one-time only server port setup */
err = ListenForClients(portNum, nonBlocking, &listenSock);
if(err) {
printf("ListenForClients returned %d; aborting\n", (int)err);
exit(1);
}
for(loopNum=1; ; loopNum++) {
err = sslServe(listenSock,
portNum,
attemptProt,
acceptedProts,
serverCerts,
password,
allowExpired,
allowAnyRoot,
allowExpiredRoot,
disableCertVerify,
anchorFile,
replaceAnchors,
cipherRestrict,
authenticate,
dhParams,
dhParamsLen,
acceptableDNList,
resumableEnable,
sessionCacheTimeout,
disableAnonCiphers,
quiet,
pause,
&negVersion,
&negCipher,
&certState,
&sessionWasResumed,
sessionID,
&sessionIDLength,
&peerCerts,
argv);
if(err) {
errCount++;
}
if(!quiet) {
SSLProtocol tryProt = attemptProt;
showSSLResult(tryProt,
acceptedProts,
err,
negVersion,
negCipher,
sessionWasResumed,
sessionID,
sessionIDLength,
peerCerts,
displayCerts,
certState,
fileBase ? fullFileBase : NULL);
}
errCount += verifyClientCertState(vfyCertState, expectCertState,
certState);
freePeerCerts(peerCerts);
if(loops && (loopNum == loops)) {
break;
}
};
endpointShutdown(listenSock);
if(serverKc) {
CFRelease(serverKc);
}
return errCount;
}