/* Prompts the user to accept the certificate as it failed due to the * passed errors. */ static void request_accept_certificate(const gchar *identity, GTlsCertificate *peer_cert, GTlsCertificateFlags errors) { UserCertRequestData *data; gchar *primary; g_return_if_fail(identity != NULL && identity[0] != '\0'); g_return_if_fail(G_IS_TLS_CERTIFICATE(peer_cert)); g_return_if_fail(errors != 0); data = g_new(UserCertRequestData, 1); data->identity = g_strdup(identity); data->cert = g_object_ref(peer_cert); primary = g_strdup_printf(_("Accept certificate for %s?"), identity); purple_request_certificate(data, _("TLS Certificate Verification"), primary, tls_certificate_flags_to_reason(errors), data->cert, _("Accept"), G_CALLBACK(user_cert_request_accept_cb), _("Reject"), G_CALLBACK(user_cert_request_deny_cb), data); g_free(primary); }
/** * g_tls_database_verify_chain_async: * @self: a #GTlsDatabase * @chain: a #GTlsCertificate chain * @purpose: the purpose that this certificate chain will be used for. * @identity: (allow-none): the expected peer identity * @interaction: (allow-none): used to interact with the user if necessary * @flags: additional verify flags * @cancellable: (allow-none): a #GCancellable, or %NULL * @callback: callback to call when the operation completes * @user_data: the data to pass to the callback function * * Asynchronously verify's a certificate chain after looking up and adding * any missing certificates to the chain. See g_tls_database_verify_chain() * for more information. * * Since: 2.30 */ void g_tls_database_verify_chain_async (GTlsDatabase *self, GTlsCertificate *chain, const gchar *purpose, GSocketConnectable *identity, GTlsInteraction *interaction, GTlsDatabaseVerifyFlags flags, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { g_return_if_fail (G_IS_TLS_DATABASE (self)); g_return_if_fail (G_IS_TLS_CERTIFICATE (chain)); g_return_if_fail (purpose != NULL); g_return_if_fail (interaction == NULL || G_IS_TLS_INTERACTION (interaction)); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); g_return_if_fail (identity == NULL || G_IS_SOCKET_CONNECTABLE (identity)); g_return_if_fail (callback != NULL); g_return_if_fail (G_TLS_DATABASE_GET_CLASS (self)->verify_chain_async); G_TLS_DATABASE_GET_CLASS (self)->verify_chain_async (self, chain, purpose, identity, interaction, flags, cancellable, callback, user_data); }
gboolean purple_tls_certificate_trust(const gchar *id, GTlsCertificate *certificate, GError **error) { gchar *path; gchar *pem = NULL; gboolean ret; g_return_val_if_fail(id != NULL && id[0] != '\0', FALSE); g_return_val_if_fail(G_IS_TLS_CERTIFICATE(certificate), FALSE); /* Ensure certificate directory exists */ if (!ensure_certificate_dir(error)) { return FALSE; } /* Get the text representation of the certificate */ g_object_get(certificate, "certificate-pem", &pem, NULL); g_return_val_if_fail(pem != NULL, FALSE); /* Save certificate text to a fail */ path = make_certificate_path(id); ret = g_file_set_contents(path, pem, -1, error); g_free(path); g_free(pem); return ret; }
static void testLoadFailedWithTLSErrors(TLSErrorsTest* test, gconstpointer) { WebKitWebContext* context = webkit_web_view_get_context(test->m_webView); WebKitTLSErrorsPolicy originalPolicy = webkit_web_context_get_tls_errors_policy(context); webkit_web_context_set_tls_errors_policy(context, WEBKIT_TLS_ERRORS_POLICY_FAIL); // The load-failed-with-tls-errors signal should be emitted when there is a TLS failure. test->loadURI(kHttpsServer->getURIForPath("/test-tls/").data()); test->waitUntilLoadFinished(); g_assert(G_IS_TLS_CERTIFICATE(test->certificate())); g_assert_cmpuint(test->tlsErrors(), ==, G_TLS_CERTIFICATE_UNKNOWN_CA); g_assert_cmpstr(test->host(), ==, soup_uri_get_host(kHttpsServer->baseURI())); g_assert_cmpint(test->m_loadEvents[0], ==, LoadTrackingTest::ProvisionalLoadStarted); g_assert_cmpint(test->m_loadEvents[1], ==, LoadTrackingTest::LoadFailedWithTLSErrors); g_assert_cmpint(test->m_loadEvents[2], ==, LoadTrackingTest::LoadFinished); // Test allowing an exception for this certificate on this host. webkit_web_context_allow_tls_certificate_for_host(context, test->certificate(), test->host()); // The page should now load without errors. test->loadURI(kHttpsServer->getURIForPath("/test-tls/").data()); test->waitUntilLoadFinished(); g_assert_cmpint(test->m_loadEvents[0], ==, LoadTrackingTest::ProvisionalLoadStarted); g_assert_cmpint(test->m_loadEvents[1], ==, LoadTrackingTest::LoadCommitted); g_assert_cmpint(test->m_loadEvents[2], ==, LoadTrackingTest::LoadFinished); g_assert_cmpstr(webkit_web_view_get_title(test->m_webView), ==, TLSExpectedSuccessTitle); webkit_web_context_set_tls_errors_policy(context, originalPolicy); }
/** * g_tls_database_verify_chain: * @self: a #GTlsDatabase * @chain: a #GTlsCertificate chain * @purpose: the purpose that this certificate chain will be used for. * @identity: (allow-none): the expected peer identity * @interaction: (allow-none): used to interact with the user if necessary * @flags: additional verify flags * @cancellable: (allow-none): a #GCancellable, or %NULL * @error: (allow-none): a #GError, or %NULL * * Verify's a certificate chain after looking up and adding any missing * certificates to the chain. * * @chain is a chain of #GTlsCertificate objects each pointing to the next * certificate in the chain by its %issuer property. The chain may initially * consist of one or more certificates. After the verification process is * complete, @chain may be modified by adding missing certificates, or removing * extra certificates. If a certificate anchor was found, then it is added to * the @chain. * * @purpose describes the purpose (or usage) for which the certificate * is being used. Typically @purpose will be set to #G_TLS_DATABASE_PURPOSE_AUTHENTICATE_SERVER * which means that the certificate is being used to authenticate a server * (and we are acting as the client). * * The @identity is used to check for pinned certificates (trust exceptions) * in the database. These will override the normal verification process on a * host by host basis. * * Currently there are no @flags, and %G_TLS_DATABASE_VERIFY_NONE should be * used. * * This function can block, use g_tls_database_verify_chain_async() to perform * the verification operation asynchronously. * * Return value: the appropriate #GTlsCertificateFlags which represents the * result of verification. * * Since: 2.30 */ GTlsCertificateFlags g_tls_database_verify_chain (GTlsDatabase *self, GTlsCertificate *chain, const gchar *purpose, GSocketConnectable *identity, GTlsInteraction *interaction, GTlsDatabaseVerifyFlags flags, GCancellable *cancellable, GError **error) { g_return_val_if_fail (G_IS_TLS_DATABASE (self), G_TLS_CERTIFICATE_GENERIC_ERROR); g_return_val_if_fail (G_IS_TLS_DATABASE (self), G_TLS_CERTIFICATE_GENERIC_ERROR); g_return_val_if_fail (G_IS_TLS_CERTIFICATE (chain), G_TLS_CERTIFICATE_GENERIC_ERROR); g_return_val_if_fail (purpose, G_TLS_CERTIFICATE_GENERIC_ERROR); g_return_val_if_fail (interaction == NULL || G_IS_TLS_INTERACTION (interaction), G_TLS_CERTIFICATE_GENERIC_ERROR); g_return_val_if_fail (identity == NULL || G_IS_SOCKET_CONNECTABLE (identity), G_TLS_CERTIFICATE_GENERIC_ERROR); g_return_val_if_fail (error == NULL || *error == NULL, G_TLS_CERTIFICATE_GENERIC_ERROR); g_return_val_if_fail (G_TLS_DATABASE_GET_CLASS (self)->verify_chain, G_TLS_CERTIFICATE_GENERIC_ERROR); return G_TLS_DATABASE_GET_CLASS (self)->verify_chain (self, chain, purpose, identity, interaction, flags, cancellable, error); }
static void g_tls_database_real_lookup_certificate_issuer_async (GTlsDatabase *self, GTlsCertificate *certificate, GTlsInteraction *interaction, GTlsDatabaseLookupFlags flags, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GSimpleAsyncResult *res; AsyncLookupCertificateIssuer *args; g_return_if_fail (G_IS_TLS_CERTIFICATE (certificate)); g_return_if_fail (callback != NULL); args = g_slice_new0 (AsyncLookupCertificateIssuer); args->certificate = g_object_ref (certificate); args->flags = flags; args->interaction = interaction ? g_object_ref (interaction) : NULL; res = g_simple_async_result_new (G_OBJECT (self), callback, user_data, g_tls_database_real_lookup_certificate_issuer_async); g_simple_async_result_set_op_res_gpointer (res, args, async_lookup_certificate_issuer_free); g_simple_async_result_run_in_thread (res, async_lookup_certificate_issuer_thread, G_PRIORITY_DEFAULT, cancellable); g_object_unref (res); }
/** * g_dtls_connection_set_certificate: * @conn: a #GDtlsConnection * @certificate: the certificate to use for @conn * * This sets the certificate that @conn will present to its peer * during the TLS handshake. For a #GDtlsServerConnection, it is * mandatory to set this, and that will normally be done at construct * time. * * For a #GDtlsClientConnection, this is optional. If a handshake fails * with %G_TLS_ERROR_CERTIFICATE_REQUIRED, that means that the server * requires a certificate, and if you try connecting again, you should * call this method first. You can call * g_dtls_client_connection_get_accepted_cas() on the failed connection * to get a list of Certificate Authorities that the server will * accept certificates from. * * (It is also possible that a server will allow the connection with * or without a certificate; in that case, if you don't provide a * certificate, you can tell that the server requested one by the fact * that g_dtls_client_connection_get_accepted_cas() will return * non-%NULL.) * * Since: 2.48 */ void g_dtls_connection_set_certificate (GDtlsConnection *conn, GTlsCertificate *certificate) { g_return_if_fail (G_IS_DTLS_CONNECTION (conn)); g_return_if_fail (G_IS_TLS_CERTIFICATE (certificate)); g_object_set (G_OBJECT (conn), "certificate", certificate, NULL); }
/** * g_tls_database_create_certificate_handle: * @self: a #GTlsDatabase * @certificate: certificate for which to create a handle. * * Create a handle string for the certificate. The database will only be able * to create a handle for certificates that originate from the database. In * cases where the database cannot create a handle for a certificate, %NULL * will be returned. * * This handle should be stable across various instances of the application, * and between applications. If a certificate is modified in the database, * then it is not guaranteed that this handle will continue to point to it. * * Returns: (allow-none): a newly allocated string containing the handle. * Since: 2.30 */ gchar* g_tls_database_create_certificate_handle (GTlsDatabase *self, GTlsCertificate *certificate) { g_return_val_if_fail (G_IS_TLS_DATABASE (self), NULL); g_return_val_if_fail (G_IS_TLS_CERTIFICATE (certificate), NULL); g_return_val_if_fail (G_TLS_DATABASE_GET_CLASS (self)->create_certificate_handle, NULL); return G_TLS_DATABASE_GET_CLASS (self)->create_certificate_handle (self, certificate); }
/* 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; }
/** * g_tls_database_lookup_certificate_issuer: * @self: a #GTlsDatabase * @certificate: a #GTlsCertificate * @interaction: (allow-none): used to interact with the user if necessary * @flags: flags which affect the lookup operation * @cancellable: (allow-none): a #GCancellable, or %NULL * @error: (allow-none): a #GError, or %NULL * * Lookup the issuer of @certificate in the database. * * The %issuer property * of @certificate is not modified, and the two certificates are not hooked * into a chain. * * This function can block, use g_tls_database_lookup_certificate_issuer_async() to perform * the lookup operation asynchronously. * * Return value: (transfer full): a newly allocated issuer #GTlsCertificate, * or %NULL. Use g_object_unref() to release the certificate. * * Since: 2.30 */ GTlsCertificate* g_tls_database_lookup_certificate_issuer (GTlsDatabase *self, GTlsCertificate *certificate, GTlsInteraction *interaction, GTlsDatabaseLookupFlags flags, GCancellable *cancellable, GError **error) { g_return_val_if_fail (G_IS_TLS_DATABASE (self), NULL); g_return_val_if_fail (G_IS_TLS_CERTIFICATE (certificate), NULL); g_return_val_if_fail (interaction == NULL || G_IS_TLS_INTERACTION (interaction), NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); g_return_val_if_fail (G_TLS_DATABASE_GET_CLASS (self)->lookup_certificate_issuer, NULL); return G_TLS_DATABASE_GET_CLASS (self)->lookup_certificate_issuer (self, certificate, interaction, flags, cancellable, error); }
/** * g_tls_database_lookup_certificate_issuer_async: * @self: a #GTlsDatabase * @certificate: a #GTlsCertificate * @interaction: (allow-none): used to interact with the user if necessary * @flags: flags which affect the lookup operation * @cancellable: (allow-none): a #GCancellable, or %NULL * @callback: callback to call when the operation completes * @user_data: the data to pass to the callback function * * Asynchronously lookup the issuer of @certificate in the database. See * g_tls_database_lookup_certificate_issuer() for more information. * * Since: 2.30 */ void g_tls_database_lookup_certificate_issuer_async (GTlsDatabase *self, GTlsCertificate *certificate, GTlsInteraction *interaction, GTlsDatabaseLookupFlags flags, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { g_return_if_fail (G_IS_TLS_DATABASE (self)); g_return_if_fail (G_IS_TLS_CERTIFICATE (certificate)); g_return_if_fail (interaction == NULL || G_IS_TLS_INTERACTION (interaction)); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); g_return_if_fail (callback != NULL); g_return_if_fail (G_TLS_DATABASE_GET_CLASS (self)->lookup_certificate_issuer_async); G_TLS_DATABASE_GET_CLASS (self)->lookup_certificate_issuer_async (self, certificate, interaction, flags, cancellable, callback, user_data); }