Skip to content

Instantly share code, notes, and snippets.

@aragaer
Created September 16, 2011 07:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save aragaer/a0531270636f407b4a1d to your computer and use it in GitHub Desktop.
Save aragaer/a0531270636f407b4a1d to your computer and use it in GitHub Desktop.
#define WIN32_LEAN_AND_MEAN
#define SECURITY_WIN32
#include <Windows.h>
#include <WinSock2.h>
#include <WS2tcpip.h>
#include <WinCrypt.h>
#include <schannel.h>
#include <Security.h>
#include <stdio.h>
#pragma comment(lib, "secur32")
#pragma comment(lib, "crypt32")
#pragma comment(lib, "ws2_32")
#define skip(...) do { printf(__VA_ARGS__); goto out; } while (0)
#define ok(cond, ...) if (!(cond)) skip(__VA_ARGS__)
static void init_buffers(SecBufferDesc *desc, unsigned count, unsigned size) {
desc->ulVersion = SECBUFFER_VERSION;
desc->cBuffers = count;
desc->pBuffers = (SecBuffer *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, count*sizeof(SecBuffer));
desc->pBuffers->cbBuffer = size;
desc->pBuffers->pvBuffer = HeapAlloc(GetProcessHeap(), 0, size);
}
static int receive_data(SOCKET sock, SecBuffer *buf) {
unsigned received = 0;
while (1) {
unsigned char *data = (unsigned char *) buf->pvBuffer;
unsigned expected = 0;
int ret = recv(sock, (char *) data+received, buf->cbBuffer-received, 0);
if (ret == -1) {
printf("recv failed\n");
return -1;
} else if (ret == 0) {
printf("connection closed\n");
return -1;
}
received += ret;
while (expected < received) {
unsigned frame_size = 5 + ((data[3]<<8) | data[4]);
expected += frame_size;
data += frame_size;
}
if (expected == received)
break;
}
return buf->cbBuffer = received;
}
int main() {
int ret;
WSADATA wsa_data;
SOCKET sock;
struct hostent *host;
struct sockaddr_in addr;
SECURITY_STATUS status;
ULONG attrs;
SCHANNEL_CRED cred;
CredHandle cred_handle;
CtxtHandle context;
PCCERT_CONTEXT cert, cert2 = NULL;
HCERTSTORE store;
SecBufferDesc buffers[2];
SecBuffer *buf;
unsigned buf_size = 4000;
ret = WSAStartup(0x0202, &wsa_data);
if (ret)
skip("Can't init winsock 2.2\n");
host = gethostbyname("www.google.com");
if (!host)
skip("Can't resolve www.google.com\n");
addr.sin_family = host->h_addrtype;
addr.sin_addr = *(struct in_addr *) host->h_addr_list[0];
addr.sin_port = htons(443);
sock = socket(host->h_addrtype, SOCK_STREAM, 0);
if (sock == SOCKET_ERROR)
skip("Can't create socket\n");
ret = connect(sock, (struct sockaddr *)&addr, sizeof(addr));
if (ret == SOCKET_ERROR)
skip("Can't connect to www.google.com\n");
/* Create client credentials */
memset(&cred, 0, sizeof cred);
cred.dwVersion = SCHANNEL_CRED_VERSION;
cred.grbitEnabledProtocols = SP_PROT_SSL3_CLIENT;
cred.dwFlags = SCH_CRED_NO_DEFAULT_CREDS|SCH_CRED_MANUAL_CRED_VALIDATION;
status = AcquireCredentialsHandle(NULL, UNISP_NAME, SECPKG_CRED_OUTBOUND, NULL,
&cred, NULL, NULL, &cred_handle, NULL);
ok(status == SEC_E_OK, "AcquireCredentialsHandle failed: %08x\n", status);
/* Initialize the connection */
init_buffers(buffers, 4, buf_size);
init_buffers(buffers + 1, 4, buf_size);
buffers[0].pBuffers[0].BufferType = SECBUFFER_TOKEN;
buffers[0].pBuffers[0].cbBuffer = buf_size;
buffers[1].cBuffers = 4;
buffers[1].pBuffers[0].cbBuffer = buf_size;
status = InitializeSecurityContextA(&cred_handle, NULL, (SEC_CHAR *) "localhost",
ISC_REQ_CONFIDENTIALITY|ISC_REQ_STREAM,
0, 0, NULL, 0, &context, buffers, &attrs, NULL);
ok(status == SEC_I_CONTINUE_NEEDED, "Expected SEC_I_CONTINUE_NEEDED on first initialize, got %08x\n", status);
while (status == SEC_I_CONTINUE_NEEDED) {
buf = buffers[0].pBuffers;
send(sock, (const char *) buf->pvBuffer, buf->cbBuffer, 0);
buf->cbBuffer = buf_size;
buf = buffers[1].pBuffers;
ret = receive_data(sock, buf);
if (ret == -1)
skip("Failed to receive_data\n");
buf->BufferType = SECBUFFER_TOKEN;
status = InitializeSecurityContextA(&cred_handle, &context, (SEC_CHAR *) "localhost",
ISC_REQ_CONFIDENTIALITY|ISC_REQ_STREAM,
0, 0, buffers + 1, 0, NULL, buffers, &attrs, NULL);
buffers[1].pBuffers[0].cbBuffer = buf_size;
}
if (status != SEC_E_OK)
skip("Out of handshake with status %08X\n", status);
printf("Handshake done\n");
status = QueryContextAttributes(&context, SECPKG_ATTR_REMOTE_CERT_CONTEXT, &cert);
if (status != SEC_E_OK)
skip("Query cert expected OK, got %08x\n", status);
printf("Got the certificate %p, store = %p\n", cert, store = cert->hCertStore);
/* expected result - 2 records */
while (cert2 = CertEnumCertificatesInStore(store, cert2))
printf("cert %p\n", cert2);
printf("Now freeing stuff\n");
CertFreeCertificateContext(cert);
printf("Freed. Trying again with store %p.\n", store);
/* expected result - no records */
while (cert2 = CertEnumCertificatesInStore(store, cert2))
printf("cert %p\n", cert2);
out:
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment