SSL: Client Authentication, multiple certificate version in same store - java

Here is the situation:
Our Application talks to multiple 3rd party applications and few of them need client authentication.
One particular third party app needs client auth and has appropriately provided certificates (which we imported in our key store (JKS)). This is during integration testing. Things are working fine in the Test environment.
Now before going live, they want to upgrade the certificate issued by an CA.
For the new certificate, we can always create a new store, but for the sake
of convenience wanted to know if the two certificates(old and new) can reside in the same store? (So that in case they rollback, there is no change on our side)
URL being same, how does the application(http-client library) knows which client certificate(s) version to present when making calls to server?

You can have both certificates in the truststore. JSSE will select whichever one matches the trusted CAs the server advises when it requests the client certificate.
However the scenario you describe is radically insecure. If you are the client, you should be providing your own client certificate, not one that comes from someone else. Otherwise there must be a compromise of the private key, which means the certificate can't be used for the purpose it is intended for, and you can legally repudiate all transactions that are supposedly authenticated via this means. Client authentication under such a scheme serves no useful purpose whatsoever and you should not waste further time on it.

Related

Handling security when deploying Java application

I have a Java app (deployed as a JAR file) that allows file sharing through SLLSockets. If all users use the same certificate, file transfers are not secure, since it violates the core concept of asymmetric encrypted communication. Therefore, I understand that each user needs to have its own certificate. This brings up my first question:
How can you generate a certificate programmatically, and where would you store it ? I don't want users to have to generate their own certificate with keytool, then have to tell the app where it is located.
Now, let's say my first question is answered and each user has its own certificate. Prior to opening the SSL connection between two hosts, you need to add each other's certificate to the trustStore. The only way I know to achieve this is by exchanging them through Sockets (note that I am using JGroups to exchange Socket connection info). This brings up my next two questions:
How do you guarantee authentication and integrity when exchanging the certificates ?
How do you programmatically add the received certificate to the trustStore ?
Finally, this whole post brings up my fourth question:
Are the steps described above the correct way to send data securely between two hosts, using SSLSocket asymmetric encrypted communication ?
You don't need client certificates necessarily.
Could you not use username/password authentication?
You can still secure the transfer just by using a server certificate.
Client certs are also kind of a pain, and not entirely secure. They tie you to a machine, and evil processes can read them. Smart cards mitigate this, but aren't free.

Passing user authentication details from one server to the next

I've got users authenticating with client certificates in a JBoss server. All fine.
If I then use Apache HTTPClient to call onto another server it sends the client certificate of the user JBoss is configured with. I'd like to be able to pass the client certificate through so the second server authenticates the calling user too.
Is this possible (I'm assuming not as the server won't have the private key of the client certificate) and if so, how?
I'm pretty convinced from RFC5246 [1] that it's not possible.
If the client has sent
a certificate with signing ability, a digitally-signed
CertificateVerify message is sent to explicitly verify possession of
the private key in the certificate.
After all, what's the point of a private key if you make it public? I'll just get the server I'm connecting to to give my system user increased privileges.
1 https://www.rfc-editor.org/rfc/rfc5246
Not possible. The certificate is merely a public identifier of who the user is. The actual authentication is done using the client's private key. As a result, you would need to obtain both the certificate AND private key to accomplish this, which would eliminate all of the security around the use of certificates in the first place. Certificates are considered public, and can be distributed wherever needed to allow for identity verification, digital signature validation, encryption, etc. The private key must, by definition, remain private in order to ensure the security of the credential.
To accomplish your goal of propagating identity information, there are other tools you can use. If your JBoss server(s) are all part of the same security domain, you can use JavaEE Security to propagate the identity information. With some creative coding, you may also be able to use Kerberos to propagate the identity, although that is a non-trivial amount of effort.

How to ensure that a android app is accessing the Real server

I've implemented HTTPS connection with servlet running REST api.
Device is able to connect to server using HTTPS.
Device is accepting server's certificate and establishing HTTPS.
How to make sure that the device accepts only a particular certificate? The intention is that someone should not be able to setup a fake server identifying itself as right server using self-signed certificate.
In a browser environment, user would see Chrome's crossed out https in the url and know that the certificate is not verified. How to ensure that for an app.
The procedure is called certificate validation and is pretty standard. Some classes and components perform validation for you, others leave it for your manual implementation and control.
Validation ensures (in ideal world) that you are connecting to the legitimate server, i.e. the server whose host name and the name in the presented certificate match. This requires that the server has acquired a valid CA-signed (we omit self-signed variants for lack of security and flexibility) certificate for the needed host name. So far so good.
Now you can either rely on pre-implemented certificate validation or implement your own or add your own checks to the pre-implemented validation procedure. Implementing your own validation is too cumbersome for your task, so let's assume that the client code you use already performs some validation (you have not specified what exactly code you use for connection so I can't comment on it). You can rely on it, however in some countries state agencies perlustrate traffic, and for doing this they acquire (or generate on-the-fly in some cases) certificates which are fake by nature but valid if we follow the validation procedure blindly.
So if you control both the server and the client and also you can implement additional validation (your client component or class lets you do this) then your additional check can be to compare the issuer of the certificate (or the whole certificate chain) to the issuer you know to be valid. This is less flexible and to some extent against the PKI rules, but this approach significantly reduces the chance for the fake certificate to be generated and accepted as valid. The idea is that you know what certificate you use and what CA you used (and maybe use in future), so you can store this information in the client and compare it during validation.
You can read more about certificate validation by simply searching here on SO for "certificate validation" - this is quite popular topic.

