1 /*
2 * Copyright (C) 2013-2018 Nikos Mavrogiannopoulos
3 * Copyright (C) 2015 Red Hat
4 *
5 * This file is part of ocserv.
6 *
7 * ocserv is free software: you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * ocserv is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include <config.h>
22
23 #include <gnutls/gnutls.h>
24 #include <gnutls/crypto.h>
25 #include <gnutls/x509.h>
26 #include <errno.h>
27 #include <stdlib.h>
28 #include <stdarg.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <fcntl.h>
34 #include <unistd.h>
35 #include <limits.h>
36
37 #include <vpn.h>
38 #include <worker.h>
39 #include <tlslib.h>
40
41 #define HTML_404 "<html><body><h1>404 Not Found</h1></body></html>\r\n"
42
response_404(worker_st * ws,unsigned http_ver)43 int response_404(worker_st *ws, unsigned http_ver)
44 {
45 if (cstp_printf(ws, "HTTP/1.%u 404 Not found\r\n", http_ver) < 0 ||
46 cstp_printf(ws, "Content-length: %u\r\n", (unsigned)(sizeof(HTML_404) - 1)) < 0 ||
47 cstp_puts (ws, "Connection: close\r\n\r\n") < 0 ||
48 cstp_puts (ws, HTML_404) < 0)
49 return -1;
50 return 0;
51 }
52
send_headers(worker_st * ws,unsigned http_ver,const char * content_type,unsigned content_length)53 static int send_headers(worker_st *ws, unsigned http_ver, const char *content_type,
54 unsigned content_length)
55 {
56 if (cstp_printf(ws, "HTTP/1.%u 200 OK\r\n", http_ver) < 0 ||
57 cstp_puts (ws, "Connection: Keep-Alive\r\n") < 0 ||
58 cstp_printf(ws, "Content-Type: %s\r\n", content_type) < 0 ||
59 cstp_puts (ws, "X-Transcend-Version: 1\r\n") < 0 ||
60 cstp_printf(ws, "Content-Length: %u\r\n", content_length) < 0 ||
61 add_owasp_headers(ws) < 0 ||
62 cstp_puts (ws, "\r\n") < 0)
63 return -1;
64 return 0;
65 }
66
send_data(worker_st * ws,unsigned http_ver,const char * content_type,const char * data,int content_length)67 static int send_data(worker_st *ws, unsigned http_ver, const char *content_type,
68 const char *data, int content_length)
69 {
70 /* don't bother uncorking on error - the connection will be closed anyway */
71 cstp_cork(ws);
72 if (send_headers(ws, http_ver, content_type, content_length) < 0 ||
73 cstp_send(ws, data, content_length) < 0 ||
74 cstp_uncork(ws) < 0)
75 return -1;
76 return 0;
77 }
78
get_cert_handler(worker_st * ws,unsigned http_ver)79 int get_cert_handler(worker_st * ws, unsigned http_ver)
80 {
81 if (ws->conn_type != SOCK_TYPE_UNIX) { /* we have TLS */
82 const gnutls_datum_t *certs;
83 gnutls_datum_t out = {NULL, 0};
84 int ret;
85
86 oclog(ws, LOG_DEBUG, "requested server certificate");
87
88 certs = gnutls_certificate_get_ours(ws->session);
89 if (certs == NULL) {
90 return -1;
91 }
92
93 ret = gnutls_pem_base64_encode_alloc("CERTIFICATE", &certs[0], &out);
94 if (ret < 0)
95 return -1;
96
97 ret = send_data(ws, http_ver, "application/x-pem-file", (char*)out.data, out.size);
98 gnutls_free(out.data);
99
100 return ret;
101 } else {
102 return -1;
103 }
104 }
get_cert_der_handler(worker_st * ws,unsigned http_ver)105 int get_cert_der_handler(worker_st * ws, unsigned http_ver)
106 {
107 if (ws->conn_type != SOCK_TYPE_UNIX) { /* we have TLS */
108 const gnutls_datum_t *certs;
109
110 oclog(ws, LOG_DEBUG, "requested raw server certificate");
111
112 certs = gnutls_certificate_get_ours(ws->session);
113 if (certs == NULL) {
114 return -1;
115 }
116
117 return send_data(ws, http_ver, "application/pkix-cert", (char*)certs[0].data, certs[0].size);
118 } else {
119 return -1;
120 }
121 }
122
123
124 static
ca_handler(worker_st * ws,unsigned http_ver,unsigned der)125 int ca_handler(worker_st * ws, unsigned http_ver, unsigned der)
126 {
127 if (ws->conn_type != SOCK_TYPE_UNIX) { /* we have TLS */
128 const gnutls_datum_t *certs;
129 gnutls_datum_t out = {NULL, 0}, tmpca;
130 unsigned i;
131 int ret;
132 gnutls_x509_crt_t issuer = NULL, crt = NULL;
133
134 oclog(ws, LOG_DEBUG, "requested server CA");
135
136 certs = gnutls_certificate_get_ours(ws->session);
137 if (certs == NULL) {
138 oclog(ws, LOG_DEBUG, "could not obtain our cert");
139 return -1;
140 }
141
142 ret = gnutls_x509_crt_init(&crt);
143 if (ret < 0) {
144 oclog(ws, LOG_DEBUG, "could not initialize cert");
145 return -1;
146 }
147
148 ret = gnutls_x509_crt_init(&issuer);
149 if (ret < 0) {
150 oclog(ws, LOG_DEBUG, "could not initialize cert");
151 ret = -1;
152 goto cleanup;
153 }
154
155 ret = gnutls_x509_crt_import(crt, &certs[0], GNUTLS_X509_FMT_DER);
156 if (ret < 0) {
157 ret = -1;
158 oclog(ws, LOG_DEBUG, "could not import our cert");
159 goto cleanup;
160 }
161
162 for (i=0;i<8;i++) {
163 ret = gnutls_certificate_get_crt_raw(WSCREDS(ws)->xcred, i, 1, &tmpca);
164 if (ret < 0) {
165 goto cleanup;
166 }
167
168 ret = gnutls_x509_crt_import(issuer, &tmpca, GNUTLS_X509_FMT_DER);
169 if (ret < 0) {
170 ret = -1;
171 oclog(ws, LOG_DEBUG, "could not import issuer cert");
172 goto cleanup;
173 }
174
175 ret = gnutls_x509_crt_check_issuer(crt, issuer);
176 if (ret != 0) {
177 ret = gnutls_x509_crt_export2(issuer, der?GNUTLS_X509_FMT_DER:GNUTLS_X509_FMT_PEM, &out);
178 if (ret < 0) {
179 ret = -1;
180 oclog(ws, LOG_DEBUG, "could not export issuer of cert");
181 goto cleanup;
182 }
183 break;
184 }
185
186 gnutls_x509_crt_deinit(issuer);
187 issuer = NULL;
188 }
189
190 ret = send_data(ws, http_ver, "application/pkix-cert", (char*)out.data, out.size);
191
192 cleanup:
193 if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
194 oclog(ws, LOG_DEBUG, "could not get CA; does the server cert list contain the CA certificate?");
195 ret = -1;
196 }
197
198 if (crt)
199 gnutls_x509_crt_deinit(crt);
200 if (issuer)
201 gnutls_x509_crt_deinit(issuer);
202 gnutls_free(out.data);
203
204 return ret;
205 } else {
206 return -1;
207 }
208 }
209
get_ca_handler(worker_st * ws,unsigned http_ver)210 int get_ca_handler(worker_st * ws, unsigned http_ver)
211 {
212 return ca_handler(ws, http_ver, 0);
213 }
214
get_ca_der_handler(worker_st * ws,unsigned http_ver)215 int get_ca_der_handler(worker_st * ws, unsigned http_ver)
216 {
217 return ca_handler(ws, http_ver, 1);
218 }
219
220 #ifdef ANYCONNECT_CLIENT_COMPAT
get_config_handler(worker_st * ws,unsigned http_ver)221 int get_config_handler(worker_st *ws, unsigned http_ver)
222 {
223 int ret;
224 struct stat st;
225
226 oclog(ws, LOG_HTTP_DEBUG, "requested config: %s", ws->req.url);
227
228 cookie_authenticate_or_exit(ws);
229
230 if (ws->user_config->xml_config_file == NULL) {
231 oclog(ws, LOG_INFO, "requested config but no config file is set");
232 response_404(ws, http_ver);
233 return -1;
234 }
235
236 ret = stat(ws->user_config->xml_config_file, &st);
237 if (ret == -1) {
238 oclog(ws, LOG_INFO, "cannot load config file '%s'", ws->user_config->xml_config_file);
239 response_404(ws, http_ver);
240 return -1;
241 }
242
243 cstp_cork(ws);
244 if (send_headers(ws, http_ver, "text/xml", (unsigned)st.st_size) < 0 ||
245 cstp_uncork(ws) < 0)
246 return -1;
247
248 ret = cstp_send_file(ws, ws->user_config->xml_config_file);
249 if (ret < 0) {
250 oclog(ws, LOG_ERR, "error sending file '%s': %s", ws->user_config->xml_config_file, gnutls_strerror(ret));
251 return -1;
252 }
253
254 return 0;
255 }
256
257 #define VPN_VERSION "0,0,0000\n"
258 #define XML_START "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<vpn rev=\"1.0\">\n</vpn>\n"
259
get_string_handler(worker_st * ws,unsigned http_ver)260 int get_string_handler(worker_st *ws, unsigned http_ver)
261 {
262 oclog(ws, LOG_HTTP_DEBUG, "requested fixed string: %s", ws->req.url);
263 if (!strcmp(ws->req.url, "/1/binaries/update.txt")) {
264 return send_data(ws, http_ver, "text/xml", VPN_VERSION,
265 sizeof(VPN_VERSION) - 1);
266 } else {
267 return send_data(ws, http_ver, "text/xml", XML_START,
268 sizeof(XML_START) - 1);
269 }
270 }
271
272 #define SH_SCRIPT "#!/bin/sh\n\n" \
273 "exit 0"
274
get_dl_handler(worker_st * ws,unsigned http_ver)275 int get_dl_handler(worker_st *ws, unsigned http_ver)
276 {
277 oclog(ws, LOG_HTTP_DEBUG, "requested downloader: %s", ws->req.url);
278 return send_data(ws, http_ver, "application/x-shellscript", SH_SCRIPT,
279 sizeof(SH_SCRIPT) - 1);
280 }
281
282 #define EMPTY_MSG "<html></html>\n"
283
get_empty_handler(worker_st * ws,unsigned http_ver)284 int get_empty_handler(worker_st *ws, unsigned http_ver)
285 {
286 return send_data(ws, http_ver, "text/html", EMPTY_MSG,
287 sizeof(EMPTY_MSG) - 1);
288 }
289
290 #endif
291
292