Merge branch 'master' into 'master'

GTlsConnection: add ALPN support

See merge request GNOME/glib!520
This commit is contained in:
Philip Withnall 2018-12-19 12:01:50 +00:00
commit 04af8f12f0
5 changed files with 244 additions and 2 deletions

View File

@ -3747,6 +3747,8 @@ g_tls_connection_get_require_close_notify
GTlsRehandshakeMode GTlsRehandshakeMode
g_tls_connection_set_rehandshake_mode g_tls_connection_set_rehandshake_mode
g_tls_connection_get_rehandshake_mode g_tls_connection_get_rehandshake_mode
g_tls_connection_set_advertised_protocols
g_tls_connection_get_negotiated_protocol
g_tls_connection_set_use_system_certdb g_tls_connection_set_use_system_certdb
g_tls_connection_get_use_system_certdb g_tls_connection_get_use_system_certdb
g_tls_connection_get_database g_tls_connection_get_database
@ -3938,6 +3940,8 @@ g_dtls_connection_set_require_close_notify
g_dtls_connection_get_require_close_notify g_dtls_connection_get_require_close_notify
g_dtls_connection_set_rehandshake_mode g_dtls_connection_set_rehandshake_mode
g_dtls_connection_get_rehandshake_mode g_dtls_connection_get_rehandshake_mode
g_dtls_connection_set_advertised_protocols
g_dtls_connection_get_negotiated_protocol
g_dtls_connection_get_database g_dtls_connection_get_database
g_dtls_connection_set_database g_dtls_connection_set_database
g_dtls_connection_get_interaction g_dtls_connection_get_interaction

View File

@ -232,6 +232,37 @@ g_dtls_connection_default_init (GDtlsConnectionInterface *iface)
0, 0,
G_PARAM_READABLE | G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS)); G_PARAM_STATIC_STRINGS));
/**
* GDtlsConnection:advertised-protocols:
*
* The list of application-layer protocols that the connection
* advertises that it is willing to speak. See
* g_dtls_connection_set_advertised_protocols().
*
* Since: 2.60
*/
g_object_interface_install_property (iface,
g_param_spec_boxed ("advertised-protocols",
P_("Advertised Protocols"),
P_("Application-layer protocols available on this connection"),
G_TYPE_STRV,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS));
/**
* GDtlsConnection:negotiated-protocol:
*
* The application-layer protocol negotiated during the TLS
* handshake. See g_dtls_connection_get_negotiated_protocol().
*
* Since: 2.60
*/
g_object_interface_install_property (iface,
g_param_spec_string ("negotiated-protocol",
P_("Negotiated Protocol"),
P_("Application-layer protocol negotiated for this connection"),
NULL,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
/** /**
* GDtlsConnection::accept-certificate: * GDtlsConnection::accept-certificate:
@ -989,3 +1020,63 @@ g_dtls_connection_emit_accept_certificate (GDtlsConnection *conn,
peer_cert, errors, &accept); peer_cert, errors, &accept);
return accept; return accept;
} }
/**
* g_dtls_connection_set_advertised_protocols:
* @conn: a #GDtlsConnection
* @protocols: (array zero-terminated=1) (nullable): a %NULL-terminated
* array of ALPN protocol names (eg, "http/1.1", "h2"), or %NULL
*
* Sets the list of application-layer protocols to advertise that the
* caller is willing to speak on this connection. The
* Application-Layer Protocol Negotiation (ALPN) extension will be
* used to negotiate a compatible protocol with the peer; use
* g_dtls_connection_get_negotiated_protocol() to find the negotiated
* protocol after the handshake. Specifying %NULL for the the value
* of @protocols will disable ALPN negotiation.
*
* See [IANA TLS ALPN Protocol IDs](https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids)
* for a list of registered protocol IDs.
*
* Since: 2.60
*/
void
g_dtls_connection_set_advertised_protocols (GDtlsConnection *conn,
const gchar * const *protocols)
{
GDtlsConnectionInterface *iface;
iface = G_DTLS_CONNECTION_GET_INTERFACE (conn);
if (iface->set_advertised_protocols == NULL)
return;
return iface->set_advertised_protocols (conn, protocols);
}
/**
* g_dtls_connection_get_negotiated_protocol:
* @conn: a #GDtlsConnection
*
* Gets the name of the application-layer protocol negotiated during
* the handshake.
*
* If the peer did not use the ALPN extension, or did not advertise a
* protocol that matched one of @conn's protocols, or the TLS backend
* does not support ALPN, then this will be %NULL. See
* g_dtls_connection_set_advertised_protocols().
*
* Returns: (nullable): the negotiated protocol, or %NULL
*
* Since: 2.60
*/
const gchar *
g_dtls_connection_get_negotiated_protocol (GDtlsConnection *conn)
{
GDtlsConnectionInterface *iface;
iface = G_DTLS_CONNECTION_GET_INTERFACE (conn);
if (iface->set_advertised_protocols == NULL)
return NULL;
return iface->get_negotiated_protocol (conn);
}

View File

@ -45,6 +45,8 @@ typedef struct _GDtlsConnectionInterface GDtlsConnectionInterface;
* @shutdown: Shut down one or both directions of the connection. * @shutdown: Shut down one or both directions of the connection.
* @shutdown_async: Start an asynchronous shutdown operation. * @shutdown_async: Start an asynchronous shutdown operation.
* @shutdown_finish: Finish an asynchronous shutdown operation. * @shutdown_finish: Finish an asynchronous shutdown operation.
* @set_advertised_protocols: Set APLN protocol list
* @get_negotiated_protocol: Retrieve ALPN-negotiated protocol
* *
* Virtual method table for a #GDtlsConnection implementation. * Virtual method table for a #GDtlsConnection implementation.
* *
@ -89,6 +91,10 @@ struct _GDtlsConnectionInterface
gboolean (*shutdown_finish) (GDtlsConnection *conn, gboolean (*shutdown_finish) (GDtlsConnection *conn,
GAsyncResult *result, GAsyncResult *result,
GError **error); GError **error);
void (*set_advertised_protocols) (GDtlsConnection *conn,
const gchar * const *protocols);
const gchar *(*get_negotiated_protocol) (GDtlsConnection *conn);
}; };
GLIB_AVAILABLE_IN_2_48 GLIB_AVAILABLE_IN_2_48
@ -186,6 +192,13 @@ GLIB_AVAILABLE_IN_2_48
gboolean g_dtls_connection_emit_accept_certificate (GDtlsConnection *conn, gboolean g_dtls_connection_emit_accept_certificate (GDtlsConnection *conn,
GTlsCertificate *peer_cert, GTlsCertificate *peer_cert,
GTlsCertificateFlags errors); GTlsCertificateFlags errors);
GLIB_AVAILABLE_IN_2_60
void g_dtls_connection_set_advertised_protocols (GDtlsConnection *conn,
const gchar * const *protocols);
GLIB_AVAILABLE_IN_2_60
const gchar * g_dtls_connection_get_negotiated_protocol (GDtlsConnection *conn);
G_END_DECLS G_END_DECLS
#endif /* __G_DTLS_CONNECTION_H__ */ #endif /* __G_DTLS_CONNECTION_H__ */

