Пример #1
0
/* 
 * Verifies the given certificate again a certificate list of
 * trusted CAs.
 *
 * Returns only 0 or 1. If 1 it means that the certificate 
 * was successfuly verified.
 *
 * 'flags': an OR of the gnutls_certificate_verify_flags enumeration.
 *
 * Output will hold some extra information about the verification
 * procedure. Issuer will hold the actual issuer from the trusted list.
 */
static int
_gnutls_verify_certificate2 (gnutls_x509_crt_t cert,
                             const gnutls_x509_crt_t * trusted_cas,
                             int tcas_size, unsigned int flags,
                             unsigned int *output,
                             gnutls_x509_crt_t * _issuer,
                             time_t now,
                             gnutls_verify_output_function func)
{
  gnutls_datum_t cert_signed_data = { NULL, 0 };
  gnutls_datum_t cert_signature = { NULL, 0 };
  gnutls_x509_crt_t issuer = NULL;
  int issuer_version, result, hash_algo;
  unsigned int out = 0;

  if (output)
    *output = 0;

  if (tcas_size >= 1)
    issuer = find_issuer (cert, trusted_cas, tcas_size);
  else
    {
      gnutls_assert ();
      out = GNUTLS_CERT_SIGNER_NOT_FOUND | GNUTLS_CERT_INVALID;
      if (output)
        *output |= out;
      result = 0;
      goto cleanup;
    }

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

  if (_issuer != NULL)
    *_issuer = issuer;

  issuer_version = gnutls_x509_crt_get_version (issuer);
  if (issuer_version < 0)
    {
      gnutls_assert ();
      return issuer_version;
    }

  if (!(flags & GNUTLS_VERIFY_DISABLE_CA_SIGN) &&
      ((flags & GNUTLS_VERIFY_DO_NOT_ALLOW_X509_V1_CA_CRT)
       || issuer_version != 1))
    {
      if (check_if_ca (cert, issuer, flags) == 0)
        {
          gnutls_assert ();
          out = GNUTLS_CERT_SIGNER_NOT_CA | GNUTLS_CERT_INVALID;
          if (output)
            *output |= out;
          result = 0;
          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 (cert->cert, "signature", &cert_signature);
  if (result < 0)
    {
      gnutls_assert ();
      goto cleanup;
    }

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

  hash_algo = gnutls_sign_get_hash_algorithm(result);

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

  /* If the certificate is not self signed check if the algorithms
   * used are secure. If the certificate is self signed it doesn't
   * really matter.
   */
  if (is_issuer (cert, cert) == 0)
    {
      int sigalg;

      sigalg = gnutls_x509_crt_get_signature_algorithm (cert);

      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)))
        {
          out = GNUTLS_CERT_INSECURE_ALGORITHM | GNUTLS_CERT_INVALID;
          if (output)
            *output |= out;
          result = 0;
        }
    }

  /* 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))
        {
          out |= check_time (issuer, now);
          if (out != 0)
            {
              result = 0;
              if (output) *output |= out;
            }
        }

      out |= check_time (cert, now);
      if (out != 0)
        {
          result = 0;
          if (output) *output |= out;
        }
    }

cleanup:
  if (result >= 0 && func) func(cert, issuer, NULL, out);
  _gnutls_free_datum (&cert_signed_data);
  _gnutls_free_datum (&cert_signature);

  return result;
}
Пример #2
0
int X509_verify_cert(X509_STORE_CTX *ctx)
	{
	X509 *x,*xtmp,*chain_ss=NULL;
	X509_NAME *xn;
	int depth,i,ok=0;
	int num;
	int (*cb)();
	STACK_OF(X509) *sktmp=NULL;

	if (ctx->cert == NULL)
		{
		X509err(X509_F_X509_VERIFY_CERT,X509_R_NO_CERT_SET_FOR_US_TO_VERIFY);
		return -1;
		}

	cb=ctx->verify_cb;

	/* first we make sure the chain we are going to build is
	 * present and that the first entry is in place */
	if (ctx->chain == NULL)
		{
		if (	((ctx->chain=sk_X509_new_null()) == NULL) ||
			(!sk_X509_push(ctx->chain,ctx->cert)))
			{
			X509err(X509_F_X509_VERIFY_CERT,ERR_R_MALLOC_FAILURE);
			goto end;
			}
		CRYPTO_add(&ctx->cert->references,1,CRYPTO_LOCK_X509);
		ctx->last_untrusted=1;
		}

	/* We use a temporary STACK so we can chop and hack at it */
	if (ctx->untrusted != NULL
	    && (sktmp=sk_X509_dup(ctx->untrusted)) == NULL)
		{
		X509err(X509_F_X509_VERIFY_CERT,ERR_R_MALLOC_FAILURE);
		goto end;
		}

	num=sk_X509_num(ctx->chain);
	x=sk_X509_value(ctx->chain,num-1);
	depth=ctx->depth;


	for (;;)
		{
		/* If we have enough, we break */
		if (depth < num) break; /* FIXME: If this happens, we should take
		                         * note of it and, if appropriate, use the
		                         * X509_V_ERR_CERT_CHAIN_TOO_LONG error
		                         * code later.
		                         */

		/* If we are self signed, we break */
		xn=X509_get_issuer_name(x);
		if (ctx->check_issued(ctx, x,x)) break;

		/* If we were passed a cert chain, use it first */
		if (ctx->untrusted != NULL)
			{
			xtmp=find_issuer(ctx, sktmp,x);
			if (xtmp != NULL)
				{
				if (!sk_X509_push(ctx->chain,xtmp))
					{
					X509err(X509_F_X509_VERIFY_CERT,ERR_R_MALLOC_FAILURE);
					goto end;
					}
				CRYPTO_add(&xtmp->references,1,CRYPTO_LOCK_X509);
				sk_X509_delete_ptr(sktmp,xtmp);
				ctx->last_untrusted++;
				x=xtmp;
				num++;
				/* reparse the full chain for
				 * the next one */
				continue;
				}
			}
		break;
		}

	/* at this point, chain should contain a list of untrusted
	 * certificates.  We now need to add at least one trusted one,
	 * if possible, otherwise we complain. */

	/* Examine last certificate in chain and see if it
 	 * is self signed.
 	 */

	i=sk_X509_num(ctx->chain);
	x=sk_X509_value(ctx->chain,i-1);
	xn = X509_get_subject_name(x);
	if (ctx->check_issued(ctx, x, x))
		{
		/* we have a self signed certificate */
		if (sk_X509_num(ctx->chain) == 1)
			{
			/* We have a single self signed certificate: see if
			 * we can find it in the store. We must have an exact
			 * match to avoid possible impersonation.
			 */
			ok = ctx->get_issuer(&xtmp, ctx, x);
			if ((ok <= 0) || X509_cmp(x, xtmp)) 
				{
				ctx->error=X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT;
				ctx->current_cert=x;
				ctx->error_depth=i-1;
				if (ok == 1) X509_free(xtmp);
				ok=cb(0,ctx);
				if (!ok) goto end;
				}
			else 
				{
				/* We have a match: replace certificate with store version
				 * so we get any trust settings.
				 */
				X509_free(x);
				x = xtmp;
				sk_X509_set(ctx->chain, i - 1, x);
				ctx->last_untrusted=0;
				}
			}
		else
			{
			/* extract and save self signed certificate for later use */
			chain_ss=sk_X509_pop(ctx->chain);
			ctx->last_untrusted--;
			num--;
			x=sk_X509_value(ctx->chain,num-1);
			}
		}

	/* We now lookup certs from the certificate store */
	for (;;)
		{
		/* If we have enough, we break */
		if (depth < num) break;

		/* If we are self signed, we break */
		xn=X509_get_issuer_name(x);
		if (ctx->check_issued(ctx,x,x)) break;

		ok = ctx->get_issuer(&xtmp, ctx, x);

		if (ok < 0) return ok;
		if (ok == 0) break;

		x = xtmp;
		if (!sk_X509_push(ctx->chain,x))
			{
			X509_free(xtmp);
			X509err(X509_F_X509_VERIFY_CERT,ERR_R_MALLOC_FAILURE);
			return 0;
			}
		num++;
		}

	/* we now have our chain, lets check it... */
	xn=X509_get_issuer_name(x);

	/* Is last certificate looked up self signed? */
	if (!ctx->check_issued(ctx,x,x))
		{
		if ((chain_ss == NULL) || !ctx->check_issued(ctx, x, chain_ss))
			{
			if (ctx->last_untrusted >= num)
				ctx->error=X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY;
			else
				ctx->error=X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT;
			ctx->current_cert=x;
			}
		else
			{

			sk_X509_push(ctx->chain,chain_ss);
			num++;
			ctx->last_untrusted=num;
			ctx->current_cert=chain_ss;
			ctx->error=X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN;
			chain_ss=NULL;
			}

		ctx->error_depth=num-1;
		ok=cb(0,ctx);
		if (!ok) goto end;
		}

	/* We have the chain complete: now we need to check its purpose */
	ok = check_chain_extensions(ctx);

	if (!ok) goto end;

	/* The chain extensions are OK: check trust */

	if (ctx->trust > 0) ok = check_trust(ctx);

	if (!ok) goto end;

	/* We may as well copy down any DSA parameters that are required */
	X509_get_pubkey_parameters(NULL,ctx->chain);

	/* Check revocation status: we do this after copying parameters
	 * because they may be needed for CRL signature verification.
	 */

	ok = ctx->check_revocation(ctx);
	if(!ok) goto end;

	/* At this point, we have a chain and just need to verify it */
	if (ctx->verify != NULL)
		ok=ctx->verify(ctx);
	else
		ok=internal_verify(ctx);
	if (0)
		{
end:
		X509_get_pubkey_parameters(NULL,ctx->chain);
		}
	if (sktmp != NULL) sk_X509_free(sktmp);
	if (chain_ss != NULL) X509_free(chain_ss);
	return ok;
	}
