Example #1
0
/*-
  * gnutls_x509_extract_certificate_ca_status - This function returns the certificate CA status
  * @cert: should contain an X.509 DER encoded certificate
  *
  * This function will return certificates CA status, by reading the 
  * basicConstraints X.509 extension. If the certificate is a CA a positive
  * value will be returned, or zero if the certificate does not have
  * CA flag set. 
  *
  * A negative value may be returned in case of parsing error.
  * If the certificate does not contain the basicConstraints extension
  * GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE will be returned.
  *
  -*/
int
gnutls_x509_extract_certificate_ca_status (const gnutls_datum_t * cert)
{
  gnutls_x509_crt_t xcert;
  int result;

  result = gnutls_x509_crt_init (&xcert);
  if (result < 0)
    return result;

  result = gnutls_x509_crt_import (xcert, cert, GNUTLS_X509_FMT_DER);
  if (result < 0)
    {
      gnutls_x509_crt_deinit (xcert);
      return result;
    }

  result = gnutls_x509_crt_get_ca_status (xcert, NULL);

  gnutls_x509_crt_deinit (xcert);

  return result;
}
Example #2
0
/* 
 * Returns only 0 or 1. If 1 it means that the CRL
 * was successfuly verified.
 *
 * 'flags': an OR of the gnutls_certificate_verify_flags enumeration.
 *
 * Output will hold information about the verification
 * procedure. 
 */
static int
_gnutls_verify_crl2 (gnutls_x509_crl_t crl,
                     const gnutls_x509_crt_t * trusted_cas,
                     int tcas_size, unsigned int flags, unsigned int *output)
{
/* CRL is ignored for now */
  gnutls_datum_t crl_signed_data = { NULL, 0 };
  gnutls_datum_t crl_signature = { NULL, 0 };
  gnutls_x509_crt_t issuer;
  int result, hash_algo;

  if (output)
    *output = 0;

  if (tcas_size >= 1)
    issuer = find_crl_issuer (crl, trusted_cas, tcas_size);
  else
    {
      gnutls_assert ();
      if (output)
        *output |= GNUTLS_CERT_SIGNER_NOT_FOUND | GNUTLS_CERT_INVALID;
      return 0;
    }

  /* issuer is not in trusted certificate
   * authorities.
   */
  if (issuer == NULL)
    {
      gnutls_assert ();
      if (output)
        *output |= GNUTLS_CERT_SIGNER_NOT_FOUND | GNUTLS_CERT_INVALID;
      return 0;
    }

  if (!(flags & GNUTLS_VERIFY_DISABLE_CA_SIGN))
    {
      if (gnutls_x509_crt_get_ca_status (issuer, NULL) != 1)
        {
          gnutls_assert ();
          if (output)
            *output |= GNUTLS_CERT_SIGNER_NOT_CA | GNUTLS_CERT_INVALID;
          return 0;
        }
    }

  result =
    _gnutls_x509_get_signed_data (crl->crl, "tbsCertList", &crl_signed_data);
  if (result < 0)
    {
      gnutls_assert ();
      goto cleanup;
    }

  result = _gnutls_x509_get_signature (crl->crl, "signature", &crl_signature);
  if (result < 0)
    {
      gnutls_assert ();
      goto cleanup;
    }

  result = _gnutls_x509_get_signature_algorithm(crl->crl, "signatureAlgorithm.algorithm");
  if (result < 0)
    {
      gnutls_assert ();
      goto cleanup;
    }

  hash_algo = gnutls_sign_get_hash_algorithm(result);

  result =
    _gnutls_x509_verify_data (hash_algo, &crl_signed_data, &crl_signature,
                                   issuer);
  if (result == GNUTLS_E_PK_SIG_VERIFY_FAILED)
    {
      gnutls_assert ();
      /* error. ignore it */
      if (output)
        *output |= GNUTLS_CERT_INVALID | GNUTLS_CERT_SIGNATURE_FAILURE;
      result = 0;
    }
  else if (result < 0)
    {
      gnutls_assert ();
      goto cleanup;
    }

  {
    int sigalg;

    sigalg = gnutls_x509_crl_get_signature_algorithm (crl);

    if (((sigalg == GNUTLS_SIGN_RSA_MD2) &&
         !(flags & GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD2)) ||
        ((sigalg == GNUTLS_SIGN_RSA_MD5) &&
         !(flags & GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5)))
      {
        if (output)
          *output |= GNUTLS_CERT_INSECURE_ALGORITHM | GNUTLS_CERT_INVALID;
        result = 0;
      }
  }

cleanup:
  _gnutls_free_datum (&crl_signed_data);
  _gnutls_free_datum (&crl_signature);

  return result;
}
Example #3
0
/* Checks if the issuer of a certificate is a
 * Certificate Authority, or if the certificate is the same
 * as the issuer (and therefore it doesn't need to be a CA).
 *
 * Returns true or false, if the issuer is a CA,
 * or not.
 */
