| 1 | #include <stdint.h> |
| 2 | #include <stdio.h> |
| 3 | #include <stdlib.h> |
| 4 | #include <windows.h> |
| 5 | #include <winsock.h> |
| 6 | #include <wincrypt.h> |
| 7 | #include <wintrust.h> |
| 8 | #include <schannel.h> |
| 9 | |
| 10 | #define SECURITY_WIN32 |
| 11 | #include <security.h> |
| 12 | #include <sspi.h> |
| 13 | |
| 14 | #define vsc_init_resp_buff_size 44000 |
| 15 | |
| 16 | #define IO_BUFFER_SIZE 0x10000 |
| 17 | |
| 18 | #define TLS_MAX_BUFSIZ 32768 |
| 19 | |
| 20 | // Define here to be sure |
| 21 | #define SP_PROT_TLS1_2_CLIENT 0x00000800 |
| 22 | |
| 23 | typedef void* (*vschannel_allocator)(void*, INT64); |
| 24 | |
| 25 | typedef struct TlsContext TlsContext; |
| 26 | |
| 27 | TlsContext new_tls_context(); |
| 28 | |
| 29 | // ALPN (RFC 7301) support. `wire` is the standard ALPN wire format: each |
| 30 | // protocol name preceded by a 1-byte length, e.g. "\x02h2\x08http/1.1". |
| 31 | // vschannel_alpn_supported reports whether this Windows version's SChannel |
| 32 | // can advertise ALPN at all (Windows 8.1+). |
| 33 | INT vschannel_alpn_supported(); |
| 34 | void vschannel_set_alpn(TlsContext *tls_ctx, const char *wire, INT len); |
| 35 | INT vschannel_get_alpn(TlsContext *tls_ctx, char *out, INT out_cap); |
| 36 | INT vschannel_alpn_probe(TlsContext *tls_ctx, INT iport, LPWSTR host, char *out, INT out_cap); |
| 37 | |
| 38 | // vschannel_request_on_open runs a one-shot HTTP/1.1 request over an already |
| 39 | // open connection (the HTTP/1.1 fallback when `h2` was not negotiated). |
| 40 | INT vschannel_request_on_open(TlsContext *tls_ctx, CHAR *req, DWORD req_len, CHAR **out, vschannel_allocator afn); |
| 41 | |
| 42 | // Streaming transport for the HTTP/2 driver: open the connection and keep it |
| 43 | // open, then move raw application bytes across it. See vschannel.c. |
| 44 | INT vschannel_h2_connect(TlsContext *tls_ctx, INT iport, LPWSTR host); |
| 45 | INT vschannel_write(TlsContext *tls_ctx, const char *buf, INT len); |
| 46 | INT vschannel_read(TlsContext *tls_ctx, char *buf, INT cap); |
| 47 | void vschannel_h2_close(TlsContext *tls_ctx); |
| 48 | |
| 49 | static void vschannel_init(TlsContext *tls_ctx, BOOL validate_server_certificate); |
| 50 | |
| 51 | static void vschannel_cleanup(TlsContext *tls_ctx); |
| 52 | |
| 53 | static INT vschannel_last_error(TlsContext *tls_ctx); |
| 54 | |
| 55 | static INT request(TlsContext *tls_ctx, INT iport, LPWSTR host, CHAR *req, DWORD req_len, CHAR **out, vschannel_allocator afn); |
| 56 | |
| 57 | static SECURITY_STATUS https_make_request(TlsContext *tls_ctx, CHAR *req, DWORD req_len, CHAR **out, int *length, vschannel_allocator afn); |
| 58 | |
| 59 | static INT connect_to_server(TlsContext *tls_ctx, LPWSTR host, INT port_number); |
| 60 | |
| 61 | static LONG disconnect_from_server(TlsContext *tls_ctx); |
| 62 | |
| 63 | static SECURITY_STATUS perform_client_handshake(TlsContext *tls_ctx, LPWSTR host, SecBuffer *pExtraData); |
| 64 | |
| 65 | static SECURITY_STATUS client_handshake_loop(TlsContext *tls_ctx, BOOL fDoInitialRead, SecBuffer *pExtraData); |
| 66 | |
| 67 | static DWORD verify_server_certificate(PCCERT_CONTEXT pServerCert, LPWSTR host, DWORD dwCertFlags); |
| 68 | |
| 69 | static SECURITY_STATUS create_credentials(TlsContext *tls_ctx); |
| 70 | |
| 71 | static void get_new_client_credentials(TlsContext *tls_ctx); |
| 72 | |