I have created my own CA, and I want to use its certificates to communicate with a server using SSLSockets. I can do that with the truststore I am currently using, but I would like to be more restrictive, so that my server only accepts connections from the clients I explicitly decide, which must own certificates signed by my CA (right now, anyone with a certificate signed by my CA is granted access). The goal behind this is to be able to revoke certificates, by eliminating some certificates from the server's truststore.
Imagine there are two devices, A and B, both with signed certificates by my CA. I only want to grant access to A, not B. If I only have in the server's truststore A's certificate, I get a BadCertificate exception for both of the clients; the moment I add my CA's pem file both A and B are granted access, regardless of whether A's or B's certificates are explicitly added to the truststore.
Any ideas or alternatives to this approach? Thanks.
The revocation part of a PKI infrastructure (e.g. what you get if you have your own CA) is usually done with CRL (certificate revocation lists) or OCSP (online certificate status protocol).
If this is too much effort for a small PKI with only few clients you can also hard code the fingerprints of the certificates your accept (white list) or which got revoked (blacklist) into your application and check on each connect if the certificate you got matches the fingerprint. Of course you need to update the application on each revocation (blacklist) or whenever you issue a new certificate (white list) so this does not scale very well. But the same problems occurs with CRLs which need to be distributed to each client.
OCSP scales much better because the client try to retrieve the revocation status on connect, but then you need to setup an OCSP responder.
Related
I have a Java program that connects to an https remote webservice which exposes a TLS certificate of this structure:
Webservice certificate
Signed with some certificate
Signed with some corporate certificate
Now, when my Java app makes a https request to that webservice it fails due to invalid certificate. This is normal, so I added the webservice direct certificate to the Java/lib/security/cacerts file.
But this didn't work, I still had the certificate exception.
After a long debugging session and hours wasted, I tried to add all three individual certificates, and this time it worked. But why ?
Why does Java checks the full certificate path even though the direct certificate is made trusted ?
Is this behavior as per SSL/TLS RFCs ? Will this behavior occur with other tools/languages like curl ?
Thanks.
... so I added the webservice direct certificate to the Java/lib/security/cacerts file
The webservice certificate is not a CA certificate, so it does not belong in cacerts in the first place (as the name indicates). A CA certificate is a certificate which is used to sign other certificates, a webservice certificate is a leaf certificate which cannot be used to sign other certificates.
Will this behavior occur with other tools/languages like curl ?
This is a common behavior. With OpenSSL based tools one usually needs to provide the root CA (and of course the chain to it), only with X509_V_FLAG_PARTIAL_CHAIN it will accept when parts of the chain a specified as trusted.
I have a client/server application that sends data over SSLSockets, so I generated a cert and loaded it with a trust store and keystore. The client is going to be public, so in order to work I need the client to have the javaTrustStore.jts file with it. Is it ok to bundle it in the resources directory? Or should I have the client generate a new key every time and add it to the server's keystore?
There are two ways that you can approach this.
The first is to have a certificate just on the server, and no certificate on the client.
The is the usual way that websites work - when the SSL connection is negotiated, the server sends it's certificate to the client, and the client verifies that the server cert is signed by a Certificate Authority that the client trusts. Most (all?) web browsers are pre-loaded with a number of certificate authoritys' "master certificates",
So, a Java application operating in this mode would need the "master CA certificate", and any "intermediate" signing certificates in it's trust store.
You can also be your own CA, which was done often in years past, when you had to pay for a server cert. These days, if you want a free cert, you can just use Let's Encrypt, or one of several other providers of free certificates.
If you need to validate the client when negotiating the SSL connection, then you would also put a certificate on the client. But, you can't just have the client generate it's own certificate. You'll need to have your CA generate and sign the certificate, and then give that to the client, who would need to add it to their keystore.
Again, in this case, you can act as your own CA, and generate "self-signed" certificates.
If you'd like to see an example of this, I wrote a blog post for my employer's web site about nine or ten years ago about doing this with an Android app.
I am reading about the best way to create a secure connection between a client and a server.
Through this tutorial it seems that the certificate (and the keystore) is not only given to the server, but it is also given to the client.
Isn't this insecure? If the client has the certificate file (in the keystore), won't it have all the server private keys?
In the end what I want is to have a secure/encrypted connection between the client and the server, while the client itself proving to the server that it is an authentic client. Is this the right way to go?
Thanks!
As Boris stated in the first comment, the keystore contains the keys to authenticate and truststore contains the certificates that are trusted, as their names imply.
First of all, a certificate does not have to contain the private key. It is just an identity with a public key (with possibly signed by a trusted party, like CAs). That's why, if you use them appropriately, it is not insecure. What is the appropriate way of this? Here we go:
Before answering your question, i.e. the case that not only the server but also the client is authenticated, let's consider the usual case: only the server is authenticated by the client. In this scenario, we have three parties: Certificate Authority (CA), Server (S) and Client(C). To make it work, you should do the following:
Create a keypair for CA and store it in some ca.jks.
Export the certificate (containing only the public key, not private) from ca.jks and import it into another jks file, namely truststore.jks.
Create another keypair for S and store it in some server.jks.
Sign the certificate of S with the private key of CA. For this procedure, you need to generate a CSR (certificate signing request) from server.jks, sign the csr file with ca.jks and produce some crt (or pem, whatever you want) file containing the signed certificate. Finally you have to import this crt file back to server.jks. It is important to use the same alias as before.
Use server.jks at S as the keystore, and truststore.jks at C as truststore.
Keep ca.jks in a safe place. It is the root of trust.
In this way, C trusts CA since its certificate is in his truststore. Since S has a certificate signed by CA, C will trust S too. In other words, S is authenticated by C.
To achieve what you want, i.e. both parties are authenticated by each other, you will have two certificate authorities, namely CA1 and CA2. (They can be same of course, but I am writing like this for the sake of completeness.) You have to do the procedures above twice: once with CA=CA1 and once with CA=CA2. The first one is exactly like above. In the second one, you will create client.jks, sign it with CA2, and use public key of CA2 as the truststore of the S. (Just the roles of C and S are swapped.) In this way, both parties will authenticate each other.
As I said, you can use the same CA, which is very convenient and reasonable.
I know this is a long answer but be sure that I omitted most details and tried to make it simple. I hope it helps.
EDIT: Again, do not get confused: the client authenticates himself using his private key, stored in his keystore. Certificate is already a public thing...
Regarging your question, of course, if some thief steals the keystore file, then he can imitate himself to be the real client. The server cannot know who he is communicating with, he only validates the certificate. For such scenarios, issued certificates can be revoked. Search for revocation on the web. Simply, if you know that a client's keystore is stolen, you will inform the server about this through revocation, instead of regenerating all key material.
One corner case for this is, certificates are some kind of bindings of public keys with identities. For web servers, which is the usual case, their certificate binds their public key with their hostname, i.e. hostname is their identity. So if abc.com uses the certificate issued for xyz.com, your browser will give an error when you try to connect to abc.com. In Java world, this is called host name verification. The common name field of certificates are used for such identities. (When you generate using openssl or keystore, it may ask you a common name, and it is very important.)
If your clients are actually servers with static IPs or some valid domain names, you can use it. In this way, since the thief will try to connect from some other IP or domain, the server will detect it through hostname verification. However, usually clients do not have such stable identities, thus it is very hard to use this technique, so the thief may be able to imitate the real client.
My application is running in intranet in tomcat server. I am able to run my application with https but with warning(The security certificate presented by this website was not issued by a trusted certificate authority) also https symbol is crossed in red.
How we can have trusted SSL with self sign certificate in tomcat server without pain of importing certificate in browser?
How we can have trusted SSL with self sign certificate in tomcat server without pain of importing certificate in browser?
You can't. Self-signed is not trusted by default (where should the trust come from?) and thus you cannot expect the browser to trust it without telling the browser that it can trust it (by importing). Trust is a relationship and can not simply emerge from nowhere.
The warning States that the certificate is valid but browser don't trust the authority issuing the certificate. The only way is to Configure Browser to Ignore the untrusted CA issues, or Trust The organization in this case you .
Alternatively the recommended way is to get a certificate issues from one the of the CA Authority ( Verisign , Godaddy etc).
Any browser confirms below list items before marking a website/url secure:
Match the base DNS with that of the certificate CN (Note that the port number doesn't come into picture in this case). For example, if you are accessing https://example.com:8445/something, the certificate CN should be "example.com"
The self-signed certificate has to be imported into the respective trust store (Root Certification Authorities) of the system.
The certificate must have a SAN (Subject Alternative Name), that matches the DNS. With respect to previous example, the certificate must have at least one SAN equivalent to "example.com". This is a must, and most of the folks miss out on this point, and could not understand why the browser doesn't trust the certificate.
The Free way to establish trust in browser for internal applications
Now, all the above 3 criteria cannot be met unless the certificate is signed by a CA. However, there is an easy way. Go to https://freesslcert.org/ to receive a completely free 1 year certificate with all the above criteria incorporated. Follow the steps mentioned in https://freesslcert.org/trust-freesslcert-in-browser and you are all set.
Paid Solution for external websites
You can spend some dollars to get a certificate from one of the CA as mentioned here : https://freesslcert.org/get-cert
I hope this isn't a duplicate.
I'm currently working on client server game based on netty with a client on Android. I'm trying to make a secure login process so I tryed using ssl on top of java socket.
I managed to create a self-signed certificate and to use SSL. The problem is that the example source code i found use à custom TrustManagerFactory which doesn't make any check upon certificate validity. Since I don't wan't to allow Man In The Middle attack i searched for more information on SSL handshake and here is what i understood:
To initiate SSL session, the client send a request to the server.
The server which own the certificate(.jks or .bks) extract public informations into a X509 certificate and send it to the client.
The client check for the validity of the certificate ( In my current solution do nothing)
If check succed retrieve the server's public key from the certificate, generate a random key, encrypt it with the public key and sends it to the server.
The server use his private key to decrypt the randomly generated key.
Both client and server now share the same random key and they start a comunication using this key for symetric encryption ( like AES ).
I don't need to accept certificate from anyone else than my own server so i thought about 2 solution:
Save the X509 on client side and create à custom TrustManager witch only accept this certificate. This solution seems easy to implement but rather hard to maintain since every certificate change on server side would need to update X509 certificate on every client.
Create my own CA certificate sign my ssl certificate with this certificate and manage somehow to tel my client to only trust all certificate signed with my CA.
What i understood about CA authentification is this :
A CA root certificate is a normal certificate that contain a key pair.
signing a certificate with a CA mean adding at the end of the being-signed certificate a hash of the whole certificate encrypted with the CA private key.
this signature is contained in the X509 certificate along with some informations about CA.
To check certificate validity, the client generate certificate hash and compare it to the decrypted hash (using CA public key) contained in the X509 certificate.
So if i'm not mistaking in all of this, if i want to implement my second solution, I need to provide a CA certificate to the client so that he can check certificates. I've seen that it is possible to init à TrustManager with a truststore. I asume it must be a different certificate from the root CA one since the whole security of this depends on my CA private key 's confidentiality. So my questions are :
What should this client truststore contain and how to generate if from my root CA ??
I have red that ssl engine is broken for self signed certificate. So is my second solutions viable on android?
If this can work, how can i invalidate my certificate if i see that someone manage to get my private key somehow? I have red things about crl but i don't know how to generate/use them in my truststore?
thanks in advance.
I can only answer part of your questions:
The truststore should contain your CA, you can generate it with keytool:
http://docs.oracle.com/cd/E19509-01/820-3503/6nf1il6er/index.html
No problem you can implement this in android in the same way than in java using java.security.* and org.apache.http.* classes. One warning, for android versions <=2.3, you could need to implement a workaround as some public CA are missing and it doesn't support miss-ordered certificates chains. I can give you more details if needed.
I don't know
Edit:
A good turorial:
http://nelenkov.blogspot.com/2011/12/using-custom-certificate-trust-store-on.html