Add initial TLS (SSL) support to gio

This adds an extension point for TLS connections to gio, with a
gnutls-based implementation in glib-networking.

Full TLS support is still a work in progress; the current API is
missing some features, and parts of it may still be changed before
2.28.

https://bugzilla.gnome.org/show_bug.cgi?id=588189
This commit is contained in:
Dan Winship 2009-12-21 20:50:32 +01:00
parent a1690339c7
commit 59d62726de
27 changed files with 3473 additions and 211 deletions

View File

@ -125,6 +125,15 @@
<xi:include href="xml/gsocketservice.xml"/>
<xi:include href="xml/gthreadedsocketservice.xml"/>
</chapter>
<chapter id="tls">
<title>TLS (SSL) support</title>
<xi:include href="xml/gtls.xml"/>
<xi:include href="xml/gtlscertificate.xml"/>
<xi:include href="xml/gtlsconnection.xml"/>
<xi:include href="xml/gtlsclientconnection.xml"/>
<xi:include href="xml/gtlsserverconnection.xml"/>
<xi:include href="xml/gtlsbackend.xml"/>
</chapter>
<chapter id="resolver">
<title>DNS resolution</title>
<xi:include href="xml/gresolver.xml"/>

View File

@ -1798,13 +1798,17 @@ g_socket_client_set_local_address
g_socket_client_set_protocol
g_socket_client_set_socket_type
g_socket_client_set_timeout
g_socket_client_set_enable_proxy
g_socket_client_set_tls
g_socket_client_set_tls_validation_flags
g_socket_client_get_family
g_socket_client_get_local_address
g_socket_client_get_protocol
g_socket_client_get_socket_type
g_socket_client_get_timeout
g_socket_client_get_enable_proxy
g_socket_client_set_enable_proxy
g_socket_client_get_tls
g_socket_client_get_tls_validation_flags
<SUBSECTION Standard>
GSocketClientClass
G_IS_SOCKET_CLIENT
@ -2994,3 +2998,126 @@ G_TYPE_POLLABLE_OUTPUT_STREAM
<SUBSECTION Private>
g_pollable_output_stream_get_type
</SECTION>
<SECTION>
<FILE>gtls</FILE>
G_TLS_ERROR
GTlsError
<SUBSECTION>
GTlsAuthenticationMode
GTlsCertificateFlags
</SECTION>
<SECTION>
<FILE>gtlsbackend</FILE>
<TITLE>GTlsBackend</FILE>
G_TLS_BACKEND_EXTENSION_POINT_NAME
GTlsBackend
GTlsBackendInterface
g_tls_backend_get_default
g_tls_backend_supports_tls
g_tls_backend_get_certificate_type
g_tls_backend_get_client_connection_type
g_tls_backend_get_server_connection_type
<SUBSECTION Standard>
G_IS_TLS_BACKEND
G_TLS_BACKEND
G_TLS_BACKEND_GET_INTERFACE
G_TYPE_TLS_BACKEND
g_tls_error_quark
<SUBSECTION Private>
g_tls_backend_get_type
</SECTION>
<SECTION>
<FILE>gtlscertificate</FILE>
<TITLE>GTlsCertificate</TITLE>
GTlsCertificate
g_tls_certificate_new
g_tls_certificate_new_from_pem
g_tls_certificate_new_from_file
g_tls_certificate_new_from_files
g_tls_certificate_list_new_from_file
g_tls_certificate_get_issuer
<SUBSECTION Standard>
GTlsCertificateClass
GTlsCertificatePrivate
G_IS_TLS_CERTIFICATE
G_IS_TLS_CERTIFICATE_CLASS
G_TLS_CERTIFICATE
G_TLS_CERTIFICATE_CLASS
G_TLS_CERTIFICATE_GET_CLASS
G_TYPE_TLS_CERTIFICATE
<SUBSECTION Private>
g_tls_certificate_get_type
</SECTION>
<SECTION>
<FILE>gtlsconnection</FILE>
<TITLE>GTlsConnection</TITLE>
GTlsConnection
g_tls_connection_set_certificate
g_tls_connection_get_certificate
g_tls_connection_get_peer_certificate
g_tls_connection_set_require_close_notify
g_tls_connection_get_require_close_notify
GTlsRehandshakeMode
g_tls_connection_set_rehandshake_mode
g_tls_connection_get_rehandshake_mode
<SUBSECTION>
g_tls_connection_handshake
g_tls_connection_handshake_async
g_tls_connection_handshake_finish
<SUBSECTION>
g_tls_connection_set_peer_certificate
g_tls_connection_emit_accept_certificate
g_tls_connection_emit_need_certificate
<SUBSECTION Standard>
GTlsConnectionClass
GTlsConnectionPrivate
G_IS_TLS_CONNECTION
G_IS_TLS_CONNECTION_CLASS
G_TLS_CONNECTION
G_TLS_CONNECTION_CLASS
G_TLS_CONNECTION_GET_CLASS
G_TYPE_TLS_CONNECTION
<SUBSECTION Private>
g_tls_connection_get_type
</SECTION>
<SECTION>
<FILE>gtlsclientconnection</FILE>
<TITLE>GTlsClientConnection</TITLE>
GTlsClientConnection
GTlsClientConnectionInterface
g_tls_client_connection_new
g_tls_client_connection_set_server_identity
g_tls_client_connection_get_server_identity
g_tls_client_connection_set_validation_flags
g_tls_client_connection_get_validation_flags
g_tls_client_connection_set_use_ssl3
g_tls_client_connection_get_use_ssl3
g_tls_client_connection_get_accepted_cas
<SUBSECTION Standard>
G_IS_TLS_CLIENT_CONNECTION
G_TLS_CLIENT_CONNECTION
G_TLS_CLIENT_CONNECTION_GET_INTERFACE
G_TYPE_TLS_CLIENT_CONNECTION
<SUBSECTION Private>
g_tls_client_connection_get_type
</SECTION>
<SECTION>
<FILE>gtlsserverconnection</FILE>
<TITLE>GTlsServerConnection</TITLE>
GTlsServerConnection
GTlsServerConnectionInterface
g_tls_server_connection_new
<SUBSECTION Standard>
G_IS_TLS_SERVER_CONNECTION
G_TLS_SERVER_CONNECTION
G_TLS_SERVER_CONNECTION_GET_INTERFACE
G_TYPE_TLS_SERVER_CONNECTION
<SUBSECTION Private>
g_tls_server_connection_get_type
</SECTION>

View File

@ -108,6 +108,11 @@ g_tcp_connection_get_type
g_tcp_wrapper_connection_get_type
g_themed_icon_get_type
g_threaded_socket_service_get_type
g_tls_backend_get_type
g_tls_certificate_get_type
g_tls_client_connection_get_type
g_tls_connection_get_type
g_tls_server_connection_get_type
g_unix_connection_get_type
g_unix_fd_list_get_type
g_unix_fd_message_get_type

View File

@ -202,7 +202,6 @@ platform_libadd += win32/libgiowin32.la
platform_deps += win32/libgiowin32.la
endif
SUBDIRS += .
if HAVE_FAM
@ -307,6 +306,8 @@ libgio_2_0_la_SOURCES = \
gdummyfile.c \
gdummyproxyresolver.c \
gdummyproxyresolver.h \
gdummytlsbackend.c \
gdummytlsbackend.h \
gemblem.h \
gemblem.c \
gemblemedicon.h \
@ -381,6 +382,11 @@ libgio_2_0_la_SOURCES = \
gthemedicon.c \
gthreadedresolver.c \
gthreadedresolver.h \
gtlsbackend.c \
gtlscertificate.c \
gtlsclientconnection.c \
gtlsconnection.c \
gtlsserverconnection.c \
gunionvolumemonitor.c \
gunionvolumemonitor.h \
gvfs.c \
@ -530,6 +536,11 @@ gio_headers = \
gtcpwrapperconnection.h \
gthreadedsocketservice.h\
gthemedicon.h \
gtlsbackend.h \
gtlscertificate.h \
gtlsclientconnection.h \
gtlsconnection.h \
gtlsserverconnection.h \
gvfs.h \
gvolume.h \
gvolumemonitor.h \

274
gio/gdummytlsbackend.c Normal file
View File

@ -0,0 +1,274 @@
/* GIO - GLib Input, Output and Streaming Library
*
* Copyright (C) 2010 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "config.h"
#include "gdummytlsbackend.h"
#include <glib.h>
#include "gasyncresult.h"
#include "gcancellable.h"
#include "ginitable.h"
#include "gtlsbackend.h"
#include "gtlscertificate.h"
#include "gtlsclientconnection.h"
#include "gtlsserverconnection.h"
#include "gsimpleasyncresult.h"
#include "giomodule.h"
#include "giomodule-priv.h"
#include "glibintl.h"
static GType _g_dummy_tls_certificate_get_type (void);
static GType _g_dummy_tls_connection_get_type (void);
struct _GDummyTlsBackend {
GObject parent_instance;
};
static void g_dummy_tls_backend_iface_init (GTlsBackendInterface *iface);
#define g_dummy_tls_backend_get_type _g_dummy_tls_backend_get_type
G_DEFINE_TYPE_WITH_CODE (GDummyTlsBackend, g_dummy_tls_backend, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (G_TYPE_TLS_BACKEND,
g_dummy_tls_backend_iface_init)
_g_io_modules_ensure_extension_points_registered ();
g_io_extension_point_implement (G_TLS_BACKEND_EXTENSION_POINT_NAME,
g_define_type_id,
"dummy",
-100))
static void
g_dummy_tls_backend_init (GDummyTlsBackend *backend)
{
}
static void
g_dummy_tls_backend_class_init (GDummyTlsBackendClass *backend_class)
{
}
static void
g_dummy_tls_backend_iface_init (GTlsBackendInterface *iface)
{
iface->get_certificate_type = _g_dummy_tls_certificate_get_type;
iface->get_client_connection_type = _g_dummy_tls_connection_get_type;
iface->get_server_connection_type = _g_dummy_tls_connection_get_type;
}
/* Dummy certificate type */
typedef struct _GDummyTlsCertificate GDummyTlsCertificate;
typedef struct _GDummyTlsCertificateClass GDummyTlsCertificateClass;
struct _GDummyTlsCertificate {
GTlsCertificate parent_instance;
};
struct _GDummyTlsCertificateClass {
GTlsCertificateClass parent_class;
};
enum
{
PROP_CERTIFICATE_0,
PROP_CERTIFICATE,
PROP_CERTIFICATE_PEM,
PROP_PRIVATE_KEY,
PROP_PRIVATE_KEY_PEM
};
static void g_dummy_tls_certificate_initable_iface_init (GInitableIface *iface);
#define g_dummy_tls_certificate_get_type _g_dummy_tls_certificate_get_type
G_DEFINE_TYPE_WITH_CODE (GDummyTlsCertificate, g_dummy_tls_certificate, G_TYPE_TLS_CERTIFICATE,
G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
g_dummy_tls_certificate_initable_iface_init);)
static void
g_dummy_tls_certificate_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
/* We need to define this method to make GObject happy, but it will
* never be possible to construct a working GDummyTlsCertificate, so
* it doesn't have to do anything useful.
*/
}
static void
g_dummy_tls_certificate_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
/* Just ignore all attempts to set properties. */
}
static void
g_dummy_tls_certificate_class_init (GDummyTlsCertificateClass *certificate_class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (certificate_class);
gobject_class->get_property = g_dummy_tls_certificate_get_property;
gobject_class->set_property = g_dummy_tls_certificate_set_property;
g_object_class_override_property (gobject_class, PROP_CERTIFICATE, "certificate");
g_object_class_override_property (gobject_class, PROP_CERTIFICATE_PEM, "certificate-pem");
g_object_class_override_property (gobject_class, PROP_PRIVATE_KEY, "private-key");
g_object_class_override_property (gobject_class, PROP_PRIVATE_KEY_PEM, "private-key-pem");
}
static void
g_dummy_tls_certificate_init (GDummyTlsCertificate *certificate)
{
}
static gboolean
g_dummy_tls_certificate_initable_init (GInitable *initable,
GCancellable *cancellable,
GError **error)
{
g_set_error_literal (error, G_TLS_ERROR, G_TLS_ERROR_MISC,
_("TLS support is not available"));
return FALSE;
}
static void
g_dummy_tls_certificate_initable_iface_init (GInitableIface *iface)
{
iface->init = g_dummy_tls_certificate_initable_init;
}
/* Dummy connection type; since GTlsClientConnection and
* GTlsServerConnection are just interfaces, we can implement them
* both on a single object.
*/
typedef struct _GDummyTlsConnection GDummyTlsConnection;
typedef struct _GDummyTlsConnectionClass GDummyTlsConnectionClass;
struct _GDummyTlsConnection {
GTlsConnection parent_instance;
};
struct _GDummyTlsConnectionClass {
GTlsConnectionClass parent_class;
};
enum
{
PROP_CONNECTION_0,
PROP_BASE_IO_STREAM,
PROP_REQUIRE_CLOSE_NOTIFY,
PROP_REHANDSHAKE_MODE,
PROP_VALIDATION_FLAGS,
PROP_SERVER_IDENTITY,
PROP_USE_SSL3,
PROP_ACCEPTED_CAS,
PROP_AUTHENTICATION_MODE
};
static void g_dummy_tls_connection_initable_iface_init (GInitableIface *iface);
#define g_dummy_tls_connection_get_type _g_dummy_tls_connection_get_type
G_DEFINE_TYPE_WITH_CODE (GDummyTlsConnection, g_dummy_tls_connection, G_TYPE_TLS_CONNECTION,
G_IMPLEMENT_INTERFACE (G_TYPE_TLS_CLIENT_CONNECTION, NULL);
G_IMPLEMENT_INTERFACE (G_TYPE_TLS_SERVER_CONNECTION, NULL);
G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
g_dummy_tls_connection_initable_iface_init);)
static void
g_dummy_tls_connection_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
}
static void
g_dummy_tls_connection_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
}
static gboolean
g_dummy_tls_connection_close (GIOStream *stream,
GCancellable *cancellable,
GError **error)
{
return TRUE;
}
static void
g_dummy_tls_connection_class_init (GDummyTlsConnectionClass *connection_class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (connection_class);
GIOStreamClass *io_stream_class = G_IO_STREAM_CLASS (connection_class);
gobject_class->get_property = g_dummy_tls_connection_get_property;
gobject_class->set_property = g_dummy_tls_connection_set_property;
/* Need to override this because when initable_init fails it will
* dispose the connection, which will close it, which would
* otherwise try to close its input/output streams, which don't
* exist.
*/
io_stream_class->close_fn = g_dummy_tls_connection_close;
g_object_class_override_property (gobject_class, PROP_BASE_IO_STREAM, "base-io-stream");
g_object_class_override_property (gobject_class, PROP_REQUIRE_CLOSE_NOTIFY, "require-close-notify");
g_object_class_override_property (gobject_class, PROP_REHANDSHAKE_MODE, "rehandshake-mode");
g_object_class_override_property (gobject_class, PROP_VALIDATION_FLAGS, "validation-flags");
g_object_class_override_property (gobject_class, PROP_SERVER_IDENTITY, "server-identity");
g_object_class_override_property (gobject_class, PROP_USE_SSL3, "use-ssl3");
g_object_class_override_property (gobject_class, PROP_ACCEPTED_CAS, "accepted-cas");
g_object_class_override_property (gobject_class, PROP_AUTHENTICATION_MODE, "authentication-mode");
}
static void
g_dummy_tls_connection_init (GDummyTlsConnection *connection)
{
}
static gboolean
g_dummy_tls_connection_initable_init (GInitable *initable,
GCancellable *cancellable,
GError **error)
{
g_set_error_literal (error, G_TLS_ERROR, G_TLS_ERROR_MISC,
_("TLS support is not available"));
return FALSE;
}
static void
g_dummy_tls_connection_initable_iface_init (GInitableIface *iface)
{
iface->init = g_dummy_tls_connection_initable_init;
}

