[glib: 1/2] Implement support for ALPN in GTlsConnection, GDtlsConnection



commit 9032e8897da5b93df16fd33e200523243dfc50ac
Author: Scott Hutton <schutton cisco com>
Date:   Tue Dec 18 16:32:55 2018 -0800

    Implement support for ALPN in GTlsConnection, GDtlsConnection

 docs/reference/gio/gio-sections.txt |   4 ++
 gio/gdtlsconnection.c               |  91 +++++++++++++++++++++++++
 gio/gdtlsconnection.h               |  13 ++++
 gio/gtlsconnection.c                | 131 +++++++++++++++++++++++++++++++++++-
 gio/gtlsconnection.h                |   7 ++
 5 files changed, 244 insertions(+), 2 deletions(-)
---
diff --git a/docs/reference/gio/gio-sections.txt b/docs/reference/gio/gio-sections.txt
index 3c0491a7b..02c461fc2 100644
--- a/docs/reference/gio/gio-sections.txt
+++ b/docs/reference/gio/gio-sections.txt
@@ -3747,6 +3747,8 @@ g_tls_connection_get_require_close_notify
 GTlsRehandshakeMode
 g_tls_connection_set_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_get_use_system_certdb
 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_set_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_set_database
 g_dtls_connection_get_interaction
diff --git a/gio/gdtlsconnection.c b/gio/gdtlsconnection.c
index 4177fb4aa..254537198 100644
--- a/gio/gdtlsconnection.c
+++ b/gio/gdtlsconnection.c
@@ -232,6 +232,37 @@ g_dtls_connection_default_init (GDtlsConnectionInterface *iface)
                                                            0,
                                                            G_PARAM_READABLE |
                                                            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:
@@ -989,3 +1020,63 @@ g_dtls_connection_emit_accept_certificate (GDtlsConnection      *conn,
                  peer_cert, errors, &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);
+}
diff --git a/gio/gdtlsconnection.h b/gio/gdtlsconnection.h
index 3cf6cb31c..364be935e 100644
--- a/gio/gdtlsconnection.h
+++ b/gio/gdtlsconnection.h
@@ -45,6 +45,8 @@ typedef struct _GDtlsConnectionInterface GDtlsConnectionInterface;
  * @shutdown: Shut down one or both directions of the connection.
  * @shutdown_async: Start 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.
  *
@@ -89,6 +91,10 @@ struct _GDtlsConnectionInterface
   gboolean (*shutdown_finish)    (GDtlsConnection       *conn,
                                   GAsyncResult          *result,
                                   GError               **error);
+
+  void (*set_advertised_protocols)        (GDtlsConnection     *conn,
+                                           const gchar * const *protocols);
+  const gchar *(*get_negotiated_protocol) (GDtlsConnection     *conn);
 };
 
 GLIB_AVAILABLE_IN_2_48
@@ -186,6 +192,13 @@ GLIB_AVAILABLE_IN_2_48
 gboolean              g_dtls_connection_emit_accept_certificate     (GDtlsConnection       *conn,
                                                                      GTlsCertificate       *peer_cert,
                                                                      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
 
 #endif /* __G_DTLS_CONNECTION_H__ */
diff --git a/gio/gtlsconnection.c b/gio/gtlsconnection.c
index 26d1881c3..a1e98c0c9 100644
--- a/gio/gtlsconnection.c
+++ b/gio/gtlsconnection.c
@@ -54,7 +54,12 @@
  * 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,
                                           guint       prop_id,
@@ -64,6 +69,7 @@ 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);
 
 enum {
   ACCEPT_CERTIFICATE,
@@ -83,7 +89,9 @@ enum {
   PROP_INTERACTION,
   PROP_CERTIFICATE,
   PROP_PEER_CERTIFICATE,
-  PROP_PEER_CERTIFICATE_ERRORS
+  PROP_PEER_CERTIFICATE_ERRORS,
+  PROP_ADVERTISED_PROTOCOLS,
+  PROP_NEGOTIATED_PROTOCOL,
 };
 
 static void
@@ -93,6 +101,7 @@ g_tls_connection_class_init (GTlsConnectionClass *klass)
 
   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:
@@ -251,6 +260,37 @@ g_tls_connection_class_init (GTlsConnectionClass *klass)
                                                       0,
                                                       G_PARAM_READABLE |
                                                       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:
@@ -334,6 +374,17 @@ g_tls_connection_set_property (GObject      *object,
   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:
  * @conn: a #GTlsConnection
@@ -742,6 +793,82 @@ g_tls_connection_get_rehandshake_mode (GTlsConnection       *conn)
   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:
  * @conn: a #GTlsConnection
diff --git a/gio/gtlsconnection.h b/gio/gtlsconnection.h
index 0cfcb5910..39ec3fa02 100644
--- a/gio/gtlsconnection.h
+++ b/gio/gtlsconnection.h
@@ -115,6 +115,13 @@ void                  g_tls_connection_set_rehandshake_mode        (GTlsConnecti
 GLIB_DEPRECATED_IN_2_60
 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
 gboolean              g_tls_connection_handshake                   (GTlsConnection       *conn,
                                                                    GCancellable         *cancellable,


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]