Bug 57815

Summary: Improve error message when OpenSSL does not support the requested highest SSLProtocol
Product: Tomcat Native Reporter: Justin <crynax>
Component: LibraryAssignee: Tomcat Developers Mailing List <dev>
Status: RESOLVED FIXED    
Severity: enhancement    
Priority: P2    
Version: 1.1.33   
Target Milestone: ---   
Hardware: PC   
OS: Linux   

Description Justin 2015-04-15 02:20:00 UTC
Tomcat Native builds against older versions of OpenSSL, but then throws a runtime error when parsing SSLProtocol. In my case, building Tomcat Native 1.1.33 on CentOS 6.2 against openssl-1.0.0-20.el6.x86_64 leads to the following exception when parsing SSLProtocol="TLSv1+TLSv1.1+TLSv1.2" in server.xml, even on latest CentOS 6.6 when linking openssl-1.0.1e-30.el6.8.x86_64.


 java.lang.Exception: Unable to create SSLContext. Check that SSLEngine is enabled in the AprLifecycleListener, the AprLifecycleListener has initialised correctly and that a valid SSLProtocol has been specified
        at org.apache.tomcat.util.net.AprEndpoint.bind(AprEndpoint.java:532)
        at org.apache.tomcat.util.net.AbstractEndpoint.init(AbstractEndpoint.java:730)
        at org.apache.coyote.AbstractProtocol.init(AbstractProtocol.java:456)
        at org.apache.catalina.connector.Connector.initInternal(Connector.java:960)
        at org.apache.catalina.util.LifecycleBase.init(LifecycleBase.java:102)
        at org.apache.catalina.core.StandardService.initInternal(StandardService.java:567)
        at org.apache.catalina.util.LifecycleBase.init(LifecycleBase.java:102)
        at org.apache.catalina.core.StandardServer.initInternal(StandardServer.java:842)
        at org.apache.catalina.util.LifecycleBase.init(LifecycleBase.java:102)
        at org.apache.catalina.startup.Catalina.load(Catalina.java:576)
        at org.apache.catalina.startup.Catalina.load(Catalina.java:599)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:497)
        at org.apache.catalina.startup.Bootstrap.load(Bootstrap.java:310)
        at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:484)
Caused by: java.lang.Exception: Invalid Server SSL Protocol (error:00000000:lib(0):func(0):reason(0))
        at org.apache.tomcat.jni.SSLContext.make(Native Method)
        at org.apache.tomcat.util.net.AprEndpoint.bind(AprEndpoint.java:527)
        ... 16 more


I suspect this same circumstance was reported here:
https://mail-archives.apache.org/mod_mbox/tomcat-users/201412.mbox/%3cCAPvtZefZzW9L73D0s4B7rGq8DTxzcJkv8OO9SMdQOx+awxfYBA@mail.gmail.com%3e

Tomcat Native should probably have either configure or compile checks for OpenSSL version or for supported protocols, it should dynamically support these protocols as it dynamically links OpenSSL, or it should have better runtime error logging.

No such error or exception occurs if I build and run against OpenSSL 1.0.1m on CentOS 6.2.
Comment 1 Christopher Schultz 2015-04-15 04:27:12 UTC
I'm inclined to simply improve the error message, though it's already telling you what is wrong: you are requesting a protocol it can't support. (Here, you are requesting TLS1.2 which wasn't supported in your 1.0.0 version of OpenSSL and so support wasn't compiled-in to the native library; the fact that you are running it on 1.0.1 is unfortunately not relevant).

When configuring OpenSSL, we must try to instantiate a server "method" object that implements the highest-allowed protocol. If there isn't any protocol match between what you chose for your highest-level protocol version (TLS1.2 in this case) and what the current library-version can support, then we will throw this error.

Of course, we are essentially reporting that the error is "0" (no error), probably because you built against 1.0.0 (max TLSv1.1) and you are requesting TLS1.2, which isn't available, so we fall-through and choose no server method. The null-check for the created-context fails and we assume there was an OpenSSL error and throw an exception.

The behavior should still be the same (throw an exception), but we should give the proper reason: we couldn't support your requested protocol and so we chose *nothing*, rather than OpenSSL actually failing to initialize a particular protocol.

> Tomcat Native should probably have either configure or compile checks for
> OpenSSL version

We have these checks in both configure (checks for an acceptable OpenSSL version) and the pre-processor (to conditionally-compile support for various supported protocols, etc.).

> or for supported protocols, it should dynamically support these protocols
> as it dynamically links OpenSSL

This is not possible in C. While the library is dynamically loaded at runtime, the actual linking step is performed along with the compiler. Native libraries aren't as flexible as Java is when it comes to discovering available functions in library code.

> or it should have better runtime error logging.

