> -----Original Message-----
> From: Robert Sulliman [mailto:robert.sulli...@sjrb.ca]
> Sent: Monday, November 14, 2016 12:25 PM
> To: users@tomcat.apache.org
> Subject: Tomcat - Two Way SSL as Server
>
> Hi All,
>
> I'm trying to implement two way SSL on a new web service that we are building
> and I'm having some issues.
>
> First some info on the environment.
>
> Server version: Apache Tomcat/8.0.36
> Server built: Jun 9 2016 13:55:50 UTC
> Server number: 8.0.36.0
> OS Name: Linux
> OS Version: 3.10.0-514.el7.x86_64
> Architecture: amd64
> JVM Version: 1.8.0_111-b14
> JVM Vendor: Oracle Corporation
>
> We use an internal certificate authority to sign all of our certificates. So
> all the
> client certificates are signed by our internal root. When I trust the root
> certificate in the client trust store everything works. All client
> certificates signed
> by the internal root work.
>
> However, if I remove the root certificate from the client trust store, and add
> individual client certificates instead I get a cert chain error.
> ________________________________
> *** ECDH ServerKeyExchange
> Signature Algorithm SHA512withRSA
> Server key: Sun EC public key, 256 bits
> public x coord:
> 10710875017633521043383492698333011680577506891922716697438973534
> 1685270962458
> public y coord:
> 93195725734236902743006469378087068209149058097948526490562555560
> 744449337507
> parameters: secp256r1 [NIST P-256, X9.62 prime256v1] (1.2.840.10045.3.1.7)
> *** CertificateRequest
> Cert Types: RSA, DSS, ECDSA
> Supported Signature Algorithms: SHA512withECDSA, SHA512withRSA,
> SHA384withECDSA, SHA384withRSA, SHA256withECDSA, SHA256withRSA,
> SHA256withDSA, SHA224withECDSA, SHA224withRSA, SHA224withDSA,
> SHA1withECDSA, SHA1withRSA, SHA1withDSA Cert Authorities:
> <CN=Client, OU=Information Technology, O=Company, L=Calgary, ST=Alberta,
> C=CA>
> *** ServerHelloDone
> http-nio2-8443-exec-4, WRITE: TLSv1.2 Handshake, length = 4482 http-nio2-
> 8443-exec-2, READ: TLSv1.2 Handshake, length = 7
> *** Certificate chain
> <Empty>
> ***
> http-nio2-8443-exec-2, fatal error: 42: null cert chain
> javax.net.ssl.SSLHandshakeException: null cert chain %% Invalidated:
> [Session-
> 2, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256]
> http-nio2-8443-exec-2, SEND TLSv1.2 ALERT: fatal, description =
> bad_certificate http-nio2-8443-exec-2, WRITE: TLSv1.2 Alert, length = 2 http-
> nio2-8443-exec-2, fatal: engine already closed. Rethrowing
> javax.net.ssl.SSLHandshakeException: null cert chain http-nio2-8443-exec-2,
> called closeOutbound() http-nio2-8443-exec-2, closeOutboundInternal()
> ________________________________ This is an issue for us as we can't have
> all the client certificates in the company granted access to this endpoint,
> it kind
> of defeats the purpose.
>
> The company root certificate is in another trust store used on server startup.
> Here are my configs.
>
> Server.xml connector:
> ________________________________
> <Connector protocol="org.apache.coyote.http11.Http11Nio2Protocol"
> port="8443" maxThreads="24" minSpareThreads="4"
> maxSpareThreads="4" acceptCount="1000" server=" "
> scheme="https" secure="true" SSLEnabled="true"
> keystoreFile="certs/servercert.jks" keystorePass="
> CrazyPasswordHere"
> clientAuth="true"
> truststoreFile="/usr/local/tomcat/certs/clienttrust.jks"
> truststorePass="CrazyPasswordHere"
> sslEnabledProtocols="TLSv1.2" sslProtocol="TLS"
>
> ciphers="TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WIT
> H_AES_128_CBC_SHA256,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
>
> TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,TLS_DHE_RSA_WITH_AES_128_C
> BC_SHA256,TLS_DHE_RSA_WITH_AES_128_CBC_SHA"
> useServerCipherSuitesOrder="true" compression="on"
> compressionMinSize="2048"
>
> compressableMimeType="text/html,text/xml,text/plain,text/css,text/javascript,
> application/javascript" /> ________________________________ Systemd init:
> ________________________________
> # Systemd unit file for tomcat
> [Unit]
> Description=Apache Tomcat
> After=syslog.target network.target
>
> [Service]
> Type=forking
>
> Environment=JAVA_HOME=/usr/lib/jvm/jre
> Environment=CATALINA_PID=/usr/local/tomcat/temp/tomcat.pid
> Environment=CATALINA_HOME=/usr/local/tomcat
> Environment=CATALINA_BASE=/usr/local/tomcat
> Environment='CATALINA_OPTS= -Xms2048M -Xmx2048M -server -
> XX:+UseParallelGC \ -Dcom.sun.management.jmxremote \
> -Dcom.sun.management.jmxremote.port=8090 \ -
> Dcom.sun.management.jmxremote.ssl=false \ -
> Dcom.sun.management.jmxremote.authenticate=true \ -
> Dcom.sun.management.jmxremote.password.file=/usr/local/tomcat/conf/jmxr
> emote.password \ -
> Dcom.sun.management.jmxremote.access.file=/usr/local/tomcat/conf/jmxrem
> ote.access \ -Djavax.net.debug=SSL \ -
> Djavax.net.ssl.trustStore=/usr/local/tomcat/certs/servertrust.jks \ -
> Djavax.net.ssl.trustStorePassword=CrazyPasswordHere \ -
> Djavax.net.ssl.keyStore=/usr/local/tomcat/certs/serverclient.jks \ -
> Djavax.net.ssl.keyStorePassword=CrazyPasswordHere '
> Environment='JAVA_OPTS=-Djava.awt.headless=true -
> Djava.security.egd=file:/dev/./urandom'
>
> ExecStart=/usr/local/tomcat/bin/startup.sh
> ExecStop=/bin/kill -15 $MAINPID
>
> User=tomcat
> Group=tomcat
>
> [Install]
> WantedBy=multi-user.target
> ________________________________
>
> Thanks!
>
> Robert Sulliman
When you say "we can't have all the client certificates in the company granted
access to this endpoint," it sounds like you're talking about a whitelist on
the server. I think that's possible with Apache, but not in Tomcat itself that
I know of.
What I've seen done instead is use a custom servlet filter that grabs the
subject from the client certificate and checks it against a DB, config file,
etc. You can access the client cert using
request.getAttribute("javax.servlet.request.X509Certificate"). It doesn't have
to be a literal full match. Instead you can have the code enforce a rule like
this: "In test environments, the subject must contain OU=TEST and the CN can be
one of foo, bar, baz, etc." You can make it as simple or complex as you want.
You'll still need to set the server to require client auth and will still need
the server to trust the internal CA that signs the clients' certs. Technically
any client with a cert signed by that CA will be able to connect, but your
servlet filter should stop the wrong clients from getting any farther. This is
definitely one of those cases where you want the code to fail closed!
If you don't want to go this route, other things I can think of are:
1. Create a dedicated internal CA for just this purpose and trust it instead of
the company-wide one.
2. Add all client certs directly to the server's trust store. Is this what you
were trying to do? I don't know why it didn't work, but this will be a huge
maintenance headache. Inevitably clients will forget to tell you when they get
new certs and suddenly they'll be locked out.
John
---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org
For additional commands, e-mail: users-h...@tomcat.apache.org