Example #1
0
int main(int argc, char **argv)
{   
    OSStatus            err;
	int					arg;
	char				fullFileBase[100];
	SSLProtocol			negVersion;
	SSLCipherSuite		negCipher;
	CFArrayRef			peerCerts = NULL;		
	char				*argp;
	otSocket			listenSock;
	CFArrayRef			serverCerts = nil;		// required
	CFArrayRef			encryptCerts = nil;		// optional
	SecKeychainRef		serverKc = nil;
	SecKeychainRef		encryptKc = nil;
	
	/* user-spec'd parameters */
	char				*hostName = DEFAULT_HOST;	
	unsigned short		portNum = DEFAULT_PORT;
	CSSM_BOOL			allowExpired = CSSM_FALSE;
	CSSM_BOOL			allowAnyRoot = CSSM_FALSE;
	char				*fileBase = NULL;
	CSSM_BOOL			displayRxData = CSSM_FALSE;
	CSSM_BOOL			displayCerts = CSSM_FALSE;
	char				cipherRestrict = '\0';
	SSLProtocol			attemptProt = kTLSProtocol1;
	CSSM_BOOL			protXOnly = CSSM_FALSE;	// kSSLProtocol3Only, 
												//    kTLSProtocol1Only
	CSSM_BOOL			quiet = CSSM_FALSE;
	CSSM_BOOL			resumableEnable = CSSM_TRUE;
	CSSM_BOOL			pause = CSSM_FALSE;
	char				*keyChainName = NULL;
	char				*encryptKeyChainName = NULL;
	CSSM_BOOL			loop = CSSM_FALSE;
	SSLAuthenticate		authenticate = kNeverAuthenticate;
	
	for(arg=1; arg<argc; arg++) {
		argp = argv[arg];
		switch(argp[0]) {
			case 'H':
				hostName = &argp[2];
				break;
			case 'P':
				portNum = atoi(&argp[2]);
				break;
			case 'k':
				keyChainName = &argp[2];
				break;
			case 'E':
				encryptKeyChainName = &argp[2];
				break;
			case 'e':
				allowExpired = CSSM_TRUE;
				break;
			case 'r':
				allowAnyRoot = CSSM_TRUE;
				break;
			case 'd':
				displayRxData = CSSM_TRUE;
				break;
			case 'c':
				displayCerts = CSSM_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 = CSSM_TRUE;
				break;
			case 'R':
				resumableEnable = CSSM_FALSE;
				break;
			case 'a':
				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 'p':
				pause = CSSM_TRUE;
				break;
			case 'q':
				quiet = CSSM_TRUE;
				break;
			case 'l':
				loop = CSSM_TRUE;
				break;
			default:
				usage(argv);
		}
	}

	/* get server cert and optional encryption cert as CFArrayRef */
	serverCerts = getSslCerts(keyChainName, CSSM_FALSE, &serverKc);
	if(serverCerts == nil) {
		exit(1);
	}
	if(encryptKeyChainName) {
		encryptCerts = getSslCerts(encryptKeyChainName, CSSM_TRUE, &encryptKc);
		if(encryptCerts == nil) {
			exit(1);
		}
	}
	
	/* one-time only server port setup */
	err = ListenForClients(portNum, &listenSock);
	if(err) {
    	printf("ListenForClients returned %d; aborting\n", err);
		exit(1);
	}
	do {
		err = sslServe(listenSock,
			attemptProt,
			hostName,
			serverCerts,
			encryptCerts,
			allowExpired,
			allowAnyRoot,
			cipherRestrict,
			authenticate,
			resumableEnable,
			quiet,
			pause,
			&negVersion,
			&negCipher,
			&peerCerts);
		if(!quiet) {
			showSSLResult(attemptProt,
				err, 
				negVersion, 
				negCipher, 
				peerCerts,
				displayCerts,
				fileBase ? fullFileBase : NULL);
		}
		freePeerCerts(peerCerts);
			
	} while(loop);
	
	endpointShutdown(listenSock);
	parseCertShutdown();
	if(serverKc) {
		CFRelease(serverKc);
	}
	if(encryptKc) {
		CFRelease(encryptKc);
	}
    return 0;

}
Example #2
0
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;
}
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
	CFArrayRef			encryptCerts = nil;		// optional
	SecKeychainRef		serverKc = nil;
	SecKeychainRef		encryptKc = nil;
	int 				loopNum;
	int					errCount = 0;
	SSLClientCertificateState certState;		// obtained from sslServe

	/* 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;
	char				*encryptKeyChainName = 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;
	char				*dhParamsFile = NULL;
	unsigned char		*dhParams = NULL;
	unsigned			dhParamsLen = 0;
	bool			doIdSearch = false;
	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 'y':
				encryptKeyChainName = &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);
				}
				dhParamsFile = argv[arg];
				break;
			case 'z':
				password = &argp[2];
				break;
			case 'H':
				doIdSearch = true;
				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;
#if 0
			case 'U':
				if(++arg == argc)  {
					/* requires another arg */
					usage(argv);
				}
				if(cspReadFile(argv[arg], &caCert, &caCertLen)) {
					printf("***Error reading file %s. Aborting.\n", argv[arg]);
					exit(1);
				}
				if(acceptableDNList == NULL) {
					acceptableDNList = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
				}
				certData.Data = caCert;
				certData.Length = caCertLen;
				ortn = SecCertificateCreateFromData(&certData,
													CSSM_CERT_X_509v3,
													CSSM_CERT_ENCODING_DER,
													&secCert);
				if(ortn) {
					cssmPerror("SecCertificateCreateFromData", ortn);
					exit(1);
				}
				CFArrayAppendValue(acceptableDNList, secCert);
				CFRelease(secCert);
				break;
