Trouble using Positive SSL Multi-Site Cert with Java HttpsServer - java

I'm trying to load a comodo Positive SSL Multi-Site cert into Java's HttpsServer. I'm not getting any errors from the code, but when I try and access the URL in a browser it tells me there is an SSL error. Neither Chrome nor FireFox give any additional information. This cert is working fine in Apache.
Below is the code I am using. I've made it fairly verbose. Does anything stand out as incorrect? I've converted the private key to pkcs8 for importing. The certificate and bundle I'm loading are PEM encoded.
serverHttps = HttpsServer.create(new InetSocketAddress(ports[port_selector]), 0);
SSLContext sslContext = SSLContext.getInstance("TLS");
String alias = "alias";
// Load Certificates
InputStream stream = MyClass.class.getResourceAsStream("/certs/mycert.crt");
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate)cf.generateCertificate(stream);
stream.close();
stream = MyClass.class.getResourceAsStream("/certs/bundle.crt");
cf = CertificateFactory.getInstance("X.509");
Collection bundle = cf.generateCertificates(stream);
stream.close();
// Build cert chain
java.security.cert.Certificate[] chain = new Certificate[bundle.size()+1];
Iterator i = bundle.iterator();
int pos = 0;
while (i.hasNext()) {
chain[pos] = (Certificate)i.next();
pos++;
}
chain[chain.length-1] = cert;
// Load private key
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
stream = MyClass.class.getResourceAsStream("/certs/pkcs8_my_key");
PKCS8EncodedKeySpec pkcs8 = new PKCS8EncodedKeySpec(IOUtils.toByteArray(stream));
RSAPrivateKey privKey = (RSAPrivateKey) keyFactory.generatePrivate(pkcs8);
stream.close();
stream = null;
KeyStore ks = KeyStore.getInstance("JKS");
char[] ksPassword = "mypass".toCharArray();
ks.load(null, ksPassword);
ks.setKeyEntry(alias, privKey, ksPassword, chain);
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, ksPassword);
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(ks);
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
// serverHttps.setHttpsConfigurator(new HttpsConfigurator(sslContext));
serverHttps.setHttpsConfigurator ( new HttpsConfigurator( sslContext )
{
#Override
public void configure ( HttpsParameters params )
{
try
{
// initialise the SSL context
SSLContext c = SSLContext.getDefault ();
SSLEngine engine = c.createSSLEngine ();
params.setNeedClientAuth ( false );
params.setCipherSuites ( engine.getEnabledCipherSuites () );
params.setProtocols ( engine.getEnabledProtocols () );
// get the default parameters
SSLParameters defaultSSLParameters = c.getDefaultSSLParameters ();
params.setSSLParameters ( defaultSSLParameters );
}
catch ( Exception ex )
{
System.out.println( "Failed to configure HTTPS server: "+ex.getMessage() );
System.exit(100);
}
}
} );

Your server cert must be chain[0] in the keystore entry.
The remaining certs should be in upward order i.e. root last -- and when you use keytool it puts them in that order -- because JSSE server sends them in the keystore order and SSL/TLS protocol says they should be sent in upward order. However, in my experience (most?) browsers/clients will tolerate the rest of the chain being out of order as long as the server cert is first.
PS: I think everything in your configure overrride is unnecessary. You haven't done anything to make the parameters of your SSLContext different from the default one, and the SSLParameters of the default context are (and override) the CipherSuites and Protocols you just set individually. But I can't easily test.

Related

How to use java to generate csr from exist keystore

