1

我正在尝试在 Tomcat v10.0.x 中使用 HSM 中的密钥来使用 TLS。

tl; dr:请参阅下面的答案以及所有步骤。剩余部分留在下面以允许搜索算法找到它。

我想知道的是,a:(事物的宏伟计划)应该可行,并且 b:(细节)我在 server.xml 连接器中错过了什么?

<Connector port="8080" protocol="HTTP/1.1" redirectPort="8443"/>
<Connector 
  protocol="org.apache.coyote.http11.Http11NioProtocol" 
  port="8443" 
  SSLEnabled="true" 
  scheme="https" 
  secure="true" 
  clientAuth="false" 
  >
  <SSLHostConfig>
    protocols="TLSv1.2"
    >
    <Certificate 
      type="RSA" 
      certificateKeystoreType="PKCS11" 
      certificateKeystoreFile="" 
      certificateKeystoreProvider="SunPKCS11-CryptoServer"
      certificateKeystorePassword="123456" 
    />
  </SSLHostConfig>
</Connector>

当 Tomcat 启动时,我得到各种 NullPointerExceptions(取决于连接器中的内容)。例子:

27-Oct-2021 10:03:42.669 INFO [main] org.apache.coyote.AbstractProtocol.init Initializing ProtocolHandler ["https-openssl-nio-443"]
27-Oct-2021 10:03:42.869 WARNING [main] org.apache.tomcat.util.net.openssl.OpenSSLContext.init Error initializing SSL context
    java.lang.NullPointerException: Cannot read the array length because "src" is null

27-Oct-2021 15:16:20.406 WARNING [main] org.apache.tomcat.util.net.openssl.OpenSSLContext.init Error initializing SSL context
    java.lang.NullPointerException
            at java.base/java.util.Base64$Encoder.encode(Base64.java:289)
            at java.base/java.util.Base64$Encoder.encodeToString(Base64.java:343)
            at org.apache.tomcat.util.net.openssl.OpenSSLContext.addCertificate(OpenSSLContext.java:408)
            at org.apache.tomcat.util.net.openssl.OpenSSLContext.init(OpenSSLContext.java:250)

底层 HSM 已正确配置,并且在插槽 0 中具有可用的密钥/证书。SunPKCS11-CryptoServer 确实适用于密钥工具。当我启动 tomcat 时,HSM 日志文件中填充了我希望看到的信息。

如果我尝试通过 curl 使用端口,我会得到

curl -k -v --tlsv1.2 https://127.0.0.1:8080/
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to 127.0.0.1 (127.0.0.1) port 8080 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: /etc/ssl/certs
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* error:1408F10B:SSL routines:ssl3_get_record:wrong version number
* stopped the pause stream!
* Closing connection 0
curl: (35) error:1408F10B:SSL routines:ssl3_get_record:wrong version number

curl -k -v --tlsv1.2 https://127.0.0.1:8443
* Rebuilt URL to: https://127.0.0.1:8443/
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to 127.0.0.1 (127.0.0.1) port 8443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: /etc/ssl/certs
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* OpenSSL SSL_connect: SSL_ERROR_SYSCALL in connection to 127.0.0.1:8443
* stopped the pause stream!
* Closing connection 0
curl: (35) OpenSSL SSL_connect: SSL_ERROR_SYSCALL in connection to 127.0.0.1:8443

在日志中,我得到“在方法名称中发现无效字符”和十六进制值:

27-Oct-2021 15:22:58.552 INFO [http-nio-8080-exec-1] org.apache.coyote.http11.Http11Processor.service Error parsing HTTP request header
    Note: further occurrences of HTTP request parsing errors will be logged at DEBUG level.
    java.lang.IllegalArgumentException: Invalid character found in method name [0x..0x..0x.. ...]. HTTP method names must be tokens

尝试使用 nio 和 nio2。

我欢迎任何建议。

根据 dave_thompson 的建议,我补充说

sslImplementationName="org.apache.tomcat.util.net.jsse.JSSEImplementation"

现在,Tomcat 无一例外地启动了。但是,当我尝试卷曲时:

