ServletRequest.getAttribute("javax.servlet.request.X509Certificate") returns null - ssl

I've got a stop-ship problem that is driving me crazy. I hope that one of you experts out there can help.
I'm running the latest release version of TomEE+ (1.6.0.2) and the latest version of Java 8 (build 1.8.0_05-b13). No matter what I try, the following line of code in my HttpServlet always returns null.
X509Certificate certs[] = (X509Certificate[])request.getAttribute("javax.servlet.request.X509Certificate");
I initially assumed that I had specified the attribute name incorrectly, so to diagnose the problem, I decided to take a look at the full list of attributes using the following:
Enumeration<String> enums = request.getAttributeNames();
However that showed me were only two attributes: one for the cipher suite and the other for the key strength.
I read the other articles and verified that my connector was correct and that it had the clientAuth attribute set properly. Here's the connector:
<Connector port="4449" protocol="org.apache.coyote.http11.Http11AprProtocol"
maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
clientAuth="true" sslProtocol="TLSv1.2"
SSLCertificateFile="/etc/unipagos/certs/pay.crt"
SSLCertificateKeyFile="/etc/unipagos/certs/pay.key"
SSLVerifyClient="required"
SSLHonorCipherOrder="true"
ciphers="TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"/>
The connection seems to work, however using openssl s_client with -msg shows that the server isn't asking for the client certificate.
Why is the server not asking for a client certificate? What am I doing wrong?

I have a working connector configuration for tomee and server is requesting client cert.
you can try
<Connector port="7443" protocol="org.apache.coyote.http11.Http11AprProtocol"
maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
SSLProtocol="TLSv1.2"
SSLVerifyClient="require"
SSLCertificateFile="/opt/_cdrom_apache/certs/ec-dev-apr.pem"
SSLCertificateKeyFile="/opt/_cdrom_apache/certs/ec-dev.key"
SSLCACertificateFile="/opt/_cdrom_apache/certs/CA.pem"
/>

Related

Unexpected behavior difference between Nio and Nio2 connectors in Tomcat 8.5

I've run across some peculiar behavior with the NIO2 connector in Tomcat 8.5.23
Here is how I am using it:
<Connector port="8443" protocol="org.apache.coyote.http11.Http11Nio2Protocol"
SSLEnabled="true"
sslImplementationName="org.apache.tomcat.util.net.openssl.OpenSSLImplementation"
maxThreads="200"
minSpareThreads="25"
scheme="https"
secure="true"
keystoreFile="/path/to/keystore.jks"
keystorePass="key-pass"
clientAuth="false"
ciphers="long,list,of,ciphers"/>
Now what happens is, if I happen to POST and the request includes the Header: 'Cache-Control: max-age=0' then the form parameters are not there when I try to retrieve them. I've tried putting in a filter to try and grab them and/or the body itself at the very beginning of the filter chain but it is already too late - the body has been consumed, and there are no parameters. The request structure does however show that the body is of the correct size, so it would appear not to be a network issue.
I would normally think I had something configured incorrectly, but everything works fine under Http11NioProtocol.
Any suggestions - aside from not using Nio2?

symmetricDS two way ssl handshake(clientAuth=false)

