1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2  * contributor license agreements.  See the NOTICE file distributed with
3  * this work for additional information regarding copyright ownership.
4  * The ASF licenses this file to You under the Apache License, Version 2.0
5  * (the "License"); you may not use this file except in compliance with
6  * the License.  You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include <assert.h>
17 #include <apr_lib.h>
18 #include <apr_strings.h>
19 
20 #include <httpd.h>
21 #include <http_connection.h>
22 #include <http_core.h>
23 #include <http_main.h>
24 #include <http_log.h>
25 #include <ap_socache.h>
26 
27 #include <rustls.h>
28 
29 #include "tls_conf.h"
30 #include "tls_core.h"
31 #include "tls_cert.h"
32 #include "tls_util.h"
33 #include "tls_var.h"
34 #include "tls_version.h"
35 
36 
37 extern module AP_MODULE_DECLARE_DATA tls_module;
38 APLOG_USE_MODULE(tls);
39 
40 typedef struct {
41     apr_pool_t *p;
42     server_rec *s;
43     conn_rec *c;
44     request_rec *r;
45     tls_conf_conn_t *cc;
46     const char *name;
47     const char *arg_s;
48     int arg_i;
49 } tls_var_lookup_ctx_t;
50 
51 typedef const char *var_lookup(const tls_var_lookup_ctx_t *ctx);
52 
var_get_ssl_protocol(const tls_var_lookup_ctx_t * ctx)53 static const char *var_get_ssl_protocol(const tls_var_lookup_ctx_t *ctx)
54 {
55     return ctx->cc->tls_protocol_name;
56 }
57 
var_get_ssl_cipher(const tls_var_lookup_ctx_t * ctx)58 static const char *var_get_ssl_cipher(const tls_var_lookup_ctx_t *ctx)
59 {
60     return ctx->cc->tls_cipher_name;
61 }
62 
var_get_sni_hostname(const tls_var_lookup_ctx_t * ctx)63 static const char *var_get_sni_hostname(const tls_var_lookup_ctx_t *ctx)
64 {
65     return ctx->cc->sni_hostname;
66 }
67 
var_get_version_interface(const tls_var_lookup_ctx_t * ctx)68 static const char *var_get_version_interface(const tls_var_lookup_ctx_t *ctx)
69 {
70     tls_conf_server_t *sc = tls_conf_server_get(ctx->s);
71     return sc->global->module_version;
72 }
73 
var_get_version_library(const tls_var_lookup_ctx_t * ctx)74 static const char *var_get_version_library(const tls_var_lookup_ctx_t *ctx)
75 {
76     tls_conf_server_t *sc = tls_conf_server_get(ctx->s);
77     return sc->global->crustls_version;
78 }
79 
var_get_false(const tls_var_lookup_ctx_t * ctx)80 static const char *var_get_false(const tls_var_lookup_ctx_t *ctx)
81 {
82     (void)ctx;
83     return "false";
84 }
85 
var_get_null(const tls_var_lookup_ctx_t * ctx)86 static const char *var_get_null(const tls_var_lookup_ctx_t *ctx)
87 {
88     (void)ctx;
89     return "NULL";
90 }
91 
var_get_client_s_dn_cn(const tls_var_lookup_ctx_t * ctx)92 static const char *var_get_client_s_dn_cn(const tls_var_lookup_ctx_t *ctx)
93 {
94     /* There is no support in the crustls/rustls/webpki APIs to
95      * parse X.509 certificates and extract information about
96      * subject, issuer, etc. */
97     if (!ctx->cc->peer_certs || !ctx->cc->peer_certs->nelts) return NULL;
98     return "Not Implemented";
99 }
100 
var_get_client_verify(const tls_var_lookup_ctx_t * ctx)101 static const char *var_get_client_verify(const tls_var_lookup_ctx_t *ctx)
102 {
103     return ctx->cc->peer_certs? "SUCCESS" : "NONE";
104 }
105 
var_get_session_resumed(const tls_var_lookup_ctx_t * ctx)106 static const char *var_get_session_resumed(const tls_var_lookup_ctx_t *ctx)
107 {
108     return ctx->cc->session_id_cache_hit? "Resumed" : "Initial";
109 }
110 
var_get_client_cert(const tls_var_lookup_ctx_t * ctx)111 static const char *var_get_client_cert(const tls_var_lookup_ctx_t *ctx)
112 {
113     const rustls_certificate *cert;
114     const char *pem;
115     apr_status_t rv;
116     int cert_idx = 0;
117 
118     if (ctx->arg_s) {
119         if (strcmp(ctx->arg_s, "chain")) return NULL;
120         /* ctx->arg_i'th chain cert, which is in out list as */
121         cert_idx = ctx->arg_i + 1;
122     }
123     if (!ctx->cc->peer_certs || cert_idx >= ctx->cc->peer_certs->nelts) return NULL;
124     cert = APR_ARRAY_IDX(ctx->cc->peer_certs, cert_idx, const rustls_certificate*);
125     if (APR_SUCCESS != (rv = tls_cert_to_pem(&pem, ctx->p, cert))) {
126         ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, ctx->s, APLOGNO(10315)
127                          "Failed to create client certificate PEM");
128         return NULL;
129     }
130     return pem;
131 }
132 
var_get_server_cert(const tls_var_lookup_ctx_t * ctx)133 static const char *var_get_server_cert(const tls_var_lookup_ctx_t *ctx)
134 {
135     const rustls_certificate *cert;
136     const char *pem;
137     apr_status_t rv;
138 
139     if (!ctx->cc->key) return NULL;
140     cert = rustls_certified_key_get_certificate(ctx->cc->key, 0);
141     if (!cert) return NULL;
142     if (APR_SUCCESS != (rv = tls_cert_to_pem(&pem, ctx->p, cert))) {
143         ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, ctx->s, APLOGNO(10316)
144                          "Failed to create server certificate PEM");
145         return NULL;
146     }
147     return pem;
148 }
149 
150 typedef struct {
151     const char *name;
152     var_lookup* fn;
153     const char *arg_s;
154     int arg_i;
155 } var_def_t;
156 
157 static const var_def_t VAR_DEFS[] = {
158     { "SSL_PROTOCOL", var_get_ssl_protocol, NULL, 0 },
159     { "SSL_CIPHER", var_get_ssl_cipher, NULL, 0 },
160     { "SSL_TLS_SNI", var_get_sni_hostname, NULL, 0 },
161     { "SSL_CLIENT_S_DN_CN", var_get_client_s_dn_cn, NULL, 0 },
162     { "SSL_VERSION_INTERFACE", var_get_version_interface, NULL, 0 },
163     { "SSL_VERSION_LIBRARY", var_get_version_library, NULL, 0 },
164     { "SSL_SECURE_RENEG", var_get_false, NULL, 0 },
165     { "SSL_COMPRESS_METHOD", var_get_null, NULL, 0 },
166     { "SSL_CIPHER_EXPORT", var_get_false, NULL, 0 },
167     { "SSL_CLIENT_VERIFY", var_get_client_verify, NULL, 0 },
168     { "SSL_SESSION_RESUMED", var_get_session_resumed, NULL, 0 },
169     { "SSL_CLIENT_CERT", var_get_client_cert, NULL, 0 },
170     { "SSL_CLIENT_CHAIN_0", var_get_client_cert, "chain", 0 },
171     { "SSL_CLIENT_CHAIN_1", var_get_client_cert, "chain", 1 },
172     { "SSL_CLIENT_CHAIN_2", var_get_client_cert, "chain", 2 },
173     { "SSL_CLIENT_CHAIN_3", var_get_client_cert, "chain", 3 },
174     { "SSL_CLIENT_CHAIN_4", var_get_client_cert, "chain", 4 },
175     { "SSL_CLIENT_CHAIN_5", var_get_client_cert, "chain", 5 },
176     { "SSL_CLIENT_CHAIN_6", var_get_client_cert, "chain", 6 },
177     { "SSL_CLIENT_CHAIN_7", var_get_client_cert, "chain", 7 },
178     { "SSL_CLIENT_CHAIN_8", var_get_client_cert, "chain", 8 },
179     { "SSL_CLIENT_CHAIN_9", var_get_client_cert, "chain", 9 },
180     { "SSL_SERVER_CERT", var_get_server_cert, NULL, 0 },
181 };
182 
183 static const char *const TlsAlwaysVars[] = {
184     "SSL_TLS_SNI",
185     "SSL_PROTOCOL",
186     "SSL_CIPHER",
187     "SSL_CLIENT_S_DN_CN",
188 };
189 
190 /* what mod_ssl defines, plus server cert and client cert DN and SAN entries */
191 static const char *const StdEnvVars[] = {
192     "SSL_VERSION_INTERFACE", /* implemented: module version string */
193     "SSL_VERSION_LIBRARY",   /* implemented: crustls/rustls version string */
194     "SSL_SECURE_RENEG",      /* implemented: always "false" */
195     "SSL_COMPRESS_METHOD",   /* implemented: always "NULL" */
196     "SSL_CIPHER_EXPORT",     /* implemented: always "false" */
197     "SSL_CIPHER_USEKEYSIZE",
198     "SSL_CIPHER_ALGKEYSIZE",
199     "SSL_CLIENT_VERIFY",     /* implemented: always "SUCCESS" or "NONE" */
200     "SSL_CLIENT_M_VERSION",
201     "SSL_CLIENT_M_SERIAL",
202     "SSL_CLIENT_V_START",
203     "SSL_CLIENT_V_END",
204     "SSL_CLIENT_V_REMAIN",
205     "SSL_CLIENT_S_DN",
206     "SSL_CLIENT_I_DN",
207     "SSL_CLIENT_A_KEY",
208     "SSL_CLIENT_A_SIG",
209     "SSL_CLIENT_CERT_RFC4523_CEA",
210     "SSL_SERVER_M_VERSION",
211     "SSL_SERVER_M_SERIAL",
212     "SSL_SERVER_V_START",
213     "SSL_SERVER_V_END",
214     "SSL_SERVER_S_DN",
215     "SSL_SERVER_I_DN",
216     "SSL_SERVER_A_KEY",
217     "SSL_SERVER_A_SIG",
218     "SSL_SESSION_ID",        /* not implemented: highly sensitive data we do not expose */
219     "SSL_SESSION_RESUMED",   /* implemented: if our cache was hit successfully */
220 };
221 
222 /* Cert related variables, export when TLSOption ExportCertData is set */
223 static const char *const ExportCertVars[] = {
224     "SSL_CLIENT_CERT",       /* implemented: */
225     "SSL_CLIENT_CHAIN_0",    /* implemented: */
226     "SSL_CLIENT_CHAIN_1",    /* implemented: */
227     "SSL_CLIENT_CHAIN_2",    /* implemented: */
228     "SSL_CLIENT_CHAIN_3",    /* implemented: */
229     "SSL_CLIENT_CHAIN_4",    /* implemented: */
230     "SSL_CLIENT_CHAIN_5",    /* implemented: */
231     "SSL_CLIENT_CHAIN_6",    /* implemented: */
232     "SSL_CLIENT_CHAIN_7",    /* implemented: */
233     "SSL_CLIENT_CHAIN_8",    /* implemented: */
234     "SSL_CLIENT_CHAIN_9",    /* implemented: */
235     "SSL_SERVER_CERT",       /* implemented: */
236 };
237 
tls_var_init_lookup_hash(apr_pool_t * pool,apr_hash_t * map)238 void tls_var_init_lookup_hash(apr_pool_t *pool, apr_hash_t *map)
239 {
240     const var_def_t *def;
241     apr_size_t i;
242 
243     (void)pool;
244     for (i = 0; i < TLS_DIM(VAR_DEFS); ++i) {
245         def = &VAR_DEFS[i];
246         apr_hash_set(map, def->name, APR_HASH_KEY_STRING, def);
247     }
248 }
249 
invoke(var_def_t * def,tls_var_lookup_ctx_t * ctx)250 static const char *invoke(var_def_t* def, tls_var_lookup_ctx_t *ctx)
251 {
252     if (TLS_CONN_ST_IS_ENABLED(ctx->cc)) {
253         const char *val = ctx->cc->subprocess_env?
254             apr_table_get(ctx->cc->subprocess_env, def->name) : NULL;
255         if (val && *val) return val;
256         ctx->arg_s = def->arg_s;
257         ctx->arg_i = def->arg_i;
258         return def->fn(ctx);
259     }
260     return NULL;
261 }
262 
set_var(tls_var_lookup_ctx_t * ctx,apr_hash_t * lookups,apr_table_t * table)263 static void set_var(
264     tls_var_lookup_ctx_t *ctx, apr_hash_t *lookups, apr_table_t *table)
265 {
266     var_def_t* def = apr_hash_get(lookups, ctx->name, APR_HASH_KEY_STRING);
267     if (def) {
268         const char *val = invoke(def, ctx);
269         if (val && *val) {
270             apr_table_setn(table, ctx->name, val);
271         }
272     }
273 }
274 
tls_var_lookup(apr_pool_t * p,server_rec * s,conn_rec * c,request_rec * r,const char * name)275 const char *tls_var_lookup(
276     apr_pool_t *p, server_rec *s, conn_rec *c, request_rec *r, const char *name)
277 {
278     const char *val = NULL;
279     tls_conf_server_t *sc;
280     var_def_t* def;
281 
282     ap_assert(p);
283     ap_assert(name);
284     s = s? s : (r? r->server : (c? c->base_server : NULL));
285     c = c? c : (r? r->connection : NULL);
286 
287     sc = tls_conf_server_get(s? s : ap_server_conf);
288     def = apr_hash_get(sc->global->var_lookups, name, APR_HASH_KEY_STRING);
289     if (def) {
290         tls_var_lookup_ctx_t ctx;
291         ctx.p = p;
292         ctx.s = s;
293         ctx.c = c;
294         ctx.r = r;
295         ctx.cc = c? tls_conf_conn_get(c->master? c->master : c) : NULL;
296                 ctx.cc = c? tls_conf_conn_get(c->master? c->master : c) : NULL;
297         ctx.name = name;
298         val = invoke(def, &ctx);
299         ap_log_cerror(APLOG_MARK, APLOG_TRACE3, 0, c, "tls lookup of var '%s' -> '%s'", name, val);
300     }
301     return val;
302 }
303 
add_vars(apr_table_t * env,conn_rec * c,server_rec * s,request_rec * r)304 static void add_vars(apr_table_t *env, conn_rec *c, server_rec *s, request_rec *r)
305 {
306     tls_conf_server_t *sc;
307     tls_conf_dir_t *dc, *sdc;
308     tls_var_lookup_ctx_t ctx;
309     apr_size_t i;
310     int overlap;
311 
312     sc = tls_conf_server_get(s);
313     dc = r? tls_conf_dir_get(r) : tls_conf_dir_server_get(s);
314     sdc = r? tls_conf_dir_server_get(s): dc;
315     ctx.p = r? r->pool : c->pool;
316     ctx.s = s;
317     ctx.c = c;
318     ctx.r = r;
319     ctx.cc = tls_conf_conn_get(c->master? c->master : c);
320     /* Can we re-use the precomputed connection values? */
321     overlap = (r && ctx.cc->subprocess_env && r->server == ctx.cc->server);
322     if (overlap) {
323         apr_table_overlap(env, ctx.cc->subprocess_env, APR_OVERLAP_TABLES_SET);
324     }
325     else {
326         apr_table_setn(env, "HTTPS", "on");
327         for (i = 0; i < TLS_DIM(TlsAlwaysVars); ++i) {
328             ctx.name = TlsAlwaysVars[i];
329             set_var(&ctx, sc->global->var_lookups, env);
330         }
331     }
332     if (dc->std_env_vars == TLS_FLAG_TRUE) {
333         for (i = 0; i < TLS_DIM(StdEnvVars); ++i) {
334             ctx.name = StdEnvVars[i];
335             set_var(&ctx, sc->global->var_lookups, env);
336         }
337     }
338     else if (overlap && sdc->std_env_vars == TLS_FLAG_TRUE) {
339         /* Remove variables added on connection init that are disabled here */
340         for (i = 0; i < TLS_DIM(StdEnvVars); ++i) {
341             apr_table_unset(env, StdEnvVars[i]);
342         }
343     }
344     if (dc->export_cert_vars == TLS_FLAG_TRUE) {
345         for (i = 0; i < TLS_DIM(ExportCertVars); ++i) {
346             ctx.name = ExportCertVars[i];
347             set_var(&ctx, sc->global->var_lookups, env);
348         }
349     }
350     else if (overlap && sdc->std_env_vars == TLS_FLAG_TRUE) {
351         /* Remove variables added on connection init that are disabled here */
352         for (i = 0; i < TLS_DIM(ExportCertVars); ++i) {
353             apr_table_unset(env, ExportCertVars[i]);
354         }
355     }
356  }
357 
tls_var_handshake_done(conn_rec * c)358 apr_status_t tls_var_handshake_done(conn_rec *c)
359 {
360     tls_conf_conn_t *cc;
361     tls_conf_server_t *sc;
362     apr_status_t rv = APR_SUCCESS;
363 
364     cc = tls_conf_conn_get(c);
365     if (!TLS_CONN_ST_IS_ENABLED(cc)) goto cleanup;
366 
367     sc = tls_conf_server_get(cc->server);
368     if (cc->peer_certs && sc->var_user_name) {
369         cc->user_name = tls_var_lookup(c->pool, cc->server, c, NULL, sc->var_user_name);
370         if (!cc->user_name) {
371             ap_log_error(APLOG_MARK, APLOG_WARNING, 0, cc->server, APLOGNO(10317)
372                 "Failed to set r->user to '%s'", sc->var_user_name);
373         }
374     }
375     cc->subprocess_env = apr_table_make(c->pool, 5);
376     add_vars(cc->subprocess_env, c, cc->server, NULL);
377 
378 cleanup:
379     return rv;
380 }
381 
tls_var_request_fixup(request_rec * r)382 int tls_var_request_fixup(request_rec *r)
383 {
384     conn_rec *c = r->connection;
385     tls_conf_conn_t *cc;
386 
387     cc = tls_conf_conn_get(c->master? c->master : c);
388     if (!TLS_CONN_ST_IS_ENABLED(cc)) goto cleanup;
389     if (cc->user_name) {
390         /* why is r->user a char* and not const? */
391         r->user = apr_pstrdup(r->pool, cc->user_name);
392     }
393     add_vars(r->subprocess_env, c, r->server, r);
394 
395 cleanup:
396     return DECLINED;
397 }
398