Convert PKCS7 to PKCS12 using java.security.KeyStore - java

When I try to import a renewed X509 certificate on Chrome / Firefox (and probably other browser), it does not recognize that the certificate I am trying to import uses the same private key stored in my expiring user certificate with the same DN. I don't know if this is a bug with the implementation of certificate import tool of all major browsers, but I can (somewhat) work around this problem by storing my user certificate inside a private key-less PKCS12 file using openssl tool like following.
openssl pkcs12 -export -in usercert.pem -nokeys -name "CN: Same Name" -out certonly.p12
(-nokeys is the trick here)
I don't know why this works, but I can then import certonly.p12 to Chrome / Firefox and it will attach my private key from the last year; although it creates a separate certificate entry so that I need to remove my old certificate manually.
So, I assume that, in order to renew my user certificate on my browser, I will need to package my certificate in PKCS12 format (with or without a pass-phrase).
Now, I need to do this in my Java application using java.security.KeyStore or similar libraries, because it is actually my web application which is generating user's renewed certificates. I don't want to ask our users to use the openssl command themselve to convert it to pkcs12 before importing to their browsers. My application should do this automatically, and provide them the renewed certificate contained inside a PKCS12 file.
I've looked many places, but so far I can't find a concrete example of how to do this using Java. Does anyone know how to output a pass-phrase less PKCS12 with only an issued certificate (or pkcs7) without a private key?
I tried something like following but it did not work.
java.security.cert.Certificate[] chain = CertificateManager.parsePKCS7(renewed_cert_in_pkcs7);
KeyStore p12 = KeyStore.getInstance("PKCS12");
p12.load(null, null);
p12.setKeyEntry("USER Cert 123", null, "".toCharArray(), chain);
response.setContentType("application/x-pkcs12");
response.setHeader("Content-Disposition", "attachment; filename=user_certificate_only.p12");
p12.store(response.getOutputStream(), "".toCharArray());

Related

using KeyStore with .crt

