Can't change GioTlsCertificate in runtime

I'm working on GTK browser that primary use Glib/Gio dependencies for it socket connection.

  • before, I have some problem when tried to keep SocketConnection alive in async thread (because Rust have decreased reference counter automatically), so now I understand that should delegate SocketConnection reference clone to other threads.

Now I have another problem, when selecting new cert (by UI), creating new connection (by reload page action), create new TLS wrapper - new connection created use old certificate yet after initial handshake. New certificate applying only when restart GTK application. It looks like previous connection still alive, or something get cached.

Here is the code fragment of TLS wrapper (wrote it because of this subject):

fn auth(
    connection: impl IsA<IOStream>,
    connectable: impl IsA<SocketConnectable>,
    certificate: Option<TlsCertificate>,
) -> impl IsA<IOStream> {
    if let Some(certificate) = certificate {
        let tls_connection =
            TlsClientConnection::new(&connection, Some(&connectable)).unwrap(); // @TODO handle

        tls_connection.set_certificate(&certificate);

        // @TODO
        tls_connection.set_require_close_notify(true);

        // @TODO
        tls_connection.connect_accept_certificate(move |_, _, _| true);

        // Take encrypted I/O stream
        tls_connection.upcast::<IOStream>()
    } else {
        // Take default I/O stream
        connection.upcast::<IOStream>()
    }
}

Maybe something went wrong when I'm upcasting streams

Also, reading these docs as maybe related

but strange, tls_connection.set_certificate(&certificate) does not apply the changes.

p.s. I'm creating new socket client on every page reload also, everything should be new, but GTK think I work with previous cert, and does not emit SocketClientEvent::TlsHandshaking event also until I restart the app:

client.connect_event(
    move |_, event, _, stream| {
        meta.set_status(match event {
            SocketClientEvent::TlsHandshaking => { // ignored
                stream
                    .unwrap()
                    .dynamic_cast_ref::<TlsClientConnection>()
                    .unwrap()
                    .connect_accept_certificate(|_, _, _| true); // ignored
                Status::TlsHandshaking
                // ..

Here is the super dirty draft with entire controller line:

I'm beginner in GTK, created subject there but maybe this problem related with cast or reference cleanup again (for example when trying to return and keep IOStream not entire Connection)

Spent few days and can't catch the reason, maybe misunderstand something in GTK - it's really not simple for beginner, or just my fail with casting or lifetime somewhere. If somebody work with encrypted GTK sockets in Rust, please help with advice.

Are you using a library to interact with GIO?

Yes, forgot to say, I'm using this set (with glib and gio features included as gnome_47 versions)

[dependencies.gtk]
package = "gtk4"
version = "0.9.1"
features = ["gnome_47"]

Hm, playing around TlsDatabase debug for newly TlsConnection created, seems DB always have same address in memory, even I call newly created tls_con object:

tls_connection.connect_accept_certificate(move |tls_con, _, _| {
    println!("{:?}", tls_con.database());
    true
});

println!(
    "{:?}",
    tls_connection.emit_accept_certificate(
        &certificate,
        gtk::gio::TlsCertificateFlags::all()
    )
);
Some(TlsDatabase { inner: TypedObjectRef { inner: 0x55b52c59a400, type: GTlsDatabaseGnutls } })
true
Some(TlsDatabase { inner: TypedObjectRef { inner: 0x55b52c59a400, type: GTlsDatabaseGnutls } })
true

Looks like GTK holds single shared TlsDatabase for all new connections, let me try to update it..

Found some dirty solution, but it work

Found another solution, valid for TLS 1.3

Short:

tls_client_connection.set_property("session-resumption-enabled", false);

If somebody want entire implementation, checkout ggemini sources

Other details in this post:

1 Like