Esempio n. 1
0
static int32 initializeResumedHandshake(sslConn_t *clnConn, sslConn_t *svrConn,
										testCipherSpec_t cipherSuite)
{
	sslSessionId_t	*sessionId;
#ifdef ENABLE_PERF_TIMING
	psTime_t		start, end;
#endif /* ENABLE_PERF_TIMING */	
	
	sessionId = clnConn->ssl->sid;
	
	matrixSslDeleteSession(clnConn->ssl);

#ifdef ENABLE_PERF_TIMING
	clnConn->runningTime = 0;
	psGetTime(&start);
#endif /* ENABLE_PERF_TIMING */	
	if (matrixSslNewClientSession(&clnConn->ssl, clnConn->keys, sessionId,
			cipherSuite.cipherId, clnCertChecker, NULL, NULL) < 0) {
        return PS_FAILURE;
    }
#ifdef ENABLE_PERF_TIMING
	psGetTime(&end);
	clnConn->runningTime += psDiffMsecs(start, end);
#endif /* ENABLE_PERF_TIMING */
	
	matrixSslDeleteSession(svrConn->ssl);
#ifdef ENABLE_PERF_TIMING
	svrConn->runningTime = 0;
	psGetTime(&start);
#endif /* ENABLE_PERF_TIMING */		
	if (matrixSslNewServerSession(&svrConn->ssl, svrConn->keys, NULL) < 0) {
        return PS_FAILURE;
    }
#ifdef ENABLE_PERF_TIMING
	psGetTime(&end);
	svrConn->runningTime += psDiffMsecs(start, end);
#endif /* ENABLE_PERF_TIMING */	
	return PS_SUCCESS;
}
Esempio n. 2
0
static int32 initializeClientAuthHandshake(sslConn_t *clnConn,
					sslConn_t *svrConn, uint32 cipherSuite, sslSessionId_t *sid)
{
#ifdef ENABLE_PERF_TIMING
	psTime_t		start, end;
#endif /* ENABLE_PERF_TIMING */	

	matrixSslDeleteSession(clnConn->ssl);
#ifdef ENABLE_PERF_TIMING
	clnConn->runningTime = 0;
	psGetTime(&start);
#endif /* ENABLE_PERF_TIMING */	
	if (matrixSslNewClientSession(&clnConn->ssl, clnConn->keys, sid,
			cipherSuite, clnCertChecker, NULL, NULL, newSessionFlag) < 0) {
        return PS_FAILURE;
    }
#ifdef ENABLE_PERF_TIMING
	psGetTime(&end);
	clnConn->runningTime += psDiffMsecs(start, end);
#endif /* ENABLE_PERF_TIMING */
	
	matrixSslDeleteSession(svrConn->ssl);
#ifdef ENABLE_PERF_TIMING
	svrConn->runningTime = 0;
	psGetTime(&start);
#endif /* ENABLE_PERF_TIMING */		
	if (matrixSslNewServerSession(&svrConn->ssl, svrConn->keys, svrCertChecker,
			newSessionFlag)	< 0) {
        return PS_FAILURE;
    }
#ifdef ENABLE_PERF_TIMING
	psGetTime(&end);
	svrConn->runningTime += psDiffMsecs(start, end);
#endif /* ENABLE_PERF_TIMING */		
	return PS_SUCCESS;
}
Esempio n. 3
0
int matrixssl_freebuf(int fp)
{
	int i = 0;

	for (i = 0; i < MAX_MATRIXSSL_SESSIONS; i++) {
		if (bufs[i]->fp == fp) {
			matrixSslDeleteSession(bufs[i]->ssl);
			free(bufs[i]->ssl_recv_buf);
			free(bufs[i]->ssl_send_buf);
			free(bufs[i]);
			bufs[i] = NULL;
			no_matrixssl_sessions--;
			return 0;
		}
	}

	return -1;
}
Esempio n. 4
0
void SSL_free(SSL * ssl) {
  syslog(LOG_DEBUG, "Matrix SSL_Free()");
  if (ssl->ssl)
    matrixSslDeleteSession(ssl->ssl);
  ssl->ssl = 0;
  if (ssl->insock.buf) {
    free(ssl->insock.buf);
    ssl->insock.buf = 0;
  }
  if (ssl->outsock.buf) {
    free(ssl->outsock.buf);
    ssl->outsock.buf = 0;
  }
  if (ssl->inbuf.buf) {
    free(ssl->inbuf.buf);
    ssl->inbuf.buf = 0;
  }
  free(ssl);
}
Esempio n. 5
0
void SSL_free(SSL * ssl) {
  log_dbg("Matrix SSL_Free()");
  if (ssl->ssl)
    matrixSslDeleteSession(ssl->ssl);
  ssl->ssl = 0;
  if (ssl->insock.buf) {
    free(ssl->insock.buf);
    ssl->insock.buf = 0;
  }
  if (ssl->outsock.buf) {
    free(ssl->outsock.buf);
    ssl->outsock.buf = 0;
  }
  if (ssl->inbuf.buf) {
    free(ssl->inbuf.buf);
    ssl->inbuf.buf = 0;
  }
  free(ssl);
}
Esempio n. 6
0
/*
	Close a seesion that was opened with sslAccept or sslConnect and
	free the insock and outsock buffers
*/
void sslFreeConnection(sslConn_t **cpp)
{
	sslConn_t	*conn;
	conn = *cpp;
	matrixSslDeleteSession(conn->ssl);
	conn->ssl = NULL;
	if (conn->insock.buf) {
		free(conn->insock.buf);
		conn->insock.buf = NULL;
	}
	if (conn->outsock.buf) {
		free(conn->outsock.buf);
		conn->outsock.buf = NULL;
	}
	if (conn->inbuf.buf) {
		free(conn->inbuf.buf);
		conn->inbuf.buf = NULL;
	}
	free(conn);
	*cpp = NULL;
}
Esempio n. 7
0
/*
	Create a new server SSL session
	This creates internal SSL buffers and cipher structures
	Internal SSL state is set to expect an incoming 'HelloRequest'

	Return	MATRIXSSL_SUCCESS on success
			< 0 on error
 */
