-
-
Save aragaer/a0531270636f407b4a1d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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