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;
}
Beispiel #4
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;
}