How to protect keystore from unauthorized access - java

I was working on TLS implementations and found out that you can use any keystore or truststore without providing any password in java client or server.
How does it prevent the server identity theft where someone can just copy the keystore from server and use that as their identity. If password would have been used then we might had some level of security on the keystore from unauthorized access.
One detailed description is provided in below link:
Do you not need a password to access a truststore (made with the java keytool)?

I got the answer for this.
Basically you can access the keystore or trustore without password but that is applicable only for accessing the certificates.
If you want to access the private key from keystore without password you cannot do that because the private keys are kept in encrypted format in the keystore and keystore password is the key for that.
That's how the private keys are kept secret in keystore files.

In general you have to keep your certificates secured. A file (and the password) can be copied easily. You can use cryptographic hardware to store certificates and perform signatures avoiding anybody could steal them.
For SSL certificates, note that they have been issued to a domain name or IP address. So anybody who steals your certificatecan not use it because he has not own your DNS. If he tries to use the certificate from other domain, the browser will reject the connection

I was working on TLS implementations and found out that you can use any keystore or truststore without providing any password in java client or server.
This is incorrect. A Java KeyStore can contain three types of entries: trusted; private key; and secret key entries.
The integrity of trusted entries is protected by the key store password. However, the key store can be loaded and the trusted entries used without checking the integrity of the key stores. Doing so creates a vulnerability.
The confidentiality of private key and secret key entries is protected by password-based encryption. Unlike trusted entries, these confidential entries cannot be accessed without the password. You can see this yourself by trying to recover a private key without a password, or with the wrong password.

Related

How the proper SSL certificate is selected from java keystore in order to be sent to corresponding endpoint in case of mutual TLS

I have an HTTPS endpoint that requires a client certificate(mutual TLS).
I have created a keystore using KeyStore Explorer tool and inserted the client certificate and private key into it(entry has an alias, that is some random string).
Then I have attached that keystore to RestTemplate and my question is the following:
How the right entry(certificate) is picked up from keystore when the call is made to a particular endpoint ? What if I have multiple certificates inserted into keystore so that each of them should be picked up only in case when request is made to an appropriate endpoint(domain).
If you are maintaining multiple public private key entries in one keystore file, then in each connector of respective public keys you need to pass the value in java as "keytoreAlias" . This way the application can distinguish which certificate to Cal based on alias mentioned.

Should certificates be always imported in keystores?

I'm doing some crytography in Java and I wanted to know what are the best and common pratices on certificate storage.
Can certificates be loaded from a file or should they always be imported in keystore/truststore ?
EDIT: My use case is to load a private key and a certificate in order to be able to crypt and decrypt data.
The question is: should the private key and the certificate be both in a keystore or can the certificate be aside in a file ?
I'd strongly recommend storing the certificates at least in the key store. If your key store and file have about the same access rights security is not that much different - although the password does add a level of protection (it's not called "changeit" by default for nothing).
Java and Java key stores are however pretty focused on X.509 based PKI, and you may not be even store the private key successfully without the certificate. So it is certainly best practice to store the certificate or rather, the certificate chain in the key store.

When to install keystore & when to install only certificate wrapped in keystore [duplicate]

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

User Certificate is Null in HTTPServletRequest

I am running a servlet in Weblogic 10.3 with two-way SSL enabled. When I try to get the following attributes from the HTTPServletRequest, both are null:
- javax.servlet.request.X509Certificate
- weblogic.servlet.request.SSLSession
How then do I access the user's certificate from the servlet? I have searched online with no luck.
I would take a look at how your keystore is set up. From my experience, this kind of error can occur if the user's or server's signed certificate isn't imported into the keystore correctly.
To verify this, run keytool on your keystore to determine which alias in the keystore contains a private key. Then, take a look at that alias and see if it has the signed (approved) certificate associated with it, or if the signed certificate has another alias associated with it.
This kind of error is common when using applications which will only look for a specific alias in your keystore for validation. Normally this is configurable so that you can ensure that your certificates all have unique "names" in the certificate. It is common, for example, to use a linux box' hostname in the certificate name, and then to create an alias that is the hostname.

Do you not need a password to access a truststore (made with the java keytool)?

I just created a truststore with the java keytool (for server authentication of a server that does not have a CA cert). However I just noticed something strange. I am starting my client like this:
java -Djavax.net.ssl.trustStore=<PATHSTUFF>/client.keystore -classpath <STUFF> Client
(Note: there is NOT a password specified)
The above call works.
However when I try this:
java -classpath <STUFF> Client
It does not work. (Obviously it does not work it requires the truststore).
I was expecting to need to pass in this option (but I did not):
-Djavax.net.ssl.trustStorePassword=mypass
Question: Do you not need a password to access a truststore? Is the password just for modification? What about a keystore?
The password is used to protect the integrity of a keystore. if you don't provide any store password, you can still read the contents of the keystore. The command keytool -list demonstrates this behavior (use it with an empty password).
In addition to pascal-thivent's excellent answer:
The keystore password has two purposes - if not supplied, keytool refuses to let you replace the contents of the store with new contents e.g. by deleting existing or adding new certificate entries.
Of course if you have write-access to update the keystore file using keytool (it's not setuid), you could replace the contents using another tool which didn't check the password. And we know that the store and its format is readable without a password, so presumably we can write what we want there.
That's where the verification password comes-in. When the store entries are written-out, the supplied store password is used to compute a digest of the store-contents, as salted by the password. This is a one-way hash/digest, so without the password, you cannot verify whether the store contents have been tampered with or not. Equally, someone malicious who does not know the password also cannot modify the store's contents and produce the digest-hash that would be produced by that password.
That's why when you supply no-password, keytool just warns you that it can't verify that the store has not been tampered with. If you provide an invalid password, or the store has been tampered with, you will get a different message:
Enter keystore password:
keytool error: java.io.IOException: Keystore was tampered with, or password was incorrect
keytool was unable to re-create the existing hash digest based on the current store contents and the password you supplied, so either the password is incorrect, or the keystore is compromised - keytool cannot tell, but it assumes that you or the software reading the store knows.
Note that whilst the term keystore is used generally, it refers equally to keystores and truststores. Less-generally, a keystore is more often an identity store and contains identities and their secret, private keys, as used e.g. by a server running HTTPS. A truststore more often contains only public keys and no private keys, so no secrets, but is important to determine what identities a client trusts.
By default, the JRE trust store password is "changeit". If you want to change the default trust store (cacerts) password programmatically using Java, then please go through this link.
If you do not specify a truststore, the default one is used instead. I assume, you get an error, that you'll need to specify a truststore in order to trust the host you request? The default truststore resides in $JAVA_HOME/lib/security/jssecacerts.

Categories

Resources