/* 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; }
static unsigned int CVE_2009_1417_gnutls1_4_3__gnutls_x509_verify_certificate (const gnutls_x509_crt_t * certificate_list, int clist_size, const gnutls_x509_crt_t * trusted_cas, int tcas_size, const gnutls_x509_crl_t * CRLs, int crls_size, unsigned int flags) { int i = 0, ret; unsigned int status = 0, output; /* 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. */ ret = _gnutls_verify_certificate2 (certificate_list[clist_size - 1], trusted_cas, tcas_size, flags, &output); 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; } /* Check for revoked certificates in the chain */ #ifdef ENABLE_PKI for (i = 0; i < clist_size; i++) { ret = gnutls_x509_crt_check_revocation (certificate_list[i], CRLs, crls_size); if (ret == 1) { /* revoked */ status |= GNUTLS_CERT_REVOKED; status |= GNUTLS_CERT_INVALID; return status; } } #endif /* 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). */ if (gnutls_x509_crt_check_issuer (certificate_list[clist_size - 1], certificate_list[clist_size - 1]) > 0 && clist_size > 0) { clist_size--; } /* Verify the certificate path (chain) */ for (i = clist_size - 1; i > 0; i--) { 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, NULL)) == 0) { status |= GNUTLS_CERT_INVALID; return status; } } return 0; }