]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
Add APIs to register TLS extension handlers.
authorSimon Josefsson <simon@josefsson.org>
Thu, 3 Jul 2008 15:28:44 +0000 (17:28 +0200)
committerSimon Josefsson <simon@josefsson.org>
Thu, 3 Jul 2008 15:28:44 +0000 (17:28 +0200)
includes/gnutls/gnutls.h.in
lib/gnutls_extensions.c
lib/gnutls_extensions.h
lib/gnutls_global.c
lib/gnutls_handshake.c
lib/gnutls_int.h

index 1bd5d03876e490730972289ca7290225ab5f9be5..13d507bdfee100b665be70aa15be7c2861171c70 100644 (file)
@@ -480,6 +480,29 @@ extern "C"
 
 /* TLS Extensions */
 
+  typedef int (*gnutls_ext_recv_func) (gnutls_session_t session,
+                                      const unsigned char *data, size_t len);
+  typedef int (*gnutls_ext_send_func) (gnutls_session_t session,
+                                      unsigned char *data, size_t len);
+
+  /* This flag indicates for an extension whether
+   * it is useful to application level or TLS level only.
+   * This is (only) used to parse the application level extensions
+   * before the user_hello callback is called.
+   */
+  typedef enum
+    {
+      GNUTLS_EXT_ANY,
+      GNUTLS_EXT_APPLICATION,
+      GNUTLS_EXT_TLS
+    } gnutls_ext_parse_type_t;
+
+  int gnutls_ext_register (int type,
+                          const char *name,
+                          gnutls_ext_parse_type_t parse_type,
+                          gnutls_ext_recv_func recv_func,
+                          gnutls_ext_send_func send_func);
+
   typedef enum
   {
     GNUTLS_NAME_DNS = 1
index fd43f7d4e010b128526962a583cf8955cde323bd..3a9b650a17f52cf2f39cf35950a973b00a788146 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, 2008 Free Software Foundation
  *
- * Author: Nikos Mavrogiannopoulos
+ * Author: Nikos Mavrogiannopoulos, Simon Josefsson
  *
  * This file is part of GNUTLS.
  *
 #include <ext_inner_application.h>
 #include <gnutls_num.h>
 
-/* Key Exchange Section */
-#define GNUTLS_EXTENSION_ENTRY(type, parse_type, ext_func_recv, ext_func_send) \
-       { #type, type, parse_type, ext_func_recv, ext_func_send }
-
-
-#define MAX_EXT_SIZE 10
-const int _gnutls_extensions_size = MAX_EXT_SIZE;
-
-gnutls_extension_entry _gnutls_extensions[MAX_EXT_SIZE] = {
-  GNUTLS_EXTENSION_ENTRY (GNUTLS_EXTENSION_MAX_RECORD_SIZE,
-                         EXTENSION_TLS,
-                         _gnutls_max_record_recv_params,
-                         _gnutls_max_record_send_params),
-  GNUTLS_EXTENSION_ENTRY (GNUTLS_EXTENSION_CERT_TYPE,
-                         EXTENSION_TLS,
-                         _gnutls_cert_type_recv_params,
-                         _gnutls_cert_type_send_params),
-  GNUTLS_EXTENSION_ENTRY (GNUTLS_EXTENSION_SERVER_NAME,
-                         EXTENSION_APPLICATION,
-                         _gnutls_server_name_recv_params,
-                         _gnutls_server_name_send_params),
-#ifdef ENABLE_OPRFI
-  GNUTLS_EXTENSION_ENTRY (GNUTLS_EXTENSION_OPAQUE_PRF_INPUT,
-                         EXTENSION_TLS,
-                         _gnutls_oprfi_recv_params,
-                         _gnutls_oprfi_send_params),
-#endif
-#ifdef ENABLE_SRP
-  GNUTLS_EXTENSION_ENTRY (GNUTLS_EXTENSION_SRP,
-                         EXTENSION_TLS,
-                         _gnutls_srp_recv_params,
-                         _gnutls_srp_send_params),
-#endif
-  GNUTLS_EXTENSION_ENTRY (GNUTLS_EXTENSION_INNER_APPLICATION,
-                         EXTENSION_TLS,
-                         _gnutls_inner_application_recv_params,
-                         _gnutls_inner_application_send_params),
-  {NULL, 0, 0, NULL, NULL}
-};
-
-#define GNUTLS_EXTENSION_LOOP2(b) \
-        gnutls_extension_entry *p; \
-                for(p = _gnutls_extensions; p->name != NULL; p++) { b ; }
-
-#define GNUTLS_EXTENSION_LOOP(a) \
-                        GNUTLS_EXTENSION_LOOP2( if(p->type == type) { a; break; } )
-
-
-/* EXTENSION functions */
-
-ext_recv_func
-_gnutls_ext_func_recv (uint16_t type, tls_ext_parse_type_t parse_type)
+typedef struct
 {
-  ext_recv_func ret = NULL;
-  GNUTLS_EXTENSION_LOOP (if
-                        (parse_type == EXTENSION_ANY
-                         || p->parse_type == parse_type) ret =
-                        p->gnutls_ext_func_recv);
-  return ret;
+  const char *name;
+  uint16_t type;
+  gnutls_ext_parse_type_t parse_type;
+  gnutls_ext_recv_func recv_func;
+  gnutls_ext_send_func send_func;
+} gnutls_extension_entry;
 
-}
+size_t extfunc_size = 0;
+static gnutls_extension_entry *extfunc = NULL;
 
-ext_send_func
-_gnutls_ext_func_send (uint16_t type)
+static gnutls_ext_recv_func
+_gnutls_ext_func_recv (uint16_t type, gnutls_ext_parse_type_t parse_type)
 {
-  ext_send_func ret = NULL;
-  GNUTLS_EXTENSION_LOOP (ret = p->gnutls_ext_func_send);
-  return ret;
+  size_t i;
 
+  for (i = 0; i < extfunc_size; i++)
+    if (extfunc[i].type == type)
+      if (parse_type == GNUTLS_EXT_ANY
+         || extfunc[i].parse_type == parse_type)
+       return extfunc[i].recv_func;
+
+  return NULL;
 }
 
 const char *
 _gnutls_extension_get_name (uint16_t type)
 {
-  const char *ret = NULL;
+  size_t i;
 
-  /* avoid prefix */
-  GNUTLS_EXTENSION_LOOP (ret = p->name + sizeof ("GNUTLS_EXTENSION_") - 1);
+  for (i = 0; i < extfunc_size; i++)
+    if (extfunc[i].type == type)
+      return extfunc[i].name;
 
-  return ret;
+  return NULL;
 }
 
 /* Checks if the extension we just received is one of the 
@@ -129,11 +85,13 @@ _gnutls_extension_list_check (gnutls_session_t session, uint16_t type)
   if (session->security_parameters.entity == GNUTLS_CLIENT)
     {
       int i;
+
       for (i = 0; i < session->internals.extensions_sent_size; i++)
        {
          if (type == session->internals.extensions_sent[i])
            return 0;           /* ok found */
        }