This seems like a reasonable request. Marking as "enhancement" since the behavior won't change.
Comment 2 Justin 2015-04-15 14:00:23 UTC
(In reply to Christopher Schultz from comment #1)
> when it comes to discovering available functions

Seems to me there are many ways to do this. OpenSSL's own "ciphers" command tells you what ciphers are supported. These are standard names which also indicate which SSL protocols are supported.

> 14-Apr-2015 17:30:50.069 INFO [main] org.apache.catalina.core.AprLifecycleListener.initializeSSL OpenSSL successfully
 initialized (OpenSSL 1.0.1e 11 Feb 2013)

I'm a little bothered that you'll log the runtime library, but not the build time library that you are restricting users to.

This obviously isn't a problem on Windows where most use the pre-built Tomcat Native where OpenSSL is statically linked. They must wait for a new build of Tomcat Native.
Comment 3 Christopher Schultz 2015-04-16 13:02:42 UTC
(In reply to Justin from comment #2)
> (In reply to Christopher Schultz from comment #1)
> > when it comes to discovering available functions
> 
> Seems to me there are many ways to do this. OpenSSL's own "ciphers" command
> tells you what ciphers are supported.

Ciphers are s different story: you give a list of ciphers to OpenSSL and tell it to use those. Any that it doesn't support, it will ignore, and there are (usually) plenty of others to choose from. For protocols, you're pretty much limited to 3 useful ones, and some versions of the library only support one. If you choose one it doesn't support, it simply will not support it, no matter what version you built against.

> These are standard names which also indicate which SSL protocols are
> supported.

While true, the mechanism for configuring OpenSSL for a protocol is fundamentally different from the way that ciphers are specified and selected. The Java analogy would be that I have to know at build-time the exact name of the class I want to instantiate in order to get an engine that supports e.g. TLS1.2. If it's not available at built time, I simply can't guarantee it will be available at runtime, so I can't compile-in the usage of that class (it's a function that returns a complex structure in C) or you'll get runtime failures that will usually bring-down the process.

Bringing-down the process is much worse than downgrading to the features available in the build-time version of OpenSSL.

> > 14-Apr-2015 17:30:50.069 INFO [main] org.apache.catalina.core.AprLifecycleListener.initializeSSL OpenSSL successfully
>  initialized (OpenSSL 1.0.1e 11 Feb 2013)
> 
> I'm a little bothered that you'll log the runtime library, but not the build
> time library that you are restricting users to.

Bothered? Well, feel free to ask for that information to be added. I'm the one who added the version information to that log message, and it didn't occur to be to log the version of OpenSSL we built-against. If you think that's useful, I'm happy to add it.

Back to "doing the right thing". I'm not sure it's possible to make tcnative forward-compatible with as-yet-unseen versions of OpenSSL; the best we can do is build against the version we have at hand.

On the other hand, we could be better about picking a protocol given the protocol(s) requested by the caller and those supported by the build-time library. I can review the code in there, which I thought was a little funny at the time. I can also fix the error message so that it makes more sense.

> This obviously isn't a problem on Windows where most use the pre-built
> Tomcat Native where OpenSSL is statically linked. They must wait for a new
> build of Tomcat Native.

Windows users can certainly build their own; they just aren't used to compiling their own software like most UNIX admins are.
Comment 4 Justin 2015-04-16 22:39:53 UTC
Thanks for your time and contributions. I would definitely find both the compile time and run time versions of OpenSSL helpful, at least while such static restrictions exist.

Sadly Tomcat Native is not actively maintained in many distributions, e.g. pulled from Fedora EPEL 6, at 1.1.30 in Fedora EPEL 7 (as of April 16, 2015). OpenSSL will be more actively maintained, particularly for security concerns. Might help many to support future protocols and ciphers.

Slightly off topic: have you or others considered alternatives to OpenSSL/LibreSSL? Maybe GnuTLS, NSS, Botan?
Comment 5 Christopher Schultz 2015-04-17 05:05:28 UTC
(In reply to Justin from comment #4)
> Thanks for your time and contributions. I would definitely find both the
> compile time and run time versions of OpenSSL helpful, at least while such
> static restrictions exist.

Okay.

> Sadly Tomcat Native is not actively maintained in many distributions, e.g.
> pulled from Fedora EPEL 6, at 1.1.30 in Fedora EPEL 7 (as of April 16,
> 2015). OpenSSL will be more actively maintained, particularly for security
> concerns. Might help many to support future protocols and ciphers.

Please lobby your distribution for updates. Generally-speaking, Linux distros try to maintain stability and will only back-port security patches, so many improvements are ignored. There may not be a way to change that policy.

> Slightly off topic: have you or others considered alternatives to
> OpenSSL/LibreSSL? Maybe GnuTLS, NSS, Botan?

If you look at the TLS-related tcnative code, you'll notice that is is *very* tightly coupled with the OpenSSL API. Even the Java binding exposes OpenSSL API calls (I'm specifically thinking of the "hasOp" method).

LibreSSL's initial goal is library-compatibility, so using that library ought to be relatively easy to do. The others, not so much.

If you'd be interested in taking a look at how to implement some of the native functions that are currently implemented as OpenSSL-only, except with GnuTLS, etc., I'd certainly be interested in seeing them.
Comment 6 Mark Thomas 2019-06-18 20:41:35 UTC
This is handled in Tomcat.