static int
check_if_ca (gnutls_x509_crt_t cert, gnutls_x509_crt_t issuer,
             unsigned int flags)
{
  gnutls_datum_t cert_signed_data = { NULL, 0 };
  gnutls_datum_t issuer_signed_data = { NULL, 0 };
  gnutls_datum_t cert_signature = { NULL, 0 };
  gnutls_datum_t issuer_signature = { NULL, 0 };
  int result;

  /* Check if the issuer is the same with the
   * certificate. This is added in order for trusted
   * certificates to be able to verify themselves.
   */

  result =
    _gnutls_x509_get_signed_data (issuer->cert, "tbsCertificate",
                                  &issuer_signed_data);
  if (result < 0)
    {
      gnutls_assert ();
      goto cleanup;
    }

  result =
    _gnutls_x509_get_signed_data (cert->cert, "tbsCertificate",
                                  &cert_signed_data);
  if (result < 0)
    {
      gnutls_assert ();
      goto cleanup;
    }

  result =
    _gnutls_x509_get_signature (issuer->cert, "signature", &issuer_signature);
  if (result < 0)
    {
      gnutls_assert ();
      goto cleanup;
    }

  result =
    _gnutls_x509_get_signature (cert->cert, "signature", &cert_signature);
  if (result < 0)
    {
      gnutls_assert ();
      goto cleanup;
    }

  /* If the subject certificate is the same as the issuer
   * return true.
   */
  if (!(flags & GNUTLS_VERIFY_DO_NOT_ALLOW_SAME))
    if (cert_signed_data.size == issuer_signed_data.size)
      {
        if ((memcmp (cert_signed_data.data, issuer_signed_data.data,
                     cert_signed_data.size) == 0) &&
            (cert_signature.size == issuer_signature.size) &&
            (memcmp (cert_signature.data, issuer_signature.data,
                     cert_signature.size) == 0))
          {
            result = 1;
            goto cleanup;
          }
      }

  result = gnutls_x509_crt_get_ca_status (issuer, NULL);
  if (result == 1)
    {
      result = 1;
      goto cleanup;
    }
  /* Handle V1 CAs that do not have a basicConstraint, but accept
     these certs only if the appropriate flags are set. */
  else if ((result == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) &&
           ((flags & GNUTLS_VERIFY_ALLOW_ANY_X509_V1_CA_CRT) ||
            (!(flags & GNUTLS_VERIFY_DO_NOT_ALLOW_X509_V1_CA_CRT) &&
             (gnutls_x509_crt_check_issuer (issuer, issuer) == 1))))
    {
      gnutls_assert ();
      result = 1;
      goto cleanup;
    }
  else
    gnutls_assert ();

  result = 0;

cleanup:
  _gnutls_free_datum (&cert_signed_data);
  _gnutls_free_datum (&issuer_signed_data);
  _gnutls_free_datum (&cert_signature);
  _gnutls_free_datum (&issuer_signature);
  return result;
}
Example #4
0
/**
 * gnutls_x509_crl_verify:
 * @crl: is the crl to be verified
 * @trusted_cas: is a certificate list that is considered to be trusted one
 * @tcas_size: holds the number of CA certificates in CA_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 crl verification output.
 *
 * This function will try to verify the given crl and return its verification status.
 * See gnutls_x509_crt_list_verify() for a detailed description of
 * return values. Note that since GnuTLS 3.1.4 this function includes
 * the time checks.
 *
 * Note that value in @verify is set only when the return value of this 
 * function is success (i.e, failure to trust a CRL a certificate does not imply 
 * a negative return value).
 *
 * Before GnuTLS 3.5.7 this function would return zero or a positive
 * number on success.
 *
 * Returns: On success, %GNUTLS_E_SUCCESS (0), otherwise a
 *   negative error value.
 **/
