mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-02-12 13:49:22 +01:00
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:
parent
a1690339c7
commit
59d62726de
@ -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"/>
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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
274
gio/gdummytlsbackend.c
Normal 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
46
gio/gdummytlsbackend.h
Normal 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__ */
|
@ -27,3 +27,5 @@ INT:OBJECT
|
||||
VOID:INT64
|
||||
VOID:UINT64
|
||||
BOOLEAN:FLAGS
|
||||
BOOLEAN:OBJECT,FLAGS
|
||||
OBJECT:VOID
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
100
gio/gioenums.h
100
gio/gioenums.h
@ -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__ */
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
|
@ -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
201
gio/gtlsbackend.c
Normal 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
92
gio/gtlsbackend.h
Normal 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
486
gio/gtlscertificate.c
Normal 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
75
gio/gtlscertificate.h
Normal 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
333
gio/gtlsclientconnection.c
Normal 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;
|
||||
}
|
72
gio/gtlsclientconnection.h
Normal file
72
gio/gtlsclientconnection.h
Normal 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
720
gio/gtlsconnection.c
Normal 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
137
gio/gtlsconnection.h
Normal 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__ */
|
96
gio/gtlsserverconnection.c
Normal file
96
gio/gtlsserverconnection.c
Normal 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);
|
||||
}
|
61
gio/gtlsserverconnection.h
Normal file
61
gio/gtlsserverconnection.h
Normal 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__ */
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user