]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
Removed the limitation of one name per certificate.
authorNikos Mavrogiannopoulos <nmav@gnutls.org>
Fri, 19 Aug 2011 11:53:12 +0000 (13:53 +0200)
committerNikos Mavrogiannopoulos <nmav@gnutls.org>
Fri, 19 Aug 2011 11:53:12 +0000 (13:53 +0200)
NEWS
lib/Makefile.am
lib/auth/cert.c
lib/auth/cert.h
lib/gnutls_cert.c
lib/gnutls_str_array.h [new file with mode: 0644]
lib/gnutls_x509.c
lib/openpgp/gnutls_openpgp.c

diff --git a/NEWS b/NEWS
index f11ca36762e04f69591c8cebf8124d3cd6e8b3d1..330f031ffbbd5eba53d20a62d1ba72e0b1f36f4a 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -7,8 +7,7 @@ See the end for copying conditions.
 ** libgnutls: gnutls_certificate_set_x509_key_file() and 
 friends support server name indication. If multiple 
 certificates are set using these functions the proper one 
-will be selected during a handshake, with the limitation 
-of a single name per certificate.
+will be selected during a handshake. 
 
 ** libgnutls: Added AES-256-GCM which was left out from
 the previous release. Reported by Benjamin Hof.
index a6879c2655005dc2b5171a65f5d4a653a147ecda..f03274e5039a8947d1f3ccabf4a5f0a0fb0388e9 100644 (file)
@@ -89,7 +89,7 @@ HFILES = abstract_int.h debug.h gnutls_compress.h gnutls_cipher.h     \
        x509_b64.h gnutls_v2_compat.h gnutls_datum.h \
        gnutls_mpi.h gnutls_pk.h gnutls_record.h                \
        gnutls_constate.h gnutls_global.h gnutls_sig.h gnutls_mem.h     \
-       gnutls_session_pack.h gnutls_str.h              \
+       gnutls_session_pack.h gnutls_str.h gnutls_str_arrary.h          \
        gnutls_state.h gnutls_x509.h crypto-backend.h                   \
        gnutls_rsa_export.h gnutls_srp.h auth/srp.h auth/srp_passwd.h   \
        gnutls_helper.h gnutls_supplemental.h crypto.h random.h system.h\