int32 matrixSslNewServerSession(ssl_t **ssl, sslKeys_t *keys,
			int32 (*certCb)(ssl_t *ssl, psX509Cert_t *cert, int32 alert),
			int32 flags)
{
	ssl_t		*lssl;
	int32		lflags = SSL_FLAGS_SERVER;
	
	if (!ssl) {
		return PS_ARG_FAIL;
	}
	
	lflags |= flags;
	*ssl = NULL;
	lssl = NULL;
	
#ifdef USE_CLIENT_AUTH	
	if (certCb) {
		lflags |= SSL_FLAGS_CLIENT_AUTH;
		if (matrixSslNewSession(&lssl, keys, NULL, lflags) < 0) {
			goto NEW_SVR_ERROR;
		}
		matrixSslSetCertValidator(lssl, (sslCertCb_t)certCb);
	} else if (matrixSslNewSession(&lssl, keys, NULL, lflags) < 0) {
		goto NEW_SVR_ERROR;
	}
#else
	psAssert(certCb == NULL);
	if (matrixSslNewSession(&lssl, keys, NULL, lflags) < 0) {
		goto NEW_SVR_ERROR;
	}
#endif /* USE_CLIENT_AUTH */
	
	lssl->maxPtFrag = SSL_MAX_PLAINTEXT_LEN;
	*ssl = lssl;
	return MATRIXSSL_SUCCESS;
	
NEW_SVR_ERROR:
	if (lssl) matrixSslDeleteSession(lssl);
	return PS_FAILURE;
}
Esempio n. 8
0
/*
	Close a socket and free associated SSL context and buffers
 */
