1*1c60b9acSAndroid Build Coastguard Worker /*
2*1c60b9acSAndroid Build Coastguard Worker * libwebsockets - small server side websockets and web server implementation
3*1c60b9acSAndroid Build Coastguard Worker *
4*1c60b9acSAndroid Build Coastguard Worker * Copyright (C) 2010 - 2021 Andy Green <[email protected]>
5*1c60b9acSAndroid Build Coastguard Worker *
6*1c60b9acSAndroid Build Coastguard Worker * Permission is hereby granted, free of charge, to any person obtaining a copy
7*1c60b9acSAndroid Build Coastguard Worker * of this software and associated documentation files (the "Software"), to
8*1c60b9acSAndroid Build Coastguard Worker * deal in the Software without restriction, including without limitation the
9*1c60b9acSAndroid Build Coastguard Worker * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10*1c60b9acSAndroid Build Coastguard Worker * sell copies of the Software, and to permit persons to whom the Software is
11*1c60b9acSAndroid Build Coastguard Worker * furnished to do so, subject to the following conditions:
12*1c60b9acSAndroid Build Coastguard Worker *
13*1c60b9acSAndroid Build Coastguard Worker * The above copyright notice and this permission notice shall be included in
14*1c60b9acSAndroid Build Coastguard Worker * all copies or substantial portions of the Software.
15*1c60b9acSAndroid Build Coastguard Worker *
16*1c60b9acSAndroid Build Coastguard Worker * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17*1c60b9acSAndroid Build Coastguard Worker * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18*1c60b9acSAndroid Build Coastguard Worker * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19*1c60b9acSAndroid Build Coastguard Worker * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20*1c60b9acSAndroid Build Coastguard Worker * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21*1c60b9acSAndroid Build Coastguard Worker * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22*1c60b9acSAndroid Build Coastguard Worker * IN THE SOFTWARE.
23*1c60b9acSAndroid Build Coastguard Worker */
24*1c60b9acSAndroid Build Coastguard Worker
25*1c60b9acSAndroid Build Coastguard Worker #include "private-lib-core.h"
26*1c60b9acSAndroid Build Coastguard Worker #include "private-lib-tls-mbedtls.h"
27*1c60b9acSAndroid Build Coastguard Worker
28*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_WITH_TLS_JIT_TRUST)
29*1c60b9acSAndroid Build Coastguard Worker
30*1c60b9acSAndroid Build Coastguard Worker /*
31*1c60b9acSAndroid Build Coastguard Worker * We get called for each peer certificate that was provided in turn.
32*1c60b9acSAndroid Build Coastguard Worker *
33*1c60b9acSAndroid Build Coastguard Worker * Our job is just to collect the AKID and SKIDs into ssl->kid_chain, and walk
34*1c60b9acSAndroid Build Coastguard Worker * later at verification result time if it failed.
35*1c60b9acSAndroid Build Coastguard Worker *
36*1c60b9acSAndroid Build Coastguard Worker * None of these should be trusted, even if a misconfigured server sends us
37*1c60b9acSAndroid Build Coastguard Worker * his root CA.
38*1c60b9acSAndroid Build Coastguard Worker */
39*1c60b9acSAndroid Build Coastguard Worker
40*1c60b9acSAndroid Build Coastguard Worker static int
lws_mbedtls_client_verify_callback(SSL * ssl,mbedtls_x509_crt * x509)41*1c60b9acSAndroid Build Coastguard Worker lws_mbedtls_client_verify_callback(SSL *ssl, mbedtls_x509_crt *x509)
42*1c60b9acSAndroid Build Coastguard Worker {
43*1c60b9acSAndroid Build Coastguard Worker union lws_tls_cert_info_results ci;
44*1c60b9acSAndroid Build Coastguard Worker
45*1c60b9acSAndroid Build Coastguard Worker /* we reached the max we can hold? */
46*1c60b9acSAndroid Build Coastguard Worker
47*1c60b9acSAndroid Build Coastguard Worker if (ssl->kid_chain.count == LWS_ARRAY_SIZE(ssl->kid_chain.akid))
48*1c60b9acSAndroid Build Coastguard Worker return 0;
49*1c60b9acSAndroid Build Coastguard Worker
50*1c60b9acSAndroid Build Coastguard Worker /* if not, stash the SKID and AKID into the next kid slot */
51*1c60b9acSAndroid Build Coastguard Worker
52*1c60b9acSAndroid Build Coastguard Worker if (!lws_tls_mbedtls_cert_info(x509, LWS_TLS_CERT_INFO_SUBJECT_KEY_ID,
53*1c60b9acSAndroid Build Coastguard Worker &ci, 0))
54*1c60b9acSAndroid Build Coastguard Worker lws_tls_kid_copy(&ci,
55*1c60b9acSAndroid Build Coastguard Worker &ssl->kid_chain.skid[ssl->kid_chain.count]);
56*1c60b9acSAndroid Build Coastguard Worker
57*1c60b9acSAndroid Build Coastguard Worker if (!lws_tls_mbedtls_cert_info(x509, LWS_TLS_CERT_INFO_AUTHORITY_KEY_ID,
58*1c60b9acSAndroid Build Coastguard Worker &ci, 0))
59*1c60b9acSAndroid Build Coastguard Worker lws_tls_kid_copy(&ci,
60*1c60b9acSAndroid Build Coastguard Worker &ssl->kid_chain.akid[ssl->kid_chain.count]);
61*1c60b9acSAndroid Build Coastguard Worker
62*1c60b9acSAndroid Build Coastguard Worker ssl->kid_chain.count++;
63*1c60b9acSAndroid Build Coastguard Worker
64*1c60b9acSAndroid Build Coastguard Worker // lwsl_notice("%s: %u\n", __func__, ssl->kid_chain.count);
65*1c60b9acSAndroid Build Coastguard Worker
66*1c60b9acSAndroid Build Coastguard Worker return 0;
67*1c60b9acSAndroid Build Coastguard Worker }
68*1c60b9acSAndroid Build Coastguard Worker
69*1c60b9acSAndroid Build Coastguard Worker #endif
70*1c60b9acSAndroid Build Coastguard Worker
71*1c60b9acSAndroid Build Coastguard Worker int
lws_ssl_client_bio_create(struct lws * wsi)72*1c60b9acSAndroid Build Coastguard Worker lws_ssl_client_bio_create(struct lws *wsi)
73*1c60b9acSAndroid Build Coastguard Worker {
74*1c60b9acSAndroid Build Coastguard Worker char hostname[128], *p;
75*1c60b9acSAndroid Build Coastguard Worker const char *alpn_comma = wsi->a.context->tls.alpn_default;
76*1c60b9acSAndroid Build Coastguard Worker struct alpn_ctx protos;
77*1c60b9acSAndroid Build Coastguard Worker int fl = SSL_VERIFY_PEER;
78*1c60b9acSAndroid Build Coastguard Worker
79*1c60b9acSAndroid Build Coastguard Worker if (wsi->stash)
80*1c60b9acSAndroid Build Coastguard Worker lws_strncpy(hostname, wsi->stash->cis[CIS_HOST], sizeof(hostname));
81*1c60b9acSAndroid Build Coastguard Worker else
82*1c60b9acSAndroid Build Coastguard Worker if (lws_hdr_copy(wsi, hostname, sizeof(hostname),
83*1c60b9acSAndroid Build Coastguard Worker _WSI_TOKEN_CLIENT_HOST) <= 0) {
84*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: Unable to get hostname\n", __func__);
85*1c60b9acSAndroid Build Coastguard Worker
86*1c60b9acSAndroid Build Coastguard Worker return -1;
87*1c60b9acSAndroid Build Coastguard Worker }
88*1c60b9acSAndroid Build Coastguard Worker
89*1c60b9acSAndroid Build Coastguard Worker /*
90*1c60b9acSAndroid Build Coastguard Worker * remove any :port part on the hostname... necessary for network
91*1c60b9acSAndroid Build Coastguard Worker * connection but typical certificates do not contain it
92*1c60b9acSAndroid Build Coastguard Worker */
93*1c60b9acSAndroid Build Coastguard Worker p = hostname;
94*1c60b9acSAndroid Build Coastguard Worker while (*p) {
95*1c60b9acSAndroid Build Coastguard Worker if (*p == ':') {
96*1c60b9acSAndroid Build Coastguard Worker *p = '\0';
97*1c60b9acSAndroid Build Coastguard Worker break;
98*1c60b9acSAndroid Build Coastguard Worker }
99*1c60b9acSAndroid Build Coastguard Worker p++;
100*1c60b9acSAndroid Build Coastguard Worker }
101*1c60b9acSAndroid Build Coastguard Worker
102*1c60b9acSAndroid Build Coastguard Worker wsi->tls.ssl = SSL_new(wsi->a.vhost->tls.ssl_client_ctx);
103*1c60b9acSAndroid Build Coastguard Worker if (!wsi->tls.ssl) {
104*1c60b9acSAndroid Build Coastguard Worker lwsl_info("%s: SSL_new() failed\n", __func__);
105*1c60b9acSAndroid Build Coastguard Worker return -1;
106*1c60b9acSAndroid Build Coastguard Worker }
107*1c60b9acSAndroid Build Coastguard Worker
108*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_WITH_TLS_SESSIONS)
109*1c60b9acSAndroid Build Coastguard Worker if (!(wsi->a.vhost->options & LWS_SERVER_OPTION_DISABLE_TLS_SESSION_CACHE))
110*1c60b9acSAndroid Build Coastguard Worker lws_tls_reuse_session(wsi);
111*1c60b9acSAndroid Build Coastguard Worker #endif
112*1c60b9acSAndroid Build Coastguard Worker
113*1c60b9acSAndroid Build Coastguard Worker if (wsi->a.vhost->tls.ssl_info_event_mask)
114*1c60b9acSAndroid Build Coastguard Worker SSL_set_info_callback(wsi->tls.ssl, lws_ssl_info_callback);
115*1c60b9acSAndroid Build Coastguard Worker
116*1c60b9acSAndroid Build Coastguard Worker if (!(wsi->tls.use_ssl & LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK)) {
117*1c60b9acSAndroid Build Coastguard Worker X509_VERIFY_PARAM *param = SSL_get0_param(wsi->tls.ssl);
118*1c60b9acSAndroid Build Coastguard Worker /* Enable automatic hostname checks */
119*1c60b9acSAndroid Build Coastguard Worker // X509_VERIFY_PARAM_set_hostflags(param,
120*1c60b9acSAndroid Build Coastguard Worker // X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
121*1c60b9acSAndroid Build Coastguard Worker lwsl_info("%s: setting hostname %s\n", __func__, hostname);
122*1c60b9acSAndroid Build Coastguard Worker if (X509_VERIFY_PARAM_set1_host(param, hostname, 0) != 1)
123*1c60b9acSAndroid Build Coastguard Worker return -1;
124*1c60b9acSAndroid Build Coastguard Worker }
125*1c60b9acSAndroid Build Coastguard Worker
126*1c60b9acSAndroid Build Coastguard Worker if (wsi->a.vhost->tls.alpn)
127*1c60b9acSAndroid Build Coastguard Worker alpn_comma = wsi->a.vhost->tls.alpn;
128*1c60b9acSAndroid Build Coastguard Worker
129*1c60b9acSAndroid Build Coastguard Worker if (wsi->stash) {
130*1c60b9acSAndroid Build Coastguard Worker lws_strncpy(hostname, wsi->stash->cis[CIS_HOST],
131*1c60b9acSAndroid Build Coastguard Worker sizeof(hostname));
132*1c60b9acSAndroid Build Coastguard Worker if (wsi->stash->cis[CIS_ALPN])
133*1c60b9acSAndroid Build Coastguard Worker alpn_comma = wsi->stash->cis[CIS_ALPN];
134*1c60b9acSAndroid Build Coastguard Worker } else {
135*1c60b9acSAndroid Build Coastguard Worker if (lws_hdr_copy(wsi, hostname, sizeof(hostname),
136*1c60b9acSAndroid Build Coastguard Worker _WSI_TOKEN_CLIENT_ALPN) > 0)
137*1c60b9acSAndroid Build Coastguard Worker alpn_comma = hostname;
138*1c60b9acSAndroid Build Coastguard Worker }
139*1c60b9acSAndroid Build Coastguard Worker
140*1c60b9acSAndroid Build Coastguard Worker lwsl_info("%s: %s: client conn sending ALPN list '%s'\n",
141*1c60b9acSAndroid Build Coastguard Worker __func__, lws_wsi_tag(wsi), alpn_comma);
142*1c60b9acSAndroid Build Coastguard Worker
143*1c60b9acSAndroid Build Coastguard Worker protos.len = (uint8_t)lws_alpn_comma_to_openssl(alpn_comma, protos.data,
144*1c60b9acSAndroid Build Coastguard Worker sizeof(protos.data) - 1);
145*1c60b9acSAndroid Build Coastguard Worker
146*1c60b9acSAndroid Build Coastguard Worker /* with mbedtls, protos is not pointed to after exit from this call */
147*1c60b9acSAndroid Build Coastguard Worker SSL_set_alpn_select_cb(wsi->tls.ssl, &protos);
148*1c60b9acSAndroid Build Coastguard Worker
149*1c60b9acSAndroid Build Coastguard Worker if (wsi->flags & LCCSCF_ALLOW_SELFSIGNED) {
150*1c60b9acSAndroid Build Coastguard Worker lwsl_notice("%s: allowing selfsigned\n", __func__);
151*1c60b9acSAndroid Build Coastguard Worker fl = SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
152*1c60b9acSAndroid Build Coastguard Worker }
153*1c60b9acSAndroid Build Coastguard Worker
154*1c60b9acSAndroid Build Coastguard Worker if (wsi->flags & LCCSCF_ALLOW_INSECURE)
155*1c60b9acSAndroid Build Coastguard Worker fl = SSL_VERIFY_NONE;
156*1c60b9acSAndroid Build Coastguard Worker
157*1c60b9acSAndroid Build Coastguard Worker /*
158*1c60b9acSAndroid Build Coastguard Worker * use server name indication (SNI), if supported,
159*1c60b9acSAndroid Build Coastguard Worker * when establishing connection
160*1c60b9acSAndroid Build Coastguard Worker */
161*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_WITH_TLS_JIT_TRUST)
162*1c60b9acSAndroid Build Coastguard Worker SSL_set_verify(wsi->tls.ssl, SSL_VERIFY_PEER,
163*1c60b9acSAndroid Build Coastguard Worker lws_mbedtls_client_verify_callback);
164*1c60b9acSAndroid Build Coastguard Worker (void)fl;
165*1c60b9acSAndroid Build Coastguard Worker #else
166*1c60b9acSAndroid Build Coastguard Worker SSL_set_verify(wsi->tls.ssl, fl, NULL);
167*1c60b9acSAndroid Build Coastguard Worker #endif
168*1c60b9acSAndroid Build Coastguard Worker
169*1c60b9acSAndroid Build Coastguard Worker SSL_set_fd(wsi->tls.ssl, (int)wsi->desc.sockfd);
170*1c60b9acSAndroid Build Coastguard Worker
171*1c60b9acSAndroid Build Coastguard Worker if (wsi->sys_tls_client_cert) {
172*1c60b9acSAndroid Build Coastguard Worker lws_system_blob_t *b = lws_system_get_blob(wsi->a.context,
173*1c60b9acSAndroid Build Coastguard Worker LWS_SYSBLOB_TYPE_CLIENT_CERT_DER,
174*1c60b9acSAndroid Build Coastguard Worker wsi->sys_tls_client_cert - 1);
175*1c60b9acSAndroid Build Coastguard Worker const uint8_t *pem_data = NULL;
176*1c60b9acSAndroid Build Coastguard Worker uint8_t *data = NULL;
177*1c60b9acSAndroid Build Coastguard Worker lws_filepos_t flen;
178*1c60b9acSAndroid Build Coastguard Worker size_t size;
179*1c60b9acSAndroid Build Coastguard Worker int err = 0;
180*1c60b9acSAndroid Build Coastguard Worker
181*1c60b9acSAndroid Build Coastguard Worker if (!b)
182*1c60b9acSAndroid Build Coastguard Worker goto no_client_cert;
183*1c60b9acSAndroid Build Coastguard Worker
184*1c60b9acSAndroid Build Coastguard Worker /*
185*1c60b9acSAndroid Build Coastguard Worker * Set up the per-connection client cert
186*1c60b9acSAndroid Build Coastguard Worker */
187*1c60b9acSAndroid Build Coastguard Worker
188*1c60b9acSAndroid Build Coastguard Worker size = lws_system_blob_get_size(b);
189*1c60b9acSAndroid Build Coastguard Worker if (!size)
190*1c60b9acSAndroid Build Coastguard Worker goto no_client_cert;
191*1c60b9acSAndroid Build Coastguard Worker
192*1c60b9acSAndroid Build Coastguard Worker if (lws_system_blob_get_single_ptr(b, &pem_data))
193*1c60b9acSAndroid Build Coastguard Worker goto no_client_cert;
194*1c60b9acSAndroid Build Coastguard Worker
195*1c60b9acSAndroid Build Coastguard Worker if (lws_tls_alloc_pem_to_der_file(wsi->a.context, NULL,
196*1c60b9acSAndroid Build Coastguard Worker (const char *)pem_data, size,
197*1c60b9acSAndroid Build Coastguard Worker &data, &flen))
198*1c60b9acSAndroid Build Coastguard Worker goto no_client_cert;
199*1c60b9acSAndroid Build Coastguard Worker size = (size_t) flen;
200*1c60b9acSAndroid Build Coastguard Worker
201*1c60b9acSAndroid Build Coastguard Worker err = SSL_use_certificate_ASN1(wsi->tls.ssl, data, (int)size);
202*1c60b9acSAndroid Build Coastguard Worker lws_free_set_NULL(data);
203*1c60b9acSAndroid Build Coastguard Worker if (err != 1)
204*1c60b9acSAndroid Build Coastguard Worker goto no_client_cert;
205*1c60b9acSAndroid Build Coastguard Worker
206*1c60b9acSAndroid Build Coastguard Worker b = lws_system_get_blob(wsi->a.context,
207*1c60b9acSAndroid Build Coastguard Worker LWS_SYSBLOB_TYPE_CLIENT_KEY_DER,
208*1c60b9acSAndroid Build Coastguard Worker wsi->sys_tls_client_cert - 1);
209*1c60b9acSAndroid Build Coastguard Worker if (!b)
210*1c60b9acSAndroid Build Coastguard Worker goto no_client_cert;
211*1c60b9acSAndroid Build Coastguard Worker size = lws_system_blob_get_size(b);
212*1c60b9acSAndroid Build Coastguard Worker if (!size)
213*1c60b9acSAndroid Build Coastguard Worker goto no_client_cert;
214*1c60b9acSAndroid Build Coastguard Worker
215*1c60b9acSAndroid Build Coastguard Worker if (lws_system_blob_get_single_ptr(b, &pem_data))
216*1c60b9acSAndroid Build Coastguard Worker goto no_client_cert;
217*1c60b9acSAndroid Build Coastguard Worker
218*1c60b9acSAndroid Build Coastguard Worker if (lws_tls_alloc_pem_to_der_file(wsi->a.context, NULL,
219*1c60b9acSAndroid Build Coastguard Worker (const char *)pem_data, size,
220*1c60b9acSAndroid Build Coastguard Worker &data, &flen))
221*1c60b9acSAndroid Build Coastguard Worker goto no_client_cert;
222*1c60b9acSAndroid Build Coastguard Worker size = (size_t) flen;
223*1c60b9acSAndroid Build Coastguard Worker
224*1c60b9acSAndroid Build Coastguard Worker err = SSL_use_PrivateKey_ASN1(0, wsi->tls.ssl, data, (int)size);
225*1c60b9acSAndroid Build Coastguard Worker lws_free_set_NULL(data);
226*1c60b9acSAndroid Build Coastguard Worker if (err != 1)
227*1c60b9acSAndroid Build Coastguard Worker goto no_client_cert;
228*1c60b9acSAndroid Build Coastguard Worker
229*1c60b9acSAndroid Build Coastguard Worker /* no wrapper api for check key */
230*1c60b9acSAndroid Build Coastguard Worker
231*1c60b9acSAndroid Build Coastguard Worker lwsl_notice("%s: set system client cert %u\n", __func__,
232*1c60b9acSAndroid Build Coastguard Worker wsi->sys_tls_client_cert - 1);
233*1c60b9acSAndroid Build Coastguard Worker }
234*1c60b9acSAndroid Build Coastguard Worker
235*1c60b9acSAndroid Build Coastguard Worker return 0;
236*1c60b9acSAndroid Build Coastguard Worker
237*1c60b9acSAndroid Build Coastguard Worker no_client_cert:
238*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: unable to set up system client cert %d\n", __func__,
239*1c60b9acSAndroid Build Coastguard Worker wsi->sys_tls_client_cert - 1);
240*1c60b9acSAndroid Build Coastguard Worker
241*1c60b9acSAndroid Build Coastguard Worker return 1;
242*1c60b9acSAndroid Build Coastguard Worker }
243*1c60b9acSAndroid Build Coastguard Worker
ERR_get_error(void)244*1c60b9acSAndroid Build Coastguard Worker int ERR_get_error(void)
245*1c60b9acSAndroid Build Coastguard Worker {
246*1c60b9acSAndroid Build Coastguard Worker return 0;
247*1c60b9acSAndroid Build Coastguard Worker }
248*1c60b9acSAndroid Build Coastguard Worker
249*1c60b9acSAndroid Build Coastguard Worker enum lws_ssl_capable_status
lws_tls_client_connect(struct lws * wsi,char * errbuf,size_t elen)250*1c60b9acSAndroid Build Coastguard Worker lws_tls_client_connect(struct lws *wsi, char *errbuf, size_t elen)
251*1c60b9acSAndroid Build Coastguard Worker {
252*1c60b9acSAndroid Build Coastguard Worker int m, n = SSL_connect(wsi->tls.ssl), en;
253*1c60b9acSAndroid Build Coastguard Worker
254*1c60b9acSAndroid Build Coastguard Worker if (n == 1) {
255*1c60b9acSAndroid Build Coastguard Worker lws_tls_server_conn_alpn(wsi);
256*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_WITH_TLS_SESSIONS)
257*1c60b9acSAndroid Build Coastguard Worker lws_tls_session_new_mbedtls(wsi);
258*1c60b9acSAndroid Build Coastguard Worker #endif
259*1c60b9acSAndroid Build Coastguard Worker lwsl_info("%s: client connect OK\n", __func__);
260*1c60b9acSAndroid Build Coastguard Worker return LWS_SSL_CAPABLE_DONE;
261*1c60b9acSAndroid Build Coastguard Worker }
262*1c60b9acSAndroid Build Coastguard Worker
263*1c60b9acSAndroid Build Coastguard Worker en = (int)LWS_ERRNO;
264*1c60b9acSAndroid Build Coastguard Worker m = SSL_get_error(wsi->tls.ssl, n);
265*1c60b9acSAndroid Build Coastguard Worker
266*1c60b9acSAndroid Build Coastguard Worker if (m == SSL_ERROR_WANT_READ || SSL_want_read(wsi->tls.ssl))
267*1c60b9acSAndroid Build Coastguard Worker return LWS_SSL_CAPABLE_MORE_SERVICE_READ;
268*1c60b9acSAndroid Build Coastguard Worker
269*1c60b9acSAndroid Build Coastguard Worker if (m == SSL_ERROR_WANT_WRITE || SSL_want_write(wsi->tls.ssl))
270*1c60b9acSAndroid Build Coastguard Worker return LWS_SSL_CAPABLE_MORE_SERVICE_WRITE;
271*1c60b9acSAndroid Build Coastguard Worker
272*1c60b9acSAndroid Build Coastguard Worker if (!n) /* we don't know what he wants, but he says to retry */
273*1c60b9acSAndroid Build Coastguard Worker return LWS_SSL_CAPABLE_MORE_SERVICE;
274*1c60b9acSAndroid Build Coastguard Worker
275*1c60b9acSAndroid Build Coastguard Worker if (m == SSL_ERROR_SYSCALL && !en)
276*1c60b9acSAndroid Build Coastguard Worker return LWS_SSL_CAPABLE_MORE_SERVICE;
277*1c60b9acSAndroid Build Coastguard Worker
278*1c60b9acSAndroid Build Coastguard Worker lws_snprintf(errbuf, elen, "mbedtls connect %d %d %d", n, m, en);
279*1c60b9acSAndroid Build Coastguard Worker
280*1c60b9acSAndroid Build Coastguard Worker return LWS_SSL_CAPABLE_ERROR;
281*1c60b9acSAndroid Build Coastguard Worker }
282*1c60b9acSAndroid Build Coastguard Worker
283*1c60b9acSAndroid Build Coastguard Worker int
lws_tls_client_confirm_peer_cert(struct lws * wsi,char * ebuf,size_t ebuf_len)284*1c60b9acSAndroid Build Coastguard Worker lws_tls_client_confirm_peer_cert(struct lws *wsi, char *ebuf, size_t ebuf_len)
285*1c60b9acSAndroid Build Coastguard Worker {
286*1c60b9acSAndroid Build Coastguard Worker int n;
287*1c60b9acSAndroid Build Coastguard Worker unsigned int avoid = 0;
288*1c60b9acSAndroid Build Coastguard Worker X509 *peer = SSL_get_peer_certificate(wsi->tls.ssl);
289*1c60b9acSAndroid Build Coastguard Worker struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
290*1c60b9acSAndroid Build Coastguard Worker const char *type = "";
291*1c60b9acSAndroid Build Coastguard Worker char *sb = (char *)&pt->serv_buf[0];
292*1c60b9acSAndroid Build Coastguard Worker
293*1c60b9acSAndroid Build Coastguard Worker if (!peer) {
294*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_WITH_SYS_METRICS)
295*1c60b9acSAndroid Build Coastguard Worker lws_metrics_hist_bump_describe_wsi(wsi, lws_metrics_priv_to_pub(
296*1c60b9acSAndroid Build Coastguard Worker wsi->a.context->mth_conn_failures),
297*1c60b9acSAndroid Build Coastguard Worker "tls=\"nocert\"");
298*1c60b9acSAndroid Build Coastguard Worker #endif
299*1c60b9acSAndroid Build Coastguard Worker lwsl_info("peer did not provide cert\n");
300*1c60b9acSAndroid Build Coastguard Worker lws_snprintf(ebuf, ebuf_len, "no peer cert");
301*1c60b9acSAndroid Build Coastguard Worker
302*1c60b9acSAndroid Build Coastguard Worker return -1;
303*1c60b9acSAndroid Build Coastguard Worker }
304*1c60b9acSAndroid Build Coastguard Worker
305*1c60b9acSAndroid Build Coastguard Worker n = (int)SSL_get_verify_result(wsi->tls.ssl);
306*1c60b9acSAndroid Build Coastguard Worker lwsl_debug("get_verify says %d\n", n);
307*1c60b9acSAndroid Build Coastguard Worker
308*1c60b9acSAndroid Build Coastguard Worker switch (n) {
309*1c60b9acSAndroid Build Coastguard Worker case X509_V_OK:
310*1c60b9acSAndroid Build Coastguard Worker return 0;
311*1c60b9acSAndroid Build Coastguard Worker
312*1c60b9acSAndroid Build Coastguard Worker case X509_V_ERR_HOSTNAME_MISMATCH:
313*1c60b9acSAndroid Build Coastguard Worker type = "hostname";
314*1c60b9acSAndroid Build Coastguard Worker avoid = LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK;
315*1c60b9acSAndroid Build Coastguard Worker break;
316*1c60b9acSAndroid Build Coastguard Worker
317*1c60b9acSAndroid Build Coastguard Worker case X509_V_ERR_INVALID_CA:
318*1c60b9acSAndroid Build Coastguard Worker type = "invalidca";
319*1c60b9acSAndroid Build Coastguard Worker avoid = LCCSCF_ALLOW_SELFSIGNED;
320*1c60b9acSAndroid Build Coastguard Worker break;
321*1c60b9acSAndroid Build Coastguard Worker
322*1c60b9acSAndroid Build Coastguard Worker case X509_V_ERR_CERT_NOT_YET_VALID:
323*1c60b9acSAndroid Build Coastguard Worker type = "notyetvalid";
324*1c60b9acSAndroid Build Coastguard Worker avoid = LCCSCF_ALLOW_EXPIRED;
325*1c60b9acSAndroid Build Coastguard Worker break;
326*1c60b9acSAndroid Build Coastguard Worker
327*1c60b9acSAndroid Build Coastguard Worker case X509_V_ERR_CERT_HAS_EXPIRED:
328*1c60b9acSAndroid Build Coastguard Worker type = "expired";
329*1c60b9acSAndroid Build Coastguard Worker avoid = LCCSCF_ALLOW_EXPIRED;
330*1c60b9acSAndroid Build Coastguard Worker break;
331*1c60b9acSAndroid Build Coastguard Worker }
332*1c60b9acSAndroid Build Coastguard Worker
333*1c60b9acSAndroid Build Coastguard Worker lwsl_info("%s: cert problem: %s\n", __func__, type);
334*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_WITH_SYS_METRICS)
335*1c60b9acSAndroid Build Coastguard Worker {
336*1c60b9acSAndroid Build Coastguard Worker char buckname[64];
337*1c60b9acSAndroid Build Coastguard Worker lws_snprintf(buckname, sizeof(buckname), "tls=\"%s\"", type);
338*1c60b9acSAndroid Build Coastguard Worker lws_metrics_hist_bump_describe_wsi(wsi,
339*1c60b9acSAndroid Build Coastguard Worker lws_metrics_priv_to_pub(wsi->a.context->mth_conn_failures),
340*1c60b9acSAndroid Build Coastguard Worker buckname);
341*1c60b9acSAndroid Build Coastguard Worker }
342*1c60b9acSAndroid Build Coastguard Worker #endif
343*1c60b9acSAndroid Build Coastguard Worker if (wsi->tls.use_ssl & avoid) {
344*1c60b9acSAndroid Build Coastguard Worker lwsl_info("%s: allowing anyway\n", __func__);
345*1c60b9acSAndroid Build Coastguard Worker
346*1c60b9acSAndroid Build Coastguard Worker return 0;
347*1c60b9acSAndroid Build Coastguard Worker }
348*1c60b9acSAndroid Build Coastguard Worker
349*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_WITH_TLS_JIT_TRUST)
350*1c60b9acSAndroid Build Coastguard Worker if (n == X509_V_ERR_INVALID_CA)
351*1c60b9acSAndroid Build Coastguard Worker lws_tls_jit_trust_sort_kids(wsi, &wsi->tls.ssl->kid_chain);
352*1c60b9acSAndroid Build Coastguard Worker #endif
353*1c60b9acSAndroid Build Coastguard Worker lws_snprintf(ebuf, ebuf_len,
354*1c60b9acSAndroid Build Coastguard Worker "server's cert didn't look good, %s (use_ssl 0x%x) X509_V_ERR = %d: %s\n",
355*1c60b9acSAndroid Build Coastguard Worker type, (unsigned int)wsi->tls.use_ssl, n,
356*1c60b9acSAndroid Build Coastguard Worker ERR_error_string((unsigned long)n, sb));
357*1c60b9acSAndroid Build Coastguard Worker
358*1c60b9acSAndroid Build Coastguard Worker lwsl_info("%s\n", ebuf);
359*1c60b9acSAndroid Build Coastguard Worker
360*1c60b9acSAndroid Build Coastguard Worker lws_tls_err_describe_clear();
361*1c60b9acSAndroid Build Coastguard Worker
362*1c60b9acSAndroid Build Coastguard Worker return -1;
363*1c60b9acSAndroid Build Coastguard Worker }
364*1c60b9acSAndroid Build Coastguard Worker
365*1c60b9acSAndroid Build Coastguard Worker int
lws_tls_client_create_vhost_context(struct lws_vhost * vh,const struct lws_context_creation_info * info,const char * cipher_list,const char * ca_filepath,const void * ca_mem,unsigned int ca_mem_len,const char * cert_filepath,const void * cert_mem,unsigned int cert_mem_len,const char * private_key_filepath,const void * key_mem,unsigned int key_mem_len)366*1c60b9acSAndroid Build Coastguard Worker lws_tls_client_create_vhost_context(struct lws_vhost *vh,
367*1c60b9acSAndroid Build Coastguard Worker const struct lws_context_creation_info *info,
368*1c60b9acSAndroid Build Coastguard Worker const char *cipher_list,
369*1c60b9acSAndroid Build Coastguard Worker const char *ca_filepath,
370*1c60b9acSAndroid Build Coastguard Worker const void *ca_mem,
371*1c60b9acSAndroid Build Coastguard Worker unsigned int ca_mem_len,
372*1c60b9acSAndroid Build Coastguard Worker const char *cert_filepath,
373*1c60b9acSAndroid Build Coastguard Worker const void *cert_mem,
374*1c60b9acSAndroid Build Coastguard Worker unsigned int cert_mem_len,
375*1c60b9acSAndroid Build Coastguard Worker const char *private_key_filepath,
376*1c60b9acSAndroid Build Coastguard Worker const void *key_mem,
377*1c60b9acSAndroid Build Coastguard Worker unsigned int key_mem_len
378*1c60b9acSAndroid Build Coastguard Worker )
379*1c60b9acSAndroid Build Coastguard Worker {
380*1c60b9acSAndroid Build Coastguard Worker X509 *d2i_X509(X509 **cert, const unsigned char *buffer, long len);
381*1c60b9acSAndroid Build Coastguard Worker SSL_METHOD *method = (SSL_METHOD *)TLS_client_method();
382*1c60b9acSAndroid Build Coastguard Worker unsigned long error;
383*1c60b9acSAndroid Build Coastguard Worker int n;
384*1c60b9acSAndroid Build Coastguard Worker
385*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_WITH_TLS_SESSIONS)
386*1c60b9acSAndroid Build Coastguard Worker vh->tls_session_cache_max = info->tls_session_cache_max ?
387*1c60b9acSAndroid Build Coastguard Worker info->tls_session_cache_max : 10;
388*1c60b9acSAndroid Build Coastguard Worker lws_tls_session_cache(vh, info->tls_session_timeout);
389*1c60b9acSAndroid Build Coastguard Worker #endif
390*1c60b9acSAndroid Build Coastguard Worker
391*1c60b9acSAndroid Build Coastguard Worker if (!method) {
392*1c60b9acSAndroid Build Coastguard Worker error = (unsigned long)ERR_get_error();
393*1c60b9acSAndroid Build Coastguard Worker lwsl_err("problem creating ssl method %lu: %s\n",
394*1c60b9acSAndroid Build Coastguard Worker error, ERR_error_string(error,
395*1c60b9acSAndroid Build Coastguard Worker (char *)vh->context->pt[0].serv_buf));
396*1c60b9acSAndroid Build Coastguard Worker return 1;
397*1c60b9acSAndroid Build Coastguard Worker }
398*1c60b9acSAndroid Build Coastguard Worker /* create context */
399*1c60b9acSAndroid Build Coastguard Worker vh->tls.ssl_client_ctx = SSL_CTX_new(method, &vh->context->mcdc);
400*1c60b9acSAndroid Build Coastguard Worker if (!vh->tls.ssl_client_ctx) {
401*1c60b9acSAndroid Build Coastguard Worker error = (unsigned long)ERR_get_error();
402*1c60b9acSAndroid Build Coastguard Worker lwsl_err("problem creating ssl context %lu: %s\n",
403*1c60b9acSAndroid Build Coastguard Worker error, ERR_error_string(error,
404*1c60b9acSAndroid Build Coastguard Worker (char *)vh->context->pt[0].serv_buf));
405*1c60b9acSAndroid Build Coastguard Worker return 1;
406*1c60b9acSAndroid Build Coastguard Worker }
407*1c60b9acSAndroid Build Coastguard Worker
408*1c60b9acSAndroid Build Coastguard Worker if (!ca_filepath && (!ca_mem || !ca_mem_len))
409*1c60b9acSAndroid Build Coastguard Worker return 0;
410*1c60b9acSAndroid Build Coastguard Worker
411*1c60b9acSAndroid Build Coastguard Worker if (ca_filepath) {
412*1c60b9acSAndroid Build Coastguard Worker #if !defined(LWS_PLAT_OPTEE)
413*1c60b9acSAndroid Build Coastguard Worker uint8_t *buf;
414*1c60b9acSAndroid Build Coastguard Worker lws_filepos_t len;
415*1c60b9acSAndroid Build Coastguard Worker
416*1c60b9acSAndroid Build Coastguard Worker if (alloc_file(vh->context, ca_filepath, &buf, &len)) {
417*1c60b9acSAndroid Build Coastguard Worker lwsl_err("Load CA cert file %s failed\n", ca_filepath);
418*1c60b9acSAndroid Build Coastguard Worker return 1;
419*1c60b9acSAndroid Build Coastguard Worker }
420*1c60b9acSAndroid Build Coastguard Worker vh->tls.x509_client_CA = d2i_X509(NULL, buf, (long)len);
421*1c60b9acSAndroid Build Coastguard Worker free(buf);
422*1c60b9acSAndroid Build Coastguard Worker
423*1c60b9acSAndroid Build Coastguard Worker lwsl_info("Loading vh %s client CA for verification %s\n", vh->name, ca_filepath);
424*1c60b9acSAndroid Build Coastguard Worker #endif
425*1c60b9acSAndroid Build Coastguard Worker } else {
426*1c60b9acSAndroid Build Coastguard Worker vh->tls.x509_client_CA = d2i_X509(NULL, (uint8_t*)ca_mem, (long)ca_mem_len);
427*1c60b9acSAndroid Build Coastguard Worker lwsl_info("%s: using mem client CA cert %d\n",
428*1c60b9acSAndroid Build Coastguard Worker __func__, ca_mem_len);
429*1c60b9acSAndroid Build Coastguard Worker }
430*1c60b9acSAndroid Build Coastguard Worker
431*1c60b9acSAndroid Build Coastguard Worker if (!vh->tls.x509_client_CA) {
432*1c60b9acSAndroid Build Coastguard Worker lwsl_err("client CA: x509 parse failed\n");
433*1c60b9acSAndroid Build Coastguard Worker return 1;
434*1c60b9acSAndroid Build Coastguard Worker }
435*1c60b9acSAndroid Build Coastguard Worker
436*1c60b9acSAndroid Build Coastguard Worker if (!vh->tls.ssl_ctx)
437*1c60b9acSAndroid Build Coastguard Worker SSL_CTX_add_client_CA(vh->tls.ssl_client_ctx, vh->tls.x509_client_CA);
438*1c60b9acSAndroid Build Coastguard Worker else
439*1c60b9acSAndroid Build Coastguard Worker SSL_CTX_add_client_CA(vh->tls.ssl_ctx, vh->tls.x509_client_CA);
440*1c60b9acSAndroid Build Coastguard Worker
441*1c60b9acSAndroid Build Coastguard Worker /* support for client-side certificate authentication */
442*1c60b9acSAndroid Build Coastguard Worker if (cert_filepath) {
443*1c60b9acSAndroid Build Coastguard Worker #if !defined(LWS_PLAT_OPTEE)
444*1c60b9acSAndroid Build Coastguard Worker uint8_t *buf;
445*1c60b9acSAndroid Build Coastguard Worker lws_filepos_t amount;
446*1c60b9acSAndroid Build Coastguard Worker
447*1c60b9acSAndroid Build Coastguard Worker if (lws_tls_use_any_upgrade_check_extant(cert_filepath) !=
448*1c60b9acSAndroid Build Coastguard Worker LWS_TLS_EXTANT_YES &&
449*1c60b9acSAndroid Build Coastguard Worker (info->options & LWS_SERVER_OPTION_IGNORE_MISSING_CERT))
450*1c60b9acSAndroid Build Coastguard Worker return 0;
451*1c60b9acSAndroid Build Coastguard Worker
452*1c60b9acSAndroid Build Coastguard Worker lwsl_notice("%s: doing cert filepath %s\n", __func__,
453*1c60b9acSAndroid Build Coastguard Worker cert_filepath);
454*1c60b9acSAndroid Build Coastguard Worker
455*1c60b9acSAndroid Build Coastguard Worker if (alloc_file(vh->context, cert_filepath, &buf, &amount))
456*1c60b9acSAndroid Build Coastguard Worker return 1;
457*1c60b9acSAndroid Build Coastguard Worker
458*1c60b9acSAndroid Build Coastguard Worker buf[amount++] = '\0';
459*1c60b9acSAndroid Build Coastguard Worker
460*1c60b9acSAndroid Build Coastguard Worker n = SSL_CTX_use_certificate_ASN1(vh->tls.ssl_client_ctx,
461*1c60b9acSAndroid Build Coastguard Worker (int)amount, buf);
462*1c60b9acSAndroid Build Coastguard Worker lws_free(buf);
463*1c60b9acSAndroid Build Coastguard Worker if (n < 1) {
464*1c60b9acSAndroid Build Coastguard Worker lwsl_err("problem %d getting cert '%s'\n", n,
465*1c60b9acSAndroid Build Coastguard Worker cert_filepath);
466*1c60b9acSAndroid Build Coastguard Worker lws_tls_err_describe_clear();
467*1c60b9acSAndroid Build Coastguard Worker return 1;
468*1c60b9acSAndroid Build Coastguard Worker }
469*1c60b9acSAndroid Build Coastguard Worker
470*1c60b9acSAndroid Build Coastguard Worker lwsl_info("Loaded client cert %s\n", cert_filepath);
471*1c60b9acSAndroid Build Coastguard Worker #endif
472*1c60b9acSAndroid Build Coastguard Worker } else if (cert_mem && cert_mem_len) {
473*1c60b9acSAndroid Build Coastguard Worker /* lwsl_hexdump_notice(cert_mem, cert_mem_len - 1); */
474*1c60b9acSAndroid Build Coastguard Worker n = SSL_CTX_use_certificate_ASN1(vh->tls.ssl_client_ctx,
475*1c60b9acSAndroid Build Coastguard Worker (int)cert_mem_len, cert_mem);
476*1c60b9acSAndroid Build Coastguard Worker if (n < 1) {
477*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: (mbedtls) problem interpreting client cert\n",
478*1c60b9acSAndroid Build Coastguard Worker __func__);
479*1c60b9acSAndroid Build Coastguard Worker lws_tls_err_describe_clear();
480*1c60b9acSAndroid Build Coastguard Worker return 1;
481*1c60b9acSAndroid Build Coastguard Worker }
482*1c60b9acSAndroid Build Coastguard Worker lwsl_info("%s: using mem client cert %d\n",
483*1c60b9acSAndroid Build Coastguard Worker __func__, cert_mem_len);
484*1c60b9acSAndroid Build Coastguard Worker }
485*1c60b9acSAndroid Build Coastguard Worker
486*1c60b9acSAndroid Build Coastguard Worker if (private_key_filepath) {
487*1c60b9acSAndroid Build Coastguard Worker #if !defined(LWS_PLAT_OPTEE)
488*1c60b9acSAndroid Build Coastguard Worker
489*1c60b9acSAndroid Build Coastguard Worker uint8_t *buf;
490*1c60b9acSAndroid Build Coastguard Worker lws_filepos_t amount;
491*1c60b9acSAndroid Build Coastguard Worker
492*1c60b9acSAndroid Build Coastguard Worker lwsl_notice("%s: doing private key filepath %s\n", __func__,
493*1c60b9acSAndroid Build Coastguard Worker private_key_filepath);
494*1c60b9acSAndroid Build Coastguard Worker if (alloc_file(vh->context, private_key_filepath, &buf, &amount))
495*1c60b9acSAndroid Build Coastguard Worker return 1;
496*1c60b9acSAndroid Build Coastguard Worker
497*1c60b9acSAndroid Build Coastguard Worker buf[amount++] = '\0';
498*1c60b9acSAndroid Build Coastguard Worker
499*1c60b9acSAndroid Build Coastguard Worker n = SSL_CTX_use_PrivateKey_ASN1(0, vh->tls.ssl_client_ctx,
500*1c60b9acSAndroid Build Coastguard Worker buf, (long)amount);
501*1c60b9acSAndroid Build Coastguard Worker
502*1c60b9acSAndroid Build Coastguard Worker lws_free(buf);
503*1c60b9acSAndroid Build Coastguard Worker if (n < 1) {
504*1c60b9acSAndroid Build Coastguard Worker lwsl_err("problem %d getting private key '%s'\n", n,
505*1c60b9acSAndroid Build Coastguard Worker private_key_filepath);
506*1c60b9acSAndroid Build Coastguard Worker lws_tls_err_describe_clear();
507*1c60b9acSAndroid Build Coastguard Worker return 1;
508*1c60b9acSAndroid Build Coastguard Worker }
509*1c60b9acSAndroid Build Coastguard Worker
510*1c60b9acSAndroid Build Coastguard Worker lwsl_notice("Loaded private key %s\n", private_key_filepath);
511*1c60b9acSAndroid Build Coastguard Worker #endif
512*1c60b9acSAndroid Build Coastguard Worker } else if (key_mem && key_mem_len) {
513*1c60b9acSAndroid Build Coastguard Worker /* lwsl_hexdump_notice(cert_mem, cert_mem_len - 1); */
514*1c60b9acSAndroid Build Coastguard Worker n = SSL_CTX_use_PrivateKey_ASN1(0, vh->tls.ssl_client_ctx,
515*1c60b9acSAndroid Build Coastguard Worker key_mem, (long)key_mem_len - 1);
516*1c60b9acSAndroid Build Coastguard Worker
517*1c60b9acSAndroid Build Coastguard Worker if (n < 1) {
518*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: (mbedtls) problem interpreting private key\n",
519*1c60b9acSAndroid Build Coastguard Worker __func__);
520*1c60b9acSAndroid Build Coastguard Worker lws_tls_err_describe_clear();
521*1c60b9acSAndroid Build Coastguard Worker return 1;
522*1c60b9acSAndroid Build Coastguard Worker }
523*1c60b9acSAndroid Build Coastguard Worker lwsl_info("%s: using mem private key %d\n",
524*1c60b9acSAndroid Build Coastguard Worker __func__, key_mem_len);
525*1c60b9acSAndroid Build Coastguard Worker
526*1c60b9acSAndroid Build Coastguard Worker }
527*1c60b9acSAndroid Build Coastguard Worker return 0;
528*1c60b9acSAndroid Build Coastguard Worker }
529*1c60b9acSAndroid Build Coastguard Worker
530*1c60b9acSAndroid Build Coastguard Worker int
lws_tls_client_vhost_extra_cert_mem(struct lws_vhost * vh,const uint8_t * der,size_t der_len)531*1c60b9acSAndroid Build Coastguard Worker lws_tls_client_vhost_extra_cert_mem(struct lws_vhost *vh,
532*1c60b9acSAndroid Build Coastguard Worker const uint8_t *der, size_t der_len)
533*1c60b9acSAndroid Build Coastguard Worker {
534*1c60b9acSAndroid Build Coastguard Worker if (SSL_CTX_add_client_CA_ASN1(vh->tls.ssl_client_ctx, (int)der_len, der) != 1) {
535*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: failed\n", __func__);
536*1c60b9acSAndroid Build Coastguard Worker return 1;
537*1c60b9acSAndroid Build Coastguard Worker }
538*1c60b9acSAndroid Build Coastguard Worker
539*1c60b9acSAndroid Build Coastguard Worker return 0;
540*1c60b9acSAndroid Build Coastguard Worker }
541*1c60b9acSAndroid Build Coastguard Worker
542