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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With