index 6aa37b91eb2234e6fc3036ae9e497fbfb3f586ae..e69279793b66e5705b655004c280d97a144af6ed 100644 (file)
@@ -2146,8 +2146,7 @@ _gnutls_server_select_cert (gnutls_session_t session,
     {
       for (i = 0; i < cred->ncerts; i++)
         {
-fprintf(stderr, "\n*** name[i]: %s, req: %s\n\n", cred->certs[i].name, server_name);
-          if (cred->certs[i].name != NULL && strcasecmp(cred->certs[i].name, server_name) == 0)
+          if (cred->certs[i].names != NULL && _gnutls_str_array_match(cred->certs[i].names, server_name) != 0)
             {
               /* if requested algorithms are also compatible select it */
               gnutls_pk_algorithm pk =
index 5b0d15f487313b6fd549ec34351929a60c1f1bf6..176d2149997ff4b042c07322c102a3b326ffa2ba 100644 (file)
 #include "openpgp/openpgp_int.h"
 #include <gnutls/abstract.h>
 #include <gnutls/compat.h>
+#include <gnutls_str_array.h>
 
 typedef struct {
   gnutls_pcert_st * cert_list; /* a certificate chain */
   unsigned int cert_list_length; /* its length */
-  char* name; /* the name of the first certificate - only 1 allowed*/
+  gnutls_str_array_t names; /* the names in the first certificate */
 } certs_st;
 
 /* This structure may be complex, but it's the only way to
@@ -153,7 +154,8 @@ int _gnutls_get_auth_info_pcert (gnutls_pcert_st* gcert,
                                  cert_auth_info_t info);
 
 int certificate_credential_append_crt_list (gnutls_certificate_credentials_t
-                                            res, const char* name, gnutls_pcert_st* crt, int nr);
+                                            res, gnutls_str_array_t names, 
+                                            gnutls_pcert_st* crt, int nr);
 int certificate_credentials_append_pkey (gnutls_certificate_credentials_t res,
                                          gnutls_privkey_t pkey);
 
index c5a872ffe3c17f32d80a6de65c89d5249f3f27af..e72a662e43f504c212b6e166c8907e61b7e61504 100644 (file)
@@ -37,6 +37,7 @@
 #include <gnutls_state.h>
 #include <gnutls_auth.h>
 #include <gnutls_x509.h>
+#include <gnutls_str_array.h>
 #include "x509/x509_int.h"
 #ifdef ENABLE_OPENPGP
 #include "openpgp/gnutls_openpgp.h"
@@ -63,7 +64,7 @@ gnutls_certificate_free_keys (gnutls_certificate_credentials_t sc)
           gnutls_pcert_deinit (&sc->certs[i].cert_list[j]);
         }
       gnutls_free (sc->certs[i].cert_list);
-      gnutls_free (sc->certs[i].name);
+      _gnutls_str_array_clear (&sc->certs[i].names);
     }
 
   gnutls_free (sc->certs);
diff --git a/lib/gnutls_str_array.h b/lib/gnutls_str_array.h
new file mode 100644 (file)
index 0000000..7cc1ec2
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2011 Free Software Foundation, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS 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 3 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 program.  If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef GNUTLS_STR_ARRAY_H
+#define GNUTLS_STR_ARRAY_H
+
+#include <gnutls_int.h>
+
+/* Functionality to allow an array of strings. Strings
+ * are allowed to be added to the list and matched against it.
+ */
+
+typedef struct gnutls_str_array_st
+{
+  char* str;
+  int len;
+  struct gnutls_str_array_st* next;
+} *gnutls_str_array_t;
+
+inline static void _gnutls_str_array_init(gnutls_str_array_t* head)
+{
+  *head = NULL;
+}
+
+inline static void _gnutls_str_array_clear (gnutls_str_array_t *head)
+{
+  gnutls_str_array_t prev, array = *head;
+
+  while(array != NULL)
+    {
+      prev = array;
+      array = prev->next;
+      gnutls_free(prev);
+    }
+  *head = NULL;
+}
+
+inline static int _gnutls_str_array_match (gnutls_str_array_t head, const char* str)
+{
+  gnutls_str_array_t array = head;
+
+  while(array != NULL)
+    {
+      if (strcmp(array->str, str) == 0) return 1;
+      array = array->next;
+    }
+  
+  return 0;
+}
+
+inline static void append(gnutls_str_array_t array, const char* str, int len)
+{
+  array->str = ((uint8_t*)array) + sizeof(struct gnutls_str_array_st);
+  memcpy(array->str, str, len);
+  array->str[len] = 0;
+  array->len = len;
+  array->next = NULL;
+}
+
+inline static int _gnutls_str_array_append (gnutls_str_array_t* head, const char* str, int len)
+{
+  gnutls_str_array_t prev, array;
+  if (*head == NULL)
+    {
+      *head = gnutls_malloc(len + 1 + sizeof(struct gnutls_str_array_st));
+      if (*head == NULL)
+        return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+      
+      array = *head;
+      append(array, str, len);
+    }
+  else
+    {
+      array = *head;
+      prev = array;
+      while(array != NULL)
+        {
+          prev = array;
+          array = prev->next;
+        }
+      prev->next = gnutls_malloc(len + 1 + sizeof(struct gnutls_str_array_st));
+      
+      array = prev->next;
+      
+      if (array == NULL)
+        return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+      
+      append(array, str, len);
+    }
+  
+  return 0;
+}
+
+#endif
index 774454a4461c184e19b64b623ba014c8eaf8f968..96d280d4b986116b91308999e67ecf1f9baac594 100644 (file)
@@ -41,6 +41,7 @@
 #include <gnutls_x509.h>
 #include "x509/common.h"
 #include "x509/x509_int.h"
+#include <gnutls_str_array.h>
 #include "read-file.h"
 
 /*
@@ -210,38 +211,53 @@ _gnutls_check_key_cert_match (gnutls_certificate_credentials_t res)
 
 /* Returns the name of the certificate of a null name
  */
-static void get_x509_name(gnutls_x509_crt_t crt, char* name, size_t max_name_size)
+static int get_x509_name(gnutls_x509_crt_t crt, gnutls_str_array_t *names)
 {
 size_t max_size;
-int i, ret = 0;
-
-  name[0] = 0;
+int i, ret = 0, ret2;
+char name[MAX_CN];
 
   for (i = 0; !(ret < 0); i++)
     {
-      max_size = max_name_size;
+      max_size = sizeof(name);
 
-      ret = gnutls_x509_crt_get_subject_alt_name(crt, 0, name, &max_size, NULL);
+      ret = gnutls_x509_crt_get_subject_alt_name(crt, i, name, &max_size, NULL);
       if (ret == GNUTLS_SAN_DNSNAME)
-        return;
+        {
+          ret2 = _gnutls_str_array_append(names, name, max_size);
+          if (ret2 < 0)
+            {
+              _gnutls_str_array_clear(names);
+              return gnutls_assert_val(ret2);
+            }
+        }
     }
     
-  max_size = max_name_size;
-  gnutls_x509_crt_get_dn_by_oid (crt, OID_X520_COMMON_NAME, 0, 0, name, &max_size);
+  max_size = sizeof(name);
+  ret = gnutls_x509_crt_get_dn_by_oid (crt, OID_X520_COMMON_NAME, 0, 0, name, &max_size);
+  if (ret >= 0)
+    {
+      ret = _gnutls_str_array_append(names, name, max_size);
+      if (ret < 0)
+        {
+          _gnutls_str_array_clear(names);
+          return gnutls_assert_val(ret);
+        }
+    }
+  
+  return 0;
 }
 
-static void get_x509_name_raw(gnutls_datum_t *raw, gnutls_x509_crt_fmt_t type, char* name, size_t max_name_size)
+static int get_x509_name_raw(gnutls_datum_t *raw, gnutls_x509_crt_fmt_t type, gnutls_str_array_t *names)
 {
 int ret;
 gnutls_x509_crt_t crt;
 
-  name[0] = 0;
-
   ret = gnutls_x509_crt_init (&crt);
   if (ret < 0)
     {
       gnutls_assert ();
-      return;
+      return ret;
     }
 
   ret = gnutls_x509_crt_import (crt, raw, type);
@@ -249,12 +265,12 @@ gnutls_x509_crt_t crt;
     {
       gnutls_assert ();
       gnutls_x509_crt_deinit (crt);
-      return;
+      return ret;
     }
 
-  get_x509_name(crt, name, max_name_size);
+  ret = get_x509_name(crt, names);
   gnutls_x509_crt_deinit (crt);
-  return;
+  return ret;
 }
 
 /* Reads a DER encoded certificate list from memory and stores it to a
@@ -268,7 +284,9 @@ parse_der_cert_mem (gnutls_certificate_credentials_t res,
   gnutls_x509_crt_t crt;
   gnutls_pcert_st *ccert;
   int ret;
-  char name[MAX_CN];
+  gnutls_str_array_t names;
+  
+  _gnutls_str_array_init(&names);
 
   ccert = gnutls_malloc (sizeof (*ccert));
   if (ccert == NULL)
@@ -295,7 +313,13 @@ parse_der_cert_mem (gnutls_certificate_credentials_t res,
       goto cleanup;
     }
 
-  get_x509_name(crt, name, sizeof(name));
+  ret = get_x509_name(crt, &names);
+  if (ret < 0)
+    {
+      gnutls_assert();
+      gnutls_x509_crt_deinit (crt);
+      goto cleanup;
+    }
 
   ret = gnutls_pcert_import_x509 (ccert, crt, 0);
   gnutls_x509_crt_deinit (crt);
@@ -306,7 +330,7 @@ parse_der_cert_mem (gnutls_certificate_credentials_t res,
       goto cleanup;
     }
 
-  ret = certificate_credential_append_crt_list (res, name, ccert, 1);
+  ret = certificate_credential_append_crt_list (res, names, ccert, 1);
   if (ret < 0)
     {
       gnutls_assert ();
@@ -316,6 +340,7 @@ parse_der_cert_mem (gnutls_certificate_credentials_t res,
   return ret;
 
 cleanup:
+  _gnutls_str_array_clear(&names);
   gnutls_free (ccert);
   return ret;
 }
@@ -332,7 +357,9 @@ parse_pem_cert_mem (gnutls_certificate_credentials_t res,
   gnutls_datum_t tmp;
   int ret, count, i;
   gnutls_pcert_st *certs = NULL;
-  char name[MAX_CN];
+  gnutls_str_array_t names;
+
+  _gnutls_str_array_init(&names);
 
   /* move to the certificate
    */
@@ -365,7 +392,15 @@ parse_pem_cert_mem (gnutls_certificate_credentials_t res,
       tmp.data = (void*)ptr;
       tmp.size = size;
 
-      if (count == 0) get_x509_name_raw(&tmp, GNUTLS_X509_FMT_PEM, name, sizeof(name));
+      if (count == 0)
+        {
+          ret = get_x509_name_raw(&tmp, GNUTLS_X509_FMT_PEM, &names);
+          if (ret < 0)
+            {
+              gnutls_assert();
+              goto cleanup;
+            }
+        }
 
       ret = gnutls_pcert_import_x509_raw (&certs[count], &tmp, GNUTLS_X509_FMT_PEM, 0);
       if (ret < 0)
@@ -400,7 +435,7 @@ parse_pem_cert_mem (gnutls_certificate_credentials_t res,
     }
   while (ptr != NULL);
 
-  ret = certificate_credential_append_crt_list (res, name, certs, count);
+  ret = certificate_credential_append_crt_list (res, names, certs, count);
   if (ret < 0)
     {
       gnutls_assert ();
@@ -410,6 +445,7 @@ parse_pem_cert_mem (gnutls_certificate_credentials_t res,
   return count;
 
 cleanup:
+  _gnutls_str_array_clear(&names);
   for (i=0;i<count;i++)
     gnutls_pcert_deinit(&certs[i]);
   gnutls_free(certs);
@@ -675,7 +711,9 @@ read_cert_url (gnutls_certificate_credentials_t res, const char *url)
   int ret;
   gnutls_x509_crt_t crt;
   gnutls_pcert_st *ccert;
-  char name[MAX_CN];
+  gnutls_str_array_t names;
+  
+  _gnutls_str_array_init(&names);
 
   ccert = gnutls_malloc (sizeof (*ccert));
   if (ccert == NULL)
@@ -688,8 +726,7 @@ read_cert_url (gnutls_certificate_credentials_t res, const char *url)
   if (ret < 0)
     {
       gnutls_assert ();
-      gnutls_free (ccert);
-      return ret;
+      goto cleanup;
     }
 
   ret = gnutls_x509_crt_import_pkcs11_url (crt, url, 0);
@@ -701,12 +738,17 @@ read_cert_url (gnutls_certificate_credentials_t res, const char *url)
   if (ret < 0)
     {
       gnutls_assert ();
-      gnutls_free (ccert);
       gnutls_x509_crt_deinit (crt);
-      return ret;
+      goto cleanup;
     }
 
-  get_x509_name(crt, name, sizeof(name));
+  ret = get_x509_name(crt, &names);
+  if (ret < 0)
+    {
+      gnutls_assert ();
+      gnutls_x509_crt_deinit (crt);
+      goto cleanup;
+    }
 
   ret = gnutls_pcert_import_x509 (ccert, crt, 0);
   gnutls_x509_crt_deinit (crt);
@@ -714,20 +756,22 @@ read_cert_url (gnutls_certificate_credentials_t res, const char *url)
   if (ret < 0)
     {
       gnutls_assert ();
-      gnutls_free (ccert);
-      return ret;
+      goto cleanup;
     }
 
-  ret = certificate_credential_append_crt_list (res, name, ccert, 1);
+  ret = certificate_credential_append_crt_list (res, names, ccert, 1);
   if (ret < 0)
     {
       gnutls_assert ();
-      gnutls_free (ccert);
-      return ret;
+      goto cleanup;
     }
 
   return 0;
 
+cleanup:
+  _gnutls_str_array_clear(&names);
+  gnutls_free (ccert);
+  return ret;
 }
 
 #endif /* ENABLE_PKCS11 */
@@ -913,7 +957,7 @@ cleanup:
 
 int
 certificate_credential_append_crt_list (gnutls_certificate_credentials_t res,
-                                        const char* name, gnutls_pcert_st * crt, int nr)
+                                        gnutls_str_array_t names, gnutls_pcert_st * crt, int nr)
 {
 int ret;
 
@@ -932,10 +976,7 @@ int ret;
 
   res->certs[res->ncerts].cert_list = crt;
   res->certs[res->ncerts].cert_list_length = nr;
-  if (name[0] != 0)
-    res->certs[res->ncerts].name = gnutls_strdup(name);
-  else
-    res->certs[res->ncerts].name = NULL;
+  res->certs[res->ncerts].names = names;
 
   return 0;
 
@@ -987,7 +1028,9 @@ gnutls_certificate_set_x509_key (gnutls_certificate_credentials_t res,
   int ret, i;
   gnutls_privkey_t pkey;
   gnutls_pcert_st *pcerts = NULL;
-  char name[MAX_CN];
+  gnutls_str_array_t names;
+  
+  _gnutls_str_array_init(&names);
 
   /* this should be first
    */
@@ -1020,7 +1063,9 @@ gnutls_certificate_set_x509_key (gnutls_certificate_credentials_t res,
       return GNUTLS_E_MEMORY_ERROR;
     }
 
-  get_x509_name(cert_list[0], name, sizeof(name));
+  ret = get_x509_name(cert_list[0], &names);
+  if (ret < 0)
+    return gnutls_assert_val(ret);
 
   for (i = 0; i < cert_list_size; i++)
     {
@@ -1028,15 +1073,15 @@ gnutls_certificate_set_x509_key (gnutls_certificate_credentials_t res,
       if (ret < 0)
         {
           gnutls_assert ();
-          return ret;
+          goto cleanup;
         }
     }
 
-  ret = certificate_credential_append_crt_list (res, name, pcerts, cert_list_size);
+  ret = certificate_credential_append_crt_list (res, names, pcerts, cert_list_size);
   if (ret < 0)
     {
       gnutls_assert ();
-      return ret;
+      goto cleanup;
     }
 
   res->ncerts++;
@@ -1048,6 +1093,10 @@ gnutls_certificate_set_x509_key (gnutls_certificate_credentials_t res,
     }
 
   return 0;
+  
+cleanup:
+  _gnutls_str_array_clear(&names);
+  return ret;
 }
 
 /**
index 9696e67d6d86461c0c2cea256c53ebc8b49b3f0f..2d2afd5e103b04c7478e98db8ab02f05cc59475d 100644 (file)
@@ -87,12 +87,15 @@ gnutls_certificate_set_openpgp_key (gnutls_certificate_credentials_t res,
                                     gnutls_openpgp_crt_t crt,
                                     gnutls_openpgp_privkey_t pkey)
 {
-  int ret;
+  int ret, ret2, i;
   gnutls_privkey_t privkey;
-  gnutls_pcert_st *ccert;
+  gnutls_pcert_st *ccert = NULL;
   char name[MAX_CN];
-  size_t name_size = sizeof(name);
+  size_t max_size;
+  gnutls_str_array_t names;
 
+  _gnutls_str_array_init(&names);
+  
   /* this should be first */
 
   ret = gnutls_privkey_init (&privkey);
@@ -107,42 +110,50 @@ gnutls_certificate_set_openpgp_key (gnutls_certificate_credentials_t res,
                                    GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE);
   if (ret < 0)
     {
-      gnutls_privkey_deinit (privkey);
       gnutls_assert ();
-      return ret;
+      goto cleanup;
     }
 
-  ret = gnutls_openpgp_crt_get_name(crt, 0, name, &name_size);
-  if (ret < 0)
-    name[0] = 0;
-
   ccert = gnutls_calloc (1, sizeof (gnutls_pcert_st));
   if (ccert == NULL)
     {
       gnutls_assert ();
-      gnutls_privkey_deinit (privkey);
-      return GNUTLS_E_MEMORY_ERROR;
+      ret = GNUTLS_E_MEMORY_ERROR;
+      goto cleanup;
+    }
+
+  max_size = sizeof(name);
+  ret = 0;
+  for (i = 0; !(ret < 0); i++)
+    {
+      ret = gnutls_openpgp_crt_get_name(crt, i, name, &max_size);
+      if (ret >= 0)
+        {
+          ret2 = _gnutls_str_array_append(&names, name, max_size);
+          if (ret2 < 0)
+            {
+              gnutls_assert();
+              ret = ret2;
+              goto cleanup;
+            }
+        }
     }
 
   ret = gnutls_pcert_import_openpgp (ccert, crt, 0);
   if (ret < 0)
     {
       gnutls_assert ();
-      gnutls_free (ccert);
-      gnutls_privkey_deinit (privkey);
-      return ret;
+      goto cleanup;
     }
 
   ret = certificate_credentials_append_pkey (res, privkey);
   if (ret >= 0)
-    ret = certificate_credential_append_crt_list (res, name, ccert, 1);
+    ret = certificate_credential_append_crt_list (res, names, ccert, 1);
 
   if (ret < 0)
     {
       gnutls_assert ();
-      gnutls_free (ccert);
-      gnutls_privkey_deinit (privkey);
-      return ret;
+      goto cleanup;
     }
 
   res->ncerts++;
@@ -150,6 +161,12 @@ gnutls_certificate_set_openpgp_key (gnutls_certificate_credentials_t res,
   /* FIXME: Check if the keys match. */
 
   return 0;
+
+cleanup:
+  gnutls_privkey_deinit (privkey);
+  gnutls_free (ccert);
+  _gnutls_str_array_clear(&names);
+  return ret;
 }
 
 /*-