I need to send a POST request to a server that uses some levels of security. Unfortunately I don't know much about self signed certificates, I never used or studied it.
In the developer guide of the service it sais that the server uses a "public 1024-bit self signed certificate".
What does it mean? I've to create a certificate or I've to ask for it?
If i've to create a certificate, then how I should use it?
I'm implementing the client in Java
You need to download the certificate e.g. with your internet browser. Click through the security information and export the certificate.
Then you need to import it into your local java keystore so that the JVM can find it. For import use the keytool which you find in your jre/bin directory. Documentation for the keytool: http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/keytool.html
The default keystore is jre/lib/security/cacerts.
Then you can import the downloaded certificate:
jre/bin/keytool -import -keystore jre/lib/security/cacerts -alias mycertificate -file downloads/mycertificate.cer
Hope this helps.
P.S. If it is self signed or verified its not important at this point. Just you (your client) must trust it.
Related
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.
I developed an application that uses Java Webstart. It needs write access to the disk so it has to be signed, but it would only be used by a limited group of users so I don't want to pay for a trusted certificate.
What is the easiest option to let the users trust my application/self signed certificate? I don't want them to use keytool because it is not really user friendly. I though about creating a certificate that can be imported via the Java Control Panel and first tried creating an importable certificate using the following commands:
keytool -genkeypair -keystore patrickgotthard.jks -alias patrickgotthard
keytool -exportcert -keystore patrickgotthard.jks -alias patrickgotthard -file patrickgotthard.cer
But it is not possible to import the generated .cer file. Then I found Cannot import certificate into java control panel and used the following command:
keytool -genkey -alias patrickgotthard -keystore patrickgotthard.p12 -storetype pkcs12
But as far as I understand, the .p12 file also contains my private key - I don't think that the private key should be shared?! Can you tell me how to create a self signed certificate that can be imported via Java Control Panel but does not contain my private key? Or do you know a better solution for my problem?
In this scenario, it may be sufficient to check the SHA1 fingerprint associated with the self-signed certificate used to sign the JAR:
Sign the JAR with your self-signed certificate.
Use keytool -v -list to determine your certificate's fingerprint.
Communicate the certificate's fingerprint in a mutually agreed way.
Instruct user's to add your secure site to the Exception Site List in the Security tab of the Java Control Panel; this allows the user to retain the minimum recommended security level setting, High.
At the security prompt, click on More Information to compare the communicated fingerprint with the one received.
This approach does not confer trust, but it reduces the risk of the user accepting an altered JAR.
Addendum: The article Self-signed certificates for a known community discusses how to export a self-signed certificate. Members of the community can then import the certificate as warranted.
I was developing Java Web Start app years ago with NetBeans. It did everything for me automatically.
You just have to put permissions tags in JNLP file.
Also 6 month after I had problems to create a new self-signed certificate.
But self signed app still works. (many years after, no modification, certs to install)
Clients do not have to install any certificates.
It just warns everytime when it starts that is signed with self signed cert.
Another option is to have this "limited group of users" lower the security level for Java. In Windows, you go to the Control Panel->Java and then one of the tabs is for Security (sorry on my mac right now and it is not quite the same). I believe that if you push that security level lower to Medium, you can get away with the self-signed certificate.
This question already has answers here:
Truststore and Keystore Definitions
(7 answers)
Closed 6 years ago.
I have a PKCS#12 file which I considered as a keystore file since it contains one key entry & one certificate entry.
In Android, I see people programmatically install keystore in the following way (The code is from Android developer blog):
byte[] keystore = . . (read from a PKCS#12 keystore)
Intent installIntent = KeyChain.createInstallIntent();
installIntent.putExtra(KeyChain.EXTRA_PKCS12, keystore);
startActivityForResult(installIntent, INSTALL_KEYSTORE_CODE);
I also see people programmatically install only the certificate wrapped inside keystore:
Intent intent = KeyChain.createInstallIntent();
intent.putExtra(KeyChain.EXTRA_CERTIFICATE, cert);
startActivity(intent);
Besides, I also see people install both the keystore & the certificate wrapped in keystore. For example, this article shows us how to first install keystore & then install the certificate wrapped in keystore programmatically.
I really get confused about when should I install keystore only & when should I install certificate (wrapped inside keystore) only ? And when should I install both ?? Could someone make me clear about this please?
For example, my keystore PKCS#12 file (mycert.p12) contains key/certificate pair, it is used to connect to VPN server. When should my android client install both keystore and certificate wrapped in the keystore ? When should client install only certificate wrapped in keystore? What are the differences ? I am quite confused about this.
I have a PKCS#12 file which I considered as a keystore file since it contains one key entry & one certificate entry.
Correct.
In Android, I see people programmatically install keystore in the following way ...
This is done when you have a keystore, i.e. a keypair and certificate.
I also see people programmatically install only the certificate wrapped inside keystore
This is done when you have someone else's certificate, typically a self-signed one, that isn't trusted by any of the default CA's (certificate authorities) that are already installed. You should never have to do this.
So note that you never do both with the same certificate, because the cases (the ownerships) are different. There can never be any doubt about which process is appropriate. If it's yours, import the keystore. If it's someone else's, import the certificate.
The ultimate normative reference for all this stuff is ITU Recommendation X.509.
Finally, some notes on the poor quality blog articles you have linked.
From Unifying key store access in ICS:
In the past, it was common practice for apps to maintain their own key
store if they needed to authenticate a secure SSL web server, or
authenticate the user to a server via a client certificate.
This is already incorrect.
To authenticate a web server you shouldn't need anything, if it has a CA-signed certificate. If it has a self-signed certificate you will need to import it into your truststore.
To authenticate yourself to a web server, you need a keystore containing your own private key and a certificate, preferably a CA-signed one. Otherwise the server has to import your self-signed certificate into its truststore, i.e. the converse of (1) above. Don't go down this path. Self-signed certificates are far more trouble than they are worth, which is nothing, as you can tell from the price you pay for them.
From Using ICS keychain API:
We first get the private key and certificate chain using the key alias
and then create and verify a signature to check if the key is actually
usable.
Complete nonsense. We already have the private key, the public key, and the certificate. They are already usable. Creating a signature and verifying it locally is just a complete waste of time.
Installing a CA certificate is not very different from installing a
PKCS#12 file: you load the certificate in a byte array and pass it as
an extra to the install intent.
The difference being that you use KeyChain.EXTRA_CERTIFICATE in the CA certificate case, and KeyChain.EXTRA_PKCS12 in the keystore case.
Since no one has answered you yet, I hope I can at least clarify some points from the blog article you have linked to.
In the past, it was common practice for apps to maintain their own key
store if they needed to authenticate a secure SSL web server, or
authenticate the user to a server via a client certificate.
These are the two basic use-cases right here:
If you are authenticating with a client certificate (which proves to the server that you are an authorized client), then you would only install a certificate.
If you are trying to verify the server's identity, then you will want to validate the server's certificate. In this case you will need a keystore installed (possibly a chain if you're not using self-signed certs). The private key in the keystore will be used to validate the server's certificate.
That second bit of code you have in your question was intended for creating a certificate chain (when you're NOT using self-signed certs):
We first get the private key and certificate chain using the key alias
and then create and verify a signature to check if the key is actually
usable. Since we are using a self-signed certificate the 'chain'
consists of a single entry, but for a certificate signed by a CA you
will need to find the actual end entity certificate in the returned
array.
Installing a CA certificate is not very different from installing a
PKCS#12 file: you load the certificate in a byte array and pass it as
an extra to the install intent.
Intent intent = KeyChain.createInstallIntent();
intent.putExtra(KeyChain.EXTRA_CERTIFICATE, cert);
startActivity(intent);
I hope this explanation helps! :)
With respect to an android or any other 'client', that is, an application, the following hold -
A truststore (public key only) is required whenever it needs to validate the certificate (or a certificate chain) that is sent across by the server during SSL communication (in case of ssl communication the server will always present its certificate to the client).
If the server's certificate is already signed by a trusted certificate authority (implying that certificate is already present in the java-runtime-truststore that can usually be found under $JAVA_HOME/jre/lib/security/cacerts), then this step is not required unless a customized SSLContext is being used (which also means that a customized TrustManager is being used).
For example SO's current certificate is signed by DigiCert identified by SHA1-Thumbprint : 5F:B7:EE:06:33:E2:59:DB:AD:0C:4C:9A:E6:D3:8F:1A:61:C7:DC:25 and would likely be present in the 'cacerts' truststore under the alias 'digicerthighassuranceevrootca'. If a java client were to make a request to https://stackoverflow.com then by default there would not be any specific keystore or truststore required for communication.
A keystore (private and public key) is generally required when the client is required to digitally-sign some data which is being posting to the server.
A common example is xml-signing, you can find a mention here
It is also required if the server expects the client to present its own certificate for authentication as part of two-way ssl handshake. From what I have come across this is not common.
Links :
Two Way SSL
SO's own Keystore and truststore post
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!
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 ..