summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@gnutls.org>2013-03-05 21:46:26 +0100
committerNikos Mavrogiannopoulos <nmav@gnutls.org>2013-03-05 21:46:26 +0100
commit92c2dcd836c0c1d32016243d1dd6d1a0df547094 (patch)
treecd8ec53fdfed16aa792fd270c66eee13795b73a4
parentecb901e2b8caea49ca6e835e23ea67a6b9f888b4 (diff)
downloadgnutls-92c2dcd836c0c1d32016243d1dd6d1a0df547094.tar.gz
correctly remove revoked certificates. That required quite some backports from the 3.1 branch.
-rw-r--r--lib/gnutls_x509.c109
-rw-r--r--lib/x509/verify-high.c38
-rw-r--r--lib/x509/verify-high.h4
3 files changed, 138 insertions, 13 deletions
diff --git a/lib/gnutls_x509.c b/lib/gnutls_x509.c
index 5bc343ffd6..b81486e424 100644
--- a/lib/gnutls_x509.c
+++ b/lib/gnutls_x509.c
@@ -39,6 +39,7 @@
#include <x509_b64.h>
#include <gnutls_x509.h>
#include "x509/common.h"
+#include "x509/verify-high.h"
#include "x509/x509_int.h"
#include <gnutls_str_array.h>
#include "read-file.h"
@@ -1643,8 +1644,10 @@ unsigned int i;
#elif defined(ANDROID) || defined(__ANDROID__)
# include <dirent.h>
# include <unistd.h>
+# include "read-file.h"
+
static int load_dir_certs(const char* dirname, gnutls_certificate_credentials_t cred,
- unsigned type, unsigned check_revoked)
+ unsigned type)
{
DIR * dirp;
struct dirent *d;
@@ -1659,16 +1662,6 @@ char path[512];
{
d = readdir(dirp);
if (d != NULL && d->d_type == DT_REG) {
-
- if (check_revoked)
- {
- snprintf(path, sizeof(path),
- "/data/misc/keychain/cacerts-removed/%s", d->d_name);
- if (access(path, R_OK) == 0)
- /* revoked -> do not add */
- continue;
- }
-
snprintf(path, sizeof(path), "%s/%s", dirname, d->d_name);
ret = gnutls_certificate_set_x509_trust_file (cred, path, type);
if (ret >= 0)
@@ -1682,6 +1675,92 @@ char path[512];
return r;
}
+static int
+gnutls_x509_trust_list_remove_trust_mem(gnutls_x509_trust_list_t list,
+ const gnutls_datum_t * cas,
+ gnutls_x509_crt_fmt_t type)
+{
+ int ret;
+ gnutls_x509_crt_t *x509_ca_list = NULL;
+ unsigned int x509_ncas;
+ unsigned int r = 0, i;
+
+ if (cas != NULL && cas->data != NULL)
+ {
+ ret = gnutls_x509_crt_list_import2( &x509_ca_list, &x509_ncas, cas, type, 0);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ ret = gnutls_x509_trust_list_remove_cas(list, x509_ca_list, x509_ncas);
+
+ for (i=0;i<x509_ncas;i++)
+ gnutls_x509_crt_deinit(x509_ca_list[i]);
+ gnutls_free(x509_ca_list);
+
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+ else
+ r += ret;
+ }
+
+ return r;
+}
+
+static int
+gnutls_x509_trust_list_remove_trust_file(gnutls_x509_trust_list_t list,
+ const char* ca_file,
+ gnutls_x509_crt_fmt_t type)
+{
+ gnutls_datum_t cas = { NULL, 0 };
+ size_t size;
+ int ret;
+
+ {
+ cas.data = (void*)read_binary_file (ca_file, &size);
+ if (cas.data == NULL)
+ {
+ gnutls_assert ();
+ return GNUTLS_E_FILE_ERROR;
+ }
+ cas.size = size;
+ }
+
+ ret = gnutls_x509_trust_list_remove_trust_mem(list, &cas, type);
+ free(cas.data);
+
+ return ret;
+}
+
+static int load_revoked_certs(gnutls_x509_trust_list_t list, unsigned type)
+{
+DIR * dirp;
+struct dirent *d;
+int ret;
+int r = 0;
+char path[512];
+
+ dirp = opendir("/data/misc/keychain/cacerts-removed/");
+ if (dirp != NULL)
+ {
+ do
+ {
+ d = readdir(dirp);
+ if (d != NULL && d->d_type == DT_REG)
+ {
+ snprintf(path, sizeof(path), "/data/misc/keychain/cacerts-removed/%s", d->d_name);
+
+ ret = gnutls_x509_trust_list_remove_trust_file(list, path, type);
+ if (ret >= 0)
+ r += ret;
+ }
+ }
+ while(d != NULL);
+ closedir(dirp);
+ }
+
+ return r;
+}
+
/* This works on android 4.x
*/
static int
@@ -1689,13 +1768,17 @@ set_x509_system_trust_file (gnutls_certificate_credentials_t cred)
{
int r = 0, ret;
- ret = load_dir_certs("/system/etc/security/cacerts/", cred, GNUTLS_X509_FMT_PEM, 1);
+ ret = load_dir_certs("/system/etc/security/cacerts/", cred, GNUTLS_X509_FMT_PEM);
if (ret >= 0)
r += ret;
- ret = load_dir_certs("/data/misc/keychain/cacerts-added/", cred, GNUTLS_X509_FMT_DER, 0);
+ ret = load_dir_certs("/data/misc/keychain/cacerts-added/", cred, GNUTLS_X509_FMT_DER);
if (ret >= 0)
r += ret;
+
+ ret = load_revoked_certs(cred->tlist, GNUTLS_X509_FMT_DER);
+ if (ret >= 0)
+ r -= ret;
return r;
}
diff --git a/lib/x509/verify-high.c b/lib/x509/verify-high.c
index 88407b9ad5..6523f4c19c 100644
--- a/lib/x509/verify-high.c
+++ b/lib/x509/verify-high.c
@@ -188,6 +188,44 @@ gnutls_x509_trust_list_add_cas(gnutls_x509_trust_list_t list,
return i;
}
+int
+gnutls_x509_trust_list_remove_cas(gnutls_x509_trust_list_t list,
+ const gnutls_x509_crt_t * clist,
+ int clist_size)
+{
+ int i, r = 0, ret;
+ unsigned j;
+ uint32_t hash;
+ gnutls_datum_t dn;
+
+ for (i = 0; i < clist_size; i++)
+ {
+ ret = gnutls_x509_crt_get_raw_dn(clist[i], &dn);
+ if (ret < 0) {
+ gnutls_assert();
+ return i;
+ }
+
+ hash = _gnutls_bhash(dn.data, dn.size, INIT_HASH);
+ hash %= list->size;
+
+ _gnutls_free_datum(&dn);
+
+ for (j=0;j<list->node[hash].trusted_ca_size;j++)
+ {
+ if (check_if_same_cert(clist[i], list->node[hash].trusted_cas[j]) == 0)
+ {
+ list->node[hash].trusted_cas[j] =
+ list->node[hash].trusted_cas[list->node[hash].trusted_ca_size-1];
+ list->node[hash].trusted_ca_size--;
+ r++;
+ }
+ }
+ }
+
+ return r;
+}
+
/**
* gnutls_x509_trust_list_add_named_crt:
* @list: The structure of the list
diff --git a/lib/x509/verify-high.h b/lib/x509/verify-high.h
index 67d96c5113..2e9027c594 100644
--- a/lib/x509/verify-high.h
+++ b/lib/x509/verify-high.h
@@ -22,3 +22,7 @@
int _gnutls_trustlist_inlist (gnutls_x509_trust_list_t list,
gnutls_x509_crt_t cert);
+int
+gnutls_x509_trust_list_remove_cas(gnutls_x509_trust_list_t list,
+ const gnutls_x509_crt_t * clist,
+ int clist_size);