diff options
57 files changed, 4 insertions, 9853 deletions
diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index b14f570774..588be443d5 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -249,17 +249,6 @@ jobs: # TEST_MD=1 # ------------------------------------------------------------------------- ### TODO: if: *condition_not_24x - - name: MOD_TLS test suite - config: --enable-mods-shared=reallyall --with-mpm=event --enable-mpms-shared=event - pkgs: curl python3-pytest nghttp2-client python3-cryptography python3-requests python3-multipart python3-filelock python3-websockets cargo cbindgen - env: | - APR_VERSION=1.7.4 - APU_VERSION=1.6.3 - APU_CONFIG="--with-crypto" - RUSTLS_VERSION="v0.13.0" - NO_TEST_FRAMEWORK=1 - TEST_INSTALL=1 - TEST_MOD_TLS=1 - name: Configured w/reduced exports config: --enable-reduced-exports --enable-maintainer-mode --enable-systemd pkgs: libsystemd-dev diff --git a/changes-entries/tls_removed.txt b/changes-entries/tls_removed.txt new file mode 100644 index 0000000000..d56a3dc4e9 --- /dev/null +++ b/changes-entries/tls_removed.txt @@ -0,0 +1,4 @@ + *) mod_tls: removed the experimental module. It now is availble standalone + from https://github.com/icing/mod_tls. The rustls provided API is not + stable and does not align with the httpd release cycle. + [Stefan Eissing] diff --git a/docs/manual/mod/allmodules.xml b/docs/manual/mod/allmodules.xml index 0a9d8b752b..cb8b6fcad1 100644 --- a/docs/manual/mod/allmodules.xml +++ b/docs/manual/mod/allmodules.xml @@ -129,7 +129,6 @@ <modulefile>mod_suexec.xml</modulefile> <modulefile>mod_syslog.xml</modulefile> <modulefile>mod_systemd.xml</modulefile> - <modulefile>mod_tls.xml</modulefile> <modulefile>mod_unique_id.xml</modulefile> <modulefile>mod_unixd.xml</modulefile> <modulefile>mod_userdir.xml</modulefile> diff --git a/docs/manual/mod/mod_tls.xml b/docs/manual/mod/mod_tls.xml deleted file mode 100644 index 8e88923482..0000000000 --- a/docs/manual/mod/mod_tls.xml +++ /dev/null @@ -1,640 +0,0 @@ -<?xml version="1.0"?> -<!DOCTYPE modulesynopsis SYSTEM "../style/modulesynopsis.dtd"> -<?xml-stylesheet type="text/xsl" href="../style/manual.en.xsl"?> -<!-- $LastChangedRevision: 1895285 $ --> - -<!-- - Licensed to the Apache Software Foundation (ASF) under one or more - contributor license agreements. See the NOTICE file distributed with - this work for additional information regarding copyright ownership. - The ASF licenses this file to You under the Apache License, Version 2.0 - (the "License"); you may not use this file except in compliance with - the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - --> - -<modulesynopsis metafile="mod_tls.xml.meta"> - - <name>mod_tls</name> - <description>TLS v1.2 and v1.3 implemented in memory-safe Rust via - the rustls library - </description> - <status>Experimental</status> - <sourcefile>mod_tls.c</sourcefile> - <identifier>tls_module</identifier> - <compatibility>Available in version 2.4.52 and later</compatibility> - <summary> - <p> - mod_tls is an alternative to <module>mod_ssl</module> for providing https to a server. - It's feature set is a subset, described in more detail below. It can - be used as a companion to <module>mod_ssl</module>, e.g. both modules can be loaded at - the same time. - </p><p> - mod_tls, being written in C, used the Rust implementation of TLS named - <a href="https://github.com/rustls/rustls">rustls</a> via its C interface - <a href="https://github.com/rustls/rustls-ffi">rustls-ffi</a>. This gives - <em>memory safe</em> cryptography and protocol handling at comparable - performance. - </p><p> - It can be configured for frontend and backend connections. The configuration - directive have been kept mostly similar to <module>mod_ssl</module> ones. - </p> - </summary> - <section id="vhost_context"> - <title>TLS in a VirtualHost context</title> - <highlight language="config"> -Listen 443 -TLSEngine 443 - -<VirtualHost *:443> - ServerName example.net - TLSCertificate file_with_certificate.pem file_with_key.pem - ... -</VirtualHost> - </highlight> - <p> - The above is a minimal configuration. Instead of enabling mod_tls - in every virtual host, the port for incoming TLS connections is - specified. - </p><p> - You cannot mix virtual hosts with <module>mod_ssl</module> and mod_tls on the same - port. It's either or. SNI and ALPN are supported. You may use several - virtual hosts on the same port and a mix of protocols like http/1.1 - and h2. - </p> - </section> - - <section id="comparison"><title>Feature Comparison with mod_ssl</title> - <p> - The table below gives a comparison of feature between - <module>mod_ssl</module> and mod_tls. If a feature of <module>mod_ssl</module> is no listed here, - it is not supported by mod_tls. The one difference, probably most relevant - is the lack for client certificate support in the current version of - mod_tls. - </p> - <table> - <tr><th>Feature</th><th>mod_ssl</th><th>mod_tls</th><th>Comment</th></tr> -<tr><td>Frontend TLS</td><td>yes</td><td>yes</td><td></td></tr> -<tr><td>Backend TLS</td><td>yes</td><td>yes</td><td></td></tr> -<tr><td>TLS v1.3</td><td>yes*</td><td>yes</td><td>*)with recent OpenSSL</td></tr> -<tr><td>TLS v1.2</td><td>yes</td><td>yes</td><td></td></tr> -<tr><td>TLS v1.0</td><td>yes*</td><td>no</td><td>*)if enabled in OpenSSL</td></tr> -<tr><td>SNI Virtual Hosts</td><td>yes</td><td>yes</td><td></td></tr> -<tr><td>Client Certificates</td><td>yes</td><td>no</td><td></td></tr> -<tr><td>Machine Certificates for Backend</td><td>yes</td><td>yes</td><td></td></tr> -<tr><td>OCSP Stapling</td><td>yes</td><td>yes*</td><td>*)via <module>mod_md</module></td></tr> -<tr><td>Backend OCSP check</td><td>yes</td><td>no*</td><td>*)stapling will be verified</td></tr> -<tr><td>TLS version to allow</td><td>min-max</td><td>min</td><td></td></tr> -<tr><td>TLS ciphers</td><td>exclusive list</td><td>preferred/suppressed</td><td></td></tr> -<tr><td>TLS cipher ordering</td><td>client/server</td><td>client/server</td><td></td></tr> -<tr><td>TLS sessions</td><td>yes</td><td>yes</td><td></td></tr> -<tr><td>SNI strictness</td><td>default no</td><td>default yes</td><td></td></tr> -<tr><td>Option EnvVars</td><td>exhaustive</td><td>limited*</td><td>*)see var list</td></tr> -<tr><td>Option ExportCertData</td><td>client+server</td><td>server</td><td></td></tr> -<tr><td>Backend CA</td><td>file/dir</td><td>file</td><td></td></tr> -<tr><td>Revocation CRLs</td><td>yes</td><td>no</td><td></td></tr> -<tr><td>TLS Renegotiation</td><td>yes*</td><td>no</td><td>*)in TLS v1.2</td></tr> -<tr><td>Encrypted Cert Keys</td><td>yes</td><td>no</td><td></td></tr> - </table> - <p> - </p> - </section> - - <section id="protocols"><title>TLS Protocols</title> - <p> - mod_tls supports TLS protocol version 1.2 and 1.3. Should there ever be - a version 1.4 and <code>rustls</code> supports it, it will be available as well. - </p> - <p> - In mod_tls, you configure the <em>minimum</em> version to use, never the maximum: - </p> - <highlight language="config"> -TLSProtocol TLSv1.3+ - </highlight> - <p> - This allows only version 1.3 and whatever may be its successor one day when talking - to your server or to a particular virtual host. - </p> - </section> - - <section id="ciphers"><title>TLS Ciphers</title> - <p> - The list of TLS ciphers supported in the <code>rustls</code> library, - can be found <a href="https://docs.rs/rustls/">here</a>. All TLS v1.3 - ciphers are supported. For TLS v1.2, only ciphers that rustls considers - secure are available. - </p><p> - mod_tls supports the following names for TLS ciphers: - </p> - <ol> - <li> - The <a href="https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-4">IANA assigned name</a> - which uses `_` to separate parts. Example: <code>TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384</code> - </li> - <li> - The OpenSSL name, using `-` as separator (for 1.2). Example: <code>ECDHE-ECDSA-AES256-SHA384</code>. - Such names often appear in documentation. `mod_tls` defines them for all TLS v1.2 ciphers. - For TLS v1.3 ciphers, names starting with <code>TLS13_</code> are also supported. - </li> - <li> - The <a href="https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-4">IANA assigned identifier</a>, - which is a 16-bit numeric value. Example: <code>0xc024</code>. - You can use this in configurations as <code>TLS_CIPHER_0xc024</code>. - </li> - </ol> - <p> - You can configure a preference for ciphers, which means they will be used - for clients that support them. If you do not configure a preference, <code>rustls</code> - will use the one that it considers best. This is recommended. - </p> - <p> - Should you nevertheless have the need to prefer one cipher over another, you - may configure it like this: - </p> - <highlight language="config"> -TLSCiphersPrefer ECDHE-ECDSA-AES256-SHA384 -# or several -TLSCiphersPrefer ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305 - </highlight> - <p> - If you name a cipher that is unknown, the configuration will fail. - If you name a cipher is not supported by <code>rustls</code> (or no - longer supported in an updated version of <code>rustls</code> for security - reasons), mod_tls will log a <code>WARNING</code>, but continue to work. - </p> - <p> - A similar mechanism exists, if you want to disable a particular cipher: - </p> - <highlight language="config"> -TLSCipherSuppress ECDHE-ECDSA-AES256-SHA384 - </highlight> - <p> - A suppressed cipher will not longer be used. - If you name a cipher that is unknown, the configuration will fail. - If you name a cipher is not supported by <code>rustls</code> (or no - longer supported in an updated version of <code>rustls</code> for security - reasons), mod_tls will log a <code>WARNING</code>, but continue to work. - </p> - </section> - - <section id="vhosts"><title>Virtual Hosts</title> - <p> - mod_tls uses the SNI (Server Name Indicator) to select one of the - configured virtual hosts that match the port being served. Should - the client not provide an SNI, the <em>first</em> configured - virtual host will be selected. If the client <em>does</em> provide - an SNI (as all today's clients do), it <em>must</em> match one - virtual host (<directive module="core">ServerName</directive> or - <directive module="core">ServerAlias</directive>) - or the connection will fail. - </p> - <p> - As with <module>mod_ssl</module>, you may specify ciphers and protocol - versions for the base server (global) and/or individual virtual hosts - that are selected via SNI by the client. - </p> - <highlight language="config"> -Listen 443 -TLSEngine 443 - -<VirtualHost *:443> - ServerName example1.net - TLSCertificate example1-cert.pem - ... -</VirtualHost> - -<VirtualHost *:443> - ServerName example2.net - TLSCertificate example2-cert.pem - ... - TLSProtocol v1.3+ -</VirtualHost> - </highlight> - <p> - The example above show different TLS settings for virtual hosts on the - same port. This is supported. <code>example1</code> can be contacted via - all TLS versions and <code>example2</code> only allows v1.3 or later. - </p> - </section> - - <section id="ACME"><title>ACME Certificates</title> - <p> - ACME certificates via <module>mod_md</module> are supported, just as - for <module>mod_ssl</module>. A minimal configuration: - </p> - <highlight language="config"> -Listen 443 -TLSEngine 443 -MDomain example.net - -<VirtualHost *:443> - ServerName example.net - ... -</VirtualHost> - </highlight> - </section> - - <section id="OCSP"><title>OCSP Stapling</title> - <p> - mod_tls has no own implementation to retrieve OCSP information for - a certificate. However, it will use such for Stapling if it is provided - by <module>mod_md</module>. See <module>mod_md</module>'s documentation - on how to enable this. - </p> - </section> - - <section id="variables"><title>TLS Variables</title> - <p> - Via the directive <directive module="mod_tls">TLSOptions</directive>, several variables - are placed into the environment of requests and can be inspected, for - example in a CGI script. - </p> - <p> - The variable names are given by <module>mod_ssl</module>. Note that these - are only a subset of the many variables that <module>mod_ssl</module> exposes. - </p> - <table> - <tr><th>Variable</th><th>TLSOption</th><th>Description</th></tr> - <tr><td>SSL_TLS_SNI</td><td>*</td><td>the server name indicator (SNI) send by the client</td></tr> - <tr><td>SSL_PROTOCOL</td><td>*</td><td>the TLS protocol negotiated</td></tr> - <tr><td>SSL_CIPHER</td><td>*</td><td>the name of the TLS cipher negotiated</td></tr> - <tr><td>SSL_VERSION_INTERFACE</td><td>StdEnvVars</td><td>the module version</td></tr> - <tr><td>SSL_VERSION_LIBRARY</td><td>StdEnvVars</td><td>the rustls-ffi version</td></tr> - <tr><td>SSL_SECURE_RENEG</td><td>StdEnvVars</td><td>always `false`</td></tr> - <tr><td>SSL_COMPRESS_METHOD</td><td>StdEnvVars</td><td>always `false`</td></tr> - <tr><td>SSL_CIPHER_EXPORT</td><td>StdEnvVars</td><td>always `false`</td></tr> - <tr><td>SSL_CLIENT_VERIFY</td><td>StdEnvVars</td><td>always `false`</td></tr> - <tr><td>SSL_SESSION_RESUMED</td><td>StdEnvVars</td><td>either `Resumed` if a known TLS session id was presented by the client or `Initial` otherwise</td></tr> - <tr><td>SSL_SERVER_CERT</td><td>ExportCertData</td><td>the selected server certificate in PEM format</td></tr> - </table> - <p> - The variable <code>SSL_SESSION_ID</code> is intentionally not supported as - it contains sensitive information. - </p> - </section> - - <section id="certificates"><title>Client Certificates</title> - <p> - While <code>rustls</code> supports client certificates in principle, parts - of the infrastructure to make <em>use</em> of these in a server are not - offered. - </p> - <p> - Among these features are: revocation lists, inspection of certificate - extensions and the matched issuer chain for OCSP validation. Without these, - revocation of client certificates is not possible. Offering authentication - without revocation is not considered an option. - </p> - <p> - Work will continue on this and client certificate support may become - available in a future release. - </p> - </section> - - <directivesynopsis> - <name>TLSEngine</name> - <description>defines on which address+port the module shall handle incoming connections.</description> - <syntax>TLSEngine [<em>address</em>:]<em>port</em></syntax> - <contextlist> - <context>server config</context> - </contextlist> - <usage> - <p> - This is set on a global level, not in individual <directive module="core" - type="section">VirtualHost</directive>s. - It will affect all <directive module="core" type="section">VirtualHost</directive> - that match the specified address/port. - You can use <directive>TLSEngine</directive> several times to use more than one address/port. - </p><p> - </p> - <example><title>Example</title> - <highlight language="config"> - TLSEngine 443 - </highlight> - </example> - <p> - The example tells mod_tls to handle incoming connection on port 443 for - all listeners. - </p> - </usage> - </directivesynopsis> - - <directivesynopsis> - <name>TLSCertificate</name> - <description>adds a certificate and key (PEM encoded) to a server/virtual host.</description> - <syntax>TLSCertificate <em>cert_file</em> [<em>key_file</em>]</syntax> - <contextlist> - <context>server config</context> - <context>virtual host</context> - </contextlist> - <usage> - <p> - If you do not specify a separate key file, the key is assumed to also be - found in the first file. You may add more than one certificate to a - server/virtual host. The first certificate suitable for a client is then chosen. - </p><p> - The path can be specified relative to the server root. - </p> - </usage> - </directivesynopsis> - - <directivesynopsis> - <name>TLSProtocol</name> - <description>specifies the minimum version of the TLS protocol to use.</description> - <syntax>TLSProtocol <em>version</em>+</syntax> - <default>TLSProtocol v1.2+</default> - <contextlist> - <context>server config</context> - <context>virtual host</context> - </contextlist> - <usage> - <p> - The default is `v1.2+`. Settings this to `v1.3+` would disable TLSv1.2. - </p> - </usage> - </directivesynopsis> - - <directivesynopsis> - <name>TLSCiphersPrefer</name> - <description>defines ciphers that are preferred.</description> - <syntax>TLSCiphersPrefer <em>cipher(-list)</em></syntax> - <contextlist> - <context>server config</context> - <context>virtual host</context> - </contextlist> - <usage> - <p> - This will not disable any ciphers supported by `rustls`. If you - specify a cipher that is completely unknown, the configuration will - fail. If you specify a cipher that is known but not supported by `rustls`, - a warning will be logged but the server will continue. - </p><p> - </p> - <example><title>Example</title> - <highlight language="config"> -TLSCiphersPrefer ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305 - </highlight> - </example> - <p> - The example gives 2 ciphers preference over others, in the - order they are mentioned. - </p> - </usage> - </directivesynopsis> - - <directivesynopsis> - <name>TLSCiphersSuppress</name> - <description>defines ciphers that are not to be used.</description> - <syntax>TLSCiphersSuppress <em>cipher(-list)</em></syntax> - <contextlist> - <context>server config</context> - <context>virtual host</context> - </contextlist> - <usage> - <p> - This will not disable any unmentioned ciphers supported by `rustls`. - If you specify a cipher that is completely unknown, the configuration will fail. - If you specify a cipher that is known but not supported by `rustls`, - a warning will be logged but the server will continue. - </p><p> - </p> - <example><title>Example</title> - <highlight language="config"> -TLSCiphersSuppress ECDHE-ECDSA-CHACHA20-POLY1305 - </highlight> - </example> - <p> - The example removes a cipher for use in connections. - </p> - </usage> - </directivesynopsis> - - <directivesynopsis> - <name>TLSHonorClientOrder</name> - <description>determines if the order of ciphers supported by the client is honored</description> - <syntax>TLSHonorClientOrder on|off</syntax> - <default>TLSHonorClientOrder on</default> - <contextlist> - <context>server config</context> - <context>virtual host</context> - </contextlist> - <usage> - <p> - <directive>TLSHonorClientOrder</directive> determines if the order of ciphers - supported by the client is honored. - </p><p> - </p> - </usage> - </directivesynopsis> - - <directivesynopsis> - <name>TLSOptions</name> - <description>enables SSL variables for requests.</description> - <syntax>TLSOptions [+|-]<em>option</em></syntax> - <contextlist> - <context>server config</context> - <context>virtual host</context> - <context>directory</context> - <context>.htaccess</context> - </contextlist> - <usage> - <p> - <directive>TLSOptions</directive> is analog to <directive - module="mod_ssl">SSLOptions</directive> in <module>mod_ssl</module>. - It can be set per directory/location and `option` can be: - </p> - <ul> - <li>`StdEnvVars`: adds more variables to the requests environment, - as forwarded for example to CGI processing and other applications. - </li> - <li>`ExportCertData`: adds certificate related variables to the request environment. - </li> - <li>`Defaults`: resets all options to their default values.</li> - </ul> - <p> - Adding variables to a request environment adds overhead, especially - when certificates need to be inspected and fields extracted. - Therefore most variables are not set by default. - </p> - <p> - You can configure <directive>TLSOptions</directive> per location or generally on a - server/virtual host. Prefixing an option with `-` disables this - option while leaving others unchanged. - A `+` prefix is the same as writing the option without one. - </p> - <p> - The `Defaults` value can be used to reset any options that are - inherited from other locations or the virtual host/server. - </p> - <example><title>Example</title> - <highlight language="config"> -<Location /myplace/app> - TLSOptions Defaults StdEnvVars - ... -</Location> - </highlight> - </example> - </usage> - </directivesynopsis> - - <directivesynopsis> - <name>TLSProxyEngine</name> - <description>enables TLS for backend connections.</description> - <syntax>TLSProxyEngine on|off</syntax> - <contextlist> - <context>server config</context> - <context>virtual host</context> - <context>proxy section</context> - </contextlist> - <usage> - <p> - <directive>TLSProxyEngine</directive> is analog to <directive - module="mod_ssl">SSLProxyEngine</directive> in <module>mod_ssl</module>. - </p><p> - This can be used in a server/virtual host or <directive module="mod_proxy" - type="section">Proxy</directive> section to - enable the module for outgoing connections using <module>mod_proxy</module>. - </p> - </usage> - </directivesynopsis> - - <directivesynopsis> - <name>TLSProxyCA</name> - <description>sets the root certificates to validate the backend server with.</description> - <syntax>TLSProxyCA <em>file.pem</em></syntax> - <contextlist> - <context>server config</context> - <context>virtual host</context> - <context>proxy section</context> - </contextlist> - <usage> - <p> - - </p> - </usage> - </directivesynopsis> - - <directivesynopsis> - <name>TLSProxyProtocol</name> - <description>specifies the minimum version of the TLS protocol to use in proxy connections.</description> - <syntax>TLSProxyProtocol <em>version</em>+</syntax> - <default>TLSProxyProtocol v1.2+</default> - <contextlist> - <context>server config</context> - <context>virtual host</context> - <context>proxy section</context> - </contextlist> - <usage> - <p> - The default is `v1.2+`. Settings this to `v1.3+` would disable TLSv1.2. - </p> - </usage> - </directivesynopsis> - - <directivesynopsis> - <name>TLSProxyCiphersPrefer</name> - <description>defines ciphers that are preferred for a proxy connection.</description> - <syntax>TLSProxyCiphersPrefer <em>cipher(-list)</em></syntax> - <contextlist> - <context>server config</context> - <context>virtual host</context> - <context>proxy section</context> - </contextlist> - <usage> - <p> - This will not disable any ciphers supported by `rustls`. - If you specify a cipher that is completely unknown, the configuration will fail. - If you specify a cipher that is known but not supported by `rustls`, - a warning will be logged but the server will continue. - </p> - </usage> - </directivesynopsis> - - <directivesynopsis> - <name>TLSProxyCiphersSuppress</name> - <description>defines ciphers that are not to be used for a proxy connection.</description> - <syntax>TLSProxyCiphersSuppress <em>cipher(-list)</em></syntax> - <contextlist> - <context>server config</context> - <context>virtual host</context> - <context>proxy section</context> - </contextlist> - <usage> - <p> - This will not disable any unmentioned ciphers supported by `rustls`. - If you specify a cipher that is completely unknown, the configuration will fail. - If you specify a cipher that is known but not supported by `rustls`, - a warning will be logged but the server will continue. - </p> - </usage> - </directivesynopsis> - - <directivesynopsis> - <name>TLSProxyMachineCertificate</name> - <description>adds a certificate and key file (PEM encoded) to a proxy setup.</description> - <syntax>TLSProxyMachineCertificate <em>cert_file</em> [<em>key_file</em>]</syntax> - <contextlist> - <context>server config</context> - <context>virtual host</context> - <context>proxy section</context> - </contextlist> - <usage> - <p> - The certificate is used to authenticate against a proxied backend server. - </p><p> - If you do not specify a separate key file, the key is assumed to also be - found in the first file. You may add more than one certificate to a proxy - setup. The first certificate suitable for a proxy connection to a backend - is then chosen by <code>rustls</code>. - </p> - <p> - The path can be specified relative to the server root. - </p> - </usage> - </directivesynopsis> - - <directivesynopsis> - <name>TLSStrictSNI</name> - <description>enforces exact matches of client server indicators (SNI) against host names.</description> - <syntax>TLSStrictSNI on|off</syntax> - <default>TLSStrictSNI on</default> - <contextlist> - <context>server config</context> - </contextlist> - <usage> - <p> - Client connections using SNI will be unsuccessful if no match is found. - </p> - </usage> - </directivesynopsis> - - <directivesynopsis> - <name>TLSSessionCache</name> - <description>specifies the cache for TLS session resumption.</description> - <syntax>TLSSessionCache <em>cache-spec</em></syntax> - <contextlist> - <context>server config</context> - </contextlist> - <usage> - <p> - This uses a cache on the server side to allow clients to resume connections. - </p><p> - You can set this to `none` or define a cache as in the <directive - module="mod_ssl">SSLSessionCache</directive> - directive of <module>mod_ssl</module>. - </p><p> - If not configured, `mod_tls` will try to create a shared memory cache on its own, - using `shmcb:tls/session-cache` as specification. - Should that fail, a warning is logged, but the server continues. - </p> - </usage> - </directivesynopsis> - -</modulesynopsis> diff --git a/modules/tls/Makefile.in b/modules/tls/Makefile.in deleted file mode 100644 index 4395bc3ac7..0000000000 --- a/modules/tls/Makefile.in +++ /dev/null @@ -1,20 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# -# standard stuff -# - -include $(top_srcdir)/build/special.mk diff --git a/modules/tls/config2.m4 b/modules/tls/config2.m4 deleted file mode 100644 index 8a32490cb6..0000000000 --- a/modules/tls/config2.m4 +++ /dev/null @@ -1,173 +0,0 @@ -dnl Licensed to the Apache Software Foundation (ASF) under one or more -dnl contributor license agreements. See the NOTICE file distributed with -dnl this work for additional information regarding copyright ownership. -dnl The ASF licenses this file to You under the Apache License, Version 2.0 -dnl (the "License"); you may not use this file except in compliance with -dnl the License. You may obtain a copy of the License at -dnl -dnl http://www.apache.org/licenses/LICENSE-2.0 -dnl -dnl Unless required by applicable law or agreed to in writing, software -dnl distributed under the License is distributed on an "AS IS" BASIS, -dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -dnl See the License for the specific language governing permissions and -dnl limitations under the License. - -dnl # start of module specific part -APACHE_MODPATH_INIT(tls) - -dnl # list of module object files -tls_objs="dnl -mod_tls.lo dnl -tls_cache.lo dnl -tls_cert.lo dnl -tls_conf.lo dnl -tls_core.lo dnl -tls_filter.lo dnl -tls_ocsp.lo dnl -tls_proto.lo dnl -tls_util.lo dnl -tls_var.lo dnl -" - -dnl -dnl APACHE_CHECK_TLS -dnl -dnl Configure for rustls, giving preference to -dnl "--with-rustls=<path>" if it was specified. -dnl -AC_DEFUN([APACHE_CHECK_RUSTLS],[ - AC_CACHE_CHECK([for rustls], [ac_cv_rustls], [ - dnl initialise the variables we use - ac_cv_rustls=no - ap_rustls_found="" - ap_rustls_base="" - ap_rustls_libs="" - - dnl Determine the rustls base directory, if any - AC_MSG_CHECKING([for user-provided rustls base directory]) - AC_ARG_WITH(rustls, APACHE_HELP_STRING(--with-rustls=PATH, rustls installation directory), [ - dnl If --with-rustls specifies a directory, we use that directory - if test "x$withval" != "xyes" -a "x$withval" != "x"; then - dnl This ensures $withval is actually a directory and that it is absolute - ap_rustls_base="`cd $withval ; pwd`" - fi - ]) - if test "x$ap_rustls_base" = "x"; then - AC_MSG_RESULT(none) - else - AC_MSG_RESULT($ap_rustls_base) - fi - - dnl Run header and version checks - saved_CPPFLAGS="$CPPFLAGS" - saved_LIBS="$LIBS" - saved_LDFLAGS="$LDFLAGS" - - dnl Before doing anything else, load in pkg-config variables - if test -n "$PKGCONFIG"; then - saved_PKG_CONFIG_PATH="$PKG_CONFIG_PATH" - AC_MSG_CHECKING([for pkg-config along $PKG_CONFIG_PATH]) - if test "x$ap_rustls_base" != "x" ; then - if test -f "${ap_rustls_base}/lib/pkgconfig/librustls.pc"; then - dnl Ensure that the given path is used by pkg-config too, otherwise - dnl the system librustls.pc might be picked up instead. - PKG_CONFIG_PATH="${ap_rustls_base}/lib/pkgconfig${PKG_CONFIG_PATH+:}${PKG_CONFIG_PATH}" - export PKG_CONFIG_PATH - elif test -f "${ap_rustls_base}/lib64/pkgconfig/librustls.pc"; then - dnl Ensure that the given path is used by pkg-config too, otherwise - dnl the system librustls.pc might be picked up instead. - PKG_CONFIG_PATH="${ap_rustls_base}/lib64/pkgconfig${PKG_CONFIG_PATH+:}${PKG_CONFIG_PATH}" - export PKG_CONFIG_PATH - fi - fi - ap_rustls_libs="`$PKGCONFIG $PKGCONFIG_LIBOPTS --libs-only-l --silence-errors librustls`" - if test $? -eq 0; then - ap_rustls_found="yes" - pkglookup="`$PKGCONFIG --cflags-only-I librustls`" - APR_ADDTO(CPPFLAGS, [$pkglookup]) - APR_ADDTO(MOD_CFLAGS, [$pkglookup]) - pkglookup="`$PKGCONFIG $PKGCONFIG_LIBOPTS --libs-only-L librustls`" - APR_ADDTO(LDFLAGS, [$pkglookup]) - APR_ADDTO(MOD_LDFLAGS, [$pkglookup]) - pkglookup="`$PKGCONFIG $PKGCONFIG_LIBOPTS --libs-only-other librustls`" - APR_ADDTO(LDFLAGS, [$pkglookup]) - APR_ADDTO(MOD_LDFLAGS, [$pkglookup]) - fi - PKG_CONFIG_PATH="$saved_PKG_CONFIG_PATH" - fi - - dnl fall back to the user-supplied directory if not found via pkg-config - if test "x$ap_rustls_base" != "x" -a "x$ap_rustls_found" = "x"; then - APR_ADDTO(CPPFLAGS, [-I$ap_rustls_base/include]) - APR_ADDTO(MOD_CFLAGS, [-I$ap_rustls_base/include]) - APR_ADDTO(LDFLAGS, [-L$ap_rustls_base/lib]) - APR_ADDTO(MOD_LDFLAGS, [-L$ap_rustls_base/lib]) - if test "x$ap_platform_runtime_link_flag" != "x"; then - APR_ADDTO(LDFLAGS, [$ap_platform_runtime_link_flag$ap_rustls_base/lib]) - APR_ADDTO(MOD_LDFLAGS, [$ap_platform_runtime_link_flag$ap_rustls_base/lib]) - fi - fi - - AC_MSG_CHECKING([for rustls version >= 0.9.2]) - AC_TRY_COMPILE([#include <rustls.h>],[ -rustls_version(); -rustls_acceptor_new(); -], - [AC_MSG_RESULT(OK) - ac_cv_rustls=yes], - [AC_MSG_RESULT(FAILED)]) - - dnl restore - CPPFLAGS="$saved_CPPFLAGS" - LIBS="$saved_LIBS" - LDFLAGS="$saved_LDFLAGS" - ]) - if test "x$ac_cv_rustls" = "xyes"; then - AC_DEFINE(HAVE_RUSTLS, 1, [Define if rustls is available]) - fi -]) - - -dnl # hook module into the Autoconf mechanism (--enable-http2) -APACHE_MODULE(tls, [TLS protocol handling using rustls. Implemented by mod_tls. -This module requires a librustls installation. -See --with-rustls on how to manage non-standard locations. This module -is usually linked shared and requires loading. ], $tls_objs, , most, [ - APACHE_CHECK_RUSTLS - if test "$ac_cv_rustls" = "yes" ; then - if test "x$enable_tls" = "xshared"; then - case `uname` in - "Darwin") - MOD_TLS_LINK_LIBS="-lrustls -framework Security -framework Foundation" - ;; - *) - MOD_TLS_LINK_LIBS="-lrustls" - ;; - esac - - # Some rustls versions need an extra -lm when linked - # See https://github.com/rustls/rustls-ffi/issues/133 - rustls_version=`rustc --version` - case "$rustls_version" in - *1.55*) need_lm="yes" ;; - *1.56*) need_lm="yes" ;; - *1.57*) need_lm="yes" ;; - esac - if test "$need_lm" = "yes" ; then - MOD_TLS_LINK_LIBS="$MOD_TLS_LINK_LIBS -lm" - fi - - # The only symbol which needs to be exported is the module - # structure, so ask libtool to hide everything else: - APR_ADDTO(MOD_TLS_LDADD, [$MOD_TLS_LINK_LIBS -export-symbols-regex tls_module]) - fi - else - enable_tls=no - fi -]) - - -dnl # end of module specific part -APACHE_MODPATH_FINISH - diff --git a/modules/tls/mod_tls.c b/modules/tls/mod_tls.c deleted file mode 100644 index 9d795210a3..0000000000 --- a/modules/tls/mod_tls.c +++ /dev/null @@ -1,288 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include <assert.h> -#include <apr_optional.h> -#include <apr_strings.h> - -#include <mpm_common.h> -#include <httpd.h> -#include <http_core.h> -#include <http_connection.h> -#include <http_log.h> -#include <http_protocol.h> -#include <http_ssl.h> -#include <http_request.h> -#include <ap_socache.h> - -#include <rustls.h> - -#include "mod_tls.h" -#include "tls_conf.h" -#include "tls_core.h" -#include "tls_cache.h" -#include "tls_proto.h" -#include "tls_filter.h" -#include "tls_var.h" -#include "tls_version.h" - -#include "mod_proxy.h" - -static void tls_hooks(apr_pool_t *pool); - -AP_DECLARE_MODULE(tls) = { - STANDARD20_MODULE_STUFF, - tls_conf_create_dir, /* create per dir config */ - tls_conf_merge_dir, /* merge per dir config */ - tls_conf_create_svr, /* create per server config */ - tls_conf_merge_svr, /* merge per server config (inheritance) */ - tls_conf_cmds, /* command handlers */ - tls_hooks, -#if defined(AP_MODULE_FLAG_NONE) - AP_MODULE_FLAG_ALWAYS_MERGE -#endif -}; - -static const char* crustls_version(apr_pool_t *p) -{ - struct rustls_str rversion; - - rversion = rustls_version(); - return apr_pstrndup(p, rversion.data, rversion.len); -} - -static int tls_pre_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp) -{ - tls_proto_pre_config(pconf, ptemp); - tls_cache_pre_config(pconf, plog, ptemp); - return OK; -} - -static apr_status_t tls_post_config(apr_pool_t *p, apr_pool_t *plog, - apr_pool_t *ptemp, server_rec *s) -{ - const char *tls_init_key = "mod_tls_init_counter"; - tls_conf_server_t *sc; - void *data = NULL; - - (void)plog; - sc = tls_conf_server_get(s); - assert(sc); - assert(sc->global); - sc->global->module_version = "mod_tls/" MOD_TLS_VERSION; - sc->global->crustls_version = crustls_version(p); - - apr_pool_userdata_get(&data, tls_init_key, s->process->pool); - if (data == NULL) { - /* At the first start, httpd makes a config check dry run - * to see if the config is ok in principle. - */ - ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, s, "post config dry run"); - apr_pool_userdata_set((const void *)1, tls_init_key, - apr_pool_cleanup_null, s->process->pool); - } - else { - ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(10365) - "%s (%s), initializing...", - sc->global->module_version, - sc->global->crustls_version); - } - - return tls_core_init(p, ptemp, s); -} - -static apr_status_t tls_post_proxy_config( - apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s) -{ - tls_conf_server_t *sc = tls_conf_server_get(s); - (void)plog; - sc->global->mod_proxy_post_config_done = 1; - return tls_core_init(p, ptemp, s); -} - -#if AP_MODULE_MAGIC_AT_LEAST(20120211, 109) -static int tls_ssl_outgoing(conn_rec *c, ap_conf_vector_t *dir_conf, int enable_ssl) -{ - /* we are not handling proxy connections - for now */ - tls_core_conn_bind(c, dir_conf); - if (enable_ssl && tls_core_setup_outgoing(c) == OK) { - ap_log_error(APLOG_MARK, APLOG_TRACE2, 0, c->base_server, - "accepted ssl_bind_outgoing(enable=%d) for %s", - enable_ssl, c->base_server->server_hostname); - return OK; - } - tls_core_conn_disable(c); - ap_log_error(APLOG_MARK, APLOG_TRACE2, 0, c->base_server, - "declined ssl_bind_outgoing(enable=%d) for %s", - enable_ssl, c->base_server->server_hostname); - return DECLINED; -} - -#else /* #if AP_MODULE_MAGIC_AT_LEAST(20120211, 109) */ - -APR_DECLARE_OPTIONAL_FN(int, ssl_proxy_enable, (conn_rec *)); -APR_DECLARE_OPTIONAL_FN(int, ssl_engine_disable, (conn_rec *)); -APR_DECLARE_OPTIONAL_FN(int, ssl_engine_set, (conn_rec *, - ap_conf_vector_t *, - int proxy, int enable)); -static APR_OPTIONAL_FN_TYPE(ssl_engine_set) *module_ssl_engine_set; - -static int ssl_engine_set( - conn_rec *c, ap_conf_vector_t *dir_conf, int proxy, int enable) -{ - ap_log_error(APLOG_MARK, APLOG_TRACE3, 0, c->base_server, - "ssl_engine_set(proxy=%d, enable=%d) for %s", - proxy, enable, c->base_server->server_hostname); - tls_core_conn_bind(c, dir_conf); - if (enable && tls_core_setup_outgoing(c) == OK) { - if (module_ssl_engine_set) { - module_ssl_engine_set(c, dir_conf, proxy, 0); - } - return 1; - } - if (proxy || !enable) { - /* we are not handling proxy connections - for now */ - tls_core_conn_disable(c); - } - if (module_ssl_engine_set) { - return module_ssl_engine_set(c, dir_conf, proxy, enable); - } - return 0; -} - -static int ssl_proxy_enable(conn_rec *c) -{ - return ssl_engine_set(c, NULL, 1, 1); -} - -static int ssl_engine_disable(conn_rec *c) -{ - return ssl_engine_set(c, NULL, 0, 0); -} - -static apr_status_t tls_post_config_proxy_ssl( - apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s) -{ - if (1) { - const char *tls_init_key = "mod_tls_proxy_ssl_counter"; - void *data = NULL; - APR_OPTIONAL_FN_TYPE(ssl_engine_set) *fn_ssl_engine_set; - - (void)p; - (void)plog; - (void)ptemp; - apr_pool_userdata_get(&data, tls_init_key, s->process->pool); - if (data == NULL) { - /* At the first start, httpd makes a config check dry run - * to see if the config is ok in principle. - */ - apr_pool_userdata_set((const void *)1, tls_init_key, - apr_pool_cleanup_null, s->process->pool); - return APR_SUCCESS; - } - - /* mod_ssl (if so loaded, has registered its optional functions. - * When mod_proxy runs in post-config, it looks up those functions and uses - * them to manipulate SSL status for backend connections. - * We provide our own implementations to avoid becoming active on such - * connections for now. - * */ - fn_ssl_engine_set = APR_RETRIEVE_OPTIONAL_FN(ssl_engine_set); - module_ssl_engine_set = (fn_ssl_engine_set - && fn_ssl_engine_set != ssl_engine_set)? fn_ssl_engine_set : NULL; - APR_REGISTER_OPTIONAL_FN(ssl_engine_set); - APR_REGISTER_OPTIONAL_FN(ssl_proxy_enable); - APR_REGISTER_OPTIONAL_FN(ssl_engine_disable); - } - return APR_SUCCESS; -} -#endif /* #if AP_MODULE_MAGIC_AT_LEAST(20120211, 109) */ - -static void tls_init_child(apr_pool_t *p, server_rec *s) -{ - tls_cache_init_child(p, s); -} - -static int hook_pre_connection(conn_rec *c, void *csd) -{ - (void)csd; /* mpm specific socket data, not used */ - - /* are we on a primary connection? */ - if (c->master) return DECLINED; - - /* Decide connection TLS stats and install our - * input/output filters for handling TLS/application data - * if enabled. - */ - return tls_filter_pre_conn_init(c); -} - -static int hook_connection(conn_rec* c) -{ - tls_filter_conn_init(c); - /* we do *not* take over. we are not processing requests. */ - return DECLINED; -} - -static const char *tls_hook_http_scheme(const request_rec *r) -{ - return (tls_conn_check_ssl(r->connection) == OK)? "https" : NULL; -} - -static apr_port_t tls_hook_default_port(const request_rec *r) -{ - return (tls_conn_check_ssl(r->connection) == OK) ? 443 : 0; -} - -static const char* const mod_http2[] = { "mod_http2.c", NULL}; - -static void tls_hooks(apr_pool_t *pool) -{ - /* If our request check denies further processing, certain things - * need to be in place for the response to be correctly generated. */ - static const char *dep_req_check[] = { "mod_setenvif.c", NULL }; - static const char *dep_proxy[] = { "mod_proxy.c", NULL }; - - ap_log_perror(APLOG_MARK, APLOG_TRACE1, 0, pool, "installing hooks"); - tls_filter_register(pool); - - ap_hook_pre_config(tls_pre_config, NULL,NULL, APR_HOOK_MIDDLE); - /* run post-config hooks one before, one after mod_proxy, as the - * mod_proxy's own one calls us in its "section_post_config" hook. */ - ap_hook_post_config(tls_post_config, NULL, dep_proxy, APR_HOOK_MIDDLE); - APR_OPTIONAL_HOOK(proxy, section_post_config, - tls_proxy_section_post_config, NULL, NULL, - APR_HOOK_MIDDLE); - ap_hook_post_config(tls_post_proxy_config, dep_proxy, NULL, APR_HOOK_MIDDLE); - ap_hook_child_init(tls_init_child, NULL,NULL, APR_HOOK_MIDDLE); - /* connection things */ - ap_hook_pre_connection(hook_pre_connection, NULL, NULL, APR_HOOK_MIDDLE); - ap_hook_process_connection(hook_connection, NULL, mod_http2, APR_HOOK_MIDDLE); - /* request things */ - ap_hook_default_port(tls_hook_default_port, NULL,NULL, APR_HOOK_MIDDLE); - ap_hook_http_scheme(tls_hook_http_scheme, NULL,NULL, APR_HOOK_MIDDLE); - ap_hook_post_read_request(tls_core_request_check, dep_req_check, NULL, APR_HOOK_MIDDLE); - ap_hook_fixups(tls_var_request_fixup, NULL,NULL, APR_HOOK_MIDDLE); - - ap_hook_ssl_conn_is_ssl(tls_conn_check_ssl, NULL, NULL, APR_HOOK_MIDDLE); - ap_hook_ssl_var_lookup(tls_var_lookup, NULL, NULL, APR_HOOK_MIDDLE); - -#if AP_MODULE_MAGIC_AT_LEAST(20120211, 109) - ap_hook_ssl_bind_outgoing(tls_ssl_outgoing, NULL, NULL, APR_HOOK_MIDDLE); -#else - ap_hook_post_config(tls_post_config_proxy_ssl, NULL, dep_proxy, APR_HOOK_MIDDLE); -#endif - -} diff --git a/modules/tls/mod_tls.h b/modules/tls/mod_tls.h deleted file mode 100644 index db7dc418c6..0000000000 --- a/modules/tls/mod_tls.h +++ /dev/null @@ -1,19 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef mod_tls_h -#define mod_tls_h - -#endif /* mod_tls_h */
\ No newline at end of file diff --git a/modules/tls/tls_cache.c b/modules/tls/tls_cache.c deleted file mode 100644 index de4be18810..0000000000 --- a/modules/tls/tls_cache.c +++ /dev/null @@ -1,310 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include <assert.h> -#include <apr_lib.h> -#include <apr_strings.h> -#include <apr_hash.h> - -#include <httpd.h> -#include <http_connection.h> -#include <http_log.h> -#include <ap_socache.h> -#include <util_mutex.h> - -#include <rustls.h> - -#include "tls_conf.h" -#include "tls_core.h" -#include "tls_cache.h" - -extern module AP_MODULE_DECLARE_DATA tls_module; -APLOG_USE_MODULE(tls); - -#define TLS_CACHE_DEF_PROVIDER "shmcb" -#define TLS_CACHE_DEF_DIR "tls" -#define TLS_CACHE_DEF_FILE "session_cache" -#define TLS_CACHE_DEF_SIZE 512000 - -static const char *cache_provider_unknown(const char *name, apr_pool_t *p) -{ - apr_array_header_t *known; - const char *known_names; - - known = ap_list_provider_names(p, AP_SOCACHE_PROVIDER_GROUP, - AP_SOCACHE_PROVIDER_VERSION); - known_names = apr_array_pstrcat(p, known, ','); - return apr_psprintf(p, "cache type '%s' not supported " - "(known names: %s). Maybe you need to load the " - "appropriate socache module (mod_socache_%s?).", - name, known_names, name); -} - -void tls_cache_pre_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp) -{ - (void)plog; - (void)ptemp; - /* we make this visible, in case someone wants to configure it. - * this does not mean that we will really use it, which is determined - * by configuration and cache provider capabilities. */ - ap_mutex_register(pconf, TLS_SESSION_CACHE_MUTEX_TYPE, NULL, APR_LOCK_DEFAULT, 0); -} - -static const char *cache_init(tls_conf_global_t *gconf, apr_pool_t *p, apr_pool_t *ptemp) -{ - const char *err = NULL; - const char *name, *args = NULL; - apr_status_t rv; - - if (gconf->session_cache) { - goto cleanup; - } - else if (!apr_strnatcasecmp("none", gconf->session_cache_spec)) { - gconf->session_cache_provider = NULL; - gconf->session_cache = NULL; - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, gconf->ap_server, APLOGNO(10346) - "session cache explicitly disabled"); - goto cleanup; - } - else if (!apr_strnatcasecmp("default", gconf->session_cache_spec)) { - const char *path = TLS_CACHE_DEF_DIR; - -#if AP_MODULE_MAGIC_AT_LEAST(20180906, 2) - path = ap_state_dir_relative(p, path); -#endif - gconf->session_cache_spec = apr_psprintf(p, "%s:%s/%s(%ld)", - TLS_CACHE_DEF_PROVIDER, path, TLS_CACHE_DEF_FILE, (long)TLS_CACHE_DEF_SIZE); - gconf->session_cache_spec = "shmcb:mod_tls-sesss(64000)"; - } - - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, gconf->ap_server, APLOGNO(10347) - "Using session cache: %s", gconf->session_cache_spec); - name = gconf->session_cache_spec; - args = ap_strchr((char*)name, ':'); - if (args) { - name = apr_pstrmemdup(p, name, (apr_size_t)(args - name)); - ++args; - } - gconf->session_cache_provider = ap_lookup_provider(AP_SOCACHE_PROVIDER_GROUP, - name, AP_SOCACHE_PROVIDER_VERSION); - if (!gconf->session_cache_provider) { - err = cache_provider_unknown(name, p); - goto cleanup; - } - err = gconf->session_cache_provider->create(&gconf->session_cache, args, ptemp, p); - if (err != NULL) goto cleanup; - - if (gconf->session_cache_provider->flags & AP_SOCACHE_FLAG_NOTMPSAFE - && !gconf->session_cache_mutex) { - /* we need a global lock to access the cache */ - rv = ap_global_mutex_create(&gconf->session_cache_mutex, NULL, - TLS_SESSION_CACHE_MUTEX_TYPE, NULL, gconf->ap_server, p, 0); - if (APR_SUCCESS != rv) { - err = apr_psprintf(p, "error setting up global %s mutex: %d", - TLS_SESSION_CACHE_MUTEX_TYPE, rv); - gconf->session_cache_mutex = NULL; - goto cleanup; - } - } - -cleanup: - if (NULL != err) { - gconf->session_cache_provider = NULL; - gconf->session_cache = NULL; - } - return err; -} - -const char *tls_cache_set_specification( - const char *spec, tls_conf_global_t *gconf, apr_pool_t *p, apr_pool_t *ptemp) -{ - gconf->session_cache_spec = spec; - return cache_init(gconf, p, ptemp); -} - -apr_status_t tls_cache_post_config(apr_pool_t *p, apr_pool_t *ptemp, server_rec *s) -{ - tls_conf_server_t *sc = tls_conf_server_get(s); - const char *err; - apr_status_t rv = APR_SUCCESS; - - err = cache_init(sc->global, p, ptemp); - if (err) { - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(10348) - "session cache [%s] could not be initialized, will continue " - "without session one. Since this will impact performance, " - "consider making use of the 'TLSSessionCache' directive. The " - "error was: %s", sc->global->session_cache_spec, err); - } - - if (sc->global->session_cache) { - struct ap_socache_hints hints; - - ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, s, "provider init session cache [%s]", - sc->global->session_cache_spec); - memset(&hints, 0, sizeof(hints)); - hints.avg_obj_size = 100; - hints.avg_id_len = 33; - hints.expiry_interval = 30; - - rv = sc->global->session_cache_provider->init( - sc->global->session_cache, "mod_tls-sess", &hints, s, p); - if (APR_SUCCESS != rv) { - ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10349) - "error initializing session cache."); - } - } - return rv; -} - -void tls_cache_init_child(apr_pool_t *p, server_rec *s) -{ - tls_conf_server_t *sc = tls_conf_server_get(s); - const char *lockfile; - apr_status_t rv; - - if (sc->global->session_cache_mutex) { - lockfile = apr_global_mutex_lockfile(sc->global->session_cache_mutex); - rv = apr_global_mutex_child_init(&sc->global->session_cache_mutex, lockfile, p); - if (APR_SUCCESS != rv) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(10350) - "Cannot reinit %s mutex (file `%s`)", - TLS_SESSION_CACHE_MUTEX_TYPE, lockfile? lockfile : "-"); - } - } -} - -void tls_cache_free(server_rec *s) -{ - tls_conf_server_t *sc = tls_conf_server_get(s); - if (sc->global->session_cache_provider) { - sc->global->session_cache_provider->destroy(sc->global->session_cache, s); - } -} - -static void tls_cache_lock(tls_conf_global_t *gconf) -{ - if (gconf->session_cache_mutex) { - apr_status_t rv = apr_global_mutex_lock(gconf->session_cache_mutex); - if (APR_SUCCESS != rv) { - ap_log_error(APLOG_MARK, APLOG_WARNING, rv, gconf->ap_server, APLOGNO(10351) - "Failed to acquire TLS session cache lock"); - } - } -} - -static void tls_cache_unlock(tls_conf_global_t *gconf) -{ - if (gconf->session_cache_mutex) { - apr_status_t rv = apr_global_mutex_unlock(gconf->session_cache_mutex); - if (APR_SUCCESS != rv) { - ap_log_error(APLOG_MARK, APLOG_WARNING, rv, gconf->ap_server, APLOGNO(10352) - "Failed to release TLS session cache lock"); - } - } -} - -static rustls_result tls_cache_get( - void *userdata, - const rustls_slice_bytes *key, - int remove_after, - unsigned char *buf, - size_t count, - size_t *out_n) -{ - conn_rec *c = userdata; - tls_conf_conn_t *cc = tls_conf_conn_get(c); - tls_conf_server_t *sc = tls_conf_server_get(cc->server); - apr_status_t rv = APR_ENOENT; - unsigned int vlen, klen; - const unsigned char *kdata; - - if (!sc->global->session_cache) goto not_found; - tls_cache_lock(sc->global); - - kdata = key->data; - klen = (unsigned int)key->len; - vlen = (unsigned int)count; - rv = sc->global->session_cache_provider->retrieve( - sc->global->session_cache, cc->server, kdata, klen, buf, &vlen, c->pool); - - if (APLOGctrace4(c)) { - apr_ssize_t n = klen; - ap_log_cerror(APLOG_MARK, APLOG_TRACE4, rv, c, "retrieve key %d[%8x], found %d val", - klen, apr_hashfunc_default((const char*)kdata, &n), vlen); - } - if (remove_after || (APR_SUCCESS != rv && !APR_STATUS_IS_NOTFOUND(rv))) { - sc->global->session_cache_provider->remove( - sc->global->session_cache, cc->server, key->data, klen, c->pool); - } - - tls_cache_unlock(sc->global); - if (APR_SUCCESS != rv) goto not_found; - cc->session_id_cache_hit = 1; - *out_n = count; - return RUSTLS_RESULT_OK; - -not_found: - *out_n = 0; - return RUSTLS_RESULT_NOT_FOUND; -} - -static rustls_result tls_cache_put( - void *userdata, - const rustls_slice_bytes *key, - const rustls_slice_bytes *val) -{ - conn_rec *c = userdata; - tls_conf_conn_t *cc = tls_conf_conn_get(c); - tls_conf_server_t *sc = tls_conf_server_get(cc->server); - apr_status_t rv = APR_ENOENT; - apr_time_t expires_at; - unsigned int klen, vlen; - const unsigned char *kdata; - - if (!sc->global->session_cache) goto not_stored; - tls_cache_lock(sc->global); - - expires_at = apr_time_now() + apr_time_from_sec(300); - kdata = key->data; - klen = (unsigned int)key->len; - vlen = (unsigned int)val->len; - rv = sc->global->session_cache_provider->store(sc->global->session_cache, cc->server, - kdata, klen, expires_at, - (unsigned char*)val->data, vlen, c->pool); - if (APLOGctrace4(c)) { - ap_log_cerror(APLOG_MARK, APLOG_TRACE4, rv, c, - "stored %d key bytes, with %d val bytes", klen, vlen); - } - tls_cache_unlock(sc->global); - if (APR_SUCCESS != rv) goto not_stored; - return RUSTLS_RESULT_OK; - -not_stored: - return RUSTLS_RESULT_NOT_FOUND; -} - -apr_status_t tls_cache_init_server( - rustls_server_config_builder *builder, server_rec *s) -{ - tls_conf_server_t *sc = tls_conf_server_get(s); - - if (sc && sc->global->session_cache) { - ap_log_error(APLOG_MARK, APLOG_TRACE3, 0, s, "adding session persistence to rustls"); - rustls_server_config_builder_set_persistence( - builder, tls_cache_get, tls_cache_put); - } - return APR_SUCCESS; -} diff --git a/modules/tls/tls_cache.h b/modules/tls/tls_cache.h deleted file mode 100644 index 64ca0778ca..0000000000 --- a/modules/tls/tls_cache.h +++ /dev/null @@ -1,63 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef tls_cache_h -#define tls_cache_h - -/* name of the global session cache mutex, should we need it */ -#define TLS_SESSION_CACHE_MUTEX_TYPE "tls-session-cache" - - -/** - * Set the specification of the session cache to use. The syntax is - * "default|none|<provider_name>(:<arguments>)?" - * - * @param spec the cache specification - * @param gconf the modules global configuration - * @param p pool for permanent allocations - * @param ptemp pool for temporary allocations - * @return NULL on success or an error message - */ -const char *tls_cache_set_specification( - const char *spec, tls_conf_global_t *gconf, apr_pool_t *p, apr_pool_t *ptemp); - -/** - * Setup before configuration runs, announces our potential global mutex. - */ -void tls_cache_pre_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp); - -/** - * Verify the cache settings at the end of the configuration and - * create the default session cache, if not already done. - */ -apr_status_t tls_cache_post_config(apr_pool_t *p, apr_pool_t *ptemp, server_rec *s); - -/** - * Started a new child, make sure that global mutex we might use is set up. - */ -void tls_cache_init_child(apr_pool_t *p, server_rec *s); - -/** - * Free all cache related resources. - */ -void tls_cache_free(server_rec *s); - -/** - * Initialize the session store for the server's config builder. - */ -apr_status_t tls_cache_init_server( - rustls_server_config_builder *builder, server_rec *s); - -#endif /* tls_cache_h */
\ No newline at end of file diff --git a/modules/tls/tls_cert.c b/modules/tls/tls_cert.c deleted file mode 100644 index ffb941cae4..0000000000 --- a/modules/tls/tls_cert.c +++ /dev/null @@ -1,583 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include <assert.h> -#include <apr_lib.h> -#include <apr_encode.h> -#include <apr_strings.h> - -#include <httpd.h> -#include <http_connection.h> -#include <http_core.h> -#include <http_log.h> - -#include <rustls.h> - -#include "tls_cert.h" -#include "tls_util.h" - -extern module AP_MODULE_DECLARE_DATA tls_module; -APLOG_USE_MODULE(tls); - - -apr_status_t tls_cert_load_pem( - apr_pool_t *p, const tls_cert_spec_t *cert, tls_cert_pem_t **ppem) -{ - apr_status_t rv; - const char *fpath; - tls_cert_pem_t *cpem; - - ap_assert(cert->cert_file); - cpem = apr_pcalloc(p, sizeof(*cpem)); - fpath = ap_server_root_relative(p, cert->cert_file); - if (NULL == fpath) { - rv = APR_ENOENT; goto cleanup; - } - rv = tls_util_file_load(p, fpath, 0, 100*1024, &cpem->cert_pem); - if (APR_SUCCESS != rv) goto cleanup; - - if (cert->pkey_file) { - fpath = ap_server_root_relative(p, cert->pkey_file); - if (NULL == fpath) { - rv = APR_ENOENT; goto cleanup; - } - rv = tls_util_file_load(p, fpath, 0, 100*1024, &cpem->pkey_pem); - if (APR_SUCCESS != rv) goto cleanup; - } - else { - cpem->pkey_pem = cpem->cert_pem; - } -cleanup: - *ppem = (APR_SUCCESS == rv)? cpem : NULL; - return rv; -} - -#define PEM_IN_CHUNK 48 /* PEM demands at most 64 chars per line */ - -static apr_status_t tls_der_to_pem( - const char **ppem, apr_pool_t *p, - const unsigned char *der_data, apr_size_t der_len, - const char *header, const char *footer) -{ - apr_status_t rv = APR_SUCCESS; - char *pem = NULL, *s; - apr_size_t b64_len, n, hd_len, ft_len; - apr_ssize_t in_len, i; - - if (der_len > INT_MAX) { - rv = APR_ENOMEM; - goto cleanup; - } - in_len = (apr_ssize_t)der_len; - rv = apr_encode_base64(NULL, (const char*)der_data, in_len, APR_ENCODE_NONE, &b64_len); - if (APR_SUCCESS != rv) goto cleanup; - if (b64_len > INT_MAX) { - rv = APR_ENOMEM; - goto cleanup; - } - hd_len = header? strlen(header) : 0; - ft_len = footer? strlen(footer) : 0; - s = pem = apr_pcalloc(p, - + b64_len + (der_len/PEM_IN_CHUNK) + 1 /* \n per chunk */ - + hd_len +1 + ft_len + 1 /* adding \n */ - + 1); /* NUL-terminated */ - if (header) { - strcpy(s, header); - s += hd_len; - *s++ = '\n'; - } - for (i = 0; in_len > 0; i += PEM_IN_CHUNK, in_len -= PEM_IN_CHUNK) { - rv = apr_encode_base64(s, - (const char*)der_data + i, in_len > PEM_IN_CHUNK? PEM_IN_CHUNK : in_len, - APR_ENCODE_NONE, &n); - s += n; - *s++ = '\n'; - } - if (footer) { - strcpy(s, footer); - s += ft_len; - *s++ = '\n'; - } -cleanup: - *ppem = (APR_SUCCESS == rv)? pem : NULL; - return rv; -} - -#define PEM_CERT_HD "-----BEGIN CERTIFICATE-----" -#define PEM_CERT_FT "-----END CERTIFICATE-----" - -apr_status_t tls_cert_to_pem(const char **ppem, apr_pool_t *p, const rustls_certificate *cert) -{ - const unsigned char* der_data; - size_t der_len; - rustls_result rr = RUSTLS_RESULT_OK; - apr_status_t rv = APR_SUCCESS; - const char *pem = NULL; - - rr = rustls_certificate_get_der(cert, &der_data, &der_len); - if (RUSTLS_RESULT_OK != rr) goto cleanup; - rv = tls_der_to_pem(&pem, p, der_data, der_len, PEM_CERT_HD, PEM_CERT_FT); -cleanup: - if (RUSTLS_RESULT_OK != rr) { - rv = tls_util_rustls_error(p, rr, NULL); - } - *ppem = (APR_SUCCESS == rv)? pem : NULL; - return rv; -} - -static void nullify_key_pem(tls_cert_pem_t *pems) -{ - if (pems->pkey_pem.len) { - memset((void*)pems->pkey_pem.data, 0, pems->pkey_pem.len); - } -} - -static apr_status_t make_certified_key( - apr_pool_t *p, const char *name, - const tls_data_t *cert_pem, const tls_data_t *pkey_pem, - const rustls_certified_key **pckey) -{ - const rustls_certified_key *ckey = NULL; - rustls_result rr = RUSTLS_RESULT_OK; - apr_status_t rv = APR_SUCCESS; - - rr = rustls_certified_key_build( - cert_pem->data, cert_pem->len, - pkey_pem->data, pkey_pem->len, - &ckey); - - if (RUSTLS_RESULT_OK != rr) { - const char *err_descr; - rv = tls_util_rustls_error(p, rr, &err_descr); - ap_log_perror(APLOG_MARK, APLOG_ERR, rv, p, APLOGNO(10363) - "Failed to load certified key %s: [%d] %s", - name, (int)rr, err_descr); - } - if (APR_SUCCESS == rv) { - *pckey = ckey; - } - else if (ckey) { - rustls_certified_key_free(ckey); - } - return rv; -} - -apr_status_t tls_cert_load_cert_key( - apr_pool_t *p, const tls_cert_spec_t *spec, - const char **pcert_pem, const rustls_certified_key **pckey) -{ - apr_status_t rv = APR_SUCCESS; - - if (spec->cert_file) { - tls_cert_pem_t *pems; - - rv = tls_cert_load_pem(p, spec, &pems); - if (APR_SUCCESS != rv) goto cleanup; - if (pcert_pem) *pcert_pem = tls_data_to_str(p, &pems->cert_pem); - rv = make_certified_key(p, spec->cert_file, &pems->cert_pem, &pems->pkey_pem, pckey); - /* dont want them hanging around in memory unnecessarily. */ - nullify_key_pem(pems); - } - else if (spec->cert_pem) { - tls_data_t pkey_pem, pem; - pem = tls_data_from_str(spec->cert_pem); - if (spec->pkey_pem) { - pkey_pem = tls_data_from_str(spec->pkey_pem); - } - else { - pkey_pem = pem; - } - if (pcert_pem) *pcert_pem = spec->cert_pem; - rv = make_certified_key(p, "memory", &pem, &pkey_pem, pckey); - /* pems provided from outside are responsibility of the caller */ - } - else { - rv = APR_ENOENT; goto cleanup; - } -cleanup: - return rv; -} - -typedef struct { - const char *id; - const char *cert_pem; - server_rec *server; - const rustls_certified_key *certified_key; -} tls_cert_reg_entry_t; - -static int reg_entry_cleanup(void *ctx, const void *key, apr_ssize_t klen, const void *val) -{ - tls_cert_reg_entry_t *entry = (tls_cert_reg_entry_t*)val; - (void)ctx; (void)key; (void)klen; - if (entry->certified_key) { - rustls_certified_key_free(entry->certified_key); - entry->certified_key = NULL; - } - return 1; -} - -static apr_status_t reg_cleanup(void *data) -{ - tls_cert_reg_t *reg = data; - if (reg->id2entry) { - apr_hash_do(reg_entry_cleanup, reg, reg->id2entry); - apr_hash_clear(reg->id2entry); - if (reg->key2entry) apr_hash_clear(reg->key2entry); - } - return APR_SUCCESS; -} - -tls_cert_reg_t *tls_cert_reg_make(apr_pool_t *p) -{ - tls_cert_reg_t *reg; - - reg = apr_pcalloc(p, sizeof(*reg)); - reg->pool = p; - reg->id2entry = apr_hash_make(p); - reg->key2entry = apr_hash_make(p); - apr_pool_cleanup_register(p, reg, reg_cleanup, apr_pool_cleanup_null); - return reg; -} - -apr_size_t tls_cert_reg_count(tls_cert_reg_t *reg) -{ - return apr_hash_count(reg->id2entry); -} - -static const char *cert_spec_to_id(const tls_cert_spec_t *spec) -{ - if (spec->cert_file) return spec->cert_file; - if (spec->cert_pem) return spec->cert_pem; - return NULL; -} - -apr_status_t tls_cert_reg_get_certified_key( - tls_cert_reg_t *reg, server_rec *s, const tls_cert_spec_t *spec, - const rustls_certified_key **pckey) -{ - apr_status_t rv = APR_SUCCESS; - const char *id; - tls_cert_reg_entry_t *entry; - - id = cert_spec_to_id(spec); - assert(id); - entry = apr_hash_get(reg->id2entry, id, APR_HASH_KEY_STRING); - if (!entry) { - const rustls_certified_key *certified_key; - const char *cert_pem; - rv = tls_cert_load_cert_key(reg->pool, spec, &cert_pem, &certified_key); - if (APR_SUCCESS != rv) goto cleanup; - entry = apr_pcalloc(reg->pool, sizeof(*entry)); - entry->id = apr_pstrdup(reg->pool, id); - entry->cert_pem = cert_pem; - entry->server = s; - entry->certified_key = certified_key; - apr_hash_set(reg->id2entry, entry->id, APR_HASH_KEY_STRING, entry); - /* associates the pointer value */ - apr_hash_set(reg->key2entry, &entry->certified_key, sizeof(entry->certified_key), entry); - } - -cleanup: - if (APR_SUCCESS == rv) { - *pckey = entry->certified_key; - } - else { - *pckey = NULL; - } - return rv; -} - -typedef struct { - void *userdata; - tls_cert_reg_visitor *visitor; -} reg_visit_ctx_t; - -static int reg_visit(void *vctx, const void *key, apr_ssize_t klen, const void *val) -{ - reg_visit_ctx_t *ctx = vctx; - tls_cert_reg_entry_t *entry = (tls_cert_reg_entry_t*)val; - - (void)key; (void)klen; - return ctx->visitor(ctx->userdata, entry->server, entry->id, entry->cert_pem, entry->certified_key); -} - -void tls_cert_reg_do( - tls_cert_reg_visitor *visitor, void *userdata, tls_cert_reg_t *reg) -{ - reg_visit_ctx_t ctx; - ctx.visitor = visitor; - ctx.userdata = userdata; - apr_hash_do(reg_visit, &ctx, reg->id2entry); -} - -const char *tls_cert_reg_get_id(tls_cert_reg_t *reg, const rustls_certified_key *certified_key) -{ - tls_cert_reg_entry_t *entry; - - entry = apr_hash_get(reg->key2entry, &certified_key, sizeof(certified_key)); - return entry? entry->id : NULL; -} - -apr_status_t tls_cert_load_root_store( - apr_pool_t *p, const char *store_file, const rustls_root_cert_store **pstore) -{ - const char *fpath; - tls_data_t pem; - rustls_root_cert_store_builder *store_builder = NULL; - const rustls_root_cert_store *store = NULL; - rustls_result rr = RUSTLS_RESULT_OK; - apr_pool_t *ptemp = NULL; - apr_status_t rv; - - ap_assert(store_file); - - rv = apr_pool_create(&ptemp, p); - if (APR_SUCCESS != rv) goto cleanup; - apr_pool_tag(ptemp, "tls_load_root_cert_store"); - fpath = ap_server_root_relative(ptemp, store_file); - if (NULL == fpath) { - rv = APR_ENOENT; goto cleanup; - } - /* we use this for client auth CAs. 1MB seems large enough. */ - rv = tls_util_file_load(ptemp, fpath, 0, 1024*1024, &pem); - if (APR_SUCCESS != rv) goto cleanup; - - store_builder = rustls_root_cert_store_builder_new(); - rr = rustls_root_cert_store_builder_add_pem(store_builder, pem.data, pem.len, 1); - if (RUSTLS_RESULT_OK != rr) goto cleanup; - - rr = rustls_root_cert_store_builder_build(store_builder, &store); - if (RUSTLS_RESULT_OK != rr) goto cleanup; - -cleanup: - if (store_builder != NULL) { - rustls_root_cert_store_builder_free(store_builder); - } - if (RUSTLS_RESULT_OK != rr) { - const char *err_descr; - rv = tls_util_rustls_error(p, rr, &err_descr); - ap_log_perror(APLOG_MARK, APLOG_ERR, rv, p, APLOGNO(10364) - "Failed to load root store %s: [%d] %s", - store_file, (int)rr, err_descr); - } - if (APR_SUCCESS == rv) { - *pstore = store; - } - else { - *pstore = NULL; - if (store) rustls_root_cert_store_free(store); - } - if (ptemp) apr_pool_destroy(ptemp); - return rv; -} - -typedef struct { - const char *id; - const rustls_root_cert_store *store; -} tls_cert_root_stores_entry_t; - -static int stores_entry_cleanup(void *ctx, const void *key, apr_ssize_t klen, const void *val) -{ - tls_cert_root_stores_entry_t *entry = (tls_cert_root_stores_entry_t*)val; - (void)ctx; (void)key; (void)klen; - if (entry->store) { - rustls_root_cert_store_free(entry->store); - entry->store = NULL; - } - return 1; -} - -static apr_status_t stores_cleanup(void *data) -{ - tls_cert_root_stores_t *stores = data; - tls_cert_root_stores_clear(stores); - return APR_SUCCESS; -} - -tls_cert_root_stores_t *tls_cert_root_stores_make(apr_pool_t *p) -{ - tls_cert_root_stores_t *stores; - - stores = apr_pcalloc(p, sizeof(*stores)); - stores->pool = p; - stores->file2store = apr_hash_make(p); - apr_pool_cleanup_register(p, stores, stores_cleanup, apr_pool_cleanup_null); - return stores; -} - -void tls_cert_root_stores_clear(tls_cert_root_stores_t *stores) -{ - if (stores->file2store) { - apr_hash_do(stores_entry_cleanup, stores, stores->file2store); - apr_hash_clear(stores->file2store); - } -} - -apr_status_t tls_cert_root_stores_get( - tls_cert_root_stores_t *stores, - const char *store_file, - const rustls_root_cert_store **pstore) -{ - apr_status_t rv = APR_SUCCESS; - tls_cert_root_stores_entry_t *entry; - - entry = apr_hash_get(stores->file2store, store_file, APR_HASH_KEY_STRING); - if (!entry) { - const rustls_root_cert_store *store; - rv = tls_cert_load_root_store(stores->pool, store_file, &store); - if (APR_SUCCESS != rv) goto cleanup; - entry = apr_pcalloc(stores->pool, sizeof(*entry)); - entry->id = apr_pstrdup(stores->pool, store_file); - entry->store = store; - apr_hash_set(stores->file2store, entry->id, APR_HASH_KEY_STRING, entry); - } - -cleanup: - if (APR_SUCCESS == rv) { - *pstore = entry->store; - } - else { - *pstore = NULL; - } - return rv; -} - -typedef struct { - const char *id; - rustls_client_cert_verifier *client_verifier; - rustls_client_cert_verifier *client_verifier_opt; -} tls_cert_verifiers_entry_t; - -static int verifiers_entry_cleanup(void *ctx, const void *key, apr_ssize_t klen, const void *val) -{ - tls_cert_verifiers_entry_t *entry = (tls_cert_verifiers_entry_t*)val; - (void)ctx; (void)key; (void)klen; - if (entry->client_verifier) { - rustls_client_cert_verifier_free(entry->client_verifier); - entry->client_verifier = NULL; - } - if (entry->client_verifier_opt) { - rustls_client_cert_verifier_free(entry->client_verifier_opt); - entry->client_verifier_opt = NULL; - } - return 1; -} - -static apr_status_t verifiers_cleanup(void *data) -{ - tls_cert_verifiers_t *verifiers = data; - tls_cert_verifiers_clear(verifiers); - return APR_SUCCESS; -} - -tls_cert_verifiers_t *tls_cert_verifiers_make( - apr_pool_t *p, tls_cert_root_stores_t *stores) -{ - tls_cert_verifiers_t *verifiers; - - verifiers = apr_pcalloc(p, sizeof(*verifiers)); - verifiers->pool = p; - verifiers->stores = stores; - verifiers->file2verifier = apr_hash_make(p); - apr_pool_cleanup_register(p, verifiers, verifiers_cleanup, apr_pool_cleanup_null); - return verifiers; -} - -void tls_cert_verifiers_clear(tls_cert_verifiers_t *verifiers) -{ - if (verifiers->file2verifier) { - apr_hash_do(verifiers_entry_cleanup, verifiers, verifiers->file2verifier); - apr_hash_clear(verifiers->file2verifier); - } -} - -static tls_cert_verifiers_entry_t * verifiers_get_or_make_entry( - tls_cert_verifiers_t *verifiers, - const char *store_file) -{ - tls_cert_verifiers_entry_t *entry; - - entry = apr_hash_get(verifiers->file2verifier, store_file, APR_HASH_KEY_STRING); - if (!entry) { - entry = apr_pcalloc(verifiers->pool, sizeof(*entry)); - entry->id = apr_pstrdup(verifiers->pool, store_file); - apr_hash_set(verifiers->file2verifier, entry->id, APR_HASH_KEY_STRING, entry); - } - return entry; -} - -static apr_status_t tls_cert_client_verifiers_get_internal( - tls_cert_verifiers_t *verifiers, - const char *store_file, - const rustls_client_cert_verifier **pverifier, - bool allow_unauthenticated) -{ - apr_status_t rv = APR_SUCCESS; - tls_cert_verifiers_entry_t *entry; - rustls_result rr = RUSTLS_RESULT_OK; - struct rustls_web_pki_client_cert_verifier_builder *verifier_builder = NULL; - - entry = verifiers_get_or_make_entry(verifiers, store_file); - if (!entry->client_verifier) { - const rustls_root_cert_store *store; - rv = tls_cert_root_stores_get(verifiers->stores, store_file, &store); - if (APR_SUCCESS != rv) goto cleanup; - verifier_builder = rustls_web_pki_client_cert_verifier_builder_new(store); - - if (allow_unauthenticated) { - rr = rustls_web_pki_client_cert_verifier_builder_allow_unauthenticated(verifier_builder); - if (rr != RUSTLS_RESULT_OK) { - goto cleanup; - } - } - - rr = rustls_web_pki_client_cert_verifier_builder_build(verifier_builder, &entry->client_verifier); - if (rr != RUSTLS_RESULT_OK) { - goto cleanup; - } - } - -cleanup: - if (verifier_builder != NULL) { - rustls_web_pki_client_cert_verifier_builder_free(verifier_builder); - } - if (rr != RUSTLS_RESULT_OK) { - rv = tls_util_rustls_error(verifiers->pool, rr, NULL); - } - if (APR_SUCCESS == rv) { - *pverifier = entry->client_verifier; - } - else { - *pverifier = NULL; - } - return rv; -} - - -apr_status_t tls_cert_client_verifiers_get( - tls_cert_verifiers_t *verifiers, - const char *store_file, - const rustls_client_cert_verifier **pverifier) -{ - return tls_cert_client_verifiers_get_internal(verifiers, store_file, pverifier, false); -} - -apr_status_t tls_cert_client_verifiers_get_optional( - tls_cert_verifiers_t *verifiers, - const char *store_file, - const rustls_client_cert_verifier **pverifier) -{ - return tls_cert_client_verifiers_get_internal(verifiers, store_file, pverifier, true); -} diff --git a/modules/tls/tls_cert.h b/modules/tls/tls_cert.h deleted file mode 100644 index 3326f0eb3e..0000000000 --- a/modules/tls/tls_cert.h +++ /dev/null @@ -1,211 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef tls_cert_h -#define tls_cert_h - -#include "tls_util.h" - -/** - * The PEM data of a certificate and its key. - */ -typedef struct { - tls_data_t cert_pem; - tls_data_t pkey_pem; -} tls_cert_pem_t; - -/** - * Specify a certificate via files or PEM data. - */ -typedef struct { - const char *cert_file; /* file path, relative to ap_root */ - const char *pkey_file; /* file path, relative to ap_root */ - const char *cert_pem; /* NUL-terminated PEM string */ - const char *pkey_pem; /* NUL-terminated PEM string */ -} tls_cert_spec_t; - -/** - * Load the PEM data for a certificate file and key file as given in `cert`. - */ -apr_status_t tls_cert_load_pem( - apr_pool_t *p, const tls_cert_spec_t *cert, tls_cert_pem_t **ppem); - -apr_status_t tls_cert_to_pem(const char **ppem, apr_pool_t *p, const rustls_certificate *cert); - -/** - * Load a rustls certified key from a certificate specification. - * The returned `rustls_certified_key` is owned by the caller. - * @param p the memory pool to use - * @param spec the specification for the certificate (file or PEM data) - * @param cert_pem return the PEM data used for loading the certificates, optional - * @param pckey the loaded certified key on return - */ -apr_status_t tls_cert_load_cert_key( - apr_pool_t *p, const tls_cert_spec_t *spec, - const char **pcert_pem, const rustls_certified_key **pckey); - -/** - * A registry of rustls_certified_key* by identifier. - */ -typedef struct tls_cert_reg_t tls_cert_reg_t; -struct tls_cert_reg_t{ - apr_pool_t *pool; - apr_hash_t *id2entry; - apr_hash_t *key2entry; -}; - -/** - * Create a new registry with lifetime based on the memory pool. - * The registry will take care of its memory and allocated keys when - * the pool is destroyed. - */ -tls_cert_reg_t *tls_cert_reg_make(apr_pool_t *p); - -/** - * Return the number of certified keys in the registry. - */ -apr_size_t tls_cert_reg_count(tls_cert_reg_t *reg); - -/** - * Get a the `rustls_certified_key` identified by `spec` from the registry. - * This will load the key the first time it is requested. - * The returned `rustls_certified_key` is owned by the registry. - * @param reg the certified key registry - * @param s the server_rec this is loaded into, useful for error logging - * @param spec the specification of the certified key - * @param pckey the certified key instance on return - */ -apr_status_t tls_cert_reg_get_certified_key( - tls_cert_reg_t *reg, server_rec *s, const tls_cert_spec_t *spec, const rustls_certified_key **pckey); - -/** - * Visit all certified keys in the registry. - * The callback may return 0 to abort the iteration. - * @param userdata supplied by the visit invocation - * @param s the server_rec the certified was load into first - * @param id internal identifier of the certified key - * @param cert_pem the PEM data of the certificate and its chain - * @param certified_key the key instance itself - */ -typedef int tls_cert_reg_visitor( - void *userdata, server_rec *s, - const char *id, const char *cert_pem, const rustls_certified_key *certified_key); - -/** - * Visit all certified_key entries in the registry. - * @param visitor callback invoked on each entry until it returns 0. - * @param userdata passed to callback - * @param reg the registry to iterate over - */ -void tls_cert_reg_do( - tls_cert_reg_visitor *visitor, void *userdata, tls_cert_reg_t *reg); - -/** - * Get the identity assigned to a loaded, certified key. Returns NULL, if the - * key is not part of the registry. The returned bytes are owned by the registry - * entry. - * @param reg the registry to look in. - * @param certified_key the key to get the identifier for - */ -const char *tls_cert_reg_get_id(tls_cert_reg_t *reg, const rustls_certified_key *certified_key); - -/** - * Load all root certificates from a PEM file into a rustls_root_cert_store. - * @param p the memory pool to use - * @param store_file the (server relative) path of the PEM file - * @param pstore the loaded root store on success - */ -apr_status_t tls_cert_load_root_store( - apr_pool_t *p, const char *store_file, const rustls_root_cert_store **pstore); - -typedef struct tls_cert_root_stores_t tls_cert_root_stores_t; -struct tls_cert_root_stores_t { - apr_pool_t *pool; - apr_hash_t *file2store; -}; - -/** - * Create a new root stores registry with lifetime based on the memory pool. - * The registry will take care of its memory and allocated stores when - * the pool is destroyed. - */ -tls_cert_root_stores_t *tls_cert_root_stores_make(apr_pool_t *p); - -/** - * Clear the root stores registry, freeing all stores. - */ -void tls_cert_root_stores_clear(tls_cert_root_stores_t *stores); - -/** - * Load all root certificates from a PEM file into a rustls_root_cert_store. - * @param p the memory pool to use - * @param store_file the (server relative) path of the PEM file - * @param pstore the loaded root store on success - */ -apr_status_t tls_cert_root_stores_get( - tls_cert_root_stores_t *stores, - const char *store_file, - const rustls_root_cert_store **pstore); - -typedef struct tls_cert_verifiers_t tls_cert_verifiers_t; -struct tls_cert_verifiers_t { - apr_pool_t *pool; - tls_cert_root_stores_t *stores; - apr_hash_t *file2verifier; -}; - -/** - * Create a new registry for certificate verifiers with lifetime based on the memory pool. - * The registry will take care of its memory and allocated verifiers when - * the pool is destroyed. - * @param p the memory pool to use - * @param stores the store registry for lookups - */ -tls_cert_verifiers_t *tls_cert_verifiers_make( - apr_pool_t *p, tls_cert_root_stores_t *stores); - -/** - * Clear the verifiers registry, freeing all verifiers. - */ -void tls_cert_verifiers_clear( - tls_cert_verifiers_t *verifiers); - -/** - * Get the mandatory client certificate verifier for the - * root certificate store in `store_file`. Will create - * the verifier if not already known. - * @param verifiers the registry of certificate verifiers - * @param store_file the (server relative) path of the PEM file with certificates - * @param pverifiers the verifier on success - */ -apr_status_t tls_cert_client_verifiers_get( - tls_cert_verifiers_t *verifiers, - const char *store_file, - const rustls_client_cert_verifier **pverifier); - -/** - * Get the optional client certificate verifier for the - * root certificate store in `store_file`. Will create - * the verifier if not already known. - * @param verifiers the registry of certificate verifiers - * @param store_file the (server relative) path of the PEM file with certificates - * @param pverifiers the verifier on success - */ -apr_status_t tls_cert_client_verifiers_get_optional( - tls_cert_verifiers_t *verifiers, - const char *store_file, - const rustls_client_cert_verifier **pverifier); - -#endif /* tls_cert_h */ diff --git a/modules/tls/tls_conf.c b/modules/tls/tls_conf.c deleted file mode 100644 index a9f27de87a..0000000000 --- a/modules/tls/tls_conf.c +++ /dev/null @@ -1,780 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include <assert.h> -#include <apr_lib.h> -#include <apr_strings.h> -#include <apr_version.h> - -#include <httpd.h> -#include <http_core.h> -#include <http_config.h> -#include <http_log.h> -#include <http_main.h> -#include <ap_socache.h> - -#include <rustls.h> - -#include "tls_cert.h" -#include "tls_proto.h" -#include "tls_conf.h" -#include "tls_util.h" -#include "tls_var.h" -#include "tls_cache.h" - - -extern module AP_MODULE_DECLARE_DATA tls_module; -APLOG_USE_MODULE(tls); - -static tls_conf_global_t *conf_global_get_or_make(apr_pool_t *pool, server_rec *s) -{ - tls_conf_global_t *gconf; - - /* we create this only once for apache's one ap_server_conf. - * If this gets called for another server, we should already have - * done it for ap_server_conf. */ - if (ap_server_conf && s != ap_server_conf) { - tls_conf_server_t *sconf = tls_conf_server_get(ap_server_conf); - ap_assert(sconf); - ap_assert(sconf->global); - return sconf->global; - } - - gconf = apr_pcalloc(pool, sizeof(*gconf)); - gconf->ap_server = ap_server_conf; - gconf->status = TLS_CONF_ST_INIT; - gconf->proto = tls_proto_init(pool, s); - gconf->proxy_configs = apr_array_make(pool, 10, sizeof(tls_conf_proxy_t*)); - - gconf->var_lookups = apr_hash_make(pool); - tls_var_init_lookup_hash(pool, gconf->var_lookups); - gconf->session_cache_spec = "default"; - - return gconf; -} - -tls_conf_server_t *tls_conf_server_get(server_rec *s) -{ - tls_conf_server_t *sc = ap_get_module_config(s->module_config, &tls_module); - ap_assert(sc); - return sc; -} - - -#define CONF_S_NAME(s) (s && s->server_hostname? s->server_hostname : "default") - -void *tls_conf_create_svr(apr_pool_t *pool, server_rec *s) -{ - tls_conf_server_t *conf; - - conf = apr_pcalloc(pool, sizeof(*conf)); - conf->global = conf_global_get_or_make(pool, s); - conf->server = s; - - conf->enabled = TLS_FLAG_UNSET; - conf->cert_specs = apr_array_make(pool, 3, sizeof(tls_cert_spec_t*)); - conf->honor_client_order = TLS_FLAG_UNSET; - conf->strict_sni = TLS_FLAG_UNSET; - conf->tls_protocol_min = TLS_FLAG_UNSET; - conf->tls_pref_ciphers = apr_array_make(pool, 3, sizeof(apr_uint16_t));; - conf->tls_supp_ciphers = apr_array_make(pool, 3, sizeof(apr_uint16_t));; - return conf; -} - -#define MERGE_INT(base, add, field) \ - (add->field == TLS_FLAG_UNSET)? base->field : add->field; - -void *tls_conf_merge_svr(apr_pool_t *pool, void *basev, void *addv) -{ - tls_conf_server_t *base = basev; - tls_conf_server_t *add = addv; - tls_conf_server_t *nconf; - - nconf = apr_pcalloc(pool, sizeof(*nconf)); - nconf->server = add->server; - nconf->global = add->global? add->global : base->global; - - nconf->enabled = MERGE_INT(base, add, enabled); - nconf->cert_specs = apr_array_append(pool, base->cert_specs, add->cert_specs); - nconf->tls_protocol_min = MERGE_INT(base, add, tls_protocol_min); - nconf->tls_pref_ciphers = add->tls_pref_ciphers->nelts? - add->tls_pref_ciphers : base->tls_pref_ciphers; - nconf->tls_supp_ciphers = add->tls_supp_ciphers->nelts? - add->tls_supp_ciphers : base->tls_supp_ciphers; - nconf->honor_client_order = MERGE_INT(base, add, honor_client_order); - nconf->client_ca = add->client_ca? add->client_ca : base->client_ca; - nconf->client_auth = (add->client_auth != TLS_CLIENT_AUTH_UNSET)? - add->client_auth : base->client_auth; - nconf->var_user_name = add->var_user_name? add->var_user_name : base->var_user_name; - return nconf; -} - -tls_conf_dir_t *tls_conf_dir_get(request_rec *r) -{ - tls_conf_dir_t *dc = ap_get_module_config(r->per_dir_config, &tls_module); - ap_assert(dc); - return dc; -} - -tls_conf_dir_t *tls_conf_dir_server_get(server_rec *s) -{ - tls_conf_dir_t *dc = ap_get_module_config(s->lookup_defaults, &tls_module); - ap_assert(dc); - return dc; -} - -void *tls_conf_create_dir(apr_pool_t *pool, char *dir) -{ - tls_conf_dir_t *conf; - - (void)dir; - conf = apr_pcalloc(pool, sizeof(*conf)); - conf->std_env_vars = TLS_FLAG_UNSET; - conf->proxy_enabled = TLS_FLAG_UNSET; - conf->proxy_protocol_min = TLS_FLAG_UNSET; - conf->proxy_pref_ciphers = apr_array_make(pool, 3, sizeof(apr_uint16_t));; - conf->proxy_supp_ciphers = apr_array_make(pool, 3, sizeof(apr_uint16_t));; - conf->proxy_machine_cert_specs = apr_array_make(pool, 3, sizeof(tls_cert_spec_t*)); - return conf; -} - - -static int same_proxy_settings(tls_conf_dir_t *a, tls_conf_dir_t *b) -{ - return a->proxy_ca == b->proxy_ca; -} - -static void dir_assign_merge( - tls_conf_dir_t *dest, apr_pool_t *pool, tls_conf_dir_t *base, tls_conf_dir_t *add) -{ - tls_conf_dir_t local; - - memset(&local, 0, sizeof(local)); - local.std_env_vars = MERGE_INT(base, add, std_env_vars); - local.export_cert_vars = MERGE_INT(base, add, export_cert_vars); - local.proxy_enabled = MERGE_INT(base, add, proxy_enabled); - local.proxy_ca = add->proxy_ca? add->proxy_ca : base->proxy_ca; - local.proxy_protocol_min = MERGE_INT(base, add, proxy_protocol_min); - local.proxy_pref_ciphers = add->proxy_pref_ciphers->nelts? - add->proxy_pref_ciphers : base->proxy_pref_ciphers; - local.proxy_supp_ciphers = add->proxy_supp_ciphers->nelts? - add->proxy_supp_ciphers : base->proxy_supp_ciphers; - local.proxy_machine_cert_specs = apr_array_append(pool, - base->proxy_machine_cert_specs, add->proxy_machine_cert_specs); - if (local.proxy_enabled == TLS_FLAG_TRUE) { - if (add->proxy_config) { - local.proxy_config = same_proxy_settings(&local, add)? add->proxy_config : NULL; - } - else if (base->proxy_config) { - local.proxy_config = same_proxy_settings(&local, base)? add->proxy_config : NULL; - } - } - memcpy(dest, &local, sizeof(*dest)); -} - -void *tls_conf_merge_dir(apr_pool_t *pool, void *basev, void *addv) -{ - tls_conf_dir_t *base = basev; - tls_conf_dir_t *add = addv; - tls_conf_dir_t *nconf = apr_pcalloc(pool, sizeof(*nconf)); - dir_assign_merge(nconf, pool, base, add); - return nconf; -} - -static void tls_conf_dir_set_options_defaults(apr_pool_t *pool, tls_conf_dir_t *dc) -{ - (void)pool; - dc->std_env_vars = TLS_FLAG_FALSE; - dc->export_cert_vars = TLS_FLAG_FALSE; -} - -apr_status_t tls_conf_server_apply_defaults(tls_conf_server_t *sc, apr_pool_t *p) -{ - (void)p; - if (sc->enabled == TLS_FLAG_UNSET) sc->enabled = TLS_FLAG_FALSE; - if (sc->tls_protocol_min == TLS_FLAG_UNSET) sc->tls_protocol_min = 0; - if (sc->honor_client_order == TLS_FLAG_UNSET) sc->honor_client_order = TLS_FLAG_TRUE; - if (sc->strict_sni == TLS_FLAG_UNSET) sc->strict_sni = TLS_FLAG_TRUE; - if (sc->client_auth == TLS_CLIENT_AUTH_UNSET) sc->client_auth = TLS_CLIENT_AUTH_NONE; - return APR_SUCCESS; -} - -apr_status_t tls_conf_dir_apply_defaults(tls_conf_dir_t *dc, apr_pool_t *p) -{ - (void)p; - if (dc->std_env_vars == TLS_FLAG_UNSET) dc->std_env_vars = TLS_FLAG_FALSE; - if (dc->export_cert_vars == TLS_FLAG_UNSET) dc->export_cert_vars = TLS_FLAG_FALSE; - if (dc->proxy_enabled == TLS_FLAG_UNSET) dc->proxy_enabled = TLS_FLAG_FALSE; - return APR_SUCCESS; -} - -tls_conf_proxy_t *tls_conf_proxy_make( - apr_pool_t *p, tls_conf_dir_t *dc, tls_conf_global_t *gc, server_rec *s) -{ - tls_conf_proxy_t *pc = apr_pcalloc(p, sizeof(*pc)); - pc->defined_in = s; - pc->global = gc; - pc->proxy_ca = dc->proxy_ca; - pc->proxy_protocol_min = dc->proxy_protocol_min; - pc->proxy_pref_ciphers = dc->proxy_pref_ciphers; - pc->proxy_supp_ciphers = dc->proxy_supp_ciphers; - pc->machine_cert_specs = dc->proxy_machine_cert_specs; - pc->machine_certified_keys = apr_array_make(p, 3, sizeof(const rustls_certified_key*)); - return pc; -} - -int tls_proxy_section_post_config( - apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s, - ap_conf_vector_t *section_config) -{ - tls_conf_dir_t *proxy_dc, *server_dc; - tls_conf_server_t *sc; - - /* mod_proxy collects the <Proxy>...</Proxy> sections per server (base server or virtualhost) - * and in its post_config hook, calls our function registered at its hook for each with - * s - the server they were define in - * section_config - the set of dir_configs for a <Proxy> section - * - * If none of _our_ config directives had been used, here or in the server, we get a NULL. - * Which means we have to do nothing. Otherwise, we add to `proxy_dc` the - * settings from `server_dc` - since this is not automagically done by apache. - * - * `proxy_dc` is then complete and tells us if we handle outgoing connections - * here and with what parameter settings. - */ - (void)ptemp; (void)plog; - ap_log_error(APLOG_MARK, APLOG_TRACE3, 0, s, - "%s: tls_proxy_section_post_config called", s->server_hostname); - proxy_dc = ap_get_module_config(section_config, &tls_module); - if (!proxy_dc) goto cleanup; - server_dc = ap_get_module_config(s->lookup_defaults, &tls_module); - ap_assert(server_dc); - dir_assign_merge(proxy_dc, p, server_dc, proxy_dc); - tls_conf_dir_apply_defaults(proxy_dc, p); - if (proxy_dc->proxy_enabled && !proxy_dc->proxy_config) { - /* remember `proxy_dc` for subsequent configuration of outoing TLS setups */ - sc = tls_conf_server_get(s); - proxy_dc->proxy_config = tls_conf_proxy_make(p, proxy_dc, sc->global, s); - ap_log_error(APLOG_MARK, APLOG_TRACE3, 0, s, - "%s: adding proxy_conf to globals in proxy_post_config_section", - s->server_hostname); - APR_ARRAY_PUSH(sc->global->proxy_configs, tls_conf_proxy_t*) = proxy_dc->proxy_config; - } -cleanup: - return OK; -} - -static const char *cmd_check_file(cmd_parms *cmd, const char *fpath) -{ - char *real_path; - - /* just a dump of the configuration, dont resolve/check */ - if (ap_state_query(AP_SQ_RUN_MODE) == AP_SQ_RM_CONFIG_DUMP) { - return NULL; - } - real_path = ap_server_root_relative(cmd->pool, fpath); - if (!real_path) { - return apr_pstrcat(cmd->pool, cmd->cmd->name, - ": Invalid file path ", fpath, NULL); - } - if (!tls_util_is_file(cmd->pool, real_path)) { - return apr_pstrcat(cmd->pool, cmd->cmd->name, - ": file '", real_path, - "' does not exist or is empty", NULL); - } - return NULL; -} - -static const char *tls_conf_add_engine(cmd_parms *cmd, void *dc, const char*v) -{ - tls_conf_server_t *sc = tls_conf_server_get(cmd->server); - tls_conf_global_t *gc = sc->global; - const char *err = NULL; - char *host, *scope_id; - apr_port_t port; - apr_sockaddr_t *sa; - server_addr_rec *sar; - apr_status_t rv; - - (void)dc; - /* Example of use: - * TLSEngine 443 - * TLSEngine hostname:443 - * TLSEngine 91.0.0.1:443 - * TLSEngine [::0]:443 - */ - rv = apr_parse_addr_port(&host, &scope_id, &port, v, cmd->pool); - if (APR_SUCCESS != rv) { - err = apr_pstrcat(cmd->pool, cmd->cmd->name, - ": invalid address/port in '", v, "'", NULL); - goto cleanup; - } - - /* translate host/port to a sockaddr that we can match with incoming connections */ - rv = apr_sockaddr_info_get(&sa, host, APR_UNSPEC, port, 0, cmd->pool); - if (APR_SUCCESS != rv) { - err = apr_pstrcat(cmd->pool, cmd->cmd->name, - ": unable to get sockaddr for '", host, "'", NULL); - goto cleanup; - } - - if (scope_id) { -#if APR_VERSION_AT_LEAST(1,7,0) - rv = apr_sockaddr_zone_set(sa, scope_id); - if (APR_SUCCESS != rv) { - err = apr_pstrcat(cmd->pool, cmd->cmd->name, - ": error setting ipv6 scope id: '", scope_id, "'", NULL); - goto cleanup; - } -#else - err = apr_pstrcat(cmd->pool, cmd->cmd->name, - ": IPv6 scopes not supported by your APR: '", scope_id, "'", NULL); - goto cleanup; -#endif - } - - sar = apr_pcalloc(cmd->pool, sizeof(*sar)); - sar->host_addr = sa; - sar->virthost = host; - sar->host_port = port; - - sar->next = gc->tls_addresses; - gc->tls_addresses = sar; -cleanup: - return err; -} - -static int flag_value( - const char *arg) -{ - if (!strcasecmp(arg, "On")) { - return TLS_FLAG_TRUE; - } - else if (!strcasecmp(arg, "Off")) { - return TLS_FLAG_FALSE; - } - return TLS_FLAG_UNSET; -} - -static const char *flag_err( - cmd_parms *cmd, const char *v) -{ - return apr_pstrcat(cmd->pool, cmd->cmd->name, - ": value must be 'On' or 'Off': '", v, "'", NULL); -} - -static const char *tls_conf_add_certificate( - cmd_parms *cmd, void *dc, const char *cert_file, const char *pkey_file) -{ - tls_conf_server_t *sc = tls_conf_server_get(cmd->server); - const char *err = NULL, *fpath; - tls_cert_spec_t *cert; - - (void)dc; - if (NULL != (err = cmd_check_file(cmd, cert_file))) goto cleanup; - /* key file may be NULL, in which case cert_file must contain the key PEM */ - if (pkey_file && NULL != (err = cmd_check_file(cmd, pkey_file))) goto cleanup; - - cert = apr_pcalloc(cmd->pool, sizeof(*cert)); - fpath = ap_server_root_relative(cmd->pool, cert_file); - if (!tls_util_is_file(cmd->pool, fpath)) { - return apr_pstrcat(cmd->pool, cmd->cmd->name, - ": unable to find certificate file: '", fpath, "'", NULL); - } - cert->cert_file = cert_file; - if (pkey_file) { - fpath = ap_server_root_relative(cmd->pool, pkey_file); - if (!tls_util_is_file(cmd->pool, fpath)) { - return apr_pstrcat(cmd->pool, cmd->cmd->name, - ": unable to find certificate key file: '", fpath, "'", NULL); - } - } - cert->pkey_file = pkey_file; - *(const tls_cert_spec_t **)apr_array_push(sc->cert_specs) = cert; - -cleanup: - return err; -} - -static const char *parse_ciphers( - cmd_parms *cmd, - tls_conf_global_t *gc, - const char *nop_name, - int argc, char *const argv[], - apr_array_header_t *ciphers) -{ - apr_array_clear(ciphers); - if (argc > 1 || apr_strnatcasecmp(nop_name, argv[0])) { - apr_uint16_t cipher; - int i; - - for (i = 0; i < argc; ++i) { - char *name, *last = NULL; - const char *value = argv[i]; - - name = apr_strtok(apr_pstrdup(cmd->pool, value), ":", &last); - while (name) { - if (tls_proto_get_cipher_by_name(gc->proto, name, &cipher) != APR_SUCCESS) { - return apr_pstrcat(cmd->pool, cmd->cmd->name, - ": cipher not recognized '", name, "'", NULL); - } - APR_ARRAY_PUSH(ciphers, apr_uint16_t) = cipher; - name = apr_strtok(NULL, ":", &last); - } - } - } - return NULL; -} - -static const char *tls_conf_set_preferred_ciphers( - cmd_parms *cmd, void *dc, int argc, char *const argv[]) -{ - tls_conf_server_t *sc = tls_conf_server_get(cmd->server); - const char *err = NULL; - - (void)dc; - if (!argc) { - err = "specify the TLS ciphers to prefer or 'default' for the rustls default ordering."; - goto cleanup; - } - err = parse_ciphers(cmd, sc->global, "default", argc, argv, sc->tls_pref_ciphers); -cleanup: - return err; -} - -static const char *tls_conf_set_suppressed_ciphers( - cmd_parms *cmd, void *dc, int argc, char *const argv[]) -{ - tls_conf_server_t *sc = tls_conf_server_get(cmd->server); - const char *err = NULL; - - (void)dc; - if (!argc) { - err = "specify the TLS ciphers to never use or 'none'."; - goto cleanup; - } - err = parse_ciphers(cmd, sc->global, "none", argc, argv, sc->tls_supp_ciphers); -cleanup: - return err; -} - -static const char *tls_conf_set_honor_client_order( - cmd_parms *cmd, void *dc, const char *v) -{ - tls_conf_server_t *sc = tls_conf_server_get(cmd->server); - int flag = flag_value(v); - - (void)dc; - if (TLS_FLAG_UNSET == flag) return flag_err(cmd, v); - sc->honor_client_order = flag; - return NULL; -} - -static const char *tls_conf_set_strict_sni( - cmd_parms *cmd, void *dc, const char *v) -{ - tls_conf_server_t *sc = tls_conf_server_get(cmd->server); - int flag = flag_value(v); - - (void)dc; - if (TLS_FLAG_UNSET == flag) return flag_err(cmd, v); - sc->strict_sni = flag; - return NULL; -} - -static const char *get_min_protocol( - cmd_parms *cmd, const char *v, int *pmin) -{ - tls_conf_server_t *sc = tls_conf_server_get(cmd->server); - const char *err = NULL; - - if (!apr_strnatcasecmp("default", v)) { - *pmin = 0; - } - else if (*v && v[strlen(v)-1] == '+') { - char *name = apr_pstrdup(cmd->pool, v); - name[strlen(name)-1] = '\0'; - *pmin = tls_proto_get_version_by_name(sc->global->proto, name); - if (!*pmin) { - err = apr_pstrcat(cmd->pool, cmd->cmd->name, - ": unrecognized protocol version specifier (try TLSv1.2+ or TLSv1.3+): '", v, "'", NULL); - goto cleanup; - } - } - else { - err = apr_pstrcat(cmd->pool, cmd->cmd->name, - ": value must be 'default', 'TLSv1.2+' or 'TLSv1.3+': '", v, "'", NULL); - goto cleanup; - } -cleanup: - return err; -} - -static const char *tls_conf_set_protocol( - cmd_parms *cmd, void *dc, const char *v) -{ - tls_conf_server_t *sc = tls_conf_server_get(cmd->server); - (void)dc; - return get_min_protocol(cmd, v, &sc->tls_protocol_min); -} - -static const char *tls_conf_set_options( - cmd_parms *cmd, void *dcv, int argc, char *const argv[]) -{ - tls_conf_dir_t *dc = dcv; - const char *err = NULL, *option; - int i, val; - - /* Are we only having deltas (+/-) or do we reset the options? */ - for (i = 0; i < argc; ++i) { - if (argv[i][0] != '+' && argv[i][0] != '-') { - tls_conf_dir_set_options_defaults(cmd->pool, dc); - break; - } - } - - for (i = 0; i < argc; ++i) { - option = argv[i]; - if (!apr_strnatcasecmp("Defaults", option)) { - dc->std_env_vars = TLS_FLAG_FALSE; - dc->export_cert_vars = TLS_FLAG_FALSE; - } - else { - val = TLS_FLAG_TRUE; - if (*option == '+' || *option == '-') { - val = (*option == '+')? TLS_FLAG_TRUE : TLS_FLAG_FALSE; - ++option; - } - - if (!apr_strnatcasecmp("StdEnvVars", option)) { - dc->std_env_vars = val; - } - else if (!apr_strnatcasecmp("ExportCertData", option)) { - dc->export_cert_vars = val; - } - else { - err = apr_pstrcat(cmd->pool, cmd->cmd->name, - ": unknown option '", option, "'", NULL); - goto cleanup; - } - } - } -cleanup: - return err; -} - -static const char *tls_conf_set_session_cache( - cmd_parms *cmd, void *dc, const char *value) -{ - tls_conf_server_t *sc = tls_conf_server_get(cmd->server); - const char *err = NULL; - - (void)dc; - if ((err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) goto cleanup; - - err = tls_cache_set_specification(value, sc->global, cmd->pool, cmd->temp_pool); -cleanup: - return err; -} - -static const char *tls_conf_set_proxy_engine(cmd_parms *cmd, void *dir_conf, int flag) -{ - tls_conf_dir_t *dc = dir_conf; - (void)cmd; - dc->proxy_enabled = flag ? TLS_FLAG_TRUE : TLS_FLAG_FALSE; - return NULL; -} - -static const char *tls_conf_set_proxy_ca( - cmd_parms *cmd, void *dir_conf, const char *proxy_ca) -{ - tls_conf_dir_t *dc = dir_conf; - const char *err = NULL; - - if (strcasecmp(proxy_ca, "default") && NULL != (err = cmd_check_file(cmd, proxy_ca))) goto cleanup; - dc->proxy_ca = proxy_ca; -cleanup: - return err; -} - -static const char *tls_conf_set_proxy_protocol( - cmd_parms *cmd, void *dir_conf, const char *v) -{ - tls_conf_dir_t *dc = dir_conf; - return get_min_protocol(cmd, v, &dc->proxy_protocol_min); -} - -static const char *tls_conf_set_proxy_preferred_ciphers( - cmd_parms *cmd, void *dir_conf, int argc, char *const argv[]) -{ - tls_conf_server_t *sc = tls_conf_server_get(cmd->server); - tls_conf_dir_t *dc = dir_conf; - const char *err = NULL; - - if (!argc) { - err = "specify the proxy TLS ciphers to prefer or 'default' for the rustls default ordering."; - goto cleanup; - } - err = parse_ciphers(cmd, sc->global, "default", argc, argv, dc->proxy_pref_ciphers); -cleanup: - return err; -} - -static const char *tls_conf_set_proxy_suppressed_ciphers( - cmd_parms *cmd, void *dir_conf, int argc, char *const argv[]) -{ - tls_conf_server_t *sc = tls_conf_server_get(cmd->server); - tls_conf_dir_t *dc = dir_conf; - const char *err = NULL; - - if (!argc) { - err = "specify the proxy TLS ciphers to never use or 'none'."; - goto cleanup; - } - err = parse_ciphers(cmd, sc->global, "none", argc, argv, dc->proxy_supp_ciphers); -cleanup: - return err; -} - -#if TLS_CLIENT_CERTS - -static const char *tls_conf_set_client_ca( - cmd_parms *cmd, void *dc, const char *client_ca) -{ - tls_conf_server_t *sc = tls_conf_server_get(cmd->server); - const char *err; - - (void)dc; - if (NULL != (err = cmd_check_file(cmd, client_ca))) goto cleanup; - sc->client_ca = client_ca; -cleanup: - return err; -} - -static const char *tls_conf_set_client_auth( - cmd_parms *cmd, void *dc, const char *mode) -{ - tls_conf_server_t *sc = tls_conf_server_get(cmd->server); - const char *err = NULL; - (void)dc; - if (!strcasecmp(mode, "required")) { - sc->client_auth = TLS_CLIENT_AUTH_REQUIRED; - } - else if (!strcasecmp(mode, "optional")) { - sc->client_auth = TLS_CLIENT_AUTH_OPTIONAL; - } - else if (!strcasecmp(mode, "none")) { - sc->client_auth = TLS_CLIENT_AUTH_NONE; - } - else { - err = apr_pstrcat(cmd->pool, cmd->cmd->name, - ": unknown value: '", mode, "', use required/optional/none.", NULL); - } - return err; -} - -static const char *tls_conf_set_user_name( - cmd_parms *cmd, void *dc, const char *var_user_name) -{ - tls_conf_server_t *sc = tls_conf_server_get(cmd->server); - (void)dc; - sc->var_user_name = var_user_name; - return NULL; -} - -#endif /* if TLS_CLIENT_CERTS */ - -#if TLS_MACHINE_CERTS - -static const char *tls_conf_add_proxy_machine_certificate( - cmd_parms *cmd, void *dir_conf, const char *cert_file, const char *pkey_file) -{ - tls_conf_dir_t *dc = dir_conf; - const char *err = NULL, *fpath; - tls_cert_spec_t *cert; - - (void)dc; - if (NULL != (err = cmd_check_file(cmd, cert_file))) goto cleanup; - /* key file may be NULL, in which case cert_file must contain the key PEM */ - if (pkey_file && NULL != (err = cmd_check_file(cmd, pkey_file))) goto cleanup; - - cert = apr_pcalloc(cmd->pool, sizeof(*cert)); - fpath = ap_server_root_relative(cmd->pool, cert_file); - if (!tls_util_is_file(cmd->pool, fpath)) { - return apr_pstrcat(cmd->pool, cmd->cmd->name, - ": unable to find certificate file: '", fpath, "'", NULL); - } - cert->cert_file = cert_file; - if (pkey_file) { - fpath = ap_server_root_relative(cmd->pool, pkey_file); - if (!tls_util_is_file(cmd->pool, fpath)) { - return apr_pstrcat(cmd->pool, cmd->cmd->name, - ": unable to find certificate key file: '", fpath, "'", NULL); - } - } - cert->pkey_file = pkey_file; - *(const tls_cert_spec_t **)apr_array_push(dc->proxy_machine_cert_specs) = cert; - -cleanup: - return err; -} - -#endif /* if TLS_MACHINE_CERTS */ - -const command_rec tls_conf_cmds[] = { - AP_INIT_TAKE12("TLSCertificate", tls_conf_add_certificate, NULL, RSRC_CONF, - "Add a certificate to the server by specifying a file containing the " - "certificate PEM, followed by its chain PEMs. The PEM of the key must " - "either also be there or can be given as a separate file."), - AP_INIT_TAKE_ARGV("TLSCiphersPrefer", tls_conf_set_preferred_ciphers, NULL, RSRC_CONF, - "Set the TLS ciphers to prefer when negotiating with a client."), - AP_INIT_TAKE_ARGV("TLSCiphersSuppress", tls_conf_set_suppressed_ciphers, NULL, RSRC_CONF, - "Set the TLS ciphers to never use when negotiating with a client."), - AP_INIT_TAKE1("TLSHonorClientOrder", tls_conf_set_honor_client_order, NULL, RSRC_CONF, - "Set 'on' to have the server honor client preferences in cipher suites, default off."), - AP_INIT_TAKE1("TLSEngine", tls_conf_add_engine, NULL, RSRC_CONF, - "Specify an address+port where the module shall handle incoming TLS connections."), - AP_INIT_TAKE_ARGV("TLSOptions", tls_conf_set_options, NULL, OR_OPTIONS, - "En-/disables optional features in the module."), - AP_INIT_TAKE1("TLSProtocol", tls_conf_set_protocol, NULL, RSRC_CONF, - "Set the minimum TLS protocol version to use."), - AP_INIT_TAKE1("TLSStrictSNI", tls_conf_set_strict_sni, NULL, RSRC_CONF, - "Set strictness of client server name (SNI) check against hosts, default on."), - AP_INIT_TAKE1("TLSSessionCache", tls_conf_set_session_cache, NULL, RSRC_CONF, - "Set which cache to use for TLS sessions."), - AP_INIT_FLAG("TLSProxyEngine", tls_conf_set_proxy_engine, NULL, RSRC_CONF|PROXY_CONF, - "Enable TLS encryption of outgoing connections in this location/server."), - AP_INIT_TAKE1("TLSProxyCA", tls_conf_set_proxy_ca, NULL, RSRC_CONF|PROXY_CONF, - "Set the trust anchors for certificates from proxied backend servers from a PEM file."), - AP_INIT_TAKE1("TLSProxyProtocol", tls_conf_set_proxy_protocol, NULL, RSRC_CONF|PROXY_CONF, - "Set the minimum TLS protocol version to use for proxy connections."), - AP_INIT_TAKE_ARGV("TLSProxyCiphersPrefer", tls_conf_set_proxy_preferred_ciphers, NULL, RSRC_CONF|PROXY_CONF, - "Set the TLS ciphers to prefer when negotiating a proxy connection."), - AP_INIT_TAKE_ARGV("TLSProxyCiphersSuppress", tls_conf_set_proxy_suppressed_ciphers, NULL, RSRC_CONF|PROXY_CONF, - "Set the TLS ciphers to never use when negotiating a proxy connection."), -#if TLS_CLIENT_CERTS - AP_INIT_TAKE1("TLSClientCA", tls_conf_set_client_ca, NULL, RSRC_CONF, - "Set the trust anchors for client certificates from a PEM file."), - AP_INIT_TAKE1("TLSClientCertificate", tls_conf_set_client_auth, NULL, RSRC_CONF, - "If TLS client authentication is 'required', 'optional' or 'none'."), - AP_INIT_TAKE1("TLSUserName", tls_conf_set_user_name, NULL, RSRC_CONF, - "Set the SSL variable to be used as user name."), -#endif /* if TLS_CLIENT_CERTS */ -#if TLS_MACHINE_CERTS - AP_INIT_TAKE12("TLSProxyMachineCertificate", tls_conf_add_proxy_machine_certificate, NULL, RSRC_CONF|PROXY_CONF, - "Add a certificate to be used as client certificate on a proxy connection. "), -#endif /* if TLS_MACHINE_CERTS */ - AP_INIT_TAKE1(NULL, NULL, NULL, RSRC_CONF, NULL) -}; diff --git a/modules/tls/tls_conf.h b/modules/tls/tls_conf.h deleted file mode 100644 index e924412d54..0000000000 --- a/modules/tls/tls_conf.h +++ /dev/null @@ -1,185 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef tls_conf_h -#define tls_conf_h - -/* Configuration flags */ -#define TLS_FLAG_UNSET (-1) -#define TLS_FLAG_FALSE (0) -#define TLS_FLAG_TRUE (1) - -struct tls_proto_conf_t; -struct tls_cert_reg_t; -struct tls_cert_root_stores_t; -struct tls_cert_verifiers_t; -struct ap_socache_instance_t; -struct ap_socache_provider_t; -struct apr_global_mutex_t; - - -/* disabled, since rustls support is lacking - * - x.509 retrieval of certificate fields and extensions - * - certificate revocation lists (CRL) - * - x.509 access to issuer of trust chain in x.509 CA store: - * server CA has ca1, ca2, ca3 - * client present certA - * rustls verifies that it is signed by *one of* ca* certs - * OCSP check needs (certA, issuing cert) for query - */ -#define TLS_CLIENT_CERTS 0 - -/* support for this exists as PR <https://github.com/rustls/rustls-ffi/pull/128> - */ -#define TLS_MACHINE_CERTS 1 - - -typedef enum { - TLS_CLIENT_AUTH_UNSET, - TLS_CLIENT_AUTH_NONE, - TLS_CLIENT_AUTH_REQUIRED, - TLS_CLIENT_AUTH_OPTIONAL, -} tls_client_auth_t; - -typedef enum { - TLS_CONF_ST_INIT, - TLS_CONF_ST_INCOMING_DONE, - TLS_CONF_ST_OUTGOING_DONE, - TLS_CONF_ST_DONE, -} tls_conf_status_t; - -/* The global module configuration, created after post-config - * and then readonly. - */ -typedef struct { - server_rec *ap_server; /* the global server we initialized on */ - const char *module_version; - const char *crustls_version; - - tls_conf_status_t status; - int mod_proxy_post_config_done; /* if mod_proxy did its post-config things */ - - server_addr_rec *tls_addresses; /* the addresses/ports our engine is enabled on */ - apr_array_header_t *proxy_configs; /* tls_conf_proxy_t* collected from everywhere */ - - struct tls_proto_conf_t *proto; /* TLS protocol/rustls specific globals */ - apr_hash_t *var_lookups; /* variable lookup functions by var name */ - struct tls_cert_reg_t *cert_reg; /* all certified keys loaded */ - struct tls_cert_root_stores_t *stores; /* loaded certificate stores */ - struct tls_cert_verifiers_t *verifiers; /* registry of certificate verifiers */ - - const char *session_cache_spec; /* how the session cache was specified */ - const struct ap_socache_provider_t *session_cache_provider; /* provider used for session cache */ - struct ap_socache_instance_t *session_cache; /* session cache instance */ - struct apr_global_mutex_t *session_cache_mutex; /* global mutex for access to session cache */ - - const rustls_server_config *rustls_hello_config; /* used for initial client hello parsing */ -} tls_conf_global_t; - -/* The module configuration for a server (vhost). - * Populated during config parsing, merged and completed - * in the post config phase. Readonly after that. - */ -typedef struct { - server_rec *server; /* server this config belongs to */ - tls_conf_global_t *global; /* global module config, singleton */ - - int enabled; /* TLS_FLAG_TRUE if mod_tls is active on this server */ - apr_array_header_t *cert_specs; /* array of (tls_cert_spec_t*) of configured certificates */ - int tls_protocol_min; /* the minimum TLS protocol version to use */ - apr_array_header_t *tls_pref_ciphers; /* List of apr_uint16_t cipher ids to prefer */ - apr_array_header_t *tls_supp_ciphers; /* List of apr_uint16_t cipher ids to suppress */ - const apr_array_header_t *ciphersuites; /* Computed post-config, ordered list of rustls cipher suites */ - int honor_client_order; /* honor client cipher ordering */ - int strict_sni; - - const char *client_ca; /* PEM file with trust anchors for client certs */ - tls_client_auth_t client_auth; /* how client authentication with certificates is used */ - const char *var_user_name; /* which SSL variable to use as user name */ - - apr_array_header_t *certified_keys; /* rustls_certified_key list configured */ - int base_server; /* != 0 iff this is the base server */ - int service_unavailable; /* TLS not trustworthy configured, return 503s */ -} tls_conf_server_t; - -typedef struct { - server_rec *defined_in; /* the server/host defining this dir_conf */ - tls_conf_global_t *global; /* global module config, singleton */ - const char *proxy_ca; /* PEM file with trust anchors for proxied remote server certs */ - int proxy_protocol_min; /* the minimum TLS protocol version to use for proxy connections */ - apr_array_header_t *proxy_pref_ciphers; /* List of apr_uint16_t cipher ids to prefer */ - apr_array_header_t *proxy_supp_ciphers; /* List of apr_uint16_t cipher ids to suppress */ - apr_array_header_t *machine_cert_specs; /* configured machine certificates specs */ - apr_array_header_t *machine_certified_keys; /* rustls_certified_key list */ - const rustls_client_config *rustls_config; -} tls_conf_proxy_t; - -typedef struct { - int std_env_vars; - int export_cert_vars; - int proxy_enabled; /* TLS_FLAG_TRUE if mod_tls is active on outgoing connections */ - const char *proxy_ca; /* PEM file with trust anchors for proxied remote server certs */ - int proxy_protocol_min; /* the minimum TLS protocol version to use for proxy connections */ - apr_array_header_t *proxy_pref_ciphers; /* List of apr_uint16_t cipher ids to prefer */ - apr_array_header_t *proxy_supp_ciphers; /* List of apr_uint16_t cipher ids to suppress */ - apr_array_header_t *proxy_machine_cert_specs; /* configured machine certificates specs */ - - tls_conf_proxy_t *proxy_config; -} tls_conf_dir_t; - -/* our static registry of configuration directives. */ -extern const command_rec tls_conf_cmds[]; - -/* create the modules configuration for a server_rec. */ -void *tls_conf_create_svr(apr_pool_t *pool, server_rec *s); - -/* merge (inherit) server configurations for the module. - * Settings in 'add' overwrite the ones in 'base' and unspecified - * settings shine through. */ -void *tls_conf_merge_svr(apr_pool_t *pool, void *basev, void *addv); - -/* create the modules configuration for a directory. */ -void *tls_conf_create_dir(apr_pool_t *pool, char *dir); - -/* merge (inherit) directory configurations for the module. - * Settings in 'add' overwrite the ones in 'base' and unspecified - * settings shine through. */ -void *tls_conf_merge_dir(apr_pool_t *pool, void *basev, void *addv); - - -/* Get the server specific module configuration. */ -tls_conf_server_t *tls_conf_server_get(server_rec *s); - -/* Get the directory specific module configuration for the request. */ -tls_conf_dir_t *tls_conf_dir_get(request_rec *r); - -/* Get the directory specific module configuration for the server. */ -tls_conf_dir_t *tls_conf_dir_server_get(server_rec *s); - -/* If any configuration values are unset, supply the global server defaults. */ -apr_status_t tls_conf_server_apply_defaults(tls_conf_server_t *sc, apr_pool_t *p); - -/* If any configuration values are unset, supply the global dir defaults. */ -apr_status_t tls_conf_dir_apply_defaults(tls_conf_dir_t *dc, apr_pool_t *p); - -/* create a new proxy configuration from directory config in server */ -tls_conf_proxy_t *tls_conf_proxy_make( - apr_pool_t *p, tls_conf_dir_t *dc, tls_conf_global_t *gc, server_rec *s); - -int tls_proxy_section_post_config( - apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s, - ap_conf_vector_t *section_config); - -#endif /* tls_conf_h */ diff --git a/modules/tls/tls_core.c b/modules/tls/tls_core.c deleted file mode 100644 index 1cef254f10..0000000000 --- a/modules/tls/tls_core.c +++ /dev/null @@ -1,1439 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include <assert.h> -#include <apr_lib.h> -#include <apr_strings.h> -#include <apr_network_io.h> - -#include <httpd.h> -#include <http_core.h> -#include <http_log.h> -#include <http_protocol.h> -#include <http_ssl.h> -#include <http_vhost.h> -#include <http_main.h> -#include <ap_socache.h> - -#include <rustls.h> - -#include "tls_proto.h" -#include "tls_cert.h" -#include "tls_conf.h" -#include "tls_core.h" -#include "tls_ocsp.h" -#include "tls_util.h" -#include "tls_cache.h" -#include "tls_var.h" - - -extern module AP_MODULE_DECLARE_DATA tls_module; -APLOG_USE_MODULE(tls); - -tls_conf_conn_t *tls_conf_conn_get(conn_rec *c) -{ - return ap_get_module_config(c->conn_config, &tls_module); -} - -void tls_conf_conn_set(conn_rec *c, tls_conf_conn_t *cc) -{ - ap_set_module_config(c->conn_config, &tls_module, cc); -} - -int tls_conn_check_ssl(conn_rec *c) -{ - tls_conf_conn_t *cc = tls_conf_conn_get(c->master? c->master : c); - if (TLS_CONN_ST_IS_ENABLED(cc)) { - return OK; - } - return DECLINED; -} - -static int we_listen_on(tls_conf_global_t *gc, server_rec *s, tls_conf_server_t *sc) -{ - server_addr_rec *sa, *la; - - if (gc->tls_addresses && sc->base_server) { - /* The base server listens to every port and may be selected via SNI */ - return 1; - } - for (la = gc->tls_addresses; la; la = la->next) { - for (sa = s->addrs; sa; sa = sa->next) { - if (la->host_port == sa->host_port - && la->host_addr->ipaddr_len == sa->host_addr->ipaddr_len - && !memcmp(la->host_addr->ipaddr_ptr, - la->host_addr->ipaddr_ptr, (size_t)la->host_addr->ipaddr_len)) { - /* exact match */ - return 1; - } - } - } - return 0; -} - -static apr_status_t tls_core_free(void *data) -{ - server_rec *base_server = (server_rec *)data; - tls_conf_server_t *sc = tls_conf_server_get(base_server); - - if (sc && sc->global && sc->global->rustls_hello_config) { - rustls_server_config_free(sc->global->rustls_hello_config); - sc->global->rustls_hello_config = NULL; - } - tls_cache_free(base_server); - return APR_SUCCESS; -} - -static apr_status_t load_certified_keys( - apr_array_header_t *keys, server_rec *s, - apr_array_header_t *cert_specs, - tls_cert_reg_t *cert_reg) -{ - apr_status_t rv = APR_SUCCESS; - const rustls_certified_key *ckey; - tls_cert_spec_t *spec; - int i; - - if (cert_specs && cert_specs->nelts > 0) { - for (i = 0; i < cert_specs->nelts; ++i) { - spec = APR_ARRAY_IDX(cert_specs, i, tls_cert_spec_t*); - rv = tls_cert_reg_get_certified_key(cert_reg, s, spec, &ckey); - if (APR_SUCCESS != rv) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(10318) - "Failed to load certificate %d[cert=%s(%d), key=%s(%d)] for %s", - i, spec->cert_file, (int)(spec->cert_pem? strlen(spec->cert_pem) : 0), - spec->pkey_file, (int)(spec->pkey_pem? strlen(spec->pkey_pem) : 0), - s->server_hostname); - goto cleanup; - } - assert(ckey); - APR_ARRAY_PUSH(keys, const rustls_certified_key*) = ckey; - } - } -cleanup: - return rv; -} - -static apr_status_t use_local_key( - conn_rec *c, const char *cert_pem, const char *pkey_pem) -{ - tls_conf_conn_t *cc = tls_conf_conn_get(c); - const rustls_certified_key *ckey = NULL; - tls_cert_spec_t spec; - apr_status_t rv = APR_SUCCESS; - - memset(&spec, 0, sizeof(spec)); - spec.cert_pem = cert_pem; - spec.pkey_pem = pkey_pem; - rv = tls_cert_load_cert_key(c->pool, &spec, NULL, &ckey); - if (APR_SUCCESS != rv) goto cleanup; - - cc->local_keys = apr_array_make(c->pool, 2, sizeof(const rustls_certified_key*)); - APR_ARRAY_PUSH(cc->local_keys, const rustls_certified_key*) = ckey; - ckey = NULL; - -cleanup: - if (ckey != NULL) rustls_certified_key_free(ckey); - return rv; -} - -static void add_file_specs( - apr_array_header_t *certificates, - apr_pool_t *p, - apr_array_header_t *cert_files, - apr_array_header_t *key_files) -{ - tls_cert_spec_t *spec; - int i; - - for (i = 0; i < cert_files->nelts; ++i) { - spec = apr_pcalloc(p, sizeof(*spec)); - spec->cert_file = APR_ARRAY_IDX(cert_files, i, const char*); - spec->pkey_file = (i < key_files->nelts)? APR_ARRAY_IDX(key_files, i, const char*) : NULL; - *(const tls_cert_spec_t**)apr_array_push(certificates) = spec; - } -} - -static apr_status_t calc_ciphers( - apr_pool_t *pool, - server_rec *s, - tls_conf_global_t *gc, - const char *proxy, - apr_array_header_t *pref_ciphers, - apr_array_header_t *supp_ciphers, - const apr_array_header_t **pciphers) -{ - apr_array_header_t *ordered_ciphers; - const apr_array_header_t *ciphers; - apr_array_header_t *unsupported = NULL; - rustls_result rr = RUSTLS_RESULT_OK; - apr_status_t rv = APR_SUCCESS; - apr_uint16_t id; - int i; - - - /* remove all suppressed ciphers from the ones supported by rustls */ - ciphers = tls_util_array_uint16_remove(pool, gc->proto->supported_cipher_ids, supp_ciphers); - ordered_ciphers = NULL; - /* if preferred ciphers are actually still present in allowed_ciphers, put - * them into `ciphers` in this order */ - for (i = 0; i < pref_ciphers->nelts; ++i) { - id = APR_ARRAY_IDX(pref_ciphers, i, apr_uint16_t); - ap_log_error(APLOG_MARK, APLOG_TRACE4, rv, s, - "checking preferred cipher %s: %d", - s->server_hostname, id); - if (tls_util_array_uint16_contains(ciphers, id)) { - ap_log_error(APLOG_MARK, APLOG_TRACE4, rv, s, - "checking preferred cipher %s: %d is known", - s->server_hostname, id); - if (ordered_ciphers == NULL) { - ordered_ciphers = apr_array_make(pool, ciphers->nelts, sizeof(apr_uint16_t)); - } - APR_ARRAY_PUSH(ordered_ciphers, apr_uint16_t) = id; - } - else if (!tls_proto_is_cipher_supported(gc->proto, id)) { - ap_log_error(APLOG_MARK, APLOG_TRACE4, rv, s, - "checking preferred cipher %s: %d is unsupported", - s->server_hostname, id); - if (!unsupported) unsupported = apr_array_make(pool, 5, sizeof(apr_uint16_t)); - APR_ARRAY_PUSH(unsupported, apr_uint16_t) = id; - } - } - /* if we found ciphers with preference among allowed_ciphers, - * append all other allowed ciphers. */ - if (ordered_ciphers) { - for (i = 0; i < ciphers->nelts; ++i) { - id = APR_ARRAY_IDX(ciphers, i, apr_uint16_t); - if (!tls_util_array_uint16_contains(ordered_ciphers, id)) { - APR_ARRAY_PUSH(ordered_ciphers, apr_uint16_t) = id; - } - } - ciphers = ordered_ciphers; - } - - if (ciphers == gc->proto->supported_cipher_ids) { - ciphers = NULL; - } - - if (unsupported && unsupported->nelts) { - ap_log_error(APLOG_MARK, APLOG_WARNING, rv, s, APLOGNO(10319) - "Server '%s' has TLS%sCiphersPrefer configured that are not " - "supported by rustls. These will not have an effect: %s", - s->server_hostname, proxy, - tls_proto_get_cipher_names(gc->proto, unsupported, pool)); - } - - if (RUSTLS_RESULT_OK != rr) { - const char *err_descr; - rv = tls_util_rustls_error(pool, rr, &err_descr); - ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(10320) - "Failed to configure ciphers %s: [%d] %s", - s->server_hostname, (int)rr, err_descr); - } - *pciphers = (APR_SUCCESS == rv)? ciphers : NULL; - return rv; -} - -static apr_status_t get_server_ciphersuites( - const apr_array_header_t **pciphersuites, - apr_pool_t *pool, tls_conf_server_t *sc) -{ - const apr_array_header_t *ciphers, *suites = NULL; - apr_status_t rv = APR_SUCCESS; - - rv = calc_ciphers(pool, sc->server, sc->global, - "", sc->tls_pref_ciphers, sc->tls_supp_ciphers, - &ciphers); - if (APR_SUCCESS != rv) goto cleanup; - - if (ciphers) { - suites = tls_proto_get_rustls_suites( - sc->global->proto, ciphers, pool); - if (APLOGtrace2(sc->server)) { - tls_proto_conf_t *conf = sc->global->proto; - ap_log_error(APLOG_MARK, APLOG_TRACE2, 0, sc->server, - "tls ciphers configured[%s]: %s", - sc->server->server_hostname, - tls_proto_get_cipher_names(conf, ciphers, pool)); - } - } - -cleanup: - *pciphersuites = (APR_SUCCESS == rv)? suites : NULL; - return rv; -} - -static apr_array_header_t *complete_cert_specs( - apr_pool_t *p, tls_conf_server_t *sc) -{ - apr_array_header_t *cert_adds, *key_adds, *specs; - - /* Take the configured certificate specifications and ask - * around for other modules to add specifications to this server. - * This is the way mod_md provides certificates. - * - * If the server then still has no cert specifications, ask - * around for `fallback` certificates which are commonly self-signed, - * temporary ones which let the server startup in order to - * obtain the `real` certificates from sources like ACME. - * Servers will fallbacks will answer all requests with 503. - */ - specs = apr_array_copy(p, sc->cert_specs); - cert_adds = apr_array_make(p, 2, sizeof(const char*)); - key_adds = apr_array_make(p, 2, sizeof(const char*)); - - ap_ssl_add_cert_files(sc->server, p, cert_adds, key_adds); - ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, sc->server, - "init server: complete_cert_specs added %d certs", cert_adds->nelts); - add_file_specs(specs, p, cert_adds, key_adds); - - if (apr_is_empty_array(specs)) { - ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, sc->server, - "init server: no certs configured, looking for fallback"); - ap_ssl_add_fallback_cert_files(sc->server, p, cert_adds, key_adds); - if (cert_adds->nelts > 0) { - add_file_specs(specs, p, cert_adds, key_adds); - sc->service_unavailable = 1; - ap_log_error(APLOG_MARK, APLOG_INFO, 0, sc->server, APLOGNO(10321) - "Init: %s will respond with '503 Service Unavailable' for now. There " - "are no SSL certificates configured and no other module contributed any.", - sc->server->server_hostname); - } - else if (!sc->base_server) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, sc->server, APLOGNO(10322) - "Init: %s has no certificates configured. Use 'TLSCertificate' to " - "configure a certificate and key file.", - sc->server->server_hostname); - } - } - return specs; -} - -static const rustls_certified_key *select_certified_key( - void* userdata, const rustls_client_hello *hello) -{ - conn_rec *c = userdata; - tls_conf_conn_t *cc; - tls_conf_server_t *sc; - apr_array_header_t *keys; - const rustls_certified_key *clone; - rustls_result rr = RUSTLS_RESULT_OK; - apr_status_t rv; - - ap_assert(c); - cc = tls_conf_conn_get(c); - ap_assert(cc); - ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c, "client hello select certified key"); - if (!cc || !cc->server) goto cleanup; - sc = tls_conf_server_get(cc->server); - if (!sc) goto cleanup; - - cc->key = NULL; - cc->key_cloned = 0; - if (cc->local_keys && cc->local_keys->nelts > 0) { - keys = cc->local_keys; - } - else { - keys = sc->certified_keys; - } - if (!keys || keys->nelts <= 0) goto cleanup; - - rr = rustls_client_hello_select_certified_key(hello, - (const rustls_certified_key**)keys->elts, (size_t)keys->nelts, &cc->key); - if (RUSTLS_RESULT_OK != rr) goto cleanup; - - if (APR_SUCCESS == tls_ocsp_update_key(c, cc->key, &clone)) { - /* got OCSP response data for it, meaning the key was cloned and we need to remember */ - cc->key_cloned = 1; - cc->key = clone; - } - if (APLOGctrace2(c)) { - const char *key_id = tls_cert_reg_get_id(sc->global->cert_reg, cc->key); - ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c, APLOGNO(10323) - "client hello selected key: %s", key_id? key_id : "unknown"); - } - return cc->key; - -cleanup: - if (RUSTLS_RESULT_OK != rr) { - const char *err_descr; - rv = tls_util_rustls_error(c->pool, rr, &err_descr); - ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c, APLOGNO(10324) - "Failed to select certified key: [%d] %s", (int)rr, err_descr); - } - return NULL; -} - -static apr_status_t server_conf_setup( - apr_pool_t *p, apr_pool_t *ptemp, tls_conf_server_t *sc, tls_conf_global_t *gc) -{ - apr_array_header_t *cert_specs; - apr_status_t rv = APR_SUCCESS; - - /* TODO: most code has been stripped here with the changes in rustls-ffi v0.8.0 - * and this means that any errors are only happening at connection setup, which - * is too late. - */ - (void)p; - ap_log_error(APLOG_MARK, APLOG_TRACE1, rv, sc->server, - "init server: %s", sc->server->server_hostname); - - if (sc->client_auth != TLS_CLIENT_AUTH_NONE && !sc->client_ca) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, sc->server, APLOGNO(10325) - "TLSClientAuthentication is enabled for %s, but no client CA file is set. " - "Use 'TLSClientCA <file>' to specify the trust anchors.", - sc->server->server_hostname); - rv = APR_EINVAL; goto cleanup; - } - - cert_specs = complete_cert_specs(ptemp, sc); - sc->certified_keys = apr_array_make(p, 3, sizeof(rustls_certified_key *)); - rv = load_certified_keys(sc->certified_keys, sc->server, cert_specs, gc->cert_reg); - if (APR_SUCCESS != rv) goto cleanup; - - rv = get_server_ciphersuites(&sc->ciphersuites, p, sc); - if (APR_SUCCESS != rv) goto cleanup; - - ap_log_error(APLOG_MARK, APLOG_TRACE1, rv, sc->server, - "init server: %s with %d certificates loaded", - sc->server->server_hostname, sc->certified_keys->nelts); -cleanup: - return rv; -} - -static apr_status_t get_proxy_ciphers(const apr_array_header_t **pciphersuites, - apr_pool_t *pool, tls_conf_proxy_t *pc) -{ - const apr_array_header_t *ciphers, *suites = NULL; - apr_status_t rv = APR_SUCCESS; - - rv = calc_ciphers(pool, pc->defined_in, pc->global, - "", pc->proxy_pref_ciphers, pc->proxy_supp_ciphers, &ciphers); - if (APR_SUCCESS != rv) goto cleanup; - - if (ciphers) { - suites = tls_proto_get_rustls_suites(pc->global->proto, ciphers, pool); - /* this changed the default rustls ciphers, configure it. */ - if (APLOGtrace2(pc->defined_in)) { - tls_proto_conf_t *conf = pc->global->proto; - ap_log_error(APLOG_MARK, APLOG_TRACE2, 0, pc->defined_in, - "tls proxy ciphers configured[%s]: %s", - pc->defined_in->server_hostname, - tls_proto_get_cipher_names(conf, ciphers, pool)); - } - } - -cleanup: - *pciphersuites = (APR_SUCCESS == rv)? suites : NULL; - return rv; -} - -static apr_status_t proxy_conf_setup( - apr_pool_t *p, apr_pool_t *ptemp, tls_conf_proxy_t *pc, tls_conf_global_t *gc) -{ - apr_status_t rv = APR_SUCCESS; - - (void)p; (void)ptemp; - ap_assert(pc->defined_in); - pc->global = gc; - - if (pc->proxy_ca && strcasecmp(pc->proxy_ca, "default")) { - ap_log_error(APLOG_MARK, APLOG_TRACE2, rv, pc->defined_in, - "proxy: will use roots in %s from %s", - pc->defined_in->server_hostname, pc->proxy_ca); - } - else { - ap_log_error(APLOG_MARK, APLOG_WARNING, rv, pc->defined_in, - "proxy: there is no TLSProxyCA configured in %s which means " - "the certificates of remote servers contacted from here will not be trusted.", - pc->defined_in->server_hostname); - } - - if (pc->proxy_protocol_min > 0) { - apr_array_header_t *tls_versions; - - ap_log_error(APLOG_MARK, APLOG_TRACE1, rv, pc->defined_in, - "init server: set proxy protocol min version %04x", pc->proxy_protocol_min); - tls_versions = tls_proto_create_versions_plus( - gc->proto, (apr_uint16_t)pc->proxy_protocol_min, ptemp); - if (tls_versions->nelts > 0) { - if (pc->proxy_protocol_min != APR_ARRAY_IDX(tls_versions, 0, apr_uint16_t)) { - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, pc->defined_in, APLOGNO(10326) - "Init: the minimum proxy protocol version configured for %s (%04x) " - "is not supported and version %04x was selected instead.", - pc->defined_in->server_hostname, pc->proxy_protocol_min, - APR_ARRAY_IDX(tls_versions, 0, apr_uint16_t)); - } - } - else { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, pc->defined_in, APLOGNO(10327) - "Unable to configure the proxy protocol version for %s: " - "neither the configured minimum version (%04x), nor any higher one is " - "available.", pc->defined_in->server_hostname, pc->proxy_protocol_min); - rv = APR_ENOTIMPL; goto cleanup; - } - } - -#if TLS_MACHINE_CERTS - rv = load_certified_keys(pc->machine_certified_keys, pc->defined_in, - pc->machine_cert_specs, gc->cert_reg); - if (APR_SUCCESS != rv) goto cleanup; -#endif - -cleanup: - return rv; -} - -static const rustls_certified_key *extract_client_hello_values( - void* userdata, const rustls_client_hello *hello) -{ - conn_rec *c = userdata; - tls_conf_conn_t *cc = tls_conf_conn_get(c); - size_t i, len; - unsigned short n; - - ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c, "extract client hello values"); - if (!cc) goto cleanup; - cc->client_hello_seen = 1; - if (hello->server_name.len > 0) { - cc->sni_hostname = apr_pstrndup(c->pool, hello->server_name.data, hello->server_name.len); - ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, "sni detected: %s", cc->sni_hostname); - } - else { - cc->sni_hostname = NULL; - ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, "no sni from client"); - } - if (APLOGctrace4(c) && hello->signature_schemes.len > 0) { - for (i = 0; i < hello->signature_schemes.len; ++i) { - n = hello->signature_schemes.data[i]; - ap_log_cerror(APLOG_MARK, APLOG_TRACE4, 0, c, - "client supports signature scheme: %x", (int)n); - } - } - if ((len = rustls_slice_slice_bytes_len(hello->alpn)) > 0) { - apr_array_header_t *alpn = apr_array_make(c->pool, 5, sizeof(const char*)); - const char *protocol; - ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, "ALPN: client proposes %d protocols", (int)len); - for (i = 0; i < len; ++i) { - rustls_slice_bytes rs = rustls_slice_slice_bytes_get(hello->alpn, i); - protocol = apr_pstrndup(c->pool, (const char*)rs.data, rs.len); - APR_ARRAY_PUSH(alpn, const char*) = protocol; - ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, - "ALPN: client proposes %d: `%s`", (int)i, protocol); - } - cc->alpn = alpn; - } - else { - ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, "ALPN: no alpn proposed by client"); - } -cleanup: - return NULL; -} - -static apr_status_t setup_hello_config(apr_pool_t *p, server_rec *base_server, tls_conf_global_t *gc) -{ - rustls_server_config_builder *builder; - rustls_result rr = RUSTLS_RESULT_OK; - apr_status_t rv = APR_SUCCESS; - - builder = rustls_server_config_builder_new(); - if (!builder) { - rr = RUSTLS_RESULT_PANIC; goto cleanup; - } - rustls_server_config_builder_set_hello_callback(builder, extract_client_hello_values); - gc->rustls_hello_config = rustls_server_config_builder_build(builder); - if (!gc->rustls_hello_config) { - rr = RUSTLS_RESULT_PANIC; goto cleanup; - } - -cleanup: - if (RUSTLS_RESULT_OK != rr) { - const char *err_descr = NULL; - rv = tls_util_rustls_error(p, rr, &err_descr); - ap_log_error(APLOG_MARK, APLOG_ERR, rv, base_server, APLOGNO(10328) - "Failed to init generic hello config: [%d] %s", (int)rr, err_descr); - goto cleanup; - } - return rv; -} - -static apr_status_t init_incoming(apr_pool_t *p, apr_pool_t *ptemp, server_rec *base_server) -{ - tls_conf_server_t *sc = tls_conf_server_get(base_server); - tls_conf_global_t *gc = sc->global; - server_rec *s; - apr_status_t rv = APR_ENOMEM; - - ap_log_error(APLOG_MARK, APLOG_TRACE2, 0, base_server, "tls_core_init incoming"); - apr_pool_cleanup_register(p, base_server, tls_core_free, - apr_pool_cleanup_null); - - rv = tls_proto_post_config(p, ptemp, base_server); - if (APR_SUCCESS != rv) goto cleanup; - - for (s = base_server; s; s = s->next) { - sc = tls_conf_server_get(s); - assert(sc); - ap_assert(sc->global == gc); - - /* If 'TLSEngine' has been configured, use those addresses to - * decide if we are enabled on this server. */ - sc->base_server = (s == base_server); - sc->enabled = we_listen_on(gc, s, sc)? TLS_FLAG_TRUE : TLS_FLAG_FALSE; - } - - rv = tls_cache_post_config(p, ptemp, base_server); - if (APR_SUCCESS != rv) goto cleanup; - - rv = setup_hello_config(p, base_server, gc); - if (APR_SUCCESS != rv) goto cleanup; - - /* Setup server configs and collect all certificates we use. */ - gc->cert_reg = tls_cert_reg_make(p); - gc->stores = tls_cert_root_stores_make(p); - gc->verifiers = tls_cert_verifiers_make(p, gc->stores); - for (s = base_server; s; s = s->next) { - sc = tls_conf_server_get(s); - rv = tls_conf_server_apply_defaults(sc, p); - if (APR_SUCCESS != rv) goto cleanup; - if (sc->enabled != TLS_FLAG_TRUE) continue; - rv = server_conf_setup(p, ptemp, sc, gc); - if (APR_SUCCESS != rv) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, "server setup failed: %s", - s->server_hostname); - goto cleanup; - } - } - -cleanup: - if (APR_SUCCESS != rv) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, base_server, "error during post_config"); - } - return rv; -} - -static apr_status_t init_outgoing(apr_pool_t *p, apr_pool_t *ptemp, server_rec *base_server) -{ - tls_conf_server_t *sc = tls_conf_server_get(base_server); - tls_conf_global_t *gc = sc->global; - tls_conf_dir_t *dc; - tls_conf_proxy_t *pc; - server_rec *s; - apr_status_t rv = APR_SUCCESS; - int i; - - (void)p; (void)ptemp; - (void)gc; - ap_log_error(APLOG_MARK, APLOG_TRACE2, 0, base_server, "tls_core_init outgoing"); - ap_assert(gc->mod_proxy_post_config_done); - /* Collect all proxy'ing default server dir configs. - * All <Proxy> section dir_configs should already be there - if there were any. */ - for (s = base_server; s; s = s->next) { - dc = tls_conf_dir_server_get(s); - rv = tls_conf_dir_apply_defaults(dc, p); - if (APR_SUCCESS != rv) goto cleanup; - if (dc->proxy_enabled != TLS_FLAG_TRUE) continue; - dc->proxy_config = tls_conf_proxy_make(p, dc, gc, s); - ap_log_error(APLOG_MARK, APLOG_TRACE3, 0, s, "%s: adding proxy_conf to globals", - s->server_hostname); - APR_ARRAY_PUSH(gc->proxy_configs, tls_conf_proxy_t*) = dc->proxy_config; - } - /* Now gc->proxy_configs contains all configurations we need to possibly - * act on for outgoing connections. */ - for (i = 0; i < gc->proxy_configs->nelts; ++i) { - pc = APR_ARRAY_IDX(gc->proxy_configs, i, tls_conf_proxy_t*); - rv = proxy_conf_setup(p, ptemp, pc, gc); - if (APR_SUCCESS != rv) goto cleanup; - } - -cleanup: - return rv; -} - -apr_status_t tls_core_init(apr_pool_t *p, apr_pool_t *ptemp, server_rec *base_server) -{ - tls_conf_server_t *sc = tls_conf_server_get(base_server); - tls_conf_global_t *gc = sc->global; - apr_status_t rv = APR_SUCCESS; - - ap_assert(gc); - if (TLS_CONF_ST_INIT == gc->status) { - rv = init_incoming(p, ptemp, base_server); - if (APR_SUCCESS != rv) goto cleanup; - gc->status = TLS_CONF_ST_INCOMING_DONE; - } - if (TLS_CONF_ST_INCOMING_DONE == gc->status) { - if (!gc->mod_proxy_post_config_done) goto cleanup; - - rv = init_outgoing(p, ptemp, base_server); - if (APR_SUCCESS != rv) goto cleanup; - gc->status = TLS_CONF_ST_OUTGOING_DONE; - } - if (TLS_CONF_ST_OUTGOING_DONE == gc->status) { - /* register all loaded certificates for OCSP stapling */ - rv = tls_ocsp_prime_certs(gc, p, base_server); - if (APR_SUCCESS != rv) goto cleanup; - - if (gc->verifiers) tls_cert_verifiers_clear(gc->verifiers); - if (gc->stores) tls_cert_root_stores_clear(gc->stores); - gc->status = TLS_CONF_ST_DONE; - } -cleanup: - return rv; -} - -static apr_status_t tls_core_conn_free(void *data) -{ - tls_conf_conn_t *cc = data; - - /* free all rustls things we are owning. */ - if (cc->rustls_connection) { - rustls_connection_free(cc->rustls_connection); - cc->rustls_connection = NULL; - } - if (cc->rustls_server_config) { - rustls_server_config_free(cc->rustls_server_config); - cc->rustls_server_config = NULL; - } - if (cc->rustls_client_config) { - rustls_client_config_free(cc->rustls_client_config); - cc->rustls_client_config = NULL; - } - if (cc->key_cloned && cc->key) { - rustls_certified_key_free(cc->key); - cc->key = NULL; - } - if (cc->local_keys) { - const rustls_certified_key *key; - int i; - - for (i = 0; i < cc->local_keys->nelts; ++i) { - key = APR_ARRAY_IDX(cc->local_keys, i, const rustls_certified_key*); - rustls_certified_key_free(key); - } - apr_array_clear(cc->local_keys); - } - return APR_SUCCESS; -} - -static tls_conf_conn_t *cc_get_or_make(conn_rec *c) -{ - tls_conf_conn_t *cc = tls_conf_conn_get(c); - if (!cc) { - cc = apr_pcalloc(c->pool, sizeof(*cc)); - cc->server = c->base_server; - cc->state = TLS_CONN_ST_INIT; - tls_conf_conn_set(c, cc); - apr_pool_cleanup_register(c->pool, cc, tls_core_conn_free, - apr_pool_cleanup_null); - } - return cc; -} - -void tls_core_conn_disable(conn_rec *c) -{ - tls_conf_conn_t *cc; - cc = cc_get_or_make(c); - if (cc->state == TLS_CONN_ST_INIT) { - cc->state = TLS_CONN_ST_DISABLED; - } -} - -void tls_core_conn_bind(conn_rec *c, ap_conf_vector_t *dir_conf) -{ - tls_conf_conn_t *cc = cc_get_or_make(c); - cc->dc = dir_conf? ap_get_module_config(dir_conf, &tls_module) : NULL; -} - - -static apr_status_t init_outgoing_connection(conn_rec *c) -{ - tls_conf_conn_t *cc = tls_conf_conn_get(c); - tls_conf_proxy_t *pc; - const apr_array_header_t *ciphersuites = NULL; - apr_array_header_t *tls_versions = NULL; - rustls_web_pki_server_cert_verifier_builder *verifier_builder = NULL; - struct rustls_server_cert_verifier *verifier = NULL; - rustls_client_config_builder *builder = NULL; - const rustls_root_cert_store *ca_store = NULL; - const char *hostname = NULL, *alpn_note = NULL; - rustls_result rr = RUSTLS_RESULT_OK; - apr_status_t rv = APR_SUCCESS; - - ap_assert(cc->outgoing); - ap_assert(cc->dc); - pc = cc->dc->proxy_config; - ap_assert(pc); - - hostname = apr_table_get(c->notes, "proxy-request-hostname"); - alpn_note = apr_table_get(c->notes, "proxy-request-alpn-protos"); - ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, c->base_server, - "setup_outgoing: to %s [ALPN: %s] from configuration in %s" - " using CA %s", hostname, alpn_note, pc->defined_in->server_hostname, pc->proxy_ca); - - rv = get_proxy_ciphers(&ciphersuites, c->pool, pc); - if (APR_SUCCESS != rv) goto cleanup; - - if (pc->proxy_protocol_min > 0) { - tls_versions = tls_proto_create_versions_plus( - pc->global->proto, (apr_uint16_t)pc->proxy_protocol_min, c->pool); - } - - if (ciphersuites && ciphersuites->nelts > 0 - && tls_versions && tls_versions->nelts >= 0) { - rr = rustls_client_config_builder_new_custom( - (const struct rustls_supported_ciphersuite *const *)ciphersuites->elts, - (size_t)ciphersuites->nelts, - (const uint16_t *)tls_versions->elts, (size_t)tls_versions->nelts, - &builder); - if (RUSTLS_RESULT_OK != rr) goto cleanup; - } - else { - builder = rustls_client_config_builder_new(); - if (NULL == builder) { - rv = APR_ENOMEM; - goto cleanup; - } - } - - if (pc->proxy_ca && strcasecmp(pc->proxy_ca, "default")) { - rv = tls_cert_root_stores_get(pc->global->stores, pc->proxy_ca, &ca_store); - if (APR_SUCCESS != rv) goto cleanup; - verifier_builder = rustls_web_pki_server_cert_verifier_builder_new(ca_store); - rr = rustls_web_pki_server_cert_verifier_builder_build(verifier_builder, &verifier); - if (RUSTLS_RESULT_OK != rr) goto cleanup; - rustls_client_config_builder_set_server_verifier(builder, verifier); - } - -#if TLS_MACHINE_CERTS - if (pc->machine_certified_keys->nelts > 0) { - ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, c->base_server, - "setup_outgoing: adding %d client certificate", (int)pc->machine_certified_keys->nelts); - rr = rustls_client_config_builder_set_certified_key( - builder, (const rustls_certified_key**)pc->machine_certified_keys->elts, - (size_t)pc->machine_certified_keys->nelts); - if (RUSTLS_RESULT_OK != rr) goto cleanup; - } -#endif - - if (hostname) { - rustls_client_config_builder_set_enable_sni(builder, true); - } - else { - hostname = "unknown.proxy.local"; - rustls_client_config_builder_set_enable_sni(builder, false); - } - - if (alpn_note) { - apr_array_header_t *alpn_proposed = NULL; - char *p, *last; - apr_size_t len; - - alpn_proposed = apr_array_make(c->pool, 3, sizeof(const char*)); - p = apr_pstrdup(c->pool, alpn_note); - while ((p = apr_strtok(p, ", ", &last))) { - len = (apr_size_t)(last - p - (*last? 1 : 0)); - if (len > 255) { - ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(10329) - "ALPN proxy protocol identifier too long: %s", p); - rv = APR_EGENERAL; - goto cleanup; - } - APR_ARRAY_PUSH(alpn_proposed, const char*) = apr_pstrndup(c->pool, p, len); - p = NULL; - } - if (alpn_proposed->nelts > 0) { - apr_array_header_t *rustls_protocols; - const char* proto; - rustls_slice_bytes bytes; - int i; - - rustls_protocols = apr_array_make(c->pool, alpn_proposed->nelts, sizeof(rustls_slice_bytes)); - for (i = 0; i < alpn_proposed->nelts; ++i) { - proto = APR_ARRAY_IDX(alpn_proposed, i, const char*); - bytes.data = (const unsigned char*)proto; - bytes.len = strlen(proto); - APR_ARRAY_PUSH(rustls_protocols, rustls_slice_bytes) = bytes; - } - - rr = rustls_client_config_builder_set_alpn_protocols(builder, - (rustls_slice_bytes*)rustls_protocols->elts, (size_t)rustls_protocols->nelts); - if (RUSTLS_RESULT_OK != rr) goto cleanup; - - ap_log_error(APLOG_MARK, APLOG_TRACE2, 0, c->base_server, - "setup_outgoing: to %s, added %d ALPN protocols from %s", - hostname, rustls_protocols->nelts, alpn_note); - } - } - - cc->rustls_client_config = rustls_client_config_builder_build(builder); - builder = NULL; - - rr = rustls_client_connection_new(cc->rustls_client_config, hostname, &cc->rustls_connection); - if (RUSTLS_RESULT_OK != rr) goto cleanup; - rustls_connection_set_userdata(cc->rustls_connection, c); - -cleanup: - if (verifier_builder != NULL) rustls_web_pki_server_cert_verifier_builder_free(verifier_builder); - if (builder != NULL) rustls_client_config_builder_free(builder); - if (RUSTLS_RESULT_OK != rr) { - const char *err_descr = NULL; - rv = tls_util_rustls_error(c->pool, rr, &err_descr); - ap_log_error(APLOG_MARK, APLOG_ERR, rv, cc->server, APLOGNO(10330) - "Failed to init pre_session for outgoing %s to %s: [%d] %s", - cc->server->server_hostname, hostname, (int)rr, err_descr); - c->aborted = 1; - cc->state = TLS_CONN_ST_DISABLED; - goto cleanup; - } - return rv; -} - -int tls_core_pre_conn_init(conn_rec *c) -{ - tls_conf_server_t *sc = tls_conf_server_get(c->base_server); - tls_conf_conn_t *cc; - - cc = cc_get_or_make(c); - if (cc->state == TLS_CONN_ST_INIT) { - /* Need to decide if we TLS this connection or not */ - int enabled = -#if AP_MODULE_MAGIC_AT_LEAST(20120211, 109) - !c->outgoing && -#endif - sc->enabled == TLS_FLAG_TRUE; - cc->state = enabled? TLS_CONN_ST_CLIENT_HELLO : TLS_CONN_ST_DISABLED; - cc->client_auth = sc->client_auth; - ap_log_error(APLOG_MARK, APLOG_TRACE3, 0, c->base_server, - "tls_core_conn_init: %s for tls: %s", - enabled? "enabled" : "disabled", c->base_server->server_hostname); - } - else if (cc->state == TLS_CONN_ST_DISABLED) { - ap_log_error(APLOG_MARK, APLOG_TRACE4, 0, c->base_server, - "tls_core_conn_init, not our connection: %s", - c->base_server->server_hostname); - goto cleanup; - } - -cleanup: - return TLS_CONN_ST_IS_ENABLED(cc)? OK : DECLINED; -} - -apr_status_t tls_core_conn_init(conn_rec *c) -{ - tls_conf_server_t *sc = tls_conf_server_get(c->base_server); - tls_conf_conn_t *cc; - rustls_result rr = RUSTLS_RESULT_OK; - apr_status_t rv = APR_SUCCESS; - - cc = tls_conf_conn_get(c); - if (cc && TLS_CONN_ST_IS_ENABLED(cc) && !cc->rustls_connection) { - if (cc->outgoing) { - rv = init_outgoing_connection(c); - if (APR_SUCCESS != rv) goto cleanup; - } - else { - /* Use a generic rustls_connection with its defaults, which we feed - * the first TLS bytes from the client. Its Hello message will trigger - * our callback where we can inspect the (possibly) supplied SNI and - * select another server. - */ - rr = rustls_server_connection_new(sc->global->rustls_hello_config, &cc->rustls_connection); - if (RUSTLS_RESULT_OK != rr) goto cleanup; - /* we might refuse requests on this connection, e.g. ACME challenge */ - cc->service_unavailable = sc->service_unavailable; - } - rustls_connection_set_userdata(cc->rustls_connection, c); - } - -cleanup: - if (RUSTLS_RESULT_OK != rr) { - const char *err_descr = NULL; - rv = tls_util_rustls_error(c->pool, rr, &err_descr); - ap_log_error(APLOG_MARK, APLOG_ERR, rv, sc->server, APLOGNO(10331) - "Failed to init TLS connection for server %s: [%d] %s", - sc->server->server_hostname, (int)rr, err_descr); - c->aborted = 1; - cc->state = TLS_CONN_ST_DISABLED; - goto cleanup; - } - return rv; -} - -static int find_vhost(void *sni_hostname, conn_rec *c, server_rec *s) -{ - if (tls_util_name_matches_server(sni_hostname, s)) { - tls_conf_conn_t *cc = tls_conf_conn_get(c); - cc->server = s; - return 1; - } - return 0; -} - -static apr_status_t select_application_protocol( - conn_rec *c, server_rec *s, rustls_server_config_builder *builder) -{ - tls_conf_conn_t *cc = tls_conf_conn_get(c); - const char *proposed; - rustls_result rr = RUSTLS_RESULT_OK; - apr_status_t rv = APR_SUCCESS; - - /* The server always has a protocol it uses, normally "http/1.1". - * if the client, via ALPN, proposes protocols, they are in - * order of preference. - * We propose those to modules registered in the server and - * get the protocol back that someone is willing to run on this - * connection. - * If this is different from what the connection already does, - * we tell the server (and all protocol modules) to switch. - * If successful, we announce that protocol back to the client as - * our only ALPN protocol and then do the 'real' handshake. - */ - cc->application_protocol = ap_get_protocol(c); - if (cc->alpn && cc->alpn->nelts > 0) { - rustls_slice_bytes rsb; - - proposed = ap_select_protocol(c, NULL, s, cc->alpn); - if (!proposed) { - ap_log_cerror(APLOG_MARK, APLOG_TRACE2, rv, c, - "ALPN: no protocol selected in server"); - goto cleanup; - } - - if (strcmp(proposed, cc->application_protocol)) { - ap_log_cerror(APLOG_MARK, APLOG_TRACE2, rv, c, - "ALPN: switching protocol from `%s` to `%s`", cc->application_protocol, proposed); - rv = ap_switch_protocol(c, NULL, cc->server, proposed); - if (APR_SUCCESS != rv) goto cleanup; - } - - rsb.data = (const unsigned char*)proposed; - rsb.len = strlen(proposed); - rr = rustls_server_config_builder_set_alpn_protocols(builder, &rsb, 1); - if (RUSTLS_RESULT_OK != rr) goto cleanup; - - cc->application_protocol = proposed; - ap_log_cerror(APLOG_MARK, APLOG_TRACE2, rv, c, - "ALPN: using connection protocol `%s`", cc->application_protocol); - - /* protocol was switched, this could be a challenge protocol - * such as "acme-tls/1". Give handlers the opportunity to - * override the certificate for this connection. */ - if (strcmp("h2", proposed) && strcmp("http/1.1", proposed)) { - const char *cert_pem = NULL, *key_pem = NULL; - if (ap_ssl_answer_challenge(c, cc->sni_hostname, &cert_pem, &key_pem)) { - /* With ACME we can have challenge connections to a unknown domains - * that need to be answered with a special certificate and will - * otherwise not answer any requests. See RFC 8555 */ - rv = use_local_key(c, cert_pem, key_pem); - if (APR_SUCCESS != rv) goto cleanup; - - cc->service_unavailable = 1; - cc->client_auth = TLS_CLIENT_AUTH_NONE; - } - } - } - -cleanup: - if (rr != RUSTLS_RESULT_OK) { - const char *err_descr = NULL; - rv = tls_util_rustls_error(c->pool, rr, &err_descr); - ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(10332) - "Failed to init session for server %s: [%d] %s", - s->server_hostname, (int)rr, err_descr); - c->aborted = 1; - goto cleanup; - } - return rv; -} - -static apr_status_t build_server_connection(rustls_connection **pconnection, - const rustls_server_config **pconfig, - conn_rec *c) -{ - tls_conf_conn_t *cc = tls_conf_conn_get(c); - tls_conf_server_t *sc; - const apr_array_header_t *tls_versions = NULL; - rustls_server_config_builder *builder = NULL; - const rustls_server_config *config = NULL; - rustls_connection *rconnection = NULL; - rustls_result rr = RUSTLS_RESULT_OK; - apr_status_t rv = APR_SUCCESS; - - sc = tls_conf_server_get(cc->server); - - if (sc->tls_protocol_min > 0) { - ap_log_error(APLOG_MARK, APLOG_TRACE1, rv, sc->server, - "init server: set protocol min version %04x", sc->tls_protocol_min); - tls_versions = tls_proto_create_versions_plus( - sc->global->proto, (apr_uint16_t)sc->tls_protocol_min, c->pool); - if (tls_versions->nelts > 0) { - if (sc->tls_protocol_min != APR_ARRAY_IDX(tls_versions, 0, apr_uint16_t)) { - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, sc->server, APLOGNO(10333) - "Init: the minimum protocol version configured for %s (%04x) " - "is not supported and version %04x was selected instead.", - sc->server->server_hostname, sc->tls_protocol_min, - APR_ARRAY_IDX(tls_versions, 0, apr_uint16_t)); - } - } - else { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, sc->server, APLOGNO(10334) - "Unable to configure the protocol version for %s: " - "neither the configured minimum version (%04x), nor any higher one is " - "available.", sc->server->server_hostname, sc->tls_protocol_min); - rv = APR_ENOTIMPL; goto cleanup; - } - } - else if (sc->ciphersuites && sc->ciphersuites->nelts > 0) { - /* FIXME: rustls-ffi current has not way to make a builder with ALL_PROTOCOL_VERSIONS */ - tls_versions = tls_proto_create_versions_plus(sc->global->proto, 0, c->pool); - } - - if (sc->ciphersuites && sc->ciphersuites->nelts > 0 - && tls_versions && tls_versions->nelts >= 0) { - rr = rustls_server_config_builder_new_custom( - (const struct rustls_supported_ciphersuite *const *)sc->ciphersuites->elts, - (size_t)sc->ciphersuites->nelts, - (const uint16_t *)tls_versions->elts, (size_t)tls_versions->nelts, - &builder); - if (RUSTLS_RESULT_OK != rr) goto cleanup; - } - else { - builder = rustls_server_config_builder_new(); - if (NULL == builder) { - rv = APR_ENOMEM; - goto cleanup; - } - } - - /* decide on the application protocol, this may change other - * settings like client_auth. */ - rv = select_application_protocol(c, cc->server, builder); - - if (cc->client_auth != TLS_CLIENT_AUTH_NONE) { - ap_assert(sc->client_ca); /* checked in server_setup */ - if (cc->client_auth == TLS_CLIENT_AUTH_REQUIRED) { - const rustls_client_cert_verifier *verifier; - rv = tls_cert_client_verifiers_get(sc->global->verifiers, sc->client_ca, &verifier); - if (APR_SUCCESS != rv) goto cleanup; - rustls_server_config_builder_set_client_verifier(builder, verifier); - } - else { - const rustls_client_cert_verifier *verifier; - rv = tls_cert_client_verifiers_get_optional(sc->global->verifiers, sc->client_ca, &verifier); - if (APR_SUCCESS != rv) goto cleanup; - rustls_server_config_builder_set_client_verifier(builder, verifier); - } - } - - rustls_server_config_builder_set_hello_callback(builder, select_certified_key); - - rr = rustls_server_config_builder_set_ignore_client_order( - builder, sc->honor_client_order == TLS_FLAG_FALSE); - if (RUSTLS_RESULT_OK != rr) goto cleanup; - - rv = tls_cache_init_server(builder, sc->server); - if (APR_SUCCESS != rv) goto cleanup; - - config = rustls_server_config_builder_build(builder); - builder = NULL; - if (!config) { - rv = APR_ENOMEM; goto cleanup; - } - - rr = rustls_server_connection_new(config, &rconnection); - if (RUSTLS_RESULT_OK != rr) goto cleanup; - rustls_connection_set_userdata(rconnection, c); - -cleanup: - if (rr != RUSTLS_RESULT_OK) { - const char *err_descr = NULL; - rv = tls_util_rustls_error(c->pool, rr, &err_descr); - ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, sc->server, APLOGNO(10335) - "Failed to init session for server %s: [%d] %s", - sc->server->server_hostname, (int)rr, err_descr); - } - if (APR_SUCCESS == rv) { - *pconfig = config; - *pconnection = rconnection; - ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, sc->server, - "tls_core_conn_server_init done: %s", - sc->server->server_hostname); - } - else { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, sc->server, APLOGNO(10336) - "Failed to init session for server %s", - sc->server->server_hostname); - c->aborted = 1; - if (config) rustls_server_config_free(config); - if (builder) rustls_server_config_builder_free(builder); - } - return rv; -} - -apr_status_t tls_core_conn_seen_client_hello(conn_rec *c) -{ - tls_conf_conn_t *cc = tls_conf_conn_get(c); - tls_conf_server_t *sc; - apr_status_t rv = APR_SUCCESS; - int sni_match = 0; - - /* The initial rustls generic session has been fed the client hello and - * we have extracted SNI and ALPN values (so present). - * Time to select the actual server_rec and application protocol that - * will be used on this connection. */ - ap_assert(cc); - sc = tls_conf_server_get(cc->server); - if (!cc->client_hello_seen) goto cleanup; - - if (cc->sni_hostname) { - if (ap_vhost_iterate_given_conn(c, find_vhost, (void*)cc->sni_hostname)) { - ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rv, c, APLOGNO(10337) - "vhost_init: virtual host found for SNI '%s'", cc->sni_hostname); - sni_match = 1; - } - else if (tls_util_name_matches_server(cc->sni_hostname, ap_server_conf)) { - ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rv, c, APLOGNO(10338) - "vhost_init: virtual host NOT found, but base server[%s] matches SNI '%s'", - ap_server_conf->server_hostname, cc->sni_hostname); - cc->server = ap_server_conf; - sni_match = 1; - } - else if (sc->strict_sni == TLS_FLAG_FALSE) { - ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rv, c, APLOGNO(10339) - "vhost_init: no virtual host found, relaxed SNI checking enabled, SNI '%s'", - cc->sni_hostname); - } - else { - ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rv, c, APLOGNO(10340) - "vhost_init: no virtual host, nor base server[%s] matches SNI '%s'", - c->base_server->server_hostname, cc->sni_hostname); - cc->server = sc->global->ap_server; - rv = APR_NOTFOUND; goto cleanup; - } - } - else { - ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(10341) - "vhost_init: no SNI hostname provided by client"); - } - - /* reinit, we might have a new server selected */ - sc = tls_conf_server_get(cc->server); - /* on relaxed SNI matches, we do not enforce the 503 of fallback - * certificates. */ - if (!cc->service_unavailable) { - cc->service_unavailable = sni_match? sc->service_unavailable : 0; - } - - /* if found or not, cc->server will be the server we use now to do - * the real handshake and, if successful, the traffic after that. - * Free the current session and create the real one for the - * selected server. */ - if (cc->rustls_server_config) { - rustls_server_config_free(cc->rustls_server_config); - cc->rustls_server_config = NULL; - } - rustls_connection_free(cc->rustls_connection); - cc->rustls_connection = NULL; - - rv = build_server_connection(&cc->rustls_connection, &cc->rustls_server_config, c); - -cleanup: - return rv; -} - -apr_status_t tls_core_conn_post_handshake(conn_rec *c) -{ - tls_conf_conn_t *cc = tls_conf_conn_get(c); - tls_conf_server_t *sc = tls_conf_server_get(cc->server); - const rustls_supported_ciphersuite *rsuite; - const rustls_certificate *cert; - apr_status_t rv = APR_SUCCESS; - - if (rustls_connection_is_handshaking(cc->rustls_connection)) { - rv = APR_EGENERAL; - ap_log_error(APLOG_MARK, APLOG_ERR, rv, cc->server, APLOGNO(10342) - "post handshake, but rustls claims to still be handshaking: %s", - cc->server->server_hostname); - goto cleanup; - } - - cc->tls_protocol_id = rustls_connection_get_protocol_version(cc->rustls_connection); - cc->tls_protocol_name = tls_proto_get_version_name(sc->global->proto, - cc->tls_protocol_id, c->pool); - rsuite = rustls_connection_get_negotiated_ciphersuite(cc->rustls_connection); - if (!rsuite) { - rv = APR_EGENERAL; - ap_log_error(APLOG_MARK, APLOG_ERR, rv, cc->server, APLOGNO(10343) - "post handshake, but rustls does not report negotiated cipher suite: %s", - cc->server->server_hostname); - goto cleanup; - } - cc->tls_cipher_id = rustls_supported_ciphersuite_get_suite(rsuite); - cc->tls_cipher_name = tls_proto_get_cipher_name(sc->global->proto, - cc->tls_cipher_id, c->pool); - ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, "post_handshake %s: %s [%s]", - cc->server->server_hostname, cc->tls_protocol_name, cc->tls_cipher_name); - - cert = rustls_connection_get_peer_certificate(cc->rustls_connection, 0); - if (cert) { - size_t i = 0; - - cc->peer_certs = apr_array_make(c->pool, 5, sizeof(const rustls_certificate*)); - while (cert) { - APR_ARRAY_PUSH(cc->peer_certs, const rustls_certificate*) = cert; - cert = rustls_connection_get_peer_certificate(cc->rustls_connection, ++i); - } - } - if (!cc->peer_certs && sc->client_auth == TLS_CLIENT_AUTH_REQUIRED) { - ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, c, APLOGNO(10344) - "A client certificate is required, but no acceptable certificate was presented."); - rv = APR_ECONNABORTED; - } - - rv = tls_var_handshake_done(c); -cleanup: - return rv; -} - -/** - * Return != 0, if a connection also serve requests for server <other>. - */ -static int tls_conn_compatible_for(tls_conf_conn_t *cc, server_rec *other) -{ - tls_conf_server_t *oc, *sc; - const rustls_certified_key *sk, *ok; - int i; - - /* - differences in certificates are the responsibility of the client. - * if it thinks the SNI server works for r->server, we are fine with that. - * - if there are differences in requirements to client certificates, we - * need to deny the request. - */ - if (!cc->server || !other) return 0; - if (cc->server == other) return 1; - oc = tls_conf_server_get(other); - if (!oc) return 0; - sc = tls_conf_server_get(cc->server); - if (!sc) return 0; - - /* same certified keys used? */ - if (sc->certified_keys->nelts != oc->certified_keys->nelts) return 0; - for (i = 0; i < sc->certified_keys->nelts; ++i) { - sk = APR_ARRAY_IDX(sc->certified_keys, i, const rustls_certified_key*); - ok = APR_ARRAY_IDX(oc->certified_keys, i, const rustls_certified_key*); - if (sk != ok) return 0; - } - - /* If the connection TLS version is below other other min one, no */ - if (oc->tls_protocol_min > 0 && cc->tls_protocol_id < oc->tls_protocol_min) return 0; - /* If the connection TLS cipher is listed as suppressed by other, no */ - if (oc->tls_supp_ciphers && tls_util_array_uint16_contains( - oc->tls_supp_ciphers, cc->tls_cipher_id)) return 0; - return 1; -} - -int tls_core_request_check(request_rec *r) -{ - conn_rec *c = r->connection; - tls_conf_conn_t *cc = tls_conf_conn_get(c->master? c->master : c); - int rv = DECLINED; /* do not object to the request */ - - /* If we are not enabled on this connection, leave. We are not renegotiating. - * Otherwise: - * - service is unavailable when we have only a fallback certificate or - * when a challenge protocol is active (ACME tls-alpn-01 for example). - * - with vhosts configured and no SNI from the client, deny access. - * - are servers compatible for connection sharing? - */ - if (!TLS_CONN_ST_IS_ENABLED(cc)) goto cleanup; - - ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 0, r, - "tls_core_request_check[%s, %d]: %s", r->hostname, - cc? cc->service_unavailable : 2, r->the_request); - if (cc->service_unavailable) { - rv = HTTP_SERVICE_UNAVAILABLE; goto cleanup; - } - if (!cc->sni_hostname && r->connection->vhost_lookup_data) { - rv = HTTP_FORBIDDEN; goto cleanup; - } - if (!tls_conn_compatible_for(cc, r->server)) { - rv = HTTP_MISDIRECTED_REQUEST; - ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(10345) - "Connection host %s, selected via SNI, and request host %s" - " have incompatible TLS configurations.", - cc->server->server_hostname, r->hostname); - goto cleanup; - } -cleanup: - return rv; -} - -apr_status_t tls_core_error(conn_rec *c, rustls_result rr, const char **perrstr) -{ - tls_conf_conn_t *cc = tls_conf_conn_get(c); - apr_status_t rv; - - rv = tls_util_rustls_error(c->pool, rr, perrstr); - if (cc) { - cc->last_error = rr; - cc->last_error_descr = *perrstr; - } - return rv; -} - -int tls_core_setup_outgoing(conn_rec *c) -{ - tls_conf_conn_t *cc; - int rv = DECLINED; - - ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c, - "tls_core_setup_outgoing called"); -#if AP_MODULE_MAGIC_AT_LEAST(20120211, 109) - if (!c->outgoing) goto cleanup; -#endif - cc = cc_get_or_make(c); - if (cc->state == TLS_CONN_ST_DISABLED) { - ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c, - "tls_core_setup_outgoing: already disabled"); - goto cleanup; - } - if (TLS_CONN_ST_IS_ENABLED(cc)) { - /* we already handle it, allow repeated calls */ - ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c, - "tls_core_setup_outgoing: already enabled"); - rv = OK; goto cleanup; - } - cc->outgoing = 1; - if (!cc->dc) { - /* In case there is not dir_conf bound for this connection, we fallback - * to the defaults in the base server (we have no virtual host config to use) */ - cc->dc = ap_get_module_config(c->base_server->lookup_defaults, &tls_module); - } - if (cc->dc->proxy_enabled != TLS_FLAG_TRUE) { - cc->state = TLS_CONN_ST_DISABLED; - ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c, - "tls_core_setup_outgoing: TLSProxyEngine not configured"); - goto cleanup; - } - /* we handle this connection */ - cc->state = TLS_CONN_ST_CLIENT_HELLO; - rv = OK; - -cleanup: - ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c, - "tls_core_setup_outgoing returns %s", rv == OK? "OK" : "DECLINED"); - return rv; -} diff --git a/modules/tls/tls_core.h b/modules/tls/tls_core.h deleted file mode 100644 index 6ee1713b5e..0000000000 --- a/modules/tls/tls_core.h +++ /dev/null @@ -1,184 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef tls_core_h -#define tls_core_h - -/* The module's state handling of a connection in normal chronological order, - */ -typedef enum { - TLS_CONN_ST_INIT, /* being initialized */ - TLS_CONN_ST_DISABLED, /* TLS is disabled here */ - TLS_CONN_ST_CLIENT_HELLO, /* TLS is enabled, prep handshake */ - TLS_CONN_ST_HANDSHAKE, /* TLS is enabled, handshake ongonig */ - TLS_CONN_ST_TRAFFIC, /* TLS is enabled, handshake done */ - TLS_CONN_ST_NOTIFIED, /* TLS is enabled, notification to end sent */ - TLS_CONN_ST_DONE, /* TLS is enabled, TLS has shut down */ -} tls_conn_state_t; - -#define TLS_CONN_ST_IS_ENABLED(cc) (cc && cc->state >= TLS_CONN_ST_CLIENT_HELLO) - -struct tls_filter_ctx_t; - -/* The modules configuration for a connection. Created at connection - * start and mutable during the lifetime of the connection. - * (A conn_rec is only ever processed by one thread at a time.) - */ -typedef struct { - server_rec *server; /* the server_rec selected for this connection, - * initially c->base_server, to be negotiated via SNI. */ - tls_conf_dir_t *dc; /* directory config applying here */ - tls_conn_state_t state; - int outgoing; /* != 0 iff outgoing connection (redundant once c->outgoing is everywhere) */ - int service_unavailable; /* we 503 all requests on this connection */ - tls_client_auth_t client_auth; /* how client authentication with certificates is used */ - int client_hello_seen; /* the client hello has been inspected */ - - rustls_connection *rustls_connection; /* the session used on this connection or NULL */ - const rustls_server_config *rustls_server_config; /* the config made for this connection (incoming) or NULL */ - const rustls_client_config *rustls_client_config; /* the config made for this connection (outgoing) or NULL */ - struct tls_filter_ctx_t *filter_ctx; /* the context used by this connection's tls filters */ - - apr_array_header_t *local_keys; /* rustls_certified_key* array of connection specific keys */ - const rustls_certified_key *key; /* the key selected for the session */ - int key_cloned; /* != 0 iff the key is a unique clone, to be freed */ - apr_array_header_t *peer_certs; /* handshaked peer ceritificates or NULL */ - const char *sni_hostname; /* the SNI value from the client hello, or NULL */ - const apr_array_header_t *alpn; /* the protocols proposed via ALPN by the client */ - const char *application_protocol; /* the ALPN selected protocol or NULL */ - - int session_id_cache_hit; /* if a submitted session id was found in our cache */ - - apr_uint16_t tls_protocol_id; /* the TLS version negotiated */ - const char *tls_protocol_name; /* the name of the TLS version negotiated */ - apr_uint16_t tls_cipher_id; /* the TLS cipher suite negotiated */ - const char *tls_cipher_name; /* the name of TLS cipher suite negotiated */ - - const char *user_name; /* != NULL if we derived a TLSUserName from the client_cert */ - apr_table_t *subprocess_env; /* common TLS variables for this connection */ - - rustls_result last_error; - const char *last_error_descr; - -} tls_conf_conn_t; - -/* Get the connection specific module configuration. */ -tls_conf_conn_t *tls_conf_conn_get(conn_rec *c); - -/* Set the module configuration for a connection. */ -void tls_conf_conn_set(conn_rec *c, tls_conf_conn_t *cc); - -/* Return OK iff this connection is a TSL connection (or a secondary on a TLS connection). */ -int tls_conn_check_ssl(conn_rec *c); - -/** - * Initialize the module's global and server specific settings. This runs - * in Apache's "post-config" phase, meaning the configuration has been read - * and checked for syntactic and other easily verifiable errors and now - * it is time to load everything in and make it ready for traffic. - * <p> a memory pool staying with us the whole time until the server stops/reloads. - * <ptemp> a temporary pool as a scratch buffer that will be destroyed shortly after. - * <base_server> the server for the global configuration which links -> next to - * all contained virtual hosts configured. - */ -apr_status_t tls_core_init(apr_pool_t *p, apr_pool_t *ptemp, server_rec *base_server); - -/** - * Initialize the module's outgoing connection settings. This runs - * in Apache's "post-config" phase after mod_proxy. - */ -apr_status_t tls_core_init_outgoing(apr_pool_t *p, apr_pool_t *ptemp, server_rec *base_server); - -/** - * Supply a directory configuration for the connection to work with. This - * maybe NULL. This can be called several times during the lifetime of a - * connection and must not change the current TLS state. - * @param c the connection - * @param dir_conf optional directory configuration that applies - */ -void tls_core_conn_bind(conn_rec *c, ap_conf_vector_t *dir_conf); - -/** - * Disable TLS on a new connection. Will do nothing on already initialized - * connections. - * @param c a new connection - */ -void tls_core_conn_disable(conn_rec *c); - -/** - * Initialize the tls_conf_connt_t for the connection - * and decide if TLS is enabled or not. - * @return OK if enabled, DECLINED otherwise - */ -int tls_core_pre_conn_init(conn_rec *c); - -/** - * Initialize the module for a TLS enabled connection. - * @param c a new connection - */ -apr_status_t tls_core_conn_init(conn_rec *c); - -/** - * Called when the ClientHello has been received and values from it - * have been extracted into the `tls_conf_conn_t` of the connection. - * - * Decides: - * - which `server_rec` this connection is for (SNI) - * - which application protocol to use (ALPN) - * This may be unsuccessful for several reasons. The SNI - * from the client may not be known or the selected server - * has not certificates available. etc. - * On success, a proper `rustls_connection` will have been - * created and set in the `tls_conf_conn_t` of the connection. - */ -apr_status_t tls_core_conn_seen_client_hello(conn_rec *c); - -/** - * The TLS handshake for the connection has been successfully performed. - * This means that TLS related properties, such as TLS version and cipher, - * are known and the props in `tls_conf_conn_t` of the connection - * can be set. - */ -apr_status_t tls_core_conn_post_handshake(conn_rec *c); - -/** - * After a request has been read, but before processing is started, we - * check if everything looks good to us: - * - was an SNI hostname provided by the client when we have vhosts to choose from? - * if not, we deny it. - * - if the SNI hostname and request host are not the same, are they - from TLS - * point of view - 'compatible' enough? For example, if one server requires - * client certificates and the other not (or with different settings), such - * a request will also be denied. - * returns DECLINED if everything is ok, otherwise an HTTP response code to - * generate an error page for. - */ -int tls_core_request_check(request_rec *r); - -/** - * A Rustls error happened while processing the connection. Look up an - * error description, determine the apr_status_t to use for it and remember - * this as the last error at tls_conf_conn_t. - */ -apr_status_t tls_core_error(conn_rec *c, rustls_result rr, const char **perrstr); - -/** - * Determine if we handle the TLS for an outgoing connection or not. - * @param c the connection - * @return OK if we handle the TLS, DECLINED otherwise. - */ -int tls_core_setup_outgoing(conn_rec *c); - -#endif /* tls_core_h */ diff --git a/modules/tls/tls_filter.c b/modules/tls/tls_filter.c deleted file mode 100644 index 0ee6be61a2..0000000000 --- a/modules/tls/tls_filter.c +++ /dev/null @@ -1,1017 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include <assert.h> -#include <apr_lib.h> -#include <apr_strings.h> - -#include <httpd.h> -#include <http_connection.h> -#include <http_core.h> -#include <http_request.h> -#include <http_log.h> -#include <ap_socache.h> - -#include <rustls.h> - -#include "tls_proto.h" -#include "tls_conf.h" -#include "tls_core.h" -#include "tls_filter.h" -#include "tls_util.h" - - -extern module AP_MODULE_DECLARE_DATA tls_module; -APLOG_USE_MODULE(tls); - - -static rustls_io_result tls_read_callback( - void *userdata, unsigned char *buf, size_t n, size_t *out_n) -{ - tls_data_t *d = userdata; - size_t len = d->len > n? n : d->len; - memcpy(buf, d->data, len); - *out_n = len; - return 0; -} - -/** - * Provide TLS encrypted data to the rustls server_session in <fctx->cc->rustls_connection>. - * - * If <fctx->fin_tls_bb> holds data, take it from there. Otherwise perform a - * read via the network filters below us into that brigade. - * - * <fctx->fin_block> determines if we do a blocking read inititally or not. - * If the first read did to not produce enough data, any secondary read is done - * non-blocking. - * - * Had any data been added to <fctx->cc->rustls_connection>, call its "processing" - * function to handle the added data before leaving. - */ -static apr_status_t read_tls_to_rustls( - tls_filter_ctx_t *fctx, apr_size_t len, apr_read_type_e block, int errors_expected) -{ - tls_data_t d; - apr_size_t rlen; - apr_off_t passed = 0; - rustls_result rr = RUSTLS_RESULT_OK; - int os_err; - apr_status_t rv = APR_SUCCESS; - - if (APR_BRIGADE_EMPTY(fctx->fin_tls_bb)) { - ap_log_error(APLOG_MARK, APLOG_TRACE2, rv, fctx->cc->server, - "read_tls_to_rustls, get data from network, block=%d", block); - rv = ap_get_brigade(fctx->fin_ctx->next, fctx->fin_tls_bb, - AP_MODE_READBYTES, block, (apr_off_t)len); - if (APR_SUCCESS != rv) { - goto cleanup; - } - } - - while (!APR_BRIGADE_EMPTY(fctx->fin_tls_bb) && passed < (apr_off_t)len) { - apr_bucket *b = APR_BRIGADE_FIRST(fctx->fin_tls_bb); - - if (APR_BUCKET_IS_EOS(b)) { - ap_log_error(APLOG_MARK, APLOG_TRACE2, rv, fctx->cc->server, - "read_tls_to_rustls, EOS"); - if (fctx->fin_tls_buffer_bb) { - apr_brigade_cleanup(fctx->fin_tls_buffer_bb); - } - rv = APR_EOF; goto cleanup; - } - - rv = apr_bucket_read(b, (const char**)&d.data, &d.len, block); - if (APR_STATUS_IS_EOF(rv)) { - apr_bucket_delete(b); - continue; - } - else if (APR_SUCCESS != rv) { - goto cleanup; - } - - if (d.len > 0) { - /* got something, do not block on getting more */ - block = APR_NONBLOCK_READ; - - os_err = rustls_connection_read_tls(fctx->cc->rustls_connection, - tls_read_callback, &d, &rlen); - if (os_err) { - rv = APR_FROM_OS_ERROR(os_err); - goto cleanup; - } - - if (fctx->fin_tls_buffer_bb) { - /* we buffer for later replay on the 'real' rustls_connection */ - apr_brigade_write(fctx->fin_tls_buffer_bb, NULL, NULL, (const char*)d.data, rlen); - } - if (rlen >= d.len) { - apr_bucket_delete(b); - } - else { - b->start += (apr_off_t)rlen; - b->length -= rlen; - } - fctx->fin_bytes_in_rustls += (apr_off_t)d.len; - passed += (apr_off_t)rlen; - } - else if (d.len == 0) { - apr_bucket_delete(b); - } - } - - if (passed > 0) { - rr = rustls_connection_process_new_packets(fctx->cc->rustls_connection); - if (rr != RUSTLS_RESULT_OK) goto cleanup; - } - -cleanup: - if (rr != RUSTLS_RESULT_OK) { - rv = APR_ECONNRESET; - if (!errors_expected) { - const char *err_descr = ""; - rv = tls_core_error(fctx->c, rr, &err_descr); - ap_log_cerror(APLOG_MARK, APLOG_WARNING, rv, fctx->c, APLOGNO(10353) - "processing TLS data: [%d] %s", (int)rr, err_descr); - } - } - else if (APR_STATUS_IS_EOF(rv) && passed > 0) { - /* encountering EOF while actually having read sth is a success. */ - rv = APR_SUCCESS; - } - else if (APR_SUCCESS == rv && passed == 0 && fctx->fin_block == APR_NONBLOCK_READ) { - rv = APR_EAGAIN; - } - else { - ap_log_error(APLOG_MARK, APLOG_TRACE2, rv, fctx->cc->server, - "read_tls_to_rustls, passed %ld bytes to rustls", (long)passed); - } - return rv; -} - -static apr_status_t fout_pass_tls_to_net(tls_filter_ctx_t *fctx) -{ - apr_status_t rv = APR_SUCCESS; - - if (!APR_BRIGADE_EMPTY(fctx->fout_tls_bb)) { - rv = ap_pass_brigade(fctx->fout_ctx->next, fctx->fout_tls_bb); - if (APR_SUCCESS == rv && fctx->c->aborted) { - rv = APR_ECONNRESET; - } - fctx->fout_bytes_in_tls_bb = 0; - apr_brigade_cleanup(fctx->fout_tls_bb); - } - return rv; -} - -static apr_status_t fout_pass_all_to_net( - tls_filter_ctx_t *fctx, int flush); - -static apr_status_t filter_abort( - tls_filter_ctx_t *fctx) -{ - apr_status_t rv; - - if (fctx->cc->state != TLS_CONN_ST_DONE) { - if (fctx->cc->state > TLS_CONN_ST_CLIENT_HELLO) { - rustls_connection_send_close_notify(fctx->cc->rustls_connection); - rv = fout_pass_all_to_net(fctx, 1); - ap_log_cerror(APLOG_MARK, APLOG_TRACE2, rv, fctx->c, "filter_abort, flushed output"); - } - fctx->c->aborted = 1; - fctx->cc->state = TLS_CONN_ST_DONE; - } - return APR_ECONNABORTED; -} - -static apr_status_t filter_recv_client_hello(tls_filter_ctx_t *fctx) -{ - apr_status_t rv = APR_SUCCESS; - - ap_log_error(APLOG_MARK, APLOG_TRACE2, 0, fctx->cc->server, - "tls_filter, server=%s, recv client hello", fctx->cc->server->server_hostname); - /* only for incoming connections */ - ap_assert(!fctx->cc->outgoing); - - if (rustls_connection_is_handshaking(fctx->cc->rustls_connection)) { - apr_bucket_brigade *bb_tmp; - - ap_log_cerror(APLOG_MARK, APLOG_TRACE2, rv, fctx->c, "filter_recv_client_hello: start"); - fctx->fin_tls_buffer_bb = apr_brigade_create(fctx->c->pool, fctx->c->bucket_alloc); - do { - if (rustls_connection_wants_read(fctx->cc->rustls_connection)) { - rv = read_tls_to_rustls(fctx, fctx->fin_max_in_rustls, APR_BLOCK_READ, 1); - if (APR_SUCCESS != rv) { - if (fctx->cc->client_hello_seen) { - rv = APR_EAGAIN; /* we got what we needed */ - break; - } - /* Something went wrong before we saw the client hello. - * This is a real error on which we should not continue. */ - goto cleanup; - } - } - /* Notice: we never write here to the client. We just want to inspect - * the client hello. */ - } while (!fctx->cc->client_hello_seen); - - /* We have seen the client hello and selected the server (vhost) to use - * on this connection. Set up the 'real' rustls_connection based on the - * servers 'real' rustls_config. */ - rv = tls_core_conn_seen_client_hello(fctx->c); - if (APR_SUCCESS != rv) goto cleanup; - - bb_tmp = fctx->fin_tls_bb; /* data we have yet to feed to rustls */ - fctx->fin_tls_bb = fctx->fin_tls_buffer_bb; /* data we already fed to the pre_session */ - fctx->fin_tls_buffer_bb = NULL; - APR_BRIGADE_CONCAT(fctx->fin_tls_bb, bb_tmp); /* all tls data from the client so far, reloaded */ - apr_brigade_destroy(bb_tmp); - rv = APR_SUCCESS; - } - -cleanup: - ap_log_cerror(APLOG_MARK, APLOG_TRACE2, rv, fctx->c, "filter_recv_client_hello: done"); - return rv; -} - -static apr_status_t filter_send_client_hello(tls_filter_ctx_t *fctx) -{ - apr_status_t rv = APR_SUCCESS; - - ap_log_error(APLOG_MARK, APLOG_TRACE2, 0, fctx->cc->server, - "tls_filter, server=%s, send client hello", fctx->cc->server->server_hostname); - /* Only for outgoing connections */ - ap_assert(fctx->cc->outgoing); - if (rustls_connection_is_handshaking(fctx->cc->rustls_connection)) { - while (rustls_connection_wants_write(fctx->cc->rustls_connection)) { - /* write flushed, so it really gets out */ - rv = fout_pass_all_to_net(fctx, 1); - if (APR_SUCCESS != rv) goto cleanup; - } - } - -cleanup: - return rv; -} - -/** - * While <fctx->cc->rustls_connection> indicates that a handshake is ongoing, - * write TLS data from and read network TLS data to the server session. - * - * @return APR_SUCCESS when the handshake is completed - */ -static apr_status_t filter_do_handshake( - tls_filter_ctx_t *fctx) -{ - apr_status_t rv = APR_SUCCESS; - - ap_log_error(APLOG_MARK, APLOG_TRACE2, 0, fctx->cc->server, - "tls_filter, server=%s, do handshake", fctx->cc->server->server_hostname); - if (rustls_connection_is_handshaking(fctx->cc->rustls_connection)) { - do { - if (rustls_connection_wants_write(fctx->cc->rustls_connection)) { - rv = fout_pass_all_to_net(fctx, 1); - if (APR_SUCCESS != rv) goto cleanup; - } - else if (rustls_connection_wants_read(fctx->cc->rustls_connection)) { - rv = read_tls_to_rustls(fctx, fctx->fin_max_in_rustls, APR_BLOCK_READ, 0); - if (APR_SUCCESS != rv) goto cleanup; - } - } - while (rustls_connection_is_handshaking(fctx->cc->rustls_connection)); - - /* rustls reports the TLS handshake to be done, when it *internally* has - * processed everything into its buffers. Not when the buffers have been - * send to the other side. */ - if (rustls_connection_wants_write(fctx->cc->rustls_connection)) { - rv = fout_pass_all_to_net(fctx, 1); - if (APR_SUCCESS != rv) goto cleanup; - } - } -cleanup: - ap_log_error(APLOG_MARK, APLOG_TRACE2, rv, fctx->cc->server, - "tls_filter, server=%s, handshake done", fctx->cc->server->server_hostname); - if (APR_SUCCESS != rv) { - if (fctx->cc->last_error_descr) { - ap_log_cerror(APLOG_MARK, APLOG_INFO, APR_ECONNABORTED, fctx->c, APLOGNO(10354) - "handshake failed: %s", fctx->cc->last_error_descr); - } - } - return rv; -} - -static apr_status_t progress_tls_atleast_to(tls_filter_ctx_t *fctx, tls_conn_state_t state) -{ - apr_status_t rv = APR_SUCCESS; - - /* handle termination immediately */ - if (state == TLS_CONN_ST_DONE) { - rv = APR_ECONNABORTED; - goto cleanup; - } - - if (state > TLS_CONN_ST_CLIENT_HELLO - && TLS_CONN_ST_CLIENT_HELLO == fctx->cc->state) { - rv = tls_core_conn_init(fctx->c); - if (APR_SUCCESS != rv) goto cleanup; - - if (fctx->cc->outgoing) { - rv = filter_send_client_hello(fctx); - } - else { - rv = filter_recv_client_hello(fctx); - } - if (APR_SUCCESS != rv) goto cleanup; - fctx->cc->state = TLS_CONN_ST_HANDSHAKE; - } - - if (state > TLS_CONN_ST_HANDSHAKE - && TLS_CONN_ST_HANDSHAKE== fctx->cc->state) { - rv = filter_do_handshake(fctx); - if (APR_SUCCESS != rv) goto cleanup; - rv = tls_core_conn_post_handshake(fctx->c); - if (APR_SUCCESS != rv) goto cleanup; - fctx->cc->state = TLS_CONN_ST_TRAFFIC; - } - - if (state < fctx->cc->state) { - rv = APR_ECONNABORTED; - } - -cleanup: - if (APR_SUCCESS != rv) { - filter_abort(fctx); /* does change the state itself */ - } - return rv; -} - -/** - * The connection filter converting TLS encrypted network data into plain, unencrpyted - * traffic data to be processed by filters above it in the filter chain. - * - * Unfortunately, Apache's filter infrastructure places a heavy implementation - * complexity on its input filters for the various use cases its HTTP/1.x parser - * (mainly) finds convenient: - * - * <bb> the bucket brigade to place the data into. - * <mode> one of - * - AP_MODE_READBYTES: just add up to <readbytes> data into <bb> - * - AP_MODE_GETLINE: make a best effort to get data up to and including a CRLF. - * it can be less, but not more t than that. - * - AP_MODE_EATCRLF: never used, we puke on it. - * - AP_MODE_SPECULATIVE: read data without consuming it. - * - AP_MODE_EXHAUSTIVE: never used, we puke on it. - * - AP_MODE_INIT: called once on a connection. needs to pass down the filter - * chain, giving every filter the change to "INIT". - * <block> do blocking or non-blocking reads - * <readbytes> max amount of data to add to <bb>, seems to be 0 for GETLINE - */ -static apr_status_t filter_conn_input( - ap_filter_t *f, apr_bucket_brigade *bb, ap_input_mode_t mode, - apr_read_type_e block, apr_off_t readbytes) -{ - tls_filter_ctx_t *fctx = f->ctx; - apr_status_t rv = APR_SUCCESS; - apr_off_t passed = 0, nlen; - rustls_result rr = RUSTLS_RESULT_OK; - apr_size_t in_buf_len; - char *in_buf = NULL; - - fctx->fin_block = block; - if (f->c->aborted) { - rv = filter_abort(fctx); goto cleanup; - } - - ap_log_error(APLOG_MARK, APLOG_TRACE2, 0, fctx->cc->server, - "tls_filter_conn_input, server=%s, mode=%d, block=%d, readbytes=%ld", - fctx->cc->server->server_hostname, mode, block, (long)readbytes); - - rv = progress_tls_atleast_to(fctx, TLS_CONN_ST_TRAFFIC); - if (APR_SUCCESS != rv) goto cleanup; /* this also leaves on APR_EAGAIN */ - - if (!fctx->cc->rustls_connection) { - return ap_get_brigade(f->next, bb, mode, block, readbytes); - } - -#if AP_MODULE_MAGIC_AT_LEAST(20200420, 1) - ap_filter_reinstate_brigade(f, fctx->fin_plain_bb, NULL); -#endif - - if (AP_MODE_INIT == mode) { - /* INIT is used to trigger the handshake, it does not return any traffic data. */ - goto cleanup; - } - - /* If we have nothing buffered, try getting more input. - * a) ask rustls_connection for decrypted data, if it has any. - * Note that only full records can be decrypted. We might have - * written TLS data to the session, but that does not mean it - * can give unencryted data out again. - * b) read TLS bytes from the network and feed them to the rustls session. - * c) go back to a) if b) added data. - */ - while (APR_BRIGADE_EMPTY(fctx->fin_plain_bb)) { - apr_size_t rlen = 0; - apr_bucket *b; - - if (fctx->fin_bytes_in_rustls > 0) { - in_buf_len = APR_BUCKET_BUFF_SIZE; - in_buf = ap_calloc(in_buf_len, sizeof(char)); - rr = rustls_connection_read(fctx->cc->rustls_connection, - (unsigned char*)in_buf, in_buf_len, &rlen); - if (rr == RUSTLS_RESULT_PLAINTEXT_EMPTY) { - rr = RUSTLS_RESULT_OK; - rlen = 0; - } - if (rr != RUSTLS_RESULT_OK) goto cleanup; - ap_log_cerror(APLOG_MARK, APLOG_TRACE2, rv, fctx->c, - "tls_filter_conn_input: got %ld plain bytes from rustls", (long)rlen); - if (rlen > 0) { - b = apr_bucket_heap_create(in_buf, rlen, free, fctx->c->bucket_alloc); - APR_BRIGADE_INSERT_TAIL(fctx->fin_plain_bb, b); - } - else { - free(in_buf); - } - in_buf = NULL; - } - if (rlen == 0) { - /* that did not produce anything either. try getting more - * TLS data from the network into the rustls session. */ - fctx->fin_bytes_in_rustls = 0; - rv = read_tls_to_rustls(fctx, fctx->fin_max_in_rustls, block, 0); - if (APR_SUCCESS != rv) goto cleanup; /* this also leave on APR_EAGAIN */ - } - } - - if (AP_MODE_GETLINE == mode) { - if (readbytes <= 0) readbytes = HUGE_STRING_LEN; - rv = tls_util_brigade_split_line(bb, fctx->fin_plain_bb, block, readbytes, &nlen); - if (APR_SUCCESS != rv) goto cleanup; - passed += nlen; - } - else if (AP_MODE_READBYTES == mode) { - ap_assert(readbytes > 0); - rv = tls_util_brigade_transfer(bb, fctx->fin_plain_bb, readbytes, &nlen); - if (APR_SUCCESS != rv) goto cleanup; - passed += nlen; - } - else if (AP_MODE_SPECULATIVE == mode) { - ap_assert(readbytes > 0); - rv = tls_util_brigade_copy(bb, fctx->fin_plain_bb, readbytes, &nlen); - if (APR_SUCCESS != rv) goto cleanup; - passed += nlen; - } - else if (AP_MODE_EXHAUSTIVE == mode) { - /* return all we have */ - APR_BRIGADE_CONCAT(bb, fctx->fin_plain_bb); - } - else { - /* We do support any other mode */ - rv = APR_ENOTIMPL; goto cleanup; - } - - fout_pass_all_to_net(fctx, 0); - -cleanup: - if (NULL != in_buf) free(in_buf); - - if (APLOGctrace3(fctx->c)) { - tls_util_bb_log(fctx->c, APLOG_TRACE3, "tls_input, fctx->fin_plain_bb", fctx->fin_plain_bb); - tls_util_bb_log(fctx->c, APLOG_TRACE3, "tls_input, bb", bb); - } - if (rr != RUSTLS_RESULT_OK) { - const char *err_descr = ""; - - rv = tls_core_error(fctx->c, rr, &err_descr); - ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rv, fctx->c, APLOGNO(10355) - "tls_filter_conn_input: [%d] %s", (int)rr, err_descr); - } - else if (APR_STATUS_IS_EAGAIN(rv)) { - ap_log_cerror(APLOG_MARK, APLOG_TRACE4, rv, fctx->c, - "tls_filter_conn_input: no data available"); - } - else if (APR_SUCCESS != rv) { - ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rv, fctx->c, APLOGNO(10356) - "tls_filter_conn_input"); - } - else { - ap_log_cerror(APLOG_MARK, APLOG_TRACE2, rv, fctx->c, - "tls_filter_conn_input: passed %ld bytes", (long)passed); - } - -#if AP_MODULE_MAGIC_AT_LEAST(20200420, 1) - if (APR_SUCCESS == rv || APR_STATUS_IS_EAGAIN(rv)) { - ap_filter_setaside_brigade(f, fctx->fin_plain_bb); - } -#endif - return rv; -} - -static rustls_io_result tls_write_callback( - void *userdata, const unsigned char *buf, size_t n, size_t *out_n) -{ - tls_filter_ctx_t *fctx = userdata; - apr_status_t rv; - - if ((apr_off_t)n + fctx->fout_bytes_in_tls_bb >= (apr_off_t)fctx->fout_auto_flush_size) { - apr_bucket *b = apr_bucket_transient_create((const char*)buf, n, fctx->fout_tls_bb->bucket_alloc); - APR_BRIGADE_INSERT_TAIL(fctx->fout_tls_bb, b); - fctx->fout_bytes_in_tls_bb += (apr_off_t)n; - rv = fout_pass_tls_to_net(fctx); - *out_n = n; - } - else { - rv = apr_brigade_write(fctx->fout_tls_bb, NULL, NULL, (const char*)buf, n); - if (APR_SUCCESS != rv) goto cleanup; - fctx->fout_bytes_in_tls_bb += (apr_off_t)n; - *out_n = n; - } -cleanup: - ap_log_error(APLOG_MARK, APLOG_TRACE5, rv, fctx->cc->server, - "tls_write_callback: %ld bytes", (long)n); - return APR_TO_OS_ERROR(rv); -} - -static rustls_io_result tls_write_vectored_callback( - void *userdata, const rustls_iovec *riov, size_t count, size_t *out_n) -{ - tls_filter_ctx_t *fctx = userdata; - const struct iovec *iov = (const struct iovec*)riov; - apr_status_t rv; - size_t i, n = 0; - apr_bucket *b; - - for (i = 0; i < count; ++i, ++iov) { - b = apr_bucket_transient_create((const char*)iov->iov_base, iov->iov_len, fctx->fout_tls_bb->bucket_alloc); - APR_BRIGADE_INSERT_TAIL(fctx->fout_tls_bb, b); - n += iov->iov_len; - } - fctx->fout_bytes_in_tls_bb += (apr_off_t)n; - rv = fout_pass_tls_to_net(fctx); - *out_n = n; - ap_log_error(APLOG_MARK, APLOG_TRACE5, rv, fctx->cc->server, - "tls_write_vectored_callback: %ld bytes in %d slices", (long)n, (int)count); - return APR_TO_OS_ERROR(rv); -} - -#define TLS_WRITE_VECTORED 1 -/** - * Read TLS encrypted data from <fctx->cc->rustls_connection> and pass it down - * Apache's filter chain to the network. - * - * For now, we always FLUSH the data, since that is what we need during handshakes. - */ -static apr_status_t fout_pass_rustls_to_tls(tls_filter_ctx_t *fctx) -{ - apr_status_t rv = APR_SUCCESS; - - if (rustls_connection_wants_write(fctx->cc->rustls_connection)) { - size_t dlen; - int os_err; - - if (TLS_WRITE_VECTORED) { - do { - os_err = rustls_connection_write_tls_vectored( - fctx->cc->rustls_connection, tls_write_vectored_callback, fctx, &dlen); - if (os_err) { - rv = APR_FROM_OS_ERROR(os_err); - goto cleanup; - } - } - while (rustls_connection_wants_write(fctx->cc->rustls_connection)); - } - else { - do { - os_err = rustls_connection_write_tls( - fctx->cc->rustls_connection, tls_write_callback, fctx, &dlen); - if (os_err) { - rv = APR_FROM_OS_ERROR(os_err); - goto cleanup; - } - } - while (rustls_connection_wants_write(fctx->cc->rustls_connection)); - ap_log_cerror(APLOG_MARK, APLOG_TRACE3, rv, fctx->c, - "fout_pass_rustls_to_tls, %ld bytes ready for network", (long)fctx->fout_bytes_in_tls_bb); - fctx->fout_bytes_in_rustls = 0; - } - } -cleanup: - return rv; -} - -static apr_status_t fout_pass_buf_to_rustls( - tls_filter_ctx_t *fctx, const char *buf, apr_size_t len) -{ - apr_status_t rv = APR_SUCCESS; - rustls_result rr = RUSTLS_RESULT_OK; - apr_size_t written; - - while (len) { - /* check if we will exceed the limit of data in rustls. - * rustls does not guarantuee that it will accept all data, so we - * iterate and flush when needed. */ - if (fctx->fout_bytes_in_rustls + (apr_off_t)len > (apr_off_t)fctx->fout_max_in_rustls) { - rv = fout_pass_rustls_to_tls(fctx); - if (APR_SUCCESS != rv) goto cleanup; - } - - rr = rustls_connection_write(fctx->cc->rustls_connection, - (const unsigned char*)buf, len, &written); - if (rr != RUSTLS_RESULT_OK) goto cleanup; - ap_assert(written <= len); - fctx->fout_bytes_in_rustls += (apr_off_t)written; - buf += written; - len -= written; - if (written == 0) { - rv = APR_EAGAIN; - ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, fctx->c, APLOGNO(10357) - "fout_pass_buf_to_rustls: not read by rustls at all"); - goto cleanup; - } - } -cleanup: - if (rr != RUSTLS_RESULT_OK) { - const char *err_descr = ""; - rv = tls_core_error(fctx->c, rr, &err_descr); - ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rv, fctx->c, APLOGNO(10358) - "fout_pass_buf_to_tls to rustls: [%d] %s", (int)rr, err_descr); - } - return rv; -} - -static apr_status_t fout_pass_all_to_tls(tls_filter_ctx_t *fctx) -{ - apr_status_t rv = APR_SUCCESS; - - if (fctx->fout_buf_plain_len) { - rv = fout_pass_buf_to_rustls(fctx, fctx->fout_buf_plain, fctx->fout_buf_plain_len); - ap_log_cerror(APLOG_MARK, APLOG_TRACE2, rv, fctx->c, - "fout_pass_all_to_tls: %ld plain bytes written to rustls", - (long)fctx->fout_buf_plain_len); - if (APR_SUCCESS != rv) goto cleanup; - fctx->fout_buf_plain_len = 0; - } - - rv = fout_pass_rustls_to_tls(fctx); -cleanup: - return rv; -} - -static apr_status_t fout_pass_all_to_net(tls_filter_ctx_t *fctx, int flush) -{ - apr_status_t rv; - - rv = fout_pass_all_to_tls(fctx); - if (APR_SUCCESS != rv) goto cleanup; - if (flush) { - apr_bucket *b = apr_bucket_flush_create(fctx->fout_tls_bb->bucket_alloc); - APR_BRIGADE_INSERT_TAIL(fctx->fout_tls_bb, b); - } - rv = fout_pass_tls_to_net(fctx); -cleanup: - return rv; -} - -static apr_status_t fout_add_bucket_to_plain(tls_filter_ctx_t *fctx, apr_bucket *b) -{ - const char *data; - apr_size_t dlen, buf_remain; - apr_status_t rv = APR_SUCCESS; - - ap_assert((apr_size_t)-1 != b->length); - if (b->length == 0) { - apr_bucket_delete(b); - goto cleanup; - } - - buf_remain = fctx->fout_buf_plain_size - fctx->fout_buf_plain_len; - if (buf_remain == 0) { - rv = fout_pass_all_to_tls(fctx); - if (APR_SUCCESS != rv) goto cleanup; - buf_remain = fctx->fout_buf_plain_size - fctx->fout_buf_plain_len; - ap_assert(buf_remain > 0); - } - if (b->length > buf_remain) { - apr_bucket_split(b, buf_remain); - } - rv = apr_bucket_read(b, &data, &dlen, APR_BLOCK_READ); - if (APR_SUCCESS != rv) goto cleanup; - /*if (dlen > TLS_PREF_PLAIN_CHUNK_SIZE)*/ - ap_assert(dlen <= buf_remain); - memcpy(fctx->fout_buf_plain + fctx->fout_buf_plain_len, data, dlen); - fctx->fout_buf_plain_len += dlen; - apr_bucket_delete(b); -cleanup: - return rv; -} - -static apr_status_t fout_add_bucket_to_tls(tls_filter_ctx_t *fctx, apr_bucket *b) -{ - apr_status_t rv; - - rv = fout_pass_all_to_tls(fctx); - if (APR_SUCCESS != rv) goto cleanup; - APR_BUCKET_REMOVE(b); - APR_BRIGADE_INSERT_TAIL(fctx->fout_tls_bb, b); - if (AP_BUCKET_IS_EOC(b)) { - rustls_connection_send_close_notify(fctx->cc->rustls_connection); - fctx->cc->state = TLS_CONN_ST_NOTIFIED; - rv = fout_pass_rustls_to_tls(fctx); - if (APR_SUCCESS != rv) goto cleanup; - } -cleanup: - return rv; -} - -static apr_status_t fout_append_plain(tls_filter_ctx_t *fctx, apr_bucket *b) -{ - const char *data; - apr_size_t dlen, buf_remain; - rustls_result rr = RUSTLS_RESULT_OK; - apr_status_t rv = APR_SUCCESS; - const char *lbuf = NULL; - int flush = 0; - - if (b) { - /* if our plain buffer is full, now is a good time to flush it. */ - buf_remain = fctx->fout_buf_plain_size - fctx->fout_buf_plain_len; - if (buf_remain == 0) { - rv = fout_pass_all_to_tls(fctx); - if (APR_SUCCESS != rv) goto cleanup; - buf_remain = fctx->fout_buf_plain_size - fctx->fout_buf_plain_len; - ap_assert(buf_remain > 0); - } - - /* Resolve any indeterminate bucket to a "real" one by reading it. */ - if ((apr_size_t)-1 == b->length) { - rv = apr_bucket_read(b, &data, &dlen, APR_BLOCK_READ); - if (APR_STATUS_IS_EOF(rv)) { - apr_bucket_delete(b); - goto maybe_flush; - } - else if (APR_SUCCESS != rv) goto cleanup; - } - /* Now `b` is the bucket that we need to append and consume */ - if (APR_BUCKET_IS_METADATA(b)) { - /* outgoing buckets: - * [PLAINDATA META PLAINDATA META META] - * need to become: - * [TLSDATA META TLSDATA META META] - * because we need to send the meta buckets down the - * network filters. */ - rv = fout_add_bucket_to_tls(fctx, b); - flush = 1; - } - else if (b->length == 0) { - apr_bucket_delete(b); - } - else if (b->length < 1024 || fctx->fout_buf_plain_len > 0) { - /* we want to buffer small chunks to create larger TLS records and - * not leak security relevant information. So, we buffer small - * chunks and add (parts of) later, larger chunks if the plain - * buffer contains data. */ - rv = fout_add_bucket_to_plain(fctx, b); - if (APR_SUCCESS != rv) goto cleanup; - } - else { - /* we have a large chunk and our plain buffer is empty, write it - * directly into rustls. */ -#define TLS_FILE_CHUNK_SIZE 4 * TLS_PREF_PLAIN_CHUNK_SIZE - if (b->length > TLS_FILE_CHUNK_SIZE) { - apr_bucket_split(b, TLS_FILE_CHUNK_SIZE); - } - - if (APR_BUCKET_IS_FILE(b) - && (lbuf = malloc(b->length))) { - /* A file bucket is a most wonderous thing. Since the dawn of time, - * it has been subject to many optimizations for efficient handling - * of large data in the server: - * - unless one reads from it, it will just consist of a file handle - * and the offset+length information. - * - a apr_bucket_read() will transform itself to a bucket holding - * some 8000 bytes of data (APR_BUCKET_BUFF_SIZE), plus a following - * bucket that continues to hold the file handle and updated offsets/length - * information. - * Using standard bucket brigade handling, one would send 8000 bytes - * chunks to the network and that is fine for many occasions. - * - to have improved performance, the http: network handler takes - * the file handle directly and uses sendfile() when the OS supports it. - * - But there is not sendfile() for TLS (netflix did some experiments). - * So. - * rustls will try to collect max length traffic data into ont TLS - * message, but it can only work with what we gave it. If we give it buffers - * that fit what it wants to assemble already, its work is much easier. - * - * We can read file buckets in large chunks than APR_BUCKET_BUFF_SIZE, - * with a bit of knowledge about how they work. - */ - apr_bucket_file *f = (apr_bucket_file *)b->data; - apr_file_t *fd = f->fd; - apr_off_t offset = b->start; - - dlen = b->length; - rv = apr_file_seek(fd, APR_SET, &offset); - if (APR_SUCCESS != rv) goto cleanup; - rv = apr_file_read(fd, (void*)lbuf, &dlen); - if (APR_SUCCESS != rv && !APR_STATUS_IS_EOF(rv)) goto cleanup; - rv = fout_pass_buf_to_rustls(fctx, lbuf, dlen); - if (APR_SUCCESS != rv) goto cleanup; - apr_bucket_delete(b); - } - else { - rv = apr_bucket_read(b, &data, &dlen, APR_BLOCK_READ); - if (APR_SUCCESS != rv) goto cleanup; - rv = fout_pass_buf_to_rustls(fctx, data, dlen); - if (APR_SUCCESS != rv) goto cleanup; - apr_bucket_delete(b); - } - } - } - -maybe_flush: - if (flush) { - rv = fout_pass_all_to_net(fctx, 1); - if (APR_SUCCESS != rv) goto cleanup; - } - -cleanup: - if (lbuf) free((void*)lbuf); - if (rr != RUSTLS_RESULT_OK) { - const char *err_descr = ""; - rv = tls_core_error(fctx->c, rr, &err_descr); - ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rv, fctx->c, APLOGNO(10359) - "write_bucket_to_rustls: [%d] %s", (int)rr, err_descr); - } - return rv; -} - -/** - * The connection filter converting plain, unencrypted traffic data into TLS - * encrypted bytes and send the down the Apache filter chain out to the network. - * - * <bb> the data to send, including "meta data" such as FLUSH indicators - * to force filters to write any data set aside (an apache term for - * 'buffering'). - * The buckets in <bb> need to be completely consumed, e.g. <bb> will be - * empty on a successful return. but unless FLUSHed, filters may hold - * buckets back internally, for various reasons. However they always - * need to be processed in the order they arrive. - */ -static apr_status_t filter_conn_output( - ap_filter_t *f, apr_bucket_brigade *bb) -{ - tls_filter_ctx_t *fctx = f->ctx; - apr_status_t rv = APR_SUCCESS; - rustls_result rr = RUSTLS_RESULT_OK; - - if (f->c->aborted) { - ap_log_cerror(APLOG_MARK, APLOG_TRACE4, 0, fctx->c, - "tls_filter_conn_output: aborted conn"); - apr_brigade_cleanup(bb); - rv = APR_ECONNABORTED; goto cleanup; - } - - rv = progress_tls_atleast_to(fctx, TLS_CONN_ST_TRAFFIC); - if (APR_SUCCESS != rv) goto cleanup; /* this also leaves on APR_EAGAIN */ - - if (fctx->cc->state == TLS_CONN_ST_DONE) { - /* have done everything, just pass through */ - ap_log_cerror(APLOG_MARK, APLOG_TRACE4, 0, fctx->c, - "tls_filter_conn_output: tls session is already done"); - rv = ap_pass_brigade(f->next, bb); - goto cleanup; - } - - ap_log_error(APLOG_MARK, APLOG_TRACE2, 0, fctx->cc->server, - "tls_filter_conn_output, server=%s", fctx->cc->server->server_hostname); - if (APLOGctrace5(fctx->c)) { - tls_util_bb_log(fctx->c, APLOG_TRACE5, "filter_conn_output", bb); - } - - while (!APR_BRIGADE_EMPTY(bb)) { - rv = fout_append_plain(fctx, APR_BRIGADE_FIRST(bb)); - if (APR_SUCCESS != rv) goto cleanup; - } - - if (APLOGctrace5(fctx->c)) { - tls_util_bb_log(fctx->c, APLOG_TRACE5, "filter_conn_output, processed plain", bb); - tls_util_bb_log(fctx->c, APLOG_TRACE5, "filter_conn_output, tls", fctx->fout_tls_bb); - } - -cleanup: - if (rr != RUSTLS_RESULT_OK) { - const char *err_descr = ""; - rv = tls_core_error(fctx->c, rr, &err_descr); - ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rv, fctx->c, APLOGNO(10360) - "tls_filter_conn_output: [%d] %s", (int)rr, err_descr); - } - else { - ap_log_cerror(APLOG_MARK, APLOG_TRACE2, rv, fctx->c, - "tls_filter_conn_output: done"); - } - return rv; -} - -int tls_filter_pre_conn_init(conn_rec *c) -{ - tls_conf_conn_t *cc; - tls_filter_ctx_t *fctx; - - if (OK != tls_core_pre_conn_init(c)) { - return DECLINED; - } - - ap_log_error(APLOG_MARK, APLOG_TRACE2, 0, c->base_server, - "tls_filter_pre_conn_init on %s", c->base_server->server_hostname); - - cc = tls_conf_conn_get(c); - ap_assert(cc); - - fctx = apr_pcalloc(c->pool, sizeof(*fctx)); - fctx->c = c; - fctx->cc = cc; - cc->filter_ctx = fctx; - - /* a bit tricky: registering out filters returns the ap_filter_t* - * that it created for it. The ->next field points always - * to the filter "below" our filter. That will be other registered - * filters and last, but not least, the network filter on the socket. - * - * Therefore, wenn we need to read/write TLS data during handshake, we can - * pass the data to/call on ->next- Since ->next can change during the setup of - * a connections (other modules register also sth.), we keep the ap_filter_t* - * returned here, since httpd core will update the ->next whenever someone - * adds a filter or removes one. This can potentially happen all the time. - */ - fctx->fin_ctx = ap_add_input_filter(TLS_FILTER_RAW, fctx, NULL, c); - fctx->fin_tls_bb = apr_brigade_create(c->pool, c->bucket_alloc); - fctx->fin_tls_buffer_bb = NULL; - fctx->fin_plain_bb = apr_brigade_create(c->pool, c->bucket_alloc); - fctx->fout_ctx = ap_add_output_filter(TLS_FILTER_RAW, fctx, NULL, c); - fctx->fout_tls_bb = apr_brigade_create(c->pool, c->bucket_alloc); - fctx->fout_buf_plain_size = APR_BUCKET_BUFF_SIZE; - fctx->fout_buf_plain = apr_pcalloc(c->pool, fctx->fout_buf_plain_size); - fctx->fout_buf_plain_len = 0; - - /* Let the filters have 2 max-length TLS Messages in the rustls buffers. - * The effects we would like to achieve here are: - * 1. pass data out, so that every bucket becomes its own TLS message. - * This hides, if possible, the length of response parts. - * If we give rustls enough plain data, it will use the max TLS message - * size and things are more hidden. But we can only write what the application - * or protocol gives us. - * 2. max length records result in less overhead for all layers involved. - * 3. a TLS message from the client can only be decrypted when it has - * completely arrived. If we provide rustls with enough data (if the - * network has it for us), it should always be able to decrypt at least - * one TLS message and we have plain bytes to forward to the protocol - * handler. - */ - fctx->fin_max_in_rustls = 4 * TLS_REC_MAX_SIZE; - fctx->fout_max_in_rustls = 4 * TLS_PREF_PLAIN_CHUNK_SIZE; - fctx->fout_auto_flush_size = 2 * TLS_REC_MAX_SIZE; - - return OK; -} - -void tls_filter_conn_init(conn_rec *c) -{ - tls_conf_conn_t *cc = tls_conf_conn_get(c); - - if (cc && cc->filter_ctx && !cc->outgoing) { - /* We are one in a row of hooks that - possibly - want to process this - * connection, the (HTTP) protocol handlers among them. - * - * For incoming connections, we need to select the protocol to use NOW, - * so that the later protocol handlers do the right thing. - * Send an INIT down the input filter chain to trigger the TLS handshake, - * which will select a protocol via ALPN. */ - apr_bucket_brigade* temp; - - ap_log_error(APLOG_MARK, APLOG_TRACE2, 0, c->base_server, - "tls_filter_conn_init on %s, triggering handshake", c->base_server->server_hostname); - temp = apr_brigade_create(c->pool, c->bucket_alloc); - ap_get_brigade(c->input_filters, temp, AP_MODE_INIT, APR_BLOCK_READ, 0); - apr_brigade_destroy(temp); - } -} - -void tls_filter_register( - apr_pool_t *pool) -{ - (void)pool; - ap_register_input_filter(TLS_FILTER_RAW, filter_conn_input, NULL, AP_FTYPE_CONNECTION + 5); - ap_register_output_filter(TLS_FILTER_RAW, filter_conn_output, NULL, AP_FTYPE_CONNECTION + 5); -} diff --git a/modules/tls/tls_filter.h b/modules/tls/tls_filter.h deleted file mode 100644 index 4f3d38bbc1..0000000000 --- a/modules/tls/tls_filter.h +++ /dev/null @@ -1,90 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef tls_filter_h -#define tls_filter_h - -#define TLS_FILTER_RAW "TLS raw" - -typedef struct tls_filter_ctx_t tls_filter_ctx_t; - -struct tls_filter_ctx_t { - conn_rec *c; /* connection this context is for */ - tls_conf_conn_t *cc; /* tls module configuration of connection */ - - ap_filter_t *fin_ctx; /* Apache's entry into the input filter chain */ - apr_bucket_brigade *fin_tls_bb; /* TLS encrypted, incoming network data */ - apr_bucket_brigade *fin_tls_buffer_bb; /* TLS encrypted, incoming network data buffering */ - apr_bucket_brigade *fin_plain_bb; /* decrypted, incoming traffic data */ - apr_off_t fin_bytes_in_rustls; /* # of input TLS bytes in rustls_connection */ - apr_read_type_e fin_block; /* Do we block on input reads or not? */ - - ap_filter_t *fout_ctx; /* Apache's entry into the output filter chain */ - char *fout_buf_plain; /* a buffer to collect plain bytes for output */ - apr_size_t fout_buf_plain_len; /* the amount of bytes in the buffer */ - apr_size_t fout_buf_plain_size; /* the total size of the buffer */ - apr_bucket_brigade *fout_tls_bb; /* TLS encrypted, outgoing network data */ - apr_off_t fout_bytes_in_rustls; /* # of output plain bytes in rustls_connection */ - apr_off_t fout_bytes_in_tls_bb; /* # of output tls bytes in our brigade */ - - apr_size_t fin_max_in_rustls; /* how much tls we like to read into rustls */ - apr_size_t fout_max_in_rustls; /* how much plain bytes we like in rustls */ - apr_size_t fout_max_bucket_size; /* how large bucket chunks we handle before splitting */ - apr_size_t fout_auto_flush_size; /* on much outoing TLS data we flush to network */ -}; - -/** - * Register the in-/output filters for converting TLS to application data and vice versa. - */ -void tls_filter_register(apr_pool_t *pool); - -/** - * Initialize the pre_connection state. Install all filters. - * - * @return OK if TLS on connection is enabled, DECLINED otherwise - */ -int tls_filter_pre_conn_init(conn_rec *c); - -/** - * Initialize the connection for use, perform the TLS handshake. - * - * Any failure will lead to the connection becoming aborted. - */ -void tls_filter_conn_init(conn_rec *c); - -/* - * <https://tools.ietf.org/html/rfc8449> says: - * "For large data transfers, small record sizes can materially affect performance." - * and - * "For TLS 1.2 and earlier, that limit is 2^14 octets. TLS 1.3 uses a limit of - * 2^14+1 octets." - * Maybe future TLS versions will raise that value, but for now these limits stand. - * Given the choice, we would like rustls to provide traffic data in those chunks. - */ -#define TLS_PREF_PLAIN_CHUNK_SIZE (16384) - -/* - * When retrieving TLS chunks for rustls, or providing it a buffer - * to pass out TLS chunks (which are then bucketed and written to the - * network filters), we ideally would do that in multiples of TLS - * messages sizes. - * That would be TLS_PREF_WRITE_SIZE + TLS Message Overhead, such as - * MAC and padding. But these vary with protocol and ciphers chosen, so - * we define something which should be "large enough", but not overly so. - */ -#define TLS_REC_EXTRA (1024) -#define TLS_REC_MAX_SIZE (TLS_PREF_PLAIN_CHUNK_SIZE + TLS_REC_EXTRA) - -#endif /* tls_filter_h */
\ No newline at end of file diff --git a/modules/tls/tls_ocsp.c b/modules/tls/tls_ocsp.c deleted file mode 100644 index 37e95b1521..0000000000 --- a/modules/tls/tls_ocsp.c +++ /dev/null @@ -1,120 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include <assert.h> -#include <apr_lib.h> -#include <apr_strings.h> - -#include <httpd.h> -#include <http_connection.h> -#include <http_core.h> -#include <http_log.h> -#include <http_ssl.h> - -#include <rustls.h> - -#include "tls_cert.h" -#include "tls_conf.h" -#include "tls_core.h" -#include "tls_proto.h" -#include "tls_ocsp.h" - -extern module AP_MODULE_DECLARE_DATA tls_module; -APLOG_USE_MODULE(tls); - - -static int prime_cert( - void *userdata, server_rec *s, const char *cert_id, const char *cert_pem, - const rustls_certified_key *certified_key) -{ - apr_pool_t *p = userdata; - apr_status_t rv; - - (void)certified_key; - rv = ap_ssl_ocsp_prime(s, p, cert_id, strlen(cert_id), cert_pem); - ap_log_error(APLOG_MARK, APLOG_TRACE1, rv, s, "ocsp prime of cert [%s] from %s", - cert_id, s->server_hostname); - return 1; -} - -apr_status_t tls_ocsp_prime_certs(tls_conf_global_t *gc, apr_pool_t *p, server_rec *s) -{ - ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, s, "ocsp priming of %d certs", - (int)tls_cert_reg_count(gc->cert_reg)); - tls_cert_reg_do(prime_cert, p, gc->cert_reg); - return APR_SUCCESS; -} - -typedef struct { - conn_rec *c; - const rustls_certified_key *key_in; - const rustls_certified_key *key_out; -} ocsp_copy_ctx_t; - -static void ocsp_clone_key(const unsigned char *der, apr_size_t der_len, void *userdata) -{ - ocsp_copy_ctx_t *ctx = userdata; - rustls_slice_bytes rslice; - rustls_result rr; - - rslice.data = der; - rslice.len = der_len; - - rr = rustls_certified_key_clone_with_ocsp(ctx->key_in, der_len? &rslice : NULL, &ctx->key_out); - if (RUSTLS_RESULT_OK != rr) { - const char *err_descr = NULL; - apr_status_t rv = tls_util_rustls_error(ctx->c->pool, rr, &err_descr); - ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, ctx->c, APLOGNO(10362) - "Failed add OCSP data to certificate: [%d] %s", (int)rr, err_descr); - } - else { - ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, ctx->c, - "provided %ld bytes of ocsp response DER data to key.", (long)der_len); - } -} - -apr_status_t tls_ocsp_update_key( - conn_rec *c, const rustls_certified_key *certified_key, - const rustls_certified_key **pkey_out) -{ - tls_conf_conn_t *cc = tls_conf_conn_get(c); - tls_conf_server_t *sc; - const char *key_id; - apr_status_t rv = APR_SUCCESS; - ocsp_copy_ctx_t ctx; - - assert(cc); - assert(cc->server); - sc = tls_conf_server_get(cc->server); - key_id = tls_cert_reg_get_id(sc->global->cert_reg, certified_key); - if (!key_id) { - rv = APR_ENOENT; - ap_log_cerror(APLOG_MARK, APLOG_TRACE1, rv, c, "certified key not registered"); - goto cleanup; - } - - ctx.c = c; - ctx.key_in = certified_key; - ctx.key_out = NULL; - rv = ap_ssl_ocsp_get_resp(cc->server, c, key_id, strlen(key_id), ocsp_clone_key, &ctx); - if (APR_SUCCESS != rv) { - ap_log_cerror(APLOG_MARK, APLOG_TRACE1, rv, c, - "ocsp response not available for cert %s", key_id); - } - -cleanup: - *pkey_out = (APR_SUCCESS == rv)? ctx.key_out : NULL; - return rv; -} diff --git a/modules/tls/tls_ocsp.h b/modules/tls/tls_ocsp.h deleted file mode 100644 index 60770a9f8e..0000000000 --- a/modules/tls/tls_ocsp.h +++ /dev/null @@ -1,47 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef tls_ocsp_h -#define tls_ocsp_h - -/** - * Prime the collected certified keys for OCSP response provisioning (aka. Stapling). - * - * To be called in the post-config phase of the server before connections are handled. - * @param gc the global module configuration with the certified_key registry - * @param p the pool to use for allocations - * @param s the base server record - */ -apr_status_t tls_ocsp_prime_certs(tls_conf_global_t *gc, apr_pool_t *p, server_rec *s); - -/** - * Provide the OCSP response data for the certified_key into the offered buffer, - * so available. - * If not data is available `out_n` is set to 0. Same, if the offered buffer - * is not large enough to hold the complete response. - * If OCSP response DER data is copied, the number of copied bytes is given in `out_n`. - * - * Note that only keys that have been primed initially will have OCSP data available. - * @param c the current connection - * @param certified_key the key to get the OCSP response data for - * @param buf a buffer which can hold up to `buf_len` bytes - * @param buf_len the length of `buf` - * @param out_n the number of OCSP response DER bytes copied or 0. - */ -apr_status_t tls_ocsp_update_key( - conn_rec *c, const rustls_certified_key *certified_key, - const rustls_certified_key **key_out); - -#endif /* tls_ocsp_h */ diff --git a/modules/tls/tls_proto.c b/modules/tls/tls_proto.c deleted file mode 100644 index 95a903b715..0000000000 --- a/modules/tls/tls_proto.c +++ /dev/null @@ -1,603 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include <assert.h> -#include <apr_lib.h> -#include <apr_strings.h> - -#include <httpd.h> -#include <http_connection.h> -#include <http_core.h> -#include <http_log.h> - -#include <rustls.h> - -#include "tls_proto.h" -#include "tls_conf.h" -#include "tls_util.h" - -extern module AP_MODULE_DECLARE_DATA tls_module; -APLOG_USE_MODULE(tls); - - - -/** - * Known cipher as registered in - * <https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-4> - */ -static tls_cipher_t KNOWN_CIPHERS[] = { - { 0x0000, "TLS_NULL_WITH_NULL_NULL", NULL }, - { 0x0001, "TLS_RSA_WITH_NULL_MD5", NULL }, - { 0x0002, "TLS_RSA_WITH_NULL_SHA", NULL }, - { 0x0003, "TLS_RSA_EXPORT_WITH_RC4_40_MD5", NULL }, - { 0x0004, "TLS_RSA_WITH_RC4_128_MD5", NULL }, - { 0x0005, "TLS_RSA_WITH_RC4_128_SHA", NULL }, - { 0x0006, "TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5", NULL }, - { 0x0007, "TLS_RSA_WITH_IDEA_CBC_SHA", NULL }, - { 0x0008, "TLS_RSA_EXPORT_WITH_DES40_CBC_SHA", NULL }, - { 0x0009, "TLS_RSA_WITH_DES_CBC_SHA", NULL }, - { 0x000a, "TLS_RSA_WITH_3DES_EDE_CBC_SHA", NULL }, - { 0x000b, "TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA", NULL }, - { 0x000c, "TLS_DH_DSS_WITH_DES_CBC_SHA", NULL }, - { 0x000d, "TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA", NULL }, - { 0x000e, "TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA", NULL }, - { 0x000f, "TLS_DH_RSA_WITH_DES_CBC_SHA", NULL }, - { 0x0010, "TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA", NULL }, - { 0x0011, "TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA", NULL }, - { 0x0012, "TLS_DHE_DSS_WITH_DES_CBC_SHA", NULL }, - { 0x0013, "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA", NULL }, - { 0x0014, "TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", NULL }, - { 0x0015, "TLS_DHE_RSA_WITH_DES_CBC_SHA", NULL }, - { 0x0016, "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA", NULL }, - { 0x0017, "TLS_DH_anon_EXPORT_WITH_RC4_40_MD5", NULL }, - { 0x0018, "TLS_DH_anon_WITH_RC4_128_MD5", NULL }, - { 0x0019, "TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA", NULL }, - { 0x001a, "TLS_DH_anon_WITH_DES_CBC_SHA", NULL }, - { 0x001b, "TLS_DH_anon_WITH_3DES_EDE_CBC_SHA", NULL }, - { 0x001c, "SSL_FORTEZZA_KEA_WITH_NULL_SHA", NULL }, - { 0x001d, "SSL_FORTEZZA_KEA_WITH_FORTEZZA_CBC_SHA", NULL }, - { 0x001e, "TLS_KRB5_WITH_DES_CBC_SHA_or_SSL_FORTEZZA_KEA_WITH_RC4_128_SHA", NULL }, - { 0x001f, "TLS_KRB5_WITH_3DES_EDE_CBC_SHA", NULL }, - { 0x0020, "TLS_KRB5_WITH_RC4_128_SHA", NULL }, - { 0x0021, "TLS_KRB5_WITH_IDEA_CBC_SHA", NULL }, - { 0x0022, "TLS_KRB5_WITH_DES_CBC_MD5", NULL }, - { 0x0023, "TLS_KRB5_WITH_3DES_EDE_CBC_MD5", NULL }, - { 0x0024, "TLS_KRB5_WITH_RC4_128_MD5", NULL }, - { 0x0025, "TLS_KRB5_WITH_IDEA_CBC_MD5", NULL }, - { 0x0026, "TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA", NULL }, - { 0x0027, "TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA", NULL }, - { 0x0028, "TLS_KRB5_EXPORT_WITH_RC4_40_SHA", NULL }, - { 0x0029, "TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5", NULL }, - { 0x002a, "TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5", NULL }, - { 0x002b, "TLS_KRB5_EXPORT_WITH_RC4_40_MD5", NULL }, - { 0x002c, "TLS_PSK_WITH_NULL_SHA", NULL }, - { 0x002d, "TLS_DHE_PSK_WITH_NULL_SHA", NULL }, - { 0x002e, "TLS_RSA_PSK_WITH_NULL_SHA", NULL }, - { 0x002f, "TLS_RSA_WITH_AES_128_CBC_SHA", NULL }, - { 0x0030, "TLS_DH_DSS_WITH_AES_128_CBC_SHA", NULL }, - { 0x0031, "TLS_DH_RSA_WITH_AES_128_CBC_SHA", NULL }, - { 0x0032, "TLS_DHE_DSS_WITH_AES_128_CBC_SHA", NULL }, - { 0x0033, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", NULL }, - { 0x0034, "TLS_DH_anon_WITH_AES_128_CBC_SHA", NULL }, - { 0x0035, "TLS_RSA_WITH_AES_256_CBC_SHA", NULL }, - { 0x0036, "TLS_DH_DSS_WITH_AES_256_CBC_SHA", NULL }, - { 0x0037, "TLS_DH_RSA_WITH_AES_256_CBC_SHA", NULL }, - { 0x0038, "TLS_DHE_DSS_WITH_AES_256_CBC_SHA", NULL }, - { 0x0039, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA", NULL }, - { 0x003a, "TLS_DH_anon_WITH_AES_256_CBC_SHA", NULL }, - { 0x003b, "TLS_RSA_WITH_NULL_SHA256", "NULL-SHA256" }, - { 0x003c, "TLS_RSA_WITH_AES_128_CBC_SHA256", "AES128-SHA256" }, - { 0x003d, "TLS_RSA_WITH_AES_256_CBC_SHA256", "AES256-SHA256" }, - { 0x003e, "TLS_DH_DSS_WITH_AES_128_CBC_SHA256", "DH-DSS-AES128-SHA256" }, - { 0x003f, "TLS_DH_RSA_WITH_AES_128_CBC_SHA256", "DH-RSA-AES128-SHA256" }, - { 0x0040, "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256", "DHE-DSS-AES128-SHA256" }, - { 0x0041, "TLS_RSA_WITH_CAMELLIA_128_CBC_SHA", NULL }, - { 0x0042, "TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA", NULL }, - { 0x0043, "TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA", NULL }, - { 0x0044, "TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA", NULL }, - { 0x0045, "TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA", NULL }, - { 0x0046, "TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA", NULL }, - { 0x0047, "TLS_ECDH_ECDSA_WITH_NULL_SHA_draft", NULL }, - { 0x0048, "TLS_ECDH_ECDSA_WITH_RC4_128_SHA_draft", NULL }, - { 0x0049, "TLS_ECDH_ECDSA_WITH_DES_CBC_SHA_draft", NULL }, - { 0x004a, "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA_draft", NULL }, - { 0x004b, "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA_draft", NULL }, - { 0x004c, "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA_draft", NULL }, - { 0x004d, "TLS_ECDH_ECNRA_WITH_DES_CBC_SHA_draft", NULL }, - { 0x004e, "TLS_ECDH_ECNRA_WITH_3DES_EDE_CBC_SHA_draft", NULL }, - { 0x004f, "TLS_ECMQV_ECDSA_NULL_SHA_draft", NULL }, - { 0x0050, "TLS_ECMQV_ECDSA_WITH_RC4_128_SHA_draft", NULL }, - { 0x0051, "TLS_ECMQV_ECDSA_WITH_DES_CBC_SHA_draft", NULL }, - { 0x0052, "TLS_ECMQV_ECDSA_WITH_3DES_EDE_CBC_SHA_draft", NULL }, - { 0x0053, "TLS_ECMQV_ECNRA_NULL_SHA_draft", NULL }, - { 0x0054, "TLS_ECMQV_ECNRA_WITH_RC4_128_SHA_draft", NULL }, - { 0x0055, "TLS_ECMQV_ECNRA_WITH_DES_CBC_SHA_draft", NULL }, - { 0x0056, "TLS_ECMQV_ECNRA_WITH_3DES_EDE_CBC_SHA_draft", NULL }, - { 0x0057, "TLS_ECDH_anon_NULL_WITH_SHA_draft", NULL }, - { 0x0058, "TLS_ECDH_anon_WITH_RC4_128_SHA_draft", NULL }, - { 0x0059, "TLS_ECDH_anon_WITH_DES_CBC_SHA_draft", NULL }, - { 0x005a, "TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA_draft", NULL }, - { 0x005b, "TLS_ECDH_anon_EXPORT_WITH_DES40_CBC_SHA_draft", NULL }, - { 0x005c, "TLS_ECDH_anon_EXPORT_WITH_RC4_40_SHA_draft", NULL }, - { 0x0060, "TLS_RSA_EXPORT1024_WITH_RC4_56_MD5", NULL }, - { 0x0061, "TLS_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5", NULL }, - { 0x0062, "TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA", NULL }, - { 0x0063, "TLS_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA", NULL }, - { 0x0064, "TLS_RSA_EXPORT1024_WITH_RC4_56_SHA", NULL }, - { 0x0065, "TLS_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA", NULL }, - { 0x0066, "TLS_DHE_DSS_WITH_RC4_128_SHA", NULL }, - { 0x0067, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256", "DHE-RSA-AES128-SHA256" }, - { 0x0068, "TLS_DH_DSS_WITH_AES_256_CBC_SHA256", "DH-DSS-AES256-SHA256" }, - { 0x0069, "TLS_DH_RSA_WITH_AES_256_CBC_SHA256", "DH-RSA-AES256-SHA256" }, - { 0x006a, "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256", "DHE-DSS-AES256-SHA256" }, - { 0x006b, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256", "DHE-RSA-AES256-SHA256" }, - { 0x006c, "TLS_DH_anon_WITH_AES_128_CBC_SHA256", "ADH-AES128-SHA256" }, - { 0x006d, "TLS_DH_anon_WITH_AES_256_CBC_SHA256", "ADH-AES256-SHA256" }, - { 0x0072, "TLS_DHE_DSS_WITH_3DES_EDE_CBC_RMD", NULL }, - { 0x0073, "TLS_DHE_DSS_WITH_AES_128_CBC_RMD", NULL }, - { 0x0074, "TLS_DHE_DSS_WITH_AES_256_CBC_RMD", NULL }, - { 0x0077, "TLS_DHE_RSA_WITH_3DES_EDE_CBC_RMD", NULL }, - { 0x0078, "TLS_DHE_RSA_WITH_AES_128_CBC_RMD", NULL }, - { 0x0079, "TLS_DHE_RSA_WITH_AES_256_CBC_RMD", NULL }, - { 0x007c, "TLS_RSA_WITH_3DES_EDE_CBC_RMD", NULL }, - { 0x007d, "TLS_RSA_WITH_AES_128_CBC_RMD", NULL }, - { 0x007e, "TLS_RSA_WITH_AES_256_CBC_RMD", NULL }, - { 0x0080, "TLS_GOSTR341094_WITH_28147_CNT_IMIT", NULL }, - { 0x0081, "TLS_GOSTR341001_WITH_28147_CNT_IMIT", NULL }, - { 0x0082, "TLS_GOSTR341094_WITH_NULL_GOSTR3411", NULL }, - { 0x0083, "TLS_GOSTR341001_WITH_NULL_GOSTR3411", NULL }, - { 0x0084, "TLS_RSA_WITH_CAMELLIA_256_CBC_SHA", NULL }, - { 0x0085, "TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA", NULL }, - { 0x0086, "TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA", NULL }, - { 0x0087, "TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA", NULL }, - { 0x0088, "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA", NULL }, - { 0x0089, "TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA", NULL }, - { 0x008a, "TLS_PSK_WITH_RC4_128_SHA", "PSK-RC4-SHA" }, - { 0x008b, "TLS_PSK_WITH_3DES_EDE_CBC_SHA", "PSK-3DES-EDE-CBC-SHA" }, - { 0x008c, "TLS_PSK_WITH_AES_128_CBC_SHA", NULL }, - { 0x008d, "TLS_PSK_WITH_AES_256_CBC_SHA", NULL }, - { 0x008e, "TLS_DHE_PSK_WITH_RC4_128_SHA", NULL }, - { 0x008f, "TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA", NULL }, - { 0x0090, "TLS_DHE_PSK_WITH_AES_128_CBC_SHA", NULL }, - { 0x0091, "TLS_DHE_PSK_WITH_AES_256_CBC_SHA", NULL }, - { 0x0092, "TLS_RSA_PSK_WITH_RC4_128_SHA", NULL }, - { 0x0093, "TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA", NULL }, - { 0x0094, "TLS_RSA_PSK_WITH_AES_128_CBC_SHA", NULL }, - { 0x0095, "TLS_RSA_PSK_WITH_AES_256_CBC_SHA", NULL }, - { 0x0096, "TLS_RSA_WITH_SEED_CBC_SHA", NULL }, - { 0x0097, "TLS_DH_DSS_WITH_SEED_CBC_SHA", NULL }, - { 0x0098, "TLS_DH_RSA_WITH_SEED_CBC_SHA", NULL }, - { 0x0099, "TLS_DHE_DSS_WITH_SEED_CBC_SHA", NULL }, - { 0x009a, "TLS_DHE_RSA_WITH_SEED_CBC_SHA", NULL }, - { 0x009b, "TLS_DH_anon_WITH_SEED_CBC_SHA", NULL }, - { 0x009c, "TLS_RSA_WITH_AES_128_GCM_SHA256", "AES128-GCM-SHA256" }, - { 0x009d, "TLS_RSA_WITH_AES_256_GCM_SHA384", "AES256-GCM-SHA384" }, - { 0x009e, "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", "DHE-RSA-AES128-GCM-SHA256" }, - { 0x009f, "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", "DHE-RSA-AES256-GCM-SHA384" }, - { 0x00a0, "TLS_DH_RSA_WITH_AES_128_GCM_SHA256", "DH-RSA-AES128-GCM-SHA256" }, - { 0x00a1, "TLS_DH_RSA_WITH_AES_256_GCM_SHA384", "DH-RSA-AES256-GCM-SHA384" }, - { 0x00a2, "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256", "DHE-DSS-AES128-GCM-SHA256" }, - { 0x00a3, "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384", "DHE-DSS-AES256-GCM-SHA384" }, - { 0x00a4, "TLS_DH_DSS_WITH_AES_128_GCM_SHA256", "DH-DSS-AES128-GCM-SHA256" }, - { 0x00a5, "TLS_DH_DSS_WITH_AES_256_GCM_SHA384", "DH-DSS-AES256-GCM-SHA384" }, - { 0x00a6, "TLS_DH_anon_WITH_AES_128_GCM_SHA256", "ADH-AES128-GCM-SHA256" }, - { 0x00a7, "TLS_DH_anon_WITH_AES_256_GCM_SHA384", "ADH-AES256-GCM-SHA384" }, - { 0x00a8, "TLS_PSK_WITH_AES_128_GCM_SHA256", NULL }, - { 0x00a9, "TLS_PSK_WITH_AES_256_GCM_SHA384", NULL }, - { 0x00aa, "TLS_DHE_PSK_WITH_AES_128_GCM_SHA256", NULL }, - { 0x00ab, "TLS_DHE_PSK_WITH_AES_256_GCM_SHA384", NULL }, - { 0x00ac, "TLS_RSA_PSK_WITH_AES_128_GCM_SHA256", NULL }, - { 0x00ad, "TLS_RSA_PSK_WITH_AES_256_GCM_SHA384", NULL }, - { 0x00ae, "TLS_PSK_WITH_AES_128_CBC_SHA256", "PSK-AES128-CBC-SHA" }, - { 0x00af, "TLS_PSK_WITH_AES_256_CBC_SHA384", "PSK-AES256-CBC-SHA" }, - { 0x00b0, "TLS_PSK_WITH_NULL_SHA256", NULL }, - { 0x00b1, "TLS_PSK_WITH_NULL_SHA384", NULL }, - { 0x00b2, "TLS_DHE_PSK_WITH_AES_128_CBC_SHA256", NULL }, - { 0x00b3, "TLS_DHE_PSK_WITH_AES_256_CBC_SHA384", NULL }, - { 0x00b4, "TLS_DHE_PSK_WITH_NULL_SHA256", NULL }, - { 0x00b5, "TLS_DHE_PSK_WITH_NULL_SHA384", NULL }, - { 0x00b6, "TLS_RSA_PSK_WITH_AES_128_CBC_SHA256", NULL }, - { 0x00b7, "TLS_RSA_PSK_WITH_AES_256_CBC_SHA384", NULL }, - { 0x00b8, "TLS_RSA_PSK_WITH_NULL_SHA256", NULL }, - { 0x00b9, "TLS_RSA_PSK_WITH_NULL_SHA384", NULL }, - { 0x00ba, "TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256", NULL }, - { 0x00bb, "TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256", NULL }, - { 0x00bc, "TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256", NULL }, - { 0x00bd, "TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256", NULL }, - { 0x00be, "TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256", NULL }, - { 0x00bf, "TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256", NULL }, - { 0x00c0, "TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256", NULL }, - { 0x00c1, "TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256", NULL }, - { 0x00c2, "TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256", NULL }, - { 0x00c3, "TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256", NULL }, - { 0x00c4, "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256", NULL }, - { 0x00c5, "TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256", NULL }, - { 0x00ff, "TLS_EMPTY_RENEGOTIATION_INFO_SCSV", NULL }, - { 0x1301, "TLS_AES_128_GCM_SHA256", "TLS13_AES_128_GCM_SHA256" }, - { 0x1302, "TLS_AES_256_GCM_SHA384", "TLS13_AES_256_GCM_SHA384" }, - { 0x1303, "TLS_CHACHA20_POLY1305_SHA256", "TLS13_CHACHA20_POLY1305_SHA256" }, - { 0x1304, "TLS_AES_128_CCM_SHA256", "TLS13_AES_128_CCM_SHA256" }, - { 0x1305, "TLS_AES_128_CCM_8_SHA256", "TLS13_AES_128_CCM_8_SHA256" }, - { 0xc001, "TLS_ECDH_ECDSA_WITH_NULL_SHA", NULL }, - { 0xc002, "TLS_ECDH_ECDSA_WITH_RC4_128_SHA", NULL }, - { 0xc003, "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA", NULL }, - { 0xc004, "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA", NULL }, - { 0xc005, "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA", NULL }, - { 0xc006, "TLS_ECDHE_ECDSA_WITH_NULL_SHA", NULL }, - { 0xc007, "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", NULL }, - { 0xc008, "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA", NULL }, - { 0xc009, "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", NULL }, - { 0xc00a, "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", NULL }, - { 0xc00b, "TLS_ECDH_RSA_WITH_NULL_SHA", NULL }, - { 0xc00c, "TLS_ECDH_RSA_WITH_RC4_128_SHA", NULL }, - { 0xc00d, "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA", NULL }, - { 0xc00e, "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA", NULL }, - { 0xc00f, "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA", NULL }, - { 0xc010, "TLS_ECDHE_RSA_WITH_NULL_SHA", NULL }, - { 0xc011, "TLS_ECDHE_RSA_WITH_RC4_128_SHA", NULL }, - { 0xc012, "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", NULL }, - { 0xc013, "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", NULL }, - { 0xc014, "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", NULL }, - { 0xc015, "TLS_ECDH_anon_WITH_NULL_SHA", NULL }, - { 0xc016, "TLS_ECDH_anon_WITH_RC4_128_SHA", NULL }, - { 0xc017, "TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA", NULL }, - { 0xc018, "TLS_ECDH_anon_WITH_AES_128_CBC_SHA", NULL }, - { 0xc019, "TLS_ECDH_anon_WITH_AES_256_CBC_SHA", NULL }, - { 0xc01a, "TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA", NULL }, - { 0xc01b, "TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA", NULL }, - { 0xc01c, "TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA", NULL }, - { 0xc01d, "TLS_SRP_SHA_WITH_AES_128_CBC_SHA", NULL }, - { 0xc01e, "TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA", NULL }, - { 0xc01f, "TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA", NULL }, - { 0xc020, "TLS_SRP_SHA_WITH_AES_256_CBC_SHA", NULL }, - { 0xc021, "TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA", NULL }, - { 0xc022, "TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA", NULL }, - { 0xc023, "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", "ECDHE-ECDSA-AES128-SHA256" }, - { 0xc024, "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", "ECDHE-ECDSA-AES256-SHA384" }, - { 0xc025, "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256", "ECDH-ECDSA-AES128-SHA256" }, - { 0xc026, "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384", "ECDH-ECDSA-AES256-SHA384" }, - { 0xc027, "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", "ECDHE-RSA-AES128-SHA256" }, - { 0xc028, "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", "ECDHE-RSA-AES256-SHA384" }, - { 0xc029, "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256", "ECDH-RSA-AES128-SHA256" }, - { 0xc02a, "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384", "ECDH-RSA-AES256-SHA384" }, - { 0xc02b, "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", "ECDHE-ECDSA-AES128-GCM-SHA256" }, - { 0xc02c, "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "ECDHE-ECDSA-AES256-GCM-SHA384" }, - { 0xc02d, "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", "ECDH-ECDSA-AES128-GCM-SHA256" }, - { 0xc02e, "TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384", "ECDH-ECDSA-AES256-GCM-SHA384" }, - { 0xc02f, "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "ECDHE-RSA-AES128-GCM-SHA256" }, - { 0xc030, "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", "ECDHE-RSA-AES256-GCM-SHA384" }, - { 0xc031, "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256", "ECDH-RSA-AES128-GCM-SHA256" }, - { 0xc032, "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384", "ECDH-RSA-AES256-GCM-SHA384" }, - { 0xc033, "TLS_ECDHE_PSK_WITH_RC4_128_SHA", NULL }, - { 0xc034, "TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA", NULL }, - { 0xc035, "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA", NULL }, - { 0xc036, "TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA", NULL }, - { 0xc037, "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256", NULL }, - { 0xc038, "TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384", NULL }, - { 0xc039, "TLS_ECDHE_PSK_WITH_NULL_SHA", NULL }, - { 0xc03a, "TLS_ECDHE_PSK_WITH_NULL_SHA256", NULL }, - { 0xc03b, "TLS_ECDHE_PSK_WITH_NULL_SHA384", NULL }, - { 0xc03c, "TLS_RSA_WITH_ARIA_128_CBC_SHA256", NULL }, - { 0xc03d, "TLS_RSA_WITH_ARIA_256_CBC_SHA384", NULL }, - { 0xc03e, "TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256", NULL }, - { 0xc03f, "TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384", NULL }, - { 0xc040, "TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256", NULL }, - { 0xc041, "TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384", NULL }, - { 0xc042, "TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256", NULL }, - { 0xc043, "TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384", NULL }, - { 0xc044, "TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256", NULL }, - { 0xc045, "TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384", NULL }, - { 0xc046, "TLS_DH_anon_WITH_ARIA_128_CBC_SHA256", NULL }, - { 0xc047, "TLS_DH_anon_WITH_ARIA_256_CBC_SHA384", NULL }, - { 0xc048, "TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256", NULL }, - { 0xc049, "TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384", NULL }, - { 0xc04a, "TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256", NULL }, - { 0xc04b, "TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384", NULL }, - { 0xc04c, "TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256", NULL }, - { 0xc04d, "TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384", NULL }, - { 0xc04e, "TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256", NULL }, - { 0xc04f, "TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384", NULL }, - { 0xc050, "TLS_RSA_WITH_ARIA_128_GCM_SHA256", NULL }, - { 0xc051, "TLS_RSA_WITH_ARIA_256_GCM_SHA384", NULL }, - { 0xc052, "TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256", NULL }, - { 0xc053, "TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384", NULL }, - { 0xc054, "TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256", NULL }, - { 0xc055, "TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384", NULL }, - { 0xc056, "TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256", NULL }, - { 0xc057, "TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384", NULL }, - { 0xc058, "TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256", NULL }, - { 0xc059, "TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384", NULL }, - { 0xc05a, "TLS_DH_anon_WITH_ARIA_128_GCM_SHA256", NULL }, - { 0xc05b, "TLS_DH_anon_WITH_ARIA_256_GCM_SHA384", NULL }, - { 0xc05c, "TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256", NULL }, - { 0xc05d, "TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384", NULL }, - { 0xc05e, "TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256", NULL }, - { 0xc05f, "TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384", NULL }, - { 0xc060, "TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256", NULL }, - { 0xc061, "TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384", NULL }, - { 0xc062, "TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256", NULL }, - { 0xc063, "TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384", NULL }, - { 0xc064, "TLS_PSK_WITH_ARIA_128_CBC_SHA256", NULL }, - { 0xc065, "TLS_PSK_WITH_ARIA_256_CBC_SHA384", NULL }, - { 0xc066, "TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256", NULL }, - { 0xc067, "TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384", NULL }, - { 0xc068, "TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256", NULL }, - { 0xc069, "TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384", NULL }, - { 0xc06a, "TLS_PSK_WITH_ARIA_128_GCM_SHA256", NULL }, - { 0xc06b, "TLS_PSK_WITH_ARIA_256_GCM_SHA384", NULL }, - { 0xc06c, "TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256", NULL }, - { 0xc06d, "TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384", NULL }, - { 0xc06e, "TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256", NULL }, - { 0xc06f, "TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384", NULL }, - { 0xc070, "TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256", NULL }, - { 0xc071, "TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384", NULL }, - { 0xc072, "TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256", NULL }, - { 0xc073, "TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384", NULL }, - { 0xc074, "TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256", NULL }, - { 0xc075, "TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384", NULL }, - { 0xc076, "TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256", NULL }, - { 0xc077, "TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384", NULL }, - { 0xc078, "TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256", NULL }, - { 0xc079, "TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384", NULL }, - { 0xc07a, "TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256", NULL }, - { 0xc07b, "TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384", NULL }, - { 0xc07c, "TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256", NULL }, - { 0xc07d, "TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384", NULL }, - { 0xc07e, "TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256", NULL }, - { 0xc07f, "TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384", NULL }, - { 0xc080, "TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256", NULL }, - { 0xc081, "TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384", NULL }, - { 0xc082, "TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256", NULL }, - { 0xc083, "TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384", NULL }, - { 0xc084, "TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256", NULL }, - { 0xc085, "TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384", NULL }, - { 0xc086, "TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256", NULL }, - { 0xc087, "TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384", NULL }, - { 0xc088, "TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256", NULL }, - { 0xc089, "TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384", NULL }, - { 0xc08a, "TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256", NULL }, - { 0xc08b, "TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384", NULL }, - { 0xc08c, "TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256", NULL }, - { 0xc08d, "TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384", NULL }, - { 0xc08e, "TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256", NULL }, - { 0xc08f, "TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384", NULL }, - { 0xc090, "TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256", NULL }, - { 0xc091, "TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384", NULL }, - { 0xc092, "TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256", NULL }, - { 0xc093, "TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384", NULL }, - { 0xc094, "TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256", NULL }, - { 0xc095, "TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384", NULL }, - { 0xc096, "TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256", NULL }, - { 0xc097, "TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384", NULL }, - { 0xc098, "TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256", NULL }, - { 0xc099, "TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384", NULL }, - { 0xc09a, "TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256", NULL }, - { 0xc09b, "TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384", NULL }, - { 0xc09c, "TLS_RSA_WITH_AES_128_CCM", NULL }, - { 0xc09d, "TLS_RSA_WITH_AES_256_CCM", NULL }, - { 0xc09e, "TLS_DHE_RSA_WITH_AES_128_CCM", NULL }, - { 0xc09f, "TLS_DHE_RSA_WITH_AES_256_CCM", NULL }, - { 0xc0a0, "TLS_RSA_WITH_AES_128_CCM_8", NULL }, - { 0xc0a1, "TLS_RSA_WITH_AES_256_CCM_8", NULL }, - { 0xc0a2, "TLS_DHE_RSA_WITH_AES_128_CCM_8", NULL }, - { 0xc0a3, "TLS_DHE_RSA_WITH_AES_256_CCM_8", NULL }, - { 0xc0a4, "TLS_PSK_WITH_AES_128_CCM", NULL }, - { 0xc0a5, "TLS_PSK_WITH_AES_256_CCM", NULL }, - { 0xc0a6, "TLS_DHE_PSK_WITH_AES_128_CCM", NULL }, - { 0xc0a7, "TLS_DHE_PSK_WITH_AES_256_CCM", NULL }, - { 0xc0a8, "TLS_PSK_WITH_AES_128_CCM_8", NULL }, - { 0xc0a9, "TLS_PSK_WITH_AES_256_CCM_8", NULL }, - { 0xc0aa, "TLS_PSK_DHE_WITH_AES_128_CCM_8", NULL }, - { 0xc0ab, "TLS_PSK_DHE_WITH_AES_256_CCM_8", NULL }, - { 0xcca8, "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", "ECDHE-RSA-CHACHA20-POLY1305" }, - { 0xcca9, "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", "ECDHE-ECDSA-CHACHA20-POLY1305" }, - { 0xccaa, "TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256", "DHE-RSA-CHACHA20-POLY1305" }, - { 0xccab, "TLS_PSK_WITH_CHACHA20_POLY1305_SHA256", "PSK-CHACHA20-POLY1305" }, - { 0xccac, "TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256", "ECDHE-PSK-CHACHA20-POLY1305" }, - { 0xccad, "TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256", "DHE-PSK-CHACHA20-POLY1305" }, - { 0xccae, "TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256", "RSA-PSK-CHACHA20-POLY1305" }, - { 0xfefe, "SSL_RSA_FIPS_WITH_DES_CBC_SHA", NULL }, - { 0xfeff, "SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA", NULL }, -}; - -typedef struct { - apr_uint16_t id; - const rustls_supported_ciphersuite *rustls_suite; -} rustls_cipher_t; - -tls_proto_conf_t *tls_proto_init(apr_pool_t *pool, server_rec *s) -{ - tls_proto_conf_t *conf; - tls_cipher_t *cipher; - const rustls_supported_ciphersuite *rustls_suite; - rustls_cipher_t *rcipher; - apr_uint16_t id; - apr_size_t i; - - (void)s; - conf = apr_pcalloc(pool, sizeof(*conf)); - - conf->supported_versions = apr_array_make(pool, 3, sizeof(apr_uint16_t)); - /* Until we can look that up at crustls, we assume what we currently know */ - APR_ARRAY_PUSH(conf->supported_versions, apr_uint16_t) = TLS_VERSION_1_2; - APR_ARRAY_PUSH(conf->supported_versions, apr_uint16_t) = TLS_VERSION_1_3; - - conf->known_ciphers_by_name = apr_hash_make(pool); - conf->known_ciphers_by_id = apr_hash_make(pool); - for (i = 0; i < TLS_DIM(KNOWN_CIPHERS); ++i) { - cipher = &KNOWN_CIPHERS[i]; - apr_hash_set(conf->known_ciphers_by_id, &cipher->id, sizeof(apr_uint16_t), cipher); - apr_hash_set(conf->known_ciphers_by_name, cipher->name, APR_HASH_KEY_STRING, cipher); - if (cipher->alias) { - apr_hash_set(conf->known_ciphers_by_name, cipher->alias, APR_HASH_KEY_STRING, cipher); - } - } - - conf->supported_cipher_ids = apr_array_make(pool, 10, sizeof(apr_uint16_t)); - conf->rustls_ciphers_by_id = apr_hash_make(pool); - i = 0; - while ((rustls_suite = rustls_all_ciphersuites_get_entry(i++))) { - id = rustls_supported_ciphersuite_get_suite(rustls_suite); - rcipher = apr_pcalloc(pool, sizeof(*rcipher)); - rcipher->id = id; - rcipher->rustls_suite = rustls_suite; - APR_ARRAY_PUSH(conf->supported_cipher_ids, apr_uint16_t) = id; - apr_hash_set(conf->rustls_ciphers_by_id, &rcipher->id, sizeof(apr_uint16_t), rcipher); - - } - - return conf; -} - -const char *tls_proto_get_cipher_names( - tls_proto_conf_t *conf, const apr_array_header_t *ciphers, apr_pool_t *pool) -{ - apr_array_header_t *names; - int n; - - names = apr_array_make(pool, ciphers->nelts, sizeof(const char*)); - for (n = 0; n < ciphers->nelts; ++n) { - apr_uint16_t id = APR_ARRAY_IDX(ciphers, n, apr_uint16_t); - APR_ARRAY_PUSH(names, const char *) = tls_proto_get_cipher_name(conf, id, pool); - } - return apr_array_pstrcat(pool, names, ':'); -} - -apr_status_t tls_proto_pre_config(apr_pool_t *pool, apr_pool_t *ptemp) -{ - (void)pool; - (void)ptemp; - return APR_SUCCESS; -} - -apr_status_t tls_proto_post_config(apr_pool_t *pool, apr_pool_t *ptemp, server_rec *s) -{ - tls_conf_server_t *sc = tls_conf_server_get(s); - tls_proto_conf_t *conf = sc->global->proto; - - (void)pool; - if (APLOGdebug(s)) { - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(10314) - "tls ciphers supported: %s", - tls_proto_get_cipher_names(conf, conf->supported_cipher_ids, ptemp)); - } - return APR_SUCCESS; -} - -static apr_status_t get_uint16_from(const char *name, const char *prefix, apr_uint16_t *pint) -{ - apr_size_t plen = strlen(prefix); - if (strlen(name) == plen+4 && !strncmp(name, prefix, plen)) { - /* may be a hex notation cipher id */ - char *end = NULL; - apr_int64_t code = apr_strtoi64(name + plen, &end, 16); - if ((!end || !*end) && code && code <= APR_UINT16_MAX) { - *pint = (apr_uint16_t)code; - return APR_SUCCESS; - } - } - return APR_ENOENT; -} - -apr_uint16_t tls_proto_get_version_by_name(tls_proto_conf_t *conf, const char *name) -{ - apr_uint16_t version; - (void)conf; - if (!apr_strnatcasecmp(name, "TLSv1.2")) { - return TLS_VERSION_1_2; - } - else if (!apr_strnatcasecmp(name, "TLSv1.3")) { - return TLS_VERSION_1_3; - } - if (APR_SUCCESS == get_uint16_from(name, "TLSv0x", &version)) { - return version; - } - return 0; -} - -const char *tls_proto_get_version_name( - tls_proto_conf_t *conf, apr_uint16_t id, apr_pool_t *pool) -{ - (void)conf; - switch (id) { - case TLS_VERSION_1_2: - return "TLSv1.2"; - case TLS_VERSION_1_3: - return "TLSv1.3"; - default: - return apr_psprintf(pool, "TLSv0x%04x", id); - } -} - -apr_array_header_t *tls_proto_create_versions_plus( - tls_proto_conf_t *conf, apr_uint16_t min_version, apr_pool_t *pool) -{ - apr_array_header_t *versions = apr_array_make(pool, 3, sizeof(apr_uint16_t)); - apr_uint16_t version; - int i; - - for (i = 0; i < conf->supported_versions->nelts; ++i) { - version = APR_ARRAY_IDX(conf->supported_versions, i, apr_uint16_t); - if (version >= min_version) { - APR_ARRAY_PUSH(versions, apr_uint16_t) = version; - } - } - return versions; -} - -int tls_proto_is_cipher_supported(tls_proto_conf_t *conf, apr_uint16_t cipher) -{ - return tls_util_array_uint16_contains(conf->supported_cipher_ids, cipher); -} - -apr_status_t tls_proto_get_cipher_by_name( - tls_proto_conf_t *conf, const char *name, apr_uint16_t *pcipher) -{ - tls_cipher_t *cipher = apr_hash_get(conf->known_ciphers_by_name, name, APR_HASH_KEY_STRING); - if (cipher) { - *pcipher = cipher->id; - return APR_SUCCESS; - } - return get_uint16_from(name, "TLS_CIPHER_0x", pcipher); -} - -const char *tls_proto_get_cipher_name( - tls_proto_conf_t *conf, apr_uint16_t id, apr_pool_t *pool) -{ - tls_cipher_t *cipher = apr_hash_get(conf->known_ciphers_by_id, &id, sizeof(apr_uint16_t)); - if (cipher) { - return cipher->name; - } - return apr_psprintf(pool, "TLS_CIPHER_0x%04x", id); -} - -apr_array_header_t *tls_proto_get_rustls_suites( - tls_proto_conf_t *conf, const apr_array_header_t *ids, apr_pool_t *pool) -{ - apr_array_header_t *suites; - rustls_cipher_t *rcipher; - apr_uint16_t id; - int i; - - suites = apr_array_make(pool, ids->nelts, sizeof(const rustls_supported_ciphersuite*)); - for (i = 0; i < ids->nelts; ++i) { - id = APR_ARRAY_IDX(ids, i, apr_uint16_t); - rcipher = apr_hash_get(conf->rustls_ciphers_by_id, &id, sizeof(apr_uint16_t)); - if (rcipher) { - APR_ARRAY_PUSH(suites, const rustls_supported_ciphersuite *) = rcipher->rustls_suite; - } - } - return suites; -} diff --git a/modules/tls/tls_proto.h b/modules/tls/tls_proto.h deleted file mode 100644 index a3fe881dba..0000000000 --- a/modules/tls/tls_proto.h +++ /dev/null @@ -1,124 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef tls_proto_h -#define tls_proto_h - -#include "tls_util.h" - - -#define TLS_VERSION_1_2 0x0303 -#define TLS_VERSION_1_3 0x0304 - -/** - * Specification of a TLS cipher by name, possible alias and its 16 bit value - * as assigned by IANA. - */ -typedef struct { - apr_uint16_t id; /* IANA 16-bit assigned value as used on the wire */ - const char *name; /* IANA given name of the cipher */ - const char *alias; /* Optional, commonly known alternate name */ -} tls_cipher_t; - -/** - * TLS protocol related definitions constructed - * by querying crustls lib. - */ -typedef struct tls_proto_conf_t tls_proto_conf_t; -struct tls_proto_conf_t { - apr_array_header_t *supported_versions; /* supported protocol versions (apr_uint16_t) */ - apr_hash_t *known_ciphers_by_name; /* hash by name of known tls_cipher_t* */ - apr_hash_t *known_ciphers_by_id; /* hash by id of known tls_cipher_t* */ - apr_hash_t *rustls_ciphers_by_id; /* hash by id of rustls rustls_supported_ciphersuite* */ - apr_array_header_t *supported_cipher_ids; /* cipher ids (apr_uint16_t) supported by rustls */ - const rustls_root_cert_store *native_roots; -}; - -/** - * Create and populate the protocol configuration. - */ -tls_proto_conf_t *tls_proto_init(apr_pool_t *p, server_rec *s); - -/** - * Called during pre-config phase to start initialization - * of the tls protocol configuration. - */ -apr_status_t tls_proto_pre_config(apr_pool_t *pool, apr_pool_t *ptemp); - -/** - * Called during post-config phase to conclude the initialization - * of the tls protocol configuration. - */ -apr_status_t tls_proto_post_config(apr_pool_t *p, apr_pool_t *ptemp, server_rec *s); - -/** - * Get the TLS protocol identifier (as used on the wire) for the TLS - * protocol of the given name. Returns 0 if protocol is unknown. - */ -apr_uint16_t tls_proto_get_version_by_name(tls_proto_conf_t *conf, const char *name); - -/** - * Get the name of the protocol version identified by its identifier. This - * will return the name from the protocol configuration or, if unknown, create - * the string `TLSv0x%04x` from the 16bit identifier. - */ -const char *tls_proto_get_version_name( - tls_proto_conf_t *conf, apr_uint16_t id, apr_pool_t *pool); - -/** - * Create an array of the given TLS protocol version identifier `min_version` - * and all supported new ones. The array carries apr_uint16_t values. - */ -apr_array_header_t *tls_proto_create_versions_plus( - tls_proto_conf_t *conf, apr_uint16_t min_version, apr_pool_t *pool); - -/** - * Get a TLS cipher spec by name/alias. - */ -apr_status_t tls_proto_get_cipher_by_name( - tls_proto_conf_t *conf, const char *name, apr_uint16_t *pcipher); - -/** - * Return != 0 iff the cipher is supported by the rustls library. - */ -int tls_proto_is_cipher_supported(tls_proto_conf_t *conf, apr_uint16_t cipher); - -/** - * Get the name of a TLS cipher for the IANA assigned 16bit value. This will - * return the name in the protocol configuration, if the cipher is known, and - * create the string `TLS_CIPHER_0x%04x` for the 16bit cipher value. - */ -const char *tls_proto_get_cipher_name( - tls_proto_conf_t *conf, apr_uint16_t cipher, apr_pool_t *pool); - -/** - * Get the concatenated names with ':' as separator of all TLS cipher identifiers - * as given in `ciphers`. - * @param conf the TLS protocol configuration - * @param ciphers the 16bit values of the TLS ciphers - * @param pool to use for allocation the string. - */ -const char *tls_proto_get_cipher_names( - tls_proto_conf_t *conf, const apr_array_header_t *ciphers, apr_pool_t *pool); - -/** - * Convert an array of TLS cipher 16bit identifiers into the `rustls_supported_ciphersuite` - * instances that can be passed to crustls in session configurations. - * Any cipher identifier not supported by rustls we be silently omitted. - */ -apr_array_header_t *tls_proto_get_rustls_suites( - tls_proto_conf_t *conf, const apr_array_header_t *ids, apr_pool_t *pool); - -#endif /* tls_proto_h */ diff --git a/modules/tls/tls_util.c b/modules/tls/tls_util.c deleted file mode 100644 index 9eac212815..0000000000 --- a/modules/tls/tls_util.c +++ /dev/null @@ -1,367 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include <assert.h> -#include <apr_lib.h> -#include <apr_file_info.h> -#include <apr_strings.h> - -#include <httpd.h> -#include <http_core.h> -#include <http_log.h> - -#include <rustls.h> - -#include "tls_proto.h" -#include "tls_util.h" - - -extern module AP_MODULE_DECLARE_DATA tls_module; -APLOG_USE_MODULE(tls); - - -tls_data_t tls_data_from_str(const char *s) -{ - tls_data_t d; - d.data = (const unsigned char*)s; - d.len = s? strlen(s) : 0; - return d; -} - -tls_data_t tls_data_assign_copy(apr_pool_t *p, const tls_data_t *d) -{ - tls_data_t copy; - copy.data = apr_pmemdup(p, d->data, d->len); - copy.len = d->len; - return copy; -} - -tls_data_t *tls_data_copy(apr_pool_t *p, const tls_data_t *d) -{ - tls_data_t *copy; - copy = apr_pcalloc(p, sizeof(*copy)); - *copy = tls_data_assign_copy(p, d); - return copy; -} - -const char *tls_data_to_str(apr_pool_t *p, const tls_data_t *d) -{ - char *s = apr_pcalloc(p, d->len+1); - memcpy(s, d->data, d->len); - return s; -} - -apr_status_t tls_util_rustls_error( - apr_pool_t *p, rustls_result rr, const char **perr_descr) -{ - if (perr_descr) { - char buffer[HUGE_STRING_LEN]; - apr_size_t len = 0; - - rustls_error(rr, buffer, sizeof(buffer), &len); - *perr_descr = apr_pstrndup(p, buffer, len); - } - return APR_EGENERAL; -} - -int tls_util_is_file( - apr_pool_t *p, const char *fpath) -{ - apr_finfo_t finfo; - - return (fpath != NULL - && apr_stat(&finfo, fpath, APR_FINFO_TYPE|APR_FINFO_SIZE, p) == 0 - && finfo.filetype == APR_REG); -} - -apr_status_t tls_util_file_load( - apr_pool_t *p, const char *fpath, apr_size_t min_len, apr_size_t max_len, tls_data_t *data) -{ - apr_finfo_t finfo; - apr_status_t rv; - apr_file_t *f = NULL; - unsigned char *buffer; - apr_size_t len; - const char *err = NULL; - tls_data_t *d; - - rv = apr_stat(&finfo, fpath, APR_FINFO_TYPE|APR_FINFO_SIZE, p); - if (APR_SUCCESS != rv) { - err = "cannot stat"; goto cleanup; - } - if (finfo.filetype != APR_REG) { - err = "not a plain file"; - rv = APR_EINVAL; goto cleanup; - } - if (finfo.size > LONG_MAX) { - err = "file is too large"; - rv = APR_EINVAL; goto cleanup; - } - len = (apr_size_t)finfo.size; - if (len < min_len || len > max_len) { - err = "file size not in allowed range"; - rv = APR_EINVAL; goto cleanup; - } - d = apr_pcalloc(p, sizeof(*d)); - buffer = apr_pcalloc(p, len+1); /* keep it NUL terminated in any case */ - rv = apr_file_open(&f, fpath, APR_FOPEN_READ, 0, p); - if (APR_SUCCESS != rv) { - err = "error opening"; goto cleanup; - } - rv = apr_file_read(f, buffer, &len); - if (APR_SUCCESS != rv) { - err = "error reading"; goto cleanup; - } -cleanup: - if (f) apr_file_close(f); - if (APR_SUCCESS == rv) { - data->data = buffer; - data->len = len; - } - else { - memset(data, 0, sizeof(*data)); - ap_log_perror(APLOG_MARK, APLOG_ERR, rv, p, APLOGNO(10361) - "Failed to load file %s: %s", fpath, err? err: "-"); - } - return rv; -} - -int tls_util_array_uint16_contains(const apr_array_header_t* a, apr_uint16_t n) -{ - int i; - for (i = 0; i < a->nelts; ++i) { - if (APR_ARRAY_IDX(a, i, apr_uint16_t) == n) return 1; - } - return 0; -} - -const apr_array_header_t *tls_util_array_uint16_remove( - apr_pool_t *pool, const apr_array_header_t* from, const apr_array_header_t* others) -{ - apr_array_header_t *na = NULL; - apr_uint16_t id; - int i, j; - - for (i = 0; i < from->nelts; ++i) { - id = APR_ARRAY_IDX(from, i, apr_uint16_t); - if (tls_util_array_uint16_contains(others, id)) { - if (na == NULL) { - /* first removal, make a new result array, copy elements before */ - na = apr_array_make(pool, from->nelts, sizeof(apr_uint16_t)); - for (j = 0; j < i; ++j) { - APR_ARRAY_PUSH(na, apr_uint16_t) = APR_ARRAY_IDX(from, j, apr_uint16_t); - } - } - } - else if (na) { - APR_ARRAY_PUSH(na, apr_uint16_t) = id; - } - } - return na? na : from; -} - -apr_status_t tls_util_brigade_transfer( - apr_bucket_brigade *dest, apr_bucket_brigade *src, apr_off_t length, - apr_off_t *pnout) -{ - apr_bucket *b; - apr_off_t remain = length; - apr_status_t rv = APR_SUCCESS; - const char *ign; - apr_size_t ilen; - - *pnout = 0; - while (!APR_BRIGADE_EMPTY(src)) { - b = APR_BRIGADE_FIRST(src); - - if (APR_BUCKET_IS_METADATA(b)) { - APR_BUCKET_REMOVE(b); - APR_BRIGADE_INSERT_TAIL(dest, b); - } - else { - if (remain == (apr_off_t)b->length) { - /* fall through */ - } - else if (remain <= 0) { - goto cleanup; - } - else { - if (b->length == ((apr_size_t)-1)) { - rv= apr_bucket_read(b, &ign, &ilen, APR_BLOCK_READ); - if (APR_SUCCESS != rv) goto cleanup; - } - if (remain < (apr_off_t)b->length) { - apr_bucket_split(b, (apr_size_t)remain); - } - } - APR_BUCKET_REMOVE(b); - APR_BRIGADE_INSERT_TAIL(dest, b); - remain -= (apr_off_t)b->length; - *pnout += (apr_off_t)b->length; - } - } -cleanup: - return rv; -} - -apr_status_t tls_util_brigade_copy( - apr_bucket_brigade *dest, apr_bucket_brigade *src, apr_off_t length, - apr_off_t *pnout) -{ - apr_bucket *b, *next; - apr_off_t remain = length; - apr_status_t rv = APR_SUCCESS; - const char *ign; - apr_size_t ilen; - - *pnout = 0; - for (b = APR_BRIGADE_FIRST(src); - b != APR_BRIGADE_SENTINEL(src); - b = next) { - next = APR_BUCKET_NEXT(b); - - if (APR_BUCKET_IS_METADATA(b)) { - /* fall through */ - } - else { - if (remain == (apr_off_t)b->length) { - /* fall through */ - } - else if (remain <= 0) { - goto cleanup; - } - else { - if (b->length == ((apr_size_t)-1)) { - rv = apr_bucket_read(b, &ign, &ilen, APR_BLOCK_READ); - if (APR_SUCCESS != rv) goto cleanup; - } - if (remain < (apr_off_t)b->length) { - apr_bucket_split(b, (apr_size_t)remain); - } - } - } - rv = apr_bucket_copy(b, &b); - if (APR_SUCCESS != rv) goto cleanup; - APR_BRIGADE_INSERT_TAIL(dest, b); - remain -= (apr_off_t)b->length; - *pnout += (apr_off_t)b->length; - } -cleanup: - return rv; -} - -apr_status_t tls_util_brigade_split_line( - apr_bucket_brigade *dest, apr_bucket_brigade *src, - apr_read_type_e block, apr_off_t length, - apr_off_t *pnout) -{ - apr_off_t nstart, nend; - apr_status_t rv; - - apr_brigade_length(dest, 0, &nstart); - rv = apr_brigade_split_line(dest, src, block, length); - if (APR_SUCCESS != rv) goto cleanup; - apr_brigade_length(dest, 0, &nend); - /* apr_brigade_split_line() has the nasty habit of leaving a 0-length bucket - * at the start of the brigade when it transferred the whole content. Get rid of it. - */ - if (!APR_BRIGADE_EMPTY(src)) { - apr_bucket *b = APR_BRIGADE_FIRST(src); - if (!APR_BUCKET_IS_METADATA(b) && 0 == b->length) { - APR_BUCKET_REMOVE(b); - apr_bucket_delete(b); - } - } -cleanup: - *pnout = (APR_SUCCESS == rv)? (nend - nstart) : 0; - return rv; -} - -int tls_util_name_matches_server(const char *name, server_rec *s) -{ - apr_array_header_t *names; - char **alias; - int i; - - if (!s || !s->server_hostname) return 0; - if (!strcasecmp(name, s->server_hostname)) return 1; - /* first the fast equality match, then the pattern wild_name matches */ - names = s->names; - if (!names) return 0; - alias = (char **)names->elts; - for (i = 0; i < names->nelts; ++i) { - if (alias[i] && !strcasecmp(name, alias[i])) return 1; - } - names = s->wild_names; - if (!names) return 0; - alias = (char **)names->elts; - for (i = 0; i < names->nelts; ++i) { - if (alias[i] && !ap_strcasecmp_match(name, alias[i])) return 1; - } - return 0; -} - -apr_size_t tls_util_bucket_print(char *buffer, apr_size_t bmax, - apr_bucket *b, const char *sep) -{ - apr_size_t off = 0; - if (sep && *sep) { - off += (size_t)apr_snprintf(buffer+off, bmax-off, "%s", sep); - } - - if (bmax <= off) { - return off; - } - else if (APR_BUCKET_IS_METADATA(b)) { - off += (size_t)apr_snprintf(buffer+off, bmax-off, "%s", b->type->name); - } - else if (bmax > off) { - off += (size_t)apr_snprintf(buffer+off, bmax-off, "%s[%ld]", - b->type->name, (long)(b->length == ((apr_size_t)-1)? - -1 : (int)b->length)); - } - return off; -} - -apr_size_t tls_util_bb_print(char *buffer, apr_size_t bmax, - const char *tag, const char *sep, - apr_bucket_brigade *bb) -{ - apr_size_t off = 0; - const char *sp = ""; - apr_bucket *b; - - if (bmax > 1) { - if (bb) { - memset(buffer, 0, bmax--); - off += (size_t)apr_snprintf(buffer+off, bmax-off, "%s(", tag); - for (b = APR_BRIGADE_FIRST(bb); - (bmax > off) && (b != APR_BRIGADE_SENTINEL(bb)); - b = APR_BUCKET_NEXT(b)) { - - off += tls_util_bucket_print(buffer+off, bmax-off, b, sp); - sp = " "; - } - if (bmax > off) { - off += (size_t)apr_snprintf(buffer+off, bmax-off, ")%s", sep); - } - } - else { - off += (size_t)apr_snprintf(buffer+off, bmax-off, "%s(null)%s", tag, sep); - } - } - return off; -} - diff --git a/modules/tls/tls_util.h b/modules/tls/tls_util.h deleted file mode 100644 index 18ae4dff4a..0000000000 --- a/modules/tls/tls_util.h +++ /dev/null @@ -1,157 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef tls_util_h -#define tls_util_h - -#define TLS_DIM(a) (sizeof(a)/sizeof(a[0])) - - -/** - * Simple struct to hold a range of bytes and its length together. - */ -typedef struct tls_data_t tls_data_t; -struct tls_data_t { - const unsigned char* data; - apr_size_t len; -}; - -/** - * Return a tls_data_t for a string. - */ -tls_data_t tls_data_from_str(const char *s); - -/** - * Create a copy of a tls_data_t using the given pool. - */ -tls_data_t *tls_data_copy(apr_pool_t *p, const tls_data_t *d); - -/** - * Return a copy of a tls_data_t bytes allocated from pool. - */ -tls_data_t tls_data_assign_copy(apr_pool_t *p, const tls_data_t *d); - -/** - * Convert the data bytes in `d` into a NUL-terminated string. - * There is no check if the data bytes already contain NUL. - */ -const char *tls_data_to_str(apr_pool_t *p, const tls_data_t *d); - -/** - * Return != 0 if fpath is a 'real' file. - */ -int tls_util_is_file(apr_pool_t *p, const char *fpath); - -/** - * Inspect a 'rustls_result', retrieve the error description for it and - * return the apr_status_t to use as our error status. - */ -apr_status_t tls_util_rustls_error(apr_pool_t *p, rustls_result rr, const char **perr_descr); - -/** - * Load up to `max_len` bytes into a buffer allocated from the pool. - * @return ARP_SUCCESS on successful load. - * APR_EINVAL when the file was not a regular file or is too large. - */ -apr_status_t tls_util_file_load( - apr_pool_t *p, const char *fpath, size_t min_len, size_t max_len, tls_data_t *data); - -/** - * Return != 0 iff the array of apr_uint16_t contains value n. - */ -int tls_util_array_uint16_contains(const apr_array_header_t* a, apr_uint16_t n); - -/** - * Remove all apr_uint16_t in `others` from array `from`. - * Returns the new array or, if no overlap was found, the `from` array unchanged. - */ -const apr_array_header_t *tls_util_array_uint16_remove( - apr_pool_t *pool, const apr_array_header_t* from, const apr_array_header_t* others); - -/** - * Transfer up to <length> bytes from <src> to <dest>, including all - * encountered meta data buckets. The transferred buckets/data are - * removed from <src>. - * Return the actual byte count transferred in <pnout>. - */ -apr_status_t tls_util_brigade_transfer( - apr_bucket_brigade *dest, apr_bucket_brigade *src, apr_off_t length, - apr_off_t *pnout); - -/** - * Copy up to <length> bytes from <src> to <dest>, including all - * encountered meta data buckets. <src> remains semantically unchaanged, - * meaning there might have been buckets split or changed while reading - * their content. - * Return the actual byte count copied in <pnout>. - */ -apr_status_t tls_util_brigade_copy( - apr_bucket_brigade *dest, apr_bucket_brigade *src, apr_off_t length, - apr_off_t *pnout); - -/** - * Get a line of max `length` bytes from `src` into `dest`. - * Return the number of bytes transferred in `pnout`. - */ -apr_status_t tls_util_brigade_split_line( - apr_bucket_brigade *dest, apr_bucket_brigade *src, - apr_read_type_e block, apr_off_t length, - apr_off_t *pnout); - -/** - * Return != 0 iff the given <name> matches the configured 'ServerName' - * or one of the 'ServerAlias' name of <s>, including wildcard patterns - * as understood by ap_strcasecmp_match(). - */ -int tls_util_name_matches_server(const char *name, server_rec *s); - - -/** - * Print a bucket's meta data (type and length) to the buffer. - * @return number of characters printed - */ -apr_size_t tls_util_bucket_print(char *buffer, apr_size_t bmax, - apr_bucket *b, const char *sep); - -/** - * Prints the brigade bucket types and lengths into the given buffer - * up to bmax. - * @return number of characters printed - */ -apr_size_t tls_util_bb_print(char *buffer, apr_size_t bmax, - const char *tag, const char *sep, - apr_bucket_brigade *bb); -/** - * Logs the bucket brigade (which bucket types with what length) - * to the log at the given level. - * @param c the connection to log for - * @param sid the stream identifier this brigade belongs to - * @param level the log level (as in APLOG_*) - * @param tag a short message text about the context - * @param bb the brigade to log - */ -#define tls_util_bb_log(c, level, tag, bb) \ -do { \ - char buffer[4 * 1024]; \ - const char *line = "(null)"; \ - apr_size_t len, bmax = sizeof(buffer)/sizeof(buffer[0]); \ - len = tls_util_bb_print(buffer, bmax, (tag), "", (bb)); \ - ap_log_cerror(APLOG_MARK, level, 0, (c), "bb_dump(%ld): %s", \ - ((c)->master? (c)->master->id : (c)->id), (len? buffer : line)); \ -} while(0) - - - -#endif /* tls_util_h */ diff --git a/modules/tls/tls_var.c b/modules/tls/tls_var.c deleted file mode 100644 index fa4ae2aed6..0000000000 --- a/modules/tls/tls_var.c +++ /dev/null @@ -1,397 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include <assert.h> -#include <apr_lib.h> -#include <apr_strings.h> - -#include <httpd.h> -#include <http_connection.h> -#include <http_core.h> -#include <http_main.h> -#include <http_log.h> -#include <ap_socache.h> - -#include <rustls.h> - -#include "tls_conf.h" -#include "tls_core.h" -#include "tls_cert.h" -#include "tls_util.h" -#include "tls_var.h" -#include "tls_version.h" - - -extern module AP_MODULE_DECLARE_DATA tls_module; -APLOG_USE_MODULE(tls); - -typedef struct { - apr_pool_t *p; - server_rec *s; - conn_rec *c; - request_rec *r; - tls_conf_conn_t *cc; - const char *name; - const char *arg_s; - int arg_i; -} tls_var_lookup_ctx_t; - -typedef const char *var_lookup(const tls_var_lookup_ctx_t *ctx); - -static const char *var_get_ssl_protocol(const tls_var_lookup_ctx_t *ctx) -{ - return ctx->cc->tls_protocol_name; -} - -static const char *var_get_ssl_cipher(const tls_var_lookup_ctx_t *ctx) -{ - return ctx->cc->tls_cipher_name; -} - -static const char *var_get_sni_hostname(const tls_var_lookup_ctx_t *ctx) -{ - return ctx->cc->sni_hostname; -} - -static const char *var_get_version_interface(const tls_var_lookup_ctx_t *ctx) -{ - tls_conf_server_t *sc = tls_conf_server_get(ctx->s); - return sc->global->module_version; -} - -static const char *var_get_version_library(const tls_var_lookup_ctx_t *ctx) -{ - tls_conf_server_t *sc = tls_conf_server_get(ctx->s); - return sc->global->crustls_version; -} - -static const char *var_get_false(const tls_var_lookup_ctx_t *ctx) -{ - (void)ctx; - return "false"; -} - -static const char *var_get_null(const tls_var_lookup_ctx_t *ctx) -{ - (void)ctx; - return "NULL"; -} - -static const char *var_get_client_s_dn_cn(const tls_var_lookup_ctx_t *ctx) -{ - /* There is no support in the crustls/rustls/webpki APIs to - * parse X.509 certificates and extract information about - * subject, issuer, etc. */ - if (!ctx->cc->peer_certs || !ctx->cc->peer_certs->nelts) return NULL; - return "Not Implemented"; -} - -static const char *var_get_client_verify(const tls_var_lookup_ctx_t *ctx) -{ - return ctx->cc->peer_certs? "SUCCESS" : "NONE"; -} - -static const char *var_get_session_resumed(const tls_var_lookup_ctx_t *ctx) -{ - return ctx->cc->session_id_cache_hit? "Resumed" : "Initial"; -} - -static const char *var_get_client_cert(const tls_var_lookup_ctx_t *ctx) -{ - const rustls_certificate *cert; - const char *pem; - apr_status_t rv; - int cert_idx = 0; - - if (ctx->arg_s) { - if (strcmp(ctx->arg_s, "chain")) return NULL; - /* ctx->arg_i'th chain cert, which is in out list as */ - cert_idx = ctx->arg_i + 1; - } - if (!ctx->cc->peer_certs || cert_idx >= ctx->cc->peer_certs->nelts) return NULL; - cert = APR_ARRAY_IDX(ctx->cc->peer_certs, cert_idx, const rustls_certificate*); - if (APR_SUCCESS != (rv = tls_cert_to_pem(&pem, ctx->p, cert))) { - ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, ctx->s, APLOGNO(10315) - "Failed to create client certificate PEM"); - return NULL; - } - return pem; -} - -static const char *var_get_server_cert(const tls_var_lookup_ctx_t *ctx) -{ - const rustls_certificate *cert; - const char *pem; - apr_status_t rv; - - if (!ctx->cc->key) return NULL; - cert = rustls_certified_key_get_certificate(ctx->cc->key, 0); - if (!cert) return NULL; - if (APR_SUCCESS != (rv = tls_cert_to_pem(&pem, ctx->p, cert))) { - ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, ctx->s, APLOGNO(10316) - "Failed to create server certificate PEM"); - return NULL; - } - return pem; -} - -typedef struct { - const char *name; - var_lookup* fn; - const char *arg_s; - int arg_i; -} var_def_t; - -static const var_def_t VAR_DEFS[] = { - { "SSL_PROTOCOL", var_get_ssl_protocol, NULL, 0 }, - { "SSL_CIPHER", var_get_ssl_cipher, NULL, 0 }, - { "SSL_TLS_SNI", var_get_sni_hostname, NULL, 0 }, - { "SSL_CLIENT_S_DN_CN", var_get_client_s_dn_cn, NULL, 0 }, - { "SSL_VERSION_INTERFACE", var_get_version_interface, NULL, 0 }, - { "SSL_VERSION_LIBRARY", var_get_version_library, NULL, 0 }, - { "SSL_SECURE_RENEG", var_get_false, NULL, 0 }, - { "SSL_COMPRESS_METHOD", var_get_null, NULL, 0 }, - { "SSL_CIPHER_EXPORT", var_get_false, NULL, 0 }, - { "SSL_CLIENT_VERIFY", var_get_client_verify, NULL, 0 }, - { "SSL_SESSION_RESUMED", var_get_session_resumed, NULL, 0 }, - { "SSL_CLIENT_CERT", var_get_client_cert, NULL, 0 }, - { "SSL_CLIENT_CHAIN_0", var_get_client_cert, "chain", 0 }, - { "SSL_CLIENT_CHAIN_1", var_get_client_cert, "chain", 1 }, - { "SSL_CLIENT_CHAIN_2", var_get_client_cert, "chain", 2 }, - { "SSL_CLIENT_CHAIN_3", var_get_client_cert, "chain", 3 }, - { "SSL_CLIENT_CHAIN_4", var_get_client_cert, "chain", 4 }, - { "SSL_CLIENT_CHAIN_5", var_get_client_cert, "chain", 5 }, - { "SSL_CLIENT_CHAIN_6", var_get_client_cert, "chain", 6 }, - { "SSL_CLIENT_CHAIN_7", var_get_client_cert, "chain", 7 }, - { "SSL_CLIENT_CHAIN_8", var_get_client_cert, "chain", 8 }, - { "SSL_CLIENT_CHAIN_9", var_get_client_cert, "chain", 9 }, - { "SSL_SERVER_CERT", var_get_server_cert, NULL, 0 }, -}; - -static const char *const TlsAlwaysVars[] = { - "SSL_TLS_SNI", - "SSL_PROTOCOL", - "SSL_CIPHER", - "SSL_CLIENT_S_DN_CN", -}; - -/* what mod_ssl defines, plus server cert and client cert DN and SAN entries */ -static const char *const StdEnvVars[] = { - "SSL_VERSION_INTERFACE", /* implemented: module version string */ - "SSL_VERSION_LIBRARY", /* implemented: crustls/rustls version string */ - "SSL_SECURE_RENEG", /* implemented: always "false" */ - "SSL_COMPRESS_METHOD", /* implemented: always "NULL" */ - "SSL_CIPHER_EXPORT", /* implemented: always "false" */ - "SSL_CIPHER_USEKEYSIZE", - "SSL_CIPHER_ALGKEYSIZE", - "SSL_CLIENT_VERIFY", /* implemented: always "SUCCESS" or "NONE" */ - "SSL_CLIENT_M_VERSION", - "SSL_CLIENT_M_SERIAL", - "SSL_CLIENT_V_START", - "SSL_CLIENT_V_END", - "SSL_CLIENT_V_REMAIN", - "SSL_CLIENT_S_DN", - "SSL_CLIENT_I_DN", - "SSL_CLIENT_A_KEY", - "SSL_CLIENT_A_SIG", - "SSL_CLIENT_CERT_RFC4523_CEA", - "SSL_SERVER_M_VERSION", - "SSL_SERVER_M_SERIAL", - "SSL_SERVER_V_START", - "SSL_SERVER_V_END", - "SSL_SERVER_S_DN", - "SSL_SERVER_I_DN", - "SSL_SERVER_A_KEY", - "SSL_SERVER_A_SIG", - "SSL_SESSION_ID", /* not implemented: highly sensitive data we do not expose */ - "SSL_SESSION_RESUMED", /* implemented: if our cache was hit successfully */ -}; - -/* Cert related variables, export when TLSOption ExportCertData is set */ -static const char *const ExportCertVars[] = { - "SSL_CLIENT_CERT", /* implemented: */ - "SSL_CLIENT_CHAIN_0", /* implemented: */ - "SSL_CLIENT_CHAIN_1", /* implemented: */ - "SSL_CLIENT_CHAIN_2", /* implemented: */ - "SSL_CLIENT_CHAIN_3", /* implemented: */ - "SSL_CLIENT_CHAIN_4", /* implemented: */ - "SSL_CLIENT_CHAIN_5", /* implemented: */ - "SSL_CLIENT_CHAIN_6", /* implemented: */ - "SSL_CLIENT_CHAIN_7", /* implemented: */ - "SSL_CLIENT_CHAIN_8", /* implemented: */ - "SSL_CLIENT_CHAIN_9", /* implemented: */ - "SSL_SERVER_CERT", /* implemented: */ -}; - -void tls_var_init_lookup_hash(apr_pool_t *pool, apr_hash_t *map) -{ - const var_def_t *def; - apr_size_t i; - - (void)pool; - for (i = 0; i < TLS_DIM(VAR_DEFS); ++i) { - def = &VAR_DEFS[i]; - apr_hash_set(map, def->name, APR_HASH_KEY_STRING, def); - } -} - -static const char *invoke(var_def_t* def, tls_var_lookup_ctx_t *ctx) -{ - if (TLS_CONN_ST_IS_ENABLED(ctx->cc)) { - const char *val = ctx->cc->subprocess_env? - apr_table_get(ctx->cc->subprocess_env, def->name) : NULL; - if (val && *val) return val; - ctx->arg_s = def->arg_s; - ctx->arg_i = def->arg_i; - return def->fn(ctx); - } - return NULL; -} - -static void set_var( - tls_var_lookup_ctx_t *ctx, apr_hash_t *lookups, apr_table_t *table) -{ - var_def_t* def = apr_hash_get(lookups, ctx->name, APR_HASH_KEY_STRING); - if (def) { - const char *val = invoke(def, ctx); - if (val && *val) { - apr_table_setn(table, ctx->name, val); - } - } -} - -const char *tls_var_lookup( - apr_pool_t *p, server_rec *s, conn_rec *c, request_rec *r, const char *name) -{ - const char *val = NULL; - tls_conf_server_t *sc; - var_def_t* def; - - ap_assert(p); - ap_assert(name); - s = s? s : (r? r->server : (c? c->base_server : NULL)); - c = c? c : (r? r->connection : NULL); - - sc = tls_conf_server_get(s? s : ap_server_conf); - def = apr_hash_get(sc->global->var_lookups, name, APR_HASH_KEY_STRING); - if (def) { - tls_var_lookup_ctx_t ctx; - ctx.p = p; - ctx.s = s; - ctx.c = c; - ctx.r = r; - ctx.cc = c? tls_conf_conn_get(c->master? c->master : c) : NULL; - ctx.cc = c? tls_conf_conn_get(c->master? c->master : c) : NULL; - ctx.name = name; - val = invoke(def, &ctx); - ap_log_cerror(APLOG_MARK, APLOG_TRACE3, 0, c, "tls lookup of var '%s' -> '%s'", name, val); - } - return val; -} - -static void add_vars(apr_table_t *env, conn_rec *c, server_rec *s, request_rec *r) -{ - tls_conf_server_t *sc; - tls_conf_dir_t *dc, *sdc; - tls_var_lookup_ctx_t ctx; - apr_size_t i; - int overlap; - - sc = tls_conf_server_get(s); - dc = r? tls_conf_dir_get(r) : tls_conf_dir_server_get(s); - sdc = r? tls_conf_dir_server_get(s): dc; - ctx.p = r? r->pool : c->pool; - ctx.s = s; - ctx.c = c; - ctx.r = r; - ctx.cc = tls_conf_conn_get(c->master? c->master : c); - /* Can we re-use the precomputed connection values? */ - overlap = (r && ctx.cc->subprocess_env && r->server == ctx.cc->server); - if (overlap) { - apr_table_overlap(env, ctx.cc->subprocess_env, APR_OVERLAP_TABLES_SET); - } - else { - apr_table_setn(env, "HTTPS", "on"); - for (i = 0; i < TLS_DIM(TlsAlwaysVars); ++i) { - ctx.name = TlsAlwaysVars[i]; - set_var(&ctx, sc->global->var_lookups, env); - } - } - if (dc->std_env_vars == TLS_FLAG_TRUE) { - for (i = 0; i < TLS_DIM(StdEnvVars); ++i) { - ctx.name = StdEnvVars[i]; - set_var(&ctx, sc->global->var_lookups, env); - } - } - else if (overlap && sdc->std_env_vars == TLS_FLAG_TRUE) { - /* Remove variables added on connection init that are disabled here */ - for (i = 0; i < TLS_DIM(StdEnvVars); ++i) { - apr_table_unset(env, StdEnvVars[i]); - } - } - if (dc->export_cert_vars == TLS_FLAG_TRUE) { - for (i = 0; i < TLS_DIM(ExportCertVars); ++i) { - ctx.name = ExportCertVars[i]; - set_var(&ctx, sc->global->var_lookups, env); - } - } - else if (overlap && sdc->std_env_vars == TLS_FLAG_TRUE) { - /* Remove variables added on connection init that are disabled here */ - for (i = 0; i < TLS_DIM(ExportCertVars); ++i) { - apr_table_unset(env, ExportCertVars[i]); - } - } - } - -apr_status_t tls_var_handshake_done(conn_rec *c) -{ - tls_conf_conn_t *cc; - tls_conf_server_t *sc; - apr_status_t rv = APR_SUCCESS; - - cc = tls_conf_conn_get(c); - if (!TLS_CONN_ST_IS_ENABLED(cc)) goto cleanup; - - sc = tls_conf_server_get(cc->server); - if (cc->peer_certs && sc->var_user_name) { - cc->user_name = tls_var_lookup(c->pool, cc->server, c, NULL, sc->var_user_name); - if (!cc->user_name) { - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, cc->server, APLOGNO(10317) - "Failed to set r->user to '%s'", sc->var_user_name); - } - } - cc->subprocess_env = apr_table_make(c->pool, 5); - add_vars(cc->subprocess_env, c, cc->server, NULL); - -cleanup: - return rv; -} - -int tls_var_request_fixup(request_rec *r) -{ - conn_rec *c = r->connection; - tls_conf_conn_t *cc; - - cc = tls_conf_conn_get(c->master? c->master : c); - if (!TLS_CONN_ST_IS_ENABLED(cc)) goto cleanup; - if (cc->user_name) { - /* why is r->user a char* and not const? */ - r->user = apr_pstrdup(r->pool, cc->user_name); - } - add_vars(r->subprocess_env, c, r->server, r); - -cleanup: - return DECLINED; -} diff --git a/modules/tls/tls_var.h b/modules/tls/tls_var.h deleted file mode 100644 index 2e8c0bb09b..0000000000 --- a/modules/tls/tls_var.h +++ /dev/null @@ -1,39 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef tls_var_h -#define tls_var_h - -void tls_var_init_lookup_hash(apr_pool_t *pool, apr_hash_t *map); - -/** - * Callback for installation in Apache's 'ssl_var_lookup' hook to provide - * SSL related variable lookups to other modules. - */ -const char *tls_var_lookup( - apr_pool_t *p, server_rec *s, conn_rec *c, request_rec *r, const char *name); - -/** - * A connection has been handshaked. Prepare commond TLS variables on this connection. - */ -apr_status_t tls_var_handshake_done(conn_rec *c); - -/** - * A request is ready for processing, add TLS variables r->subprocess_env if applicable. - * This is a hook function returning OK/DECLINED. - */ -int tls_var_request_fixup(request_rec *r); - -#endif /* tls_var_h */
\ No newline at end of file diff --git a/modules/tls/tls_version.h b/modules/tls/tls_version.h deleted file mode 100644 index bc9fb0bbb7..0000000000 --- a/modules/tls/tls_version.h +++ /dev/null @@ -1,39 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef mod_tls_version_h -#define mod_tls_version_h - -#undef PACKAGE_VERSION -#undef PACKAGE_TARNAME -#undef PACKAGE_STRING -#undef PACKAGE_NAME -#undef PACKAGE_BUGREPORT - -/** - * @macro - * Version number of the md module as c string - */ -#define MOD_TLS_VERSION "0.9.0" - -/** - * @macro - * Numerical representation of the version number of the md module - * release. This is a 24 bit number with 8 bits for major number, 8 bits - * for minor and 8 bits for patch. Version 1.2.3 becomes 0x010203. - */ -#define MOD_TLS_VERSION_NUM 0x000900 - -#endif /* mod_md_md_version_h */ diff --git a/test/modules/tls/__init__.py b/test/modules/tls/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 --- a/test/modules/tls/__init__.py +++ /dev/null diff --git a/test/modules/tls/conf.py b/test/modules/tls/conf.py deleted file mode 100644 index b34f746004..0000000000 --- a/test/modules/tls/conf.py +++ /dev/null @@ -1,68 +0,0 @@ -import os -from typing import List, Dict, Any - -from pyhttpd.conf import HttpdConf -from pyhttpd.env import HttpdTestEnv - - -class TlsTestConf(HttpdConf): - - def __init__(self, env: HttpdTestEnv, extras: Dict[str, Any] = None): - extras = extras if extras is not None else {} - super().__init__(env=env, extras=extras) - - def start_tls_vhost(self, domains: List[str], port=None, ssl_module=None): - if ssl_module is None: - if not self.env.has_shared_module("tls"): - ssl_module = "mod_ssl" - else: - ssl_module = 'mod_tls' - super().start_vhost(domains=domains, port=port, doc_root=f"htdocs/{domains[0]}", ssl_module=ssl_module) - - def end_tls_vhost(self): - self.end_vhost() - - def add_tls_vhosts(self, domains: List[str], port=None, ssl_module=None): - for domain in domains: - self.start_tls_vhost(domains=[domain], port=port, ssl_module=ssl_module) - self.end_tls_vhost() - - def add_md_vhosts(self, domains: List[str], port = None): - self.add([ - f"LoadModule md_module {self.env.libexec_dir}/mod_md.so", - "LogLevel md:debug", - ]) - for domain in domains: - self.add(f"<MDomain {domain}>") - for cred in self.env.ca.get_credentials_for_name(domain): - cert_file = os.path.relpath(cred.cert_file, self.env.server_dir) - pkey_file = os.path.relpath(cred.pkey_file, self.env.server_dir) if cred.pkey_file else cert_file - self.add([ - f" MDCertificateFile {cert_file}", - f" MDCertificateKeyFile {pkey_file}", - ]) - self.add("</MDomain>") - if self.env.has_shared_module("tls"): - ssl_module= "mod_tls" - else: - ssl_module= "mod_ssl" - super().add_vhost(domains=[domain], port=port, doc_root=f"htdocs/{domain}", - with_ssl=True, with_certificates=False, ssl_module=ssl_module) - - def add_md_base(self, domain: str): - self.add([ - f"LoadModule md_module {self.env.libexec_dir}/mod_md.so", - "LogLevel md:debug", - f"ServerName {domain}", - "MDBaseServer on", - ]) - self.add(f"TLSEngine {self.env.https_port}") - self.add(f"<MDomain {domain}>") - for cred in self.env.ca.get_credentials_for_name(domain): - cert_file = os.path.relpath(cred.cert_file, self.env.server_dir) - pkey_file = os.path.relpath(cred.pkey_file, self.env.server_dir) if cred.pkey_file else cert_file - self.add([ - f"MDCertificateFile {cert_file}", - f"MDCertificateKeyFile {pkey_file}", - ]) - self.add("</MDomain>") diff --git a/test/modules/tls/conftest.py b/test/modules/tls/conftest.py deleted file mode 100644 index 6f6f983cfd..0000000000 --- a/test/modules/tls/conftest.py +++ /dev/null @@ -1,38 +0,0 @@ -import logging -import os -import sys -import pytest - -sys.path.append(os.path.join(os.path.dirname(__file__), '../..')) - -from .env import TlsTestEnv - - -def pytest_report_header(config, startdir): - _x = config - _x = startdir - env = TlsTestEnv() - return "mod_tls [apache: {aversion}({prefix})]".format( - prefix=env.prefix, - aversion=env.get_httpd_version() - ) - - -@pytest.fixture(scope="package") -def env(pytestconfig) -> TlsTestEnv: - level = logging.INFO - console = logging.StreamHandler() - console.setLevel(level) - console.setFormatter(logging.Formatter('%(levelname)s: %(message)s')) - logging.getLogger('').addHandler(console) - logging.getLogger('').setLevel(level=level) - env = TlsTestEnv(pytestconfig=pytestconfig) - env.setup_httpd() - env.apache_access_log_clear() - env.httpd_error_log.clear_log() - return env - -@pytest.fixture(autouse=True, scope="package") -def _stop_package_scope(env): - yield - assert env.apache_stop() == 0 diff --git a/test/modules/tls/env.py b/test/modules/tls/env.py deleted file mode 100644 index efc4f0b247..0000000000 --- a/test/modules/tls/env.py +++ /dev/null @@ -1,199 +0,0 @@ -import inspect -import logging -import os -import re -import subprocess - -from datetime import timedelta, datetime -from typing import List, Optional, Dict, Tuple, Union - -from pyhttpd.certs import CertificateSpec -from pyhttpd.env import HttpdTestEnv, HttpdTestSetup -from pyhttpd.result import ExecResult - -log = logging.getLogger(__name__) - - -class TlsTestSetup(HttpdTestSetup): - - def __init__(self, env: 'HttpdTestEnv'): - super().__init__(env=env) - self.add_source_dir(os.path.dirname(inspect.getfile(TlsTestSetup))) - self.add_modules(["tls", "http2", "cgid", "watchdog", "proxy_http2"]) - - -class TlsCipher: - - def __init__(self, id: int, name: str, flavour: str, - min_version: float, max_version: float = None, - openssl: str = None): - self.id = id - self.name = name - self.flavour = flavour - self.min_version = min_version - self.max_version = max_version if max_version is not None else self.min_version - if openssl is None: - if name.startswith('TLS13_'): - openssl = re.sub(r'^TLS13_', 'TLS_', name) - else: - openssl = re.sub(r'^TLS_', '', name) - openssl = re.sub(r'_WITH_([^_]+)_', r'_\1_', openssl) - openssl = re.sub(r'_AES_(\d+)', r'_AES\1', openssl) - openssl = re.sub(r'(_POLY1305)_\S+$', r'\1', openssl) - openssl = re.sub(r'_', '-', openssl) - self.openssl_name = openssl - self.id_name = "TLS_CIPHER_0x{0:04x}".format(self.id) - - def __repr__(self): - return self.name - - def __str__(self): - return self.name - - -class TlsTestEnv(HttpdTestEnv): - - CURL_SUPPORTS_TLS_1_3 = None - - @classmethod - @property - def is_unsupported(cls): - mpm_module = f"mpm_{os.environ['MPM']}" if 'MPM' in os.environ else 'mpm_event' - return mpm_module == 'mpm_prefork' - - @classmethod - def curl_supports_tls_1_3(cls) -> bool: - if cls.CURL_SUPPORTS_TLS_1_3 is None: - # Unfortunately, there is no reliable, platform-independant - # way to verify that TLSv1.3 is properly supported by curl. - # - # p = subprocess.run(['curl', '--tlsv1.3', 'https://shouldneverexistreally'], - # stderr=subprocess.PIPE, stdout=subprocess.PIPE) - # return code 6 means the site could not be resolved, but the - # tls parameter was recognized - cls.CURL_SUPPORTS_TLS_1_3 = False - return cls.CURL_SUPPORTS_TLS_1_3 - - - # current rustls supported ciphers in their order of preference - # used to test cipher selection, see test_06_ciphers.py - RUSTLS_CIPHERS = [ - TlsCipher(0x1303, "TLS13_CHACHA20_POLY1305_SHA256", "CHACHA", 1.3), - TlsCipher(0x1302, "TLS13_AES_256_GCM_SHA384", "AES", 1.3), - TlsCipher(0x1301, "TLS13_AES_128_GCM_SHA256", "AES", 1.3), - TlsCipher(0xcca9, "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", "ECDSA", 1.2), - TlsCipher(0xcca8, "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", "RSA", 1.2), - TlsCipher(0xc02c, "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "ECDSA", 1.2), - TlsCipher(0xc02b, "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", "ECDSA", 1.2), - TlsCipher(0xc030, "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", "RSA", 1.2), - TlsCipher(0xc02f, "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "RSA", 1.2), - ] - - def __init__(self, pytestconfig=None): - super().__init__(pytestconfig=pytestconfig) - self._domain_a = "a.mod-tls.test" - self._domain_b = "b.mod-tls.test" - self.add_httpd_conf([ - f'<Directory "{self.server_dir}/htdocs/{self.domain_a}">', - ' AllowOverride None', - ' Require all granted', - ' AddHandler cgi-script .py', - ' Options +ExecCGI', - '</Directory>', - f'<Directory "{self.server_dir}/htdocs/{self.domain_b}">', - ' AllowOverride None', - ' Require all granted', - ' AddHandler cgi-script .py', - ' Options +ExecCGI', - '</Directory>', - f'<VirtualHost *:{self.http_port}>', - ' ServerName localhost', - ' DocumentRoot "htdocs"', - '</VirtualHost>', - f'<VirtualHost *:{self.http_port}>', - f' ServerName {self.domain_a}', - ' DocumentRoot "htdocs/a.mod-tls.test"', - '</VirtualHost>', - f'<VirtualHost *:{self.http_port}>', - f' ServerName {self.domain_b}', - ' DocumentRoot "htdocs/b.mod-tls.test"', - '</VirtualHost>', - ]) - self.add_cert_specs([ - CertificateSpec(domains=[self.domain_a]), - CertificateSpec(domains=[self.domain_b], key_type='secp256r1', single_file=True), - CertificateSpec(domains=[self.domain_b], key_type='rsa4096'), - CertificateSpec(name="clientsX", sub_specs=[ - CertificateSpec(name="user1", client=True, single_file=True), - CertificateSpec(name="user2", client=True, single_file=True), - CertificateSpec(name="user_expired", client=True, - single_file=True, valid_from=timedelta(days=-91), - valid_to=timedelta(days=-1)), - ]), - CertificateSpec(name="clientsY", sub_specs=[ - CertificateSpec(name="user1", client=True, single_file=True), - ]), - CertificateSpec(name="user1", client=True, single_file=True), - ]) - if not HttpdTestEnv.has_shared_module("tls"): - self.add_httpd_log_modules(['ssl']) - else: - self.add_httpd_log_modules(['tls']) - - - def setup_httpd(self, setup: TlsTestSetup = None): - if setup is None: - setup = TlsTestSetup(env=self) - super().setup_httpd(setup=setup) - - @property - def domain_a(self) -> str: - return self._domain_a - - @property - def domain_b(self) -> str: - return self._domain_b - - def tls_get(self, domain, paths: Union[str, List[str]], options: List[str] = None, no_stdout_list = False) -> ExecResult: - if isinstance(paths, str): - paths = [paths] - urls = [f"https://{domain}:{self.https_port}{path}" for path in paths] - return self.curl_raw(urls=urls, options=options, no_stdout_list=no_stdout_list) - - def tls_get_json(self, domain: str, path: str, options=None): - r = self.tls_get(domain=domain, paths=path, options=options) - return r.json - - def run_diff(self, fleft: str, fright: str) -> ExecResult: - return self.run(['diff', '-u', fleft, fright]) - - def openssl(self, args: List[str]) -> ExecResult: - return self.run(['openssl'] + args) - - def openssl_client(self, domain, extra_args: List[str] = None) -> ExecResult: - args = ["s_client", "-CAfile", self.ca.cert_file, "-servername", domain, - "-connect", "localhost:{port}".format( - port=self.https_port - )] - if extra_args: - args.extend(extra_args) - args.extend([]) - return self.openssl(args) - - OPENSSL_SUPPORTED_PROTOCOLS = None - - @staticmethod - def openssl_supports_tls_1_3() -> bool: - if TlsTestEnv.OPENSSL_SUPPORTED_PROTOCOLS is None: - env = TlsTestEnv() - r = env.openssl(args=["ciphers", "-v"]) - protos = set() - ciphers = set() - for line in r.stdout.splitlines(): - m = re.match(r'^(\S+)\s+(\S+)\s+(.*)$', line) - if m: - ciphers.add(m.group(1)) - protos.add(m.group(2)) - TlsTestEnv.OPENSSL_SUPPORTED_PROTOCOLS = protos - TlsTestEnv.OPENSSL_SUPPORTED_CIPHERS = ciphers - return "TLSv1.3" in TlsTestEnv.OPENSSL_SUPPORTED_PROTOCOLS diff --git a/test/modules/tls/htdocs/a.mod-tls.test/index.json b/test/modules/tls/htdocs/a.mod-tls.test/index.json deleted file mode 100644 index ffc32cb275..0000000000 --- a/test/modules/tls/htdocs/a.mod-tls.test/index.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "domain": "a.mod-tls.test" -}
\ No newline at end of file diff --git a/test/modules/tls/htdocs/a.mod-tls.test/vars.py b/test/modules/tls/htdocs/a.mod-tls.test/vars.py deleted file mode 100755 index bd520e27bb..0000000000 --- a/test/modules/tls/htdocs/a.mod-tls.test/vars.py +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/env python3 -import json -import os, sys -from urllib import parse -import multipart # https://github.com/andrew-d/python-multipart (`apt install python3-multipart`) - - -def get_request_params(): - oforms = {} - ofiles = {} - if "REQUEST_URI" in os.environ: - qforms = parse.parse_qs(parse.urlsplit(os.environ["REQUEST_URI"]).query) - for name, values in qforms.items(): - oforms[name] = values[0] - if "HTTP_CONTENT_TYPE" in os.environ: - ctype = os.environ["HTTP_CONTENT_TYPE"] - if ctype == "application/x-www-form-urlencoded": - qforms = parse.parse_qs(parse.urlsplit(sys.stdin.read()).query) - for name, values in qforms.items(): - oforms[name] = values[0] - elif ctype.startswith("multipart/"): - def on_field(field): - oforms[field.field_name] = field.value - def on_file(file): - ofiles[field.field_name] = field.value - multipart.parse_form(headers={"Content-Type": ctype}, input_stream=sys.stdin.buffer, on_field=on_field, on_file=on_file) - return oforms, ofiles - - -forms, files = get_request_params() - -jenc = json.JSONEncoder() - -def get_var(name: str, def_val: str = ""): - if name in os.environ: - return os.environ[name] - return def_val - -def get_json_var(name: str, def_val: str = ""): - var = get_var(name, def_val=def_val) - return jenc.encode(var) - - -name = forms['name'] if 'name' in forms else None - -print("Content-Type: application/json\n") -if name: - print(f"""{{ "{name}" : {get_json_var(name, '')}}}""") -else: - print(f"""{{ "https" : {get_json_var('HTTPS', '')}, - "host" : {get_json_var('SERVER_NAME', '')}, - "protocol" : {get_json_var('SERVER_PROTOCOL', '')}, - "ssl_protocol" : {get_json_var('SSL_PROTOCOL', '')}, - "ssl_cipher" : {get_json_var('SSL_CIPHER', '')} -}}""") - diff --git a/test/modules/tls/htdocs/b.mod-tls.test/dir1/vars.py b/test/modules/tls/htdocs/b.mod-tls.test/dir1/vars.py deleted file mode 100755 index b86a968b55..0000000000 --- a/test/modules/tls/htdocs/b.mod-tls.test/dir1/vars.py +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env python3 -import os - -def get_var(name: str, def_val: str = ""): - if name in os.environ: - return os.environ[name] - return def_val - -print("Content-Type: application/json") -print() -print("""{{ "https" : "{https}", - "host" : "{server_name}", - "protocol" : "{protocol}", - "ssl_protocol" : "{ssl_protocol}", - "ssl_cipher" : "{ssl_cipher}" -}}""".format( - https=get_var('HTTPS', ''), - server_name=get_var('SERVER_NAME', ''), - protocol=get_var('SERVER_PROTOCOL', ''), - ssl_protocol=get_var('SSL_PROTOCOL', ''), - ssl_cipher=get_var('SSL_CIPHER', ''), -)) - diff --git a/test/modules/tls/htdocs/b.mod-tls.test/index.json b/test/modules/tls/htdocs/b.mod-tls.test/index.json deleted file mode 100644 index e5d3ccf1fa..0000000000 --- a/test/modules/tls/htdocs/b.mod-tls.test/index.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "domain": "b.mod-tls.test" -}
\ No newline at end of file diff --git a/test/modules/tls/htdocs/b.mod-tls.test/resp-jitter.py b/test/modules/tls/htdocs/b.mod-tls.test/resp-jitter.py deleted file mode 100755 index f7b134999d..0000000000 --- a/test/modules/tls/htdocs/b.mod-tls.test/resp-jitter.py +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env python3 -import random -import sys -import time -from datetime import timedelta - -random.seed() -to_write = total_len = random.randint(1, 10*1024*1024) - -sys.stdout.write("Content-Type: application/octet-stream\n") -sys.stdout.write(f"Content-Length: {total_len}\n") -sys.stdout.write("\n") -sys.stdout.flush() - -while to_write > 0: - len = random.randint(1, 1024*1024) - len = min(len, to_write) - sys.stdout.buffer.write(random.randbytes(len)) - to_write -= len - delay = timedelta(seconds=random.uniform(0.0, 0.5)) - time.sleep(delay.total_seconds()) -sys.stdout.flush() - diff --git a/test/modules/tls/htdocs/b.mod-tls.test/vars.py b/test/modules/tls/htdocs/b.mod-tls.test/vars.py deleted file mode 100755 index bd520e27bb..0000000000 --- a/test/modules/tls/htdocs/b.mod-tls.test/vars.py +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/env python3 -import json -import os, sys -from urllib import parse -import multipart # https://github.com/andrew-d/python-multipart (`apt install python3-multipart`) - - -def get_request_params(): - oforms = {} - ofiles = {} - if "REQUEST_URI" in os.environ: - qforms = parse.parse_qs(parse.urlsplit(os.environ["REQUEST_URI"]).query) - for name, values in qforms.items(): - oforms[name] = values[0] - if "HTTP_CONTENT_TYPE" in os.environ: - ctype = os.environ["HTTP_CONTENT_TYPE"] - if ctype == "application/x-www-form-urlencoded": - qforms = parse.parse_qs(parse.urlsplit(sys.stdin.read()).query) - for name, values in qforms.items(): - oforms[name] = values[0] - elif ctype.startswith("multipart/"): - def on_field(field): - oforms[field.field_name] = field.value - def on_file(file): - ofiles[field.field_name] = field.value - multipart.parse_form(headers={"Content-Type": ctype}, input_stream=sys.stdin.buffer, on_field=on_field, on_file=on_file) - return oforms, ofiles - - -forms, files = get_request_params() - -jenc = json.JSONEncoder() - -def get_var(name: str, def_val: str = ""): - if name in os.environ: - return os.environ[name] - return def_val - -def get_json_var(name: str, def_val: str = ""): - var = get_var(name, def_val=def_val) - return jenc.encode(var) - - -name = forms['name'] if 'name' in forms else None - -print("Content-Type: application/json\n") -if name: - print(f"""{{ "{name}" : {get_json_var(name, '')}}}""") -else: - print(f"""{{ "https" : {get_json_var('HTTPS', '')}, - "host" : {get_json_var('SERVER_NAME', '')}, - "protocol" : {get_json_var('SERVER_PROTOCOL', '')}, - "ssl_protocol" : {get_json_var('SSL_PROTOCOL', '')}, - "ssl_cipher" : {get_json_var('SSL_CIPHER', '')} -}}""") - diff --git a/test/modules/tls/htdocs/index.html b/test/modules/tls/htdocs/index.html deleted file mode 100644 index 3c07626144..0000000000 --- a/test/modules/tls/htdocs/index.html +++ /dev/null @@ -1,9 +0,0 @@ -<html> - <head> - <title>mod_h2 test site generic</title> - </head> - <body> - <h1>mod_h2 test site generic</h1> - </body> -</html> - diff --git a/test/modules/tls/htdocs/index.json b/test/modules/tls/htdocs/index.json deleted file mode 100644 index 6d456e0af5..0000000000 --- a/test/modules/tls/htdocs/index.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "domain": "localhost" -}
\ No newline at end of file diff --git a/test/modules/tls/test_01_apache.py b/test/modules/tls/test_01_apache.py deleted file mode 100644 index cb6af6d461..0000000000 --- a/test/modules/tls/test_01_apache.py +++ /dev/null @@ -1,14 +0,0 @@ -import pytest - -from .conf import TlsTestConf - - -class TestApache: - - @pytest.fixture(autouse=True, scope='class') - def _class_scope(self, env): - TlsTestConf(env=env).install() - assert env.apache_restart() == 0 - - def test_tls_01_apache_http(self, env): - assert env.is_live(env.http_base_url) diff --git a/test/modules/tls/test_02_conf.py b/test/modules/tls/test_02_conf.py deleted file mode 100644 index 88be80c3a6..0000000000 --- a/test/modules/tls/test_02_conf.py +++ /dev/null @@ -1,144 +0,0 @@ -import os -from datetime import timedelta - -import pytest - -from .conf import TlsTestConf - - -class TestConf: - - @pytest.fixture(autouse=True, scope='class') - def _class_scope(self, env): - TlsTestConf(env=env).install() - assert env.apache_restart() == 0 - - @pytest.fixture(autouse=True, scope='function') - def _function_scope(self, env): - if env.is_live(timeout=timedelta(milliseconds=100)): - assert env.apache_stop() == 0 - - def test_tls_02_conf_cert_args_missing(self, env): - conf = TlsTestConf(env=env) - conf.add("TLSCertificate") - conf.install() - assert env.apache_fail() == 0 - - def test_tls_02_conf_cert_single_arg(self, env): - conf = TlsTestConf(env=env) - conf.add("TLSCertificate cert.pem") - conf.install() - assert env.apache_fail() == 0 - - def test_tls_02_conf_cert_file_missing(self, env): - conf = TlsTestConf(env=env) - conf.add("TLSCertificate cert.pem key.pem") - conf.install() - assert env.apache_fail() == 0 - - def test_tls_02_conf_cert_file_exist(self, env): - conf = TlsTestConf(env=env) - conf.add("TLSCertificate test-02-cert.pem test-02-key.pem") - conf.install() - for name in ["test-02-cert.pem", "test-02-key.pem"]: - with open(os.path.join(env.server_dir, name), "w") as fd: - fd.write("") - assert env.apache_fail() == 0 - - def test_tls_02_conf_cert_listen_missing(self, env): - conf = TlsTestConf(env=env) - conf.add("TLSEngine") - conf.install() - assert env.apache_fail() == 0 - - def test_tls_02_conf_cert_listen_wrong(self, env): - conf = TlsTestConf(env=env) - conf.add("TLSEngine ^^^^^") - conf.install() - assert env.apache_fail() == 0 - - @pytest.mark.parametrize("listen", [ - "443", - "129.168.178.188:443", - "[::]:443", - ]) - def test_tls_02_conf_cert_listen_valid(self, env, listen: str): - conf = TlsTestConf(env=env) - if not env.has_shared_module("tls"): - # Without cert/key openssl will complain - conf.add("SSLEngine on"); - conf.install() - assert env.apache_restart() == 1 - else: - conf.add("TLSEngine {listen}".format(listen=listen)) - conf.install() - assert env.apache_restart() == 0 - - def test_tls_02_conf_cert_listen_cert(self, env): - domain = env.domain_a - conf = TlsTestConf(env=env) - conf.add_tls_vhosts(domains=[domain]) - conf.install() - assert env.apache_restart() == 0 - - def test_tls_02_conf_proto_wrong(self, env): - conf = TlsTestConf(env=env) - conf.add("TLSProtocol wrong") - conf.install() - assert env.apache_fail() == 0 - - @pytest.mark.parametrize("proto", [ - "default", - "TLSv1.2+", - "TLSv1.3+", - "TLSv0x0303+", - ]) - def test_tls_02_conf_proto_valid(self, env, proto): - conf = TlsTestConf(env=env) - conf.add("TLSProtocol {proto}".format(proto=proto)) - conf.install() - assert env.apache_restart() == 0 - - def test_tls_02_conf_honor_wrong(self, env): - conf = TlsTestConf(env=env) - conf.add("TLSHonorClientOrder wrong") - conf.install() - assert env.apache_fail() == 0 - - @pytest.mark.parametrize("honor", [ - "on", - "OfF", - ]) - def test_tls_02_conf_honor_valid(self, env, honor: str): - conf = TlsTestConf(env=env) - conf.add("TLSHonorClientOrder {honor}".format(honor=honor)) - conf.install() - assert env.apache_restart() == 0 - - @pytest.mark.parametrize("cipher", [ - "default", - "TLS13_AES_128_GCM_SHA256:TLS13_AES_256_GCM_SHA384:TLS13_CHACHA20_POLY1305_SHA256", - "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:" - "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:" - "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", - """TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 \\ - TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384\\ - TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256""" - ]) - def test_tls_02_conf_cipher_valid(self, env, cipher): - conf = TlsTestConf(env=env) - conf.add("TLSCiphersPrefer {cipher}".format(cipher=cipher)) - conf.install() - assert env.apache_restart() == 0 - - @pytest.mark.parametrize("cipher", [ - "wrong", - "YOLO", - "TLS_NULL_WITH_NULL_NULLX", # not supported - "TLS_DHE_RSA_WITH_AES128_GCM_SHA256", # not supported - ]) - def test_tls_02_conf_cipher_wrong(self, env, cipher): - conf = TlsTestConf(env=env) - conf.add("TLSCiphersPrefer {cipher}".format(cipher=cipher)) - conf.install() - assert env.apache_fail() == 0 diff --git a/test/modules/tls/test_03_sni.py b/test/modules/tls/test_03_sni.py deleted file mode 100644 index cbd142afbc..0000000000 --- a/test/modules/tls/test_03_sni.py +++ /dev/null @@ -1,89 +0,0 @@ -from datetime import timedelta - -import pytest - -from .conf import TlsTestConf -from .env import TlsTestEnv - - -class TestSni: - - @pytest.fixture(autouse=True, scope='class') - def _class_scope(self, env): - conf = TlsTestConf(env=env) - conf.add_tls_vhosts(domains=[env.domain_a, env.domain_b]) - conf.install() - assert env.apache_restart() == 0 - - @pytest.fixture(autouse=True, scope='function') - def _function_scope(self, env): - pass - - def test_tls_03_sni_get_a(self, env): - # do we see the correct json for the domain_a? - data = env.tls_get_json(env.domain_a, "/index.json") - assert data == {'domain': env.domain_a} - - def test_tls_03_sni_get_b(self, env): - # do we see the correct json for the domain_a? - data = env.tls_get_json(env.domain_b, "/index.json") - assert data == {'domain': env.domain_b} - - def test_tls_03_sni_unknown(self, env): - # connection will be denied as cert does not cover this domain - domain_unknown = "unknown.test" - r = env.tls_get(domain_unknown, "/index.json") - assert r.exit_code != 0 - # - env.httpd_error_log.ignore_recent( - lognos = [ - "AH10353" # cannot decrypt peer's message - ] - ) - - def test_tls_03_sni_request_other_same_config(self, env): - # do we see the first vhost response for another domain with different certs? - r = env.tls_get(env.domain_a, "/index.json", options=[ - "-vvvv", "--header", "Host: {0}".format(env.domain_b) - ]) - # request is marked as misdirected - assert r.exit_code == 0 - assert r.json is None - assert r.response['status'] == 421 - # - env.httpd_error_log.ignore_recent( - lognos = [ - "AH10345" # Connection host selected via SNI and request have incompatible TLS configurations - ] - ) - - def test_tls_03_sni_request_other_other_honor(self, env): - # do we see the first vhost response for an unknown domain? - conf = TlsTestConf(env=env, extras={ - env.domain_a: "TLSProtocol TLSv1.2+", - env.domain_b: "TLSProtocol TLSv1.3+" - }) - conf.add_tls_vhosts(domains=[env.domain_a, env.domain_b]) - conf.install() - assert env.apache_restart() == 0 - r = env.tls_get(env.domain_a, "/index.json", options=[ - "-vvvv", "--tls-max", "1.2", "--header", "Host: {0}".format(env.domain_b) - ]) - # request denied - assert r.exit_code == 0 - assert r.json is None - # - env.httpd_error_log.ignore_recent( - lognos = [ - "AH10345" # Connection host selected via SNI and request have incompatible TLS configurations - ] - ) - - @pytest.mark.skip('openssl behaviour changed on ventura, unreliable') - def test_tls_03_sni_bad_hostname(self, env): - # curl checks hostnames we give it, but the openssl client - # does not. Good for us, since we need to test it. - r = env.openssl(["s_client", "-connect", - "localhost:{0}".format(env.https_port), - "-servername", b'x\x2f.y'.decode()]) - assert r.exit_code == 1, r.stderr diff --git a/test/modules/tls/test_04_get.py b/test/modules/tls/test_04_get.py deleted file mode 100644 index 6944381307..0000000000 --- a/test/modules/tls/test_04_get.py +++ /dev/null @@ -1,67 +0,0 @@ -import os -import time -from datetime import timedelta - -import pytest - -from .env import TlsTestEnv -from .conf import TlsTestConf - - -def mk_text_file(fpath: str, lines: int): - t110 = 11 * "0123456789" - with open(fpath, "w") as fd: - for i in range(lines): - fd.write("{0:015d}: ".format(i)) # total 128 bytes per line - fd.write(t110) - fd.write("\n") - - -class TestGet: - - @pytest.fixture(autouse=True, scope='class') - def _class_scope(self, env): - conf = TlsTestConf(env=env) - conf.add_tls_vhosts(domains=[env.domain_a, env.domain_b]) - conf.install() - docs_a = os.path.join(env.server_docs_dir, env.domain_a) - mk_text_file(os.path.join(docs_a, "1k.txt"), 8) - mk_text_file(os.path.join(docs_a, "10k.txt"), 80) - mk_text_file(os.path.join(docs_a, "100k.txt"), 800) - mk_text_file(os.path.join(docs_a, "1m.txt"), 8000) - mk_text_file(os.path.join(docs_a, "10m.txt"), 80000) - assert env.apache_restart() == 0 - - @pytest.mark.parametrize("fname, flen", [ - ("1k.txt", 1024), - ("10k.txt", 10*1024), - ("100k.txt", 100 * 1024), - ("1m.txt", 1000 * 1024), - ("10m.txt", 10000 * 1024), - ]) - def test_tls_04_get(self, env, fname, flen): - # do we see the correct json for the domain_a? - docs_a = os.path.join(env.server_docs_dir, env.domain_a) - r = env.tls_get(env.domain_a, "/{0}".format(fname)) - assert r.exit_code == 0 - assert len(r.stdout) == flen - pref = os.path.join(docs_a, fname) - pout = os.path.join(docs_a, "{0}.out".format(fname)) - with open(pout, 'w') as fd: - fd.write(r.stdout) - dr = env.run_diff(pref, pout) - assert dr.exit_code == 0, "differences found:\n{0}".format(dr.stdout) - - @pytest.mark.parametrize("fname, flen", [ - ("1k.txt", 1024), - ]) - def test_tls_04_double_get(self, env, fname, flen): - # we'd like to check that we can do >1 requests on the same connection - # however curl hides that from us, unless we analyze its verbose output - docs_a = os.path.join(env.server_docs_dir, env.domain_a) - r = env.tls_get(env.domain_a, no_stdout_list=True, paths=[ - "/{0}".format(fname), - "/{0}".format(fname) - ]) - assert r.exit_code == 0 - assert len(r.stdout) == 2*flen diff --git a/test/modules/tls/test_05_proto.py b/test/modules/tls/test_05_proto.py deleted file mode 100644 index d874a905ef..0000000000 --- a/test/modules/tls/test_05_proto.py +++ /dev/null @@ -1,64 +0,0 @@ -import time -from datetime import timedelta -import socket -from threading import Thread - -import pytest - -from .conf import TlsTestConf -from .env import TlsTestEnv - - -class TestProto: - - @pytest.fixture(autouse=True, scope='class') - def _class_scope(self, env): - conf = TlsTestConf(env=env, extras={ - env.domain_a: "TLSProtocol TLSv1.3+", - env.domain_b: [ - "# the commonly used name", - "TLSProtocol TLSv1.2+", - "# the numeric one (yes, this is 1.2)", - "TLSProtocol TLSv0x0303+", - ], - }) - conf.add_tls_vhosts(domains=[env.domain_a, env.domain_b]) - conf.install() - assert env.apache_restart() == 0 - - @pytest.fixture(autouse=True, scope='function') - def _function_scope(self, env): - pass - - def test_tls_05_proto_1_2(self, env): - r = env.tls_get(env.domain_b, "/index.json", options=["--tlsv1.2"]) - assert r.exit_code == 0, r.stderr - - @pytest.mark.skip('curl does not have TLSv1.3 on all platforms') - def test_tls_05_proto_1_3(self, env): - r = env.tls_get(env.domain_a, "/index.json", options=["--tlsv1.3", '-v']) - if True: # testing TlsTestEnv.curl_supports_tls_1_3() is unreliable (curl should support TLS1.3 nowadays..) - assert r.exit_code == 0, f'{r}' - else: - assert r.exit_code == 4, f'{r}' - - def test_tls_05_proto_close(self, env): - s = socket.create_connection(('localhost', env.https_port)) - time.sleep(0.1) - s.close() - - def test_tls_05_proto_ssl_close(self, env): - conf = TlsTestConf(env=env, extras={ - 'base': "LogLevel ssl:debug", - env.domain_a: "SSLProtocol TLSv1.3", - env.domain_b: "SSLProtocol TLSv1.2", - }) - for d in [env.domain_a, env.domain_b]: - conf.add_vhost(domains=[d], port=env.https_port) - conf.install() - assert env.apache_restart() == 0 - s = socket.create_connection(('localhost', env.https_port)) - time.sleep(0.1) - s.close() - - diff --git a/test/modules/tls/test_06_ciphers.py b/test/modules/tls/test_06_ciphers.py deleted file mode 100644 index 4bedd692ce..0000000000 --- a/test/modules/tls/test_06_ciphers.py +++ /dev/null @@ -1,212 +0,0 @@ -import re -from datetime import timedelta - -import pytest - -from .env import TlsTestEnv -from .conf import TlsTestConf - - -class TestCiphers: - - @pytest.fixture(autouse=True, scope='class') - def _class_scope(self, env): - conf = TlsTestConf(env=env, extras={ - 'base': "TLSHonorClientOrder off", - }) - conf.add_tls_vhosts(domains=[env.domain_a, env.domain_b]) - conf.install() - assert env.apache_restart() == 0 - - @pytest.fixture(autouse=True, scope='function') - def _function_scope(self, env): - pass - - def _get_protocol_cipher(self, output: str): - protocol = None - cipher = None - for line in output.splitlines(): - m = re.match(r'^\s+Protocol\s*:\s*(\S+)$', line) - if m: - protocol = m.group(1) - continue - m = re.match(r'^\s+Cipher\s*:\s*(\S+)$', line) - if m: - cipher = m.group(1) - return protocol, cipher - - def test_tls_06_ciphers_ecdsa(self, env): - ecdsa_1_2 = [c for c in env.RUSTLS_CIPHERS - if c.max_version == 1.2 and c.flavour == 'ECDSA'][0] - # client speaks only this cipher, see that it gets it - r = env.openssl_client(env.domain_b, extra_args=[ - "-cipher", ecdsa_1_2.openssl_name, "-tls1_2" - ]) - protocol, cipher = self._get_protocol_cipher(r.stdout) - assert protocol == "TLSv1.2", r.stdout - assert cipher == ecdsa_1_2.openssl_name, r.stdout - - def test_tls_06_ciphers_rsa(self, env): - rsa_1_2 = [c for c in env.RUSTLS_CIPHERS - if c.max_version == 1.2 and c.flavour == 'RSA'][0] - # client speaks only this cipher, see that it gets it - r = env.openssl_client(env.domain_b, extra_args=[ - "-cipher", rsa_1_2.openssl_name, "-tls1_2" - ]) - protocol, cipher = self._get_protocol_cipher(r.stdout) - assert protocol == "TLSv1.2", r.stdout - assert cipher == rsa_1_2.openssl_name, r.stdout - - @pytest.mark.parametrize("cipher", [ - c for c in TlsTestEnv.RUSTLS_CIPHERS if c.max_version == 1.2 and c.flavour == 'ECDSA' - ], ids=[ - c.name for c in TlsTestEnv.RUSTLS_CIPHERS if c.max_version == 1.2 and c.flavour == 'ECDSA' - ]) - def test_tls_06_ciphers_server_prefer_ecdsa(self, env, cipher): - # Select a ECSDA ciphers as preference and suppress all RSA ciphers. - # The last is not strictly necessary since rustls prefers ECSDA anyway - suppress_names = [c.name for c in env.RUSTLS_CIPHERS - if c.max_version == 1.2 and c.flavour == 'RSA'] - conf = TlsTestConf(env=env, extras={ - env.domain_b: [ - "TLSHonorClientOrder off", - f"TLSCiphersPrefer {cipher.name}", - f"TLSCiphersSuppress {':'.join(suppress_names)}", - ] - }) - conf.add_tls_vhosts(domains=[env.domain_a, env.domain_b]) - conf.install() - assert env.apache_restart() == 0 - r = env.openssl_client(env.domain_b, extra_args=["-tls1_2"]) - client_proto, client_cipher = self._get_protocol_cipher(r.stdout) - assert client_proto == "TLSv1.2", r.stdout - assert client_cipher == cipher.openssl_name, r.stdout - - @pytest.mark.skip(reason="Wrong certified key selected by rustls") - # see <https://github.com/rustls/rustls-ffi/issues/236> - @pytest.mark.parametrize("cipher", [ - c for c in TlsTestEnv.RUSTLS_CIPHERS if c.max_version == 1.2 and c.flavour == 'RSA' - ], ids=[ - c.name for c in TlsTestEnv.RUSTLS_CIPHERS if c.max_version == 1.2 and c.flavour == 'RSA' - ]) - def test_tls_06_ciphers_server_prefer_rsa(self, env, cipher): - # Select a RSA ciphers as preference and suppress all ECDSA ciphers. - # The last is necessary since rustls prefers ECSDA and openssl leaks that it can. - suppress_names = [c.name for c in env.RUSTLS_CIPHERS - if c.max_version == 1.2 and c.flavour == 'ECDSA'] - conf = TlsTestConf(env=env, extras={ - env.domain_b: [ - "TLSHonorClientOrder off", - f"TLSCiphersPrefer {cipher.name}", - f"TLSCiphersSuppress {':'.join(suppress_names)}", - ] - }) - conf.add_tls_vhosts(domains=[env.domain_a, env.domain_b]) - conf.install() - assert env.apache_restart() == 0 - r = env.openssl_client(env.domain_b, extra_args=["-tls1_2"]) - client_proto, client_cipher = self._get_protocol_cipher(r.stdout) - assert client_proto == "TLSv1.2", r.stdout - assert client_cipher == cipher.openssl_name, r.stdout - - @pytest.mark.skip(reason="Wrong certified key selected by rustls") - # see <https://github.com/rustls/rustls-ffi/issues/236> - @pytest.mark.parametrize("cipher", [ - c for c in TlsTestEnv.RUSTLS_CIPHERS if c.max_version == 1.2 and c.flavour == 'RSA' - ], ids=[ - c.openssl_name for c in TlsTestEnv.RUSTLS_CIPHERS if c.max_version == 1.2 and c.flavour == 'RSA' - ]) - def test_tls_06_ciphers_server_prefer_rsa_alias(self, env, cipher): - # same as above, but using openssl names for ciphers - suppress_names = [c.openssl_name for c in env.RUSTLS_CIPHERS - if c.max_version == 1.2 and c.flavour == 'ECDSA'] - conf = TlsTestConf(env=env, extras={ - env.domain_b: [ - "TLSHonorClientOrder off", - f"TLSCiphersPrefer {cipher.openssl_name}", - f"TLSCiphersSuppress {':'.join(suppress_names)}", - ] - }) - conf.add_tls_vhosts(domains=[env.domain_a, env.domain_b]) - conf.install() - assert env.apache_restart() == 0 - r = env.openssl_client(env.domain_b, extra_args=["-tls1_2"]) - client_proto, client_cipher = self._get_protocol_cipher(r.stdout) - assert client_proto == "TLSv1.2", r.stdout - assert client_cipher == cipher.openssl_name, r.stdout - - @pytest.mark.skip(reason="Wrong certified key selected by rustls") - # see <https://github.com/rustls/rustls-ffi/issues/236> - @pytest.mark.parametrize("cipher", [ - c for c in TlsTestEnv.RUSTLS_CIPHERS if c.max_version == 1.2 and c.flavour == 'RSA' - ], ids=[ - c.id_name for c in TlsTestEnv.RUSTLS_CIPHERS if c.max_version == 1.2 and c.flavour == 'RSA' - ]) - def test_tls_06_ciphers_server_prefer_rsa_id(self, env, cipher): - # same as above, but using openssl names for ciphers - suppress_names = [c.id_name for c in env.RUSTLS_CIPHERS - if c.max_version == 1.2 and c.flavour == 'ECDSA'] - conf = TlsTestConf(env=env, extras={ - env.domain_b: [ - "TLSHonorClientOrder off", - f"TLSCiphersPrefer {cipher.id_name}", - f"TLSCiphersSuppress {':'.join(suppress_names)}", - ] - }) - conf.add_tls_vhosts(domains=[env.domain_a, env.domain_b]) - conf.install() - assert env.apache_restart() == 0 - r = env.openssl_client(env.domain_b, extra_args=["-tls1_2"]) - client_proto, client_cipher = self._get_protocol_cipher(r.stdout) - assert client_proto == "TLSv1.2", r.stdout - assert client_cipher == cipher.openssl_name, r.stdout - - def test_tls_06_ciphers_pref_unknown(self, env): - conf = TlsTestConf(env=env, extras={ - env.domain_b: "TLSCiphersPrefer TLS_MY_SUPER_CIPHER:SSL_WHAT_NOT" - }) - conf.add_tls_vhosts(domains=[env.domain_a, env.domain_b]) - conf.install() - assert env.apache_restart() != 0 - # get a working config again, so that subsequent test cases do not stumble - conf = TlsTestConf(env=env) - conf.add_tls_vhosts(domains=[env.domain_a, env.domain_b]) - conf.install() - env.apache_restart() - - def test_tls_06_ciphers_pref_unsupported(self, env): - # a warning on preferring a known, but not supported cipher - conf = TlsTestConf(env=env, extras={ - env.domain_b: "TLSCiphersPrefer TLS_NULL_WITH_NULL_NULL" - }) - conf.add_tls_vhosts(domains=[env.domain_a, env.domain_b]) - conf.install() - if not conf.env.has_shared_module("tls"): - assert env.apache_restart() != 0 - else: - assert env.apache_restart() == 0 - # - env.httpd_error_log.ignore_recent( - lognos = [ - "AH10319" # Server has TLSCiphersPrefer configured that are not supported by rustls - ] - ) - - def test_tls_06_ciphers_supp_unknown(self, env): - conf = TlsTestConf(env=env, extras={ - env.domain_b: "TLSCiphersSuppress TLS_MY_SUPER_CIPHER:SSL_WHAT_NOT" - }) - conf.add_tls_vhosts(domains=[env.domain_a, env.domain_b]) - conf.install() - assert env.apache_restart() != 0 - - def test_tls_06_ciphers_supp_unsupported(self, env): - # no warnings on suppressing known, but not supported ciphers - conf = TlsTestConf(env=env, extras={ - env.domain_b: "TLSCiphersSuppress TLS_NULL_WITH_NULL_NULL" - }) - conf.add_tls_vhosts(domains=[env.domain_a, env.domain_b]) - conf.install() - if not conf.env.has_shared_module("tls"): - return - assert env.apache_restart() == 0 diff --git a/test/modules/tls/test_07_alpn.py b/test/modules/tls/test_07_alpn.py deleted file mode 100644 index aa7e1b844c..0000000000 --- a/test/modules/tls/test_07_alpn.py +++ /dev/null @@ -1,45 +0,0 @@ -import re -from datetime import timedelta - -import pytest - -from .conf import TlsTestConf -from .env import TlsTestEnv - - -@pytest.mark.skipif(condition=TlsTestEnv.is_unsupported, reason="h2 not supported here") -class TestAlpn: - - @pytest.fixture(autouse=True, scope='class') - def _class_scope(self, env): - conf = TlsTestConf(env=env, extras={ - env.domain_b: "Protocols h2 http/1.1" - }) - conf.add_tls_vhosts(domains=[env.domain_a, env.domain_b]) - conf.install() - assert env.apache_restart() == 0 - - @pytest.fixture(autouse=True, scope='function') - def _function_scope(self, env): - pass - - def _get_protocol(self, output: str): - for line in output.splitlines(): - m = re.match(r'^\*\s+ALPN[:,] server accepted (to use\s+)?(.*)$', line) - if m: - return m.group(2) - return None - - def test_tls_07_alpn_get_a(self, env): - # do we see the correct json for the domain_a? - r = env.tls_get(env.domain_a, "/index.json", options=["-vvvvvv", "--http1.1"]) - assert r.exit_code == 0, r.stderr - protocol = self._get_protocol(r.stderr) - assert protocol == "http/1.1", r.stderr - - def test_tls_07_alpn_get_b(self, env): - # do we see the correct json for the domain_a? - r = env.tls_get(env.domain_b, "/index.json", options=["-vvvvvv"]) - assert r.exit_code == 0, r.stderr - protocol = self._get_protocol(r.stderr) - assert protocol == "h2", r.stderr diff --git a/test/modules/tls/test_08_vars.py b/test/modules/tls/test_08_vars.py deleted file mode 100644 index 0e3ee74d2d..0000000000 --- a/test/modules/tls/test_08_vars.py +++ /dev/null @@ -1,75 +0,0 @@ -import re - -import pytest - -from .conf import TlsTestConf -from .env import TlsTestEnv - - -class TestVars: - - @pytest.fixture(autouse=True, scope='class') - def _class_scope(self, env): - conf = TlsTestConf(env=env, extras={ - 'base': [ - "TLSHonorClientOrder off", - "TLSOptions +StdEnvVars", - ] - }) - conf.add_tls_vhosts(domains=[env.domain_a, env.domain_b]) - conf.install() - assert env.apache_restart() == 0 - - def test_tls_08_vars_root(self, env): - # in domain_b root, the StdEnvVars is switch on - exp_proto = "TLSv1.2" - if env.has_shared_module("tls"): - exp_cipher = "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384" - else: - exp_cipher = "ECDHE-ECDSA-AES256-GCM-SHA384" - options = [ '--tls-max', '1.2'] - r = env.tls_get(env.domain_b, "/vars.py", options=options) - assert r.exit_code == 0, r.stderr - assert r.json == { - 'https': 'on', - 'host': 'b.mod-tls.test', - 'protocol': 'HTTP/1.1', - 'ssl_protocol': exp_proto, - # this will vary by client potentially - 'ssl_cipher': exp_cipher, - } - - @pytest.mark.parametrize("name, value", [ - ("SERVER_NAME", "b.mod-tls.test"), - ("SSL_SESSION_RESUMED", "Initial"), - ("SSL_SECURE_RENEG", "false"), - ("SSL_COMPRESS_METHOD", "NULL"), - ("SSL_CIPHER_EXPORT", "false"), - ("SSL_CLIENT_VERIFY", "NONE"), - ]) - def test_tls_08_vars_const(self, env, name: str, value: str): - r = env.tls_get(env.domain_b, f"/vars.py?name={name}") - assert r.exit_code == 0, r.stderr - if env.has_shared_module("tls"): - assert r.json == {name: value}, r.stdout - else: - if name == "SSL_SECURE_RENEG": - value = "true" - assert r.json == {name: value}, r.stdout - - @pytest.mark.parametrize("name, pattern", [ - ("SSL_VERSION_INTERFACE", r'mod_tls/\d+\.\d+\.\d+'), - ("SSL_VERSION_LIBRARY", r'rustls-ffi/\d+\.\d+\.\d+/rustls/\d+\.\d+(\.\d+)?'), - ]) - def test_tls_08_vars_match(self, env, name: str, pattern: str): - r = env.tls_get(env.domain_b, f"/vars.py?name={name}") - assert r.exit_code == 0, r.stderr - assert name in r.json - if env.has_shared_module("tls"): - assert re.match(pattern, r.json[name]), r.json - else: - if name == "SSL_VERSION_INTERFACE": - pattern = r'mod_ssl/\d+\.\d+\.\d+' - else: - pattern = r'OpenSSL/\d+\.\d+\.\d+' - assert re.match(pattern, r.json[name]), r.json diff --git a/test/modules/tls/test_09_timeout.py b/test/modules/tls/test_09_timeout.py deleted file mode 100644 index 70cc89417a..0000000000 --- a/test/modules/tls/test_09_timeout.py +++ /dev/null @@ -1,43 +0,0 @@ -import socket -from datetime import timedelta - -import pytest - -from .conf import TlsTestConf - - -class TestTimeout: - - @pytest.fixture(autouse=True, scope='class') - def _class_scope(self, env): - conf = TlsTestConf(env=env, extras={ - 'base': "RequestReadTimeout handshake=1", - }) - conf.add_tls_vhosts(domains=[env.domain_a, env.domain_b]) - conf.install() - assert env.apache_restart() == 0 - - @pytest.fixture(autouse=True, scope='function') - def _function_scope(self, env): - pass - - def test_tls_09_timeout_handshake(self, env): - # in domain_b root, the StdEnvVars is switch on - s = socket.create_connection(('localhost', env.https_port)) - s.send(b'1234') - s.settimeout(0.0) - try: - s.recv(1024) - assert False, "able to recv() on a TLS connection before we sent a hello" - except BlockingIOError: - pass - s.settimeout(3.0) - try: - while True: - buf = s.recv(1024) - if not buf: - break - print("recv() -> {0}".format(buf)) - except (socket.timeout, BlockingIOError): - assert False, "socket not closed as handshake timeout should trigger" - s.close() diff --git a/test/modules/tls/test_10_session_id.py b/test/modules/tls/test_10_session_id.py deleted file mode 100644 index 848bc1a556..0000000000 --- a/test/modules/tls/test_10_session_id.py +++ /dev/null @@ -1,50 +0,0 @@ -import re -from typing import List - -import pytest - -from pyhttpd.result import ExecResult -from .env import TlsTestEnv -from .conf import TlsTestConf - - -class TestSessionID: - - @pytest.fixture(autouse=True, scope='class') - def _class_scope(self, env): - conf = TlsTestConf(env=env) - conf.add_tls_vhosts(domains=[env.domain_a, env.domain_b]) - conf.install() - assert env.apache_restart() == 0 - - def find_openssl_session_ids(self, r: ExecResult) -> List[str]: - ids = [] - for line in r.stdout.splitlines(): - m = re.match(r'^\s*Session-ID: (\S+)$', line) - if m: - ids.append(m.group(1)) - return ids - - def test_tls_10_session_id_12(self, env): - r = env.openssl_client(env.domain_b, extra_args=[ - "-reconnect", "-tls1_2" - ]) - session_ids = self.find_openssl_session_ids(r) - assert 1 < len(session_ids), "expected several session-ids: {0}, stderr={1}".format( - session_ids, r.stderr - ) - assert 1 == len(set(session_ids)), "sesion-ids should all be the same: {0}".format(session_ids) - - @pytest.mark.skipif(True or not TlsTestEnv.openssl_supports_tls_1_3(), - reason="openssl TLSv1.3 session storage test incomplete") - def test_tls_10_session_id_13(self, env): - r = env.openssl_client(env.domain_b, extra_args=[ - "-reconnect", "-tls1_3" - ]) - # openssl -reconnect closes connection immediately after the handhshake, so - # the Session data in TLSv1.3 is not seen and not found in its output. - # FIXME: how to check session data with TLSv1.3? - session_ids = self.find_openssl_session_ids(r) - assert 0 == len(session_ids), "expected no session-ids: {0}, stderr={1}".format( - session_ids, r.stdout - ) diff --git a/test/modules/tls/test_11_md.py b/test/modules/tls/test_11_md.py deleted file mode 100644 index 9d733db9d1..0000000000 --- a/test/modules/tls/test_11_md.py +++ /dev/null @@ -1,37 +0,0 @@ -import time -from datetime import timedelta - -import pytest - -from .conf import TlsTestConf - - -class TestMD: - - @pytest.fixture(autouse=True, scope='class') - def _class_scope(self, env): - conf = TlsTestConf(env=env, extras={ - 'base': "LogLevel md:trace4" - }) - conf.add_md_vhosts(domains=[env.domain_a, env.domain_b]) - conf.install() - assert env.apache_restart() == 0 - - def test_tls_11_get_a(self, env): - # do we see the correct json for the domain_a? - data = env.tls_get_json(env.domain_a, "/index.json") - assert data == {'domain': env.domain_a} - - def test_tls_11_get_b(self, env): - # do we see the correct json for the domain_a? - data = env.tls_get_json(env.domain_b, "/index.json") - assert data == {'domain': env.domain_b} - - def test_tls_11_get_base(self, env): - # give the base server domain_a and lookup its index.json - conf = TlsTestConf(env=env) - conf.add_md_base(domain=env.domain_a) - conf.install() - assert env.apache_restart() == 0 - data = env.tls_get_json(env.domain_a, "/index.json") - assert data == {'domain': 'localhost'} diff --git a/test/modules/tls/test_12_cauth.py b/test/modules/tls/test_12_cauth.py deleted file mode 100644 index 14116091c6..0000000000 --- a/test/modules/tls/test_12_cauth.py +++ /dev/null @@ -1,235 +0,0 @@ -import os -from datetime import timedelta -from typing import Optional - -import pytest - -from pyhttpd.certs import Credentials -from .conf import TlsTestConf - - -@pytest.fixture -def clients_x(env): - return env.ca.get_first("clientsX") - - -@pytest.fixture -def clients_y(env): - return env.ca.get_first("clientsY") - - -@pytest.fixture -def cax_file(clients_x): - return os.path.join(os.path.dirname(clients_x.cert_file), "clientX-ca.pem") - - -@pytest.mark.skip(reason="client certs disabled") -class TestTLS: - - @pytest.fixture(autouse=True, scope='class') - def _class_scope(self, env, clients_x, cax_file): - with open(cax_file, 'w') as fd: - fd.write("".join(open(clients_x.cert_file).readlines())) - fd.write("".join(open(env.ca.cert_file).readlines())) - - @pytest.fixture(autouse=True, scope='function') - def _function_scope(self, env): - if env.is_live(timeout=timedelta(milliseconds=100)): - assert env.apache_stop() == 0 - - def get_ssl_var(self, env, domain: str, cert: Optional[Credentials], name: str): - r = env.tls_get(domain, f"/vars.py?name={name}", options=[ - "--cert", cert.cert_file - ] if cert else []) - assert r.exit_code == 0, r.stderr - assert r.json, r.stderr + r.stdout - return r.json[name] if name in r.json else None - - def test_tls_12_set_ca_non_existing(self, env): - conf = TlsTestConf(env=env, extras={ - env.domain_a: "TLSClientCA xxx" - }) - conf.add_md_vhosts(domains=[env.domain_a, env.domain_b]) - conf.install() - assert env.apache_restart() == 1 - - def test_tls_12_set_ca_existing(self, env, cax_file): - conf = TlsTestConf(env=env, extras={ - env.domain_a: f"TLSClientCA {cax_file}" - }) - conf.add_md_vhosts(domains=[env.domain_a, env.domain_b]) - conf.install() - assert env.apache_restart() == 0 - - def test_tls_12_set_auth_no_ca(self, env): - conf = TlsTestConf(env=env, extras={ - env.domain_a: "TLSClientCertificate required" - }) - conf.add_md_vhosts(domains=[env.domain_a, env.domain_b]) - conf.install() - # will fail bc lacking clien CA - assert env.apache_restart() == 1 - - def test_tls_12_auth_option_std(self, env, cax_file, clients_x): - conf = TlsTestConf(env=env, extras={ - env.domain_b: [ - f"TLSClientCertificate required", - f"TLSClientCA {cax_file}", - "# TODO: TLSUserName SSL_CLIENT_S_DN_CN", - "TLSOptions +StdEnvVars", - ] - }) - conf.add_md_vhosts(domains=[env.domain_b]) - conf.install() - assert env.apache_restart() == 0 - # should be denied - r = env.tls_get(domain=env.domain_b, paths="/index.json") - assert r.exit_code != 0, r.stdout - # should work - ccert = clients_x.get_first("user1") - data = env.tls_get_json(env.domain_b, "/index.json", options=[ - "--cert", ccert.cert_file - ]) - assert data == {'domain': env.domain_b} - r = env.tls_get(env.domain_b, "/vars.py?name=SSL_CLIENT_S_DN_CN") - assert r.exit_code != 0, "should have been prevented" - val = self.get_ssl_var(env, env.domain_b, ccert, "SSL_CLIENT_S_DN_CN") - assert val == 'Not Implemented' - # TODO - # val = self.get_ssl_var(env, env.domain_b, ccert, "REMOTE_USER") - # assert val == 'Not Implemented' - # not set on StdEnvVars, needs option ExportCertData - val = self.get_ssl_var(env, env.domain_b, ccert, "SSL_CLIENT_CERT") - assert val == "" - - def test_tls_12_auth_option_cert(self, env, test_ca, cax_file, clients_x): - conf = TlsTestConf(env=env, extras={ - env.domain_b: [ - "TLSClientCertificate required", - f"TLSClientCA {cax_file}", - "TLSOptions Defaults +ExportCertData", - ] - }) - conf.add_md_vhosts(domains=[env.domain_b]) - conf.install() - assert env.apache_restart() == 0 - ccert = clients_x.get_first("user1") - val = self.get_ssl_var(env, env.domain_b, ccert, "SSL_CLIENT_CERT") - assert val == ccert.cert_pem.decode() - # no chain should be present - val = self.get_ssl_var(env, env.domain_b, ccert, "SSL_CLIENT_CHAIN_0") - assert val == '' - val = self.get_ssl_var(env, env.domain_b, ccert, "SSL_SERVER_CERT") - assert val - server_certs = test_ca.get_credentials_for_name(env.domain_b) - assert val in [c.cert_pem.decode() for c in server_certs] - - def test_tls_12_auth_ssl_optional(self, env, cax_file, clients_x): - domain = env.domain_b - conf = TlsTestConf(env=env, extras={ - domain: [ - "SSLVerifyClient optional", - "SSLVerifyDepth 2", - "SSLOptions +StdEnvVars +ExportCertData", - f"SSLCACertificateFile {cax_file}", - "SSLUserName SSL_CLIENT_S_DN", - ] - }) - conf.add_ssl_vhosts(domains=[domain]) - conf.install() - assert env.apache_restart() == 0 - # should work either way - data = env.tls_get_json(domain, "/index.json") - assert data == {'domain': domain} - # no client cert given, we expect the server variable to be empty - val = self.get_ssl_var(env, env.domain_b, None, "SSL_CLIENT_S_DN_CN") - assert val == '' - ccert = clients_x.get_first("user1") - data = env.tls_get_json(domain, "/index.json", options=[ - "--cert", ccert.cert_file - ]) - assert data == {'domain': domain} - val = self.get_ssl_var(env, env.domain_b, ccert, "SSL_CLIENT_S_DN_CN") - assert val == 'user1' - val = self.get_ssl_var(env, env.domain_b, ccert, "SSL_CLIENT_S_DN") - assert val == 'O=abetterinternet-mod_tls,OU=clientsX,CN=user1' - val = self.get_ssl_var(env, env.domain_b, ccert, "REMOTE_USER") - assert val == 'O=abetterinternet-mod_tls,OU=clientsX,CN=user1' - val = self.get_ssl_var(env, env.domain_b, ccert, "SSL_CLIENT_I_DN") - assert val == 'O=abetterinternet-mod_tls,OU=clientsX' - val = self.get_ssl_var(env, env.domain_b, ccert, "SSL_CLIENT_I_DN_CN") - assert val == '' - val = self.get_ssl_var(env, env.domain_b, ccert, "SSL_CLIENT_I_DN_OU") - assert val == 'clientsX' - val = self.get_ssl_var(env, env.domain_b, ccert, "SSL_CLIENT_CERT") - assert val == ccert.cert_pem.decode() - - def test_tls_12_auth_optional(self, env, cax_file, clients_x): - domain = env.domain_b - conf = TlsTestConf(env=env, extras={ - domain: [ - "TLSClientCertificate optional", - f"TLSClientCA {cax_file}", - ] - }) - conf.add_md_vhosts(domains=[domain]) - conf.install() - assert env.apache_restart() == 0 - # should work either way - data = env.tls_get_json(domain, "/index.json") - assert data == {'domain': domain} - # no client cert given, we expect the server variable to be empty - r = env.tls_get(domain, "/vars.py?name=SSL_CLIENT_S_DN_CN") - assert r.exit_code == 0, r.stderr - assert r.json == { - 'SSL_CLIENT_S_DN_CN': '', - }, r.stdout - data = env.tls_get_json(domain, "/index.json", options=[ - "--cert", clients_x.get_first("user1").cert_file - ]) - assert data == {'domain': domain} - r = env.tls_get(domain, "/vars.py?name=SSL_CLIENT_S_DN_CN", options=[ - "--cert", clients_x.get_first("user1").cert_file - ]) - # with client cert, we expect the server variable to show? Do we? - assert r.exit_code == 0, r.stderr - assert r.json == { - 'SSL_CLIENT_S_DN_CN': 'Not Implemented', - }, r.stdout - - def test_tls_12_auth_expired(self, env, cax_file, clients_x): - conf = TlsTestConf(env=env, extras={ - env.domain_b: [ - "TLSClientCertificate required", - f"TLSClientCA {cax_file}", - ] - }) - conf.add_md_vhosts(domains=[env.domain_b]) - conf.install() - assert env.apache_restart() == 0 - # should not work - r = env.tls_get(domain=env.domain_b, paths="/index.json", options=[ - "--cert", clients_x.get_first("user_expired").cert_file - ]) - assert r.exit_code != 0 - - def test_tls_12_auth_other_ca(self, env, cax_file, clients_y): - conf = TlsTestConf(env=env, extras={ - env.domain_b: [ - "TLSClientCertificate required", - f"TLSClientCA {cax_file}", - ] - }) - conf.add_md_vhosts(domains=[env.domain_b]) - conf.install() - assert env.apache_restart() == 0 - # should not work - r = env.tls_get(domain=env.domain_b, paths="/index.json", options=[ - "--cert", clients_y.get_first("user1").cert_file - ]) - assert r.exit_code != 0 - # This will work, as the CA root is present in the CA file - r = env.tls_get(domain=env.domain_b, paths="/index.json", options=[ - "--cert", env.ca.get_first("user1").cert_file - ]) - assert r.exit_code == 0 diff --git a/test/modules/tls/test_13_proxy.py b/test/modules/tls/test_13_proxy.py deleted file mode 100644 index 8bd305f718..0000000000 --- a/test/modules/tls/test_13_proxy.py +++ /dev/null @@ -1,40 +0,0 @@ -from datetime import timedelta - -import pytest - -from .conf import TlsTestConf - - -class TestProxy: - - @pytest.fixture(autouse=True, scope='class') - def _class_scope(self, env): - conf = TlsTestConf(env=env, extras={ - 'base': "LogLevel proxy:trace1 proxy_http:trace1 ssl:trace1", - env.domain_b: [ - "ProxyPreserveHost on", - f'ProxyPass "/proxy/" "http://127.0.0.1:{env.http_port}/"', - f'ProxyPassReverse "/proxy/" "http://{env.domain_b}:{env.http_port}"', - ] - }) - # add vhosts a+b and a ssl proxy from a to b - conf.add_tls_vhosts(domains=[env.domain_a, env.domain_b]) - conf.install() - assert env.apache_restart() == 0 - - def test_tls_13_proxy_http_get(self, env): - data = env.tls_get_json(env.domain_b, "/proxy/index.json") - assert data == {'domain': env.domain_b} - - @pytest.mark.parametrize("name, value", [ - ("SERVER_NAME", "b.mod-tls.test"), - ("SSL_SESSION_RESUMED", ""), - ("SSL_SECURE_RENEG", ""), - ("SSL_COMPRESS_METHOD", ""), - ("SSL_CIPHER_EXPORT", ""), - ("SSL_CLIENT_VERIFY", ""), - ]) - def test_tls_13_proxy_http_vars(self, env, name: str, value: str): - r = env.tls_get(env.domain_b, f"/proxy/vars.py?name={name}") - assert r.exit_code == 0, r.stderr - assert r.json == {name: value}, r.stdout diff --git a/test/modules/tls/test_14_proxy_ssl.py b/test/modules/tls/test_14_proxy_ssl.py deleted file mode 100644 index 81cb4f31b0..0000000000 --- a/test/modules/tls/test_14_proxy_ssl.py +++ /dev/null @@ -1,125 +0,0 @@ -import re -import pytest - -from .conf import TlsTestConf -from .env import TlsTestEnv -from pyhttpd.env import HttpdTestEnv - - -class TestProxySSL: - - @pytest.fixture(autouse=True, scope='class') - def _class_scope(self, env): - # add vhosts a+b and a ssl proxy from a to b - if not HttpdTestEnv.has_shared_module("tls"): - myoptions="SSLOptions +StdEnvVars" - myssl="mod_ssl" - else: - myoptions="TLSOptions +StdEnvVars" - myssl="mod_tls" - conf = TlsTestConf(env=env, extras={ - 'base': [ - "LogLevel proxy:trace1 proxy_http:trace1 ssl:trace1 proxy_http2:trace1", - f"<Proxy https://127.0.0.1:{env.https_port}/>", - " SSLProxyEngine on", - " SSLProxyVerify require", - f" SSLProxyCACertificateFile {env.ca.cert_file}", - " ProxyPreserveHost on", - "</Proxy>", - f"<Proxy https://localhost:{env.https_port}/>", - " ProxyPreserveHost on", - "</Proxy>", - f"<Proxy h2://127.0.0.1:{env.https_port}/>", - " SSLProxyEngine on", - " SSLProxyVerify require", - f" SSLProxyCACertificateFile {env.ca.cert_file}", - " ProxyPreserveHost on", - "</Proxy>", - ], - env.domain_b: [ - "Protocols h2 http/1.1", - f'ProxyPass /proxy-ssl/ https://127.0.0.1:{env.https_port}/', - f'ProxyPass /proxy-local/ https://localhost:{env.https_port}/', - f'ProxyPass /proxy-h2-ssl/ h2://127.0.0.1:{env.https_port}/', - myoptions, - ], - }) - conf.add_tls_vhosts(domains=[env.domain_a, env.domain_b], ssl_module=myssl) - conf.install() - assert env.apache_restart() == 0 - - def test_tls_14_proxy_ssl_get(self, env): - data = env.tls_get_json(env.domain_b, "/proxy-ssl/index.json") - assert data == {'domain': env.domain_b} - - def test_tls_14_proxy_ssl_get_local(self, env): - # does not work, since SSLProxy* not configured - data = env.tls_get_json(env.domain_b, "/proxy-local/index.json") - assert data is None - # - env.httpd_error_log.ignore_recent( - lognos = [ - "AH01961", # failed to enable ssl support [Hint: if using mod_ssl, see SSLProxyEngine] - "AH00961" # failed to enable ssl support (mod_proxy) - ] - ) - - @pytest.mark.skipif(condition=TlsTestEnv.is_unsupported, reason="h2 not supported here") - def test_tls_14_proxy_ssl_h2_get(self, env): - r = env.tls_get(env.domain_b, "/proxy-h2-ssl/index.json") - assert r.exit_code == 0 - assert r.json == {'domain': env.domain_b} - - @pytest.mark.parametrize("name, value", [ - ("SERVER_NAME", "b.mod-tls.test"), - ("SSL_SESSION_RESUMED", "Initial"), - ("SSL_SECURE_RENEG", "false"), - ("SSL_COMPRESS_METHOD", "NULL"), - ("SSL_CIPHER_EXPORT", "false"), - ("SSL_CLIENT_VERIFY", "NONE"), - ]) - def test_tls_14_proxy_ssl_vars_const(self, env, name: str, value: str): - if not HttpdTestEnv.has_shared_module("tls"): - return - r = env.tls_get(env.domain_b, f"/proxy-ssl/vars.py?name={name}") - assert r.exit_code == 0, r.stderr - assert r.json == {name: value}, r.stdout - - @pytest.mark.parametrize("name, value", [ - ("SERVER_NAME", "b.mod-tls.test"), - ("SSL_SESSION_RESUMED", "Initial"), - ("SSL_SECURE_RENEG", "true"), - ("SSL_COMPRESS_METHOD", "NULL"), - ("SSL_CIPHER_EXPORT", "false"), - ("SSL_CLIENT_VERIFY", "NONE"), - ]) - def test_tls_14_proxy_ssl_vars_const(self, env, name: str, value: str): - if HttpdTestEnv.has_shared_module("tls"): - return - r = env.tls_get(env.domain_b, f"/proxy-ssl/vars.py?name={name}") - assert r.exit_code == 0, r.stderr - assert r.json == {name: value}, r.stdout - - @pytest.mark.parametrize("name, pattern", [ - ("SSL_VERSION_INTERFACE", r'mod_tls/\d+\.\d+\.\d+'), - ("SSL_VERSION_LIBRARY", r'rustls-ffi/\d+\.\d+\.\d+/rustls/\d+\.\d+(\.\d+)?'), - ]) - def test_tls_14_proxy_ssl_vars_match(self, env, name: str, pattern: str): - if not HttpdTestEnv.has_shared_module("tls"): - return - r = env.tls_get(env.domain_b, f"/proxy-ssl/vars.py?name={name}") - assert r.exit_code == 0, r.stderr - assert name in r.json - assert re.match(pattern, r.json[name]), r.json - - @pytest.mark.parametrize("name, pattern", [ - ("SSL_VERSION_INTERFACE", r'mod_ssl/\d+\.\d+\.\d+'), - ("SSL_VERSION_LIBRARY", r'OpenSSL/\d+\.\d+\.\d+'), - ]) - def test_tls_14_proxy_ssl_vars_match(self, env, name: str, pattern: str): - if HttpdTestEnv.has_shared_module("tls"): - return - r = env.tls_get(env.domain_b, f"/proxy-ssl/vars.py?name={name}") - assert r.exit_code == 0, r.stderr - assert name in r.json - assert re.match(pattern, r.json[name]), r.json diff --git a/test/modules/tls/test_15_proxy_tls.py b/test/modules/tls/test_15_proxy_tls.py deleted file mode 100644 index 3fe6cfe478..0000000000 --- a/test/modules/tls/test_15_proxy_tls.py +++ /dev/null @@ -1,97 +0,0 @@ -from datetime import timedelta - -import pytest - -from .conf import TlsTestConf -from .env import TlsTestEnv -from pyhttpd.env import HttpdTestEnv - -@pytest.mark.skipif(condition=not HttpdTestEnv.has_shared_module("tls"), reason="no mod_tls available") - -class TestProxyTLS: - - @pytest.fixture(autouse=True, scope='class') - def _class_scope(self, env): - # add vhosts a+b and a ssl proxy from a to b - conf = TlsTestConf(env=env, extras={ - 'base': [ - "LogLevel proxy:trace1 proxy_http:trace1 proxy_http2:trace2 http2:trace2 cgid:trace4", - "TLSProxyProtocol TLSv1.3+", - f"<Proxy https://127.0.0.1:{env.https_port}/>", - " TLSProxyEngine on", - f" TLSProxyCA {env.ca.cert_file}", - " TLSProxyProtocol TLSv1.2+", - " TLSProxyCiphersPrefer TLS13_AES_256_GCM_SHA384", - " TLSProxyCiphersSuppress TLS13_AES_128_GCM_SHA256", - " ProxyPreserveHost on", - "</Proxy>", - f"<Proxy https://localhost:{env.https_port}/>", - " ProxyPreserveHost on", - "</Proxy>", - f"<Proxy h2://127.0.0.1:{env.https_port}/>", - " TLSProxyEngine on", - f" TLSProxyCA {env.ca.cert_file}", - " TLSProxyCiphersSuppress TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256", - " ProxyPreserveHost on", - "</Proxy>", - ], - env.domain_b: [ - "Protocols h2 http/1.1", - f"ProxyPass /proxy-tls/ https://127.0.0.1:{env.https_port}/", - f"ProxyPass /proxy-local/ https://localhost:{env.https_port}/", - f"ProxyPass /proxy-h2-tls/ h2://127.0.0.1:{env.https_port}/", - "TLSOptions +StdEnvVars", - ], - }) - conf.add_tls_vhosts(domains=[env.domain_a, env.domain_b]) - conf.install() - assert env.apache_restart() == 0 - - def test_tls_15_proxy_tls_get(self, env): - data = env.tls_get_json(env.domain_b, "/proxy-tls/index.json") - assert data == {'domain': env.domain_b} - - def test_tls_15_proxy_tls_get_local(self, env): - # does not work, since SSLProxy* not configured - data = env.tls_get_json(env.domain_b, "/proxy-local/index.json") - assert data is None - # - env.httpd_error_log.ignore_recent( - lognos = [ - "AH01961", # failed to enable ssl support [Hint: if using mod_ssl, see SSLProxyEngine] - "AH00961" # failed to enable ssl support (mod_proxy) - ] - ) - - @pytest.mark.skipif(condition=TlsTestEnv.is_unsupported, reason="h2 not supported here") - def test_tls_15_proxy_tls_h2_get(self, env): - r = env.tls_get(env.domain_b, "/proxy-h2-tls/index.json") - assert r.exit_code == 0 - assert r.json == {'domain': env.domain_b}, f"{r.stdout}" - - @pytest.mark.parametrize("name, value", [ - ("SERVER_NAME", "b.mod-tls.test"), - ("SSL_PROTOCOL", "TLSv1.3"), - ("SSL_CIPHER", "TLS_AES_256_GCM_SHA384"), - ("SSL_SESSION_RESUMED", "Initial"), - ("SSL_SECURE_RENEG", "false"), - ("SSL_COMPRESS_METHOD", "NULL"), - ("SSL_CIPHER_EXPORT", "false"), - ("SSL_CLIENT_VERIFY", "NONE"), - ]) - def test_tls_15_proxy_tls_h1_vars(self, env, name: str, value: str): - r = env.tls_get(env.domain_b, f"/proxy-tls/vars.py?name={name}") - assert r.exit_code == 0, r.stderr - assert r.json == {name: value}, r.stdout - - @pytest.mark.parametrize("name, value", [ - ("SERVER_NAME", "b.mod-tls.test"), - ("SSL_PROTOCOL", "TLSv1.3"), - ("SSL_CIPHER", "TLS_CHACHA20_POLY1305_SHA256"), - ("SSL_SESSION_RESUMED", "Initial"), - ]) - @pytest.mark.skipif(condition=TlsTestEnv.is_unsupported, reason="h2 not supported here") - def test_tls_15_proxy_tls_h2_vars(self, env, name: str, value: str): - r = env.tls_get(env.domain_b, f"/proxy-h2-tls/vars.py?name={name}") - assert r.exit_code == 0, r.stderr - assert r.json == {name: value}, r.stdout diff --git a/test/modules/tls/test_16_proxy_mixed.py b/test/modules/tls/test_16_proxy_mixed.py deleted file mode 100644 index 88b351fd94..0000000000 --- a/test/modules/tls/test_16_proxy_mixed.py +++ /dev/null @@ -1,50 +0,0 @@ -import time - -import pytest - -from .conf import TlsTestConf -from pyhttpd.env import HttpdTestEnv - -@pytest.mark.skipif(condition=not HttpdTestEnv.has_shared_module("tls"), reason="no mod_tls available") - - -class TestProxyMixed: - - @pytest.fixture(autouse=True, scope='class') - def _class_scope(self, env): - conf = TlsTestConf(env=env, extras={ - 'base': [ - "LogLevel proxy:trace1 proxy_http:trace1 ssl:trace1 proxy_http2:trace1 http2:debug", - "ProxyPreserveHost on", - ], - env.domain_a: [ - "Protocols h2 http/1.1", - "TLSProxyEngine on", - f"TLSProxyCA {env.ca.cert_file}", - "<Location /proxy-tls/>", - f" ProxyPass h2://127.0.0.1:{env.https_port}/", - "</Location>", - ], - env.domain_b: [ - "SSLProxyEngine on", - "SSLProxyVerify require", - f"SSLProxyCACertificateFile {env.ca.cert_file}", - "<Location /proxy-ssl/>", - f" ProxyPass https://127.0.0.1:{env.https_port}/", - "</Location>", - ], - }) - # add vhosts a+b and a ssl proxy from a to b - conf.add_tls_vhosts(domains=[env.domain_a, env.domain_b]) - conf.install() - assert env.apache_restart() == 0 - - def test_tls_16_proxy_mixed_ssl_get(self, env, repeat): - data = env.tls_get_json(env.domain_b, "/proxy-ssl/index.json") - assert data == {'domain': env.domain_b} - - def test_tls_16_proxy_mixed_tls_get(self, env, repeat): - data = env.tls_get_json(env.domain_a, "/proxy-tls/index.json") - if data is None: - time.sleep(300) - assert data == {'domain': env.domain_a} diff --git a/test/modules/tls/test_17_proxy_machine_cert.py b/test/modules/tls/test_17_proxy_machine_cert.py deleted file mode 100644 index a5410d63ad..0000000000 --- a/test/modules/tls/test_17_proxy_machine_cert.py +++ /dev/null @@ -1,70 +0,0 @@ -import os - -import pytest - -from .conf import TlsTestConf -from pyhttpd.env import HttpdTestEnv - -@pytest.mark.skipif(condition=not HttpdTestEnv.has_shared_module("tls"), reason="no mod_tls available") -class TestProxyMachineCert: - - @pytest.fixture(autouse=True, scope='class') - def clients_x(cls, env): - return env.ca.get_first("clientsX") - - @pytest.fixture(autouse=True, scope='class') - def clients_y(cls, env): - return env.ca.get_first("clientsY") - - @pytest.fixture(autouse=True, scope='class') - def cax_file(cls, clients_x): - return os.path.join(os.path.dirname(clients_x.cert_file), "clientsX-ca.pem") - - @pytest.fixture(autouse=True, scope='class') - def _class_scope(cls, env, cax_file, clients_x): - # add vhosts a(tls)+b(ssl, port2) and a ssl proxy from a to b with a machine cert - # host b requires a client certificate - conf = TlsTestConf(env=env, extras={ - 'base': [ - "LogLevel proxy:trace1 proxy_http:trace1 ssl:trace4 proxy_http2:trace1", - "ProxyPreserveHost on", - f"Listen {env.proxy_port}", - ], - }) - conf.start_tls_vhost(domains=[env.domain_a], port=env.https_port) - conf.add([ - "Protocols h2 http/1.1", - "TLSProxyEngine on", - f"TLSProxyCA {env.ca.cert_file}", - f"TLSProxyMachineCertificate {clients_x.get_first('user1').cert_file}", - "<Location /proxy-tls/>", - f" ProxyPass https://127.0.0.1:{env.proxy_port}/", - "</Location>", - ]) - conf.end_tls_vhost() - conf.start_vhost(domains=[env.domain_a], port=env.proxy_port, - doc_root=f"htdocs/{env.domain_a}", with_ssl=True) - conf.add([ - "SSLVerifyClient require", - "SSLVerifyDepth 2", - "SSLOptions +StdEnvVars +ExportCertData", - f"SSLCACertificateFile {cax_file}", - "SSLUserName SSL_CLIENT_S_DN_CN" - ]) - conf.end_vhost() - conf.install() - assert env.apache_restart() == 0 - - def test_tls_17_proxy_machine_cert_get_a(self, env): - data = env.tls_get_json(env.domain_a, "/proxy-tls/index.json") - assert data == {'domain': env.domain_a} - - @pytest.mark.parametrize("name, value", [ - ("SERVER_NAME", "a.mod-tls.test"), - ("SSL_CLIENT_VERIFY", "SUCCESS"), - ("REMOTE_USER", "user1"), - ]) - def test_tls_17_proxy_machine_cert_vars(self, env, name: str, value: str): - r = env.tls_get(env.domain_a, f"/proxy-tls/vars.py?name={name}") - assert r.exit_code == 0, r.stderr - assert r.json == {name: value}, r.stdout diff --git a/test/travis_run_linux.sh b/test/travis_run_linux.sh index 7f99b23415..1e0a5b2031 100755 --- a/test/travis_run_linux.sh +++ b/test/travis_run_linux.sh @@ -282,14 +282,6 @@ if test -v TEST_MD -a $RV -eq 0; then RV=$? fi -if test -v TEST_MOD_TLS -a $RV -eq 0; then - # Run mod_tls tests. The underlying librustls was build - # and installed before we configured the server (see top of file). - # This will be replaced once librustls is available as a package. - py.test-3 test/modules/tls - RV=$? -fi - # Catch cases where abort()s get logged to stderr by libraries but # only cause child processes to terminate e.g. during shutdown, # which may not otherwise trigger test failures. |