sslAlert.cpp   [plain text]


/*
 * sslAlert.cpp - test alert msg sending and processing, client and server side
 */
#include <Security/SecureTransport.h>
#include <Security/Security.h>
#include <clAppUtils/sslAppUtils.h>
#include <clAppUtils/ioSock.h>
#include <clAppUtils/sslThreading.h>
#include <utilLib/common.h>
#include <security_cdsa_utils/cuPrintCert.h>
#include <security_utilities/threading.h>
#include <security_utilities/devrandom.h>

#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
#include <sys/param.h>

#define STARTING_PORT			2000

/* 
 * localcert is a KC containing server cert and signing key
 * assumptions: 
 *	-- common name = "localcert"
 *  -- password of KC = "localcert"
 */
#define SERVER_KC		"localcert"
#define SERVER_ROOT		"localcert.cer"
/*
 * clientcert is a KC containing client cert and signing key
 * assumptions: 
 *  -- password of KC = "clientcert"
 *  -- note common name not checked by SecureTransport when verifying client cert chain
 */
#define CLIENT_KC		"clientcert"
#define CLIENT_ROOT		"clientcert.cer"

/* main() fills these in using sslKeychainPath() */
static char serverKcPath[MAXPATHLEN];
static char clientKcPath[MAXPATHLEN];

static void usage(char **argv)
{
	printf("Usage: %s [options]\n", argv[0]);
	printf("options:\n");
	printf("   q(uiet)\n");
	printf("   v(erbose)\n");
	printf("   p=startingPortNum\n");
	printf("   b (non blocking I/O)\n");
	printf("   s=serverCertName; default %s\n", SERVER_ROOT);
	printf("   c=clientCertName; default %s\n", CLIENT_ROOT);
	printf("   R (ringBuffer I/O)\n");
	printf("   l=loops (default=1; 0=forever)\n");
	exit(1);
}

#define IGNORE_SIGPIPE	1
#if 	IGNORE_SIGPIPE
#include <signal.h>

void sigpipe(int sig) 
{ 
}
#endif	/* IGNORE_SIGPIPE */

/*
 * Default params for each test. Main() will make a copy of this and 
 * adjust its copy on a per-test basis.
 */
SslAppTestParams serverDefaults = 
{
	"no name here",
	false,				// skipHostNameCHeck
	0,					// port - test must set this	
	NULL, NULL,			// RingBuffers
	false,				// noProtSpec
	kTLSProtocol1,
	NULL,				// acceptedProts
	serverKcPath,		// myCerts
	SERVER_KC,			// password
	true,				// idIsTrustedRoot
	false,				// disableCertVerify
	NULL,				// anchorFile
	false,				// replaceAnchors
	kNeverAuthenticate,
	false,				// resumeEnable
	NULL,				// ciphers
	false,				// nonBlocking
	NULL,				// dhParams
	0,					// dhParamsLen
	noErr,				// expectRtn
	kTLSProtocol1,		// expectVersion
	kSSLClientCertNone,
	SSL_CIPHER_IGNORE,
	false,				// quiet
	false,				// silent
	false,				// verbose
	{0},				// lock
	{0},				// cond
	false,				// serverReady
	0,					// clientDone
	false,				// serverAbort
	/* returned */
	kSSLProtocolUnknown,
	SSL_NULL_WITH_NULL_NULL,
	kSSLClientCertNone,
	noHardwareErr
	
};

SslAppTestParams clientDefaults = 
{
	"localhost",
	false,				// skipHostNameCHeck
	0,					// port - test must set this
	NULL, NULL,			// RingBuffers
	false,				// noProtSpec
	kTLSProtocol1,
	NULL,				// acceptedProts
	NULL,				// myCertKcName
	CLIENT_KC,			// password - only meaningful when test sets myCertKcName
	true,				// idIsTrustedRoot
	false,				// disableCertVerify
	SERVER_ROOT,		// anchorFile
	false,				// replaceAnchors
	kNeverAuthenticate,
	false,				// resumeEnable
	NULL,				// ciphers
	false,				// nonBlocking
	NULL,				// dhParams
	0,					// dhParamsLen
	noErr,				// expectRtn
	kTLSProtocol1,		// expectVersion
	kSSLClientCertNone,
	SSL_CIPHER_IGNORE,
	false,				// quiet
	false,				// silent
	false,				// verbose
	{0},				// lock
	{0},				// cond
	false,				// serverReady
	0,					// clientDone
	false,				// serverAbort
	/* returned */
	kSSLProtocolUnknown,
	SSL_NULL_WITH_NULL_NULL,
	kSSLClientCertNone,
	noHardwareErr
};