int
gnutls_x509_crl_verify(gnutls_x509_crl_t crl,
		       const gnutls_x509_crt_t * trusted_cas,
		       unsigned tcas_size, unsigned int flags,
		       unsigned int *verify)
{
/* CRL is ignored for now */
	gnutls_datum_t crl_signed_data = { NULL, 0 };
	gnutls_datum_t crl_signature = { NULL, 0 };
	gnutls_x509_crt_t issuer = NULL;
	int result, hash_algo;
	time_t now = gnutls_time(0);
	unsigned int usage;

	if (verify)
		*verify = 0;

	if (tcas_size >= 1)
		issuer = find_crl_issuer(crl, trusted_cas, tcas_size);

	result =
	    _gnutls_x509_get_signed_data(crl->crl, &crl->der, "tbsCertList",
					 &crl_signed_data);
	if (result < 0) {
		gnutls_assert();
		if (verify)
			*verify |= GNUTLS_CERT_INVALID;
		goto cleanup;
	}

	result =
	    _gnutls_x509_get_signature(crl->crl, "signature",
				       &crl_signature);
	if (result < 0) {
		gnutls_assert();
		if (verify)
			*verify |= GNUTLS_CERT_INVALID;
		goto cleanup;
	}

	result =
	    _gnutls_x509_get_signature_algorithm(crl->crl,
						 "signatureAlgorithm.algorithm");
	if (result < 0) {
		gnutls_assert();
		if (verify)
			*verify |= GNUTLS_CERT_INVALID;
		goto cleanup;
	}

	hash_algo = gnutls_sign_get_hash_algorithm(result);

	/* issuer is not in trusted certificate
	 * authorities.
	 */
	if (issuer == NULL) {
		gnutls_assert();
		if (verify)
			*verify |=
			    GNUTLS_CERT_SIGNER_NOT_FOUND |
			    GNUTLS_CERT_INVALID;
	} else {
		if (!(flags & GNUTLS_VERIFY_DISABLE_CA_SIGN)) {
			if (gnutls_x509_crt_get_ca_status(issuer, NULL) != 1) {
				gnutls_assert();
				if (verify)
					*verify |=
					    GNUTLS_CERT_SIGNER_NOT_CA |
					    GNUTLS_CERT_INVALID;
			}

			result =
			    gnutls_x509_crt_get_key_usage(issuer, &usage, NULL);
			if (result != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
				if (result < 0) {
					gnutls_assert();
					if (verify)
						*verify |= GNUTLS_CERT_INVALID;
				} else if (!(usage & GNUTLS_KEY_CRL_SIGN)) {
					gnutls_assert();
					if (verify)
						*verify |=
						    GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE
						    | GNUTLS_CERT_INVALID;
				}
			}
		}

		result =
		    _gnutls_x509_verify_data(mac_to_entry(hash_algo),
					     &crl_signed_data, &crl_signature,
					     issuer);
		if (result == GNUTLS_E_PK_SIG_VERIFY_FAILED) {
			gnutls_assert();
			/* error. ignore it */
			if (verify)
				*verify |= GNUTLS_CERT_SIGNATURE_FAILURE;
			result = 0;
		} else if (result < 0) {
			gnutls_assert();
			if (verify)
				*verify |= GNUTLS_CERT_INVALID;
			goto cleanup;
		} else if (result >= 0) {
			result = 0; /* everything ok */
		}
	}

	{
		int sigalg;

		sigalg = gnutls_x509_crl_get_signature_algorithm(crl);

		if (((sigalg == GNUTLS_SIGN_RSA_MD2) &&
		     !(flags & GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD2)) ||
		    ((sigalg == GNUTLS_SIGN_RSA_MD5) &&
		     !(flags & GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5))) {
			if (verify)
				*verify |= GNUTLS_CERT_INSECURE_ALGORITHM;
			result = 0;
		}
	}

	if (gnutls_x509_crl_get_this_update(crl) > now && verify)
		*verify |= GNUTLS_CERT_REVOCATION_DATA_ISSUED_IN_FUTURE;

	if (gnutls_x509_crl_get_next_update(crl) < now && verify)
		*verify |= GNUTLS_CERT_REVOCATION_DATA_SUPERSEDED;


      cleanup:
	if (verify && *verify != 0)
		*verify |= GNUTLS_CERT_INVALID;

	_gnutls_free_datum(&crl_signed_data);
	_gnutls_free_datum(&crl_signature);

	return result;
}
Example #5
0
/**
 * gnutls_x509_trust_list_add_cas:
 * @list: The structure of the list
 * @clist: A list of CAs
 * @clist_size: The length of the CA list
 * @flags: should be 0 or an or'ed sequence of %GNUTLS_TL options.
 *
 * This function will add the given certificate authorities
 * to the trusted list. The list of CAs must not be deinitialized
 * during this structure's lifetime.
 *
 * If the flag %GNUTLS_TL_NO_DUPLICATES is specified, then
 * the provided @clist entries that are duplicates will not be
 * added to the list and will be deinitialized.
 *
 * Returns: The number of added elements is returned.
 *
 * Since: 3.0.0
 **/
