/** * gnutls_x509_trust_list_verify_crt: * @list: The structure of the list * @cert_list: is the certificate list to be verified * @cert_list_size: is the certificate list size * @flags: Flags that may be used to change the verification algorithm. Use OR of the gnutls_certificate_verify_flags enumerations. * @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 verify the given certificate and return * its status. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. * * Since: 3.0.0 **/ int gnutls_x509_trust_list_verify_crt(gnutls_x509_trust_list_t list, gnutls_x509_crt_t * cert_list, unsigned int cert_list_size, unsigned int flags, unsigned int *verify, gnutls_verify_output_function func) { gnutls_datum_t dn; int ret, i; uint32_t hash; if (cert_list == NULL || cert_list_size < 1) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); cert_list_size = shorten_clist(list, cert_list, cert_list_size); if (cert_list_size <= 0) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); ret = gnutls_x509_crt_get_raw_issuer_dn(cert_list[cert_list_size - 1], &dn); if (ret < 0) { gnutls_assert(); return ret; } hash = _gnutls_bhash(dn.data, dn.size, INIT_HASH); hash %= list->size; _gnutls_free_datum(&dn); *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; /* Check revocation of individual certificates. * start with the last one that we already have its hash */ ret = _gnutls_x509_crt_check_revocation(cert_list[cert_list_size - 1], list->node[hash].crls, list->node[hash].crl_size, func); if (ret == 1) { /* revoked */ *verify |= GNUTLS_CERT_REVOKED; *verify |= GNUTLS_CERT_INVALID; return 0; } for (i = 0; i < cert_list_size - 1; i++) { ret = gnutls_x509_crt_get_raw_issuer_dn(cert_list[i], &dn); if (ret < 0) { gnutls_assert(); return ret; } hash = _gnutls_bhash(dn.data, dn.size, INIT_HASH); hash %= list->size; _gnutls_free_datum(&dn); ret = _gnutls_x509_crt_check_revocation(cert_list[i], list->node[hash].crls, list->node[hash].crl_size, func); if (ret == 1) { /* revoked */ *verify |= GNUTLS_CERT_REVOKED; *verify |= GNUTLS_CERT_INVALID; return 0; } } return 0; }
/** * gnutls_x509_trust_list_verify_crt2: * @list: The structure of the list * @cert_list: is the certificate list to be verified * @cert_list_size: is the certificate list size * @data: an array of typed data * @elements: the number of data elements * @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 attempt to verify the given certificate and return * its status. The @voutput parameter will hold an OR'ed sequence of * %gnutls_certificate_status_t flags. When a chain of @cert_list_size with * more than one certificates is provided, the verification status will apply * to the first certificate in the chain that failed verification. The * verification process starts from the end of the chain (from CA to end * certificate). * * 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. * * The acceptable @data types are %GNUTLS_DT_DNS_HOSTNAME and %GNUTLS_DT_KEY_PURPOSE_OID. * The former accepts as data a null-terminated hostname, and the latter a null-terminated * object identifier (e.g., %GNUTLS_KP_TLS_WWW_SERVER). * If a DNS hostname is provided then this function will compare * the hostname in the certificate against the given. If names do not match the * %GNUTLS_CERT_UNEXPECTED_OWNER status flag will be set. In addition it * will consider certificates provided with gnutls_x509_trust_list_add_named_crt(). * * If a key purpose OID is provided and the end-certificate contains the extended key * usage PKIX extension, it will be required to match the provided OID * or be marked for any purpose, otherwise verification will fail with * %GNUTLS_CERT_PURPOSE_MISMATCH status. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. Note that verification failure will not result to an * error code, only @voutput will be updated. * * Since: 3.3.8 **/ int gnutls_x509_trust_list_verify_crt2(gnutls_x509_trust_list_t list, gnutls_x509_crt_t * cert_list, unsigned int cert_list_size, gnutls_typed_vdata_st *data, unsigned int elements, unsigned int flags, unsigned int *voutput, gnutls_verify_output_function func) { int ret; unsigned int i; uint32_t hash; gnutls_x509_crt_t sorted[DEFAULT_MAX_VERIFY_DEPTH]; const char *hostname = NULL, *purpose = NULL; unsigned hostname_size = 0; if (cert_list == NULL || cert_list_size < 1) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); for (i=0;i<elements;i++) { if (data[i].type == GNUTLS_DT_DNS_HOSTNAME) { hostname = (void*)data[i].data; if (data[i].size > 0) { hostname_size = data[i].size; } } else if (data[i].type == GNUTLS_DT_KEY_PURPOSE_OID) { purpose = (void*)data[i].data; } } if (hostname) { /* shortcut using the named certs - if any */ unsigned vtmp = 0; if (hostname_size == 0) hostname_size = strlen(hostname); ret = gnutls_x509_trust_list_verify_named_crt(list, cert_list[0], hostname, hostname_size, flags, &vtmp, func); if (ret == 0 && vtmp == 0) { *voutput = vtmp; return 0; } } if (!(flags & GNUTLS_VERIFY_DO_NOT_ALLOW_UNSORTED_CHAIN)) 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) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); hash = hash_pjw_bare(cert_list[cert_list_size - 1]->raw_issuer_dn. data, cert_list[cert_list_size - 1]->raw_issuer_dn.size); hash %= list->size; ret = check_if_in_blacklist(cert_list, cert_list_size, list->blacklisted, list->blacklisted_size); if (ret != 0) { *voutput = 0; *voutput |= GNUTLS_CERT_REVOKED; *voutput |= GNUTLS_CERT_INVALID; return 0; } *voutput = _gnutls_verify_crt_status(cert_list, cert_list_size, list->node[hash].trusted_cas, list-> node[hash].trusted_ca_size, flags, purpose, func); #define LAST_DN cert_list[cert_list_size-1]->raw_dn #define LAST_IDN cert_list[cert_list_size-1]->raw_issuer_dn if ((*voutput) & GNUTLS_CERT_SIGNER_NOT_FOUND && (LAST_DN.size != LAST_IDN.size || memcmp(LAST_DN.data, LAST_IDN.data, LAST_IDN.size) != 0)) { /* if we couldn't find the issuer, try to see if the last * certificate is in the trusted list and try to verify against * (if it is not self signed) */ hash = hash_pjw_bare(cert_list[cert_list_size - 1]->raw_dn. data, cert_list[cert_list_size - 1]->raw_dn.size); hash %= list->size; *voutput = _gnutls_verify_crt_status(cert_list, cert_list_size, list->node[hash].trusted_cas, list-> node[hash].trusted_ca_size, flags, purpose, func); } #ifdef ENABLE_PKCS11 if ((*voutput & GNUTLS_CERT_SIGNER_NOT_FOUND) && list->pkcs11_token) { /* use the token for verification */ *voutput = _gnutls_pkcs11_verify_crt_status(list->pkcs11_token, cert_list, cert_list_size, purpose, flags, func); if (*voutput != 0) { gnutls_assert(); } } #endif /* End-certificate, key purpose and hostname checks. */ if (purpose) { ret = _gnutls_check_key_purpose(cert_list[0], purpose, 0); if (ret != 1) { gnutls_assert(); *voutput |= GNUTLS_CERT_PURPOSE_MISMATCH|GNUTLS_CERT_INVALID; } } if (hostname) { ret = gnutls_x509_crt_check_hostname2(cert_list[0], hostname, flags); if (ret == 0) *voutput |= GNUTLS_CERT_UNEXPECTED_OWNER|GNUTLS_CERT_INVALID; } /* CRL checks follow */ if (*voutput != 0 || (flags & GNUTLS_VERIFY_DISABLE_CRL_CHECKS)) return 0; /* Check revocation of individual certificates. * start with the last one that we already have its hash */ ret = _gnutls_x509_crt_check_revocation(cert_list [cert_list_size - 1], list->node[hash].crls, list->node[hash].crl_size, func); if (ret == 1) { /* revoked */ *voutput |= GNUTLS_CERT_REVOKED; *voutput |= GNUTLS_CERT_INVALID; return 0; } for (i = 0; i < cert_list_size - 1; i++) { hash = hash_pjw_bare(cert_list[i]->raw_issuer_dn.data, cert_list[i]->raw_issuer_dn.size); hash %= list->size; ret = _gnutls_x509_crt_check_revocation(cert_list[i], list->node[hash]. crls, list->node[hash]. crl_size, func); if (ret < 0) { gnutls_assert(); } else if (ret == 1) { /* revoked */ *voutput |= GNUTLS_CERT_REVOKED; *voutput |= GNUTLS_CERT_INVALID; return 0; } } return 0; }