#endif
			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 0
    if(doIdSearch) {
		OSStatus ortn = sslIdentityPicker(NULL, anchorFile, true, NULL, &serverCerts);
		if(ortn) {
			printf("***IdentitySearch failure; aborting.\n");
			exit(1);
		}
	}
	if(password) {
		OSStatus ortn = SecKeychainUnlock(serverKc, strlen(password), password, true);
		if(ortn) {
			printf("SecKeychainUnlock returned %d\n", (int)ortn);
			/* oh well */
		}
	}
	if(encryptKeyChainName) {
		encryptCerts = getSslCerts(encryptKeyChainName, true, completeCertChain,
			anchorFile, &encryptKc);
		if(encryptCerts == nil) {
			exit(1);
		}
	}
#else
    (void) doIdSearch;
    (void) encryptKeyChainName;
#endif
	if(protXOnly) {
		switch(attemptProt) {
			case kTLSProtocol1:
				attemptProt = kTLSProtocol1Only;
				break;
			case kSSLProtocol3:
				attemptProt = kSSLProtocol3Only;
				break;
			default:
				break;
		}
	}
#if 0
	if(dhParamsFile) {
		int r = cspReadFile(dhParamsFile, &dhParams, &dhParamsLen);
		if(r) {
			printf("***Error reading diffie-hellman params from %s; aborting\n",
				dhParamsFile);
		}
	}
#else
    (void) dhParamsFile;
#endif

	/* 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,
			encryptCerts,
			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);
	}
	if(encryptKc) {
		CFRelease(encryptKc);
	}
    return errCount;

}
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;
}
Example #5
0
/*
 * params->lock is held for us by runSession() - we use it as a semapahore by
 * unlocking it when we've created a port to listen on. 
 * This is generally run from a thread via sslRunSession() and 
 * sslServerThread() in sslAppUtils.cpp. 
 */
