SSPI implement SSL
- From: ivenxu@xxxxxxxxx
- Date: 28 Feb 2006 21:17:23 -0800
Hi All
Happy coding : )
I want implement a smtp client for gmail. In my code I use the SSPI to
implement the SSL. 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[^].
The handshake and DectryptMessage is OK. But EnctryptMessage seem to
occur error. dos any one have any idea about this?
Here is my code:
#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
#include
#include
#include
#include
#include
#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(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 {
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
.
- Prev by Date: Application crash
- Next by Date: how to set variable in Work space of VC++
- Previous by thread: Application crash
- Next by thread: how to set variable in Work space of VC++
- Index(es):
Relevant Pages
|