Thanks for reply matt.Yeah your correct I want implement completely from
starch as my agenda is to have complete manged code in my server app and i
did't find any manged manged crypto library with will is compatable with
Open SSL Client. Client will still remain using with Open SSL libraries
.There will not be any changes in client appWhen can i find the complete low
level details including the raw byte structure of initial handshake between
the client and server and the internal logic used for encryption and
decryption.I am understood of how Diffie Hellman works but i need to know
how Open SSL client excepts initial handshake for exchange of DH public
parameters.Here is my current server code which uses Open SSL . I want to
rewrite this part with my own implementation in c# with out using Open SSL
Libraries.#include "StdAfx.h"#include "sslserver.h"namespace OSSL{
namespace
Server { // Global declarations int listenSd;
/// /// SSLServer
Initialises SSL context and load Diffie HielMann parameters ///
SSLServer::SSLServer(String* DHFilePath) {
try { m_pIDClientsList =
new CLIENTS_LIST(); m_pcsClients = new
CRITICAL_SECTION();
m_pcsAcceptThreadLoop = new CRITICAL_SECTION();
// Initialise of SSL
Init(); //
win32_locking_callback
InitializeCriticalSection(m_pcsClients);
InitializeCriticalSection(m_pcsAcceptThreadLoop);
// Set the Diffe
HielMann parameters
LoadDHParams(m_pSSLCtx,DHFilePath); // Keep the
acceptor socket running until stopped from BNG
m_shouldStopAcceptThread =
false; } catch(Exception* ex)
{ // Event entry
LogManager::Instance->WriteEntry("SSLServer:",ex); }
} /// ///
Initialise SSL context /// SSL_CTX * SSLServer::Init()
{ // Create a
new SSL_CTX object m_pSSLCtx =
SSL_CTX_new(SSLv23_server_method()); //
SSL_CTX couldnt be created if(m_pSSLCtx == NULL)
{
LogManager::Instance->WriteEntry("SSLServer:Init:SSL_CTX could not be
created"); }
SSL_CTX_set_verify(m_pSSLCtx,SSL_VERIFY_NONE,NULL);
SSL_CTX_set_options(m_pSSLCtx, SSL_OP_ALL |
SSL_OP_NO_SSLv2|SSL_OP_SINGLE_DH_USE);
// Set cipher list
"ADH:@STRENGTH" if(1 != SSL_CTX_set_cipher_list(m_pSSLCtx,
"ADH:@STRENGTH")) {
LogManager::Instance->WriteEntry("SSLServer:Init:Error in ADH:Strength");
} return m_pSSLCtx; } ///
/// Accept TCP/IP Connections from the
clients /// /// Returns false if the accept
socket could not be bound.
bool SSLServer::AcceptConnections() { int
fileDescriptor; struct
sockaddr_in socketServer; struct sockaddr_in
socketClient; size_t
clientLength; // Create a socket and bind
listenSd =
socket(AF_INET, SOCK_STREAM, 0); memset (&socketServer,
'\0',
sizeof(socketServer)); socketServer.sin_family = AF_INET;
socketServer.sin_addr.s_addr = INADDR_ANY;
socketServer.sin_port =
htons(ConfigManager::GetConfigAsInt(Constants::TcpPortNumber));
int
bindRes = bind(listenSd, (struct sockaddr*) &socketServer,
sizeof(socketServer)); // If the listener socket could not be
bound, throw
an exception and return immediately if (bindRes < 0)
{ Exception*
bindEx = new Exception("Could not bind TCP port. Service will shutdown.");
LogManager::Instance->WriteEntry("SSLServer::AcceptConnecetions", bindEx);
return false; } while(1)
{ // See if the thread has been requested
to stop by BNG if (GetShouldStopAcceptThread())
{ break;
}
try { // Listen for
incoming connections listen (listenSd,
99); clientLength = sizeof(socketClient);
// Accept the
connection fileDescriptor = accept(listenSd,
(struct sockaddr*)
&socketClient, (int*) &clientLength);
// Get client ipaddress
String* ipAddress = socketClient.sin_addr.S_un.S_un_b.s_b1.ToString();
ipAddress =
ipAddress->Concat(ipAddress,".",socketClient.sin_addr.S_un.S_un_b.s_b2.ToString());
ipAddress =
ipAddress->Concat(ipAddress,".",socketClient.sin_addr.S_un.S_un_b.s_b3.ToString());
ipAddress =
ipAddress->Concat(ipAddress,".",socketClient.sin_addr.S_un.S_un_b.s_b4.ToString());
// Store the new client information pClientData =
new
CLIENTDATA(m_pSSLCtx); pClientData->IpAddress =
DotNetStringToCppString(ipAddress); // Check if
initialization for new
client failed if(pClientData->m_FailedInit)
{ // Event entry
Exception* ex = new Exception("pClientData->m_FailedInit failed");
LogManager::Instance->WriteEntry("SSLServer:AcceptConnections",ex);
}
// Set the socket file descriptor
SSL_set_fd(pClientData->m_pSSL,
fileDescriptor);
// Perform SSL Handshake
if(SSL_accept(pClientData->m_pSSL) <=0) {
// Event entry
String *errorLog;
errorLog->Concat("Error in SSL handshake on accept
from ", ipAddress); Exception* ex = new
Exception(errorLog);
LogManager::Instance->WriteEntry("SSLServer:AcceptConnections",ex);
}
else { try
{
// Store the Client information by mapping to
its File descriptor value
EnterCriticalSection(m_pcsClients);
(*m_pIDClientsList)[fileDescriptor] = pClientData;
LeaveCriticalSection(m_pcsClients); }
catch(Exception* ex)
{
LeaveCriticalSection(m_pcsClients);
LogManager::Instance->WriteEntry("SSLServer:AcceptConnections:Error in
adding client information",ex); }
} }
catch(std::exception&
e) {
closesocket(listenSd); Exception* ex =
new
Exception("std::exception& e");
LogManager::Instance->WriteEntry("Connection lost.
SSLServer:AcceptConnections.", ex); }
catch (...) {
closesocket(listenSd);
LogManager::Instance->WriteEntry("Connection
lost. SSLServer:AcceptConnections."); }
} closesocket(listenSd);
return true; } /// /// Get the incoming
messages from clients via
SSL_read /// void SSLServer::ReadData()
{ int nRead = 0; int Error =
0; int rc = 0; int max_sd = 0;
char buf[10000]; fd_set selectFD;
timeval timeout; // clear all File descriptors from
Select list before
calling Select() API FD_ZERO(&selectFD);
// Iterate through the client
information std::map<int, CLIENTDATA __nogc*>::iterator i =
m_pIDClientsList->begin(); for(;i !=
m_pIDClientsList->end();++i) {
// Get the Max value of the File descriptor max_sd =
max(i->first,max_sd); FD_SET(i->first,&selectFD);
} // If the max
value of File Descriptor is zero, then do nothing
if(max_sd == 0) {
return; } // Set the timeout interval for
Select timeout.tv_sec = 0;
timeout.tv_usec = 10*10; rc = select(max_sd
+1,&selectFD,NULL,NULL,&timeout); // If Select operation
failed on the
available File descriptors if(rc<0)
{ // Event entry
Exception* ex
= new Exception("Select() failed");
LogManager::Instance->WriteEntry("SSLServer:ReadData",ex);
return; }
// If none of the clients are currently communicating, then
// Just look
up for incoming data a little while later if(rc==0)
{ return; }
// Loop for all the clients for(i=
m_pIDClientsList->begin(); i !=
m_pIDClientsList->end();) {
// Get the File Descriptor of the client
int sock = i->first; // Check if this client if
currently sending data
if(FD_ISSET(sock,&selectFD)) {
try {
EnterCriticalSection(m_pcsClients);
// Get the incoming data from the
client nRead =
SSL_read(i->second->m_pSSL, buf, 10000);
Error =
SSL_get_error(i->second->m_pSSL, nRead);
LeaveCriticalSection(m_pcsClients); }
catch (...)
{
LogManager::Instance->WriteEntry("Stopped. SSLServer:ReadData:Error in
SSL_read");
LeaveCriticalSection(m_pcsClients);
return; }
// Check if the data is obtained successfully
if(nRead > 0) {
Byte data[] = new Byte[nRead];
Marshal::Copy(IntPtr(buf), data, 0,
nRead);
//LogManager::Instance->WriteEntry(String::Format("SSL {0}
bytes read", Convert::ToString(nRead)));
// Send data to BNG
Application
PassDataToBNG(data,i->second->IpAddress.c_str() ,
nRead,sock);
// Delete the allocated memory
delete [] data;
data = NULL; }
else {
// If there was any error in getting
client's data /*if(Error ==
SSL_ERROR_ZERO_RETURN) {
Exception* ex = new Exception("SSL READ FAILED");
LogManager::Instance->WriteEntry("SSLServer:ReadData:
SSL_ERROR_ZERO_RETURN",ex); }
else*/ if(Error == SSL_ERROR_SSL)
{ Exception* ex = new
Exception("SSL READ FAILED");
LogManager::Instance->WriteEntry("SSLServer:ReadData: SSL_ERROR_SSL",ex);
} else if(Error ==
SSL_ERROR_WANT_READ) {
Exception* ex =
new Exception("SSL READ FAILED");
LogManager::Instance->WriteEntry("SSLServer:ReadData:
SSL_ERROR_WANT_READ",ex); }
else if(Error == SSL_ERROR_WANT_WRITE)
{ Exception* ex = new
Exception("SSL READ FAILED");
LogManager::Instance->WriteEntry("SSLServer:ReadData:
SSL_ERROR_WANT_WRITE",ex); }
else
{ Exception* ex =
new
Exception("SSL READ FAILED");
LogManager::Instance->WriteEntry("Client
connection lost. SSLServer:ReadData. SSL READ FAILED");
} // Raise
the Disconnect event, as the client has disconnected
SendDisconnectEvent(i->second->IpAddress.c_str(),sock);
// Close the
socket and remove the client's information, as we dont need it
closesocket(sock);
DisconnectFromClient(i->first);
FD_CLR(sock,
&selectFD); // Iterate through the
loop from the beginning i=
m_pIDClientsList->begin();
continue; }
// Clear off the
File descriptor value from SelectFD list
FD_CLR(sock, &selectFD); }
// Process for the next client ++i;
} } /// /// Send the outgoing
client messages vie SSL_Write /// void
SSLServer::SendData(int
fileDescriptor, Byte data[], int length) {
EnterCriticalSection(m_pcsClients); int nBytesWritten= 0;
int Error = 0;
int max_sd = 0; timeval timeout; int rc
= 0; fd_set selectFD;
//
clear all File descriptors from Select list before calling Select() API
FD_ZERO(&selectFD); const unsigned char __pin* pBuf =
&data[0];
CLIENTDATA* pClientData; try {
// Check and get the Client info based
on the File descriptor value
if(GetClientInfo(fileDescriptor,pClientData)) {
try {
max_sd
= fileDescriptor;
FD_SET(fileDescriptor,&selectFD);
// Set the
timeout interval for Select
timeout.tv_sec = 60; timeout.tv_usec
=
0; rc = select(max_sd
+1,NULL,&selectFD,NULL,&timeout);
if(rc >0)
{
if(FD_ISSET(fileDescriptor,&selectFD))
{
//LogManager::Instance->WriteEntry(String::Format("Writing {0} bytes",
Convert::ToString(length)));
// Send the data to the client
nBytesWritten = SSL_write(pClientData->m_pSSL,pBuf,length);
Error =
SSL_get_error(pClientData->m_pSSL,nBytesWritten);
} }
else
{ char error_buf[100];
if(rc == -1)
rc =
WSAGetLastError();
sprintf_s(error_buf, "SSL WRITE FAILED: ErrorCode:
%d", rc); Exception* ex =
new Exception(error_buf);
LogManager::Instance->WriteEntry("SSLServer:SendData : Select() call failed
on write",ex); }
} catch (...)
{ //
"Error" is logged
below }
// Check if there was any error in SSL write
if(Error !=
SSL_ERROR_NONE) {
if(Error == SSL_ERROR_ZERO_RETURN)
{
Exception* ex = new Exception("SSL WRITE FAILED");
LogManager::Instance->WriteEntry("SSLServer:SendData:
SSL_ERROR_ZERO_RETURN",ex); }
else if(Error == SSL_ERROR_SSL)
{ Exception* ex = new
Exception("SSL WRITE FAILED");
LogManager::Instance->WriteEntry("SSLServer:SendData: SSL_ERROR_SSL",ex);
} else if(Error ==
SSL_ERROR_WANT_READ) {
Exception* ex =
new Exception("SSL WRITE FAILED");
LogManager::Instance->WriteEntry("SSLServer:SendData:
SSL_ERROR_WANT_READ",ex); }
else if(Error == SSL_ERROR_WANT_WRITE)
{ Exception* ex = new
Exception("SSL WRITE FAILED");
LogManager::Instance->WriteEntry("SSLServer:SendData:
SSL_ERROR_WANT_WRITE",ex); }
else
{ Exception* ex =
new
Exception("SSL WRITE FAILED");
LogManager::Instance->WriteEntry("SSLServer:SendData",ex);
} }
ERR_remove_state(0); } }
catch(Exception* ex) {
LogManager::Instance->WriteEntry("SSLServer:SendData:Exception in sending
data",ex); }
LeaveCriticalSection(m_pcsClients); } ///
/// Load the
Diffe HellMann parameters from the file /// DH*
SSLServer::LoadDHParams(SSL_CTX * m_pSSLCtx,String* DHFilePath) {
// Get
the filepath from App.config file char* DHFile =
(char*)(void*)Marshal::StringToHGlobalAnsi(DHFilePath);
// Load the BIO
with the DH parameters BIO *bio(BIO_new_file(DHFile,"r"));
if(! bio) {
// Event entry Exception* ex = new Exception("Error in
loading the DH
file");
LogManager::Instance->WriteEntry("SSLServer:LoadDHParams",ex);
} dh1024=PEM_read_bio_DHparams(bio,NULL,NULL,NULL);
// Set the DH
paramters to the SSL Context
if(SSL_CTX_set_tmp_dh(m_pSSLCtx,dh1024)<0)
{ // Event entry
Exception* ex = new Exception("Error in setting DH
parameters for SSL_CTX_set_tmp_dh");
LogManager::Instance->WriteEntry("SSLServer:LoadDHParams",ex);
}
BIO_free(bio); Marshal::FreeHGlobal(DHFile);
return dh1024; } ///
/// Convert System::String* to std::string ///
std::string
SSLServer::DotNetStringToCppString(System::String* dotNetString)
{ char*
str = (char*)(void*)Marshal::StringToHGlobalAnsi(dotNetString);
std::string ret(str); Marshal::FreeHGlobal(str);
return ret; } ///
/// Disconnect the client and remove client's information ///
void
SSLServer::DisconnectFromClient(int fileDescriptor) {
try {
CLIENTDATA* pClientData; pClientData =
(*m_pIDClientsList)[fileDescriptor];
SSL_shutdown(pClientData->m_pSSL);
RemoveClient(fileDescriptor); }
catch(Exception* ex) {
LogManager::Instance->WriteEntry("SSLServer:DisconnectFromClient",ex);
}
} /// /// Gets the clientInfo based on the
file descriptor ///
bool SSLServer::GetClientInfo(int fileDescriptor, CLIENTDATA __nogc*&
pClientData) { bool returnValue = false;
EnterCriticalSection(m_pcsClients); if(m_pIDClientsList ==
NULL) {
LeaveCriticalSection(m_pcsClients); return
returnValue; } // Look for
the client based on the File descriptor CLIENTS_LIST::iterator
iter =
m_pIDClientsList->find(fileDescriptor); if(iter !=
m_pIDClientsList->end()) {
pClientData = iter->second; returnValue =
true; } else {
returnValue = false; }
LeaveCriticalSection(m_pcsClients); return returnValue;
} /// ///
Remove the client's information /// void
SSLServer::RemoveClient(int
fileDescriptor) {
EnterCriticalSection(m_pcsClients);
if(m_pIDClientsList != NULL) {
CLIENTS_LIST::iterator iter =
m_pIDClientsList->find(fileDescriptor); if(iter !=
m_pIDClientsList->end()) {
delete iter->second;
iter->second =
NULL;
m_pIDClientsList->erase(fileDescriptor); }
}
LeaveCriticalSection(m_pcsClients); } ///
/// Free all used memory ///
void SSLServer::Dispose(bool disposing) {
ERR_remove_state(0);
if(m_pIDClientsList != NULL) {
EnterCriticalSection(m_pcsClients);
CLIENTS_LIST::iterator iter = m_pIDClientsList->begin();
for(; iter !=
m_pIDClientsList->end(); iter++) {
delete iter->second;
iter->second = NULL; }
m_pIDClientsList->erase(m_pIDClientsList->begin(), m_pIDClientsList->end());
delete m_pIDClientsList; m_pIDClientsList =
NULL;
LeaveCriticalSection(m_pcsClients); }
if(!disposing) {
DeleteCriticalSection(m_pcsClients); delete
m_pcsClients; m_pcsClients
= NULL; DeleteCriticalSection(m_pcsAcceptThreadLoop);
delete
m_pcsAcceptThreadLoop; m_pcsAcceptThreadLoop = NULL;
m_pSSLMethod =
NULL; if(m_pSSLCtx != NULL)
{ // Free allocated SSL_CTX object
SSL_CTX_free(m_pSSLCtx); m_pSSLCtx =
NULL; } } }
/// ///
Closes the listener socket /// void
SSLServer::CloseSockets() {
closesocket(listenSd); } /// /// Returns the
flag which tells SSLServer
whether or not to exit the socket accept thread /// bool
SSLServer::GetShouldStopAcceptThread() { bool
result;
EnterCriticalSection(m_pcsAcceptThreadLoop); result =
m_shouldStopAcceptThread;
LeaveCriticalSection(m_pcsAcceptThreadLoop);
return result; } /// /// Sets the flag which
tells SSLServer whether or
not to exit the socket accept thread /// void
SSLServer::SetShouldStopAcceptThread(bool shouldStop) {
EnterCriticalSection(m_pcsAcceptThreadLoop);
m_shouldStopAcceptThread =
shouldStop; LeaveCriticalSection(m_pcsAcceptThreadLoop);
} }}
--
View this message in context:
http://openssl.6102.n7.nabble.com/Diffie-hellman-Open-SSL-Client-and-C-Server-tp47524p47527.html
Sent from the OpenSSL - User mailing list archive at Nabble.com.