KeyUsage does not allow digital signatures - java

I'm trying to send HTTPS request from my Java EE program to the host that requires certificate authentication. I have a proper keystore file, truststore with imported CA, the listing of both shows that certificates are inside.
But I receive the following error:
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: KeyUsage does not allow digital signatures
at ...
...
Caused by: sun.security.validator.ValidatorException: KeyUsage does not allow digital signatures
at sun.security.validator.EndEntityChecker.checkTLSServer(EndEntityChecker.java:270)
at sun.security.validator.EndEntityChecker.check(EndEntityChecker.java:141)
at sun.security.validator.Validator.validate(Validator.java:264)
at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:326)
at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:231)
at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:126)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1319)
... 29 more
Viewing the certificate contents in the part of Extensions I see the following:
Extensions:
#1: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 33 87 72 1D 09 2F DF FF 1A A7 D1 C0 E1 CF C5 FA 3.r../..........
0010: A4 19 54 2E ..T.
]
]
#2: ObjectId: 2.16.840.1.113730.1.1 Criticality=false
NetscapeCertType [
SSL client
]
#3: ObjectId: 2.5.29.35 Criticality=false
AuthorityKeyIdentifier [
KeyIdentifier [
0000: 74 9F 43 07 CC 75 FA D3 D0 13 0F 65 36 CC 4A 9A t.C..u.....e6.J.
0010: E0 8E 9C 52 ...R
]
]
#4: ObjectId: 2.5.29.31 Criticality=false
CRLDistributionPoints [
[DistributionPoint:
[URIName: http://test.az:7447/Test%20CA.crl]
]]
#5: ObjectId: 2.5.29.15 Criticality=true
KeyUsage [
DigitalSignature
]
So my certificate does contain KeyUsage [ DigitalSignature ]
The code snippet of the place throwing the exception looks like the following:
private final static int KU_SIGNATURE = 0;
...
private void checkTLSServer(X509Certificate cert, String parameter)
throws CertificateException {
Set<String> exts = getCriticalExtensions(cert);
...
} else if (KU_SERVER_SIGNATURE.contains(parameter)) {
if (checkKeyUsage(cert, KU_SIGNATURE) == false) {
throw new ValidatorException
("KeyUsage does not allow digital signatures",
ValidatorException.T_EE_EXTENSIONS, cert);
}
}
...
}
and checkKeyUsage function:
private boolean checkKeyUsage(X509Certificate cert, int bit)
throws CertificateException {
boolean[] keyUsage = cert.getKeyUsage();
if (keyUsage == null) {
return true;
}
return (keyUsage.length > bit) && keyUsage[bit];
}
it fails in return (keyUsage.length > bit) && keyUsage[bit];
The question is why the result of above expression = false? When bit = 0 and cert.getKeyUsage() must return an array of boolean [true, false, false, false, false, false, false, false, false]

The error actually comes from verifying the server's certificate. That certificate has a key usage section that doesn't include a digitalSignature bit.
Some cipher suites require the digital signature bit, specifically Diffie-Hellman key exchange (DHE_RSA and ECDHE_RSA). You may be able to avoid this error by avoiding those cipher types. Otherwise the server certificate needs to support it.

this error happened also to me and while the answer of #Chris D is correct I thought about giving you a way to overcome this issue.
We are in a situation where our Java application has to talk with a server through HTTPS. If we are able to tune this server's TLS we can solve the issue.
Basically we need to disable all the ciphers based on Diffie Hellman on the HTTPS server. You need to exclude all ciphers which contain DH.
In case of Haproxy I used these directives:
global
ssl-default-bind-ciphers AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA
ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
In case of a Java HTTPS server I've set this env var:
SERVER_SSL_CIPHERS=TLS_RSA_WITH_AES_128_GCM_SHA256:TLS_RSA_WITH_AES_256_GCM_SHA384:TLS_RSA_WITH_AES_128_CBC_SHA256:TLS_RSA_WITH_AES_256_CBC_SHA256:TLS_RSA_WITH_AES_128_CBC_SHA:TLS_RSA_WITH_AES_256_CBC_SHA:TLS_RSA_WITH_3DES_EDE_CBC_SHA
which will then be translated to the Java property server.ssl.ciphers
If you want to force some ciphers on the client-side, this SO question might be what you're looking for Java - How can I disable a TLS cipher for only some protocols using JVM Config?

Confirming that this behavior is still the same for the latest JRE version (19).
There seems to be another way how to avoid the problem (beside the one mentioned by Chris D). It looks like when a trust anchor is present inside the truststore java does not trigger the checks responsible for throwing the described exception and blindly trust to the server's certificate.
The related code can be saw here:
https://github.com/openjdk/jdk/blob/4cec141a90bc5d3b8ec17c024291d9c74a112cd4/src/java.base/share/classes/sun/security/validator/Validator.java#L259
This means importing the server's certificate directly into the java's truststore resolves the issue.

Related

How do I get OpenJDK 16 to talk with an SSL enabled nginx server?

