Unverified Commit 7f4c3585 authored by marcosdiazr's avatar marcosdiazr Committed by Daniel Stenberg
Browse files

schannel: make CURLOPT_CERTINFO support using Issuer chain

Closes #3197
parent 58d04252
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -70,7 +70,7 @@ if(curl) {
}
.fi
.SH AVAILABILITY
This option is supported by the OpenSSL, GnuTLS, NSS and GSKit backends.
This option is supported by the OpenSSL, GnuTLS, WinSSL, NSS and GSKit backends.
.SH RETURN VALUE
Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
.SH "SEE ALSO"
+64 −8
Original line number Diff line number Diff line
@@ -1121,6 +1121,61 @@ schannel_connect_step2(struct connectdata *conn, int sockindex)
  return CURLE_OK;
}

static bool
valid_cert_encoding(const CERT_CONTEXT *cert_context)
{
  return (cert_context != NULL) &&
    ((cert_context->dwCertEncodingType & X509_ASN_ENCODING) != 0) &&
    (cert_context->pbCertEncoded != NULL) &&
    (cert_context->cbCertEncoded > 0);
}

typedef bool(*Read_crt_func)(const CERT_CONTEXT *ccert_context, void *arg);

static void
traverse_cert_store(const CERT_CONTEXT *context, Read_crt_func func,
                    void *arg)
{
  const CERT_CONTEXT *current_context = NULL;
  bool should_continue = true;
  while(should_continue &&
        (current_context = CertEnumCertificatesInStore(
          context->hCertStore,
          current_context)) != NULL)
    should_continue = func(current_context, arg);

  if(current_context)
    CertFreeCertificateContext(current_context);
}

static bool
cert_counter_callback(const CERT_CONTEXT *ccert_context, void *certs_count)
{
  if(valid_cert_encoding(ccert_context))
    (*(int *)certs_count)++;
  return true;
}

struct Adder_args
{
  struct connectdata *conn;
  CURLcode result;
  int idx;
};

static bool
add_cert_to_certinfo(const CERT_CONTEXT *ccert_context, void *raw_arg)
{
  struct Adder_args *args = (struct Adder_args*)raw_arg;
  args->result = CURLE_OK;
  if(valid_cert_encoding(ccert_context)) {
    const char *beg = (const char *) ccert_context->pbCertEncoded;
    const char *end = beg + ccert_context->cbCertEncoded;
    args->result = Curl_extract_certinfo(args->conn, (args->idx)++, beg, end);
  }
  return args->result == CURLE_OK;
}

static CURLcode
schannel_connect_step3(struct connectdata *conn, int sockindex)
{
@@ -1230,6 +1285,7 @@ schannel_connect_step3(struct connectdata *conn, int sockindex)
  }

  if(data->set.ssl.certinfo) {
    int certs_count = 0;
    sspi_status = s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
      SECPKG_ATTR_REMOTE_CERT_CONTEXT, &ccert_context);

@@ -1238,15 +1294,15 @@ schannel_connect_step3(struct connectdata *conn, int sockindex)
      return CURLE_PEER_FAILED_VERIFICATION;
    }

    result = Curl_ssl_init_certinfo(data, 1);
    if(!result) {
      if(((ccert_context->dwCertEncodingType & X509_ASN_ENCODING) != 0) &&
         (ccert_context->cbCertEncoded > 0)) {
    traverse_cert_store(ccert_context, cert_counter_callback, &certs_count);

        const char *beg = (const char *) ccert_context->pbCertEncoded;
        const char *end = beg + ccert_context->cbCertEncoded;
        result = Curl_extract_certinfo(conn, 0, beg, end);
      }
    result = Curl_ssl_init_certinfo(data, certs_count);
    if(!result) {
      struct Adder_args args;
      args.conn = conn;
      args.idx = 0;
      traverse_cert_store(ccert_context, add_cert_to_certinfo, &args);
      result = args.result;
    }
    CertFreeCertificateContext(ccert_context);
    if(result)