static void closeConn(httpConn_t *cp, int32 reason)
{
	unsigned char	*buf;
	int32			len;
	
	DLListRemove(&cp->List);
	/* Quick attempt to send a closure alert, don't worry about failure */
	if (matrixSslEncodeClosureAlert(cp->ssl) >= 0) {
		if ((len = matrixSslGetOutdata(cp->ssl, &buf)) > 0) {
			if ((len = send(cp->fd, buf, len, MSG_DONTWAIT)) > 0) {
				matrixSslSentData(cp->ssl, len);
			}
		}
	}
	if (cp->parsebuf != NULL) {
		psAssert(cp->parsebuflen > 0);
		free(cp->parsebuf);
		cp->parsebuflen = 0;
	}

	matrixSslDeleteSession(cp->ssl);
#ifdef USE_SERVER_NAME_INDICATION
	if (sni_keys) {
		matrixSslDeleteKeys(sni_keys);
		sni_keys = NULL;
	}
#endif

	if (cp->fd != INVALID_SOCKET) {
		close(cp->fd);
	}
	if (reason >= 0) {
/*		_psTraceInt("=== Closing Client %d ===\n", cp->fd); */
	} else {
		_psTraceInt("=== Closing Client %d on Error ===\n", cp->fd);
	}
	free(cp);
}
Esempio n. 9
0
/*
	Close a socket and free associated SSL context and buffers
	An attempt is made to send a closure alert
 */
static void closeConn(ssl_t *ssl, SOCKET fd)
{
	unsigned char	*buf;
	int32			len;
	
	/* Set the socket to non-blocking to flush remaining data */
#ifdef POSIX
	fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
#elif WIN32
	len = 1;		/* 1 for non-block, 0 for block */
    ioctlsocket(fd, FIONBIO, &len);
#endif
	/* Quick attempt to send a closure alert, don't worry about failure */
	if (matrixSslEncodeClosureAlert(ssl) >= 0) {
		if ((len = matrixSslGetOutdata(ssl, &buf)) > 0) {
			if ((len = send(fd, buf, len, MSG_DONTWAIT)) > 0) {
				matrixSslSentData(ssl, len);
			}
		}
	}
	matrixSslDeleteSession(ssl);
	if (fd != INVALID_SOCKET) close(fd);
}
Esempio n. 10
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;	
}
Esempio n. 11
0
/*
	Make a secure HTTP request to a defined IP and port
	Connection is made in blocking socket mode
	The connection is considered successful if the SSL/TLS session is
	negotiated successfully, a request is sent, and a HTTP response is received.
 */