Пример #3
0
/* 
 * Verifies the given certificate again a certificate list of
 * trusted CAs.
 *
 * Returns only 0 or 1. If 1 it means that the certificate 
 * was successfuly verified.
 *
 * 'flags': an OR of the gnutls_certificate_verify_flags enumeration.
 *
 * Output will hold some extra information about the verification
 * procedure. Issuer will hold the actual issuer from the trusted list.
 */
static int
_gnutls_verify_certificate2 (gnutls_x509_crt_t cert,
                             const gnutls_x509_crt_t * trusted_cas,
                             int tcas_size, unsigned int flags,
                             unsigned int *output,
                             gnutls_x509_crt_t * _issuer)
{
  gnutls_datum_t cert_signed_data = { NULL, 0 };
  gnutls_datum_t cert_signature = { NULL, 0 };
  gnutls_x509_crt_t issuer = NULL;
  int issuer_version, result;

  if (output)
    *output = 0;

  if (tcas_size >= 1)
    issuer = find_issuer (cert, 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)
    {
      if (output)
        *output |= GNUTLS_CERT_SIGNER_NOT_FOUND | GNUTLS_CERT_INVALID;
      gnutls_assert ();
      return 0;
    }

  if (_issuer != NULL)
    *_issuer = issuer;

  issuer_version = gnutls_x509_crt_get_version (issuer);
  if (issuer_version < 0)
    {
      gnutls_assert ();
      return issuer_version;
    }

  if (!(flags & GNUTLS_VERIFY_DISABLE_CA_SIGN) &&
      ((flags & GNUTLS_VERIFY_DO_NOT_ALLOW_X509_V1_CA_CRT)
       || issuer_version != 1))
    {
      if (check_if_ca (cert, issuer, flags) == 0)
        {
          gnutls_assert ();
          if (output)
            *output |= GNUTLS_CERT_SIGNER_NOT_CA | GNUTLS_CERT_INVALID;
          return 0;
        }
    }

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

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

  result =
    _gnutls_x509_verify_signature (&cert_signed_data, NULL, &cert_signature,
                                   issuer);
  if (result == GNUTLS_E_PK_SIG_VERIFY_FAILED)
    {
      gnutls_assert ();
      /* error. ignore it */
      if (output)
        *output |= GNUTLS_CERT_INVALID;
      result = 0;
    }
  else if (result < 0)
    {
      gnutls_assert();
      goto cleanup;
    }

  /* If the certificate is not self signed check if the algorithms
   * used are secure. If the certificate is self signed it doesn't
   * really matter.
   */
  if (is_issuer (cert, cert) == 0)
    {
      int sigalg;

      sigalg = gnutls_x509_crt_get_signature_algorithm (cert);

      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 (&cert_signed_data);
  _gnutls_free_datum (&cert_signature);

  return result;
}
Пример #4
0
/* 
 * Verifies the given certificate against a certificate list of
 * trusted CAs.
 *
 * Returns only 0 or 1. If 1 it means that the certificate 
 * was successfuly verified.
 *
 * 'flags': an OR of the gnutls_certificate_verify_flags enumeration.
 *
 * Output will hold some extra information about the verification
 * procedure.
 */
static unsigned
verify_crt(gnutls_x509_crt_t cert,
			    const gnutls_x509_crt_t * trusted_cas,
			    int tcas_size, unsigned int flags,
			    unsigned int *output,
			    verify_state_st *vparams,
			    unsigned end_cert)
{
	gnutls_datum_t cert_signed_data = { NULL, 0 };
	gnutls_datum_t cert_signature = { NULL, 0 };
	gnutls_x509_crt_t issuer = NULL;
	int issuer_version, hash_algo;
	unsigned result = 1;
	const mac_entry_st * me;
	unsigned int out = 0, usage;
	int sigalg, ret;

	if (output)
		*output = 0;

	if (vparams->max_path == 0) {
		MARK_INVALID(GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE);
		/* bail immediately, to avoid inconistency  */
		goto cleanup;
	}
	vparams->max_path--;

	if (tcas_size >= 1)
		issuer = find_issuer(cert, trusted_cas, tcas_size);

	ret =
	    _gnutls_x509_get_signed_data(cert->cert, &cert->der, "tbsCertificate",
					 &cert_signed_data);
	if (ret < 0) {
		MARK_INVALID(0);
		cert_signed_data.data = NULL;
	}

	ret =
	    _gnutls_x509_get_signature(cert->cert, "signature",
				       &cert_signature);
	if (ret < 0) {
		MARK_INVALID(0);
		cert_signature.data = NULL;
	}

	ret =
	    _gnutls_x509_get_signature_algorithm(cert->cert,
						 "signatureAlgorithm.algorithm");
	if (ret < 0) {
		MARK_INVALID(0);
	}
	sigalg = ret;

	/* issuer is not in trusted certificate
	 * authorities.
	 */
	if (issuer == NULL) {
		MARK_INVALID(GNUTLS_CERT_SIGNER_NOT_FOUND);
	} else {
		if (vparams->nc != NULL) {
			/* append the issuer's constraints */
			ret = gnutls_x509_crt_get_name_constraints(issuer, vparams->nc, 
				GNUTLS_NAME_CONSTRAINTS_FLAG_APPEND, NULL);
			if (ret < 0 && ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
				MARK_INVALID(GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE);
				goto nc_done;
			}

			/* only check name constraints in server certificates, not CAs */
			if (end_cert != 0) {
				ret = gnutls_x509_name_constraints_check_crt(vparams->nc, GNUTLS_SAN_DNSNAME, cert);
				if (ret == 0) {
					MARK_INVALID(GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE);
					goto nc_done;
				}

				ret = gnutls_x509_name_constraints_check_crt(vparams->nc, GNUTLS_SAN_RFC822NAME, cert);
				if (ret == 0) {
					MARK_INVALID(GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE);
					goto nc_done;
				}

				ret = gnutls_x509_name_constraints_check_crt(vparams->nc, GNUTLS_SAN_DN, cert);
				if (ret == 0) {
					MARK_INVALID(GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE);
					goto nc_done;
				}

				ret = gnutls_x509_name_constraints_check_crt(vparams->nc, GNUTLS_SAN_URI, cert);
				if (ret == 0) {
					MARK_INVALID(GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE);
					goto nc_done;
				}

				ret = gnutls_x509_name_constraints_check_crt(vparams->nc, GNUTLS_SAN_IPADDRESS, cert);
				if (ret == 0) {
					MARK_INVALID(GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE);
					goto nc_done;
				}
			}
		}

 nc_done:
		if (vparams->tls_feat != NULL) {
			/* append the issuer's constraints */
			ret = gnutls_x509_crt_get_tlsfeatures(issuer, vparams->tls_feat, GNUTLS_EXT_FLAG_APPEND, NULL);
			if (ret < 0 && ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
				MARK_INVALID(GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE);
				goto feat_done;
			}

			ret = gnutls_x509_tlsfeatures_check_crt(vparams->tls_feat, cert);
			if (ret == 0) {
				MARK_INVALID(GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE);
				goto feat_done;
			}
		}

 feat_done:
		issuer_version = gnutls_x509_crt_get_version(issuer);

		if (issuer_version < 0) {
			MARK_INVALID(0);
		} else if (!(flags & GNUTLS_VERIFY_DISABLE_CA_SIGN) &&
			   ((flags & GNUTLS_VERIFY_DO_NOT_ALLOW_X509_V1_CA_CRT)
			    || issuer_version != 1)) {
			if (check_if_ca(cert, issuer, &vparams->max_path, flags) != 1) {
				MARK_INVALID(GNUTLS_CERT_SIGNER_NOT_CA);
			}

			ret =
			    gnutls_x509_crt_get_key_usage(issuer, &usage, NULL);
			if (ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
				if (ret < 0) {
					MARK_INVALID(0);
				} else if (!(usage & GNUTLS_KEY_KEY_CERT_SIGN)) {
					MARK_INVALID(GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE);
				}
			}
		}

		if (sigalg >= 0) {
			hash_algo = gnutls_sign_get_hash_algorithm(sigalg);
			me = mac_to_entry(hash_algo);
		} else {
			me = NULL;
		}

		if (me == NULL) {
			MARK_INVALID(0);
		} else if (cert_signed_data.data != NULL &&
			   cert_signature.data != NULL) {
			ret =
			    _gnutls_x509_verify_data(me,
						     &cert_signed_data,
						     &cert_signature,
						     issuer);
			if (ret == GNUTLS_E_PK_SIG_VERIFY_FAILED) {
				MARK_INVALID(GNUTLS_CERT_SIGNATURE_FAILURE);
			} else if (ret < 0) {
				MARK_INVALID(0);
			}
		}
	}

	/* we always check the issuer for unsupported critical extensions */
	if (issuer && check_for_unknown_exts(issuer) != 0) {
		if (!(flags & GNUTLS_VERIFY_IGNORE_UNKNOWN_CRIT_EXTENSIONS)) {
			MARK_INVALID(GNUTLS_CERT_UNKNOWN_CRIT_EXTENSIONS);
		}
	}

	/* we only check the end-certificate for critical extensions; that
	 * way do not perform this check twice on the certificates when
	 * verifying a large list */
	if (end_cert && check_for_unknown_exts(cert) != 0) {
		if (!(flags & GNUTLS_VERIFY_IGNORE_UNKNOWN_CRIT_EXTENSIONS)) {
			MARK_INVALID(GNUTLS_CERT_UNKNOWN_CRIT_EXTENSIONS);
		}
	}

	if (sigalg >= 0) {
		if (is_level_acceptable(cert, issuer, sigalg, flags) == 0) {
			MARK_INVALID(GNUTLS_CERT_INSECURE_ALGORITHM);
		}

		/* If the certificate is not self signed check if the algorithms
		 * used are secure. If the certificate is self signed it doesn't
		 * really matter.
		 */
		if (gnutls_sign_is_secure(sigalg) == 0 &&
		    _gnutls_is_broken_sig_allowed(sigalg, flags) == 0 &&
		    is_issuer(cert, cert) == 0) {
			MARK_INVALID(GNUTLS_CERT_INSECURE_ALGORITHM);
		}
	}

	/* Check activation/expiration times
	 */
	if (!(flags & GNUTLS_VERIFY_DISABLE_TIME_CHECKS)) {
		/* check the time of the issuer first */
		if (issuer != NULL &&
		    !(flags & GNUTLS_VERIFY_DISABLE_TRUSTED_TIME_CHECKS)) {
			out |= check_time_status(issuer, vparams->now);
			if (out != 0) {
				gnutls_assert();
				result = 0;
			}
		}

		out |= check_time_status(cert, vparams->now);
		if (out != 0) {
			gnutls_assert();
			result = 0;
		}
	}

      cleanup:
	if (output)
		*output |= out;

	if (vparams->func) {
		if (result == 0) {
			out |= GNUTLS_CERT_INVALID;
		}
		vparams->func(cert, issuer, NULL, out);
	}
	_gnutls_free_datum(&cert_signed_data);
	_gnutls_free_datum(&cert_signature);

	return result;
}
Пример #5
0
/* Return the certificate chain sent by the peer, or NULL on error. */
static ne_ssl_certificate *make_peers_chain(gnutls_session sock,
                                            gnutls_certificate_credentials crd)
{
    ne_ssl_certificate *current = NULL, *top = NULL;
    const gnutls_datum *certs;
    unsigned int n, count;
    ne_ssl_certificate *cert;

    certs = gnutls_certificate_get_peers(sock, &count);
    if (!certs) {
        return NULL;
    }

    NE_DEBUG(NE_DBG_SSL, "ssl: Got %u certs in peer chain.\n", count);
    
    for (n = 0; n < count; n++) {
        gnutls_x509_crt x5;

        if (gnutls_x509_crt_init(&x5) ||
            gnutls_x509_crt_import(x5, &certs[n], GNUTLS_X509_FMT_DER)) {
            if (top) {
                ne_ssl_cert_free(top);
            }
            return NULL;
        }

        cert = populate_cert(ne_calloc(sizeof *cert), x5);
        
        if (top == NULL) {
            current = top = cert;
        } else {
            current->issuer = cert;
            current = cert;
        }
    }

#ifdef HAVE_GNUTLS_CERTIFICATE_GET_X509_CAS
    /* GnuTLS only returns the peers which were *sent* by the server
     * in the Certificate list during the handshake.  Fill in the
     * complete chain manually against the certs we trust: */
    if (current->issuer == NULL) {
        gnutls_x509_crt issuer;
        gnutls_x509_crt *ca_list;
        unsigned int num_cas;
        
        gnutls_certificate_get_x509_cas(crd, &ca_list, &num_cas);

        do { 
            /* Look up the issuer. */
            issuer = find_issuer(ca_list, num_cas, current->subject);
            if (issuer) {
                issuer = x509_crt_copy(issuer);
                cert = populate_cert(ne_calloc(sizeof *cert), issuer);
                /* Check that the issuer does not match the current
                 * cert. */
                if (ne_ssl_cert_cmp(current, cert)) {
                    current = current->issuer = cert;
                }
                else {
                    ne_ssl_cert_free(cert);
                    issuer = NULL;
                }
            }
        } while (issuer);
    }
#endif
    
    return top;
}