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 )