Problem summary:
I am trying to run symmetric ds on tomcat with ssl. Setup details
1). MasterNode M1: running on tomcat.
2). Cleint node C1: running on tomcat.
I am able to run symmetricds on tomcat without ssl. This setup works fine all sync happens.
Now when I am trying to run tomcat with following setting for ssl, it gives bad_certificate error on client node:
connection setting on Master node:
<Connector SSLEnabled="true" acceptCount="10"
algorithm="PKIX" allowTrace="false"
ciphers=""
clientAuth="true"
enableLookups="true"
keystoreFile="/root/symmetric-server-3.8.28/security/keystore.p12"
keystorePass="changeit#1"
keystoreType="pkcs12"
port="31415"
redirectPort="-1"
scheme="https"
secure="true"
sslEnabledProtocols="TLSv1.2"
sslProtocol="TLSv1.2"
truststoreFile="/root/symmetric-server-3.8.28/security/keystore.p12"
truststorePass="changeit#1"
truststoreType="pkcs12"/>
connector setting on Client node:
<Connector SSLEnabled="true" acceptCount="10"
algorithm="PKIX" allowTrace="false"
ciphers=""
clientAuth="true"
enableLookups="true"
keystoreFile="/root/symmetric-server-3.8.28/security/keystore2.p12"
keystorePass="changeit#1"
keystoreType="pkcs12"
port="31415"
redirectPort="-1"
scheme="https"
secure="true"
sslEnabledProtocols="TLSv1.2"
sslProtocol="TLSv1.2"
truststoreFile="/root/symmetric-server-3.8.28/security/keystore2.p12"
truststorePass="changeit#1"
truststoreType="pkcs12"/>
Note: If I run Master node tomcat with clientAuth=false then everything works fine. On further debugging I found that client is not providing its certificate during TLS handshake. Following is error: Experts please help what config I need to do so that client provide certificate:
Error:
javax.net.ssl.SSLHandshakeException: Received fatal alert: bad_certificate
Upgrade to SymmetricDS 3.8.31. There was an issue that was fixed that allows for client TLS authentication now:
http://www.symmetricds.org/issues/view.php?id=2886

How can I get client certificate authentication working in JBoss 5.1.0.GA when I'm using APR, and not all web deployments use CLIENT-CERT auth?

