summaryrefslogtreecommitdiff
blob: ca6a9a403ba21c65b857038ef2cdbe05f4330d9a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
httpd-2.2.x-sni.patch - server name indication support for Apache 2.2 or later
(cf. RFC 4366, "Transport Layer Security (TLS) Extensions")

Based on a patch from the EdelKey project (http://www.edelweb.fr/EdelKey/),
which is used with permission from its author.

Index: httpd-2.2.6/modules/ssl/ssl_engine_init.c
===================================================================
--- httpd-2.2.6.orig/modules/ssl/ssl_engine_init.c
+++ httpd-2.2.6/modules/ssl/ssl_engine_init.c
@@ -135,6 +135,87 @@ static int ssl_tmp_keys_init(server_rec 
     return OK;
 }
 
+#ifndef OPENSSL_NO_TLSEXT
+static int set_ssl_vhost(void *servername, conn_rec *c, server_rec *s) 
+{
+    SSLSrvConfigRec *sc;
+    SSL *ssl;
+    BOOL found = FALSE;
+    apr_array_header_t *names;
+    int i;
+
+    /* check ServerName */
+    if (!strcasecmp(servername, s->server_hostname))
+        found = TRUE;
+
+    /* if not matched yet, check ServerAlias entries */
+    if (!found) {
+        names = s->names;
+        if (names) {
+            char **name = (char **) names->elts;
+            for (i = 0; i < names->nelts; ++i) {
+                if(!name[i]) continue;
+                if (!strcasecmp(servername, name[i])) {
+                    found = TRUE;
+                    break;
+                }
+            }
+        }
+    }
+
+    /* if still no match, check ServerAlias entries with wildcards */
+    if (!found) {
+        names = s->wild_names;
+        if (names) {
+            char **name = (char **) names->elts;
+            for (i = 0; i < names->nelts; ++i) {
+                if(!name[i]) continue;
+                if (!ap_strcasecmp_match(servername, name[i])) {
+                    found = TRUE;
+                    break;
+                }
+            }
+        }
+    }
+
+    /* set SSL_CTX (if matched) */
+    if (found) {
+        if ((ssl = ((SSLConnRec *)myConnConfig(c))->ssl) == NULL) 
+            return 0;
+        if (!(sc = mySrvConfig(s)))
+            return 0;	
+        SSL_set_SSL_CTX(ssl,sc->server->ssl_ctx);
+        return 1;
+    }
+    return 0;
+}
+
+int ssl_set_vhost_ctx(SSL *ssl, const char *servername) 
+{
+    conn_rec *c;
+
+    if (servername == NULL)   /* should not occur. */
+        return 0;
+
+    SSL_set_SSL_CTX(ssl,NULL);
+
+    if (!(c = (conn_rec *)SSL_get_app_data(ssl))) 
+        return 0;
+
+    return ap_vhost_iterate_given_conn(c,set_ssl_vhost,servername);
+}
+
+int ssl_servername_cb(SSL *s, int *al, modssl_ctx_t *mctx)
+{
+    const char *servername = SSL_get_servername(s,TLSEXT_NAMETYPE_host_name);
+
+    if (servername) {
+        return ssl_set_vhost_ctx(s,servername)?SSL_TLSEXT_ERR_OK:SSL_TLSEXT_ERR_ALERT_FATAL;
+    }
+    return SSL_TLSEXT_ERR_NOACK;
+}
+#endif
+
 /*
  *  Per-module initialization
  */
@@ -355,6 +436,29 @@ static void ssl_init_server_check(server
     }
 }
 