View File

@ -54,7 +54,12 @@
* Since: 2.28 * Since: 2.28
*/ */
G_DEFINE_ABSTRACT_TYPE (GTlsConnection, g_tls_connection, G_TYPE_IO_STREAM) struct _GTlsConnectionPrivate
{
gchar *negotiated_protocol;
};
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GTlsConnection, g_tls_connection, G_TYPE_IO_STREAM)
static void g_tls_connection_get_property (GObject *object, static void g_tls_connection_get_property (GObject *object,
guint prop_id, guint prop_id,
@ -64,6 +69,7 @@ static void g_tls_connection_set_property (GObject *object,
guint prop_id, guint prop_id,
const GValue *value, const GValue *value,
GParamSpec *pspec); GParamSpec *pspec);
static void g_tls_connection_finalize (GObject *object);
enum { enum {
ACCEPT_CERTIFICATE, ACCEPT_CERTIFICATE,
@ -83,7 +89,9 @@ enum {
PROP_INTERACTION, PROP_INTERACTION,
PROP_CERTIFICATE, PROP_CERTIFICATE,
PROP_PEER_CERTIFICATE, PROP_PEER_CERTIFICATE,
PROP_PEER_CERTIFICATE_ERRORS PROP_PEER_CERTIFICATE_ERRORS,
PROP_ADVERTISED_PROTOCOLS,
PROP_NEGOTIATED_PROTOCOL,
}; };
static void static void
@ -93,6 +101,7 @@ g_tls_connection_class_init (GTlsConnectionClass *klass)
gobject_class->get_property = g_tls_connection_get_property; gobject_class->get_property = g_tls_connection_get_property;
gobject_class->set_property = g_tls_connection_set_property; gobject_class->set_property = g_tls_connection_set_property;
gobject_class->finalize = g_tls_connection_finalize;
/** /**
* GTlsConnection:base-io-stream: * GTlsConnection:base-io-stream:
@ -251,6 +260,37 @@ g_tls_connection_class_init (GTlsConnectionClass *klass)
0, 0,
G_PARAM_READABLE | G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS)); G_PARAM_STATIC_STRINGS));
/**
* GTlsConnection:advertised-protocols:
*
* The list of application-layer protocols that the connection
* advertises that it is willing to speak. See
* g_tls_connection_set_advertised_protocols().
*
* Since: 2.60
*/
g_object_class_install_property (gobject_class, PROP_ADVERTISED_PROTOCOLS,
g_param_spec_boxed ("advertised-protocols",
P_("Advertised Protocols"),
P_("Application-layer protocols available on this connection"),
G_TYPE_STRV,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS));
/**
* GTlsConnection:negotiated-protocol:
*
* The application-layer protocol negotiated during the TLS
* handshake. See g_tls_connection_get_negotiated_protocol().
*
* Since: 2.60
*/
g_object_class_install_property (gobject_class, PROP_NEGOTIATED_PROTOCOL,
g_param_spec_string ("negotiated-protocol",
P_("Negotiated Protocol"),
P_("Application-layer protocol negotiated for this connection"),
NULL,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
/** /**
* GTlsConnection::accept-certificate: * GTlsConnection::accept-certificate:
@ -334,6 +374,17 @@ g_tls_connection_set_property (GObject *object,
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
} }
static void
g_tls_connection_finalize (GObject *object)
{
GTlsConnection *conn = G_TLS_CONNECTION(object);
GTlsConnectionPrivate *priv = g_tls_connection_get_instance_private (conn);
g_clear_pointer (&priv->negotiated_protocol, g_free);
G_OBJECT_CLASS (g_tls_connection_parent_class)->finalize (object);
}
/** /**
* g_tls_connection_set_use_system_certdb: * g_tls_connection_set_use_system_certdb:
* @conn: a #GTlsConnection * @conn: a #GTlsConnection
@ -742,6 +793,82 @@ g_tls_connection_get_rehandshake_mode (GTlsConnection *conn)
return mode; return mode;
} }
/**
* g_tls_connection_set_advertised_protocols:
* @conn: a #GTlsConnection
* @protocols: (array zero-terminated=1) (nullable): a %NULL-terminated
* array of ALPN protocol names (eg, "http/1.1", "h2"), or %NULL
*
* Sets the list of application-layer protocols to advertise that the
* caller is willing to speak on this connection. The
* Application-Layer Protocol Negotiation (ALPN) extension will be
* used to negotiate a compatible protocol with the peer; use
* g_tls_connection_get_negotiated_protocol() to find the negotiated
* protocol after the handshake. Specifying %NULL for the the value
* of @protocols will disable ALPN negotiation.
*
* See [IANA TLS ALPN Protocol IDs](https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids)
* for a list of registered protocol IDs.
*
* Since: 2.60
*/
void
g_tls_connection_set_advertised_protocols (GTlsConnection *conn,
const gchar * const *protocols)
{
g_return_if_fail (G_IS_TLS_CONNECTION (conn));
g_object_set (G_OBJECT (conn),
"advertised-protocols", protocols,
NULL);
}
/**
* g_tls_connection_get_negotiated_protocol:
* @conn: a #GTlsConnection
*
* Gets the name of the application-layer protocol negotiated during
* the handshake.
*
* If the peer did not use the ALPN extension, or did not advertise a
* protocol that matched one of @conn's protocols, or the TLS backend
* does not support ALPN, then this will be %NULL. See
* g_tls_connection_set_advertised_protocols().
*
* Returns: (nullable): the negotiated protocol, or %NULL
*
* Since: 2.60
*/
const gchar *
g_tls_connection_get_negotiated_protocol (GTlsConnection *conn)
{
GTlsConnectionPrivate *priv;
gchar *protocol;
g_return_val_if_fail (G_IS_TLS_CONNECTION (conn), NULL);
g_object_get (G_OBJECT (conn),
"negotiated-protocol", &protocol,
NULL);
/*
* Cache the property internally so we can return a `const` pointer
* to the caller.
*/
priv = g_tls_connection_get_instance_private (conn);
if (g_strcmp0 (priv->negotiated_protocol, protocol) != 0)
{
g_free (priv->negotiated_protocol);
priv->negotiated_protocol = protocol;
}
else
{
g_free (protocol);
}
return priv->negotiated_protocol;
}
/** /**
* g_tls_connection_handshake: * g_tls_connection_handshake:
* @conn: a #GTlsConnection * @conn: a #GTlsConnection

View File

@ -115,6 +115,13 @@ void g_tls_connection_set_rehandshake_mode (GTlsConnecti
GLIB_DEPRECATED_IN_2_60 GLIB_DEPRECATED_IN_2_60
GTlsRehandshakeMode g_tls_connection_get_rehandshake_mode (GTlsConnection *conn); GTlsRehandshakeMode g_tls_connection_get_rehandshake_mode (GTlsConnection *conn);
GLIB_AVAILABLE_IN_2_60
void g_tls_connection_set_advertised_protocols (GTlsConnection *conn,
const gchar * const *protocols);
GLIB_AVAILABLE_IN_2_60
const gchar * g_tls_connection_get_negotiated_protocol (GTlsConnection *conn);
GLIB_AVAILABLE_IN_ALL GLIB_AVAILABLE_IN_ALL
gboolean g_tls_connection_handshake (GTlsConnection *conn, gboolean g_tls_connection_handshake (GTlsConnection *conn,
GCancellable *cancellable, GCancellable *cancellable,