I'm running a spring boot application that needs to make an https call to an nginx server. The application is running on CentOS 7 with OpenJDK 16.
Following this more or less, I gathered a list of all the ciphers available to the JVM:
TLS_AES_256_GCM_SHA384
TLS_AES_128_GCM_SHA256
TLS_CHACHA20_POLY1305_SHA256
TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256
TLS_DHE_DSS_WITH_AES_256_GCM_SHA384
TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
TLS_DHE_DSS_WITH_AES_128_GCM_SHA256
TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
TLS_DHE_DSS_WITH_AES_256_CBC_SHA256
TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
TLS_DHE_DSS_WITH_AES_128_CBC_SHA256
TLS_DHE_RSA_WITH_AES_256_CBC_SHA
TLS_DHE_DSS_WITH_AES_256_CBC_SHA
TLS_DHE_RSA_WITH_AES_128_CBC_SHA
TLS_DHE_DSS_WITH_AES_128_CBC_SHA
TLS_RSA_WITH_AES_256_GCM_SHA384
TLS_RSA_WITH_AES_128_GCM_SHA256
TLS_RSA_WITH_AES_256_CBC_SHA256
TLS_RSA_WITH_AES_128_CBC_SHA256
TLS_RSA_WITH_AES_256_CBC_SHA
TLS_RSA_WITH_AES_128_CBC_SHA
TLS_EMPTY_RENEGOTIATION_INFO_SCSV
In nginx, I have the following:
ssl_certificate /etc/ssl/cert;
ssl_certificate_key /etc/ssl/key;
ssl_protocols TLSv1.2 TLSv1.3;
resolver 169.254.169.253;
ssl_prefer_server_ciphers off;
ssl_ciphers ...keys here...;
ssl_session_timeout 10m;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
add_header Strict-Transport-Security "max-age=63072000; includeSubdomains";
ssl_dhparam /etc/ssl/dhparam;
I've tried every one of the ciphers available to my JVM in place of ...keys here... and they all result in nginx failing to start with:
nginx: [emerg] SSL_CTX_set_cipher_list("...") failed (SSL: error:1410D0B9:SSL routines:SSL_CTX_set_cipher_list:no cipher match)
I can add a list more like I would expect, such as:
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
nginx starts at this point - and most applications like Chrome, wget, etc are fine with it. Oracle's JDK 11 on my laptop also connects to it without issue. However the OpenJDK based application refuses to connect:
"ClientHello": {
"client version" : "TLSv1.2",
"random" : "1F F7 66 B2 EB 52 F0 3A 99 E6 9B A7 10 1A 85 E1 0C FF DC 36 06 C7 52 38 0C 8A 27 9F 21 AA 0E 7D",
"session id" : "70 E0 79 AB 78 7B 48 22 41 22 1E 38 64 01 BF E8 7D E0 2C DD BA 08 09 00 20 B2 39 8D 53 B4 65 A2",
"cipher suites" : "[TLS_AES_256_GCM_SHA384(0x1302), TLS_AES_128_GCM_SHA256(0x1301), TLS_CHACHA20_POLY1305_SHA256(0x1303), TLS_DHE_RSA_WITH_AES_256_GCM_SHA384(0x009F), TLS_DHE_DSS_WITH_AES_256_GCM_SHA384(0x00A3), TLS_DHE_RSA_
WITH_AES_128_GCM_SHA256(0x009E), TLS_DHE_DSS_WITH_AES_128_GCM_SHA256(0x00A2), TLS_DHE_RSA_WITH_AES_256_CBC_SHA256(0x006B), TLS_DHE_DSS_WITH_AES_256_CBC_SHA256(0x006A), TLS_DHE_RSA_WITH_AES_128_CBC_SHA256(0x0067), TLS_DHE_DSS_WITH_AE
S_128_CBC_SHA256(0x0040), TLS_DHE_RSA_WITH_AES_256_CBC_SHA(0x0039), TLS_DHE_DSS_WITH_AES_256_CBC_SHA(0x0038), TLS_DHE_RSA_WITH_AES_128_CBC_SHA(0x0033), TLS_DHE_DSS_WITH_AES_128_CBC_SHA(0x0032), TLS_RSA_WITH_AES_256_GCM_SHA384(0x009D
), TLS_RSA_WITH_AES_128_GCM_SHA256(0x009C), TLS_RSA_WITH_AES_256_CBC_SHA256(0x003D), TLS_RSA_WITH_AES_128_CBC_SHA256(0x003C), TLS_RSA_WITH_AES_256_CBC_SHA(0x0035), TLS_RSA_WITH_AES_128_CBC_SHA(0x002F)]",
...
javax.net.ssl|DEBUG|1C|http-nio-8080-exec-7|2022-03-21 22:37:28.252 UTC|Alert.java:238|Received alert message (
"Alert": {
"level" : "fatal",
"description": "handshake_failure"
}
)
I also ran across this - I'm assuming this means that the JDK cipher named TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 for instance should be DHE-RSA-AES256-GCM-SHA384 in nginx/OpenSSL. So I tried a modified cipher list in nginx of:
ssl_ciphers DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA;
but still the same result. In the nginx logs:
2022/03/22 06:05:55 [info] 74#74: *22 SSL_do_handshake() failed (SSL: error:141F7065:SSL routines:final_key_share:no suitable key share) while SSL handshaking, client: #.#.#.#, server: 0.0.0.0:443
and in the Java service logs:
javax.net.ssl|DEBUG|18|http-nio-8080-exec-3|2022-03-22 06:05:56.332 UTC|ClientHello.java:652|Produced ClientHello handshake message (
"ClientHello": {
"client version" : "TLSv1.2",
"random" : "A9 28 13 AB 6F 82 B6 F1 88 E9 2C C9 CE 84 55 15 84 9E 25 E9 57 72 C3 BA CF 1C 9B 45 3D 13 28 7F",
"session id" : "5E F8 0E 52 83 A9 C2 AF DE 6C BD E4 D7 3C A5 FD D9 00 6F 1C D7 CA 07 E0 63 EF C4 24 CF 57 9F A1",
"cipher suites" : "[TLS_AES_256_GCM_SHA384(0x1302), TLS_AES_128_GCM_SHA256(0x1301), TLS_CHACHA20_POLY1305_SHA256(0x1303), TLS_DHE_RSA_WITH_AES_256_GCM_SHA384(0x009F), TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256(0xCCAA), TLS_DH
...
)
javax.net.ssl|DEBUG|18|http-nio-8080-exec-3|2022-03-22 06:05:56.334 UTC|Alert.java:238|Received alert message (
"Alert": {
"level" : "fatal",
"description": "handshake_failure"
}
)
javax.net.ssl|ERROR|18|http-nio-8080-exec-3|2022-03-22 06:05:56.335 UTC|TransportContext.java:361|Fatal (HANDSHAKE_FAILURE): Received fatal alert: handshake_failure (
"throwable" : {
javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:131)
...
I can't seem to find any good documentation on adding additional ciphers to the JVM, only enabling ones that are present but not enabled for some reason. I've seen some vague references to BouncyCastle, but unclear how to properly use that for this purpose, especially since I won't be creating the sockets myself (using a library that needs to make the call).
I also can't seem to figure out how to configure nginx/OpenSSL to enable additional ciphers to support what the Java application is expecting. I'm using nginx 1.21.6 and OpenSSL 1.1.1k.
So... How do I add/configure ciphers to make the two play well together?
For me, the issue came down to an outdated installation of OpenSSL.
I mistakenly read the OpenSSL version from the docker host (1.1.1x) instead of from the container (don't remember the version, but was from 2017). Unfortunately, this can't easily be updated in CentOS 7 - nothing from the package manager, and compiling from source runs into all sorts of issues. But once past those issues, the list of ciphers was about 5x as long and the connection worked fine.
I then switched to Ubuntu 20.04, which made the installation of OpenSSL much easier (1.1.1f comes standard from the package manager). SSL handshake went through as expected.
On to the next problem - even with a successful SSL negotiation, for some reason all SSL connections are timing out after 25ms... but that'll be another topic (here for anyone going down the same rathole as I am).

Hyperledger Fabric: TLS Internal Error using Fabric Gateway Java SDK

Fabric Version: v2.2.4
Fabric Gateway Version: v2.2.0
Currently, I am not using Fabric CA and docker. Instead, I am using OpenSSL to generate my own certificates. There is no problem using command line to join channel or invoke chaincode with TLS enabled (Server TLS).
However, when I try to invoke my chaincode using Fabric Gateway Java SDK with TLS, the peer shows:
2021-10-20 23:53:51.571 EDT [core.comm] ServerHandshake -> ERRO 411 Server TLS handshake failed in 731.664253ms with error remote error: tls: internal error server=PeerServer remoteaddress=127.0.0.1:48920
2021-10-20 23:53:51.648 EDT [core.comm] ServerHandshake -> ERRO 412 Server TLS handshake failed in 17.623962ms with error remote error: tls: internal error server=PeerServer remoteaddress=127.0.0.1:48924
2021-10-20 23:53:52.389 EDT [core.comm] ServerHandshake -> ERRO 413 Server TLS handshake failed in 31.834126ms with error remote error: tls: internal error server=PeerServer remoteaddress=127.0.0.1:48928
2021-10-20 23:53:53.013 EDT [core.comm] ServerHandshake -> ERRO 414 Server TLS handshake failed in 20.97883ms with error remote error: tls: internal error server=PeerServer remoteaddress=127.0.0.1:48932
2021-10-20 23:53:53.453 EDT [core.comm] ServerHandshake -> ERRO 415 Server TLS handshake failed in 27.840631ms with error remote error: tls: internal error server=PeerServer remoteaddress=127.0.0.1:48936
if I disable the TLS, the chaincode can be invoked and queried but it shows an error message and display the certificate of the peer:
04:45:56.020 [main] ERROR org.hyperledger.fabric.sdk.security.CryptoPrimitives - Cannot
validate certificate. Error is: Path does not chain with any of the trust anchors
Certificate[
[
Version: V3
Subject: CN=peer-telecom, OU=peer, O=peer0.telecom.com, ST=Wilayah Persekutuan Kuala Lumpur, C=MY
Signature Algorithm: SHA256withECDSA, OID = 1.2.840.10045.4.3.2
Key: Sun EC public key, 256 bits
public x coord: 63258922835963897769642318382353579773301130246303245867091942631050654760639
public y coord: 17014436126955018341557373411142402131278326611630973049174140241981148702177
parameters: secp256r1 [NIST P-256, X9.62 prime256v1] (1.2.840.10045.3.1.7)
Validity: [From: Mon Oct 18 04:30:10 EDT 2021,
To: Tue Oct 18 04:30:10 EDT 2022]
Issuer: CN=hyperledger-telecom, O=ica.hyperledger.telecom.com, ST=Wilayah Persekutuan Kuala Lumpur, C=MY
SerialNumber: [ 1000]
Certificate Extensions: 4
[1]: ObjectId: 2.5.29.35 Criticality=false
AuthorityKeyIdentifier [
KeyIdentifier [
0000: 70 2B 57 B5 7C 6A 38 DE AB 6F DD 7E C4 63 FE 39 p+W..j8..o...c.9
0010: 54 22 D9 F9 T"..
]
]
[2]: ObjectId: 2.5.29.19 Criticality=false
BasicConstraints:[
CA:false
PathLen: undefined
]
[3]: ObjectId: 2.5.29.15 Criticality=true
KeyUsage [
DigitalSignature
]
[4]: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 62 C2 4A FB 13 54 44 DF 15 AB 2B 09 78 4F 79 4A b.J..TD...+.xOyJ
0010: CB 37 1D D7 .7..
]
]
]
Algorithm: [SHA256withECDSA]
Signature:
0000: 30 44 02 20 2D 20 15 9D 53 D4 DE EF 56 0D E6 6D 0D. - ..S...V..m
0010: 04 DA 99 F8 0C AC D5 A7 87 66 51 04 23 A0 4D C2 .........fQ.#.M.
0020: C8 98 95 5C 02 20 5C A5 5A 2D 19 43 FA E8 C0 E1 ...\. \.Z-.C....
0030: 49 4E C0 DF C9 59 F8 10 34 D6 94 05 51 38 E9 17 IN...Y..4...Q8..
0040: C5 F1 20 1F 0C EC .. ...
]
Java Application code:
package org.example.contract;
import java.io.IOException;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.Files;
import java.util.concurrent.TimeoutException;
import java.security.InvalidKeyException;
import java.security.PrivateKey;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import org.hyperledger.fabric.gateway.Identities;
import org.hyperledger.fabric.gateway.Identity;
import org.hyperledger.fabric.gateway.Contract;
import org.hyperledger.fabric.gateway.ContractException;
import org.hyperledger.fabric.gateway.Gateway;
import org.hyperledger.fabric.gateway.Network;
import org.hyperledger.fabric.gateway.Wallet;
import org.hyperledger.fabric.gateway.Wallets;
public class Sample {
X509Certificate[] clientCert = null;
PrivateKey clientKey = null;
private static X509Certificate readX509Certificate(final Path certificatePath) throws IOException, CertificateException {
try (Reader certificateReader = Files.newBufferedReader(certificatePath, StandardCharsets.UTF_8)) {
return Identities.readX509Certificate(certificateReader);
}
}
private static PrivateKey getPrivateKey(final Path privateKeyPath) throws IOException, InvalidKeyException {
try (Reader privateKeyReader = Files.newBufferedReader(privateKeyPath, StandardCharsets.UTF_8)) {
return Identities.readPrivateKey(privateKeyReader);
}
}
public static void main(String[] args) throws IOException {
// Load an existing wallet holding identities used to access the network.
// A wallet stores a collection of identities
Path walletPath = Paths.get(".", "wallet");
Wallet wallet = Wallets.newFileSystemWallet(walletPath);
try {
Path credentialPath = Paths.get("/root","fabric","localtls","crypto-config", "peerOrganizations",
"org1.telecom.com", "users", "Admin#org1.telecom.com", "msp");
System.out.println("credentialPath: " + credentialPath.toString());
Path certificatePath = credentialPath.resolve(Paths.get("signcerts",
"Admin#org1.telecom.com-cert.pem"));
System.out.println("certificatePem: " + certificatePath.toString());
Path privateKeyPath = credentialPath.resolve(Paths.get("keystore",
"Admin#telecom.com.key"));
X509Certificate certificate = readX509Certificate(certificatePath);
PrivateKey privateKey = getPrivateKey(privateKeyPath);
Identity identity = Identities.newX509Identity("Org1MSP", certificate, privateKey);
String identityLabel = "Admin#org1.telecom.com";
wallet.put(identityLabel, identity);
System.out.println("Write wallet info into " + walletPath.toString() + " successfully.");
} catch (IOException | CertificateException | InvalidKeyException e) {
System.err.println("Error adding to wallet");
e.printStackTrace();
}
// Path to a common connection profile describing the network.
Path networkConfigFile = Paths.get("/root","fabric","localtls","connection.yaml");
String userName = "Admin#org1.telecom.com";
// Configure the gateway connection used to access the network.,
Gateway.Builder builder = Gateway.createBuilder()
.identity(wallet, userName)
.networkConfig(networkConfigFile);
// Create a gateway connection
try (Gateway gateway = builder.connect()) {
// Obtain a smart contract deployed on the network.
Network network = gateway.getNetwork("mychannel");
Contract contract = network.getContract("chaincode");
// Submit transactions that store state to the ledger.
byte[] createCarResult = contract.createTransaction("createMyAsset")
.submit("CAR", "Honda");
System.out.println(new String(createCarResult, StandardCharsets.UTF_8));
byte[] queryCar = contract.submitTransaction("readMyAsset", "CAR");
System.out.println(new String(queryCar, StandardCharsets.UTF_8));
} catch (ContractException | TimeoutException | InterruptedException e) {
e.printStackTrace();
}
}
}
connection.yaml:
name: "Network-Config-Test"
description: "The network used in the integration tests"
version: 1.0.0
client:
organization: telecom
organizations:
telecom:
mspid: Org1MSP
peers:
- peer0.org1.telecom.com
#adminPrivateKey:
#path: '/root/fabric/localtls/crypto-config/peerOrganizations/org1.telecom.com/users/Admin#org1.telecom.com/msp/keystore/Admin#telecom.com.key'
#signedCert:
#path: '/root/fabric/localtls/crypto-config/peerOrganizations/org1.telecom.com/users/Admin#org1.telecom.com/msp/signcerts/Admin#org1.telecom.com-cert.pem'
orderers:
orderer.example.com:
url: grpcs://localhost:6050
#client:
#keyfile: '/root/fabric/localtls/crypto-config/peerOrganizations/org1.telecom.com/users/Admin#org1.telecom.com/tls/client-o.key'
#certfile: '/root/fabric/localtls/crypto-config/peerOrganizations/org1.telecom.com/users/Admin#org1.telecom.com/tls/client-o.crt'
grpcOptions:
hostnameOverride: orderer.example.com
grpc-max-send-message-length: 15
grpc.keepalive_time_ms: 360000
grpc.keepalive_timeout_ms: 180000
negotiationType: TLS
sslProvider: openSSL
tlsCACerts:
path: /root/fabric/localtls/crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/tls/ca.crt
peers:
peer0.org1.telecom.com:
url: grpcs://localhost:7051
#client:
#keyfile: '/root/fabric/localtls/crypto-config/peerOrganizations/org1.telecom.com/users/Admin#org1.telecom.com/tls/client.key'
#certfile: '/root/fabric/localtls/crypto-config/peerOrganizations/org1.telecom.com/users/Admin#org1.telecom.com/tls/client.crt'
grpcOptions:
ssl-target-name-override: peer0.org1.telecom.com
grpc.http2.keepalive_time: 15
hostnameOverride: peer0.org1.telecom.com
negotiationType: TLS
sslProvider: openSSL
tlsCACerts:
path: /root/fabric/localtls/crypto-config/peerOrganizations/org1.telecom.com/peers/peer0.org1.telecom.com/tls/ca.crt
What am I missing? Any answer is welcomed!
Update 1.0
These are the certificates generated by using openSSL, they work when I use command line (I ommitted the hf thing in the Subject Alternative Name, not sure is it important for the application to work?):
The tlscacert:
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
1f:a5:9f:1a:01:ed:c7:3d:30:ca:27:b6:79:9c:82:10:b8:94:84:23
Signature Algorithm: ecdsa-with-SHA256
Issuer: C = MY, ST = Wilayah Persekutuan Kuala Lumpur, L = Kuala Lumpur, O = rca.verisign.com, CN = tls-verisign
Validity
Not Before: Oct 21 03:11:13 2021 GMT
Not After : Oct 19 03:11:13 2031 GMT
Subject: C = MY, ST = Wilayah Persekutuan Kuala Lumpur, L = Kuala Lumpur, O = rca.verisign.com, CN = tls-verisign
Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey
Public-Key: (256 bit)
pub:
04:34:b5:ac:a3:42:8c:d4:17:97:ca:16:d5:2f:7a:
00:32:bf:fd:dd:02:8a:33:28:ed:c0:53:5d:e0:42:
79:0d:08:43:1c:22:83:1e:f0:71:91:08:d6:c3:ec:
eb:ac:9c:56:00:da:e8:08:cf:ad:4c:b3:46:e7:e1:
39:1c:5f:bf:fc
ASN1 OID: prime256v1
NIST CURVE: P-256
X509v3 extensions:
X509v3 Subject Key Identifier:
EB:7B:8E:23:26:A7:17:3D:E0:0B:8D:B4:6E:6C:5D:D5:EE:EF:80:AF
X509v3 Authority Key Identifier:
keyid:EB:7B:8E:23:26:A7:17:3D:E0:0B:8D:B4:6E:6C:5D:D5:EE:EF:80:AF
X509v3 Basic Constraints: critical
CA:TRUE
X509v3 Key Usage: critical
Digital Signature, Key Encipherment, Certificate Sign, CRL Sign
Signature Algorithm: ecdsa-with-SHA256
30:45:02:20:63:40:88:2d:c8:51:e5:42:2b:d3:98:60:6f:1e:
3c:d2:f6:59:48:bb:0c:7c:10:b6:28:27:86:20:58:35:0b:19:
02:21:00:c7:87:df:79:75:21:8d:bf:bc:be:aa:c9:44:53:b5:
b4:32:4d:06:2b:a0:05:eb:38:b7:9f:3d:71:80:17:77:69
The Peer TLS cert:
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 4097 (0x1001)
Signature Algorithm: ecdsa-with-SHA256
Issuer: C = MY, ST = Wilayah Persekutuan Kuala Lumpur, L = Kuala Lumpur, O = rca.verisign.com, CN = tls-verisign
Validity
Not Before: Oct 21 03:11:13 2021 GMT
Not After : Oct 21 03:11:13 2022 GMT
Subject: C = MY, ST = Wilayah Persekutuan Kuala Lumpur, O = tls.peer.telecom.com, CN = tls-peer-telecom
Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey
Public-Key: (256 bit)
pub:
04:76:c2:e9:94:10:03:2c:3b:2d:90:56:e8:b5:30:
bf:67:f6:b5:b8:9c:73:cd:28:b3:f2:f7:21:e9:f7:
6c:66:38:a9:e8:7c:b0:ea:67:fb:f7:db:72:29:9d:
aa:56:20:92:ab:b1:e5:53:2a:a1:19:0b:0c:8b:65:
36:fe:98:aa:e1
ASN1 OID: prime256v1
NIST CURVE: P-256
X509v3 extensions:
X509v3 Basic Constraints: critical
CA:FALSE
X509v3 Key Usage: critical
Digital Signature, Key Encipherment
X509v3 Extended Key Usage:
TLS Web Client Authentication, TLS Web Server Authentication
X509v3 Subject Key Identifier:
08:9D:B8:81:4B:39:0D:B1:D4:BD:EC:49:E5:AC:BA:FB:F1:7A:58:51
X509v3 Authority Key Identifier:
keyid:EB:7B:8E:23:26:A7:17:3D:E0:0B:8D:B4:6E:6C:5D:D5:EE:EF:80:AF
X509v3 Subject Alternative Name:
IP Address:127.0.0.1
Signature Algorithm: ecdsa-with-SHA256
30:46:02:21:00:c0:d7:26:b4:e9:30:08:b5:37:46:66:0f:fb:
b6:36:22:04:5f:78:ab:ae:ff:7f:48:e0:7b:ff:e8:f0:88:b4:
e5:02:21:00:86:64:ec:c8:9b:b4:06:b5:3d:d3:c1:54:4f:d2:
a2:bb:1a:e1:a7:e7:84:28:9a:ef:ac:db:ab:65:95:0d:10:2d
The only thing I am missing in the cert is:
1.2.3.4.5.6.7.8.1:
{"attrs":{"hf.Affiliation":"","hf.EnrollmentID":"peer0","hf.Type":"peer"}}
Is this only being used by the Fabric CA? Or it is a must to include?
Fabric TLS certificates are very fiddly. For instance, we've found several cases where the peer and chaincode will accept a malformed cert, but the gateway client refuses to connect using the same certificate. What is probably happening is that you have a problem with the openssl generated cert, but the peer is too lax to report the error. (It also doesn't help that the client TLS libraries simply disconnect, without reporting on the root failure during the handshake.)
In the example above, the cert output shows some differences in PathLen and KeyUsage attributes that differ from what are normally generated by a Fabric CA.
Here are some ideas and techniques that we've found to be useful in debugging TLS handshake issues with the gateway / client SDKs. Try to use these techniques to close any gaps between your certs and the reference certs generated by the Fabric CAs:
Use the Fabric CAs. Even if you plan to generate a certificate chain using OpenSSL and an external authority, you can use the Fabric CAs to generate TLS enrollments and certificates, and compare the reference certs against what you have built up with OpenSSL.
Use curl, or other TLS-enabled clients to help verify the correctness of a certificate. In many cases the errors output by an independent client are directly applicable to the failed TLS handshake when connecting the fabric client.
Use the test-network-k8s system as a reference for setting up the TLS and CA infrastructure. In addition to a "push button" test network, this will provide CA endpoints that can be used to generate reference enrollments / certificates for study.
Inspect the certificates generated by the Fabric CAs, and compare against your hand-crafted certs. For example, here is a certificate dump from a TLS cert generated with the Kube test network - make sure your OpenSSL certs have the same, or similar feature sets and attributes.
$ openssl x509 -in /tmp/ca-cert.pem -text
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
4c:63:74:d5:99:29:ce:e0:b6:28:a2:b5:a4:0e:a0:c1:f3:e9:a9:d5
Signature Algorithm: ecdsa-with-SHA256
Issuer: C=US, ST=North Carolina, O=Hyperledger, OU=Fabric, CN=fabric-ca-server
Validity
Not Before: Oct 21 10:36:00 2021 GMT
Not After : Oct 17 10:36:00 2036 GMT
Subject: C=US, ST=North Carolina, O=Hyperledger, OU=Fabric, CN=fabric-ca-server
Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey
Public-Key: (256 bit)
pub:
04:53:f4:ad:e6:6b:4c:75:7e:4a:6d:6e:cd:73:b0:
81:a8:d7:d7:55:c0:fd:22:92:15:fc:2d:20:44:c6:
ec:55:c9:cc:88:3a:14:09:77:e5:4f:4b:b8:98:ee:
71:09:da:e6:f8:7c:f7:39:fa:41:fc:f3:a2:fe:a4:
1e:34:ec:a9:b5
ASN1 OID: prime256v1
NIST CURVE: P-256
X509v3 extensions:
X509v3 Key Usage: critical
Certificate Sign, CRL Sign
X509v3 Basic Constraints: critical
CA:TRUE, pathlen:1
X509v3 Subject Key Identifier:
AB:AF:85:A3:D3:2E:9A:A9:03:49:F5:5C:30:32:2B:92:EC:92:B3:D0
X509v3 Subject Alternative Name:
IP Address:127.0.0.1
Signature Algorithm: ecdsa-with-SHA256
30:45:02:21:00:bf:cc:c1:d2:29:b1:04:3f:55:31:c6:b7:69:
ca:72:12:d7:67:55:14:cd:23:f7:75:16:6c:b1:63:7f:e6:9c:
24:02:20:5d:ff:e3:7e:84:22:d3:f3:52:bd:96:fa:dc:2d:94:
2f:6b:a3:bc:ab:3e:b3:87:10:fd:30:51:a2:4a:ca:ce:b4
-----BEGIN CERTIFICATE-----
MIICKDCCAc6gAwIBAgIUTGN01ZkpzuC2KKK1pA6gwfPpqdUwCgYIKoZIzj0EAwIw
aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK
EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt
Y2Etc2VydmVyMB4XDTIxMTAyMTEwMzYwMFoXDTM2MTAxNzEwMzYwMFowaDELMAkG
A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl
cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy
dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEU/St5mtMdX5KbW7Nc7CBqNfX
VcD9IpIV/C0gRMbsVcnMiDoUCXflT0u4mO5xCdrm+Hz3OfpB/POi/qQeNOyptaNW
MFQwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE
FKuvhaPTLpqpA0n1XDAyK5LskrPQMA8GA1UdEQQIMAaHBH8AAAEwCgYIKoZIzj0E
AwIDSAAwRQIhAL/MwdIpsQQ/VTHGt2nKchLXZ1UUzSP3dRZssWN/5pwkAiBd/+N+
hCLT81K9lvrcLZQva6O8qz6zhxD9MFGiSsrOtA==
-----END CERTIFICATE-----

