summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@redhat.com>2014-11-27 15:06:11 +0100
committerNikos Mavrogiannopoulos <nmav@redhat.com>2014-11-27 15:51:04 +0100
commit0349b3c4c2d33b13fc0757d363714214135c9eff (patch)
treeeb1cb14d7171fd5474c6ad0f246783900db233f8 /lib
parented3913fdbc8ffe3b552c0d0f593f17c4e1a273d5 (diff)
downloadgnutls-0349b3c4c2d33b13fc0757d363714214135c9eff.tar.gz
Added flag GNUTLS_X509_CRT_LIST_SORT for gnutls_x509_crt_list_import*
That also allows automatically sorting input chains to the gnutls_certificate_credentials_t structure.
Diffstat (limited to 'lib')
-rw-r--r--lib/gnutls_pcert.c56
-rw-r--r--lib/gnutls_x509.c123
-rw-r--r--lib/includes/gnutls/abstract.h4
-rw-r--r--lib/includes/gnutls/x509.h4
-rw-r--r--lib/libgnutls.map1
-rw-r--r--lib/x509/common.c70
-rw-r--r--lib/x509/common.h9
-rw-r--r--lib/x509/verify-high.c62
-rw-r--r--lib/x509/x509.c17
9 files changed, 216 insertions, 130 deletions
diff --git a/lib/gnutls_pcert.c b/lib/gnutls_pcert.c
index 1d81cbbedc..0ce2989831 100644
--- a/lib/gnutls_pcert.c
+++ b/lib/gnutls_pcert.c
@@ -23,6 +23,7 @@
#include <gnutls_int.h>
#include <gnutls_errors.h>
#include <auth/cert.h>
+#include <x509/common.h>
#include <gnutls_x509.h>
#include "x509/x509_int.h"
#ifdef ENABLE_OPENPGP
@@ -32,7 +33,7 @@
/**
* gnutls_pcert_import_x509:
* @pcert: The pcert structure
- * @crt: The raw certificate to be imported
+ * @crt: The certificate to be imported
* @flags: zero for now
*
* This convenience function will import the given certificate to a
@@ -85,6 +86,59 @@ int gnutls_pcert_import_x509(gnutls_pcert_st * pcert,
}
/**
+ * gnutls_pcert_import_x509_list:
+ * @pcert: The pcert structure
+ * @crt: The certificates to be imported
+ * @ncrt: The number of certificates
+ * @flags: zero or %GNUTLS_X509_CRT_LIST_SORT
+ *
+ * This convenience function will import the given certificate to a
+ * #gnutls_pcert_st structure. The structure must be deinitialized
+ * afterwards using gnutls_pcert_deinit();
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
+ * negative error value.
+ *
+ * Since: 3.4.0
+ **/
+int gnutls_pcert_import_x509_list(gnutls_pcert_st * pcert,
+ gnutls_x509_crt_t *crt, unsigned *ncrt,
+ unsigned int flags)
+{
+ int ret;
+ unsigned i;
+ unsigned current = 0;
+ gnutls_x509_crt_t sorted[DEFAULT_MAX_VERIFY_DEPTH];
+ gnutls_x509_crt_t *s;
+
+ s = crt;
+ if (flags & GNUTLS_X509_CRT_LIST_SORT && *ncrt > 1) {
+ s = _gnutls_sort_clist(sorted, crt, ncrt, NULL);
+ if (s == crt) {
+ gnutls_assert();
+ return GNUTLS_E_UNIMPLEMENTED_FEATURE;
+ }
+ }
+
+ for (i=0;i<*ncrt;i++) {
+ ret = gnutls_pcert_import_x509(&pcert[i], s[i], 0);
+ if (ret < 0) {
+ current = i;
+ goto cleanup;
+ }
+ }
+
+ return 0;
+
+ cleanup:
+ for (i=0;i<current;i++) {
+ gnutls_pcert_deinit(&pcert[i]);
+ }
+ return ret;
+
+}
+
+/**
* gnutls_pcert_list_import_x509_raw:
* @pcerts: The structures to store the parsed certificate. Must not be initialized.
* @pcert_max: Initially must hold the maximum number of certs. It will be updated with the number of certs available.
diff --git a/lib/gnutls_x509.c b/lib/gnutls_x509.c
index b2cf632493..c9b099b55c 100644
--- a/lib/gnutls_x509.c
+++ b/lib/gnutls_x509.c
@@ -355,31 +355,6 @@ static int get_x509_name(gnutls_x509_crt_t crt, gnutls_str_array_t * names)
return 0;
}
-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;
-
- ret = gnutls_x509_crt_init(&crt);
- if (ret < 0) {
- gnutls_assert();
- return ret;
- }
-
- ret = gnutls_x509_crt_import(crt, raw, type);
- if (ret < 0) {
- gnutls_assert();
- gnutls_x509_crt_deinit(crt);
- return ret;
- }
-
- ret = get_x509_name(crt, names);
- gnutls_x509_crt_deinit(crt);
- return ret;
-}
-
/* Reads a DER encoded certificate list from memory and stores it to a
* gnutls_cert structure. Returns the number of certificates parsed.
*/
@@ -457,8 +432,10 @@ parse_pem_cert_mem(gnutls_certificate_credentials_t res,
const char *ptr;
gnutls_datum_t tmp;
int ret, count, i;
- gnutls_pcert_st *certs = NULL;
+ unsigned ncerts = 0;
+ gnutls_pcert_st *pcerts = NULL;
gnutls_str_array_t names;
+ gnutls_x509_crt_t unsorted[DEFAULT_MAX_VERIFY_DEPTH];
_gnutls_str_array_init(&names);
@@ -479,37 +456,21 @@ parse_pem_cert_mem(gnutls_certificate_credentials_t res,
count = 0;
do {
- certs =
- gnutls_realloc_fast(certs,
- (count +
- 1) * sizeof(gnutls_pcert_st));
-
- if (certs == NULL) {
- gnutls_assert();
- ret = GNUTLS_E_MEMORY_ERROR;
- goto cleanup;
- }
-
tmp.data = (void *) ptr;
tmp.size = size;
- if (count == 0) {
- ret =
- get_x509_name_raw(&tmp, GNUTLS_X509_FMT_PEM,
- &names);
- if (ret < 0) {
- gnutls_assert();
- goto cleanup;
- }
+ ret = gnutls_x509_crt_init(&unsorted[count]);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
}
- ret =
- gnutls_pcert_import_x509_raw(&certs[count], &tmp,
- GNUTLS_X509_FMT_PEM, 0);
+ ret = gnutls_x509_crt_import(unsorted[count], &tmp, GNUTLS_X509_FMT_PEM);
if (ret < 0) {
gnutls_assert();
goto cleanup;
}
+ count++;
/* now we move ptr after the pem header
*/
@@ -532,27 +493,53 @@ parse_pem_cert_mem(gnutls_certificate_credentials_t res,
} else
ptr = NULL;
- count++;
+ }
+ while (ptr != NULL && count < DEFAULT_MAX_VERIFY_DEPTH);
+ ret =
+ get_x509_name(unsorted[0], &names);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ pcerts = gnutls_malloc(sizeof(gnutls_pcert_st) * count);
+ if (pcerts == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
}
- while (ptr != NULL);
+ ncerts = count;
ret =
- certificate_credential_append_crt_list(res, names, certs,
- count);
+ gnutls_pcert_import_x509_list(pcerts, unsorted, &ncerts, GNUTLS_X509_CRT_LIST_SORT);
if (ret < 0) {
+ gnutls_free(pcerts);
+ pcerts = NULL;
gnutls_assert();
goto cleanup;
}
- return count;
+ ret =
+ certificate_credential_append_crt_list(res, names, pcerts,
+ ncerts);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ for (i = 0; i < count; i++)
+ gnutls_x509_crt_deinit(unsorted[i]);
+
+ return ncerts;
cleanup:
_gnutls_str_array_clear(&names);
- if (certs) {
+ for (i = 0; i < count; i++)
+ gnutls_x509_crt_deinit(unsorted[i]);
+ if (pcerts) {
for (i = 0; i < count; i++)
- gnutls_pcert_deinit(&certs[i]);
- gnutls_free(certs);
+ gnutls_pcert_deinit(&pcerts[i]);
+ gnutls_free(pcerts);
}
return ret;
}
@@ -1080,7 +1067,7 @@ gnutls_certificate_set_x509_key(gnutls_certificate_credentials_t res,
int cert_list_size,
gnutls_x509_privkey_t key)
{
- int ret, i;
+ int ret;
gnutls_privkey_t pkey;
gnutls_pcert_st *pcerts = NULL;
gnutls_str_array_t names;
@@ -1121,16 +1108,17 @@ gnutls_certificate_set_x509_key(gnutls_certificate_credentials_t res,
}
ret = get_x509_name(cert_list[0], &names);
- if (ret < 0)
- return gnutls_assert_val(ret);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
- for (i = 0; i < cert_list_size; i++) {
- ret =
- gnutls_pcert_import_x509(&pcerts[i], cert_list[i], 0);
- if (ret < 0) {
- gnutls_assert();
- goto cleanup;
- }
+ ret =
+ gnutls_pcert_import_x509_list(pcerts, cert_list, (unsigned int*)&cert_list_size,
+ GNUTLS_X509_CRT_LIST_SORT);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
}
ret =
@@ -1145,12 +1133,13 @@ gnutls_certificate_set_x509_key(gnutls_certificate_credentials_t res,
if ((ret = _gnutls_check_key_cert_match(res)) < 0) {
gnutls_assert();
- return ret;
+ goto cleanup;
}
return 0;
cleanup:
+ gnutls_free(pcerts);
_gnutls_str_array_clear(&names);
return ret;
}
diff --git a/lib/includes/gnutls/abstract.h b/lib/includes/gnutls/abstract.h
index 5382336325..ab59e57aec 100644
--- a/lib/includes/gnutls/abstract.h
+++ b/lib/includes/gnutls/abstract.h
@@ -462,6 +462,10 @@ typedef struct gnutls_pcert_st {
int gnutls_pcert_import_x509(gnutls_pcert_st * pcert,
gnutls_x509_crt_t crt, unsigned int flags);
+int gnutls_pcert_import_x509_list(gnutls_pcert_st * pcert,
+ gnutls_x509_crt_t *crt, unsigned *ncrt,
+ unsigned int flags);
+
int gnutls_pcert_export_x509(gnutls_pcert_st * pcert,
gnutls_x509_crt_t * crt);
diff --git a/lib/includes/gnutls/x509.h b/lib/includes/gnutls/x509.h
index eb606c8615..87b948d588 100644
--- a/lib/includes/gnutls/x509.h
+++ b/lib/includes/gnutls/x509.h
@@ -112,12 +112,14 @@ extern "C" {
* @GNUTLS_X509_CRT_LIST_FAIL_IF_UNSORTED: Fail if the certificates
* in the buffer are not ordered starting from subject to issuer.
* The error code will be %GNUTLS_E_CERTIFICATE_LIST_UNSORTED.
+ * @GNUTLS_X509_CRT_LIST_SORT: Sort the certificate chain if unsorted.
*
* Enumeration of different certificate import flags.
*/
typedef enum gnutls_certificate_import_flags {
GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED = 1,
- GNUTLS_X509_CRT_LIST_FAIL_IF_UNSORTED = 2
+ GNUTLS_X509_CRT_LIST_FAIL_IF_UNSORTED = 1<<1,
+ GNUTLS_X509_CRT_LIST_SORT = 1<<2
} gnutls_certificate_import_flags;
int gnutls_x509_crt_init(gnutls_x509_crt_t * cert);
diff --git a/lib/libgnutls.map b/lib/libgnutls.map
index 2b0a32dd9a..7e91ad4ba6 100644
--- a/lib/libgnutls.map
+++ b/lib/libgnutls.map
@@ -1065,6 +1065,7 @@ GNUTLS_3_1_0 {
gnutls_system_key_delete;
gnutls_system_key_add_x509;
gnutls_register_custom_url;
+ gnutls_pcert_import_x509_list;
} GNUTLS_3_0_0;
GNUTLS_FIPS140 {
diff --git a/lib/x509/common.c b/lib/x509/common.c
index f85c6de85e..a34cdd5582 100644
--- a/lib/x509/common.c
+++ b/lib/x509/common.c
@@ -1978,3 +1978,73 @@ _gnutls_check_valid_key_id(gnutls_datum_t *key_id,
out:
return result;
}
+
+/* Takes a certificate list and orders it with subject, issuer order.
+ *
+ * *clist_size contains the size of the ordered list (which is always less or
+ * equal to the original).
+ * @func: the function to call to elements outside the sort.
+ *
+ * Returns the sorted list which may be the original clist.
+ */
+gnutls_x509_crt_t *_gnutls_sort_clist(gnutls_x509_crt_t
+ sorted[DEFAULT_MAX_VERIFY_DEPTH],
+ gnutls_x509_crt_t *clist,
+ unsigned int *clist_size,
+ gnutls_cert_vfunc func)
+{
+ int prev;
+ unsigned int j, i;
+ int issuer[DEFAULT_MAX_VERIFY_DEPTH]; /* contain the index of the issuers */
+
+ /* Do not bother sorting if too many certificates are given.
+ * Prevent any DoS attacks.
+ */
+ if (*clist_size > DEFAULT_MAX_VERIFY_DEPTH)
+ return clist;
+
+ for (i = 0; i < DEFAULT_MAX_VERIFY_DEPTH; i++)
+ issuer[i] = -1;
+
+ /* Find the issuer of each certificate and store it
+ * in issuer array.
+ */
+ for (i = 0; i < *clist_size; i++) {
+ for (j = 1; j < *clist_size; j++) {
+ if (i == j)
+ continue;
+
+ if (gnutls_x509_crt_check_issuer(clist[i],
+ clist[j]) != 0) {
+ issuer[i] = j;
+ break;
+ }
+ }
+ }
+
+ if (issuer[0] == -1) {
+ *clist_size = 1;
+ return clist;
+ }
+
+ prev = 0;
+ sorted[0] = clist[0];
+ for (i = 1; i < *clist_size; i++) {
+ prev = issuer[prev];
+ if (prev == -1) { /* no issuer */
+ *clist_size = i;
+ break;
+ }
+ sorted[i] = clist[prev];
+ }
+
+ if (func) {
+ for (i = 1; i < *clist_size; i++) {
+ if (issuer[i] == -1) {
+ func(clist[i]);
+ }
+ }
+ }
+
+ return sorted;
+}
diff --git a/lib/x509/common.h b/lib/x509/common.h
index d39a87c24f..f319b5be1e 100644
--- a/lib/x509/common.h
+++ b/lib/x509/common.h
@@ -231,4 +231,13 @@ int x509_raw_crt_to_raw_pubkey(const gnutls_datum_t * cert,
int x509_crt_to_raw_pubkey(gnutls_x509_crt_t crt,
gnutls_datum_t * rpubkey);
+
+typedef void (*gnutls_cert_vfunc)(gnutls_x509_crt_t);
+
+gnutls_x509_crt_t *_gnutls_sort_clist(gnutls_x509_crt_t
+ sorted[DEFAULT_MAX_VERIFY_DEPTH],
+ gnutls_x509_crt_t * clist,
+ unsigned int *clist_size,
+ gnutls_cert_vfunc func);
+
#endif
diff --git a/lib/x509/verify-high.c b/lib/x509/verify-high.c
index 98d5af18f5..b8e8be4606 100644
--- a/lib/x509/verify-high.c
+++ b/lib/x509/verify-high.c
@@ -790,66 +790,6 @@ static int shorten_clist(gnutls_x509_trust_list_t list,
return clist_size;
}
-/* Takes a certificate list and orders it with subject, issuer order.
- *
- * *clist_size contains the size of the ordered list (which is always less or
- * equal to the original).
- *
- * Returns the sorted list which may be the original clist.
- */
-static gnutls_x509_crt_t *sort_clist(gnutls_x509_crt_t
- sorted[DEFAULT_MAX_VERIFY_DEPTH],
- gnutls_x509_crt_t * clist,
- unsigned int *clist_size)
-{
- int prev;
- unsigned int j, i;
- int issuer[DEFAULT_MAX_VERIFY_DEPTH]; /* contain the index of the issuers */
-
- /* Do not bother sorting if too many certificates are given.
- * Prevent any DoS attacks.
- */
- if (*clist_size > DEFAULT_MAX_VERIFY_DEPTH)
- return clist;
-
- for (i = 0; i < DEFAULT_MAX_VERIFY_DEPTH; i++)
- issuer[i] = -1;
-
- /* Find the issuer of each certificate and store it
- * in issuer array.
- */
- for (i = 0; i < *clist_size; i++) {
- for (j = 1; j < *clist_size; j++) {
- if (i == j)
- continue;
-
- if (gnutls_x509_crt_check_issuer(clist[i],
- clist[j]) != 0) {
- issuer[i] = j;
- break;
- }
- }
- }
-
- if (issuer[0] == -1) {
- *clist_size = 1;
- return clist;
- }
-
- prev = 0;
- sorted[0] = clist[0];
- for (i = 1; i < *clist_size; i++) {
- prev = issuer[prev];
- if (prev == -1) { /* no issuer */
- *clist_size = i;
- break;
- }
- sorted[i] = clist[prev];
- }
-
- return sorted;
-}
-
static
int trust_list_get_issuer(gnutls_x509_trust_list_t list,
gnutls_x509_crt_t cert,
@@ -1163,7 +1103,7 @@ gnutls_x509_trust_list_verify_crt2(gnutls_x509_trust_list_t list,
}
if (!(flags & GNUTLS_VERIFY_DO_NOT_ALLOW_UNSORTED_CHAIN))
- cert_list = sort_clist(sorted, cert_list, &cert_list_size);
+ cert_list = _gnutls_sort_clist(sorted, cert_list, &cert_list_size, NULL);
cert_list_size = shorten_clist(list, cert_list, cert_list_size);
if (cert_list_size <= 0)
diff --git a/lib/x509/x509.c b/lib/x509/x509.c
index 5c8ee0fca0..d2b594876c 100644
--- a/lib/x509/x509.c
+++ b/lib/x509/x509.c
@@ -3445,6 +3445,23 @@ gnutls_x509_crt_list_import(gnutls_x509_crt_t * certs,
*cert_max = count;
+ if (flags & GNUTLS_X509_CRT_LIST_SORT && *cert_max > 1) {
+ gnutls_x509_crt_t sorted[DEFAULT_MAX_VERIFY_DEPTH];
+ gnutls_x509_crt_t *s;
+
+ s = _gnutls_sort_clist(sorted, certs, cert_max, gnutls_x509_crt_deinit);
+ if (s == certs) {
+ gnutls_assert();
+ ret = GNUTLS_E_UNIMPLEMENTED_FEATURE;
+ goto error;
+ }
+
+ count = *cert_max;
+ if (s == sorted) {
+ memcpy(certs, s, (*cert_max)*sizeof(gnutls_x509_crt_t));
+ }
+ }
+
if (flags & GNUTLS_X509_CRT_LIST_FAIL_IF_UNSORTED) {
ret = check_if_sorted(certs, *cert_max);
if (ret < 0) {