Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor TLS engine IO #188

Merged
merged 8 commits into from
Nov 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ set(tlsuv_sources
src/compression.h
src/p11.c
src/p11.h
)
src/util.h
)

if(USE_OPENSSL)
set(tlsImpl openssl)
Expand Down
65 changes: 43 additions & 22 deletions include/tlsuv/tls_engine.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

#include <stdlib.h>
#include <stdio.h>
#include <uv.h>

#if _WIN32
#pragma comment (lib, "crypt32.lib")
Expand All @@ -37,7 +38,8 @@ enum TLS_RESULT {
TLS_OK = 0,
TLS_ERR = -1,
TLS_EOF = -2,
TLS_READ_AGAIN = -3,
TLS_AGAIN = -3,

TLS_MORE_AVAILABLE = -4,
TLS_HAS_WRITE = -5,
};
Expand All @@ -50,59 +52,78 @@ enum hash_algo {

typedef struct tlsuv_engine_s *tlsuv_engine_t;

typedef void* io_ctx;
typedef ssize_t (*io_read)(io_ctx, char *buf, size_t len);
typedef ssize_t (*io_write)(io_ctx, const char *buf, size_t len);

struct tlsuv_engine_s {

/**
* set TLS engine abstract IO
* @param self engine
* @param io_ctx IO object passed into [io_read] and [io_write] callbacks
* @param io_read read callback, called when TLS engine requires input SSL bytes
* @param io_write write callback, called when TLS engine requires output SSL bytes
*/
void (*set_io)(tlsuv_engine_t self, io_ctx, io_read, io_write);

/**
* sets TLS engine file descriptor IO (usually socket)
* @param self engine
* @param fd file descriptor
*/
void (*set_io_fd)(tlsuv_engine_t self, uv_os_fd_t fd);

/**
* set requested ALPN protocols
* @param self
* @param protocols
* @param len
*/
void (*set_protocols)(tlsuv_engine_t self, const char **protocols, int len);

tls_handshake_state (*handshake_state)(tlsuv_engine_t self);

/**
* Initiates/continues TLS handshake.
* @param self
* @param in data received from TSL peer
* @param in_bytes number of bytes in inbound buffer
* @param out data to be send to TLS peer
* @param out_bytes number of bytes to be sent
* @param maxout outbound buffer size
*/
tls_handshake_state
(*handshake)(tlsuv_engine_t self, char *in, size_t in_bytes, char *out, size_t *out_bytes, size_t maxout);
tls_handshake_state (*handshake)(tlsuv_engine_t self);

/**
* Returns negotiated ALPN
* @param self
*/
const char* (*get_alpn)(tlsuv_engine_t self);

/**
* Genereate TSL close notify.
* Generate TSL close notify.
* @param self
* @param out outbound buffer
* @param out_bytes number of outbound bytes written
* @param maxout size of outbound buffer
*/
int (*close)(tlsuv_engine_t self, char *out, size_t *out_bytes, size_t maxout);
int (*close)(tlsuv_engine_t self);

/**
* wraps application data into ssl stream format, out bound buffer contains bytes to be sent to TSL peer
* writes application data into ssl stream
* @param engine
* @param data
* @param data_len
* @param out
* @param out_bytes
* @param maxout
* @return number of written bytes or error
*/
int (*write)(tlsuv_engine_t self, const char *data, size_t data_len, char *out, size_t *out_bytes, size_t maxout);
int (*write)(tlsuv_engine_t self, const char *data, size_t data_len);

/**
* process bytes received from TLS peer. Application data is placed in out buffer.
* read application bytes from ssl stream.
* @param engine
* @param ssl_in bytes received from TLS peer
* @param ssl_in_len number of bytes received
* @param out buffer for application data
* @param out_bytes number of bytes received
* @param maxout size of out buffer
* @return [TLS_OK] - successful read, no more data for reading
* [TLS_MORE_AVAILABLE] - successful read, more data available for reading
* [TLS_AGAIN] - no more data is available from underlying IO
* [TLS_EOF] - peer send close notify
* [TLS_ERR] - TLS engine encountered a TLS error
*/
int (*read)(tlsuv_engine_t self, const char *ssl_in, size_t ssl_in_len, char *out, size_t *out_bytes, size_t maxout);
int (*read)(tlsuv_engine_t self, char *out, size_t *out_bytes, size_t maxout);

const char* (*strerror)(tlsuv_engine_t engine);

Expand Down
6 changes: 5 additions & 1 deletion include/tlsuv/tls_link.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,19 @@

typedef struct tls_link_s tls_link_t;
typedef void (*tls_handshake_cb)(tls_link_t *l, int status);

typedef struct ssl_buf_s ssl_buf_t;
struct tls_link_s {
UV_LINK_FIELDS

tlsuv_engine_t engine;
tls_handshake_cb hs_cb;

ssl_buf_t *ssl_in; // buffer holding inbound ssl bytes
ssl_buf_t *ssl_out; // buffer holding outbound ssl_bytes
};


int tlsuv_tls_link_init(tls_link_t *tls, tlsuv_engine_t engine, tls_handshake_cb cb);
void tlsuv_tls_link_free(tls_link_t *tls);

#endif//TLSUV_TLS_LINK_H
57 changes: 22 additions & 35 deletions sample/engine_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,10 @@
#include <stdlib.h>
#include <string.h>
#include <tlsuv/tlsuv.h>
#include "common.h"

#define HOST "wttr.in"
#define HOST "httpbingo.org"
#define PATH "/json"

int sockClose(SOCKET sock)
{
Expand All @@ -46,6 +48,7 @@ int sockClose(SOCKET sock)


int main(int argc, char **argv) {
tlsuv_set_debug(5, logger);

#if _WIN32
//changes the output to UTF-8 so that the windows output looks correct and not all jumbly
Expand Down Expand Up @@ -98,16 +101,11 @@ int main(int argc, char **argv) {
printf("connected\n");
}

// do handshake
char ssl_in[32 * 1024];
char ssl_out[32 * 1024];
size_t in_bytes = 0;
size_t out_bytes = 0;
engine->set_io_fd(engine, (uv_os_sock_t)sock);

int i = 0;
// do handshake
do {
tls_handshake_state state = engine->handshake(engine, ssl_in, in_bytes, ssl_out, &out_bytes,
sizeof(ssl_out));
tls_handshake_state state = engine->handshake(engine);

if (state == TLS_HS_COMPLETE) {
printf("handshake complete alpn[%s]\n", engine->get_alpn(engine));
Expand All @@ -117,49 +115,38 @@ int main(int argc, char **argv) {
fprintf(stderr, "handshake failed\n");
exit(1);
}

printf("hs: out_bytes=%zd, state=%x\n", out_bytes, state);
if (out_bytes > 0) {
size_t wrote = send(sock, ssl_out, out_bytes, 0);
printf("hs: wrote_bytes=%zd\n", wrote);
}

in_bytes = recv(sock, ssl_in, sizeof(ssl_in), 0);
printf("hs: in_bytes=%zd\n", in_bytes);
} while (true);

const char *req = "GET /Charlotte HTTP/1.1\n"
const char *req = "GET " PATH " HTTP/1.1\n"
"Accept: */*\n"
"Accept-Enconding: plain\n"
"Connection: keep-alive\n"
"Host: " HOST "\n"
"User-Agent: HTTPie/1.0.2\n"
"\n";

engine->write(engine, req, strlen(req), ssl_out, &out_bytes, sizeof(ssl_out));
printf("writing req=%zd bytes\n", out_bytes);

send(sock, ssl_out, out_bytes, 0);
engine->write(engine, req, strlen(req));

char resp[128];
char resp[12800];
size_t resp_read = 0;

int read_res = 0;
do {
if (read_res == 0 || read_res == TLS_READ_AGAIN) {
in_bytes = recv(sock, ssl_in, sizeof(ssl_in), 0);
printf("read resp=%zd bytes\n", in_bytes);
}
else {
in_bytes = 0;
fprintf(stderr, "reading(%d)...\n", read_res);
read_res = engine->read(engine, resp, &resp_read, sizeof(resp));
fprintf(stderr, "read(%d,%zd)...\n", read_res, resp_read);

if (resp_read > 0) {
printf("%.*s", (int) resp_read, resp);
fflush(stdout);
}
else
fprintf(stderr, "read_res = %d\n", read_res);
} while (read_res != TLS_EOF && read_res != TLS_ERR);

read_res = engine->read(engine, ssl_in, in_bytes, resp, &resp_read, sizeof(resp));
printf("%*.*s", (int) resp_read, (int) resp_read, resp);
} while (read_res == TLS_READ_AGAIN || read_res == TLS_MORE_AVAILABLE);
printf("closing \n");

engine->close(engine, ssl_out, &out_bytes, sizeof(ssl_out));
send(sock, ssl_out, out_bytes, 0);
engine->close(engine);

sockClose(sock);

Expand Down
5 changes: 3 additions & 2 deletions sample/sample.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
#include <tlsuv/tlsuv.h>
#include <uv.h>

#define HOST "www.wttr.in"
#define HOST "httpbingo.org"
#define PATH "/json"

static void alloc(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) {
buf->base = (char*) malloc(suggested_size);
Expand Down Expand Up @@ -64,7 +65,7 @@ void on_connect(uv_connect_t *cr, int status) {
tlsuv_stream_read_start(mbed, alloc, on_data);

uv_write_t *wr = malloc(sizeof(uv_write_t));
char req[] = "GET / HTTP/1.1\r\n"
char req[] = "GET " PATH " HTTP/1.1\r\n"
"Accept: */*\r\n"
"Connection: close\r\n"
"Host: " HOST "\r\n"
Expand Down
6 changes: 3 additions & 3 deletions sample/um-curl.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ struct app_ctx {
static void do_request(uv_timer_t *t) {
struct app_ctx *app = t->data;

tlsuv_http_req_t *r = tlsuv_http_req(&app->clt, "GET", app->path, resp_cb, NULL);
r->resp.body_cb = body_cb;

if (app->count-- > 0) {
tlsuv_http_req_t *r = tlsuv_http_req(&app->clt, "GET", app->path, resp_cb, NULL);
r->resp.body_cb = body_cb;

uv_timer_start(t, do_request, app->cycle * 1000, 0);
} else {
uv_close((uv_handle_t *) t, NULL);
Expand Down
3 changes: 3 additions & 0 deletions src/http.c
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@
clt->engine->set_protocols(clt->engine, supported_alpn, supported_apln_num);
}

tlsuv_tls_link_free(&clt->tls_link);
tlsuv_tls_link_init(&clt->tls_link, clt->engine, on_tls_handshake);
clt->tls_link.data = clt;

Expand Down Expand Up @@ -279,12 +280,12 @@
clt->src->cancel(clt->src);
}

static void req_write_cb(uv_link_t *source, int status, void *arg) {

Check warning on line 283 in src/http.c

View workflow job for this annotation

GitHub Actions / build (windows, openssl)

'source': unreferenced formal parameter

Check warning on line 283 in src/http.c

View workflow job for this annotation

GitHub Actions / build (windows, mbedtls)

'source': unreferenced formal parameter
UM_LOG(VERB, "request write completed: %d", status);
free(arg);
}

static void req_write_body_cb(uv_link_t *source, int status, void *arg) {

Check warning on line 288 in src/http.c

View workflow job for this annotation

GitHub Actions / build (windows, openssl)

'source': unreferenced formal parameter

Check warning on line 288 in src/http.c

View workflow job for this annotation

GitHub Actions / build (windows, mbedtls)

'source': unreferenced formal parameter
UM_LOG(VERB, "request body write completed: %d", status);
struct body_chunk_s *chunk = arg;
if (chunk->cb) {
Expand All @@ -293,7 +294,7 @@
free(chunk);
}

static void chunk_hdr_wcb(uv_link_t *l, int status, void *arg) {

Check warning on line 297 in src/http.c

View workflow job for this annotation

GitHub Actions / build (windows, openssl)

'status': unreferenced formal parameter

Check warning on line 297 in src/http.c

View workflow job for this annotation

GitHub Actions / build (windows, openssl)

'l': unreferenced formal parameter

Check warning on line 297 in src/http.c

View workflow job for this annotation

GitHub Actions / build (windows, mbedtls)

'status': unreferenced formal parameter

Check warning on line 297 in src/http.c

View workflow job for this annotation

GitHub Actions / build (windows, mbedtls)

'l': unreferenced formal parameter
if (arg != NULL) {
free(arg);
}
Expand All @@ -319,7 +320,7 @@
uv_link_write((uv_link_t *) &clt->http_link, &buf, 1, NULL, chunk_hdr_wcb, buf.base);

buf.base = (char*)b->chunk;
buf.len = b->len;

Check warning on line 323 in src/http.c

View workflow job for this annotation

GitHub Actions / build (windows, openssl)

'=': conversion from 'size_t' to 'ULONG', possible loss of data

Check warning on line 323 in src/http.c

View workflow job for this annotation

GitHub Actions / build (windows, mbedtls)

'=': conversion from 'size_t' to 'ULONG', possible loss of data
uv_link_write((uv_link_t *) &clt->http_link, &buf, 1, NULL, req_write_body_cb, b);

buf.base = "\r\n";
Expand All @@ -336,12 +337,12 @@
else {
buf = uv_buf_init((char*)b->chunk, (unsigned int)b->len);
uv_link_write((uv_link_t *) &clt->http_link, &buf, 1, NULL, req_write_body_cb, b);
if (req->body_sent_size > req->req_body_size) {

Check warning on line 340 in src/http.c

View workflow job for this annotation

GitHub Actions / build (windows, openssl)

'>': signed/unsigned mismatch

Check warning on line 340 in src/http.c

View workflow job for this annotation

GitHub Actions / build (windows, mbedtls)

'>': signed/unsigned mismatch
UM_LOG(WARN, "Supplied data[%ld] is larger than provided Content-Length[%ld]",
req->body_sent_size, req->req_body_size);
}

if (req->body_sent_size >= req->req_body_size) {

Check warning on line 345 in src/http.c

View workflow job for this annotation

GitHub Actions / build (windows, openssl)

'>=': signed/unsigned mismatch

Check warning on line 345 in src/http.c

View workflow job for this annotation

GitHub Actions / build (windows, mbedtls)

'>=': signed/unsigned mismatch
req->state = body_sent;
}
}
Expand Down Expand Up @@ -553,6 +554,7 @@
tcp_src_keepalive(src, 1, 3);
int rc = tlsuv_http_init_with_src(l, clt, url, (tlsuv_src_t *) src);
clt->own_src = true;
clt->tls_link = (tls_link_t){0};
return rc;
}

Expand Down Expand Up @@ -742,6 +744,7 @@
free(clt->src);
clt->src = NULL;
}
tlsuv_tls_link_free(&clt->tls_link);
}

int tlsuv_parse_url(struct tlsuv_url_s *url, const char *urlstr) {
Expand Down
Loading
Loading