Java SSL handshake always get "PKIX path building failed" for any domain

I get this error message when build a gradle project in idea:
> Could not resolve io.spring.gradle:dependency-management-plugin:1.0.6.RELEASE.
> Could not get resource 'https://plugins.gradle.org/m2/io/spring/gradle/dependency-management-plugin/1.0.6.RELEASE/dependency-management-plugin-1.0.6.RELEASE.pom'.
> Could not HEAD 'https://plugins.gradle.org/m2/io/spring/gradle/dependency-management-plugin/1.0.6.RELEASE/dependency-management-plugin-1.0.6.RELEASE.pom'.
> sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
I found that all ssl handshack in java get the same error.
I use SSLPoke to check some domains, such as stackoverflow.com, github.com, all of them return the same error message: "PKIX path building failed". But I can visit this sites on the browser with no error.
I try to change the jdk from jdk11 to jdk8, and try to reinstall the jdk, but also get the same result. I check the default jdk keystore by keytool -list command, and it looks like no problem.
I try to debug and found that the certificate looks weird, it only has one cert in the cert chain, and the Issuer is always CN=GlobalSign Root CA, C=EN, no matter which domain. Such as stackoverflow.com:
[
[
Version: V3
Subject: CN=*.stackexchange.com
Signature Algorithm: SHA256withRSA, OID = 1.2.840.113549.1.1.11
Key: Sun RSA public key, 1024 bits
modulus: 129343236870246922217917428341848371602010941604981692235450252202393431416169367447480541321401904173442212978999107322095875009215075266308069463921433338673265672174736174633404814882397952490528363553362969976277321592285699339620492251079789709609773064124868826755702755848122392099215387700370904957487
public exponent: 65537
Validity: [From: Fri Jul 26 22:38:33 CST 2019,
To: Thu Oct 24 22:38:33 CST 2019]
Issuer: CN=GlobalSign Root CA, C=EN
SerialNumber: [ bae8be0e 04cb0e2b 0e83d26f c22ba1e7]
Certificate Extensions: 3
[1]: ObjectId: 2.5.29.19 Criticality=true
BasicConstraints:[
CA:false
PathLen: undefined
]
[2]: ObjectId: 2.5.29.37 Criticality=false
ExtendedKeyUsages [
serverAuth
clientAuth
]
[3]: ObjectId: 2.5.29.17 Criticality=false
SubjectAlternativeName [
DNSName: *.askubuntu.com
DNSName: *.blogoverflow.com
DNSName: *.mathoverflow.net
DNSName: *.meta.stackexchange.com
DNSName: *.meta.stackoverflow.com
DNSName: *.serverfault.com
DNSName: *.sstatic.net
DNSName: *.stackexchange.com
DNSName: *.stackoverflow.com
DNSName: *.stackoverflow.email
DNSName: *.superuser.com
DNSName: askubuntu.com
DNSName: blogoverflow.com
DNSName: mathoverflow.net
DNSName: openid.stackauth.com
DNSName: serverfault.com
DNSName: sstatic.net
DNSName: stackapps.com
DNSName: stackauth.com
DNSName: stackexchange.com
DNSName: stackoverflow.blog
DNSName: stackoverflow.com
DNSName: stackoverflow.email
DNSName: stacksnippets.net
DNSName: superuser.com
]
]
Algorithm: [SHA256withRSA]
Signature:
0000: B5 35 45 AA 8D 99 FF F1 3F 5D CA 94 6D 5F 6A 12 .5E.....?]..m_j.
0010: D2 39 0E 66 1D 11 63 80 12 0C A1 2D A7 CA A7 39 .9.f..c....-...9
0020: 36 4B A4 12 45 AD A8 4D E5 1E DD 7B AF A9 10 CD 6K..E..M........
0030: ED 5B 15 76 F2 49 41 F8 AB 82 67 5D E8 09 0A 65 .[.v.IA...g]...e
0040: 7D BC 22 C5 53 7D DD 32 15 9E 88 92 FB 35 C2 C8 ..".S..2.....5..
0050: 86 E0 53 BF 32 72 DA FA CE 27 A0 BA 78 5F DA B2 ..S.2r...'..x_..
0060: CA C3 8B 14 0B C5 EF E1 4D 96 8F BF 4A AC B0 DB ........M...J...
0070: 24 5E 20 7C 32 51 58 93 36 0B 1A 2A BB 88 A3 9B $^ .2QX.6..*....
0080: DF 6F B4 F1 25 CD B8 C6 C1 1D 19 BD A7 54 27 73 .o..%........T's
0090: 56 A8 5D 78 13 E6 86 00 59 E2 32 34 34 28 6D 4F V.]x....Y.244(mO
00A0: 30 39 F6 3A 2E 43 1F E6 7B 43 57 C2 79 E5 87 4C 09.:.C...CW.y..L
00B0: CB 9E 95 6D 99 6D 46 AD FA 7D 74 BA 12 D9 D0 8B ...m.mF...t.....
00C0: 93 B7 49 E4 61 FD 4B 73 00 FA 0E 61 9A 4E DA C1 ..I.a.Ks...a.N..
00D0: D3 B9 45 B1 79 13 BB 90 02 98 24 E7 4D 31 01 52 ..E.y.....$.M1.R
00E0: 1F 38 47 0B 4E 4C E0 91 2A 8A 05 6E 20 89 81 E3 .8G.NL..*..n ...
00F0: 3B E3 60 D5 70 DF 28 D3 58 E7 D6 FF A6 CA 1D B6 ;.`.p.(.X.......
]
Different to the normal cert:
Key length. Normal is 2048 bits, not 1024 bits.
Issuer. Normal is CN=Let's Encrypt Authority X3, O=Let's Encrypt, C=US
Certificate Extensions. Normal has 9 extensions, not 3.
modulus, SerialNumber, Signature. Their value is different to the normal.
Normal cert has a intermediate certificate in the cert chain, Issuer is CN=DST Root CA X3, O=Digital Signature Trust Co.
So, how can I find the real reason of the problem, and how to solve the problem.
Meta: not an answer yet but need space to respond to data
Aside: I assume you are in timezone +8. The PCAPs are 09-18 01:43:00-01 and 01:49:52-54 Z
while the Java-log timestamps are 09-18 09:42:59-43:01 and 09:49:51-54 CST.
First, the Java-logs. In the success log at line 3652, the ServerHello selects TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
and agrees to extensions renegotiation_info server_name ec_point_formats status_request extended_master_secret;
this is consistent with the real stackoverflow servers in my testing. In the fail log at 3651,
it selects TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 and agrees to only renegotiation_info ec_point_formats,
which is substantially different behavior. We then see the different certificates,
with success.txt getting the correct leaf cert (under Let's Encrypt) and chain cert (under DST),
and fail.txt getting the bogus cert under "CN=GlobalSign Root CA, C=EN" with most extensions missing, and no chain.
But as to the PCAPs:
See line 3638 in the fail log, the raw read bytes is different to the first five bytes of Transport Layer Security in the server hello response. In success log, they are the same.
That's not the only difference. Although the time matches,
your fail.PCAP doesn't match your fail.txt at all. Most importantly, it doesn't fail --
it receives the correct cert chain (Let's Encrypt + DST) and completes the handshake successfully.
In more detail:
the ClientHello is very different. It offers max TLS1.2, not TLS1.3 as offered by (your) Java.
It has a different list of ciphersuites, and different extensions (necessarily so for 1.2 vs 1.3),
among which are Heartbeat and ticket neither of which Java supports.
the ServerHello is shorter (record header 16 03 03 00 45 vs 16 03 03 00 59 in the fail.txt or 16 03 03 00 65 in the success.txt,
as you noticed) because it offered ticket and the server agreed, and thus the server does not provide a session-id.
(as above) it gets the good certs, as well as CertStatus ServerKX ServerDone,
and proceeds to send ClientKX CCS Finished and receive ticket CCS Finished -- i.e. success.
your client soon (but not instantly) RSTs without sending (or receiving) any data; this is the behavior of a Windows program that closes without doing shutdown (perhaps due to being killed) or a Unix program that explicitly sets linger=0 (which is unusual).
I also notice the fail.PCAP connection goes to 151.101.65.69 but the success.PCAP goes to 151.101.193.69.
Both of those addresses (and two others) are valid for stackoverflow.com, but usually connections
from the same machine within a short time window like this would resolve to and use the same address.
Look carefully at what you did for the fail.PCAP and see if you can get a PCAP that actually is a failure case.
Actually, an idea occurs here. DO YOU HAVE AN ANTIVIRUS OR OTHER 'ENDPOINT PROTECTION'? That might intercept the outgoing connection before it leaves your machine, so that the program (Java) sees the bogus cert even though the correct cert was actually fetched from the network. But there would still need to be a reason it intercepts one connection and not another.

Can't connect mongodb with ssl from server application

I'm having problems connecting to mongodb with ssl, first all I could connect mongodb with an application java without any problem, but when I connect from server application like Jetty with spring boot I can't connect to mongodb. Curiously I could connect to mongodb with eclipse.
Java code to connect:
String trustStorePath = "/path/ssl_keystore_mongodb";
String trustStorePassword = "somePassword";
String uri = "mongodb://admin:password#domain1:31251,domain2:31251/my-db?authSource=admin&ssl=true";
System.setProperty("javax.net.ssl.trustStore", trustStorePath);
System.setProperty("javax.net.ssl.trustStorePassword", trustStorePassword);
MongoClient mongoClient = new MongoClient(new MongoClientURI(uri);
Code works fine without server application but with server application the output is:
com.mongodb.MongoSocketWriteException: Exception sending message}, caused by {javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No subject alternative names matching IP address 169.47.75.121 found}, caused by {java.security.cert.CertificateException: No subject alternative names matching IP address 169.47.75.121 found}}, {address=sl-us-south-1-portal.14.dblayer.com:31251, type=UNKNOWN, state=CONNECTING, exception={com.mongodb.MongoSocketWriteException: Exception sending message}, caused by {javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No subject alternative names matching IP address xxx.xx.xx.xxx found}, caused by {java.security.cert.CertificateException: No subject alternative names matching IP address xxx.xx.xx.xxx found}}]
My ssl certificate:
Owner: CN=kbengtsson#efact.pe-4178203cf8de512257f4efeebac75b34
Issuer: CN=kbengtsson#efact.pe-4178203cf8de512257f4efeebac75b34
Serial number: 5a4d0994
Valid from: Wed Jan 03 11:49:24 PET 2018 until: Sun Jan 03 11:00:00 PET 2038
Certificate fingerprints:
MD5: 94:EC:B1:49:BB:56:B9:4B:E3:FC:D3:FE:74:C8:FA:D8
SHA1: EA:95:CC:45:43:E4:DA:12:EA:6C:D6:3F:8D:D3:0A:E6:C5:62:B3:96
SHA256: 9F:A9:AA:84:83:33:BB:B7:39:50:3A:8B:11:3D:B6:07:CD:7E:6D:C3:29:F8:9C:21:4C:B5:47:65:86:19:E7:73
Signature algorithm name: SHA512withRSA
Subject Public Key Algorithm: 2048-bit RSA key
Version: 3
Extensions:
#1: ObjectId: 2.5.29.35 Criticality=false
AuthorityKeyIdentifier [
KeyIdentifier [
0000: 61 71 23 3E FF 31 E2 D1 C0 D0 23 F6 4A 1F 0E 55 aq#>.1....#.J..U
0010: B3 28 1D 69 .(.i
]
]
#2: ObjectId: 2.5.29.19 Criticality=false
BasicConstraints:[
CA:true
PathLen:2147483647
]
#3: ObjectId: 2.5.29.37 Criticality=false
ExtendedKeyUsages [
serverAuth
clientAuth
]
#4: ObjectId: 2.5.29.15 Criticality=true
KeyUsage [
Key_CertSign
]
#5: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 61 71 23 3E FF 31 E2 D1 C0 D0 23 F6 4A 1F 0E 55 aq#>.1....#.J..U
0010: B3 28 1D 69 .(.i
]
]
The certificate is provided by IBM.
How can I solve this issue?
This Exception says that you're waiting for a certificate with a CN (or SAN) containing an IP instead of an FQDN. For any reason you're requesting https://169.47.75.121 instead of https://sl-us-south-1-portal.14.dblayer.com
How to solve ? By letting the DNS doing its job. Check all of your config files and code, if they contain this IP remove it. Check also your hosts files on each computer, add references where needed. If you still can't find why this happens, another method is to disable the certificate validation as explained in the doc Host name verification

How to disable constraint check (Netscape cert type) in Java6?

I am trying to build a custom HTTPS Server in Java (6) using the built in class com.sun.net.httpserver.HttpsServer. It works fine until I require client authentication. At that point it fails with the following exception in the SSL debug on the server.
sun.security.validator.ValidatorException: Netscape cert type does not permit use for SSL client
I am using certificates issued by our internal CA which is used for all applications internal to us. I checked the certificate details and found that type was "SSL Server" (details quoted below). Since our policy is to use a "SSL Server" type for all internal applications, it is difficult to change the cerificate. Since I want to use a Server certificate for Client, I don't believe this is a security issue.
What I am looking for is a way disable this constraint check in Java. Has anyone encountered this and solved this? Any help is highly appreciated.
Best Regards,
Arun
Owner: CN=myapp, OU=mygroup, O=mycompany
Issuer: O=MYCA
Serial number: 4cc8c1da
Valid from: Mon Jan 10 13:46:34 EST 2011 until: Thu Jan 10 14:16:34 EST 2013
Certificate fingerprints:
MD5: 8C:84:7F:7A:40:23:F1:B5:81:CD:F9:0C:27:16:69:5E
SHA1: 9B:39:0B:2F:61:83:52:93:D5:58:E5:43:13:7A:8F:E1:FD:AC:98:A4
Signature algorithm name: SHA1withRSA
Version: 3
Extensions:
[1]: ObjectId: 2.5.29.16 Criticality=false
PrivateKeyUsage: [
From: Mon Jan 10 13:46:34 EST 2011, To: Wed Jul 11 21:16:34 EDT 2012]
[2]: ObjectId: 2.5.29.15 Criticality=false
KeyUsage [
DigitalSignature
Key_Encipherment
]
[3]: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: D3 47 35 9B B4 B7 03 18 C6 53 2C B0 FE FD 49 D8 .G5......S,...I.
0010: D0 FB EE 15 ....
]
]
[4]: ObjectId: 1.2.840.113533.7.65.0 Criticality=false
[5]: ObjectId: 2.5.29.31 Criticality=false
CRLDistributionPoints [
[DistributionPoint:
[CN=CRL413, O=SWIFT]
]]
[6]: ObjectId: 2.5.29.19 Criticality=false
BasicConstraints:[
CA:false
PathLen: undefined
]
****[7]: ObjectId: 2.16.840.1.113730.1.1 Criticality=false
NetscapeCertType [
SSL server
]****
[8]: ObjectId: 2.5.29.35 Criticality=false
AuthorityKeyIdentifier [
KeyIdentifier [
0000: 8F AF 56 BC 80 77 A3 FD 9E D2 89 83 98 FE 98 C7 ..V..w..........
0010: 20 65 23 CC e#.
]
]
You could wrap the default trust managers and catch this particular exception. This would be something along these lines:
class IgnoreClientUsageTrustManager extends X509TrustManager {
private final X509TrustManager origTrustManager;
public class IgnoreClientUsageTrustManager(X509TrustManager origTrustManager) {
this.origTrustManager = origTrustManager;
}
public checkClientTrusted(X509Certificate[] chain, String authType
throws IllegalArgumentException, CertificateException {
try {
this.origTrustManager.checkClientTrusted(chain, authType);
} catch (ValidatorException e) {
// Check it's that very exception, otherwise, re-throw.
}
}
// delegate the other methods to the origTrustManager
}
Then, use that trust manager to create an SSLContext and use it with your server.
TrustManagerFactory tmf = TrustManagerFactory.getInstance(
TrustManagerFactory.getDefaultAlgorithm());
tmf.init((KeyStore)null);
TrustManager[] trustManagers = tmf.getTrustManagers();
for (int i = 0; i < trustManagers.length; i++) {
if (trustManagers[i] instanceof X509TrustManager) {
trustManagers[i] = IgnoreClientUsageTrustManager(trustManagers[i]);
}
}
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(... you keymanagers ..., trustManagers, null);
You should initialise your keymanagers from your server keystores (as normal). You should then be able to use the HttpsServer's HttpsConfigurator to set up the SSLContext (see example in the documentation).
This technique isn't ideal, though.
Firstly, ValidatorException is in a sun.* package that's not part of the public API: this code will be specific for the Oracle/OpenJDK JRE.
Secondly, it relies on the fact that the end entity checked (which verifies the key usage extension) happens after the rest of the trust validation (which makes it acceptable to ignore that exception, since you don't ignore other more fundamental checks this way).
You could of course re-implement your own validation instead, using the Java Certificate Path API, and ignoring only the key usage for this purpose. This requires a bit more code.
More generally, you're trying to bypass the specifications anyway, if you want to use a certificate for SSL/TLS as a client certificate when it doesn't have the right extension. The best fix for this is to amend your CA policy, which should be feasible if it's an internal CA anyway. It's quite common for server certificates to have the TLS client extended key usage set too, even with big CAs.

Categories

Resources