BadVPN – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /** |
2 | * @file |
||
3 | * Application layered TCP/TLS connection API (to be used from TCPIP thread) |
||
4 | * |
||
5 | * This file provides a TLS layer using mbedTLS |
||
6 | */ |
||
7 | |||
8 | /* |
||
9 | * Copyright (c) 2017 Simon Goldschmidt |
||
10 | * All rights reserved. |
||
11 | * |
||
12 | * Redistribution and use in source and binary forms, with or without modification, |
||
13 | * are permitted provided that the following conditions are met: |
||
14 | * |
||
15 | * 1. Redistributions of source code must retain the above copyright notice, |
||
16 | * this list of conditions and the following disclaimer. |
||
17 | * 2. Redistributions in binary form must reproduce the above copyright notice, |
||
18 | * this list of conditions and the following disclaimer in the documentation |
||
19 | * and/or other materials provided with the distribution. |
||
20 | * 3. The name of the author may not be used to endorse or promote products |
||
21 | * derived from this software without specific prior written permission. |
||
22 | * |
||
23 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED |
||
24 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
||
25 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT |
||
26 | * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||
27 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT |
||
28 | * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
||
29 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
||
30 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING |
||
31 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY |
||
32 | * OF SUCH DAMAGE. |
||
33 | * |
||
34 | * This file is part of the lwIP TCP/IP stack. |
||
35 | * |
||
36 | * Author: Simon Goldschmidt <goldsimon@gmx.de> |
||
37 | * |
||
38 | * Watch out: |
||
39 | * - 'sent' is always called with len==0 to the upper layer. This is because keeping |
||
40 | * track of the ratio of application data and TLS overhead would be too much. |
||
41 | * |
||
42 | * Mandatory security-related configuration: |
||
43 | * - define ALTCP_MBEDTLS_RNG_FN to a custom GOOD rng function returning 0 on success: |
||
44 | * int my_rng_fn(void *ctx, unsigned char *buffer , size_t len) |
||
45 | * - define ALTCP_MBEDTLS_ENTROPY_PTR and ALTCP_MBEDTLS_ENTROPY_LEN to something providing |
||
46 | * GOOD custom entropy |
||
47 | * |
||
48 | * Missing things / @todo: |
||
49 | * - RX data is acknowledged after receiving (tcp_recved is called when enqueueing |
||
50 | * the pbuf for mbedTLS receive, not when processed by mbedTLS or the inner |
||
51 | * connection; altcp_recved() from inner connection does nothing) |
||
52 | * - Client connections starting with 'connect()' are not handled yet... |
||
53 | * - some unhandled things are caught by LWIP_ASSERTs... |
||
54 | */ |
||
55 | |||
56 | #include "lwip/opt.h" |
||
57 | |||
58 | #if LWIP_ALTCP /* don't build if not configured for use in lwipopts.h */ |
||
59 | |||
60 | #include "lwip/apps/altcp_tls_mbedtls_opts.h" |
||
61 | |||
62 | #if LWIP_ALTCP_TLS && LWIP_ALTCP_TLS_MBEDTLS |
||
63 | |||
64 | #include "lwip/altcp.h" |
||
65 | #include "lwip/altcp_tls.h" |
||
66 | #include "lwip/priv/altcp_priv.h" |
||
67 | |||
68 | #include "altcp_tls_mbedtls_structs.h" |
||
69 | #include "altcp_tls_mbedtls_mem.h" |
||
70 | |||
71 | /* @todo: which includes are really needed? */ |
||
72 | #include "mbedtls/entropy.h" |
||
73 | #include "mbedtls/ctr_drbg.h" |
||
74 | #include "mbedtls/certs.h" |
||
75 | #include "mbedtls/x509.h" |
||
76 | #include "mbedtls/ssl.h" |
||
77 | #include "mbedtls/net.h" |
||
78 | #include "mbedtls/error.h" |
||
79 | #include "mbedtls/debug.h" |
||
80 | #include "mbedtls/platform.h" |
||
81 | #include "mbedtls/memory_buffer_alloc.h" |
||
82 | #include "mbedtls/ssl_cache.h" |
||
83 | |||
84 | #include "mbedtls/ssl_internal.h" /* to call mbedtls_flush_output after ERR_MEM */ |
||
85 | |||
86 | #include <string.h> |
||
87 | |||
88 | #ifndef ALTCP_MBEDTLS_ENTROPY_PTR |
||
89 | #define ALTCP_MBEDTLS_ENTROPY_PTR NULL |
||
90 | #endif |
||
91 | #ifndef ALTCP_MBEDTLS_ENTROPY_LEN |
||
92 | #define ALTCP_MBEDTLS_ENTROPY_LEN 0 |
||
93 | #endif |
||
94 | |||
95 | /* Variable prototype, the actual declaration is at the end of this file |
||
96 | since it contains pointers to static functions declared here */ |
||
97 | extern const struct altcp_functions altcp_mbedtls_functions; |
||
98 | |||
99 | /** Our global mbedTLS configuration (server-specific, not connection-specific) */ |
||
100 | struct altcp_tls_config { |
||
101 | mbedtls_ssl_config conf; |
||
102 | mbedtls_entropy_context entropy; |
||
103 | mbedtls_ctr_drbg_context ctr_drbg; |
||
104 | #if defined(MBEDTLS_SSL_CACHE_C) && ALTCP_MBEDTLS_SESSION_CACHE_TIMEOUT_SECONDS |
||
105 | /** Inter-connection cache for fast connection startup */ |
||
106 | struct mbedtls_ssl_cache_context cache; |
||
107 | #endif |
||
108 | }; |
||
109 | |||
110 | static err_t altcp_mbedtls_lower_recv(void *arg, struct altcp_pcb *inner_conn, struct pbuf *p, err_t err); |
||
111 | static err_t altcp_mbedtls_setup(void *conf, struct altcp_pcb *conn, struct altcp_pcb *inner_conn); |
||
112 | static void altcp_mbedtls_dealloc(struct altcp_pcb *conn); |
||
113 | static err_t altcp_mbedtls_lower_recv_process(struct altcp_pcb *conn, altcp_mbedtls_state_t *state); |
||
114 | static err_t altcp_mbedtls_handle_rx_appldata(struct altcp_pcb *conn, altcp_mbedtls_state_t *state); |
||
115 | static int altcp_mbedtls_bio_send(void *ctx, const unsigned char *dataptr, size_t size); |
||
116 | |||
117 | |||
118 | /* callback functions from inner/lower connection: */ |
||
119 | |||
120 | /** Accept callback from lower connection (i.e. TCP) |
||
121 | * Allocate one of our structures, assign it to the new connection's 'state' and |
||
122 | * call the new connection's 'accepted' callback. If that succeeds, we wait |
||
123 | * to receive connection setup handshake bytes from the client. |
||
124 | */ |
||
125 | static err_t |
||
126 | altcp_mbedtls_lower_accept(void *arg, struct altcp_pcb *accepted_conn, err_t err) |
||
127 | { |
||
128 | struct altcp_pcb *listen_conn = (struct altcp_pcb *)arg; |
||
129 | if (listen_conn && listen_conn->state && listen_conn->accept) { |
||
130 | err_t setup_err; |
||
131 | altcp_mbedtls_state_t *listen_state = (altcp_mbedtls_state_t *)listen_conn->state; |
||
132 | /* create a new altcp_conn to pass to the next 'accept' callback */ |
||
133 | struct altcp_pcb *new_conn = altcp_alloc(); |
||
134 | if (new_conn == NULL) { |
||
135 | return ERR_MEM; |
||
136 | } |
||
137 | setup_err = altcp_mbedtls_setup(listen_state->conf, new_conn, accepted_conn); |
||
138 | if (setup_err != ERR_OK) { |
||
139 | altcp_free(new_conn); |
||
140 | return setup_err; |
||
141 | } |
||
142 | return listen_conn->accept(listen_conn->arg, new_conn, err); |
||
143 | } |
||
144 | return ERR_ARG; |
||
145 | } |
||
146 | |||
147 | /** Connected callback from lower connection (i.e. TCP). |
||
148 | * Not really implemented/tested yet... |
||
149 | */ |
||
150 | static err_t |
||
151 | altcp_mbedtls_lower_connected(void *arg, struct altcp_pcb *inner_conn, err_t err) |
||
152 | { |
||
153 | struct altcp_pcb *conn = (struct altcp_pcb *)arg; |
||
154 | if (conn && conn->state) { |
||
155 | LWIP_ASSERT("pcb mismatch", conn->inner_conn == inner_conn); |
||
156 | /* upper connected is called when handshake is done */ |
||
157 | if (err != ERR_OK) { |
||
158 | if (conn->connected) { |
||
159 | if (conn->connected(conn->arg, conn, err) == ERR_ABRT) { |
||
160 | return ERR_ABRT; |
||
161 | } |
||
162 | return ERR_OK; |
||
163 | } |
||
164 | } |
||
165 | return altcp_mbedtls_lower_recv_process(conn, (altcp_mbedtls_state_t *)conn->state); |
||
166 | } |
||
167 | return ERR_VAL; |
||
168 | } |
||
169 | |||
170 | /* Call recved for possibly more than an u16_t */ |
||
171 | static void |
||
172 | altcp_mbedtls_lower_recved(struct altcp_pcb *inner_conn, int recvd_cnt) |
||
173 | { |
||
174 | while (recvd_cnt > 0) { |
||
175 | u16_t recvd_part = (u16_t)LWIP_MIN(recvd_cnt, 0xFFFF); |
||
176 | altcp_recved(inner_conn, recvd_part); |
||
177 | recvd_cnt -= recvd_part; |
||
178 | } |
||
179 | } |
||
180 | |||
181 | /** Recv callback from lower connection (i.e. TCP) |
||
182 | * This one mainly differs between connection setup/handshake (data is fed into mbedTLS only) |
||
183 | * and application phase (data is decoded by mbedTLS and passed on to the application). |
||
184 | */ |
||
185 | static err_t |
||
186 | altcp_mbedtls_lower_recv(void *arg, struct altcp_pcb *inner_conn, struct pbuf *p, err_t err) |
||
187 | { |
||
188 | altcp_mbedtls_state_t *state; |
||
189 | struct altcp_pcb *conn = (struct altcp_pcb *)arg; |
||
190 | |||
191 | LWIP_ASSERT("no err expected", err == ERR_OK); |
||
192 | LWIP_UNUSED_ARG(err); |
||
193 | |||
194 | if (!conn) { |
||
195 | /* no connection given as arg? should not happen, but prevent pbuf/conn leaks */ |
||
196 | if (p != NULL) { |
||
197 | pbuf_free(p); |
||
198 | } |
||
199 | altcp_close(inner_conn); |
||
200 | return ERR_CLSD; |
||
201 | } |
||
202 | state = (altcp_mbedtls_state_t *)conn->state; |
||
203 | LWIP_ASSERT("pcb mismatch", conn->inner_conn == inner_conn); |
||
204 | if (!state) { |
||
205 | /* already closed */ |
||
206 | if (p != NULL) { |
||
207 | pbuf_free(p); |
||
208 | } |
||
209 | altcp_close(inner_conn); |
||
210 | return ERR_CLSD; |
||
211 | } |
||
212 | |||
213 | /* handle NULL pbuf (connection closed) */ |
||
214 | if (p == NULL) { |
||
215 | /* remote host sent FIN, remember this (SSL state is destroyed |
||
216 | when both sides are closed only!) */ |
||
217 | state->flags |= ALTCP_MBEDTLS_FLAGS_RX_CLOSE_QUEUED; |
||
218 | if ((state->flags & (ALTCP_MBEDTLS_FLAGS_HANDSHAKE_DONE | ALTCP_MBEDTLS_FLAGS_UPPER_CALLED)) == |
||
219 | (ALTCP_MBEDTLS_FLAGS_HANDSHAKE_DONE | ALTCP_MBEDTLS_FLAGS_UPPER_CALLED)) { |
||
220 | /* need to notify upper layer (e.g. 'accept' called or 'connect' succeeded) */ |
||
221 | if ((state->rx != NULL) || (state->rx_app != NULL)) { |
||
222 | /* this is a normal close (FIN) but we have unprocessed data, so delay the FIN */ |
||
223 | altcp_mbedtls_handle_rx_appldata(conn, state); |
||
224 | return ERR_OK; |
||
225 | } |
||
226 | if (conn->recv) { |
||
227 | err_t local_err = conn->recv(conn->arg, conn, NULL, ERR_OK); |
||
228 | if (local_err == ERR_ABRT) { |
||
229 | return ERR_ABRT; |
||
230 | } |
||
231 | } |
||
232 | } else { |
||
233 | /* before connection setup is done: call 'err' */ |
||
234 | if (conn->err) { |
||
235 | conn->err(conn->arg, ERR_CLSD); |
||
236 | } |
||
237 | } |
||
238 | altcp_close(conn); |
||
239 | state->flags |= ALTCP_MBEDTLS_FLAGS_RX_CLOSED; |
||
240 | if (conn->state && ((state->flags & ALTCP_MBEDTLS_FLAGS_CLOSED) == ALTCP_MBEDTLS_FLAGS_CLOSED)) { |
||
241 | altcp_mbedtls_dealloc(conn); |
||
242 | } |
||
243 | return ERR_OK; |
||
244 | } |
||
245 | |||
246 | /* If we come here, the connection is in good state (handshake phase or application data phase). |
||
247 | Queue up the pbuf for processing as handshake data or application data. */ |
||
248 | if (state->rx == NULL) { |
||
249 | state->rx = p; |
||
250 | } else { |
||
251 | LWIP_ASSERT("rx pbuf overflow", (int)p->tot_len + (int)p->len <= 0xFFFF); |
||
252 | pbuf_cat(state->rx, p); |
||
253 | } |
||
254 | return altcp_mbedtls_lower_recv_process(conn, state); |
||
255 | } |
||
256 | |||
257 | static err_t |
||
258 | altcp_mbedtls_lower_recv_process(struct altcp_pcb *conn, altcp_mbedtls_state_t *state) |
||
259 | { |
||
260 | if (!(state->flags & ALTCP_MBEDTLS_FLAGS_HANDSHAKE_DONE)) { |
||
261 | /* handle connection setup (handshake not done) */ |
||
262 | int ret = mbedtls_ssl_handshake(&state->ssl_context); |
||
263 | /* try to send data... */ |
||
264 | altcp_output(conn->inner_conn); |
||
265 | if (state->bio_bytes_read) { |
||
266 | /* acknowledge all bytes read */ |
||
267 | altcp_mbedtls_lower_recved(conn->inner_conn, state->bio_bytes_read); |
||
268 | state->bio_bytes_read = 0; |
||
269 | } |
||
270 | |||
271 | if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) { |
||
272 | /* handshake not done, wait for more recv calls */ |
||
273 | LWIP_ASSERT("in this state, the rx chain should be empty", state->rx == NULL); |
||
274 | return ERR_OK; |
||
275 | } |
||
276 | if (ret != 0) { |
||
277 | LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_ssl_handshake failed: %d\n", ret)); |
||
278 | /* handshake failed, connection has to be closed */ |
||
279 | conn->recv(conn->arg, conn, NULL, ERR_OK); |
||
280 | if (altcp_close(conn->inner_conn) != ERR_OK) { |
||
281 | altcp_abort(conn->inner_conn); |
||
282 | } |
||
283 | return ERR_OK; |
||
284 | } |
||
285 | /* If we come here, handshake succeeded. */ |
||
286 | LWIP_ASSERT("state", state->bio_bytes_read == 0); |
||
287 | LWIP_ASSERT("state", state->bio_bytes_appl == 0); |
||
288 | state->flags |= ALTCP_MBEDTLS_FLAGS_HANDSHAKE_DONE; |
||
289 | /* issue "connect" callback" to upper connection (this can only happen for active open) */ |
||
290 | if (conn->connected) { |
||
291 | conn->connected(conn->arg, conn, ERR_OK); |
||
292 | } |
||
293 | if (state->rx == NULL) { |
||
294 | return ERR_OK; |
||
295 | } |
||
296 | } |
||
297 | /* handle application data */ |
||
298 | return altcp_mbedtls_handle_rx_appldata(conn, state); |
||
299 | } |
||
300 | |||
301 | /* Pass queued decoded rx data to application */ |
||
302 | static err_t |
||
303 | altcp_mbedtls_pass_rx_data(struct altcp_pcb *conn, altcp_mbedtls_state_t *state) |
||
304 | { |
||
305 | err_t err; |
||
306 | struct pbuf *buf; |
||
307 | LWIP_ASSERT("conn != NULL", conn != NULL); |
||
308 | LWIP_ASSERT("state != NULL", state != NULL); |
||
309 | buf = state->rx_app; |
||
310 | if (buf) { |
||
311 | if (conn->recv) { |
||
312 | u16_t tot_len = state->rx_app->tot_len; |
||
313 | /* this needs to be increased first because the 'recved' call may come nested */ |
||
314 | state->rx_passed_unrecved += tot_len; |
||
315 | state->flags |= ALTCP_MBEDTLS_FLAGS_UPPER_CALLED; |
||
316 | err = conn->recv(conn->arg, conn, state->rx_app, ERR_OK); |
||
317 | if (err != ERR_OK) { |
||
318 | /* not received, leave the pbuf(s) queued (and decrease 'unrecved' again) */ |
||
319 | state->rx_passed_unrecved -= tot_len; |
||
320 | LWIP_ASSERT("state->rx_passed_unrecved >= 0", state->rx_passed_unrecved >= 0); |
||
321 | if (state->rx_passed_unrecved < 0) { |
||
322 | state->rx_passed_unrecved = 0; |
||
323 | } |
||
324 | return err; |
||
325 | } |
||
326 | } else { |
||
327 | pbuf_free(buf); |
||
328 | } |
||
329 | state->rx_app = NULL; |
||
330 | } else if ((state->flags & (ALTCP_MBEDTLS_FLAGS_RX_CLOSE_QUEUED | ALTCP_MBEDTLS_FLAGS_RX_CLOSED)) == |
||
331 | ALTCP_MBEDTLS_FLAGS_RX_CLOSE_QUEUED) { |
||
332 | state->flags |= ALTCP_MBEDTLS_FLAGS_RX_CLOSED; |
||
333 | if (conn->recv) { |
||
334 | err = conn->recv(conn->arg, conn, NULL, ERR_OK); |
||
335 | if (err == ERR_ABRT) { |
||
336 | return ERR_ABRT; |
||
337 | } |
||
338 | } |
||
339 | } |
||
340 | |||
341 | return ERR_OK; |
||
342 | } |
||
343 | |||
344 | /* Helper function that processes rx application data stored in rx pbuf chain */ |
||
345 | static err_t |
||
346 | altcp_mbedtls_handle_rx_appldata(struct altcp_pcb *conn, altcp_mbedtls_state_t *state) |
||
347 | { |
||
348 | int ret; |
||
349 | LWIP_ASSERT("state != NULL", state != NULL); |
||
350 | if (!(state->flags & ALTCP_MBEDTLS_FLAGS_HANDSHAKE_DONE)) { |
||
351 | /* handshake not done yet */ |
||
352 | return ERR_VAL; |
||
353 | } |
||
354 | do { |
||
355 | /* allocate a full-sized unchained PBUF_POOL: this is for RX! */ |
||
356 | struct pbuf *buf = pbuf_alloc(PBUF_RAW, PBUF_POOL_BUFSIZE, PBUF_POOL); |
||
357 | if (buf == NULL) { |
||
358 | /* We're short on pbufs, try again later from 'poll' or 'recv' callbacks. |
||
359 | @todo: close on excessive allocation failures or leave this up to upper conn? */ |
||
360 | return ERR_OK; |
||
361 | } |
||
362 | |||
363 | /* decrypt application data, this pulls encrypted RX data off state->rx pbuf chain */ |
||
364 | ret = mbedtls_ssl_read(&state->ssl_context, (unsigned char *)buf->payload, PBUF_POOL_BUFSIZE); |
||
365 | if (ret < 0) { |
||
366 | if (ret == MBEDTLS_ERR_SSL_CLIENT_RECONNECT) { |
||
367 | /* client is initiating a new connection using the same source port -> close connection or make handshake */ |
||
368 | LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("new connection on same source port\n")); |
||
369 | LWIP_ASSERT("TODO: new connection on same source port, close this connection", 0); |
||
370 | } else if ((ret != MBEDTLS_ERR_SSL_WANT_READ) && (ret != MBEDTLS_ERR_SSL_WANT_WRITE)) { |
||
371 | if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) { |
||
372 | LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("connection was closed gracefully\n")); |
||
373 | } else if (ret == MBEDTLS_ERR_NET_CONN_RESET) { |
||
374 | LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("connection was reset by peer\n")); |
||
375 | } |
||
376 | pbuf_free(buf); |
||
377 | return ERR_OK; |
||
378 | } else { |
||
379 | pbuf_free(buf); |
||
380 | return ERR_OK; |
||
381 | } |
||
382 | pbuf_free(buf); |
||
383 | altcp_abort(conn); |
||
384 | return ERR_ABRT; |
||
385 | } else { |
||
386 | err_t err; |
||
387 | if (ret) { |
||
388 | LWIP_ASSERT("bogus receive length", ret <= PBUF_POOL_BUFSIZE); |
||
389 | /* trim pool pbuf to actually decoded length */ |
||
390 | pbuf_realloc(buf, (u16_t)ret); |
||
391 | |||
392 | state->bio_bytes_appl += ret; |
||
393 | if (mbedtls_ssl_get_bytes_avail(&state->ssl_context) == 0) { |
||
394 | /* Record is done, now we know the share between application and protocol bytes |
||
395 | and can adjust the RX window by the protocol bytes. |
||
396 | The rest is 'recved' by the application calling our 'recved' fn. */ |
||
397 | int overhead_bytes; |
||
398 | LWIP_ASSERT("bogus byte counts", state->bio_bytes_read > state->bio_bytes_appl); |
||
399 | overhead_bytes = state->bio_bytes_read - state->bio_bytes_appl; |
||
400 | altcp_mbedtls_lower_recved(conn->inner_conn, overhead_bytes); |
||
401 | state->bio_bytes_read = 0; |
||
402 | state->bio_bytes_appl = 0; |
||
403 | } |
||
404 | |||
405 | if (state->rx_app == NULL) { |
||
406 | state->rx_app = buf; |
||
407 | } else { |
||
408 | pbuf_cat(state->rx_app, buf); |
||
409 | } |
||
410 | } else { |
||
411 | pbuf_free(buf); |
||
412 | buf = NULL; |
||
413 | } |
||
414 | err = altcp_mbedtls_pass_rx_data(conn, state); |
||
415 | if (err != ERR_OK) { |
||
416 | if (err == ERR_ABRT) { |
||
417 | /* recv callback needs to return this as the pcb is deallocated */ |
||
418 | return ERR_ABRT; |
||
419 | } |
||
420 | /* we hide all other errors as we retry feeding the pbuf to the app later */ |
||
421 | return ERR_OK; |
||
422 | } |
||
423 | } |
||
424 | } while (ret > 0); |
||
425 | return ERR_OK; |
||
426 | } |
||
427 | |||
428 | /** Receive callback function called from mbedtls (set via mbedtls_ssl_set_bio) |
||
429 | * This function mainly copies data from pbufs and frees the pbufs after copying. |
||
430 | */ |
||
431 | static int |
||
432 | altcp_mbedtls_bio_recv(void *ctx, unsigned char *buf, size_t len) |
||
433 | { |
||
434 | struct altcp_pcb *conn = (struct altcp_pcb *)ctx; |
||
435 | altcp_mbedtls_state_t *state; |
||
436 | struct pbuf *p; |
||
437 | u16_t ret; |
||
438 | u16_t copy_len; |
||
439 | err_t err; |
||
440 | |||
441 | if ((conn == NULL) || (conn->state == NULL)) { |
||
442 | return MBEDTLS_ERR_NET_INVALID_CONTEXT; |
||
443 | } |
||
444 | state = (altcp_mbedtls_state_t *)conn->state; |
||
445 | p = state->rx; |
||
446 | |||
447 | /* @todo: return MBEDTLS_ERR_NET_CONN_RESET/MBEDTLS_ERR_NET_RECV_FAILED? */ |
||
448 | |||
449 | if ((p == NULL) || ((p->len == 0) && (p->next == NULL))) { |
||
450 | if (p) { |
||
451 | pbuf_free(p); |
||
452 | } |
||
453 | state->rx = NULL; |
||
454 | if ((state->flags & (ALTCP_MBEDTLS_FLAGS_RX_CLOSE_QUEUED | ALTCP_MBEDTLS_FLAGS_RX_CLOSED)) == |
||
455 | ALTCP_MBEDTLS_FLAGS_RX_CLOSE_QUEUED) { |
||
456 | /* close queued but not passed up yet */ |
||
457 | return 0; |
||
458 | } |
||
459 | return MBEDTLS_ERR_SSL_WANT_READ; |
||
460 | } |
||
461 | /* limit number of bytes again to copy from first pbuf in a chain only */ |
||
462 | copy_len = (u16_t)LWIP_MIN(len, p->len); |
||
463 | /* copy the data */ |
||
464 | ret = pbuf_copy_partial(p, buf, copy_len, 0); |
||
465 | LWIP_ASSERT("ret == copy_len", ret == copy_len); |
||
466 | /* hide the copied bytes from the pbuf */ |
||
467 | err = pbuf_remove_header(p, ret); |
||
468 | LWIP_ASSERT("error", err == ERR_OK); |
||
469 | if (p->len == 0) { |
||
470 | /* the first pbuf has been fully read, free it */ |
||
471 | state->rx = p->next; |
||
472 | p->next = NULL; |
||
473 | pbuf_free(p); |
||
474 | } |
||
475 | |||
476 | state->bio_bytes_read += (int)ret; |
||
477 | return ret; |
||
478 | } |
||
479 | |||
480 | /** Sent callback from lower connection (i.e. TCP) |
||
481 | * This only informs the upper layer to try to send more, not about |
||
482 | * the number of ACKed bytes. |
||
483 | */ |
||
484 | static err_t |
||
485 | altcp_mbedtls_lower_sent(void *arg, struct altcp_pcb *inner_conn, u16_t len) |
||
486 | { |
||
487 | struct altcp_pcb *conn = (struct altcp_pcb *)arg; |
||
488 | LWIP_UNUSED_ARG(len); |
||
489 | if (conn) { |
||
490 | altcp_mbedtls_state_t *state = (altcp_mbedtls_state_t *)conn->state; |
||
491 | LWIP_ASSERT("pcb mismatch", conn->inner_conn == inner_conn); |
||
492 | if (!state || !(state->flags & ALTCP_MBEDTLS_FLAGS_HANDSHAKE_DONE)) { |
||
493 | /* @todo: do something here? */ |
||
494 | return ERR_OK; |
||
495 | } |
||
496 | /* try to send more if we failed before */ |
||
497 | mbedtls_ssl_flush_output(&state->ssl_context); |
||
498 | /* call upper sent with len==0 if the application already sent data */ |
||
499 | if ((state->flags & ALTCP_MBEDTLS_FLAGS_APPLDATA_SENT) && conn->sent) { |
||
500 | return conn->sent(conn->arg, conn, 0); |
||
501 | } |
||
502 | } |
||
503 | return ERR_OK; |
||
504 | } |
||
505 | |||
506 | /** Poll callback from lower connection (i.e. TCP) |
||
507 | * Just pass this on to the application. |
||
508 | * @todo: retry sending? |
||
509 | */ |
||
510 | static err_t |
||
511 | altcp_mbedtls_lower_poll(void *arg, struct altcp_pcb *inner_conn) |
||
512 | { |
||
513 | struct altcp_pcb *conn = (struct altcp_pcb *)arg; |
||
514 | if (conn) { |
||
515 | LWIP_ASSERT("pcb mismatch", conn->inner_conn == inner_conn); |
||
516 | /* check if there's unreceived rx data */ |
||
517 | if (conn->state) { |
||
518 | altcp_mbedtls_state_t *state = (altcp_mbedtls_state_t *)conn->state; |
||
519 | /* try to send more if we failed before */ |
||
520 | mbedtls_ssl_flush_output(&state->ssl_context); |
||
521 | if (altcp_mbedtls_handle_rx_appldata(conn, state) == ERR_ABRT) { |
||
522 | return ERR_ABRT; |
||
523 | } |
||
524 | } |
||
525 | if (conn->poll) { |
||
526 | return conn->poll(conn->arg, conn); |
||
527 | } |
||
528 | } |
||
529 | return ERR_OK; |
||
530 | } |
||
531 | |||
532 | static void |
||
533 | altcp_mbedtls_lower_err(void *arg, err_t err) |
||
534 | { |
||
535 | struct altcp_pcb *conn = (struct altcp_pcb *)arg; |
||
536 | if (conn) { |
||
537 | conn->inner_conn = NULL; /* already freed */ |
||
538 | if (conn->err) { |
||
539 | conn->err(conn->arg, err); |
||
540 | } |
||
541 | altcp_free(conn); |
||
542 | } |
||
543 | } |
||
544 | |||
545 | /* setup functions */ |
||
546 | static void |
||
547 | altcp_mbedtls_setup_callbacks(struct altcp_pcb *conn, struct altcp_pcb *inner_conn) |
||
548 | { |
||
549 | altcp_arg(inner_conn, conn); |
||
550 | altcp_recv(inner_conn, altcp_mbedtls_lower_recv); |
||
551 | altcp_sent(inner_conn, altcp_mbedtls_lower_sent); |
||
552 | altcp_err(inner_conn, altcp_mbedtls_lower_err); |
||
553 | /* tcp_poll is set when interval is set by application */ |
||
554 | /* listen is set totally different :-) */ |
||
555 | } |
||
556 | |||
557 | static err_t |
||
558 | altcp_mbedtls_setup(void *conf, struct altcp_pcb *conn, struct altcp_pcb *inner_conn) |
||
559 | { |
||
560 | int ret; |
||
561 | struct altcp_tls_config *config = (struct altcp_tls_config *)conf; |
||
562 | altcp_mbedtls_state_t *state; |
||
563 | if (!conf) { |
||
564 | return ERR_ARG; |
||
565 | } |
||
566 | /* allocate mbedtls context */ |
||
567 | state = altcp_mbedtls_alloc(conf); |
||
568 | if (state == NULL) { |
||
569 | return ERR_MEM; |
||
570 | } |
||
571 | /* initialize mbedtls context: */ |
||
572 | mbedtls_ssl_init(&state->ssl_context); |
||
573 | ret = mbedtls_ssl_setup(&state->ssl_context, &config->conf); |
||
574 | if (ret != 0) { |
||
575 | LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_ssl_setup failed\n")); |
||
576 | /* @todo: convert 'ret' to err_t */ |
||
577 | altcp_mbedtls_free(conf, state); |
||
578 | return ERR_MEM; |
||
579 | } |
||
580 | /* tell mbedtls about our I/O functions */ |
||
581 | mbedtls_ssl_set_bio(&state->ssl_context, conn, altcp_mbedtls_bio_send, altcp_mbedtls_bio_recv, NULL); |
||
582 | |||
583 | altcp_mbedtls_setup_callbacks(conn, inner_conn); |
||
584 | conn->inner_conn = inner_conn; |
||
585 | conn->fns = &altcp_mbedtls_functions; |
||
586 | conn->state = state; |
||
587 | return ERR_OK; |
||
588 | } |
||
589 | |||
590 | struct altcp_pcb * |
||
591 | altcp_tls_new(struct altcp_tls_config *config, struct altcp_pcb *inner_pcb) |
||
592 | { |
||
593 | struct altcp_pcb *ret; |
||
594 | if (inner_pcb == NULL) { |
||
595 | return NULL; |
||
596 | } |
||
597 | ret = altcp_alloc(); |
||
598 | if (ret != NULL) { |
||
599 | if (altcp_mbedtls_setup(config, ret, inner_pcb) != ERR_OK) { |
||
600 | altcp_free(ret); |
||
601 | return NULL; |
||
602 | } |
||
603 | } |
||
604 | return ret; |
||
605 | } |
||
606 | |||
607 | void * |
||
608 | altcp_tls_context(struct altcp_pcb *conn) |
||
609 | { |
||
610 | if (conn && conn->state) { |
||
611 | altcp_mbedtls_state_t *state = (altcp_mbedtls_state_t *)conn->state; |
||
612 | return &state->ssl_context; |
||
613 | } |
||
614 | return NULL; |
||
615 | } |
||
616 | |||
617 | #if ALTCP_MBEDTLS_DEBUG != LWIP_DBG_OFF |
||
618 | static void |
||
619 | altcp_mbedtls_debug(void *ctx, int level, const char *file, int line, const char *str) |
||
620 | { |
||
621 | LWIP_UNUSED_ARG(str); |
||
622 | LWIP_UNUSED_ARG(level); |
||
623 | LWIP_UNUSED_ARG(file); |
||
624 | LWIP_UNUSED_ARG(line); |
||
625 | LWIP_UNUSED_ARG(ctx); |
||
626 | /* @todo: output debug string :-) */ |
||
627 | } |
||
628 | #endif |
||
629 | |||
630 | #ifndef ALTCP_MBEDTLS_RNG_FN |
||
631 | /** ATTENTION: It is *really* important to *NOT* use this dummy RNG in production code!!!! */ |
||
632 | static int |
||
633 | dummy_rng(void *ctx, unsigned char *buffer, size_t len) |
||
634 | { |
||
635 | static size_t ctr; |
||
636 | size_t i; |
||
637 | LWIP_UNUSED_ARG(ctx); |
||
638 | for (i = 0; i < len; i++) { |
||
639 | buffer[i] = (unsigned char)++ctr; |
||
640 | } |
||
641 | return 0; |
||
642 | } |
||
643 | #define ALTCP_MBEDTLS_RNG_FN dummy_rng |
||
644 | #endif /* ALTCP_MBEDTLS_RNG_FN */ |
||
645 | |||
646 | /** Create new TLS configuration |
||
647 | * ATTENTION: Server certificate and private key have to be added outside this function! |
||
648 | */ |
||
649 | static struct altcp_tls_config * |
||
650 | altcp_tls_create_config(int is_server) |
||
651 | { |
||
652 | int ret; |
||
653 | struct altcp_tls_config *conf; |
||
654 | |||
655 | altcp_mbedtls_mem_init(); |
||
656 | |||
657 | conf = (struct altcp_tls_config *)altcp_mbedtls_alloc_config(sizeof(struct altcp_tls_config)); |
||
658 | if (conf == NULL) { |
||
659 | return NULL; |
||
660 | } |
||
661 | |||
662 | mbedtls_ssl_config_init(&conf->conf); |
||
663 | mbedtls_entropy_init(&conf->entropy); |
||
664 | mbedtls_ctr_drbg_init(&conf->ctr_drbg); |
||
665 | |||
666 | /* Seed the RNG */ |
||
667 | ret = mbedtls_ctr_drbg_seed(&conf->ctr_drbg, ALTCP_MBEDTLS_RNG_FN, &conf->entropy, ALTCP_MBEDTLS_ENTROPY_PTR, ALTCP_MBEDTLS_ENTROPY_LEN); |
||
668 | if (ret != 0) { |
||
669 | LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_ctr_drbg_seed failed: %d\n", ret)); |
||
670 | altcp_mbedtls_free_config(conf); |
||
671 | return NULL; |
||
672 | } |
||
673 | |||
674 | /* Setup ssl context (@todo: what's different for a client here? -> might better be done on listen/connect) */ |
||
675 | ret = mbedtls_ssl_config_defaults(&conf->conf, is_server ? MBEDTLS_SSL_IS_SERVER : MBEDTLS_SSL_IS_CLIENT, |
||
676 | MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT); |
||
677 | if (ret != 0) { |
||
678 | LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_ssl_config_defaults failed: %d\n", ret)); |
||
679 | altcp_mbedtls_free_config(conf); |
||
680 | return NULL; |
||
681 | } |
||
682 | mbedtls_ssl_conf_authmode(&conf->conf, MBEDTLS_SSL_VERIFY_OPTIONAL); |
||
683 | |||
684 | mbedtls_ssl_conf_rng(&conf->conf, mbedtls_ctr_drbg_random, &conf->ctr_drbg); |
||
685 | #if ALTCP_MBEDTLS_DEBUG != LWIP_DBG_OFF |
||
686 | mbedtls_ssl_conf_dbg(&conf->conf, altcp_mbedtls_debug, stdout); |
||
687 | #endif |
||
688 | #if defined(MBEDTLS_SSL_CACHE_C) && ALTCP_MBEDTLS_SESSION_CACHE_TIMEOUT_SECONDS |
||
689 | mbedtls_ssl_conf_session_cache(&conf->conf, &conf->cache, mbedtls_ssl_cache_get, mbedtls_ssl_cache_set); |
||
690 | mbedtls_ssl_cache_set_timeout(&conf->cache, 30); |
||
691 | mbedtls_ssl_cache_set_max_entries(&conf->cache, 30); |
||
692 | #endif |
||
693 | |||
694 | return conf; |
||
695 | } |
||
696 | |||
697 | /** Create new TLS configuration |
||
698 | * This is a suboptimal version that gets the encrypted private key and its password, |
||
699 | * as well as the server certificate. |
||
700 | */ |
||
701 | struct altcp_tls_config * |
||
702 | altcp_tls_create_config_server_privkey_cert(const u8_t *privkey, size_t privkey_len, |
||
703 | const u8_t *privkey_pass, size_t privkey_pass_len, |
||
704 | const u8_t *cert, size_t cert_len) |
||
705 | { |
||
706 | int ret; |
||
707 | static mbedtls_x509_crt srvcert; |
||
708 | static mbedtls_pk_context pkey; |
||
709 | struct altcp_tls_config *conf = altcp_tls_create_config(1); |
||
710 | if (conf == NULL) { |
||
711 | return NULL; |
||
712 | } |
||
713 | |||
714 | mbedtls_x509_crt_init(&srvcert); |
||
715 | mbedtls_pk_init(&pkey); |
||
716 | |||
717 | /* Load the certificates and private key */ |
||
718 | ret = mbedtls_x509_crt_parse(&srvcert, cert, cert_len); |
||
719 | if (ret != 0) { |
||
720 | LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_x509_crt_parse failed: %d\n", ret)); |
||
721 | altcp_mbedtls_free_config(conf); |
||
722 | return NULL; |
||
723 | } |
||
724 | |||
725 | ret = mbedtls_pk_parse_key(&pkey, (const unsigned char *) privkey, privkey_len, privkey_pass, privkey_pass_len); |
||
726 | if (ret != 0) { |
||
727 | LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_pk_parse_public_key failed: %d\n", ret)); |
||
728 | altcp_mbedtls_free_config(conf); |
||
729 | return NULL; |
||
730 | } |
||
731 | |||
732 | mbedtls_ssl_conf_ca_chain(&conf->conf, srvcert.next, NULL); |
||
733 | ret = mbedtls_ssl_conf_own_cert(&conf->conf, &srvcert, &pkey); |
||
734 | if (ret != 0) { |
||
735 | LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_ssl_conf_own_cert failed: %d\n", ret)); |
||
736 | altcp_mbedtls_free_config(conf); |
||
737 | return NULL; |
||
738 | } |
||
739 | return conf; |
||
740 | } |
||
741 | |||
742 | struct altcp_tls_config * |
||
743 | altcp_tls_create_config_client(const u8_t *cert, size_t cert_len) |
||
744 | { |
||
745 | int ret; |
||
746 | static mbedtls_x509_crt acc_cert; |
||
747 | struct altcp_tls_config *conf = altcp_tls_create_config(0); |
||
748 | if (conf == NULL) { |
||
749 | return NULL; |
||
750 | } |
||
751 | |||
752 | mbedtls_x509_crt_init(&acc_cert); |
||
753 | |||
754 | /* Load the certificates */ |
||
755 | ret = mbedtls_x509_crt_parse(&acc_cert, cert, cert_len); |
||
756 | if (ret != 0) { |
||
757 | LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_x509_crt_parse failed: %d", ret)); |
||
758 | altcp_mbedtls_free_config(conf); |
||
759 | return NULL; |
||
760 | } |
||
761 | |||
762 | mbedtls_ssl_conf_ca_chain(&conf->conf, &acc_cert, NULL); |
||
763 | return conf; |
||
764 | } |
||
765 | |||
766 | void |
||
767 | altcp_tls_free_config(struct altcp_tls_config *conf) |
||
768 | { |
||
769 | altcp_mbedtls_free_config(conf); |
||
770 | } |
||
771 | |||
772 | /* "virtual" functions */ |
||
773 | static void |
||
774 | altcp_mbedtls_set_poll(struct altcp_pcb *conn, u8_t interval) |
||
775 | { |
||
776 | if (conn != NULL) { |
||
777 | altcp_poll(conn->inner_conn, altcp_mbedtls_lower_poll, interval); |
||
778 | } |
||
779 | } |
||
780 | |||
781 | static void |
||
782 | altcp_mbedtls_recved(struct altcp_pcb *conn, u16_t len) |
||
783 | { |
||
784 | u16_t lower_recved; |
||
785 | altcp_mbedtls_state_t *state; |
||
786 | if (conn == NULL) { |
||
787 | return; |
||
788 | } |
||
789 | state = (altcp_mbedtls_state_t *)conn->state; |
||
790 | if (state == NULL) { |
||
791 | return; |
||
792 | } |
||
793 | if (!(state->flags & ALTCP_MBEDTLS_FLAGS_HANDSHAKE_DONE)) { |
||
794 | return; |
||
795 | } |
||
796 | lower_recved = len; |
||
797 | if (lower_recved > state->rx_passed_unrecved) { |
||
798 | LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("bogus recved count (len > state->rx_passed_unrecved / %d / %d)", |
||
799 | len, state->rx_passed_unrecved)); |
||
800 | lower_recved = (u16_t)state->rx_passed_unrecved; |
||
801 | } |
||
802 | state->rx_passed_unrecved -= lower_recved; |
||
803 | |||
804 | altcp_recved(conn->inner_conn, lower_recved); |
||
805 | } |
||
806 | |||
807 | static err_t |
||
808 | altcp_mbedtls_connect(struct altcp_pcb *conn, const ip_addr_t *ipaddr, u16_t port, altcp_connected_fn connected) |
||
809 | { |
||
810 | if (conn == NULL) { |
||
811 | return ERR_VAL; |
||
812 | } |
||
813 | conn->connected = connected; |
||
814 | return altcp_connect(conn->inner_conn, ipaddr, port, altcp_mbedtls_lower_connected); |
||
815 | } |
||
816 | |||
817 | static struct altcp_pcb * |
||
818 | altcp_mbedtls_listen(struct altcp_pcb *conn, u8_t backlog, err_t *err) |
||
819 | { |
||
820 | struct altcp_pcb *lpcb; |
||
821 | if (conn == NULL) { |
||
822 | return NULL; |
||
823 | } |
||
824 | lpcb = altcp_listen_with_backlog_and_err(conn->inner_conn, backlog, err); |
||
825 | if (lpcb != NULL) { |
||
826 | conn->inner_conn = lpcb; |
||
827 | altcp_accept(lpcb, altcp_mbedtls_lower_accept); |
||
828 | return conn; |
||
829 | } |
||
830 | return NULL; |
||
831 | } |
||
832 | |||
833 | static void |
||
834 | altcp_mbedtls_abort(struct altcp_pcb *conn) |
||
835 | { |
||
836 | if (conn != NULL) { |
||
837 | altcp_abort(conn->inner_conn); |
||
838 | } |
||
839 | } |
||
840 | |||
841 | static err_t |
||
842 | altcp_mbedtls_close(struct altcp_pcb *conn) |
||
843 | { |
||
844 | altcp_mbedtls_state_t *state; |
||
845 | if (conn == NULL) { |
||
846 | return ERR_VAL; |
||
847 | } |
||
848 | state = (altcp_mbedtls_state_t *)conn->state; |
||
849 | if (state != NULL) { |
||
850 | state->flags |= ALTCP_MBEDTLS_FLAGS_TX_CLOSED; |
||
851 | if (state->flags & ALTCP_MBEDTLS_FLAGS_RX_CLOSED) { |
||
852 | altcp_mbedtls_dealloc(conn); |
||
853 | } |
||
854 | } |
||
855 | return altcp_close(conn->inner_conn); |
||
856 | } |
||
857 | |||
858 | /** Write data to a TLS connection. Calls into mbedTLS, which in turn calls into |
||
859 | * @ref altcp_mbedtls_bio_send() to send the encrypted data |
||
860 | */ |
||
861 | static err_t |
||
862 | altcp_mbedtls_write(struct altcp_pcb *conn, const void *dataptr, u16_t len, u8_t apiflags) |
||
863 | { |
||
864 | int ret; |
||
865 | altcp_mbedtls_state_t *state; |
||
866 | |||
867 | LWIP_UNUSED_ARG(apiflags); |
||
868 | |||
869 | if (conn == NULL) { |
||
870 | return ERR_VAL; |
||
871 | } |
||
872 | |||
873 | state = (altcp_mbedtls_state_t *)conn->state; |
||
874 | if (state == NULL) { |
||
875 | /* @todo: which error? */ |
||
876 | return ERR_CLSD; |
||
877 | } |
||
878 | if (!(state->flags & ALTCP_MBEDTLS_FLAGS_HANDSHAKE_DONE)) { |
||
879 | /* @todo: which error? */ |
||
880 | return ERR_VAL; |
||
881 | } |
||
882 | |||
883 | /* HACK: if thre is something left to send, try to flush it and only |
||
884 | allow sending more if this succeeded (this is a hack because neither |
||
885 | returning 0 nor MBEDTLS_ERR_SSL_WANT_WRITE worked for me) */ |
||
886 | if (state->ssl_context.out_left) { |
||
887 | mbedtls_ssl_flush_output(&state->ssl_context); |
||
888 | if (state->ssl_context.out_left) { |
||
889 | return ERR_MEM; |
||
890 | } |
||
891 | } |
||
892 | ret = mbedtls_ssl_write(&state->ssl_context, (const unsigned char *)dataptr, len); |
||
893 | /* try to send data... */ |
||
894 | altcp_output(conn->inner_conn); |
||
895 | if (ret >= 0) { |
||
896 | if (ret == len) { |
||
897 | state->flags |= ALTCP_MBEDTLS_FLAGS_APPLDATA_SENT; |
||
898 | return ERR_OK; |
||
899 | } else { |
||
900 | /* @todo/@fixme: assumption: either everything sent or error */ |
||
901 | LWIP_ASSERT("ret <= 0", 0); |
||
902 | return ERR_MEM; |
||
903 | } |
||
904 | } else { |
||
905 | if (ret == MBEDTLS_ERR_SSL_WANT_WRITE) { |
||
906 | /* @todo: convert error to err_t */ |
||
907 | return ERR_MEM; |
||
908 | } |
||
909 | LWIP_ASSERT("unhandled error", 0); |
||
910 | return ERR_VAL; |
||
911 | } |
||
912 | } |
||
913 | |||
914 | /** Send callback function called from mbedtls (set via mbedtls_ssl_set_bio) |
||
915 | * This function is either called during handshake or when sending application |
||
916 | * data via @ref altcp_mbedtls_write (or altcp_write) |
||
917 | */ |
||
918 | static int |
||
919 | altcp_mbedtls_bio_send(void *ctx, const unsigned char *dataptr, size_t size) |
||
920 | { |
||
921 | struct altcp_pcb *conn = (struct altcp_pcb *) ctx; |
||
922 | int written = 0; |
||
923 | size_t size_left = size; |
||
924 | u8_t apiflags = TCP_WRITE_FLAG_COPY; |
||
925 | |||
926 | LWIP_ASSERT("conn != NULL", conn != NULL); |
||
927 | if ((conn == NULL) || (conn->inner_conn == NULL)) { |
||
928 | return MBEDTLS_ERR_NET_INVALID_CONTEXT; |
||
929 | } |
||
930 | |||
931 | while (size_left) { |
||
932 | u16_t write_len = (u16_t)LWIP_MIN(size_left, 0xFFFF); |
||
933 | err_t err = altcp_write(conn->inner_conn, (const void *)dataptr, write_len, apiflags); |
||
934 | if (err == ERR_OK) { |
||
935 | written += write_len; |
||
936 | size_left -= write_len; |
||
937 | } else if (err == ERR_MEM) { |
||
938 | if (written) { |
||
939 | return written; |
||
940 | } |
||
941 | return 0; /* MBEDTLS_ERR_SSL_WANT_WRITE; */ |
||
942 | } else { |
||
943 | LWIP_ASSERT("tls_write, tcp_write: err != ERR MEM", 0); |
||
944 | /* @todo: return MBEDTLS_ERR_NET_CONN_RESET or MBEDTLS_ERR_NET_SEND_FAILED */ |
||
945 | return MBEDTLS_ERR_NET_SEND_FAILED; |
||
946 | } |
||
947 | } |
||
948 | return written; |
||
949 | } |
||
950 | |||
951 | static u16_t |
||
952 | altcp_mbedtls_mss(struct altcp_pcb *conn) |
||
953 | { |
||
954 | if (conn == NULL) { |
||
955 | return 0; |
||
956 | } |
||
957 | /* @todo: LWIP_MIN(mss, mbedtls_ssl_get_max_frag_len()) ? */ |
||
958 | return altcp_mss(conn->inner_conn); |
||
959 | } |
||
960 | |||
961 | static void |
||
962 | altcp_mbedtls_dealloc(struct altcp_pcb *conn) |
||
963 | { |
||
964 | /* clean up and free tls state */ |
||
965 | if (conn) { |
||
966 | altcp_mbedtls_state_t *state = (altcp_mbedtls_state_t *)conn->state; |
||
967 | if (state) { |
||
968 | mbedtls_ssl_free(&state->ssl_context); |
||
969 | state->flags = 0; |
||
970 | altcp_mbedtls_free(state->conf, state); |
||
971 | conn->state = NULL; |
||
972 | } |
||
973 | if (conn->inner_conn) { |
||
974 | altcp_free(conn->inner_conn); |
||
975 | conn->inner_conn = NULL; |
||
976 | } |
||
977 | } |
||
978 | } |
||
979 | |||
980 | const struct altcp_functions altcp_mbedtls_functions = { |
||
981 | altcp_mbedtls_set_poll, |
||
982 | altcp_mbedtls_recved, |
||
983 | altcp_default_bind, |
||
984 | altcp_mbedtls_connect, |
||
985 | altcp_mbedtls_listen, |
||
986 | altcp_mbedtls_abort, |
||
987 | altcp_mbedtls_close, |
||
988 | altcp_default_shutdown, |
||
989 | altcp_mbedtls_write, |
||
990 | altcp_default_output, |
||
991 | altcp_mbedtls_mss, |
||
992 | altcp_default_sndbuf, |
||
993 | altcp_default_sndqueuelen, |
||
994 | altcp_default_nagle_disable, |
||
995 | altcp_default_nagle_enable, |
||
996 | altcp_default_nagle_disabled, |
||
997 | altcp_default_setprio, |
||
998 | altcp_mbedtls_dealloc, |
||
999 | altcp_default_get_tcp_addrinfo, |
||
1000 | altcp_default_get_ip, |
||
1001 | altcp_default_get_port |
||
1002 | #ifdef LWIP_DEBUG |
||
1003 | , altcp_default_dbg_get_tcp_state |
||
1004 | #endif |
||
1005 | }; |
||
1006 | |||
1007 | #endif /* LWIP_ALTCP_TLS && LWIP_ALTCP_TLS_MBEDTLS */ |
||
1008 | #endif /* LWIP_ALTCP */ |