int
gnutls_x509_trust_list_add_cas(gnutls_x509_trust_list_t list,
			       const gnutls_x509_crt_t * clist,
			       unsigned clist_size, unsigned int flags)
{
	unsigned i, j;
	uint32_t hash;
	int ret;
	unsigned exists;

	for (i = 0; i < clist_size; i++) {
		exists = 0;
		hash =
		    hash_pjw_bare(clist[i]->raw_dn.data,
				  clist[i]->raw_dn.size);
		hash %= list->size;

		/* avoid duplicates */
		if (flags & GNUTLS_TL_NO_DUPLICATES || flags & GNUTLS_TL_NO_DUPLICATE_KEY) {
			for (j=0;j<list->node[hash].trusted_ca_size;j++) {
				if (flags & GNUTLS_TL_NO_DUPLICATES)
					ret = _gnutls_check_if_same_cert(list->node[hash].trusted_cas[j], clist[i]);
				else
					ret = _gnutls_check_if_same_key(list->node[hash].trusted_cas[j], clist[i], 1);
				if (ret != 0) {
					exists = 1;
					break;
				}
			}

			if (exists != 0) {
				gnutls_x509_crt_deinit(list->node[hash].trusted_cas[j]);
				list->node[hash].trusted_cas[j] = clist[i];
				continue;
			}
		}

		list->node[hash].trusted_cas =
		    gnutls_realloc_fast(list->node[hash].trusted_cas,
					(list->node[hash].trusted_ca_size +
					 1) *
					sizeof(list->node[hash].
					       trusted_cas[0]));
		if (list->node[hash].trusted_cas == NULL) {
			gnutls_assert();
			return i;
		}

		if (gnutls_x509_crt_get_version(clist[i]) >= 3 &&
		    gnutls_x509_crt_get_ca_status(clist[i], NULL) <= 0) {
			gnutls_datum_t dn;
			gnutls_assert();
			if (gnutls_x509_crt_get_dn2(clist[i], &dn) >= 0) {
				_gnutls_audit_log(NULL,
					  "There was a non-CA certificate in the trusted list: %s.\n",
					  dn.data);
				gnutls_free(dn.data);
			}
		}

		list->node[hash].trusted_cas[list->node[hash].
					     trusted_ca_size] = clist[i];
		list->node[hash].trusted_ca_size++;

		if (flags & GNUTLS_TL_USE_IN_TLS) {
			ret = add_new_ca_to_rdn_seq(list, clist[i]);
			if (ret < 0) {
				gnutls_assert();
				return i;
			}
		}
	}

	return i;
}
Example #6
0
bool
Certificate::isCA() const
{
    unsigned critical;
    return gnutls_x509_crt_get_ca_status(cert, &critical) > 0;
}
void
empathy_tls_certificate_store_ca (EmpathyTLSCertificate *self)
{
  GArray *last_cert;
  gnutls_x509_crt_t cert;
  gnutls_datum_t datum = { NULL, 0 };
  gsize exported_len;
  guchar *exported_cert = NULL;
  gint res, offset;
  gchar *user_certs_dir = NULL, *filename = NULL, *path = NULL;
  gchar *hostname = NULL;
  GError *error = NULL;
  EmpathyTLSCertificatePriv *priv = GET_PRIV (self);

  last_cert = g_ptr_array_index (priv->cert_data, priv->cert_data->len - 1);
  datum.data = (guchar *) last_cert->data;
  datum.size = last_cert->len;

  gnutls_x509_crt_init (&cert);
  gnutls_x509_crt_import (cert, &datum, GNUTLS_X509_FMT_DER);

  /* make sure it's self-signed, otherwise it's not a CA */
  if (gnutls_x509_crt_check_issuer (cert, cert) <= 0)
    {
      DEBUG ("Can't import the CA, as it's not self-signed");
      gnutls_x509_crt_deinit (cert);

      return;
    }

  if (gnutls_x509_crt_get_ca_status (cert, NULL) <= 0)
    {
      DEBUG ("Can't import the CA, it's not a valid CA certificate");
      gnutls_x509_crt_deinit (cert);

      goto out;
    }

  exported_len = get_exported_size (cert);
  exported_cert = g_malloc (sizeof (guchar) * exported_len);

  res = gnutls_x509_crt_export (cert, GNUTLS_X509_FMT_PEM,
      exported_cert, &exported_len);

  if (res < 0)
    {
      DEBUG ("Failed to export the CA certificate; GnuTLS returned %d,"
          "and should be %lu bytes long", res, (gulong) exported_len);
      gnutls_x509_crt_deinit (cert);

      goto out;
    }

  hostname = empathy_get_x509_certificate_hostname (cert);

  if (hostname == NULL)
    hostname = g_strdup ("ca");

  gnutls_x509_crt_deinit (cert);

  /* write the file */
  user_certs_dir = g_build_filename (g_get_user_config_dir (),
      "telepathy", "certs", NULL);

  res = g_mkdir_with_parents (user_certs_dir, S_IRWXU | S_IRWXG);

  if (res < 0)
    {
      DEBUG ("Failed to create the user certificate directory: %s",
          g_strerror (errno));

      goto out;
    }

  offset = 0;

  do
    {
      g_free (path);

      if (offset == 0)
        filename = g_strdup_printf ("cert-%s", hostname);
      else
        filename = g_strdup_printf ("cert-%s-%d", hostname, offset);

      path = g_build_filename (user_certs_dir, filename, NULL);

      offset++;
      g_free (filename);
    }
  while (g_file_test (path, G_FILE_TEST_EXISTS));

  DEBUG ("Will save to %s", path);

  g_file_set_contents (path, (const gchar *) exported_cert, exported_len,
      &error);

  if (error != NULL)
    {
      DEBUG ("Can't save the CA certificate to %s: %s",
          path, error->message);

      g_error_free (error);
    }

 out:
  g_free (path);
  g_free (exported_cert);
  g_free (user_certs_dir);
  g_free (hostname);
}
void doit(void)
{
	int ret;
	gnutls_x509_crt_t crt, ocrt;
	unsigned keyusage;
	const char *lib;

	ret = global_init();
	if (ret != 0) {
		fail("%d: %s\n", ret, gnutls_strerror(ret));
		exit(1);
	}

	lib = getenv("P11MOCKLIB1");
	if (lib == NULL)
		lib = P11LIB;

	gnutls_global_set_time_function(mytime);
	if (debug) {
		gnutls_global_set_log_level(4711);
		success("loading lib %s\n", lib);
	}

	ret = gnutls_pkcs11_init(GNUTLS_PKCS11_FLAG_MANUAL, NULL);
	if (ret != 0) {
		fail("%d: %s\n", ret, gnutls_strerror(ret));
		exit(1);
	}

	ret = gnutls_pkcs11_add_provider(lib, "trusted");
	if (ret != 0) {
		fail("%d: %s\n", ret, gnutls_strerror(ret));
		exit(1);
	}

	assert(gnutls_x509_crt_init(&crt)>=0);
	assert(gnutls_x509_crt_init(&ocrt)>=0);

	/* check high level certificate functions */
	ret = gnutls_x509_crt_import_url(crt, "pkcs11:type=cert;object=cert1", 0);
	if (ret < 0) {
		fail("%d: %s\n", ret, gnutls_strerror(ret));
		exit(1);
	}

	ret = gnutls_x509_crt_import_url(ocrt, "pkcs11:type=cert;object=cert1", GNUTLS_PKCS11_OBJ_FLAG_OVERWRITE_TRUSTMOD_EXT);
	if (ret < 0) {
		fail("%d: %s\n", ret, gnutls_strerror(ret));
		exit(1);
	}

	ret = gnutls_x509_crt_equals(crt, ocrt);
	if (ret != 0) {
	    fail("exported certificates are equal!\n");
	}

	ret = gnutls_x509_crt_get_ca_status(ocrt, NULL);
	if (ret < 0) {
		fail("%d: %s\n", ret, gnutls_strerror(ret));
		exit(1);
	}

	if (ret == 0) {
		fail("overriden cert is not a CA!\n");
		exit(1);
	}

	ret = gnutls_x509_crt_get_key_usage(ocrt, &keyusage, NULL);
	if (ret < 0) {
		fail("%d: %s\n", ret, gnutls_strerror(ret));
		exit(1);
	}

	if (keyusage != (GNUTLS_KEY_KEY_ENCIPHERMENT|GNUTLS_KEY_ENCIPHER_ONLY|GNUTLS_KEY_KEY_CERT_SIGN)) {
		fail("Extension does not have the expected key usage!\n");
	}

	gnutls_x509_crt_deinit(crt);
	gnutls_x509_crt_deinit(ocrt);
	if (debug)
		printf("done\n\n\n");

	gnutls_global_deinit();
}