OSStatus sslAppServe(
	SslAppTestParams	*params)
{
	otSocket			listenSock = 0;
	otSocket			acceptSock = 0;
    PeerSpec            peerId;
    OSStatus            ortn;
    SSLContextRef       ctx = NULL;
	SecKeychainRef		serverKc = nil;
	CFArrayRef			serverCerts = nil;
	
	sslThrDebug("Server", "starting");
    params->negVersion = kSSLProtocolUnknown;
    params->negCipher = SSL_NULL_WITH_NULL_NULL;
	params->ortn = noHardwareErr;
    
	/* set up a socket on which to listen */
	for(unsigned retry=0; retry<BIND_RETRIES; retry++) {
		ortn = ListenForClients(params->port, params->nonBlocking,
			&listenSock);
		switch(ortn) {
			case errSecSuccess:
				break;
			case errSecOpWr:
				/* port already in use - try another */
				params->port++;
				if(params->verbose || THREADING_DEBUG) {
					printf("...retrying ListenForClients at port %d\n",
						params->port);
				}
				break;
			default:
				break;
		}
		if(ortn != errSecOpWr) {
			break;
		}
	}
	
	/* let main thread know a socket is ready */
	if(pthread_mutex_lock(&params->pthreadMutex)) {
		printf("***Error acquiring server lock; aborting.\n");
		return -1;
	}
	params->serverReady = true;
	if(pthread_cond_broadcast(&params->pthreadCond)) {
		printf("***Error waking main thread; aborting.\n");
		return -1;
	}
	if(pthread_mutex_unlock(&params->pthreadMutex)) {
		printf("***Error acquiring server lock; aborting.\n");
		return -1;
	}

	if(ortn) {
		printf("ListenForClients returned %d; aborting\n", (int)ortn);
		return ortn;
	}

	/* wait for a connection */
	if(params->verbose) {
		printf("Waiting for client connection...");
		fflush(stdout);
	}
	ortn = AcceptClientConnection(listenSock, &acceptSock, &peerId);
    if(ortn) {
    	printf("AcceptClientConnection returned %d; aborting\n", (int)ortn);
    	return ortn;
    }

	/* 
	 * Set up a SecureTransport session.
	 */
	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)acceptSock);
	if(ortn) {
		printSslErrStr("SSLSetConnection", ortn);
		goto cleanup;
	}
	
	if(params->anchorFile) {
		ortn = sslAddTrustedRoot(ctx, params->anchorFile, 
			params->replaceAnchors);
		if(ortn) {
			goto cleanup;
		}
	}
	if(params->myCertKcName != NULL) {
		/* if not, better be trying anonymous diff-hellman... :-) */
		serverCerts = getSslCerts(params->myCertKcName, false, false, NULL,
			&serverKc);
		if(serverCerts == nil) {
			exit(1);
		}
		if(params->password) {
			ortn = SecKeychainUnlock(serverKc, strlen(params->password), 
					(void *)params->password, true);
			if(ortn) {
				printf("SecKeychainUnlock returned %d\n", (int)ortn);
				/* oh well */
			}
		}
		if(params->idIsTrustedRoot) {
			/* assume this is a root we want to implicitly trust */
			ortn = addIdentityAsTrustedRoot(ctx, serverCerts);
			if(ortn) {
				goto cleanup;
			}
		}
		ortn = SSLSetCertificate(ctx, serverCerts);
		if(ortn) {
			printSslErrStr("SSLSetCertificate", ortn);
			goto cleanup;
		}
	}
	
	if(params->disableCertVerify) {
		ortn = SSLSetEnableCertVerify(ctx, false);
		if(ortn) {
			printSslErrStr("SSLSetEnableCertVerify", ortn);
			goto cleanup;
		}
	}
	ortn = sslSetProtocols(ctx, params->acceptedProts, params->tryVersion);
	if(ortn) {
		goto cleanup;
	}
	if(params->resumeEnable) {
		ortn = SSLSetPeerID(ctx, &peerId, sizeof(PeerSpec));
		if(ortn) {
			printSslErrStr("SSLSetPeerID", ortn);
			goto cleanup;
		}
	}
	if(params->ciphers != NULL) {
		ortn = sslSetEnabledCiphers(ctx, params->ciphers);
		if(ortn) {
			goto cleanup;
		}
	}
	if(params->authenticate != kNeverAuthenticate) {
		ortn = SSLSetClientSideAuthenticate(ctx, params->authenticate);
		if(ortn) {
			printSslErrStr("SSLSetClientSideAuthenticate", ortn);
			goto cleanup;
		}
	}
	if(params->dhParams) {
		#if JAGUAR_BUILD
		printf("***Diffie-Hellman not supported in this config.\n");
		#else
		ortn = SSLSetDiffieHellmanParams(ctx, params->dhParams, 
			params->dhParamsLen);
		if(ortn) {
			printSslErrStr("SSLSetDiffieHellmanParams", ortn);
			goto cleanup;
		}
		#endif
	}

	/* Perform SSL/TLS handshake */
    do {   
		ortn = SSLHandshake(ctx);
	    if((ortn == errSSLWouldBlock) && !params->silent) {
	    	/* keep UI responsive */ 
	    	sslOutputDot();
	    }
    } while (ortn == errSSLWouldBlock);
	
	SSLGetClientCertificateState(ctx, &params->certState);
	SSLGetNegotiatedCipher(ctx, &params->negCipher);
	SSLGetNegotiatedProtocolVersion(ctx, &params->negVersion);
	
	if(params->verbose) {
		printf("\n");
	}
	if(ortn) {
		goto cleanup;
	}

	/* wait for one complete line */
	char readBuf[READBUF_LEN];
	size_t length;
	while(ortn == errSecSuccess) {
	    length = READBUF_LEN;
	    ortn = SSLRead(ctx, readBuf, length, &length);
	    if (ortn == errSSLWouldBlock) {
			/* keep trying */
	        ortn = errSecSuccess;
			continue;
	    }
	    if(length == 0) {
			/* keep trying */
			continue;
	    }
	    
	    /* poor person's line completion scan */
	    for(unsigned i=0; i<length; i++) {
	    	if((readBuf[i] == '\n') || (readBuf[i] == '\r')) {
	    		goto serverResp;
	    	}
	    }
	}
	