46
gio/gdummytlsbackend.h Normal file
View File

@ -0,0 +1,46 @@
/* GIO - GLib Input, Output and Streaming Library
*
* Copyright (C) 2010 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __G_DUMMY_TLS_BACKEND_H__
#define __G_DUMMY_TLS_BACKEND_H__
#include <gio/giotypes.h>
G_BEGIN_DECLS
#define G_TYPE_DUMMY_TLS_BACKEND (_g_dummy_tls_backend_get_type ())
#define G_DUMMY_TLS_BACKEND(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_DUMMY_TLS_BACKEND, GDummyTlsBackend))
#define G_DUMMY_TLS_BACKEND_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_DUMMY_TLS_BACKEND, GDummyTlsBackendClass))
#define G_IS_DUMMY_TLS_BACKEND(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_DUMMY_TLS_BACKEND))
#define G_IS_DUMMY_TLS_BACKEND_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_DUMMY_TLS_BACKEND))
#define G_DUMMY_TLS_BACKEND_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_DUMMY_TLS_BACKEND, GDummyTlsBackendClass))
typedef struct _GDummyTlsBackend GDummyTlsBackend;
typedef struct _GDummyTlsBackendClass GDummyTlsBackendClass;
struct _GDummyTlsBackendClass {
GObjectClass parent_class;
};
GType _g_dummy_tls_backend_get_type (void);
G_END_DECLS
#endif /* __G_DUMMY_TLS_BACKEND_H__ */

View File

@ -27,3 +27,5 @@ INT:OBJECT
VOID:INT64
VOID:UINT64
BOOLEAN:FLAGS
BOOLEAN:OBJECT,FLAGS
OBJECT:VOID

View File

@ -120,6 +120,11 @@
#include <gio/gtcpwrapperconnection.h>
#include <gio/gthemedicon.h>
#include <gio/gthreadedsocketservice.h>
#include <gio/gtlsbackend.h>
#include <gio/gtlscertificate.h>
#include <gio/gtlsclientconnection.h>
#include <gio/gtlsconnection.h>
#include <gio/gtlsserverconnection.h>
#include <gio/gvfs.h>
#include <gio/gvolume.h>
#include <gio/gvolumemonitor.h>

View File

@ -1067,6 +1067,9 @@ g_dbus_signal_flags_get_type G_GNUC_CONST
g_dbus_send_message_flags_get_type G_GNUC_CONST
g_credentials_type_get_type G_GNUC_CONST
g_dbus_message_byte_order_get_type G_GNUC_CONST
g_tls_authentication_mode_get_type G_GNUC_CONST
g_tls_certificate_flags_get_type G_GNUC_CONST
g_tls_rehandshake_mode_get_type G_GNUC_CONST
#endif
#endif
@ -1371,6 +1374,7 @@ g_socket_control_message_serialize
#if IN_HEADER(__G_SOCKET_CLIENT_H__)
#if IN_FILE(__G_SOCKET_CLIENT_C__)
g_socket_client_get_type G_GNUC_CONST
g_socket_client_add_application_proxy
g_socket_client_connect
g_socket_client_connect_async
g_socket_client_connect_finish
@ -1383,20 +1387,23 @@ g_socket_client_connect_to_service_finish
g_socket_client_connect_to_uri
g_socket_client_connect_to_uri_async
g_socket_client_connect_to_uri_finish
g_socket_client_get_enable_proxy
g_socket_client_get_family
g_socket_client_get_local_address
g_socket_client_get_protocol
g_socket_client_get_socket_type
g_socket_client_get_timeout
g_socket_client_get_enable_proxy
g_socket_client_get_tls
g_socket_client_get_tls_validation_flags
g_socket_client_new
g_socket_client_set_enable_proxy
g_socket_client_set_family
g_socket_client_set_local_address
g_socket_client_set_protocol
g_socket_client_set_socket_type
g_socket_client_set_timeout
g_socket_client_set_enable_proxy
g_socket_client_add_application_proxy
g_socket_client_set_tls
g_socket_client_set_tls_validation_flags
#endif
#endif
@ -2002,3 +2009,67 @@ g_tcp_wrapper_connection_get_base_io_stream
g_tcp_wrapper_connection_new
#endif
#endif
#if IN_HEADER(__G_TLS_BACKEND_H__)
#if IN_FILE(__G_TLS_BACKEND_C__)
g_tls_backend_get_certificate_type
g_tls_backend_get_client_connection_type
g_tls_backend_get_default
g_tls_backend_get_server_connection_type
g_tls_backend_get_type G_GNUC_CONST
g_tls_backend_supports_tls
g_tls_error_get_type G_GNUC_CONST
g_tls_error_quark
#endif
#endif
#if IN_HEADER(__G_TLS_CERTIFICATE_H__)
#if IN_FILE(__G_TLS_CERTIFICATE_C__)
g_tls_certificate_get_issuer
g_tls_certificate_get_type G_GNUC_CONST
g_tls_certificate_list_new_from_file
g_tls_certificate_new_from_file
g_tls_certificate_new_from_files
g_tls_certificate_new_from_pem
#endif
#endif
#if IN_HEADER(__G_TLS_CONNECTION_H__)
#if IN_FILE(__G_TLS_CONNECTION_C__)
g_tls_connection_emit_accept_certificate
g_tls_connection_emit_need_certificate
g_tls_connection_get_certificate
g_tls_connection_get_peer_certificate
g_tls_connection_get_rehandshake_mode
g_tls_connection_get_require_close_notify
g_tls_connection_get_type G_GNUC_CONST
g_tls_connection_handshake
g_tls_connection_handshake_async
g_tls_connection_handshake_finish
g_tls_connection_set_certificate
g_tls_connection_set_peer_certificate
g_tls_connection_set_rehandshake_mode
g_tls_connection_set_require_close_notify
#endif
#endif
#if IN_HEADER(__G_TLS_CLIENT_CONNECTION_H__)
#if IN_FILE(__G_TLS_CLIENT_CONNECTION_C__)
g_tls_client_connection_get_accepted_cas
g_tls_client_connection_get_server_identity
g_tls_client_connection_get_type G_GNUC_CONST
g_tls_client_connection_get_use_ssl3
g_tls_client_connection_get_validation_flags
g_tls_client_connection_new
g_tls_client_connection_set_server_identity
g_tls_client_connection_set_use_ssl3
g_tls_client_connection_set_validation_flags
#endif
#endif
#if IN_HEADER(__G_TLS_SERVER_CONNECTION_H__)
#if IN_FILE(__G_TLS_SERVER_CONNECTION_C__)
g_tls_server_connection_get_type G_GNUC_CONST
g_tls_server_connection_new
#endif
#endif

View File

@ -1249,6 +1249,106 @@ typedef enum
G_APPLICATION_SEND_ENVIRONMENT = (1 << 4)
} GApplicationFlags;
/**
* GTlsError:
* @G_TLS_ERROR_MISC: Miscellaneous TLS error
* @G_TLS_ERROR_BAD_CERTIFICATE: A certificate could not be parsed
* @G_TLS_ERROR_NOT_TLS: The TLS handshake failed because the
* peer does not seem to be a TLS server.
* @G_TLS_ERROR_HANDSHAKE: The TLS handshake failed because the
* peer's certificate was not acceptable.
* @G_TLS_ERROR_CERTIFICATE_REQUIRED: The TLS handshake failed because
* the server requested a client-side certificate, but none was
* provided. See #GTlsConnection::need-certificate.
* @G_TLS_ERROR_EOF: The TLS connection was closed without proper
* notice, which may indicate an attack. See
* g_tls_connection_set_require_close_notify().
*
* An error code used with %G_TLS_ERROR in a #GError returned from a
* TLS-related routine.
*
* Since: 2.28
*/
typedef enum {
G_TLS_ERROR_MISC,
G_TLS_ERROR_BAD_CERTIFICATE,
G_TLS_ERROR_NOT_TLS,
G_TLS_ERROR_HANDSHAKE,
G_TLS_ERROR_CERTIFICATE_REQUIRED,
G_TLS_ERROR_EOF
} GTlsError;
/**
* GTlsCertificateFlags:
* @G_TLS_CERTIFICATE_UNKNOWN_CA: The signing certificate authority is
* not known.
* @G_TLS_CERTIFICATE_BAD_IDENTITY: The certificate does not match the
* expected identity of the site that it was retrieved from.
* @G_TLS_CERTIFICATE_NOT_ACTIVATED: The certificate's activation time
* is still in the future
* @G_TLS_CERTIFICATE_EXPIRED: The certificate has expired
* @G_TLS_CERTIFICATE_REVOKED: The certificate has been revoked
* according to the #GTlsContext's certificate revocation list.
* @G_TLS_CERTIFICATE_INSECURE: The certificate's algorithm is
* considered insecure.
* @G_TLS_CERTIFICATE_GENERIC_ERROR: Some other error occurred validating
* the certificate
* @G_TLS_CERTIFICATE_VALIDATE_ALL: the combination of all of the above
* flags
*
* A set of flags describing TLS certification validation. This can be
* used to set which validation steps to perform (eg, with
* g_tls_client_connection_set_validation_flags()), or to describe why
* a particular certificate was rejected (eg, in
* #GTlsConnection::accept-certificate).
*
* Since: 2.28
*/
typedef enum {
G_TLS_CERTIFICATE_UNKNOWN_CA = (1 << 0),
G_TLS_CERTIFICATE_BAD_IDENTITY = (1 << 1),
G_TLS_CERTIFICATE_NOT_ACTIVATED = (1 << 2),
G_TLS_CERTIFICATE_EXPIRED = (1 << 3),
G_TLS_CERTIFICATE_REVOKED = (1 << 4),
G_TLS_CERTIFICATE_INSECURE = (1 << 5),
G_TLS_CERTIFICATE_GENERIC_ERROR = (1 << 6),
G_TLS_CERTIFICATE_VALIDATE_ALL = 0x007f
} GTlsCertificateFlags;
/**
* GTlsAuthenticationMode:
* @G_TLS_AUTHENTICATION_NONE: client authentication not required
* @G_TLS_AUTHENTICATION_REQUESTED: client authentication is requested
* @G_TLS_AUTHENTICATION_REQUIRED: client authentication is required
*
* The client authentication mode for a #GTlsServerConnection.
*
* Since: 2.28
*/
typedef enum {
G_TLS_AUTHENTICATION_NONE,
G_TLS_AUTHENTICATION_REQUESTED,
G_TLS_AUTHENTICATION_REQUIRED
} GTlsAuthenticationMode;
/**
* GTlsRehandshakeMode:
* @G_TLS_REHANDSHAKE_NEVER: Never allow rehandshaking
* @G_TLS_REHANDSHAKE_SAFELY: Allow safe rehandshaking only
* @G_TLS_REHANDSHAKE_UNSAFELY: Allow unsafe rehandshaking
*
* When to allow rehandshaking. See
* g_tls_connection_set_rehandshake_mode().
*
* Since: 2.28
*/
typedef enum {
G_TLS_REHANDSHAKE_NEVER,
G_TLS_REHANDSHAKE_SAFELY,
G_TLS_REHANDSHAKE_UNSAFELY
} GTlsRehandshakeMode;
G_END_DECLS
#endif /* __GIO_ENUMS_H__ */

View File

@ -35,6 +35,7 @@
#include "gsocks4proxy.h"
#include "gsocks4aproxy.h"
#include "gsocks5proxy.h"
#include "gtlsbackend.h"
#include "gvfs.h"
#ifdef G_OS_WIN32
#include "gregistrysettingsbackend.h"
@ -480,6 +481,7 @@ extern GType g_win32_directory_monitor_get_type (void);
extern GType _g_winhttp_vfs_get_type (void);
extern GType _g_dummy_proxy_resolver_get_type (void);
extern GType _g_dummy_tls_backend_get_type (void);
#ifdef G_PLATFORM_WIN32
@ -556,6 +558,9 @@ _g_io_modules_ensure_extension_points_registered (void)
ep = g_io_extension_point_register (G_PROXY_EXTENSION_POINT_NAME);
g_io_extension_point_set_required_type (ep, G_TYPE_PROXY);
ep = g_io_extension_point_register (G_TLS_BACKEND_EXTENSION_POINT_NAME);
g_io_extension_point_set_required_type (ep, G_TYPE_TLS_BACKEND);
}
G_UNLOCK (registered_extensions);
@ -618,6 +623,7 @@ _g_io_modules_ensure_loaded (void)
_g_socks4a_proxy_get_type ();
_g_socks4_proxy_get_type ();
_g_socks5_proxy_get_type ();
_g_dummy_tls_backend_get_type ();
}
G_UNLOCK (loaded_dirs);

View File