How to use java code to generate csr from exist keystore?
The function affect would be as same as(but not genearate the file)
keytool -certreq -alias certificate_alias -keystore jssecacerts -storepass changeit -file client.csr
I just found out "Generating a Certificate Signing Request using Java API"
But I already have X.509 certificate, how can I use this certificate to generate csr in java?
KeyStore ts = KeyStore.getInstance("JKS");
FileInputStream is = new FileInputStream(trustStoreFileName);
ts.load(is, trustStorePassword.toCharArray());
is.close();
X509Certificate x509Cert = (X509Certificate)ts.getCertificate("certificate_alias");
How can I use above info to generate CSR?
I Just solve it~
To share all my code to generate csr from exist certificate.
KeyStore ks = KeyStore.getInstance("JKS");
FileInputStream is = new FileInputStream(trustStoreFileName);
ks.load(is, trustStorePassword.toCharArray());
is.close();
X509Certificate x509Cert = (X509Certificate)ks.getCertificate("certificate_alias");
X500Principal principal = x509Cert.getSubjectX500Principal();
X500Name x500Name = new X500Name( principal.getName() );
PublicKey publicKey = x509Cert.getPublicKey();
PrivateKey privateKey = (PrivateKey) ks.getKey("certificate_alias", trustStorePassword.toCharArray());
String sigAlg = x509Cert.getSigAlgName();
PKCS10 pkcs10 = new PKCS10(publicKey);
Signature signature = Signature.getInstance(sigAlg);
signature.initSign(privateKey);
pkcs10.encodeAndSign(new X500Signer(signature, x500Name));
ByteArrayOutputStream bs = new ByteArrayOutputStream();
PrintStream ps = new PrintStream(bs);
pkcs10.print(ps);
byte[] c = bs.toByteArray();
try {
if (ps != null)
ps.close();
if (bs != null)
bs.close();
} catch (Throwable th) {
}
You need the public key from certificate and the private key to sign the CSR. A JKS can contain x509 certificates and key pairs. So, ensure you have it
PrivateKey privateKey = ts.getPrivateKey("certificate_alias");
Once the CSR is signed, the CA will issue a new X509Certificate. But is not usual to reuse existing keys ( that could have been compromised) to issue a new certificate. It is recommended to generate a new key pair

Android SSLHandshake failed - CA certificate

