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;
}
示例#2
0
/**
 * 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;
}
示例#3
0
/* 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;
}
示例#4
0
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);
}
示例#5
0
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;
}