I got list of URLs, and I want to validate their Extended Validation (EV) attribute using JAVA
I can make request and get their certificate, but I am not sure how to validate “Extended Validation” for a given site.
Is there any special value in certificate? Or any attribute?
Extended validation is mostly useful from a user-interface perspective. It's not so useful if your client doesn't have anything in its user interface to display the certificate. These verifications are not integrated by default in the JSSE, possibly because there is little demand for it (lack of Java browsers). (By the way, you should verify the certificate you get upon connection, not check with a first connection and connect with another, just in case).
The specifications are defined by the CA/browser forum.
The OID values and root CA certificate fingerprints are hard-coded into browsers (see security/certverifier/ExtendedValidation.cpp in Firefox, used to be in in security/manager/ssl/src/nsIdentityChecking.cpp). There is also a list on Wikipedia for reference, although in principle you should check the policy OIDs with each CA.
To analyse the extensions, it might be useful to use BouncyCastle if X509Certificate.getExtensionValue() isn't enough.
One problem you will have to watch out for is that the hard-coded SHA-1 fingerprints of the root CA certificates need to match exactly those certificates in the trust store. Some CAs renew their CA certificates once in a while in the bundles that are shipped with most browsers/OS/JREs: make sure you're using the same.
Related
Could you please help me on following two questions?
I have a FIX engine that connects to FIX servers. There is a FIX server that requires client to authenticate itself during SSL handshake. It also provides a SSL certificate that I need to use during SSL handshake as client side certificate.
Question#1: Can I store multiple certificates (private keys) in a keystore that I will load later in my FIX engine?
Question#2: If answer to #1 is yes, then how would the SSL context select a client certificate during SSL handshake when it establishes a SSL connection with the server?
Note- I am thinking of these questions because in future there may be another Servers that also have similar requirement.
Question#1: Can I store multiple certificates (private keys) in a keystore that I will load later in my FIX engine?
As far as Java is concerned, you definitely can have multiple privateKey entries, each containing a privatekey plus certificate or (usually) chain, in one keystore file or other storage object. (Note that if you use PKCS12 to interchange with other software that other software may not support multiple entries in one PKCS12. If you use PKCS12 only for better security in Java, or to silence the warnings in j9+, this is not a concern.)
I don't know what FIX engine you are using, or how it handles its key-and-cert info for TLS-formerly-SSL (or indeed how it handles TLS at all). If it simply loads a keystore file (or stream) as a KeyStore object, the the Java capability above applies. If it does something else, what it can do depends on that something else.
Question#2: If answer to #1 is yes, then how would the SSL context select a client certificate during SSL handshake when it establishes a SSL connection with the server?
In the TLS protocol, when a server requests that the client use a certificate, it specifies algorithm constraints (the leaf key algorithms through 1.2 and/or the chain signature algorithms in 1.2 and 1.3) and may specify a list of desired Certificate Authorities (CAs) (which may have issued any cert in the chain).
If your client (FIX engine) uses the Java-standard implementation of TLS (JSSE) with its standard (and default) 'SunX509' KeyManager, that will choose from the keystore an entry satisfying the above constraints from the server; if you select or configure the 'NewSunX509' or 'PKIX' KeyManager, it also checks any algorithm constraints defined for your JVM (for example Oracle JVMs since about 2017 prohibit certs using MD5- or SHA1-based signatures, or RSA keys less than 1024 bits), and gives preference to entries where the cert is not expired and does not have inappropriate KeyUsage or ExtendedKeyUsage extensions. Among multiple acceptable or preferred entries the selection is arbitrary -- however the keystore implementation enumerated them. Most servers support all standard (maybe and non-obsolete) algorithms and usually cannot be distinguished by that. If a server accepts certs from 'public' CAs like Digicert, GoDaddy, LetsEncrypt those also are not likely distinct, but if it uses a CA (or perhaps a few) specific to that server or its operator, such CA name(s) will often be unique and thus the key-and-cert will be selected only for that server.
If your client uses a custom KeyManager -- either explicitly in your application or via middleware (for example Apache HttpClient) -- it can do something different. It can even choose to use a key-and-cert the server will reject, although that would normally not be considered useful.
If your client uses a different TLS implementation, that could use the standard KeyManager structure, probably with the options above, or could do anything else.
if you use spring framework you can specify alias of certificate that you prefer to select by adding
-Dserver.ssl.key-alias=your_preffered_alias
You said that you have a FIX engine that connects to FIX server, then asked if private keys can be stored in a keystore for your FIX engine. This leads me to believe that the FIX engine is in a client application. You should NOT store private keys publicly in a keystore. Instead, you should be providing the client with a truststore, which just contains the certificate.
I don't have an answer for this, but this post might be helpful; https://stackoverflow.com/a/1710543/4417924
I have developed a webservice in Java. This webservice will be called by other servers, which will have been assigned a certificate from us.
Now I don't know much about SSL, and I have been given a
Root CA
Issuing CA
And I need to check that the certificate provided (when the webservice is called), is "a chain from the root ca". What would be the best way to go about this?
I've read a lot about trustmanagers and keystores, but it's quite confusing and I haven't found anything which is very similar to my question.
I also need to extract a line from the certificate (the 'issued to' field) to use in my application.
Thanks in advance
I have been given a
Root CA
Issuing CA
I need to check that the certificate provided (when the webservice is called), is "a chain from the root ca"
Just put those files, and no others, into your truststore. No code required. See the JSSE Reference Guide.
I also need to extract a line from the certificate (the 'issued to' field) to use in my application
You mean dynamically? when the peer connects? You can get the certificate from the javax.servlet.request.X509Certificate request attribute, and you then just use the certificate API to get the IssuerDN.
These may be phrased as separate questions for clarity, but they are all related to the same issue.
How are SSL certificate server names resolved?
Why do browsers seem to use the CN field of the certificate, but Java's mechanism seem to only look at "subject alternative names" only?
Is it possible to add alternative names to a SSL certificate using keytool?
If not, is using openSSL instead a good option??
Just a little background: I need to get a main server to communicate with several servers using HTTPS. Obviously, we don't want to buy SSL certificates for every server (there could be many), so I want to use self-signed certificates (I have been using keytool to generate them). After I add the certificates as trusted in the OS, the browsers (IE and Chrome) happily accept the connection as trusted. However, even after adding the certificates to Java's cacerts, Java still won't accept the connection as trusted and throws the following Exception:
Caused by: java.security.cert.CertificateException: No subject alternative names
present
at sun.security.util.HostnameChecker.matchIP(HostnameChecker.java:142)
at sun.security.util.HostnameChecker.match(HostnameChecker.java:75)
at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkIdentity(X509T
rustManagerImpl.java:264)
at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(
X509TrustManagerImpl.java:250)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(Clien
tHandshaker.java:1185)
... 14 more
I found that I can make Java trust the certificate implementing my own HostNameVerifier, which I copied from here: com.sun.jbi.internal.security.https.DefaultHostnameVerifier just to test (by the way, the hostname passed as an argument to the HostnameVerifier is correct, so I think it should have been accepted).
I have been using the certificate field CN as the hostname (usually the IP address).
Can anybody please tell me if I am doing something wrong and point me in the right direction?
How host name verification should be done is defined in RFC 6125, which is quite recent and generalises the practice to all protocols, and replaces RFC 2818, which was specific to HTTPS. (I'm not even sure Java 7 uses RFC 6125, which might be too recent for this.)
From RFC 2818 (Section 3.1):
If a subjectAltName extension of type dNSName is present, that MUST
be used as the identity. Otherwise, the (most specific) Common Name
field in the Subject field of the certificate MUST be used. Although
the use of the Common Name is existing practice, it is deprecated and
Certification Authorities are encouraged to use the dNSName instead.
[...]
In some cases, the URI is specified as an IP address rather than a
hostname. In this case, the iPAddress subjectAltName must be present
in the certificate and must exactly match the IP in the URI.
Essentially, the specific problem you have comes from the fact that you're using IP addresses in your CN and not a host name. Some browsers might work because not all tools follow this specification strictly, in particular because "most specific" in RFC 2818 isn't clearly defined (see discussions in RFC 6215).
If you're using keytool, as of Java 7, keytool has an option to include a Subject Alternative Name (see the table in the documentation for -ext): you could use -ext san=dns:www.example.com or -ext san=ip:10.0.0.1.
EDIT:
You can request a SAN in OpenSSL by changing openssl.cnf (it will pick the copy in the current directory if you don't want to edit the global configuration, as far as I remember, or you can choose an explicit location using the OPENSSL_CONF environment variable).
Set the following options (find the appropriate sections within brackets first):
[req]
req_extensions = v3_req
[ v3_req ]
subjectAltName=IP:10.0.0.1
# or subjectAltName=DNS:www.example.com
There's also a nice trick to use an environment variable for this (rather in than fixing it in a configuration file) here: http://www.crsr.net/Notes/SSL.html
Lead in ...
I'm not an expert, by far, in application security via SSL, but am trying to establish a test environment that includes all possible scenarios we may encounter in production. For this I have a tree of Certificate Authorities (CAs) that are the issuers of an assortment of test client certificates, and node/server certificates (complex test environment representing the various published web services and other applications we integrate with).
The structure of these CAs are as follows:
Root CA, which has signed/issued Sub CA1, Sub CA2, and Sub CA3. These subs have then signed/issued all certificates of those various nodes and clients in the environment.
Now for the question ....
In my application's truststore I would like to trust everything signed by Sub CA1, and Sub CA2, but not Sub CA3 (untrusted). Does this mean my truststore should (1) ONLY include Sub CA1 and Sub CA2, or (2) should it include Root CA, Sub CA1, and Sub CA2?
I don't know what is the proper way to represent this trust chain in a truststore. In the future I would also like to add a Sub CA4 (also signed/issued by the Root CA), but add that to a Certificate Revocation List (CRL) for testing purposes.
Ahead of time, thank you for any help concerning this. It's greatly appreciated.
CAVEAT: I'm not going to test this so I hope my answer is correct.
I think your basic assumption is correct. I don't believe you can selectively revoke trust without writing custom code, so your truststore should only contain certificates who are trusted completely. So leave the root CA out and choose your option (1).
As you can see, trying to enforce such fine grained access control is ill-suited to the Java (and most every other system's) X509 certificate -based authentication model. They are basically designed to outsource identity verification to Verisign, Thawte, GoDaddy, GlobalSign, etc. for SSL certificates and code signing certificates. It can support other models, including self-signed certificates, but not without considerable up-front pain and ongoing maintenance headaches.
I use SSL to communicate between two components written in Java. I can't use a CA, so I have to self-sign everything. Unfortunately, this means that when I try to handshake, I get a SunCertPathBuilderException. I can create my own X509TrustManager that just trusts everything, but that sort of defeats the purpose of having a signed cert.
I would like, when first making the connection, to prompt the user with "SSL handshake with invalid cert. Add cert to store?" or something so they could have it added for them to their certificate store, like web browsers do at sites with invalid certs. I can find plenty of examples online of adding a cert to the store through the commandline, but I can't figure out how to do it programmatically. Is there a way to do this?
Yes it is possible.
There is some code here that I've used before. I had to modify it to do what I wanted and I suspect that you will too but this should get you close - you aren't trying to import a key so theoretically you should be able to simplify things. In any case you can get an idea of what you'll need.
The JDK JavaDoc for java.security.KeyStore is pretty useful too.
Why don't you create your own CA and sign your certificates with that? Then all you would need to do is install the CA own certificate on the machines and every certificate signed by that CA would validate.
Why would you need to do this, you are not validating that the client is who they say they are you are only using the certs to encrypt the comms, so a custom trust manager that allows all certs is all you need.
What you are asking is possible and from memory also involves a custom trust manager to validate the certificates and store them in the keystore. I can't remember the details, but at least you know it is possible to do it.