Note: I will be answering my own question... just wanted to add this tidbit to the collective wisdom of The Internets.
I've successfully configured certificate authentication on my JBoss 5.1.0.GA server, largely with the help of the information on this page: http://docs.jboss.org/jbossas/jboss4guide/r1/html/ch8.chapter.html
I have one context (let's call it /openContext) that doesn't require any authentication, and another context (let's call it /securedContext) that requires client certificate authentication (i.e., it's configured to use CLIENT-CERT in web.xml). When using JBoss's default web connector, this works splendidly. I can hit http://myhost/openContext and I'm not prompted for a certificate, but when I hit http://myhost/securedContext, I'm prompted for a client certificate as I'd expect.
However, when I install JBossWeb Native and use APR as my web connector, I'm no longer prompted for a certificate when I hit http://myhost/securedContext.
My APR connector config in server.xml looks like:
<Connector protocol="HTTP/1.1" SSLEnabled="true"
port="8443" address="${jboss.bind.address}"
scheme="https" secure="true" clientAuth="false"
SSLProtocol="SSLv3+TLSv1"
SSLCipherSuite="ALL:!ADH:!SSLv2:!EXPORT40:!EXP:!LOW"
SSLRandomSeed="/dev/urandom"
SSLCertificateFile="/etc/pki/tls/certs/mycert.crt"
SSLCertificateKeyFile="/etc/pki/tls/private/mycert.key"
SSLPassword="mypasswordwhichiassureyouisbetterthanthisone"
SSLCACertificateFile="/etc/pki/tls/certs/clientCAs.crt"
/>
I've also tried adding the SSLVerifyClient parameter to that configuration and setting it to optional, but that prompts for a certificate in both /openContext and /securedContext, which isn't the behavior I want.
How can I get JBoss with APR to require certificate authentication for one web context, but not another web context?
What worked for me was to just add a whole new web connector, and have clients use that alternate port for the secured web context. My connectors config now looks like:
<Connector protocol="HTTP/1.1" SSLEnabled="true"
port="8443" address="${jboss.bind.address}"
scheme="https" secure="true" clientAuth="false"
SSLProtocol="SSLv3+TLSv1"
SSLCipherSuite="ALL:!ADH:!SSLv2:!EXPORT40:!EXP:!LOW"
SSLRandomSeed="/dev/urandom"
SSLCertificateFile="/etc/pki/tls/certs/mycert.crt"
SSLCertificateKeyFile="/etc/pki/tls/private/mycert.key"
SSLPassword="mypasswordwhichiassureyouisbetterthanthisone"
/>
<Connector protocol="HTTP/1.1" SSLEnabled="true"
port="8543" address="${jboss.bind.address}"
scheme="https" secure="true" clientAuth="true"
SSLProtocol="SSLv3+TLSv1"
SSLCipherSuite="ALL:!ADH:!SSLv2:!EXPORT40:!EXP:!LOW"
SSLRandomSeed="/dev/urandom"
SSLCertificateFile="/etc/pki/tls/certs/mycert.crt"
SSLCertificateKeyFile="/etc/pki/tls/private/mycert.key"
SSLPassword="mypasswordwhichiassureyouisbetterthanthisone"
SSLCACertificateFile="/etc/pki/tls/certs/clientCAs.crt"
SSLVerifyClient="require"
/>
Now, if I hit http://myhost:8443/openContext, I'm not prompted for a certificate, but when I hit http://myhost:8543/securedContext, I am prompted for a certificate. Of course, I can still access either web app with the "wrong" port, but the consequences are negligible for my purposes. If a client hits http://myhost:8443/securedContext, they simply get an HTTP authentication error. If a client hits http://myhost:8543/openContext, they're prompted for a client certificate. If they provide one, great (though I don't care who you are), and if they don't provide one or provide an invalid one, they get an HTTP auth error (they should have used the correct port in the first place).
I'm pretty sure there's an alternative way to get this working without requiring a second connector by putting httpd in front of JBoss and doing some clever configuration there, but this worked well enough for my purposes.

Using multiple SSL certificates in Tomcat 7

I've been using a wildcard SSL certificate in Apache Tomcat 7. But now that I have to renew, I see there are these EV (extended verification) SSL certificates where browsers show a nice green bar so users feel better. That would be important for my site, so I want it! But I have multiple subdomains and apparently EV SSL certificates are NOT wildcard by nature. So ok, I have a set number of subdomains, I can just buy a bunch (I definitely need at least 2) EV SSL certificates for each subdomain.
Can I set this up in Tomcat 7 so that there are multiple SSL certificates on 1 web application? It's not a problem for me to assign multiple IP addresses to this machine.
Without Server Name Indication (SNI), which is not supported in Java (6), you need one certificate per IP address.
You can configure Tomcat to use multiple connectors, with different IP addresses and certificates, using the address attribute.
For example:
<Connector
port="8443" maxThreads="200" address="10.0.0.1"
scheme="https" secure="true" SSLEnabled="true"
keystoreFile="keystore1.jks" keystorePass="..."
clientAuth="false" sslProtocol="TLS"/>
<Connector
port="8443" maxThreads="200" address="10.0.0.2"
scheme="https" secure="true" SSLEnabled="true"
keystoreFile="keystore2.jks" keystorePass="..."
clientAuth="false" sslProtocol="TLS"/>
You may also be able to use the same keystore, if you need, and use the keyAlias attribute (in Connector) to tell the connector which key/certificate to use (based on the alias name in the keystore).
I am not sure, here if "SNI" is really relevant.
But in your case, the typical solution would be so called ssloffloading or ssl Termination:
i.e. put your tomcat behinde an apache, which configured to use multiple vhosts / domain names on the same ip. You could configure for each vhost in apache to use its own SSL certificate.
There is a step by step guide for this topic here:
http://milestonenext.blogspot.de/2012/09/ssl-offloading-with-modjk-part-1.html
I am using tomcat 8.5 and now it is possible to configure tomcat with multiple SSL/ multi domain. Here is my config.
<Connector port="443" protocol="org.apache.coyote.http11.Http11AprProtocol"
maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
defaultSSLHostConfigName="localhost" >
<UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol" />
<SSLHostConfig hostName="localhost">
<Certificate certificateKeyFile="/$path/privkey.pem"
certificateFile="/$path/certificate.pem"
certificateChainFile="/$path/chain.pem"
type="RSA" />
</SSLHostConfig>
<SSLHostConfig hostName="domainname.com">
<Certificate certificateKeyFile="/$path/privkey.pem"
certificateFile="/$path/certificate.pem"
certificateChainFile="/$path/chain.pem"
type="RSA" />
</SSLHostConfig>
</Connector>
I have just got this to work on a server with multiple SSL's and IP's.
Added IP's this way:
http://www.loadtestingtool.com/help/how-setup-ip.shtml
Added code to make the server use maximum possible security with the "ciphers" (when having a 2048bit key).
Tested first that this will work with self-signed keys this way:
http://community.jboss.org/wiki/GeneratingSelfSignedCertificateWithKeytool
Note that the test in this page has erroneous characters in the beginning of the "-keystore" text (on multiple places).
Here is the code:
<Connector protocol="org.apache.coyote.http11.Http11Protocol" address="###.###.###.##1" port="443" minSpareThreads="5"
enableLookups="true" acceptCount="100" maxThreads="200"
scheme="https" secure="true" SSLEnabled="true" keystoreFile="key1.key"
keystorePass="password1" clientAuth="false" sslProtocol="TLS"
ciphers="SSL_RSA_WITH_RC4_128_MD5, SSL_RSA_WITH_RC4_128_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA"/>
<Connector protocol="org.apache.coyote.http11.Http11Protocol" address="###.###.###.##2" port="443" minSpareThreads="5"
enableLookups="true" acceptCount="100" maxThreads="200"
scheme="https" secure="true" SSLEnabled="true" keystoreFile="key2.key"
keystorePass="password2" clientAuth="false" sslProtocol="TLS"
ciphers="SSL_RSA_WITH_RC4_128_MD5, SSL_RSA_WITH_RC4_128_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA"/>
You could just make life easier and get an EV SAN (also know as UCC) and add each domain as an entry in the subject alternative name field. And if want to use several ip addresses, just export the certificate and reimport it onto each ip address (http://www.ssltools.com/manager is great for that if you are running windows). A good example of an EV SAN certificate is the certificate found at https://www.ssl.com, just examine it.

Setup SSL (self signed cert) with tomcat

I am mostly following this page:
http://tomcat.apache.org/tomcat-6.0-doc/ssl-howto.html
I used this command to create the keystore
keytool -genkey -alias tomcat -keyalg RSA -keystore /etc/tomcat6/keystore
and answered the prompts
Then i edited my server.xml file and uncommented/edited this line
<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
maxThreads="150" scheme="https" secure="true"
clientAuth="false" sslProtocol="TLS"
keystoreFile="/etc/tomcat6/keystore"
keystorePass="tomcat" />
then I go to the web.xml file for my project and add this into the file
<security-constraint>
<web-resource-collection>
<web-resource-name>Security</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
When I try to run my webapp I am met with this:
Unable to connect
Firefox can't establish a connection to the server at localhost:8443.
* The site could be temporarily unavailable or too busy. Try again in a few
moments.
* If you are unable to load any pages, check your computer's network
connection.
If I comment out the lines I've added to my web.xml file, the webapp works fine. My log file in /var/lib/tomcat6/logs says nothing. I can't figure out if this is a problem with my keystore file, my server.xml file or my web.xml file.... Any assistance is appreciated
I am using tomcat 6 on ubuntu.
Edit: I changed my server.xml to
<Connector port="8443" protocol="org.apache.coyote.http11.Http11Protocol" SSLEnabled="true"
maxThreads="150" scheme="https" secure="true"
clientAuth="false" sslProtocol="TLS"
keystoreFile="/etc/tomcat6/keystore"
keystorePass="tomcat" />
incase there was an issue with it being autoconfigured to "APR" as suggested by the tomcat tutorial (not sure if I have that or how to find out if I do). However I am still getting the same error.
Well, I'm an idiot...
I was under the impression that netbeans was restarting my server for me, because eclipse used to know when files that required restarting were changed and it would restart the server for you. Apparently netbeans doesn't have that functionality. Once I've manually restarted the server using the script at /etc/init.d/tomcat6 then everything worked..
Thanks for your help anyway pascal, your questions help me think about what other problems I might be running in to.
I just tested the same setup with a vanilla Tomcat on Ubuntu and :
I generated a keystore
I uncommented the SSL connector in server.xml and pointed on my keystore
I added the security constraint in the web.xml of my-webapp to force the use of SSL
And accessing https://localhost:8443/my-webapp just works on my machine(c).
Are you accessing the application using the right protocol i.e. https:// (notice the s in https)?
By the way, I would recommend to set the redirectPort=8443 attribute in the non-SSL connector so that http://localhost:8080/my-webapp gets redirected to https://localhost:8443/my-webapp.