#define WIN32_LEAN_AND_MEAN
#include <assert.h>
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>
#define SECURITY_WIN32 1
#include <Security.h>
#include <WinCrypt.h>
#include <schannel.h>
#include <string.h>
#define SERVER_CERTIFICATE_SUBJECT_NAME "C=US,ST=Ks,L=Olathe,O=XYZ LTD,OU=ABC,CN=Server7,
[email protected]"
#pragma comment(lib, "Ws2_32.lib")
#pragma comment(lib, "Advapi32.lib")
#pragma comment(lib,"Secur32.lib")
#pragma comment(lib,"Crypt32.lib")
#define DEFAULT_BUFLEN 100
#define DEFAULT_PORT "27015"
int context_expire = 0;
static DWORD EncryptSend(SOCKET Socket, CtxtHandle * phContext, PBYTE pbIoBuffer, SecPkgContext_StreamSizes Sizes);
int ReadDecrypt(SOCKET Socket, PCredHandle phCreds, CtxtHandle * phContext, PBYTE pbIoBuffer, DWORD cbIoBufferLength, char* message, int messagelen);
PBYTE ExtraEncBuff;
#define ExtraMemorySize 1024
unsigned int ExtraEncBufferSize = 0;
unsigned int ExtraEncBufferLen = 0;
char *ExtraDecBuff=NULL;
unsigned int ExtraDecBufferSize = 0;
unsigned int ExtraDecBufferLen = 0;
static int
ssl_default_callback_read(SOCKET fd, void *buf, int num)
{
int rc;
do {
{
while (((rc = recv(fd, buf, num, 0)) == -1) && ((NT_WSA2errno ()) == EINTR || (NT_WSA2errno ()) == EINPROGRESS));
};
} while (rc < 0 &&
((NT_WSA2errno ()) == EAGAIN || (NT_WSA2errno()) == EWOULDBLOCK) &&
ssl_wait_for_socket(fd, 1) > 0);
if (rc < 0)
printf("cannot recv data from socket %d", (int)fd);
return rc;
}
static int
ssl_default_callback_write(SOCKET fd, void *buf, int num)
{
int rc;
do
{
{
while (((rc = send(fd, buf, num, 0)) == -1) && ((NT_WSA2errno ()) == EINTR || (NT_WSA2errno ()) == EINPROGRESS));
};
} while (rc < 0 &&
((NT_WSA2errno ()) == EAGAIN || (NT_WSA2errno ()) == EWOULDBLOCK) &&
ssl_wait_for_socket(fd, 0) > 0);
if (rc < 0)
printf("cannot send data to socket %d", (int)fd);
return rc;
}
#define ESHUTDOWN 58
static int
NT_WSA2errno()
{
int ret;
switch (WSAGetLastError()) {
case WSAEACCES: ret = EACCES; break;
case WSAEADDRINUSE: ret = EADDRINUSE; break;
case WSAEADDRNOTAVAIL: ret = EADDRNOTAVAIL; break;
case WSAEAFNOSUPPORT: ret = EAFNOSUPPORT; break;
case WSAEALREADY: ret = EALREADY; break;
case WSAEBADF: ret = EBADF; break;
case WSAECONNABORTED: ret = ECONNABORTED; break;
case WSAECONNREFUSED: ret = ECONNREFUSED; break;
case WSAECONNRESET: ret = ECONNRESET; break;
case WSAEDESTADDRREQ: ret = EDESTADDRREQ; break;
case WSAEFAULT: ret = EFAULT; break;
case WSAEHOSTUNREACH: ret = EHOSTUNREACH; break;
case WSAEINPROGRESS: ret = EINPROGRESS; break;
case WSAEINTR: ret = EINTR; break;
case WSAEINVAL: ret = EINVAL; break;
case WSAEISCONN: ret = EISCONN; break;
case WSAELOOP: ret = ELOOP; break;
case WSAEMFILE: ret = EMFILE; break;
case WSAEMSGSIZE: ret = EMSGSIZE; break;
case WSAENAMETOOLONG: ret = ENAMETOOLONG; break;
case WSAENETDOWN: ret = ENETDOWN; break;
case WSAENETRESET: ret = EBADF; break;
case WSAENETUNREACH: ret = ENETUNREACH; break;
case WSAENOBUFS: ret = ENOBUFS; break;
case WSAENOPROTOOPT: ret = ENOPROTOOPT; break;
case WSAENOTCONN: ret = ENOTCONN; break;
case WSAENOTEMPTY: ret = ENOTEMPTY; break;
case WSAENOTSOCK: ret = EBADF; break;
case WSAEOPNOTSUPP: ret = EBADF; break;
case WSAEPROTONOSUPPORT: ret = EPROTONOSUPPORT; break;
case WSAEPROTOTYPE: ret = EPROTOTYPE; break;
case WSAESHUTDOWN: ret = ESHUTDOWN; break;
case WSAETIMEDOUT: ret = ETIMEDOUT; break;
case WSAEWOULDBLOCK: ret = EWOULDBLOCK; break;
case WSA_INVALID_PARAMETER: ret = EINVAL; break;
case WSA_NOT_ENOUGH_MEMORY: ret = ENOMEM; break;
case WSANOTINITIALISED: ret = ENETDOWN; break;
default: ret = WSAGetLastError(); break;
}
return ret;
}
#define SELECT_TIMEOUT_MS 200
static int
ssl_wait_for_socket(SOCKET fd, int mode_read)
{
int rc;
fd_set fds, *read_fds, *write_fds;
struct timeval timeout = { 0, SELECT_TIMEOUT_MS * 1000 };
read_fds = mode_read ? &fds : NULL;
write_fds = mode_read ? NULL : &fds;
do {
FD_ZERO(&fds);
FD_SET(fd, &fds);
{while (((rc = select(fd + 1, read_fds, write_fds, NULL, &timeout)) == -1) && ((NT_WSA2errno ()) == EINTR || (NT_WSA2errno ()) == EINPROGRESS));};
} while (rc == 0);
if (rc < 0)
printf("failed checking socket %d for being %s", (int)fd, mode_read ? "readable" : "writable");
return rc;
}
/*****************************************************************************/
DWORD server_send(char * client_message, SOCKET Socket,CtxtHandle * phContext, SecPkgContext_StreamSizes Sizes ){
DWORD cbIoBufferLength, cbData;
PBYTE pbIoBuffer;
// Create a buffer.
cbIoBufferLength = Sizes.cbHeader + Sizes.cbMaximumMessage + Sizes.cbTrailer;
pbIoBuffer = LocalAlloc(LMEM_FIXED, cbIoBufferLength);
if(pbIoBuffer == NULL)
{
printf("**** Out of memory (2)\n");
return -1;
}
// Build the request - must be < maximum message size2
sprintf( pbIoBuffer+Sizes.cbHeader, "%s", client_message ); // message begins after the header
cbData = EncryptSend( Socket, phContext, pbIoBuffer, Sizes );
if(cbData == SOCKET_ERROR || cbData == 0)
{
printf("**** Error %d sending data to server (3)\n", WSAGetLastError());
}
LocalFree(pbIoBuffer);
return cbData;
}
static void DisplaySchannelError(DWORD ErrCode)
{
LPSTR pszName = NULL;
switch(ErrCode)
{
case SEC_E_BUFFER_TOO_SMALL:
pszName = "SEC_E_BUFFER_TOO_SMALL - The message buffer is too small. Used with the Digest SSP.";
break;
case SEC_E_CRYPTO_SYSTEM_INVALID:
pszName = "SEC_E_CRYPTO_SYSTEM_INVALID - The cipher chosen for the security context is not supported. Used with the Digest SSP.";
break;
case SEC_E_INCOMPLETE_MESSAGE:
pszName = "SEC_E_INCOMPLETE_MESSAGE - The data in the input buffer is incomplete. The application needs to read more data from the server and call DecryptMessage (General) again.";
break;
case SEC_E_INVALID_HANDLE:
pszName = "SEC_E_INVALID_HANDLE - A context handle that is not valid was specified in the phContext parameter. Used with the Digest and Schannel SSPs.";
break;
case SEC_E_INVALID_TOKEN:
pszName = "SEC_E_INVALID_TOKEN - The buffers are of the wrong type or no buffer of type SECBUFFER_DATA was found. Used with the Schannel SSP.";
break;
case SEC_E_MESSAGE_ALTERED:
pszName = "SEC_E_MESSAGE_ALTERED - The message has been altered. Used with the Digest and Schannel SSPs.";
break;
case SEC_E_OUT_OF_SEQUENCE:
pszName = "SEC_E_OUT_OF_SEQUENCE - The message was not received in the correct sequence.";
break;
case SEC_E_QOP_NOT_SUPPORTED:
pszName = "SEC_E_QOP_NOT_SUPPORTED - Neither confidentiality nor integrity are supported by the security context. Used with the Digest SSP.";
break;
case SEC_I_CONTEXT_EXPIRED:
pszName = "SEC_I_CONTEXT_EXPIRED - The message sender has finished using the connection and has initiated a shutdown.";
break;
case SEC_I_RENEGOTIATE:
pszName = "SEC_I_RENEGOTIATE - The remote party requires a new handshake sequence or the application has just initiated a shutdown.";
break;
case SEC_E_ENCRYPT_FAILURE:
pszName = "SEC_E_ENCRYPT_FAILURE - The specified data could not be encrypted.";
break;
case SEC_E_DECRYPT_FAILURE:
pszName = "SEC_E_DECRYPT_FAILURE - The specified data could not be decrypted.";
break;
}
printf("Error 0x%x %s \n", ErrCode, pszName);
}
static void DisplayCertChain(PCCERT_CONTEXT pServerCert)
{
CHAR szName[1000];
PCCERT_CONTEXT pCurrentCert, pIssuerCert;
DWORD dwVerificationFlags;
printf("\n");
// display leaf name
if(!CertNameToStr( pServerCert->dwCertEncodingType,
&pServerCert->pCertInfo->Subject,
CERT_X500_NAME_STR | CERT_NAME_STR_NO_PLUS_FLAG,
szName, sizeof(szName) ) )
{
printf("**** Error 0x%x building subject name\n", GetLastError());
}
printf("Server subject: %s\n", szName);
if(!CertNameToStr( pServerCert->dwCertEncodingType,
&pServerCert->pCertInfo->Issuer,
CERT_X500_NAME_STR | CERT_NAME_STR_NO_PLUS_FLAG,
szName, sizeof(szName) ) )
{
printf("**** Error 0x%x building issuer name\n", GetLastError());
}
printf("Server issuer: %s\n\n", szName);
// display certificate chain
pCurrentCert = pServerCert;
while(pCurrentCert != NULL)
{
dwVerificationFlags = 0;
pIssuerCert = CertGetIssuerCertificateFromStore( pServerCert->hCertStore, pCurrentCert, NULL, &dwVerificationFlags );
if(pIssuerCert == NULL)
{
if(pCurrentCert != pServerCert) CertFreeCertificateContext(pCurrentCert);
break;
}
if( !CertNameToStr( pIssuerCert->dwCertEncodingType,
&pIssuerCert->pCertInfo->Subject,
CERT_X500_NAME_STR | CERT_NAME_STR_NO_PLUS_FLAG,
szName, sizeof(szName) ) )
{
printf("**** Error 0x%x building subject name\n", GetLastError());
}
printf("CA subject: %s\n", szName);
if(!CertNameToStr( pIssuerCert->dwCertEncodingType,
&pIssuerCert->pCertInfo->Issuer,
CERT_X500_NAME_STR | CERT_NAME_STR_NO_PLUS_FLAG,
szName, sizeof(szName) ) )
{
printf("**** Error 0x%x building issuer name\n", GetLastError());
}
printf("CA issuer: %s\n\n", szName);
if(pCurrentCert != pServerCert)
CertFreeCertificateContext(pCurrentCert);
pCurrentCert = pIssuerCert;
pIssuerCert = NULL;
}
}
int GetCertificateandCredHandle(CredHandle *pcredHandle)
{
HCERTSTORE cert_store = NULL;
PCCERT_CONTEXT server_cert = NULL;
cert_store = CertOpenStore(CERT_STORE_PROV_SYSTEM,
PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
NULL,
CERT_SYSTEM_STORE_LOCAL_MACHINE,
L"MY");
if(!cert_store) {
printf("\nschannel: Failed to open cert store last error is 0x%x", GetLastError());
}
CERT_NAME_BLOB *subBlob = NULL;
DWORD subBlobLen = 0;
if (!CertStrToNameA(X509_ASN_ENCODING,
"C=US,ST=Ks,L=Olathe,O=XYZ LTD,OU=ABC,CN=Server7,
[email protected]",
CERT_X500_NAME_STR,
NULL,
NULL,
&subBlobLen,
NULL))
{
printf("\nCertStrToName 1 failed");
return -1;
}
subBlob = malloc(subBlobLen);
if (!CertStrToNameA(X509_ASN_ENCODING,
"C=US,ST=Ks,L=Olathe,O=XYZ LTD,OU=ABC,CN=Server7,
[email protected]",
CERT_X500_NAME_STR,
NULL,
(BYTE*)subBlob,
&subBlobLen,
NULL))
{
printf("\n CertStrToName 2 failed");
return -1;
}
const char *cert_prop="8c9d88c9ad953cd66f1f98504f16414cbbeaa1d5";
unsigned char hash[255];
char *p;
int i, x = 0;
CRYPT_HASH_BLOB blob;
for (p = (char *) cert_prop, i = 0; *p && i < sizeof(hash); i++) {
if (*p >= '0' && *p <= '9')
x = (*p - '0') << 4;
else if (*p >= 'A' && *p <= 'F')
x = (*p - 'A' + 10) << 4;
else if (*p >= 'a' && *p <= 'f')
x = (*p - 'a' + 10) << 4;
if (!*++p) /* unexpected end of string */
break;
if (*p >= '0' && *p <= '9')
x += *p - '0';
else if (*p >= 'A' && *p <= 'F')
x += *p - 'A' + 10;
else if (*p >= 'a' && *p <= 'f')
x += *p - 'a' + 10;
hash[i] = x;
/* skip any space(s) between hex numbers */
for (p++; *p && *p == ' '; p++);
}
blob.cbData = i;
blob.pbData = (unsigned char *) &hash;
server_cert = CertFindCertificateInStore(cert_store,
X509_ASN_ENCODING,
0,
CERT_FIND_HASH,
&blob,
NULL);
if(server_cert == NULL)
{
printf("\n\n certificate not found");
return -1;
}
else
printf("\n\n certificate found");
DisplayCertChain(server_cert);
TimeStamp expiration;
SCHANNEL_CRED schannelCred;
memset(&schannelCred, 0, sizeof(schannelCred));
schannelCred.dwVersion = SCHANNEL_CRED_VERSION;
schannelCred.cCreds = 1;
schannelCred.paCred = &server_cert;
schannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_SERVER;
schannelCred.hRootStore = NULL;
schannelCred.dwFlags = SCH_USE_STRONG_CRYPTO ;
SECURITY_STATUS status = AcquireCredentialsHandle(
NULL,
UNISP_NAME,
SECPKG_CRED_INBOUND,
NULL,
&schannelCred,
NULL,
NULL,
pcredHandle,
&expiration);
printf("\nstatus after AcquireCredentialsHandle <0x%x >",status);
if (status != SEC_E_OK) {
CertCloseStore(cert_store, 0);
return -1;
}
CertCloseStore(cert_store, 0);
return 0;
}
#define IO_BUFFER_SIZE 0x10000
int SSPINegotiateLoop(CredHandle *pcredHandle, SOCKET ClientSocket, CtxtHandle *hContext )
{
TimeStamp tsExpiry;
SECURITY_STATUS scRet;
SecBufferDesc InBuffer;
SecBufferDesc OutBuffer;
SecBuffer InBuffers[2];
SecBuffer OutBuffers[1];
DWORD dwSSPIOutFlags = 0;
int first_time = 1;
DWORD readBufferBytes = 0;
DWORD dwSSPIFlags =
ASC_REQ_SEQUENCE_DETECT |
ASC_REQ_REPLAY_DETECT |
ASC_REQ_CONFIDENTIALITY |
ASC_REQ_EXTENDED_ERROR |
ASC_REQ_ALLOCATE_MEMORY |
ASC_REQ_STREAM ;
dwSSPIFlags |= ASC_REQ_MUTUAL_AUTH;
OutBuffer.cBuffers = 1;
OutBuffer.pBuffers = OutBuffers;
OutBuffer.ulVersion = SECBUFFER_VERSION;
printf("\nStarted SSPINegotiateLoop with %d bytes already received from client.", readBufferBytes);
scRet = SEC_E_INCOMPLETE_MESSAGE;
// Main loop, keep going around this until the handshake is completed or fails
while (scRet == SEC_I_CONTINUE_NEEDED || scRet == SEC_E_INCOMPLETE_MESSAGE || scRet == SEC_I_INCOMPLETE_CREDENTIALS)
{
printf("\nExtraEncbufflen : %d",ExtraEncBufferLen);
printf("\nExtraEncbuffsize : %d",ExtraEncBufferSize);
printf("\nscRet Value : 0x%x",scRet);
if (ExtraEncBufferLen == 0 || scRet == SEC_E_INCOMPLETE_MESSAGE)
{ // Read some more bytes if available, we may read more than is needed for this phase of handshake
if(ExtraEncBufferSize - ExtraDecBufferLen < ExtraMemorySize){
ExtraEncBuff = realloc(ExtraEncBuff, ExtraEncBufferSize + ExtraMemorySize);
if(ExtraEncBuff == NULL){
printf("**** Out of memory (1)\n"); return SEC_E_INTERNAL_ERROR;
}
ExtraEncBufferSize = ExtraEncBufferSize + ExtraMemorySize;
}
printf("\n sizeof %d",(int) (sizeof(ExtraEncBuff) - readBufferBytes));
int err = ssl_default_callback_read(ClientSocket, ExtraEncBuff + ExtraEncBufferLen, ExtraEncBufferSize - ExtraEncBufferLen);
//const DWORD err = recv(ClientSocket, readBuffer + readBufferBytes, IO_BUFFER_SIZE - readBufferBytes, 0);
if (err == SOCKET_ERROR || err == 0)
{
if (ERROR_TIMEOUT == GetLastError())
printf("\nRecv timed out");
else if (WSA_IO_PENDING == GetLastError())
printf("\nRecv Overlapped operations will complete later");
else if (WSAECONNRESET == GetLastError())
printf("\nRecv failed, the socket was closed by the other host");
else
printf("\nRecv failed: %d", GetLastError());
return 0;
}
else
{
readBufferBytes += err;
ExtraEncBufferLen += err;
printf("\n ");
if (err == readBufferBytes)
printf("\nReceived %d handshake bytes from client", err);
else
printf("\nReceived %d handshake bytes from client, total is now %d ", err, readBufferBytes);
}
}
InBuffers[0].pvBuffer = ExtraEncBuff ;
InBuffers[0].cbBuffer = ExtraEncBufferLen;
InBuffers[0].BufferType = SECBUFFER_TOKEN;
InBuffers[1].pvBuffer = NULL;
InBuffers[1].cbBuffer = 0;
InBuffers[1].BufferType = SECBUFFER_EMPTY;
InBuffer.cBuffers = 2;
InBuffer.pBuffers = InBuffers;
InBuffer.ulVersion = SECBUFFER_VERSION;
OutBuffers[0].pvBuffer = NULL;
OutBuffers[0].BufferType = SECBUFFER_TOKEN;
OutBuffers[0].cbBuffer = 0;
if(first_time)
{
printf("\n first_time");
scRet = AcceptSecurityContext(
pcredHandle, // Which certificate to use, already established
NULL, // The context handle if we have one, ask to make one if this is first call
&InBuffer, // Input buffer list
dwSSPIFlags, // What we require of the connection
0, // Data representation, not used
hContext, // If we don't yet have a context handle, it is returned here
&OutBuffer, // [out] The output buffer, for messages to be sent to the other end
&dwSSPIOutFlags, // [out] The flags associated with the negotiated connection
&tsExpiry);
if(scRet != SEC_E_INCOMPLETE_MESSAGE){
first_time =0;
}
}
else
{
printf("\n second_time");
scRet = AcceptSecurityContext(
pcredHandle, // Which certificate to use, already established
hContext, // The context handle if we have one, ask to make one if this is first call
&InBuffer, // Input buffer list
dwSSPIFlags, // What we require of the connection
0, // Data representation, not used
hContext, // If we don't yet have a context handle, it is returned here
&OutBuffer, // [out] The output buffer, for messages to be sent to the other end
&dwSSPIOutFlags, // [out] The flags associated with the negotiated connection
&tsExpiry);
}
printf("\nscRet Value soon after : 0x%x",scRet);
if (scRet == SEC_E_OK || scRet == SEC_I_CONTINUE_NEEDED
|| (!scRet && (0 != (dwSSPIOutFlags & ASC_RET_EXTENDED_ERROR))))
{
if (OutBuffers[0].cbBuffer != 0 && OutBuffers[0].pvBuffer != NULL)
{
// Send response to client if there is one
int err = ssl_default_callback_write(ClientSocket, OutBuffers[0].pvBuffer,OutBuffers[0].cbBuffer);
if (err == SOCKET_ERROR || err == 0)
{
printf("\nSend handshake to client failed: %d", GetLastError());
FreeContextBuffer(OutBuffers[0].pvBuffer);
return 0;
}
else
{
printf("\nSend %d handshake bytes to client", OutBuffers[0].cbBuffer);
}
FreeContextBuffer(OutBuffers[0].pvBuffer);
OutBuffers[0].pvBuffer = NULL;
}
}
// At this point, we've read and checked a message (giving scRet) and maybe sent a response (giving err)
// as far as the client is concerned, the SSL handshake may be done, but we still have checks to make.
if (InBuffers[1].BufferType == SECBUFFER_EXTRA && InBuffers[1].cbBuffer > 0)
{
if(ExtraEncBufferSize==0){
ExtraEncBuff=malloc(InBuffers[1].cbBuffer);
ExtraEncBufferSize=InBuffers[1].cbBuffer;
}
int free_mem = ExtraEncBufferSize - ExtraEncBufferLen;
if(ExtraEncBufferSize < InBuffers[1].cbBuffer)
{
ExtraEncBuff = realloc(ExtraEncBuff, ExtraEncBufferSize + InBuffers[1].cbBuffer - free_mem );
ExtraEncBufferSize = ExtraEncBufferSize + InBuffers[1].cbBuffer - free_mem;
}
memmove(ExtraEncBuff,InBuffers[1].pvBuffer, InBuffers[1].cbBuffer);
ExtraEncBufferLen = InBuffers[1].cbBuffer;
}
else
{
readBufferBytes = 0;
ExtraEncBufferLen = 0;
readBufferBytes = 0; // prepare for next receive
printf("\nHandshake working so far, more packets required");
}
if (scRet == SEC_E_OK)
{
break; // The normal exit
}
else if (scRet == SEC_E_INCOMPLETE_MESSAGE)
{
printf("\nAcceptSecurityContext got a partial message and is requesting more be read");
continue;
}
else if (scRet == SEC_E_INCOMPLETE_CREDENTIALS)
{
printf("\nAcceptSecurityContext got SEC_E_INCOMPLETE_CREDENTIALS, it shouldn't but we'll treat it like a partial message");
// Go around again.
break;
}
else if (scRet == SEC_I_CONTINUE_NEEDED)
{
printf("\nAcceptSecurityContext got SEC_I_CONTINUE_NEEDED, it shouldn't but we'll treat it like a partial message");
// Go around again.
continue;
}
else if (scRet)
{
if (scRet == SEC_E_INVALID_TOKEN)
printf("\nAcceptSecurityContext detected an invalid token, maybe the client rejected our certificate");
else
printf("\nAcceptSecurityContext Failed with error code %lx", scRet);
return 0;
}
printf("\n scRet value %lx", scRet);
} // while loop
printf("\n scRet value %lx", scRet);
return 0;
}
static LONG DisconnectFromClient( SOCKET Socket, PCredHandle phCreds, CtxtHandle * phContext )
{
PBYTE pbMessage;
DWORD dwType, dwSSPIFlags, dwSSPIOutFlags, cbMessage, Status;
SecBufferDesc OutBuffer;
SecBuffer OutBuffers[1];
TimeStamp tsExpiry;
int cbData;
dwType = SCHANNEL_SHUTDOWN; // Notify schannel that we are about to close the connection.
OutBuffers[0].pvBuffer = &dwType;
OutBuffers[0].BufferType = SECBUFFER_TOKEN;
OutBuffers[0].cbBuffer = sizeof(dwType);
OutBuffer.cBuffers = 1;
OutBuffer.pBuffers = OutBuffers;
OutBuffer.ulVersion = SECBUFFER_VERSION;
Status = ApplyControlToken(phContext, &OutBuffer);
if(FAILED(Status))
{
printf("**** Error 0x%x returned by ApplyControlToken\n", Status);
goto cleanup;
}
// Build an SSL close notify message.
dwSSPIFlags = ISC_REQ_SEQUENCE_DETECT |
ISC_REQ_REPLAY_DETECT |
ISC_REQ_CONFIDENTIALITY |
ISC_RET_EXTENDED_ERROR |
ISC_REQ_ALLOCATE_MEMORY |
ISC_REQ_STREAM;
OutBuffers[0].pvBuffer = NULL;
OutBuffers[0].BufferType = SECBUFFER_TOKEN;
OutBuffers[0].cbBuffer = 0;
OutBuffer.cBuffers = 1;
OutBuffer.pBuffers = OutBuffers;
OutBuffer.ulVersion = SECBUFFER_VERSION;
Status = AcceptSecurityContext( phCreds,
phContext,
NULL,
dwSSPIFlags,
0,
NULL,
&OutBuffer,
&dwSSPIOutFlags,
&tsExpiry );
if(FAILED(Status))
{
printf("**** Error 0x%x returned by InitializeSecurityContext\n", Status);
goto cleanup;
}
pbMessage = OutBuffers[0].pvBuffer;
cbMessage = OutBuffers[0].cbBuffer;
// Send the close notify message to the server.
if(pbMessage != NULL && cbMessage != 0)
{
cbData = ssl_default_callback_write(Socket,pbMessage, cbMessage);
// cbData = send(Socket, pbMessage, cbMessage, 0);
if(cbData == SOCKET_ERROR || cbData == 0)
{
Status = WSAGetLastError();
printf("**** Error %d sending close notify\n", Status);
}
printf("Sending Close Notify\n");
printf("%d bytes of handshake data sent\n", cbData);
FreeContextBuffer(pbMessage); // Free output buffer.
}
cleanup:
int iResult;
DeleteSecurityContext(phContext); // Free the security context.
iResult = shutdown(Socket, SD_SEND);
if (iResult == SOCKET_ERROR) {
printf("\nshutdown failed with error: %d\n", WSAGetLastError());
closesocket(Socket);
WSACleanup();
}
else{
closesocket(Socket);
WSACleanup();
printf(" shutdown done/n");
}
return Status;
}
static DWORD EncryptSend( SOCKET Socket, CtxtHandle * phContext, PBYTE pbIoBuffer, SecPkgContext_StreamSizes Sizes )
// http://msdn.microsoft.com/en-us/library/aa375378(VS.85).aspx
// The encrypted message is encrypted in place, overwriting the original contents of its buffer.
{
SECURITY_STATUS scRet; // unsigned long cbBuffer; // Size of the buffer, in bytes
SecBufferDesc Message; // unsigned long BufferType; // Type of the buffer (below)
SecBuffer Buffers[4]; // void SEC_FAR * pvBuffer; // Pointer to the buffer
DWORD cbMessage;
PBYTE pbMessage;
int cbData;
printf("inside encrypt send");
pbMessage = pbIoBuffer + Sizes.cbHeader; // Offset by "header size"
cbMessage = (DWORD)strlen(pbMessage);
printf("Sending %d bytes of plaintext:", cbMessage);
// Encrypt the HTTP request.
Buffers[0].pvBuffer = pbIoBuffer; // Pointer to buffer 1
Buffers[0].cbBuffer = Sizes.cbHeader; // length of header
Buffers[0].BufferType = SECBUFFER_STREAM_HEADER; // Type of the buffer
Buffers[1].pvBuffer = pbMessage; // Pointer to buffer 2
Buffers[1].cbBuffer = cbMessage; // length of the message
Buffers[1].BufferType = SECBUFFER_DATA; // Type of the buffer
Buffers[2].pvBuffer = pbMessage + cbMessage; // Pointer to buffer 3
Buffers[2].cbBuffer = Sizes.cbTrailer; // length of the trailor
Buffers[2].BufferType = SECBUFFER_STREAM_TRAILER; // Type of the buffer
Buffers[3].pvBuffer = SECBUFFER_EMPTY; // Pointer to buffer 4
Buffers[3].cbBuffer = SECBUFFER_EMPTY; // length of buffer 4
Buffers[3].BufferType = SECBUFFER_EMPTY; // Type of the buffer 4
Message.ulVersion = SECBUFFER_VERSION; // Version number
Message.cBuffers = 4; // Number of buffers - must contain four SecBuffer structures.
Message.pBuffers = Buffers; // Pointer to array of buffers
scRet = EncryptMessage(phContext, 0, &Message, 0); // must contain four SecBuffer structures.
if(FAILED(scRet))
{
printf("**** Error 0x%x returned by EncryptMessage\n", scRet);
return scRet;
}
if(scRet == SEC_E_CONTEXT_EXPIRED){
printf("SEC_E_CONTEXT_EXPIRED\n");
return scRet;
}
// Send the encrypted data to the server.
cbData = ssl_default_callback_write(Socket, pbIoBuffer, Buffers[0].cbBuffer + Buffers[1].cbBuffer + Buffers[2].cbBuffer);
printf("%d bytes of encrypted data sent\n", cbData);
return cbData; // send( Socket, pbIoBuffer, Sizes.cbHeader + strlen(pbMessage) + Sizes.cbTrailer, 0 );
}
int ReadDecrypt(SOCKET Socket,
PCredHandle phCreds,
CtxtHandle *phContext,
PBYTE pbIoBuffer,
DWORD cbIoBufferLength,
char * message,
int messagesize)
{
SecBuffer ExtraBuffer;
SecBuffer *pDataBuffer, *pExtraBuffer;
SECURITY_STATUS scRet; // unsigned long cbBuffer; // Size of the buffer, in bytes
SecBufferDesc Message; // unsigned long BufferType; // Type of the buffer (below)
SecBuffer Buffers[4]; // void SEC_FAR * pvBuffer; // Pointer to the buffer
DWORD cbIoBuffer, length;
PBYTE buff;
int free_mem = 0;
int cbData,i;
cbIoBuffer = 0;
printf("\nread decrypt-Started");
if(ExtraDecBufferLen>0 && messagesize<ExtraDecBufferLen){
printf("\nFound Decrypted Data");
memcpy(message, ExtraDecBuff,messagesize);
memmove(ExtraDecBuff,ExtraDecBuff+messagesize,ExtraDecBufferLen - messagesize);//Check this ExtraDecBufferSize
ExtraDecBufferLen=ExtraDecBufferLen-messagesize;
return messagesize;
}
if(context_expire==1){
return -1;
}
// Read data from server until done.
while(TRUE) // Read some data.
{
if( ExtraEncBufferLen == 0 || scRet == SEC_E_INCOMPLETE_MESSAGE ) // get the data
{
if((ExtraEncBufferSize - ExtraEncBufferLen) < cbIoBufferLength)
{
if(ExtraEncBufferSize == 0)
{
ExtraEncBuff = malloc(cbIoBufferLength);
ExtraEncBufferSize = cbIoBufferLength;
printf("\nAllocated merory ExtraEncBufferSize <%d>",ExtraEncBufferSize);
}
else
{
ExtraEncBuff = realloc(ExtraEncBuff,cbIoBufferLength+ExtraEncBufferSize);
ExtraEncBufferSize = ExtraEncBufferSize + cbIoBufferLength;
}
}
cbData = ssl_default_callback_read(Socket, ExtraEncBuff + ExtraEncBufferLen, cbIoBufferLength - ExtraEncBufferLen);
printf("\nafter read cbData is <%d>",cbData);
if(cbData == SOCKET_ERROR)
{
printf("\n**** Error %d reading data from server", WSAGetLastError());
scRet = SEC_E_INTERNAL_ERROR;
break;
}
else if(cbData == 0) // Server disconnected.
{
if(cbIoBuffer)
{
printf("\n**** Server unexpectedly disconnected");
scRet = SEC_E_INTERNAL_ERROR;
return -1;
}
else
break; // All Done
}
else // success
{
cbIoBuffer += cbData;
printf("\nBefore updating ExtraEncBufferLen %d\n",ExtraEncBufferLen);
ExtraEncBufferLen += cbData;
printf("\nAfter updating ExtraEncBufferLen %d\n",ExtraEncBufferLen);
}
}
// Decrypt the received data.
Buffers[0].pvBuffer = ExtraEncBuff;
Buffers[0].cbBuffer = ExtraEncBufferLen;
Buffers[0].BufferType = SECBUFFER_DATA; // Initial Type of the buffer 1
Buffers[1].BufferType = SECBUFFER_EMPTY; // Initial Type of the buffer 2
Buffers[2].BufferType = SECBUFFER_EMPTY; // Initial Type of the buffer 3
Buffers[3].BufferType = SECBUFFER_EMPTY; // Initial Type of the buffer 4
Message.ulVersion = SECBUFFER_VERSION; // Version number
Message.cBuffers = 4; // Number of buffers - must contain four SecBuffer structures.
Message.pBuffers = Buffers; // Pointer to array of buffers
scRet = DecryptMessage(phContext, &Message, 0, NULL);
if( scRet == SEC_I_CONTEXT_EXPIRED ){
context_expire=1;
break;
}
if( scRet != SEC_E_OK &&
scRet != SEC_I_RENEGOTIATE &&
scRet != SEC_I_CONTEXT_EXPIRED )
{
printf("\n**** DecryptMessage");
DisplaySchannelError((DWORD)scRet);
return -1;
}
// Locate data and (optional) extra buffers.
pDataBuffer = NULL;
pExtraBuffer = NULL;
for(i = 1; i < 4; i++)
{
if( pDataBuffer == NULL && Buffers[i].BufferType == SECBUFFER_DATA ) pDataBuffer = &Buffers[i];
if( pExtraBuffer == NULL && Buffers[i].BufferType == SECBUFFER_EXTRA ) pExtraBuffer = &Buffers[i];
}
if(pDataBuffer)
{
free_mem = ExtraDecBufferSize - ExtraDecBufferLen;
if(free_mem < pDataBuffer->cbBuffer)
{
ExtraDecBuff = realloc(ExtraDecBuff,ExtraDecBufferSize + pDataBuffer->cbBuffer- free_mem);
ExtraDecBufferSize=ExtraDecBufferSize + pDataBuffer->cbBuffer - free_mem;
}
memcpy(ExtraDecBuff+ExtraDecBufferLen,pDataBuffer->pvBuffer,pDataBuffer->cbBuffer);
ExtraDecBufferLen=pDataBuffer->cbBuffer + ExtraDecBufferLen;
printf("\nDecrypt mess %.*s\n",ExtraDecBufferLen,ExtraDecBuff);
printf("\n ExtraDecBufferLen <%d> pDataBuffer->cbBuffer <%d>",ExtraDecBufferLen,pDataBuffer->cbBuffer);
if(messagesize <= ExtraDecBufferLen)
{
printf("\nextra message decripted 2");
memcpy(message,ExtraDecBuff,messagesize);
memmove(ExtraDecBuff,ExtraDecBuff+messagesize,ExtraDecBufferLen - messagesize);
ExtraDecBufferLen=ExtraDecBufferLen-messagesize;
// break;
}
}
// Move any "extra" data to the input buffer.
printf("\nDecrypted message pvBuffer : %.*s",pDataBuffer->cbBuffer,(char *)pDataBuffer->pvBuffer);
if(pExtraBuffer && pExtraBuffer->cbBuffer > 0 )
{
free_mem = ExtraEncBufferSize - ExtraEncBufferLen;
if(ExtraEncBufferLen > pExtraBuffer->cbBuffer)
{
if(ExtraEncBufferSize < pExtraBuffer->cbBuffer)
{
printf("\nExtra ExtraEncBufferSize Before <%d>",ExtraEncBufferSize);
ExtraEncBuff = realloc(ExtraEncBuff, pExtraBuffer->cbBuffer);
ExtraEncBufferSize = pExtraBuffer->cbBuffer;
printf("\nExtra ExtraEncBufferSize after <%d>",ExtraEncBufferSize);
}
//memmove(ExtraEncBuff,ExtraEncBuff + ExtraEncBufferLen - pExtraBuffer->cbBuffer, pExtraBuffer->cbBuffer );
memmove(ExtraEncBuff,pExtraBuffer->pvBuffer, pExtraBuffer->cbBuffer );
ExtraEncBufferLen = pExtraBuffer->cbBuffer;
printf("\nAfter moving data %d",ExtraEncBufferLen);
}
}
else
{
ExtraEncBufferLen = 0;
}
// The server wants to perform another handshake sequence.
if(scRet == SEC_I_RENEGOTIATE)
{
printf("\nServer requested renegotiate!");
scRet = SSPINegotiateLoop(phCreds, Socket, phContext);
if(scRet != SEC_E_OK) return -2;
}
if(scRet == SEC_E_INCOMPLETE_MESSAGE){
continue;
}
else{
break;
}
} // Loop till CRLF is found at the end of the data
printf("\n%.16s",message);
return messagesize;
}
int __cdecl main(void)
{
WSADATA wsaData;
int iResult;
CtxtHandle hContext;
SOCKET ListenSocket = INVALID_SOCKET;
SOCKET ClientSocket = INVALID_SOCKET;
struct addrinfo *result = NULL;
struct addrinfo hints;
int iSendResult;
char recvbuf[DEFAULT_BUFLEN];
int recvbuflen = DEFAULT_BUFLEN;
char* message, message_same[3000];
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0) {
printf("\nWSAStartup failed with error: %d\n", iResult);
return 1;
}
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
// Resolve the server address and port
iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result);
if (iResult != 0) {
printf("\ngetaddrinfo failed with error: %d\n", iResult);
WSACleanup();
return 1;
}
CredHandle credHandle;
int status=GetCertificateandCredHandle(&credHandle);
if (status < 0) {
printf("\nGetCertificateandCredHandle failed");
freeaddrinfo(result);
WSACleanup();
return 1;
}
// Create a SOCKET for connecting to server
ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (ListenSocket == INVALID_SOCKET) {
printf("\nsocket failed with error: %ld\n", WSAGetLastError());
freeaddrinfo(result);
WSACleanup();
return 1;
}
// Setup the TCP listening socket
iResult = bind(ListenSocket, result->ai_addr, (int)result->ai_addrlen);
if (iResult == SOCKET_ERROR) {
printf("\nbind failed with error: %d\n", WSAGetLastError());
freeaddrinfo(result);
closesocket(ListenSocket);
WSACleanup();
return 1;
}
freeaddrinfo(result);
iResult = listen(ListenSocket, SOMAXCONN);
if (iResult == SOCKET_ERROR) {
printf("\nlisten failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
// Accept a client socket
ClientSocket = accept(ListenSocket, NULL, NULL);
if (ClientSocket == INVALID_SOCKET) {
printf("\naccept failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
closesocket(ListenSocket);
PCCERT_CONTEXT pRemoteCertContext = NULL;
void **Token;
SECURITY_STATUS Status ;
// Receive until the peer shuts down the connection
SSPINegotiateLoop(&credHandle, ClientSocket, &hContext );
Status = QuerySecurityContextToken(&hContext, Token);
if(Status != SEC_E_OK)
{
printf("Error 0x%x QuerySecurityContextToken\n", Status);
}
PSecPkgInfoA *ppPackageInfo;
Status = QuerySecurityPackageInfoA(L"schannel", ppPackageInfo);
{
printf("Error 0x%x QuerySecurityPackageInfoA\n", Status);
}
Status = ImpersonateSecurityContext(&hContext);
if(Status != SEC_E_OK)
{
printf("Error 0x%x ImpersonateSecurityContext\n", Status);
}
Status = QuerySecurityContextToken(&hContext, Token);
if(Status != SEC_E_OK)
{
printf("Error 0x%x QuerySecurityContextToken\n", Status);
}
Status = QueryContextAttributes(&hContext, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (PVOID)&pRemoteCertContext);
if(Status != SEC_E_OK)
{
printf("Error 0x%x querying remote certificate\n", Status);
return -1;
}
SecPkgContext_StreamSizes Sizes;
SECURITY_STATUS scRet;
PBYTE pbIoBuffer;
DWORD cbIoBufferLength, cbData;
scRet = QueryContextAttributes( &hContext, SECPKG_ATTR_STREAM_SIZES, &Sizes );
if(scRet != SEC_E_OK)
{
printf("**** Error 0x%x reading SECPKG_ATTR_STREAM_SIZES\n", scRet);
closesocket(ListenSocket);
WSACleanup();
return 1;
}
// Create a buffer.
cbIoBufferLength = Sizes.cbHeader + Sizes.cbMaximumMessage + Sizes.cbTrailer;
pbIoBuffer = LocalAlloc(LMEM_FIXED, cbIoBufferLength);
if(pbIoBuffer == NULL)
{
printf("**** Out of memory (2)\n");
closesocket(ListenSocket);
WSACleanup();
return 1;
}
int recv_len=0;
message=malloc(3000);
int mess_len=2887;
recv_len = ReadDecrypt( ClientSocket, &credHandle, &hContext, pbIoBuffer, cbIoBufferLength ,message_same,mess_len);
if(recv_len > 0){
printf("\nReceived mess length id:%d\n",recv_len);
}
else{
printf("something went wrong in read decrypt\n");
}
mess_len=16;
recv_len = ReadDecrypt( ClientSocket, &credHandle, &hContext, pbIoBuffer, cbIoBufferLength ,message_same,mess_len);
if(recv_len > 0){
printf("\nReceived mess length id:%d\n",recv_len);
}
else{
printf("something went wrong in read decrypt\n");
}
recv_len = ReadDecrypt( ClientSocket, &credHandle, &hContext, pbIoBuffer, cbIoBufferLength ,message_same,mess_len);
if(recv_len > 0){
printf("\nReceived mess length id:%d\n",recv_len);
}
else{
printf("something went wrong in read decrypt\n");
}
recv_len = ReadDecrypt( ClientSocket, &credHandle, &hContext, pbIoBuffer, cbIoBufferLength ,message_same,mess_len);
if(recv_len > 0){
printf("\nReceived mess length id:%d\n",recv_len);
}
else{
printf("something went wrong in read decrypt\n");
}
char server_message[] ="server message 1";
message=server_message;
server_send(message,ClientSocket, &hContext, Sizes);
char server_message2[] ="server message 2";
message=server_message2;
server_send(message,ClientSocket, &hContext, Sizes);
char server_message3[] ="server message 3";
message=server_message3;
server_send(message,ClientSocket, &hContext, Sizes);
char server_message4[] ="server message 4";
message=server_message4;
server_send(message,ClientSocket, &hContext, Sizes);
recv_len = ReadDecrypt( ClientSocket, &credHandle, &hContext, pbIoBuffer, cbIoBufferLength ,message_same,mess_len);
if(recv_len > 0){
printf("\nReceived mess length id:%d\n",recv_len);
}
else{
printf("something went wrong in read decrypt\n");
}
recv_len = ReadDecrypt( ClientSocket, &credHandle, &hContext, pbIoBuffer, cbIoBufferLength ,message_same,mess_len);
if(recv_len > 0){
printf("\nReceived mess length id:%d\n",recv_len);
}
else{
printf("something went wrong in read decrypt\n");
}
char server_message5[] ="server message 5";
message=server_message5;
server_send(message,ClientSocket, &hContext, Sizes);
char server_message6[] ="server message 6";
message=server_message6;
server_send(message,ClientSocket, &hContext, Sizes);
recv_len = ReadDecrypt( ClientSocket, &credHandle, &hContext, pbIoBuffer, cbIoBufferLength ,message_same,mess_len);
if(recv_len > 0){
printf("\nReceived mess length id:%d\n",recv_len);
}
else{
printf("something went wrong in read decrypt\n");
}
char server_message7[] ="server message 7";
message=server_message7;
server_send(message,ClientSocket, &hContext, Sizes);
recv_len = ReadDecrypt( ClientSocket, &credHandle, &hContext, pbIoBuffer, cbIoBufferLength ,message_same,mess_len);
if(recv_len > 0){
printf("\nReceived mess length id:%d\n",recv_len);
}
else{
printf("something went wrong in read decrypt\n");
}
char server_message8[] ="server message 8";
message=server_message8;
server_send(message,ClientSocket, &hContext, Sizes);
// shutdown the connection since we're done
if(DisconnectFromClient(ClientSocket, &credHandle, &hContext))
{
printf("Error disconnecting from Client\n");
}
printf("----- Disconnected From Client\n");
// cleanup
closesocket(ClientSocket);
WSACleanup();
return 0;
}