+static void ssl_init_server_extensions(server_rec *s,
+                             apr_pool_t *p,
+                             apr_pool_t *ptemp,
+                             modssl_ctx_t *mctx)
+{
+    /*
+     * Configure TLS extensions support
+     */
+
+#ifndef OPENSSL_NO_TLSEXT
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
+                 "Configuring TLS extensions facility");
+
+    if (!SSL_CTX_set_tlsext_servername_callback(mctx->ssl_ctx, ssl_servername_cb) ||
+        !SSL_CTX_set_tlsext_servername_arg(mctx->ssl_ctx, mctx)) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
+                "Unable to initialize servername callback, bad openssl version.");
+        ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, s);
+        ssl_die();
+    }
+#endif
+}
+
 static void ssl_init_ctx_protocol(server_rec *s,
                                   apr_pool_t *p,
                                   apr_pool_t *ptemp,
@@ -688,6 +792,8 @@ static void ssl_init_ctx(server_rec *s,
         /* XXX: proxy support? */
         ssl_init_ctx_cert_chain(s, p, ptemp, mctx);
     }
+
+    ssl_init_server_extensions(s, p, ptemp, mctx);
 }
 
 static int ssl_server_import_cert(server_rec *s,
@@ -1014,6 +1120,7 @@ void ssl_init_CheckServers(server_rec *b
         }
     }
 
+#ifdef OPENSSL_NO_TLSEXT
     /*
      * Give out warnings when more than one SSL-aware virtual server uses the
      * same IP:port. This doesn't work because mod_ssl then will always use
@@ -1058,6 +1165,7 @@ void ssl_init_CheckServers(server_rec *b
                      "Init: You should not use name-based "
                      "virtual hosts in conjunction with SSL!!");
     }
+#endif
 }
 
 #ifdef SSLC_VERSION_NUMBER
Index: httpd-2.2.6/modules/ssl/ssl_engine_kernel.c
===================================================================
--- httpd-2.2.6.orig/modules/ssl/ssl_engine_kernel.c
+++ httpd-2.2.6/modules/ssl/ssl_engine_kernel.c
@@ -231,6 +231,19 @@ int ssl_hook_Access(request_rec *r)
      * the currently active one.
      */
 
+#ifndef OPENSSL_NO_TLSEXT
+    /*
+     * We will switch to another virtualhost and to its ssl_ctx
+     * if changed, we will force a renegotiation.
+     */
+    if (r->hostname && !SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name)) {
+        SSL_CTX *ctx = SSL_get_SSL_CTX(ssl);
+        if (ssl_set_vhost_ctx(ssl,(char *)r->hostname) &&
+            ctx != SSL_get_SSL_CTX(ssl))
+            renegotiate = TRUE;
+    }
+#endif
+
     /*
      * Override of SSLCipherSuite
      *
@@ -997,6 +1010,9 @@ int ssl_hook_Fixup(request_rec *r)
     SSLDirConfigRec *dc = myDirConfig(r);
     apr_table_t *env = r->subprocess_env;
     char *var, *val = "";
+#ifndef OPENSSL_NO_TLSEXT
+    const char* servername;
+#endif
     STACK_OF(X509) *peer_certs;
     SSL *ssl;
     int i;
@@ -1018,6 +1034,12 @@ int ssl_hook_Fixup(request_rec *r)
     /* the always present HTTPS (=HTTP over SSL) flag! */
     apr_table_setn(env, "HTTPS", "on");
 
