I want to make a server SSL socket connection using the following code:
int port = 12000;
ServerSocketFactory ssocketFactory = SSLServerSocketFactory.getDefault();
ServerSocket ssocket = ssocketFactory.createServerSocket(port);
// Listen for connections
Socket socket = ssocket.accept();
I get a "javax.net.ssl.SSLException: No available certificate or key corresponds to the SSL cipher suites which are enabled." when doing the accept.
I created a Keystore that contains a RSA key using:
keytool -genkeypair -alias ClubConnectionCert -keyalg RSA -validity 7 -keystore ClubConnectionKeystore
and I start my Program with the following options:
-Djavax.net.ssl.keyStore=ClubConnectionKeystore -Djavax.net.ssl.keyStorePassword=mypassword
Do I miss some code to read in the Keystore, or how can I test/debug that the given keystore is actually used?
I executed your code and I confirm it's working fine.
Make sure javax.net.ssl.keyStore points exactly to your keystore file.
I put my keystore file at the root of my project.
Perhaps try absolute path to your keystore.
Make sure the -D parameters are set as JVM params, not Program options (in your IDE).
Good luck, you're about to make it work.
Related
when I am creating Restservices in java using GET, POST etc then I am requesting them using
http protocol. as soon as i use https it gives error.
for eg : http://localhost:8080/demorest/webapi/aliens is working properly.
but when I query same using https
https://localhost:8080/demorest/webapi/aliens
I get error site can not provide secured connection
what modification is required to make them compatible with https.
As you mentioned you are new to APIs here is a detailed answer for you.
Answer is based on assumption that you are using tomcat server. There is 4 step approach to have application running on https, red below
Get an SSL certificate or Generate a self-signed SSL certificate
Enable HTTPS in application
Redirect HTTP to HTTPS
Distribute the SSL certificate to clients.
If you dont already have ssl certificate generate yourself using keytool.
Keytool is a certificate management utility provided together with the JDK, so if you have the JDK installed, you should already have keytool available.
Let's open our Terminal prompt and write the following command to create a JKS keystore:
keytool -genkeypair -alias tomcat -keyalg RSA -keysize 2048 -keystore
keystore.jks -validity 3650 -storepass password
To create a PKCS12 keystore, and we should, the command is the following:
keytool -genkeypair -alias tomcat -keyalg RSA -keysize 2048 -storetype
PKCS12 -keystore keystore.p12 -validity 3650 -storepass password
Let's have a closer look at the command we just run:
genkeypair: generates a key pair;
alias: the alias name for the item we are generating;
keyalg: the cryptographic algorithm to generate the key pair;
keysize: the size of the key. We have used 2048 bits, but 4096 would be a better choice for production;
storetype: the type of keystore;
keystore: the name of the keystore;
validity: validity number of days;
storepass: a password for the keystore.
When running the previous command, we will be asked to input some information, but we are free to skip all of it (just press Return to skip an option). When asked if the information is correct, we should type yes. Finally, we hit return to use the keystore password as key password as well.
What is your first and last name?
[Unknown]: What is the name of your organizational unit?
[Unknown]: What is the name of your organization?
[Unknown]: What is the name of your City or Locality?
[Unknown]: What is the name of your State or Province?
[Unknown]: What is the two-letter country code for this unit?
[Unknown]: Is CN=localhost, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=Unknown correct?
[no]: yes
Enter key password for <tomcat>
(RETURN if same as keystore password):
Verify the keystore content
To check the content of the keystore following the JKS format, we can use keytool again:
keytool -list -v -keystore keystore.jks
To test the content of a keystore following the PKCS12 format:
keytool -list -v -storetype pkcs12 -keystore keystore.p12
Convert a JKS keystore into PKCS12
Should we have already a JKS keystore, we have the option to migrate it to PKCS12; keytool has a convenient command for that:
keytool -importkeystore -srckeystore keystore.jks -destkeystore
keystore.p12 -deststoretype pkcs12
2.) To Enable https in your project
If you have a application.properties file
server.port=8443
server.ssl.key-store-type=PKCS12
server.ssl.key-store=classpath:keystore.p12
server.ssl.key-store-password=password
server.ssl.key-alias=tomcat
security.require-ssl=true
If you have application.yml file
server:
ssl:
key-store: classpath:keystore.p12
key-store-password: password
key-store-type: pkcs12
key-alias: tomcat
key-password: password
port: 8443
To achieve in application, we need to extend the WebSecurityConfigurerAdapter class, since the security.require-ssl property has been deprecated.
if you are on older version then you can skip below mentioned code.
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.requiresChannel()
.anyRequest()
.requiresSecure();
}
}
3.) Redirect http to https
Now that we have enabled HTTPS in our Spring Boot application and blocked any HTTP request, we want to redirect all traffic to HTTPS.
Spring allows defining just one network connector in application.properties (or application.yml). Since we have used it for HTTPS, we have to set the HTTP connector programmatically for our Tomcat web server.
#Configuration
public class ServerConfig {
#Bean
public ServletWebServerFactory servletContainer() {
TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory() {
#Override
protected void postProcessContext(Context context) {
SecurityConstraint securityConstraint = new SecurityConstraint();
securityConstraint.setUserConstraint("CONFIDENTIAL");
SecurityCollection collection = new SecurityCollection();
collection.addPattern("/*");
securityConstraint.addCollection(collection);
context.addConstraint(securityConstraint);
}
};
tomcat.addAdditionalTomcatConnectors(getHttpConnector());
return tomcat;
}
private Connector getHttpConnector() {
Connector connector = new Connector(TomcatServletWebServerFactory.DEFAULT_PROTOCOL);
connector.setScheme("http");
connector.setPort(8080);
connector.setSecure(false);
connector.setRedirectPort(8443);
return connector;
}
}
4.) Distribute the SSL certificate to clients
When using a self-signed SSL certificate, our browser won't trust our application and will warn the user that it's not secure. And that'll be the same with any other client.
It's possible to make a client trust our application by providing it with our certificate.
Extract an SSL certificate from a keystore
We have stored our certificate inside a keystore, so we need to extract it. Again, keytool supports us very well:
keytool -export -keystore keystore.jks -alias tomcat -file
myCertificate.crt
Make a browser trust an SSL certificate
When using a keystore in the industry-standard PKCS12 format, we should be able to use it directly without extracting the certificate.
I suggest you check the official guide on how to import a PKCS12 file into your specific client.
If deploying the application on localhost, we may need to do a further step from our browser: enabling insecure connections with localhost.
In Chrome, we can write the following URL in the search bar: chrome://flags/#allow-insecure-localhost and activate the relative option.
Import an SSL certificate inside the JRE keystore
To make the JRE trust our certificate, we need to import it inside cacerts: the JRE trust store in charge of holding all certificates that can be trusted.
First, we need to know the path to our JDK home. A quick way to find it, if we are using Eclipse or STS as our IDE, is by going to Preferences > Java > Installed JREs. If using IntelliJ IDEA, we can access this information by going to Project Structure > SDKs and look at the value of the JDK home path field.
Then, from our Terminal prompt, let's insert the following command (we might need to run it with administrator privileges by prefixing it with sudo):
keytool -importcert -file myCertificate.crt -alias tomcat -keystore
$JDK_HOME/jre/lib/security/cacerts
you can refer project on github here
It depends, your rest services might run on Tomcat or Spring Boot so should read their documentation, you can also use a different https service like nginx that proxies all or parts of the requests from https to http.
First check https protocol using the same port as 8080? in most of the cases http (8080) and https(8443 or 443) use different ports.
If port is correct then import the certificate.
https://stackoverflow.com/a/27928213/5662508
It would be helpful if you can give the sever you are using, also would be always nice if the java version, frameworks(if any) and their version and in this case of-course the server and the server version.
In the link mentioned here on DZone you can find an example of how to set up https locally with tomcat server in a java application, else you can also try with a more generic article not specific to java here on freecodecamp
Step 1 : You can create a keystore using java keytool;
Command : keytool -genkey -alias {any-name} -keyalg RSA -keystore {path to store the keystore}
Step 2 : You can go to your server config file such as conf/server.xml for Tomcat and uncomment the 8443 setting and then add the following in the end before tag closing;
keystoreFile="{path to keystore}"
keystorePass="{Password you set while creating the keystore}" />
Step 3 : Now restart the server and hit "https://localhost:8443/demorest/webapi/aliens".
Happy coding!
I need to create a web service client with a keystore. But this is the error:
sun.security.provider.certpath.SunCertPathBuilderException: unable to
find valid certification path to requested target
My code:
private SSLSocketFactory getFactory() throws Exception {
File pKeyFile = new ClassPathResource("jks/dex-client-issuer-wss.jks").getFile();
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("PKIX");
KeyStore keyStore = KeyStore.getInstance("JKS");
InputStream keyInput = new FileInputStream(pKeyFile);
keyStore.load(keyInput, pass.toCharArray());
keyInput.close();
keyManagerFactory.init(keyStore, pass.toCharArray());
SSLContext context = SSLContext.getInstance("TLS");
context.init(keyManagerFactory.getKeyManagers(), null, new SecureRandom());
return context.getSocketFactory();
}
this is the http conection:
URL url = new URL("https://dexxis-demo1.gemalto.com/DEX/communication/issuer-interface");
HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
con.setSSLSocketFactory(getFactory());
I only have a dex-client-issuer-wss.jks file which works with soap ui, how can I create a connection with this certificate file?
'unable to find valid certification path' (during SSL/TLS handshake) has nothing to do with your keystore -- it means that the server cert does not validate against your truststore, which since you passed null as the 2nd arg to context.init is the JRE's default, which is the file specified by sysprop javax.net.ssl.trustStore if set otherwise JRE/lib/security/cacerts (or .../jssecacerts if it exists).
That server is using a cert issued under the root cert Gemalto Business Root Certificate Authority which is not included in the cacerts supplied with Oracle Java packages, or any other established truststores I know, and is not known by the public transparency logs (per https://crt.sh). SoapUI, presumably because it is designed as a development, test and debug tool, ignores invalid or suspect certs, but a browser or curl or wget on that URL should fail unless the truststore(s) on your system(s) have been modified or are otherwise unusual.
OTOH openssl s_client which is also primarily a debug tool reports an error but makes the connection anyway.
If you do want to trust that CA, or one of its (two) intermediates, or the site anyway, you need to have the appropriate cert in your truststore. The usual practice is to trust the root CA cert, but Java supports using any cert in the chain, including the EE cert, as an anchor. Since you are already creating your own context, and keymanager, you might as well create your own trustmanager rather than modifying the JRE default, which is (usually) platform/environment dependent and sometimes tricky. You could fetch the desired cert and put it in a separate keystore file (see below), load that and use it to create a trustmanager. Or since you already have a keystore file for your own key+cert(s), Java supports having both a privateKey entry or entries and a trustedCert entry or entries for other party/parties in the same file, so you could just add their cert to your existing JKS and use the same KeyStore object in a TrustManagerFactory just like you have for KeyManagerFactory to create the trustmanager array for your context.
Easy ways to get the cert are:
openssl s_client -showcerts -connect host:port </dev/null (on Windows <NUL:) -- with port 443; many servers nowadays need the Server Name Indication extension (aka SNI) and for OpenSSL below 1.1.1 you must add -servername host to provide it, but this server doesn't. This outputs a PEM block for each cert from the server, with labels before each showing s: (subjectname) and i: (issuername). Note that after the first cert, which is as required the EE cert, this server sends the CA certs in top-down order not bottom-up. This is technically in violation of RFC 5246 (or earlier 4346 or 2246); RFC 8446 for TLS1.3 allows it because it was already a common extension, and Java JSSE in particular supports it.
keytool -printcert -rfc -sslserver host -- also supports host:port but the default is 443 which is okay for you. This outputs only the PEM blocks, so if you didn't already know from my previous item about the order, you would have to decode each one to find out which is which, or just experiment until you found the correct one.
In either case take the desired PEM block and put it in a file, and do
keytool -importcert -keystore jksfile -alias somealias -file thecertfile
somealias is only required to be unique within the file (which is trivial if you put it in its own file) and case-insensitive (conventionally lowercase), but should be descriptive or mnemonic, and alphanumeric only if possible. Then use the resulting file as above.
I'm trying to get JMX working under Tomcat 7.0.23 with SSL. The servers are located in AWS, which means all the hosts are NATed, and I need to use JmxRemoteLifecycleListener to explicitly set the two ports used by JMX. I've been doing a lot of reading on the subject but I just can't get all the pieces working together properly.
I can get JMX working fine without SSL. I have downloaded the version of catalina-jmx-remote.jar for my version of Tomcat and installed it in my tomcat/lib directory. My server.xml contains:
<Listener className="org.apache.catalina.mbeans.JmxRemoteLifecycleListener"
rmiRegistryPortPlatform="1099" rmiServerPortPlatform="1098" />
When I launch Tomcat with the following settings I can connect with an insecure session:
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.password.file=/path/to/jmxremote.password
-Dcom.sun.management.jmxremote.access.file=/path/to/jmxremote.access
-Djava.rmi.server.hostname=<public IP of server>
-Dcom.sun.management.jmxremote.ssl=false
However if I change these to the following then I'm unable to establish an SSL connection:
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.password.file=/path/to/jmxremote.password
-Dcom.sun.management.jmxremote.access.file=/path/to/jmxremote.access
-Djava.rmi.server.hostname=<public IP of server>
-Dcom.sun.management.jmxremote.ssl=true
-Dcom.sun.management.jmxremote.ssl.need.client.auth=false
-Dcom.sun.management.jmxremote.authenticate=true
-Djavax.net.ssl.keyStore=/path/to/keystore.dat
-Djavax.net.ssl.keyStorePassword=<password>
-Djavax.net.ssl.trustStore=/path/to/truststore.dat
-Djavax.net.ssl.trustStorePassword=<password>
keystore.dat contains just a single certificate created via:
openssl x509 -outform der -in cert.pem -out cert.der
keytool -import -alias tomcat -keystore keystore.dat -file cert.der -storepass <password>
truststore.dat contains a full copy of the java cacerts plus the CA cert for my self-signed cert:
cp $JAVA_HOME/jre/lib/security/cacerts truststore.dat
keytool -storepasswd -storepass changeit -new <password> -keystore truststore.dat
keytool -import -trustcacerts -file mycacert.pem -alias myalias -keystore truststore.dat -storepass <password>
After launching Tomcat I've tried connecting via jconsole but it can't establish a connection. I tried to verify SSL using openssl but it looks like Tomcat isn't making use of the cert:
$ openssl s_client -connect <host>:1099
CONNECTED(00000003)
140735160957372:error:140790E5:SSL routines:SSL23_WRITE:ssl handshake failure:s23_lib.c:177:
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 0 bytes and written 322 bytes
---
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
---
I've verified that my local keystore and truststore are set up properly by exporting the keys and verifying the cert chain (combined.pem is all the CA certs from truststore.dat and cert.pem is my cert from keystore.dat):
$ openssl verify -verbose -purpose sslserver -CAfile combined.pem cert.pem
cert.pem: OK
So now I'm at a complete loss. The cert and CA cert look correct. Unencrypted JMX connections work. But I can't seem to get the connection to use SSL. What am I missing here?
I don't know if this is just a red herring or not, but I don't see any way to specify what cert in the keyStore is used by JMX. Some of what I read implies that it just uses a cert with the alias "tomcat". Is that correct?
You are starting the RMI Registry on port 1099. In order for the RMI Registry to utilize SSL you need to pass an additional -Dcom.sun.management.jmxremote.registry.ssl=true argument.
Edit:
Do you use jconsole -J-Djavax.net.ssl.trustStore=truststore -J-Djavax.net.ssl.trustStorePassword=trustword -Djavax.net.ssl.keyStore=keystore -Djavax.net.ssl.keyStorePassword=password to start JConsole? It needs to know where the stores are and the corresponding passwords.
For VisualVM you can install VisualVM-Security plugin which will add a new tab to the Options dialogue allowing you customize the SSL related options in UI.
I wanted tomcat getting to work with jmx and ssl and followed Bruce setup. In case someone runs int the same problem: using the openssl and keytool commands form Bruce I was getting at client ssl errors:
javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
Not sure why but the figerprint on one side was 5 chars longer at the beginning.
I recreated the keystore using:
keytool -genkeypair -alias tomcat -keyalg RSA -keystore keystore.jks -dname cn=test,ou=test,dc=example,dc=com
In tomcat sever.xml I added the listener as Bruce suggested.
Because client auth is set to false I do not add truststore in tomcat jmx configuration. Instead I added registry.ssl:
[...]
-Djavax.net.ssl.keyStorePassword=your_keystore_pass
-Dcom.sun.management.jmxremote.registry.ssl=true
Then on client side as J.B. suggested I download ssl plugin for visualvm and criss-cross the keystore resulting in:
visualvm -J-Djavax.net.ssl.trustStore=keystore.jks -J-Djavax.net.ssl.trustStorePassword=your_keystore_pass
When adding authentication make sure that your jmx access file looks like:
<user_name> readwrite
and your password file looks like:
<user_name> <your_password>
This solved my ssl jmx setup for testing with visualm vm.
Edit:
Had some issues with having the registry also over SSL, set by:
-Dcom.sun.management.jmxremote.registry.ssl=true
leading at client to throw:
Root exception is java.rmi.ConnectIOException: non-JRMP server at remote endpoint
Adding client auth authentication:
-Dcom.sun.management.jmxremote.ssl.need.client.auth=true
-Djavax.net.ssl.trustStore=truststore.jks
-Djavax.net.ssl.trustStorePassword=your_trust_store_pass
solved both jmx and its registry to use ssl.
so here's what I'm trying to do:
I connect to my SSL server
It sends me two certificates, and one of them is self-signed
At this stage, there are no problems, I've:
X509Certificate[] myTwoCerts;
// with 2 certificates in there, and I'm sure it's there because, I print them in my console.
Now I want to create .p12 file with 2 certificates inside.
Until now, I've tried something like this:
KeyStore pkcs12Store = KeyStore.getInstance("PKCS12");
pkcs12Store.load(null, null);
X509Certificate cert1 = myTwoCerts[0];
X509Certificate cert2 = myTwoCerts[1]
String alias1 = "FIRST";
String alias2 = "SECOND";
pkcs12Store.setCertificateEntry(alias1, cert2);
pkcs12Store.setCertificateEntry(alias2, cert2);
But I'm getting the following Exception:
Exception in thread "main" java.security.KeyStoreException: TrustedCertEntry not supported
Can anybody help me plz??
The PKCS12 keystore in Java cannot be used to store certificates or certificate chains without their private keys.
See this note in the JCA reference guide:
"pkcs12" is another option. This is a cross platform keystore based on the RSA PKCS12 Personal Information Exchange Syntax Standard. This standard is primarily meant for storing or transporting a user's private keys, certificates, and miscellaneous secrets. As of JDK 6, standards for storing Trusted Certificates in "pkcs12" have not been established yet, and thus "jks" or "jceks" should be used for trusted certificates.
(Despite mentioning JDK 6, this still is in the JDK 7 documentation.)
If you want to store a private key + certificate (chain) in a PKCS#12 store in Java, there needs to be a private key and you need to use the setKeyEntry method.
keytool -trustcacerts -keystore keystore.p12 -storetype pkcs12 -alias root -genkeypair
KeyStore pkcs12 = KeyStore.getInstance("PKCS12");
String filename = "/tmp/keystore.p12";
keyStore.load(
new FileInputStream(/*"myKeyStore.jks"*/filename),
password);
I'm creating a Java client program that will be sending sensitive information to a Tomcat server. So I need to use SSL Connection so information will be encrypted.
I need to use self-signed untrusted certificate but having problems making connection from java client.
I have successfully setup Tomcat 5.5 to use SSL and tested it through Firefox, which displays warning of self-signed certificate.
I followed the Tomcat 5.5 SSL setup and they mentioned to create a keystore:
keytool -genkey -alias tomcat -keyalg RSA
Then I did an export of the above:
keytool -export -keystore .keystore -alias tomcat -file localhost.cer
Then I did an import of the above certificate into client machine:
keytool -import -alias tomcat -file localhost.cer -keystore "C:\Program Files"\Java\jdk1.6.0_17\jre\lib\security\cacerts"
But when running client I get:
Exception in thread "main" 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
This is the client code:
URL url = new URL("https://localhost:8443");
HttpsURLConnection conn = (HttpsURLConnection)url.openConnection();
conn.setSSLSocketFactory(sslsocketfactory);
InputStream inputstream = conn.getInputStream();
Now I just started playing with these certificates today and I'm new to keystores, so please be patient.
Can someone please explain how to export and import the certificate created in Tomcat to client machine?
Thank you.
Atlassian has good instructions on how to fix this.
http://confluence.atlassian.com/display/JIRA/Connecting+to+SSL+services
Another approach is to install less unforgiving certificate validators, but that should only be done as a last resort.
Use Apache HTTP Cleint jar and follow this SSL Guide.
EasySSLProtocolSocketFactory can be used to create SSL connections that allow the target server to authenticate with a self-signed certificate.
I think you should input password using "changeit".