Using client certificates to access restricted website

I’am trying to restrict access to a website. The desired state is this:

  • only clients with certificate are allowed to access the website.
  • everyone else is blocked

Steps I have taken to achieve this:
1/ Created new certificate at (Cloudflare → SSL/TLS → Client Certificates) and downloaded all of it’s variants (pem, pkcs, der) + private key.
2/ Set-up WAF (Cloudflare → Securitz → WAF) with a new rule like this:

(not cf.tls_client_auth.cert_verified and http.request.full_uri contains “my.domain.com”)
3/ After publishing the WAF rule, I verified the website being successfully blocked (so far so good)
4/ Tried Curl for testing access to the blocked site. Unfortunately even though I tried several attempts with several variants of the certificate and key, everything was unsuccessfull.

Some attempts returned:

schannel: disabled automatic use of client certificate
* schannel: Failed to import cert file client.pfx, last error is 0x80092002
* schannel: Failed to import cert file client.pem, last error is 0x80092002
and such

other attempts returned:

*   Trying IP:443...
* Connected to my.domain.com (IP) port 443 (#0)
* schannel: disabled automatic use of client certificate
* ALPN: offers http/1.1
* ALPN: server accepted http/1.1
* using HTTP/1.1
> GET /Default.aspx HTTP/1.1
> Host: my.domain.com
> User-Agent: curl/8.0.1
> Accept: */*
>
* schannel: remote party requests renegotiation
* schannel: renegotiating SSL/TLS connection
* schannel: SSL/TLS connection renegotiated
< HTTP/1.1 403 Forbidden

Can someone please point me in the right direction if I’m doing something wrong?

Thank you

Hi there,

From your description it sounds like you on the right track. When testing with curl, can you test with this command below when the PEM formatted certificates - let us know if this makes any difference.

curl --cert cert.crt --key private.key -sv https://api.example.com/

Some very quick, rough research I found this - How to tell curl to use one client cert from the Windows Cert Store? - Super User which suggests “(Schannel only) Client certificates must be specified by a path expression to a certificate store. (Loading PFX is not supported; you can import it to a store first)”

If you are defining your cert/key in PFX format in your curl command, it sounds like it may not work, but my testing with this command above and PEM format, I’m confident works.

Hope this helps!

1 Like

Hello Damian,

thank you for your quick reply.

I have downloaded all 3 “versions” of the key (PEM, PKCS7, DER) and saved them as:
cert.crt
cert.pkcs
cert.der

I don’t think the extension of the files matters … it should work even if I don’t use any extension (at least I think so).

PEM content starts and ends with
-----BEGIN CERTIFICATE-----
-----END CERTIFICATE-----

PKCS starts/ends with
-----BEGIN PKCS7-----
-----END PKCS7-----

Only DER looks completely different and I have no prior experience with that type of certificate.

I tried your command on both PEM and PKCS versions of the certificate, but unfortunately it still does not work. This is the error it returns:

  • Trying xxx.xxx.xxx.xxx:443…
  • Connected to my.domain.com (xxx.xxx.xxx.xxx) port 443
  • schannel: disabled automatic use of client certificate
  • schannel: Failed to import cert file .\cert.crt, last error is 0x80092002
  • Closing connection

I’am using this version of Curl if it makes any difference:

curl 8.4.0 (Windows) libcurl/8.4.0 Schannel WinIDN
Release-Date: 2023-10-11
Protocols: dict file ftp ftps http https imap imaps pop3 pop3s smtp smtps telnet tftp
Features: AsynchDNS HSTS HTTPS-proxy IDN IPv6 Kerberos Largefile NTLM SPNEGO SSL SSPI threadsafe Unicode UnixSockets

I tried the process described in the link you provided. Managed to import the PKCS version of the cert into my Windows cert manager.

When I call Curl now, it returns this:

curl.exe --cert CurrentUser\\MY\\032029a98a0dcaa02dfd1164de108f1c8dc9f829 https://my.domain.com/
curl: (35) schannel: AcquireCredentialsHandle failed: SEC_E_NO_CREDENTIALS (0x8009030E) - V balíčku zabezpečení nejsou k dispozici žádné přihlašovací údaje.

I do think we’re dealing with a client issue here rather than something not being configured correctly on Cloudflare. Unfortunately I don’t have Windows, so I have no way to test and replicate with a Windows version of curl you are using.

Are you able to install WSL - Install WSL | Microsoft Learn ?

If you could test with a Linux version of curl, see if we have a change in behavior - then we know we’re dealing with a window curl/library problem.

1 Like

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.

Iam following up on a quite rudely closed Topic:
using-client-certificates-to-access-restricted-website

You are closing Topics after just 2 days of inactivity after last post? Really? You like, reply to my request before weekend and don’t even have the courtesy to wait till Monday? Wooow, did not see that one coming from a service like yours.

Nevertheless, I tried using WSL like Damian replied in my previous Topic. It got me slightly further, but ultimately I ended up coming short and was again blocked even though I successfully used the certificate (as far as I can tell).

Here is the reply if anyone even cares to continue this support ticket:

curl -v --cert client.pem --key client.key  https://my.domain.com/
*   Trying 188.114.96.10:443...
* Connected to my.domain.com (188.114.96.10) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
*  CAfile: /etc/ssl/certs/ca-certificates.crt
*  CApath: /etc/ssl/certs
* TLSv1.0 (OUT), TLS header, Certificate Status (22):
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS header, Certificate Status (22):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS header, Finished (20):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.2 (OUT), TLS header, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN, server accepted to use h2
* Server certificate:
*  subject: CN=domain.com
*  start date: May 13 06:59:58 2024 GMT
*  expire date: Aug 11 06:59:57 2024 GMT
*  subjectAltName: host "my.domain.com" matched cert's "*.domain.com"
*  issuer: C=US; O=Google Trust Services LLC; CN=GTS CA 1P5
*  SSL certificate verify ok.
* Using HTTP2, server supports multiplexing
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
* Using Stream ID: 1 (easy handle 0x556f2c785550)
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
> GET /Default.aspx HTTP/2
> Host: my.domain.com
> user-agent: curl/7.81.0
> accept: */*
>
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* old SSL session ID is stale, removing
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
< HTTP/2 403
< date: Mon, 03 Jun 2024 08:58:58 GMT
< content-type: text/html; charset=UTF-8
< content-length: 4517
< x-frame-options: SAMEORIGIN
< referrer-policy: same-origin
< cache-control: max-age=15
< expires: Mon, 03 Jun 2024 08:59:13 GMT
< report-to: {"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v4?s=4kwKLwPFwwLY93M0siIlQi1RY7z3s4xoAhydknN09Srsyg6XIRypPWoA9gHPVmT3Ti6HZASokLAc5hy8iIwkSi4fmCVOSG0SVirOpX3Jrr0j8N4UbLAPAhaE38k4oLVENn5ej2XTpSszLQ%3D%3D"}],"group":"cf-nel","max_age":604800}
< nel: {"success_fraction":0,"report_to":"cf-nel","max_age":604800}
< server: cloudflare
< cf-ray: 88de7c042a422798-PRG
< alt-svc: h3=":443"; ma=86400
<
* TLSv1.2 (IN), TLS header, Supplemental data (23):