From: Nikos Mavrogiannopoulos Date: Thu, 2 Jan 2014 11:50:13 +0000 (+0100) Subject: Updated PKCS #11 support for gnutls_x509_trust_list_add_trust_file(). X-Git-Tag: gnutls_3_3_0pre0~382 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=5a62c80de00658b76e3cdc038d0a09eec808ea7b;p=thirdparty%2Fgnutls.git Updated PKCS #11 support for gnutls_x509_trust_list_add_trust_file(). It will now use the PKCS #11 trust URL while verifying instead of importing all CAs. That way it allows verification on the spot without requiring the gnutls to restart in case of a blacklisted CA. --- diff --git a/configure.ac b/configure.ac index 225349f95b..bd17821de3 100644 --- a/configure.ac +++ b/configure.ac @@ -479,7 +479,7 @@ dnl auto detect http://lists.gnu.org/archive/html/help-gnutls/2012-05/msg00004.h AC_ARG_WITH([default-trust-store-file], [AS_HELP_STRING([--with-default-trust-store-file=FILE], [use the given file default trust store])], with_default_trust_store_file="$withval", - [if test "$build" = "$host";then + [if test "$build" = "$host" && test x$with_default_trust_store_pkcs11 = x;then for i in \ /etc/ssl/ca-bundle.pem \ /etc/ssl/certs/ca-certificates.crt \ @@ -487,7 +487,7 @@ AC_ARG_WITH([default-trust-store-file], /usr/local/share/certs/ca-root-nss.crt \ /etc/ssl/cert.pem do - if test -e $i; then + if test -e "$i"; then with_default_trust_store_file="$i" break fi @@ -803,7 +803,7 @@ AC_MSG_NOTICE([Optional libraries: AC_MSG_NOTICE([System files: - Trust store pkcs: $with_default_trust_store_pkcs11 + Trust store pkcs11: $with_default_trust_store_pkcs11 Trust store file: $with_default_trust_store_file Blacklist file: $with_default_blacklist_file CRL file: $with_default_crl_file diff --git a/lib/x509/verify-high.c b/lib/x509/verify-high.c index d8f8b667fa..646e8a59e9 100644 --- a/lib/x509/verify-high.c +++ b/lib/x509/verify-high.c @@ -53,14 +53,6 @@ struct node_st { }; -struct gnutls_x509_trust_list_st { - unsigned int size; - struct node_st *node; - - gnutls_x509_crt_t *blacklisted; - unsigned int blacklisted_size; -}; - #define DEFAULT_SIZE 127 /** @@ -80,9 +72,9 @@ gnutls_x509_trust_list_init(gnutls_x509_trust_list_t * list, unsigned int size) { gnutls_x509_trust_list_t tmp; - + FAIL_IF_LIB_ERROR; - + tmp = gnutls_calloc(1, sizeof(struct gnutls_x509_trust_list_st)); @@ -154,6 +146,7 @@ gnutls_x509_trust_list_deinit(gnutls_x509_trust_list_t list, } gnutls_free(list->node); + gnutls_free(list->pkcs11_token); gnutls_free(list); } @@ -215,13 +208,13 @@ int ret; gnutls_assert(); return NULL; } - + ret = _gnutls_x509_crt_cpy(dst, src); if (ret < 0) { gnutls_assert(); return NULL; } - + return dst; } @@ -277,7 +270,7 @@ gnutls_x509_trust_list_remove_cas(gnutls_x509_trust_list_t list, break; } } - + /* Add the CA (or plain) certificate to the black list as well. * This will prevent a subordinate CA from being valid, and * ensure that a server certificate will also get rejected. @@ -603,7 +596,7 @@ unsigned i, j; if (blacklist_size == 0) return 0; - + for (i=0;inode[hash].trusted_cas, - list-> - node[hash].trusted_ca_size, - flags, func); +#ifdef ENABLE_PKCS11 + if (list->pkcs11_token) { + /* use the token for verification */ + + *verify = _gnutls_pkcs11_verify_certificate(list->pkcs11_token, + cert_list, cert_list_size, + flags, func); + } else +#endif + { + *verify = + _gnutls_x509_verify_certificate(cert_list, cert_list_size, + list->node[hash].trusted_cas, + list-> + node[hash].trusted_ca_size, + flags, func); + } if (*verify != 0 || (flags & GNUTLS_VERIFY_DISABLE_CRL_CHECKS)) return 0; @@ -727,10 +731,10 @@ gnutls_x509_trust_list_verify_crt(gnutls_x509_trust_list_t list, * @verify: will hold the certificate verification output. * @func: If non-null will be called on each chain element verification with the output. * - * This function will try to find a certificate that is associated with the provided - * name --see gnutls_x509_trust_list_add_named_crt(). If a match is found the certificate is considered valid. In addition to that - * this function will also check CRLs. The @verify parameter will hold an OR'ed sequence of - * %gnutls_certificate_status_t flags. + * This function will try to find a certificate that is associated with the provided + * name --see gnutls_x509_trust_list_add_named_crt(). If a match is found the certificate is considered valid. + * In addition to that this function will also check CRLs. + * The @verify parameter will hold an OR'ed sequence of %gnutls_certificate_status_t flags. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. diff --git a/lib/x509/verify-high.h b/lib/x509/verify-high.h index ba45f6ee55..1b2303eb02 100644 --- a/lib/x509/verify-high.h +++ b/lib/x509/verify-high.h @@ -20,5 +20,20 @@ * */ +#ifndef VERIFY_HIGH_H +# define VERIFY_HIGH_H + +struct gnutls_x509_trust_list_st { + unsigned int size; + struct node_st *node; + + gnutls_x509_crt_t *blacklisted; + unsigned int blacklisted_size; + + char* pkcs11_token; +}; + int _gnutls_trustlist_inlist(gnutls_x509_trust_list_t list, gnutls_x509_crt_t cert); + +#endif diff --git a/lib/x509/verify-high2.c b/lib/x509/verify-high2.c index 1c3c365026..d810a59899 100644 --- a/lib/x509/verify-high2.c +++ b/lib/x509/verify-high2.c @@ -157,56 +157,6 @@ gnutls_x509_trust_list_remove_trust_mem(gnutls_x509_trust_list_t list, } #ifdef ENABLE_PKCS11 -static -int import_pkcs11_url(gnutls_x509_trust_list_t list, const char *ca_file, - unsigned int flags) -{ - gnutls_x509_crt_t *xcrt_list = NULL; - gnutls_pkcs11_obj_t *pcrt_list = NULL; - unsigned int pcrt_list_size = 0, i; - int ret; - - ret = - gnutls_pkcs11_obj_list_import_url2(&pcrt_list, &pcrt_list_size, - ca_file, - GNUTLS_PKCS11_OBJ_ATTR_CRT_TRUSTED_CA, - 0); - if (ret < 0) - return gnutls_assert_val(ret); - - if (pcrt_list_size == 0) { - ret = 0; - goto cleanup; - } - - xcrt_list = - gnutls_malloc(sizeof(gnutls_x509_crt_t) * pcrt_list_size); - if (xcrt_list == NULL) { - ret = GNUTLS_E_MEMORY_ERROR; - goto cleanup; - } - - ret = - gnutls_x509_crt_list_import_pkcs11(xcrt_list, pcrt_list_size, - pcrt_list, 0); - if (ret < 0) { - gnutls_assert(); - goto cleanup; - } - - ret = - gnutls_x509_trust_list_add_cas(list, xcrt_list, pcrt_list_size, - flags); - - cleanup: - for (i = 0; i < pcrt_list_size; i++) - gnutls_pkcs11_obj_deinit(pcrt_list[i]); - gnutls_free(pcrt_list); - gnutls_free(xcrt_list); - - return ret; -} - static int remove_pkcs11_url(gnutls_x509_trust_list_t list, const char *ca_file) { @@ -293,9 +243,9 @@ gnutls_x509_trust_list_add_trust_file(gnutls_x509_trust_list_t list, #ifdef ENABLE_PKCS11 if (strncmp(ca_file, "pkcs11:", 7) == 0) { - ret = import_pkcs11_url(list, ca_file, tl_flags); - if (ret < 0) - return gnutls_assert_val(ret); + list->pkcs11_token = strdup(ca_file); + + return 0; } else #endif { diff --git a/lib/x509/verify.c b/lib/x509/verify.c index 39bd1f432e..d6c2884a12 100644 --- a/lib/x509/verify.c +++ b/lib/x509/verify.c @@ -682,6 +682,80 @@ _gnutls_x509_verify_certificate(const gnutls_x509_crt_t * certificate_list, return 0; } +#ifdef ENABLE_PKCS11 +/* Verify X.509 certificate chain using a PKCS #11 token. + * + * Note that the return value is an OR of GNUTLS_CERT_* elements. + * + * This function verifies a X.509 certificate list. The certificate + * list should lead to a trusted certificate in order to be trusted. + */ +unsigned int +_gnutls_pkcs11_verify_certificate(const char* url, + const gnutls_x509_crt_t * certificate_list, + int clist_size, + unsigned int flags, + gnutls_verify_output_function func) +{ + int ret; + unsigned int status = 0; + gnutls_x509_crt_t issuer = NULL; + gnutls_datum_t raw_issuer = {NULL, 0}; + + if (clist_size > 1) { + /* Check if the last certificate in the path is self signed. + * In that case ignore it (a certificate is trusted only if it + * leads to a trusted party by us, not the server's). + * + * This prevents from verifying self signed certificates against + * themselves. This (although not bad) caused verification + * failures on some root self signed certificates that use the + * MD2 algorithm. + */ + if (gnutls_x509_crt_check_issuer + (certificate_list[clist_size - 1], + certificate_list[clist_size - 1]) != 0) { + clist_size--; + } + } + + ret = gnutls_pkcs11_get_raw_issuer(url, certificate_list[clist_size - 1], + &raw_issuer, GNUTLS_X509_FMT_DER, 0); + if (ret < 0) { + gnutls_assert(); + status |= GNUTLS_CERT_INVALID; + status |= GNUTLS_CERT_SIGNER_NOT_FOUND; + return status; + } + + ret = gnutls_x509_crt_init(&issuer); + if (ret < 0) { + gnutls_assert(); + status |= GNUTLS_CERT_INVALID; + status |= GNUTLS_CERT_SIGNER_NOT_FOUND; + goto cleanup; + } + + ret = gnutls_x509_crt_import(issuer, &raw_issuer, GNUTLS_X509_FMT_DER); + if (ret < 0) { + gnutls_assert(); + status |= GNUTLS_CERT_INVALID; + status |= GNUTLS_CERT_SIGNER_NOT_FOUND; + goto cleanup; + } + + status = _gnutls_x509_verify_certificate(certificate_list, clist_size, + &issuer, 1, flags, func); + +cleanup: + gnutls_free(raw_issuer.data); + if (issuer != NULL) + gnutls_x509_crt_deinit(issuer); + + return status; +} +#endif + /* This will return the appropriate hash to verify the given signature. * If signature is NULL it will return an (or the) appropriate hash for * the given parameters. diff --git a/lib/x509/x509_int.h b/lib/x509/x509_int.h index 9863e0b7fa..5615934ae6 100644 --- a/lib/x509/x509_int.h +++ b/lib/x509/x509_int.h @@ -378,6 +378,15 @@ _gnutls_x509_verify_certificate(const gnutls_x509_crt_t * certificate_list, unsigned int flags, gnutls_verify_output_function func); +#ifdef ENABLE_PKCS11 +unsigned int +_gnutls_pkcs11_verify_certificate(const char* url, + const gnutls_x509_crt_t * certificate_list, + int clist_size, + unsigned int flags, + gnutls_verify_output_function func); +#endif + int _gnutls_is_same_dn(gnutls_x509_crt_t cert1, gnutls_x509_crt_t cert2); int