1 /*
2 
3    uWSGI HTTPS router
4 
5 */
6 
7 #include "common.h"
8 
9 #ifdef UWSGI_SSL
10 
11 extern struct uwsgi_http uhttp;
12 
13 // taken from nginx
hr_ssl_clear_errors()14 static void hr_ssl_clear_errors() {
15 	while (ERR_peek_error()) {
16 		(void) ERR_get_error();
17 	}
18 	ERR_clear_error();
19 }
20 
uwsgi_opt_https(char * opt,char * value,void * cr)21 void uwsgi_opt_https(char *opt, char *value, void *cr) {
22         struct uwsgi_corerouter *ucr = (struct uwsgi_corerouter *) cr;
23         char *client_ca = NULL;
24 
25         // build socket, certificate and key file
26         char *sock = uwsgi_str(value);
27         char *crt = strchr(sock, ',');
28         if (!crt) {
29                 uwsgi_log("invalid https syntax must be socket,crt,key\n");
30                 exit(1);
31         }
32         *crt = '\0'; crt++;
33         char *key = strchr(crt, ',');
34         if (!key) {
35                 uwsgi_log("invalid https syntax must be socket,crt,key\n");
36                 exit(1);
37         }
38         *key = '\0'; key++;
39 
40         char *ciphers = strchr(key, ',');
41         if (ciphers) {
42                 *ciphers = '\0'; ciphers++;
43                 client_ca = strchr(ciphers, ',');
44                 if (client_ca) {
45                         *client_ca = '\0'; client_ca++;
46                 }
47         }
48 
49         struct uwsgi_gateway_socket *ugs = uwsgi_new_gateway_socket(sock, ucr->name);
50         // ok we have the socket, initialize ssl if required
51         if (!uwsgi.ssl_initialized) {
52                 uwsgi_ssl_init();
53         }
54 
55         // initialize ssl context
56 	char *name = uhttp.https_session_context;
57 	if (!name) {
58 		name = uwsgi_concat3(ucr->short_name, "-", ugs->name);
59 	}
60 
61         ugs->ctx = uwsgi_ssl_new_server_context(name, crt, key, ciphers, client_ca);
62 	if (!ugs->ctx) {
63 		exit(1);
64 	}
65         // set the ssl mode
66         ugs->mode = UWSGI_HTTP_SSL;
67 
68         ucr->has_sockets++;
69 }
70 
uwsgi_opt_https2(char * opt,char * value,void * cr)71 void uwsgi_opt_https2(char *opt, char *value, void *cr) {
72         struct uwsgi_corerouter *ucr = (struct uwsgi_corerouter *) cr;
73 
74 	char *s2_addr = NULL;
75 	char *s2_cert = NULL;
76 	char *s2_key = NULL;
77 	char *s2_ciphers = NULL;
78 	char *s2_clientca = NULL;
79 	char *s2_spdy = NULL;
80 
81 	if (uwsgi_kvlist_parse(value, strlen(value), ',', '=',
82                         "addr", &s2_addr,
83                         "cert", &s2_cert,
84                         "crt", &s2_cert,
85                         "key", &s2_key,
86                         "ciphers", &s2_ciphers,
87                         "clientca", &s2_clientca,
88                         "client_ca", &s2_clientca,
89                         "spdy", &s2_spdy,
90                 	NULL)) {
91 		uwsgi_log("error parsing --https2 option\n");
92 		exit(1);
93         }
94 
95 	if (!s2_addr || !s2_cert || !s2_key) {
96 		uwsgi_log("--https2 option needs addr, cert and key items\n");
97 		exit(1);
98 	}
99 
100         struct uwsgi_gateway_socket *ugs = uwsgi_new_gateway_socket(s2_addr, ucr->name);
101         // ok we have the socket, initialize ssl if required
102         if (!uwsgi.ssl_initialized) {
103                 uwsgi_ssl_init();
104         }
105 
106         // initialize ssl context
107         char *name = uhttp.https_session_context;
108         if (!name) {
109                 name = uwsgi_concat3(ucr->short_name, "-", ugs->name);
110         }
111 
112 #ifdef UWSGI_SPDY
113 	if (s2_spdy) {
114         	uhttp.spdy_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL, NULL);
115 		uhttp.spdy3_settings = uwsgi_buffer_new(uwsgi.page_size);
116 		if (uwsgi_buffer_append(uhttp.spdy3_settings, "\x80\x03\x00\x04\x01", 5)) goto spdyerror;
117 		if (uwsgi_buffer_u24be(uhttp.spdy3_settings, (8 * 2) + 4)) goto spdyerror;
118 		if (uwsgi_buffer_u32be(uhttp.spdy3_settings, 2)) goto spdyerror;
119 
120 		// SETTINGS_ROUND_TRIP_TIME
121 		if (uwsgi_buffer_append(uhttp.spdy3_settings, "\x01\x00\x00\x03", 4)) goto spdyerror;
122 		if (uwsgi_buffer_u32be(uhttp.spdy3_settings, 30 * 1000)) goto spdyerror;
123 		// SETTINGS_INITIAL_WINDOW_SIZE
124 		if (uwsgi_buffer_append(uhttp.spdy3_settings, "\x01\x00\x00\x07", 4)) goto spdyerror;
125 		if (uwsgi_buffer_u32be(uhttp.spdy3_settings, 8192)) goto spdyerror;
126 
127 		uhttp.spdy3_settings_size = uhttp.spdy3_settings->pos;
128 	}
129 #endif
130 
131         ugs->ctx = uwsgi_ssl_new_server_context(name, s2_cert, s2_key, s2_ciphers, s2_clientca);
132         if (!ugs->ctx) {
133                 exit(1);
134         }
135 #ifdef UWSGI_SPDY
136 	if (s2_spdy) {
137         	SSL_CTX_set_info_callback(ugs->ctx, uwsgi_spdy_info_cb);
138         	SSL_CTX_set_next_protos_advertised_cb(ugs->ctx, uwsgi_spdy_npn, NULL);
139 	}
140 #endif
141         // set the ssl mode
142         ugs->mode = UWSGI_HTTP_SSL;
143 
144         ucr->has_sockets++;
145 
146 	return;
147 
148 #ifdef UWSGI_SPDY
149 spdyerror:
150 	uwsgi_log("unable to initialize SPDY settings buffers\n");
151 	exit(1);
152 #endif
153 }
154 
155 
156 
uwsgi_opt_http_to_https(char * opt,char * value,void * cr)157 void uwsgi_opt_http_to_https(char *opt, char *value, void *cr) {
158         struct uwsgi_corerouter *ucr = (struct uwsgi_corerouter *) cr;
159 
160         char *sock = uwsgi_str(value);
161         char *port = strchr(sock, ',');
162         if (port) {
163                 *port = '\0';
164                 port++;
165         }
166 
167         struct uwsgi_gateway_socket *ugs = uwsgi_new_gateway_socket(sock, ucr->name);
168 
169         // set context to the port
170         ugs->ctx = port;
171         // force SSL mode
172         ugs->mode = UWSGI_HTTP_FORCE_SSL;
173 
174         ucr->has_sockets++;
175 }
176 
hr_https_add_vars(struct http_session * hr,struct corerouter_peer * peer,struct uwsgi_buffer * out)177 int hr_https_add_vars(struct http_session *hr, struct corerouter_peer *peer, struct uwsgi_buffer *out) {
178 // HTTPS (adapted from nginx)
179         if (hr->session.ugs->mode == UWSGI_HTTP_SSL) {
180                 if (uwsgi_buffer_append_keyval(out, "HTTPS", 5, "on", 2)) return -1;
181 #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
182 			const char *servername = SSL_get_servername(hr->ssl, TLSEXT_NAMETYPE_host_name);
183                         if (servername && strlen(servername) <= 0xff) {
184 				peer->key_len = strlen(servername);
185                         	memcpy(peer->key, servername, peer->key_len) ;
186                         }
187 #endif
188                 hr->ssl_client_cert = SSL_get_peer_certificate(hr->ssl);
189                 if (hr->ssl_client_cert) {
190                         int client_cert_len;
191                         unsigned char *client_cert_der = NULL;
192                         client_cert_len = i2d_X509(hr->ssl_client_cert, &client_cert_der);
193                         if (client_cert_len < 0) return -1;
194 			int ret = uwsgi_buffer_append_keyval(out, "HTTPS_CLIENT_CERTIFICATE", 24, (char*)client_cert_der, client_cert_len);
195 			OPENSSL_free(client_cert_der);
196 			if (ret) return -1;
197 
198                         X509_NAME *name = X509_get_subject_name(hr->ssl_client_cert);
199                         if (name) {
200                                 hr->ssl_client_dn = X509_NAME_oneline(name, NULL, 0);
201                                 if (uwsgi_buffer_append_keyval(out, "HTTPS_DN", 8, hr->ssl_client_dn, strlen(hr->ssl_client_dn))) return -1;
202                         }
203                         if (uhttp.https_export_cert) {
204                         hr->ssl_bio = BIO_new(BIO_s_mem());
205                         if (hr->ssl_bio) {
206                                 if (PEM_write_bio_X509(hr->ssl_bio, hr->ssl_client_cert) > 0) {
207                                         size_t cc_len = BIO_pending(hr->ssl_bio);
208                                         hr->ssl_cc = uwsgi_malloc(cc_len);
209                                         BIO_read(hr->ssl_bio, hr->ssl_cc, cc_len);
210                                         if (uwsgi_buffer_append_keyval(out, "HTTPS_CC", 8, hr->ssl_cc, cc_len)) return -1;
211                                 }
212                         }
213                         }
214                 }
215         }
216         else if (hr->session.ugs->mode == UWSGI_HTTP_FORCE_SSL) {
217                 hr->force_https = 1;
218         }
219 
220 	return 0;
221 }
222 
hr_session_ssl_close(struct corerouter_session * cs)223 void hr_session_ssl_close(struct corerouter_session *cs) {
224 	hr_session_close(cs);
225 	struct http_session *hr = (struct http_session *) cs;
226 	if (hr->ssl_client_dn) {
227                 OPENSSL_free(hr->ssl_client_dn);
228         }
229 
230         if (hr->ssl_cc) {
231                 free(hr->ssl_cc);
232         }
233 
234         if (hr->ssl_bio) {
235                 BIO_free(hr->ssl_bio);
236         }
237 
238         if (hr->ssl_client_cert) {
239                 X509_free(hr->ssl_client_cert);
240         }
241 
242 #ifdef UWSGI_SPDY
243 	if (hr->spdy_ping) {
244 		uwsgi_buffer_destroy(hr->spdy_ping);
245 	}
246 	if (hr->spdy) {
247 		deflateEnd(&hr->spdy_z_in);
248 		deflateEnd(&hr->spdy_z_out);
249 	}
250 #endif
251 
252 	// clear the errors (otherwise they could be propagated)
253 	hr_ssl_clear_errors();
254         SSL_free(hr->ssl);
255 }
256 
hr_force_https(struct corerouter_peer * peer)257 int hr_force_https(struct corerouter_peer *peer) {
258 	struct corerouter_session *cs = peer->session;
259         struct http_session *hr = (struct http_session *) cs;
260 
261 	if (uwsgi_buffer_append(peer->in, "HTTP/1.1 301 Moved Permanently\r\nLocation: https://", 50)) return -1;
262 
263         char *colon = memchr(peer->key, ':', peer->key_len);
264         if (colon) {
265         	if (uwsgi_buffer_append(peer->in, peer->key, colon-peer->key)) return -1;
266         }
267         else {
268         	if (uwsgi_buffer_append(peer->in, peer->key, peer->key_len)) return -1;
269         }
270 
271         if (cs->ugs->ctx) {
272         	if (uwsgi_buffer_append(peer->in, ":", 1)) return -1;
273         	if (uwsgi_buffer_append(peer->in,cs->ugs->ctx, strlen(cs->ugs->ctx))) return -1;
274         }
275         if (uwsgi_buffer_append(peer->in, hr->request_uri, hr->request_uri_len)) return -1;
276         if (uwsgi_buffer_append(peer->in, "\r\n\r\n", 4)) return -1;
277 
278 	hr->session.wait_full_write = 1;
279         peer->session->main_peer->out = peer->in;
280         peer->session->main_peer->out_pos = 0;
281         cr_write_to_main(peer, hr->func_write);
282         return 0;
283 }
284 
hr_ssl_write(struct corerouter_peer * main_peer)285 ssize_t hr_ssl_write(struct corerouter_peer *main_peer) {
286         struct corerouter_session *cs = main_peer->session;
287         struct http_session *hr = (struct http_session *) cs;
288 
289 	hr_ssl_clear_errors();
290 
291         int ret = SSL_write(hr->ssl, main_peer->out->buf + main_peer->out_pos, main_peer->out->pos - main_peer->out_pos);
292         if (ret > 0) {
293                 main_peer->out_pos += ret;
294                 if (main_peer->out->pos == main_peer->out_pos) {
295 			// reset the buffer (if needed)
296 			main_peer->out->pos = 0;
297 			if (main_peer->session->wait_full_write) {
298                         	main_peer->session->wait_full_write = 0;
299                         	return 0;
300                 	}
301 			if (main_peer->session->connect_peer_after_write) {
302                         	cr_connect(main_peer->session->connect_peer_after_write, hr_instance_connected);
303                         	main_peer->session->connect_peer_after_write = NULL;
304                         	return ret;
305                 	}
306                         cr_reset_hooks(main_peer);
307 #ifdef UWSGI_SPDY
308 			if (hr->spdy) {
309 				return spdy_parse(main_peer);
310 			}
311 #endif
312                 }
313                 return ret;
314         }
315 
316         int err = SSL_get_error(hr->ssl, ret);
317 
318 	if (err == SSL_ERROR_ZERO_RETURN || err == 0) return 0;
319 
320         if (err == SSL_ERROR_WANT_READ) {
321                 cr_reset_hooks_and_read(main_peer, hr_ssl_write);
322                 return 1;
323         }
324 
325         else if (err == SSL_ERROR_WANT_WRITE) {
326                 cr_write_to_main(main_peer, hr_ssl_write);
327                 return 1;
328         }
329 
330         else if (err == SSL_ERROR_SYSCALL) {
331 		if (errno != 0)
332                 	uwsgi_cr_error(main_peer, "hr_ssl_write()");
333         }
334 
335         else if (err == SSL_ERROR_SSL && uwsgi.ssl_verbose) {
336                 ERR_print_errors_fp(stderr);
337         }
338 
339         return -1;
340 }
341 
hr_ssl_read(struct corerouter_peer * main_peer)342 ssize_t hr_ssl_read(struct corerouter_peer *main_peer) {
343         struct corerouter_session *cs = main_peer->session;
344         struct http_session *hr = (struct http_session *) cs;
345 
346 	hr_ssl_clear_errors();
347 
348         // try to always leave 4k available
349         if (uwsgi_buffer_ensure(main_peer->in, uwsgi.page_size)) return -1;
350         int ret = SSL_read(hr->ssl, main_peer->in->buf + main_peer->in->pos, main_peer->in->len - main_peer->in->pos);
351         if (ret > 0) {
352                 // fix the buffer
353                 main_peer->in->pos += ret;
354                 // check for pending data
355                 int ret2 = SSL_pending(hr->ssl);
356                 if (ret2 > 0) {
357                         if (uwsgi_buffer_fix(main_peer->in, main_peer->in->len + ret2 )) {
358                                 uwsgi_cr_log(main_peer, "cannot fix the buffer to %d\n", main_peer->in->len + ret2);
359                                 return -1;
360                         }
361                         if (SSL_read(hr->ssl, main_peer->in->buf + main_peer->in->pos, ret2) != ret2) {
362                                 uwsgi_cr_log(main_peer, "SSL_read() on %d bytes of pending data failed\n", ret2);
363                                 return -1;
364                         }
365                         // fix the buffer
366                         main_peer->in->pos += ret2;
367                 }
368 #ifdef UWSGI_SPDY
369                 if (hr->spdy) {
370                         //uwsgi_log("RUNNING THE SPDY PARSER FOR %d bytes\n", main_peer->in->pos);
371                         return spdy_parse(main_peer);
372                 }
373 #endif
374                 return http_parse(main_peer);
375         }
376 
377         int err = SSL_get_error(hr->ssl, ret);
378 
379 	if (err == SSL_ERROR_ZERO_RETURN || err == 0) return 0;
380 
381         if (err == SSL_ERROR_WANT_READ) {
382                 cr_reset_hooks_and_read(main_peer, hr_ssl_read);
383                 return 1;
384         }
385 
386         else if (err == SSL_ERROR_WANT_WRITE) {
387                 cr_write_to_main(main_peer, hr_ssl_read);
388                 return 1;
389         }
390 
391         else if (err == SSL_ERROR_SYSCALL) {
392 		if (errno != 0)
393                 	uwsgi_cr_error(main_peer, "hr_ssl_read()");
394         }
395 
396         else if (err == SSL_ERROR_SSL && uwsgi.ssl_verbose) {
397                 ERR_print_errors_fp(stderr);
398         }
399 
400         return -1;
401 }
402 
hr_ssl_shutdown(struct corerouter_peer * peer)403 ssize_t hr_ssl_shutdown(struct corerouter_peer *peer) {
404 	// ensure no hooks are set
405 	if (uwsgi_cr_set_hooks(peer, NULL, NULL)) return -1;
406 
407 	struct corerouter_session *cs = peer->session;
408         struct http_session *hr = (struct http_session *) cs;
409 
410 	hr_ssl_clear_errors();
411 
412 	int ret = SSL_shutdown(hr->ssl);
413 	int err = 0;
414 
415 	if (ret != 1 && ERR_peek_error()) {
416 		err = SSL_get_error(hr->ssl, ret);
417 	}
418 
419 	// no error, close the connection
420 	if (ret == 1 || err == 0 || err == SSL_ERROR_ZERO_RETURN) return 0;
421 
422 	if (err == SSL_ERROR_WANT_READ) {
423 		if (uwsgi_cr_set_hooks(peer, hr_ssl_shutdown, NULL)) return -1;
424                 return 1;
425         }
426 
427         else if (err == SSL_ERROR_WANT_WRITE) {
428 		if (uwsgi_cr_set_hooks(peer, NULL, hr_ssl_shutdown)) return -1;
429                 return 1;
430         }
431 
432         else if (err == SSL_ERROR_SYSCALL) {
433 		if (errno != 0)
434                 	uwsgi_cr_error(peer, "hr_ssl_shutdown()");
435         }
436 
437         else if (err == SSL_ERROR_SSL && uwsgi.ssl_verbose) {
438                 ERR_print_errors_fp(stderr);
439         }
440 
441         return -1;
442 }
443 
hr_setup_ssl(struct http_session * hr,struct uwsgi_gateway_socket * ugs)444 void hr_setup_ssl(struct http_session *hr, struct uwsgi_gateway_socket *ugs) {
445  	hr->ssl = SSL_new(ugs->ctx);
446         SSL_set_fd(hr->ssl, hr->session.main_peer->fd);
447         SSL_set_accept_state(hr->ssl);
448 #ifdef UWSGI_SPDY
449         SSL_set_ex_data(hr->ssl, uhttp.spdy_index, hr);
450 #endif
451         uwsgi_cr_set_hooks(hr->session.main_peer, hr_ssl_read, NULL);
452 	hr->session.main_peer->flush = hr_ssl_shutdown;
453         hr->session.close = hr_session_ssl_close;
454 	hr->func_write = hr_ssl_write;
455 }
456 
457 #endif
458