I'm trying to use TLS using a key in an HSM, in Tomcat v10.0.x .
tl;dr: See my answer below with all the steps. Remainder is left below to allow search algorithms to find it.
What I'm wondering is, a: (grand scheme of things) should this work, and b: (specifics) what did I miss in the server.xml connectors?
<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>
When Tomcat starts, I get various NullPointerExceptions (depending on what's in the connector). Examples:
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
and
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)
The underlying HSM is correctly configured and has a key/certificate available in slot 0. SunPKCS11-CryptoServer does work for the keytool. When I start tomcat, the HSM logfile is populated with information that I expect to see.
If I try to use the port via curl, I get
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
and
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
And in the log, I get "invalid character found in method name" and hex values:
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
Tried with nio and nio2.
I would welcome any suggestions.
Per dave_thompson's suggestion, I added
sslImplementationName="org.apache.tomcat.util.net.jsse.JSSEImplementation"
Now, Tomcat starts without an exception. When I try to curl to it, however:
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
The Tomcat log shows nothing, and, interestingly, the HSM log file does not show any new data. I would expect to see a call to the HSM as part of the DH key agreement.
Firefox returns
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
And, openssl s_client -connect localhost:8443, in case this helps. This looks like a config error on what can be negotiated; while I can identify the problem I'm not sure what changes are needed where.
---
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)
---
I enabled ssl:handshake in the Tomcat instance by adding
set "JAVA_OPTS=%JAVA_OPTS% -Djavax.net.debug=ssl:handshake"
to {install}\bin\catalina.bat.
And ... i can't even.
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
Following up on the latest comments from the most excellent dave_thompson, I regenerated the key because I couldn't figure out why a 3072 bit key was reporting 3096 in the openssl output. I generated a 4096 bit key (and fixed a problem in the certificate -dname) and then it worked.