static int32 httpsClientConnection(sslKeys_t *keys, sslSessionId_t *sid)
{
	int32			rc, transferred, len, complete;
	ssl_t			*ssl;
	unsigned char	*buf;
	httpConn_t		cp;
	SOCKET			fd;
	
	complete = 0;
	memset(&cp, 0x0, sizeof(httpConn_t));
	fd = socketConnect(HTTPS_IP, HTTPS_PORT, &rc);
	if (fd == INVALID_SOCKET || rc != PS_SUCCESS) {
		_psTraceInt("Connect failed: %d.  Exiting\n", rc);
		return PS_PLATFORM_FAIL;
	}
	
	rc = matrixSslNewClientSession(&ssl, keys, sid, 0, certCb, NULL, NULL);
	if (rc != MATRIXSSL_REQUEST_SEND) {
		_psTraceInt("New Client Session Failed: %d.  Exiting\n", rc);
		close(fd);
		return PS_ARG_FAIL;
	}
WRITE_MORE:
	while ((len = matrixSslGetOutdata(ssl, &buf)) > 0) {
		transferred = send(fd, buf, len, 0);
		if (transferred <= 0) {
			goto L_CLOSE_ERR;
		} else {
			/* Indicate that we've written > 0 bytes of data */
			if ((rc = matrixSslSentData(ssl, transferred)) < 0) {
				goto L_CLOSE_ERR;
			}
			if (rc == MATRIXSSL_REQUEST_CLOSE) {
				closeConn(ssl, fd);
				return MATRIXSSL_SUCCESS;
			} 
			if (rc == MATRIXSSL_HANDSHAKE_COMPLETE) {
				/* If we sent the Finished SSL message, initiate the HTTP req */
				/* (This occurs on a resumption handshake) */
				if (httpWriteRequest(ssl) < 0) {
					goto L_CLOSE_ERR;
				}
				goto WRITE_MORE;
			}
			/* SSL_REQUEST_SEND is handled by loop logic */
		}
	}
READ_MORE:
	if ((len = matrixSslGetReadbuf(ssl, &buf)) <= 0) {
		goto L_CLOSE_ERR;
	}
	if ((transferred = recv(fd, buf, len, 0)) < 0) {
		goto L_CLOSE_ERR;
	}
	/*	If EOF, remote socket closed. But we haven't received the HTTP response 
		so we consider it an error in the case of an HTTP client */
	if (transferred == 0) {
		goto L_CLOSE_ERR;
	}
	if ((rc = matrixSslReceivedData(ssl, (int32)transferred, &buf,
									(uint32*)&len)) < 0) {
		goto L_CLOSE_ERR;
	}
	
PROCESS_MORE:
	switch (rc) {
		case MATRIXSSL_HANDSHAKE_COMPLETE:
#ifdef REHANDSHAKE_TEST
/*
			Test rehandshake capabilities of server.  If a successful
			session resmption rehandshake occurs, this client will be last to
			send handshake data and MATRIXSSL_HANDSHAKE_COMPLETE will hit on
			the WRITE_MORE handler and httpWriteRequest will occur there.
			
			NOTE: If the server doesn't support session resumption it is
			possible to fall into an endless rehandshake loop
*/
			if (matrixSslEncodeRehandshake(ssl, NULL, NULL, 0, 0) < 0) {
				goto L_CLOSE_ERR;
			}
#else		
			/* We got the Finished SSL message, initiate the HTTP req */
			if (httpWriteRequest(ssl) < 0) {
				goto L_CLOSE_ERR;
			}
#endif
			goto WRITE_MORE;
		case MATRIXSSL_APP_DATA:
			if ((rc = httpBasicParse(&cp, buf, len)) < 0) {
				closeConn(ssl, fd);
				if (cp.parsebuf) free(cp.parsebuf); cp.parsebuf = NULL;
				cp.parsebuflen = 0;
				return MATRIXSSL_ERROR;
			}
			if (rc == HTTPS_COMPLETE) {
				rc = matrixSslProcessedData(ssl, &buf, (uint32*)&len);
				closeConn(ssl, fd);
				if (cp.parsebuf) free(cp.parsebuf); cp.parsebuf = NULL;
				cp.parsebuflen = 0;
				if (rc < 0) {
					return MATRIXSSL_ERROR;
				} else {
					if (rc > 0) {
						_psTrace("HTTP data parsing not supported, ignoring.\n");
					}
					_psTrace("SUCCESS: Received HTTP Response\n");
					return MATRIXSSL_SUCCESS;
				}
			}
			/* We processed a partial HTTP message */
			if ((rc = matrixSslProcessedData(ssl, &buf, (uint32*)&len)) == 0) {
				goto READ_MORE;
			}
			goto PROCESS_MORE;
		case MATRIXSSL_REQUEST_SEND:
			goto WRITE_MORE;
		case MATRIXSSL_REQUEST_RECV:
			goto READ_MORE;
		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));
				goto L_CLOSE_ERR;
			}
			/* Closure alert is normal (and best) way to close */
			if (*(buf + 1) == SSL_ALERT_CLOSE_NOTIFY) {
				closeConn(ssl, fd);
				if (cp.parsebuf) free(cp.parsebuf); cp.parsebuf = NULL;
				cp.parsebuflen = 0;
				return MATRIXSSL_SUCCESS;
			}
			psTraceIntInfo("Warning alert: %d\n", *(buf + 1));
			if ((rc = matrixSslProcessedData(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 */
			goto L_CLOSE_ERR;
	}
	
L_CLOSE_ERR:
	_psTrace("FAIL: No HTTP Response\n");
	matrixSslDeleteSession(ssl);
	close(fd);
	if (cp.parsebuf) free(cp.parsebuf); cp.parsebuf = NULL;
	cp.parsebuflen = 0;
	return MATRIXSSL_ERROR;
}
Esempio n. 12
0
int32_t matrixSslNewClientSession(ssl_t **ssl, const sslKeys_t *keys,
				sslSessionId_t *sid,
				const uint16_t cipherSpec[], uint8_t cipherSpecLen,
				sslCertCb_t certCb,
				const char *expectedName, tlsExtension_t *extensions,
				sslExtCb_t extCb,
				sslSessOpts_t *options)
{
	ssl_t		*lssl;
	psBuf_t		tmp;
	uint32		len;
	int32		rc, i;

	if (!ssl) {
		return PS_ARG_FAIL;
	}
	if (cipherSpecLen > 0 && (cipherSpec == NULL || cipherSpec[0] == 0)) {
		return PS_ARG_FAIL;
	}
	if (options == NULL) {
		return PS_ARG_FAIL;
	}

	*ssl = NULL;
	lssl = NULL;

	/* Give priority to cipher suite if session id is provided and doesn't match */
	if (cipherSpec != NULL && cipherSpec[0] != 0 && sid != NULL &&
			sid->cipherId != 0) {
		rc = 1;
		for (i = 0; i < cipherSpecLen; i++) {
			if (cipherSpec[i] == sid->cipherId) {
				rc = 0;
			}
		}
		if (rc) {
			psTraceInfo("Explicit cipher suite will override session cache\n");
			memset(sid->id, 0, SSL_MAX_SESSION_ID_SIZE);
			memset(sid->masterSecret, 0, SSL_HS_MASTER_SIZE);
			sid->cipherId = 0;
		}
	}

	if ((rc = matrixSslNewSession(&lssl, keys, sid, options)) < 0) {
		return rc;
	}
	lssl->userPtr = options->userPtr;

#ifndef USE_ONLY_PSK_CIPHER_SUITE
	if (expectedName) {
		if (psX509ValidateGeneralName((char*)expectedName) < 0) {
			matrixSslDeleteSession(lssl);
			return rc;
		}
		rc = strlen(expectedName);
		lssl->expectedName = psMalloc(lssl->sPool, rc + 1);
		strcpy(lssl->expectedName, expectedName);
	}
	if (certCb) {
		matrixSslSetCertValidator(lssl, certCb);
	}
#endif
	if (extCb) {
		lssl->extCb = extCb;
	}
RETRY_HELLO:
	tmp.size = lssl->outsize;
	tmp.buf = tmp.start = tmp.end = lssl->outbuf;
	if ((rc = matrixSslEncodeClientHello(lssl, &tmp, cipherSpec, cipherSpecLen,
			&len, extensions, options)) < 0) {
		if (rc == SSL_FULL) {
			if ((tmp.buf = psRealloc(lssl->outbuf, len, lssl->bufferPool))
					== NULL) {
				matrixSslDeleteSession(lssl);
				return PS_MEM_FAIL;
			}
			lssl->outbuf = tmp.buf;
			lssl->outsize = len;
			goto RETRY_HELLO;
		} else {
			matrixSslDeleteSession(lssl);
			return rc;
		}
	}
	psAssert(tmp.start == tmp.buf);
	lssl->outlen = tmp.end - tmp.start;
	*ssl = lssl;
	return MATRIXSSL_REQUEST_SEND;
}
Esempio n. 13
0
void child_process(struct spead_client *cl, sslKeys_t *keys)
{
#define BUFF   1000 
//#define REPLY   "HTTP/1.1 200 OK\nServer: pshr\nConnection: Keep-Alive\nContent-Type: audio/mpeg\nCache-Control: no-cache\nPragma: no-cache\n\n"
#define REPLY   "HTTP/1.1 200 OK\nServer: pshr\nConnection: Keep-Alive\nContent-Type: text/plain\nCache-Control: no-cache\nPragma: no-cache\n\nhello world"
#define MODE_CONNECTING 0
#define MODE_SENDING    1  

  //int bytes, mode = MODE_CONNECTING;
  //unsigned char data[BUFF];
  
  unsigned char *data, *res;
  uint32 err, len ,rb, wb;
  ssl_t *ssl;
  //int fd = (-1), initial=1450-300;
  
  data = NULL;
  res  = NULL;
  ssl  = NULL;

  if (cl == NULL || keys == NULL){
#ifdef DEBUG
    fprintf(stderr, "%s: parameter error\n", __func__);
#endif
    exit(EXIT_FAILURE);
  }


#ifdef DEBUG
  fprintf(stderr, "%s: child created with fd[%d]\n", __func__, cl->c_fd);
#endif
  
  err = matrixSslNewServerSession(&ssl, keys, NULL, 0);
  if (err != PS_SUCCESS){
#ifdef DEBUG
    switch(err){
      case PS_ARG_FAIL:
        fprintf(stderr, "Bad input function parameter\n");
        break;
      case PS_FAILURE:
        fprintf(stderr, "Internal memory allocation failure\n");
        break;
    }
#endif
#if 0
    matrixSslDeleteKeys(keys);
    matrixSslClose();
#endif
    exit(EXIT_FAILURE);
  }

  while(run){

READ_STATE:
    len = matrixSslGetReadbuf(ssl, &data);
    if (rb < 0){
#ifdef DEBUG
      fprintf(stderr, "%s: matrixssl getreadbuf error\n", __func__);
#endif
      matrixSslDeleteSession(ssl);
      destroy_spead_client(cl);
      exit(EXIT_FAILURE);
    }

#ifdef DEBUG
    fprintf(stderr, "%s: matrixssl getreadbuf rtn [%d]\n", __func__, len);
#endif

    rb = read(cl->c_fd, data, len);
    if (rb == 0){
#ifdef DEBUG
      fprintf(stderr, "%s: read EOF\n", __func__);
#endif
      matrixSslDeleteSession(ssl);
      destroy_spead_client(cl);
      exit(EXIT_FAILURE);
    } else if (rb < 0){
#ifdef DEBUG
      fprintf(stderr, "%s: read error (%s)\n", __func__, strerror(errno));
#endif
      matrixSslDeleteSession(ssl);
      destroy_spead_client(cl);
      exit(EXIT_FAILURE);
    }

#ifdef DEBUG
    fprintf(stderr, "%s: read rtn [%d]\n", __func__, rb);
#endif

    rb = matrixSslReceivedData(ssl, rb, &data, &len);
    if (rb < 0){
#ifdef DEBUG
      fprintf(stderr, "%s: matrixssl receiveddata error\n", __func__);
#endif
      matrixSslDeleteSession(ssl);
      destroy_spead_client(cl);
      exit(EXIT_FAILURE);
    } else if (rb == 0){
#ifdef DEBUG
      fprintf(stderr, "%s: matrix ssl received 0 bytes (false start?)\n", __func__);
#endif
    } else if (rb > 0){
      switch(rb){
        case MATRIXSSL_REQUEST_SEND:
#ifdef DEBUG
          fprintf(stderr, "%s: RS req send\n", __func__);
#endif
          goto WRITE_STATE;
          break;
        case MATRIXSSL_REQUEST_RECV:
#ifdef DEBUG
          fprintf(stderr, "%s: RS req recv\n", __func__);
#endif  
          goto READ_STATE;
          break;
        case MATRIXSSL_HANDSHAKE_COMPLETE:
#ifdef DEBUG
          fprintf(stderr, "%s: RS handshake complete\n", __func__);
#endif
          goto READ_STATE;
          break;
        case MATRIXSSL_RECEIVED_ALERT:
#ifdef DEBUG
          fprintf(stderr, "%s: RS rec alert\n", __func__);
#endif
          break;
        case MATRIXSSL_APP_DATA:
#ifdef DEBUG
          fprintf(stderr, "%s: RS app data\n", __func__);
#endif

#ifdef DEBUG
          fprintf(stderr, "%s: RS got data [%s]\n", __func__, data);
#endif
          
          /*process client data here*/
  
          res = get_resource_str(data);
          if (res == NULL){
#ifdef DEBUG
            fprintf(stderr, "%s: NULL RESOURCE\n", __func__);        
#endif
            run = 0;
          }

#ifdef DEBUG
          fprintf(stderr, "%s: got resource [%s]\n", __func__, res); 
#endif
                    
          unsigned char *tbuf;
          int32 tbuflen;

          tbuflen = matrixSslGetWritebuf(ssl, &tbuf, strlen(REPLY));
          if (tbuflen < 0){
#ifdef DEBUG
            fprintf(stderr, "%s: matrixssl getwritebuf error\n", __func__);
#endif
            matrixSslDeleteSession(ssl);
            destroy_spead_client(cl);
            exit(EXIT_FAILURE);
          }
          
          strncpy((char *) tbuf, REPLY, tbuflen);
          
          if (matrixSslEncodeWritebuf(ssl, strlen((char *) tbuf)) < 0){
            matrixSslDeleteSession(ssl);
            destroy_spead_client(cl);
            exit(EXIT_FAILURE);
          }

          matrixSslEncodeClosureAlert(ssl);

          rb = matrixSslProcessedData(ssl, &data, &len);
          
#ifdef DEBUG
          fprintf(stderr, "%s: processed data rtn [%d]\n", __func__, rb);
#endif

          goto WRITE_STATE;
          
          break;
      }

    }

WRITE_STATE:
    len = matrixSslGetOutdata(ssl, &data);
    if (len < 0){
#ifdef DEBUG
      fprintf(stderr, "%s: matrixssl getoutdata error\n", __func__);
#endif
      matrixSslDeleteSession(ssl);
      destroy_spead_client(cl);
      exit(EXIT_FAILURE);
    }

#ifdef DEBUG
    fprintf(stderr, "%s: getoutdata rtn [%d]\n", __func__, len);
#endif
    
    wb = write(cl->c_fd, data, len);
    if (wb == 0){
#ifdef DEBUG
      fprintf(stderr, "%s: write 0\n", __func__);
#endif
      goto READ_STATE;
    } else if (wb < 0){
#ifdef DEBUG
      fprintf(stderr, "%s: write error (%s)\n", __func__, strerror(errno));
#endif
      matrixSslDeleteSession(ssl);
      destroy_spead_client(cl);
      exit(EXIT_FAILURE);
    }

#ifdef DEBUG
    fprintf(stderr, "%s: write rtn [%d]\n", __func__, wb);
#endif
    
    wb = matrixSslSentData(ssl, wb);
    if (wb < 0) {
      #ifdef DEBUG
      fprintf(stderr, "%s: matrixssl sentdata error\n", __func__);
#endif
      matrixSslDeleteSession(ssl);
      destroy_spead_client(cl);
      exit(EXIT_FAILURE);
    } else if (wb > 0){
      switch(wb){
        case MATRIXSSL_REQUEST_SEND:
#ifdef DEBUG
          fprintf(stderr, "%s: WS req send\n", __func__);
#endif
          goto WRITE_STATE;
          break;
        case MATRIXSSL_REQUEST_CLOSE:
#ifdef DEBUG
          fprintf(stderr, "%s: WS req close\n", __func__);
#endif  
          matrixSslDeleteSession(ssl);
          destroy_spead_client(cl);
          exit(EXIT_FAILURE);
          break;
        case MATRIXSSL_HANDSHAKE_COMPLETE:
#ifdef DEBUG
          fprintf(stderr, "%s: WS handshake complete\n", __func__);
#endif
          goto READ_STATE; /*note might need to jump to receiveddata*/
          break;
      }

    }

  }

  matrixSslDeleteSession(ssl);

#if 0
  const char *filename = "/home/adam/live_audio_streaming/tenc/agoria-scala_original_mixwww.mp3vip.org.mp3";

  //fd = open("/home/adam/build/lame-3.99.5/testcase.mp3", O_RDONLY);
  fd = open("/home/adam/live_audio_streaming/tenc/agoria-scala_original_mixwww.mp3vip.org.mp3", O_RDONLY);
  if (fd < 0){
#ifdef DEBUG
    fprintf(stderr, "%s: open error (%s)\n", __func__, strerror(errno));
#endif
    exit(EXIT_SUCCESS);
  }

  while((bytes = read_ssl(ssl, data, BUFF)) > 0){
#ifdef DEBUG
    fprintf(stderr, "%s: read [%d] [%s:%d] [%s]\n", __func__, bytes, get_client_address(cl), get_client_port(cl), data);
#endif
  }
#endif
  
#if 0
  while (run){

    switch (mode){
      
      case MODE_CONNECTING:
        
        bytes = read_ssl(ssl, data, BUFF);
        switch (bytes){
          case 0:
#ifdef DEBUG
            fprintf(stderr, "%s: read EOF client[%s:%d]\n", __func__, get_client_address(cl), get_client_port(cl));
#endif
            run = 0;
            break;

          case -1:
#ifdef DEBUG
            fprintf(stderr, "%s: read error client[%s:%d] (%s)\n", __func__, get_client_address(cl), get_client_port(cl), strerror(errno));
#endif
            run = 0;
            break;
        }

#ifdef DEBUG
        fprintf(stderr, "%s: [%s:%d] [%s]\n", __func__, get_client_address(cl), get_client_port(cl), data);
#endif
        
        res = get_resource_str(data);
        if (res == NULL){
#ifdef DEBUG
          fprintf(stderr, "%s: NULL RESOURCE\n", __func__);        
#endif
          run = 0;
        }
  
#ifdef DEBUG
       fprintf(stderr, "%s: got resource [%s]\n", __func__, res); 
#endif
       
       if (strncmp(res, "/sound", 6) == 0){
         bytes = write_ssl(ssl, REPLY, sizeof(REPLY));
         switch(bytes){
           case -1:
#ifdef DEBUG
             fprintf(stderr, "%s: write error client[%s:%d] (%s)\n", __func__, get_client_address(cl), get_client_port(cl), strerror(errno));
#endif
             run = 0;
             break;
         }
         mode = MODE_SENDING;
       } else {
         run = 0;
       }
       break;


      case MODE_SENDING:
#if 0
        bytes = sendfile(cl->c_fd, fd, NULL, BUFF+initial);
        if (bytes == 0){
          close(fd);
#if 0
          fd = open("/srv/beats/Meditations On Afrocentrism EP/03 Down The Line (It Takes A Number).mp3", O_RDONLY);
          if (fd < 0){
#ifdef DEBUG
            fprintf(stderr, "%s: open error (%s)\n", __func__, strerror(errno));
#endif
            exit(EXIT_SUCCESS);
          }
#endif
        } else if (bytes < 0){
#ifdef DEBUG
          fprintf(stderr, "%s: sendfile error client[%s:%d] (%s)\n", __func__, get_client_address(cl), get_client_port(cl), strerror(errno));
#endif
          exit(EXIT_SUCCESS);
        }

        if (initial > 1){
          initial--;
        } 

#if 0
def DEBUG
        fprintf(stderr, "%s: [%s:%d] sent %d bytes\n", __func__, get_client_address(cl), get_client_port(cl), bytes);
#endif
        usleep(9766/initial);
#endif    
        run = 0;
        break;
    }
  }
#endif

#ifdef DEBUG
  fprintf(stderr, "%s: child[%d] ending\n", __func__, getpid());
#endif

#if 0
  if (fd > 0){
    close(fd);
  } 
#endif

  destroy_spead_client(cl);
  //shutdown(cl->c_fd, SHUT_RDWR);
  exit(EXIT_SUCCESS);
}
Esempio n. 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;
}