Can a signed certificate be used without importing explicitly?

I've read a lot of articles regarding the import of a cert, but I am still unclear on a couple things.
When connecting to an SSL site from a Java application [in this case, a JBOSS web app], does the client cert need to be explicitly installed on the application server prior?
I can install a client cert manually, but there is an expiration date. So I'll need to manage the expiration dates of all client installed certs on our application server, and take an outage to update each one.
It feels like there should be a better way.
Shouldn't the application automatically accept a valid signed cert? [In this case, it is signed by VeriSign]
We are getting an exception currently when trying to access an https url from the application without explicitly installing the cert.
The API proxy library is swallowing the internal exception, so I dont know the details.
If the cert should be accepted automatically, then there may be a different issue here...
Can a signed certificate be used without importing explicitly?
Yes, it does not need to be installed prior to use. In fact, if you know in advance of what to expect, then you can include that information into the application. That has an added benefit of improving the application's security posture.
To avoid importing the certificate, use a custom X509TrustManager and override checkServerTrusted. In checkServerTrusted, ensure the server's public key is expected (i.e., pin the server's certificate or public key); or verify the server's certificate is valid (i.e., is within validity and forms a chain to your trusted root).
When connecting to an SSL site from a Java application [in this case, a JBOSS web app], does the client cert need to be explicitly installed on the application server prior?
In the case of client certificates, the server advertises the issuer whom it relies upon to issue client certificates. So the server will need to know the trust point for issuing client certifcates for authenticating clients.
In this case, it is signed by VeriSign
This could be really bad. In this case, you will trust all of your clients signed under the Verisign PKI, and all of Verisign's other clients signed under the Verisign PKI.
In this case, it would probably be better to avoid public CAs and run your own PKI (i.e., be your own CA). In this case, pick up a copy of Network Security with OpenSSL. The book will show you how to accomplish the customary tasks using both the openssl command and programmatically.

Any way of creating an Client Certificate programmatically for SSL Client-Auth without BouncyCastle?

I'm writing a server application that identifies it's clients by SSL-Client-Auth. Every Client should create it's own KeyPair and Certificate to connect to this server. Any unknown client (identified by a new public key) will be thread as a new client and registered with this public key. I don't want to sign client certs serverside (since this is would not increase security).
But it seems (after studing hundreds of pages) that I can't create the necessary files (or objects) programatically in plain Java, since the KeyStore would need at least self-signed client-certificates (which I can't create without BouncyCastle lib).
Am i wrong or is there really no way to do this?
And please provide me with a link or code. Java SSL semms to be VERY overcomplicated and has a bad documentation.
As far as I know, there is nothing in the JSSE API (including JSSE and JCE) to issue an X.509 certificate indeed. Dealing with the X.509 structures manually is actually quite complex, and you'd certainly need to read a lot more if you want to replicate what BouncyCastle does, without using BouncyCastle.
BouncyCastle is by far the most convenient way to achieve what you want. You could also use the sun.* packages (since keytool uses them to produce self-signed certificates), but using these packages is usually bad practice, since they're not part of the public JSSE API. They are not documented, rely on a specific implementation of the JSSE, and are subject to change. In contrast, BouncyCastle is meant to be used as a library.
I don't want to sign client certs serverside (since this is would not
increase security).
Since your server will only use the public key (and not the certificate) to perform the authentication (based on whatever mapping between public key and user you choose to implement), issuing the certificate on the server side or the client side doesn't matter in terms of security. The client could self-sign anything it wants, to the server can only rely on the public key anyway, not the rest of the certificate. The reason you'd need to "bundle" the public key into an X.509 certificate is because it's the only kind of client certificate supported (for example, the JSSE doesn't support OpenPGP certificates).
Having a service on your server that receives a public key and sends an X.509 certificate (with any dummy attributes, signed by any private key) might be the easiest option. In addition, if you use a mini CA internal to that server, this would simplify the way you'd need to tweak the trust managers to get the self-signed certificates through. (You'd still need to check the actual public key with your internal mapping, if you want to design such a security scheme.)

Categories