diff options
author | Nikos Mavrogiannopoulos <nmav@redhat.com> | 2014-01-02 12:50:13 +0100 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@redhat.com> | 2014-01-02 13:53:52 +0100 |
commit | f656e069183b51c72e458b6290c143f9c8d5704d (patch) | |
tree | 948a0d08d9080280cb3e7ea3c65837e42a4d7fa7 /lib/x509 | |
parent | f83c679f202b6c2c84c2dea2c79420e9bce54794 (diff) | |
download | gnutls-f656e069183b51c72e458b6290c143f9c8d5704d.tar.gz |
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.
Conflicts:
lib/x509/verify-high.c
Diffstat (limited to 'lib/x509')
-rw-r--r-- | lib/x509/verify-high.c | 52 | ||||
-rw-r--r-- | lib/x509/verify-high.h | 15 | ||||
-rw-r--r-- | lib/x509/verify-high2.c | 56 | ||||
-rw-r--r-- | lib/x509/verify.c | 74 | ||||
-rw-r--r-- | lib/x509/x509_int.h | 9 |
5 files changed, 130 insertions, 76 deletions
diff --git a/lib/x509/verify-high.c b/lib/x509/verify-high.c index f3b42c94dd..5297f0c05c 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 /** @@ -79,7 +71,9 @@ int gnutls_x509_trust_list_init(gnutls_x509_trust_list_t * list, unsigned int size) { - gnutls_x509_trust_list_t tmp = + gnutls_x509_trust_list_t tmp; + + tmp = gnutls_calloc(1, sizeof(struct gnutls_x509_trust_list_st)); if (!tmp) @@ -150,6 +144,7 @@ gnutls_x509_trust_list_deinit(gnutls_x509_trust_list_t list, } gnutls_free(list->node); + gnutls_free(list->pkcs11_token); gnutls_free(list); } @@ -211,13 +206,13 @@ int ret; gnutls_assert(); return NULL; } - + ret = _gnutls_x509_crt_cpy(dst, src); if (ret < 0) { gnutls_assert(); return NULL; } - + return dst; } @@ -273,7 +268,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. @@ -599,7 +594,7 @@ unsigned i, j; if (blacklist_size == 0) return 0; - + for (i=0;i<cert_list_size;i++) { for (j=0;j<blacklist_size;j++) { if (_gnutls_check_if_same_cert(cert_list[i], blacklist[j]) != 0) { @@ -667,12 +662,23 @@ gnutls_x509_trust_list_verify_crt(gnutls_x509_trust_list_t list, return 0; } - *verify = - _gnutls_x509_verify_certificate(cert_list, cert_list_size, - list->node[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; @@ -723,10 +729,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 @@ -158,56 +158,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) { gnutls_x509_crt_t *xcrt_list = NULL; @@ -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 f7390dcccc..b9facbe60e 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 8fa86e705c..b849f03a50 100644 --- a/lib/x509/x509_int.h +++ b/lib/x509/x509_int.h @@ -371,6 +371,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 |