#define SECURITY_WIN32
#define IO_BUFFER_SIZE 0x10000
#define CLIENT_CERTIFICATE_SUBJECT_NAME L"C=US,ST=Ks,L=Olathe,O=XYZ LTD,OU=ABC,CN=Client8,
[email protected]"
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <winsock.h>
#include <wincrypt.h>
#include <wintrust.h>
#include <schannel.h>
#include <security.h>
#include <sspi.h>
#pragma comment(lib, "WSock32.Lib")
#pragma comment(lib, "Ws2_32.lib")
#pragma comment(lib, "Advapi32.lib")
#pragma comment(lib,"Secur32.lib")
#pragma comment(lib,"Crypt32.lib")
int context_expire = 0;
INT iPortNumber = 27015;
LPSTR pszServerName = "localhost";
PBYTE ExtraEncBuff = NULL;
#define ExtraMemorySize 1024
unsigned int ExtraEncBufferSize = 0;
unsigned int ExtraEncBufferLen = 0;
char * ExtraDecBuff = NULL;
unsigned int ExtraDecBufferSize = 0;
unsigned int ExtraDecBufferLen = 0;
SCHANNEL_CRED SchannelCred;
static DWORD EncryptSend( SOCKET Socket, CtxtHandle * phContext, PBYTE pbIoBuffer, SecPkgContext_StreamSizes Sizes );
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 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;
}
/*****************************************************************************/
static void DisplayWinVerifyTrustError(DWORD Status)
{
LPSTR pszName = NULL;
switch(Status)
{
case CERT_E_EXPIRED: pszName = "CERT_E_EXPIRED"; break;
case CERT_E_VALIDITYPERIODNESTING: pszName = "CERT_E_VALIDITYPERIODNESTING"; break;
case CERT_E_ROLE: pszName = "CERT_E_ROLE"; break;
case CERT_E_PATHLENCONST: pszName = "CERT_E_PATHLENCONST"; break;
case CERT_E_CRITICAL: pszName = "CERT_E_CRITICAL"; break;
case CERT_E_PURPOSE: pszName = "CERT_E_PURPOSE"; break;
case CERT_E_ISSUERCHAINING: pszName = "CERT_E_ISSUERCHAINING"; break;
case CERT_E_MALFORMED: pszName = "CERT_E_MALFORMED"; break;
case CERT_E_UNTRUSTEDROOT: pszName = "CERT_E_UNTRUSTEDROOT"; break;
case CERT_E_CHAINING: pszName = "CERT_E_CHAINING"; break;
case TRUST_E_FAIL: pszName = "TRUST_E_FAIL"; break;
case CERT_E_REVOKED: pszName = "CERT_E_REVOKED"; break;
case CERT_E_UNTRUSTEDTESTROOT: pszName = "CERT_E_UNTRUSTEDTESTROOT"; break;
case CERT_E_REVOCATION_FAILURE: pszName = "CERT_E_REVOCATION_FAILURE"; break;
case CERT_E_CN_NO_MATCH: pszName = "CERT_E_CN_NO_MATCH"; break;
case CERT_E_WRONG_USAGE: pszName = "CERT_E_WRONG_USAGE"; break;
default: pszName = "(unknown)"; break;
}
printf("Error 0x%x (%s) returned by CertVerifyCertificateChainPolicy!\n", Status, pszName);
}
/*****************************************************************************/
static void DisplaySchannelError(DWORD ErrCode)
{
LPSTR pszName = NULL; // WinError.h
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);
}
DWORD client_send(char * client_message, SOCKET Socket,CtxtHandle * phContext, SecPkgContext_StreamSizes Sizes ){
DWORD cbIoBufferLength, cbData;
PBYTE pbIoBuffer;
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 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;
}
}
/*****************************************************************************/
static void DisplayConnectionInfo( CtxtHandle *phContext )
{
SECURITY_STATUS Status;
SecPkgContext_ConnectionInfo ConnectionInfo;
SecPkgContext_CipherInfo CipherInfo = { SECPKGCONTEXT_CIPHERINFO_V1 };
Status = QueryContextAttributes( phContext, SECPKG_ATTR_CIPHER_INFO, &CipherInfo);
if(Status != SEC_E_OK)
{
printf("Error 0x%x querying cipher info\n", Status);
return;
}
printf("%S\n", CipherInfo.szCipherSuite);
Status = QueryContextAttributes( phContext, SECPKG_ATTR_CONNECTION_INFO, (PVOID)&ConnectionInfo );
if(Status != SEC_E_OK)
{
printf("Error 0x%x querying connection info\n", Status);
return;
}
printf("\n");
switch(ConnectionInfo.dwProtocol)
{
case SP_PROT_TLS1_CLIENT:
printf("Protocol: TLS1\n");
break;
case SP_PROT_SSL3_CLIENT:
printf("Protocol: SSL3\n");
break;
case SP_PROT_PCT1_CLIENT:
printf("Protocol: PCT\n");
break;
case SP_PROT_SSL2_CLIENT:
printf("Protocol: SSL2\n");
break;
default:
printf("Protocol: 0x%x\n", ConnectionInfo.dwProtocol);
}
switch(ConnectionInfo.aiCipher)
{
case CALG_RC4:
printf("Cipher: RC4\n");
break;
case CALG_3DES:
printf("Cipher: Triple DES\n");
break;
case CALG_RC2:
printf("Cipher: RC2\n");
break;
case CALG_DES:
case CALG_CYLINK_MEK:
printf("Cipher: DES\n");
break;
case CALG_SKIPJACK:
printf("Cipher: Skipjack\n");
break;
default:
printf("Cipher: 0x%x\n", ConnectionInfo.aiCipher);
}
printf("Cipher strength: %d\n", ConnectionInfo.dwCipherStrength);
switch(ConnectionInfo.aiHash)
{
case CALG_MD5:
printf("Hash: MD5\n");
break;
case CALG_SHA:
printf("Hash: SHA\n");
break;
default:
printf("Hash: 0x%x\n", ConnectionInfo.aiHash);
}
printf("Hash strength: %d\n", ConnectionInfo.dwHashStrength);
switch(ConnectionInfo.aiExch)
{
case CALG_RSA_KEYX:
case CALG_RSA_SIGN:
printf("Key exchange: RSA\n");
break;
case CALG_KEA_KEYX:
printf("Key exchange: KEA\n");
break;
case CALG_DH_EPHEM:
printf("Key exchange: DH Ephemeral\n");
break;
default:
printf("Key exchange: 0x%x\n", ConnectionInfo.aiExch);
}
printf("Key exchange strength: %d\n", ConnectionInfo.dwExchStrength);
}
/*****************************************************************************/
static DWORD VerifyServerCertificate( PCCERT_CONTEXT pServerCert, PSTR pszServerName, DWORD dwCertFlags )
{
HTTPSPolicyCallbackData polHttps;
CERT_CHAIN_POLICY_PARA PolicyPara;
CERT_CHAIN_POLICY_STATUS PolicyStatus;
CERT_CHAIN_PARA ChainPara;
PCCERT_CHAIN_CONTEXT pChainContext = NULL;
DWORD cchServerName, Status;
LPSTR rgszUsages[] = { szOID_PKIX_KP_SERVER_AUTH,
szOID_SERVER_GATED_CRYPTO,
szOID_SGC_NETSCAPE };
DWORD cUsages = sizeof(rgszUsages) / sizeof(LPSTR);
PWSTR pwszServerName = NULL;
if(pServerCert == NULL)
{
Status = SEC_E_WRONG_PRINCIPAL;
goto cleanup;
}
// Convert server name to unicode.
if(pszServerName == NULL || strlen(pszServerName) == 0)
{
Status = SEC_E_WRONG_PRINCIPAL;
goto cleanup;
}
cchServerName = MultiByteToWideChar(CP_ACP, 0, pszServerName, -1, NULL, 0);
pwszServerName = LocalAlloc(LMEM_FIXED, cchServerName * sizeof(WCHAR));
if(pwszServerName == NULL)
{
Status = SEC_E_INSUFFICIENT_MEMORY;
goto cleanup;
}
cchServerName = MultiByteToWideChar(CP_ACP, 0, pszServerName, -1, pwszServerName, cchServerName);
if(cchServerName == 0)
{
Status = SEC_E_WRONG_PRINCIPAL;
goto cleanup;
}
// Build certificate chain.
ZeroMemory(&ChainPara, sizeof(ChainPara));
ChainPara.cbSize = sizeof(ChainPara);
ChainPara.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR;
ChainPara.RequestedUsage.Usage.cUsageIdentifier = cUsages;
ChainPara.RequestedUsage.Usage.rgpszUsageIdentifier = rgszUsages;
if(!CertGetCertificateChain(NULL,
pServerCert,
NULL,
pServerCert->hCertStore,
&ChainPara,
0,
NULL,
&pChainContext))
{
Status = GetLastError();
printf("Error 0x%x returned by CertGetCertificateChain!\n", Status);
goto cleanup;
}
// Validate certificate chain.
ZeroMemory(&polHttps, sizeof(HTTPSPolicyCallbackData));
polHttps.cbStruct = sizeof(HTTPSPolicyCallbackData);
polHttps.dwAuthType = AUTHTYPE_SERVER;
polHttps.fdwChecks = dwCertFlags;
memset(&PolicyPara, 0, sizeof(PolicyPara));
PolicyPara.cbSize = sizeof(PolicyPara);
PolicyPara.pvExtraPolicyPara = &polHttps;
memset(&PolicyStatus, 0, sizeof(PolicyStatus));
PolicyStatus.cbSize = sizeof(PolicyStatus);
if( !CertVerifyCertificateChainPolicy( CERT_CHAIN_POLICY_SSL,
pChainContext,
&PolicyPara,
&PolicyStatus ) )
{
Status = GetLastError();
printf("Error 0x%x returned by CertVerifyCertificateChainPolicy!\n", Status);
goto cleanup;
}
if(PolicyStatus.dwError)
{
Status = PolicyStatus.dwError;
DisplayWinVerifyTrustError(Status);
goto cleanup;
}
Status = SEC_E_OK;
cleanup:
if(pChainContext) CertFreeCertificateChain(pChainContext);
if(pwszServerName) LocalFree(pwszServerName);
return Status;
}
/*****************************************************************************/
static SECURITY_STATUS CreateCredentials(PCredHandle phCreds)
{
TimeStamp tsExpiry;
SECURITY_STATUS Status;
PCCERT_CONTEXT client_cert = NULL;
const char *cert_prop="118563ef50222440b4f638cc9f8b9bbbf3044ca0";
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;
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());
}
client_cert = CertFindCertificateInStore(cert_store,
X509_ASN_ENCODING,
0,
CERT_FIND_HASH,
&blob,
NULL);
if(client_cert == NULL)
{
printf("\n\ncertificate not found");
//return -1;
}
else
printf("\n\ncertificate found");
// Build Schannel credential structure. Currently, this sample only
// specifies the protocol to be used (and optionally the certificate,
// of course). Real applications may wish to specify other parameters as well.
ZeroMemory( &SchannelCred, sizeof(SchannelCred) );
SchannelCred.dwVersion = SCHANNEL_CRED_VERSION;
if(client_cert)
{
SchannelCred.cCreds = 1;
SchannelCred.paCred = &client_cert;
}
SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_CLIENT;
SchannelCred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION | SCH_CRED_NO_DEFAULT_CREDS |
SCH_CRED_IGNORE_NO_REVOCATION_CHECK | SCH_CRED_IGNORE_REVOCATION_OFFLINE ;
// Create an SSPI credential.
Status = AcquireCredentialsHandle(NULL, // Name of principal
UNISP_NAME, // Name of package
SECPKG_CRED_OUTBOUND, // Flags indicating use
NULL, // Pointer to logon ID
&SchannelCred, // Package specific data
NULL, // Pointer to GetKey() func
NULL, // Value to pass to GetKey()
phCreds, // (out) Cred Handle
&tsExpiry ); // (out) Lifetime (optional)
if(Status != SEC_E_OK)
printf("**** Error 0x%x returned by AcquireCredentialsHandle\n", Status);
// cleanup: Free the certificate context. Schannel has already made its own copy.
if(client_cert)
CertFreeCertificateContext(client_cert);
return Status;
}
/*****************************************************************************/
static INT ConnectToServer( LPSTR pszServerName, INT iPortNumber, SOCKET * pSocket )
{
SOCKET Socket;
struct sockaddr_in sin;
struct hostent *hp;
Socket = socket(PF_INET, SOCK_STREAM, 0);
if(Socket == INVALID_SOCKET)
{
printf("**** Error %d creating socket\n", WSAGetLastError());
return WSAGetLastError();
}
sin.sin_family = AF_INET;
sin.sin_port = htons((u_short)iPortNumber);
if((hp = gethostbyname(pszServerName)) == NULL)
{
printf("**** Error returned by gethostbyname\n");
return WSAGetLastError();
}
else
memcpy(&sin.sin_addr, hp->h_addr, 4);
if(connect(Socket, (struct sockaddr *)&sin, sizeof(sin)) == SOCKET_ERROR)
{
printf( "**** Error %d connecting to \"%s\" (%s)\n", WSAGetLastError(), pszServerName, inet_ntoa(sin.sin_addr) );
closesocket(Socket);
return WSAGetLastError();
}
*pSocket = Socket;
return SEC_E_OK;
}
/*****************************************************************************/
static LONG DisconnectFromServer( 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 |
ISC_REQ_MANUAL_CRED_VALIDATION |
ISC_REQ_MUTUAL_AUTH;
OutBuffers[0].pvBuffer = NULL;
OutBuffers[0].BufferType = SECBUFFER_TOKEN;
OutBuffers[0].cbBuffer = 0;
OutBuffer.cBuffers = 1;
OutBuffer.pBuffers = OutBuffers;
OutBuffer.ulVersion = SECBUFFER_VERSION;
Status = InitializeSecurityContextA( phCreds,
phContext,
NULL,
dwSSPIFlags,
0,
SECURITY_NATIVE_DREP,
NULL,
0,
phContext,
&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);
if(cbData == SOCKET_ERROR || cbData == 0)
{
Status = WSAGetLastError();
printf("**** Error %d sending close notify\n", Status);
goto cleanup;
}
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, 0);
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 SECURITY_STATUS ClientHandshakeLoop( SOCKET Socket, // in
PCredHandle phCreds, // in
CtxtHandle * phContext, // in, out
BOOL fDoInitialRead, // in
SecBuffer * pExtraData ) // out
{
SecBufferDesc OutBuffer, InBuffer;
SecBuffer InBuffers[2], OutBuffers[1];
DWORD dwSSPIFlags, dwSSPIOutFlags;
TimeStamp tsExpiry;
SECURITY_STATUS scRet;
int cbData;
dwSSPIFlags = ISC_REQ_SEQUENCE_DETECT |
ISC_REQ_REPLAY_DETECT |
ISC_REQ_CONFIDENTIALITY |
ISC_RET_EXTENDED_ERROR |
ISC_REQ_ALLOCATE_MEMORY |
ISC_REQ_STREAM |
ISC_REQ_MANUAL_CRED_VALIDATION |
ISC_REQ_MUTUAL_AUTH ;
printf("\ninside handshake loop\n");
// Loop until the handshake is finished or an error occurs.
scRet = SEC_I_CONTINUE_NEEDED;
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(0 == ExtraEncBufferLen || scRet == SEC_E_INCOMPLETE_MESSAGE) // Read data from server.
{
if(ExtraEncBufferSize - ExtraEncBufferLen < ExtraMemorySize)
{
printf("\n memalloc ");
fflush(stdout);
ExtraEncBuff = realloc(ExtraEncBuff, ExtraEncBufferSize + ExtraMemorySize);
if(ExtraEncBuff == NULL)
{
printf("**** Out of memory (1)\n"); return SEC_E_INTERNAL_ERROR;
}
ExtraEncBufferSize = ExtraEncBufferSize + ExtraMemorySize;
}
cbData = ssl_default_callback_read(Socket,ExtraEncBuff+ ExtraEncBufferLen, ExtraEncBufferSize - ExtraEncBufferLen);
if(cbData == SOCKET_ERROR)
{
printf("**** Error %d reading data from server\n", WSAGetLastError());
scRet = SEC_E_INTERNAL_ERROR;
break;
}
else if(cbData == 0)
{
printf("**** Server unexpectedly disconnected\n");
scRet = SEC_E_INTERNAL_ERROR;
break;
}
printf("\n%d bytes of handshake data received\n", cbData);
ExtraEncBufferLen += cbData;
}
// Set up the input buffers. Buffer 0 is used to pass in data
// received from the server. Schannel will consume some or all
// of this. Leftover data (if any) will be placed in buffer 1 and
// given a buffer type of SECBUFFER_EXTRA.
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;
// Set up the output buffers. These are initialized to NULL
// so as to make it less likely we'll attempt to free random
// garbage later.
OutBuffers[0].pvBuffer = NULL;
OutBuffers[0].BufferType= SECBUFFER_TOKEN;
OutBuffers[0].cbBuffer = 0;
OutBuffer.cBuffers = 1;
OutBuffer.pBuffers = OutBuffers;
OutBuffer.ulVersion = SECBUFFER_VERSION;
// Call InitializeSecurityContext.
scRet = InitializeSecurityContextA( phCreds,
phContext,
NULL,
dwSSPIFlags,
0,
SECURITY_NATIVE_DREP,
&InBuffer,
0,
NULL,
&OutBuffer,
&dwSSPIOutFlags,
&tsExpiry );
printf("\nscRet Value : 0x%x\n",scRet);
if (scRet == SEC_I_INCOMPLETE_CREDENTIALS)
{
printf("\nRecieved SEC_I_INCOMPLETE_CREDENTIALS");
}
if(scRet == SEC_E_OK ||
scRet == SEC_I_CONTINUE_NEEDED ||
FAILED(scRet) && (dwSSPIOutFlags & ISC_RET_EXTENDED_ERROR))
{
if(OutBuffers[0].cbBuffer != 0 && OutBuffers[0].pvBuffer != NULL)
{
cbData = ssl_default_callback_write(Socket, OutBuffers[0].pvBuffer, OutBuffers[0].cbBuffer);
if(cbData == SOCKET_ERROR || cbData == 0)
{
printf( "**** Error %d sending data to server (2)\n", WSAGetLastError() );
FreeContextBuffer(OutBuffers[0].pvBuffer);
DeleteSecurityContext(phContext);
return SEC_E_INTERNAL_ERROR;
}
printf("%d bytes of handshake data sent\n", cbData);
// Free output buffer.
FreeContextBuffer(OutBuffers[0].pvBuffer);
OutBuffers[0].pvBuffer = NULL;
}
}
// If InitializeSecurityContext returned SEC_E_INCOMPLETE_MESSAGE,
// then we need to read more data from the server and try again.
if(scRet == SEC_E_INCOMPLETE_MESSAGE){
printf("\n Incomplete message");
continue;
}
if(ExtraEncBufferSize==0){
ExtraEncBuff=malloc(InBuffers[1].cbBuffer);
ExtraEncBufferSize=InBuffers[1].cbBuffer;
}
if(InBuffers[1].BufferType == SECBUFFER_EXTRA && InBuffers[1].pvBuffer != NULL && InBuffers[1].cbBuffer > 0) {
int free_mem = ExtraEncBufferSize - ExtraEncBufferLen;
if(free_mem < InBuffers[1].cbBuffer)
{
ExtraEncBuff = realloc(ExtraEncBuff, ExtraEncBufferSize + InBuffers[1].cbBuffer - free_mem );
if(ExtraEncBuff == NULL){
printf("**** Out of memory (1)\n"); return SEC_E_INTERNAL_ERROR;
}
ExtraEncBufferSize = ExtraEncBufferSize + InBuffers[1].cbBuffer - free_mem;
}
memmove(ExtraEncBuff,InBuffers[1].pvBuffer, InBuffers[1].cbBuffer);
ExtraEncBufferLen = InBuffers[1].cbBuffer;
}
else
{
ExtraEncBufferLen = 0;
}
if(scRet == SEC_E_OK)
{
printf("Handshake was successful\n");
break; // Bail out to quit
}
// Check for fatal error.
if(FAILED(scRet))
{
printf("**** Error 0x%x returned by InitializeSecurityContext (2)\n", scRet);
break;
}
// If InitializeSecurityContext returned SEC_I_INCOMPLETE_CREDENTIALS,
// then the server just requested client authentication.
if(scRet == SEC_I_INCOMPLETE_CREDENTIALS)
{
scRet = SEC_E_INTERNAL_ERROR;
break;
}
}
// Delete the security context in the case of a fatal error.
if(FAILED(scRet)) DeleteSecurityContext(phContext);
return scRet;
}
/*****************************************************************************/
static SECURITY_STATUS PerformClientHandshake( SOCKET Socket, // in
PCredHandle phCreds, // in
LPSTR pszServerName, // in
CtxtHandle * phContext, // out
SecBuffer * pExtraData ) // out
{
SecBufferDesc OutBuffer;
SecBuffer OutBuffers[1];
DWORD dwSSPIFlags, dwSSPIOutFlags;
TimeStamp tsExpiry;
SECURITY_STATUS scRet;
int cbData;
dwSSPIFlags = ISC_REQ_SEQUENCE_DETECT |
ISC_REQ_REPLAY_DETECT |
ISC_REQ_CONFIDENTIALITY |
ISC_RET_EXTENDED_ERROR |
ISC_REQ_ALLOCATE_MEMORY |
ISC_REQ_STREAM |
ISC_REQ_MANUAL_CRED_VALIDATION |
ISC_REQ_MUTUAL_AUTH;
// Initiate a ClientHello message and generate a token.
OutBuffers[0].pvBuffer = NULL;
OutBuffers[0].BufferType = SECBUFFER_TOKEN;
OutBuffers[0].cbBuffer = 0;
OutBuffer.cBuffers = 1;
OutBuffer.pBuffers = OutBuffers;
OutBuffer.ulVersion = SECBUFFER_VERSION;
scRet = InitializeSecurityContextA( phCreds,
NULL,
NULL,
dwSSPIFlags,
0,
SECURITY_NATIVE_DREP,
NULL,
0,
phContext,
&OutBuffer,
&dwSSPIOutFlags,
&tsExpiry );
if(scRet != SEC_I_CONTINUE_NEEDED) { printf("**** Error 0x%x returned by InitializeSecurityContext (1)\n", scRet); return scRet; }
// Send response to server if there is one.
if(OutBuffers[0].cbBuffer != 0 && OutBuffers[0].pvBuffer != NULL)
{
cbData = ssl_default_callback_write(Socket, OutBuffers[0].pvBuffer, OutBuffers[0].cbBuffer);
// cbData = send( Socket, OutBuffers[0].pvBuffer, OutBuffers[0].cbBuffer, 0 );
if( cbData == SOCKET_ERROR || cbData == 0 )
{
printf("**** Error %d sending data to server (1)\n", WSAGetLastError());
FreeContextBuffer(OutBuffers[0].pvBuffer);
DeleteSecurityContext(phContext);
return SEC_E_INTERNAL_ERROR;
}
printf("%d bytes of handshake data sent\n", cbData);
FreeContextBuffer(OutBuffers[0].pvBuffer); // Free output buffer.
OutBuffers[0].pvBuffer = NULL;
}
return ClientHandshakeLoop(Socket, phCreds, phContext, TRUE, pExtraData);
}
/*****************************************************************************/
static DWORD EncryptSend( SOCKET Socket, CtxtHandle * phContext, PBYTE pbIoBuffer, SecPkgContext_StreamSizes Sizes )
{
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, cbData;
PBYTE pbMessage;
pbMessage = pbIoBuffer + Sizes.cbHeader; // Offset by "header size"
cbMessage = (DWORD)strlen(pbMessage);
// 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, ExtraEncBufferSize - 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];
}
//printf("\npDataBuffer data is:%s\n",(char *)pDataBuffer->pvBuffer);
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",ExtraDecBuff);
printf("\nExtraDecBufferLen <%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);
//ExtraEncBufferLen = 0;
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, pExtraBuffer->pvBuffer, pExtraBuffer->cbBuffer );
ExtraEncBufferLen = pExtraBuffer->cbBuffer;
printf("\nAfter moving data %d",ExtraEncBufferLen);
}
}
else
{
ExtraEncBufferLen = 0;
}
if(scRet == SEC_I_RENEGOTIATE)
{
printf("\nServer requested renegotiate!");
scRet = ClientHandshakeLoop( Socket, phCreds, phContext, FALSE, &ExtraBuffer);
if(scRet != SEC_E_OK) return -2;
}
if(scRet == SEC_E_INCOMPLETE_MESSAGE){
continue;
}
else{
break;
}
}
printf("\n%.16s",message);
return messagesize;
}
/*****************************************************************************/
void _cdecl main( int argc, char *argv[] )
{
WSADATA WsaData;
SOCKET Socket = INVALID_SOCKET;
CredHandle hClientCreds;
CtxtHandle hContext;
BOOL fCredsInitialized = FALSE;
BOOL fContextInitialized = FALSE;
SecBuffer ExtraData;
SECURITY_STATUS Status;
char message[100];
PCCERT_CONTEXT pRemoteCertContext = NULL;
// Initialize the WinSock subsystem.
if(WSAStartup(0x0101, &WsaData) == SOCKET_ERROR)
{
printf("Error %d returned by WSAStartup\n", GetLastError());
goto cleanup;
} //
printf("----- WinSock Initialized\n");
// Create credentials.
if(CreateCredentials(&hClientCreds))
{
printf("Error creating credentials\n");
goto cleanup;
}
fCredsInitialized = TRUE; //
printf("----- Credentials Initialized\n");
// Connect to server.
if(ConnectToServer(pszServerName, iPortNumber, &Socket))
{
printf("Error connecting to server\n");
goto cleanup;
} //
printf("----- Connectd To Server\n");
// Perform handshake
if( PerformClientHandshake( Socket, &hClientCreds, pszServerName, &hContext, &ExtraData ) )
{
printf("Error performing handshake\n");
goto cleanup;
}
fContextInitialized = TRUE; //
printf("----- Client Handshake Performed\n");
// Authenticate server's credentials. Get server's certificate.
Status = QueryContextAttributes(&hContext, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (PVOID)&pRemoteCertContext);
if(Status != SEC_E_OK)
{
printf("Error 0x%x querying remote certificate\n", Status);
goto cleanup;
} //
printf("----- Server Credentials Authenticated \n");
// Display server certificate chain.
DisplayCertChain(pRemoteCertContext); //
printf("----- Certificate Chain Displayed \n");
// Attempt to validate server certificate.
Status = VerifyServerCertificate(pRemoteCertContext, "client_cert", 0);
if(Status)
{
printf("**** Error 0x%x authenticating server credentials!\n", Status);
goto cleanup;
}
// The server certificate did not validate correctly. At this point, we cannot tell
// if we are connecting to the correct server, or if we are connecting to a
// "man in the middle" attack server - Best to just abort the connection.
printf("----- Server Certificate Verified\n");
// Free the server certificate context.
CertFreeCertificateContext(pRemoteCertContext);
pRemoteCertContext = NULL; //
printf("----- Server certificate context released \n");
// Display connection info.
DisplayConnectionInfo(&hContext); //
printf("----- Secure Connection Info\n");
SECURITY_STATUS scRet; // unsigned long BufferType; // Type of the buffer (below)
PBYTE pbIoBuffer; // void SEC_FAR * pvBuffer; // Pointer to the buffer
DWORD cbIoBufferLength, cbData;
SecPkgContext_StreamSizes Sizes;
// Read stream encryption properties.
scRet = QueryContextAttributes(&hContext, SECPKG_ATTR_STREAM_SIZES, &Sizes);
if(scRet != SEC_E_OK)
{
printf("**** Error 0x%x reading SECPKG_ATTR_STREAM_SIZES\n", scRet);
}
// Create a buffer.
cbIoBufferLength = Sizes.cbHeader + Sizes.cbMaximumMessage + Sizes.cbTrailer;
pbIoBuffer = LocalAlloc(LMEM_FIXED, cbIoBufferLength);
if(pbIoBuffer == NULL) {
printf("**** Out of memory (2)\n");
}
char message1[] =" client message 1"
"These are reserved words in C language are int, float, "
"if, else, for, while etc. An Identifier is a sequence of"
"letters and digits, but must start with a letter. "
"Underscore ( _ ) is treated as a letter. Identifiers are "
"case sensitive. Identifiers are used to name variables,"
"functions etc."
"These are reserved words in C language are int, float, "
"if, else, for, while etc. An Identifier is a sequence of"
"letters and digits, but must start with a letter. "
"Underscore ( _ ) is treated as a letter. Identifiers are "
"case sensitive. Identifiers are used to name variables,"
"functions etc."
"These are reserved words in C language are int, float, "
"if, else, for, while etc. An Identifier is a sequence of"
"letters and digits, but must start with a letter. "
"Underscore ( _ ) is treated as a letter. Identifiers are "
"case sensitive. Identifiers are used to name variables,"
"functions etc."
"These are reserved words in C language are int, float, "
"if, else, for, while etc. An Identifier is a sequence of"
"letters and digits, but must start with a letter. "
"Underscore ( _ ) is treated as a letter. Identifiers are "
"case sensitive. Identifiers are used to name variables,"
"functions etc."
"These are reserved words in C language are int, float, "
"if, else, for, while etc. An Identifier is a sequence of"
"letters and digits, but must start with a letter. "
"Underscore ( _ ) is treated as a letter. Identifiers are "
"case sensitive. Identifiers are used to name variables,"
"functions etc."
"These are reserved words in C language are int, float, "
"if, else, for, while etc. An Identifier is a sequence of"
"letters and digits, but must start with a letter. "
"Underscore ( _ ) is treated as a letter. Identifiers are "
"case sensitive. Identifiers are used to name variables,"
"functions etc."
"These are reserved words in C language are int, float, "
"if, else, for, while etc. An Identifier is a sequence of"
"letters and digits, but must start with a letter. "
"Underscore ( _ ) is treated as a letter. Identifiers are "
"case sensitive. Identifiers are used to name variables,"
"functions etc."
"These are reserved words in C language are int, float, "
"if, else, for, while etc. An Identifier is a sequence of"
"letters and digits, but must start with a letter. "
"Underscore ( _ ) is treated as a letter. Identifiers are "
"case sensitive. Identifiers are used to name variables,"
"functions etc."
"These are reserved words in C language are int, float, "
"if, else, for, while etc. An Identifier is a sequence of"
"letters and digits, but must start with a letter. "
"Underscore ( _ ) is treated as a letter. Identifiers are "
"case sensitive. Identifiers are used to name variables,"
"functions etc."
"These are reserved words in C language are int, float, "
"if, else, for, while etc. An Identifier is a sequence of"
"letters and digits, but must start with a letter. "
"Underscore ( _ ) is treated as a letter. Identifiers are "
"case sensitive. Identifiers are used to name variables,"
"functions etc.";
char * client_message=message1;
client_send(client_message,Socket, &hContext, Sizes);
char message2[] ="client message 2";
client_message=message2;
client_send(client_message,Socket, &hContext, Sizes);
char message3[] ="client message 3";
client_message=message3;
client_send(client_message,Socket, &hContext, Sizes);
char message4[] ="client message 4";
client_message=message4;
client_send(client_message,Socket, &hContext, Sizes);
int mess_len=16;
int recv_len=0;
recv_len = ReadDecrypt( Socket, &hClientCreds, &hContext, pbIoBuffer, cbIoBufferLength ,message,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;
scRet = ReadDecrypt( Socket, &hClientCreds, &hContext, pbIoBuffer, cbIoBufferLength ,message,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;
scRet = ReadDecrypt( Socket, &hClientCreds, &hContext, pbIoBuffer, cbIoBufferLength ,message,mess_len);
if(recv_len > 0)
{
printf("\nReceived mess length id:%d\n",recv_len);
}
else
{
printf("something went wrong in read decrypt\n");
}
scRet = ReadDecrypt( Socket, &hClientCreds, &hContext, pbIoBuffer, cbIoBufferLength ,message,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 message5[] ="client message 5";
client_message=message5;
client_send(client_message,Socket, &hContext, Sizes);
char message6[] ="client message 6";
client_message=message6;
client_send(client_message,Socket, &hContext, Sizes);
scRet = ReadDecrypt( Socket, &hClientCreds, &hContext, pbIoBuffer, cbIoBufferLength ,message,mess_len);
if(recv_len > 0){
printf("\nReceived mess length id:%d\n",recv_len);
}
else{
printf("something went wrong in read decrypt\n");
}
scRet = ReadDecrypt( Socket, &hClientCreds, &hContext, pbIoBuffer, cbIoBufferLength ,message,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 message7[] ="client message 7";
client_message=message7;
client_send(client_message,Socket, &hContext, Sizes);
scRet = ReadDecrypt( Socket, &hClientCreds, &hContext, pbIoBuffer, cbIoBufferLength ,message,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 message8[] ="client message 8";
client_message=message8;
client_send(client_message,Socket, &hContext, Sizes);
scRet = ReadDecrypt( Socket, &hClientCreds, &hContext, pbIoBuffer, cbIoBufferLength ,message,mess_len);
if(recv_len > 0){
printf("\nReceived mess length id:%d\n",recv_len);
}
else{
printf("something went wrong in read decrypt\n");
}
// Send a close_notify alert to the server and close down the connection.
if(DisconnectFromServer(Socket, &hClientCreds, &hContext))
{
printf("Error disconnecting from server\n");
goto cleanup;
}
fContextInitialized = FALSE;
Socket = INVALID_SOCKET; //
printf("----- Disconnected From Server\n");
cleanup: //
printf("----- Begin Cleanup\n");
// Free the server certificate context.
if(pRemoteCertContext)
{
CertFreeCertificateContext(pRemoteCertContext);
pRemoteCertContext = NULL;
}
// Free SSPI context handle.
if(fContextInitialized)
{
DeleteSecurityContext(&hContext);
fContextInitialized = FALSE;
}
// Free SSPI credentials handle.
if(fCredsInitialized)
{
FreeCredentialsHandle(&hClientCreds);
fCredsInitialized = FALSE;
}
// Close socket.
if(Socket != INVALID_SOCKET) closesocket(Socket);
// Shutdown WinSock subsystem.
WSACleanup();
printf("----- All Done ----- \n");
free(ExtraEncBuff);
free(ExtraDecBuff);
}