We are trying to create a node.js application which should interact with a server over HTTPS (>TLS v1.2). We are given some list of key, cert files to establish a connection with the server. Node HTTPS requires CA, cert, key files which are CA file, client certificate, and key files. When provided these we are getting the following error:
Error: unhandled critical extension.
After spending some time on the internet, we found that the Server cert that was received at the time of TLS handshake has some custom extensions. Later when we did openssl verify -CAfile ca_file.pem client_cert.pem
we could reproduce it:
error 34 at 0 depth lookup:unhandled critical extension
OK
So, this seems something to do with OpenSSL. How do we make OpenSSL understand our custom extensions? Those custom extensions are critical as well, so that we cannot just ignore the error by setting -ignore_critical
.
Edit:
CA certificate has the following in its X509v3 extensions
section,
X509v3 extensions:
X509v3 Subject Key Identifier:
A1:*:*:*...
X509v3 Authority Key Identifier:
keyid:1D:*:*:*
X509v3 Basic Constraints: critical
CA:TRUE, pathlen:0
X509v3 Key Usage:
Digital Signature, Certificate Sign, CRL Sign
Server certificate has the following in its X509v3 extensions
section,
X509v3 extensions:
X509v3 Basic Constraints:
CA:FALSE
Netscape Cert Type:
SSL Client
X509v3 Key Usage:
Digital Signature, Non Repudiation, Key Encipherment
X509v3 Subject Key Identifier:
E1:*:*...
X509v3 Authority Key Identifier:
keyid:F9:*:*:*...
X509v3 Extended Key Usage:
TLS Web Client Authentication
1.3.*.*.*...: critical
02.
TYPE:TEST..FCC_ID:12345..DP_ID:54321
1.3.*.*.*...: critical
..NULL:TRUE
The CA certificate don't have the X509v3 Extended Key Usage
section.
Years later this question still exists and has no (satisfying) answer...
[TL;DR]
From the OpenSSL documentation X509_VERIFY_PARAM_set_flags:
In Node.js HTTPS/TLS Server, a workaround can be to set the
rejectUnauthorized
option to false. If the client certificate is rejected (checked fromreq.client.authorized
during request), we can manually re-check (may be with pkijs, node-forge or other x509 certificate aware packages), ignoring offending extensions.The long journey to come to this conclusion:
In Node.js HTTPS/TLS Server, the option controlling the client certificate verification is
requestCert
. Tracked down to 'crypto_tls.cc' file, this option is used bySSL_set_verify()
:The certificate validation will be done in
crypto_common.cc
. The functionSSL_get_peer_certificate
will callVerifyCallback
.From the OpenSSL documentation SSL_set_verify:
But in Node.js 'crypto_util.cc' file:
So:
X509_V_FLAG_IGNORE_CRITICAL
flag in production),ctx
to see which error occurred (no JS callback).Note: quotes from Node.js version 13.18.0 and OpenSSL version 3.1.2