I need to integrate an application with external web service which forces to use https. Authors of this web service provided me with .crt file which I should use for making https requests. After some investigation I've found the following code which uses KeyStore class for secured https access:
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
FileInputStream instream = new FileInputStream(new File(file));
try {
trustStore.load(instream, password.toCharArray());
} finally {
instream.close();
}
SSLContext sslcontext =
SSLContexts.custom().loadTrustMaterial(trustStore, new TrustSelfSignedStrategy()).build();
SSLConnectionSocketFactory sslsf =
new SSLConnectionSocketFactory(sslcontext, new String[]{"TLSv1.2"}, null,
BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
HttpClients.custom().setSSLSocketFactory(sslsf).build();
In this code KeyStore requires input stream along with password trustStore.load(instream, password.toCharArray());. However, as I understand, we don't need password when using .crt file. So this way of loading certificate is not suitable for me. At the same time, from what I've discovered so far, the code I provided here is the only way to configure HttpClient for using SSL certificate. Is there any workaround to configure HttpClient for using .crt certificate?
Thanks,
Andrey
I assume the Web service is providing you with a self-signed certificate (i.e. not signed by a well-known CA). If it is already signed by a well-known CA that is in Java's cacerts file, then you don't need to do anything.
Otherwise, you have a couple of options:
Import the certificate into global cacerts keystore
Launch your application with application-specific keystore
In either case, you first need to convert crt file into jks keystore that Java uses. You can do this by:
$ keytool -import -keystore mykeystore.jks -storepass horsestaple
Note that keytool requires the password (horsestaple above) to be supplied for creating a jks store. You can put anything there; as you mention, public website certificates do not need password protection, they are public after all.
If you are doing option 1, make a backup of your cacerts and supply the cacerts file instead of mykeystore.jks. See the link below for the location of cacerts. For this option, you are all set, your application should be connecting to the Web service via HTTPS without any additional configuration, since Java loads cacerts by default.
If you are doing option 2, which is probably preferred at least for testing phase, you need to run your application with this parameter:
-Djavax.net.ssl.trustStore=mykeystore.jks
This is a JVM parameter, so supply it appropriately. This depends on how you are running you application.
Note that you will only have the imported certificate in this case, so your other HTTPS connections will not work. You can avoid this by first copying the standard cacerts to a temporary location, importing the key into it and using that in the command above. That will give you all the standard certificates, plus the one you need.
A slight downside of option 2 is that if new certificates are added or revoked, your application-specific keystore will not be updated. If this is a concern, you can merge keystores on the fly, for example:
Registering multiple keystores in JVM
In either case, you should now be able to just do a standard URL fetch, such as in example given here:
https://blogs.oracle.com/java-platform-group/entry/diagnosing_tls_ssl_and_https
i.e.:
final URL url = new URL("https://example.com");
try(final InputStream in = url.openStream()){
//…
}
More information here:
Keytool and general certificates info
https://docs.oracle.com/cd/E19830-01/819-4712/ablqw/index.html
Cacerts location
http://docs.oracle.com/javase/7/docs/technotes/tools/solaris/keytool.html
More options for importing self-signed certificates
How to properly import a selfsigned certificate into Java keystore that is available to all Java applications by default?
Unless they provided you with their .crt file which should be used for validating connections to them, which would indicate they are using a self-signed certificate, they haven't provided you with anything useful. If you need a certificate as a client, the first thing you need is a public/private key pair, from which you generate a CSR, which you get signed. Nobody else can securely provide any of that except the signed certificate.
If they've provided their own (self-signed?) certificate, you need to load it into a truststore, not a keystore, via the keytool with the -trustcacerts option, and then tell Java to use that truststore, either via the javax.net.ssl.trustStore system property or by constructing your own TrustManager and feeding it to a custom SSLContext, as described in the JSSE Reference Guide.

Converting .jks truststores and keystores to ios

I have created a java webservice that is going to be communicating with iPads using restlet on the server side that communicates over HTTPS with mutual authentication. I have generated two .jks keystores using this guide
http://www.herongyang.com/JDK/ssl_client_auth.html
I have implemented a client for testing purpose in java and everything worked out fine.
I assume that it isn't possible to use the format .jks in ios so should I convert the client.jks to a pkcs12 file in order to make it compatible with ios?
I am having trouble finding information about this.
Thanks!
If I understand your situation correctly, and I may not, you shouldn't need to change the .jks at all. The KeyStore for your application is just a container of certificates used by your system. To achieve certificate integration on IOS you may have to add the client and ca certs to your local system key chain ( check out : iOS: Pre install SSL certificate in keychain - programmatically ) but the JKS itself should transfer to the other platform with no modifications required.
Also, here is an example of using a keystore on IOS to do apple push notifications. iOS Push Notification - JavaPNS - keystore.p12 file security If you want to do it exactly the same way that this person did (using a local p12 rather than a loaded store) just follow the instructions over here: Converting .jks to p12
For more information about the differences between these files check out: Difference between .keystore file and .jks file
Best of luck with your project.
Converting the .jks to pkcs12 sounds like a good bet. The certificates generated by iOS provisioning portal can be exported (by KeyChain Access) to pkcs12 format, so it's safe to assume this format is compatible with iOS.
You can use keytool to convert your jks to pkcs12. I used it in the opposite direction (converted a pkcs12 file obtained from Apple to jks), and it should work with no problems in your case too.
This command should do the trick :
keytool -importkeystore -srckeystore input.jks -destkeystore output.p12 -srcstoretype JKS -storetype PKCS12

Creating an SSL Connection in Java

I looked around and did not see any questions that fully answered what I wanted, though if this is a duplicate, point me to the question and I will be on my way.
Right now I am trying to write a Java server that will receive data from an SSLServerSocket and for now, just print it out. I would eventually like to have this data come from an Android, but right now it throws an SSLException before it even starts listening for data.
code:
System.setProperty("javax.net.ssl.keyStore","C:\\ProgramFiles\\jre6\\bin\\server.jks");
System.setProperty("javax.net.ssl.keyStorePassword","password");
SSLServerSocketFactory factory = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
ServerSocket ss = factory.createServerSocket(6543);
Socket s = ss.accept();
There is more code after that to process it, but it gets hung up and throws the exception there, so I'm not sure posting it will help any, but if it will, just comment for it.
I created the certificate following a tutorial for openssl on Ubuntu and transferred it over and created my keystore using:
keytool -import -file "C:\Documents and Settings\matt\Desktop\server.crt" -keystore server.jks
I can easily admit that I don't fully understand how a large portion of this works, so any help would be appreciated. Also, I suppose I am going to leave it outside the scope of this question becauseI feel like this is a pretty big question on its own, butI would also like some insight as to how to connect the client if possible. Sorry for all the trouble and thanks ahead of time for all the help.
EDIT:
the tutorial I followed is here:
http://www.akadia.com/services/ssh_test_certificate.html
Thanks again!
EDIT:
The Exception being throw is:
javax.net.ssl.SSLException: No available certificate or key corresponds to the SSL cipher suites which are enabled
I tried to Google the exception and most everything was a tutorial describing how to create a keystore (which I am under the impression that I already have). I will continue to sift through these search results.
Thanks!
When you create a keystore like this, you only put a certificate in your keystore:
keytool -import -file "server.crt" -keystore server.jks
What you need is to have a private key + a certificate.
Either you import them from somewhere else if you already have a certificate issued by a Certification Authority, or you can create a self-signed certificate if it's for limited use.
If the certificate you've created with OpenSSL is self-signed (or from a mini CA for your own use, e.g. with CA.pl), it's probably not worth the trouble of doing the conversion. You might as well generate a self-signed certificate directly with keytool. See the "Generating Your Key Pair" example in the official keytool documentation:
keytool -genkeypair -dname "cn=Mark Jones, ou=JavaSoft, o=Sun, c=US"
-alias business -keypass kpi135 -keystore /working/mykeystore
-storepass ab987c -validity 180
Make sure you use cn=your.fqdn.host.name (or cn=localhost if it's for local tests only). (I think keytool provided with Java 7 also has support for subject alternative names, which would be better.)
If you already have a private key + certificate you want to re-use in PKCS#12 format (usually .p12 file), you can import it using the method described in this question.
If what you've produced with OpenSSL is in PEM format, it might be easier to bundle them in a PKCS#12 file with OpenSSL and then import them as above. This can be done with this:
openssl pkcs12 -export -in cert.pem -inkey key.pem -out creds.p12

Import client self signed cert into java keystore

See also: Can a Java key store import a key pair generated by OpenSSL?
I am provided with the following files to authenticate against a thrift endpoint:
cacert.pem
local.crt
local.key
I am having the hardest time trying to create a keystore that has the client cert in it. The endpoint application has its own CA to authenticate they client certs. I honestly am not sure what needs to be included in the keystore (assuming the client cert, and the endpoint public cert), but for the life of me can not get it working.
Does anyone know how to import a client cert into a keystore? Or, what I need to do in order to get this working? Thanks.
The problem was with the keystore, this is how I finally got it working.
First thing to note is that its not possible (as far as I know) to import private keys into a keystore using keytool...
Knowing that, I converted the local.crt and local.key to a .p12 file via openssl:
openssl pkcs12 -export -in local.crt -inkey local.key -out local.p12
Then used a tool from IBM (keyman): http://www.alphaworks.ibm.com/tech/keyman/download
To import the CA cert (cacert.crt) and then the .p12 file, then saved that as a keystore.
Hope this helps someone!

Java Sign jars with server certificate

Is it possible to use a server certificate to sign a java web start app? What I want to know is if will it work. I have a trusted certificate for my server, and I would like to reuse the same certificate to sign an app.
Right now, I have this warning:
This jar contains entries whose signer certificate's ExtendedKeyUsage
extension doesn't allow code signing. This jar contains entries whose
signer certificate's NetscapeCertType extension doesn't allow code
signing.
Will I be able to launch my app without the warning that the certificate is not trusted?
You will get warning if you don't use a code signing certificate. For most CA, code signing cert costs more than the server cert. In my opinion, this is just a marketing scheme to make you to pay for another cert. There is no technical difference between two certs. Some CA may provide combo deals with usage for both.
I assume you have created the JKS file using the KEY and CRT of your SSL and hence you get the error..
I have a simple solution here:
As you know you can create a JKS using the following command
keytool -genkey -v -keystore my-release-key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias my-alias
and when you use this JKS you get self signed certification message which is absolutely fine to make the app live at Google play store.. But buying code signing certificate is good if you can afford it ..

Categories

Resources