コード例 #1
0
OSStatus sslSetProtocols(
	SSLContextRef 	ctx,
	const char		*acceptedProts,
	SSLProtocol		tryVersion)			// only used if acceptedProts NULL
{
	OSStatus ortn;
	
	if(acceptedProts) {
		#if JAGUAR_BUILD
		printf("***SSLSetProtocolVersionEnabled not supported in this config.\n");
		exit(1);
		#endif
		ortn = SSLSetProtocolVersionEnabled(ctx, kSSLProtocolAll, false);
		if(ortn) {
			printSslErrStr("SSLSetProtocolVersionEnabled(all off)", ortn);
			return ortn;
		}
		for(const char *cp = acceptedProts; *cp; cp++) {
			SSLProtocol prot;
			switch(*cp) {
				case '2':
					prot = kSSLProtocol2;
					break;
				case '3':
					prot = kSSLProtocol3;
					break;
				case 't':
					prot = kTLSProtocol1;
					break;
				default:
					printf("***BRRZAP! Bad acceptedProts string %s. Aborting.\n", acceptedProts);
					exit(1);
			}
			ortn = SSLSetProtocolVersionEnabled(ctx, prot, true);
			if(ortn) {
				printSslErrStr("SSLSetProtocolVersionEnabled", ortn);
				return ortn;
			}
		}
	}
	else {
		ortn = SSLSetProtocolVersion(ctx, tryVersion);
		if(ortn) {
			printSslErrStr("SSLSetProtocolVersion", ortn);
			return ortn;
		} 
	}
	return errSecSuccess;
}
コード例 #2
0
ファイル: sslServer.cpp プロジェクト: fruitsamples/SSLSample
static OSStatus sslServe(
	otSocket				listenSock,
	SSLProtocol				tryVersion,
	const char				*hostName,			// e.g., "www.amazon.com"
	CFArrayRef				serverCerts,		// required
	CFArrayRef				encryptServerCerts,	// optional
	CSSM_BOOL				allowExpired,
	CSSM_BOOL				allowAnyRoot,
	char					cipherRestrict,		// '2', 'd'. etc...'\0' for no
												//   restriction
	SSLAuthenticate			authenticate,
	CSSM_BOOL				resumableEnable,
	CSSM_BOOL				silent,				// no stdout
	CSSM_BOOL				pause,
	SSLProtocol				*negVersion,		// RETURNED
	SSLCipherSuite			*negCipher,			// RETURNED
	CFArrayRef				*peerCerts)			// mallocd & RETURNED
{
	otSocket			acceptSock;
    PeerSpec            peerId;
    OSStatus            ortn;
    SSLContextRef       ctx = NULL;
    UInt32              length;
    uint8               rcvBuf[RCV_BUF_SIZE];
	char *outMsg = SERVER_MESSAGE;
	
    *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...");
		fflush(stdout);
	}
	ortn = AcceptClientConnection(listenSock, &acceptSock, &peerId);
    if(ortn) {
    	printf("AcceptClientConnection returned %d; aborting\n", 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 = SSLSetProtocolVersion(ctx, tryVersion);
	if(ortn) {
		printSslErrStr("SSLSetProtocolVersion", ortn);
		goto cleanup;
	} 
	ortn = SSLSetConnection(ctx, acceptSock);
	if(ortn) {
		printSslErrStr("SSLSetConnection", ortn);
		goto cleanup;
	}
	ortn = SSLSetPeerDomainName(ctx, hostName, strlen(hostName) + 1);
	if(ortn) {
		printSslErrStr("SSLSetPeerDomainName", 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;
		}
	}

	ortn = SSLSetCertificate(ctx, serverCerts);
	if(ortn) {
		printSslErrStr("SSLSetCertificate", ortn);
		goto cleanup;
	}
	if(encryptServerCerts) {
		ortn = SSLSetEncryptionCertificate(ctx, encryptServerCerts);
		if(ortn) {
			printSslErrStr("SSLSetEncryptionCertificate", ortn);
			goto cleanup;
		}
	}
	
	/* 
	 * SecureTransport options.
	 */ 
	if(resumableEnable) {
		ortn = SSLSetPeerID(ctx, &peerId, sizeof(PeerSpec));
		if(ortn) {
			printSslErrStr("SSLSetPeerID", ortn);
			goto cleanup;
		}
	}
	if(cipherRestrict != '\0') {
		ortn = setCipherRestrictions(ctx, cipherRestrict);
		if(ortn) {
			goto cleanup;
		}
	}
	#if AUTHENTICATE_ENABLE
	if(authenticate != kNeverAuthenticate) {
		ortn = SSLSetClientSideAuthenticate(ctx, authenticate);
		if(ortn) {
			printSslErrStr("SSLSetClientSideAuthenticate", ortn);
			goto cleanup;
		}
	}
	#endif
	if(pause) {
		doPause("SSLContext initialized");
	}
	
	/* Perform SSL/TLS handshake */
    do
    {   ortn = SSLHandshake(ctx);
	    if((ortn == errSSLWouldBlock) && !silent) {
	    	/* keep UI responsive */ 
	    	outputDot();
	    }
    } while (ortn == errSSLWouldBlock);
	
	/* this works even if handshake failed due to cert chain invalid */
	copyPeerCerts(ctx, peerCerts);

	SSLGetNegotiatedCipher(ctx, negCipher);
	SSLGetNegotiatedProtocolVersion(ctx, negVersion);
	
	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 == noErr) {
	    length = sizeof(rcvBuf);
	    ortn = SSLRead(ctx, rcvBuf, length, &length);
	    if(length == 0) {
	    	/* keep UI responsive */ 
	    	outputDot();
	    }
	    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 = noErr;
	    }
	}
	
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");
	}
    if (ortn == noErr) {
        ortn = SSLClose(ctx);
	}
