Unable to load certificate chain to java keystore - java

I have a blah.p7b certificate type PKCS#7 which i want to import it to a java keystore using keytool in order to enable HTTPS on tomcat , i don't have the alias name and keystore when the certificate was generated i took it from the client whose want to enable https on our web-application server that they use, can this works without having the original alias name and keystore ?
when i tried to import the certificate i used this command
keytool -import -trustcacerts -file certificate.p7b -keystore keystore -storepass <mypasswd> -alias "myalias"
but it gives me this error
keytool error: java.lang.Exception: Certificate reply does not contain public key for <mydomain>
Please help...

If you haven't got the original KeyStore you are hosed. You have to generate a new KeyStore, a new keypair, a new CSR, get it signed, and then import the signed cert and its chain into the KeyStore using the same alias as the keypair.

Related

KeyStore and TrustStore load failed - Private key must be accompanied by certificate chain

I have created a self signed certificate using the following command:
keytool -genkeypair -keyalg RSA -alias test-api -keystore test-api.p12 -storepass password -validity 3650 -keysize 2048 -storetype pkcs12
I then imported this keystore into new truststore:
keytool -import -trustcacerts -alias test-api-2018 -file test.crt -keystore trusted-keystore.p12 -storetype pkcs12
In Java, creating a custom SSL store provider (org.springframework.boot.context.embedded.SslStoreProvider). As a part of it, loaded keystore and truststore using the following Java code:
try {
try (final InputStream keyStoreStream = new ByteArrayInputStream(Base64.decode(keyStoreEncoded))) {
keyStore = KeyStore.getInstance(KEYSTORE_TYPE_PKCS12);
LOGGER.info("Loading a KeyStore object based on the decoded value.");
keyStore.load(keyStoreStream, serverSslKeyPassword.toCharArray());
}
....
trustStore.load(trustStoreStream, serverSslTrustStorePassword.toCharArray());
}
Created custom implementation of EmbeddedServletContainerCustomizer and set SSL Provider:
public void customize(final ConfigurableEmbeddedServletContainer configurableEmbeddedServletContainer) {
configurableEmbeddedServletContainer.setSslStoreProvider(awsSslStoreProvider);
}
Application fails to start because of the following error:
Caused by: java.lang.IllegalArgumentException: Private key must be accompanied by certificate chain
at java.security.KeyStore.setKeyEntry(KeyStore.java:1136)
at org.apache.tomcat.util.net.jsse.JSSEUtil.getKeyManagers(JSSEUtil.java:253)
at org.apache.tomcat.util.net.AbstractJsseEndpoint.createSSLContext(AbstractJsseEndpoint.java:114)
... 19 common frames omitted
I just jad this problem to today, the problem occurs when the security config in the application.properties file isnt configured properly, this causes the certificate chain to break.
in my case i used
server.ssl.key-password=123456789
instead of
server.ssl.key-store-password=123456789
minor issues like this can cause issues.
This also happens when using BouncyCastle as PKCS12 key store provider and the key alias is using incorrect upper case.
E.g. (incorrect):
server.ssl.key-alias=17B2E92E5694C7AE11A65C4A4EBFC75558399E05
instead (correct):
server.ssl.key-alias=17b2e92e5694c7ae11a65c4a4ebfc75558399e05
The strange thing about this error is that the key is found, so obviously is not case sensitive, but the check for ks.getCertificateChain(keyAlias) is.

java.security.KeyStoreException: failed to extract any certificates or private keys - maybe bad password?

I'm using Not-yet commons SSL to develop my own TLS Socket.
But always got No private keys found in keystore on following code
private SSLServer sslS=null;
//...
sslS=new SSLServer();
KeyMaterial km=new KeyMaterial(certChain, privateKeyFile, certPassword.toCharArray(), privateKeyPassword.toCharArray());
The certChain used original JRE's cacert:
C:/Program Files/Java/jre1.8.0_101/lib/security/cacerts
This give me a java.security.KeyStoreException: No private keys found in keystore!
The certChain used my own:
keytool -certreq -alias 127.0.0.1 -keystore ServerKey.jks -file 127.0.0.1.csr
This give me a java.security.KeyStoreException: failed to extract any certificates or private keys - maybe bad password?
But I can 100% sure that my password is right. My password is a simple "123456", there is no reason I can do wrong on it.
The privateKey I generated by:
keytool -genkey -alias 127.0.0.1 -keyalg RSA -keystore ServerKey.jks -keysize 2048
How can I solve this problem, any suggestion ?

InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty

I am getting this weird error from my java code:
java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty
The command I used to generate the keystore:
keytool -genkey -alias tomcat -keystore keystore.jks
Here is my java code:
import java.security.cert.PKIXParameters;
import java.security.KeyStore;
import java.io.FileInputStream;
public class MyKeyTest {
public static void main(String[] args) throws Exception {
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
String password = "mypass";
ks.load(new FileInputStream("keystore.jks"), password.toCharArray());
new PKIXParameters(ks);
}
}
I tried to google around for this error but mostly it says this happens when keystore was not found or is not permissive to be read.
But neither of these two cases is true in my case. Any ideas?
Some brief and simplified background just case it's not clear. The PKIXParameters object is used for client certificate validation. This is a way for you to allow or disallow access to your web resources. The way this typically works is that
you have a list of certificate authority (CA) certificates you trust (this is your trust store).
your application asks the client to provide a digital certificate (the client certificate)
the client cert will include the CA certificate which signed the client cert. If the CA certificate is on your list, the client passes the validation.
The keystore.jks file is your trust store. Your trust store does not currently contain any certificates(just a useless private key). To add a ca certificate you would use this command
keytool -import -alias <an alias for the CA cert> -file <the trusted CA cert> -keystore <your keystore>
As an example, export a CA certificate from your browser to a file and then import it into your trust store
Go to your control panel/internet options/Content tab and click on certificates.
select the "Trusted Root Certificate Authorities" tab and select a certificate (for example the "Microsoft Root Certificate Authority")
click export and save it to file (for this example I used "msroot.cer").
at your command prompt run the following command
keytool -import -alias msroot -file msroot.cer -keystore keystore.jks
Now when your run your java code using this updated keystore.jks, it should run just fine.

How do you setup SSL with Grails?

How do you setup SSL with Grails? We have our signed certificate from our provider, and have tried creating a keystore under .grails/1.3.7/ssl/keystore. With just putting our key in, we start grails and get:
Caused by: javax.net.ssl.SSLException: No available certificate or key corresponds to the SSL cipher suites which are enabled.
at sun.security.ssl.SSLServerSocketImpl.checkEnabledSuites(SSLServerSocketImpl.java:327)
at sun.security.ssl.SSLServerSocketImpl.accept(SSLServerSocketImpl.java:272)
at org.apache.tomcat.util.net.jsse.JSSESocketFactory.checkConfig(JSSESocketFactory.java:742)
Maybe we have to import the .crt file with a different command? I used:
keytool -import -v -trustcacerts -alias riseup.org.nz -file /etc/ssl/telethon/telethon.crt
When I use and alias other than riseup.org.nz, it complains the alias doesn't match the crt.
After running the command, it does ask me if I trust the information, which makes me think of:
Note: it is not required that you execute a -printcert command prior to importing a certificate, since before adding a certificate to the list of trusted certificates in the keystore, the -import command prints out the certificate information and prompts you to verify it.
from: http://download.oracle.com/javase/1.3/docs/tooldocs/win32/keytool.html

How to create a BKS (BouncyCastle) format Java Keystore that contains a client certificate chain