+#ifndef OPENSSL_NO_TLSEXT
+    /* add content of SNI TLS extension (if supplied with ClientHello) */
+    if (servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name))
+	apr_table_set(env, "TLS_SNI", servername);
+#endif
+
     /* standard SSL environment variables */
     if (dc->nOptions & SSL_OPT_STDENVVARS) {
         for (i = 0; ssl_hook_Fixup_vars[i]; i++) {
Index: httpd-2.2.6/modules/ssl/ssl_toolkit_compat.h
===================================================================
--- httpd-2.2.6.orig/modules/ssl/ssl_toolkit_compat.h
+++ httpd-2.2.6/modules/ssl/ssl_toolkit_compat.h
@@ -258,6 +258,12 @@ typedef void (*modssl_popfree_fn)(char *
 #define SSL_SESS_CACHE_NO_INTERNAL  SSL_SESS_CACHE_NO_INTERNAL_LOOKUP
 #endif
 
+#ifndef OPENSSL_NO_TLSEXT
+#ifndef SSL_CTRL_SET_TLSEXT_HOSTNAME
+#define OPENSSL_NO_TLSEXT
+#endif
+#endif
+
 #endif /* SSL_TOOLKIT_COMPAT_H */
 
 /** @} */
Index: httpd-2.2.6/modules/ssl/ssl_engine_io.c
===================================================================
--- httpd-2.2.6.orig/modules/ssl/ssl_engine_io.c
+++ httpd-2.2.6/modules/ssl/ssl_engine_io.c
@@ -1541,14 +1541,25 @@ int ssl_io_buffer_fill(request_rec *r)
 
     apr_brigade_destroy(tempb);
 
-    /* Insert the filter which will supply the buffered data. */
+    /* After consuming all protocol-level input, remove all protocol-level
+     * filters.  It should strictly only be necessary to remove filters
+     * at exactly ftype == AP_FTYPE_PROTOCOL, since this filter will 
+     * precede all > AP_FTYPE_PROTOCOL anyway. */
+    while (r->proto_input_filters->frec->ftype < AP_FTYPE_CONNECTION) {
+        ap_remove_input_filter(r->proto_input_filters);
+    }
+
+    /* Insert the filter which will supply the buffered content. */
     ap_add_input_filter(ssl_io_buffer, ctx, r, c);
 
     return 0;
 }
 
 /* This input filter supplies the buffered request body to the caller
- * from the brigade stored in f->ctx. */
+ * from the brigade stored in f->ctx.  Note that the placement of this
+ * filter in the filter stack is important; it must be the first
+ * r->proto_input_filter; lower-typed filters will not be preserved
+ * across internal redirects (see PR 43738).  */
 static apr_status_t ssl_io_filter_buffer(ap_filter_t *f,
                                          apr_bucket_brigade *bb,
                                          ap_input_mode_t mode,
@@ -1567,6 +1578,19 @@ static apr_status_t ssl_io_filter_buffer
         return APR_ENOTIMPL;
     }
 
+    if (APR_BRIGADE_EMPTY(ctx->bb)) {
+        /* Suprisingly (and perhaps, wrongly), the request body can be
+         * pulled from the input filter stack more than once; a
+         * handler may read it, and ap_discard_request_body() will
+         * attempt to do so again after *every* request.  So input
+         * filters must be prepared to give up an EOS if invoked after
+         * initially reading the request. The HTTP_IN filter does this
+         * with its ->eos_sent flag. */
+
+        APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_eos_create(f->c->bucket_alloc));
+        return APR_SUCCESS;
+    }
+
     if (mode == AP_MODE_READBYTES) {
         apr_bucket *e;
 
@@ -1621,8 +1645,9 @@ static apr_status_t ssl_io_filter_buffer
         }
 
         ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, f->c,
-                      "buffered SSL brigade now exhausted; removing filter");
-        ap_remove_input_filter(f);
+                      "buffered SSL brigade exhausted");
+        /* Note that the filter must *not* be removed here; it may be
+         * invoked again, see comment above. */
     }
 
     return APR_SUCCESS;
@@ -1691,7 +1716,7 @@ void ssl_io_filter_register(apr_pool_t *
     ap_register_input_filter  (ssl_io_filter, ssl_io_filter_input,  NULL, AP_FTYPE_CONNECTION + 5);
     ap_register_output_filter (ssl_io_filter, ssl_io_filter_output, NULL, AP_FTYPE_CONNECTION + 5);
 
-    ap_register_input_filter  (ssl_io_buffer, ssl_io_filter_buffer, NULL, AP_FTYPE_PROTOCOL - 1);
+    ap_register_input_filter  (ssl_io_buffer, ssl_io_filter_buffer, NULL, AP_FTYPE_PROTOCOL);
 
     return;
 }