cleanup:
	if(acceptSock) {
		endpointShutdown(acceptSock);
	}
	if(ctx) {
	    SSLDisposeContext(ctx);  
	}    
	/* FIXME - dispose of serverCerts */
	return ortn;
}
コード例 #3
0
static OSStatus sslServe(
	otSocket				listenSock,
	unsigned short			portNum,
	SSLProtocol				tryVersion,			// only used if acceptedProts NULL
	const char				*acceptedProts,
	CFArrayRef				serverCerts,		// required
	char					*password,			// optional
	CFArrayRef				encryptServerCerts,	// 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;
	
    *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(encryptServerCerts) {
		ortn = SSLSetEncryptionCertificate(ctx, encryptServerCerts);
		if(ortn) {
			printSslErrStr("SSLSetEncryptionCertificate", 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;
	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);  
	}    
	/* FIXME - dispose of serverCerts */
	return ortn;
}
コード例 #4
0
int main(int argc, char **argv)
{
	/* user-spec'd variables */
	const char 		*kcName = DEFAULT_KC;
	unsigned 		xferSize = XFERSIZE_DEF;
	int 			port = PORT_DEF;
	const char 		*hostName = HOST_DEF;
	SSLCipherSuite 	cipherSuite = TLS_RSA_WITH_AES_128_CBC_SHA;
	SSLProtocol 	prot = kTLSProtocol1Only;
	char 			password[200];
	bool 			clientAuthEnable = false;
	bool 			isServer = false;
	unsigned 		bufSize = BUFSIZE;
	bool			diffieHellman = false;
	int				nonBlocking = 0;
	
	if(argc < 2) {
		usage(argv);
	}
	password[0] = 0;
	switch(argv[1][0]) {
		case 's':
			isServer = true;
			break;
		case 'c':
			isServer = false;
			break;
		default:
			usage(argv);
	}
	
	extern int optind;
	extern char *optarg;
	int arg;
	optind = 2;
	while ((arg = getopt(argc, argv, "h:p:k:x:c:v:w:b:aB")) != -1) {
		switch (arg) {
			case 'h':
				hostName = optarg;
				break;
			case 'p':
				port = atoi(optarg);
				break;
			case 'k':
				kcName = optarg;
				break;
			case 'x':
				xferSize = atoi(optarg);
				break;
			case 'c':
				if(!isServer) {
					printf("***Specify cipherSuite on server side.\n");
					exit(1);
				}
				switch(optarg[0]) {
					case 'r':
						cipherSuite = SSL_RSA_WITH_RC4_128_SHA;
						break;
					case 'd':
						cipherSuite = SSL_RSA_WITH_DES_CBC_SHA;
						break;
					case 'D':
						cipherSuite = SSL_RSA_WITH_3DES_EDE_CBC_SHA;
						break;
					case 'h':
						cipherSuite = SSL_DH_anon_WITH_RC4_128_MD5;
						diffieHellman = true;
						break;
					case 'H':
						cipherSuite = SSL_DHE_DSS_WITH_DES_CBC_SHA;
						diffieHellman = true;
						break;
					case 'A':
						cipherSuite = TLS_RSA_WITH_AES_256_CBC_SHA;
						break;
					default:
						usage(argv);
				}
				break;
			case 'v':
				if(!isServer) {
					printf("***Specify protocol on server side.\n");
					exit(1);
				}
				switch(optarg[0]) {
					case 't':
						prot = kTLSProtocol1Only;
						break;
					case '2':
						prot = kSSLProtocol2;
						break;
					case '3':
						prot = kSSLProtocol3Only;
						break;
					default:
						usage(argv);
				}
				break;
			case 'w':
				strcpy(password, optarg);
				break;
			case 'b':
				bufSize = atoi(optarg);
				break;
			case 'a':
				clientAuthEnable = true;
				break;
			case 'B':
				nonBlocking = 1;
				break;
			default:
				usage(argv);
		}
	}
	
	/* per-transfer buffer - make it random for server */
	char *buf = (char *)malloc(bufSize);
	if(isServer) {
		Security::DevRandomGenerator rng;
		rng.random(buf, bufSize);
	}
	
	/* gather Diffie-Hellman params from cwd */
	unsigned char *dhParams = NULL;
	unsigned dhParamsLen = 0;
	if(diffieHellman && isServer) {
		if(readFile(DH_PARAM_FILE, &dhParams, &dhParamsLen)) {
			printf("***Error reading Diffie-Hellman Params. Prepare to "
				"wait for a minute during SSL handshake.\n");
		}
	}
	
	/*
	 * Open keychain; both sides use the same one.
	 */
	OSStatus ortn;
	SecKeychainRef certKc = NULL;
	CFAbsoluteTime kcOpenStart = CFAbsoluteTimeGetCurrent();
	ortn = SecKeychainOpen(kcName, &certKc);
	if(ortn) {
		printf("Error opening keychain %s (%d); aborting.\n",
			kcName, (int)ortn);
		exit(1);
	}
	if(password[0]) {
		ortn = SecKeychainUnlock(certKc, strlen(password), password, true);
		if(ortn) {
			printf("SecKeychainUnlock returned %d\n", (int)ortn);
			/* oh well */
		}
	}
	CFAbsoluteTime kcOpenEnd = CFAbsoluteTimeGetCurrent();
	
	otSocket peerSock = 0;
	otSocket listenSock = 0;			// for server only
    PeerSpec peerId;
	
	if(isServer) {
		printf("...listening for client connection on port %d\n", port);
		ortn = ListenForClients(port, nonBlocking, &listenSock);
		if(ortn) {
			printf("...error establishing a listen socket. Aborting.\n");
			exit(1);
		}
		ortn = AcceptClientConnection(listenSock, &peerSock, &peerId);
		if(ortn) {
			printf("...error listening for connection. Aborting.\n");
			exit(1);
		}
	}
	else {
		printf("...connecting to host %s at port %d\n", hostName, port);
		ortn = MakeServerConnection(hostName, port, nonBlocking, &peerSock,
			&peerId);
		if(ortn) {
			printf("...error connecting to server %s. Aborting.\n",
				hostName);
			exit(1);
		}
	}

	/* start timing SSL setup */
	CFAbsoluteTime setupStart = CFAbsoluteTimeGetCurrent();

	SSLContextRef ctx;
	ortn = SSLNewContext(isServer, &ctx);
	if(ortn) {
		printSslErrStr("SSLNewContext", ortn);
		exit(1);
	} 
	ortn = SSLSetIOFuncs(ctx, SocketRead, SocketWrite);
	if(ortn) {
		printSslErrStr("SSLSetIOFuncs", ortn);
		exit(1);
	} 
	ortn = SSLSetConnection(ctx, (SSLConnectionRef)peerSock);
	if(ortn) {
		printSslErrStr("SSLSetConnection", ortn);
		exit(1);
	}
	ortn = SSLSetPeerDomainName(ctx, hostName, strlen(hostName) + 1);
	if(ortn) {
		printSslErrStr("SSLSetPeerDomainName", ortn);
		exit(1);
	}	
	
	/*
	 * Server/client specific setup.
	 *
	 * Client uses the same keychain as server, but it uses it for 
	 * sslAddTrustedRoots() instead of getSslCerts() and 
	 * SSLSetCertificate().
	 */
	CFArrayRef myCerts = NULL;
	if(clientAuthEnable || isServer) {
		myCerts = sslKcRefToCertArray(certKc, CSSM_FALSE, CSSM_FALSE, NULL, NULL);
		if(myCerts == NULL) {
			exit(1);
		}
		ortn = addIdentityAsTrustedRoot(ctx, myCerts);
		if(ortn) {
			exit(1);
		}
		ortn = SSLSetCertificate(ctx, myCerts);
		if(ortn) {
			printSslErrStr("SSLSetCertificate", ortn);
			exit(1);
		}
	}
	if(isServer) {
		SSLAuthenticate auth;
		if(clientAuthEnable) {
			auth = kAlwaysAuthenticate;
		}
		else {
			auth = kNeverAuthenticate;
		}
		ortn = SSLSetClientSideAuthenticate(ctx, auth);
		if(ortn) {
			printSslErrStr("SSLSetClientSideAuthenticate", ortn);
			exit(1);
		}
		ortn = SSLSetEnabledCiphers(ctx, &cipherSuite, 1);
		if(ortn) {
			printSslErrStr("SSLSetEnabledCiphers", ortn);
			exit(1);
		}
		ortn = SSLSetProtocolVersion(ctx, prot);
		if(ortn) {
			printSslErrStr("SSLSetProtocolVersion", ortn);
			exit(1);
		}
		if(dhParams != NULL) {
			ortn = SSLSetDiffieHellmanParams(ctx, dhParams, dhParamsLen);
			if(ortn) {
				printSslErrStr("SSLSetDiffieHellmanParams", ortn);
				exit(1);
			}
		}
	}
	else {
		/* client setup */
		if(!clientAuthEnable) {
			/* We're not presenting a cert; trust the server certs */
			bool foundOne;
			ortn = sslAddTrustedRoots(ctx, certKc, &foundOne);
			if(ortn) {
				printSslErrStr("sslAddTrustedRoots", ortn);
				exit(1);
			}
		}
	}
	
	/*
	 * Context setup complete. Start timing handshake.
	 */
	CFAbsoluteTime hshakeStart = CFAbsoluteTimeGetCurrent();
    do {   
		ortn = SSLHandshake(ctx);
    } while (ortn == errSSLWouldBlock);
	if(ortn) {
		printSslErrStr("SSLHandshake", ortn);
		exit(1);
	}
	CFAbsoluteTime hshakeEnd = CFAbsoluteTimeGetCurrent();
	
	/* snag these before data xfer possibly shuts down connection */
	SSLProtocol	negVersion;
	SSLCipherSuite negCipher;
	SSLClientCertificateState certState;		// RETURNED

	SSLGetNegotiatedCipher(ctx, &negCipher);
	SSLGetNegotiatedProtocolVersion(ctx, &negVersion);
	SSLGetClientCertificateState(ctx, &certState);
	
	/* server sends xferSize bytes to client and shuts down */
	size_t bytesMoved;
	
	CFAbsoluteTime dataStart = CFAbsoluteTimeGetCurrent();
	size_t totalMoved = 0;
	if(isServer) {
		size_t bytesToGo = xferSize;
		bool done = false;
		do {
			size_t thisMove = bufSize;
			if(thisMove > bytesToGo) {
				thisMove = bytesToGo;
			}
			ortn = SSLWrite(ctx, buf, thisMove, &bytesMoved);
			switch(ortn) {
				case noErr:
				case errSSLWouldBlock:
					break;
				default:
					done = true;
					break;
			}
			bytesToGo -= bytesMoved;
			totalMoved += bytesMoved;
			if(bytesToGo == 0) {
				done = true;
			}
		} while(!done);
		if(ortn != noErr) {
			printSslErrStr("SSLWrite", ortn);
			exit(1);
		}
	}
	else {
		/* client reads until error or errSSLClosedGraceful */
		bool done = false;
		do {
			ortn = SSLRead(ctx, buf, bufSize, &bytesMoved);
			switch(ortn) {
				case errSSLClosedGraceful:
					done = true;
					break;
				case noErr:
				case errSSLWouldBlock:
					break;
				default:
					done = true;
					break;
			}
			totalMoved += bytesMoved;
		} while(!done);
		if(ortn != errSSLClosedGraceful) {
			printSslErrStr("SSLRead", ortn);
			exit(1);
		}
	}
	
	/* shut down channel */
	ortn = SSLClose(ctx);
	if(ortn) {
		printSslErrStr("SSLCLose", ortn);
		exit(1);
	}
	CFAbsoluteTime dataEnd = CFAbsoluteTimeGetCurrent();

	/* how'd we do? */
	printf("SSL version          : %s\n", 
		sslGetProtocolVersionString(negVersion));
	printf("CipherSuite          : %s\n",
		sslGetCipherSuiteString(negCipher));
	printf("Client Cert State    : %s\n",
			sslGetClientCertStateString(certState));

	if(password[0]) {
		printf("keychain open/unlock : ");
	}
	else {
		printf("keychain open        : ");
	}
	printf("%f s\n", kcOpenEnd - kcOpenStart);
	printf("SSLContext setup     : %f s\n", hshakeStart - setupStart);
	printf("SSL Handshake        : %f s\n", hshakeEnd - hshakeStart);
	printf("Data Transfer        : %u bytes in %f s\n", (unsigned)totalMoved, 
		dataEnd - dataStart);
	printf("                     : %.1f Kbytes/s\n", 
			totalMoved / (dataEnd - dataStart) / 1024.0);
	return 0;
}