What excepttions I will/may recive if certificates stored in java trust store expires?
Will I certantly recive exception accessing certified resource? Under what circumstances there will be no exceptions?
If a certificate in the trust store expires, and is not replaces with an updated version with the same subject and key, it will be discarded for the purpose of building the certification path, so you'll get an javax.net.ssl.SSLHandshakeException (coming from "PKIX path building failed...").
If you look at the JSSE Reference Guide (trust manager section), it relies on the CertPath API (which implements what's needed to verify the date/time).
The default PKIX trust manager implements RFC 3280, which requires all certificates in the chain to be valid at the current date/time. See section 6.1:
The algorithm presented in this section validates the certificate with respect to the current date and time.
and
(d) for all x in {1, ..., n}, the certificate was valid at the time in question.
If you want to bypass this, you can implement your own trust manager (although it's generally not recommended, since you'd weaken the default algorithm).
I would expect an expired certificate to not be used by the system. So to your code, it should behave as though not found at all.
Related
I'm implementing a mutual authentication with a web server in Java on Windows.
I have a certificate on a SmartCard which is supposed to be used to authenticate me (or other user).
So far I've figured out that I can access the certificates using Windows-MY key store.
I do it like that:
KeyStore keyStore = KeyStore.getInstance("Windows-MY");
keyStore.init(null, null);
This works. I can see all certificates inside keystoreSpi (in debugger). One of them is the one which I need to use - I confirmed that.
The problem is as follows:
KeyStore api allows me to get a certificate only by using it's alias. e.g. keyStore.getCertificate("alias") or keystore.getCertificateChain("alias")
I noticed that there are multiple different certificates with the same alias in this keystore. I cannot change the aliases. I just physicaly got the smartcard with given certificates.
When I call one of the mentioned methods, keystore returns just the first certificate in the list with given alias. (generally, in the implementation there is a map where aliases are it's keys, so all duplicated aliases are ignored).
Unfortunately first certificate's purpose is "email encryption", etc. The second certificate's purpose is "SmartCard Logon" and this one I need to use. I confirmed that by going into debugger and manually hacking the list of certificates.
The question is: how do I get a proper certificate using the API (eg. the second one) when there are duplicated aliases?
If this can be done by external libraries, I can opt for that.
More details which may be useful:
I use KeyStore, then create KeyStoreManager.
I initialize SSLContext with given keyStoreManager sslContext.init(keyManagerFactory.getKeyManagers(), ...)
I create HttpsUrlConnection with given ssl context, which is my objective.
This has been fixed a while ago. Just update to a recent JRE. For more information see here: https://bugs.java.com/bugdatabase/view_bug.do?bug_id=6483657
I'm trying to access https://blockchain.info/lastblock from java,
but the code throws:
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
This is usually due to self signed certificate, but this one is not self signed(you can check it in your browser). Looks like java doesn't user system CA certificates.
Isn't it a bug?
I exported the certificate and insert it dynamically into java KeyStore, but I don't like this solution(Not sure it will check revocation lists for this certificate etc).
So what's the best solution to fix the problem?
I used this code to test http://www.cs.ucsb.edu/~pconrad/cs56/examples/ldap/SimpleQuery/InstallCert.java
The list of roots of trust changes from time to time, and Java's built-in one is often a little different to that of browsers. Those trust roots are what is stored in the system keystore (well, technically in the system truststore) and you can add to them by placing the extra roots that you want to support in a per-user keystore, stored in your home directory. It's in the default location manipulated with keytool.
The certificate that you'd actually consider putting there — if it isn't already — would be the “COMODO Certification Authority” one; browsers like it (i.e., you can verify it independently of Java) but your Java doesn't. It has revokation information signed directly into it, so it should be all you need; SSL/PKI is supposed to be able to be bootstrapped from just the root CA certificates.
When the checkServerTrusted method of classes implementing X509TrustManager is invoked, I need to get ALL validation errors that are associated with a certificate chain including
Certificate path validation problems. e.g CA not trusted
Certificate fields validation problems. e.g Expired certificate, Invalid extended key usage
The motivation behind this is so that I can present the user with the certificate validation issues before he adds it as an "exception" as Firefox does now. However, right now, as soon as a path validation issue is found, a CertPathValidatorException is thrown, but it gives me no information about the validity of the fields in the certificate. How can I implement this?
After some reading, I found the CertPath API provides such features, and found that the PKIX implementation is a wrapper around this, but just does not return the CertPathValidatorResult. I would like to make maximum use of existing JAVA functionality(without writing my own custom wrapper to the API) while returning all validation issues.
You won't even get to X509TrustManager.checkServerTrusted() if there was a certificate error. You would need to hook the certificate handling at an earlier point, and I don't believe there is one in JSSE.
I am using jdk1.7.
i am using self signed certificates for SSL handshake.
is it mandatory to have keyusage in certificate if i am using jdk1.7.
Please let me know i am confused.
Thanks,
Rahul
Here is what RFC 5280 says:
Conforming CAs MUST include this extension in certificates that
contain public keys that are used to validate digital signatures on
other public key certificates or CRLs. When present, conforming CAs
SHOULD mark this extension as critical.
However, RFC 6818, which is an update to RFC 5280, says:
Consistent with Section 3.4.61 of X.509 (11/2008) [X.509], we note
that use of self-issued certificates and self-signed certificates
issued by entities other than CAs are outside the scope of this
specification. Thus, for example, a web server or client might
generate a self-signed certificate to identify itself. These
certificates and how a relying party uses them to authenticate
asserted identities are both outside the scope of RFC 5280.
So, if you're acting in the capacity of a CA, you should include keyusage. It's probably a good idea to include it anyway, although it isn't strictly required based on the paragraph above.
I'm building an application that needs to open self-signed HTTPS SSL URLs in java. I've learned that you can bypass the SSL problems by adding a call to HttpsURLConnection.setDefaultHostnameVerifier() where you say what hostnames are allowed.
However, I have a second problem where my servers are running self-signed certs. So even with the hostname bypass I'm getting exceptions like:
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
I've looked around and the only solutions I've found is to add the certificate to the java key store, but this is a problem for me because I have no control over when or how they update java, and I've read that the keystore isn't preserved between updates, and I have no access to the system outside of the JVM.
My application will only make calls to a single server so if there was a way to bypass the self-signed restrictions, and never consult keystores, it wouldn't be a security problem, but is there a way to do this?
I'm building an application that needs to open self-signed HTTPS SSL
URLs in java. I've learned that you can bypass the SSL problems by
adding a call to HttpsURLConnection.setDefaultHostnameVerifier() where
you say what hostnames are allowed.
There are some misconceptions from your question:
Hostname verification is unrelated to whether the certificate is self-signed or not.
It is a verification that matches the domain you are trying to access with the certificate info (CN or Subject Alt Name).
You would need to configure the verifier if you needed to accept a certificate that did not match the url (not recommended at all!!!)
Concerning the self-signed.
This is irrelevant.
You can configure your application to load your custom truststore which would include the certificate your application will trust. In fact this is the best approach (than using Java's cacerts).
All you have to do is import the certificate in a keystore (JKS or PKCS12) and load it in your custom TrustManagers in your application.
Just google arround, plenty of examples E.g. self-signed-ssl
As much as I hate to say this, sometimes it's better to just go with the flow.
Java is attempting to make applications more secure through the use of proper SSL verification practices. In this case, it is succeeding: had you been able to tell the program "it's okay, accept the untrusted self-signed certificate", your program would have been vulnerable to a man-in-the-middle attack where Mallory puts his server (with its own self-signed certificate, just as valid as yours!) in between the host and the target it's attempting to communicate with. Then he proceeds to read all the traffic you thought was nice and safe, and you don't even notice.
So, your assertion that telling Java to "trust any self-signed certificate when connecting to this host" is secure is, regrettably, not correct.
You can get free, totally valid SSL certificates from StartSSL. They're good folks.
That's how PKI is supposed to work - you must have complete chain of trust from some trusted certificate stored in you keystore to your certificate. So you can
set you certificate as trusted
ask somebody already trusted (i.e. with trusted certificate in the keystore) to sign you certificate
Trying to bypass that is not good bad idea. You can install you certificate in some Java post-install hook, you may have some cron job checking it periodically or do it in exception handling. You can even download this way a certificate from the server and install it everytime it changes (extracting the cert with openssl is easy). But for god's sake, if you decide to do such thing, at least write some audit log about it to some third machine a make sure somebody reads it.
You can also write "hacker-friendly" on you doors. :)
(Note that when you're talking about "keystore" in your question, you're in fact talking about the trust store (which is a keystore). More details on this unfortunately confusing Java terminology are in this answer.)
My application will only make calls to a single server so if there was
a way to bypass the self-signed restrictions, and never consult
keystores, it wouldn't be a security problem, but is there a way to do
this?
Actually, it would be a security problem. Your application may indeed be intended to call only a single server, but the trust store is precisely there to help make sure you're connecting to the machine you intended to connect to. Without it, you wouldn't be able to know whether you're connecting to that server or a MITM server.
If you want the security provided by SSL/TLS, don't bypass these rules. (In particular, don't use a trust manager that will accept any certificate.)
I've looked around and the only solutions I've found is to add the
certificate to the java key store, but this is a problem for me
because I have no control over when or how they update java, and I've
read that the keystore isn't preserved between updates, and I have no
access to the system outside of the JVM.
Quoting myself from this answer (to a more specific question):
The right way is to import this self-signed certificate into the client's trust store, using keytool for example:
keytool -import -file server-cert.pem -alias myserver -keystore mytruststore.jks
You can either do it directly in the JRE's trust store (lib/security/cacerts), which may lack some flexibility, or do it in your own copy of this file, which you then set as the trust store (the default password is changeit or changeme on OSX). You configure this truststore globally for your application using the usual javax.net.ssl.trustStore* system properties (e.g. -Djavax.net.ssl.trustStore=mytruststore system property (and -Djavax.net.ssl.trustStorePassword`). [...]
You don't actually have to use the trust store provided by the JRE (and which may be updated regularly). You could import your self-signed cert into a new empty keystore, which you'll use as a trust store within your application (don't import the private key with it). How to discuss trust store management was in fact discussed in this question: nothing prevents you from using a different trust store specifically for your application or part of it (and in fact Sun/Oracle make no guarantee as to the suitability of the default trust store).
I'm building an application that needs to open self-signed HTTPS SSL
URLs in java. I've learned that you can bypass the SSL problems by
adding a call to HttpsURLConnection.setDefaultHostnameVerifier() where
you say what hostnames are allowed.
While it may indeed by slightly less of a problem if you only have a single self-certificate in your trust store, host name verification is also an essential component of the security provided by SSL/TLS. Don't bypass it, verify that the certificate you're connecting to matches the name you're trying to connect to. (To make an analogy, if you want to check someone's identity, you not only want to check the their passport was emitted by a country whose passports you trust, but you'll also want to check they have the right name inside, otherwise you could be in front of anyone from that country.)
Making the CN= RDN of the Subject Distinguished Name of your self-signed certificate be the host name of the server should be enough, although it's the legacy way of doing it. You may also want to add the Subject Alternative Name extension. More on this in this answer.
Generally speaking do not bypass the SSL "problems". These mechanisms are precisely in place to make the usage of SSL/TLS secure.