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.
Related
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.
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.
I am installing a wild Card SSL certificate to my keystore which will be used for Apache Tomcat web server.
Description :
My Tomcat Server is installed on windows 2012 server.
And I have certificates provided from COMODO.
The wildcard cert I'm using has already been used previously on a few servers. so I am directly installing same on my apache tomcat server .
so what I've generated a public keystore using keytool providing the same information used while purchasing the certificate using following tool command.
keytool -keysize 2048 -genkey -alias tomcat -keyalg RSA -keystore tomcat.keystore
Then I have attached my certificates to the generated keystore using following commond
For "Comodo" certificates
i.keytool -import -trustcacerts -alias root -file AddTrustExternalCARoot.crt -keystoreselfservice.keystore
And I have used correct chain of installation of certificate like root , all intermediate, primary from above command.
And while installing each certificate i received the following message
"Certificate added to keystore"
Though I have not got any error .
And when i have opened my keystore there were no certificate chain , means there is individual entry of each certificate . but there is no chain hierarchy of certificates like Root then intermediate then primary.
And in my final PI or certifcate, i am getting provider as local first name instead of Comodo .
EXAMPLE :
CN=nims.ABC.com,OU=abcCommunications,O=abc Group LLC, L=Roseville,ST=Minnesota,C=US
Provider must be
CN=COMODO RSA Organization Validation Secure Server CA,O=COMODO CA Limited,L=Salford,ST=Greater Manchester,C=GB
So I would like to know which steps I have missed or used any extra steps .
Please provide a solution to install a wild card certificate .
Thanks in advance
You did everything correctly. The trust chain is important for another aspect. If you trust one 'certificate' of the chain, you trust the following 'certificates' of the chain too. So to trust all certs of a CA you just have to trust the root CA's cert.
What you realy need to make the wild card certificate work on you server is to import the private key part of it.
I assume you mean Tomcat using Java SSL (JSSE) not APR/Native (OpenSSL). If you want Tomcat-APR, change your question.
If the cert you want to use is already in use on other servers, and you "generated a public keystore using" the keytool command you showed on the NEW server, you generated a NEW KEY which is different from the key the other servers used and different from the key included in the certificate, thus the certificate DOES NOT MATCH that new key and cannot be used with that new key. You also implicitly generated (and have not replaced) a self-signed cert, with both subject and issuer (what you call provider) identifying you rather than a CA like Comodo. This certificate is not good for general use but can be useful for some testing, which is why keytool does it implicitly.
You need to get the certificate, the ALREADY EXISTING private key that MATCHES the certficate, and the needed chain cert(s) into your JKS as a privateKey entry. If an existing SSL server is Java (using JSSE), just copy its JKS. If you want or need to change the password(s) on the copy for your new server, see keytool -storepassword and keytool -keypasswd.
If an existing server is OpenSSL (including Apache httpd and nginx), convert the OpenSSL PEM format to PKCS#12 (preferably on the old server); depending on that server's file layout this is something like
openssl pkcs12 -export -in certfile -inkey keyfile -certfile chaincert -out xxx
and then use keytool to convert PKCS#12 to JKS (preferably on the new server)
keytool -importkeystore -srckeystore xxx -srcstoretype pkcs12 -destkeystore yyy
Note you must use a password on the PKCS#12. This does not need to be the same as the old server keyfile (if any) or the new server JKS, but it's usually more convenient if it is.
If an existing server is IIS, you should be able to export the cert WITH private key AS PFX/PKCS#12 from the Certificate snapin of mmc, and then convert the PKCS12 to JKS as just above.
If an existing server is something else, add it to the question.
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
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.