int _gnutls_trustlist_inlist_p (gnutls_x509_trust_list_t list, gnutls_x509_crt_t cert) { gnutls_datum_t dn; int ret, i; uint32_t hash; ret = gnutls_x509_crt_get_raw_dn (cert, &dn); if (ret < 0) { gnutls_assert(); return ret; } hash = _gnutls_bhash(dn.data, dn.size, INIT_HASH); hash %= list->size; _gnutls_free_datum (&dn); for (i = 0; i < list->node[hash].trusted_ca_size; i++) { ret = check_if_same_cert (cert, list->node[hash].trusted_cas[i]); if (ret < 0) { gnutls_assert (); return ret; } if (ret == 1) return 1; } return 0; }
/* Takes a certificate list and shortens it if there are * intermedia certificates already trusted by us. * * FIXME: This is very similar to _gnutls_x509_verify_certificate(). * * Returns the new size of the list or a negative number on error. */ static int shorten_clist(gnutls_x509_trust_list_t list, gnutls_x509_crt_t * certificate_list, int clist_size) { int i, ret; uint32_t hash; gnutls_datum_t dn; 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--; } } /* We want to shorten the chain by removing the cert that matches * one of the certs we trust and all the certs after that i.e. if * cert chain is A signed-by B signed-by C signed-by D (signed-by * self-signed E but already removed above), and we trust B, remove * B, C and D. */ for (i = 1; i < clist_size; i++) { int j; ret = gnutls_x509_crt_get_raw_issuer_dn(certificate_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); for (j = 0; j < list->node[hash].trusted_ca_size; j++) { if (check_if_same_cert (certificate_list[i], list->node[hash].trusted_cas[j]) == 0) { /* cut the list at the point of first the trusted certificate */ clist_size = i + 1; break; } } /* clist_size may have been changed which gets out of loop */ } return clist_size; }
/** * gnutls_x509_trust_list_verify_named_crt: * @list: The structure of the list * @cert: is the certificate to be verified * @name: is the certificate's name * @name_size: is the certificate's name 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 find a matching named certificate. If a * match is found the certificate is considered valid. In addition to that * this function will also check CRLs. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. * * Since: 3.0 **/ int gnutls_x509_trust_list_verify_named_crt(gnutls_x509_trust_list_t list, gnutls_x509_crt_t cert, const void *name, size_t name_size, unsigned int flags, unsigned int *verify, gnutls_verify_output_function func) { gnutls_datum_t dn; int ret; unsigned int i; uint32_t hash; ret = gnutls_x509_crt_get_raw_issuer_dn(cert, &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_CERT_INVALID; for (i = 0; i < list->node[hash].named_cert_size; i++) { if (check_if_same_cert(cert, list->node[hash].named_certs[i].cert) == 0) { /* check if name matches */ if (list->node[hash].named_certs[i].name_size == name_size && memcmp(list->node[hash].named_certs[i].name, name, name_size) == 0) { *verify = 0; break; } } } 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->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; }
/* Verify X.509 certificate chain. * * 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_x509_verify_certificate (const gnutls_x509_crt_t * certificate_list, int clist_size, const gnutls_x509_crt_t * trusted_cas, int tcas_size, unsigned int flags, gnutls_verify_output_function func) { int i = 0, ret; unsigned int status = 0, output; time_t now = gnutls_time (0); gnutls_x509_crt_t issuer = NULL; 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--; } } /* We want to shorten the chain by removing the cert that matches * one of the certs we trust and all the certs after that i.e. if * cert chain is A signed-by B signed-by C signed-by D (signed-by * self-signed E but already removed above), and we trust B, remove * B, C and D. */ if (!(flags & GNUTLS_VERIFY_DO_NOT_ALLOW_SAME)) i = 0; /* also replace the first one */ else i = 1; /* do not replace the first one */ for (; i < clist_size; i++) { int j; for (j = 0; j < tcas_size; j++) { if (check_if_same_cert (certificate_list[i], trusted_cas[j]) == 0) { /* explicity time check for trusted CA that we remove from * list. GNUTLS_VERIFY_DISABLE_TRUSTED_TIME_CHECKS */ if (!(flags & GNUTLS_VERIFY_DISABLE_TRUSTED_TIME_CHECKS) && !(flags & GNUTLS_VERIFY_DISABLE_TIME_CHECKS)) { status |= check_time (trusted_cas[j], now); if (status != 0) { if (func) func(certificate_list[i], trusted_cas[j], NULL, status); return status; } } if (func) func(certificate_list[i], trusted_cas[j], NULL, status); clist_size = i; break; } } /* clist_size may have been changed which gets out of loop */ } if (clist_size == 0) { /* The certificate is already present in the trusted certificate list. * Nothing to verify. */ return status; } /* Verify the last certificate in the certificate path * against the trusted CA certificate list. * * If no CAs are present returns CERT_INVALID. Thus works * in self signed etc certificates. */ output = 0; ret = _gnutls_verify_certificate2 (certificate_list[clist_size - 1], trusted_cas, tcas_size, flags, &output, &issuer, now, func); if (ret == 0) { /* if the last certificate in the certificate * list is invalid, then the certificate is not * trusted. */ gnutls_assert (); status |= output; status |= GNUTLS_CERT_INVALID; return status; } /* Verify the certificate path (chain) */ for (i = clist_size - 1; i > 0; i--) { output = 0; if (i - 1 < 0) break; /* note that here we disable this V1 CA flag. So that no version 1 * certificates can exist in a supplied chain. */ if (!(flags & GNUTLS_VERIFY_ALLOW_ANY_X509_V1_CA_CRT)) flags &= ~(GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT); if ((ret = _gnutls_verify_certificate2 (certificate_list[i - 1], &certificate_list[i], 1, flags, &output, NULL, now, func)) == 0) { status |= output; status |= GNUTLS_CERT_INVALID; return status; } } return 0; }