|
Hi
I try to configure SSL connecting that attack man-in-the-middle would be possible. I investigated your code for set up anonymous session without authentication, but could not think out anything.
Could you help me?
|
|
|
|
|
Hi
Is the first time that I write here.
I hope you can help me.
I have a problem with deployement in SSL connection with client certificate required from IIS.
Can you help me?
Have you got some complete example code in VB.NET (from client request, to SSL connection, to server response) or other?
I need for code example (getting start) for SSL communication.
Best regards.
Nicola
When you build an application, you can't say "It work!", but you can say only "I'm not yet saw where it doesn't work"!
-- modified at 12:17 Monday 9th October, 2006
|
|
|
|
|
Hello,
I really like the code. It is very useful and performs well. However, I am experiencing it having a lot of unreleased memory. If I create an application to constantly poll the server and the memory used by the server grows very very fast. It is not collected during or after server program execution.
The problem seems to be in the managed cpp SSL.dll I have not been able to resolve this.
Can you help?
Thanks,
DK
|
|
|
|
|
I followed all the procedures and installed openssl, generated a certificate, key.etc.
when i build the solution it gives me 2 errors
The referenced component 'SSL' could not be found.
The referenced component 'SSL' could not be found.
Please could anyone guide me
Thanks in advance
Ashok
|
|
|
|
|
i got the samw prob.. can anyone help?
busyboy
|
|
|
|
|
In VS2005, the Common\SSL\Debug\ or Common\SSL\Release\ directory needs to be added to the "Reference Paths" section of each project's properties for the debug and release configurations, respectively.
|
|
|
|
|
Hi,
I am using a self signed certificate to test my application. I have un-commented the line from the sample in SSLClient.cpp
SSL_CTX_set_verify(m_pSSLCtx, SSL_VERIFY_PEER, verify_callback);
I get an error which says
7000:error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify
failed:.\ssl\s3_clnt.c:894:
What could I be missing.
I have a MS CA installed on my machine and if I run this code against the certificated generated from the CA it works fine.
Thanks in advance,
sanju
|
|
|
|
|
Hi,
I want to use this lib for ftps but for the data-connection i have to use the same ssl-session as the control connection. How can i resume this ssl-session on another socket?
I´m using the MS SSPI SSL part.
Thanks already
Azrael
|
|
|
|
|
Hi Leon,
Nice code!
I translate this code to C++, but something does not work very well. In my program, some code is from Using SSPI with a Windows Sockets Clienthttp://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthn/security/using_sspi_with_a_windows_sockets_client.asp[^]. I want use the SSPI implement a smtp client to connect to Gmail server. The handshake and DectryptMessage is OK. But EnctryptMessage seem to occur error. Do you have any idea about this? Here is my code:
// SSPI.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "SSPI.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
//--------------------------------------------------------------------
// Client-side program to establish an SSPI socket connection
// with a server and exchange messages.
//--------------------------------------------------------------------
// Define macros and constants.
#define SECURITY_WIN32
#define BIG_BUFF 2048
#define SEC_SUCCESS(Status) ((Status) >= 0)
#define g_usPort 465
// The following #define statement must be changed. ServerName must be
// defined as the name of the computer running the server sample.
// TargetName must be defined as the logon name of the user running
// the server program.
#define ServerName "64.233.167.111" //gmail smtp
#define TargetName "64.233.167.111"
#define cbMaxMessage 12000
#define MessageAttribute (ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT |\
ISC_REQ_CONFIDENTIALITY | ISC_RET_EXTENDED_ERROR |\
ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM)
//#include <windows.h>
#include <winsock2.h>
#include <stdio.h>
#include <stdlib.h>
#include <sspi.h>
#include <schannel.h>
#include "security.h"
#ifdef __cplusplus
extern "C" {
#endif
void MyHandleError(char *s);
BOOL ConnectAuthSocket (
SOCKET *s,
CredHandle *hCred,
struct _SecHandle *hcText);
BOOL ReceiveBytes (
SOCKET s,
PBYTE pBuf,
DWORD cbBuf,
DWORD *pcbRead);
BOOL EncryptThis (
PBYTE pMessage,
ULONG cbMessage,
struct _SecHandle *hCtxt,
BYTE * pOutput,
ULONG * pcbOutput);
BOOL DecryptThis(
PBYTE pBuffer,
LPDWORD pcbMessage,
struct _SecHandle *hCtxt,
ULONG cbSecurityTrailer);
BOOL DoAuthentication (
SOCKET s,
CredHandle *hCred,
struct _SecHandle *hcText);
BOOL GenClientContext (
BYTE *pIn,
DWORD cbIn,
BYTE *pOut,
DWORD *pcbOut,
BOOL *pfDone,
CHAR *pszTarget,
CredHandle *hCred,
struct _SecHandle *hcText);
BOOL SendMsg (
SOCKET s,
PBYTE pBuf,
DWORD cbBuf);
BOOL ReceiveMsg (
SOCKET s,
PBYTE pBuf,
DWORD cbBuf,
DWORD *pcbRead);
void PrintHexDump(
DWORD length,
PBYTE buffer);
BOOL SendBytes (
SOCKET s,
PBYTE pBuf,
DWORD cbBuf);
void main()
{
SOCKET Client_Socket;
BYTE Data[BIG_BUFF];
PCHAR pMessage;
WSADATA wsaData;
CredHandle hCred;
struct _SecHandle hCtxt;
SECURITY_STATUS ss;
DWORD cbRead;
ULONG cbMaxSignature;
ULONG cbSecurityTrailer;
SecPkgContext_Sizes SecPkgContextSizes;
SecPkgContext_NegotiationInfo SecPkgNegInfo;
//-------------------------------------------------------------------
// Initialize the socket and the SSP security package.
//
if(WSAStartup (MAKEWORD( 2, 0 ), &wsaData))
{
MyHandleError("Could not initialize winsock ");
}
//--------------------------------------------------------------------
// Connect to a server
//
if (!ConnectAuthSocket (
&Client_Socket,
&hCred,
&hCtxt))
{
MyHandleError("Authenticated server connection ");
}
cbRead = recv(Client_Socket, (char*)Data, BIG_BUFF, 0);
DecryptThis(
Data,
&cbRead,
&hCtxt,
0);
printf ("The message from the server is \n -> %.*s \n", cbRead, Data);
BYTE pBuff[BIG_BUFF];// = (PBYTE) malloc(BIG_BUFF * sizeof(BYTE));
ULONG nLen = 0;
char* aCmd = "EHLO IVEN\r\n";
PBYTE pCmd = (PBYTE) malloc((strlen(aCmd) + 1) * sizeof(BYTE));
strcpy((char*)pCmd, aCmd);
EncryptThis(pCmd, 11, &hCtxt, pBuff, &nLen);
SendBytes(Client_Socket, pBuff, nLen);
BYTE csData[2048];
int len = recv(Client_Socket, (char*)csData, 2048, 0);
DecryptThis(
csData,
(LPDWORD)&len,
&hCtxt,
0);
printf ("The message from the server is \n -> %.*s \n", cbRead, Data);
//--------------------------------------------------------------------
// Terminate socket and security package.
//
DeleteSecurityContext (&hCtxt);
FreeCredentialHandle (&hCred);
shutdown (Client_Socket, 2);
closesocket (Client_Socket);
if (SOCKET_ERROR == WSACleanup ())
{
MyHandleError("Problem with socket cleanup ");
}
int x; scanf("%d", &x);
exit (EXIT_SUCCESS);
} // end main.
//--------------------------------------------------------------------
// ConnectAuthSocket establishes an authenticated socket connection
// with a server and initializes needed security package resources.
//
BOOL ConnectAuthSocket (
SOCKET *s,
CredHandle *hCred,
struct _SecHandle *hcText)
{
unsigned long ulAddress;
struct hostent *pHost;
SOCKADDR_IN sin;
//--------------------------------------------------------------------
// Lookup the server's address.
//
ulAddress = inet_addr (ServerName);
if (INADDR_NONE == ulAddress)
{
pHost = gethostbyname (ServerName);
if (NULL == pHost)
{
MyHandleError("Unable to resolve host name ");
}
memcpy((char FAR *)&ulAddress, pHost->h_addr, pHost->h_length);
}
//--------------------------------------------------------------------
// Create the socket
//
*s = socket (
PF_INET,
SOCK_STREAM,
0);
if (INVALID_SOCKET == *s)
{
MyHandleError("Unable to create socket");
}
else
{
printf("Socket created.\n");
}
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = ulAddress;
sin.sin_port = htons (g_usPort);
//--------------------------------------------------------------------
// Connect to the server.
//
if (connect (*s, (LPSOCKADDR) &sin, sizeof (sin)))
{
closesocket (*s);
MyHandleError( "Connect failed ");
}
//--------------------------------------------------------------------
// Authenticate the connection.
//
if (!DoAuthentication (
*s,
hCred,
hcText))
{
closesocket (*s);
MyHandleError("Authentication ");
}
return(TRUE);
} // end ConnectAuthSocket
BOOL DoAuthentication (
SOCKET s,
CredHandle *hCred,
struct _SecHandle *hcText)
{
BOOL fDone = FALSE;
DWORD cbOut = 0;
DWORD cbIn = 0;
PBYTE pInBuf;
PBYTE pOutBuf;
if(!(pInBuf = (PBYTE) malloc(cbMaxMessage)))
{
MyHandleError("Memory allocation ");
}
if(!(pOutBuf = (PBYTE) malloc(cbMaxMessage)))
{
MyHandleError("Memory allocation ");
}
cbOut = cbMaxMessage;
if (!GenClientContext (
NULL,
0,
pOutBuf,
&cbOut,
&fDone,
TargetName,
hCred,
hcText
))
{
return(FALSE);
}
if (!SendMsg (s, pOutBuf, cbOut ))
{
MyHandleError("Send message failed ");
}
while (!fDone)
{
if (!ReceiveMsg (
s,
pInBuf,
cbMaxMessage,
&cbIn))
{
MyHandleError("Receive message failed ");
}
cbOut = cbMaxMessage;
if (!GenClientContext (
pInBuf,
cbIn,
pOutBuf,
&cbOut,
&fDone,
TargetName,
hCred,
hcText))
{
MyHandleError("GenClientContext failed");
}
if (!SendMsg (
s,
pOutBuf,
cbOut))
{
MyHandleError("Send message 2 failed ");
}
}
//MyHandleError(_T("End"));
free(pInBuf);
free(pOutBuf);
return(TRUE);
}
BOOL GenClientContext (
BYTE *pIn,
DWORD cbIn,
BYTE *pOut,
DWORD *pcbOut,
BOOL *pfDone,
CHAR *pszTarget,
CredHandle *hCred,
struct _SecHandle *hcText)
{
SECURITY_STATUS ss;
TimeStamp Lifetime;
SecBufferDesc OutBuffDesc;
SecBuffer OutSecBuff;
SecBufferDesc InBuffDesc;
SecBuffer InSecBuffs[2];
ULONG ContextAttributes;
static TCHAR lpPackageName[1024];
PSCHANNEL_CRED pSChannelCred = new SCHANNEL_CRED;
memset(pSChannelCred, 0, sizeof(SCHANNEL_CRED));
pSChannelCred->dwVersion = SCHANNEL_CRED_VERSION;
pSChannelCred->grbitEnabledProtocols = SP_PROT_NONE;
pSChannelCred->dwFlags |= SCH_CRED_NO_DEFAULT_CREDS|SCH_CRED_MANUAL_CRED_VALIDATION;
if( NULL == pIn )
{
lstrcpy(lpPackageName, UNISP_NAME_A);
ss = AcquireCredentialsHandle (
NULL,
UNISP_NAME_A,
SECPKG_CRED_OUTBOUND,
NULL,
pSChannelCred,
NULL,
NULL,
hCred,
&Lifetime);
if (!(SEC_SUCCESS (ss)))
{
MyHandleError("AcquireCreds failed ");
}
}
delete pSChannelCred;
//--------------------------------------------------------------------
// Prepare the buffers
//
OutBuffDesc.ulVersion = 0;
OutBuffDesc.cBuffers = 1;
OutBuffDesc.pBuffers = &OutSecBuff;
OutSecBuff.cbBuffer = *pcbOut;
OutSecBuff.BufferType = SECBUFFER_TOKEN;
OutSecBuff.pvBuffer = NULL;
//-------------------------------------------------------------------
// The input buffer is created only if a message has been received from the server.
//
if (pIn)
{
InBuffDesc.ulVersion = 0;
InBuffDesc.cBuffers = 2;
InBuffDesc.pBuffers = InSecBuffs;
InSecBuffs[0].cbBuffer = cbIn;
InSecBuffs[0].BufferType = SECBUFFER_TOKEN;
InSecBuffs[0].pvBuffer = pIn;
InSecBuffs[1].cbBuffer = 0;
InSecBuffs[1].BufferType = SECBUFFER_EMPTY;
InSecBuffs[1].pvBuffer = NULL;
ss = InitializeSecurityContext (
hCred,
hcText,
NULL,
MessageAttribute,
0,
SECURITY_NATIVE_DREP,
&InBuffDesc,
0,
hcText,
&OutBuffDesc,
&ContextAttributes,
&Lifetime);
}
else
{
ss = InitializeSecurityContext (
hCred,
NULL,
"64.233.167.111",/*pszTarget,*/
MessageAttribute,
0,
SECURITY_NATIVE_DREP,
NULL,
0,
hcText,
&OutBuffDesc,
&ContextAttributes,
&Lifetime);
//pOut = static_cast<byte*>(OutBuffDesc.pBuffers->pvBuffer);
}
memcpy(pOut, OutBuffDesc.pBuffers->pvBuffer, OutBuffDesc.pBuffers->cbBuffer);
if (!SEC_SUCCESS (ss))
{
MyHandleError ("InitializeSecurityContext failed " );
}
//-------------------------------------------------------------------
// If necessary, complete the token.
//
if ((SEC_I_COMPLETE_NEEDED == ss)
|| (SEC_I_COMPLETE_AND_CONTINUE == ss))
{
ss = CompleteAuthToken (hcText, &OutBuffDesc);
if (!SEC_SUCCESS(ss))
{
fprintf (stderr, "complete failed: 0x%08x\n", ss);
return FALSE;
}
}
*pcbOut = OutSecBuff.cbBuffer;
*pfDone = !((SEC_I_CONTINUE_NEEDED == ss) ||
(SEC_I_COMPLETE_AND_CONTINUE == ss));
printf ("Token buffer generated (%lu bytes):\n", OutSecBuff.cbBuffer);
PrintHexDump (OutSecBuff.cbBuffer, (PBYTE)OutSecBuff.pvBuffer);
return TRUE;
}
BOOL EncryptThis (
PBYTE pMessage,
ULONG cbMessage,
struct _SecHandle *hCtxt,
BYTE * pOutput,
ULONG * pcbOutput)
{
SECURITY_STATUS ss;
SecBufferDesc BuffDesc;
SecBuffer SecBuff[4];
ULONG SigBufferSize;
char* pInBuf;
SecPkgContext_StreamSizes szStream;
ss = QueryContextAttributes(hCtxt, SECPKG_ATTR_STREAM_SIZES, &szStream);
if (!SEC_SUCCESS(ss))
{
fprintf (stderr, "QueryContextAttributes faild: 0x%08x\n", ss);
return(FALSE);
}
SigBufferSize = szStream.cbMaximumMessage + szStream.cbHeader + szStream.cbTrailer;
pInBuf = (char*) malloc(SigBufferSize);
if (!pInBuf)
{
printf(_T("Memery over erro!\r\n"));
exit (EXIT_FAILURE);
}
memcpy(pInBuf + szStream.cbHeader, pMessage, cbMessage);
printf ("Data before encryption: %s\n", pMessage);
printf ("Length of data before encryption: %d \n",cbMessage);
//------------------------------------------------------------------
// Prepare buffers
//
BuffDesc.ulVersion = 0;
BuffDesc.cBuffers = 4;
BuffDesc.pBuffers = SecBuff;
SecBuff[0].cbBuffer = szStream.cbHeader;
SecBuff[0].BufferType = SECBUFFER_STREAM_HEADER;
SecBuff[0].pvBuffer = pInBuf;
SecBuff[1].cbBuffer = cbMessage;
SecBuff[1].BufferType = SECBUFFER_DATA;
SecBuff[1].pvBuffer = pInBuf + szStream.cbHeader;
SecBuff[2].cbBuffer = szStream.cbTrailer;
SecBuff[2].BufferType = SECBUFFER_STREAM_TRAILER;
SecBuff[2].pvBuffer = pInBuf + szStream.cbHeader + szStream.cbTrailer;
SecBuff[3].cbBuffer = 0;
SecBuff[3].BufferType = SECBUFFER_EMPTY;
SecBuff[3].pvBuffer = NULL;
ss = EncryptMessage(
hCtxt,
0,
&BuffDesc,
0);
if (!SEC_SUCCESS(ss))
{
fprintf (stderr, "EncryptMessage failed: 0x%08x\n", ss);
return(FALSE);
}
else
{
printf("The message has been encrypted. \n");
}
*pcbOutput = SecBuff[0].cbBuffer + SecBuff[1].cbBuffer + SecBuff[2].cbBuffer;
memcpy (pOutput, pInBuf, *pcbOutput);
free(pInBuf);
printf ("data after encryption including trailer (%lu bytes):\n", *pcbOutput);
PrintHexDump (*pcbOutput, pOutput);
return TRUE;
} // end EncryptThis
BOOL DecryptThis(
PBYTE pBuffer,
LPDWORD pcbMessage,
struct _SecHandle *hCtxt,
ULONG cbSecurityTrailer)
{
BOOL bRet = FALSE;
SECURITY_STATUS ss;
SecBufferDesc BuffDesc;
SecBuffer SecBuff[4];
ULONG ulQop = 0;
PBYTE pSigBuffer;
void* pDataBuffer;
DWORD SigBufferSize;
//-------------------------------------------------------------------
// By agreement, the server encrypted the message and set the size
// of the trailer block to be just what it needed. DecryptMessage
// needs the size of the trailer block.
// The size of the trailer is in the first dword of the
// message received.
//
SigBufferSize = *pcbMessage;
printf ("data before decryption including trailer (%lu bytes):\n",
*pcbMessage);
PrintHexDump (*pcbMessage, (PBYTE) pBuffer);
//--------------------------------------------------------------------
// By agreement, the server placed the trailer at the beginning
// of the message sent right after the trailer size dword.
pSigBuffer = pBuffer;
//--------------------------------------------------------------------
// The data comes after the trailer.
//
//pDataBuffer = pSigBuffer;
//--------------------------------------------------------------------
// *pcbMessage is reset to the size of just the encrypted bytes.
//
//*pcbMessage = *pcbMessage - SigBufferSize - sizeof(DWORD);
//--------------------------------------------------------------------
// Prepare the buffers to be passed to the DecyrptMessage function.
//
BuffDesc.ulVersion = 0;
BuffDesc.cBuffers = 4;
BuffDesc.pBuffers = SecBuff;
SecBuff[0].cbBuffer = SigBufferSize;
SecBuff[0].BufferType = SECBUFFER_DATA;
SecBuff[0].pvBuffer = pSigBuffer;
SecBuff[1].cbBuffer = 0;
SecBuff[1].BufferType = SECBUFFER_EMPTY;
SecBuff[1].pvBuffer = NULL;
SecBuff[2].cbBuffer = 0;
SecBuff[2].BufferType = SECBUFFER_EMPTY;
SecBuff[2].pvBuffer = NULL;
SecBuff[3].cbBuffer = 0;
SecBuff[3].BufferType = SECBUFFER_EMPTY;
SecBuff[3].pvBuffer = NULL;
ss = DecryptMessage(
hCtxt,
&BuffDesc,
0,
NULL/*&ulQop*/);
if (!SEC_SUCCESS(ss))
{
fprintf(stderr, "DecryptMessage failed");
}
//-------------------------------------------------------------------
// Return a pointer to the decrypted data. The trailer data
// is discarded.
for(int i = 1; i < 4; i++)
{
if (SecBuff[i].BufferType == SECBUFFER_DATA)
{
pDataBuffer = SecBuff[i].pvBuffer;
*pcbMessage = bRet = SecBuff[i].cbBuffer;
break;
}
}
memcpy(pBuffer, pDataBuffer, bRet);
return bRet;
}
PBYTE VerifyThis(
PBYTE pBuffer,
LPDWORD pcbMessage,
struct _SecHandle *hCtxt,
ULONG cbMaxSignature)
{
SECURITY_STATUS ss;
SecBufferDesc BuffDesc;
SecBuffer SecBuff[2];
ULONG ulQop = 0;
PBYTE pSigBuffer;
PBYTE pDataBuffer;
//-------------------------------------------------------------------
// The global cbMaxSignature is the size of the signature
// in the message received.
printf ("data before verifying (including signature):\n");
PrintHexDump (*pcbMessage, pBuffer);
//--------------------------------------------------------------------
// By agreement with the server,
// the signature is at the beginning of the message received
// and the data that was signed comes after the signature.
//
pSigBuffer = pBuffer;
pDataBuffer = pBuffer + cbMaxSignature;
//-------------------------------------------------------------------
// The size of the message is reset to the size of the data only.
//
*pcbMessage = *pcbMessage - (cbMaxSignature);
//--------------------------------------------------------------------
// Prepare the buffers to be passed to the signature verification
// function.
//
BuffDesc.ulVersion = 0;
BuffDesc.cBuffers = 2;
BuffDesc.pBuffers = SecBuff;
SecBuff[0].cbBuffer = cbMaxSignature;
SecBuff[0].BufferType = SECBUFFER_TOKEN;
SecBuff[0].pvBuffer = pSigBuffer;
SecBuff[1].cbBuffer = *pcbMessage;
SecBuff[1].BufferType = SECBUFFER_DATA;
SecBuff[1].pvBuffer = pDataBuffer;
ss = VerifySignature(
hCtxt,
&BuffDesc,
0,
&ulQop
);
if (!SEC_SUCCESS(ss))
{
fprintf(stderr, "VerifyMessage failed");
}
else
{
printf("Message was properly signed.\n");
}
return pDataBuffer;
}// end VerifyThis
void PrintHexDump(
DWORD length,
PBYTE buffer)
{
DWORD i,count,index;
CHAR rgbDigits[]="0123456789abcdef";
CHAR rgbLine[100];
char cbLine;
for(index = 0; length; length -= count, buffer += count, index += count)
{
count = (length > 16) ? 16:length;
sprintf(rgbLine, "%4.4x ",index);
cbLine = 6;
for(i=0;i<count;i++)
="" {
="" rgbline[cbline++]="rgbDigits[buffer[i]">> 4];
rgbLine[cbLine++] = rgbDigits[buffer[i] & 0x0f];
if(i == 7)
{
rgbLine[cbLine++] = ':';
}
else
{
rgbLine[cbLine++] = ' ';
}
}
for(; i < 16; i++)
{
rgbLine[cbLine++] = ' ';
rgbLine[cbLine++] = ' ';
rgbLine[cbLine++] = ' ';
}
rgbLine[cbLine++] = ' ';
for(i = 0; i < count; i++)
{
if(buffer[i] < 32 || buffer[i] > 126)
{
rgbLine[cbLine++] = '.';
}
else
{
rgbLine[cbLine++] = buffer[i];
}
}
rgbLine[cbLine++] = 0;
printf("%s\n", rgbLine);
}
}
BOOL SendMsg (
SOCKET s,
PBYTE pBuf,
DWORD cbBuf)
{
if (0 == cbBuf)
return(TRUE);
//----------------------------------------------------------
// Send the size of the message.
//
//if (!SendBytes (s, (PBYTE)&cbBuf, sizeof (cbBuf)))
// return(FALSE);
//----------------------------------------------------------
// Send the body of the message.
//
if (!SendBytes (
s,
pBuf,
cbBuf))
{
return(FALSE);
}
return(TRUE);
}
BOOL ReceiveMsg (
SOCKET s,
PBYTE pBuf,
DWORD cbBuf,
DWORD *pcbRead)
{
DWORD cbRead;
DWORD cbData;
if (!ReceiveBytes (
s,
pBuf,
cbBuf,
&cbRead))
{
return(FALSE);
}
//if (cbRead != cbData)
// return(FALSE);
*pcbRead = cbRead;
return(TRUE);
} // end ReceiveMessage
BOOL SendBytes (
SOCKET s,
PBYTE pBuf,
DWORD cbBuf)
{
PBYTE pTemp = pBuf;
int cbSent;
int cbRemaining = cbBuf;
if (0 == cbBuf)
return(TRUE);
while (cbRemaining)
{
cbSent = send (
s,
(const char *)pTemp,
cbRemaining,
0);
if (SOCKET_ERROR == cbSent)
{
fprintf (stderr, "send failed: %u\n", GetLastError ());
return FALSE;
}
pTemp += cbSent;
cbRemaining -= cbSent;
}
return TRUE;
}
BOOL ReceiveBytes (
SOCKET s,
PBYTE pBuf,
DWORD cbBuf,
DWORD *pcbRead)
{
PBYTE pTemp = pBuf;
int cbRead, cbRemaining = cbBuf;
//while (cbRemaining)
{
cbRead = recv (
s,
(char *)pTemp,
cbRemaining,
0);
if (SOCKET_ERROR == cbRead)
{
fprintf (stderr, "recv failed: %u\n", GetLastError ());
return FALSE;
}
cbRemaining -= cbRead;
pTemp += cbRead;
}
*pcbRead = cbBuf - cbRemaining;
return TRUE;
} // end ReceiveBytes
void MyHandleError(char *s)
{
fprintf(stderr,"%s error. Exiting.\n",s);
int x; scanf("%d", &x);
exit (EXIT_FAILURE);
}
#ifdef __cplusplus
}
#endif
|
|
|
|
|
Hi Leon
First, thanks for the great article. This is the best article I've seen on SSPI for communicating with SSL with sockets. Anyway, this code , we have been using since 1 year with out any problems. But recently we encountered a problem.
When I am trying to read from a server response, we could able to read the complete message most of the times and able to get the SEC_E_OK, but few times we are getting SEC_I_CONTEXT_EXPIRED even after reading the complete data from the server. After analyzing the case, I came to a conclusion that due the extra buffers and SEC_I_CONTEXT_ EXPIRED, we are getting the Decryption Failed. Context Expired message.
And it is clear that server is closing the connection after sending the data.
Do you have any suggestion or correction to address the above issue?
Please help me.
Thanks & Regards
Shaik
|
|
|
|
|
First off, I want to thank you very much for the .Net C++ wrapper classes that you have created.
I have created a TCP Server and TCP Client library that basically shims in calls to the Microsoft SSP .Net C++ wrapper classes when the required connection is a secure connection. This all works great when I use the TCP Client library to talk to the TCP Server library.
My need is to have a Verifone Terminal connect up to a Terminal application server using my TCP Server library and I am receiving a SEC_E_ALGORITHM_MISMATCH 0x80090331 error.
To give you a little history, the previous Terminal application server was written in TCL (ugh) and it integrated with a TCL wrapper to the OpenSource SSL libraries. The Verifone Terminal supports OpenSource libraries and it appears to only support a single cipher.
This works fine:
When I look at the Client Hello message for a TCP Client that is using your Microsoft SSP .Net C++ wrapper class, I noticed that the Client Hello message was sent in the SSL 2.0 format, but stated that the version of SSL supported was 3.1. The SSL 2.0 format starts with 2 bytes that represent the length of the message, followed by the client hello identifier (1), followed by SSL Version (31), followed by the length of the ciphers (51 which is 17 ciphers), followed by length of sessionID (0), followed by length of challenge data (16), followed by the 17 ciphers (3 bytes for each cipher in SSL 2.0), followed by the 16 bytes of challenge data. I thought it was odd that the hello client was not sent in the SSL 3 / 3.1 format, but everything worked just fine.
This doesn't work:
When I look at the Client Hello message from the Verifone terminal, it was sent in the SSL 3.0 format. This format starts with 1 byte that represents the component type which is a handshake (22), followed by two bytes for SSL version (30), followed by two bytes for the length of the rest of the message (45), followed by handshake type (1) which is the client hello, followed by 3 bytes which represents the length of the client hello message (41), followed by 32 bytes of random numbers generated by the client, followed by length of sessionID (0), followed by length of cipher (2), followed by a single cipher (04), followed by length of compression (1), followed by compression value (0).
The format of the client hello message looks correct and it works with the TCL server that uses the OpenSource libraries just fine. The certificate was generated by the OpenSSL utility (PEM and privatekey). If the format of the client hello message was rejected by the Microsoft SSP AcceptSecurityContext call, I believe I would have received the following error, SEC_E_INVALID_TOKEN
0x80090308. The SEC_E_ALGORITHM_MISMATCH error appears to be that Microsoft SSP AcceptSecurityContext doesn't support the one cipher suite that the Verifone terminal is sending in its client hello; more on this in the next paragraph.
The cipher 0x00, 0x04 is the SSL_RSA_WITH_RC4_128_MD5 cipher suite. I believe this matches the 3 byte cipher 0x01, 0x00, 0x80 that was sent as one of the 17 cipher suites by the TCP Client using your wrapper library in the SSL 2.0 format. My thoughts are that the Microsoft SSP decided to use one of the other 17 cipher suites to communicate with the TCP Client that actually is working and it is rejecting the only cipher suite sent from the Verifone terminal SSL_RSA_WITH_RC4_128_MD5. The thing that has me puzzled is that the SSL_RSA_WITH_RC4_128_MD5 cipher suite is a pretty common one, right?
I've researched this problem for a couple of days now and am stuck. In the meantime, I will be integrating your OpenSSL wrapper and see if this does the trick, but I would rather use the Microsoft SSP wrapper if at all possible.
Thanks in advance,
Larry Herbinaux
|
|
|
|
|
The issue was that my SSLServer was set to only allow the TLS1 protocol. I added another enumeration value to the protocol enumeration defined in SSLCommon.h called SSL3_OR_TLS1 which just combinds the two enumeration values which are just bit mask values passed into the AcquireCredentialsHandleA method to allow SSL3 or TLS1 for both Client and Server. I initially set the protocol to SSL3 to determine that my problem was indeed the protocol bit flags and this dialed down my SSL Client from 3.1 to 3.0. I figured that it is best to set all the bit flags so that TLS clients don't necessarily get downgraded to 3.0.
The next problem that I ran into was that my certificate has both a Trusted Root and an Intermediate CA. The Microsoft SSP library sends the following handshake messages in a single SSL encrypted digest (ServerHello, Certificate, ServerHelloDone). The contents of the digest were 2396 bytes in length and the Verifone terminal has a problem processing more than 1024 bytes at a time. I was able to generate a self-signed SSL certificate and the SSL digest was reduced to 998 bytes, so the SSL handshake now works between the Verifone Terminal client and the Microsoft SSP implementation. I would rather not generate a self-signed certificate. Is there a way to send each of the handshake messages (ServerHello, Certificate, and ServerHelloDone) in separate SSL digests? Is there a way to only send the certificate without the chained CA certificates? The Verifone terminal doesn't validate the chained CA certificates (i.e. they don't store these on the terminal). The reason why I ask the questions above is due to some observations I had while analyzing the packets between the TCL OpenSSL Server and the Verifone terminal; see below.
The original TCL SSL (OpenSSL) server used a self-generated SSL Certificate, so the size of the certificate is smaller than the certificate chain above. The OpenSSL library appears to separate the (ServerHello, Certificate, and ServerHelloDone) messages into two separate SSL digests; they were around 500 and 400 bytes respectively. Another interesting fact is that I decided to generate a .PEM from my .cer of my chained certificate and when we had the TCL OpenSSL server use this .PEM, the size of the two handshake messages above were relatively the same. I expected the size on one of them to increase dramatically. This leads me to believe that the TCL OpenSSL server is just passing down the certificate to the Verifone client and does not additionally send the chained CA certificates.
|
|
|
|
|
The SSL client, SSL server classes are working fine for my distributed application. Both my client and Server are written in C#. I have installed a VeriSign certificate for the Server side and I am not using any certificate on the client side.
My issue now is, the client and the server continue to communicate successfully through SSL evenafter the Server side certificate has expired.
How should I handle this situation? Should the server app itself be made to fail to start when an expired certificate is configured for SSL handshake?
Thanks.
Regards,
Senthil.
|
|
|
|
|
Hi,
I don't know which SSL server/client you're using. In this sample you can handle this in ServerCertVerify on the client and check expiration date. All ssl client libraries allow to examine peer's SSL certificate. Normally client decides what to do. For example, Web Browsers display a warning and ask user if they want to continue communicating with the website. Since you control both sides you are free to do whatever you like.
Thanks
|
|
|
|
|
System.Net.HttpListener listener = new System.Net.HttpListener();
listener.Prefixes.Add("http://localhost/");
listener.Start();
HttpListenerContext context = listener.GetContext();
response = context.Response;
System.IO.Stream output = response.OutputStream;
SslStream sslStream = new SslStream(output);
for this code on last line it shows the error that "stream should be read write"
But the normal streaming with browser works with that output stream .
now if i use "SslStream(context.request.inputstream)"
i am getting null stream since the browser is not sending data to server.
only url,method properties give some data.
So what can i do to create SslStream connection between the server and browser
|
|
|
|
|
I am using sslstream class for accessing requests from client.
When connection is established between client and server through tcplistener class, I am calling authinticateserver using local certificates.
But i don't know how to handle message sent by authinticateserver on client side.And how to again send back message to server from client side.
PLease suggest me solution.
|
|
|
|
|
Hello,
I recently inherited a .net server app that communicates with its clients over a secure channel using TSL to authenticate the clients before any conversation takes place. This was working fine against .NET and Java 1.2 and 1.3 clients, but recently a problem appeared when one company upgraded their client to use Java 1.4. A colleague tracked the problem down to the following.
It seems that in TLS, when the server requests a certificate from the client, it (the server) sends down a list of the distinguished names of root certificates which it trusts. The problem is that this list only contains about 60 certificates - although the server itself has around 165 certificates in its 'Trusted Root Certificates' store. Most importantly, the certificate with the distinguished name <ou=secure server="" certification="" authority,o="RSA Data Security, Inc." ,c="US"> is not on this list - although it is installed on the server. The Java 1.4 client uses this root cert to back its client cert.
It appears that a .NET client can be made to ignore this list and send a cert even though it doesn't know that the server can validate it. Java 1.2 and 1.3 clients also ignore this list.
Java 1.4 and 1.5 clients, on the contrary, seem to rely upon the list, and use it to find a certificate in one of their certificate stores that can trace its authority back to one of the specified roots. This is, of course, perfectly correct behaviour.
This does mean that, when given a keystore containing a certificate and this list of root authorities, a Java SSL system will decide not to send a client certificate. This is the behaviour I've managed to produce using my own Java SSL cleint code and a stripped down .NET SSL server, with a lot of logging on the raw socket data. If the Java client has a certificate that traces its authority back to one of the listed root certificates, then it happily sends the certificate to the server. If it's absent then no certificate is submitted.
Any ideas why our SSL stack won't send all the certificates it trusts in client handshaking, and correct this behaviour? We're some way out of our comfort levels now.
|
|
|
|
|
Hi,
Are you sure the CA certificates that sit in your Trusted Root are marked as trusted for client authentication? Not all certificates are sent, only those that fulfill the certificate usage.
Please enable SChannel logging if using it on the server.
http://support.microsoft.com/?id=260729
Check any events in the Events Viewer, such as
Event,Warning: 36885: "When asking for client authentication, this server sends a list of trusted certificate authorities to the client. The client uses this list to choose a client certificate that is trusted by the server. Currently, this server trusts so many certificate authorities that the list has grown too long. This list has thus been truncated. The administrator of this machine should review the certificate authorities trusted for client authentication and remove those that do not really need to be trusted."
To see if your list is indeed truncated more likely the CA certificate is not trusted for client authentication.
Hope it helps
Thanks
|
|
|
|
|
Hi,
That seems to have fixed it. The CA cert wasn't set up for client authentication. Thanks muchly for figuring that out for us.
dan
|
|
|
|
|
Hi Leon,
This project is a nice piece of work. I have been looking for code that helps me in a project and yours looks like a very good starting point. I found little in the way of the actual SSL protocol and your project has it built in. Here is the situation:
My web server needs to talk to another secure app server on the internet. This needs to be done using SSL v3.0 at a port other than 443..(which I think means this is not HTTPS) The folks who run the app server sent me the RSA Private key and a certificate. Normally they want us to use 3 dlls that they supply and just pass my info into a send() call. Two of the dlls are libs from OpenSSL and theirs is the one that contains their send function. They told me I can talk directly to their server but they won't supply any source in how they do this in their supplied dll. I don't want to use the OpenSSL.
I would like to have a Microsoft solution like your project. The certificate and RSA key they sent me is in a pem file. (I don't know if it can be converted to a X509...) I think I can modify the SetupCredentials() method to use CertCreateCertificateContext instead of reading the cert store with CertFindCertificateInStore. I just need to figure out how to do that.
The next item I would like to do is change the project to an excluseively .NET C# managed code project and use classes like the RSACryptoServiceProvider. It appears the SSL project is an unmanaged code project. Is this correct? If I change it to a managed code project I would have to use PInvoke for the calls to the SSPI library. Do you agree?
Can you comment on any of this and make suggestions as to what may or may not or what should or should not be done if I used your project as a starting point?
Thanks and again, nice work.
Gery
|
|
|
|
|
Hi,
You can easily convert from .pem to PKCS12 (.pfx) using openssl:
from .pem to .pfx:
openssl pkcs12 -export -out cert.pfx -inkey userkey.pem -in usercert.pem
Then double click on generated .pfx and follow the wizard.
The sample is unmanaged (MC++) project, but you can access it from C#.
If you change it to C#, yes you'll have to use PInvoke.
Take a look at this .NET library with source:
http://www.mentalis.org/soft/projects/seclib/
Also, OpenSSL will do the job just fine.
Thanks a lot
|
|
|
|
|
If I run the client in other computer, it's not work if i don't install the Cert on this computer . < The Cert install only on computer's Chatserv .> ......but if the Cert is intalled, it work fine.
is there any way to make it work in the first case ?
VANNAM
|
|
|
|
|
On server side you can do:
.AskClientForAuth = false;
On client side:
conn.InitiateHandShake(url, null, SSL.Common.Misc.SecurityProviderProtocol.PROT_NONE, Guid.Empty);
//null for cert. ThumbPrint
|
|
|
|
|
Using the .Net SDK "MakeCert" utility (without specifying any options) I created a test certificate. When I placed this certificate in the "MY (Personal)" store, the SSLServer App failed at the AcquireCredentialsHandleA() system call with Error SEC_E_INTERNAL_ERROR. This got rectified when I moved this same certificate to the "Trusted Root Certification Authorities".
Coming to my real problem, the SSLClient application is hanging when it tries to connect to the SSLServer (i.e., the HandShakeSuccess() never gets invoked since the SSLServer App is rejecting the connection request coming from this SSLClient). What actually happens at the SSLServer end is:
New Connection from 127.0.0.1:2243 with Client ID: c49fbb8e-2893-4e49-a218-22d0c3477d87
Read: 70 bytes from 127.0.0.1:2243
Sent: 484 bytes to 127.0.0.1:2243
Read: 118 bytes from 127.0.0.1:2243
Removing Dead Connection, Client ID: c49fbb8e-2893-4e49-a218-22d0c3477d87
Active Connections: 0
This same behaviour gets logged at the server end irrespective of whether the Client App is using a ThumbPrint (which I am passing the same as the ThumbPrint used by the SSLServer) for the InitiateHandShake() call or I use "null".
Kindly please guide me further to overcome my stumbling blocks.
Thanks.
Senthil SS.
|
|
|
|
|
Hi,
* You have to specify some options to makecert.exe:
makecert -r -pe -n "CN=Test" -b 01/01/2004 -e 01/01/2006 -eku 1.3.6.1.5.5.7.3.1 -ss MY -sr CurrentUser -a sha1 -len 2096
* On some platforms (specifically servers) you should use -sy 12
option as one of the makecert.exe
args. What this does is it tells makecert to
store the private key under PROV_RSA_SCHANNEL
instead of default PROV_RSA_FULL.
* Please Enable SSL Logging:
http://support.microsoft.com/?id=260729
When AcquireCredentialsHandle fails and after enabling SSL logging
check Events Viewer for anything interesting.
Most likely you'll see an error about accessing
certificates private key.
* It could be related to the fact that account
from which your SSL server is running doesn't have access
to the private key. You can download this WinHttpCertCfg tool:
http://www.microsoft.com/downloads/details.aspx?familyid=c42e27ac-3409-40e9-8667-c748e422833f&displaylang=en
You can run it as follows (for your case):
winhttpcertcfg -l -c LOCAL_MACHINE\root -s TV
It will output something similar to:
Matching certificate:
CN=TV
Additional accounts and groups with access to the private key include:
BUILTIN\Administrators
NT AUTHORITY\SYSTEM
More pointers:
http://groups.google.com/groups?selm=%233k7OPMpCHA.2524%40TK2MSFTNGP12
http://groups.google.com/groups?q=SEC_E_UNKNOWN_CREDENTIALS
Thanx
I hope this helps
|
|
|
|
|