未处理的关键扩展

问题描述 投票:0回答:1

我们正在尝试创建一个node.js应用程序,它应该通过HTTPS(>TLS v1.2)与服务器交互。我们得到了一些密钥、证书文件的列表来建立与服务器的连接。节点 HTTPS 需要 CA、证书、密钥文件,即 CA 文件、客户端证书和密钥文件。当提供这些时,我们收到以下错误:

Error: unhandled critical extension.

在互联网上花了一些时间后,我们发现在 TLS 握手时收到的服务器证书有一些自定义扩展。后来当我们这样做时

openssl verify -CAfile ca_file.pem client_cert.pem
我们可以重现它:

error 34 at 0 depth lookup:unhandled critical extension
OK

所以,这似乎与 OpenSSL 有关。我们如何让 OpenSSL 理解我们的自定义扩展?这些自定义扩展也很重要,因此我们不能通过设置

-ignore_critical
来忽略错误。

编辑:

CA 证书的

X509v3 extensions
部分包含以下内容,

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

服务器证书的

X509v3 extensions
部分包含以下内容,

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

CA 证书没有

X509v3 Extended Key Usage
部分。

node.js ssl openssl tls1.2
1个回答
0
投票

多年后这个问题仍然存在,并且没有(令人满意的)答案......

[长话;博士]

来自 OpenSSL 文档X509_VERIFY_PARAM_set_flags

[对于 OpenSSL,] 默认情况下,证书中的任何 未处理的关键扩展 [...] 都会导致 致命错误

在 Node.js HTTPS/TLS 服务器中,解决方法是将

rejectUnauthorized
选项设置为 false。如果客户端证书被拒绝(在请求期间从
req.client.authorized
检查),我们可以手动重新检查(可能使用 pkijs、node-forge 或其他 x509 证书感知包),忽略有问题的扩展。


经过漫长的旅程才得出这个结论:

在 Node.js HTTPS/TLS 服务器中,控制客户端证书验证的选项是

requestCert
。 追踪到“crypto_tls.cc”文件,该选项由
SSL_set_verify()
使用:

// extracted from 'src/crypto/crypto_tls.cc', for 'requestCert' = true
void TLSWrap::SetVerifyMode(const FunctionCallbackInfo<Value>& args) {
    // ...
    verify_mode = SSL_VERIFY_PEER;
    // ...
    SSL_set_verify(wrap->ssl_.get(), verify_mode, VerifyCallback);
}

证书验证将在

crypto_common.cc
中完成。函数
SSL_get_peer_certificate
将调用
VerifyCallback

// extracted from 'src/crypto/crypto_common.cc'
long VerifyPeerCertificate(  // NOLINT(runtime/int)
  const SSLPointer& ssl,
  long def) {  // NOLINT(runtime/int)
    long err = def;  // NOLINT(runtime/int)
    if (X509* peer_cert = SSL_get_peer_certificate(ssl.get())) {
        X509_free(peer_cert);
        err = SSL_get_verify_result(ssl.get());
        // ...
        }
    return err;
}

来自 OpenSSL 文档SSL_set_verify

verify_callback 函数用于控制设置 SSL_VERIFY_PEER 标志时的行为。它必须由应用程序提供并接收两个参数: preverify_ok 指示相关证书的验证是否通过 (preverify_ok=1) 或未通过 (preverify_ok=0)。 x509_ctx 是指向用于证书链验证的完整上下文的指针。

但是在 Node.js 'crypto_util.cc' 文件中:

// extracted from 'src/crypto/crypto_util.cc'
int VerifyCallback(int preverify_ok, X509_STORE_CTX* ctx) {
    return 1;
}

所以:

  • 我们无法调整验证标志(没有 JS 选项,我们不应该在生产中使用
    X509_V_FLAG_IGNORE_CRITICAL
    标志),
  • 我们无法从
    ctx
    检索错误信息来查看发生了哪个错误(没有 JS 回调)。

注意:引自 Node.js 版本 13.18.0 和 OpenSSL 版本 3.1.2

© www.soinside.com 2019 - 2024. All rights reserved.