int main(int argc, char **argv)
{
	int 				ourRtn = 0;
	char	 			*argp;
	int 				thisRtn;
	SslAppTestParams 	clientParams;
	SslAppTestParams 	serverParams;
	const char			*desc;
	unsigned short		portNum = STARTING_PORT;
	const char			*clientCert = CLIENT_ROOT;
	RingBuffer			serverToClientRing;
	RingBuffer			clientToServerRing;
	bool				ringBufferIo = false;
	unsigned 			loopNum = 0;
	unsigned 			loops = 1;

	for(int arg=1; arg<argc; arg++) {
		argp = argv[arg];
		switch(argp[0]) {
			case 'q':
				serverDefaults.quiet = clientDefaults.quiet = true;
				break;
			case 'v':
				serverDefaults.verbose = clientDefaults.verbose = true;
				break;
			case 'b':
				serverDefaults.nonBlocking = clientDefaults.nonBlocking = 
						true;
				break;
			case 'p':
				portNum = atoi(&argp[2]);
				break;
			case 's':
				clientDefaults.anchorFile = &argp[2];
				break;
			case 'c':
				clientCert = &argp[2];
				break;
			case 'R':
				ringBufferIo = true;
				break;
			case 'l':
				loops = atoi(&argp[2]);
				break;
			default:
				usage(argv);
		}
	}
	
	#if IGNORE_SIGPIPE
	signal(SIGPIPE, sigpipe);
	#endif
	
	if(sslCheckFile(clientDefaults.anchorFile)) {
		exit(1);
	}
	if(sslCheckFile(clientCert)) {
		exit(1);
	}

	if(ringBufferIo) {
		/* set up ring buffers */
		ringBufSetup(&serverToClientRing, "serveToClient", DEFAULT_NUM_RB_BUFS, DEFAULT_BUF_RB_SIZE);
		ringBufSetup(&clientToServerRing, "clientToServe", DEFAULT_NUM_RB_BUFS, DEFAULT_BUF_RB_SIZE);
		serverDefaults.serverToClientRing = &serverToClientRing;
		serverDefaults.clientToServerRing = &clientToServerRing;
		clientDefaults.serverToClientRing = &serverToClientRing;
		clientDefaults.clientToServerRing = &clientToServerRing;
	}

	/* convert keychain names to paths for root */
	sslKeychainPath(SERVER_KC, serverKcPath);
	sslKeychainPath(CLIENT_KC, clientKcPath);
	
	testStartBanner("sslAlert", argc, argv);
	// printf("sslAlert: server KC: %s\n", serverKcPath);
	// printf("sslAlert: client KC: %s\n", clientKcPath);
	
	/*
	 * We could get real fancy and have a bunch of elaborate tables describing
	 * what's supposed to happen in each test case, but I really don't think
	 * it's worth it. 
	 */
	for(;;) {
		desc = "basic TLS1, nothing fancy";
		clientParams = clientDefaults; serverParams = serverDefaults;
		serverParams.port = portNum;
		SSL_THR_RUN(serverParams, clientParams, desc, ourRtn);

		desc = "client doesn't recognize server root";
		if(ringBufferIo) {
			ringBufferReset(&serverToClientRing);
			ringBufferReset(&clientToServerRing);
		}
		SSL_THR_SETUP(serverParams, clientParams, clientDefaults, serverDefault);
		clientParams.anchorFile = NULL;
		clientParams.expectRtn = errSSLUnknownRootCert;
		serverParams.expectRtn = errSSLPeerUnknownCA;
		SSL_THR_RUN(serverParams, clientParams, desc, ourRtn);

		desc = "negotiate down to SSL3, server limited";
		if(ringBufferIo) {
			ringBufferReset(&serverToClientRing);
			ringBufferReset(&clientToServerRing);
		}
		SSL_THR_SETUP(serverParams, clientParams, clientDefaults, serverDefault);
		serverParams.tryVersion = kSSLProtocol3;
		serverParams.expectVersion = kSSLProtocol3;
		clientParams.expectVersion = kSSLProtocol3;
		SSL_THR_RUN(serverParams, clientParams, desc, ourRtn);

		desc = "negotiate down to SSL3, client limited";
		if(ringBufferIo) {
			ringBufferReset(&serverToClientRing);
			ringBufferReset(&clientToServerRing);
		}
		SSL_THR_SETUP(serverParams, clientParams, clientDefaults, serverDefault);
		clientParams.tryVersion = kSSLProtocol3;
		clientParams.expectVersion = kSSLProtocol3;
		serverParams.expectVersion = kSSLProtocol3;
		SSL_THR_RUN(serverParams, clientParams, desc, ourRtn);

		desc = "successful client authentication";
		if(ringBufferIo) {
			ringBufferReset(&serverToClientRing);
			ringBufferReset(&clientToServerRing);
		}
		SSL_THR_SETUP(serverParams, clientParams, clientDefaults, serverDefault);
		clientParams.myCertKcName = clientKcPath;
		serverParams.anchorFile = clientCert;
		serverParams.authenticate = kAlwaysAuthenticate;
		clientParams.expectCertState = kSSLClientCertSent; 
		serverParams.expectCertState = kSSLClientCertSent; 
		SSL_THR_RUN(serverParams, clientParams, desc, ourRtn);

		desc = "client authentication, server doesn't recognize root TLS1";
		if(ringBufferIo) {
			ringBufferReset(&serverToClientRing);
			ringBufferReset(&clientToServerRing);
		}
		SSL_THR_SETUP(serverParams, clientParams, clientDefaults, serverDefault);
		clientParams.myCertKcName = clientKcPath;
		/* no anchor file for server; unrecognized */
		serverParams.authenticate = kAlwaysAuthenticate;
		clientParams.expectCertState = kSSLClientCertRejected; 
		serverParams.expectCertState = kSSLClientCertRejected; 
		serverParams.expectRtn = errSSLUnknownRootCert;
		clientParams.expectRtn = errSSLPeerUnknownCA;
		SSL_THR_RUN(serverParams, clientParams, desc, ourRtn);

		desc = "client authentication, server doesn't recognize root SSL3";
		if(ringBufferIo) {
			ringBufferReset(&serverToClientRing);
			ringBufferReset(&clientToServerRing);
		}
		SSL_THR_SETUP(serverParams, clientParams, clientDefaults, serverDefault);
		clientParams.tryVersion = kSSLProtocol3;
		clientParams.expectVersion = kSSLProtocol3;
		serverParams.expectVersion = kSSLProtocol3;
		clientParams.myCertKcName = clientKcPath;
		/* no anchor file for server; unrecognized */
		serverParams.authenticate = kAlwaysAuthenticate;
		clientParams.expectCertState = kSSLClientCertRejected; 
		serverParams.expectCertState = kSSLClientCertRejected; 
		serverParams.expectRtn = errSSLUnknownRootCert;
		clientParams.expectRtn = errSSLPeerUnsupportedCert;
		thisRtn = sslRunSession(&serverParams, &clientParams, desc);
		if(thisRtn) {
			if(testError(clientParams.quiet)) {
				goto done;
			}
		}

		desc = "server requires authentication, no client cert, TLS1";
		if(ringBufferIo) {
			ringBufferReset(&serverToClientRing);
			ringBufferReset(&clientToServerRing);
		}
		SSL_THR_SETUP(serverParams, clientParams, clientDefaults, serverDefault);
		serverParams.authenticate = kAlwaysAuthenticate;
		clientParams.expectCertState = kSSLClientCertRequested; 
		serverParams.expectCertState = kSSLClientCertRequested; 
		serverParams.expectRtn = errSSLXCertChainInvalid;
		clientParams.expectRtn = errSSLPeerCertUnknown;
		SSL_THR_RUN(serverParams, clientParams, desc, ourRtn);

		desc = "server requires authentication, no client cert, SSL3";
		if(ringBufferIo) {
			ringBufferReset(&serverToClientRing);
			ringBufferReset(&clientToServerRing);
		}
		SSL_THR_SETUP(serverParams, clientParams, clientDefaults, serverDefault);
		clientParams.tryVersion      = kSSLProtocol3;
		clientParams.expectVersion   = kSSLProtocol3;
		serverParams.expectVersion   = kSSLProtocol3;
		serverParams.authenticate    = kAlwaysAuthenticate;
		clientParams.expectCertState = kSSLClientCertRequested; 
		serverParams.expectCertState = kSSLClientCertRequested; 
		serverParams.expectRtn = errSSLProtocol;
		clientParams.expectRtn = errSSLPeerUnexpectedMsg;
		SSL_THR_RUN(serverParams, clientParams, desc, ourRtn);

		desc = "server (only) requests authentication, no client cert, TLS1";
		if(ringBufferIo) {
			ringBufferReset(&serverToClientRing);
			ringBufferReset(&clientToServerRing);
		}
		SSL_THR_SETUP(serverParams, clientParams, clientDefaults, serverDefault);
		serverParams.authenticate = kTryAuthenticate;
		clientParams.expectCertState = kSSLClientCertRequested; 
		serverParams.expectCertState = kSSLClientCertRequested; 
		SSL_THR_RUN(serverParams, clientParams, desc, ourRtn);

		desc = "server (only) requests authentication, no client cert, SSL3";
		if(ringBufferIo) {
			ringBufferReset(&serverToClientRing);
			ringBufferReset(&clientToServerRing);
		}
		SSL_THR_SETUP(serverParams, clientParams, clientDefaults, serverDefault);
		clientParams.tryVersion      = kSSLProtocol3;
		clientParams.expectVersion   = kSSLProtocol3;
		serverParams.expectVersion   = kSSLProtocol3;
		serverParams.authenticate    = kTryAuthenticate;
		clientParams.expectCertState = kSSLClientCertRequested; 
		serverParams.expectCertState = kSSLClientCertRequested; 
		SSL_THR_RUN(serverParams, clientParams, desc, ourRtn);

		desc = "server (only) requests authentication, client cert w/unknown root, TLS1";
		if(ringBufferIo) {
			ringBufferReset(&serverToClientRing);
			ringBufferReset(&clientToServerRing);
		}
		SSL_THR_SETUP(serverParams, clientParams, clientDefaults, serverDefault);
		serverParams.authenticate = kTryAuthenticate;
		clientParams.expectCertState = kSSLClientCertRejected; 
		serverParams.expectCertState = kSSLClientCertRejected; 
		clientParams.myCertKcName = clientKcPath;
		/* no anchor file for server; unrecognized */
		serverParams.expectRtn = errSSLUnknownRootCert;
		clientParams.expectRtn = errSSLPeerUnknownCA;
		SSL_THR_RUN(serverParams, clientParams, desc, ourRtn);

		desc = "server (only) requests authentication, client cert w/unknown root, SSL3";
		if(ringBufferIo) {
			ringBufferReset(&serverToClientRing);
			ringBufferReset(&clientToServerRing);
		}
		SSL_THR_SETUP(serverParams, clientParams, clientDefaults, serverDefault);
		clientParams.tryVersion      = kSSLProtocol3;
		clientParams.expectVersion   = kSSLProtocol3;
		serverParams.expectVersion   = kSSLProtocol3;
		serverParams.authenticate    = kTryAuthenticate;
		clientParams.expectCertState = kSSLClientCertRejected; 
		serverParams.expectCertState = kSSLClientCertRejected; 
		clientParams.myCertKcName = clientKcPath;
		/* no anchor file for server; unrecognized */
		serverParams.expectRtn = errSSLUnknownRootCert;
		clientParams.expectRtn = errSSLPeerUnsupportedCert;
		SSL_THR_RUN(serverParams, clientParams, desc, ourRtn);
		if(ringBufferIo) {
			ringBufferReset(&serverToClientRing);
			ringBufferReset(&clientToServerRing);
		}
		
		if(loops) {
			if(++loopNum == loops) {
				break;
			}
			printf("...loop %u\n", loopNum);
		}
	}

done:
	if(!clientParams.quiet) {
		if(ourRtn == 0) {
			printf("===== sslAlert test PASSED =====\n");
		}
		else {
			printf("****FAIL: %d errors detected\n", ourRtn);
		}
	}
	
	return ourRtn;
}