@ -109,6 +109,7 @@ typedef struct _GIOExtension GIOExtension;
* Opaque class for definining and scheduling IO jobs.
**/
typedef struct _GIOSchedulerJob GIOSchedulerJob;
typedef struct _GIOStreamAdapter GIOStreamAdapter;
typedef struct _GLoadableIcon GLoadableIcon; /* Dummy typedef */
typedef struct _GMemoryInputStream GMemoryInputStream;
typedef struct _GMemoryOutputStream GMemoryOutputStream;
@ -202,6 +203,13 @@ typedef struct _GTcpWrapperConnection GTcpWrapperConnectio
**/
typedef struct _GThreadedSocketService GThreadedSocketService;
typedef struct _GThemedIcon GThemedIcon;
typedef struct _GTlsCertificate GTlsCertificate;
typedef struct _GTlsClientConnection GTlsClientConnection; /* Dummy typedef */
typedef struct _GTlsClientContext GTlsClientContext; /* Dummy typedef */
typedef struct _GTlsConnection GTlsConnection;
typedef struct _GTlsContext GTlsContext;
typedef struct _GTlsServerConnection GTlsServerConnection; /* Dummy typedef */
typedef struct _GTlsServerContext GTlsServerContext; /* Dummy typedef */
typedef struct _GVfs GVfs; /* Dummy typedef */
/**

View File

@ -40,11 +40,12 @@
#include <gio/gsocket.h>
#include <gio/gnetworkaddress.h>
#include <gio/gnetworkservice.h>
#include <gio/gpollableiostream.h>
#include <gio/gproxy.h>
#include <gio/gsocketaddress.h>
#include <gio/gtcpconnection.h>
#include <gio/gtcpwrapperconnection.h>
#include <gio/gtlscertificate.h>
#include <gio/gtlsclientconnection.h>
#include "glibintl.h"
@ -80,6 +81,8 @@ enum
PROP_LOCAL_ADDRESS,
PROP_TIMEOUT,
PROP_ENABLE_PROXY,
PROP_TLS,
PROP_TLS_VALIDATION_FLAGS
};
struct _GSocketClientPrivate
@ -91,6 +94,8 @@ struct _GSocketClientPrivate
guint timeout;
gboolean enable_proxy;
GHashTable *app_proxies;
gboolean tls;
GTlsCertificateFlags tls_validation_flags;
};
static GSocket *
@ -219,6 +224,14 @@ g_socket_client_get_property (GObject *object,
g_value_set_boolean (value, client->priv->enable_proxy);
break;
case PROP_TLS:
g_value_set_boolean (value, g_socket_client_get_tls (client));
break;
case PROP_TLS_VALIDATION_FLAGS:
g_value_set_flags (value, g_socket_client_get_tls_validation_flags (client));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
@ -258,6 +271,14 @@ g_socket_client_set_property (GObject *object,
g_socket_client_set_enable_proxy (client, g_value_get_boolean (value));
break;
case PROP_TLS:
g_socket_client_set_tls (client, g_value_get_boolean (value));
break;
case PROP_TLS_VALIDATION_FLAGS:
g_socket_client_set_tls_validation_flags (client, g_value_get_flags (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
@ -526,6 +547,91 @@ g_socket_client_set_enable_proxy (GSocketClient *client,
g_object_notify (G_OBJECT (client), "enable-proxy");
}
/**
* g_socket_client_get_tls:
* @client: a #GSocketClient.
*
* Gets whether @client creates TLS connections. See
* g_socket_client_set_tls() for details.
*
* Returns: whether @client uses TLS
*
* Since: 2.28
*/
gboolean
g_socket_client_get_tls (GSocketClient *client)
{
return client->priv->tls;
}
/**
* g_socket_client_set_tls:
* @client: a #GSocketClient.
* @tls: whether to use TLS
*
* Sets whether @client creates TLS (aka SSL) connections. If @tls is
* %TRUE, @client will wrap its connections in a #GTlsClientConnection
* and perform a TLS handshake when connecting.
*
* Note that since #GSocketClient must return a #GSocketConnection,
* but #GTlsClientConnection is not a #GSocketConnection, this
* actually wraps the resulting #GTlsClientConnection in a
* #GTcpWrapperConnection when returning it. You can use
* g_tcp_wrapper_connection_get_base_io_stream() on the return value
* to extract the #GTlsClientConnection.
*
* Since: 2.28
*/
void
g_socket_client_set_tls (GSocketClient *client,
gboolean tls)
{
tls = !!tls;
if (tls == client->priv->tls)
return;
client->priv->tls = tls;
g_object_notify (G_OBJECT (client), "tls");
}
/**
* g_socket_client_get_tls_validation_flags:
* @client: a #GSocketClient.
*
* Gets the TLS validation flags used creating TLS connections via
* @client.
*
* Returns: the TLS validation flags
*
* Since: 2.28
*/
GTlsCertificateFlags
g_socket_client_get_tls_validation_flags (GSocketClient *client)
{
return client->priv->tls_validation_flags;
}
/**
* g_socket_client_set_tls_validation_flags:
* @client: a #GSocketClient.
* @flags: the validation flags
*
* Sets the TLS validation flags used when creating TLS connections
* via @client. The default value is %G_TLS_CERTIFICATE_VALIDATE_ALL.
*
* Since: 2.28
*/
void
g_socket_client_set_tls_validation_flags (GSocketClient *client,
GTlsCertificateFlags flags)
{
if (client->priv->tls_validation_flags != flags)
{
client->priv->tls_validation_flags = flags;
g_object_notify (G_OBJECT (client), "tls-validation-flags");
}
}
static void
g_socket_client_class_init (GSocketClientClass *class)
{
@ -594,6 +700,23 @@ g_socket_client_class_init (GSocketClientClass *class)
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_TLS,
g_param_spec_boolean ("tls",
P_("TLS"),
P_("Whether to create TLS connections"),
FALSE,
G_PARAM_CONSTRUCT |
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_TLS_VALIDATION_FLAGS,
g_param_spec_flags ("tls-validation-flags",
P_("TLS validation flags"),
P_("TLS validation flags to use"),
G_TYPE_TLS_CERTIFICATE_FLAGS,
G_TLS_CERTIFICATE_VALIDATE_ALL,
G_PARAM_CONSTRUCT |
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS));
}
/**
@ -632,7 +755,7 @@ g_socket_client_connect (GSocketClient *client,
GCancellable *cancellable,
GError **error)
{
GSocketConnection *connection = NULL;
GIOStream *connection = NULL;
GSocketAddressEnumerator *enumerator = NULL;
GError *last_error, *tmp_error;
@ -687,7 +810,7 @@ g_socket_client_connect (GSocketClient *client,
}
if (g_socket_connect (socket, address, cancellable, &last_error))
connection = g_socket_connection_factory_create_connection (socket);
connection = (GIOStream *)g_socket_connection_factory_create_connection (socket);
if (connection &&
G_IS_PROXY_ADDRESS (address) &&
@ -717,31 +840,16 @@ g_socket_client_connect (GSocketClient *client,
}
else if (proxy)
{
GIOStream *io_stream;
GIOStream *proxy_connection;
io_stream = g_proxy_connect (proxy,
G_IO_STREAM (connection),
proxy_addr,
cancellable,
&last_error);
proxy_connection = g_proxy_connect (proxy,
connection,
proxy_addr,
cancellable,
&last_error);
g_object_unref (connection);
connection = proxy_connection;
g_object_unref (proxy);
if (io_stream)
{
if (G_IS_SOCKET_CONNECTION (io_stream))
connection = G_SOCKET_CONNECTION (io_stream);
else
{
connection = g_tcp_wrapper_connection_new (G_POLLABLE_IO_STREAM (io_stream),
socket);
g_object_unref (io_stream);
}
}
else
{
connection = NULL;
}
}
else if (!g_hash_table_lookup_extended (client->priv->app_proxies,
protocol, NULL, NULL))
@ -754,12 +862,41 @@ g_socket_client_connect (GSocketClient *client,
}
}
if (connection && client->priv->tls)
{
GTlsClientConnection *tlsconn;
tlsconn = g_tls_client_connection_new (connection, connectable, &last_error);
g_object_unref (connection);
connection = (GIOStream *)tlsconn;
if (tlsconn)
{
g_tls_client_connection_set_validation_flags (tlsconn, client->priv->tls_validation_flags);
if (!g_tls_connection_handshake (G_TLS_CONNECTION (tlsconn),
cancellable, &last_error))
{
g_object_unref (tlsconn);
connection = NULL;
}
}
}
if (connection && !G_IS_SOCKET_CONNECTION (connection))
{
GSocketConnection *wrapper_connection;
wrapper_connection = g_tcp_wrapper_connection_new (connection, socket);
g_object_unref (connection);
connection = (GIOStream *)wrapper_connection;
}
g_object_unref (socket);
g_object_unref (address);
}
g_object_unref (enumerator);
return connection;
return G_SOCKET_CONNECTION (connection);
}
/**
@ -927,10 +1064,11 @@ typedef struct
GCancellable *cancellable;
GSocketClient *client;
GSocketConnectable *connectable;
GSocketAddressEnumerator *enumerator;
GProxyAddress *proxy_addr;
GSocket *current_socket;
GSocketConnection *connection;
GIOStream *connection;
GError *last_error;
} GSocketClientAsyncConnectData;
@ -946,6 +1084,16 @@ g_socket_client_async_connect_complete (GSocketClientAsyncConnectData *data)
{
g_assert (data->connection);
if (!G_IS_SOCKET_CONNECTION (data->connection))
{
GSocketConnection *wrapper_connection;
wrapper_connection = g_tcp_wrapper_connection_new (data->connection,
data->current_socket);
g_object_unref (data->connection);
data->connection = (GIOStream *)wrapper_connection;
}
g_simple_async_result_set_op_res_gpointer (data->result,
data->connection,
g_object_unref);
@ -953,6 +1101,7 @@ g_socket_client_async_connect_complete (GSocketClientAsyncConnectData *data)
g_simple_async_result_complete (data->result);
g_object_unref (data->result);
g_object_unref (data->connectable);
g_object_unref (data->enumerator);
if (data->cancellable)
g_object_unref (data->cancellable);
@ -987,45 +1136,103 @@ enumerator_next_async (GSocketClientAsyncConnectData *data)
}
static void
g_socket_client_proxy_connect_callback (GObject *object,
g_socket_client_tls_handshake_callback (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
GSocketClientAsyncConnectData *data = user_data;
GIOStream *io_stream;
io_stream = g_proxy_connect_finish (G_PROXY (object),
result,
&data->last_error);
g_object_unref (data->connection);
if (io_stream)
if (g_tls_connection_handshake_finish (G_TLS_CONNECTION (object),
result,
&data->last_error))
{
if (G_IS_SOCKET_CONNECTION (io_stream))
data->connection = G_SOCKET_CONNECTION (io_stream);
else
{
data->connection = g_tcp_wrapper_connection_new (G_POLLABLE_IO_STREAM (io_stream),
data->current_socket);
g_object_unref (io_stream);
}
g_object_unref (data->connection);
data->connection = G_IO_STREAM (object);
}
else
{
data->connection = NULL;
g_object_unref (object);
g_object_unref (data->current_socket);
data->current_socket = NULL;
g_object_unref (data->connection);
data->connection = NULL;
enumerator_next_async (data);
}
g_socket_client_async_connect_complete (data);
}
static void
g_socket_client_tls_handshake (GSocketClientAsyncConnectData *data)
{
GTlsClientConnection *tlsconn;
if (!data->client->priv->tls)
{
g_socket_client_async_connect_complete (data);
return;
}
tlsconn = g_tls_client_connection_new (data->connection,
data->connectable,
&data->last_error);
if (tlsconn)
{
g_tls_client_connection_set_validation_flags (tlsconn, data->client->priv->tls_validation_flags);
g_tls_connection_handshake_async (G_TLS_CONNECTION (tlsconn),
G_PRIORITY_DEFAULT,
data->cancellable,
g_socket_client_tls_handshake_callback,
data);
}
else
{
g_object_unref (data->current_socket);
data->current_socket = NULL;
g_object_unref (data->connection);
data->connection = NULL;
enumerator_next_async (data);
}
}
static void
g_socket_client_proxy_connect_callback (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
GSocketClientAsyncConnectData *data = user_data;
g_object_unref (data->connection);
data->connection = g_proxy_connect_finish (G_PROXY (object),
result,
&data->last_error);
if (!data->connection)
{
g_object_unref (data->current_socket);
data->current_socket = NULL;
enumerator_next_async (data);
return;
}
g_socket_client_tls_handshake (data);
}
static void
g_socket_client_proxy_connect (GSocketClientAsyncConnectData *data)
{
GProxy *proxy;
const gchar *protocol = g_proxy_address_get_protocol (data->proxy_addr);
const gchar *protocol;
if (!data->proxy_addr)
{
g_socket_client_tls_handshake (data);
return;
}
protocol = g_proxy_address_get_protocol (data->proxy_addr);
proxy = g_proxy_get_default_for_protocol (protocol);
/* The connection should not be anything else then TCP Connection,
@ -1050,7 +1257,7 @@ g_socket_client_proxy_connect (GSocketClientAsyncConnectData *data)
else if (proxy)
{
g_proxy_connect_async (proxy,
G_IO_STREAM (data->connection),
data->connection,
data->proxy_addr,
data->cancellable,
g_socket_client_proxy_connect_callback,
@ -1066,6 +1273,8 @@ g_socket_client_proxy_connect (GSocketClientAsyncConnectData *data)
_("Proxy protocol '%s' is not supported."),
protocol);
g_object_unref (data->current_socket);
data->current_socket = NULL;
g_object_unref (data->connection);
data->connection = NULL;
g_object_unref (data->current_socket);
@ -1080,13 +1289,10 @@ g_socket_client_socket_connected (GSocketClientAsyncConnectData *data)
{
g_socket_set_blocking (data->current_socket, TRUE);
data->connection =
data->connection = (GIOStream *)
g_socket_connection_factory_create_connection (data->current_socket);
if (data->proxy_addr)
g_socket_client_proxy_connect (data);
else
g_socket_client_async_connect_complete (data);
g_socket_client_proxy_connect (data);
}
static gboolean
@ -1243,6 +1449,10 @@ g_socket_client_connect_async (GSocketClient *client,
data->client = client;
if (cancellable)
data->cancellable = g_object_ref (cancellable);
else
data->cancellable = NULL;
data->last_error = NULL;
data->connectable = g_object_ref (connectable);
if (can_use_proxy (client))
data->enumerator = g_socket_connectable_proxy_enumerate (connectable);

View File

@ -89,6 +89,13 @@ gboolean g_socket_client_get_enable_proxy (GSocket
void g_socket_client_set_enable_proxy (GSocketClient *client,
gboolean enable);
gboolean g_socket_client_get_tls (GSocketClient *client);
void g_socket_client_set_tls (GSocketClient *client,
gboolean tls);
GTlsCertificateFlags g_socket_client_get_tls_validation_flags (GSocketClient *client);
void g_socket_client_set_tls_validation_flags (GSocketClient *client,
GTlsCertificateFlags flags);
GSocketConnection * g_socket_client_connect (GSocketClient *client,
GSocketConnectable *connectable,
GCancellable *cancellable,

201
gio/gtlsbackend.c Normal file
View File

@ -0,0 +1,201 @@
/* GIO - GLib Input, Output and Streaming Library
*
* Copyright © 2010 Red Hat, Inc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "config.h"
#include "glib.h"
#include "gtlsbackend.h"
#include "gdummytlsbackend.h"
#include "gioenumtypes.h"
#include "giomodule-priv.h"
/**
* SECTION:gtls
* @title: TLS Overview
* @short_description: TLS (aka SSL) support for #GSocketConnection
* @include: gio/gio.h
*
* #GTlsConnection and related classes provide TLS (Transport Layer
* Security, previously known as SSL, Secure Sockets Layer) support for
* gio-based network streams.
*
* In the simplest case, for a client connection, you can just set the
* #GSocketClient:tls flag on a #GSocketClient, and then any
* connections created by that client will have TLS negotiated
* automatically, using appropriate default settings, and rejecting
* any invalid or self-signed certificates (unless you change that
* default by setting the #GSocketClient:tls-validation-flags
* property). The returned object will be a #GTcpWrapperConnection,
* which wraps the underlying #GTlsClientConnection.
*
* For greater control, you can create your own #GTlsClientConnection,
* wrapping a #GSocketConnection (or an arbitrary #GIOStream with
* pollable input and output streams) and then connect to its signals,
* such as #GTlsConnection::accept-certificate, before starting the
* handshake.
*
* Server-side TLS is similar, using #GTlsServerConnection. At the
* moment, there is no support for automatically wrapping server-side
* connections in the way #GSocketClient does for client-side
* connections.
*/
/**
* SECTION:gtlsbackend
* @title: GTlsBackend
* @short_description: TLS backend implementation
* @include: gio/gio.h
*/
/**
* GTlsBackend:
*
* Type implemented by TLS #GIOModules to provide access to additional
* TLS-related types.
*
* Since: 2.28
*/
G_DEFINE_INTERFACE (GTlsBackend, g_tls_backend, G_TYPE_OBJECT);
static void
g_tls_backend_default_init (GTlsBackendInterface *iface)
{
}
static gpointer
get_default_tls_backend (gpointer arg)
{
const char *use_this;
GList *extensions;
GIOExtensionPoint *ep;
GIOExtension *extension;
_g_io_modules_ensure_loaded ();
ep = g_io_extension_point_lookup (G_TLS_BACKEND_EXTENSION_POINT_NAME);
use_this = g_getenv ("GIO_USE_TLS");
if (use_this)
{
extension = g_io_extension_point_get_extension_by_name (ep, use_this);
if (extension)
return g_object_new (g_io_extension_get_type (extension), NULL);
}
extensions = g_io_extension_point_get_extensions (ep);
if (extensions)
{
extension = extensions->data;
return g_object_new (g_io_extension_get_type (extension), NULL);
}
return NULL;
}
/**
* g_tls_backend_get_default:
*
* Gets the default #GTlsBackend for the system.
*
* Returns: a #GTlsBackend
*
* Since: 2.28
*/
GTlsBackend *
g_tls_backend_get_default (void)
{
static GOnce once_init = G_ONCE_INIT;
return g_once (&once_init, get_default_tls_backend, NULL);
}
/**
* g_tls_backend_supports_tls:
* @backend: the #GTlsBackend
*
* Checks if TLS is supported; if this returns %FALSE for the default
* #GTlsBackend, it means no "real" TLS backend is available.
*
* Return value: whether or not TLS is supported
*
* Since: 2.28
*/
gboolean
g_tls_backend_supports_tls (GTlsBackend *backend)
{
if (G_TLS_BACKEND_GET_INTERFACE (backend)->supports_tls)
return G_TLS_BACKEND_GET_INTERFACE (backend)->supports_tls (backend);
else if (G_IS_DUMMY_TLS_BACKEND (backend))
return FALSE;
else
return TRUE;
}
/**
* g_tls_backend_get_certificate_type:
* @backend: the #GTlsBackend
*
* Gets the #GType of @backend's #GTlsCertificate implementation.
*
* Return value: the #GType of @backend's #GTlsCertificate
* implementation.
*
* Since: 2.28
*/
GType
g_tls_backend_get_certificate_type (GTlsBackend *backend)
{
return G_TLS_BACKEND_GET_INTERFACE (backend)->get_certificate_type ();
}
/**
* g_tls_backend_get_client_connection_type:
* @backend: the #GTlsBackend
*
* Gets the #GType of @backend's #GTlsClientConnection implementation.
*
* Return value: the #GType of @backend's #GTlsClientConnection
* implementation.
*
* Since: 2.28
*/
GType
g_tls_backend_get_client_connection_type (GTlsBackend *backend)
{
return G_TLS_BACKEND_GET_INTERFACE (backend)->get_client_connection_type ();
}
/**
* g_tls_backend_get_server_connection_type:
* @backend: the #GTlsBackend
*
* Gets the #GType of @backend's #GTlsServerConnection implementation.
*
* Return value: the #GType of @backend's #GTlsServerConnection
* implementation.
*
* Since: 2.28
*/
GType
g_tls_backend_get_server_connection_type (GTlsBackend *backend)
{
return G_TLS_BACKEND_GET_INTERFACE (backend)->get_server_connection_type ();
}

