From: Nikos Mavrogiannopoulos Date: Mon, 8 Sep 2014 14:07:40 +0000 (+0200) Subject: Added gnutls_x509_trust_list_verify_purpose_crt() X-Git-Tag: gnutls_3_4_0~961 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d1e67ccb4d5cccdd37eb9e17b861dd335560651f;p=thirdparty%2Fgnutls.git Added gnutls_x509_trust_list_verify_purpose_crt() --- diff --git a/lib/gnutls_x509.c b/lib/gnutls_x509.c index 442427116e..ebf019b029 100644 --- a/lib/gnutls_x509.c +++ b/lib/gnutls_x509.c @@ -289,9 +289,10 @@ _gnutls_x509_cert_verify_peers(gnutls_session_t session, /* Verify certificate */ ret = - gnutls_x509_trust_list_verify_crt(cred->tlist, + gnutls_x509_trust_list_verify_purpose_crt(cred->tlist, peer_certificate_list, peer_certificate_list_size, + purpose, verify_flags, status, NULL); if (ret < 0) { @@ -308,33 +309,6 @@ _gnutls_x509_cert_verify_peers(gnutls_session_t session, *status |= GNUTLS_CERT_UNEXPECTED_OWNER|GNUTLS_CERT_INVALID; } - if (purpose) { - char oid[MAX_OID_SIZE]; - size_t oid_size; - - for (i=0;;i++) { - oid_size = sizeof(oid); - ret = gnutls_x509_crt_get_key_purpose_oid(peer_certificate_list[0], - i, oid, &oid_size, NULL); - if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { - if (i==0) - break; - else { /* no acceptable purpose was found */ - gnutls_assert(); - *status |= GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE|GNUTLS_CERT_INVALID; - break; - } - } else if (ret < 0) { - gnutls_assert(); - *status |= GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE|GNUTLS_CERT_INVALID; - break; - } - - if (strcmp(oid, purpose) == 0 || strcmp(oid, GNUTLS_KP_ANY) == 0) - break; - } - } - CLEAR_CERTS; *status |= ocsp_status; diff --git a/lib/includes/gnutls/x509.h b/lib/includes/gnutls/x509.h index 04b4ca5ca7..162af447b3 100644 --- a/lib/includes/gnutls/x509.h +++ b/lib/includes/gnutls/x509.h @@ -1278,6 +1278,15 @@ int gnutls_x509_trust_list_verify_named_crt const void *name, size_t name_size, unsigned int flags, unsigned int *verify, gnutls_verify_output_function func); +int +gnutls_x509_trust_list_verify_purpose_crt(gnutls_x509_trust_list_t list, + gnutls_x509_crt_t * cert_list, + unsigned int cert_list_size, + const char *purpose, + unsigned int flags, + unsigned int *voutput, + gnutls_verify_output_function func); + int gnutls_x509_trust_list_verify_crt(gnutls_x509_trust_list_t list, gnutls_x509_crt_t * cert_list, diff --git a/lib/libgnutls.map b/lib/libgnutls.map index f43f1be461..5c6173fc46 100644 --- a/lib/libgnutls.map +++ b/lib/libgnutls.map @@ -1023,6 +1023,7 @@ GNUTLS_3_1_0 { gnutls_pkcs11_obj_get_flags; gnutls_pkcs12_mac_info; gnutls_pkcs12_generate_mac2; + gnutls_x509_trust_list_verify_purpose_crt; } GNUTLS_3_0_0; GNUTLS_FIPS140 { diff --git a/lib/x509/verify-high.c b/lib/x509/verify-high.c index f870e2d08c..f17a8559fc 100644 --- a/lib/x509/verify-high.c +++ b/lib/x509/verify-high.c @@ -31,6 +31,7 @@ #include #include "x509_int.h" #include +#include #include "verify-high.h" struct named_cert_st { @@ -753,6 +754,91 @@ gnutls_x509_trust_list_verify_crt(gnutls_x509_trust_list_t list, unsigned int flags, unsigned int *voutput, gnutls_verify_output_function func) +{ + return gnutls_x509_trust_list_verify_purpose_crt(list, cert_list, cert_list_size, + NULL, flags, voutput, func); +} + +static +int check_key_purpose(gnutls_x509_crt_t crt, const gnutls_datum_t *ext_data, unsigned *voutput, + const char *purpose) +{ + gnutls_datum_t coid = {NULL, 0}; + gnutls_x509_key_purposes_t p = NULL; + unsigned i; + int ret; + + ret = gnutls_x509_key_purpose_init(&p); + if (ret < 0) { + gnutls_assert(); + goto fail; + } + + ret = gnutls_x509_ext_import_key_purposes(ext_data, p, 0); + if (ret < 0) { + gnutls_assert(); + goto fail; + } + + for (i=0;;i++) { + ret = gnutls_x509_key_purpose_get(p, i, &coid); + if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { + if (i==0) { + break; + } else { /* no acceptable purpose was found */ + gnutls_assert(); + goto fail; + } + } else if (ret < 0) { + gnutls_assert(); + goto fail; + } + + if (strcmp((char*)coid.data, purpose) == 0 || strcmp((char*)coid.data, GNUTLS_KP_ANY) == 0) + break; + } + + gnutls_x509_key_purpose_deinit(p); + return 0; + fail: + *voutput |= GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE|GNUTLS_CERT_INVALID; + if (p != NULL) + gnutls_x509_key_purpose_deinit(p); + return ret; +} + +/** + * gnutls_x509_trust_list_verify_purpose_crt: + * @list: The structure of the list + * @cert_list: is the certificate list to be verified + * @cert_list_size: is the certificate list size + * @purpose: the purpose OID (GNUTLS_KP) for which the certificate must be valid (may be %NULL) + * @flags: Flags that may be used to change the verification algorithm. Use OR of the gnutls_certificate_verify_flags enumerations. + * @voutput: 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 verify the given certificate and return + * its status. The @verify parameter will hold an OR'ed sequence of + * %gnutls_certificate_status_t flags. + * + * Additionally a certificate verification profile can be specified + * from the ones in %gnutls_certificate_verification_profiles_t by + * ORing the result of GNUTLS_PROFILE_TO_VFLAGS() to the verification + * flags. + * + * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a + * negative error value. + * + * Since: 3.3.8 + **/ +int +gnutls_x509_trust_list_verify_purpose_crt(gnutls_x509_trust_list_t list, + gnutls_x509_crt_t * cert_list, + unsigned int cert_list_size, + const char *purpose, + unsigned int flags, + unsigned int *voutput, + gnutls_verify_output_function func) { int ret; unsigned int i; @@ -864,6 +950,25 @@ gnutls_x509_trust_list_verify_crt(gnutls_x509_trust_list_t list, } } + /* check the purpose if given */ + if (purpose) do { + gnutls_datum_t ext_data = {NULL, 0}; + + ret = gnutls_x509_crt_get_extension_by_oid2(cert_list[0], "2.5.29.37", 0, &ext_data, NULL); + if (ret < 0) { + gnutls_assert(); + break; + } + + ret = check_key_purpose(cert_list[0], &ext_data, voutput, purpose); + gnutls_free(ext_data.data); + + if (ret < 0) { + gnutls_assert(); + } + + } while(0); + return 0; }