gboolean g_tls_connection_base_accept_peer_certificate (GTlsConnectionBase *tls, GTlsCertificate *peer_certificate, GTlsCertificateFlags peer_certificate_errors) { gboolean accepted = FALSE; if (G_IS_TLS_CLIENT_CONNECTION (tls)) { GTlsCertificateFlags validation_flags = g_tls_client_connection_get_validation_flags (G_TLS_CLIENT_CONNECTION (tls)); if ((peer_certificate_errors & validation_flags) == 0) accepted = TRUE; } if (!accepted) { accepted = g_tls_connection_emit_accept_certificate (G_TLS_CONNECTION (tls), peer_certificate, peer_certificate_errors); } return accepted; }
/** * g_vfs_ftp_connection_data_connection_enable_tls: * @conn: a connection with an active control connection * @server_identity: address of the server used to verify the certificate * @cb: callback called if there's a verification error * @user_data: user data passed to @cb * @cancellable: cancellable to interrupt wait * @error: %NULL or location to take a potential error * * Tries to enable TLS on the given @connection's data connection. If setting * up TLS fails, %FALSE will be returned and @error will be set. * * Returns: %TRUE on success, %FALSE otherwise. **/ gboolean g_vfs_ftp_connection_data_connection_enable_tls (GVfsFtpConnection *conn, GSocketConnectable *server_identity, CertificateCallback cb, gpointer user_data, GCancellable * cancellable, GError ** error) { GIOStream *secure; g_return_val_if_fail (conn != NULL, FALSE); g_return_val_if_fail (conn->commands != NULL, FALSE); secure = g_tls_client_connection_new (conn->data, server_identity, error); if (secure == NULL) return FALSE; g_object_unref (conn->data); conn->data = secure; g_tls_client_connection_copy_session_state (G_TLS_CLIENT_CONNECTION (secure), G_TLS_CLIENT_CONNECTION (conn->commands)); g_signal_connect (secure, "accept-certificate", G_CALLBACK (cb), user_data); if (!g_tls_connection_handshake (G_TLS_CONNECTION (secure), cancellable, error)) { /* Close here to be sure it won't get used anymore */ g_io_stream_close (secure, cancellable, NULL); return FALSE; } return TRUE; }
/* Called when a GTlsConnection (which this handler has been connected to) * has an error validating its certificate. * Returns TRUE if the certificate is already trusted, so the connection * can continue. * Returns FALSE if the certificate is not trusted, causing the * connection's handshake to fail, and then prompts the user to accept * the certificate. */ static gboolean accept_certificate_cb(GTlsConnection *conn, GTlsCertificate *peer_cert, GTlsCertificateFlags errors, gpointer user_data) { GTlsCertificate *trusted_cert; GSocketConnectable *connectable; const gchar *identity; g_return_val_if_fail(G_IS_TLS_CLIENT_CONNECTION(conn), FALSE); g_return_val_if_fail(G_IS_TLS_CERTIFICATE(peer_cert), FALSE); /* Get the certificate identity from the GTlsClientConnection */ connectable = g_tls_client_connection_get_server_identity( G_TLS_CLIENT_CONNECTION(conn)); g_return_val_if_fail(G_IS_SOCKET_CONNECTABLE(connectable), FALSE); /* identity is owned by the connectable */ if (G_IS_NETWORK_ADDRESS(connectable)) { identity = g_network_address_get_hostname( G_NETWORK_ADDRESS(connectable)); } else if (G_IS_NETWORK_SERVICE(connectable)) { identity = g_network_service_get_domain( G_NETWORK_SERVICE(connectable)); } else { g_return_val_if_reached(FALSE); } /* See if a trusted certificate matching the peer certificate exists */ trusted_cert = purple_tls_certificate_new_from_id(identity, NULL); if (trusted_cert != NULL && g_tls_certificate_is_same(peer_cert, trusted_cert)) { /* It's manually trusted. Accept certificate */ g_object_unref(trusted_cert); return TRUE; } g_clear_object(&trusted_cert); /* Certificate failed and isn't trusted. * Fail certificate and prompt user. */ request_accept_certificate(identity, peer_cert, errors); return FALSE; }
static void on_socket_connect (GObject *object, GAsyncResult *result, gpointer user_data) { CockpitStream *self = user_data; GError *error = NULL; g_socket_connection_connect_finish (G_SOCKET_CONNECTION (object), result, &error); if (!error && !self->priv->closed) { g_debug ("%s: connected", self->priv->name); if (self->priv->options && self->priv->options->tls_client) { self->priv->io = g_tls_client_connection_new (G_IO_STREAM (object), NULL, &error); if (self->priv->io) { g_debug ("%s: tls handshake", self->priv->name); g_tls_client_connection_set_validation_flags (G_TLS_CLIENT_CONNECTION (self->priv->io), self->priv->options->tls_client_flags); if (self->priv->options->tls_cert) { g_tls_connection_set_certificate (G_TLS_CONNECTION (self->priv->io), self->priv->options->tls_cert); } if (self->priv->options->tls_database) { g_tls_connection_set_database (G_TLS_CONNECTION (self->priv->io), self->priv->options->tls_database); } /* We track data end the same way we do for HTTP */ g_tls_connection_set_require_close_notify (G_TLS_CONNECTION (self->priv->io), FALSE); } } else { self->priv->io = g_object_ref (object); } } if (error) { g_debug ("%s: couldn't connect: %s", self->priv->name, error->message); g_clear_error (&self->priv->connect_error); self->priv->connect_error = error; g_socket_address_enumerator_next_async (self->priv->connecting, NULL, on_address_next, g_object_ref (self)); } else { initialize_io (self); } g_object_unref (object); g_object_unref (self); }
int main (int argc, char *argv[]) { GSocket *socket; GSocketAddress *address; GError *error = NULL; GOptionContext *context; GCancellable *cancellable; GIOStream *connection; GInputStream *istream; GOutputStream *ostream; GSocketAddress *src_address; GTlsCertificate *certificate = NULL; gint i; address = NULL; connection = NULL; context = g_option_context_new (" <hostname>[:port] - Test GSocket client stuff"); g_option_context_add_main_entries (context, cmd_entries, NULL); if (!g_option_context_parse (context, &argc, &argv, &error)) { g_printerr ("%s: %s\n", argv[0], error->message); return 1; } if (argc != 2) { g_printerr ("%s: %s\n", argv[0], "Need to specify hostname / unix socket name"); return 1; } if (use_udp && tls) { g_printerr ("DTLS (TLS over UDP) is not supported"); return 1; } if (cancel_timeout) { GThread *thread; cancellable = g_cancellable_new (); thread = g_thread_new ("cancel", cancel_thread, cancellable); g_thread_unref (thread); } else { cancellable = NULL; } loop = g_main_loop_new (NULL, FALSE); for (i = 0; i < 2; i++) { if (make_connection (argv[1], certificate, cancellable, &socket, &address, &connection, &istream, &ostream, &error)) break; if (g_error_matches (error, G_TLS_ERROR, G_TLS_ERROR_CERTIFICATE_REQUIRED)) { g_clear_error (&error); certificate = lookup_client_certificate (G_TLS_CLIENT_CONNECTION (connection), &error); if (certificate != NULL) continue; } g_printerr ("%s: %s", argv[0], error->message); return 1; } /* TODO: Test non-blocking connect/handshake */ if (non_blocking) g_socket_set_blocking (socket, FALSE); while (TRUE) { gchar buffer[4096]; gssize size; gsize to_send; if (fgets (buffer, sizeof buffer, stdin) == NULL) break; to_send = strlen (buffer); while (to_send > 0) { if (use_udp) { ensure_socket_condition (socket, G_IO_OUT, cancellable); size = g_socket_send_to (socket, address, buffer, to_send, cancellable, &error); } else { ensure_connection_condition (connection, G_IO_OUT, cancellable); size = g_output_stream_write (ostream, buffer, to_send, cancellable, &error); } if (size < 0) { if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) { g_print ("socket send would block, handling\n"); g_error_free (error); error = NULL; continue; } else { g_printerr ("Error sending to socket: %s\n", error->message); return 1; } } g_print ("sent %" G_GSSIZE_FORMAT " bytes of data\n", size); if (size == 0) { g_printerr ("Unexpected short write\n"); return 1; } to_send -= size; } if (use_udp) { ensure_socket_condition (socket, G_IO_IN, cancellable); size = g_socket_receive_from (socket, &src_address, buffer, sizeof buffer, cancellable, &error); } else { ensure_connection_condition (connection, G_IO_IN, cancellable); size = g_input_stream_read (istream, buffer, sizeof buffer, cancellable, &error); } if (size < 0) { g_printerr ("Error receiving from socket: %s\n", error->message); return 1; } if (size == 0) break; g_print ("received %" G_GSSIZE_FORMAT " bytes of data", size); if (use_udp) g_print (" from %s", socket_address_to_string (src_address)); g_print ("\n"); if (verbose) g_print ("-------------------------\n" "%.*s" "-------------------------\n", (int)size, buffer); } g_print ("closing socket\n"); if (connection) { if (!g_io_stream_close (connection, cancellable, &error)) { g_printerr ("Error closing connection: %s\n", error->message); return 1; } g_object_unref (connection); } else { if (!g_socket_close (socket, &error)) { g_printerr ("Error closing master socket: %s\n", error->message); return 1; } } g_object_unref (socket); g_object_unref (address); return 0; }