Hypersonic
view release on metacpan or search on metacpan
lib/Hypersonic/TLS.pm view on Meta::CPAN
->line("static $inline TLSConnection* alloc_tls_connection(int fd, SSL* ssl) {")
->line(' int i;')
->line(' for (i = 0; i < MAX_TLS_CONNECTIONS; i++) {')
->line(' if (g_tls_connections[i].fd == 0) {')
->line(' g_tls_connections[i].fd = fd;')
->line(' g_tls_connections[i].ssl = ssl;')
->line(' g_tls_connections[i].last_activity = time(NULL);')
->line(' g_tls_connections[i].handshake_complete = 0;')
->line(' return &g_tls_connections[i];')
->line(' }')
->line(' }')
->line(' return NULL;')
->line('}');
# Helper to free TLS connection
$builder->line('')
->line("static $inline void free_tls_connection(int fd) {")
->line(' int i;')
->line(' for (i = 0; i < MAX_TLS_CONNECTIONS; i++) {')
->line(' if (g_tls_connections[i].fd == fd) {')
->line(' if (g_tls_connections[i].ssl) {')
->line(' SSL_shutdown(g_tls_connections[i].ssl);')
->line(' SSL_free(g_tls_connections[i].ssl);')
->line(' }')
->line(' g_tls_connections[i].fd = 0;')
->line(' g_tls_connections[i].ssl = NULL;')
->line(' return;')
->line(' }')
->line(' }')
->line('}');
# SSL context initialization
$builder->line('')
->line('static int init_ssl_ctx(const char* cert_file, const char* key_file) {')
->line(' SSL_library_init();')
->line(' SSL_load_error_strings();')
->line(' OpenSSL_add_all_algorithms();')
->line('')
->line(' g_ssl_ctx = SSL_CTX_new(TLS_server_method());')
->line(' if (!g_ssl_ctx) {')
->line(' return -1;')
->line(' }')
->line('')
->line(' /* Set minimum TLS version to 1.2 for security */')
->line(' SSL_CTX_set_min_proto_version(g_ssl_ctx, TLS1_2_VERSION);')
->line('')
->line(' /* Load certificate and key */')
->line(' if (SSL_CTX_use_certificate_file(g_ssl_ctx, cert_file, SSL_FILETYPE_PEM) <= 0) {')
->line(' SSL_CTX_free(g_ssl_ctx);')
->line(' g_ssl_ctx = NULL;')
->line(' return -2;')
->line(' }')
->line('')
->line(' if (SSL_CTX_use_PrivateKey_file(g_ssl_ctx, key_file, SSL_FILETYPE_PEM) <= 0) {')
->line(' SSL_CTX_free(g_ssl_ctx);')
->line(' g_ssl_ctx = NULL;')
->line(' return -3;')
->line(' }')
->line('')
->line(' /* Verify private key matches certificate */')
->line(' if (!SSL_CTX_check_private_key(g_ssl_ctx)) {')
->line(' SSL_CTX_free(g_ssl_ctx);')
->line(' g_ssl_ctx = NULL;')
->line(' return -4;')
->line(' }')
->line('')
->line(' return 0;')
->line('}');
# TLS accept
$builder->line('')
->line('/* Accept TLS connection - non-blocking */')
->line('static int tls_accept(int client_fd) {')
->line(' if (!g_ssl_ctx) return -1;')
->line('')
->line(' SSL* ssl = SSL_new(g_ssl_ctx);')
->line(' if (!ssl) return -2;')
->line('')
->line(' SSL_set_fd(ssl, client_fd);')
->line(' SSL_set_accept_state(ssl);')
->line('')
->line(' TLSConnection* conn = alloc_tls_connection(client_fd, ssl);')
->line(' if (!conn) {')
->line(' SSL_free(ssl);')
->line(' return -3;')
->line(' }')
->line('')
->line(' /* Non-blocking handshake will complete on first read */')
->line(' return 0;')
->line('}');
# TLS handshake
$builder->line('')
->line('/* Complete TLS handshake - may need multiple calls */')
->line('static int tls_handshake(TLSConnection* conn) {')
->line(' if (conn->handshake_complete) return 1;')
->line('')
->line(' int ret = SSL_accept(conn->ssl);')
->line(' if (ret == 1) {')
->line(' conn->handshake_complete = 1;')
->line(' return 1;')
->line(' }')
->line('')
->line(' int err = SSL_get_error(conn->ssl, ret);')
->line(' if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) {')
->line(' return 0; /* Need more data, try again later */')
->line(' }')
->line('')
->line(' return -1; /* Fatal error */')
->line('}');
# TLS recv
$builder->line('')
->line('/* TLS read - returns bytes read, 0 for EAGAIN, -1 for error/close */')
->line('static ssize_t tls_recv(TLSConnection* conn, char* buf, size_t len) {')
->line(' if (!conn->handshake_complete) {')
->line(' int hs = tls_handshake(conn);')
->line(' if (hs <= 0) return hs;')
->line(' }')
->line('')
->line(' int ret = SSL_read(conn->ssl, buf, (int)len);')
lib/Hypersonic/TLS.pm view on Meta::CPAN
}
return NULL;
}
static $inline void free_tls_connection(int fd) {
int i;
for (i = 0; i < MAX_TLS_CONNECTIONS; i++) {
if (g_tls_connections[i].fd == fd) {
if (g_tls_connections[i].ssl) {
SSL_shutdown(g_tls_connections[i].ssl);
SSL_free(g_tls_connections[i].ssl);
}
g_tls_connections[i].fd = 0;
g_tls_connections[i].ssl = NULL;
return;
}
}
}
/* Check negotiated protocol after TLS handshake */
static $inline int get_negotiated_protocol(TLSConnection* conn) {
const unsigned char* alpn = NULL;
unsigned int alpn_len = 0;
SSL_get0_alpn_selected(conn->ssl, &alpn, &alpn_len);
if (alpn_len == 2 && memcmp(alpn, "h2", 2) == 0) {
conn->protocol = PROTO_HTTP2;
return PROTO_HTTP2;
}
conn->protocol = PROTO_HTTP1;
return PROTO_HTTP1;
}
static int init_ssl_ctx(const char* cert_file, const char* key_file) {
SSL_library_init();
SSL_load_error_strings();
OpenSSL_add_all_algorithms();
g_ssl_ctx = SSL_CTX_new(TLS_server_method());
if (!g_ssl_ctx) {
return -1;
}
/* Set minimum TLS version to 1.2 for security */
SSL_CTX_set_min_proto_version(g_ssl_ctx, TLS1_2_VERSION);
$alpn_setup
/* Load certificate and key */
if (SSL_CTX_use_certificate_file(g_ssl_ctx, cert_file, SSL_FILETYPE_PEM) <= 0) {
SSL_CTX_free(g_ssl_ctx);
g_ssl_ctx = NULL;
return -2;
}
if (SSL_CTX_use_PrivateKey_file(g_ssl_ctx, key_file, SSL_FILETYPE_PEM) <= 0) {
SSL_CTX_free(g_ssl_ctx);
g_ssl_ctx = NULL;
return -3;
}
/* Verify private key matches certificate */
if (!SSL_CTX_check_private_key(g_ssl_ctx)) {
SSL_CTX_free(g_ssl_ctx);
g_ssl_ctx = NULL;
return -4;
}
return 0;
}
C
}
# Generate TLS accept code
sub gen_ssl_accept {
return <<'C';
/* Accept TLS connection - non-blocking */
static int tls_accept(int client_fd) {
if (!g_ssl_ctx) return -1;
SSL* ssl = SSL_new(g_ssl_ctx);
if (!ssl) return -2;
SSL_set_fd(ssl, client_fd);
SSL_set_accept_state(ssl);
TLSConnection* conn = alloc_tls_connection(client_fd, ssl);
if (!conn) {
SSL_free(ssl);
return -3;
}
/* Non-blocking handshake will complete on first read */
return 0;
}
/* Complete TLS handshake - may need multiple calls */
static int tls_handshake(TLSConnection* conn) {
if (conn->handshake_complete) return 1;
int ret = SSL_accept(conn->ssl);
if (ret == 1) {
conn->handshake_complete = 1;
return 1;
}
int err = SSL_get_error(conn->ssl, ret);
if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) {
return 0; /* Need more data, try again later */
}
return -1; /* Fatal error */
}
C
}
# Generate TLS read/write wrappers
sub gen_ssl_io {
return <<'C';
/* TLS read - returns bytes read, 0 for EAGAIN, -1 for error/close */
static ssize_t tls_recv(TLSConnection* conn, char* buf, size_t len) {
if (!conn->handshake_complete) {
int hs = tls_handshake(conn);
( run in 0.710 second using v1.01-cache-2.11-cpan-13bb782fe5a )