Example #1
0
/*
 * R/W. Called out from SSL.
 */
OSStatus SocketRead(
	SSLConnectionRef 	connection,
	void 				*data, 			/* owned by 
	 									 * caller, data
	 									 * RETURNED */
	size_t 				*dataLength)	/* IN/OUT */ 
{
	UInt32			bytesToGo = *dataLength;
	UInt32 			initLen = bytesToGo;
	UInt8			*currData = (UInt8 *)data;
	int				sock = (int)((long)connection);
	OSStatus		rtn = noErr;
	UInt32			bytesRead;
	ssize_t			rrtn;
	
	*dataLength = 0;

	for(;;) {
		bytesRead = 0;
		/* paranoid check, ensure errno is getting written */
		errno = -555;
		rrtn = recv(sock, currData, bytesToGo, 0);
		if (rrtn <= 0) {
			if(rrtn == 0) {
				/* closed, EOF */
				rtn = errSSLClosedGraceful;
				break;
			}
			int theErr = errno;
			switch(theErr) {
				case ENOENT:
					/* 
					 * Undocumented but I definitely see this.
					 * Non-blocking sockets only. Definitely retriable
					 * just like an EAGAIN.
					 */
					dprintf(("SocketRead RETRYING on ENOENT, rrtn %d\n",
						(int)rrtn));
					/* normal... */
					//rtn = errSSLWouldBlock;
					/* ...for temp testing.... */
					rtn = ioErr; 
					break;
				case ECONNRESET:
					/* explicit peer abort */
					rtn = errSSLClosedAbort;
					break;
				case EAGAIN:
					/* nonblocking, no data */
					rtn = errSSLWouldBlock;
					break;
				default:
					dprintf(("SocketRead: read(%u) error %d, rrtn %d\n", 
						(unsigned)bytesToGo, theErr, (int)rrtn));
					rtn = ioErr;
					break;
			}
			/* in any case, we're done with this call if rrtn <= 0 */
			break;
		}
		bytesRead = rrtn;
		bytesToGo -= bytesRead;
		currData  += bytesRead;
		
		if(bytesToGo == 0) {
			/* filled buffer with incoming data, done */
			break;
		}
	}
	*dataLength = initLen - bytesToGo;
	tprintf("SocketRead", initLen, *dataLength, (UInt8 *)data);
	
	#if SSL_OT_DOT || (SSL_OT_DEBUG && !SSL_OT_IO_TRACE)
	if((rtn == 0) && (*dataLength == 0)) {
		/* keep UI alive */
		outputDot();
	}
	#endif
	#if SSL_DISPL_WOULD_BLOCK
	if(rtn == errSSLWouldBlock) {
		printf("."); fflush(stdout);
	}
	#endif
	return rtn;
}
/*
 * R/W. Called out from SSL.
 */
OSStatus SocketRead(
					SSLConnectionRef   connection,
					void         *data,       /* owned by 
 * caller, data
 * RETURNED */
					size_t         *dataLength)  /* IN/OUT */ 
{
	UInt32      bytesToGo = (UInt32) *dataLength;
	UInt32       initLen = bytesToGo;
	UInt8      *currData = (UInt8 *)data;
	int        sock = (int)connection;
	OSStatus    rtn = noErr;
	UInt32      bytesRead = 0;
	int        rrtn;
	
	*dataLength = 0;
	
	for(;;) {
		// bytesRead = 0;
		rrtn = (int) read(sock, currData, bytesToGo);
		if (rrtn <= 0) {
			/* this is guesswork... */
			int theErr = errno;
			dprintf(("SocketRead: read(%d) error %d\n", (int)bytesToGo, theErr));
#if !NON_BLOCKING
			if((rrtn == 0) && (theErr == 0)) {
				/* try fix for iSync */ 
				rtn = errSSLClosedGraceful;
				//rtn = errSSLClosedAbort;
			}
			else /* do the switch */
#endif
				switch(theErr) {
					case ENOENT:
						/* connection closed */
						rtn = errSSLClosedGraceful; 
						break;
					case ECONNRESET:
						rtn = errSSLClosedAbort;
						break;
#if  NON_BLOCKING
					case EAGAIN:
#else
					case 0:    /* ??? */
#endif
						rtn = errSSLWouldBlock;
						break;
					default:
						dprintf(("SocketRead: read(%d) error %d\n", 
								 (int)bytesToGo, theErr));
						rtn = ioErr;
						break;
				}
			break;
		}
		else {
			bytesRead = rrtn;
		}
		bytesToGo -= bytesRead;
		currData  += bytesRead;
		
		if(bytesToGo == 0) {
			/* filled buffer with incoming data, done */
			break;
		}
	}
	*dataLength = initLen - bytesToGo;
	tprintf("SocketRead", initLen, *dataLength, (UInt8 *)data);
	
#if SSL_OT_DOT || (SSL_OT_DEBUG && !SSL_OT_IO_TRACE)
	if((rtn == 0) && (*dataLength == 0)) {
		/* keep UI alive */
		outputDot();
	}
#endif
	return rtn;
}
Example #3
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;
}
/*
 * R/W. Called out from SSL.
 */
OSStatus SocketRead(
	SSLConnectionRef 	connection,
	void 				*data, 			/* owned by 
	 									 * caller, data
	 									 * RETURNED */
	size_t 				*dataLength)	/* IN/OUT */ 
{
	size_t			bytesToGo = *dataLength;
	size_t 			initLen = bytesToGo;
	UInt8			*currData = (UInt8 *)data;
	int		        sock = (int)((long)connection);
	OSStatus		rtn = noErr;
	size_t			bytesRead;
	int				rrtn;
	
	*dataLength = 0;

	for(;;) {
		bytesRead = 0;
		rrtn = read(sock, currData, bytesToGo);
		if (rrtn <= 0) {
			/* this is guesswork... */
			switch(errno) {
				case ENOENT:
					/* connection closed */
					rtn = errSSLClosedGraceful; 
					break;
				#if	NON_BLOCKING
				case EAGAIN:
				#else
				case 0:		/* ??? */
				#endif
					rtn = errSSLWouldBlock;
					break;
				default:
					dprintf(("SocketRead: read(%lu) error %d\n", 
						bytesToGo, errno));
					rtn = ioErr;
					break;
			}
			break;
		}
		else {
			bytesRead = rrtn;
		}
		bytesToGo -= bytesRead;
		currData  += bytesRead;
		
		if(bytesToGo == 0) {
			/* filled buffer with incoming data, done */
			break;
		}
	}
	*dataLength = initLen - bytesToGo;
	tprintf("SocketRead", initLen, *dataLength, (UInt8 *)data);
	
	#if SSL_OT_DOT || (SSL_OT_DEBUG && !SSL_OT_IO_TRACE)
	if((rtn == 0) && (*dataLength == 0)) {
		/* keep UI alive */
		outputDot();
	}
	#endif
	return rtn;
}