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