ah: require parsing complete before detach
[platform/upstream/libwebsockets.git] / lib / ssl-server.c
1 /*
2  * libwebsockets - small server side websockets and web server implementation
3  *
4  * Copyright (C) 2010-2016 Andy Green <andy@warmcat.com>
5  *
6  *  This library is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU Lesser General Public
8  *  License as published by the Free Software Foundation:
9  *  version 2.1 of the License.
10  *
11  *  This library is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  *  Lesser General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Lesser General Public
17  *  License along with this library; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19  *  MA  02110-1301  USA
20  */
21
22 #include "private-libwebsockets.h"
23
24 extern int openssl_websocket_private_data_index,
25     openssl_SSL_CTX_private_data_index;
26
27 extern void
28 lws_ssl_bind_passphrase(SSL_CTX *ssl_ctx, struct lws_context_creation_info *info);
29
30 #if !defined(LWS_WITH_ESP32)
31 static int
32 OpenSSL_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)
33 {
34         SSL *ssl;
35         int n;
36         struct lws *wsi;
37
38         ssl = X509_STORE_CTX_get_ex_data(x509_ctx,
39                 SSL_get_ex_data_X509_STORE_CTX_idx());
40
41         /*
42          * !!! nasty openssl requires the index to come as a library-scope
43          * static
44          */
45         wsi = SSL_get_ex_data(ssl, openssl_websocket_private_data_index);
46
47         n = wsi->vhost->protocols[0].callback(wsi,
48                         LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION,
49                                            x509_ctx, ssl, preverify_ok);
50
51         /* convert return code from 0 = OK to 1 = OK */
52         return !n;
53 }
54 #endif
55
56 static int
57 lws_context_ssl_init_ecdh(struct lws_vhost *vhost)
58 {
59 #ifdef LWS_SSL_SERVER_WITH_ECDH_CERT
60         EC_KEY *EC_key = NULL;
61         EVP_PKEY *pkey;
62         int KeyType;
63         X509 *x;
64
65         if (!lws_check_opt(vhost->context->options, LWS_SERVER_OPTION_SSL_ECDH))
66                 return 0;
67
68         lwsl_notice(" Using ECDH certificate support\n");
69
70         /* Get X509 certificate from ssl context */
71         x = sk_X509_value(vhost->ssl_ctx->extra_certs, 0);
72         if (!x) {
73                 lwsl_err("%s: x is NULL\n", __func__);
74                 return 1;
75         }
76         /* Get the public key from certificate */
77         pkey = X509_get_pubkey(x);
78         if (!pkey) {
79                 lwsl_err("%s: pkey is NULL\n", __func__);
80
81                 return 1;
82         }
83         /* Get the key type */
84         KeyType = EVP_PKEY_type(pkey->type);
85
86         if (EVP_PKEY_EC != KeyType) {
87                 lwsl_notice("Key type is not EC\n");
88                 return 0;
89         }
90         /* Get the key */
91         EC_key = EVP_PKEY_get1_EC_KEY(pkey);
92         /* Set ECDH parameter */
93         if (!EC_key) {
94                 lwsl_err("%s: ECDH key is NULL \n", __func__);
95                 return 1;
96         }
97         SSL_CTX_set_tmp_ecdh(vhost->ssl_ctx, EC_key);
98         EC_KEY_free(EC_key);
99 #endif
100         return 0;
101 }
102
103 static int
104 lws_context_ssl_init_ecdh_curve(struct lws_context_creation_info *info,
105                                 struct lws_vhost *vhost)
106 {
107 #ifdef LWS_HAVE_OPENSSL_ECDH_H
108         EC_KEY *ecdh;
109         int ecdh_nid;
110         const char *ecdh_curve = "prime256v1";
111
112         if (info->ecdh_curve)
113                 ecdh_curve = info->ecdh_curve;
114
115         ecdh_nid = OBJ_sn2nid(ecdh_curve);
116         if (NID_undef == ecdh_nid) {
117                 lwsl_err("SSL: Unknown curve name '%s'", ecdh_curve);
118                 return 1;
119         }
120
121         ecdh = EC_KEY_new_by_curve_name(ecdh_nid);
122         if (NULL == ecdh) {
123                 lwsl_err("SSL: Unable to create curve '%s'", ecdh_curve);
124                 return 1;
125         }
126         SSL_CTX_set_tmp_ecdh(vhost->ssl_ctx, ecdh);
127         EC_KEY_free(ecdh);
128
129         SSL_CTX_set_options(vhost->ssl_ctx, SSL_OP_SINGLE_ECDH_USE);
130
131         lwsl_notice(" SSL ECDH curve '%s'\n", ecdh_curve);
132 #else
133 #if !defined(LWS_WITH_ESP32)
134         lwsl_notice(" OpenSSL doesn't support ECDH\n");
135 #endif
136 #endif
137         return 0;
138 }
139
140 #ifndef OPENSSL_NO_TLSEXT
141 static int
142 lws_ssl_server_name_cb(SSL *ssl, int *ad, void *arg)
143 {
144         struct lws_context *context;
145         struct lws_vhost *vhost, *vh;
146         const char *servername;
147         int port;
148
149         if (!ssl)
150                 return SSL_TLSEXT_ERR_NOACK;
151
152         context = (struct lws_context *)SSL_CTX_get_ex_data(
153                                         SSL_get_SSL_CTX(ssl),
154                                         openssl_SSL_CTX_private_data_index);
155
156         /*
157          * We can only get ssl accepted connections by using a vhost's ssl_ctx
158          * find out which listening one took us and only match vhosts on the
159          * same port.
160          */
161         vh = context->vhost_list;
162         while (vh) {
163                 if (vh->ssl_ctx == SSL_get_SSL_CTX(ssl))
164                         break;
165                 vh = vh->vhost_next;
166         }
167
168         assert(vh); /* we cannot get an ssl without using a vhost ssl_ctx */
169         port = vh->listen_port;
170
171         servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
172
173         if (servername) {
174                 vhost = lws_select_vhost(context, port, servername);
175                 if (vhost) {
176                         lwsl_debug("SNI: Found: %s (port %d)\n",
177                                    servername, port);
178                         SSL_set_SSL_CTX(ssl, vhost->ssl_ctx);
179                         return SSL_TLSEXT_ERR_OK;
180                 }
181                 lwsl_err("SNI: Unknown ServerName: %s\n", servername);
182         }
183
184         return SSL_TLSEXT_ERR_OK;
185 }
186 #endif
187
188 LWS_VISIBLE int
189 lws_context_init_server_ssl(struct lws_context_creation_info *info,
190                             struct lws_vhost *vhost)
191 {
192         struct lws_context *context = vhost->context;
193         struct lws wsi;
194         unsigned long error;
195         int n;
196
197         if (!lws_check_opt(info->options, LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT)) {
198                 vhost->use_ssl = 0;
199                 return 0;
200         }
201         if (info->port != CONTEXT_PORT_NO_LISTEN) {
202
203                 vhost->use_ssl = info->ssl_cert_filepath != NULL;
204
205                 if (vhost->use_ssl && info->ssl_cipher_list)
206                         lwsl_notice(" SSL ciphers: '%s'\n", info->ssl_cipher_list);
207
208                 if (vhost->use_ssl)
209                         lwsl_notice(" Using SSL mode\n");
210                 else
211                         lwsl_notice(" Using non-SSL mode\n");
212         }
213
214         /*
215          * give him a fake wsi with context + vhost set, so he can use
216          * lws_get_context() in the callback
217          */
218         memset(&wsi, 0, sizeof(wsi));
219         wsi.vhost = vhost;
220         wsi.context = context;
221
222         (void)n;
223         (void)error;
224
225         /*
226          * Firefox insists on SSLv23 not SSLv3
227          * Konq disables SSLv2 by default now, SSLv23 works
228          *
229          * SSLv23_server_method() is the openssl method for "allow all TLS
230          * versions", compared to e.g. TLSv1_2_server_method() which only allows
231          * tlsv1.2. Unwanted versions must be disabled using SSL_CTX_set_options()
232          */
233 #if !defined(LWS_WITH_ESP32)
234         {
235                 SSL_METHOD *method;
236
237                 method = (SSL_METHOD *)SSLv23_server_method();
238                 if (!method) {
239                         error = ERR_get_error();
240                         lwsl_err("problem creating ssl method %lu: %s\n",
241                                         error, ERR_error_string(error,
242                                               (char *)context->pt[0].serv_buf));
243                         return 1;
244                 }
245                 vhost->ssl_ctx = SSL_CTX_new(method);   /* create context */
246                 if (!vhost->ssl_ctx) {
247                         error = ERR_get_error();
248                         lwsl_err("problem creating ssl context %lu: %s\n",
249                                         error, ERR_error_string(error,
250                                               (char *)context->pt[0].serv_buf));
251                         return 1;
252                 }
253         }
254 #else
255         {
256                 const SSL_METHOD *method = TLSv1_2_server_method();
257
258                 vhost->ssl_ctx = SSL_CTX_new(method);   /* create context */
259                 if (!vhost->ssl_ctx) {
260                         lwsl_err("problem creating ssl context\n");
261                         return 1;
262                 }
263
264         }
265 #endif
266 #if !defined(LWS_WITH_ESP32)
267
268         /* associate the lws context with the SSL_CTX */
269
270         SSL_CTX_set_ex_data(vhost->ssl_ctx,
271                         openssl_SSL_CTX_private_data_index, (char *)vhost->context);
272         /* Disable SSLv2 and SSLv3 */
273         SSL_CTX_set_options(vhost->ssl_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
274 #ifdef SSL_OP_NO_COMPRESSION
275         SSL_CTX_set_options(vhost->ssl_ctx, SSL_OP_NO_COMPRESSION);
276 #endif
277         SSL_CTX_set_options(vhost->ssl_ctx, SSL_OP_SINGLE_DH_USE);
278         SSL_CTX_set_options(vhost->ssl_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
279
280         if (info->ssl_cipher_list)
281                 SSL_CTX_set_cipher_list(vhost->ssl_ctx,
282                                                 info->ssl_cipher_list);
283 #endif
284
285         /* as a server, are we requiring clients to identify themselves? */
286
287         if (lws_check_opt(info->options,
288                           LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT)) {
289                 int verify_options = SSL_VERIFY_PEER;
290
291                 if (!lws_check_opt(info->options,
292                                    LWS_SERVER_OPTION_PEER_CERT_NOT_REQUIRED))
293                         verify_options |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
294
295 #if !defined(LWS_WITH_ESP32)
296                 SSL_CTX_set_session_id_context(vhost->ssl_ctx,
297                                 (unsigned char *)context, sizeof(void *));
298
299                 /* absolutely require the client cert */
300
301                 SSL_CTX_set_verify(vhost->ssl_ctx,
302                        verify_options, OpenSSL_verify_callback);
303 #endif
304         }
305
306 #ifndef OPENSSL_NO_TLSEXT
307         SSL_CTX_set_tlsext_servername_callback(vhost->ssl_ctx,
308                                                lws_ssl_server_name_cb);
309 #endif
310
311         /*
312          * give user code a chance to load certs into the server
313          * allowing it to verify incoming client certs
314          */
315 #if !defined(LWS_WITH_ESP32)
316         if (info->ssl_ca_filepath &&
317             !SSL_CTX_load_verify_locations(vhost->ssl_ctx,
318                                            info->ssl_ca_filepath, NULL)) {
319                 lwsl_err("%s: SSL_CTX_load_verify_locations unhappy\n", __func__);
320         }
321 #endif
322         if (vhost->use_ssl) {
323                 if (lws_context_ssl_init_ecdh_curve(info, vhost))
324                         return -1;
325
326                 vhost->protocols[0].callback(&wsi,
327                         LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS,
328                         vhost->ssl_ctx, NULL, 0);
329         }
330
331         if (lws_check_opt(info->options, LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT))
332                 /* Normally SSL listener rejects non-ssl, optionally allow */
333                 vhost->allow_non_ssl_on_ssl_port = 1;
334
335         if (info->ssl_options_set)
336                 SSL_CTX_set_options(vhost->ssl_ctx, info->ssl_options_set);
337
338 /* SSL_clear_options introduced in 0.9.8m */
339 #if (OPENSSL_VERSION_NUMBER >= 0x009080df) && !defined(USE_WOLFSSL)
340         if (info->ssl_options_clear)
341                 SSL_CTX_clear_options(vhost->ssl_ctx, info->ssl_options_clear);
342 #endif
343
344         lwsl_info(" SSL options 0x%lX\n",
345                     SSL_CTX_get_options(vhost->ssl_ctx));
346
347         if (vhost->use_ssl) {
348                 /* openssl init for server sockets */
349 #if !defined(LWS_WITH_ESP32)
350                 /* set the local certificate from CertFile */
351                 n = SSL_CTX_use_certificate_chain_file(vhost->ssl_ctx,
352                                         info->ssl_cert_filepath);
353                 if (n != 1) {
354                         error = ERR_get_error();
355                         lwsl_err("problem getting cert '%s' %lu: %s\n",
356                                 info->ssl_cert_filepath,
357                                 error,
358                                 ERR_error_string(error,
359                                               (char *)context->pt[0].serv_buf));
360                         return 1;
361                 }
362                 lws_ssl_bind_passphrase(vhost->ssl_ctx, info);
363 #else
364                 uint8_t *p;
365                 lws_filepos_t flen;
366                 int err;
367
368                 if (alloc_pem_to_der_file(vhost->context, info->ssl_cert_filepath, &p,
369                                                 &flen)) {
370                         lwsl_err("couldn't find cert file %s\n",
371                                  info->ssl_cert_filepath);
372
373                         return 1;
374                 }
375                 err = SSL_CTX_use_certificate_ASN1(vhost->ssl_ctx, flen, p);
376                 if (!err) {
377                         lwsl_err("Problem loading cert\n");
378                         return 1;
379                 }
380
381                 if (alloc_pem_to_der_file(vhost->context,
382                                info->ssl_private_key_filepath, &p, &flen)) {
383                         lwsl_err("couldn't find cert file %s\n",
384                                  info->ssl_cert_filepath);
385
386                         return 1;
387                 }
388                 err = SSL_CTX_use_PrivateKey_ASN1(0, vhost->ssl_ctx, p, flen);
389                 if (!err) {
390                         lwsl_err("Problem loading key\n");
391
392                         return 1;
393                 }
394
395 //              free(p);
396 #endif
397                 if (info->ssl_private_key_filepath != NULL) {
398 #if !defined(LWS_WITH_ESP32)
399                         /* set the private key from KeyFile */
400                         if (SSL_CTX_use_PrivateKey_file(vhost->ssl_ctx,
401                                      info->ssl_private_key_filepath,
402                                                        SSL_FILETYPE_PEM) != 1) {
403                                 error = ERR_get_error();
404                                 lwsl_err("ssl problem getting key '%s' %lu: %s\n",
405                                          info->ssl_private_key_filepath, error,
406                                          ERR_error_string(error,
407                                               (char *)context->pt[0].serv_buf));
408                                 return 1;
409                         }
410 #endif
411                 } else
412                         if (vhost->protocols[0].callback(&wsi,
413                                 LWS_CALLBACK_OPENSSL_CONTEXT_REQUIRES_PRIVATE_KEY,
414                                 vhost->ssl_ctx, NULL, 0)) {
415                                 lwsl_err("ssl private key not set\n");
416
417                                 return 1;
418                         }
419 #if !defined(LWS_WITH_ESP32)
420                 /* verify private key */
421                 if (!SSL_CTX_check_private_key(vhost->ssl_ctx)) {
422                         lwsl_err("Private SSL key doesn't match cert\n");
423                         return 1;
424                 }
425 #endif
426                 if (lws_context_ssl_init_ecdh(vhost))
427                         return 1;
428
429                 /*
430                  * SSL is happy and has a cert it's content with
431                  * If we're supporting HTTP2, initialize that
432                  */
433
434                 lws_context_init_http2_ssl(vhost);
435         }
436
437         return 0;
438 }
439