I'm writing an Android app that requires SSL client authentication. I know how to create a JKS keystore for a desktop Java application, but Android only supports the BKS format. Every way I've tried to create the keystore results in the following error:
handling exception: javax.net.ssl.SSLHandshakeException: null cert chain
So it looks like the client is never sending a proper certificate chain, probably because I'm not creating the keystore properly. I'm unable to enable SSL debugging like I can on the desktop, so that's making this much more difficult than it should be.
For reference the following is the command that IS working to create a BKS truststore:
keytool -importcert -v -trustcacerts -file "cacert.pem" -alias ca -keystore "mySrvTruststore.bks" -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "bcprov-jdk16-145.jar" -storetype BKS -storepass testtest
Here is the command I've tried that is NOT working to create a BKS client keystore:
cat clientkey.pem clientcert.pem cacert.pem > client.pem
keytool -import -v -file <(openssl x509 -in client.pem) -alias client -keystore "clientkeystore" -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "bcprov-jdk16-145.jar" -storetype BKS -storepass testtest
Detailed Step by Step instructions I followed to achieve this
Download bouncycastle JAR from
http://repo2.maven.org/maven2/org/bouncycastle/bcprov-ext-jdk15on/1.46/bcprov-ext-jdk15on-1.46.jar
or take it from the "doc" folder.
Configure BouncyCastle for PC using one of the below methods.
Adding the BC Provider Statically (Recommended)
Copy the bcprov-ext-jdk15on-1.46.jar to each
D:\tools\jdk1.5.0_09\jre\lib\ext (JDK (bundled JRE)
D:\tools\jre1.5.0_09\lib\ext (JRE)
C:\ (location to be used in env variable)
Modify the java.security file under
D:\tools\jdk1.5.0_09\jre\lib\security
D:\tools\jre1.5.0_09\lib\security
and add the following entry
security.provider.7=org.bouncycastle.jce.provider.BouncyCastleProvider
Add the following environment variable in "User Variables" section
CLASSPATH=%CLASSPATH%;c:\bcprov-ext-jdk15on-1.46.jar
Add bcprov-ext-jdk15on-1.46.jar to CLASSPATH of your project and Add the following line in your code
Security.addProvider(new BouncyCastleProvider());
Generate the Keystore using Bouncy Castle
Run the following command
keytool -genkey -alias myproject -keystore C:/myproject.keystore -storepass myproject -storetype BKS -provider org.bouncycastle.jce.provider.BouncyCastleProvider
This generates the file C:\myproject.keystore
Run the following command to check if it is properly generated or not
keytool -list -keystore C:\myproject.keystore -storetype BKS
Configure BouncyCastle for TOMCAT
Open D:\tools\apache-tomcat-6.0.35\conf\server.xml and add the following entry
<Connector
port="8443"
keystorePass="myproject"
alias="myproject"
keystore="c:/myproject.keystore"
keystoreType="BKS"
SSLEnabled="true"
clientAuth="false"
protocol="HTTP/1.1"
scheme="https"
secure="true"
sslProtocol="TLS"
sslImplementationName="org.bouncycastle.jce.provider.BouncyCastleProvider"/>
Restart the server after these changes.
Configure BouncyCastle for Android Client
No need to configure since Android supports Bouncy Castle Version 1.46 internally in the provided "android.jar".
Just implement your version of HTTP Client (MyHttpClient.java can be found below) and set the following in code
SSLSocketFactory.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
If you don't do this, it gives an exception as below
javax.net.ssl.SSLException: hostname in certificate didn't match: <192.168.104.66> !=
In production mode, change the above code to
SSLSocketFactory.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);
MyHttpClient.java
package com.arisglobal.aglite.network;
import java.io.InputStream;
import java.security.KeyStore;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.SingleClientConnManager;
import com.arisglobal.aglite.activity.R;
import android.content.Context;
public class MyHttpClient extends DefaultHttpClient {
final Context context;
public MyHttpClient(Context context) {
this.context = context;
}
#Override
protected ClientConnectionManager createClientConnectionManager() {
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
// Register for port 443 our SSLSocketFactory with our keystore to the ConnectionManager
registry.register(new Scheme("https", newSslSocketFactory(), 443));
return new SingleClientConnManager(getParams(), registry);
}
private SSLSocketFactory newSslSocketFactory() {
try {
// Get an instance of the Bouncy Castle KeyStore format
KeyStore trusted = KeyStore.getInstance("BKS");
// Get the raw resource, which contains the keystore with your trusted certificates (root and any intermediate certs)
InputStream in = context.getResources().openRawResource(R.raw.aglite);
try {
// Initialize the keystore with the provided trusted certificates.
// Also provide the password of the keystore
trusted.load(in, "aglite".toCharArray());
} finally {
in.close();
}
// Pass the keystore to the SSLSocketFactory. The factory is responsible for the verification of the server certificate.
SSLSocketFactory sf = new SSLSocketFactory(trusted);
// Hostname verification from certificate
// http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html#d4e506
sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
return sf;
} catch (Exception e) {
throw new AssertionError(e);
}
}
}
How to invoke the above code in your Activity class:
DefaultHttpClient client = new MyHttpClient(getApplicationContext());
HttpResponse response = client.execute(...);
I use Portecle, and it works like a charm.
I don't think your problem is with the BouncyCastle keystore; I think the problem is with a broken javax.net.ssl package in Android. The BouncyCastle keystore is a supreme annoyance because Android changed a default Java behavior without documenting it anywhere -- and removed the default provider -- but it does work.
Note that for SSL authentication you may require 2 keystores. The "TrustManager" keystore, which contains the CA certs, and the "KeyManager" keystore, which contains your client-site public/private keys. (The documentation is somewhat vague on what needs to be in the KeyManager keystore.) In theory, you shouldn't need the TrustManager keystore if all of your certficates are signed by "well-known" Certifcate Authorities, e.g., Verisign, Thawte, and so on. Let me know how that works for you. Your server will also require the CA for whatever was used to sign your client.
I could not create an SSL connection using javax.net.ssl at all. I disabled the client SSL authentication on the server side, and I still could not create the connection. Since my end goal was an HTTPS GET, I punted and tried using the Apache HTTP Client that's bundled with Android. That sort-of worked. I could make the HTTPS conection, but I still could not use SSL auth. If I enabled the client SSL authentication on my server, the connection would fail. I haven't checked the Apache HTTP Client code, but I suspect they are using their own SSL implementation, and don't use javax.net.ssl.
Not sure you resolved this issue or not, but this is how I do it and it works on Android:
Use openssl to merge client's cert(cert must be signed by a CA that accepted by server) and private key into a PCKS12 format key pair:
openssl pkcs12 -export -in clientcert.pem -inkey clientkey.pem -out client.p12
You may need patch your JRE to umlimited strength encryption depends on your key strength: copy the jar files fromJCE 5.0 unlimited strength Jurisdiction Policy FIles and override those in your JRE (eg.C:\Program Files\Java\jre6\lib\security)
Use Portecle tool mentioned above and create a new keystore with BKS format
Import PCKS12 key pair generated in step 1 and save it as BKS keystore. This keystore works with Android client authentication.
If you need to do certificate chain, you can use this IBM tool:KeyMan to merge client's PCKS12 key pair with CA cert. But it only generate JKS keystore, so you again need Protecle to convert it to BKS format.
command line:
keytool -genseckey -alias aliasName -keystore truststore.bks -providerclass org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath /path/to/jar/bcprov-jdk16-1.46.jar -storetype BKS
Your command for creating the BKS keystore looks correct for me.
How do you initialize the keystore.
You need to craeate and pass your own SSLSocketFactory. Here is an example which uses Apache's org.apache.http.conn.ssl.SSLSocketFactory
But I think you can do pretty the same on the javax.net.ssl.SSLSocketFactory
private SSLSocketFactory newSslSocketFactory() {
try {
// Get an instance of the Bouncy Castle KeyStore format
KeyStore trusted = KeyStore.getInstance("BKS");
// Get the raw resource, which contains the keystore with
// your trusted certificates (root and any intermediate certs)
InputStream in = context.getResources().openRawResource(R.raw.mykeystore);
try {
// Initialize the keystore with the provided trusted certificates
// Also provide the password of the keystore
trusted.load(in, "testtest".toCharArray());
} finally {
in.close();
}
// Pass the keystore to the SSLSocketFactory. The factory is responsible
// for the verification of the server certificate.
SSLSocketFactory sf = new SSLSocketFactory(trusted);
// Hostname verification from certificate
// http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html#d4e506
sf.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);
return sf;
} catch (Exception e) {
throw new AssertionError(e);
}
}
Please let me know if it worked.
Use this manual http://blog.antoine.li/2010/10/22/android-trusting-ssl-certificates/
This guide really helped me. It is important to observe a sequence of certificates in the store. For example: import the lowermost Intermediate CA certificate first and then all the way up to the Root CA certificate.

Categories

Resources