serverResp:
	/* send out canned response */
	ortn = SSLWrite(ctx, SERVER_MESSAGE, strlen(SERVER_MESSAGE), &length);
	if(ortn) {
		printSslErrStr("SSLWrite", ortn);
	}

cleanup:
	/*
	 * always do close, even on error - to flush outgoing write queue 
	 */
	if(ctx) {
		OSStatus cerr = SSLClose(ctx);
		if(ortn == errSecSuccess) {
			ortn = cerr;
		}
	}
	if(acceptSock) {
		while(!params->clientDone && !params->serverAbort) {
			usleep(100);
		}
		endpointShutdown(acceptSock);
	}
	if(listenSock) {
		endpointShutdown(listenSock);
	}
	if(ctx) {
	    SSLDisposeContext(ctx);  
	}    
	params->ortn = ortn;
	sslThrDebug("Server", "done");
	return ortn;
}
Example #6
0
/* relies on SSLSetProtocolVersionEnabled */
OSStatus sslAppClient(
	SslAppTestParams	*params)
{
    PeerSpec            peerId;
	otSocket			sock = 0;
    OSStatus            ortn;
    SSLContextRef       ctx = NULL;
	SecKeychainRef		clientKc = nil;
	CFArrayRef			clientCerts = nil;
	
	sslThrDebug("Client", "starting");
    params->negVersion = kSSLProtocolUnknown;
    params->negCipher  = SSL_NULL_WITH_NULL_NULL;
    params->ortn       = noHardwareErr;
	
	/* first make sure requested server is there */
	ortn = MakeServerConnection(params->hostName, params->port,
		params->nonBlocking, &sock, &peerId);
    if(ortn) {
    	printf("MakeServerConnection returned %d; aborting\n", (int)ortn);
    	return ortn;
    }
	
	/* 
	 * Set up a SecureTransport session.
	 */
	ortn = SSLNewContext(false, &ctx);
	if(ortn) {
		printSslErrStr("SSLNewContext", ortn);
		goto cleanup;
	} 
	ortn = SSLSetIOFuncs(ctx, SocketRead, SocketWrite);
	if(ortn) {
		printSslErrStr("SSLSetIOFuncs", ortn);
		goto cleanup;
	} 
	ortn = SSLSetConnection(ctx, (SSLConnectionRef)sock);
	if(ortn) {
		printSslErrStr("SSLSetConnection", ortn);
		goto cleanup;
	}
	if(!params->skipHostNameCheck) {
		ortn = SSLSetPeerDomainName(ctx, params->hostName, 
			strlen(params->hostName));
		if(ortn) {
			printSslErrStr("SSLSetPeerDomainName", ortn);
			goto cleanup;
		}
	}
	
	/* remainder of setup is optional */
	if(params->anchorFile) {
		ortn = sslAddTrustedRoot(ctx, params->anchorFile, params->replaceAnchors);
		if(ortn) {
			goto cleanup;
		}
	}
	ortn = sslSetProtocols(ctx, params->acceptedProts, params->tryVersion);
	if(ortn) {
		goto cleanup;
	}
	if(params->resumeEnable) {
		ortn = SSLSetPeerID(ctx, &peerId, sizeof(PeerSpec));
		if(ortn) {
			printSslErrStr("SSLSetPeerID", ortn);
			goto cleanup;
		}
	}
	if(params->disableCertVerify) {
		ortn = SSLSetEnableCertVerify(ctx, false);
		if(ortn) {
			printSslErrStr("SSLSetEnableCertVerify", ortn);
			goto cleanup;
		}
	}
	if(params->ciphers != NULL) {
		ortn = sslSetEnabledCiphers(ctx, params->ciphers);
		if(ortn) {
			goto cleanup;
		}
	}
	if(params->myCertKcName) {
		clientCerts = getSslCerts(params->myCertKcName, false, false, NULL, &clientKc);
		if(clientCerts == nil) {
			exit(1);
		}
		if(params->password) {
			ortn = SecKeychainUnlock(clientKc, strlen(params->password), 
					(void *)params->password, true);
			if(ortn) {
				printf("SecKeychainUnlock returned %d\n", (int)ortn);
				/* oh well */
			}
		}
		if(params->idIsTrustedRoot) {
			/* assume this is a root we want to implicitly trust */
			ortn = addIdentityAsTrustedRoot(ctx, clientCerts);
			if(ortn) {
				goto cleanup;
			}
		}
		ortn = SSLSetCertificate(ctx, clientCerts);
		if(ortn) {
			printSslErrStr("SSLSetCertificate", ortn);
			goto cleanup;
		}
	}
    do {
		ortn = SSLHandshake(ctx);
	    if((ortn == errSSLWouldBlock) && !params->silent) {
	    	/* keep UI responsive */ 
	    	sslOutputDot();
	    }
    } while (ortn == errSSLWouldBlock);
	
	SSLGetClientCertificateState(ctx, &params->certState);
	SSLGetNegotiatedCipher(ctx, &params->negCipher);
	SSLGetNegotiatedProtocolVersion(ctx, &params->negVersion);
	
	if(ortn != errSecSuccess) {
		goto cleanup;
	}

	/* send a GET msg */
	size_t actLen;
	ortn = SSLWrite(ctx, CLIENT_GETMSG, strlen(CLIENT_GETMSG), &actLen);
	if(ortn) {
		printSslErrStr("SSLWrite", ortn);
		goto cleanup;
	}
	
	#if KEEP_CONNECTED
	
	/*
	 * Consume any server data and wait for server to disconnect
	 */
	char readBuf[READBUF_LEN];
    do {
		ortn = SSLRead(ctx, readBuf, READBUF_LEN, &actLen);
    } while (ortn == errSSLWouldBlock);
	
    /* convert normal "shutdown" into zero err rtn */
	if(ortn == errSSLClosedGraceful) {
		ortn = errSecSuccess;
	}
	#endif	/* KEEP_CONNECTED */
	
cleanup:
	if(ctx) {
		OSStatus cerr = SSLClose(ctx);
		if(ortn == errSecSuccess) {
			ortn = cerr;
		}
	}
	if(sock) {
		endpointShutdown(sock);
	}
	if(ctx) {
	    SSLDisposeContext(ctx);  
	}    
	params->ortn = ortn;
	sslThrDebug("Client", "done");
	return ortn;
}