Line | Count | Source (jump to first uncovered line) |
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 | | |
17 | | /* |
18 | | * ssl.c --- routines for SSL/TLS server infrastructure. |
19 | | * |
20 | | */ |
21 | | |
22 | | #include "apr.h" |
23 | | #include "apr_strings.h" |
24 | | #include "apr_lib.h" |
25 | | #include "apr_signal.h" |
26 | | #include "apr_strmatch.h" |
27 | | |
28 | | #define APR_WANT_STRFUNC |
29 | | #define APR_WANT_MEMFUNC |
30 | | #include "apr_want.h" |
31 | | |
32 | | #include "ap_config.h" |
33 | | #include "httpd.h" |
34 | | #include "http_core.h" |
35 | | #include "http_connection.h" |
36 | | #include "http_protocol.h" |
37 | | #include "http_request.h" |
38 | | #include "http_ssl.h" |
39 | | #include "http_log.h" /* For errors detected in basic auth common |
40 | | * support code... */ |
41 | | #include "mod_core.h" |
42 | | |
43 | | #if APR_HAVE_STDARG_H |
44 | | #include <stdarg.h> |
45 | | #endif |
46 | | #if APR_HAVE_UNISTD_H |
47 | | #include <unistd.h> |
48 | | #endif |
49 | | |
50 | | /* we know core's module_index is 0 */ |
51 | | #undef APLOG_MODULE_INDEX |
52 | | #define APLOG_MODULE_INDEX AP_CORE_MODULE_INDEX |
53 | | |
54 | | APR_HOOK_STRUCT( |
55 | | APR_HOOK_LINK(ssl_conn_is_ssl) |
56 | | APR_HOOK_LINK(ssl_var_lookup) |
57 | | APR_HOOK_LINK(ssl_add_cert_files) |
58 | | APR_HOOK_LINK(ssl_add_fallback_cert_files) |
59 | | APR_HOOK_LINK(ssl_answer_challenge) |
60 | | APR_HOOK_LINK(ssl_ocsp_prime_hook) |
61 | | APR_HOOK_LINK(ssl_ocsp_get_resp_hook) |
62 | | APR_HOOK_LINK(ssl_bind_outgoing) |
63 | | ) |
64 | | |
65 | | APR_DECLARE_OPTIONAL_FN(int, ssl_is_https, (conn_rec *)); |
66 | | static APR_OPTIONAL_FN_TYPE(ssl_is_https) *module_ssl_is_https; |
67 | | APR_DECLARE_OPTIONAL_FN(int, ssl_proxy_enable, (conn_rec *)); |
68 | | static APR_OPTIONAL_FN_TYPE(ssl_proxy_enable) *module_ssl_proxy_enable; |
69 | | APR_DECLARE_OPTIONAL_FN(int, ssl_engine_disable, (conn_rec *)); |
70 | | static APR_OPTIONAL_FN_TYPE(ssl_engine_disable) *module_ssl_engine_disable; |
71 | | APR_DECLARE_OPTIONAL_FN(int, ssl_engine_set, (conn_rec *, |
72 | | ap_conf_vector_t *, |
73 | | int proxy, int enable)); |
74 | | static APR_OPTIONAL_FN_TYPE(ssl_engine_set) *module_ssl_engine_set; |
75 | | |
76 | | |
77 | | static int ssl_is_https(conn_rec *c) |
78 | 0 | { |
79 | | /* Someone retrieved the optional function., not knowing about the |
80 | | * new API. We redirect them to what they should have invoked. */ |
81 | 0 | return ap_ssl_conn_is_ssl(c); |
82 | 0 | } |
83 | | |
84 | | AP_DECLARE(int) ap_ssl_conn_is_ssl(conn_rec *c) |
85 | 0 | { |
86 | 0 | int r = (ap_run_ssl_conn_is_ssl(c) == OK); |
87 | 0 | if (r == 0 && module_ssl_is_https) { |
88 | 0 | r = module_ssl_is_https(c); |
89 | 0 | } |
90 | 0 | return r; |
91 | 0 | } |
92 | | |
93 | | static int ssl_engine_set(conn_rec *c, |
94 | | ap_conf_vector_t *per_dir_config, |
95 | | int proxy, int enable) |
96 | 0 | { |
97 | 0 | if (proxy) { |
98 | 0 | return ap_ssl_bind_outgoing(c, per_dir_config, enable) == OK; |
99 | 0 | } |
100 | 0 | else if (module_ssl_engine_set) { |
101 | 0 | return module_ssl_engine_set(c, per_dir_config, 0, enable); |
102 | 0 | } |
103 | 0 | else if (enable && module_ssl_proxy_enable) { |
104 | 0 | return module_ssl_proxy_enable(c); |
105 | 0 | } |
106 | 0 | else if (!enable && module_ssl_engine_disable) { |
107 | 0 | return module_ssl_engine_disable(c); |
108 | 0 | } |
109 | 0 | return 0; |
110 | 0 | } |
111 | | |
112 | | static int ssl_proxy_enable(conn_rec *c) |
113 | 0 | { |
114 | 0 | return ap_ssl_bind_outgoing(c, NULL, 1); |
115 | 0 | } |
116 | | |
117 | | static int ssl_engine_disable(conn_rec *c) |
118 | 0 | { |
119 | 0 | return ap_ssl_bind_outgoing(c, NULL, 0); |
120 | 0 | } |
121 | | |
122 | | AP_DECLARE(int) ap_ssl_bind_outgoing(conn_rec *c, struct ap_conf_vector_t *dir_conf, |
123 | | int enable_ssl) |
124 | 0 | { |
125 | 0 | int rv, enabled = 0; |
126 | |
|
127 | 0 | c->outgoing = 1; |
128 | 0 | rv = ap_run_ssl_bind_outgoing(c, dir_conf, enable_ssl); |
129 | 0 | enabled = (rv == OK); |
130 | 0 | if (enable_ssl && !enabled) { |
131 | | /* the hooks did not take over. Is there an old skool optional that will? */ |
132 | 0 | if (module_ssl_engine_set) { |
133 | 0 | enabled = module_ssl_engine_set(c, dir_conf, 1, 1); |
134 | 0 | } |
135 | 0 | else if (module_ssl_proxy_enable) { |
136 | 0 | enabled = module_ssl_proxy_enable(c); |
137 | 0 | } |
138 | 0 | } |
139 | 0 | else { |
140 | | /* !enable_ssl || enabled |
141 | | * any existing optional funcs need to not enable here */ |
142 | 0 | if (module_ssl_engine_set) { |
143 | 0 | module_ssl_engine_set(c, dir_conf, 1, 0); |
144 | 0 | } |
145 | 0 | else if (module_ssl_engine_disable) { |
146 | 0 | module_ssl_engine_disable(c); |
147 | 0 | } |
148 | 0 | } |
149 | 0 | if (enable_ssl && !enabled) { |
150 | 0 | ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, |
151 | 0 | c, APLOGNO(01961) " failed to enable ssl support " |
152 | 0 | "[Hint: if using mod_ssl, see SSLProxyEngine]"); |
153 | 0 | return DECLINED; |
154 | 0 | } |
155 | 0 | return OK; |
156 | 0 | } |
157 | | |
158 | | AP_DECLARE(int) ap_ssl_has_outgoing_handlers(void) |
159 | 0 | { |
160 | 0 | apr_array_header_t *hooks = ap_hook_get_ssl_bind_outgoing(); |
161 | 0 | return (hooks && hooks->nelts > 0) |
162 | 0 | || module_ssl_engine_set || module_ssl_proxy_enable; |
163 | 0 | } |
164 | | |
165 | | APR_DECLARE_OPTIONAL_FN(const char *, ssl_var_lookup, |
166 | | (apr_pool_t *p, server_rec *s, |
167 | | conn_rec *c, request_rec *r, |
168 | | const char *name)) |
169 | | AP_FN_ATTR_NONNULL((1, 2, 5)) AP_FN_ATTR_WARN_UNUSED_RESULT; |
170 | | static APR_OPTIONAL_FN_TYPE(ssl_var_lookup) *module_ssl_var_lookup; |
171 | | |
172 | | static const char *ssl_var_lookup(apr_pool_t *p, server_rec *s, |
173 | | conn_rec *c, request_rec *r, |
174 | | const char *name) |
175 | 0 | { |
176 | | /* Someone retrieved the optional function., not knowing about the |
177 | | * new API. We redirect them to what they should have invoked. */ |
178 | 0 | return ap_ssl_var_lookup(p, s, c, r, name); |
179 | 0 | } |
180 | | |
181 | | AP_DECLARE(const char *) ap_ssl_var_lookup(apr_pool_t *p, server_rec *s, |
182 | | conn_rec *c, request_rec *r, |
183 | | const char *name) |
184 | 0 | { |
185 | 0 | const char *val = ap_run_ssl_var_lookup(p, s, c, r, name); |
186 | 0 | if (val == NULL && module_ssl_var_lookup) { |
187 | 0 | val = module_ssl_var_lookup(p, s, c, r, name); |
188 | 0 | } |
189 | 0 | return val; |
190 | 0 | } |
191 | | |
192 | | AP_DECLARE(void) ap_setup_ssl_optional_fns(apr_pool_t *pool) |
193 | 0 | { |
194 | | /* Run as core's very early 'post config' hook, check for any already |
195 | | * installed optional functions related to SSL and save them. Install |
196 | | * our own instances that invoke the new hooks. */ |
197 | 0 | APR_OPTIONAL_FN_TYPE(ssl_is_https) *fn_is_https; |
198 | 0 | APR_OPTIONAL_FN_TYPE(ssl_var_lookup) *fn_ssl_var_lookup; |
199 | |
|
200 | 0 | fn_is_https = APR_RETRIEVE_OPTIONAL_FN(ssl_is_https); |
201 | 0 | module_ssl_is_https = (fn_is_https |
202 | 0 | && fn_is_https != ssl_is_https)? fn_is_https : NULL; |
203 | 0 | APR_REGISTER_OPTIONAL_FN(ssl_is_https); |
204 | |
|
205 | 0 | fn_ssl_var_lookup = APR_RETRIEVE_OPTIONAL_FN(ssl_var_lookup); |
206 | 0 | module_ssl_var_lookup = (fn_ssl_var_lookup |
207 | 0 | && fn_ssl_var_lookup != ssl_var_lookup)? fn_ssl_var_lookup : NULL; |
208 | 0 | APR_REGISTER_OPTIONAL_FN(ssl_var_lookup); |
209 | |
|
210 | 0 | module_ssl_proxy_enable = APR_RETRIEVE_OPTIONAL_FN(ssl_proxy_enable); |
211 | 0 | APR_REGISTER_OPTIONAL_FN(ssl_proxy_enable); |
212 | 0 | module_ssl_engine_disable = APR_RETRIEVE_OPTIONAL_FN(ssl_engine_disable); |
213 | 0 | APR_REGISTER_OPTIONAL_FN(ssl_engine_disable); |
214 | 0 | module_ssl_engine_set = APR_RETRIEVE_OPTIONAL_FN(ssl_engine_set); |
215 | 0 | APR_REGISTER_OPTIONAL_FN(ssl_engine_set); |
216 | 0 | } |
217 | | |
218 | | AP_DECLARE(apr_status_t) ap_ssl_add_cert_files(server_rec *s, apr_pool_t *p, |
219 | | apr_array_header_t *cert_files, |
220 | | apr_array_header_t *key_files) |
221 | 0 | { |
222 | 0 | int rv = ap_run_ssl_add_cert_files(s, p, cert_files, key_files); |
223 | 0 | return (rv == OK || rv == DECLINED)? APR_SUCCESS : APR_EGENERAL; |
224 | 0 | } |
225 | | |
226 | | AP_DECLARE(apr_status_t) ap_ssl_add_fallback_cert_files(server_rec *s, apr_pool_t *p, |
227 | | apr_array_header_t *cert_files, |
228 | | apr_array_header_t *key_files) |
229 | 0 | { |
230 | 0 | int rv = ap_run_ssl_add_fallback_cert_files(s, p, cert_files, key_files); |
231 | 0 | return (rv == OK || rv == DECLINED)? APR_SUCCESS : APR_EGENERAL; |
232 | 0 | } |
233 | | |
234 | | AP_DECLARE(int) ap_ssl_answer_challenge(conn_rec *c, const char *server_name, |
235 | | const char **pcert_pem, const char **pkey_pem) |
236 | 0 | { |
237 | 0 | return (ap_run_ssl_answer_challenge(c, server_name, pcert_pem, pkey_pem) == OK); |
238 | 0 | } |
239 | | |
240 | | AP_DECLARE(apr_status_t) ap_ssl_ocsp_prime(server_rec *s, apr_pool_t *p, |
241 | | const char *id, apr_size_t id_len, |
242 | | const char *pem) |
243 | 0 | { |
244 | 0 | int rv = ap_run_ssl_ocsp_prime_hook(s, p, id, id_len, pem); |
245 | 0 | return rv == OK? APR_SUCCESS : (rv == DECLINED? APR_ENOENT : APR_EGENERAL); |
246 | 0 | } |
247 | | |
248 | | AP_DECLARE(apr_status_t) ap_ssl_ocsp_get_resp(server_rec *s, conn_rec *c, |
249 | | const char *id, apr_size_t id_len, |
250 | | ap_ssl_ocsp_copy_resp *cb, void *userdata) |
251 | 0 | { |
252 | 0 | int rv = ap_run_ssl_ocsp_get_resp_hook(s, c, id, id_len, cb, userdata); |
253 | 0 | return rv == OK? APR_SUCCESS : (rv == DECLINED? APR_ENOENT : APR_EGENERAL); |
254 | 0 | } |
255 | | |
256 | | AP_IMPLEMENT_HOOK_RUN_FIRST(int, ssl_conn_is_ssl, |
257 | | (conn_rec *c), (c), DECLINED) |
258 | | AP_IMPLEMENT_HOOK_RUN_FIRST(const char *,ssl_var_lookup, |
259 | | (apr_pool_t *p, server_rec *s, conn_rec *c, request_rec *r, const char *name), |
260 | | (p, s, c, r, name), NULL) |
261 | | AP_IMPLEMENT_HOOK_RUN_ALL(int, ssl_add_cert_files, |
262 | | (server_rec *s, apr_pool_t *p, |
263 | | apr_array_header_t *cert_files, apr_array_header_t *key_files), |
264 | | (s, p, cert_files, key_files), OK, DECLINED) |
265 | | AP_IMPLEMENT_HOOK_RUN_ALL(int, ssl_add_fallback_cert_files, |
266 | | (server_rec *s, apr_pool_t *p, |
267 | | apr_array_header_t *cert_files, apr_array_header_t *key_files), |
268 | | (s, p, cert_files, key_files), OK, DECLINED) |
269 | | AP_IMPLEMENT_HOOK_RUN_FIRST(int, ssl_answer_challenge, |
270 | | (conn_rec *c, const char *server_name, const char **pcert_pem, const char **pkey_pem), |
271 | | (c, server_name, pcert_pem, pkey_pem), DECLINED) |
272 | | AP_IMPLEMENT_HOOK_RUN_FIRST(int, ssl_ocsp_prime_hook, |
273 | | (server_rec *s, apr_pool_t *p, const char *id, apr_size_t id_len, const char *pem), |
274 | | (s, p, id, id_len, pem), DECLINED) |
275 | | AP_IMPLEMENT_HOOK_RUN_FIRST(int, ssl_ocsp_get_resp_hook, |
276 | | (server_rec *s, conn_rec *c, const char *id, apr_size_t id_len, |
277 | | ap_ssl_ocsp_copy_resp *cb, void *userdata), |
278 | | (s, c, id, id_len, cb, userdata), DECLINED) |
279 | | AP_IMPLEMENT_HOOK_RUN_FIRST(int,ssl_bind_outgoing,(conn_rec *c, ap_conf_vector_t *dir_conf, int require_ssl), |
280 | | (c, dir_conf, require_ssl), DECLINED) |