I want to secure my SSL connection to the socket. But unfortunately, I have a problem with CA certificate.
javax.net.ssl.SSLHandshakeException: Handshake failed
at com.android.org.conscrypt.OpenSSLEngineImpl.unwrap(OpenSSLEngineImpl.java:441)
at javax.net.ssl.SSLEngine.unwrap(SSLEngine.java:1014)
at com.koushikdutta.async.AsyncSSLSocketWrapper$5.onDataAvailable(AsyncSSLSocketWrapper.java:194)
at com.koushikdutta.async.Util.emitAllData(Util.java:23)
at com.koushikdutta.async.AsyncNetworkSocket.onReadable(AsyncNetworkSocket.java:152)
at com.koushikdutta.async.AsyncServer.runLoop(AsyncServer.java:789)
at com.koushikdutta.async.AsyncServer.run(AsyncServer.java:627)
at com.koushikdutta.async.AsyncServer.access$700(AsyncServer.java:41)
at com.koushikdutta.async.AsyncServer$13.run(AsyncServer.java:569)
Caused by: java.security.cert.CertificateException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
at com.android.org.conscrypt.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:337)
at com.android.org.conscrypt.TrustManagerImpl.checkServerTrusted(TrustManagerImpl.java:231)
at com.android.org.conscrypt.Platform.checkServerTrusted(Platform.java:115)
at com.android.org.conscrypt.OpenSSLEngineImpl.verifyCertificateChain(OpenSSLEngineImpl.java:666)
at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake_bio(Native Method)
at com.android.org.conscrypt.OpenSSLEngineImpl.unwrap(OpenSSLEngineImpl.java:426)
... 8 more
Caused by: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
My code:
String type = KeyStore.getDefaultType();
KeyStore trustStore = KeyStore.getInstance(type);
trustStore.load(null, null);
trustStore.setCertificateEntry("ca", new CA().getCert());
String tmfAlg = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlg);
tmf.init(trustStore);
try {
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), null);
SSLEngine engine = context.createSSLEngine();
AsyncSSLSocketWrapper.handshake(socketNormal, url, port, engine, tmf.getTrustManagers(), new NoopHostnameVerifier(), true, (e, socket1) -> {
// ... more
My cert is in my assets catalog:
public X509Certificate getCert() throws CertificateException, IOException {
CertificateFactory certFactory;
certFactory = CertificateFactory.getInstance("X.509");
InputStream inputStream = new BufferedInputStream(context.getAssets().open("pem.pem"));
return (X509Certificate) certFactory.generateCertificate(inputStream);
}
My certificate is signed using a private key and it is self-signed.
Obviously, it is working without cert... but it's not secure.
EDIT:
I have tried to put existing BKS Keystore instead of dynamically adding at run-time:
KeyStore trustStore = KeyStore.getInstance("BKS");
BufferedInputStream is = new BufferedInputStream(c.getAssets().open("key.bks"));
trustStore.load(is, "12345".toCharArray());
Log.i("Cert", "ca " + (new CA().getCert()).getSubjectDN());
String tmfAlg = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlg);
tmf.init(trustStore);
try {
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), null);
SSLEngine engine = context.createSSLEngine();
AsyncSSLSocketWrapper.handshake(socketNormal, url, port,
engine, tmf.getTrustManagers(), new NoopHostnameVerifier(), true, (e, socket1) -> {
But unfortunetly the error is the same.
EDIT 2:
More info:
Server PHP generates this cert using:
function createSSLCert($pem_file, $pem_passphrase, $pem_dn) {
// //create ssl cert for this scripts life.
//Create private key
$privkey = openssl_pkey_new();
//Create and sign CSR
$cert = openssl_csr_new($pem_dn, $privkey);
$cert = openssl_csr_sign($cert, null, $privkey, 365 * 99);//365
//Generate PEM file
$pem = array();
openssl_x509_export($cert, $pem[0]);
openssl_pkey_export($privkey, $pem[1], $pem_passphrase);
$pem = implode($pem);
//Save PEM file
//echo $pem;
file_put_contents($pem_file, $pem);
//chmod($pem_file, 0600);
}
$pem_passphrase = "XXXXX"; //Set a password here
$pem_file = "cert.pem"; //Set a path/filename for the PEM SSL Certificate which will be created.
//The following array of data is needed to generate the SSL Cert
$pem_dn = array(
"countryName" => "PL", //Set your country name
"localityName" => "City", //Ser your city name
"organizationName" => "Firm name", //Set your company name
"commonName" => "CN", //Set your full hostname.
"emailAddress" => "admin#email.pl" //Set your email address
);
//create ssl cert for this scripts life.
$this->createSSLCert($pem_file, $pem_passphrase, $pem_dn);
Keystore was created using Portecle tool like:
New -> BKS -> Import Trusted Certificate -> My *pem file -> save
openssl s_client -debug -connect 10.100.0.24:5678 return:
No client certificate CA names sent
Server Temp Key: ECDH, P-256, 256 bits
---
SSL handshake has read 1630 bytes and written 451 bytes
---
New, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES256-SHA
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
Verify return code: 18 (self signed certificate)
plus some private informations about cert

Validating certificate chain in Java from truststore

I have a certificate chain as der encoded byte[][] array to verify. I also have a truststore file.
After I create X509Certificate[] from that byte array[][] and initializing trustmanager, how will I tell to TrustManager to verify that X509Certificate[]? What is the proper way to do it?
Thanks.
Sample code:
int certVerify(byte certChain[][])
{
CertificateFactory cf = CertificateFactory.getInstance("X509");
X509Certificate certx[] = new X509Certificate[10];
for(int i=0;i<certChain.length;i++)
{
certx[i] = (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(certChain[i]));
}
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load( new FileInputStream("cacerts.jks"),"123456".toCharArray());
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
}
You'll need to enable OCSP with the necessary system properties, or obtain CRLs for each certificate in the chain, in order to check the revocation status. (Alternatively, you can disable revocation checking, with the attendant risks.)
CertificateFactory cf = CertificateFactory.getInstance("X.509");
List<Certificate> certx = new ArrayList<>(certChain.length);
for (byte[] c : certChain)
certx.add(cf.generateCertificate(new ByteArrayInputStream(c)));
CertPath path = cf.generateCertPath(certx);
CertPathValidator validator = CertPathValidator.getInstance("PKIX");
KeyStore keystore = KeyStore.getInstance("JKS");
try (InputStream is = Files.newInputStream(Paths.get("cacerts.jks"))) {
keystore.load(is, "changeit".toCharArray());
}
Collection<? extends CRL> crls;
try (InputStream is = Files.newInputStream(Paths.get("crls.p7c"))) {
crls = cf.generateCRLs(is);
}
PKIXParameters params = new PKIXParameters(keystore);
CertStore store = CertStore.getInstance("Collection", new CollectionCertStoreParameters(crls));
/* If necessary, specify the certificate policy or other requirements
* with the appropriate params.setXXX() method. */
params.addCertStore(store);
/* Validate will throw an exception on invalid chains. */
PKIXCertPathValidatorResult r = (PKIXCertPathValidatorResult) validator.validate(path, params);
There is some good information on how to implement one here
Or you could use the BouncyCastle APIs as explained here

Certificate generated through CSR signing with BouncyCastle considered untrusted

I am struggling with the following issue:
I have a CSR which I am signing with this code:
#Override
public X509Certificate signCSR( Reader pemcsr, int validityDays ) throws APIException
{
try ( PEMParser reader = new PEMParser( pemcsr ) )
{
KeyStore keystore = getKeyStore();
Properties cryptoProps = getCryptoProperties();
String caKeyAlias = cryptoProps.getProperty( PROPERTY_KEYSTORE_CA_CERT_ALIAS );
String caKeyPassword = cryptoProps.getProperty( PROPERTY_KEYSTORE_CA_CERT_PASSWORD );
PrivateKey cakey = (PrivateKey) keystore.getKey( caKeyAlias, caKeyPassword.toCharArray() );
X509Certificate cacert = (X509Certificate) keystore.getCertificate( caKeyAlias );
PKCS10CertificationRequest csr = (PKCS10CertificationRequest) reader.readObject();
AlgorithmIdentifier sigAlgId = new DefaultSignatureAlgorithmIdentifierFinder().find( "SHA1withRSA" );
AlgorithmIdentifier digAlgId = new DefaultDigestAlgorithmIdentifierFinder().find( sigAlgId );
X500Name issuer = new X500Name( cacert.getSubjectX500Principal().getName() );
BigInteger serial = new BigInteger( 32, new SecureRandom() );
Date from = new Date();
Date to = new Date( System.currentTimeMillis() + ( validityDays * 86400000L ) );
DigestCalculator digCalc = new BcDigestCalculatorProvider().get( new AlgorithmIdentifier( OIWObjectIdentifiers.idSHA1 ) );
X509ExtensionUtils x509ExtensionUtils = new X509ExtensionUtils( digCalc );
X509v3CertificateBuilder certgen = new X509v3CertificateBuilder( issuer, serial, from, to, csr.getSubject(), csr.getSubjectPublicKeyInfo() );
// Basic Constraints
// certgen.addExtension( Extension.basicConstraints, true, new
// BasicConstraints( 0 ) );
// Subject Key Identifier
// certgen.addExtension( Extension.subjectKeyIdentifier, false,
// x509ExtensionUtils.createSubjectKeyIdentifier(
// csr.getSubjectPublicKeyInfo() ) );
// Authority Key Identifier
// byte[] caKeyEncoded = cacert.getPublicKey().getEncoded();
// SubjectPublicKeyInfo caSubjectPublicKeyInfo =
// SubjectPublicKeyInfo.getInstance( caKeyEncoded );
// certgen.addExtension( Extension.authorityKeyIdentifier, false,
// x509ExtensionUtils.createAuthorityKeyIdentifier( caSubjectPublicKeyInfo
// ) );
// Key Usage
// certgen.addExtension( Extension.keyUsage, false, new KeyUsage(
// KeyUsage.digitalSignature | KeyUsage.keyCertSign | KeyUsage.cRLSign )
// );
ContentSigner signer = new BcRSAContentSignerBuilder( sigAlgId, digAlgId ).build( PrivateKeyFactory.createKey( cakey.getEncoded() ) );
// ContentSigner signer = new JcaContentSignerBuilder(
// "SHA1WithRSAEncryption" ).setProvider( "BC" ).build( cakey );
X509CertificateHolder holder = certgen.build( signer );
return new JcaX509CertificateConverter().setProvider( "BC" ).getCertificate( holder );
}
catch ( NoSuchAlgorithmException | KeyStoreException | CertificateException | OperatorCreationException | UnrecoverableKeyException | CertIOException e )
{
throw new APIException( API_ERROR_CODE.CRYPTOGRAPHY_ERROR, e );
}
catch ( IOException e )
{
throw new APIException( API_ERROR_CODE.IO_ERROR, e );
}
}
This runs through successfully. However, when I try to check the key using:
KeyStore ks = getKeyStore();
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance( TrustManagerFactory.getDefaultAlgorithm() );
trustManagerFactory.init( ks );
for ( TrustManager trustManager : trustManagerFactory.getTrustManagers() )
{
if ( trustManager instanceof X509TrustManager )
{
X509TrustManager x509TrustManager = (X509TrustManager) trustManager;
x509TrustManager.checkClientTrusted( new X509Certificate[] { certificate }, "RSA" );
}
}
...it fails with a CertificateException. Please note that I am using the VERY SAME keystore here, which means the CA key I am signing with is included therein. Why does this happen?
By the way, strangely enough, when I open the generated signed certificate using Windows's certificate viewer, it DOES show the issuing CA name but its entry does not show up in the certificate chain. It seems as if the CA root certificate were not present in the Windows trusted authirities list, but in fact it is also there.
Even stranger: if I sign the CSR using OpenSSL, the certificate chain looks OK. I also had the idea that the process of importing the CA key pair from OpenSSL to the Java keystore via PKCS12 as an intermediate format wasn't successful, but actually if I export the CA certificate from the Java keystore and open it with the Windows certificate viewer, it is shown as trusted...
UPDATE: For those familiar with ASN.1, here are two encoded certificates. One is made with BouncyCastle and is NOT trusted, the other one is signed by the same CA key with OpenSSL and that IS trusted. They can be decoded with a tool like this: ASN.1 decoder I would be very grateful is somebody could view this decoded data and tell me what could cause the difference between them.
This one is NOT trusted:
-----BEGIN CERTIFICATE-----
MIIC6TCCAlKgAwIBAgIESdsI/TANBgkqhkiG9w0BAQUFADCBgzEgMB4GCSqGSIb3
DQEJARYRdGVzdGNhQHRlc3RjYS5jb20xEDAOBgNVBAMMB1Rlc3QgQ0ExEDAOBgNV
BAsMB1Rlc3QgQ0ExEDAOBgNVBAoMB1Rlc3QgQ0ExDTALBgNVBAcMBFdpZW4xDTAL
BgNVBAgMBFdpZW4xCzAJBgNVBAYTAkFUMB4XDTE0MDUxOTExNTYwM1oXDTE1MDUx
OTExNTYwM1owajELMAkGA1UEBhMCVUsxCzAJBgNVBAgTAlBiMQswCQYDVQQHEwJC
cDETMBEGA1UEChMKZmdmZ2ZnZGZnZDEPMA0GA1UECxMGYWJjZGVmMRswGQYDVQQD
DBJwZXRlcnZlbG9zeV90aWdyaXMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
AoIBAQCdL7taENsONBazc2iMDV5nw9ACP5mevmnzPwOJRUcd5GlGgry/iSa3tTwL
l6Um3zNc4X0m5nVVskKeJE4dTvYFV3+vJlEKCra86yQfa6XkGllU4EG6SdG8lRhE
Btk1QbOQZKrUz77IdOWWOUvIsNxtDDQcUhnrSjSxHohdoe/yoCl+60RBdjrgUrRo
uctSHFPvVt2uZaVM2rAVovx56vvJHOag2++rcvXaOh9WHvdwRAIZt/4aOv2O4jdI
jKdRrmF8dOudjR89wIeVjX9fvyvx+hw+ZolUio9GOVKLlBcYno6lEupHLUDK9ECs
W8F6y65nYGlm9/0G0+gB7K1yy1dBAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEAKJpM
7AbkWBH3ho1YV0d1glJvefQ1xaXGpDfd+Tzf3+cR1o3+YxxEyuYvBbiQ/MBxKD9/
hsFCqEWzOfu2lAZ+/6uHvt7BCEGhaLdWKXehoaIw/kEMeISIUDFbKORCsKJNbYRB
xgqBXGglTQ4gVXMDRBxzOmButN31j1VDt55gvn4=
-----END CERTIFICATE-----
This one is TRUSTED, this has been generated using theoretically the same CA certificate but through OpenSSL:
-----BEGIN CERTIFICATE-----
MIIC+TCCAmICAhI4MA0GCSqGSIb3DQEBBQUAMIGDMQswCQYDVQQGEwJBVDENMAsG
A1UECAwEV2llbjENMAsGA1UEBwwEV2llbjEQMA4GA1UECgwHVGVzdCBDQTEQMA4G
A1UECwwHVGVzdCBDQTEQMA4GA1UEAwwHVGVzdCBDQTEgMB4GCSqGSIb3DQEJARYR
dGVzdGNhQHRlc3RjYS5jb20wHhcNMTQwNTE0MTkzMTAzWhcNMTUwNTA5MTkzMTAz
WjCBgDELMAkGA1UEBhMCSFUxETAPBgNVBAgTCEJ1ZGFwZXN0MREwDwYDVQQHEwhC
dWRhcGVzdDEWMBQGA1UEChMNTWVyY2hhbnQgVGVzdDEWMBQGA1UECxMNTWVyY2hh
bnQgVGVzdDEbMBkGA1UEAwwScGV0ZXJ2ZWxvc3lfdGlncmlzMIIBIjANBgkqhkiG
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1vuY4MQ5b9Jb0MiyEuCrR4E+7VgmrvEwlswO
aMIF4H6i538PwPml5dbqx/3whxR/BcQJuJYWI/Hh7xxGS7FvSQ+DNhzxv9TpECKS
/5OZNm+JikPZwTiwrS/Cf4NP+ZcXOjtVZp6ngVtTarn3NC/J7gJVYaHVVO4NbUkt
kCYhdfCXg71QiJ42RWMjMC9tJFrrlfem+SVzh8yMtUCBKm7nbMjQ6LngawjTzDK8
2Zcdqwdzvt2pcYcsYSViO5j5t/r7rIDGjRkjJqRSEiJMOvn0W+sdTdmFoZbyj7Qe
pgyCyf28uFyCO9QZro337D8klPLXaWJOwPDXXiuYOTDYAjBVbwIDAQABMA0GCSqG
SIb3DQEBBQUAA4GBAGU60GVjR+2oEiJMSe1CKU7gf+bGuxaCxXQTzVQLU652i1sp
Fv56o6jnLtw46/rQydNKX4GBH022B/BDEPAQQiQv31YKQAoWtBZod0SRonogcx7p
AULacoma9QEgHSX0l+2yEn42/qo7o0pAmmewJlsCnHVIqI0eU8x1XbCEAf53
-----END CERTIFICATE-----
UPDATE 2:
Thanks to Bruno's answer, the certificate chain now looks OK and the following certificate is generated:
-----BEGIN CERTIFICATE-----
MIIC6TCCAlKgAwIBAgIEI2vbpTANBgkqhkiG9w0BAQUFADCBgzELMAkGA1UEBhMC
QVQxDTALBgNVBAgMBFdpZW4xDTALBgNVBAcMBFdpZW4xEDAOBgNVBAoMB1Rlc3Qg
Q0ExEDAOBgNVBAsMB1Rlc3QgQ0ExEDAOBgNVBAMMB1Rlc3QgQ0ExIDAeBgkqhkiG
9w0BCQEWEXRlc3RjYUB0ZXN0Y2EuY29tMB4XDTE0MDUyMDA3MzkyMFoXDTE1MDUy
MDA3MzkyMFowajELMAkGA1UEBhMCVUsxCzAJBgNVBAgTAlBiMQswCQYDVQQHEwJC
cDETMBEGA1UEChMKZmdmZ2ZnZGZnZDEPMA0GA1UECxMGYWJjZGVmMRswGQYDVQQD
DBJwZXRlcnZlbG9zeV90aWdyaXMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
AoIBAQCdL7taENsONBazc2iMDV5nw9ACP5mevmnzPwOJRUcd5GlGgry/iSa3tTwL
l6Um3zNc4X0m5nVVskKeJE4dTvYFV3+vJlEKCra86yQfa6XkGllU4EG6SdG8lRhE
Btk1QbOQZKrUz77IdOWWOUvIsNxtDDQcUhnrSjSxHohdoe/yoCl+60RBdjrgUrRo
uctSHFPvVt2uZaVM2rAVovx56vvJHOag2++rcvXaOh9WHvdwRAIZt/4aOv2O4jdI
jKdRrmF8dOudjR89wIeVjX9fvyvx+hw+ZolUio9GOVKLlBcYno6lEupHLUDK9ECs
W8F6y65nYGlm9/0G0+gB7K1yy1dBAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEAIdFF
h6uLY7ioKQ3O0c4cZHHjRA0HTlWjih8P2xvXY/V9jF914BT7OW52UJ16tQaJlOf+
mAeeBDq9srKnkmOQp3mCejVnkyVZF8pOOzNbqSVzylt0Csg2twnxZ0NcM63Oda5b
YSQI8+arryxykLWkHWH8i/6rPCDCtbAHBo7fSeQ=
-----END CERTIFICATE-----
However, the TrustManager code above rejects it. If I circumvent the TrustManager and do something like this:
KeyStore ks = getKeyStore();
Enumeration<String> aliases = ks.aliases();
while ( aliases.hasMoreElements() )
{
String alias = aliases.nextElement();
Certificate currentCert = ks.getCertificate( alias );
try
{
certificate.verify( currentCert.getPublicKey() );
return true;
}
catch ( Exception e )
{
// the certificate cannot be verified with this key.
}
}
return false;
...it passes. Does anybody know why it fails on the TrustManager check?
P.s. the CA certificate looks like this:
-----BEGIN CERTIFICATE-----
MIICfzCCAegCCQCU+Ah6M5qQGTANBgkqhkiG9w0BAQUFADCBgzELMAkGA1UEBhMC
QVQxDTALBgNVBAgMBFdpZW4xDTALBgNVBAcMBFdpZW4xEDAOBgNVBAoMB1Rlc3Qg
Q0ExEDAOBgNVBAsMB1Rlc3QgQ0ExEDAOBgNVBAMMB1Rlc3QgQ0ExIDAeBgkqhkiG
9w0BCQEWEXRlc3RjYUB0ZXN0Y2EuY29tMB4XDTE0MDQyMzA3MjYzNFoXDTI0MDQy
MDA3MjYzNFowgYMxCzAJBgNVBAYTAkFUMQ0wCwYDVQQIDARXaWVuMQ0wCwYDVQQH
DARXaWVuMRAwDgYDVQQKDAdUZXN0IENBMRAwDgYDVQQLDAdUZXN0IENBMRAwDgYD
VQQDDAdUZXN0IENBMSAwHgYJKoZIhvcNAQkBFhF0ZXN0Y2FAdGVzdGNhLmNvbTCB
nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAldKTo8iqF52dsOwln0Oppu+ODiaG
R4T7Znrca4Cs5FBQOmuMwqUP6ilW115p/WvkBHhm8dZyVACPKdshEfhh4VFAW5r2
mJnosYgjafQpTEv83sc938DwtK6iikZ0uvdBJKG/IuYblNq9TPMLFeTYjD8mgf9j
m6JOvA/Q9J4nRW0CAwEAATANBgkqhkiG9w0BAQUFAAOBgQB8ACYeC+zjV/KqxPr1
cyzfJP9xfUnxDTEKUJS2YVuxJqpfbHeUtvKoN89BfY07XWdnj8cgMDfJp10Kdc2A
clwP2lVDtOgHZS07UUW98q9FKQ33mLHIn0nDKNwTo5VH8t/NJVeMFuZPAbFiI2gj
KH2sTU2GNNvKC4jHh0PS+OZFtg==
-----END CERTIFICATE-----
If you look at the Issuer DN in your two certificates, they don't match (output from openssl x509 -text):
Issuer: C=AT, ST=Wien, L=Wien, O=Test CA, OU=Test CA, CN=Test CA/emailAddress=testca#testca.com
and
Issuer: emailAddress=testca#testca.com, CN=Test CA, OU=Test CA, O=Test CA, L=Wien, ST=Wien, C=AT
As a result, it's not going to be able to match the wrong issuer to the CA's Subject DN.
Unfortunately, X500Name issuer = new X500Name(cacert.getSubjectX500Principal().getName()) doesn't do what you'd expect. The order of the RDNs is reversed. Generally, re-building the DN from a string representation can fail, since there are different ways of serialising the ASN.1 representation into a string. Java's X500Principal has multiple formats available for getName(...) and it even provides a way to provide your own OID to string maps (for more obscure OIDs). The way emailAddress is separated can also cause problems (notice the way it's separated with a comma or with a slash).
Instead, build the X500Name from the encoded form, this should always work:
X500Name x500Name = X500Name.getInstance(cert
.getSubjectX500Principal().getEncoded());

Checking for CA's certificate before entering a certificate?

I am inserting a client certificate into my servertruststore using following code
FileInputStream fileInputStream = new FileInputStream( "c:/server.jks" );
keyStore.load( fileInputStream, "keystore".toCharArray() );
fileInputStream.close();
keyStore.setCertificateEntry( alias, new X509Certificate( trustedCertificate ) );
FileOutputStream fileOutputStream = new FileOutputStream("c:/server.jks" );
keyStore.store( fileOutputStream, "keystore".toCharArray() );
fileOutputStream.close();
Now i see that certificate is entered into my truststore but the CA's certificate which signed client's certificate is not present in my truststore. So I want to know is there any way we can check whether the certificate of CA is available or not before entering a certificate into keystore?
I guess what you have to do is to verify if the certificate has been issued by a root authority or it has been self-signed. I presume you are using the default java keystore which is cacerts.
I haven't tested the code but I think this may be a solution to your problem:
Code taken and modified from the following link:
How can I get a list of trusted root certificates in Java?
String filename = System.getProperty("java.home") + "/lib/security/cacerts".replace('/', File.separatorChar);
Set<X509Certificate> additionalCerts = new HashSet<X509Certificate>();
FileInputStream is = new FileInputStream(filename);
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
String password = "changeit";
keystore.load(is, password.toCharArray());
// This class retrieves the most-trusted CAs from the keystore
PKIXParameters params = new PKIXParameters(keystore);
// Get the set of trust anchors, which contain the most-trusted CA certificates
Iterator it = params.getTrustAnchors().iterator();
while( it.hasNext() ) {
TrustAnchor ta = (TrustAnchor)it.next();
// Get certificate
X509Certificate cert = ta.getTrustedCert();
additionalCerts.add(cert);
}
Then you may use the following code to pass the client certificate and the Set containing all the root CAs to the verifyCertificate(X509Certificate cert, Set additionalCerts) method of the following code:
http://www.nakov.com/blog/2009/12/01/x509-certificate-validation-in-java-build-and-verify-chain-and-verify-clr-with-bouncy-castle/

Categories

Resources