/* Verifies a certificate against our trusted CA list. * Also checks the crl_list if the certificate is revoked. */ static void verify_last_cert (gnutls_x509_crt_t crt, gnutls_x509_crt_t * ca_list, int ca_list_size, gnutls_x509_crl_t * crl_list, int crl_list_size) { unsigned int output; int ret; time_t now = time (0); size_t name_size; char name[64]; /* Print information about the certificates to * be checked. */ name_size = sizeof (name); gnutls_x509_crt_get_dn (crt, name, &name_size); fprintf (stderr, "\nCertificate: %s\n", name); name_size = sizeof (name); gnutls_x509_crt_get_issuer_dn (crt, name, &name_size); fprintf (stderr, "Issued by: %s\n", name); /* Do the actual verification. */ gnutls_x509_crt_verify (crt, ca_list, ca_list_size, GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT, &output); if (output & GNUTLS_CERT_INVALID) { fprintf (stderr, "Not trusted"); if (output & GNUTLS_CERT_SIGNER_NOT_CA) fprintf (stderr, ": Issuer is not a CA\n"); else fprintf (stderr, "\n"); } else fprintf (stderr, "Trusted\n"); /* Now check the expiration dates. */ if (gnutls_x509_crt_get_activation_time (crt) > now) fprintf (stderr, "Not yet activated\n"); if (gnutls_x509_crt_get_expiration_time (crt) < now) fprintf (stderr, "Expired\n"); /* Check if the certificate is revoked. */ ret = gnutls_x509_crt_check_revocation (crt, crl_list, crl_list_size); if (ret == 1) { /* revoked */ fprintf (stderr, "Revoked\n"); } }
/** * gnutls_x509_crt_list_verify: * @cert_list: is the certificate list to be verified * @cert_list_length: holds the number of certificate in cert_list * @CA_list: is the CA list which will be used in verification * @CA_list_length: holds the number of CA certificate in CA_list * @CRL_list: holds a list of CRLs. * @CRL_list_length: the length of CRL list. * @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. * * This function will try to verify the given certificate list and * return its status. If no flags are specified (0), this function * will use the basicConstraints (2.5.29.19) PKIX extension. This * means that only a certificate authority is allowed to sign a * certificate. * * You must also check the peer's name in order to check if the verified * certificate belongs to the actual peer. * * The certificate verification output will be put in @verify and will * be one or more of the gnutls_certificate_status_t enumerated * elements bitwise or'd. For a more detailed verification status use * gnutls_x509_crt_verify() per list element. * * GNUTLS_CERT_INVALID: the certificate chain is not valid. * * GNUTLS_CERT_REVOKED: a certificate in the chain has been revoked. * * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a * negative error value. **/ int gnutls_x509_crt_list_verify (const gnutls_x509_crt_t * cert_list, int cert_list_length, const gnutls_x509_crt_t * CA_list, int CA_list_length, const gnutls_x509_crl_t * CRL_list, int CRL_list_length, unsigned int flags, unsigned int *verify) { int i, ret; if (cert_list == NULL || cert_list_length == 0) return GNUTLS_E_NO_CERTIFICATE_FOUND; /* Verify certificate */ *verify = _gnutls_x509_verify_certificate (cert_list, cert_list_length, CA_list, CA_list_length, flags, NULL); /* Check for revoked certificates in the chain. */ #ifdef ENABLE_PKI for (i = 0; i < cert_list_length; i++) { ret = gnutls_x509_crt_check_revocation (cert_list[i], CRL_list, CRL_list_length); if (ret == 1) { /* revoked */ *verify |= GNUTLS_CERT_REVOKED; *verify |= GNUTLS_CERT_INVALID; } } #endif return 0; }
/* Verifies a certificate against an other certificate * which is supposed to be it's issuer. Also checks the * crl_list if the certificate is revoked. */ static void verify_cert2 (gnutls_x509_crt_t crt, gnutls_x509_crt_t issuer, gnutls_x509_crl_t * crl_list, int crl_list_size) { unsigned int output; int ret; time_t now = time (0); size_t name_size; char name[64]; /* Print information about the certificates to * be checked. */ name_size = sizeof (name); gnutls_x509_crt_get_dn (crt, name, &name_size); fprintf (stderr, "\nCertificate: %s\n", name); name_size = sizeof (name); gnutls_x509_crt_get_issuer_dn (crt, name, &name_size); fprintf (stderr, "Issued by: %s\n", name); /* Get the DN of the issuer cert. */ name_size = sizeof (name); gnutls_x509_crt_get_dn (issuer, name, &name_size); fprintf (stderr, "Checking against: %s\n", name); /* Do the actual verification. */ gnutls_x509_crt_verify (crt, &issuer, 1, 0, &output); if (output & GNUTLS_CERT_INVALID) { fprintf (stderr, "Not trusted"); if (output & GNUTLS_CERT_SIGNER_NOT_FOUND) fprintf (stderr, ": no issuer was found"); if (output & GNUTLS_CERT_SIGNER_NOT_CA) fprintf (stderr, ": issuer is not a CA"); fprintf (stderr, "\n"); } else fprintf (stderr, "Trusted\n"); /* Now check the expiration dates. */ if (gnutls_x509_crt_get_activation_time (crt) > now) fprintf (stderr, "Not yet activated\n"); if (gnutls_x509_crt_get_expiration_time (crt) < now) fprintf (stderr, "Expired\n"); /* Check if the certificate is revoked. */ ret = gnutls_x509_crt_check_revocation (crt, crl_list, crl_list_size); if (ret == 1) { /* revoked */ fprintf (stderr, "Revoked\n"); } }
/* 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. */ static 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, const gnutls_x509_crl_t * CRLs, int crls_size, unsigned int flags) { 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) { return 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. */ ret = _gnutls_verify_certificate2 (certificate_list[clist_size - 1], trusted_cas, tcas_size, flags, &output, &issuer); 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 activation/expiration times */ if (!(flags & GNUTLS_VERIFY_DISABLE_TIME_CHECKS)) { /* check the time of the issuer first */ if (!(flags & GNUTLS_VERIFY_DISABLE_TRUSTED_TIME_CHECKS)) { if (issuer == NULL) { gnutls_assert (); return GNUTLS_E_INTERNAL_ERROR; } status |= check_time (issuer, now); if (status != 0) { return status; } } for (i = 0; i < clist_size; i++) { status |= check_time (certificate_list[i], now); if (status != 0) { return status; } } } /* 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, NULL)) == 0) { 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; }