Apache Portable Runtime(APR) を導入してtomcatでOpenSSLエンジンを試す。

# 背景
* 今までtomcatでSSLといえば、Javaネイティブの[JSSE](https://docs.oracle.com/javase/jp/8/docs/technotes/guides/security/jsse/JSSERefGuide.html)で実装されたコネクタ（Http11NioProtocol）を使い、キーはJKS(Java Key Store)で管理するのが一般的だったと思う。
* OpenSSLでキー、証明書を管理するのが一般的なケースが多く、PEM形式のキー、証明書をどうのように組み込みか？毎回悩んでしまう。
* tomcatも進化し、pem形式への対応は行われている。
* さらにAPRは、openSSLをエンジンとしてそのまま利用でき、スケーラビリティ、パフォーマンス、管理面で優位であると言われる。
* HTTP2を利用するには、Java８のTLS実装ではALPNをサポートしておらず、OpenSSLのTLS実装を使うしか方法はない。
    server.xml内のコメントに以下の記述あり
<pre>
Because Java 8's TLS implementation does not support ALPN (which is required for 
HTTP/2 oves TLS), 
you must be using an OpenSSL based TLS implementation to enable HTTP/2 support. 
See the sslImplementationName attribute of the Connector. 
</pre>
* Javaは[PSK未実装](https://bugs.openjdk.java.net/browse/JDK-8049402)のためPSKを利用する場合は、APRコネクタ + OpenSSLエンジン一択。opensslはPSK対応。
<pre>
$ openssl ciphers -v PSK 
PSK-AES256-CBC-SHA      SSLv3 Kx=PSK      Au=PSK  Enc=AES(256)  Mac=SHA1 
PSK-AES128-CBC-SHA      SSLv3 Kx=PSK      Au=PSK  Enc=AES(128)  Mac=SHA1 
PSK-RC4-SHA             SSLv3 Kx=PSK      Au=PSK  Enc=RC4(128)  Mac=SHA1 
PSK-3DES-EDE-CBC-SHA    SSLv3 Kx=PSK      Au=PSK  Enc=3DES(168) Mac=SHA1 
</pre>

 
# tomcatでのPEM形式証明書でのSSL構成として以下の３つが考えられる。APRを利用した構成（2.3.)について導入、設定を確認する。
1. JSSE + PEM
2. APR + OpenSSL + PEM
3. APR + OpenSSL + ALPN(HTTP2) + PEM


# APRを導入する
1. libapr1-devパッケージのインストール
 <pre>
root@v_ubuntu_64:/# apt list libapr1-dev 
Listing... Done 
libapr1-dev/bionic 1.6.3-2 amd64 
root@v_ubuntu_64:/# apt install libapr1-dev 
</pre> 
 
2. libssl-devパッケージのインストール 
<pre>
root@v_ubuntu_64:/# apt list libssl-dev 
Listing... Done 
libssl-dev/bionic-updates,bionic-security 1.1.0g-2ubuntu4.1 amd64 
N: There is 1 additional version. Please use the '-a' switch to see it 
root@v_ubuntu_64:/# apt install libssl-dev 
</pre>

3. gcc/makeのインストール（確認）　※私のubuntu初期環境ではinstall済みでした 
<pre>
root@v_ubuntu_64:/# apt list gcc 
Listing... Done 
gcc/bionic,now 4:7.3.0-3ubuntu2 amd64 [installed] 
root@v_ubuntu_64:/# apt list make 
Listing... Done 
make/bionic,now 4.1-9.1ubuntu1 amd64 [installed] 
</pre>
 
4. APRコンポーネントのビルド、インストール 
  4.1. APRコンポーネントはtomcat-native.tar.gzにパッケージされていますが、"apt install tomcat8"では、インストールされていないので、別途、[ここから](https://tomcat.apache.org/download-80.cgi#8.5.34)ダウンロード
  4.2. ビルド作業ディレクトリで展開 
<pre>
     # cd /home/tetsuohino/tomcat-apr-build/apache-tomcat-8.5.34/bin 
     # tar zxvf tomcat-native.tar.gz
</pre>

  4.3. 環境変数JAVA_HOMEの設定 
  　　　　　　* JRE_HOMEではなくJDK_HOMEを指定する
  　　　　　　* 私のubuntu環境ではJREしかインストールされていなかったため、JDKをインストールし直しています。
　<pre>
 # export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64 
</pre>
  4.4. configure 
<pre>
 # cd tomcat-native-1.2.17-src/native 
 # .configure
checking build system type... x86_64-pc-linux-gnu 
checking host system type... x86_64-pc-linux-gnu 
checking target system type... x86_64-pc-linux-gnu 
checking for a BSD-compatible install... /usr/bin/install -c 
checking for working mkdir -p... yes 
Tomcat Native Version: 1.2.17 
checking for chosen layout... tcnative 
checking for APR... yes 
configure: APR 1.6.3 detected. 
  setting CC to "x86_64-linux-gnu-gcc" 
  setting CPP to "x86_64-linux-gnu-gcc -E" 
  setting LIBTOOL to "/usr/share/apr-1.0/build/libtool" 
  adding "-I/usr/lib/jvm/java-8-openjdk-amd64/include" to TCNATIVE_PRIV_INCLUDES 
checking for JDK os include directory...  linux 
  adding "-I/usr/lib/jvm/java-8-openjdk-amd64/include/linux" to TCNATIVE_PRIV_INCLUDES 
checking for gcc... x86_64-linux-gnu-gcc 
checking whether the C compiler works... yes 
checking for C compiler default output file name... a.out 
checking for suffix of executables...  
checking whether we are cross compiling... no 
checking for suffix of object files... o 
checking whether we are using the GNU C compiler... yes 
checking whether x86_64-linux-gnu-gcc accepts -g... yes 
checking for x86_64-linux-gnu-gcc option to accept ISO C89... none needed 
checking for OpenSSL library... using openssl from /usr/${exec_prefix}/lib and /usr/include 
checking OpenSSL library version >= 1.0.2... ok 
checking for OpenSSL DSA support... yes 
  setting TCNATIVE_LDFLAGS to "-lssl -lcrypto" 
  adding "-DHAVE_OPENSSL" to CFLAGS 
  setting TCNATIVE_LIBS to "" 
  setting TCNATIVE_LIBS to " /usr/lib/x86_64-linux-gnu/libapr-1.la " 
checking for apr_pollset_wakeup in -lapr-1... yes 
  adding "-DHAVE_POLLSET_WAKEUP" to CFLAGS 
configure: creating ./config.status 
config.status: creating tcnative.pc 
config.status: creating Makefile 
config.status: executing default commands 
</pre> 

  4.5. make
<pre>
  # make 
make[1]: Entering directory '/home/tetsuohino/tomcat-apr-build/apache-tomcat-8.5.34/bin/tomcat-native-1.2.17-src/native' 
/usr/share/apr-1.0/build/libtool --no-silent --mode=compile x86_64-linux-gnu-gcc -pthread  -g -O2 -DHAVE_OPENSSL -DHAVE_POLLSET_WAKEUP -DHAVE_CONFIG_H  -DLINUX -D_REENTRANT -D_GNU_SOURCE   -g -O2 -DHAVE_OPENSSL -DHAVE_POLLSET_WAKEUP   -I./include -I/usr/lib/jvm/java-8-openjdk-amd64/include -I/usr/lib/jvm/java-8-openjdk-amd64/include/linux  -I/usr/include/apr-1.0   -o src/address.lo -c src/address.c && touch src/address.lo 

libtool: compile:  x86_64-linux-gnu-gcc -pthread -g -O2 -DHAVE_OPENSSL -DHAVE_POLLSET_WAKEUP -DHAVE_CONFIG_H -DLINUX -D_REENTRANT -D_GNU_SOURCE -g -O2 -DHAVE_OPENSSL -DHAVE_POLLSET_WAKEUP -I./include -I/usr/lib/jvm/java-8-openjdk-amd64/include -I/usr/lib/jvm/java-8-openjdk-amd64/include/linux -I/usr/include/apr-1.0 -c src/address.c  -fPIC -DPIC -o src/.libs/address.o 

   ....snip....

libtool: link: (cd ".libs" && rm -f "libtcnative-1.so.0" && ln -s "libtcnative-1.so.0.2.17" "libtcnative-1.so.0") 

libtool: link: (cd ".libs" && rm -f "libtcnative-1.so" && ln -s "libtcnative-1.so.0.2.17" "libtcnative-1.so") 

libtool: link: x86_64-linux-gnu-ar cru .libs/libtcnative-1.a  src/address.o src/bb.o src/dir.o src/error.o src/file.o src/info.o src/jnilib.o src/lock.o src/misc.o src/mmap.o src/multicast.o src/network.o src/os.o src/poll.o src/pool.o src/proc.o src/shm.o src/ssl.o src/sslconf.o src/sslcontext.o src/sslinfo.o src/sslnetwork.o src/sslutils.o src/stdlib.o src/thread.o src/user.o os/unix/system.o os/unix/uxpipe.o 

x86_64-linux-gnu-ar: `u' modifier ignored since `D' is the default (see `U') 

libtool: link: x86_64-linux-gnu-ranlib .libs/libtcnative-1.a 

libtool: link: ( cd ".libs" && rm -f "libtcnative-1.la" && ln -s "../libtcnative-1.la" "libtcnative-1.la" ) 

make[1]: Leaving directory '/home/tetsuohino/tomcat-apr-build/apache-tomcat-8.5.34/bin/tomcat-native-1.2.17-src/native' 
</pre> 

  4.6. make install
<pre>
  # make install 
make[1]: Entering directory '/home/tetsuohino/tomcat-apr-build/apache-tomcat-8.5.34/bin/tomcat-native-1.2.17-src/native' 

make[1]: Nothing to be done for 'local-all'. 

make[1]: Leaving directory '/home/tetsuohino/tomcat-apr-build/apache-tomcat-8.5.34/bin/tomcat-native-1.2.17-src/native' 

   .... snip....

libtool: install: /usr/bin/install -c -m 755 .libs/libtcnative-1.so.0.2.17 /usr/local/apr/lib/libtcnative-1.so.0.2.17 

libtool: install: (cd /usr/local/apr/lib && { ln -s -f libtcnative-1.so.0.2.17 libtcnative-1.so.0 || { rm -f libtcnative-1.so.0 && ln -s libtcnative-1.so.0.2.17 libtcn

libtool: finish: PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin:/sbin" ldconfig -n /usr/local/apr/lib 

---------------------------------------------------------------------- 

Libraries have been installed in: 

   /usr/local/apr/lib 

If you ever happen to want to link against installed libraries 
in a given directory, LIBDIR, you must either use libtool, and 
specify the full pathname of the library, or use the '-LLIBDIR' 

flag during linking and do at least one of the following: 
   - add LIBDIR to the 'LD_LIBRARY_PATH' environment variable 
     during execution 
   - add LIBDIR to the 'LD_RUN_PATH' environment variable 
     during linking 
   - use the '-Wl,-rpath -Wl,LIBDIR' linker flag 
   - have your system administrator add LIBDIR to '/etc/ld.so.conf' 
See any operating system documentation about shared libraries for 
more information, such as the ld(1) and ld.so(8) manual pages. 
---------------------------------------------------------------------- 
</pre>

5. APRのインストール先を確認
<pre>
# ls -l /usr/local/apr/lib 
total 3044 
-rw-r--r-- 1 root root 1971456  9月 25 20:06 libtcnative-1.a 
-rwxr-xr-x 1 root root    1041  9月 25 20:06 libtcnative-1.la 
lrwxrwxrwx 1 root root      23  9月 25 20:06 libtcnative-1.so -> libtcnative-1.so.0.2.17 
lrwxrwxrwx 1 root root      23  9月 25 20:06 libtcnative-1.so.0 -> libtcnative-1.so.0.2.17 
-rwxr-xr-x 1 root root 1131920  9月 25 20:06 libtcnative-1.so.0.2.17 
drwxr-xr-x 2 root root    4096  9月 25 20:06 pkgconfig 
</pre> 

# APR + OpenSSL
## server.conf設定例
```
 <!-- Define a SSL Coyote HTTP/1.1 Connector on port 8443 --> 
    <Connector 
           protocol="org.apache.coyote.http11.Http11AprProtocol" 
           port="8443" maxThreads="200"  
           scheme="https" secure="true" SSLEnabled="true">
        <SSLHostConfig>
             <Certificate certificateFile="/home/hoge/pem/server.crt" 
                        certificateKeyFile="/home/hoge/pem/private.key" 
                     certificateChainFile="/home/hoge/pem/bundle.crt"/> 
        </SSLHostConfig> 
    </Connector>
```
## 起動確認(catalina.log)
```
02-Oct-2018 10:48:37.106 INFO [main] org.apache.coyote.AbstractProtocol.init Initializing ProtocolHandler ["https-openssl-apr-8443"] 
...
02-Oct-2018 10:48:39.880 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["https-openssl-apr-8443"] 
```

# APR + OpenSSL + HTTP2
## server.conf設定例
```
   <!-- Define a SSL/TLS HTTP/1.1 Connector on port 8443 with HTTP/2 
         This connector uses the APR/native implementation which always uses 
         OpenSSL for TLS. 
         Either JSSE or OpenSSL style configuration may be used. OpenSSL style 
         configuration is used below. 
    --> 
    <Connector port="8443" protocol="org.apache.coyote.http11.Http11AprProtocol" 
               maxThreads="150" SSLEnabled="true" > 
        <UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol" /> 
        <SSLHostConfig> 
            <Certificate certificateKeyFile="/home/hoge/pem/private.key" 
                         certificateFile="/home/hoge/pem/server.crt" 
                     certificateChainFile="/home/hoge/pem/bundle.crt" 
                         type="RSA" /> 
        </SSLHostConfig> 
    </Connector> 
```
## 起動確認(catalina.log)
```
["https-openssl-apr-8443"] connector has been configured to support negotiation to [h2] via ALPN 

02-Oct-2018 10:52:06.257 INFO [main] org.apache.coyote.AbstractProtocol.init Initializing ProtocolHandler ["https-openssl-apr-8443"]
...
02-Oct-2018 10:52:08.358 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["https-openssl-apr-8443"]  
```


# トラブルシュート
* 起動時に「Unable to load certificate key」というエラーが発生する。
  * PEM形式の各証明書、キーファイルをtomcatの実行グループであること。
* 起動時に「java.io.FileNotFoundException: Configured file　xxx does not exist」 というエラーが発生する。
  * "."で区切られたディレクトリに格納されたキーファイル、証明書は見つけてくれない。