From: Nikos Mavrogiannopoulos Date: Fri, 19 Aug 2011 11:53:12 +0000 (+0200) Subject: Removed the limitation of one name per certificate. X-Git-Tag: gnutls_3_0_1~4^2~5 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=a2ab2dd8f15ff20bf6c047a8f65c07371cdea410;p=thirdparty%2Fgnutls.git Removed the limitation of one name per certificate. --- diff --git a/NEWS b/NEWS index f11ca36762..330f031ffb 100644 --- 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. diff --git a/lib/Makefile.am b/lib/Makefile.am index a6879c2655..f03274e503 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -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\ diff --git a/lib/auth/cert.c b/lib/auth/cert.c index 6aa37b91eb..e69279793b 100644 --- a/lib/auth/cert.c +++ b/lib/auth/cert.c @@ -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 = diff --git a/lib/auth/cert.h b/lib/auth/cert.h index 5b0d15f487..176d214999 100644 --- a/lib/auth/cert.h +++ b/lib/auth/cert.h @@ -28,11 +28,12 @@ #include "openpgp/openpgp_int.h" #include #include +#include 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); diff --git a/lib/gnutls_cert.c b/lib/gnutls_cert.c index c5a872ffe3..e72a662e43 100644 --- a/lib/gnutls_cert.c +++ b/lib/gnutls_cert.c @@ -37,6 +37,7 @@ #include #include #include +#include #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 index 0000000000..7cc1ec26aa --- /dev/null +++ b/lib/gnutls_str_array.h @@ -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 + * + */ + +#ifndef GNUTLS_STR_ARRAY_H +#define GNUTLS_STR_ARRAY_H + +#include + +/* 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 diff --git a/lib/gnutls_x509.c b/lib/gnutls_x509.c index 774454a446..96d280d4b9 100644 --- a/lib/gnutls_x509.c +++ b/lib/gnutls_x509.c @@ -41,6 +41,7 @@ #include #include "x509/common.h" #include "x509/x509_int.h" +#include #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;icerts[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; } /** diff --git a/lib/openpgp/gnutls_openpgp.c b/lib/openpgp/gnutls_openpgp.c index 9696e67d6d..2d2afd5e10 100644 --- a/lib/openpgp/gnutls_openpgp.c +++ b/lib/openpgp/gnutls_openpgp.c @@ -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; } /*-