92
gio/gtlsbackend.h Normal file
View File

@ -0,0 +1,92 @@
/* GIO - GLib Input, Output and Streaming Library
*
* Copyright (C) 2010 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*/
#if !defined (__GIO_GIO_H_INSIDE__) && !defined (GIO_COMPILATION)
#error "Only <gio/gio.h> can be included directly."
#endif
#ifndef __G_TLS_BACKEND_H__
#define __G_TLS_BACKEND_H__
#include <gio/giotypes.h>
G_BEGIN_DECLS
/**
* G_TLS_BACKEND_EXTENSION_POINT_NAME:
*
* Extension point for TLS functionality via #GTlsBackend.
* See <link linkend="extending-gio">Extending GIO</link>.
*/
#define G_TLS_BACKEND_EXTENSION_POINT_NAME "gio-tls-backend"
#define G_TYPE_TLS_BACKEND (g_tls_backend_get_type ())
#define G_TLS_BACKEND(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_TLS_BACKEND, GTlsBackend))
#define G_IS_TLS_BACKEND(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), G_TYPE_TLS_BACKEND))
#define G_TLS_BACKEND_GET_INTERFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), G_TYPE_TLS_BACKEND, GTlsBackendInterface))
/**
* GTlsBackend:
*
* TLS (Transport Layer Security, aka SSL) backend. This is an
* internal type used to coordinate the different classes implemented
* by a TLS backend.
*
* Since: 2.28
*/
typedef struct _GTlsBackend GTlsBackend;
typedef struct _GTlsBackendInterface GTlsBackendInterface;
/**
* GTlsBackendInterface:
* @g_iface: The parent interface.
* @get_certificate_type: returns the #GTlsCertificate implementation type
* @get_client_connection_type: returns the #GTlsClientConnection implementation type
* @get_server_connection_type: returns the #GTlsServerConnection implementation type
*
* Provides an interface for describing TLS-related types.
*
* Since: 2.28
*/
struct _GTlsBackendInterface
{
GTypeInterface g_iface;
/* methods */
gboolean ( *supports_tls) (GTlsBackend *backend);
GType ( *get_certificate_type) (void);
GType ( *get_client_connection_type) (void);
GType ( *get_server_connection_type) (void);
};
GType g_tls_backend_get_type (void) G_GNUC_CONST;
GTlsBackend *g_tls_backend_get_default (void);
gboolean g_tls_backend_supports_tls (GTlsBackend *backend);
GType g_tls_backend_get_certificate_type (GTlsBackend *backend);
GType g_tls_backend_get_client_connection_type (GTlsBackend *backend);
GType g_tls_backend_get_server_connection_type (GTlsBackend *backend);
G_END_DECLS
#endif /* __G_TLS_BACKEND_H__ */

486
gio/gtlscertificate.c Normal file
View File