curl -k -v --tlsv1.2 https://127.0.0.1:8443
* Rebuilt URL to: https://127.0.0.1:8443/
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to 127.0.0.1 (127.0.0.1) port 8443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
    CApath: /etc/ssl/certs
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS alert, Server hello (2):
* error:14094438:SSL routines:ssl3_read_bytes:tlsv1 alert internal error
* stopped the pause stream!
* Closing connection 0
curl: (35) error:14094438:SSL routines:ssl3_read_bytes:tlsv1 alert internal error

curl -k -v --tlsv1.3 https://127.0.0.1:8443
* Rebuilt URL to: https://127.0.0.1:8443/
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to 127.0.0.1 (127.0.0.1) port 8443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
    CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS Unknown, Certificate Status (22):
* TLSv1.3 (IN), TLS handshake, Unknown (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS Unknown, Unknown (21):
* TLSv1.3 (IN), TLS alert, Server hello (2):
* error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure
* stopped the pause stream!
* Closing connection 0
curl: (35) error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure

Tomcat 日志没有显示任何内容,有趣的是,HSM 日志文件没有显示任何新数据。我希望看到对 HSM 的调用是 DH 密钥协议的一部分。

火狐回归

An error occurred during a connection to 127.0.0.1:8443. SSL peer was unable to negotiate an acceptable set of security parameters.

Error code: SSL_ERROR_HANDSHAKE_FAILURE_ALERT

并且, openssl s_client -connect localhost:8443,以防万一。这看起来像是可以协商的配置错误;虽然我可以确定问题,但我不确定在哪里需要进行哪些更改。

---
No client certificate CA names sent
Server Temp Key: X25519, 253 bits
---
SSL handshake has read 1324 bytes and written 307 bytes
Verification error: self signed certificate
---
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
Server public key is 3096 bit
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 18 (self signed certificate)
---

我通过添加在 Tomcat 实例中启用了 ssl:handshake

set "JAVA_OPTS=%JAVA_OPTS% -Djavax.net.debug=ssl:handshake"

到 {安装}\bin\catalina.bat。

而且......我什至不能。

javax.net.ssl|DEBUG|17|https-jsse-nio-8443-exec-1|2021-10-28 16:22:21.925 \
    PDT|CertificateMessage.java:262|Produced server Certificate handshake message (
"Certificates": [
  "certificate" : {
    "version"            : "v3",
    "serial number"      : "00 EB 48 4B 73 73 35 C6 D8",
    "signature algorithm": "SHA256withRSA",
    "issuer"             : "CN=localhost, OU=SysEng, O=UInc, L=Ca, S=Ca, C=US",
    "not before"         : "2021-10-28 16:20:07.000 PDT",
    "not  after"         : "2022-01-26 15:20:07.000 PST",
    "subject"            : "CN=localhost, OU=SysEng, O=UInc, L=Ca, S=Ca, C=US",
    "subject public key" : "RSA",
    "extensions"         : [
      {
        ObjectId: 2.5.29.14 Criticality=false
        SubjectKeyIdentifier [
        KeyIdentifier [
        0000: 91 84 8C 3A 49 C6 2E E4   95 D2 8F 84 97 34 2C 4E  ...:I........4,N
        0010: F2 B9 D2 D0                                        ....
        ]
        ]
      }
    ]}
]
)
javax.net.ssl|ERROR|17|https-jsse-nio-8443-exec-1|2021-10-28 16:22:21.945 \
    PDT|TransportContext.java:316|Fatal (INTERNAL_ERROR): Unsupported signature \
    algorithm: rsa_pss_rsae_sha256 (
"throwable" : {
  java.security.InvalidKeyException: RSA key must be at least 512 bytes
        at jdk.crypto.cryptoki/sun.security.pkcs11.P11PSSSignature.checkKeySize(P11PSSSignature.java:352)
        at jdk.crypto.cryptoki/sun.security.pkcs11.P11PSSSignature.engineInitSign(P11PSSSignature.java:480)


F:\Tomcat\apache-tomcat-10.0.12\bin>cxitool dev=3001@127.0.0.1 LogonPass=USR_0000,ask Group=* ListKeys

idx algo  size type     group                    name                             spec
--------------------------------------------------------------------------------------
1   RSA   3072 prv      SLOT_0000                                                 6
2   X509  0    cert     SLOT_0000                                                 7

跟进最优秀的 dave_thompson 的最新评论,我重新生成了密钥,因为我无法弄清楚为什么 3072 位密钥在 openssl 输出中报告 3096。我生成了一个 4096 位密钥(并修复了证书 -dname 中的一个问题),然后它就起作用了。

4

1 回答 1

1

Utimaco CryptoServer 的步骤:

将 HSM 配置为使用 PKCS11 R2 或 R3,具体取决于固件版本。可以让 R2 和 R3 配置“实时”并在 server.xml 文件中选择一个。

  1. 设置 CS_PKCS11_R2_CFG=c:\ProgramData\Utimaco\PKCS11_R2\cs_pkcs11_R2.cfg
  2. 设置 CS_PKCS11_R3_CFG=c:\ProgramData\Utimaco\PKCS11_R3\cs_pkcs11_R3.cfg
  3. 编辑相应的 .cfg 文件以指向您的 HSM(请参阅文档)
  4. 编辑“C:\Program Files\Java\-version-\conf\security\java.security”文件

security.provider.13=SunPKCS11 c:/ProgramData/Utimaco/PKCS11_R2/java_r2_sunp11.cfg security.provider.14=SunPKCS11 c:/ProgramData/Utimaco/PKCS11_R3/java_r3_sunp11.cfg

  1. 使用以下模式创建两个 java_r#_sunp11.cfg 文件:
name = CryptoServerR2
description = SunPKCS11 provider offload to CryptoServer PKCS11 R2 library
library = {path_to}\cs_pkcs11_R2.dll
# library = {path_to}\cs_pkcs11_R3.dll

# Set slotListIndex to the slot (SLOT_xxxx), where SLOT_0003 would be 3
slotListIndex = 0

attributes(*,*,CKK_EC) = {
    CKA_DERIVE = true
}
attributes(generate,*,CKK_GENERIC_SECRET) = {
    CKA_SENSITIVE = false
    CKA_EXTRACTABLE = true
}

{path_to} 将根据您用于安装工具的安装程序版本而改变。

  1. 使用 Java 密钥工具在 HSM 中生成密钥。此示例使用上述第 4 步和第 5 步中的 R2 配置,请务必正确个性化 -dname。
somepath> keytool -genkey -keyalg RSA -keysize 4096 -keystore NONE -storetype PKCS11 \
    -storepass {passphrase} -providername SunPKCS11-CryptoServerR2 -alias tomcat_demo \
    -dname "CN=localhost,OU=SysEng,O=UInc,L=Locality,S=StateOrProvince,C=Country"

此时,Java 被配置为通过安全提供程序列表使用 PKCS11 库。

  1. 通过 server.xml 文件配置 tomcat。请注意,“密码”元素可能不是必需的,或者可能过于松散或过于严格。
    <Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443"/>
    <Connector 
      protocol="org.apache.coyote.http11.Http11NioProtocol"
      sslImplementationName="org.apache.tomcat.util.net.jsse.JSSEImplementation"
      port="8443" 
      SSLEnabled="true" 
      maxThreads="150" 
      scheme="https" 
      secure="true" 
      clientAuth="false"
      >
        <SSLHostConfig
          protocols="TLSv1.2"
          ciphers="TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
            TLS_RSA_WITH_AES_128_CBC_SHA,
            TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
            TLS_RSA_WITH_AES_128_CBC_SHA256,
            TLS_RSA_WITH_AES_128_GCM_SHA256,
            TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
            TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
            TLS_RSA_WITH_AES_256_CBC_SHA,
            TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
            TLS_RSA_WITH_AES_256_CBC_SHA256,
            TLS_RSA_WITH_AES_256_GCM_SHA384,
            TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
            TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"
          >
          <Certificate 
            type="RSA" 
            certificateKeystoreType="PKCS11" 
            certificateKeystoreFile="" 
            certificateKeystoreProvider="SunPKCS11-CryptoServerR2"
            certificateKeystorePassword="{passphrase}" 
            certificateKeyAlias="tomcat_demo"
          />
        </SSLHostConfig>
    </Connector>

使用 startup.bat 脚本启动 Tomcat 并观察输出中的异常。

假设它已启动,您可以使用 curl 测试访问。-k 表示“--insecure”,但忽略上面创建的自签名证书。

curl -k -v --tlsv1.2 https://localhost:8443
于 2021-10-29T15:48:22.980 回答