Beispiel #1
0
/*
	Main routine. Initialize SSL keys and structures, and make two SSL 
	connections, the first with a blank session Id, and the second with
	a session ID populated during the first connection to do a much faster
	session resumption connection the second time.
 */
int32 main(int32 argc, char **argv)
{
	int32			rc;
	sslKeys_t		*keys;
	sslSessionId_t	sid;
#ifdef WIN32
	WSADATA			wsaData;
	WSAStartup(MAKEWORD(1, 1), &wsaData);
#endif
	if ((rc = matrixSslOpen()) < 0) {
		_psTrace("MatrixSSL library init failure.  Exiting\n");
		return rc; 
	}
	if (matrixSslNewKeys(&keys) < 0) {
		_psTrace("MatrixSSL library key init failure.  Exiting\n");
		return -1;
	}

#ifdef USE_HEADER_KEYS
/*
	In-memory based keys
*/
	if ((rc = matrixSslLoadRsaKeysMem(keys, NULL, 0, NULL, 0, RSA1024CA,
			sizeof(RSA1024CA))) < 0) {
		_psTrace("No certificate material loaded.  Exiting\n");
		matrixSslDeleteKeys(keys);
		matrixSslClose();
		return rc;
	}
#else /* USE_HEADER_KEYS */
/*
	File based keys
*/
	if ((rc = matrixSslLoadRsaKeys(keys, NULL, NULL, NULL, rsaCAFile)) < 0){
		_psTrace("No certificate material loaded.  Exiting\n");
		matrixSslDeleteKeys(keys);
		matrixSslClose();
		return rc;
	}
#endif /* USE_HEADER_KEYS */


	matrixSslInitSessionId(sid);
	_psTrace("=== INITIAL CLIENT SESSION ===\n");
	httpsClientConnection(keys, &sid);

	_psTrace("\n=== CLIENT SESSION WITH CACHED SESSION ID ===\n");
	httpsClientConnection(keys, &sid);
	
	matrixSslDeleteKeys(keys);
	matrixSslClose();

#ifdef WIN32
	_psTrace("Press any key to close");
	getchar();
#endif
	return 0;
}
Beispiel #2
0
void matrixssl_init(void)
{
	int i = 0;

	matrixSslOpen();

	for (i = 0; i < MAX_MATRIXSSL_SESSIONS; i++)
		bufs[i] = NULL;

}
Beispiel #3
0
int SP_MatrixsslChannelFactory :: init( const char * certFile, const char * keyFile )
{
	if( matrixSslOpen() < 0 ) {
		sp_syslog( LOG_WARNING, "matrixSslOpen failed" );
	}

	if( matrixSslReadKeys( &mKeys, certFile, keyFile, NULL, NULL ) < 0 ) {
		sp_syslog( LOG_WARNING, "Error reading or parsing %s or %s.", certFile, keyFile );
	}

	return 0;
}
BOOL ssl_initialize_internal() {

	int iRet;
	//
	// Initialize the SSL library.
	//
	iRet = matrixSslOpen();
	if (iRet < 0) {
		//
		// Something went wrong so kill the application with an error code.
		//
		MATRIXSSL_PERROR("MatrixSSL library open failure.  Exiting\n");
		return (FALSE);
	}

	iRet = matrixSslNewKeys(&g_pSslKeys);

	if (iRet < 0) {
		MATRIXSSL_PERROR("MatrixSSL library key init failure.  Exiting\n");
		matrixSslDeleteKeys(g_pSslKeys);
		matrixSslClose();
		//
		// Something went wrong so kill the application with an error code.
		//
		return (FALSE);
	}

	//
	// Read the required certificates from memory.
	//
	iRet = matrixSslLoadRsaKeysMem(g_pSslKeys, g_pcCertSrv, g_ulCertSrvLen,
			g_pcPrivKeySrv, g_ulPrivKeySrvLen, g_pcAcertSrv, g_ulAcertSrvLen);

	//TODO or generate it
	if (iRet < 0) {
		MATRIXSSL_PERROR("No certificate material loaded.  Exiting\n");
		matrixSslDeleteKeys(g_pSslKeys);
		matrixSslClose();
		//
		// Something went wrong so kill the application with an error code.
		//
		return (FALSE);
	}

	MATRIXSSL_PDEBUG("OK\n");
	return TRUE;
}
Beispiel #5
0
openssl_env * initssl() {
  if (sslenv_svr == 0) {
    if (openssl_init == 0) {
      openssl_init = 1;
#ifdef HAVE_OPENSSL
      SSL_library_init();
      if (_options.debug) SSL_load_error_strings();
      SSLeay_add_all_algorithms();
      SSLeay_add_ssl_algorithms();
#else
      matrixSslOpen();
      syslog(LOG_DEBUG, "MatrixSslOpen()");
#endif
    }
    openssl_env_init(sslenv_svr = calloc(1, sizeof(openssl_env)), 0, 1);
  }
  return sslenv_svr;
}
Beispiel #6
0
openssl_env * initssl_cli() {
  if (sslenv_cli == 0) {
    if (openssl_init == 0) {
      openssl_init = 1;
#ifdef HAVE_OPENSSL
      SSL_library_init();
      /*if (_options.debug) */SSL_load_error_strings();
      SSLeay_add_all_algorithms();
      SSLeay_add_ssl_algorithms();
#else
      matrixSslOpen();
      CP_ERROR(1,"MatrixSslOpen()");
#endif
    }
    openssl_env_init(sslenv_cli = calloc(1, sizeof(openssl_env)), 0, 0);
  }
  return sslenv_cli;
}
Beispiel #7
0
PUBLIC int sslOpen()
{
    char    *password;

    if (matrixSslOpen() < 0) {
        return -1;
    }
    if (matrixSslNewKeys(&sslKeys) < 0) {
        error("Failed to allocate keys in sslOpen\n");
        return -1;
    }
    password = 0;
    if (matrixSslLoadRsaKeys(sslKeys, BIT_CERTIFICATE, BIT_KEY, password,  NULL) < 0) {
        error(0, "Failed to read certificate %s or key file\n", BIT_CERTIFICATE);
        return -1;
    }
    return 0;
}
Beispiel #8
0
openssl_env * initssl_cli() {
  if (sslenv_cli == 0) {
    if (openssl_init == 0) {
      openssl_init = 1;
#ifdef HAVE_OPENSSL
      if (_options.debug) {
	SSL_load_error_strings();
      }
      SSL_library_init();
      OpenSSL_add_all_algorithms();
#else
      matrixSslOpen();
      syslog(LOG_DEBUG, "%s(%d): MatrixSslOpen()", __FUNCTION__, __LINE__);
#endif
    }
    openssl_env_init(sslenv_cli = calloc(1, sizeof(openssl_env)), 0, 0);
  }
  return sslenv_cli;
}
Beispiel #9
0
PUBLIC int sslOpen()
{
    char    *password, *cert, *key, *ca;

    if (matrixSslOpen() < 0) {
        return -1;
    }
    if (matrixSslNewKeys(&sslKeys) < 0) {
        error("Failed to allocate keys in sslOpen\n");
        return -1;
    }
    password = 0;
    cert = *ME_GOAHEAD_CERTIFICATE ? ME_GOAHEAD_CERTIFICATE : 0;
    key = *ME_GOAHEAD_KEY ? ME_GOAHEAD_KEY : 0;
    ca = *ME_GOAHEAD_CA ? ME_GOAHEAD_CA: 0;
    if (matrixSslLoadRsaKeys(sslKeys, cert, key, password, ca) < 0) {
        error("Failed to read certificate, key or ca file\n");
        return -1;
    }
    return 0;
}
Beispiel #10
0
int main(int argc, char **argv)
#endif
{
	sslConn_t		*cp;
	sslKeys_t		*keys;
	SOCKET			listenfd, fd;
	WSADATA			wsaData;
	unsigned char	buf[1024];
	unsigned char	*response, *c;
	int				responseHdrLen, acceptAgain, flags;
	int				bytes, status, quit, again, rc, err;
#if USE_MEM_CERTS
	unsigned char	*servBin, *servKeyBin, *caBin; 
	int				servBinLen, caBinLen, servKeyBinLen;
#endif

	cp = NULL;
/*
	Initialize Windows sockets (no-op on other platforms)
*/
	WSAStartup(MAKEWORD(1,1), &wsaData);
/*
	Initialize the MatrixSSL Library, and read in the public key (certificate)
	and private key.
*/
	if (matrixSslOpen() < 0) {
		fprintf(stderr, "matrixSslOpen failed, exiting...");
	}

#if USE_MEM_CERTS
/*
	Example of DER binary certs for matrixSslReadKeysMem
*/
	getFileBin("certSrv.der", &servBin, &servBinLen);
	getFileBin("privkeySrv.der", &servKeyBin, &servKeyBinLen);
	getFileBin("CACertCln.der", &caBin, &caBinLen);

	matrixSslReadKeysMem(&keys, servBin, servBinLen,
		servKeyBin, servKeyBinLen, caBin, caBinLen); 

	free(servBin);
	free(servKeyBin);
	free(caBin);
#else 
/*
	Standard PEM files
*/
	if (matrixSslReadKeys(&keys, certfile, keyfile, NULL, NULL) < 0)  {
		fprintf(stderr, "Error reading or parsing %s or %s.\n", 
			certfile, keyfile);
		goto promptAndExit;
	}
#endif /* USE_MEM_CERTS */
	fprintf(stdout, 
		"Run httpsClient or type https://127.0.0.1:%d into your local Web browser.\n",
		HTTPS_PORT);
/*
	Create the listen socket
*/
	if ((listenfd = socketListen(HTTPS_PORT, &err)) == INVALID_SOCKET) {
		fprintf(stderr, "Cannot listen on port %d\n", HTTPS_PORT);
		goto promptAndExit;
	}
/*
	Set blocking or not on the listen socket
*/
	setSocketBlock(listenfd);
/*
	Loop control initalization
*/
	quit = 0;
	again = 0;
	flags = 0;

	acceptAgain = 1;
/*
	Main connection loop
*/
	while (!quit) {

		if (acceptAgain) {
/*
			sslAccept creates a new server session
*/
			/* TODO - deadlock on blocking socket accept.  Should disable blocking here */
			if ((fd = socketAccept(listenfd, &err)) == INVALID_SOCKET) {
				fprintf(stdout, "Error accepting connection: %d\n", err);
				continue;
			}
			if ((rc = sslAccept(&cp, fd, keys, NULL, flags)) != 0) {
				socketShutdown(fd);
				continue;
			}

			flags = 0;
			acceptAgain = 0;
		}
/*
		Read response
		< 0 return indicates an error.
		0 return indicates an EOF or CLOSE_NOTIFY in this situation
		> 0 indicates that some bytes were read.  Keep reading until we see
		the /r/n/r/n from the GET request.  We don't actually parse the request,
		we just echo it back.
*/
		c = buf;
readMore:
		if ((rc = sslRead(cp, c, sizeof(buf) - (int)(c - buf), &status)) > 0) {
			c += rc;
			if (c - buf < 4 || memcmp(c - 4, "\r\n\r\n", 4) != 0) {
				goto readMore;
			}
		} else {
			if (rc < 0) {
				fprintf(stdout, "sslRead error.  dropping connection.\n");
			}
			if (rc < 0 || status == SSLSOCKET_EOF ||
					status == SSLSOCKET_CLOSE_NOTIFY) {
				socketShutdown(cp->fd);
				sslFreeConnection(&cp);
				acceptAgain = 1;
				continue;
			}
			goto readMore;
		}
/*
		Done reading.  If the incoming data starts with the quitString,
		quit the application after this request
*/
		if (memcmp(buf, quitString, min(c - buf, 
				(int)strlen(quitString))) == 0) {
			quit++;
			fprintf(stdout, "Q");
		}
/*
		If the incoming data starts with the againString,
		we are getting a pipeline request on the same session.  Don't
		close and wait for new connection in this case.
*/
		if (memcmp(buf, againString,
				min(c - buf, (int)strlen(againString))) == 0) {
			again++;
			fprintf(stdout, "A");
		} else {
			fprintf(stdout, "R");
			again = 0;
		}
/*
		Copy the canned response header and decoded data from socket as the
		response (reflector)
*/
		responseHdrLen = (int)strlen(responseHdr);
		bytes = responseHdrLen + (int)(c - buf);
		response = malloc(bytes);
		memcpy(response, responseHdr, responseHdrLen);
		memcpy(response + responseHdrLen, buf, c - buf); 
/*
		Send response.
		< 0 return indicates an error.
		0 return indicates not all data was sent and we must retry
		> 0 indicates that all requested bytes were sent
*/
writeMore:
		rc = sslWrite(cp, response, bytes, &status);
		if (rc < 0) {
			free(response);
			fprintf(stdout, "Internal sslWrite error\n");
			socketShutdown(cp->fd);
			sslFreeConnection(&cp);
			continue;
		} else if (rc == 0) {
			goto writeMore;
		}
		free(response);
/*
		If we saw an /again request, loop up and process another pipelined
		HTTP request.  The /again request is supported in the httpsClient
		example code.
*/
		if (again) {
			continue;
		}
/*
		Send a closure alert for clean shutdown of remote SSL connection
		This is for good form, some implementations just close the socket
*/
		sslWriteClosureAlert(cp);
/*
		Close the socket and wait for next connection (new session)
*/
		socketShutdown(cp->fd);
		sslFreeConnection(&cp);
		acceptAgain = 1;
	}
/*
	Close listening socket, free remaining items
*/
	if (cp && cp->ssl) {
		socketShutdown(cp->fd);
		sslFreeConnection(&cp);
	}
	socketShutdown(listenfd);

	matrixSslFreeKeys(keys);
	matrixSslClose();
	WSACleanup();
promptAndExit:
	fprintf(stdout, "\n\nPress return to exit...\n");
	getchar();
	return 0;
}
Beispiel #11
0
/*
	Non-blocking socket event handler
	Wait one time in select for events on any socket
	This will accept new connections, read and write to sockets that are
	connected, and close sockets as required.
 */