+
       return GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION;
     }
 
@@ -142,14 +100,14 @@ _gnutls_extension_list_check (gnutls_session_t session, uint16_t type)
 
 int
 _gnutls_parse_extensions (gnutls_session_t session,
-                         tls_ext_parse_type_t parse_type,
+                         gnutls_ext_parse_type_t parse_type,
                          const opaque * data, int data_size)
 {
   int next, ret;
   int pos = 0;
   uint16_t type;
   const opaque *sdata;
-  ext_recv_func ext_recv;
+  gnutls_ext_recv_func ext_recv;
   uint16_t size;
 
 #ifdef DEBUG
@@ -222,9 +180,8 @@ _gnutls_extension_list_add (gnutls_session_t session, uint16_t type)
     {
       if (session->internals.extensions_sent_size < MAX_EXT_TYPES)
        {
-         session->internals.extensions_sent[session->
-                                            internals.extensions_sent_size] =
-           type;
+         session->internals.extensions_sent[session->internals.
+                                            extensions_sent_size] = type;
          session->internals.extensions_sent_size++;
        }
       else
@@ -242,8 +199,7 @@ _gnutls_gen_extensions (gnutls_session_t session, opaque * data,
   uint16_t pos = 0;
   opaque *sdata;
   int sdata_size;
-  ext_send_func ext_send;
-  gnutls_extension_entry *p;
+  size_t i;
 
   if (data_size < 2)
     {
@@ -262,12 +218,14 @@ _gnutls_gen_extensions (gnutls_session_t session, opaque * data,
     }
 
   pos += 2;
-  for (p = _gnutls_extensions; p->name != NULL; p++)
+  for (i = 0; i < extfunc_size; i++)
     {
-      ext_send = _gnutls_ext_func_send (p->type);
-      if (ext_send == NULL)
+      gnutls_extension_entry *p = &extfunc[i];
+
+      if (p->send_func == NULL)
        continue;
-      size = ext_send (session, sdata, sdata_size);
+
+      size = p->send_func (session, sdata, sdata_size);
       if (size > 0)
        {
          if (data_size < pos + (size_t) size + 4)
@@ -292,8 +250,8 @@ _gnutls_gen_extensions (gnutls_session_t session, opaque * data,
           */
          _gnutls_extension_list_add (session, p->type);
 
-         _gnutls_debug_log ("EXT[%x]: Sending extension %s\n", session,
-                            _gnutls_extension_get_name (p->type));
+         _gnutls_debug_log ("EXT[%x]: Sending extension %s\n",
+                            session, p->name);
        }
       else if (size < 0)
        {
@@ -317,3 +275,103 @@ _gnutls_gen_extensions (gnutls_session_t session, opaque * data,
   return size;
 
 }
+
+int
+_gnutls_ext_init (void)
+{
+  int ret;
+
+  ret = gnutls_ext_register (GNUTLS_EXTENSION_MAX_RECORD_SIZE,
+                            "MAX_RECORD_SIZE",
+                            GNUTLS_EXT_TLS,
+                            _gnutls_max_record_recv_params,
+                            _gnutls_max_record_send_params);
+  if (ret != GNUTLS_E_SUCCESS)
+    return ret;
+
+  ret = gnutls_ext_register (GNUTLS_EXTENSION_CERT_TYPE,
+                            "CERT_TYPE",
+                            GNUTLS_EXT_TLS,
+                            _gnutls_cert_type_recv_params,
+                            _gnutls_cert_type_send_params);
+  if (ret != GNUTLS_E_SUCCESS)
+    return ret;
+
+  ret = gnutls_ext_register (GNUTLS_EXTENSION_SERVER_NAME,
+                            "SERVER_NAME",
+                            GNUTLS_EXT_APPLICATION,
+                            _gnutls_server_name_recv_params,
+                            _gnutls_server_name_send_params);
+  if (ret != GNUTLS_E_SUCCESS)
+    return ret;
+
+#ifdef ENABLE_OPRFI
+  ret = gnutls_ext_register (GNUTLS_EXTENSION_OPAQUE_PRF_INPUT,
+                            "OPAQUE_PRF_INPUT",
+                            GNUTLS_EXT_TLS,
+                            _gnutls_oprfi_recv_params,
+                            _gnutls_oprfi_send_params);
+  if (ret != GNUTLS_E_SUCCESS)
+    return ret;
+#endif
+
+#ifdef ENABLE_SRP
+  ret = gnutls_ext_register (GNUTLS_EXTENSION_SRP,
+                            "SRP",
+                            GNUTLS_EXT_TLS,
+                            _gnutls_srp_recv_params,
+                            _gnutls_srp_send_params);
+  if (ret != GNUTLS_E_SUCCESS)
+    return ret;
+#endif
+
+  ret = gnutls_ext_register (GNUTLS_EXTENSION_INNER_APPLICATION,
+                            "INNER_APPLICATION",
+                            GNUTLS_EXT_TLS,
+                            _gnutls_inner_application_recv_params,
+                            _gnutls_inner_application_send_params);
+  if (ret != GNUTLS_E_SUCCESS)
+    return ret;
+
+  return GNUTLS_E_SUCCESS;
+}
+
+/**
+ * gnutls_ext_register - Register a handler for a TLS extension
+ * @type: the 16-bit integer referring to the extension type
+ * @name: human printable name of the extension used for debugging
+ * @parse_type: either #GNUTLS_EXT_TLS or %GNUTLS_EXT_APPLICATION.
+ * @recv_func: a function to receive extension data
+ * @send_func: a function to send extension data
+ *
+ * This function is used to register a new TLS extension handler.
+ *
+ * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
+ **/
+int
+gnutls_ext_register (int type,
+                    const char *name,
+                    gnutls_ext_parse_type_t parse_type,
+                    gnutls_ext_recv_func recv_func,
+                    gnutls_ext_send_func send_func)
+{
+  gnutls_extension_entry *p;
+
+  p = gnutls_realloc (extfunc, sizeof (*extfunc) * (extfunc_size + 1));
+  if (!p)
+    {
+      gnutls_assert ();
+      return GNUTLS_E_MEMORY_ERROR;
+    }
+  extfunc = p;
+
+  extfunc[extfunc_size].type = type;
+  extfunc[extfunc_size].name = name;
+  extfunc[extfunc_size].parse_type = parse_type;
+  extfunc[extfunc_size].recv_func = recv_func;
+  extfunc[extfunc_size].send_func = send_func;
+
+  extfunc_size++;
+
+  return GNUTLS_E_SUCCESS;
+}
index c305846c14e77deed2e559c9b4044686823024b7..03e79881fcbd5cfcd3a4e3e6f7b3829cbaa7a54c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007 Free Software Foundation
+ * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008 Free Software Foundation
  *
  * Author: Nikos Mavrogiannopoulos
  *
  *
  */
 
-#include <gnutls_int.h>
-
-const char *_gnutls_extension_get_name (uint16_t type);
-int _gnutls_parse_extensions (gnutls_session_t, tls_ext_parse_type_t, const opaque *, int);
+int _gnutls_parse_extensions (gnutls_session_t session,
+                             gnutls_ext_parse_type_t parse_type,
+                             const opaque *data, int data_size);
 int _gnutls_gen_extensions (gnutls_session_t session, opaque * data,
                            size_t data_size);
-
-typedef int (*ext_recv_func) (gnutls_session_t, const opaque *, size_t);       /* recv data */
-typedef int (*ext_send_func) (gnutls_session_t, opaque *, size_t);     /* send data */
-
-ext_send_func _gnutls_ext_func_send (uint16_t type);
-ext_recv_func _gnutls_ext_func_recv (uint16_t type, tls_ext_parse_type_t);
-
-typedef struct
-{
-  const char *name;
-  uint16_t type;
-  tls_ext_parse_type_t parse_type;
-  ext_recv_func gnutls_ext_func_recv;
-  ext_send_func gnutls_ext_func_send;
-} gnutls_extension_entry;
+int _gnutls_ext_init (void);
index 17d5ab6a7249246191c26e2c621e5442aab099f6..ad0dde6c624d4826738c367dd2c9f194f82245ea 100644 (file)
@@ -29,6 +29,8 @@
 #include <random.h>
 #include <gcrypt.h>
 
+#include <gnutls_extensions.h> /* for _gnutls_ext_init */
+
 #ifdef HAVE_WINSOCK
 # include <winsock2.h>
 #endif
@@ -303,6 +305,14 @@ gnutls_global_init (void)
       goto out;
     }
 
+  /* Initialize the default TLS extensions */
+  result = _gnutls_ext_init ();
+  if (result < 0)
+    {
+      gnutls_assert ();
+      goto out;
+    }
+
 out:
   return result;
 }
index 3375fe445f75cb44ed9f9c5524c4ee4253e0c081..29fa071dcb1efa6a97ab326c61b5dec67ddc4480 100644 (file)
@@ -440,7 +440,9 @@ _gnutls_read_client_hello (gnutls_session_t session, opaque * data,
    */
   if (neg_version >= GNUTLS_TLS1)
     {
-      ret = _gnutls_parse_extensions (session, EXTENSION_APPLICATION, &data[pos], len);        /* len is the rest of the parsed length */
+      ret = _gnutls_parse_extensions (session, GNUTLS_EXT_APPLICATION,
+                                     &data[pos], len);
+      /* len is the rest of the parsed length */
       if (ret < 0)
        {
          gnutls_assert ();
@@ -457,7 +459,9 @@ _gnutls_read_client_hello (gnutls_session_t session, opaque * data,
 
   if (neg_version >= GNUTLS_TLS1)
     {
-      ret = _gnutls_parse_extensions (session, EXTENSION_TLS, &data[pos], len);        /* len is the rest of the parsed length */
+      ret = _gnutls_parse_extensions (session, GNUTLS_EXT_TLS,
+                                     &data[pos], len);
+      /* len is the rest of the parsed length */
       if (ret < 0)
        {
          gnutls_assert ();
@@ -1559,7 +1563,9 @@ _gnutls_read_server_hello (gnutls_session_t session,
    */
   if (version >= GNUTLS_TLS1)
     {
-      ret = _gnutls_parse_extensions (session, EXTENSION_ANY, &data[pos], len);        /* len is the rest of the parsed length */
+      ret = _gnutls_parse_extensions (session, GNUTLS_EXT_ANY,
+                                     &data[pos], len);
+      /* len is the rest of the parsed length */
       if (ret < 0)
        {
          gnutls_assert ();
index eb392e77def7c6f0e0a54bcd18fa27b98c67430e..87d1debe6aab5ba739a78b82cbc16f64a4c42e65 100644 (file)
@@ -282,18 +282,6 @@ typedef struct
   uint16_t oprfi_server_len;
 } tls_ext_st;
 
-/* This flag indicates for an extension whether
- * it is useful to application level or TLS level only.
- * This is used to parse the application level extensions
- * before the user_hello callback is called.
- */
-typedef enum tls_ext_parse_type_t
-{
-  EXTENSION_ANY,
-  EXTENSION_APPLICATION,
-  EXTENSION_TLS
-} tls_ext_parse_type_t;
-
 /* auth_info_t structures now MAY contain malloced 
  * elements.
  */