I'm trying to set up last version of MongoDB with SSL encryption, I was able to connect from mongo shell but I'm getting an error when I connect from a Java Client.
Works
mongo admin --host mongo1.xxxx.com --ssl --sslPEMKeyFile mongoClient.pem --sslCAFile mongoCA.crt
Doesn't work
public static void main(String args[]){
System.setProperty("javax.net.ssl.trustStore","/home/gasparms/truststore.ts");
System.setProperty("javax.net.ssl.trustStorePassword", "mypasswd");
System.setProperty("javax.net.ssl.keyStore", "/home/gasparms/truststore.ts");
System.setProperty("javax.net.ssl.keyStorePassword", "mypasswd");
System.setProperty("javax.security.auth.useSubjectCredsOnly","false");
MongoClientOptions options = MongoClientOptions.builder().sslEnabled(true)
.build();
MongoClient mongoClient = new MongoClient("mongo1.xxxx.com",options);
System.out.println(mongoClient.getDatabaseNames());
}
I get this error from Mongo side:
2015-06-09T15:08:14.431Z I NETWORK [initandlisten] connection
accepted from 192.168.33.1:38944 #585 (3 connections now open)
2015-06-09T15:08:14.445Z E NETWORK [conn585] no SSL certificate
provided by peer; connection rejected 2015-06-09T15:08:14.445Z I
NETWORK [conn585] end connection 192.168.33.1:38944 (2 connections
now open) 2015-06-09T15:08:14.828Z I NETWORK [conn580] end connection
192.168.33.13:39240 (1 connection now open)
and in java client program
INFORMACIÓN: Exception in monitor thread while connecting to server
mongo1.xxxx.com:27017 com.mongodb.MongoSocketReadException:
Prematurely reached end of stream at
com.mongodb.connection.SocketStream.read(SocketStream.java:88) at
com.mongodb.connection.InternalStreamConnection.receiveResponseBuffers(InternalStreamConnection.java:491)
at
com.mongodb.connection.InternalStreamConnection.receiveMessage(InternalStreamConnection.java:221)
at
com.mongodb.connection.CommandHelper.receiveReply(CommandHelper.java:134)
at
com.mongodb.connection.CommandHelper.receiveCommandResult(CommandHelper.java:121)
at
com.mongodb.connection.CommandHelper.executeCommand(CommandHelper.java:32)
at
com.mongodb.connection.InternalStreamConnectionInitializer.initializeConnectionDescription(InternalStreamConnectionInitializer.java:83)
at
com.mongodb.connection.InternalStreamConnectionInitializer.initialize(InternalStreamConnectionInitializer.java:43)
at
com.mongodb.connection.InternalStreamConnection.open(InternalStreamConnection.java:115)
at
com.mongodb.connection.DefaultServerMonitor$ServerMonitorRunnable.run(DefaultServerMonitor.java:127)
at java.lang.Thread.run(Thread.java:745)
Creation of Certificates
I have mongoCA.crt and mongoClient.pem that works with mongo shell. Then, I want to import .pem and .crt to a java keystore
openssl x509 -outform der -in certificate.pem -out certificate.der
keytool -import -alias MongoDB-Client -file certificate.der -keystore truststore.ts -noprompt -storepass "mypasswd"
keytool -import -alias "MongoDB-CA" -file mongoCA.crt -keystore truststore.ts -noprompt -storepass "mypasswd"
What I'm doing wrong?
I had the same problem, and for me it turned out to be a problem with the way I created the keystore. I notice that you are using the same file, truststore.ts, for both the truststore and keystore. This can work, but I would suggest using separate files to avoid confusion.
I had already created .pem files for the root CA and for the mongo user, and was able to successfully use them to connect with the mongo shell. From those I created truststore.jks and keystore.jks.
First, to create truststore.jks I ran:
keytool -import -alias root -storepass mypass -keystore truststore.jks -file rootca.pem -noprompt
For keystore.jks you need both the public and private keys so first convert the PEM file to PKCS12 format, and then import to a JKS:
openssl pkcs12 -export -out myuser.pkcs12 -in myuser.pem -password pass:mypass
keytool -importkeystore -srckeystore myuser.pkcs12 -srcstoretype PKCS12 -destkeystore keystore.jks -deststoretype JKS -deststorepass mypass -srcstorepass mypass
Related
I have generated the keystore using this command :
keytool -genkeypair -alias test -keyalg RSA -keystore keystore.jks
Under this section i have provided the following response:
What is your first and last name?
[Unknown]: myservice.example.com
Now i have generated the certificate with Common Name:myservice.example.com,
How should i import this certificate to my keystore so my client can connect to my service to a specific port and browser shouldn't display the invalid certificate error ?
This is a topic that has taken me quite some time to figure out. There are bits and pieces of information scattered and one has to put everything together. I was hoping that with this post I could help others quickly assemble a working solution.
I have a client-cert.pem, client-key.pem and a root.pem files and I need to used them in my Java client to access a remote REST API.
How do I package them into a truststore and use them to make API calls?
In order to load your certificates into your application your will need to package them into a truststore.
Creating a truststore
given the 3 files:
client-cert.pem
client-key.pem
root.pem
Run the following commands in your terminal. Replace PASSWORD with your desired password.
Package your client key and certificate into a keystore. This will create a PKCS12 keystore file.
openssl pkcs12 -export \
-inkey client-key.pem -in client-cert.pem \
-out client.pfx -passout pass:PASSWORD \
-name qlikClient
Add the keystore to your truststore. It will create a truststore if the destination doesn't exit. This will create a PKCS12 truststore file. By default it creates a JKS file which is a proprietary format. By specifying -deststoretype PKCS12 you will create a file which is in an industry standard format.
keytool -importkeystore \
-destkeystore truststore.pfx -deststoretype PKCS12 -deststorepass PASSWORD \
-srckeystore client.pfx -srcstorepass PASSWORD -srcstoretype PKCS12 \
-alias qlikClient
Add your root CA to the truststore
keytool -importcert \
-keystore truststore.pfx -storepass PASSWORD \
-file root.pem -noprompt \
-alias qlikServerCACert
Note that in the above commands we use the same PASSWORD for both the keystore and the truststore. You could alternatively use different passwords. Also note that you have to specify an alias for each item you add to the truststore.
If you want your truststore to trust all cacerts available in your system add -trustcacerts option to step 2 or 3.
You can use the following command to list the contents of your truststore
keytool -list -keystore truststore.pfx -storepass PASSWORD
Using the truststore in you application
Once you have your truststore you need to load it into your application. Assuming you have a constant KEYSTORE_PATH holding the path to your truststore and keyStorePass holding the password, read the truststore file into a KeyStore
private KeyStore readStore() {
try (InputStream keyStoreStream = new FileInputStream(KEYSTORE_PATH)) {
KeyStore keyStore = KeyStore.getInstance("PKCS12"); // or "JKS"
keyStore.load(keyStoreStream, keyStorePass.toCharArray());
return keyStore;
} catch (KeyStoreException | CertificateException | NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
Create a custom SSLContext and a custom HttpClient,
final KeyStore truststore = readStore();
final SSLContext sslContext;
try {
sslContext = SSLContexts.custom()
.loadTrustMaterial(truststore, new TrustAllStrategy())
.loadKeyMaterial(truststore, keyStorePass.toCharArray(), (aliases, socket) -> "qlikClient")
.build();
} catch (NoSuchAlgorithmException | KeyStoreException | KeyManagementException | UnrecoverableKeyException e) {
throw new RuntimeException("Failed to read keystore", e);
}
final CloseableHttpClient httpClient = HttpClients.custom().setSSLContext(sslContext).build();
You can now use this HttpClient to make requests to your API.
HttpResponse response = httpClient.execute(new HttpGet("https://sense-gcp-central1eu.net:4242/qrs/app/full"));
Or, if you are using the OpenUnirest/unirest-java library, you can configure Unirest to use your custom HttpClient
Unirest.config().httpClient(httpClient);
HttpResponse<JsonNode> response = Unirest.get("https://sense-gcp-central1eu.net:4242/qrs/app/full").asJson();
References
https://alvinalexander.com/java/java-keytool-keystore-certificate-tutorials
How do I use an SSL client certificate with Apache HttpClient?
I know it is an old question, but I figured out something wrong in your question.
The truststore is used by your client to list the remote server to which it can trust.
If the certificate/key you have and would like to use, is for your own java client, you should include them in your keystore, not truststore.
This is the store your client will use in case the remote server asks your client to authenticate itself.
On top of the already given answers, if you are using spring boot and resttemplate as http client implementation, you can use the keystore you created by doing so in your application properties:
server:
ssl:
enabled: true
key-alias: <<app-client-alias>>
key-store: <<path_to_your_keystore>>
key-store-password: <<PASSWORD>>
I'm running jetty on linux, and using ssl. I have a self signed certificate, and everything works fine in the browser; I just need to tell the browser to trust the certificate since it's from an untrusted source. But if I try to access a link (like an image; https://www.xxxx.com/pictures/picture.jpg) from my web application, it gives me an error:
07/16 08:14:28.708 WARN [log] () EXCEPTION
javax.net.ssl.SSLHandshakeException: Received fatal alert: certificate_unknown
at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
at sun.security.ssl.Alerts.getSSLException(Alerts.java:154)
at sun.security.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:1959)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1077)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1312)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1339)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1323)
at org.mortbay.jetty.security.SslSocketConnector$SslConnection.run(SslSocketConnector.java:631)
at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:522)
I think I need to get the client to trust the self signed certificate. I've tried this:
Using keytool, create a certificate for the broker:
keytool -genkey -alias broker -keyalg RSA -keystore broker.ks
Export the broker's certificate so it can be shared with clients:
keytool -export -alias broker -keystore broker.ks -file broker_cert
Create a certificate/keystore for the client:
keytool -genkey -alias client -keyalg RSA -keystore client.ks
Create a truststore for the client, and import the broker's certificate:
keytool -import -alias broker -keystore client.ts -file broker_cert
And I include these when I start Jetty:
javax.net.ssl.keyStore=/path/to/client.ks
javax.net.ssl.keyStorePassword=password
javax.net.ssl.trustStore=/path/to/client.ts
I made sure jetty uses the certificate I generated through browser. What am I missing?
Purchased a certificate for the server, that solved the problem.
I have Created CSR request using this command :
openssl req -out certificatecsr.csr -new -newkey rsa:2048 -keyout certificatekey.key
After that CA has shared certificate(.cer) file with me.
Now after that i have converted .cer file to .p12 using key.
Creating a .p12 certificate using cer sent by CA and private key
C:\Java\jdk1.6.0_38\jre\bin>openssl pkcs12 -export -in C:\Users\asharma1\cert.cer -inkey certificatekey.key -out
certi.p12
Creating JKS keystore :
keytool -genkey -alias quid -keystore quid.jks
importing .p12 certificate into jks keystore
C:\Java\jdk1.6.0_38\jre\bin>keytool -v -importkeystore -srckeystore C:\OpenSSL-Win64\bin\certi.p12 -srcstoretype PKCS12
-destkeystore quid.jks -deststoretype JKS
but when i am referring this JKS from my java code i am getting this error :
sun.security.validator.ValidatorException: PKIX path building failed:
sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
I have also added cer file to cacerts.but still getting the same error.
As far as JAVA code is concerned i am refering this link to refer my own created keystore :
http://jcalcote.wordpress.com/2010/06/22/managing-a-dynamic-java-trust-store/
public SSLContext getSSLContext(String tspath)
throws Exception {
TrustManager[] trustManagers = new TrustManager[] {
new ReloadableX509TrustManager(tspath)
};
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustManagers, null);
return sslContext;
}
SSLContext sslContext=getSSLContext("C:\\Java\\jdk1.6.0_38\\jre\\bin\\quid.jks");
SSLSocketFactory socketFactory = sslContext.getSocketFactory();
URL pickUrl = new URL(pickupLocation);
URLConnection urlConn = pickUrl.openConnection();
HttpsURLConnection httpsURLConn = (HttpsURLConnection)urlConn;
httpsURLConn.setSSLSocketFactory(socketFactory);
String encoding = urlConn.getContentEncoding();
InputStream is = urlConn.getInputStream();
InputStreamReader streamReader = new InputStreamReader(is, encoding != null
? encoding : "UTF-8");
Please note i am not using any server. I am trying ti run above written code thorugh main method only.
Please let me know what need to be done.
Why do i need to convert my .cer file to .p12 file ?
I would suggest you import CA certificate (or whole chain of CA and intermediate CAs) to keystore.
I think that p12 was imported fine. What I am suggesting is import of the chain to keystore. At least that is what the error message is saying.
I presume that:
the root CA in the chain is not trusted so chain building fails or
there is no AIA section in certificates in the chain so no certificates up to trusted root CA can be fetched so chain building fails or
the certificates are not being fetched based on AIA because it is not implemented in java (I am not a java programmer) so chain building fails
You could use portecle to import missing trusted CA certificates (not end entity cartificate that you have in .p12 or in separate .cer file that you received from issuing CA). It is more user friendly than keytool. Just follow this guide.
I would suggest you use the *.der format instead of the .p12 format.
Here's an overall summary of how to import certificates to fix the following error:
Error while trying to execute request.
javax.net.ssl.SSLHandshakeException:
sun.security.validator.ValidatorException: PKIX path building failed:
sun.security.provider.certpath.SunCertPathBuilderException: unable to
find valid certification path to requested target
How to import certificates
Go to URL in your browser, click on HTTPS certificate chain (little lock symbol next to URL address) to export the certificate
Click "more info" > "security" > "show certificate" > "details" > "export..".
Save as .der
Repeat for any certificates you need to import
Locate $JAVA_HOME/jre/lib/security/cacerts
Import all *.der files into the cacerts file using the following:
sudo keytool -import -alias mysitestaging -keystore $JAVA_HOME/jre/lib/security/cacerts -file staging.der
sudo keytool -import -alias mysiteprod -keystore $JAVA_HOME/jre/lib/security/cacerts -file prod.der
sudo keytool -import -alias mysitedev -keystore $JAVA_HOME/jre/lib/security/cacerts -file dev.der
The default keystore password is 'changeit'
You can view the change that you made with this command that shows the Certificate fingerprint.
keytool -list -keystore $JAVA_HOME/jre/lib/security/cacerts
If this doesn't solve the problem, try adding these java options as arguments:
-Djavax.net.ssl.trustStore="$JAVA_HOME/jre/lib/security/cacerts"
-Djavax.net.ssl.trustStorePassword="changeit"
I am using Java(Zehon) to transfer files over FTPS. This is my code snippet.
try {
FTPsClient ftpClient = new FTPsClient(host, port,username ,password ,false,keyStorePath,keyStorePass);
ftpClient.sendFile(absFilePath, ftpsFolder);
}catch (FileTransferException e) {e.printStackTrace();}
I have telnet the host ip and i am getting connected. I am quite sure that the credentials i am passing is correct.The exception am getting is com.zehon.exception.FileTransferException: java.net.SocketException: Connection reset
Any suggestions as to what else i may need to add while connecting to the host because the javadoc for FTPsClient does not show any more methods to connect to the host.
The Problem was with configuring the keystore file. This is how you actually need to make it:
Download OPENSSL and type this command
openssl pkcs12 -export -in /path/to/YourVeriSignSSLCert.crt -inkey /path/to/YourPrivateKey.key -out mycert.p12 -name tomcat -CAfile /path/to/YourIntermediateCertificate.cer -caname root
YourVeriSignSSLCert.crt is your current openssl certificate
YourPrivateKey.key is your current private key
YourIntermediateCertificate.cer is the VeriSign Intermediate CA
The exported keystore will be in 'mycert.p12'
Now the keystore file is of pkcs12 format i am converting this into jks format :
keytool -v -importkeystore -trustcacerts -srckeystore mycert.p12 -srcstoretype PKCS12 -destkeystore md_keystore.jks -deststoretype JKS
Now this is the keystore file that needs to be passed to the program.