KeyUsage does not allow digital signatures
digital-signature, java, ssl, x509certificate
Solution
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.
Problem
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]