static int32 selectLoop(sslKeys_t *keys, SOCKET lfd)
{
	httpConn_t		*cp;
	psTime_t		now;
	DLListEntry		connsTmp;
	DLListEntry		*pList;
	
	fd_set			readfd, writefd;
	struct timeval	timeout;
	SOCKET			fd, maxfd;
	
	unsigned char	*buf;
	int32			rc, len, transferred, val;
	unsigned char	rSanity, wSanity, acceptSanity;
	
	DLListInit(&connsTmp);
	rc = PS_SUCCESS;
	maxfd = INVALID_SOCKET;
	timeout.tv_sec = SELECT_TIME / 1000;
	timeout.tv_usec = (SELECT_TIME % 1000) * 1000;
	FD_ZERO(&readfd);
	FD_ZERO(&writefd);
	
	/* Always set readfd for listening socket */
	FD_SET(lfd, &readfd);
	if (lfd > maxfd) {
		maxfd = lfd;
	}
/*	
	Check timeouts and set readfd and writefd for connections as required.
	We use connsTemp so that removal on error from the active iteration list
		doesn't interfere with list traversal 
 */
	psGetTime(&now);
	while (!DLListIsEmpty(&g_conns)) {
		pList = DLListGetHead(&g_conns);
		cp = DLListGetContainer(pList, httpConn_t, List);
		DLListInsertTail(&connsTmp, &cp->List);
		/*	If timeout != 0 msec ith no new data, close */
		if (cp->timeout && (psDiffMsecs(cp->time, now) > (int32)cp->timeout)) {
			closeConn(cp, PS_TIMEOUT_FAIL);
			continue;	/* Next connection */
		}
		/* Always select for read */
		FD_SET(cp->fd, &readfd);
		/* Select for write if there's pending write data or connection */
		if (matrixSslGetOutdata(cp->ssl, NULL) > 0) {
			FD_SET(cp->fd, &writefd);
		}
		/* Housekeeping for maxsock in select call */
		if (cp->fd > maxfd) {
			maxfd = cp->fd;
		}
	}
	
	/* Use select to check for events on the sockets */
	if ((val = select(maxfd + 1, &readfd, &writefd, NULL, &timeout)) <= 0) {
		/* On error, restore global connections list */
		while (!DLListIsEmpty(&connsTmp)) {
			pList = DLListGetHead(&connsTmp);
			cp = DLListGetContainer(pList, httpConn_t, List);
			DLListInsertTail(&g_conns, &cp->List);
		}
		/* Select timeout */
		if (val == 0) {
			return PS_TIMEOUT_FAIL;
		}
		/* Woke due to interrupt */
		if (SOCKET_ERRNO == EINTR) {
			return PS_TIMEOUT_FAIL;
		}
		/* Should attempt to handle more errnos, such as EBADF */
		return PS_PLATFORM_FAIL;
	}
	
	/* Check listener for new incoming socket connections */
	if (FD_ISSET(lfd, &readfd)) {
		for (acceptSanity = 0; acceptSanity < ACCEPT_QUEUE; acceptSanity++) {
			fd = accept(lfd, NULL, NULL);
			if (fd == INVALID_SOCKET) {
				break;	/* Nothing more to accept; next listener */
			}
			setSocketOptions(fd);
			cp = malloc(sizeof(httpConn_t));
			if ((rc = matrixSslNewServerSession(&cp->ssl, keys, certCb)) < 0) {
				close(fd); fd = INVALID_SOCKET;
				continue;
			}
			cp->fd = fd;
			fd = INVALID_SOCKET;
			cp->timeout = SSL_TIMEOUT;
			psGetTime(&cp->time);
			cp->parsebuf = NULL;
			cp->parsebuflen = 0;
			DLListInsertTail(&connsTmp, &cp->List);
			/* Fake that there is read data available, no harm if there isn't */
			FD_SET(cp->fd, &readfd);
/*			_psTraceInt("=== New Client %d ===\n", cp->fd); */
		}
	}
	
	/* Check each connection for read/write activity */
	while (!DLListIsEmpty(&connsTmp)) {
		pList = DLListGetHead(&connsTmp);
		cp = DLListGetContainer(pList, httpConn_t, List);
		DLListInsertTail(&g_conns, &cp->List);
		
		rSanity = wSanity = 0;
/*
		See if there's pending data to send on this connection
		We could use FD_ISSET, but this is more reliable for the current
			state of data to send.
 */
WRITE_MORE:
		if ((len = matrixSslGetOutdata(cp->ssl, &buf)) > 0) {
			/* Could get a EWOULDBLOCK since we don't check FD_ISSET */
			transferred = send(cp->fd, buf, len, MSG_DONTWAIT);
			if (transferred <= 0) {
#ifdef WIN32
				if (SOCKET_ERRNO != EWOULDBLOCK &&
					SOCKET_ERRNO != WSAEWOULDBLOCK) {

#else
				if (SOCKET_ERRNO != EWOULDBLOCK) {
#endif
					closeConn(cp, PS_PLATFORM_FAIL);
					continue;	/* Next connection */
				}
			} else {
				/* Indicate that we've written > 0 bytes of data */
				if ((rc = matrixSslSentData(cp->ssl, transferred)) < 0) {
					closeConn(cp, PS_ARG_FAIL);
					continue;	/* Next connection */
				}
				if (rc == MATRIXSSL_REQUEST_CLOSE) {
					closeConn(cp, MATRIXSSL_REQUEST_CLOSE);
					continue;	/* Next connection */
				} else if (rc == MATRIXSSL_HANDSHAKE_COMPLETE) {
					/* If the protocol is server initiated, send data here */
#ifdef ENABLE_FALSE_START					
					/* OR this could be a Chrome browser using 
						FALSE_START and the application data is already
						waiting in our inbuf for processing */
					if ((rc = matrixSslReceivedData(cp->ssl, 0,
								&buf, (uint32*)&len)) < 0) {
							closeConn(cp, 0);
							continue;	/* Next connection */
					}
					if (rc > 0) { /* There was leftover data */
						goto PROCESS_MORE;
					}
#endif /* ENABLE_FALSE_START  */
					
				}
				/* Update activity time */
				psGetTime(&cp->time);
				/* Try to send again if more data to send */
				if (rc == MATRIXSSL_REQUEST_SEND || transferred < len) {
					if (wSanity++ < GOTO_SANITY) goto WRITE_MORE;
				}
			}
		} else if (len < 0) {
			closeConn(cp, PS_ARG_FAIL);
			continue;	/* Next connection */
		}
		
/*
		Check the file descriptor returned from select to see if the connection
		has data to be read
 */
		if (FD_ISSET(cp->fd, &readfd)) {
READ_MORE:
			/* Get the ssl buffer and how much data it can accept */
			/* Note 0 is a return failure, unlike with matrixSslGetOutdata */
			if ((len = matrixSslGetReadbuf(cp->ssl, &buf)) <= 0) {
				closeConn(cp, PS_ARG_FAIL);
				continue;	/* Next connection */
			}
			if ((transferred = recv(cp->fd, buf, len, MSG_DONTWAIT)) < 0) {
				/* We could get EWOULDBLOCK despite the FD_ISSET on goto  */
#ifdef WIN32
				if (SOCKET_ERRNO != EWOULDBLOCK &&
					SOCKET_ERRNO != WSAEWOULDBLOCK) {

#else
				if (SOCKET_ERRNO != EWOULDBLOCK) {
#endif
					closeConn(cp, PS_PLATFORM_FAIL);
				}
				continue;	/* Next connection */
			}
			/* If EOF, remote socket closed. This is semi-normal closure.
			   Officially, we should close on closure alert. */
			if (transferred == 0) {
/*				psTraceIntInfo("Closing connection %d on EOF\n", cp->fd); */
				closeConn(cp, 0);
				continue;	/* Next connection */
			}
/*
			Notify SSL state machine that we've received more data into the
			ssl buffer retreived with matrixSslGetReadbuf.
 */
			if ((rc = matrixSslReceivedData(cp->ssl, (int32)transferred, &buf, 
											(uint32*)&len)) < 0) {
				closeConn(cp, 0);
				continue;	/* Next connection */
			}
			/* Update activity time */
			psGetTime(&cp->time);
			
PROCESS_MORE:
			/* Process any incoming plaintext application data */
			switch (rc) {
				case MATRIXSSL_HANDSHAKE_COMPLETE:
					/* If the protocol is server initiated, send data here */
					goto READ_MORE;
				case MATRIXSSL_APP_DATA:
					/* Remember, must handle if len == 0! */
					if ((rc = httpBasicParse(cp, buf, len)) < 0) {
						_psTrace("Couldn't parse HTTP data.  Closing conn.\n");
						closeConn(cp, PS_PROTOCOL_FAIL);
						continue; /* Next connection */
					}
					if (rc == HTTPS_COMPLETE) {
						if (httpWriteResponse(cp->ssl) < 0) {
							closeConn(cp, PS_PROTOCOL_FAIL);
							continue; /* Next connection */
						}
						/* For HTTP, we assume no pipelined requests, so we 
						 close after parsing a single HTTP request */
						/* Ignore return of closure alert, it's optional */
						matrixSslEncodeClosureAlert(cp->ssl);
						rc = matrixSslProcessedData(cp->ssl, &buf, (uint32*)&len);
						if (rc > 0) {
							/* Additional data is available, but we ignore it */
							_psTrace("HTTP data parsing not supported, ignoring.\n");
							closeConn(cp, PS_SUCCESS);
							continue; /* Next connection */
						} else if (rc < 0) {
							closeConn(cp, PS_PROTOCOL_FAIL);
							continue; /* Next connection */
						}
						/* rc == 0, write out our response and closure alert */
						goto WRITE_MORE;
					}
					/* We processed a partial HTTP message */
					if ((rc = matrixSslProcessedData(cp->ssl, &buf, (uint32*)&len)) == 0) {
						goto READ_MORE;
					}
					goto PROCESS_MORE;
				case MATRIXSSL_REQUEST_SEND:
					/* Prevent us from reading again after the write,
					 although that wouldn't be the end of the world */
					FD_CLR(cp->fd, &readfd);
					if (wSanity++ < GOTO_SANITY) goto WRITE_MORE;
					break;
				case MATRIXSSL_REQUEST_RECV:
					if (rSanity++ < GOTO_SANITY) goto READ_MORE; 
					break;
				case MATRIXSSL_RECEIVED_ALERT:
					/* The first byte of the buffer is the level */
					/* The second byte is the description */
					if (*buf == SSL_ALERT_LEVEL_FATAL) {
						psTraceIntInfo("Fatal alert: %d, closing connection.\n", 
									*(buf + 1));
						closeConn(cp, PS_PROTOCOL_FAIL);
						continue; /* Next connection */
					}
					/* Closure alert is normal (and best) way to close */
					if (*(buf + 1) == SSL_ALERT_CLOSE_NOTIFY) {
						closeConn(cp, PS_SUCCESS);
						continue; /* Next connection */
					}
					psTraceIntInfo("Warning alert: %d\n", *(buf + 1));
					if ((rc = matrixSslProcessedData(cp->ssl, &buf, (uint32*)&len)) == 0) {
						/* No more data in buffer. Might as well read for more. */
						goto READ_MORE;
					}
					goto PROCESS_MORE;

				default:
					/* If rc <= 0 we fall here */
					closeConn(cp, PS_PROTOCOL_FAIL);
					continue; /* Next connection */
			}
			/* Always try to read more if we processed some data */
			if (rSanity++ < GOTO_SANITY) goto READ_MORE;
		} /*  readfd handling */
	}	/* connection loop */
	return PS_SUCCESS;
}

/******************************************************************************/
/*
	Create an HTTP response and encode it to the SSL buffer
 */
#define	TEST_SIZE	16000
static int32 httpWriteResponse(ssl_t *cp)
{
	unsigned char	*buf;
	int32			available;
	
	if ((available = matrixSslGetWritebuf(cp, &buf, 
							strlen((char *)g_httpResponseHdr) + 1)) < 0) {
		return PS_MEM_FAIL;
	}
	strncpy((char *)buf, (char *)g_httpResponseHdr, available);
	if (matrixSslEncodeWritebuf(cp, strlen((char *)buf)) < 0) {
		return PS_MEM_FAIL;
	}
	return MATRIXSSL_REQUEST_SEND;
}

/******************************************************************************/
/*
	Main non-blocking SSL server
	Initialize MatrixSSL and sockets layer, and loop on select
 */
int32 main(int32 argc, char **argv)
{
	sslKeys_t		*keys;
	SOCKET			lfd;
	int32			err, rc;
#ifdef WIN32
	WSADATA			wsaData;
	WSAStartup(MAKEWORD(1, 1), &wsaData);
#endif


	keys = NULL;
	DLListInit(&g_conns);
	g_exitFlag = 0;
	lfd = INVALID_SOCKET;
	
#ifdef POSIX
	if (sighandlers() < 0) {
		return PS_PLATFORM_FAIL;
	}
#endif	/* POSIX */
	if ((rc = matrixSslOpen()) < 0) {
		_psTrace("MatrixSSL library init failure.  Exiting\n");
		return rc;
	}
	if (matrixSslNewKeys(&keys) < 0) {
		_psTrace("MatrixSSL library key init failure.  Exiting\n");
		return -1;
	}

#ifdef USE_HEADER_KEYS
/*
	In-memory based keys
*/
	if ((rc = matrixSslLoadRsaKeysMem(keys, certSrvBuf, sizeof(certSrvBuf),
				   privkeySrvBuf, sizeof(privkeySrvBuf), NULL, 0)) < 0) {
		_psTrace("No certificate material loaded.  Exiting\n");
		matrixSslDeleteKeys(keys);
		matrixSslClose();
		return rc;
	}
#else /* USE_HEADER_KEYS */
/*
	File based keys
*/
	if ((rc = matrixSslLoadRsaKeys(keys, certSrvFile, privkeySrvFile, NULL,
			NULL)) < 0) {
		_psTrace("No certificate material loaded.  Exiting\n");
		matrixSslDeleteKeys(keys);
		matrixSslClose();
		return rc;
	}
#endif /* USE_HEADER_KEYS */


	/* Create the listening socket that will accept incoming connections */
	if ((lfd = socketListen(HTTPS_PORT, &err)) == INVALID_SOCKET) {
		_psTraceInt("Can't listen on port %d\n", HTTPS_PORT);
		goto L_EXIT;
	}

	/* Main select loop to handle sockets events */
	while (!g_exitFlag) {
		selectLoop(keys, lfd);
	}

L_EXIT:
	if (lfd != INVALID_SOCKET) close(lfd);
	if (keys) matrixSslDeleteKeys(keys);
	matrixSslClose();
	
	return 0;
}
Beispiel #12
0
int main(int argc, char **argv)
{
	int32			id;
	sslConn_t		*svrConn, *clnConn;
#ifdef ENABLE_PERF_TIMING
	int32			perfIter;
	uint32			clnTime, svrTime;
#endif /* ENABLE_PERF_TIMING */
		
	if (matrixSslOpen() < 0) {
		fprintf(stderr, "matrixSslOpen failed, exiting...");
	}

	svrConn = psMalloc(PEERSEC_NO_POOL, sizeof(sslConn_t));
	clnConn = psMalloc(PEERSEC_NO_POOL, sizeof(sslConn_t));
	memset(svrConn, 0, sizeof(sslConn_t));
	memset(clnConn, 0, sizeof(sslConn_t));
	
	for (id = 0; ciphers[id].cipherId > 0; id++) {
		matrixSslInitSessionId(clientSessionId);
		_psTraceStr("Testing %s suite\n", ciphers[id].name);
/*
		Standard Handshake
*/
		_psTrace("	Standard handshake test\n");
#ifdef ENABLE_PERF_TIMING
/*
		Each matrixSsl call in the handshake is wrapped by a timer.  The 
		data exchange phase is not being included in the time
*/
		clnTime = svrTime = 0;
		for (perfIter = 0; perfIter < CONN_ITER; perfIter++) {
#endif /* ENABLE_PERF_TIMING */		
		if (initializeHandshake(clnConn, svrConn, ciphers[id],
				&clientSessionId) < 0) {
			_psTrace("		FAILED: initializing Standard handshake\n");
			goto LBL_FREE;
		}
		if (performHandshake(clnConn, svrConn) < 0) {
			_psTrace("		FAILED: Standard handshake\n");
			goto LBL_FREE;
		} else {
			testTrace("		PASSED: Standard handshake");
			if (exchangeAppData(clnConn, svrConn) < 0) {
				_psTrace(" but FAILED to exchange application data\n");
			} else {
				testTrace("\n");
			}
		}
#ifdef ENABLE_PERF_TIMING
		clnTime += clnConn->runningTime;
		svrTime += svrConn->runningTime;
		/* Have to reset conn for full handshake... except last time through */
		if (perfIter + 1 != CONN_ITER) {
			matrixSslDeleteSession(clnConn->ssl);
			matrixSslDeleteSession(svrConn->ssl);
			matrixSslInitSessionId(clientSessionId);
		}
		} /* iteration loop close */
		_psTraceInt("CLIENT:  %d " TIME_UNITS, (int32)clnTime/CONN_ITER);
		_psTraceInt("SERVER:  %d " TIME_UNITS, (int32)svrTime/CONN_ITER);
//		_psTrace("Press any key to continue tests");
		_psTrace("\n==========\n");
//		getchar();
#endif /* ENABLE_PERF_TIMING */
		
#ifdef SSL_REHANDSHAKES_ENABLED		
/*
		 Re-Handshake (full handshake over existing connection)
*/		
		_psTrace("	Re-handshake test (client-initiated)\n");		
		if (initializeReHandshake(clnConn, svrConn, ciphers[id].cipherId) < 0) {
			_psTrace("		FAILED: initializing Re-handshake\n");
			goto LBL_FREE;
		}
		if (performHandshake(clnConn, svrConn) < 0) {
			_psTrace("		FAILED: Re-handshake\n");
			goto LBL_FREE;
		} else {
			testTrace("		PASSED: Re-handshake");
			if (exchangeAppData(clnConn, svrConn) < 0) {
				_psTrace(" but FAILED to exchange application data\n");
			} else {
				testTrace("\n");
			}
		}	
#else
		_psTrace("	Re-handshake tests are disabled (ENABLE_SECURE_REHANDSHAKES)\n");
#endif
				
/*
		Resumed handshake (fast handshake over new connection)
*/				
		_psTrace("	Resumed handshake test (new connection)\n");
#ifdef ENABLE_PERF_TIMING
		clnTime = svrTime = 0;
		for (perfIter = 0; perfIter < CONN_ITER; perfIter++) {
#endif /* ENABLE_PERF_TIMING */			
		if (initializeResumedHandshake(clnConn, svrConn,
				ciphers[id]) < 0) {
			_psTrace("		FAILED: initializing Resumed handshake\n");
			goto LBL_FREE;
		}
		if (performHandshake(clnConn, svrConn) < 0) {
			_psTrace("		FAILED: Resumed handshake\n");
			goto LBL_FREE;
		} else {
			testTrace("		PASSED: Resumed handshake");
			if (exchangeAppData(clnConn, svrConn) < 0) {
				_psTrace(" but FAILED to exchange application data\n");
			} else {
				testTrace("\n");
			}
		}
#ifdef ENABLE_PERF_TIMING
		clnTime += clnConn->runningTime;
		svrTime += svrConn->runningTime;
		/* Have to reset conn for full handshake */
		} /* iteration loop */
		_psTraceInt("CLIENT:  %d " TIME_UNITS, (int32)clnTime/CONN_ITER);
		_psTraceInt("SERVER:  %d " TIME_UNITS, (int32)svrTime/CONN_ITER);
		_psTrace("Press any key to continue tests");
		_psTrace("\n==========\n");
//		getchar();
#endif /* ENABLE_PERF_TIMING */		
		
#ifdef SSL_REHANDSHAKES_ENABLED		
/*
		 Re-handshake initiated by server (full handshake over existing conn)
*/			
		_psTrace("	Re-handshake test (server initiated)\n");
		if (initializeServerInitiatedReHandshake(clnConn, svrConn,
									   ciphers[id].cipherId) < 0) {
			_psTrace("		FAILED: initializing Re-handshake\n");
			goto LBL_FREE;
		}
		if (performHandshake(svrConn, clnConn) < 0) {
			_psTrace("		FAILED: Re-handshake\n");
			goto LBL_FREE;
		} else {
			testTrace("		PASSED: Re-handshake");
			if (exchangeAppData(clnConn, svrConn) < 0) {
				_psTrace(" but FAILED to exchange application data\n");
			} else {
				testTrace("\n");
			}
		}	
	
/*
		Resumed re-handshake (fast handshake over existing connection)
*/				
		_psTrace("	Resumed Re-handshake test (client initiated)\n");
		if (initializeResumedReHandshake(clnConn, svrConn,
				 ciphers[id].cipherId) < 0) {
				_psTrace("		FAILED: initializing Resumed Re-handshake\n");
			goto LBL_FREE;
		}
		if (performHandshake(clnConn, svrConn) < 0) {
			_psTrace("		FAILED: Resumed Re-handshake\n");
			goto LBL_FREE;
		} else {
			testTrace("		PASSED: Resumed Re-handshake");
			if (exchangeAppData(clnConn, svrConn) < 0) {
				_psTrace(" but FAILED to exchange application data\n");
			} else {
				testTrace("\n");
			}
		}
		
/*
		 Resumed re-handshake initiated by server (fast handshake over conn)
*/		
		_psTrace("	Resumed Re-handshake test (server initiated)\n");
		if (initializeServerInitiatedResumedReHandshake(clnConn, svrConn,
									   ciphers[id].cipherId) < 0) {
				_psTrace("		FAILED: initializing Resumed Re-handshake\n");
			goto LBL_FREE;
		}
		if (performHandshake(svrConn, clnConn) < 0) {
			_psTrace("		FAILED: Resumed Re-handshake\n");
			goto LBL_FREE;
		} else {
			testTrace("		PASSED: Resumed Re-handshake");
			if (exchangeAppData(clnConn, svrConn) < 0) {
				_psTrace(" but FAILED to exchange application data\n");
			} else {
				testTrace("\n");
			}
		}		
/*
		Re-handshaking with "upgraded" parameters
*/
		_psTrace("	Change cert callback Re-handshake test\n");
		if (initializeUpgradeCertCbackReHandshake(clnConn, svrConn,
									   ciphers[id].cipherId) < 0) {
				_psTrace("		FAILED: init upgrade certCback Re-handshake\n");
			goto LBL_FREE;
		}
		if (performHandshake(clnConn, svrConn) < 0) {
			_psTrace("		FAILED: Upgrade cert callback Re-handshake\n");
			goto LBL_FREE;
		} else {
			testTrace("		PASSED: Upgrade cert callback Re-handshake");
			if (exchangeAppData(clnConn, svrConn) < 0) {
				_psTrace(" but FAILED to exchange application data\n");
			} else {
				testTrace("\n");
			}
		}		
/*
		Upgraded keys
*/
		_psTrace("	Change keys Re-handshake test\n");
		if (initializeUpgradeKeysReHandshake(clnConn, svrConn,
									   ciphers[id].cipherId) < 0) {
				_psTrace("		FAILED: init upgrade keys Re-handshake\n");
			goto LBL_FREE;
		}
		if (performHandshake(clnConn, svrConn) < 0) {
			_psTrace("		FAILED: Upgrade keys Re-handshake\n");
			goto LBL_FREE;
		} else {
			testTrace("		PASSED: Upgrade keys Re-handshake");
			if (exchangeAppData(clnConn, svrConn) < 0) {
				_psTrace(" but FAILED to exchange application data\n");
			} else {
				testTrace("\n");
			}
		}
/*
		Change cipher spec test.  Changing to a hardcoded RSA suite so this
		will not work on suites that don't have RSA material loaded
*/
		if (ciphers[id].rsa == 1) {
			_psTrace("	Change cipher suite Re-handshake test\n");
			if (initializeChangeCipherReHandshake(clnConn, svrConn,
									   ciphers[id].cipherId) < 0) {
					_psTrace("		FAILED: init change cipher Re-handshake\n");
				goto LBL_FREE;
			}
			if (performHandshake(clnConn, svrConn) < 0) {
				_psTrace("		FAILED: Change cipher suite Re-handshake\n");
				goto LBL_FREE;
			} else {
				testTrace("		PASSED: Change cipher suite Re-handshake");
				if (exchangeAppData(clnConn, svrConn) < 0) {
					_psTrace(" but FAILED to exchange application data\n");
				} else {
					testTrace("\n");
				}
			}
		}
#endif /* !SSL_REHANDSHAKES_ENABLED */


LBL_FREE:
		freeSessionAndConnection(svrConn);
		freeSessionAndConnection(clnConn);
	}
	psFree(svrConn);
	psFree(clnConn);
	matrixSslClose();

#ifdef WIN32
	_psTrace("Press any key to close");
	getchar();
#endif

	return PS_SUCCESS;	
}
Beispiel #13
0
/*
	Non-blocking socket event handler
	Wait one time in select for events on any socket
	This will accept new connections, read and write to sockets that are
	connected, and close sockets as required.
 */
static int32 selectLoop(sslKeys_t *keys, SOCKET lfd)
{
	httpConn_t		*cp;
	psTime_t		now;
	DLListEntry		connsTmp;
	DLListEntry		*pList;
	
	fd_set			readfd, writefd;
	struct timeval	timeout;
	SOCKET			fd, maxfd;
	
	unsigned char	*buf;
	int32			rc, len, transferred, val;
	unsigned char	rSanity, wSanity, acceptSanity;
	
	sslSessOpts_t	options;
	
	DLListInit(&connsTmp);
	rc = PS_SUCCESS;
	maxfd = INVALID_SOCKET;
	timeout.tv_sec = SELECT_TIME / 1000;
	timeout.tv_usec = (SELECT_TIME % 1000) * 1000;
	FD_ZERO(&readfd);
	FD_ZERO(&writefd);
	
	/* Always set readfd for listening socket */
	FD_SET(lfd, &readfd);
	if (lfd > maxfd) {
		maxfd = lfd;
	}
/*	
	Check timeouts and set readfd and writefd for connections as required.
	We use connsTemp so that removal on error from the active iteration list
		doesn't interfere with list traversal 
 */
	psGetTime(&now, NULL);
	while (!DLListIsEmpty(&g_conns)) {
		pList = DLListGetHead(&g_conns);
		cp = DLListGetContainer(pList, httpConn_t, List);
		DLListInsertTail(&connsTmp, &cp->List);
		/*	If timeout != 0 msec ith no new data, close */
		if (cp->timeout && (psDiffMsecs(cp->time, now, NULL) >
				(int32)cp->timeout)) {
			closeConn(cp, PS_TIMEOUT_FAIL);
			continue;	/* Next connection */
		}
		/* Always select for read */
		FD_SET(cp->fd, &readfd);
		/* Select for write if there's pending write data or connection */
		if (matrixSslGetOutdata(cp->ssl, NULL) > 0) {
			FD_SET(cp->fd, &writefd);
		}
		/* Housekeeping for maxsock in select call */
		if (cp->fd > maxfd) {
			maxfd = cp->fd;
		}
	}
	
	/* Use select to check for events on the sockets */
	if ((val = select(maxfd + 1, &readfd, &writefd, NULL, &timeout)) <= 0) {
		/* On error, restore global connections list */
		while (!DLListIsEmpty(&connsTmp)) {
			pList = DLListGetHead(&connsTmp);
			cp = DLListGetContainer(pList, httpConn_t, List);
			DLListInsertTail(&g_conns, &cp->List);
		}
		/* Select timeout */
		if (val == 0) {
			return PS_TIMEOUT_FAIL;
		}
		/* Woke due to interrupt */
		if (SOCKET_ERRNO == EINTR) {
			return PS_TIMEOUT_FAIL;
		}
		/* Should attempt to handle more errnos, such as EBADF */
		return PS_PLATFORM_FAIL;
	}
	
	/* Check listener for new incoming socket connections */
	if (FD_ISSET(lfd, &readfd)) {
		for (acceptSanity = 0; acceptSanity < ACCEPT_QUEUE; acceptSanity++) {
			fd = accept(lfd, NULL, NULL);
			if (fd == INVALID_SOCKET) {
				break;	/* Nothing more to accept; next listener */
			}
			setSocketOptions(fd);
			cp = malloc(sizeof(httpConn_t));
			memset(cp, 0x0, sizeof(httpConn_t));
			
			memset(&options, 0x0, sizeof(sslSessOpts_t));
			options.versionFlag = g_proto;
			options.userPtr = keys; /* Just a test */
			//options.truncHmac = -1;
			//options.maxFragLen = -1;
			//options.ecFlags |= SSL_OPT_SECP521R1;
			//options.ecFlags |= SSL_OPT_SECP224R1;
			//options.ecFlags |= SSL_OPT_SECP384R1;
			
			
			if ((rc = matrixSslNewServerSession(&cp->ssl, keys, certCb,
					&options)) < 0) {
				close(fd); fd = INVALID_SOCKET;
				continue;
			}
			
#ifdef USE_SERVER_NAME_INDICATION
			/* Register extension callbacks to manage client connection opts */
			matrixSslRegisterSNICallback(cp->ssl, SNI_callback);
#endif
#ifdef USE_ALPN
			matrixSslRegisterALPNCallback(cp->ssl, ALPN_callback);
#endif
			
			cp->fd = fd;
			fd = INVALID_SOCKET;
			cp->timeout = SSL_TIMEOUT;
			psGetTime(&cp->time, NULL);
			cp->parsebuf = NULL;
			cp->parsebuflen = 0;
			DLListInsertTail(&connsTmp, &cp->List);
			/* Fake that there is read data available, no harm if there isn't */
			FD_SET(cp->fd, &readfd);
/*			_psTraceInt("=== New Client %d ===\n", cp->fd); */
		}
	}
	
	/* Check each connection for read/write activity */
	while (!DLListIsEmpty(&connsTmp)) {
		pList = DLListGetHead(&connsTmp);
		cp = DLListGetContainer(pList, httpConn_t, List);
		DLListInsertTail(&g_conns, &cp->List);
		
		rSanity = wSanity = 0;
/*
		See if there's pending data to send on this connection
		We could use FD_ISSET, but this is more reliable for the current
			state of data to send.
 */
WRITE_MORE:
		if ((len = matrixSslGetOutdata(cp->ssl, &buf)) > 0) {
			/* Could get a EWOULDBLOCK since we don't check FD_ISSET */
			transferred = send(cp->fd, buf, len, MSG_DONTWAIT);
			if (transferred <= 0) {
#ifdef WIN32
				if (SOCKET_ERRNO != EWOULDBLOCK &&
					SOCKET_ERRNO != WSAEWOULDBLOCK) {

#else
				if (SOCKET_ERRNO != EWOULDBLOCK) {
#endif
					closeConn(cp, PS_PLATFORM_FAIL);
					continue;	/* Next connection */
				}
			} else {
				/* Indicate that we've written > 0 bytes of data */
				if ((rc = matrixSslSentData(cp->ssl, transferred)) < 0) {
					closeConn(cp, PS_ARG_FAIL);
					continue;	/* Next connection */
				}
				if (rc == MATRIXSSL_REQUEST_CLOSE) {
					closeConn(cp, MATRIXSSL_REQUEST_CLOSE);
					continue;	/* Next connection */
				} else if (rc == MATRIXSSL_HANDSHAKE_COMPLETE) {
					/* If the protocol is server initiated, send data here */
#ifdef ENABLE_FALSE_START					
					/* OR this could be a Chrome browser using 
						FALSE_START and the application data is already
						waiting in our inbuf for processing */
					if ((rc = matrixSslReceivedData(cp->ssl, 0,
								&buf, (uint32*)&len)) < 0) {
							closeConn(cp, 0);
							continue;	/* Next connection */
					}
					if (rc > 0) { /* There was leftover data */
						goto PROCESS_MORE;
					}
#endif /* ENABLE_FALSE_START  */
					
				}
				/* Update activity time */
				psGetTime(&cp->time, NULL);
				/* Try to send again if more data to send */
				if (rc == MATRIXSSL_REQUEST_SEND || transferred < len) {
					if (wSanity++ < GOTO_SANITY) goto WRITE_MORE;
				}
			}
		} else if (len < 0) {
			closeConn(cp, PS_ARG_FAIL);
			continue;	/* Next connection */
		}
		
/*
		Check the file descriptor returned from select to see if the connection
		has data to be read
 */
		if (FD_ISSET(cp->fd, &readfd)) {
READ_MORE:
			/* Get the ssl buffer and how much data it can accept */
			/* Note 0 is a return failure, unlike with matrixSslGetOutdata */
			if ((len = matrixSslGetReadbuf(cp->ssl, &buf)) <= 0) {
				closeConn(cp, PS_ARG_FAIL);
				continue;	/* Next connection */
			}
			if ((transferred = recv(cp->fd, buf, len, MSG_DONTWAIT)) < 0) {
				/* We could get EWOULDBLOCK despite the FD_ISSET on goto  */
#ifdef WIN32
				if (SOCKET_ERRNO != EWOULDBLOCK &&
					SOCKET_ERRNO != WSAEWOULDBLOCK) {

#else
				if (SOCKET_ERRNO != EWOULDBLOCK) {
#endif
					closeConn(cp, PS_PLATFORM_FAIL);
				}
				continue;	/* Next connection */
			}
			
			/* If EOF, remote socket closed. This is semi-normal closure.
			   Officially, we should close on closure alert. */
			if (transferred == 0) {
/*				psTraceIntInfo("Closing connection %d on EOF\n", cp->fd); */
				closeConn(cp, 0);
				continue;	/* Next connection */
			}
/*
			Notify SSL state machine that we've received more data into the
			ssl buffer retreived with matrixSslGetReadbuf.
 */
			if ((rc = matrixSslReceivedData(cp->ssl, (int32)transferred, &buf, 
											(uint32*)&len)) < 0) {
				closeConn(cp, 0);
				continue;	/* Next connection */
			}
			/* Update activity time */
			psGetTime(&cp->time, NULL);
			
PROCESS_MORE:
			/* Process any incoming plaintext application data */
			switch (rc) {
				case MATRIXSSL_HANDSHAKE_COMPLETE:
					/* If the protocol is server initiated, send data here */
					goto READ_MORE;
				case MATRIXSSL_APP_DATA:
				case MATRIXSSL_APP_DATA_COMPRESSED:
					//psTraceBytes("DATA", buf, len);
					/* Remember, must handle if len == 0! */
					if ((rc = httpBasicParse(cp, buf, len, 0)) < 0) {
						_psTrace("Couldn't parse HTTP data.  Closing conn.\n");
						closeConn(cp, PS_PROTOCOL_FAIL);
						continue; /* Next connection */
					}
					if (cp->parsebuf != NULL) {
						/* Test for one of our custom testing messages */
						if (strncmp((const char*)cp->parsebuf,
								"MATRIX_SHUTDOWN", 15) == 0) {
							g_exitFlag = 1;
							matrixSslEncodeClosureAlert(cp->ssl);
							_psTrace("Got MATRIX_SHUTDOWN.  Exiting\n");
							goto WRITE_MORE;
						}
						
					}
					/* reply to /bytes?<byte count> syntax */
					if (len > 11 &&
							strncmp((char *)buf, "GET /bytes?", 11) == 0) {
						cp->bytes_requested = atoi((char *)buf + 11);
						if (cp->bytes_requested <
								strlen((char *)g_httpResponseHdr) ||
								cp->bytes_requested > 1073741824) {
                			cp->bytes_requested =
								strlen((char *)g_httpResponseHdr);
            			}
						cp->bytes_sent = 0;
					}
					if (rc == HTTPS_COMPLETE) {
						if (httpWriteResponse(cp) < 0) {
							closeConn(cp, PS_PROTOCOL_FAIL);
							continue; /* Next connection */
						}
						/* For HTTP, we assume no pipelined requests, so we 
						 close after parsing a single HTTP request */
						/* Ignore return of closure alert, it's optional */
						matrixSslEncodeClosureAlert(cp->ssl);
						rc = matrixSslProcessedData(cp->ssl, &buf, (uint32*)&len);
						if (rc > 0) {
							/* Additional data is available, but we ignore it */
							_psTrace("HTTP data parsing not supported, ignoring.\n");
							closeConn(cp, PS_SUCCESS);
							continue; /* Next connection */
						} else if (rc < 0) {
							closeConn(cp, PS_PROTOCOL_FAIL);
							continue; /* Next connection */
						}
						/* rc == 0, write out our response and closure alert */
						goto WRITE_MORE;
					}
					/* We processed a partial HTTP message */
					if ((rc = matrixSslProcessedData(cp->ssl, &buf, (uint32*)&len)) == 0) {
						goto READ_MORE;
					}
					goto PROCESS_MORE;
				case MATRIXSSL_REQUEST_SEND:
					/* Prevent us from reading again after the write,
					 although that wouldn't be the end of the world */
					FD_CLR(cp->fd, &readfd);
					if (wSanity++ < GOTO_SANITY) goto WRITE_MORE;
					break;
				case MATRIXSSL_REQUEST_RECV:
					if (rSanity++ < GOTO_SANITY) goto READ_MORE; 
					break;
				case MATRIXSSL_RECEIVED_ALERT:
					/* The first byte of the buffer is the level */
					/* The second byte is the description */
					if (*buf == SSL_ALERT_LEVEL_FATAL) {
						psTraceIntInfo("Fatal alert: %d, closing connection.\n", 
									*(buf + 1));
						closeConn(cp, PS_PROTOCOL_FAIL);
						continue; /* Next connection */
					}
					/* Closure alert is normal (and best) way to close */
					if (*(buf + 1) == SSL_ALERT_CLOSE_NOTIFY) {
						closeConn(cp, PS_SUCCESS);
						continue; /* Next connection */
					}
					psTraceIntInfo("Warning alert: %d\n", *(buf + 1));
					if ((rc = matrixSslProcessedData(cp->ssl, &buf, (uint32*)&len)) == 0) {
						/* No more data in buffer. Might as well read for more. */
						goto READ_MORE;
					}
					goto PROCESS_MORE;

				default:
					/* If rc <= 0 we fall here */
					closeConn(cp, PS_PROTOCOL_FAIL);
					continue; /* Next connection */
			}
			/* Always try to read more if we processed some data */
			if (rSanity++ < GOTO_SANITY) goto READ_MORE;
		} /*  readfd handling */
	}	/* connection loop */
	return PS_SUCCESS;
}

/******************************************************************************/
/*
	Create an HTTP response and encode it to the SSL buffer
 */
#define	TEST_SIZE	16000
static int32 httpWriteResponse(httpConn_t *conn)
{
	unsigned char	*buf;
	ssl_t			*cp;
	int32			available, len, rc;

		
	cp = conn->ssl;
	if (conn->bytes_requested) {
		/* The /bytes? syntax */
		while (conn->bytes_sent < conn->bytes_requested) {
			len = conn->bytes_requested - conn->bytes_sent;
			if (len > RESPONSE_REC_LEN) {
				len = RESPONSE_REC_LEN;
    		}
			psAssert(len > 0);
			rc = matrixSslGetWritebuf(cp, &buf, len);
			if (rc < len) {
				len = rc; /* could have been shortened due to max_frag */
			}
			memset(buf, 'J', len);
			if (conn->bytes_sent == 0) {
				/* Overwrite first N bytes with HTTP header the first time */
				strncpy((char *)buf, (char *)g_httpResponseHdr,
					strlen((char*)g_httpResponseHdr));
			}
			if ((rc = matrixSslEncodeWritebuf(cp, len)) < 0) {
				printf("couldn't encode data %d\n", rc);
    		}
			conn->bytes_sent += len;
    	}
		return MATRIXSSL_REQUEST_SEND;
	}

	/* Usual reply */

	if ((available = matrixSslGetWritebuf(cp, &buf, 
			(uint32)strlen((char *)g_httpResponseHdr) + 1)) < 0) {
		return PS_MEM_FAIL;
	}
	strncpy((char *)buf, (char *)g_httpResponseHdr, available);
	//psTraceBytes("Replying", buf, (uint32)strlen((char *)buf));
	if (matrixSslEncodeWritebuf(cp, (uint32)strlen((char *)buf)) < 0) {
		return PS_MEM_FAIL;
	}
	return MATRIXSSL_REQUEST_SEND;
}

/******************************************************************************/
/*
	Main non-blocking SSL server
	Initialize MatrixSSL and sockets layer, and loop on select
 */
int32 main(int32 argc, char **argv)
{
	sslKeys_t		*keys;
	SOCKET			lfd;
	unsigned char	*CAstream;
	int32			err, rc, CAstreamLen;
#ifdef USE_STATELESS_SESSION_TICKETS
	unsigned char	randKey[16];
#endif

#ifdef WIN32
	WSADATA			wsaData;
	WSAStartup(MAKEWORD(1, 1), &wsaData);
#endif


	keys = NULL;
	DLListInit(&g_conns);
	g_exitFlag = 0;
	lfd = INVALID_SOCKET;
	
#ifdef POSIX
	if (sighandlers() < 0) {
		return PS_PLATFORM_FAIL;
	}
#endif	/* POSIX */
	if ((rc = matrixSslOpen()) < 0) {
		_psTrace("MatrixSSL library init failure.  Exiting\n");
		return rc;
	}

	if (matrixSslNewKeys(&keys, NULL) < 0) {
		_psTrace("MatrixSSL library key init failure.  Exiting\n");
		return -1;
	}
	
#ifdef USE_STATELESS_SESSION_TICKETS
	matrixSslSetSessionTicketCallback(keys, sessTicketCb);
	psGetEntropy(randKey, 16, NULL);
	if (matrixSslLoadSessionTicketKeys(keys, randKey,
			sessTicketSymKey, 32, sessTicketMacKey, 32) < 0) {
		_psTrace("Error loading session ticket encryption key\n");
	}
#endif

#ifdef USE_HEADER_KEYS
/*
	In-memory based keys
	Build the CA list first for potential client auth usage
*/
	CAstreamLen = 0;
#ifdef USE_RSA
	CAstreamLen += sizeof(RSACAS);
#ifdef USE_ECC
	CAstreamLen += sizeof(ECDHRSACAS);
#endif
#endif
#ifdef USE_ECC
	CAstreamLen += sizeof(ECCAS);
#endif
	CAstream = psMalloc(NULL, CAstreamLen);
	
	CAstreamLen = 0;
#ifdef USE_RSA
	memcpy(CAstream, RSACAS, sizeof(RSACAS));
	CAstreamLen += sizeof(RSACAS);
#ifdef USE_ECC
	memcpy(CAstream + CAstreamLen, ECDHRSACAS, sizeof(ECDHRSACAS));
	CAstreamLen += sizeof(ECDHRSACAS);
#endif
#endif
#ifdef USE_ECC
	memcpy(CAstream + CAstreamLen, ECCAS,	sizeof(ECCAS));
	CAstreamLen += sizeof(ECCAS);
#endif
		
#ifdef EXAMPLE_RSA_KEYS
	if ((rc = matrixSslLoadRsaKeysMem(keys, RSA1024, sizeof(RSA1024),
			RSA1024KEY, sizeof(RSA1024KEY), CAstream, CAstreamLen)) < 0) {
		_psTrace("No certificate material loaded.  Exiting\n");
		psFree(CAstream, NULL);
		matrixSslDeleteKeys(keys);
		matrixSslClose();
		return rc;
	}
#endif

#ifdef EXAMPLE_ECDH_RSA_KEYS
	if ((rc = matrixSslLoadEcKeysMem(keys, ECDHRSA256, sizeof(ECDHRSA256),
				   ECDHRSA256KEY, sizeof(ECDHRSA256KEY), CAstream,
				   CAstreamLen)) < 0) {
		_psTrace("No certificate material loaded.  Exiting\n");
		psFree(CAstream, NULL);
		matrixSslDeleteKeys(keys);
		matrixSslClose();
		return rc;
	}
#endif

#ifdef EXAMPLE_EC_KEYS
	if ((rc = matrixSslLoadEcKeysMem(keys, EC521, sizeof(EC521),
			EC521KEY, sizeof(EC521KEY), CAstream, CAstreamLen)) < 0) {
//	if ((rc = matrixSslLoadEcKeysMem(keys, EC256, sizeof(EC256),
//			EC256KEY, sizeof(EC256KEY), CAstream, CAstreamLen)) < 0) {
//	if ((rc = matrixSslLoadEcKeysMem(keys, EC192, sizeof(EC192),
//			EC192KEY, sizeof(EC192KEY), CAstream, CAstreamLen)) < 0) {
		_psTrace("No certificate material loaded.  Exiting\n");
		psFree(CAstream, NULL);
		matrixSslDeleteKeys(keys);
		matrixSslClose();
		return rc;
	}
#endif
	
#ifdef REQUIRE_DH_PARAMS
	if (matrixSslLoadDhParamsMem(keys, dhParamBuf1024, sizeof(dhParamBuf1024))
			< 0){
		_psTrace("Unable to load DH parameters\n");
	}
#endif /* DH_PARAMS */

	psFree(CAstream, NULL);
#else /* USE_HEADER_KEYS */
/*
	File based keys
	Build the CA list first for potential client auth usage
*/
	CAstreamLen = 0;
#ifdef USE_RSA
	CAstreamLen += (int32)strlen(rsaCAFile) + 1;
#ifdef USE_ECC
	CAstreamLen += (int32)strlen(ecdhRsaCAFile) + 1;
#endif
#endif
#ifdef USE_ECC
	CAstreamLen += (int32)strlen(ecCAFile) + 1;
#endif		
	CAstream = psMalloc(NULL, CAstreamLen);
	memset(CAstream, 0x0, CAstreamLen);
	
	CAstreamLen = 0;
#ifdef USE_RSA	
	memcpy(CAstream, rsaCAFile,	strlen(rsaCAFile));
	CAstreamLen += strlen(rsaCAFile);
#ifdef USE_ECC
	memcpy(CAstream + CAstreamLen, ";", 1); CAstreamLen++;
	memcpy(CAstream + CAstreamLen, ecdhRsaCAFile,  strlen(ecdhRsaCAFile));
	CAstreamLen += strlen(ecdhRsaCAFile);
#endif
#endif
#ifdef USE_ECC
	if (CAstreamLen > 0) {
		memcpy(CAstream + CAstreamLen, ";", 1); CAstreamLen++;
	}
	memcpy(CAstream + CAstreamLen, ecCAFile,  strlen(ecCAFile));
#endif
	
/* Load Identiy */	
#ifdef EXAMPLE_RSA_KEYS	
	if ((rc = matrixSslLoadRsaKeys(keys, rsaCertFile, rsaPrivkeyFile, NULL,
			(char*)CAstream)) < 0) {
		_psTrace("No certificate material loaded.  Exiting\n");
		psFree(CAstream, NULL);
		matrixSslDeleteKeys(keys);
		matrixSslClose();
		return rc;
	}
#endif	

#ifdef EXAMPLE_ECDH_RSA_KEYS
	if ((rc = matrixSslLoadEcKeys(keys, ecdhRsaCertFile, ecdhRsaPrivkeyFile,
			NULL, (char*)CAstream)) < 0) {
		_psTrace("No certificate material loaded.  Exiting\n");
		psFree(CAstream, NULL);
		matrixSslDeleteKeys(keys);
		matrixSslClose();
		return rc;
	}
#endif

#ifdef EXAMPLE_EC_KEYS
	if ((rc = matrixSslLoadEcKeys(keys, ecCertFile, ecPrivkeyFile, NULL,
			(char*)CAstream)) < 0) {
		_psTrace("No certificate material loaded.  Exiting\n");
		psFree(CAstream, NULL);
		matrixSslDeleteKeys(keys);
		matrixSslClose();
		return rc;
	}
#endif
	
#ifdef REQUIRE_DH_PARAMS
	if (matrixSslLoadDhParams(keys, dhParamFile) < 0){
		_psTrace("Unable to load DH parameters\n");
	}
#endif

	psFree(CAstream, NULL);
#endif /* USE_HEADER_KEYS */

#ifdef USE_PSK_CIPHER_SUITE
	/* The first one supports the 15-byte openssl PSK ID */
	matrixSslLoadPsk(keys, pskTable[0].key, sizeof(pskTable[0].key),
		pskTable[rc].id, 15);
	for (rc = 0; rc < 8; rc++) {   
		matrixSslLoadPsk(keys, pskTable[rc].key, sizeof(pskTable[rc].key),
			pskTable[rc].id, sizeof(pskTable[rc].id));
	}
#endif /* PSK */

	if (argc == 2) {
		switch (atoi(argv[1])) {
		case 0:
			g_proto = SSL_FLAGS_SSLV3;
			break;
		case 1:
			g_proto = SSL_FLAGS_TLS_1_0;
			break;
		case 2:
			g_proto = SSL_FLAGS_TLS_1_1;
			break;
		case 3:
			g_proto = SSL_FLAGS_TLS_1_2;
			break;
		default:
			g_proto = SSL_FLAGS_TLS_1_0;
			break;
		}
	} else {
		g_proto = 0;
	}
	/* Create the listening socket that will accept incoming connections */
	if ((lfd = socketListen(HTTPS_PORT, &err)) == INVALID_SOCKET) {
		_psTraceInt("Can't listen on port %d\n", HTTPS_PORT);
		goto L_EXIT;
	}

	/* Main select loop to handle sockets events */
	while (!g_exitFlag) {
		selectLoop(keys, lfd);
	}

L_EXIT:
	if (lfd != INVALID_SOCKET) close(lfd);
	if (keys) matrixSslDeleteKeys(keys);
	matrixSslClose();
	
	return 0;
}
Beispiel #14
0
/*
	Main
*/
int main(int argc, char ** argv)
{
	struct sockaddr_in	inaddr;
	socklen_t		inaddrlen;
	struct timeval	timeout;
	ssl_t			*ssl;
	serverDtls_t	*dtlsCtx;
	SOCKET			sock;
	fd_set			readfd;
	unsigned char	*sslBuf, *recvfromBuf, *CAstream;
#ifdef USE_DTLS_DEBUG_TRACE	
	unsigned char   *addrstr;
#endif
#if !defined(ID_PSK) && !defined(ID_DHE_PSK)
	unsigned char   *keyValue, *certValue;
	int32           keyLen, certLen;
#endif	
	sslKeys_t		*keys;
	int32			freeBufLen, rc, val, recvLen, err, CAstreamLen;
	int32			sslBufLen, rcr, rcs, sendLen, recvfromBufLen;
	sslSessOpts_t	options;

#ifdef WIN32
	WSADATA         wsaData;
	WSAStartup(MAKEWORD(1, 1), &wsaData);
#endif

	rc = 0;
	ssl = NULL;
	dtlsCtx = NULL;
	sock = INVALID_SOCKET;

	/* parse input arguments */
	if (0 != process_cmd_options(argc, argv)) {
		usage();
		return 0;
	}

	if (sigsetup() < 0) {
		_psTrace("Init error creating signal handlers\n");
		return DTLS_FATAL;
	}

	if (matrixSslOpen() < 0) {
		_psTrace("Init error opening MatrixDTLS library\n");
		return DTLS_FATAL;
	}
	if (matrixSslNewKeys(&keys, NULL) < 0) {
		_psTrace("Init error allocating key structure\n");
		matrixSslClose();
		return DTLS_FATAL;
	}

	if ((rc = initClientList(MAX_CLIENTS)) < 0) {
		_psTrace("Init error opening client list\n");
		goto MATRIX_EXIT;
	}

	recvfromBufLen = matrixDtlsGetPmtu();
	if ((recvfromBuf = psMalloc(MATRIX_NO_POOL, recvfromBufLen)) == NULL) {
		rc = PS_MEM_FAIL;
		_psTrace("Init error allocating receive buffer\n");
		goto CLIENT_EXIT;
	}

#ifdef USE_HEADER_KEYS
/*
	In-memory based keys
	Build the CA list first for potential client auth usage
*/
	CAstreamLen = 0;
#ifdef USE_RSA
	CAstreamLen += sizeof(RSACAS);
#ifdef USE_ECC
	CAstreamLen += sizeof(ECDHRSACAS);
#endif
#endif
#ifdef USE_ECC
	CAstreamLen += sizeof(ECCAS);
#endif
	CAstream = psMalloc(NULL, CAstreamLen);

	CAstreamLen = 0;
#ifdef USE_RSA
	memcpy(CAstream, RSACAS, sizeof(RSACAS));
	CAstreamLen += sizeof(RSACAS);
#ifdef USE_ECC
	memcpy(CAstream + CAstreamLen, ECDHRSACAS, sizeof(ECDHRSACAS));
	CAstreamLen += sizeof(ECDHRSACAS);
#endif
#endif
#ifdef USE_ECC
	memcpy(CAstream + CAstreamLen, ECCAS, sizeof(ECCAS));
	CAstreamLen += sizeof(ECCAS);
#endif

#ifdef EXAMPLE_RSA_KEYS
	switch (g_rsaKeySize) {
		case 1024:
			certValue = (unsigned char *)RSA1024;
			certLen = sizeof(RSA1024);
			keyValue = (unsigned char *)RSA1024KEY;
			keyLen = sizeof(RSA1024KEY);
			break;
		case 2048:
			certValue = (unsigned char *)RSA2048;
			certLen = sizeof(RSA2048);
			keyValue = (unsigned char *)RSA2048KEY;
			keyLen = sizeof(RSA2048KEY);
			break;
		case 3072:
			certValue = (unsigned char *)RSA3072;
			certLen = sizeof(RSA3072);
			keyValue = (unsigned char *)RSA3072KEY;
			keyLen = sizeof(RSA3072KEY);
			break;
		case 4096:
			certValue = (unsigned char *)RSA4096;
			certLen = sizeof(RSA4096);
			keyValue = (unsigned char *)RSA4096KEY;
			keyLen = sizeof(RSA4096KEY);
			break;
		default:
			_psTraceInt("Invalid RSA key length (%d)\n", g_rsaKeySize);
			return -1;
	}

	if ((rc = matrixSslLoadRsaKeysMem(keys, (const unsigned char *)certValue,
			certLen, (const unsigned char *)keyValue, keyLen, CAstream,
			CAstreamLen)) < 0) {
		_psTrace("No certificate material loaded.  Exiting\n");
		psFree(CAstream, NULL);
		matrixSslDeleteKeys(keys);
		matrixSslClose();
		return rc;
	}
#endif


#ifdef EXAMPLE_ECDH_RSA_KEYS
	switch (g_ecdhKeySize) {
		case 256:
			certValue = (unsigned char *)ECDHRSA256;
			certLen = sizeof(ECDHRSA256);
			keyValue = (unsigned char *)ECDHRSA256KEY;
			keyLen = sizeof(ECDHRSA256KEY);
			break;
		case 521:
			certValue = (unsigned char *)ECDHRSA521;
			certLen = sizeof(ECDHRSA521);
			keyValue = (unsigned char *)ECDHRSA521KEY;
			keyLen = sizeof(ECDHRSA521KEY);
			break;
		default:
			_psTraceInt("Invalid ECDH_RSA key length (%d)\n", g_ecdhKeySize);
			return -1;
	}

	if ((rc = matrixSslLoadEcKeysMem(keys, (const unsigned char *)certValue,
				certLen, (const unsigned char *)keyValue, keyLen, CAstream,
				CAstreamLen)) < 0) {
		_psTrace("No certificate material loaded.  Exiting\n");
		psFree(CAstream, NULL);
		matrixSslDeleteKeys(keys);
		matrixSslClose();
		return rc;
	}
#endif

#ifdef EXAMPLE_EC_KEYS
	switch (g_eccKeySize) {
		case 192:
			certValue = (unsigned char *)EC192;
			certLen = sizeof(EC192);
			keyValue = (unsigned char *)EC192KEY;
			keyLen = sizeof(EC192KEY);
			break;
		case 224:
			certValue = (unsigned char *)EC224;
			certLen = sizeof(EC224);
			keyValue = (unsigned char *)EC224KEY;
			keyLen = sizeof(EC224KEY);
			break;
		case 256:
			certValue = (unsigned char *)EC256;
			certLen = sizeof(EC256);
			keyValue = (unsigned char *)EC256KEY;
			keyLen = sizeof(EC256KEY);
			break;
		case 384:
			certValue = (unsigned char *)EC384;
			certLen = sizeof(EC384);
			keyValue = (unsigned char *)EC384KEY;
			keyLen = sizeof(EC384KEY);
			break;
		case 521:
			certValue = (unsigned char *)EC521;
			certLen = sizeof(EC521);
			keyValue = (unsigned char *)EC521KEY;
			keyLen = sizeof(EC521KEY);
			break;
		default:
			_psTraceInt("Invalid ECC key length (%d)\n", g_eccKeySize);
			return -1;
	}

	if ((rc = matrixSslLoadEcKeysMem(keys, certValue, certLen,
			keyValue, keyLen, CAstream, CAstreamLen)) < 0) {
		_psTrace("No certificate material loaded.  Exiting\n");
		psFree(CAstream, NULL);
		matrixSslDeleteKeys(keys);
		matrixSslClose();
		return rc;
	}
#endif

#ifdef REQUIRE_DH_PARAMS
	if (matrixSslLoadDhParamsMem(keys, DHPARAM2048, DHPARAM2048_SIZE)
			< 0) {
		_psTrace("Unable to load DH parameters\n");
	}
#endif /* DH_PARAMS */


	psFree(CAstream, NULL);
#else /* USE_HEADER_KEYS */
/*
	File based keys
	Build the CA list first for potential client auth usage
*/
	CAstreamLen = 0;
#ifdef USE_RSA
	if (g_rsaKeySize == 3072)
		CAstreamLen += (int32)strlen(rsaCA3072File) + 1;
	else
		CAstreamLen += (int32)strlen(rsaCAFile) + 1;
#ifdef USE_ECC
	CAstreamLen += (int32)strlen(ecdhRsaCAFile) + 1;
#endif
#endif
#ifdef USE_ECC
	CAstreamLen += (int32)strlen(ecCAFile) + 1;
#endif
	CAstream = psMalloc(NULL, CAstreamLen);
	memset(CAstream, 0x0, CAstreamLen);

	CAstreamLen = 0;
#ifdef USE_RSA
	if (g_rsaKeySize == 3072) {
		memcpy(CAstream, rsaCA3072File,	strlen(rsaCA3072File));
		CAstreamLen += strlen(rsaCA3072File);
	}
	else {
		memcpy(CAstream, rsaCAFile,	strlen(rsaCAFile));
		CAstreamLen += strlen(rsaCAFile);
	}
#ifdef USE_ECC
	memcpy(CAstream + CAstreamLen, ";", 1); CAstreamLen++;
	memcpy(CAstream + CAstreamLen, ecdhRsaCAFile,  strlen(ecdhRsaCAFile));
	CAstreamLen += strlen(ecdhRsaCAFile);
#endif
#endif
#ifdef USE_ECC
	if (CAstreamLen > 0) {
		memcpy(CAstream + CAstreamLen, ";", 1); CAstreamLen++;
	}
	memcpy(CAstream + CAstreamLen, ecCAFile,  strlen(ecCAFile));
#endif

/* Load Identiy */
#ifdef EXAMPLE_RSA_KEYS
	if ((rc = matrixSslLoadRsaKeys(keys, rsaCertFile, rsaPrivkeyFile, NULL,
			(char*)CAstream)) < 0) {
		_psTrace("No certificate material loaded.  Exiting\n");
		psFree(CAstream);
		matrixSslDeleteKeys(keys);
		matrixSslClose();
		return rc;
	}
#endif


#ifdef EXAMPLE_ECDH_RSA_KEYS
	if ((rc = matrixSslLoadEcKeys(keys, ecdhRsaCertFile, ecdhRsaPrivkeyFile,
			NULL, (char*)CAstream)) < 0) {
		_psTrace("No certificate material loaded.  Exiting\n");
		psFree(CAstream);
		matrixSslDeleteKeys(keys);
		matrixSslClose();
		return rc;
	}
#endif

#ifdef EXAMPLE_EC_KEYS
	if ((rc = matrixSslLoadEcKeys(keys, ecCertFile, ecPrivkeyFile, NULL,
			(char*)CAstream)) < 0) {
		_psTrace("No certificate material loaded.  Exiting\n");
		psFree(CAstream);
		matrixSslDeleteKeys(keys);
		matrixSslClose();
		return rc;
	}
#endif

#ifdef REQUIRE_DH_PARAMS
	if (matrixSslLoadDhParams(keys, dhParamFile) < 0) {
		_psTrace("Unable to load DH parameters\n");
	}
#endif


	psFree(CAstream);
#endif /* USE_HEADER_KEYS */


#ifdef USE_PSK_CIPHER_SUITE
	/* The first ID is considered as null-terminiated string for
	   compatibility with OpenSSL's s_client default client identity
	   "Client_identity" */

 	matrixSslLoadPsk(keys,
            	PSK_HEADER_TABLE[0].key,
            	sizeof(PSK_HEADER_TABLE[0].key),
            	PSK_HEADER_TABLE[0].id,
            	strlen((const char *)PSK_HEADER_TABLE[0].id));

	for (rc = 1; rc < PSK_HEADER_TABLE_COUNT; rc++) {
        matrixSslLoadPsk(keys,
            	PSK_HEADER_TABLE[rc].key,
            	sizeof(PSK_HEADER_TABLE[rc].key),
            	PSK_HEADER_TABLE[rc].id,
            	sizeof(PSK_HEADER_TABLE[rc].id));
    }
#endif /* PSK */


	if ((sock = newUdpSocket(NULL, DTLS_PORT, &err)) == INVALID_SOCKET) {
		_psTrace("Error creating UDP socket\n");
		goto DTLS_EXIT;
	}
	_psTraceInt("DTLS server running on port %d\n", DTLS_PORT);

/*
	Server loop
*/
	for (exitFlag = 0; exitFlag == 0;) {
		timeout.tv_sec = 1;
		timeout.tv_usec = 0;
		FD_ZERO(&readfd);
		FD_SET(sock, &readfd);
/*
		Always just wait a second for any incoming data.  The primary loop
		mechanism reads data from one source and replies with handshake data
		if needed (that reply may be a resend if reading a repeat message).
		Individual client timeouts are then handled
*/
		val = select(sock+1, &readfd, NULL, NULL, &timeout);

		if (val > 0 && FD_ISSET(sock, &readfd)) {
			psTraceIntDtls("Select woke %d\n", val);
			/* recvfrom data must always go into generic buffer becuase we
			don't yet know who it is from */
			inaddrlen = sizeof(struct sockaddr_in);
			if ((recvLen = (int32)recvfrom(sock, recvfromBuf, recvfromBufLen, 0,
										   (struct sockaddr *)&inaddr, &inaddrlen)) < 0) {
#ifdef WIN32
				if (SOCKET_ERRNO != EWOULDBLOCK &&
						SOCKET_ERRNO != WSAECONNRESET) {
#else
				if (SOCKET_ERRNO != EWOULDBLOCK) {
#endif
					_psTraceInt("recvfrom error %d.  Exiting\n", SOCKET_ERRNO);
					goto DTLS_EXIT;
				}
				continue;
				}
#ifdef USE_DTLS_DEBUG_TRACE
			/* nice for debugging */
			{
				const char *addrstr;
				addrstr = getaddrstring((struct sockaddr *)&inaddr, 1);
				psTraceIntDtls("Read %d bytes ", recvLen);
				psTraceStrDtls("from %s\n", (char*)addrstr);
				psFree(addrstr, NULL);
			}
#endif

			/* Locate the SSL context of this receive and create a new session
			if not found */
			if ((dtlsCtx = findClient(inaddr)) == NULL) {
				memset(&options, 0x0, sizeof(sslSessOpts_t));
				options.versionFlag = SSL_FLAGS_DTLS;
				options.truncHmac = -1;

				if (matrixSslNewServerSession(&ssl, keys,
						certValidator, &options) < 0) {
					rc = DTLS_FATAL; goto DTLS_EXIT;
				}
				if ((dtlsCtx = registerClient(inaddr, sock, ssl)) == NULL) {
					/* Client list is full.  Just have to ignore */
					matrixSslDeleteSession(ssl);
					continue;
				}
			}

			ssl = dtlsCtx->ssl;
			/*  Move socket data into internal buffer */
			freeBufLen = matrixSslGetReadbuf(ssl, &sslBuf);
			psAssert(freeBufLen >= recvLen);
			psAssert(freeBufLen == matrixDtlsGetPmtu());
			memcpy(sslBuf, recvfromBuf, recvLen);

			/*	Notify SSL state machine that we've received more data into the
			ssl buffer retreived with matrixSslGetReadbuf. */
			if ((rcr = matrixSslReceivedData(ssl, recvLen, &sslBuf,
					(uint32*)&freeBufLen)) < 0) {
				clearClient(dtlsCtx);
				continue;	/* Next connection */
			}
			/* Update last activity time and reset timeout*/
			psGetTime(&dtlsCtx->lastRecvTime, NULL);
			dtlsCtx->timeout = MIN_WAIT_SECS;

PROCESS_MORE_FROM_BUFFER:
			/* Process any incoming plaintext application data */
			switch (rcr) {
				case MATRIXSSL_HANDSHAKE_COMPLETE:
					/* This is a resumed handshake case which means we are
					the last to receive handshake flights and we know the
					handshake is complete.  However, the internal workings
					will not flag us officially complete until we receive
					application data from the peer so we need a local flag
					to handle this case so we are not resending our final
					flight */
					dtlsCtx->connStatus = RESUMED_HANDSHAKE_COMPLETE;
					psTraceDtls("Got HANDSHAKE_COMPLETE out of ReceivedData\n");
					break;
				case MATRIXSSL_APP_DATA:
					/* Now safe to clear the connStatus flag that was keeping
					track of the state between receiving the final flight of
					a resumed handshake and receiving application data.  The
					reciept of app data has now internally disabled flight
					resends */
					dtlsCtx->connStatus = 0;
					_psTrace("Client connected.  Received...\n");
					_psTraceStr("%s\n", (char*)sslBuf);
					break;
				case MATRIXSSL_REQUEST_SEND:
					/* Still handshaking with this particular client */
					while ((sslBufLen = matrixDtlsGetOutdata(ssl,
							&sslBuf)) > 0) {
						if ((sendLen = udpSend(dtlsCtx->fd, sslBuf, sslBufLen,
											   (struct sockaddr*)&inaddr,
											   sizeof(struct sockaddr_in),
											   dtlsCtx->timeout,
											   packet_loss_prob,
											   NULL)) < 0) {
							psTraceDtls("udpSend error.  Ignoring\n");
						}
						/* Always indicate the entire datagram was sent as
						there is no way for DTLS to handle partial records.
						Resends and timeouts will handle any problems */
						rcs = matrixDtlsSentData(ssl, sslBufLen);

						if (rcs == MATRIXSSL_REQUEST_CLOSE) {
							psTraceDtls("Got REQUEST_CLOSE out of SentData\n");
							clearClient(dtlsCtx);
							break;
						}
						if (rcs == MATRIXSSL_HANDSHAKE_COMPLETE) {
							/* This is the standard handshake case */
							_psTrace("Got HANDSHAKE_COMPLETE from SentData\n");
							break;
						}
						/* SSL_REQUEST_SEND is handled by loop logic */
					}
					break;
				case MATRIXSSL_REQUEST_RECV:
					psTraceDtls("Got REQUEST_RECV from ReceivedData\n");
					break;
				case MATRIXSSL_RECEIVED_ALERT:
					/* The first byte of the buffer is the level */
					/* The second byte is the description */
					if (*sslBuf == SSL_ALERT_LEVEL_FATAL) {
						psTraceIntDtls("Fatal alert: %d, closing connection.\n",
									*(sslBuf + 1));
						clearClient(dtlsCtx);
						continue; /* Next connection */
					}
					/* Closure alert is normal (and best) way to close */
					if (*(sslBuf + 1) == SSL_ALERT_CLOSE_NOTIFY) {
						clearClient(dtlsCtx);
						continue; /* Next connection */
					}
					psTraceIntDtls("Warning alert: %d\n", *(sslBuf + 1));
					if ((rcr = matrixSslProcessedData(ssl, &sslBuf,
							(uint32*)&freeBufLen)) == 0) {
						continue;
					}
					goto PROCESS_MORE_FROM_BUFFER;

				default:
					continue; /* Next connection */
			}
		} else if (val < 0) {
			if (SOCKET_ERRNO != EINTR) {
				psTraceIntDtls("unhandled error %d from select", SOCKET_ERRNO);
			}
		}
/*
		Have either timed out waiting for a read or have processed a single
		recv.  Now check to see if any timeout resends are required
*/
		rc = handleResends(sock);
	}	/* Main Select Loop */


DTLS_EXIT:
	psFree(recvfromBuf, NULL);
CLIENT_EXIT:
	closeClientList();
MATRIX_EXIT:
	matrixSslDeleteKeys(keys);
	matrixSslClose();
	if (sock != INVALID_SOCKET) close(sock);
	return rc;
}

/******************************************************************************/
/*
	Work through client list and resend handshake flight if haven't heard
	from them in a while
*/
static int32 handleResends(SOCKET sock)
{
	serverDtls_t	*dtlsCtx;
	ssl_t			*ssl;
	psTime_t		now;
	unsigned char	*sslBuf;
	int16			i;
	int32			sendLen, rc;
	uint32			timeout, sslBufLen, clientCount;

	clientCount = 0; /* return code is number of active clients or < 0 on error */
	psGetTime(&now, NULL);
	for (i = 0; i < tableSize; i++) {
		dtlsCtx = &clientTable[i];
		if (dtlsCtx->ssl != NULL) {
			clientCount++;
			timeout = psDiffMsecs(dtlsCtx->lastRecvTime, now, NULL) / 1000;
			/* Haven't heard from this client in a while.  Might need resend */
			if (timeout > dtlsCtx->timeout) {
				/* if timeout is too great. clear conn */
				if (dtlsCtx->timeout >= MAX_WAIT_SECS) {
					clearClient(dtlsCtx);
					clientCount--;
					break;
				}
				/* Increase the timeout for next pass */
				dtlsCtx->timeout *= 2;

				/* If we are in a RESUMED_HANDSHAKE_COMPLETE state that means
				we are positive the handshake is complete so we don't want to
				resend no matter what.  This is an interim state before the
				internal mechaism sees an application data record and flags
				us as complete officially */
				if (dtlsCtx->connStatus == RESUMED_HANDSHAKE_COMPLETE) {
					psTraceDtls("Connected but awaiting data\n");
					continue;
				}
				ssl = dtlsCtx->ssl;
				while ((sslBufLen = matrixDtlsGetOutdata(ssl,
						&sslBuf)) > 0) {
					if ((sendLen = udpSend(dtlsCtx->fd, sslBuf, sslBufLen,
										   (struct sockaddr*)&dtlsCtx->addr,
										   sizeof(struct sockaddr_in),
										   dtlsCtx->timeout / 2,
										   packet_loss_prob,
										   NULL)) < 0) {
						psTraceDtls("udpSend error.  Ignoring\n");
					}
					/* Always indicate the entire datagram was sent as
					there is no way for DTLS to handle partial records.
					Resends and timeouts will handle any problems */
					if ((rc = matrixDtlsSentData(ssl, sslBufLen)) < 0) {
						psTraceDtls("internal error\n");
						clearClient(dtlsCtx);
						clientCount--;
						break;
					}
					if (rc == MATRIXSSL_REQUEST_CLOSE) {
						psTraceDtls("Got REQUEST_CLOSE out of SentData\n");
						clearClient(dtlsCtx);
						clientCount--;
						break;
					}
					if (rc == MATRIXSSL_HANDSHAKE_COMPLETE) {
						/* This is the standard handshake case */
						psTraceDtls("Got HANDSHAKE_COMPLETE out of SentData\n");
						break;
					}
					/* SSL_REQUEST_SEND is handled by loop logic */
				}

			}
		}
	}
	return clientCount;
}
Beispiel #15
0
int main(int argc, char **argv)
#endif
{
	sslSessionId_t		*sessionId;
	sslConn_t			*conn;
	sslKeys_t			*keys;
	WSADATA				wsaData;
	SOCKET				fd;
	short				cipherSuite;
	unsigned char		*ip, *c, *requestBuf;
	unsigned char		buf[1024];
	int					iterations, requests, connectAgain, status;
	int					quit, rc, bytes, i, j, err;
	time_t				t0, t1;
#if REUSE
	int					anonStatus;
#endif
#if VXWORKS
	int					argc;
	char				**argv;
	parseCmdLineArgs(arg1, &argc, &argv);
#endif /* VXWORKS */

#if WINCE
	int					argc;
	char				**argv;
	char				args[256];

/*
 *	parseCmdLineArgs expects an ASCII string and CE is unicoded, so convert
 *	the command line.  args will get hacked up, so you can't pass in a
 *	static string.
 */
	WideCharToMultiByte(CP_ACP, 0, lpCmdLine, -1, args, 256, NULL, NULL);

/*
 *	Parse the command line into an argv array.  This allocs memory, so
 *	we have to free argv when we're done.
 */
	parseCmdLineArgs(args, &argc, &argv);
#endif /* WINCE */

	conn = NULL;
/*
	First (optional) argument is ip address to connect to (port is hardcoded)
	Second (optional) argument is number of iterations to perform
	Third (optional) argument is number of keepalive HTTP requests
	Fourth (optional) argument is cipher suite number to use (0 for any)
*/
	ip = HTTPS_IP;
	iterations = ITERATIONS;
	requests = REQUESTS;
	cipherSuite = 0x0000;
	if (argc > 1) {
		ip = argv[1];
		if (argc > 2) {
			iterations = atoi(argv[2]);
			socketAssert(iterations > 0);
			if (argc > 3) {
				requests = atoi(argv[3]);
				socketAssert(requests > 0);
				if (argc > 4) {
					cipherSuite = (short)atoi(argv[4]);
				}
			}
		}
	}
/*
	Initialize Windows sockets (no-op on other platforms)
*/
	WSAStartup(MAKEWORD(1,1), &wsaData);
/*
	Initialize the MatrixSSL Library, and read in the certificate file
	used to validate the server.
*/
	if (matrixSslOpen() < 0) {
		fprintf(stderr, "matrixSslOpen failed, exiting...");
	}
	sessionId = NULL;
	if (matrixSslReadKeys(&keys, NULL, NULL, NULL, CAfile) < 0) {
		goto promptAndExit;
	}
/*
	Intialize loop control variables
*/
	quit = 0;
	connectAgain = 1;
	i = 1;
/*
	Just reuse the requestBuf and malloc to largest possible message size
*/
	requestBuf = malloc(sizeof(requestAgain));
	t0 = time(0);
/*
	Main ITERATIONS loop
*/
	while (!quit && (i < iterations)) {
/*
		sslConnect uses port and ip address to connect to SSL server.
		Generates a new session
*/
		if (connectAgain) {
			if ((fd = socketConnect(ip, HTTPS_PORT, &err)) == INVALID_SOCKET) {
				fprintf(stdout, "Error connecting to server %s:%d\n", ip, HTTPS_PORT);
				matrixSslFreeKeys(keys);
				goto promptAndExit;
			}
			if (sslConnect(&conn, fd, keys, sessionId, cipherSuite, certChecker) < 0) {
				quit = 1;
				socketShutdown(fd);
				fprintf(stderr, "Error connecting to %s:%d\n", ip, HTTPS_PORT);
				continue;
			}
			i++;
			connectAgain = 0;
			j = 1;
		}
		if (conn == NULL) {
			quit++;
			continue;
		}
/*
		Copy the HTTP request header into the buffer, based of whether or
		not we want httpReflector to keep the socket open or not
*/
		if (j == requests) {
			bytes = (int)strlen(request);
			memcpy(requestBuf, request, bytes);
		} else {
			bytes = (int)strlen(requestAgain);
			memcpy(requestBuf, requestAgain, bytes);
		}
/*
		Send request.  
		< 0 return indicates an error.
		0 return indicates not all data was sent and we must retry
		> 0 indicates that all requested bytes were sent
*/
writeMore:
		rc = sslWrite(conn, requestBuf, bytes, &status);
		if (rc < 0) {
			fprintf(stdout, "Internal sslWrite error\n");
			socketShutdown(conn->fd);
			sslFreeConnection(&conn);
			continue;
		} else if (rc == 0) {
			goto writeMore;
		}
/*
		Read response
		< 0 return indicates an error.
		0 return indicates an EOF or CLOSE_NOTIFY in this situation
		> 0 indicates that some bytes were read.  Keep reading until we see
		the /r/n/r/n from the response header.  There may be data following
		this header, but we don't try too hard to read it for this example.
*/
		c = buf;
readMore:
		if ((rc = sslRead(conn, c, sizeof(buf) - (int)(c - buf), &status)) > 0) {
			c += rc;
			if (c - buf < 4 || memcmp(c - 4, "\r\n\r\n", 4) != 0) {
				goto readMore;
			}
		} else {
			if (rc < 0) {
				fprintf(stdout, "sslRead error.  dropping connection.\n");
			}
			if (rc < 0 || status == SSLSOCKET_EOF ||
					status == SSLSOCKET_CLOSE_NOTIFY) {
				socketShutdown(conn->fd);
				sslFreeConnection(&conn);
				continue;
			}
			goto readMore;
		}
/*
		Determine if we want to do a pipelined HTTP request/response
*/
		if (j++ < requests) {
			fprintf(stdout, "R");
			continue;
		} else {
			fprintf(stdout, "C");
		}
/*
		Reuse the session.  Comment out these two lines to test the entire
		public key renegotiation each iteration
*/
#if REUSE
		matrixSslFreeSessionId(sessionId);
		matrixSslGetSessionId(conn->ssl, &sessionId);
/*
		This example shows how a user might want to limit a client to
		resuming handshakes only with authenticated servers.  In this
		example, the client will force any non-authenticated (anonymous)
		server to go through a complete handshake each time.  This is
		strictly an example of one policy decision an implementation 
		might wish to make.
*/
		matrixSslGetAnonStatus(conn->ssl, &anonStatus);
		if (anonStatus) {
			matrixSslFreeSessionId(sessionId);
			sessionId = NULL;
		}
#endif
/*
		Send a closure alert for clean shutdown of remote SSL connection
		This is for good form, some implementations just close the socket
*/
		sslWriteClosureAlert(conn);
/*
		Session done.  Connect again if more iterations remaining
*/
		socketShutdown(conn->fd);
		sslFreeConnection(&conn);
		connectAgain = 1;
	}

	t1 = time(0);
	free(requestBuf);
	matrixSslFreeSessionId(sessionId);
	if (conn && conn->ssl) {
		socketShutdown(conn->fd);
		sslFreeConnection(&conn);
	}
	fprintf(stdout, "\n%d connections in %d seconds (%f c/s)\n", 
		i, (int)(t1 - t0), (double)i / (t1 - t0));
	fprintf(stdout, "\n%d requests in %d seconds (%f r/s)\n", 
		i * requests, (int)(t1 - t0), 
		(double)(i * requests) / (t1 - t0));
/*
	Close listening socket, free remaining items
*/
	matrixSslFreeKeys(keys);
	matrixSslClose();
	WSACleanup();
promptAndExit:
	fprintf(stdout, "Press return to exit...\n");
	getchar();

#if WINCE || VXWORKS
	if (argv) {
		free((void*) argv);
	}
#endif /* WINCE */
	return 0;
}
Beispiel #16
0
int ssl_io(unsigned int newsession, const char **prog) {
  if (client) { fdstdin =6; fdstdou =7; }
  bad_certificate = env_get("SSLIO_BAD_CERTIFICATE");
  if ((s =env_get("SSLIO_BUFIN"))) scan_ulong(s, &bufsizein);
  if ((s =env_get("SSLIO_BUFOU"))) scan_ulong(s, &bufsizeou);
  if (bufsizein < 64) bufsizein =64;
  if (bufsizeou < 64) bufsizeou =64;
  if ((s =env_get("SSLIO_HANDSHAKE_TIMEOUT")))
    scan_ulong(s, &handshake_timeout);
  if (handshake_timeout < 1) handshake_timeout =1;

  if (pipe(encpipe) == -1) fatalm("unable to create pipe for encoding");
  if (pipe(decpipe) == -1) fatalm("unable to create pipe for decoding");
  if ((pid =fork()) == -1) fatalm("unable to fork");
  if (pid == 0) {
    if (close(encpipe[1]) == -1)
      fatalm("unable to close encoding pipe output");
    if (close(decpipe[0]) == -1)
      fatalm("unable to close decoding pipe input");
    if (newsession) if (matrixSslOpen() < 0) fatalm("unable to initialize ssl");
    if (root) {
      if (chdir(root) == -1) fatalm("unable to change to new root directory");
      if (chroot(".") == -1) fatalm("unable to chroot");
    }
    if (ssluser) {
      /* drop permissions */
      if (setgroups(sslugid.gids, sslugid.gid) == -1)
        fatal("unable to set groups");
      if (setgid(*sslugid.gid) == -1) fatal("unable to set gid");
      if (prot_uid(sslugid.uid) == -1) fatalm("unable to set uid");
    }
    if (newsession) {
      if (matrixSslReadKeys(&keys, cert, key, 0, ca) < 0) {
        if (client) fatalm("unable to read cert, key, or ca file");
        fatalm("unable to read cert or key file");
      }
      if (matrixSslNewSession(&ssl, keys, 0, client?0:SSL_FLAGS_SERVER) < 0)
        fatalmx("unable to create ssl session");
    }
    if (client)
      if (ca || bad_certificate) matrixSslSetCertValidator(ssl, &validate, 0);

    sig_catch(sig_term, sig_term_handler);
    sig_ignore(sig_pipe);
    doio();
    finish();
    _exit(0);
  }
  if (close(encpipe[0]) == -1) fatalm("unable to close encoding pipe input");
  if (close(decpipe[1]) == -1) fatalm("unable to close decoding pipe output");
  if (fd_move(fdstdin, decpipe[0]) == -1)
    fatalm("unable to setup filedescriptor for decoding");
  if (fd_move(fdstdou, encpipe[1]) == -1)
    fatalm("unable to setup filedescriptor for encoding");
  sslCloseOsdep();
  if (svuser) {
    if (setgroups(ugid.gids, ugid.gid) == -1)
      fatal("unable to set groups for prog");
    if (setgid(*ugid.gid) == -1) fatal("unable to set gid for prog");
    if (prot_uid(ugid.uid) == -1) fatalm("unable to set uid for prog");
  }
  pathexec(prog);
  fatalm("unable to run prog");
  return(111);
}
Beispiel #17
0
CAMLprim value stub_core_open(value unit)
{
  CAMLparam1(unit);
  int result = matrixSslOpen();
  CAMLreturn(Val_int(result));
}
Beispiel #18
0
int main(int argc, char **argv)
#endif
{
	SOCKET			srv_fd;
	int				status;
	WSADATA			wsaData;
	
	// options
	char				*srv_host = NULL;
	int				srv_port = 0;
	char 				*keyfile = NULL; //"privkeySrv.pem";
	char 				*certfile = NULL; //"certSrv.pem";
	int				vlevel = 0;
	char 				*cpos,*opos;
	int tmpport;
	int c;
	int 			intarg;
 	
#if VXWORKS
	int					argc;
	char				**argv;
	parseCmdLineArgs(arg1, &argc, &argv);
#endif /* VXWORKS */

#if WINCE
	int					argc;
	char				**argv;
	char				args[256];

/*
 *	parseCmdLineArgs expects an ASCII string and CE is unicoded, so convert
 *	the command line.  args will get hacked up, so you can't pass in a
 *	static string.
 */
	WideCharToMultiByte(CP_ACP, 0, lpCmdLine, -1, args, 256, NULL, NULL);

/*
 *	Parse the command line into an argv array.  This allocs memory, so
 *	we have to free argv when we're done.
 */
	parseCmdLineArgs(args, &argc, &argv);
#endif /* WINCE */


/*
	prepare
*/
	
#ifndef USE_FORK
	memset(connections,0,MAXPROXYCOUNT*sizeof(struct proxyConnection));
#endif
	
/*
	getopt
*/
	/* Gemtek add +++ */
	if(argc == 1) usage(1);
	/* Gemtek add --- */
	
	for (;;) {
		c = getopt (argc, argv, "VD:P:fo:cd:r:p:A:v:h");
		if (c == -1) {
			break;
		}

		switch (c) {
			case 'c':
				// client mode
				isClient=1;
				break;
			
			case 'd':
				// daemon mode [host:]port
				cpos = NULL;
				tmpport = 0;
				if((cpos = strchr(optarg,':'))) {				
					*cpos = '\0';
					if(optarg && optarg[0])
						srv_host = optarg;
					optarg = ++cpos;
				}
				if(optarg && optarg[0]) {
					tmpport = (int)strtol(optarg, (char **)NULL, 0);
					if(tmpport) srv_port = tmpport;
				}
				break;
			
			case 'r':
				// remote [host:]port
				cpos = NULL;
				tmpport = 0;
				if((cpos = strchr(optarg,':'))) {				
					*cpos = '\0';
					if(optarg && optarg[0])
						dst_host = optarg;
					optarg = ++cpos;
				}
				if(optarg && optarg[0]) {
					tmpport = (int)strtol(optarg, (char **)NULL, 0);
					if(tmpport) dst_port = tmpport;
				}
				break;
				
			case 'p':
				// pemfile (requred in servermode)
				keyfile = optarg;
				break;
			
			case 'A':
				// CA file
				certfile = optarg;
				break;
			
			case 'v':
				// veryfication level
				if(optarg && optarg[0]) {
					vlevel = (int)strtol(optarg, (char **)NULL, 0);
					if(vlevel == 1 ) {
						cervalidator = certChecker;
					}
					else if(vlevel > 3 || vlevel < 0) {
						fprintf(stderr,"-v takes whole numbers between 0 and 3");
						exit(2);
					}
				}
				break;
			
			case 'P':
				// create a pidfile
				pidfile=optarg;
				break;
				
			case 'f':
				// run in foreground.
				nofork=1;
				nosysl=1;
				break;
				
			case 'o':
				// append logmessages to a file instead of stdout/syslog
				break;
				
			case 'O':
				// socket options. TODO
				break;
			
			case 'D':
				// debug level 0...7
				intarg=strtol(optarg,NULL,0);
				if(intarg<0 || intarg>7) {
					usage(1);
				}
				gLogLevel=intarg;
				break;
				
			case 'V':
				// version
				break;
				
			case '?':
			case 'h':
				usage(0);
				break;
			
			default:
				usage(1);
				break;
		}
	}


/* install handlers */
	signal( SIGPIPE, SIG_IGN );
	signal(SIGCHLD,sigchld_handler); /* ignore child */
	signal(SIGHUP,kill_handler); /* catch hangup signal */
	signal(SIGTERM,kill_handler); /* catch kill signal */
	
/*
	Initialize Windows sockets (no-op on other platforms)
*/
	WSAStartup(MAKEWORD(1,1), &wsaData);
	
	if(!nosysl) {
		openlog("matrixtunnel", LOG_PID, LOG_DAEMON);
		setlogmask(LOG_UPTO(gLogLevel));
	}
	
/*
	Initialize the MatrixSSL Library, and read in the public key (certificate)
	and private key.
*/
	if (matrixSslOpen() < 0) {
		ELOG("matrixSslOpen failed, exiting...");
		exit(1);
	}

/*
	Standard PEM files
*/
	if (matrixSslReadKeys(&keys, certfile, keyfile, NULL, NULL) < 0)  {
		ELOG("Error reading or parsing %s or %s, exiting...", 
			certfile, keyfile);
		exit(1);
	}

	// go to background
	if(!nofork) {
		daemonize();
	}

/*
	Create the listen socket
*/
	if ((srv_fd = socketListen(srv_port, &status)) == INVALID_SOCKET) {
		ELOG("Cannot listen on port %d, exiting...", srv_port);
		exit(1);
	}
/*
	Set blocking or not on the listen socket
*/
	setSocketBlock(srv_fd);

/*
	Main connection loop
*/
	struct proxyConnection	*cp=NULL;
	struct proxyConnection	*ncp;
	
	fd_set	rs, ws, es, cr;
	int			fdmax;
	struct timeval tv;
	int			res, dontClose;
	
	char		buf[4096];
	int pc, sc;
	
	int			ccount;
	
	while (!quit) {
		fdmax=srv_fd;
		ncp=NULL;
		
		FD_ZERO(&rs);
		FD_ZERO(&ws);
		FD_ZERO(&es);
		
		FD_SET(srv_fd,&rs);
		FD_SET(srv_fd,&ws);
		FD_SET(srv_fd,&es);
		ccount=0;
		
#ifndef USE_FORK
		DLOG("next select on fds: %d ",srv_fd);
		for(cp=connections;cp<&connections[MAXPROXYCOUNT];cp++) {
			if (cp->done) {
				closeProxyConnection(cp);
			}
			if (cp->secure_up) {
				FD_SET(cp->secure->fd,&rs);
				FD_SET(cp->secure->fd,&ws);
				FD_SET(cp->secure->fd,&es);

				if (fdmax < cp->secure->fd)
					fdmax = cp->secure->fd;
				
				DLOG("fd: %d",cp->secure->fd);
				ccount++;
			}
			if (cp->plain_up) {
				FD_SET(cp->plain,&rs);			
				FD_SET(cp->plain,&ws);
				FD_SET(cp->plain,&es);
					
				if (fdmax < cp->plain)
					fdmax = cp->plain;
				
				DLOG("fd: %d",cp->plain);
				ccount++;
			}
			if(!ncp && !cp->inuse){
				ncp=cp;
				memset(ncp,0,sizeof(struct proxyConnection));
			}
		}
#else
		struct proxyConnection	ncp_s;
		ncp=&ncp_s;
		memset(ncp,0,sizeof(struct proxyConnection));
#endif
		
		tv.tv_sec=10;
		tv.tv_usec=0;

		DLOG("main : select on %d open connections. fdmax: %d", ccount, fdmax);
		res=select(fdmax+1,&rs,NULL,&es,&tv);
		DLOG("select returned: %d %s", res , strerror(errno) );

		if(res<0) {
			perror("select");
			continue;
		}
		
		if(res==0)
			continue;

#ifndef USE_FORK
		// handle open connections
		for(cp=connections;cp<&connections[MAXPROXYCOUNT];cp++) {
			if (cp->secure_up && cp->plain_up) {
				if(FD_ISSET(cp->secure->fd,&es) || FD_ISSET(cp->plain,&es)) {
						closeProxyConnection(cp);
						continue;
				}
				
				if(secureReady(cp)) {
					sc=proxyReadwrite(cp,1);
					if(sc<0) {
						closeProxyConnection(cp);
						continue;
					}
				}
				
				if(plainReady(cp)) {
					pc=proxyReadwrite(cp,0);
					if(pc<0) {
						closeProxyConnection(cp);
						continue;
					}
				}
			}
		}
#endif

		// do we have new connections?
		if(FD_ISSET(srv_fd,&rs)) {
			proxyAccept(srv_fd,ncp);
		}			
	}

/*
	Close listening socket, free remaining items
*/
	socketShutdown(srv_fd);
	
#ifndef USE_FORK
	for(cp=connections;cp<&connections[MAXPROXYCOUNT];cp++) {
		closeProxyConnection(cp);
	}
#endif
	
	if(!nosysl) {
		closelog();
	}
	
	matrixSslFreeKeys(keys);
	matrixSslClose();
	WSACleanup();
	return 0;
}
Beispiel #19
0
/*
	Main routine. Initialize SSL keys and structures, and make two SSL 
	connections, the first with a blank session Id, and the second with
	a session ID populated during the first connection to do a much faster
	session resumption connection the second time.
 */
int32 main(int32 argc, char **argv)
{
	int32			rc, CAstreamLen;
	sslKeys_t		*keys;
	sslSessionId_t	*sid;
	char			*CAstream;
#ifdef USE_CRL
	int32			numLoaded;
#endif
#ifdef WIN32
	WSADATA			wsaData;
	WSAStartup(MAKEWORD(1, 1), &wsaData);
#endif
	if ((rc = matrixSslOpen()) < 0) {
		_psTrace("MatrixSSL library init failure.  Exiting\n");
		return rc; 
	}
	if (matrixSslNewKeys(&keys) < 0) {
		_psTrace("MatrixSSL library key init failure.  Exiting\n");
		return -1;
	}

#ifdef USE_HEADER_KEYS
/*
	In-memory based keys
	Build the CA list first for potential client auth usage
*/
	CAstreamLen = 0;
	CAstreamLen += sizeof(RSACAS);
	if (CAstreamLen > 0) {
		CAstream = psMalloc(NULL, CAstreamLen);
	} else {
		CAstream = NULL;
	}
	
	CAstreamLen = 0;
	memcpy(CAstream, RSACAS, sizeof(RSACAS));
	CAstreamLen += sizeof(RSACAS);
		
#ifdef ID_RSA
	if ((rc = matrixSslLoadRsaKeysMem(keys, RSA2048, sizeof(RSA2048),
			RSA2048KEY, sizeof(RSA2048KEY), (unsigned char*)CAstream,
			CAstreamLen)) < 0) {
		_psTrace("No certificate material loaded.  Exiting\n");
		if (CAstream) psFree(CAstream);
		matrixSslDeleteKeys(keys);
		matrixSslClose();
		return rc;
	}
#endif
		

	if (CAstream) psFree(CAstream);

#else
/*
	File based keys
*/
	CAstreamLen = 0;
	CAstreamLen += (int32)strlen(rsaCAFile) + 1;
	if (CAstreamLen > 0) {
		CAstream = psMalloc(NULL, CAstreamLen);
		memset(CAstream, 0x0, CAstreamLen);
	} else {
		CAstream = NULL;
	}
	
	CAstreamLen = 0;
	memcpy(CAstream, rsaCAFile,	strlen(rsaCAFile));
	CAstreamLen += strlen(rsaCAFile);

/* Load Identiy */	
#ifdef EXAMPLE_RSA_KEYS	
	if ((rc = matrixSslLoadRsaKeys(keys, rsaCertFile, rsaPrivkeyFile, NULL,
			(char*)CAstream)) < 0) {
		_psTrace("No certificate material loaded.  Exiting\n");
		if (CAstream) psFree(CAstream);
		matrixSslDeleteKeys(keys);
		matrixSslClose();
		return rc;
	}
#endif	


	if (CAstream) psFree(CAstream);
#endif /* USE_HEADER_KEYS */


#ifdef USE_CRL
	if (matrixSslGetCRL(keys, crlCb, &numLoaded) < 0) {
		_psTrace("WARNING: A CRL failed to load\n");
	}
	_psTraceInt("CRLs loaded: %d\n", numLoaded);
#endif

	matrixSslNewSessionId(&sid);
	_psTrace("=== INITIAL CLIENT SESSION ===\n");
	httpsClientConnection(keys, sid);

	_psTrace("\n=== CLIENT SESSION WITH CACHED SESSION ID ===\n");
	httpsClientConnection(keys, sid);
	
	matrixSslDeleteSessionId(sid);
	matrixSslDeleteKeys(keys);
	matrixSslClose();

#ifdef WIN32
	_psTrace("Press any key to close");
	getchar();
#endif
	return 0;
}
Beispiel #20
0
int tcpudpsvd_main(int argc ATTRIBUTE_UNUSED, char **argv)
{
	char *str_C, *str_t;
	char *user;
	struct hcc *hccp;
	const char *instructs;
	char *msg_per_host = NULL;
	unsigned len_per_host = len_per_host; /* gcc */
#ifndef SSLSVD
	struct bb_uidgid_t ugid;
#endif
	bool tcp;
	uint16_t local_port;
	char *preset_local_hostname = NULL;
	char *remote_hostname = remote_hostname; /* for compiler */
	char *remote_addr = remote_addr; /* for compiler */
	len_and_sockaddr *lsa;
	len_and_sockaddr local, remote;
	socklen_t sa_len;
	int pid;
	int sock;
	int conn;
	unsigned backlog = 20;

	INIT_G();

	tcp = (applet_name[0] == 't');

	/* 3+ args, -i at most once, -p implies -h, -v is counter, -b N, -c N */
	opt_complementary = "-3:i--i:ph:vv:b+:c+";
#ifdef SSLSVD
	getopt32(argv, "+c:C:i:x:u:l:Eb:hpt:vU:/:Z:K:",
		&cmax, &str_C, &instructs, &instructs, &user, &preset_local_hostname,
		&backlog, &str_t, &ssluser, &root, &cert, &key, &verbose
	);
#else
	/* "+": stop on first non-option */
	getopt32(argv, "+c:C:i:x:u:l:Eb:hpt:v",
		&cmax, &str_C, &instructs, &instructs, &user, &preset_local_hostname,
		&backlog, &str_t, &verbose
	);
#endif
	if (option_mask32 & OPT_C) { /* -C n[:message] */
		max_per_host = bb_strtou(str_C, &str_C, 10);
		if (str_C[0]) {
			if (str_C[0] != ':')
				bb_show_usage();
			msg_per_host = str_C + 1;
			len_per_host = strlen(msg_per_host);
		}
	}
	if (max_per_host > cmax)
		max_per_host = cmax;
	if (option_mask32 & OPT_u) {
		if (!get_uidgid(&ugid, user, 1))
			bb_error_msg_and_die("unknown user/group: %s", user);
	}
#ifdef SSLSVD
	if (option_mask32 & OPT_U) ssluser = optarg;
	if (option_mask32 & OPT_slash) root = optarg;
	if (option_mask32 & OPT_Z) cert = optarg;
	if (option_mask32 & OPT_K) key = optarg;
#endif
	argv += optind;
	if (!argv[0][0] || LONE_CHAR(argv[0], '0'))
		argv[0] = (char*)"0.0.0.0";

	/* Per-IP flood protection is not thought-out for UDP */
	if (!tcp)
		max_per_host = 0;

	bb_sanitize_stdio(); /* fd# 0,1,2 must be opened */

#ifdef SSLSVD
	sslser = user;
	client = 0;
	if ((getuid() == 0) && !(option_mask32 & OPT_u)) {
		xfunc_exitcode = 100;
		bb_error_msg_and_die("-U ssluser must be set when running as root");
	}
	if (option_mask32 & OPT_u)
		if (!uidgid_get(&sslugid, ssluser, 1)) {
			if (errno) {
				bb_perror_msg_and_die("fatal: cannot get user/group: %s", ssluser);
			}
			bb_error_msg_and_die("unknown user/group '%s'", ssluser);
		}
	if (!cert) cert = "./cert.pem";
	if (!key) key = cert;
	if (matrixSslOpen() < 0)
		fatal("cannot initialize ssl");
	if (matrixSslReadKeys(&keys, cert, key, 0, ca) < 0) {
		if (client)
			fatal("cannot read cert, key, or ca file");
		fatal("cannot read cert or key file");
	}
	if (matrixSslNewSession(&ssl, keys, 0, SSL_FLAGS_SERVER) < 0)
		fatal("cannot create ssl session");
#endif

	sig_block(SIGCHLD);
	signal(SIGCHLD, sig_child_handler);
	bb_signals(BB_FATAL_SIGS, sig_term_handler);
	signal(SIGPIPE, SIG_IGN);

	if (max_per_host)
		ipsvd_perhost_init(cmax);

	local_port = bb_lookup_port(argv[1], tcp ? "tcp" : "udp", 0);
	lsa = xhost2sockaddr(argv[0], local_port);
	argv += 2;

	sock = xsocket(lsa->u.sa.sa_family, tcp ? SOCK_STREAM : SOCK_DGRAM, 0);
	setsockopt_reuseaddr(sock);
	sa_len = lsa->len; /* I presume sockaddr len stays the same */
	xbind(sock, &lsa->u.sa, sa_len);
	if (tcp)
		xlisten(sock, backlog);
	else /* udp: needed for recv_from_to to work: */
		socket_want_pktinfo(sock);
	/* ndelay_off(sock); - it is the default I think? */

#ifndef SSLSVD
	if (option_mask32 & OPT_u) {
		/* drop permissions */
		xsetgid(ugid.gid);
		xsetuid(ugid.uid);
	}
#endif

	if (verbose) {
		char *addr = xmalloc_sockaddr2dotted(&lsa->u.sa);
		bb_error_msg("listening on %s, starting", addr);
		free(addr);
#ifndef SSLSVD
		if (option_mask32 & OPT_u)
			printf(", uid %u, gid %u",
				(unsigned)ugid.uid, (unsigned)ugid.gid);
#endif
	}

	/* Main accept() loop */

 again:
	hccp = NULL;

	while (cnum >= cmax)
		wait_for_any_sig(); /* expecting SIGCHLD */

	/* Accept a connection to fd #0 */
 again1:
	close(0);
 again2:
	sig_unblock(SIGCHLD);
	local.len = remote.len = sa_len;
	if (tcp) {
		conn = accept(sock, &remote.u.sa, &remote.len);
	} else {
		/* In case recv_from_to won't be able to recover local addr.
		 * Also sets port - recv_from_to is unable to do it. */
		local = *lsa;
		conn = recv_from_to(sock, NULL, 0, MSG_PEEK,
				&remote.u.sa, &local.u.sa, sa_len);
	}
	sig_block(SIGCHLD);
	if (conn < 0) {
		if (errno != EINTR)
			bb_perror_msg(tcp ? "accept" : "recv");
		goto again2;
	}
	xmove_fd(tcp ? conn : sock, 0);

	if (max_per_host) {
		/* Drop connection immediately if cur_per_host > max_per_host
		 * (minimizing load under SYN flood) */
		remote_addr = xmalloc_sockaddr2dotted_noport(&remote.u.sa);
		cur_per_host = ipsvd_perhost_add(remote_addr, max_per_host, &hccp);
		if (cur_per_host > max_per_host) {
			/* ipsvd_perhost_add detected that max is exceeded
			 * (and did not store ip in connection table) */
			free(remote_addr);
			if (msg_per_host) {
				/* don't block or test for errors */
				send(0, msg_per_host, len_per_host, MSG_DONTWAIT);
			}
			goto again1;
		}
		/* NB: remote_addr is not leaked, it is stored in conn table */
	}

	if (!tcp) {
		/* Voodoo magic: making udp sockets each receive its own
		 * packets is not trivial, and I still not sure
		 * I do it 100% right.
		 * 1) we have to do it before fork()
		 * 2) order is important - is it right now? */

		/* Open new non-connected UDP socket for further clients... */
		sock = xsocket(lsa->u.sa.sa_family, SOCK_DGRAM, 0);
		setsockopt_reuseaddr(sock);
		/* Make plain write/send work for old socket by supplying default
		 * destination address. This also restricts incoming packets
		 * to ones coming from this remote IP. */
		xconnect(0, &remote.u.sa, sa_len);
	/* hole? at this point we have no wildcard udp socket...
	 * can this cause clients to get "port unreachable" icmp?
	 * Yup, time window is very small, but it exists (is it?) */
		/* ..."open new socket", continued */
		xbind(sock, &lsa->u.sa, sa_len);
		socket_want_pktinfo(sock);

		/* Doesn't work:
		 * we cannot replace fd #0 - we will lose pending packet
		 * which is already buffered for us! And we cannot use fd #1
		 * instead - it will "intercept" all following packets, but child
		 * does not expect data coming *from fd #1*! */
#if 0
		/* Make it so that local addr is fixed to localp->u.sa
		 * and we don't accidentally accept packets to other local IPs. */
		/* NB: we possibly bind to the _very_ same_ address & port as the one
		 * already bound in parent! This seems to work in Linux.
		 * (otherwise we can move socket to fd #0 only if bind succeeds) */
		close(0);
		set_nport(localp, htons(local_port));
		xmove_fd(xsocket(localp->u.sa.sa_family, SOCK_DGRAM, 0), 0);
		setsockopt_reuseaddr(0); /* crucial */
		xbind(0, &localp->u.sa, localp->len);
#endif
	}

	pid = vfork();
	if (pid == -1) {
		bb_perror_msg("vfork");
		goto again;
	}

	if (pid != 0) {
		/* Parent */
		cnum++;
		if (verbose)
			connection_status();
		if (hccp)
			hccp->pid = pid;
		/* clean up changes done by vforked child */
		undo_xsetenv();
		goto again;
	}

	/* Child: prepare env, log, and exec prog */

	/* Closing tcp listening socket */
	if (tcp)
		close(sock);

	{ /* vfork alert! every xmalloc in this block should be freed! */
		char *local_hostname = local_hostname; /* for compiler */
		char *local_addr = NULL;
		char *free_me0 = NULL;
		char *free_me1 = NULL;
		char *free_me2 = NULL;

		if (verbose || !(option_mask32 & OPT_E)) {
			if (!max_per_host) /* remote_addr is not yet known */
				free_me0 = remote_addr = xmalloc_sockaddr2dotted(&remote.u.sa);
			if (option_mask32 & OPT_h) {
				free_me1 = remote_hostname = xmalloc_sockaddr2host_noport(&remote.u.sa);
				if (!remote_hostname) {
					bb_error_msg("cannot look up hostname for %s", remote_addr);
					remote_hostname = remote_addr;
				}
			}
			/* Find out local IP peer connected to.
			 * Errors ignored (I'm not paranoid enough to imagine kernel
			 * which doesn't know local IP). */
			if (tcp)
				getsockname(0, &local.u.sa, &local.len);
			/* else: for UDP it is done earlier by parent */
			local_addr = xmalloc_sockaddr2dotted(&local.u.sa);
			if (option_mask32 & OPT_h) {
				local_hostname = preset_local_hostname;
				if (!local_hostname) {
					free_me2 = local_hostname = xmalloc_sockaddr2host_noport(&local.u.sa);
					if (!local_hostname)
						bb_error_msg_and_die("cannot look up hostname for %s", local_addr);
				}
				/* else: local_hostname is not NULL, but is NOT malloced! */
			}
		}
		if (verbose) {
			pid = getpid();
			if (max_per_host) {
				bb_error_msg("concurrency %s %u/%u",
					remote_addr,
					cur_per_host, max_per_host);
			}
			bb_error_msg((option_mask32 & OPT_h)
				? "start %u %s-%s (%s-%s)"
				: "start %u %s-%s",
				pid,
				local_addr, remote_addr,
				local_hostname, remote_hostname);
		}

		if (!(option_mask32 & OPT_E)) {
			/* setup ucspi env */
			const char *proto = tcp ? "TCP" : "UDP";

			/* Extract "original" destination addr:port
			 * from Linux firewall. Useful when you redirect
			 * an outbond connection to local handler, and it needs
			 * to know where it originally tried to connect */
			if (tcp && getsockopt(0, SOL_IP, SO_ORIGINAL_DST, &local.u.sa, &local.len) == 0) {
				char *addr = xmalloc_sockaddr2dotted(&local.u.sa);
				xsetenv_plain("TCPORIGDSTADDR", addr);
				free(addr);
			}
			xsetenv_plain("PROTO", proto);
			xsetenv_proto(proto, "LOCALADDR", local_addr);
			xsetenv_proto(proto, "REMOTEADDR", remote_addr);
			if (option_mask32 & OPT_h) {
				xsetenv_proto(proto, "LOCALHOST", local_hostname);
				xsetenv_proto(proto, "REMOTEHOST", remote_hostname);
			}
			//compat? xsetenv_proto(proto, "REMOTEINFO", "");
			/* additional */
			if (cur_per_host > 0) /* can not be true for udp */
				xsetenv_plain("TCPCONCURRENCY", utoa(cur_per_host));
		}
		free(local_addr);
		free(free_me0);
		free(free_me1);
		free(free_me2);
	}

	xdup2(0, 1);

	signal(SIGTERM, SIG_DFL);
	signal(SIGPIPE, SIG_DFL);
	signal(SIGCHLD, SIG_DFL);
	sig_unblock(SIGCHLD);

#ifdef SSLSVD
	strcpy(id, utoa(pid));
	ssl_io(0, argv);
#else
	BB_EXECVP(argv[0], argv);
#endif
	bb_perror_msg_and_die("exec '%s'", argv[0]);
}
Beispiel #21
0
int main(int argc, char **argv) {
  int opt;
  char *user =0;
  char *host;
  unsigned long port;
  int pid;
  int s;
  int conn;
  int delim;

  progname =*argv;
  phccmax =0;

#ifdef SSLSVD
  while ((opt =getopt(argc, (const char **)argv,
                      "c:C:i:x:u:l:Eb:hpt:vVU:/:Z:K:")) != opteof) {
#else
  while ((opt =getopt(argc, (const char **)argv,
                      "c:C:i:x:u:l:Eb:hpt:vV")) != opteof) {
#endif
    switch(opt) {
    case 'c': scan_ulong(optarg, &cmax); if (cmax < 1) usage(); break;
    case 'C':
      delim =scan_ulong(optarg, &phccmax);
      if (phccmax < 1) usage();
      if (optarg[delim] == ':') {
        if (ipsvd_fmt_msg(&msg, optarg +delim +1) == -1) die_nomem();
        if (! stralloc_0(&msg)) die_nomem();
        phccmsg =msg.s;
      }
      break;
    case 'i': if (instructs) usage(); instructs =optarg; break;
    case 'x': if (instructs) usage(); instructs =optarg; iscdb =1; break;
    case 'u': user =(char*)optarg; break;
    case 'l':
      if (! stralloc_copys(&local_hostname, optarg)) die_nomem();
      if (! stralloc_0(&local_hostname)) die_nomem();
      break;
    case 'E': ucspi =0; break;
    case 'b': scan_ulong(optarg, &backlog); break;
    case 'h': lookuphost =1; break;
    case 'p': lookuphost =1; paranoid =1; break;
    case 't': scan_ulong(optarg, &timeout); break;
    case 'v': ++verbose; break;
#ifdef SSLSVD
    case 'U': ssluser =(char*)optarg; break;
    case '/': root =(char*)optarg; break;
    case 'Z': cert =(char*)optarg; break;
    case 'K': key =(char*)optarg; break;
#endif
    case 'V': strerr_warn1(VERSION, 0);
    case '?': usage();
    }
  }
  argv +=optind;

  if (! argv || ! *argv) usage();
  host =*argv++;
  if (! argv || ! *argv) usage();
  local_port =*argv++;
  if (! argv || ! *argv) usage();
  prog =(const char **)argv;
  if (phccmax > cmax) phccmax =cmax;

  if (user)
    if (! uidgids_get(&ugid, user)) {
      if (errno)
        strerr_die4sys(111, FATAL, "unable to get user/group: ", user, ": ");
      strerr_die3x(100, FATAL, "unknown user/group: ", user);
    }
#ifdef SSLSVD
  svuser =user;
  client =0;
  if ((getuid() == 0) && (! ssluser))
    strerr_die2x(100, FATAL, "-U ssluser must be set when running as root");
  if (ssluser)
    if (! uidgids_get(&sslugid, ssluser)) {
      if (errno)
        strerr_die4sys(111, FATAL, "unable to get user/group: ", ssluser, ": ");
      strerr_die3x(100, FATAL, "unknown user/group: ", ssluser);
    }
  if (! cert) cert ="./cert.pem";
  if (! key) key =cert;
  if (matrixSslOpen() < 0) fatal("unable to initialize ssl");
  if (matrixSslReadKeys(&keys, cert, key, 0, ca) < 0) {
    if (client) fatal("unable to read cert, key, or ca file");
    fatal("unable to read cert or key file");
  }
  if (matrixSslNewSession(&ssl, keys, 0, SSL_FLAGS_SERVER) < 0)
    strerr_die2x(111, FATAL, "unable to create ssl session");
#endif

  dns_random_init(seed);
  sig_block(sig_child);
  sig_catch(sig_child, sig_child_handler);
  sig_catch(sig_term, sig_term_handler);
  sig_ignore(sig_pipe);

  if (phccmax) if (ipsvd_phcc_init(cmax) == -1) die_nomem();

  if (str_equal(host, "")) host ="0.0.0.0";
  if (str_equal(host, "0")) host ="0.0.0.0";

  if (! ipsvd_scan_port(local_port, "tcp", &port))
    strerr_die3x(100, FATAL, "unknown port number or name: ", local_port);

  if (! stralloc_copys(&sa, host)) die_nomem();
  if ((dns_ip4(&ips, &sa) == -1) || (ips.len < 4))
    if (dns_ip4_qualify(&ips, &fqdn, &sa) == -1)
      fatal2("unable to look up ip address", host);
  if (ips.len < 4)
    strerr_die3x(100, FATAL, "unable to look up ip address: ", host);
  ips.len =4;
  if (! stralloc_0(&ips)) die_nomem();
  local_ip[ipsvd_fmt_ip(local_ip, ips.s)] =0;

  if (! lookuphost) {
    if (! stralloc_copys(&remote_hostname, "")) die_nomem();
    if (! stralloc_0(&remote_hostname)) die_nomem();
  }

  if ((s =socket_tcp()) == -1) fatal("unable to create socket");
  if (socket_bind4_reuse(s, ips.s, port) == -1)
    fatal("unable to bind socket");
  if (listen(s, backlog) == -1) fatal("unable to listen");
  ndelay_off(s);

#ifdef SSLSVD
#else
  if (user) {
    /* drop permissions */
    if (setgroups(ugid.gids, ugid.gid) == -1) fatal("unable to set groups");
    if (setgid(*ugid.gid) == -1) fatal("unable to set gid");
    if (prot_uid(ugid.uid) == -1) fatal("unable to set uid");
  }
#endif
  close(0);

  if (verbose) {
    out(INFO); out("listening on "); outfix(local_ip); out(":");
    outfix(local_port);
#ifdef SSLSVD
#else
    if (user) {
      bufnum[fmt_ulong(bufnum, (unsigned long)ugid.uid)] =0;
      out(", uid "); out(bufnum);
      bufnum[fmt_ulong(bufnum, (unsigned long)ugid.gid)] =0;
      out(", gid "); out(bufnum);
    }
#endif
    flush(", starting.\n");
  }
  for (;;) {
    while (cnum >= cmax) sig_pause();
    socka_size =sizeof(socka);

    sig_unblock(sig_child);
    conn =accept(s, (struct sockaddr *)&socka, &socka_size);
    sig_block(sig_child);

    if (conn == -1) {
      if (errno != error_intr) warn("unable to accept connection");
      continue;
    }
    cnum++;

    if (verbose) connection_status();
    if (phccmax) phcc =ipsvd_phcc_add((char*)&socka.sin_addr);
    if ((pid =fork()) == -1) {
      warn2("drop connection", "unable to fork");
      close(conn);
      continue;
    }
    if (pid == 0) {
      /* child */
      close(s);
#ifdef SSLSVD
      if (*progname) *progname ='\\';
#endif
      connection_accept(conn);
    }
    if (phccmax) ipsvd_phcc_setpid(pid);
    close(conn);
  }
  _exit(0);
}
Beispiel #22
0
int main(int argc, char * argv[])
{
  struct spead_socket *x;
  struct spead_client *c;

  sslKeys_t *keys;
  int32 err;
  
  if (register_signals() < 0)
    return 1;

  x = create_tcp_socket(NULL, "3333");
  if (x == NULL)
    return 1;

  if (bind_spead_socket(x) < 0){
    destroy_spead_socket(x);
    destroy_shared_mem();
    return 1;
  }

  if (listen_spead_socket(x) < 0) {
    destroy_spead_socket(x);
    destroy_shared_mem();
    return 1;
  }

  err = matrixSslOpen();
  if (err != PS_SUCCESS){
#ifdef DEBUG
    fprintf(stderr, "%s: error setting up matrixssl\n", __func__);
#endif
    destroy_spead_socket(x);
    destroy_shared_mem();
    return 1;
  }

  err = matrixSslNewKeys(&keys);
  if (err != PS_SUCCESS){
#ifdef DEBUG
    fprintf(stderr, "%s: error allocationg matrixssl keys\n", __func__);
#endif
    destroy_spead_socket(x);
    destroy_shared_mem();
    matrixSslClose();
    return 1;
  }

  err = matrixSslLoadRsaKeys(keys, "./certs/server.crt", "./certs/server.key", NULL, NULL);
  if (err != PS_SUCCESS){
#ifdef DEBUG
    switch(err){
      case PS_CERT_AUTH_FAIL:
        fprintf(stderr, "Certificate or chain did not self-authenticate or private key could not authenticate certificate\n");
        break;
      case PS_PLATFORM_FAIL:
        fprintf(stderr, "Error locating or opening an input file\n");
        break;
      case PS_ARG_FAIL:
        fprintf(stderr, "Bad input function parameter\n");
        break;
      case PS_MEM_FAIL:
        fprintf(stderr, "Internal memory allocation failure\n");
        break;
      case PS_PARSE_FAIL:
        fprintf(stderr, "Error parsing certificate or private key buffer\n");
        break;
      case PS_FAILURE:
        fprintf(stderr, "Password protected decoding failed. Likey incorrect password provided\n");
        break;
      case PS_UNSUPPORTED_FAIL:
        fprintf(stderr, "Unsupported key algorithm in certificate material\n");
        break;
    }
#endif
    destroy_spead_socket(x);
    destroy_shared_mem();
    matrixSslDeleteKeys(keys);
    matrixSslClose();
    return 1;
  }


  while (run){
  
    c = accept_spead_socket(x);
    if (c){
      
      switch(fork()){
        case -1:
#ifdef DEBUG
          fprintf(stderr, "%s: fork err (%s)\n", __func__, strerror(errno));
#endif
          break;
        
        /*child*/
        case 0:
          /*child process takes over the accept object*/
          child_process(c, keys);
          exit(EXIT_SUCCESS);
          break;

        /*parent*/
        default:
#ifdef DEBUG
          fprintf(stderr, "%s: close the child fd on the parent\n", __func__);
#endif
          /*server closes the file descriptor and frees the object but doesn't 
            shutdown the connection from accept*/
          close(c->c_fd);
          free(c);
          break;
      }
    }

  }

  destroy_spead_socket(x);
  destroy_shared_mem();
  matrixSslDeleteKeys(keys);
  matrixSslClose();

  return 0;
}