@ -0,0 +1,486 @@
/* GIO - GLib Input, Output and Certificateing Library
*
* Copyright (C) 2010 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "config.h"
#include "gtlscertificate.h"
#include <string.h>
#include "ginitable.h"
#include "gtlsbackend.h"
#include "gtlsconnection.h"
#include "glibintl.h"
/**
* SECTION: gtlscertificate
* @title: GTlsCertificate
* @short_description: a TLS certificate
* @see_also: #GTlsConnection
*
* A certificate used for TLS authentication and encryption.
* This can represent either a public key only (eg, the certificate
* received by a client from a server), or the combination of
* a public key and a private key (which is needed when acting as a
* #GTlsServerConnection).
*
* Since: 2.28
*/
/**
* GTlsCertificate:
*
* Abstract base class for TLS certificate types.
*
* Since: 2.28
*/
G_DEFINE_ABSTRACT_TYPE (GTlsCertificate, g_tls_certificate, G_TYPE_OBJECT);
struct _GTlsCertificatePrivate
{
GTlsCertificate *issuer;
};
enum
{
PROP_0,
PROP_CERTIFICATE,
PROP_CERTIFICATE_PEM,
PROP_PRIVATE_KEY,
PROP_PRIVATE_KEY_PEM,
PROP_ISSUER
};
static void
g_tls_certificate_init (GTlsCertificate *cert)
{
cert->priv = G_TYPE_INSTANCE_GET_PRIVATE (cert,
G_TYPE_TLS_CERTIFICATE,
GTlsCertificatePrivate);
}
static void
g_tls_certificate_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GTlsCertificate *cert = G_TLS_CERTIFICATE (object);
switch (prop_id)
{
case PROP_ISSUER:
g_value_set_object (value, cert->priv->issuer);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
g_tls_certificate_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GTlsCertificate *cert = G_TLS_CERTIFICATE (object);
switch (prop_id)
{
case PROP_ISSUER:
cert->priv->issuer = g_value_dup_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
g_tls_certificate_finalize (GObject *object)
{
GTlsCertificate *cert = G_TLS_CERTIFICATE (object);
if (cert->priv->issuer)
g_object_unref (cert->priv->issuer);
G_OBJECT_CLASS (g_tls_certificate_parent_class)->finalize (object);
}
static void
g_tls_certificate_class_init (GTlsCertificateClass *class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (class);
g_type_class_add_private (class, sizeof (GTlsCertificatePrivate));
gobject_class->set_property = g_tls_certificate_set_property;
gobject_class->get_property = g_tls_certificate_get_property;
gobject_class->finalize = g_tls_certificate_finalize;
/**
* GTlsCertificate:certificate:
*
* The DER (binary) encoded representation of the certificate's
* public key. This property and the
* #GTlsCertificate:certificate-pem property represent the same
* data, just in different forms.
*
* Since: 2.28
*/
g_object_class_install_property (gobject_class, PROP_CERTIFICATE,
g_param_spec_boxed ("certificate",
P_("Certificate"),
P_("The DER representation of the certificate"),
G_TYPE_BYTE_ARRAY,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
/**
* GTlsCertificate:certificate-pem:
*
* The PEM (ASCII) encoded representation of the certificate's
* public key. This property and the #GTlsCertificate:certificate
* property represent the same data, just in different forms.
*
* Since: 2.28
*/
g_object_class_install_property (gobject_class, PROP_CERTIFICATE_PEM,
g_param_spec_string ("certificate-pem",
P_("Certificate (PEM)"),
P_("The PEM representation of the certificate"),
NULL,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
/**
* GTlsCertificate:private-key:
*
* The DER (binary) encoded representation of the certificate's
* private key. This property (or the
* #GTlsCertificate:private-key-pem property) can be set when
* constructing a key (eg, from a file), but cannot be read.
*
* Since: 2.28
*/
g_object_class_install_property (gobject_class, PROP_PRIVATE_KEY,
g_param_spec_boxed ("private-key",
P_("Private key"),
P_("The DER representation of the certificate's private key"),
G_TYPE_BYTE_ARRAY,
G_PARAM_WRITABLE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
/**
* GTlsCertificate:private-key-pem:
*
* The PEM (ASCII) encoded representation of the certificate's
* private key. This property (or the #GTlsCertificate:private-key
* property) can be set when constructing a key (eg, from a file),
* but cannot be read.
*
* Since: 2.28
*/
g_object_class_install_property (gobject_class, PROP_PRIVATE_KEY_PEM,
g_param_spec_string ("private-key-pem",
P_("Private key (PEM)"),
P_("The PEM representation of the certificate's private key"),
NULL,
G_PARAM_WRITABLE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
/**
* GTlsCertificate:issuer:
*
* A #GTlsCertificate representing the entity that issued this
* certificate. If %NULL, this means that the certificate is either
* self-signed, or else the certificate of the issuer is not
* available.
*
* Since: 2.28
*/
g_object_class_install_property (gobject_class, PROP_ISSUER,
g_param_spec_object ("issuer",
P_("Issuer"),
P_("The certificate for the issuing entity"),
G_TYPE_TLS_CERTIFICATE,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
}
static GTlsCertificate *
g_tls_certificate_new_internal (const gchar *certificate_pem,
const gchar *private_key_pem,
GError **error)
{
GObject *cert;
GTlsBackend *backend;
backend = g_tls_backend_get_default ();
cert = g_initable_new (g_tls_backend_get_certificate_type (backend),
NULL, error,
"certificate-pem", certificate_pem,
"private-key-pem", private_key_pem,
NULL);
return G_TLS_CERTIFICATE (cert);
}
#define PEM_CERTIFICATE_HEADER "-----BEGIN CERTIFICATE-----"
#define PEM_CERTIFICATE_FOOTER "-----END CERTIFICATE-----"
#define PEM_PRIVKEY_HEADER "-----BEGIN RSA PRIVATE KEY-----"
#define PEM_PRIVKEY_FOOTER "-----END RSA PRIVATE KEY-----"
static GTlsCertificate *
parse_next_pem_certificate (const gchar **data,
const gchar *data_end,
gboolean required,
GError **error)
{
const gchar *start, *end, *next;
gchar *cert_pem, *privkey_pem = NULL;
GTlsCertificate *cert;
start = g_strstr_len (*data, data_end - *data, PEM_CERTIFICATE_HEADER);
if (!start)
{
if (required)
{
g_set_error_literal (error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
_("No PEM-encoded certificate found"));
}
return NULL;
}
end = g_strstr_len (start, data_end - start, PEM_CERTIFICATE_FOOTER);
if (!end)
{
g_set_error_literal (error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
_("Could not parse PEM-encoded certificate"));
return NULL;
}
end += strlen (PEM_CERTIFICATE_FOOTER);
while (*end == '\r' || *end == '\n')
end++;
cert_pem = g_strndup (start, end - start);
*data = end;
next = g_strstr_len (*data, data_end - *data, PEM_CERTIFICATE_HEADER);
start = g_strstr_len (*data, data_end - *data, PEM_PRIVKEY_HEADER);
if (start)
end = g_strstr_len (start, data_end - start, PEM_PRIVKEY_FOOTER);
if (start && (!next || start < next))
{
if (!end || (next && end > next))
{
g_set_error_literal (error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
_("Could not parse PEM-encoded private key"));
return NULL;
}
end += strlen (PEM_PRIVKEY_FOOTER);
while (*end == '\r' || *end == '\n')
end++;
privkey_pem = g_strndup (start, end - start);
*data = end + strlen (PEM_PRIVKEY_FOOTER);
}
cert = g_tls_certificate_new_internal (cert_pem, privkey_pem, error);
g_free (cert_pem);
g_free (privkey_pem);
return cert;
}
/**
* g_tls_certificate_new_from_pem:
* @data: PEM-encoded certificate data
* @length: the length of @data, or -1 if it's 0-terminated.
* @error: #GError for error reporting, or %NULL to ignore.
*
* Creates a new #GTlsCertificate from the PEM-encoded data in @data.
* If @data includes both a certificate and a private key, then the
* returned certificate will include the private key data as well.
*
* If @data includes multiple certificates, only the first one will be
* parsed.
*
* Return value: the new certificate, or %NULL if @data is invalid
*
* Since: 2.28
*/
GTlsCertificate *
g_tls_certificate_new_from_pem (const gchar *data,
gssize length,
GError **error)
{
const gchar *data_end;
g_return_val_if_fail (data != NULL, NULL);
if (length == -1)
data_end = data + strlen (data);
else
data_end = data + length;
return parse_next_pem_certificate (&data, data_end, TRUE, error);
}
/**
* g_tls_certificate_new_from_file:
* @file: file containing a PEM-encoded certificate to import
* @error: #GError for error reporting, or %NULL to ignore.
*
* Creates a #GTlsCertificate from the PEM-encoded data in @file. If
* @file cannot be read or parsed, the function will return %NULL and
* set @error. Otherwise, this behaves like g_tls_certificate_new().
*
* Return value: the new certificate, or %NULL on error
*
* Since: 2.28
*/
GTlsCertificate *
g_tls_certificate_new_from_file (const gchar *file,
GError **error)
{
GTlsCertificate *cert;
gchar *contents;
gsize length;
if (!g_file_get_contents (file, &contents, &length, error))
return NULL;
cert = g_tls_certificate_new_from_pem (contents, length, error);
g_free (contents);
return cert;
}
/**
* g_tls_certificate_new_from_files:
* @cert_file: file containing a PEM-encoded certificate to import
* @key_file: file containing a PEM-encoded private key to import
* @error: #GError for error reporting, or %NULL to ignore.
*
* Creates a #GTlsCertificate from the PEM-encoded data in @cert_file
* and @key_file. If either file cannot be read or parsed, the
* function will return %NULL and set @error. Otherwise, this behaves
* like g_tls_certificate_new().
*
* Return value: the new certificate, or %NULL on error
*
* Since: 2.28
*/
GTlsCertificate *
g_tls_certificate_new_from_files (const gchar *cert_file,
const gchar *key_file,
GError **error)
{
GTlsCertificate *cert;
gchar *cert_data, *key_data;
if (!g_file_get_contents (cert_file, &cert_data, NULL, error))
return NULL;
if (!g_file_get_contents (key_file, &key_data, NULL, error))
{
g_free (cert_data);
return NULL;
}
cert = g_tls_certificate_new_internal (cert_data, key_data, error);
g_free (cert_data);
g_free (key_data);
return cert;
}
/**
* g_tls_certificate_list_new_from_file:
* @file: file containing PEM-encoded certificates to import
* @error: #GError for error reporting, or %NULL to ignore.
*
* Creates one or more #GTlsCertificate<!-- -->s from the PEM-encoded
* data in @file. If @file cannot be read or parsed, the function will
* return %NULL and set @error. If @file does not contain any
* PEM-encoded certificates, this will return an empty list and not
* set @error.
*
* Return value: (element-type Gio.TlsCertificate) (transfer full): a
* #GList containing #GTlsCertificate objects. You must free the list
* and its contents when you are done with it.
*
* Since: 2.28
*/
GList *
g_tls_certificate_list_new_from_file (const gchar *file,
GError **error)
{
GTlsCertificate *cert;
GList *list, *l;
gchar *contents, *end;
const gchar *p;
gsize length;
if (!g_file_get_contents (file, &contents, &length, error))
return NULL;
list = NULL;
end = contents + length;
p = contents;
while (p && *p)
{
cert = parse_next_pem_certificate (&p, end, FALSE, error);
if (!cert)
{
for (l = list; l; l = l->next)
g_object_unref (l->data);
g_list_free (list);
list = NULL;
break;
}
list = g_list_prepend (list, cert);
}
return g_list_reverse (list);
}
/**
* g_tls_certificate_get_issuer:
* @cert: a #GTlsCertificate
*
* Gets the #GTlsCertificate representing @cert's issuer, if known
*
* Return value: (transfer none): The certificate of @cert's issuer,
* or %NULL if @cert is self-signed or signed with an unknown
* certificate.
*
* Since: 2.28
*/
GTlsCertificate *
g_tls_certificate_get_issuer (GTlsCertificate *cert)
{
return cert->priv->issuer;
}

75
gio/gtlscertificate.h Normal file
View File

@ -0,0 +1,75 @@
/* GIO - GLib Input, Output and Streaming Library
*
* Copyright (C) 2010 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*/
#if !defined (__GIO_GIO_H_INSIDE__) && !defined (GIO_COMPILATION)
#error "Only <gio/gio.h> can be included directly."
#endif
#ifndef __G_TLS_CERTIFICATE_H__
#define __G_TLS_CERTIFICATE_H__
#include <gio/giotypes.h>
G_BEGIN_DECLS
#define G_TYPE_TLS_CERTIFICATE (g_tls_certificate_get_type ())
#define G_TLS_CERTIFICATE(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), G_TYPE_TLS_CERTIFICATE, GTlsCertificate))
#define G_TLS_CERTIFICATE_CLASS(class) (G_TYPE_CHECK_CLASS_CAST ((class), G_TYPE_TLS_CERTIFICATE, GTlsCertificateClass))
#define G_IS_TLS_CERTIFICATE(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), G_TYPE_TLS_CERTIFICATE))
#define G_IS_TLS_CERTIFICATE_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class), G_TYPE_TLS_CERTIFICATE))
#define G_TLS_CERTIFICATE_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), G_TYPE_TLS_CERTIFICATE, GTlsCertificateClass))
typedef struct _GTlsCertificateClass GTlsCertificateClass;
typedef struct _GTlsCertificatePrivate GTlsCertificatePrivate;
struct _GTlsCertificate {
GObject parent_instance;
GTlsCertificatePrivate *priv;
};
struct _GTlsCertificateClass
{
GObjectClass parent_class;
/*< private >*/
/* Padding for future expansion */
gpointer padding[8];
};
GType g_tls_certificate_get_type (void) G_GNUC_CONST;
GTlsCertificate *g_tls_certificate_new_from_pem (const gchar *data,
gssize length,
GError **error);
GTlsCertificate *g_tls_certificate_new_from_file (const gchar *file,
GError **error);
GTlsCertificate *g_tls_certificate_new_from_files (const gchar *cert_file,
const gchar *key_file,
GError **error);
GList *g_tls_certificate_list_new_from_file (const gchar *file,
GError **error);
GTlsCertificate *g_tls_certificate_get_issuer (GTlsCertificate *cert);
G_END_DECLS
#endif /* __G_TLS_CERTIFICATE_H__ */

333
gio/gtlsclientconnection.c Normal file
View File

@ -0,0 +1,333 @@
/* GIO - GLib Input, Output and Streaming Library
*
* Copyright © 2010 Red Hat, Inc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "config.h"
#include "glib.h"
#include "gtlsclientconnection.h"
#include "ginitable.h"
#include "gioenumtypes.h"
#include "gio-marshal.h"
#include "gsocket.h"
#include "gsocketconnectable.h"
#include "gtlsbackend.h"
#include "gtlscertificate.h"
#include "glibintl.h"
/**
* SECTION:gtlsclientconnection
* @short_description: TLS client-side connection
* @include: gio/gio.h
*
* #GTlsClientConnection is the client-side subclass of
* #GTlsConnection, representing a client-side TLS connection.
*
* Since: 2.28
*/
/**
* GTlsClientConnection:
*
* Abstract base class for the backend-specific client connection
* type.
*
* Since: 2.28
*/
G_DEFINE_INTERFACE (GTlsClientConnection, g_tls_client_connection, G_TYPE_TLS_CONNECTION)
static void
g_tls_client_connection_default_init (GTlsClientConnectionInterface *iface)
{
/**
* GTlsClientConnection:validation-flags:
*
* What steps to perform when validating a certificate received from
* a server. Server certificates that fail to validate in all of the
* ways indicated here will be rejected unless the application
* overrides the default via #GTlsConnection::accept-certificate.
*
* Since: 2.28
*/
g_object_interface_install_property (iface,
g_param_spec_flags ("validation-flags",
P_("Validation flags"),
P_("What certificate validation to perform"),
G_TYPE_TLS_CERTIFICATE_FLAGS,
G_TLS_CERTIFICATE_VALIDATE_ALL,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT |
G_PARAM_STATIC_STRINGS));
/**
* GTlsClientConnection:server-identity:
*
* A #GSocketConnectable describing the identity of the server that
* is expected on the other end of the connection.
*
* If the %G_TLS_CERTIFICATE_BAD_IDENTITY flag is set in
* #GTlsClientConnection:validation-flags, this object will be used
* to determine the expected identify of the remote end of the
* connection; if #GTlsClientConnection:server-identity is not set,
* or does not match the identity presented by the server, then the
* %G_TLS_CERTIFICATE_BAD_IDENTITY validation will fail.
*
* In addition to its use in verifying the server certificate,
* this is also used to give a hint to the server about what
* certificate we expect, which is useful for servers that serve
* virtual hosts.
*
* Since: 2.28
*/
g_object_interface_install_property (iface,
g_param_spec_object ("server-identity",
P_("Server identity"),
P_("GSocketConnectable identifying the server"),
G_TYPE_SOCKET_CONNECTABLE,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT |
G_PARAM_STATIC_STRINGS));
/**
* GTlsClientConnection:use-ssl3:
*
* If %TRUE, tells the connection to use SSL 3.0 rather than trying
* to negotiate the best version of TLS or SSL to use. This can be
* used when talking to servers that don't implement version
* negotiation correctly and therefore refuse to handshake at all with
* a "modern" TLS handshake.
*
* Since: 2.28
*/
g_object_interface_install_property (iface,
g_param_spec_boolean ("use-ssl3",
P_("Use SSL3"),
P_("Use SSL 3.0 rather than trying to use TLS 1.x"),
FALSE,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT |
G_PARAM_STATIC_STRINGS));
/**
* GTlsClientConnection:accepted-cas:
*
* A list of the distinguished names of the Certificate Authorities
* that the server will accept client certificates signed by. If the
* server requests a client certificate during the handshake, then
* this property will be set by the time the
* #GTlsConnection::need-certificate signal is emitted.
*
* Since: 2.28
*/
g_object_interface_install_property (iface,
g_param_spec_boxed ("accepted-cas",
P_("Accepted CAs"),
P_("Distinguished names of the CAs the server accepts certificates from"),
G_TYPE_STRV,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
}
/**
* g_tls_client_connection_new:
* @base_io_stream: the #GIOStream to wrap
* @server_identity: (allow-none): the expected identity of the server
* @error: #GError for error reporting, or %NULL to ignore.
*
* Creates a new #GTlsClientConnection wrapping @base_io_stream (which
* must have pollable input and output streams) which is assumed to
* communicate with the server identified by @server_identity.
*
* Return value: the new #GTlsClientConnection, or %NULL on error
*
* Since: 2.28
*/
GTlsClientConnection *
g_tls_client_connection_new (GIOStream *base_io_stream,
GSocketConnectable *server_identity,
GError **error)
{
GObject *conn;
GTlsBackend *backend;
backend = g_tls_backend_get_default ();
conn = g_initable_new (g_tls_backend_get_client_connection_type (backend),
NULL, error,
"base-io-stream", base_io_stream,
"server-identity", server_identity,
NULL);
return G_TLS_CLIENT_CONNECTION (conn);
}
/**
* g_tls_client_connection_get_validation_flags:
* @conn: the #GTlsClientConnection
*
* Gets @conn's validation flags
*
* Return value: the validation flags
*
* Since: 2.28
*/
GTlsCertificateFlags
g_tls_client_connection_get_validation_flags (GTlsClientConnection *conn)
{
GTlsCertificateFlags flags = 0;
g_return_val_if_fail (G_IS_TLS_CLIENT_CONNECTION (conn), 0);
g_object_get (G_OBJECT (conn), "validation-flags", &flags, NULL);
return flags;
}
/**
* g_tls_client_connection_set_validation_flags:
* @conn: the #GTlsClientConnection
* @flags: the #GTlsCertificatelags to use
*
* Sets @conn's validation flags, to override the default set of
* checks performed when validating a server certificate.
*
* Since: 2.28
*/
void
g_tls_client_connection_set_validation_flags (GTlsClientConnection *conn,
GTlsCertificateFlags flags)
{
g_return_if_fail (G_IS_TLS_CLIENT_CONNECTION (conn));
g_object_set (G_OBJECT (conn), "validation-flags", flags, NULL);
}
/**
* g_tls_client_connection_get_server_identity:
* @conn: the #GTlsClientConnection
*
* Gets @conn's expected server identity
*
* Return value: a #GSocketConnectable describing the
* expected server identity, or %NULL if the expected identity is not
* known.
*
* Since: 2.28
*/
GSocketConnectable *
g_tls_client_connection_get_server_identity (GTlsClientConnection *conn)
{
GSocketConnectable *identity = NULL;
g_return_val_if_fail (G_IS_TLS_CLIENT_CONNECTION (conn), 0);
g_object_get (G_OBJECT (conn), "server-identity", &identity, NULL);
if (identity)
g_object_unref (identity);
return identity;
}
/**
* g_tls_client_connection_set_server_identity:
* @conn: the #GTlsClientConnection
* @identity: a #GSocketConnectable describing the expected server identity
*
* Sets @conn's expected server identity, which is used both to tell
* servers on virtual hosts which certificate to present, and also
* to let @conn know what name to look for in the certificate when
* performing %G_TLS_CERTIFICATE_BAD_IDENTITY validation, if enabled.
*
* Since: 2.28
*/
void
g_tls_client_connection_set_server_identity (GTlsClientConnection *conn,
GSocketConnectable *identity)
{
g_return_if_fail (G_IS_TLS_CLIENT_CONNECTION (conn));
g_object_set (G_OBJECT (conn), "server-identity", identity, NULL);
}
/**
* g_tls_client_connection_get_use_ssl3:
* @conn: the #GTlsClientConnection
*
* Gets whether @conn will use SSL 3.0 rather than the
* highest-supported version of TLS; see
* g_tls_client_connection_set_use_ssl3().
*
* Return value: whether @conn will use SSL 3.0
*
* Since: 2.28
*/
gboolean
g_tls_client_connection_get_use_ssl3 (GTlsClientConnection *conn)
{
gboolean use_ssl3 = FALSE;
g_return_val_if_fail (G_IS_TLS_CLIENT_CONNECTION (conn), 0);
g_object_get (G_OBJECT (conn), "use-ssl3", &use_ssl3, NULL);
return use_ssl3;
}
/**
* g_tls_client_connection_set_use_ssl3:
* @conn: the #GTlsClientConnection
* @use_ssl3: whether to use SSL 3.0
*
* If @use_ssl3 is %TRUE, this forces @conn to use SSL 3.0 rather than
* trying to properly negotiate the right version of TLS or SSL to use.
* This can be used when talking to servers that do not implement the
* fallbacks correctly and which will therefore fail to handshake with
* a "modern" TLS handshake attempt.
*
* Since: 2.28
*/
void
g_tls_client_connection_set_use_ssl3 (GTlsClientConnection *conn,
gboolean use_ssl3)
{
g_return_if_fail (G_IS_TLS_CLIENT_CONNECTION (conn));
g_object_set (G_OBJECT (conn), "use-ssl3", use_ssl3, NULL);
}
/**
* g_tls_client_connection_get_accepted_cas:
* @conn: the #GTlsClientConnection
*
* Gets the list of distinguished names of the Certificate Authorities
* that the server will accept certificates from. This will be set
* during the TLS handshake if the server requests a certificate.
* Otherwise, it will be %NULL.
*
* Return value: (transfer full) (array zero-terminated=1): the list
* of CA names, which you must free (eg, with g_strfreev()).
*
* Since: 2.28
*/
char **
g_tls_client_connection_get_accepted_cas (GTlsClientConnection *conn)
{
char **accepted_cas = NULL;
g_return_val_if_fail (G_IS_TLS_CLIENT_CONNECTION (conn), NULL);
g_object_get (G_OBJECT (conn), "accepted-cas", &accepted_cas, NULL);
return accepted_cas;
}

View File

@ -0,0 +1,72 @@
/* GIO - GLib Input, Output and Streaming Library
*
* Copyright (C) 2010 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*/
#if !defined (__GIO_GIO_H_INSIDE__) && !defined (GIO_COMPILATION)
#error "Only <gio/gio.h> can be included directly."
#endif
#ifndef __G_TLS_CLIENT_CONNECTION_H__
#define __G_TLS_CLIENT_CONNECTION_H__
#include <gio/gtlsconnection.h>
G_BEGIN_DECLS
#define G_TYPE_TLS_CLIENT_CONNECTION (g_tls_client_connection_get_type ())
#define G_TLS_CLIENT_CONNECTION(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), G_TYPE_TLS_CLIENT_CONNECTION, GTlsClientConnection))
#define G_IS_TLS_CLIENT_CONNECTION(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), G_TYPE_TLS_CLIENT_CONNECTION))
#define G_TLS_CLIENT_CONNECTION_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), G_TYPE_TLS_CLIENT_CONNECTION, GTlsClientConnectionInterface))
/**
* GTlsClientConnection:
*
* TLS client-side connection; the client-side implementation of a
* #GTlsConnection
*
* Since: 2.28
*/
typedef struct _GTlsClientConnectionInterface GTlsClientConnectionInterface;
struct _GTlsClientConnectionInterface
{
GTypeInterface g_iface;
};
GType g_tls_client_connection_get_type (void) G_GNUC_CONST;
GTlsClientConnection *g_tls_client_connection_new (GIOStream *base_io_stream,
GSocketConnectable *server_identity,
GError **error);
GTlsCertificateFlags g_tls_client_connection_get_validation_flags (GTlsClientConnection *conn);
void g_tls_client_connection_set_validation_flags (GTlsClientConnection *conn,
GTlsCertificateFlags flags);
GSocketConnectable *g_tls_client_connection_get_server_identity (GTlsClientConnection *conn);
void g_tls_client_connection_set_server_identity (GTlsClientConnection *conn,
GSocketConnectable *identity);
gboolean g_tls_client_connection_get_use_ssl3 (GTlsClientConnection *conn);
void g_tls_client_connection_set_use_ssl3 (GTlsClientConnection *conn,
gboolean use_ssl3);
char ** g_tls_client_connection_get_accepted_cas (GTlsClientConnection *conn);
G_END_DECLS
#endif /* __G_TLS_CLIENT_CONNECTION_H__ */

720
gio/gtlsconnection.c Normal file
View File

@ -0,0 +1,720 @@
/* GIO - GLib Input, Output and Streaming Library
*
* Copyright © 2010 Red Hat, Inc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "config.h"
#include "glib.h"
#include "gtlsconnection.h"
#include "gcancellable.h"
#include "gioenumtypes.h"
#include "gio-marshal.h"
#include "gsocket.h"
#include "gtlsbackend.h"
#include "gtlscertificate.h"
#include "gtlsclientconnection.h"
#include "glibintl.h"
/**
* SECTION:gtlsconnection
* @short_description: TLS connection type
* @include: gio/gio.h
*
* #GTlsConnection is the base TLS connection class type, which wraps
* a #GIOStream and provides TLS encryption on top of it. Its
* subclasses, #GTlsClientConnection and #GTlsServerConnection,
* implement client-side and server-side TLS, respectively.
*
* Since: 2.28
*/
/**
* GTlsConnection:
*
* Abstract base class for the backend-specific #GTlsClientConnection
* and #GTlsServerConnection types.
*
* Since: 2.28
*/
G_DEFINE_ABSTRACT_TYPE (GTlsConnection, g_tls_connection, G_TYPE_IO_STREAM)
static void g_tls_connection_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec);
static void g_tls_connection_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec);
static void g_tls_connection_finalize (GObject *object);
static gboolean g_tls_connection_certificate_accumulator (GSignalInvocationHint *ihint,
GValue *return_accu,
const GValue *handler_return,
gpointer dummy);
enum {
NEED_CERTIFICATE,
ACCEPT_CERTIFICATE,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0 };
enum {
PROP_0,
PROP_BASE_IO_STREAM,
PROP_REQUIRE_CLOSE_NOTIFY,
PROP_REHANDSHAKE_MODE,
PROP_CERTIFICATE,
PROP_PEER_CERTIFICATE
};
struct _GTlsConnectionPrivate {
GTlsCertificate *certificate, *peer_certificate;
};
static void
g_tls_connection_class_init (GTlsConnectionClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
g_type_class_add_private (klass, sizeof (GTlsConnectionPrivate));
gobject_class->get_property = g_tls_connection_get_property;
gobject_class->set_property = g_tls_connection_set_property;
gobject_class->finalize = g_tls_connection_finalize;
/**
* GTlsConnection:base-io-stream:
*
* The #GIOStream that the connection wraps
*
* Since: 2.28
*/
g_object_class_install_property (gobject_class, PROP_BASE_IO_STREAM,
g_param_spec_object ("base-io-stream",
P_("Base IOStream"),
P_("The GIOStream that the connection wraps"),
G_TYPE_IO_STREAM,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
/**
* GTlsConnection:require-close-notify:
*
* Whether or not proper TLS close notification is required.
* See g_tls_connection_set_require_close_notify().
*
* Since: 2.28
*/
g_object_class_install_property (gobject_class, PROP_REQUIRE_CLOSE_NOTIFY,
g_param_spec_boolean ("require-close-notify",
P_("Require close notify"),
P_("Whether to require proper TLS close notification"),
TRUE,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS));
/**
* GTlsConnection:rehandshake-mode:
*
* The rehandshaking mode. See
* g_tls_connection_set_rehandshake_mode().
*
* Since: 2.28
*/
g_object_class_install_property (gobject_class, PROP_REHANDSHAKE_MODE,
g_param_spec_enum ("rehandshake-mode",
P_("Rehandshake mode"),
P_("When to allow rehandshaking"),
G_TYPE_TLS_REHANDSHAKE_MODE,
G_TLS_REHANDSHAKE_SAFELY,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS));
/**
* GTlsConnection:certificate:
*
* The connection's certificate; see
* g_tls_connection_set_certificate().
*
* Since: 2.28
*/
g_object_class_install_property (gobject_class, PROP_CERTIFICATE,
g_param_spec_object ("certificate",
P_("Certificate"),
P_("The connection's certificate"),
G_TYPE_TLS_CERTIFICATE,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS));
/**
* GTlsConnection:peer-certificate:
*
* The connection's peer's certificate, after it has been set during
* the TLS handshake.
*
* Since: 2.28
*/
g_object_class_install_property (gobject_class, PROP_PEER_CERTIFICATE,
g_param_spec_object ("peer-certificate",
P_("Peer Certificate"),
P_("The connection's peer's certificate"),
G_TYPE_TLS_CERTIFICATE,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
/**
* GTlsConnection::need-certificate:
* @conn: a #GTlsConnection
*
* Emitted during the TLS handshake if a certificate is needed and
* one has not been set via g_tls_connection_set_certificate().
*
* For server-side connections, a certificate is always needed, and
* the connection will fail if none is provided.
*
* For client-side connections, the signal will be emitted only if
* the server has requested a certificate; you can call
* g_tls_client_connection_get_accepted_cas() to get a list of
* Certificate Authorities that the server will accept certificates
* from. If you do not return a certificate (and have not provided
* one via g_tls_connection_set_certificate()) then the server may
* reject the handshake, in which case the operation will eventually
* fail with %G_TLS_ERROR_CERTIFICATE_REQUIRED.
*
* Note that if this signal is emitted as part of asynchronous I/O
* in the main thread, then you should not attempt to interact with
* the user before returning from the signal handler. If you want to
* let the user choose a certificate to return, you would have to
* return %NULL from the signal handler on the first attempt, and
* then after the connection attempt returns a
* %G_TLS_ERROR_CERTIFICATE_REQUIRED, you can interact with the
* user, create a new connection, and call
* g_tls_connection_set_certificate() on it before handshaking (or
* just connect to the signal again and return the certificate the
* next time).
*
* If you are doing I/O in another thread, you do not
* need to worry about this, and can simply block in the signal
* handler until the UI thread returns an answer.
*
* Return value: the certificate to send to the peer, or %NULL to
* send no certificate. If you return a certificate, the signal
* emission will be stopped and further handlers will not be called.
*
* Since: 2.28
*/
signals[NEED_CERTIFICATE] =
g_signal_new (I_("need-certificate"),
G_TYPE_TLS_CONNECTION,
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GTlsConnectionClass, need_certificate),
g_tls_connection_certificate_accumulator, NULL,
_gio_marshal_OBJECT__VOID,
G_TYPE_TLS_CERTIFICATE, 0);
/**
* GTlsConnection::accept-certificate:
* @conn: a #GTlsConnection
* @peer_cert: the peer's #GTlsCertificate
* @errors: the problems with @peer_cert.
*
* Emitted during the TLS handshake after the peer certificate has
* been received. You can examine @peer_cert's certification path by
* calling g_tls_certificate_get_issuer() on it.
*
* For a client-side connection, @peer_cert is the server's
* certificate, and the signal will only be emitted if the
* certificate was not acceptable according to @conn's
* #GTlsClientConnection:validation_flags. If you would like the
* certificate to be accepted despite @errors, return %TRUE from the
* signal handler. Otherwise, if no handler accepts the certificate,
* the handshake will fail with %G_TLS_ERROR_BAD_CERTIFICATE.
*
* For a server-side connection, @peer_cert is the certificate
* presented by the client, if this was requested via the server's
* #GTlsServerConnection:authentication_mode. On the server side,
* the signal is always emitted when the client presents a
* certificate, and the certificate will only be accepted if a
* handler returns %TRUE.
*
* As with #GTlsConnection::need_certificate, you should not
* interact with the user during the signal emission if the signal
* was emitted as part of an asynchronous operation in the main
* thread.
*
* Return value: %TRUE to accept @peer_cert (which will also
* immediately end the signal emission). %FALSE to allow the signal
* emission to continue, which will cause the handshake to fail if
* no one else overrides it.
*
* Since: 2.28
*/
signals[ACCEPT_CERTIFICATE] =
g_signal_new (I_("accept-certificate"),
G_TYPE_TLS_CONNECTION,
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GTlsConnectionClass, accept_certificate),
g_signal_accumulator_true_handled, NULL,
_gio_marshal_BOOLEAN__OBJECT_FLAGS,
G_TYPE_BOOLEAN, 2,
G_TYPE_TLS_CERTIFICATE,
G_TYPE_TLS_CERTIFICATE_FLAGS);
}
static void
g_tls_connection_init (GTlsConnection *conn)
{
conn->priv = G_TYPE_INSTANCE_GET_PRIVATE (conn, G_TYPE_TLS_CONNECTION, GTlsConnectionPrivate);
}
static void
g_tls_connection_finalize (GObject *object)
{
GTlsConnection *conn = G_TLS_CONNECTION (object);
if (conn->priv->certificate)
g_object_unref (conn->priv->certificate);
if (conn->priv->peer_certificate)
g_object_unref (conn->priv->peer_certificate);
G_OBJECT_CLASS (g_tls_connection_parent_class)->finalize (object);
}
static void
g_tls_connection_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GTlsConnection *conn = G_TLS_CONNECTION (object);
switch (prop_id)
{
case PROP_CERTIFICATE:
g_value_set_object (value, conn->priv->certificate);
break;
case PROP_PEER_CERTIFICATE:
g_value_set_object (value, conn->priv->peer_certificate);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
g_tls_connection_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GTlsConnection *conn = G_TLS_CONNECTION (object);
switch (prop_id)
{
case PROP_CERTIFICATE:
g_tls_connection_set_certificate (conn, g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
/**
* g_tls_connection_set_certificate:
* @conn: a #GTlsConnection
* @certificate: the certificate to use for @conn
*
* This sets the certificate that @conn will present to its peer
* during the TLS handshake. If this is not set,
* #GTlsConnection::need-certificate will be emitted during the
* handshake if needed.
*
* Since: 2.28
*/
void
g_tls_connection_set_certificate (GTlsConnection *conn,
GTlsCertificate *certificate)
{
g_return_if_fail (G_IS_TLS_CONNECTION (conn));
g_return_if_fail (G_IS_TLS_CERTIFICATE (certificate));
if (conn->priv->certificate)
g_object_unref (conn->priv->certificate);
conn->priv->certificate = certificate ? g_object_ref (certificate) : NULL;
g_object_notify (G_OBJECT (conn), "certificate");
}
/**
* g_tls_connection_get_certificate:
* @conn: a #GTlsConnection
*
* Gets @conn's certificate, as set by
* g_tls_connection_set_certificate() or returned from one of the
* signals.
*
* Return value: @conn's certificate, or %NULL
*
* Since: 2.28
*/
GTlsCertificate *
g_tls_connection_get_certificate (GTlsConnection *conn)
{
g_return_val_if_fail (G_IS_TLS_CONNECTION (conn), NULL);
return conn->priv->certificate;
}
/**
* g_tls_connection_get_peer_certificate:
* @conn: a #GTlsConnection
*
* Gets @conn's peer's certificate after it has been set during the
* handshake.
*
* Return value: @conn's peer's certificate, or %NULL
*
* Since: 2.28
*/
GTlsCertificate *
g_tls_connection_get_peer_certificate (GTlsConnection *conn)
{
g_return_val_if_fail (G_IS_TLS_CONNECTION (conn), NULL);
return conn->priv->peer_certificate;
}
/**
* g_tls_connection_set_require_close_notify:
* @conn: a #GTlsConnection
* @require_close_notify: whether or not to require close notification
*
* Sets whether or not @conn requires a proper TLS close notification
* before closing the connection. If this is %TRUE (the default), then
* calling g_io_stream_close() on @conn will send a TLS close
* notification, and likewise it will expect to receive a close
* notification before the connection is closed when reading, and will
* return a %G_TLS_ERROR_EOF error if the connection is closed without
* proper notification (since this may indicate a network error, or
* man-in-the-middle attack).
*
* In some protocols, the application will know whether or not the
* connection was closed cleanly based on application-level data
* (because the application-level data includes a length field, or is
* somehow self-delimiting); in this case, the close notify is
* redundant and sometimes omitted. (TLS 1.1 explicitly allows this;
* in TLS 1.0 it is technically an error, but often done anyway.) You
* can use g_tls_connection_set_require_close_notify() to tell @conn to
* allow an "unannounced" connection close, in which case it is up to
* the application to check that the data has been fully received.
*
* Since: 2.28
*/
void
g_tls_connection_set_require_close_notify (GTlsConnection *conn,
gboolean require_close_notify)
{
g_return_if_fail (G_IS_TLS_CONNECTION (conn));
g_object_set (G_OBJECT (conn),
"require-close-notify", require_close_notify,
NULL);
}
/**
* g_tls_connection_get_require_close_notify:
* @conn: a #GTlsConnection
*
* Tests whether or not @conn requires a proper TLS close notification
* before closing the connection. See
* g_tls_connection_set_require_close_notify() for details.
*
* Return value: %TRUE if @conn requires a proper TLS close
* notification.
*
* Since: 2.28
*/
gboolean
g_tls_connection_get_require_close_notify (GTlsConnection *conn)
{
gboolean require_close_notify;
g_return_val_if_fail (G_IS_TLS_CONNECTION (conn), TRUE);
g_object_get (G_OBJECT (conn),
"require-close-notify", &require_close_notify,
NULL);
return require_close_notify;
}
/**
* g_tls_connection_set_rehandshake_mode:
* @conn: a #GTlsConnection
* @mode: the rehandshaking mode
*
* Sets how @conn behaves with respect to rehandshaking requests.
*
* %G_TLS_REHANDSHAKE_NEVER means that it will never agree to
* rehandshake after the initial handshake is complete. (For a client,
* this means it will refuse rehandshake requests from the server, and
* for a server, this means it will close the connection with an error
* if the client attempts to rehandshake.)
*
* %G_TLS_REHANDSHAKE_SAFELY means that the connection will allow a
* rehandshake only if the other end of the connection supports the
* TLS <literal>renegotiation_info</literal> extension. This is the
* default behavior, but means that rehandshaking will not work
* against older implementations that do not support that extension.
*
* %G_TLS_REHANDSHAKE_UNSAFELY means that the connection will allow
* rehandshaking even without the
* <literal>renegotiation_info</literal> extension. On the server side
* in particular, this is not recommended, since it leaves the server
* open to certain attacks. However, this mode is necessary if you
* need to allow renegotiation with older client software.
*
* Since: 2.28
*/
void
g_tls_connection_set_rehandshake_mode (GTlsConnection *conn,
GTlsRehandshakeMode mode)
{
g_return_if_fail (G_IS_TLS_CONNECTION (conn));
g_object_set (G_OBJECT (conn),
"rehandshake-mode", mode,
NULL);
}
/**
* g_tls_connection_get_rehandshake_mode:
* @conn: a #GTlsConnection
*
* Gets @conn rehandshaking mode. See
* g_tls_connection_set_rehandshake() for details.
*
* Return value: @conn's rehandshaking mode
*
* Since: 2.28
*/
GTlsRehandshakeMode
g_tls_connection_get_rehandshake_mode (GTlsConnection *conn)
{
GTlsRehandshakeMode mode;
g_return_val_if_fail (G_IS_TLS_CONNECTION (conn), G_TLS_REHANDSHAKE_NEVER);
g_object_get (G_OBJECT (conn),
"rehandshake-mode", &mode,
NULL);
return mode;
}
/**
* g_tls_connection_handshake:
* @conn: a #GTlsConnection
* @cancellable: a #GCancellable, or %NULL
* @error: a #GError, or %NULL
*
* Attempts a TLS handshake on @conn.
*
* On the client side, it is never necessary to call this method;
* although the connection needs to perform a handshake after
* connecting (or after sending a "STARTTLS"-type command) and may
* need to rehandshake later if the server requests it,
* #GTlsConnection will handle this for you automatically when you try
* to send or receive data on the connection. However, you can call
* g_tls_connection_handshake() manually if you want to know for sure
* whether the initial handshake succeeded or failed (as opposed to
* just immediately trying to write to @conn's output stream, in which
* case if it fails, it may not be possible to tell if it failed
* before or after completing the handshake).
*
* Likewise, on the server side, although a handshake is necessary at
* the beginning of the communication, you do not need to call this
* function explicitly unless you want clearer error reporting.
* However, you may call g_tls_connection_handshake() later on to
* renegotiate parameters (encryption methods, etc) with the client.
*
* #GTlsConnection::accept_certificate and
* #GTlsConnection::need_certificate may be emitted during the
* handshake.
*
* Return value: success or failure
*
* Since: 2.28
*/
gboolean
g_tls_connection_handshake (GTlsConnection *conn,
GCancellable *cancellable,
GError **error)
{
g_return_val_if_fail (G_IS_TLS_CONNECTION (conn), FALSE);
return G_TLS_CONNECTION_GET_CLASS (conn)->handshake (conn, cancellable, error);
}
/**
* g_tls_connection_handshake_async:
* @conn: a #GTlsConnection
* @io_priority: the <link linkend="io-priority">I/O priority</link>
* of the request.
* @cancellable: a #GCancellable, or %NULL
* @callback: callback to call when the handshake is complete
* @user_data: the data to pass to the callback function
*
* Asynchronously performs a TLS handshake on @conn. See
* g_tls_connection_handshake() for more information.
*
* Since: 2.28
*/
void
g_tls_connection_handshake_async (GTlsConnection *conn,
int io_priority,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
g_return_if_fail (G_IS_TLS_CONNECTION (conn));
return G_TLS_CONNECTION_GET_CLASS (conn)->handshake_async (conn, io_priority,
cancellable,
callback, user_data);
}
/**
* g_tls_connection_handshake_finish:
* @conn: a #GTlsConnection
* @result: a #GAsyncResult.
* @error: a #GError pointer, or %NULL
*
* Finish an asynchronous TLS handshake operation. See
* g_tls_connection_handshake() for more information.
*
* Return value: %TRUE on success, %FALSE on failure, in which
* case @error will be set.
*
* Since: 2.28
*/
gboolean
g_tls_connection_handshake_finish (GTlsConnection *conn,
GAsyncResult *result,
GError **error)
{
g_return_val_if_fail (G_IS_TLS_CONNECTION (conn), FALSE);
return G_TLS_CONNECTION_GET_CLASS (conn)->handshake_finish (conn, result, error);
}
/**
* g_tls_error_quark:
*
* Gets the TLS error quark.
*
* Return value: a #GQuark.
*
* Since: 2.28
*/
GQuark
g_tls_error_quark (void)
{
return g_quark_from_static_string ("g-tls-error-quark");
}
static gboolean
g_tls_connection_certificate_accumulator (GSignalInvocationHint *ihint,
GValue *return_accu,
const GValue *handler_return,
gpointer dummy)
{
GTlsCertificate *cert;
cert = g_value_get_object (handler_return);
if (cert)
g_value_set_object (return_accu, cert);
return cert != NULL;
}
/**
* g_tls_connection_emit_need_certificate:
* @conn: a #GTlsConnection
*
* Used by #GTlsConnection implementations to emit the
* #GTlsConnection::need-certificate signal.
*
* Since: 2.28
*/
GTlsCertificate *
g_tls_connection_emit_need_certificate (GTlsConnection *conn)
{
GTlsCertificate *cert = NULL;
g_signal_emit (conn, signals[NEED_CERTIFICATE], 0,
&cert);
return cert;
}
/**
* g_tls_connection_emit_accept_certificate:
* @conn: a #GTlsConnection
*
* Used by #GTlsConnection implementations to emit the
* #GTlsConnection::accept-certificate signal.
*
* Since: 2.28
*/
gboolean
g_tls_connection_emit_accept_certificate (GTlsConnection *conn,
GTlsCertificate *peer_cert,
GTlsCertificateFlags errors)
{
gboolean accept = FALSE;
g_signal_emit (conn, signals[ACCEPT_CERTIFICATE], 0,
peer_cert, errors, &accept);
return accept;
}
/**
* g_tls_connection_set_peer_certificate:
* @conn: a #GTlsConnection
* @certificate: the peer certificate
*
* Used by #GTlsConnection implementations to set the connection's
* peer certificate.
*
* Since: 2.28
*/
void
g_tls_connection_set_peer_certificate (GTlsConnection *conn,
GTlsCertificate *certificate)
{
if (conn->priv->peer_certificate)
g_object_unref (conn->priv->peer_certificate);
conn->priv->peer_certificate = certificate ? g_object_ref (certificate) : NULL;
g_object_notify (G_OBJECT (conn), "peer-certificate");
}

137
gio/gtlsconnection.h Normal file
View File

@ -0,0 +1,137 @@
/* GIO - GLib Input, Output and Streaming Library
*
* Copyright (C) 2010 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*/
#if !defined (__GIO_GIO_H_INSIDE__) && !defined (GIO_COMPILATION)
#error "Only <gio/gio.h> can be included directly."
#endif
#ifndef __G_TLS_CONNECTION_H__
#define __G_TLS_CONNECTION_H__
#include <gio/giostream.h>
G_BEGIN_DECLS
#define G_TYPE_TLS_CONNECTION (g_tls_connection_get_type ())
#define G_TLS_CONNECTION(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), G_TYPE_TLS_CONNECTION, GTlsConnection))
#define G_TLS_CONNECTION_CLASS(class) (G_TYPE_CHECK_CLASS_CAST ((class), G_TYPE_TLS_CONNECTION, GTlsConnectionClass))
#define G_IS_TLS_CONNECTION(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), G_TYPE_TLS_CONNECTION))
#define G_IS_TLS_CONNECTION_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class), G_TYPE_TLS_CONNECTION))
#define G_TLS_CONNECTION_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), G_TYPE_TLS_CONNECTION, GTlsConnectionClass))
/**
* GTlsConnection:
*
* TLS connection. This is an abstract type that will be subclassed by
* a TLS-library-specific subtype.
*
* Since: 2.28
*/
typedef struct _GTlsConnectionClass GTlsConnectionClass;
typedef struct _GTlsConnectionPrivate GTlsConnectionPrivate;
struct _GTlsConnection {
GIOStream parent_instance;
GTlsConnectionPrivate *priv;
};
struct _GTlsConnectionClass
{
GIOStreamClass parent_class;
/* signals */
GTlsCertificate * ( *need_certificate) (GTlsConnection *connection);
gboolean ( *accept_certificate) (GTlsConnection *connection,
GTlsCertificate *peer_cert,
GTlsCertificateFlags errors);
/* methods */
gboolean ( *handshake ) (GTlsConnection *conn,
GCancellable *cancellable,
GError **error);
void ( *handshake_async ) (GTlsConnection *conn,
int io_priority,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
gboolean ( *handshake_finish ) (GTlsConnection *conn,
GAsyncResult *result,
GError **error);
/*< private >*/
/* Padding for future expansion */
gpointer padding[8];
};
GType g_tls_connection_get_type (void) G_GNUC_CONST;
void g_tls_connection_set_certificate (GTlsConnection *conn,
GTlsCertificate *certificate);
GTlsCertificate *g_tls_connection_get_certificate (GTlsConnection *conn);
GTlsCertificate *g_tls_connection_get_peer_certificate (GTlsConnection *conn);
void g_tls_connection_set_require_close_notify (GTlsConnection *conn,
gboolean require_close_notify);
gboolean g_tls_connection_get_require_close_notify (GTlsConnection *conn);
void g_tls_connection_set_rehandshake_mode (GTlsConnection *conn,
GTlsRehandshakeMode mode);
GTlsRehandshakeMode g_tls_connection_get_rehandshake_mode (GTlsConnection *conn);
gboolean g_tls_connection_handshake (GTlsConnection *conn,
GCancellable *cancellable,
GError **error);
void g_tls_connection_handshake_async (GTlsConnection *conn,
int io_priority,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
gboolean g_tls_connection_handshake_finish (GTlsConnection *conn,
GAsyncResult *result,
GError **error);
/**
* G_TLS_ERROR:
*
* Error domain for TLS. Errors in this domain will be from the
* #GTlsError enumeration. See #GError for more information on error
* domains.
*/
#define G_TLS_ERROR (g_tls_error_quark ())
GQuark g_tls_error_quark (void);
/*< protected >*/
GTlsCertificate *g_tls_connection_emit_need_certificate (GTlsConnection *conn);
gboolean g_tls_connection_emit_accept_certificate (GTlsConnection *conn,
GTlsCertificate *peer_cert,
GTlsCertificateFlags errors);
void g_tls_connection_set_peer_certificate (GTlsConnection *conn,
GTlsCertificate *certificate);
G_END_DECLS
#endif /* __G_TLS_CONNECTION_H__ */

View File

@ -0,0 +1,96 @@
/* GIO - GLib Input, Output and Streaming Library
*
* Copyright © 2010 Red Hat, Inc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "config.h"
#include "glib.h"
#include "gtlsserverconnection.h"
#include "ginitable.h"
#include "gio-marshal.h"
#include "gioenumtypes.h"
#include "gsocket.h"
#include "gtlsbackend.h"
#include "gtlscertificate.h"
#include "glibintl.h"
/**
* SECTION:gtlsserverconnection
* @short_description: TLS server-side connection
* @include: gio/gio.h
*
* #GTlsServerConnection is the server-side subclass of #GTlsConnection,
* representing a server-side TLS connection.
*
* Since: 2.28
*/
G_DEFINE_INTERFACE (GTlsServerConnection, g_tls_server_connection, G_TYPE_TLS_CONNECTION)
static void
g_tls_server_connection_default_init (GTlsServerConnectionInterface *iface)
{
/**
* GTlsServerConnection:authentication-mode:
*
* The #GTlsAuthenticationMode for the server. This can be changed
* before calling g_tls_connection_handshake() if you want to
* rehandshake with a different mode from the initial handshake.
*
* Since: 2.28
*/
g_object_interface_install_property (iface,
g_param_spec_enum ("authentication-mode",
P_("Authentication Mode"),
P_("The client authentication mode"),
G_TYPE_TLS_AUTHENTICATION_MODE,
G_TLS_AUTHENTICATION_NONE,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS));
}
/**
* g_tls_server_connection_new:
* @base_io_stream: the #GIOStream to wrap
* @certificate: (allow-none): the default server certificate, or %NULL
* @error: #GError for error reporting, or %NULL to ignore.
*
* Creates a new #GTlsServerConnection wrapping @base_io_stream (which
* must have pollable input and output streams).
*
* Return value: the new #GTlsServerConnection, or %NULL on error
*
* Since: 2.28
*/
GTlsServerConnection *
g_tls_server_connection_new (GIOStream *base_io_stream,
GTlsCertificate *certificate,
GError **error)
{
GObject *conn;
GTlsBackend *backend;
backend = g_tls_backend_get_default ();
conn = g_initable_new (g_tls_backend_get_server_connection_type (backend),
NULL, error,
"base-io-stream", base_io_stream,
"certificate", certificate,
NULL);
return G_TLS_SERVER_CONNECTION (conn);
}

View File

@ -0,0 +1,61 @@
/* GIO - GLib Input, Output and Streaming Library
*
* Copyright (C) 2010 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*/
#if !defined (__GIO_GIO_H_INSIDE__) && !defined (GIO_COMPILATION)
#error "Only <gio/gio.h> can be included directly."
#endif
#ifndef __G_TLS_SERVER_CONNECTION_H__
#define __G_TLS_SERVER_CONNECTION_H__
#include <gio/gtlsconnection.h>
G_BEGIN_DECLS
#define G_TYPE_TLS_SERVER_CONNECTION (g_tls_server_connection_get_type ())
#define G_TLS_SERVER_CONNECTION(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), G_TYPE_TLS_SERVER_CONNECTION, GTlsServerConnection))
#define G_IS_TLS_SERVER_CONNECTION(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), G_TYPE_TLS_SERVER_CONNECTION))
#define G_TLS_SERVER_CONNECTION_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), G_TYPE_TLS_SERVER_CONNECTION, GTlsServerConnectionInterface))
/**
* GTlsServerConnection:
*
* TLS server-side connection. This is the server-side implementation
* of a #GTlsConnection.
*
* Since: 2.28
*/
typedef struct _GTlsServerConnectionInterface GTlsServerConnectionInterface;
struct _GTlsServerConnectionInterface
{
GTypeInterface g_iface;
};
GType g_tls_server_connection_get_type (void) G_GNUC_CONST;
GTlsServerConnection *g_tls_server_connection_new (GIOStream *base_io_stream,
GTlsCertificate *certificate,
GError **error);
G_END_DECLS
#endif /* __G_TLS_SERVER_CONNECTION_H__ */

View File

@ -5,17 +5,15 @@
#include <stdio.h>
#include <string.h>
#include "socket-common.c"
GMainLoop *loop;
gboolean verbose = FALSE;
gboolean non_blocking = FALSE;
gboolean use_udp = FALSE;
gboolean use_source = FALSE;
int cancel_timeout = 0;
int read_timeout = 0;
gboolean unix_socket = FALSE;
gboolean tls = FALSE;
static GOptionEntry cmd_entries[] = {
{"cancel", 'c', 0, G_OPTION_ARG_INT, &cancel_timeout,
@ -26,70 +24,39 @@ static GOptionEntry cmd_entries[] = {
"Be verbose", NULL},
{"non-blocking", 'n', 0, G_OPTION_ARG_NONE, &non_blocking,
"Enable non-blocking i/o", NULL},
{"use-source", 's', 0, G_OPTION_ARG_NONE, &use_source,
"Use GSource to wait for non-blocking i/o", NULL},
#ifdef G_OS_UNIX
{"unix", 'U', 0, G_OPTION_ARG_NONE, &unix_socket,
"Use a unix socket instead of IP", NULL},
#endif
{"timeout", 't', 0, G_OPTION_ARG_INT, &read_timeout,
"Time out reads after the specified number of seconds", NULL},
{"tls", 'T', 0, G_OPTION_ARG_NONE, &tls,
"Use TLS (SSL)", NULL},
{NULL}
};
#include "socket-common.c"
static gboolean
source_ready (gpointer data,
GIOCondition condition)
accept_certificate (GTlsClientConnection *conn, GTlsCertificate *cert,
GTlsCertificateFlags errors, gpointer user_data)
{
g_main_loop_quit (loop);
return FALSE;
}
g_print ("Certificate would have been rejected ( ");
if (errors & G_TLS_CERTIFICATE_UNKNOWN_CA)
g_print ("unknown-ca ");
if (errors & G_TLS_CERTIFICATE_BAD_IDENTITY)
g_print ("bad-identity ");
if (errors & G_TLS_CERTIFICATE_NOT_ACTIVATED)
g_print ("not-activated ");
if (errors & G_TLS_CERTIFICATE_EXPIRED)
g_print ("expired ");
if (errors & G_TLS_CERTIFICATE_REVOKED)
g_print ("revoked ");
if (errors & G_TLS_CERTIFICATE_INSECURE)
g_print ("insecure ");
g_print (") but accepting anyway.\n");
static void
ensure_condition (GSocket *socket,
const char *where,
GCancellable *cancellable,
GIOCondition condition)
{
GError *error = NULL;
GSource *source;
if (!non_blocking)
return;
if (use_source)
{
source = g_socket_create_source (socket,
condition,
cancellable);
g_source_set_callback (source,
(GSourceFunc) source_ready,
NULL, NULL);
g_source_attach (source, NULL);
g_source_unref (source);
g_main_loop_run (loop);
}
else
{
if (!g_socket_condition_wait (socket, condition, cancellable, &error))
{
g_printerr ("condition wait error for %s: %s\n",
where,
error->message);
exit (1);
}
}
}
static gpointer
cancel_thread (gpointer data)
{
GCancellable *cancellable = data;
g_usleep (1000*1000*cancel_timeout);
g_print ("Cancelling\n");
g_cancellable_cancel (cancellable);
return NULL;
return TRUE;
}
int
@ -106,6 +73,9 @@ main (int argc,
GCancellable *cancellable;
GSocketAddressEnumerator *enumerator;
GSocketConnectable *connectable;
GIOStream *connection;
GInputStream *istream;
GOutputStream *ostream;
g_thread_init (NULL);
@ -125,6 +95,12 @@ main (int argc,
return 1;
}
if (use_udp && tls)
{
g_printerr ("DTLS (TLS over UDP) is not supported");
return 1;
}
if (cancel_timeout)
{
cancellable = g_cancellable_new ();
@ -201,15 +177,10 @@ main (int argc,
g_object_unref (address);
}
g_object_unref (enumerator);
g_object_unref (connectable);
g_print ("Connected to %s\n",
socket_address_to_string (address));
/* TODO: Test non-blocking connect */
if (non_blocking)
g_socket_set_blocking (socket, FALSE);
src_address = g_socket_get_local_address (socket, &error);
if (!src_address)
{
@ -221,6 +192,49 @@ main (int argc,
socket_address_to_string (src_address));
g_object_unref (src_address);
if (use_udp)
connection = NULL;
else
connection = G_IO_STREAM (g_socket_connection_factory_create_connection (socket));
if (tls)
{
GTlsClientConnection *tls_conn;
tls_conn = g_tls_client_connection_new (connection, connectable, &error);
if (!tls_conn)
{
g_printerr ("Could not create TLS connection: %s\n",
error->message);
return 1;
}
g_signal_connect (tls_conn, "accept-certificate",
G_CALLBACK (accept_certificate), NULL);
if (!g_tls_connection_handshake (G_TLS_CONNECTION (tls_conn),
cancellable, &error))
{
g_printerr ("Error during TLS handshake: %s\n",
error->message);
return 1;
}
g_object_unref (connection);
connection = G_IO_STREAM (tls_conn);
}
g_object_unref (connectable);
if (connection)
{
istream = g_io_stream_get_input_stream (connection);
ostream = g_io_stream_get_output_stream (connection);
}
/* TODO: Test non-blocking connect/handshake */
if (non_blocking)
g_socket_set_blocking (socket, FALSE);
while (TRUE)
{
gchar buffer[4096];
@ -233,14 +247,20 @@ main (int argc,
to_send = strlen (buffer);
while (to_send > 0)
{
ensure_condition (socket, "send", cancellable, G_IO_OUT);
if (use_udp)
size = g_socket_send_to (socket, address,
buffer, to_send,
cancellable, &error);
{
ensure_socket_condition (socket, G_IO_OUT, cancellable);
size = g_socket_send_to (socket, address,
buffer, to_send,
cancellable, &error);
}
else
size = g_socket_send (socket, buffer, to_send,
cancellable, &error);
{
ensure_connection_condition (connection, G_IO_OUT, cancellable);
size = g_output_stream_write (ostream,
buffer, to_send,
cancellable, &error);
}
if (size < 0)
{
@ -272,14 +292,20 @@ main (int argc,
to_send -= size;
}
ensure_condition (socket, "receive", cancellable, G_IO_IN);
if (use_udp)
size = g_socket_receive_from (socket, &src_address,
{
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);
else
size = g_socket_receive (socket, buffer, sizeof buffer,
cancellable, &error);
}
if (size < 0)
{
@ -306,15 +332,28 @@ main (int argc,
g_print ("closing socket\n");
if (!g_socket_close (socket, &error))
if (connection)
{
g_printerr ("Error closing master socket: %s\n",
error->message);
return 1;
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 (G_OBJECT (socket));
g_object_unref (G_OBJECT (address));
g_object_unref (socket);
g_object_unref (address);
return 0;
}

View File

@ -58,3 +58,64 @@ socket_address_from_string (const char *name)
#endif
return NULL;
}
static gboolean
source_ready (GPollableInputStream *stream,
gpointer data)
{
g_main_loop_quit (loop);
return FALSE;
}
static void
ensure_socket_condition (GSocket *socket,
GIOCondition condition,
GCancellable *cancellable)
{
GSource *source;
if (!non_blocking)
return;
source = g_socket_create_source (socket, condition, cancellable);
g_source_set_callback (source,
(GSourceFunc) source_ready,
NULL, NULL);
g_source_attach (source, NULL);
g_source_unref (source);
g_main_loop_run (loop);
}
static void
ensure_connection_condition (GIOStream *stream,
GIOCondition condition,
GCancellable *cancellable)
{
GSource *source;
if (!non_blocking)
return;
if (condition & G_IO_IN)
source = g_pollable_input_stream_create_source (G_POLLABLE_INPUT_STREAM (g_io_stream_get_input_stream (stream)), cancellable);
else
source = g_pollable_output_stream_create_source (G_POLLABLE_OUTPUT_STREAM (g_io_stream_get_output_stream (stream)), cancellable);
g_source_set_callback (source,
(GSourceFunc) source_ready,
NULL, NULL);
g_source_attach (source, NULL);
g_source_unref (source);
g_main_loop_run (loop);
}
static gpointer
cancel_thread (gpointer data)
{
GCancellable *cancellable = data;
g_usleep (1000*1000*cancel_timeout);
g_print ("Cancelling\n");
g_cancellable_cancel (cancellable);
return NULL;
}

View File

@ -4,8 +4,6 @@
#include <stdlib.h>
#include <string.h>
#include "socket-common.c"
GMainLoop *loop;
int port = 7777;
@ -13,11 +11,11 @@ gboolean verbose = FALSE;
gboolean dont_reuse_address = FALSE;
gboolean non_blocking = FALSE;
gboolean use_udp = FALSE;
gboolean use_source = FALSE;
int cancel_timeout = 0;
int read_timeout = 0;
int delay = 0;
gboolean unix_socket = FALSE;
const char *tls_cert_file = NULL;
static GOptionEntry cmd_entries[] = {
{"port", 'p', 0, G_OPTION_ARG_INT, &port,
@ -32,8 +30,6 @@ static GOptionEntry cmd_entries[] = {
"Don't SOADDRREUSE", NULL},
{"non-blocking", 'n', 0, G_OPTION_ARG_NONE, &non_blocking,
"Enable non-blocking i/o", NULL},
{"use-source", 's', 0, G_OPTION_ARG_NONE, &use_source,
"Use GSource to wait for non-blocking i/o", NULL},
#ifdef G_OS_UNIX
{"unix", 'U', 0, G_OPTION_ARG_NONE, &unix_socket,
"Use a unix socket instead of IP", NULL},
@ -42,63 +38,12 @@ static GOptionEntry cmd_entries[] = {
"Delay responses by the specified number of seconds", NULL},
{"timeout", 't', 0, G_OPTION_ARG_INT, &read_timeout,
"Time out reads after the specified number of seconds", NULL},
{"tls", 'T', 0, G_OPTION_ARG_STRING, &tls_cert_file,
"Use TLS (SSL) with indicated server certificate", "CERTFILE"},
{NULL}
};
static gboolean
source_ready (gpointer data,
GIOCondition condition)
{
g_main_loop_quit (loop);
return FALSE;
}
static void
ensure_condition (GSocket *socket,
const char *where,
GCancellable *cancellable,
GIOCondition condition)
{
GError *error = NULL;
GSource *source;
if (!non_blocking)
return;
if (use_source)
{
source = g_socket_create_source (socket,
condition,
cancellable);
g_source_set_callback (source,
(GSourceFunc) source_ready,
NULL, NULL);
g_source_attach (source, NULL);
g_source_unref (source);
g_main_loop_run (loop);
}
else
{
if (!g_socket_condition_wait (socket, condition, cancellable, &error))
{
g_printerr ("condition wait error for %s: %s\n",
where,
error->message);
exit (1);
}
}
}
static gpointer
cancel_thread (gpointer data)
{
GCancellable *cancellable = data;
g_usleep (1000*1000*cancel_timeout);
g_print ("Cancelling\n");
g_cancellable_cancel (cancellable);
return NULL;
}
#include "socket-common.c"
int
main (int argc,
@ -113,6 +58,10 @@ main (int argc,
GOptionContext *context;
GCancellable *cancellable;
char *display_addr;
GTlsCertificate *tlscert = NULL;
GIOStream *connection;
GInputStream *istream;
GOutputStream *ostream;
g_thread_init (NULL);
@ -142,6 +91,23 @@ main (int argc,
cancellable = NULL;
}
if (tls_cert_file)
{
if (use_udp)
{
g_printerr ("DTLS (TLS over UDP) is not supported");
return 1;
}
tlscert = g_tls_certificate_new_from_file (tls_cert_file, &error);
if (!tlscert)
{
g_printerr ("Could not read server certificate '%s': %s\n",
tls_cert_file, error->message);
return 1;
}
}
loop = g_main_loop_new (NULL, FALSE);
if (use_udp)
@ -205,7 +171,7 @@ main (int argc,
g_print ("listening on %s...\n", display_addr);
g_free (display_addr);
ensure_condition (socket, "accept", cancellable, G_IO_IN);
ensure_socket_condition (socket, G_IO_IN, cancellable);
new_socket = g_socket_accept (socket, cancellable, &error);
if (!new_socket)
{
@ -233,13 +199,45 @@ main (int argc,
g_object_unref (address);
recv_socket = new_socket;
connection = G_IO_STREAM (g_socket_connection_factory_create_connection (recv_socket));
g_object_unref (new_socket);
}
else
{
recv_socket = socket;
new_socket = NULL;
connection = NULL;
}
if (tlscert)
{
GTlsServerConnection *tls_conn;
tls_conn = g_tls_server_connection_new (connection, tlscert, &error);
if (!tls_conn)
{
g_printerr ("Could not create TLS connection: %s\n",
error->message);
return 1;
}
if (!g_tls_connection_handshake (G_TLS_CONNECTION (tls_conn),
cancellable, &error))
{
g_printerr ("Error during TLS handshake: %s\n",
error->message);
return 1;
}
g_object_unref (connection);
connection = G_IO_STREAM (tls_conn);
}
if (connection)
{
istream = g_io_stream_get_input_stream (connection);
ostream = g_io_stream_get_output_stream (connection);
}
while (TRUE)
{
@ -247,14 +245,20 @@ main (int argc,
gssize size;
gsize to_send;
ensure_condition (recv_socket, "receive", cancellable, G_IO_IN);
if (use_udp)
size = g_socket_receive_from (recv_socket, &address,
{
ensure_socket_condition (recv_socket, G_IO_IN, cancellable);
size = g_socket_receive_from (recv_socket, &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);
else
size = g_socket_receive (recv_socket, buffer, sizeof buffer,
cancellable, &error);
}
if (size < 0)
{
@ -288,13 +292,19 @@ main (int argc,
while (to_send > 0)
{
ensure_condition (recv_socket, "send", cancellable, G_IO_OUT);
if (use_udp)
size = g_socket_send_to (recv_socket, address,
buffer, to_send, cancellable, &error);
{
ensure_socket_condition (recv_socket, G_IO_OUT, cancellable);
size = g_socket_send_to (recv_socket, address,
buffer, to_send, cancellable, &error);
}
else
size = g_socket_send (recv_socket, buffer, to_send,
cancellable, &error);
{
ensure_connection_condition (connection, G_IO_OUT, cancellable);
size = g_output_stream_write (ostream,
buffer, to_send,
cancellable, &error);
}
if (size < 0)
{
@ -329,16 +339,15 @@ main (int argc,
g_print ("connection closed\n");
if (new_socket)
if (connection)
{
if (!g_socket_close (new_socket, &error))
if (!g_io_stream_close (connection, NULL, &error))
{
g_printerr ("Error closing connection socket: %s\n",
g_printerr ("Error closing connection stream: %s\n",
error->message);
return 1;
}
g_object_unref (G_OBJECT (new_socket));
g_object_unref (connection);
}
if (!g_socket_close (socket, &error))
@ -347,8 +356,7 @@ main (int argc,
error->message);
return 1;
}
g_object_unref (G_OBJECT (socket));
g_object_unref (socket);
return 0;
}