Coverage Report

Created: 2026-08-15 06:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wolfssl/src/wolfio.c
Line
Count
Source
1
/* wolfio.c
2
 *
3
 * Copyright (C) 2006-2026 wolfSSL Inc.
4
 *
5
 * This file is part of wolfSSL.
6
 *
7
 * wolfSSL is free software; you can redistribute it and/or modify
8
 * it under the terms of the GNU General Public License as published by
9
 * the Free Software Foundation; either version 3 of the License, or
10
 * (at your option) any later version.
11
 *
12
 * wolfSSL is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
20
 */
21
22
23
#ifndef WOLFSSL_STRERROR_BUFFER_SIZE
24
#define WOLFSSL_STRERROR_BUFFER_SIZE 256
25
#endif
26
27
#include <wolfssl/wolfcrypt/libwolfssl_sources.h>
28
29
#ifndef WOLFCRYPT_ONLY
30
31
#if defined(HAVE_ERRNO_H) && defined(WOLFSSL_NO_SOCK) && \
32
    (defined(USE_WOLFSSL_IO) || defined(HAVE_HTTP_CLIENT))
33
    /* error codes are needed for TranslateIoReturnCode() and
34
     * wolfIO_TcpConnect() even if defined(WOLFSSL_NO_SOCK), which inhibits
35
     * inclusion of errno.h by wolfio.h.
36
     */
37
    #include <errno.h>
38
#endif
39
40
#include <wolfssl/internal.h>
41
#include <wolfssl/error-ssl.h>
42
#include <wolfssl/wolfio.h>
43
#include <wolfssl/wolfcrypt/logging.h>
44
45
46
#ifdef NUCLEUS_PLUS_2_3
47
/* Holds last Nucleus networking error number */
48
int Nucleus_Net_Errno;
49
#endif
50
51
#if defined(USE_WOLFSSL_IO) || defined(HAVE_HTTP_CLIENT)
52
    #ifdef USE_WINDOWS_API
53
        #include <winsock2.h>
54
    #else
55
        #if defined(WOLFSSL_LWIP) && !defined(WOLFSSL_APACHE_MYNEWT)
56
        #elif defined(ARDUINO)
57
        #elif defined(FREESCALE_MQX)
58
        #elif defined(FREESCALE_KSDK_MQX)
59
        #elif (defined(WOLFSSL_MDK_ARM) || defined(WOLFSSL_KEIL_TCP_NET))
60
        #elif defined(WOLFSSL_CMSIS_RTOS)
61
        #elif defined(WOLFSSL_CMSIS_RTOSv2)
62
        #elif defined(WOLFSSL_TIRTOS)
63
        #elif defined(FREERTOS_TCP)
64
        #elif defined(WOLFSSL_IAR_ARM)
65
        #elif defined(HAVE_NETX_BSD)
66
        #elif defined(WOLFSSL_VXWORKS)
67
        #elif defined(WOLFSSL_NUCLEUS_1_2)
68
        #elif defined(WOLFSSL_LINUXKM)
69
            /* the requisite linux/net.h is included in wc_port.h, with incompatible warnings masked out. */
70
        #elif defined(WOLFSSL_ATMEL)
71
        #elif defined(INTIME_RTOS)
72
            #include <netdb.h>
73
        #elif defined(WOLFSSL_PRCONNECT_PRO)
74
            #include <netdb.h>
75
            #include <sys/ioctl.h>
76
        #elif defined(WOLFSSL_SGX)
77
        #elif defined(WOLFSSL_APACHE_MYNEWT) && !defined(WOLFSSL_LWIP)
78
        #elif defined(WOLFSSL_DEOS)
79
        #elif defined(WOLFSSL_ZEPHYR)
80
        #elif defined(MICROCHIP_PIC32)
81
        #elif defined(HAVE_NETX)
82
        #elif defined(FUSION_RTOS)
83
        #elif !defined(WOLFSSL_NO_SOCK)
84
            #if defined(HAVE_RTP_SYS)
85
            #elif defined(EBSNET)
86
            #elif defined(NETOS)
87
            #elif !defined(DEVKITPRO) && !defined(WOLFSSL_PICOTCP) \
88
                    && !defined(WOLFSSL_CONTIKI) && !defined(WOLFSSL_WICED) \
89
                    && !defined(WOLFSSL_GNRC) && !defined(WOLFSSL_RIOT_OS)
90
                #ifdef HAVE_NETDB_H
91
                    #include <netdb.h>
92
                #endif
93
                #ifdef __PPU
94
                    #include <netex/errno.h>
95
                #else
96
                    #ifdef HAVE_SYS_IOCTL_H
97
                        #include <sys/ioctl.h>
98
                    #endif
99
                #endif
100
            #endif
101
        #endif
102
103
    #endif /* USE_WINDOWS_API */
104
#endif /* defined(USE_WOLFSSL_IO) || defined(HAVE_HTTP_CLIENT) */
105
106
107
#if defined(HAVE_HTTP_CLIENT)
108
    #include <stdlib.h>   /* strtol() */
109
#endif
110
111
/*
112
Possible IO enable options:
113
 * WOLFSSL_USER_IO:     Disables default Embed* callbacks and     default: off
114
                        allows user to define their own using
115
                        wolfSSL_CTX_SetIORecv and wolfSSL_CTX_SetIOSend
116
 * USE_WOLFSSL_IO:      Enables the wolfSSL IO functions          default: on
117
 * HAVE_HTTP_CLIENT:    Enables HTTP client API's                 default: off
118
                                     (unless HAVE_OCSP or HAVE_CRL_IO defined)
119
 * HAVE_IO_TIMEOUT:     Enables support for connect timeout       default: off
120
 *
121
 * DTLS_RECEIVEFROM_NO_TIMEOUT_ON_INVALID_PEER: This flag has effect only if
122
 * ASN_NO_TIME is enabled. If enabled invalid peers messages are ignored
123
 * indefinitely. If not enabled EmbedReceiveFrom will return timeout after
124
 * DTLS_RECEIVEFROM_MAX_INVALID_PEER number of packets from invalid peers. When
125
 * enabled, without a timer, EmbedReceivefrom can't check if the timeout is
126
 * expired and it may never return under a continuous flow of invalid packets.
127
 *                                                                default: off
128
 */
129
130
131
/* if user writes own I/O callbacks they can define WOLFSSL_USER_IO to remove
132
   automatic setting of default I/O functions EmbedSend() and EmbedReceive()
133
   but they'll still need SetCallback xxx() at end of file
134
*/
135
136
#if defined(NO_ASN_TIME) && !defined(DTLS_RECEIVEFROM_NO_TIMEOUT_ON_INVALID_PEER) \
137
  && !defined(DTLS_RECEIVEFROM_MAX_INVALID_PEER)
138
#define DTLS_RECEIVEFROM_MAX_INVALID_PEER 10
139
#endif
140
141
#if defined(USE_WOLFSSL_IO) || defined(HAVE_HTTP_CLIENT)
142
143
static WC_INLINE int wolfSSL_LastError(int err, SOCKET_T sd)
144
0
{
145
0
    (void)sd;
146
147
0
    if (err > 0)
148
0
        return 0;
149
150
#ifdef USE_WINDOWS_API
151
    return WSAGetLastError();
152
#elif defined(EBSNET)
153
    return xn_getlasterror();
154
#elif defined(WOLFSSL_LINUXKM)
155
    return -err; /* Return provided error value with corrected sign. */
156
#elif defined(WOLFSSL_EMNET)
157
    /* Any negative recv/send return is a SOCKET_ERROR sentinel under
158
     * emNET; the canonical IP_ERR_* lives in the socket SO_ERROR.
159
     * Retrieving it via IP_SOCK_getsockopt works across both emNET
160
     * integrator conventions (native: recv returns IP_ERR_* directly;
161
     * POSIX facade: recv returns -1 with errno set). If the lookup
162
     * itself fails, fall back to IP_ERR_FAULT rather than returning
163
     * the raw -1 sentinel - the latter matches no SOCKET_E* constant
164
     * and would regress into WOLFSSL_CBIO_ERR_GENERAL. */
165
    if (err < 0) {
166
        int sock_err = err;
167
        if (IP_SOCK_getsockopt(sd, SOL_SOCKET, SO_ERROR, &sock_err,
168
                               (int)sizeof(sock_err)) == 0) {
169
            err = sock_err;
170
        }
171
        else if (err == -1) {
172
            err = IP_ERR_FAULT;
173
        }
174
    }
175
    return err;
176
#elif defined(FUSION_RTOS)
177
    #include <fclerrno.h>
178
    return FCL_GET_ERRNO;
179
#elif defined(NUCLEUS_PLUS_2_3)
180
    return Nucleus_Net_Errno;
181
#elif defined(FREESCALE_MQX) || defined(FREESCALE_KSDK_MQX)
182
    if ((err == 0) || (err == -SOCKET_EWOULDBLOCK)) {
183
        return SOCKET_EWOULDBLOCK; /* convert to BSD style wouldblock */
184
    } else {
185
        err = RTCS_geterror(sd);
186
        if ((err == RTCSERR_TCP_CONN_CLOSING) ||
187
            (err == RTCSERR_TCP_CONN_RLSD))
188
        {
189
            err = SOCKET_ECONNRESET;
190
        }
191
        return err;
192
    }
193
#else
194
0
    return errno;
195
0
#endif
196
0
}
197
198
/* Translates return codes returned from
199
 * send(), recv(), and other network I/O calls.
200
 */
201
static int TranslateIoReturnCode(int err, SOCKET_T sd, int direction)
202
0
{
203
#if defined(_WIN32) && !defined(__WATCOMC__) && !defined(_WIN32_WCE) && \
204
    !defined(INTIME_RTOS)
205
    size_t errstr_offset;
206
    char errstr[WOLFSSL_STRERROR_BUFFER_SIZE];
207
#endif /* _WIN32 */
208
209
#if defined(FREESCALE_MQX) || defined(FREESCALE_KSDK_MQX)
210
    if (err > 0)
211
        return err;
212
#else
213
0
    if (err >= 0)
214
0
        return err;
215
0
#endif
216
217
0
    err = wolfSSL_LastError(err, sd);
218
219
#if SOCKET_EWOULDBLOCK != SOCKET_EAGAIN
220
    if ((err == SOCKET_EWOULDBLOCK) || (err == SOCKET_EAGAIN))
221
#else
222
0
    if (err == SOCKET_EWOULDBLOCK)
223
0
#endif
224
0
    {
225
0
        WOLFSSL_MSG("\tWould block");
226
0
        if (direction == SOCKET_SENDING)
227
0
            return WOLFSSL_CBIO_ERR_WANT_WRITE;
228
0
        else if (direction == SOCKET_RECEIVING)
229
0
            return WOLFSSL_CBIO_ERR_WANT_READ;
230
0
        else
231
0
            return WOLFSSL_CBIO_ERR_GENERAL;
232
0
    }
233
234
0
#ifdef SOCKET_ETIMEDOUT
235
0
    else if (err == SOCKET_ETIMEDOUT) {
236
0
        WOLFSSL_MSG("\tTimed out");
237
0
        if (direction == SOCKET_SENDING)
238
0
            return WOLFSSL_CBIO_ERR_WANT_WRITE;
239
0
        else if (direction == SOCKET_RECEIVING)
240
0
            return WOLFSSL_CBIO_ERR_WANT_READ;
241
0
        else
242
0
            return WOLFSSL_CBIO_ERR_TIMEOUT;
243
0
    }
244
0
#endif /* SOCKET_ETIMEDOUT */
245
246
0
    else if (err == SOCKET_ECONNRESET) {
247
0
        WOLFSSL_MSG("\tConnection reset");
248
0
        return WOLFSSL_CBIO_ERR_CONN_RST;
249
0
    }
250
0
    else if (err == SOCKET_EINTR) {
251
0
        WOLFSSL_MSG("\tSocket interrupted");
252
0
        return WOLFSSL_CBIO_ERR_ISR;
253
0
    }
254
0
    else if (err == SOCKET_EPIPE) {
255
0
        WOLFSSL_MSG("\tBroken pipe");
256
0
        return WOLFSSL_CBIO_ERR_CONN_CLOSE;
257
0
    }
258
0
    else if (err == SOCKET_ECONNABORTED) {
259
0
        WOLFSSL_MSG("\tConnection aborted");
260
0
        return WOLFSSL_CBIO_ERR_CONN_CLOSE;
261
0
    }
262
263
#if defined(_WIN32) && !defined(__WATCOMC__) && !defined(_WIN32_WCE) && \
264
    !defined(INTIME_RTOS)
265
    strcpy_s(errstr, sizeof(errstr), "\tGeneral error: ");
266
    errstr_offset = strlen(errstr);
267
    FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
268
        NULL,
269
        err,
270
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
271
        (LPSTR)(errstr + errstr_offset),
272
        (DWORD)(sizeof(errstr) - errstr_offset),
273
        NULL);
274
    WOLFSSL_MSG(errstr);
275
#else
276
0
    WOLFSSL_MSG_EX("\tGeneral error: %d", err);
277
0
#endif
278
0
    return WOLFSSL_CBIO_ERR_GENERAL;
279
0
}
280
#endif /* USE_WOLFSSL_IO || HAVE_HTTP_CLIENT */
281
282
#ifdef OPENSSL_EXTRA
283
#ifndef NO_BIO
284
285
int wolfSSL_BioSend(WOLFSSL* ssl, char *buf, int sz, void *ctx)
286
{
287
    return SslBioSend(ssl, buf, sz, ctx);
288
}
289
290
int wolfSSL_BioReceive(WOLFSSL* ssl, char* buf, int sz, void* ctx)
291
{
292
    return SslBioReceive(ssl, buf, sz, ctx);
293
}
294
295
int BioReceiveInternal(WOLFSSL_BIO* biord, WOLFSSL_BIO* biowr, char* buf,
296
                       int sz)
297
{
298
    int recvd = WC_NO_ERR_TRACE(WOLFSSL_CBIO_ERR_GENERAL);
299
300
    WOLFSSL_ENTER("SslBioReceive");
301
302
    if (biord == NULL) {
303
        WOLFSSL_MSG("WOLFSSL biord not set");
304
        return WOLFSSL_CBIO_ERR_GENERAL;
305
    }
306
307
    recvd = wolfSSL_BIO_read(biord, buf, sz);
308
    if (recvd <= 0) {
309
        if (biowr != NULL &&
310
            /* ssl->biowr->wrIdx is checked for Bind9 */
311
            wolfSSL_BIO_method_type(biowr) == WOLFSSL_BIO_BIO &&
312
            wolfSSL_BIO_wpending(biowr) != 0 &&
313
            /* Not sure this pending check is necessary but let's double
314
             * check that the read BIO is empty before we signal a write
315
             * need */
316
            wolfSSL_BIO_supports_pending(biord) &&
317
            wolfSSL_BIO_ctrl_pending(biord) == 0) {
318
            /* Let's signal to the app layer that we have
319
             * data pending that needs to be sent. */
320
            return WOLFSSL_CBIO_ERR_WANT_WRITE;
321
        }
322
        else if (biord->type == WOLFSSL_BIO_SOCKET) {
323
            if (recvd == 0) {
324
                WOLFSSL_MSG("SslBioReceive connection closed");
325
                return WOLFSSL_CBIO_ERR_CONN_CLOSE;
326
            }
327
        #ifdef USE_WOLFSSL_IO
328
            recvd = TranslateIoReturnCode(recvd, biord->num.fd,
329
                                          SOCKET_RECEIVING);
330
        #endif
331
            return recvd;
332
        }
333
334
        /* If retry and read flags are set, return WANT_READ */
335
        if ((biord->flags & WOLFSSL_BIO_FLAG_READ) &&
336
            (biord->flags & WOLFSSL_BIO_FLAG_RETRY)) {
337
            return WOLFSSL_CBIO_ERR_WANT_READ;
338
        }
339
340
        WOLFSSL_MSG("BIO general error");
341
        return WOLFSSL_CBIO_ERR_GENERAL;
342
    }
343
344
    return recvd;
345
}
346
347
/* Use the WOLFSSL read BIO for receiving data. This is set by the function
348
 * wolfSSL_set_bio and can also be set by wolfSSL_CTX_SetIORecv.
349
 *
350
 * ssl  WOLFSSL struct passed in that has this function set as the receive
351
 *      callback.
352
 * buf  buffer to fill with data read
353
 * sz   size of buf buffer
354
 * ctx  a user set context
355
 *
356
 * returns the amount of data read or want read. See WOLFSSL_CBIO_ERR_* values.
357
 */
358
int SslBioReceive(WOLFSSL* ssl, char* buf, int sz, void* ctx)
359
{
360
    WOLFSSL_ENTER("SslBioReceive");
361
    (void)ctx;
362
    return BioReceiveInternal(ssl->biord, ssl->biowr, buf, sz);
363
}
364
365
366
/* Use the WOLFSSL write BIO for sending data. This is set by the function
367
 * wolfSSL_set_bio and can also be set by wolfSSL_CTX_SetIOSend.
368
 *
369
 * ssl  WOLFSSL struct passed in that has this function set as the send callback.
370
 * buf  buffer with data to write out
371
 * sz   size of buf buffer
372
 * ctx  a user set context
373
 *
374
 * returns the amount of data sent or want send. See WOLFSSL_CBIO_ERR_* values.
375
 */
376
int SslBioSend(WOLFSSL* ssl, char *buf, int sz, void *ctx)
377
{
378
    int sent = WC_NO_ERR_TRACE(WOLFSSL_CBIO_ERR_GENERAL);
379
380
    WOLFSSL_ENTER("SslBioSend");
381
382
    if (ssl->biowr == NULL) {
383
        WOLFSSL_MSG("WOLFSSL biowr not set");
384
        return WOLFSSL_CBIO_ERR_GENERAL;
385
    }
386
387
    sent = wolfSSL_BIO_write(ssl->biowr, buf, sz);
388
    if (sent <= 0) {
389
        if (ssl->biowr->type == WOLFSSL_BIO_SOCKET) {
390
        #ifdef USE_WOLFSSL_IO
391
            sent = TranslateIoReturnCode(sent, ssl->biowr->num.fd,
392
                                         SOCKET_SENDING);
393
        #endif
394
            return sent;
395
        }
396
        else if (ssl->biowr->type == WOLFSSL_BIO_BIO) {
397
            if (sent == WOLFSSL_BIO_ERROR) {
398
                WOLFSSL_MSG("\tWould Block");
399
                return WOLFSSL_CBIO_ERR_WANT_WRITE;
400
            }
401
        }
402
403
        /* If retry and write flags are set, return WANT_WRITE */
404
        if ((ssl->biowr->flags & WOLFSSL_BIO_FLAG_WRITE) &&
405
            (ssl->biowr->flags & WOLFSSL_BIO_FLAG_RETRY)) {
406
            return WOLFSSL_CBIO_ERR_WANT_WRITE;
407
        }
408
409
        return WOLFSSL_CBIO_ERR_GENERAL;
410
    }
411
    (void)ctx;
412
413
    return sent;
414
}
415
#endif /* !NO_BIO */
416
#endif /* OPENSSL_EXTRA */
417
418
419
#ifdef USE_WOLFSSL_IO
420
421
#ifndef WOLFSSL_DTLS_ONLY
422
/* The receive embedded callback
423
 *  return : nb bytes read, or error
424
 */
425
int EmbedReceive(WOLFSSL *ssl, char *buf, int sz, void *ctx)
426
0
{
427
0
    int recvd;
428
0
#ifndef WOLFSSL_LINUXKM
429
0
    int sd = *(int*)ctx;
430
#else
431
    struct socket *sd = (struct socket*)ctx;
432
#endif
433
434
0
    recvd = wolfIO_Recv(sd, buf, sz, ssl->rflags);
435
0
    if (recvd < 0) {
436
0
        WOLFSSL_MSG("Embed Receive error");
437
0
    }
438
0
    else if (recvd == 0) {
439
0
        WOLFSSL_MSG("Embed receive connection closed");
440
0
        return WOLFSSL_CBIO_ERR_CONN_CLOSE;
441
0
    }
442
443
0
    return recvd;
444
0
}
445
446
/* The send embedded callback
447
 *  return : nb bytes sent, or error
448
 */
449
int EmbedSend(WOLFSSL* ssl, char *buf, int sz, void *ctx)
450
0
{
451
0
    int sent;
452
0
#ifndef WOLFSSL_LINUXKM
453
0
    int sd = *(int*)ctx;
454
#else
455
    struct socket *sd = (struct socket*)ctx;
456
#endif
457
458
#ifdef WOLFSSL_MAX_SEND_SZ
459
    if (sz > WOLFSSL_MAX_SEND_SZ)
460
        sz = WOLFSSL_MAX_SEND_SZ;
461
#endif
462
463
0
    sent = wolfIO_Send(sd, buf, sz, ssl->wflags);
464
0
    if (sent < 0) {
465
0
        WOLFSSL_MSG("Embed Send error");
466
0
    }
467
468
0
    return sent;
469
0
}
470
#endif /* !WOLFSSL_DTLS_ONLY */
471
472
473
#ifdef WOLFSSL_DTLS
474
475
#include <wolfssl/wolfcrypt/sha.h>
476
477
#if defined(NUCLEUS_PLUS_2_3)
478
STATIC INT32 nucyassl_recv(INT sd, CHAR *buf, UINT16 sz, INT16 flags)
479
{
480
    int recvd;
481
482
    /* Read data from socket */
483
    recvd = NU_Recv(sd, buf, sz, flags);
484
    if (recvd < 0) {
485
        if (recvd == NU_NOT_CONNECTED) {
486
            recvd = 0;
487
        } else {
488
            Nucleus_Net_Errno = recvd;
489
            recvd = WOLFSSL_FATAL_ERROR;
490
        }
491
    } else {
492
        Nucleus_Net_Errno = 0;
493
    }
494
495
    return (recvd);
496
}
497
498
499
STATIC int nucyassl_send(INT sd, CHAR *buf, UINT16 sz, INT16 flags)
500
{
501
    int sent;
502
503
    /* Write data to socket */
504
    sent = NU_Send(sd, buf, sz, flags);
505
506
    if (sent < 0) {
507
        Nucleus_Net_Errno = sent;
508
        sent = WOLFSSL_FATAL_ERROR;
509
    } else {
510
        Nucleus_Net_Errno = 0;
511
    }
512
513
    return sent;
514
}
515
516
#define SELECT_FUNCTION     nucyassl_select
517
518
int nucyassl_select(INT sd, UINT32 timeout)
519
{
520
    FD_SET readfs;
521
    STATUS status;
522
523
    /* Init fs data for socket */
524
    NU_FD_Init(&readfs);
525
    NU_FD_Set(sd, &readfs);
526
527
    /* Wait for data to arrive */
528
    status = NU_Select((sd + 1), &readfs, NU_NULL, NU_NULL,
529
                            (timeout * NU_TICKS_PER_SECOND));
530
531
    if (status < 0) {
532
        Nucleus_Net_Errno = status;
533
        status = WOLFSSL_FATAL_ERROR;
534
    }
535
536
    return status;
537
}
538
539
#define sockaddr_storage    addr_struct
540
#define sockaddr            addr_struct
541
542
STATIC INT32 nucyassl_recvfrom(INT sd, CHAR *buf, UINT16 sz, INT16 flags,
543
                              SOCKADDR *peer, XSOCKLENT *peersz)
544
{
545
    int recvd;
546
547
    memset(peer, 0, sizeof(struct addr_struct));
548
549
    recvd = NU_Recv_From(sd, buf, sz, flags, (struct addr_struct *) peer,
550
                            (INT16*) peersz);
551
    if (recvd < 0) {
552
        Nucleus_Net_Errno = recvd;
553
        recvd = WOLFSSL_FATAL_ERROR;
554
    } else {
555
        Nucleus_Net_Errno = 0;
556
    }
557
558
    return recvd;
559
560
}
561
562
STATIC int nucyassl_sendto(INT sd, CHAR *buf, UINT16 sz, INT16 flags,
563
                          const SOCKADDR *peer, INT16 peersz)
564
{
565
    int sent;
566
567
    sent = NU_Send_To(sd, buf, sz, flags, (const struct addr_struct *) peer,
568
                            peersz);
569
570
    if (sent < 0) {
571
        Nucleus_Net_Errno = sent;
572
        sent = WOLFSSL_FATAL_ERROR;
573
    } else {
574
        Nucleus_Net_Errno = 0;
575
    }
576
577
    return sent;
578
}
579
#endif /* NUCLEUS_PLUS_2_3 */
580
581
#ifndef DTLS_SENDTO_FUNCTION
582
    #define DTLS_SENDTO_FUNCTION sendto
583
#endif
584
#ifndef DTLS_RECVFROM_FUNCTION
585
    #define DTLS_RECVFROM_FUNCTION recvfrom
586
#endif
587
588
int sockAddrEqual(
589
    SOCKADDR_S *a, XSOCKLENT aLen, SOCKADDR_S *b, XSOCKLENT bLen)
590
{
591
    if (aLen != bLen)
592
        return 0;
593
594
    if (a->ss_family != b->ss_family)
595
        return 0;
596
597
    if (a->ss_family == WOLFSSL_IP4) {
598
599
        if (aLen < (XSOCKLENT)sizeof(SOCKADDR_IN))
600
            return 0;
601
602
        if (((SOCKADDR_IN*)a)->sin_port != ((SOCKADDR_IN*)b)->sin_port)
603
            return 0;
604
605
        if (((SOCKADDR_IN*)a)->sin_addr.s_addr !=
606
            ((SOCKADDR_IN*)b)->sin_addr.s_addr)
607
            return 0;
608
609
        return 1;
610
    }
611
612
#ifdef WOLFSSL_IPV6
613
    if (a->ss_family == WOLFSSL_IP6) {
614
        SOCKADDR_IN6 *a6, *b6;
615
616
        if (aLen < (XSOCKLENT)sizeof(SOCKADDR_IN6))
617
            return 0;
618
619
        a6 = (SOCKADDR_IN6*)a;
620
        b6 = (SOCKADDR_IN6*)b;
621
622
        if (((SOCKADDR_IN6*)a)->sin6_port != ((SOCKADDR_IN6*)b)->sin6_port)
623
            return 0;
624
625
        if (XMEMCMP((void*)&a6->sin6_addr, (void*)&b6->sin6_addr,
626
                sizeof(a6->sin6_addr)) != 0)
627
            return 0;
628
629
        return 1;
630
    }
631
#endif /* WOLFSSL_IPV6 */
632
633
    return 0;
634
}
635
636
#ifndef WOLFSSL_IPV6
637
static int PeerIsIpv6(const SOCKADDR_S *peer, XSOCKLENT len)
638
{
639
    if (len < (XSOCKLENT)sizeof(peer->ss_family))
640
        return 0;
641
    return peer->ss_family == WOLFSSL_IP6;
642
}
643
#endif /* !WOLFSSL_IPV6 */
644
645
/* Return non-zero iff sfd is a SOCK_DGRAM socket. A descriptor's type is
646
 * fixed for its lifetime, so the probe runs where dtlsCtx.rfd/wfd is
647
 * assigned and the result is stored alongside the descriptor, keeping the
648
 * getsockopt() syscall out of the I/O callbacks. */
649
int wolfIO_SockIsDGram(int sfd)
650
{
651
    int type = 0;
652
    /* optvalue 'type' is of size int */
653
    XSOCKLENT length = (XSOCKLENT)sizeof(type);
654
655
    if (getsockopt(sfd, SOL_SOCKET, SO_TYPE, (XSOCKOPT_TYPE_OPTVAL_TYPE)&type,
656
            &length) == 0 && type != SOCK_DGRAM) {
657
        return 0;
658
    }
659
    else {
660
        return 1;
661
    }
662
}
663
664
void wolfSSL_SetRecvFrom(WOLFSSL* ssl, WolfSSLRecvFrom recvFrom)
665
{
666
    if (ssl != NULL)
667
        ssl->buffers.dtlsCtx.recvfrom = recvFrom;
668
}
669
670
void wolfSSL_SetSendTo(WOLFSSL* ssl, WolfSSLSento sendTo)
671
{
672
    if (ssl != NULL)
673
        ssl->buffers.dtlsCtx.sendto = sendTo;
674
}
675
676
/* The receive embedded callback
677
 *  return : nb bytes read, or error
678
 */
679
int EmbedReceiveFrom(WOLFSSL *ssl, char *buf, int sz, void *ctx)
680
{
681
    WOLFSSL_DTLS_CTX* dtlsCtx = (WOLFSSL_DTLS_CTX*)ctx;
682
    int recvd;
683
    int sd = dtlsCtx->rfd;
684
    int dtls_timeout = wolfSSL_dtls_get_current_timeout(ssl);
685
    byte doDtlsTimeout;
686
    SOCKADDR_S lclPeer;
687
    SOCKADDR_S* peer;
688
    XSOCKLENT peerSz = 0;
689
#ifndef NO_ASN_TIME
690
    word32 start = 0;
691
#elif !defined(DTLS_RECEIVEFROM_NO_TIMEOUT_ON_INVALID_PEER)
692
    word32 invalidPeerPackets = 0;
693
#endif
694
    int newPeer = 0;
695
    int ret = 0;
696
697
    WOLFSSL_ENTER("EmbedReceiveFrom");
698
    (void)ret; /* possibly unused */
699
700
    if (sz < 0)
701
        return WOLFSSL_CBIO_ERR_GENERAL;
702
703
    XMEMSET(&lclPeer, 0, sizeof(lclPeer));
704
705
#ifdef WOLFSSL_RW_THREADED
706
    if (wc_LockRwLock_Rd(&ssl->buffers.dtlsCtx.peerLock) != 0)
707
        return WOLFSSL_CBIO_ERR_GENERAL;
708
#endif
709
710
    if (dtlsCtx->connected) {
711
        peer = NULL;
712
    }
713
    else if (dtlsCtx->userSet) {
714
#ifndef WOLFSSL_IPV6
715
        if (PeerIsIpv6((SOCKADDR_S*)dtlsCtx->peer.sa, dtlsCtx->peer.sz)) {
716
            WOLFSSL_MSG("ipv6 dtls peer set but no ipv6 support compiled");
717
            ret = WOLFSSL_CBIO_ERR_GENERAL;
718
        }
719
#endif
720
        peer = &lclPeer;
721
        peerSz = sizeof(lclPeer);
722
    }
723
    else {
724
        /* Store the peer address. It is used to calculate the DTLS cookie. */
725
        newPeer = dtlsCtx->peer.sa == NULL || !ssl->options.dtlsStateful;
726
        peer = &lclPeer;
727
        peerSz = sizeof(lclPeer);
728
    }
729
730
#ifdef WOLFSSL_RW_THREADED
731
    /* We make a copy above to avoid holding the lock for the entire function */
732
    if (wc_UnLockRwLock(&ssl->buffers.dtlsCtx.peerLock) != 0)
733
        return WOLFSSL_CBIO_ERR_GENERAL;
734
#endif
735
736
    if (ret != 0)
737
        return ret;
738
739
    /* Don't use ssl->options.handShakeDone since it is true even if
740
     * we are in the process of renegotiation */
741
    doDtlsTimeout = ssl->options.handShakeState != HANDSHAKE_DONE;
742
743
#ifdef WOLFSSL_DTLS13
744
    if (ssl->options.dtls && IsAtLeastTLSv1_3(ssl->version)) {
745
        doDtlsTimeout = doDtlsTimeout || ssl->dtls13Rtx.rtxRecords != NULL;
746
#ifdef WOLFSSL_RW_THREADED
747
        ret = wc_LockMutex(&ssl->dtls13Rtx.mutex);
748
        if (ret != 0)
749
            return ret;
750
#endif
751
        doDtlsTimeout = doDtlsTimeout ||
752
            (ssl->dtls13FastTimeout && ssl->dtls13Rtx.seenRecords != NULL);
753
#ifdef WOLFSSL_RW_THREADED
754
        wc_UnLockMutex(&ssl->dtls13Rtx.mutex);
755
#endif
756
    }
757
#endif /* WOLFSSL_DTLS13 */
758
759
    do {
760
761
        if (!doDtlsTimeout) {
762
            dtls_timeout = 0;
763
        }
764
        else {
765
#ifndef NO_ASN_TIME
766
            if (start == 0) {
767
                start = LowResTimer();
768
            }
769
            else {
770
                dtls_timeout -= (int) (LowResTimer() - start);
771
                start = LowResTimer();
772
                if (dtls_timeout < 0 || dtls_timeout > DTLS_TIMEOUT_MAX)
773
                    return WOLFSSL_CBIO_ERR_TIMEOUT;
774
            }
775
#endif
776
        }
777
778
        if (!wolfSSL_get_using_nonblock(ssl)) {
779
        #ifdef USE_WINDOWS_API
780
            DWORD timeout = dtls_timeout * 1000;
781
            #ifdef WOLFSSL_DTLS13
782
            if (wolfSSL_dtls13_use_quick_timeout(ssl) &&
783
                IsAtLeastTLSv1_3(ssl->version))
784
                timeout /= 4;
785
            #endif /* WOLFSSL_DTLS13 */
786
        #else
787
            struct timeval timeout;
788
            XMEMSET(&timeout, 0, sizeof(timeout));
789
            #ifdef WOLFSSL_DTLS13
790
            if (wolfSSL_dtls13_use_quick_timeout(ssl) &&
791
                IsAtLeastTLSv1_3(ssl->version)) {
792
                if (dtls_timeout >= 4)
793
                    timeout.tv_sec = dtls_timeout / 4;
794
                else
795
                    timeout.tv_usec = dtls_timeout * 1000000 / 4;
796
            }
797
            else
798
            #endif /* WOLFSSL_DTLS13 */
799
                timeout.tv_sec = dtls_timeout;
800
        #endif /* USE_WINDOWS_API */
801
            if (setsockopt(sd, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout,
802
                    sizeof(timeout)) != 0) {
803
                WOLFSSL_MSG("setsockopt rcvtimeo failed");
804
            }
805
        }
806
#ifndef NO_ASN_TIME
807
        else if (IsSCR(ssl)) {
808
            if (ssl->dtls_start_timeout &&
809
                LowResTimer() - ssl->dtls_start_timeout >
810
                    (word32)dtls_timeout) {
811
                ssl->dtls_start_timeout = 0;
812
                return WOLFSSL_CBIO_ERR_TIMEOUT;
813
            }
814
            else if (!ssl->dtls_start_timeout) {
815
                ssl->dtls_start_timeout = LowResTimer();
816
            }
817
        }
818
#endif /* !NO_ASN_TIME */
819
820
        {
821
            XSOCKLENT inPeerSz = peerSz;
822
            if (dtlsCtx->recvfrom == NULL) {
823
                recvd = (int)DTLS_RECVFROM_FUNCTION(sd, buf, (size_t)sz,
824
                        ssl->rflags, (SOCKADDR*)peer,
825
                        peer != NULL ? &inPeerSz : NULL);
826
            }
827
            else {
828
                recvd = (int)dtlsCtx->recvfrom(sd, buf, (size_t) sz,
829
                        ssl->rflags, (SOCKADDR*) peer,
830
                        peer != NULL ? &inPeerSz : NULL);
831
            }
832
            /* Truncate peerSz. From the RECV(2) man page
833
             * The returned address is truncated if the buffer provided is too
834
             * small; in this case, addrlen will return a value greater than was
835
             * supplied to the call.
836
             */
837
            peerSz = MIN(peerSz, inPeerSz);
838
        }
839
840
        recvd = TranslateIoReturnCode(recvd, sd, SOCKET_RECEIVING);
841
842
        if (recvd < 0) {
843
            WOLFSSL_MSG("Embed Receive From error");
844
            if (recvd == WC_NO_ERR_TRACE(WOLFSSL_CBIO_ERR_WANT_READ) &&
845
                !wolfSSL_dtls_get_using_nonblock(ssl)) {
846
                recvd = WOLFSSL_CBIO_ERR_TIMEOUT;
847
            }
848
            return recvd;
849
        }
850
        else if (recvd == 0) {
851
            if (!dtlsCtx->rfdIsDGram) {
852
                /* Closed TCP connection */
853
                recvd = WOLFSSL_CBIO_ERR_CONN_CLOSE;
854
            }
855
            else {
856
                WOLFSSL_MSG("Ignoring 0-length datagram");
857
                continue;
858
            }
859
            return recvd;
860
        }
861
        else if (dtlsCtx->connected) {
862
            /* Nothing to do */
863
        }
864
        else if (dtlsCtx->userSet) {
865
            /* Check we received the packet from the correct peer */
866
            int ignore = 0;
867
#ifdef WOLFSSL_RW_THREADED
868
            if (wc_LockRwLock_Rd(&ssl->buffers.dtlsCtx.peerLock) != 0)
869
                return WOLFSSL_CBIO_ERR_GENERAL;
870
#endif
871
            if (dtlsCtx->peer.sz > 0 &&
872
                (peerSz != (XSOCKLENT)dtlsCtx->peer.sz ||
873
                    !sockAddrEqual(peer, peerSz, (SOCKADDR_S*)dtlsCtx->peer.sa,
874
                        dtlsCtx->peer.sz))) {
875
                WOLFSSL_MSG("    Ignored packet from invalid peer");
876
                ignore = 1;
877
            }
878
#ifdef WOLFSSL_RW_THREADED
879
            if (wc_UnLockRwLock(&ssl->buffers.dtlsCtx.peerLock) != 0)
880
                return WOLFSSL_CBIO_ERR_GENERAL;
881
#endif
882
            if (ignore) {
883
#if defined(NO_ASN_TIME) &&                                                    \
884
    !defined(DTLS_RECEIVEFROM_NO_TIMEOUT_ON_INVALID_PEER)
885
                if (doDtlsTimeout) {
886
                    invalidPeerPackets++;
887
                    if (invalidPeerPackets > DTLS_RECEIVEFROM_MAX_INVALID_PEER)
888
                        return wolfSSL_dtls_get_using_nonblock(ssl)
889
                                   ? WOLFSSL_CBIO_ERR_WANT_READ
890
                                   : WOLFSSL_CBIO_ERR_TIMEOUT;
891
                }
892
#endif /* NO_ASN_TIME && !DTLS_RECEIVEFROM_NO_TIMEOUT_ON_INVALID_PEER */
893
                continue;
894
            }
895
        }
896
        else {
897
            if (newPeer) {
898
                /* Store size of saved address. Locking handled internally. */
899
                if (wolfSSL_dtls_set_peer(ssl, peer, peerSz) != WOLFSSL_SUCCESS)
900
                    return WOLFSSL_CBIO_ERR_GENERAL;
901
                dtlsCtx->userSet = 0;
902
            }
903
#ifndef WOLFSSL_PEER_ADDRESS_CHANGES
904
            else {
905
                ret = 0;
906
    #ifdef WOLFSSL_RW_THREADED
907
                if (wc_LockRwLock_Rd(&ssl->buffers.dtlsCtx.peerLock) != 0)
908
                    return WOLFSSL_CBIO_ERR_GENERAL;
909
    #endif /* WOLFSSL_RW_THREADED */
910
                if (!sockAddrEqual(peer, peerSz, (SOCKADDR_S*)dtlsCtx->peer.sa,
911
                                    dtlsCtx->peer.sz)) {
912
                    ret = WOLFSSL_CBIO_ERR_GENERAL;
913
                }
914
    #ifdef WOLFSSL_RW_THREADED
915
                if (wc_UnLockRwLock(&ssl->buffers.dtlsCtx.peerLock) != 0)
916
                    return WOLFSSL_CBIO_ERR_GENERAL;
917
    #endif /* WOLFSSL_RW_THREADED */
918
                if (ret != 0)
919
                    return ret;
920
            }
921
#endif /* !WOLFSSL_PEER_ADDRESS_CHANGES */
922
        }
923
#ifndef NO_ASN_TIME
924
        ssl->dtls_start_timeout = 0;
925
#endif /* !NO_ASN_TIME */
926
        break;
927
    } while (1);
928
929
    return recvd;
930
}
931
932
933
/* The send embedded callback
934
 *  return : nb bytes sent, or error
935
 */
936
int EmbedSendTo(WOLFSSL* ssl, char *buf, int sz, void *ctx)
937
{
938
    WOLFSSL_DTLS_CTX* dtlsCtx = (WOLFSSL_DTLS_CTX*)ctx;
939
    int sd = dtlsCtx->wfd;
940
    int sent;
941
    const SOCKADDR_S* peer = NULL;
942
    XSOCKLENT peerSz = 0;
943
944
    WOLFSSL_ENTER("EmbedSendTo");
945
946
    if (sz < 0)
947
        return WOLFSSL_CBIO_ERR_GENERAL;
948
949
    if (!dtlsCtx->wfdIsDGram) {
950
        /* Probably a TCP socket. peer and peerSz MUST be NULL and 0 */
951
    }
952
    else if (!dtlsCtx->connected) {
953
        peer   = (const SOCKADDR_S*)dtlsCtx->peer.sa;
954
        peerSz = dtlsCtx->peer.sz;
955
#ifndef WOLFSSL_IPV6
956
        if (PeerIsIpv6(peer, peerSz)) {
957
            WOLFSSL_MSG("ipv6 dtls peer set but no ipv6 support compiled");
958
            return NOT_COMPILED_IN;
959
        }
960
#endif
961
    }
962
963
    if (dtlsCtx->sendto == NULL) {
964
        sent = (int)DTLS_SENDTO_FUNCTION(sd, buf, (size_t)sz, ssl->wflags,
965
                (const SOCKADDR*)peer, peerSz);
966
    }
967
    else {
968
        sent = (int)dtlsCtx->sendto(sd, buf, (size_t)sz, ssl->wflags,
969
                (const SOCKADDR*)peer, peerSz);
970
    }
971
972
    sent = TranslateIoReturnCode(sent, sd, SOCKET_SENDING);
973
974
    if (sent < 0) {
975
        WOLFSSL_MSG("Embed Send To error");
976
    }
977
978
    return sent;
979
}
980
981
982
#ifdef WOLFSSL_MULTICAST
983
984
/* The alternate receive embedded callback for Multicast
985
 *  return : nb bytes read, or error
986
 */
987
int EmbedReceiveFromMcast(WOLFSSL *ssl, char *buf, int sz, void *ctx)
988
{
989
    WOLFSSL_DTLS_CTX* dtlsCtx = (WOLFSSL_DTLS_CTX*)ctx;
990
    int recvd;
991
    int sd = dtlsCtx->rfd;
992
993
    WOLFSSL_ENTER("EmbedReceiveFromMcast");
994
995
    if (sz < 0)
996
        return WOLFSSL_CBIO_ERR_GENERAL;
997
998
    recvd = (int)DTLS_RECVFROM_FUNCTION(sd, buf, (size_t)sz, ssl->rflags, NULL, NULL);
999
1000
    recvd = TranslateIoReturnCode(recvd, sd, SOCKET_RECEIVING);
1001
1002
    if (recvd < 0) {
1003
        WOLFSSL_MSG("Embed Receive From error");
1004
        if (recvd == WC_NO_ERR_TRACE(WOLFSSL_CBIO_ERR_WANT_READ) &&
1005
            !wolfSSL_dtls_get_using_nonblock(ssl)) {
1006
            recvd = WOLFSSL_CBIO_ERR_TIMEOUT;
1007
        }
1008
    }
1009
1010
    return recvd;
1011
}
1012
#endif /* WOLFSSL_MULTICAST */
1013
1014
1015
/* The DTLS Generate Cookie callback
1016
 *  return : number of bytes copied into buf, or error
1017
 */
1018
int EmbedGenerateCookie(WOLFSSL* ssl, byte *buf, int sz, void *ctx)
1019
{
1020
    int sd = ssl->wfd;
1021
    SOCKADDR_S peer;
1022
    XSOCKLENT peerSz = sizeof(peer);
1023
    byte digest[WC_SHA256_DIGEST_SIZE];
1024
    int  ret = 0;
1025
1026
    (void)ctx;
1027
1028
    if (sz < 0)
1029
        return BAD_FUNC_ARG;
1030
1031
    XMEMSET(&peer, 0, sizeof(peer));
1032
    if (getpeername(sd, (SOCKADDR*)&peer, &peerSz) != 0) {
1033
        WOLFSSL_MSG("getpeername failed in EmbedGenerateCookie");
1034
        return GEN_COOKIE_E;
1035
    }
1036
1037
    ret = wc_Sha256Hash((byte*)&peer, peerSz, digest);
1038
    if (ret != 0)
1039
        return ret;
1040
1041
    if (sz > WC_SHA256_DIGEST_SIZE)
1042
        sz = WC_SHA256_DIGEST_SIZE;
1043
    XMEMCPY(buf, digest, (size_t)sz);
1044
1045
    return sz;
1046
}
1047
#endif /* WOLFSSL_DTLS */
1048
1049
#ifdef WOLFSSL_SESSION_EXPORT
1050
1051
#ifdef WOLFSSL_DTLS
1052
    static int EmbedGetPeerDTLS(WOLFSSL* ssl, char* ip, int* ipSz,
1053
                                                 unsigned short* port, int* fam)
1054
    {
1055
        SOCKADDR_S peer;
1056
        word32     peerSz;
1057
        int        ret;
1058
1059
        /* get peer information stored in ssl struct */
1060
        peerSz = sizeof(SOCKADDR_S);
1061
        if ((ret = wolfSSL_dtls_get_peer(ssl, (void*)&peer, &peerSz))
1062
                                                               != WOLFSSL_SUCCESS) {
1063
            return ret;
1064
        }
1065
1066
        /* extract family, ip, and port */
1067
        *fam = ((SOCKADDR_S*)&peer)->ss_family;
1068
        switch (*fam) {
1069
            case WOLFSSL_IP4:
1070
                if (XINET_NTOP(*fam, &(((SOCKADDR_IN*)&peer)->sin_addr),
1071
                                                           ip, *ipSz) == NULL) {
1072
                    WOLFSSL_MSG("XINET_NTOP error");
1073
                    return SOCKET_ERROR_E;
1074
                }
1075
                *port = XNTOHS(((SOCKADDR_IN*)&peer)->sin_port);
1076
                break;
1077
1078
            case WOLFSSL_IP6:
1079
            #ifdef WOLFSSL_IPV6
1080
                if (XINET_NTOP(*fam, &(((SOCKADDR_IN6*)&peer)->sin6_addr),
1081
                                                           ip, *ipSz) == NULL) {
1082
                    WOLFSSL_MSG("XINET_NTOP error");
1083
                    return SOCKET_ERROR_E;
1084
                }
1085
                *port = XNTOHS(((SOCKADDR_IN6*)&peer)->sin6_port);
1086
            #endif /* WOLFSSL_IPV6 */
1087
                break;
1088
1089
            default:
1090
                WOLFSSL_MSG("Unknown family type");
1091
                return SOCKET_ERROR_E;
1092
        }
1093
        ip[*ipSz - 1] = '\0'; /* make sure has terminator */
1094
        *ipSz = (word16)XSTRLEN(ip);
1095
1096
        return WOLFSSL_SUCCESS;
1097
    }
1098
1099
    static int EmbedSetPeerDTLS(WOLFSSL* ssl, char* ip, int ipSz,
1100
                                                   unsigned short port, int fam)
1101
    {
1102
        int    ret;
1103
        SOCKADDR_S addr;
1104
1105
        /* sanity checks on arguments */
1106
        if (ssl == NULL || ip == NULL || ipSz < 0 || ipSz > MAX_EXPORT_IP) {
1107
            return BAD_FUNC_ARG;
1108
        }
1109
1110
        addr.ss_family = fam;
1111
        switch (addr.ss_family) {
1112
            case WOLFSSL_IP4:
1113
                if (XINET_PTON(addr.ss_family, ip,
1114
                                     &(((SOCKADDR_IN*)&addr)->sin_addr)) <= 0) {
1115
                    WOLFSSL_MSG("XINET_PTON error");
1116
                    return SOCKET_ERROR_E;
1117
                }
1118
                ((SOCKADDR_IN*)&addr)->sin_port = XHTONS(port);
1119
1120
                /* peer sa is free'd in wolfSSL_ResourceFree */
1121
                if ((ret = wolfSSL_dtls_set_peer(ssl, (SOCKADDR_IN*)&addr,
1122
                                          sizeof(SOCKADDR_IN)))!= WOLFSSL_SUCCESS) {
1123
                    WOLFSSL_MSG("Import DTLS peer info error");
1124
                    return ret;
1125
                }
1126
                break;
1127
1128
            case WOLFSSL_IP6:
1129
            #ifdef WOLFSSL_IPV6
1130
                if (XINET_PTON(addr.ss_family, ip,
1131
                                   &(((SOCKADDR_IN6*)&addr)->sin6_addr)) <= 0) {
1132
                    WOLFSSL_MSG("XINET_PTON error");
1133
                    return SOCKET_ERROR_E;
1134
                }
1135
                ((SOCKADDR_IN6*)&addr)->sin6_port = XHTONS(port);
1136
1137
                /* peer sa is free'd in wolfSSL_ResourceFree */
1138
                if ((ret = wolfSSL_dtls_set_peer(ssl, (SOCKADDR_IN6*)&addr,
1139
                                         sizeof(SOCKADDR_IN6)))!= WOLFSSL_SUCCESS) {
1140
                    WOLFSSL_MSG("Import DTLS peer info error");
1141
                    return ret;
1142
                }
1143
            #endif /* WOLFSSL_IPV6 */
1144
                break;
1145
1146
            default:
1147
                WOLFSSL_MSG("Unknown address family");
1148
                return BUFFER_E;
1149
        }
1150
1151
        return WOLFSSL_SUCCESS;
1152
    }
1153
#endif /* WOLFSSL_DTLS */
1154
1155
    /* get the peer information in human readable form (ip, port, family)
1156
     * default function assumes BSD sockets
1157
     * can be overridden with wolfSSL_CTX_SetIOGetPeer
1158
     */
1159
    int EmbedGetPeer(WOLFSSL* ssl, char* ip, int* ipSz,
1160
                                                 unsigned short* port, int* fam)
1161
    {
1162
        if (ssl == NULL || ip == NULL || ipSz == NULL ||
1163
                                                  port == NULL || fam == NULL) {
1164
            return BAD_FUNC_ARG;
1165
        }
1166
1167
        if (ssl->options.dtls) {
1168
        #ifdef WOLFSSL_DTLS
1169
            return EmbedGetPeerDTLS(ssl, ip, ipSz, port, fam);
1170
        #else
1171
            return NOT_COMPILED_IN;
1172
        #endif
1173
        }
1174
        else {
1175
            *port = wolfSSL_get_fd(ssl);
1176
            ip[0] = '\0';
1177
            *ipSz = 0;
1178
            *fam  = 0;
1179
            return WOLFSSL_SUCCESS;
1180
        }
1181
    }
1182
1183
    /* set the peer information in human readable form (ip, port, family)
1184
     * default function assumes BSD sockets
1185
     * can be overridden with wolfSSL_CTX_SetIOSetPeer
1186
     */
1187
    int EmbedSetPeer(WOLFSSL* ssl, char* ip, int ipSz,
1188
                                                   unsigned short port, int fam)
1189
    {
1190
        /* sanity checks on arguments */
1191
        if (ssl == NULL || ip == NULL || ipSz < 0 || ipSz > MAX_EXPORT_IP) {
1192
            return BAD_FUNC_ARG;
1193
        }
1194
1195
        if (ssl->options.dtls) {
1196
        #ifdef WOLFSSL_DTLS
1197
            return EmbedSetPeerDTLS(ssl, ip, ipSz, port, fam);
1198
        #else
1199
            return NOT_COMPILED_IN;
1200
        #endif
1201
        }
1202
        else {
1203
            wolfSSL_set_fd(ssl, port);
1204
            (void)fam;
1205
            return WOLFSSL_SUCCESS;
1206
        }
1207
    }
1208
#endif /* WOLFSSL_SESSION_EXPORT */
1209
1210
#ifdef WOLFSSL_LINUXKM
1211
static int linuxkm_send(struct socket *socket, void *buf, int size,
1212
    unsigned int flags)
1213
{
1214
    size_t len;
1215
    int ret;
1216
    struct kvec vec;
1217
    struct msghdr msg = { .msg_flags = flags };
1218
1219
    if (size < 0)
1220
        return -EINVAL;
1221
    if (size == 0)
1222
        return 0;
1223
1224
    len = (size_t)size;
1225
    vec.iov_base = buf;
1226
    vec.iov_len  = len;
1227
1228
    ret = kernel_sendmsg(socket, &msg, &vec, 1, len);
1229
    return ret;
1230
}
1231
1232
static int linuxkm_recv(struct socket *socket, void *buf, int size,
1233
    unsigned int flags)
1234
{
1235
    size_t len;
1236
    int ret;
1237
    struct kvec vec;
1238
    struct msghdr msg = { .msg_flags = flags };
1239
1240
    if (size < 0)
1241
        return -EINVAL;
1242
    if (size == 0)
1243
        return 0;
1244
1245
    len = (size_t)size;
1246
    vec.iov_base = buf;
1247
    vec.iov_len  = len;
1248
1249
    ret = kernel_recvmsg(socket, &msg, &vec, 1, len, msg.msg_flags);
1250
    return ret;
1251
}
1252
#endif /* WOLFSSL_LINUXKM */
1253
1254
1255
int wolfIO_Recv(SOCKET_T sd, char *buf, int sz, int rdFlags)
1256
0
{
1257
0
    int recvd;
1258
1259
0
    if (sz < 0)
1260
0
        return WOLFSSL_CBIO_ERR_GENERAL;
1261
1262
0
    recvd = (int)RECV_FUNCTION(sd, buf, (size_t)sz, rdFlags);
1263
0
    recvd = TranslateIoReturnCode(recvd, sd, SOCKET_RECEIVING);
1264
1265
0
    return recvd;
1266
0
}
1267
1268
int wolfIO_Send(SOCKET_T sd, char *buf, int sz, int wrFlags)
1269
0
{
1270
0
    int sent;
1271
1272
0
    if (sz < 0)
1273
0
        return WOLFSSL_CBIO_ERR_GENERAL;
1274
1275
0
    sent = (int)SEND_FUNCTION(sd, buf, (size_t)sz, wrFlags);
1276
0
    sent = TranslateIoReturnCode(sent, sd, SOCKET_SENDING);
1277
1278
0
    return sent;
1279
0
}
1280
1281
#if defined(WOLFSSL_HAVE_BIO_ADDR) && defined(WOLFSSL_DTLS) && defined(OPENSSL_EXTRA)
1282
1283
int wolfIO_RecvFrom(SOCKET_T sd, WOLFSSL_BIO_ADDR *addr, char *buf, int sz, int rdFlags)
1284
{
1285
    int recvd;
1286
    socklen_t addr_len = (socklen_t)sizeof(*addr);
1287
1288
    if (sz < 0)
1289
        return WOLFSSL_CBIO_ERR_GENERAL;
1290
1291
    recvd = (int)DTLS_RECVFROM_FUNCTION(sd, buf, (size_t)sz, rdFlags,
1292
                                            addr ? &addr->sa : NULL,
1293
                                            addr ? &addr_len : 0);
1294
    recvd = TranslateIoReturnCode(recvd, sd, SOCKET_RECEIVING);
1295
1296
    return recvd;
1297
}
1298
1299
int wolfIO_SendTo(SOCKET_T sd, WOLFSSL_BIO_ADDR *addr, char *buf, int sz, int wrFlags)
1300
{
1301
    int sent;
1302
    socklen_t addr_len = addr ? wolfSSL_BIO_ADDR_size(addr) : 0;
1303
1304
    if (sz < 0)
1305
        return WOLFSSL_CBIO_ERR_GENERAL;
1306
1307
    sent = (int)DTLS_SENDTO_FUNCTION(sd, buf, (size_t)sz, wrFlags,
1308
                                         addr ? &addr->sa : NULL,
1309
                                         addr_len);
1310
    sent = TranslateIoReturnCode(sent, sd, SOCKET_SENDING);
1311
1312
    return sent;
1313
}
1314
1315
#endif /* WOLFSSL_HAVE_BIO_ADDR && WOLFSSL_DTLS && OPENSSL_EXTRA */
1316
1317
#endif /* USE_WOLFSSL_IO */
1318
1319
1320
#ifdef HAVE_HTTP_CLIENT
1321
1322
#ifndef HAVE_IO_TIMEOUT
1323
    #define io_timeout_sec 0
1324
#else
1325
1326
    #ifndef DEFAULT_TIMEOUT_SEC
1327
        #define DEFAULT_TIMEOUT_SEC 0 /* no timeout */
1328
    #endif
1329
1330
    static int io_timeout_sec = DEFAULT_TIMEOUT_SEC;
1331
1332
    void wolfIO_SetTimeout(int to_sec)
1333
    {
1334
        io_timeout_sec = to_sec;
1335
    }
1336
1337
    int wolfIO_SetBlockingMode(SOCKET_T sockfd, int non_blocking)
1338
    {
1339
        int ret = 0;
1340
1341
    #ifdef USE_WINDOWS_API
1342
        unsigned long blocking = non_blocking;
1343
        ret = ioctlsocket(sockfd, FIONBIO, &blocking);
1344
        if (ret == SOCKET_ERROR)
1345
            ret = WOLFSSL_FATAL_ERROR;
1346
    #elif defined(__WATCOMC__) && defined(__OS2__)
1347
        if (ioctl(sockfd, FIONBIO, &non_blocking) == -1)
1348
            ret = WOLFSSL_FATAL_ERROR;
1349
    #else
1350
        ret = fcntl(sockfd, F_GETFL, 0);
1351
        if (ret >= 0) {
1352
            if (non_blocking)
1353
                ret |= O_NONBLOCK;
1354
            else
1355
                ret &= ~O_NONBLOCK;
1356
            ret = fcntl(sockfd, F_SETFL, ret);
1357
        }
1358
    #endif
1359
        if (ret < 0) {
1360
            WOLFSSL_MSG("wolfIO_SetBlockingMode failed");
1361
        }
1362
1363
        return ret;
1364
    }
1365
1366
    int wolfIO_Select(SOCKET_T sockfd, int to_sec)
1367
    {
1368
        fd_set rfds, wfds;
1369
        int nfds = 0;
1370
        struct timeval timeout = { (to_sec > 0) ? to_sec : 0, 0};
1371
        int ret;
1372
1373
    #ifndef USE_WINDOWS_API
1374
        nfds = (int)sockfd + 1;
1375
1376
        if ((sockfd < 0) || (sockfd >= FD_SETSIZE)) {
1377
            WOLFSSL_MSG("socket fd out of FDSET range");
1378
            return WOLFSSL_FATAL_ERROR;
1379
        }
1380
    #endif
1381
1382
        FD_ZERO(&rfds);
1383
        FD_SET(sockfd, &rfds);
1384
        wfds = rfds;
1385
1386
        ret = select(nfds, &rfds, &wfds, NULL, &timeout);
1387
        if (ret == 0) {
1388
    #ifdef DEBUG_HTTP
1389
            fprintf(stderr, "Timeout: %d\n", ret);
1390
    #endif
1391
            return HTTP_TIMEOUT;
1392
        }
1393
        else if (ret > 0) {
1394
            if (FD_ISSET(sockfd, &wfds)) {
1395
                if (!FD_ISSET(sockfd, &rfds)) {
1396
                    return 0;
1397
                }
1398
            }
1399
        }
1400
1401
        WOLFSSL_MSG("Select error");
1402
        return SOCKET_ERROR_E;
1403
    }
1404
#endif /* HAVE_IO_TIMEOUT */
1405
1406
static word32 wolfIO_Word16ToString(char* d, word16 number)
1407
{
1408
    word32 i = 0;
1409
    word16 order = 10000;
1410
    word16 digit;
1411
1412
    if (d == NULL)
1413
        return i;
1414
1415
    if (number == 0)
1416
        d[i++] = '0';
1417
    else {
1418
        while (order) {
1419
            digit = number / order;
1420
            if (i > 0 || digit != 0)
1421
                d[i++] = (char)digit + '0';
1422
            if (digit != 0)
1423
                number = (word16) (number % (digit * order));
1424
1425
            order = (order > 1) ? order / 10 : 0;
1426
        }
1427
    }
1428
    d[i] = 0; /* null terminate */
1429
1430
    return i;
1431
}
1432
1433
int wolfIO_TcpConnect(SOCKET_T* sockfd, const char* ip, word16 port, int to_sec)
1434
{
1435
#ifdef HAVE_SOCKADDR
1436
    int ret = 0;
1437
    SOCKADDR_S addr;
1438
    socklen_t sockaddr_len;
1439
#if defined(HAVE_GETADDRINFO)
1440
    /* use getaddrinfo */
1441
    ADDRINFO hints;
1442
    ADDRINFO* answer = NULL;
1443
    char strPort[6];
1444
#else
1445
    /* use gethostbyname */
1446
#if defined(__GLIBC__) && (__GLIBC__ >= 2) && defined(__USE_MISC) && \
1447
    !defined(SINGLE_THREADED)
1448
    HOSTENT entry_buf, *entry = NULL;
1449
    char *ghbn_r_buf = NULL;
1450
    int ghbn_r_errno;
1451
#else
1452
    HOSTENT *entry;
1453
#endif
1454
#ifdef WOLFSSL_IPV6
1455
    SOCKADDR_IN6 *sin;
1456
#else
1457
    SOCKADDR_IN *sin;
1458
#endif /* WOLFSSL_IPV6 */
1459
#endif /* HAVE_GETADDRINFO */
1460
1461
    if (sockfd == NULL || ip == NULL) {
1462
        return WOLFSSL_FATAL_ERROR;
1463
    }
1464
1465
#if !defined(HAVE_GETADDRINFO)
1466
#ifdef WOLFSSL_IPV6
1467
    sockaddr_len = sizeof(SOCKADDR_IN6);
1468
#else
1469
    sockaddr_len = sizeof(SOCKADDR_IN);
1470
#endif /* WOLFSSL_IPV6 */
1471
#endif /* !HAVE_GETADDRINFO */
1472
    XMEMSET(&addr, 0, sizeof(addr));
1473
1474
#ifdef WOLFIO_DEBUG
1475
    printf("TCP Connect: %s:%d\n", ip, port);
1476
#endif
1477
1478
    /* use gethostbyname for c99 */
1479
#if defined(HAVE_GETADDRINFO)
1480
    XMEMSET(&hints, 0, sizeof(hints));
1481
#ifdef WOLFSSL_IPV6
1482
    hints.ai_family = AF_UNSPEC; /* detect IPv4 or IPv6 */
1483
#else
1484
    hints.ai_family = AF_INET;   /* detect only IPv4 */
1485
#endif
1486
    hints.ai_socktype = SOCK_STREAM;
1487
    hints.ai_protocol = IPPROTO_TCP;
1488
1489
    if (wolfIO_Word16ToString(strPort, port) == 0) {
1490
        WOLFSSL_MSG("invalid port number for responder");
1491
        return WOLFSSL_FATAL_ERROR;
1492
    }
1493
1494
    if (getaddrinfo(ip, strPort, &hints, &answer) < 0 || answer == NULL) {
1495
        WOLFSSL_MSG("no addr info for responder");
1496
        return WOLFSSL_FATAL_ERROR;
1497
    }
1498
1499
    sockaddr_len = answer->ai_addrlen;
1500
    XMEMCPY(&addr, answer->ai_addr, (size_t)sockaddr_len);
1501
    freeaddrinfo(answer);
1502
#else
1503
#if defined(__GLIBC__) && (__GLIBC__ >= 2) && defined(__USE_MISC) && \
1504
    !defined(SINGLE_THREADED)
1505
    /* 2048 is a magic number that empirically works.  the header and
1506
     * documentation provide no guidance on appropriate buffer size other than
1507
     * "if buf is too small, the functions will return ERANGE, and the call
1508
     * should be retried with a larger buffer."
1509
     */
1510
    ghbn_r_buf = (char *)XMALLOC(2048, NULL, DYNAMIC_TYPE_TMP_BUFFER);
1511
    if (ghbn_r_buf != NULL) {
1512
        gethostbyname_r(ip, &entry_buf, ghbn_r_buf, 2048, &entry, &ghbn_r_errno);
1513
    }
1514
#else
1515
    entry = gethostbyname(ip);
1516
#endif
1517
1518
    if (entry) {
1519
    #ifdef WOLFSSL_IPV6
1520
        sin = (SOCKADDR_IN6 *)&addr;
1521
        sin->sin6_family = AF_INET6;
1522
        sin->sin6_port = XHTONS(port);
1523
        XMEMCPY(&sin->sin6_addr, entry->h_addr_list[0], entry->h_length);
1524
    #else
1525
        sin = (SOCKADDR_IN *)&addr;
1526
        sin->sin_family = AF_INET;
1527
        sin->sin_port = XHTONS(port);
1528
        XMEMCPY(&sin->sin_addr.s_addr, entry->h_addr_list[0],
1529
                (size_t)entry->h_length);
1530
    #endif
1531
    }
1532
1533
#if defined(__GLIBC__) && (__GLIBC__ >= 2) && defined(__USE_MISC) && \
1534
    !defined(SINGLE_THREADED)
1535
    XFREE(ghbn_r_buf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
1536
#endif
1537
1538
    if (entry == NULL) {
1539
        WOLFSSL_MSG("no addr info for responder");
1540
        return WOLFSSL_FATAL_ERROR;
1541
    }
1542
#endif
1543
1544
    *sockfd = (SOCKET_T)wc_socket_cloexec(addr.ss_family, SOCK_STREAM, 0);
1545
#ifdef USE_WINDOWS_API
1546
    if (*sockfd == SOCKET_INVALID)
1547
#else
1548
    if (*sockfd <= SOCKET_INVALID)
1549
#endif
1550
    {
1551
        WOLFSSL_MSG("bad socket fd, out of fds?");
1552
        *sockfd = SOCKET_INVALID;
1553
        return WOLFSSL_FATAL_ERROR;
1554
    }
1555
1556
#ifdef HAVE_IO_TIMEOUT
1557
    /* if timeout value provided then set socket non-blocking */
1558
    if (to_sec > 0) {
1559
        wolfIO_SetBlockingMode(*sockfd, 1);
1560
    }
1561
#else
1562
    (void)to_sec;
1563
#endif /* HAVE_IO_TIMEOUT */
1564
1565
    ret = connect(*sockfd, (SOCKADDR *)&addr, sockaddr_len);
1566
#ifdef HAVE_IO_TIMEOUT
1567
    if ((ret != 0) && (to_sec > 0)) {
1568
#ifdef USE_WINDOWS_API
1569
        if ((ret == SOCKET_ERROR) &&
1570
            (wolfSSL_LastError(ret, *sockfd) == SOCKET_EWOULDBLOCK))
1571
#else
1572
        if (errno == EINPROGRESS)
1573
#endif
1574
        {
1575
            /* wait for connect to complete */
1576
            ret = wolfIO_Select(*sockfd, to_sec);
1577
1578
            /* restore blocking mode */
1579
            wolfIO_SetBlockingMode(*sockfd, 0);
1580
        }
1581
    }
1582
#endif /* HAVE_IO_TIMEOUT */
1583
    if (ret != 0) {
1584
        WOLFSSL_MSG("Responder tcp connect failed");
1585
        CloseSocket(*sockfd);
1586
        *sockfd = SOCKET_INVALID;
1587
        return WOLFSSL_FATAL_ERROR;
1588
    }
1589
    return ret;
1590
#else
1591
    (void)sockfd;
1592
    (void)ip;
1593
    (void)port;
1594
    (void)to_sec;
1595
    return WOLFSSL_FATAL_ERROR;
1596
#endif /* HAVE_SOCKADDR */
1597
}
1598
1599
int wolfIO_TcpBind(SOCKET_T* sockfd, word16 port)
1600
{
1601
#ifdef HAVE_SOCKADDR
1602
    int ret = 0;
1603
    SOCKADDR_S addr;
1604
#ifdef WOLFSSL_IPV6
1605
    socklen_t sockaddr_len = sizeof(SOCKADDR_IN6);
1606
    SOCKADDR_IN6 *sin = (SOCKADDR_IN6 *)&addr;
1607
#else
1608
    socklen_t sockaddr_len = sizeof(SOCKADDR_IN);
1609
    SOCKADDR_IN *sin = (SOCKADDR_IN *)&addr;
1610
#endif
1611
1612
    if (sockfd == NULL || port < 1) {
1613
        return WOLFSSL_FATAL_ERROR;
1614
    }
1615
1616
    XMEMSET(&addr, 0, sizeof(addr));
1617
1618
#ifdef WOLFSSL_IPV6
1619
    sin->sin6_family = AF_INET6;
1620
    sin->sin6_addr = in6addr_any;
1621
    sin->sin6_port = XHTONS(port);
1622
    *sockfd = (SOCKET_T)wc_socket_cloexec(AF_INET6, SOCK_STREAM, 0);
1623
#else
1624
    sin->sin_family = AF_INET;
1625
    sin->sin_addr.s_addr = INADDR_ANY;
1626
    sin->sin_port = XHTONS(port);
1627
    *sockfd = (SOCKET_T)wc_socket_cloexec(AF_INET, SOCK_STREAM, 0);
1628
#endif
1629
1630
#ifdef USE_WINDOWS_API
1631
    if (*sockfd == SOCKET_INVALID)
1632
#else
1633
    if (*sockfd <= SOCKET_INVALID)
1634
#endif
1635
    {
1636
        WOLFSSL_MSG("socket failed");
1637
        *sockfd = SOCKET_INVALID;
1638
        return WOLFSSL_FATAL_ERROR;
1639
    }
1640
1641
#if !defined(USE_WINDOWS_API) && !defined(WOLFSSL_MDK_ARM)\
1642
                   && !defined(WOLFSSL_KEIL_TCP_NET) && !defined(WOLFSSL_ZEPHYR)
1643
    {
1644
        int optval  = 1;
1645
        XSOCKLENT optlen = sizeof(optval);
1646
        ret = setsockopt(*sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, optlen);
1647
    }
1648
#endif
1649
1650
    if (ret == 0)
1651
        ret = bind(*sockfd, (SOCKADDR *)sin, sockaddr_len);
1652
    if (ret == 0)
1653
        ret = listen(*sockfd, SOMAXCONN);
1654
1655
    if (ret != 0) {
1656
        WOLFSSL_MSG("wolfIO_TcpBind failed");
1657
        CloseSocket(*sockfd);
1658
        *sockfd = SOCKET_INVALID;
1659
        ret = WOLFSSL_FATAL_ERROR;
1660
    }
1661
1662
    return ret;
1663
#else
1664
    (void)sockfd;
1665
    (void)port;
1666
    return WOLFSSL_FATAL_ERROR;
1667
#endif /* HAVE_SOCKADDR */
1668
}
1669
1670
#ifdef HAVE_SOCKADDR
1671
int wolfIO_TcpAccept(SOCKET_T sockfd, SOCKADDR* peer_addr, XSOCKLENT* peer_len)
1672
{
1673
    return (int)wc_accept_cloexec((int)sockfd, peer_addr, peer_len);
1674
}
1675
#endif /* HAVE_SOCKADDR */
1676
1677
#ifndef HTTP_SCRATCH_BUFFER_SIZE
1678
    #define HTTP_SCRATCH_BUFFER_SIZE 512
1679
#endif
1680
#ifndef MAX_URL_ITEM_SIZE
1681
    #define MAX_URL_ITEM_SIZE   80
1682
#endif
1683
1684
int wolfIO_DecodeUrl(const char* url, int urlSz, char* outName, char* outPath,
1685
    word16* outPort)
1686
{
1687
    int result = WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR);
1688
1689
    if (url == NULL || urlSz == 0) {
1690
        if (outName)
1691
            *outName = 0;
1692
        if (outPath)
1693
            *outPath = 0;
1694
        if (outPort)
1695
            *outPort = 0;
1696
    }
1697
    else {
1698
        int i, cur;
1699
1700
        /* need to break the url down into scheme, address, and port */
1701
        /*     "http://example.com:8080/" */
1702
        /*     "http://[::1]:443/"        */
1703
        if (XSTRNCMP(url, "http://", 7) == 0) {
1704
            cur = 7;
1705
        } else cur = 0;
1706
1707
        i = 0;
1708
        if (url[cur] == '[') {
1709
            cur++;
1710
            /* copy until ']' */
1711
            while (i < MAX_URL_ITEM_SIZE-1 && cur < urlSz && url[cur] != 0 &&
1712
                    url[cur] != ']') {
1713
                if (url[cur] == '\r' || url[cur] == '\n')
1714
                    return WOLFSSL_FATAL_ERROR;
1715
                if (outName)
1716
                    outName[i] = url[cur];
1717
                i++; cur++;
1718
            }
1719
            /* A bracketed IPv6 literal must be terminated by ']'. The loop
1720
             * above can also stop on end-of-buffer, NUL, or the length cap,
1721
             * none of which represent a well-formed host. Reject those cases
1722
             * rather than accepting the unterminated tail as the hostname. */
1723
            if (cur >= urlSz || url[cur] != ']')
1724
                return WOLFSSL_FATAL_ERROR;
1725
            cur++; /* skip ']' */
1726
        }
1727
        else {
1728
            while (i < MAX_URL_ITEM_SIZE-1 && cur < urlSz && url[cur] != 0 &&
1729
                    url[cur] != ':' && url[cur] != '/') {
1730
                if (url[cur] == '\r' || url[cur] == '\n')
1731
                    return WOLFSSL_FATAL_ERROR;
1732
                if (outName)
1733
                    outName[i] = url[cur];
1734
                i++; cur++;
1735
            }
1736
        }
1737
        if (outName)
1738
            outName[i] = 0;
1739
        /* Need to pick out the path after the domain name */
1740
1741
        if (cur < urlSz && url[cur] == ':') {
1742
            char port[5];
1743
            int j;
1744
            word32 bigPort = 0;
1745
            i = 0;
1746
            cur++;
1747
1748
            XMEMSET(port, 0, sizeof(port));
1749
1750
            while (i < 5 && cur < urlSz && url[cur] != 0 && url[cur] != '/') {
1751
                port[i] = url[cur];
1752
                i++; cur++;
1753
            }
1754
1755
            /* A valid port is at most 5 digits; if more characters remain
1756
             * before the path/terminator the port field is malformed (e.g.
1757
             * a 6-digit port) and must be rejected rather than parsed from a
1758
             * truncated digit string. */
1759
            if (cur < urlSz && url[cur] != 0 && url[cur] != '/')
1760
                return WOLFSSL_FATAL_ERROR;
1761
1762
            for (j = 0; j < i; j++) {
1763
                if (port[j] < '0' || port[j] > '9') return WOLFSSL_FATAL_ERROR;
1764
                bigPort = (bigPort * 10) + (word32)(port[j] - '0');
1765
            }
1766
            /* Reject out-of-range ports rather than silently truncating to
1767
             * word16, which would otherwise wrap (e.g. 65536 -> 0) and
1768
             * connect to an unintended port. */
1769
            if (bigPort > WOLFSSL_MAX_16BIT)
1770
                return WOLFSSL_FATAL_ERROR;
1771
            if (outPort)
1772
                *outPort = (word16)bigPort;
1773
        }
1774
        else if (outPort)
1775
            *outPort = 80;
1776
1777
1778
        if (cur < urlSz && url[cur] == '/') {
1779
            i = 0;
1780
            while (i < MAX_URL_ITEM_SIZE-1 && cur < urlSz && url[cur] != 0) {
1781
                if (url[cur] == '\r' || url[cur] == '\n')
1782
                    return WOLFSSL_FATAL_ERROR;
1783
                if (outPath)
1784
                    outPath[i] = url[cur];
1785
                i++; cur++;
1786
            }
1787
            if (outPath)
1788
                outPath[i] = 0;
1789
        }
1790
        else if (outPath) {
1791
            outPath[0] = '/';
1792
            outPath[1] = 0;
1793
        }
1794
1795
        result = 0;
1796
    }
1797
1798
    return result;
1799
}
1800
1801
#ifndef WOLFIO_HTTP_MAX_BODY
1802
/* Upper bound on an HTTP body that will be buffered in memory. */
1803
#define WOLFIO_HTTP_MAX_BODY (32 * 1024 * 1024)
1804
#endif
1805
1806
static int wolfIO_HttpProcessResponseBuf(WolfSSLGenericIORecvCb ioCb,
1807
    void* ioCbCtx, byte **recvBuf, int* recvBufSz, int chunkSz, char* start,
1808
    int len, int dynType, void* heap)
1809
{
1810
    byte* newRecvBuf = NULL;
1811
    int newRecvSz;
1812
    int pos = 0;
1813
1814
    WOLFSSL_MSG("Processing HTTP response");
1815
#ifdef WOLFIO_DEBUG
1816
    printf("HTTP Chunk %d->%d\n", *recvBufSz, chunkSz);
1817
#endif
1818
1819
    (void)heap;
1820
    (void)dynType;
1821
1822
    if (chunkSz < 0 || len < 0) {
1823
        WOLFSSL_MSG("wolfIO_HttpProcessResponseBuf invalid chunk or length size");
1824
        return MEMORY_E;
1825
    }
1826
1827
    if (chunkSz > WOLFIO_HTTP_MAX_BODY) {
1828
        WOLFSSL_MSG("wolfIO_HttpProcessResponseBuf chunk too large");
1829
        return BUFFER_ERROR;
1830
    }
1831
1832
    if (*recvBufSz < 0 || *recvBufSz > WOLFIO_HTTP_MAX_BODY - chunkSz) {
1833
        WOLFSSL_MSG("wolfIO_HttpProcessResponseBuf aggregate body too large");
1834
        return BUFFER_ERROR;
1835
    }
1836
1837
    if (len > chunkSz) {
1838
        WOLFSSL_MSG("wolfIO_HttpProcessResponseBuf len exceeds chunk size");
1839
        return WOLFSSL_FATAL_ERROR;
1840
    }
1841
1842
    newRecvSz = *recvBufSz + chunkSz;
1843
1844
    if (newRecvSz <= 0) {
1845
        WOLFSSL_MSG("wolfIO_HttpProcessResponseBuf new receive size overflow");
1846
        return MEMORY_E;
1847
    }
1848
1849
    newRecvBuf = (byte*)XMALLOC((size_t)newRecvSz, heap, dynType);
1850
    if (newRecvBuf == NULL) {
1851
        WOLFSSL_MSG("wolfIO_HttpProcessResponseBuf malloc failed");
1852
        return MEMORY_E;
1853
    }
1854
1855
    /* if buffer already exists, then we are growing it */
1856
    if (*recvBuf) {
1857
        XMEMCPY(&newRecvBuf[pos], *recvBuf, (size_t) *recvBufSz);
1858
        XFREE(*recvBuf, heap, dynType);
1859
        pos += *recvBufSz;
1860
        *recvBuf = NULL;
1861
    }
1862
1863
    /* copy the remainder of the httpBuf into the respBuf */
1864
    if (len != 0) {
1865
        if (pos + len <= newRecvSz) {
1866
            XMEMCPY(&newRecvBuf[pos], start, (size_t)len);
1867
            pos += len;
1868
        }
1869
        else {
1870
            WOLFSSL_MSG("wolfIO_HttpProcessResponseBuf bad size");
1871
            XFREE(newRecvBuf, heap, dynType);
1872
            return WOLFSSL_FATAL_ERROR;
1873
        }
1874
    }
1875
1876
    /* receive the remainder of chunk */
1877
    while (len < chunkSz) {
1878
        int rxSz = ioCb((char*)&newRecvBuf[pos], chunkSz-len, ioCbCtx);
1879
        if (rxSz > 0) {
1880
            len += rxSz;
1881
            pos += rxSz;
1882
        }
1883
        else {
1884
            WOLFSSL_MSG("wolfIO_HttpProcessResponseBuf recv failed");
1885
            XFREE(newRecvBuf, heap, dynType);
1886
            return WOLFSSL_FATAL_ERROR;
1887
        }
1888
    }
1889
1890
    *recvBuf = newRecvBuf;
1891
    *recvBufSz = newRecvSz;
1892
1893
    return 0;
1894
}
1895
1896
int wolfIO_HttpProcessResponseGenericIO(WolfSSLGenericIORecvCb ioCb,
1897
    void* ioCbCtx, const char** appStrList, unsigned char** respBuf,
1898
    unsigned char* httpBuf, int httpBufSz, int dynType, void* heap)
1899
{
1900
    static const char HTTP_PROTO[] = "HTTP/1.";
1901
    static const char HTTP_STATUS_200[] = "200";
1902
    int result = 0;
1903
    int len = 0;
1904
    char *start, *end;
1905
    int respBufSz = 0;
1906
    int isChunked = 0, chunkSz = 0;
1907
    enum phr_state { phr_init, phr_http_start, phr_have_length, phr_have_type,
1908
                     phr_wait_end, phr_get_chunk_len, phr_get_chunk_data,
1909
                     phr_http_end
1910
    } state = phr_init;
1911
1912
    WOLFSSL_ENTER("wolfIO_HttpProcessResponse");
1913
1914
    *respBuf = NULL;
1915
    start = end = NULL;
1916
    do {
1917
        if (state == phr_get_chunk_data) {
1918
            /* get chunk of data */
1919
            result = wolfIO_HttpProcessResponseBuf(ioCb, ioCbCtx, respBuf,
1920
                &respBufSz, chunkSz, start, len, dynType, heap);
1921
1922
            state = (result != 0) ? phr_http_end : phr_get_chunk_len;
1923
            end = NULL;
1924
            len = 0;
1925
        }
1926
1927
        /* read data if no \r\n or first time */
1928
        if ((start == NULL) || (end == NULL)) {
1929
            if (httpBufSz < len + 1) {
1930
                return BUFFER_ERROR; /* can't happen, but Coverity thinks it
1931
                                      * can.
1932
                                      */
1933
            }
1934
            result = ioCb((char*)httpBuf+len, httpBufSz-len-1, ioCbCtx);
1935
            if (result > 0) {
1936
                len += result;
1937
                start = (char*)httpBuf;
1938
                start[len] = 0;
1939
            }
1940
            else {
1941
                if (result == WC_NO_ERR_TRACE(WOLFSSL_CBIO_ERR_WANT_READ)) {
1942
                    return OCSP_WANT_READ;
1943
                }
1944
1945
                WOLFSSL_MSG("wolfIO_HttpProcessResponse recv http from peer failed");
1946
                return HTTP_RECV_ERR;
1947
            }
1948
        }
1949
        end = XSTRSTR(start, "\r\n"); /* locate end */
1950
1951
        /* handle incomplete rx */
1952
        if (end == NULL) {
1953
            if (len != 0)
1954
                XMEMMOVE(httpBuf, start, (size_t)len);
1955
            start = end = NULL;
1956
        }
1957
        /* when start is "\r\n" */
1958
        else if (end == start) {
1959
            /* if waiting for end or need chunk len */
1960
            if (state == phr_wait_end || state == phr_get_chunk_len) {
1961
                state = (isChunked) ? phr_get_chunk_len : phr_http_end;
1962
                len -= 2; start += 2; /* skip \r\n */
1963
             }
1964
             else {
1965
                WOLFSSL_MSG("wolfIO_HttpProcessResponse header ended early");
1966
                return HTTP_HEADER_ERR;
1967
             }
1968
        }
1969
        else {
1970
            *end = 0; /* null terminate */
1971
            len -= (int)(end - start) + 2;
1972
                /* adjust len to remove the first line including the /r/n */
1973
1974
        #ifdef WOLFIO_DEBUG
1975
            printf("HTTP Resp: %s\n", start);
1976
        #endif
1977
1978
            switch (state) {
1979
                case phr_init:
1980
                    /* length of "HTTP/1.x 200" == 12*/
1981
                    if (XSTRLEN(start) < 12) {
1982
                        WOLFSSL_MSG("wolfIO_HttpProcessResponse HTTP header "
1983
                            "too short.");
1984
                        return HTTP_HEADER_ERR;
1985
                    }
1986
                    if (XSTRNCASECMP(start, HTTP_PROTO,
1987
                                     sizeof(HTTP_PROTO) - 1) != 0) {
1988
                        WOLFSSL_MSG("wolfIO_HttpProcessResponse HTTP header "
1989
                            "doesn't start with HTTP/1.");
1990
                        return HTTP_PROTO_ERR;
1991
                    }
1992
                    /* +2 for HTTP minor version and space between version and
1993
                     * status code. */
1994
                    start += sizeof(HTTP_PROTO) - 1 + 2 ;
1995
                    if (XSTRNCASECMP(start, HTTP_STATUS_200,
1996
                                     sizeof(HTTP_STATUS_200) - 1) != 0) {
1997
                        WOLFSSL_MSG("wolfIO_HttpProcessResponse HTTP header "
1998
                            "doesn't have status code 200.");
1999
                        return HTTP_STATUS_ERR;
2000
                    }
2001
                    state = phr_http_start;
2002
                    break;
2003
                case phr_http_start:
2004
                case phr_have_length:
2005
                case phr_have_type:
2006
                    if (XSTRNCASECMP(start, "Content-Type:", 13) == 0) {
2007
                        int i;
2008
2009
                        start += 13;
2010
                        while (*start == ' ') start++;
2011
2012
                        /* try and match against appStrList */
2013
                        i = 0;
2014
                        while (appStrList[i] != NULL) {
2015
                            if (XSTRNCASECMP(start, appStrList[i],
2016
                                                XSTRLEN(appStrList[i])) == 0) {
2017
                                break;
2018
                            }
2019
                            i++;
2020
                        }
2021
                        if (appStrList[i] == NULL) {
2022
                            WOLFSSL_MSG("wolfIO_HttpProcessResponse appstr mismatch");
2023
                            return HTTP_APPSTR_ERR;
2024
                        }
2025
                        state = (state == phr_http_start) ? phr_have_type : phr_wait_end;
2026
                    }
2027
                    else if (XSTRNCASECMP(start, "Content-Length:", 15) == 0) {
2028
                        start += 15;
2029
                        while (*start == ' ') start++;
2030
                        chunkSz = XATOI(start);
2031
                        state = (state == phr_http_start) ? phr_have_length : phr_wait_end;
2032
                    }
2033
                    else if (XSTRNCASECMP(start, "Transfer-Encoding:", 18) == 0) {
2034
                        start += 18;
2035
                        while (*start == ' ') start++;
2036
                        if (XSTRNCASECMP(start, "chunked", 7) == 0) {
2037
                            isChunked = 1;
2038
                            state = (state == phr_http_start) ? phr_have_length : phr_wait_end;
2039
                        }
2040
                    }
2041
                    break;
2042
                case phr_get_chunk_len:
2043
                    chunkSz = (int)strtol(start, NULL, 16); /* hex format */
2044
                    state = (chunkSz == 0) ? phr_http_end : phr_get_chunk_data;
2045
                    break;
2046
                case phr_get_chunk_data:
2047
                    /* processing for chunk data done above, since \r\n isn't required */
2048
                case phr_wait_end:
2049
                case phr_http_end:
2050
                    /* do nothing */
2051
                    break;
2052
            } /* switch (state) */
2053
2054
            /* skip to end plus \r\n */
2055
            start = end + 2;
2056
        }
2057
    } while (state != phr_http_end);
2058
2059
    if (!isChunked) {
2060
        result = wolfIO_HttpProcessResponseBuf(ioCb, ioCbCtx, respBuf,
2061
                &respBufSz, chunkSz, start, len, dynType, heap);
2062
    }
2063
2064
    if (result >= 0) {
2065
        result = respBufSz;
2066
    }
2067
    else {
2068
        WOLFSSL_ERROR(result);
2069
    }
2070
2071
    return result;
2072
}
2073
2074
static int httpResponseIoCb(char* buf, int sz, void* ctx)
2075
{
2076
    /* Double cast to silence the compiler int/pointer width msg */
2077
    return wolfIO_Recv((SOCKET_T)(uintptr_t)ctx, buf, sz, 0);
2078
}
2079
2080
int wolfIO_HttpProcessResponse(int sfd, const char** appStrList,
2081
    byte** respBuf, byte* httpBuf, int httpBufSz, int dynType, void* heap)
2082
{
2083
    return wolfIO_HttpProcessResponseGenericIO(httpResponseIoCb,
2084
            /* Double cast to silence the compiler int/pointer width msg */
2085
            (void*)(uintptr_t)sfd, appStrList, respBuf, httpBuf, httpBufSz,
2086
            dynType, heap);
2087
}
2088
2089
int wolfIO_HttpBuildRequest(const char *reqType, const char *domainName,
2090
                               const char *path, int pathLen, int reqSz, const char *contentType,
2091
                               byte *buf, int bufSize)
2092
{
2093
    return wolfIO_HttpBuildRequest_ex(reqType, domainName, path, pathLen, reqSz, contentType, "", buf, bufSize);
2094
}
2095
2096
/* Returns 1 if the buffer contains a CR or LF byte, 0 otherwise. Used to
2097
 * reject attacker-controlled URL components that would allow HTTP header
2098
 * injection or request splitting. */
2099
static int wolfIO_UrlHasCrlf(const char* in, int inSz)
2100
{
2101
    int i = 0;
2102
    if (in == NULL)
2103
        return 0;
2104
    for (i = 0; i < inSz; i++) {
2105
        if (in[i] == '\r' || in[i] == '\n')
2106
            return 1;
2107
    }
2108
    return 0;
2109
}
2110
2111
int wolfIO_HttpBuildRequest_ex(const char *reqType, const char *domainName,
2112
                                const char *path, int pathLen, int reqSz, const char *contentType,
2113
                                const char *exHdrs, byte *buf, int bufSize)
2114
    {
2115
    word32 reqTypeLen, domainNameLen, reqSzStrLen, contentTypeLen, exHdrsLen, maxLen;
2116
    char reqSzStr[6];
2117
    char* req = (char*)buf;
2118
    const char* blankStr = " ";
2119
    const char* http11Str = " HTTP/1.1";
2120
    const char* hostStr = "\r\nHost: ";
2121
    const char* contentLenStr = "\r\nContent-Length: ";
2122
    const char* contentTypeStr = "\r\nContent-Type: ";
2123
    const char* singleCrLfStr = "\r\n";
2124
    const char* doubleCrLfStr = "\r\n\r\n";
2125
    word32 blankStrLen, http11StrLen, hostStrLen, contentLenStrLen,
2126
        contentTypeStrLen, singleCrLfStrLen, doubleCrLfStrLen;
2127
2128
    /* reject NULL pointers and invalid lengths before any deref or length
2129
     * math: the XSTRLEN/copy calls below assume non-NULL inputs */
2130
    if (reqType == NULL || domainName == NULL || path == NULL ||
2131
            contentType == NULL || pathLen < 0 || bufSize <= 0)
2132
        return 0;
2133
2134
    reqTypeLen = (word32)XSTRLEN(reqType);
2135
    domainNameLen = (word32)XSTRLEN(domainName);
2136
    reqSzStrLen = wolfIO_Word16ToString(reqSzStr, (word16)reqSz);
2137
    contentTypeLen = (word32)XSTRLEN(contentType);
2138
2139
    /* reject CR/LF in the path or host to prevent HTTP header injection or
2140
     * request splitting from attacker-controlled URL components */
2141
    if (wolfIO_UrlHasCrlf(path, pathLen) ||
2142
            wolfIO_UrlHasCrlf(domainName, (int)domainNameLen)) {
2143
        return 0;
2144
    }
2145
2146
    blankStrLen = (word32)XSTRLEN(blankStr);
2147
    http11StrLen = (word32)XSTRLEN(http11Str);
2148
    hostStrLen = (word32)XSTRLEN(hostStr);
2149
    contentLenStrLen = (word32)XSTRLEN(contentLenStr);
2150
    contentTypeStrLen = (word32)XSTRLEN(contentTypeStr);
2151
2152
    if(exHdrs){
2153
        singleCrLfStrLen = (word32)XSTRLEN(singleCrLfStr);
2154
        exHdrsLen = (word32)XSTRLEN(exHdrs);
2155
    } else {
2156
        singleCrLfStrLen = 0;
2157
        exHdrsLen = 0;
2158
    }
2159
2160
    doubleCrLfStrLen = (word32)XSTRLEN(doubleCrLfStr);
2161
2162
    /* determine max length and check it */
2163
    maxLen =
2164
        reqTypeLen +
2165
        blankStrLen +
2166
        (word32)pathLen +
2167
        http11StrLen +
2168
        hostStrLen +
2169
        domainNameLen +
2170
        contentLenStrLen +
2171
        reqSzStrLen +
2172
        contentTypeStrLen +
2173
        contentTypeLen +
2174
        singleCrLfStrLen +
2175
        exHdrsLen +
2176
        doubleCrLfStrLen +
2177
        (word32)1 /* null term */;
2178
    if (maxLen > (word32)bufSize)
2179
        return 0;
2180
2181
    XSTRNCPY((char*)buf, reqType, (size_t)bufSize);
2182
    buf += reqTypeLen; bufSize -= (int)reqTypeLen;
2183
    XSTRNCPY((char*)buf, blankStr, (size_t)bufSize);
2184
    buf += blankStrLen; bufSize -= (int)blankStrLen;
2185
    /* path may not be NUL terminated (CRL raw-URL case passes a pointer into
2186
     * the certificate with only pathLen valid bytes), so bound the copy to
2187
     * pathLen rather than scanning for a NUL */
2188
    XMEMCPY((char*)buf, path, (size_t)pathLen);
2189
    buf += pathLen; bufSize -= (int)pathLen;
2190
    XSTRNCPY((char*)buf, http11Str, (size_t)bufSize);
2191
    buf += http11StrLen; bufSize -= (int)http11StrLen;
2192
    if (domainNameLen > 0) {
2193
        XSTRNCPY((char*)buf, hostStr, (size_t)bufSize);
2194
        buf += hostStrLen; bufSize -= (int)hostStrLen;
2195
        XSTRNCPY((char*)buf, domainName, (size_t)bufSize);
2196
        buf += domainNameLen; bufSize -= (int)domainNameLen;
2197
    }
2198
    if (reqSz > 0 && reqSzStrLen > 0) {
2199
        XSTRNCPY((char*)buf, contentLenStr, (size_t)bufSize);
2200
        buf += contentLenStrLen; bufSize -= (int)contentLenStrLen;
2201
        XSTRNCPY((char*)buf, reqSzStr, (size_t)bufSize);
2202
        buf += reqSzStrLen; bufSize -= (int)reqSzStrLen;
2203
    }
2204
    if (contentTypeLen > 0) {
2205
        XSTRNCPY((char*)buf, contentTypeStr, (size_t)bufSize);
2206
        buf += contentTypeStrLen; bufSize -= (int)contentTypeStrLen;
2207
        XSTRNCPY((char*)buf, contentType, (size_t)bufSize);
2208
        buf += contentTypeLen; bufSize -= (int)contentTypeLen;
2209
    }
2210
    if (exHdrsLen > 0)
2211
    {
2212
        XSTRNCPY((char *)buf, singleCrLfStr, (size_t)bufSize);
2213
        buf += singleCrLfStrLen;
2214
        bufSize -= (int)singleCrLfStrLen;
2215
        XSTRNCPY((char *)buf, exHdrs, (size_t)bufSize);
2216
        buf += exHdrsLen;
2217
        bufSize -= (int)exHdrsLen;
2218
    }
2219
    XSTRNCPY((char*)buf, doubleCrLfStr, (size_t)bufSize);
2220
    buf += doubleCrLfStrLen;
2221
2222
#ifdef WOLFIO_DEBUG
2223
    printf("HTTP %s: %s", reqType, req);
2224
#endif
2225
2226
    /* calculate actual length based on original and new pointer */
2227
    return (int)((char*)buf - req);
2228
}
2229
2230
2231
#ifdef HAVE_OCSP
2232
2233
int wolfIO_HttpBuildRequestOcsp(const char* domainName, const char* path,
2234
                                    int ocspReqSz, byte* buf, int bufSize)
2235
{
2236
    const char *cacheCtl = "Cache-Control: no-cache";
2237
    return wolfIO_HttpBuildRequest_ex("POST", domainName, path, (int)XSTRLEN(path),
2238
        ocspReqSz, "application/ocsp-request", cacheCtl, buf, bufSize);
2239
}
2240
2241
static const char* ocspAppStrList[] = {
2242
    "application/ocsp-response",
2243
    NULL
2244
};
2245
2246
int wolfIO_HttpProcessResponseOcspGenericIO(
2247
    WolfSSLGenericIORecvCb ioCb, void* ioCbCtx, unsigned char** respBuf,
2248
    unsigned char* httpBuf, int httpBufSz, void* heap)
2249
{
2250
    return wolfIO_HttpProcessResponseGenericIO(ioCb, ioCbCtx,
2251
          ocspAppStrList, respBuf, httpBuf, httpBufSz, DYNAMIC_TYPE_OCSP, heap);
2252
}
2253
2254
/* return: >0 OCSP Response Size
2255
 *         -1 error */
2256
int wolfIO_HttpProcessResponseOcsp(int sfd, byte** respBuf,
2257
                                       byte* httpBuf, int httpBufSz, void* heap)
2258
{
2259
    return wolfIO_HttpProcessResponse(sfd, ocspAppStrList,
2260
        respBuf, httpBuf, httpBufSz, DYNAMIC_TYPE_OCSP, heap);
2261
}
2262
2263
#if defined(WOLFSSL_OCSP_SCREEN_RESPONDER) && defined(HAVE_SOCKADDR)
2264
2265
/* Return 1 if the given IPv4 address (4 octets, network byte order) falls in a
2266
 * loopback/private/link-local/reserved range that an OCSP responder must not
2267
 * live in, else 0. */
2268
static int wolfIO_OcspIPv4Blocked(const unsigned char a[4])
2269
{
2270
    if (a[0] == 0)                                 /* 0.0.0.0/8    "this" net */
2271
        return 1;
2272
    if (a[0] == 127)                               /* 127.0.0.0/8  loopback */
2273
        return 1;
2274
    if (a[0] == 10)                                /* 10.0.0.0/8   private */
2275
        return 1;
2276
    if (a[0] == 172 && (a[1] & 0xF0) == 16)        /* 172.16.0.0/12 private */
2277
        return 1;
2278
    if (a[0] == 192 && a[1] == 168)                /* 192.168.0.0/16 private */
2279
        return 1;
2280
    if (a[0] == 169 && a[1] == 254)                /* 169.254.0.0/16 link-local
2281
                                                    * (incl. cloud metadata) */
2282
        return 1;
2283
    if (a[0] == 100 && (a[1] & 0xC0) == 64)        /* 100.64.0.0/10 CGNAT */
2284
        return 1;
2285
    if (a[0] >= 224)                               /* 224.0.0.0/4 multicast,
2286
                                                    * 240.0.0.0/4 reserved,
2287
                                                    * 255.255.255.255 bcast */
2288
        return 1;
2289
    return 0;
2290
}
2291
2292
/* Only the getaddrinfo resolver path yields AF_INET6 results; the gethostbyname
2293
 * fallback is IPv4-only. Guard on HAVE_GETADDRINFO so this is not compiled as an
2294
 * unused function in a WOLFSSL_IPV6 + gethostbyname-fallback build. */
2295
#if defined(WOLFSSL_IPV6) && defined(HAVE_GETADDRINFO)
2296
/* Return 1 if the given IPv6 address (16 octets, network byte order) falls in a
2297
 * loopback/unspecified/unique-local/link-local/multicast range, else 0.
2298
 * IPv4-mapped (::ffff:0:0/96), IPv4-compatible (::a.b.c.d), and NAT64
2299
 * (64:ff9b::/96) embeddings are unwrapped and screened as IPv4. */
2300
static int wolfIO_OcspIPv6Blocked(const unsigned char a[16])
2301
{
2302
    static const unsigned char v4mapped[12] =
2303
        { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF };
2304
    int i;
2305
    int zeroPrefix = 1;  /* bytes 0..11 all zero (IPv4-compatible prefix) */
2306
2307
    for (i = 0; i < 12; i++) {
2308
        if (a[i] != 0) {
2309
            zeroPrefix = 0;
2310
            break;
2311
        }
2312
    }
2313
    if ((a[0] & 0xFE) == 0xFC)                     /* fc00::/7 unique local */
2314
        return 1;
2315
    if (a[0] == 0xFE && (a[1] & 0xC0) == 0x80)     /* fe80::/10 link-local */
2316
        return 1;
2317
    if (a[0] == 0xFF)                              /* ff00::/8 multicast */
2318
        return 1;
2319
    if (XMEMCMP(a, v4mapped, sizeof(v4mapped)) == 0) /* ::ffff:0:0/96 mapped */
2320
        return wolfIO_OcspIPv4Blocked(a + 12);
2321
    /* :: unspecified, ::1 loopback, and deprecated IPv4-compatible ::a.b.c.d
2322
     * all have 96 zero leading bits; screen the embedded IPv4 (covers them,
2323
     * since 0.0.0.0/8 is blocked). No public unicast address looks like this. */
2324
    if (zeroPrefix)
2325
        return wolfIO_OcspIPv4Blocked(a + 12);
2326
    if (a[0] == 0x00 && a[1] == 0x64 && a[2] == 0xFF && a[3] == 0x9B) {
2327
        /* NAT64 well-known prefix 64:ff9b::/96 -> screen embedded IPv4 */
2328
        int zeroMid = 1;
2329
        for (i = 4; i < 12; i++) {
2330
            if (a[i] != 0) {
2331
                zeroMid = 0;
2332
                break;
2333
            }
2334
        }
2335
        if (zeroMid)
2336
            return wolfIO_OcspIPv4Blocked(a + 12);
2337
    }
2338
    return 0;
2339
}
2340
#endif /* WOLFSSL_IPV6 && HAVE_GETADDRINFO */
2341
2342
#endif /* WOLFSSL_OCSP_SCREEN_RESPONDER && HAVE_SOCKADDR */
2343
2344
#ifdef WOLFSSL_OCSP_SCREEN_RESPONDER
2345
2346
/* Screen an OCSP responder host before connecting, so that a certificate-
2347
 * supplied AIA URL cannot steer the request at an internal/reserved address
2348
 * (SSRF, CWE-918). The host is resolved and every returned address is checked;
2349
 * the destination is rejected if ANY resolved address is in a blocked range.
2350
 * Returns 1 if the destination is permitted, 0 if it must be blocked.
2351
 *
2352
 * This is a best-effort guard performed at the integration boundary; a host
2353
 * that cannot be resolved is treated as not permitted. Note that the connect
2354
 * resolves the name again, so this does not by itself defeat a DNS-rebinding
2355
 * responder -- deployments that need a hard guarantee should install a custom
2356
 * OCSP IO callback with wolfSSL_CTX_SetOCSP_Cb.
2357
 *
2358
 * This screening is OPT-IN: it is compiled and active only when
2359
 * WOLFSSL_OCSP_SCREEN_RESPONDER is defined. It is off by default because many
2360
 * deployments legitimately run an OCSP responder on loopback or an internal
2361
 * network (the in-tree OCSP tests use http://127.0.0.1, for example), and an
2362
 * operator-configured override responder (wolfSSL_CTX_SetOCSP_OverrideURL) is
2363
 * delivered to this same default callback and would be screened identically. */
2364
int wolfIO_OcspDestAllowed(const char* host)
2365
{
2366
#ifdef HAVE_SOCKADDR
2367
    int blocked = 0;
2368
#if defined(HAVE_GETADDRINFO)
2369
    ADDRINFO  hints;
2370
    ADDRINFO* answer = NULL;
2371
    ADDRINFO* cur;
2372
2373
    if (host == NULL)
2374
        return 0;
2375
2376
    XMEMSET(&hints, 0, sizeof(hints));
2377
#ifdef WOLFSSL_IPV6
2378
    hints.ai_family = AF_UNSPEC;
2379
#else
2380
    hints.ai_family = AF_INET;
2381
#endif
2382
    hints.ai_socktype = SOCK_STREAM;
2383
    hints.ai_protocol = IPPROTO_TCP;
2384
2385
    if (getaddrinfo(host, NULL, &hints, &answer) != 0 || answer == NULL) {
2386
        /* cannot resolve -> cannot verify destination -> deny */
2387
        return 0;
2388
    }
2389
2390
    for (cur = answer; cur != NULL && !blocked; cur = cur->ai_next) {
2391
        if (cur->ai_family == AF_INET) {
2392
            SOCKADDR_IN* s = (SOCKADDR_IN*)cur->ai_addr;
2393
            blocked = wolfIO_OcspIPv4Blocked(
2394
                (const unsigned char*)&s->sin_addr.s_addr);
2395
        }
2396
    #ifdef WOLFSSL_IPV6
2397
        else if (cur->ai_family == AF_INET6) {
2398
            SOCKADDR_IN6* s = (SOCKADDR_IN6*)cur->ai_addr;
2399
            blocked = wolfIO_OcspIPv6Blocked(
2400
                (const unsigned char*)&s->sin6_addr);
2401
        }
2402
    #endif
2403
    }
2404
    freeaddrinfo(answer);
2405
#else /* !HAVE_GETADDRINFO: gethostbyname fallback */
2406
    /* gethostbyname() returns non-reentrant static storage; on multi-threaded
2407
     * glibc use gethostbyname_r() with a heap buffer, matching the resolver
2408
     * pattern in wolfIO_TcpConnect(). */
2409
#if defined(__GLIBC__) && (__GLIBC__ >= 2) && defined(__USE_MISC) && \
2410
    !defined(SINGLE_THREADED)
2411
    #define WOLFSSL_OCSP_GHBN_R
2412
#endif
2413
#ifdef WOLFSSL_OCSP_GHBN_R
2414
    HOSTENT  entry_buf, *entry = NULL;
2415
    char*    ghbn_r_buf;
2416
    int      ghbn_r_errno;
2417
#else
2418
    HOSTENT* entry;
2419
#endif
2420
    int i;
2421
2422
    if (host == NULL)
2423
        return 0;
2424
2425
#ifdef WOLFSSL_OCSP_GHBN_R
2426
    /* 2048 is the same empirically-chosen buffer size used in
2427
     * wolfIO_TcpConnect(). */
2428
    ghbn_r_buf = (char*)XMALLOC(2048, NULL, DYNAMIC_TYPE_TMP_BUFFER);
2429
    if (ghbn_r_buf != NULL) {
2430
        gethostbyname_r(host, &entry_buf, ghbn_r_buf, 2048, &entry,
2431
                        &ghbn_r_errno);
2432
    }
2433
#else
2434
    entry = gethostbyname(host);
2435
#endif
2436
    if (entry == NULL) {
2437
#ifdef WOLFSSL_OCSP_GHBN_R
2438
        XFREE(ghbn_r_buf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
2439
#endif
2440
        return 0;
2441
    }
2442
2443
    /* gethostbyname()/gethostbyname_r() resolve only IPv4 (h_addrtype
2444
     * AF_INET); IPv6 would require gethostbyname2()/getipnodebyname(), which
2445
     * are not used here, so screen each returned address as IPv4. */
2446
    for (i = 0; entry->h_addr_list[i] != NULL && !blocked; i++) {
2447
        if (entry->h_addrtype == AF_INET) {
2448
            blocked = wolfIO_OcspIPv4Blocked(
2449
                (const unsigned char*)entry->h_addr_list[i]);
2450
        }
2451
    }
2452
#ifdef WOLFSSL_OCSP_GHBN_R
2453
    XFREE(ghbn_r_buf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
2454
    #undef WOLFSSL_OCSP_GHBN_R
2455
#endif
2456
#endif /* HAVE_GETADDRINFO */
2457
2458
    return blocked ? 0 : 1;
2459
#else /* !HAVE_SOCKADDR: no address support to screen */
2460
    (void)host;
2461
    return 1;
2462
#endif /* HAVE_SOCKADDR */
2463
}
2464
2465
#endif /* WOLFSSL_OCSP_SCREEN_RESPONDER */
2466
2467
/* in default wolfSSL callback ctx is the heap pointer */
2468
int EmbedOcspLookup(void* ctx, const char* url, int urlSz,
2469
                        byte* ocspReqBuf, int ocspReqSz, byte** ocspRespBuf)
2470
{
2471
    SOCKET_T sfd = SOCKET_INVALID;
2472
    word16   port;
2473
    int      ret = -1;
2474
#ifdef WOLFSSL_SMALL_STACK
2475
    char*    path;
2476
    char*    domainName;
2477
#else
2478
    char     path[MAX_URL_ITEM_SIZE];
2479
    char     domainName[MAX_URL_ITEM_SIZE];
2480
#endif
2481
2482
#ifdef WOLFSSL_SMALL_STACK
2483
    path = (char*)XMALLOC(MAX_URL_ITEM_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
2484
    if (path == NULL)
2485
        return MEMORY_E;
2486
2487
    domainName = (char*)XMALLOC(MAX_URL_ITEM_SIZE, NULL,
2488
            DYNAMIC_TYPE_TMP_BUFFER);
2489
    if (domainName == NULL) {
2490
        XFREE(path, NULL, DYNAMIC_TYPE_TMP_BUFFER);
2491
        return MEMORY_E;
2492
    }
2493
#endif
2494
2495
    if (ocspReqBuf == NULL || ocspReqSz == 0) {
2496
        WOLFSSL_MSG("OCSP request is required for lookup");
2497
    }
2498
    else if (ocspRespBuf == NULL) {
2499
        WOLFSSL_MSG("Cannot save OCSP response");
2500
    }
2501
    else if (wolfIO_DecodeUrl(url, urlSz, domainName, path, &port) < 0) {
2502
        WOLFSSL_MSG("Unable to decode OCSP URL");
2503
    }
2504
#ifdef WOLFSSL_OCSP_SCREEN_RESPONDER
2505
    /* Opt-in: reject responders that resolve to private/loopback/link-local
2506
     * ranges to keep a certificate-supplied AIA URL from forcing an internal
2507
     * request (SSRF, CWE-918). */
2508
    else if (!wolfIO_OcspDestAllowed(domainName)) {
2509
        WOLFSSL_MSG("OCSP responder destination not permitted");
2510
    }
2511
#endif
2512
    else {
2513
        /* Note, the library uses the EmbedOcspRespFree() callback to
2514
         * free this buffer. */
2515
        int   httpBufSz = HTTP_SCRATCH_BUFFER_SIZE;
2516
        byte* httpBuf   = (byte*)XMALLOC((size_t)httpBufSz, ctx, DYNAMIC_TYPE_OCSP);
2517
2518
        if (httpBuf == NULL) {
2519
            WOLFSSL_MSG("Unable to create OCSP response buffer");
2520
        }
2521
        else {
2522
            httpBufSz = wolfIO_HttpBuildRequestOcsp(domainName, path, ocspReqSz,
2523
                                                            httpBuf, httpBufSz);
2524
2525
            if (httpBufSz <= 0) {
2526
                WOLFSSL_MSG("Unable to build OCSP request");
2527
            }
2528
            else if ((ret = wolfIO_TcpConnect(&sfd, domainName, port,
2529
                                              io_timeout_sec)) != 0) {
2530
                WOLFSSL_MSG("OCSP Responder connection failed");
2531
            }
2532
            else if (wolfIO_Send(sfd, (char*)httpBuf, httpBufSz, 0) !=
2533
                                                                    httpBufSz) {
2534
                WOLFSSL_MSG("OCSP http request failed");
2535
            }
2536
            else if (wolfIO_Send(sfd, (char*)ocspReqBuf, ocspReqSz, 0) !=
2537
                                                                    ocspReqSz) {
2538
                WOLFSSL_MSG("OCSP ocsp request failed");
2539
            }
2540
            else {
2541
                ret = wolfIO_HttpProcessResponseOcsp((int)sfd, ocspRespBuf, httpBuf,
2542
                                                 HTTP_SCRATCH_BUFFER_SIZE, ctx);
2543
            }
2544
            if (sfd != SOCKET_INVALID)
2545
                CloseSocket(sfd);
2546
            XFREE(httpBuf, ctx, DYNAMIC_TYPE_OCSP);
2547
        }
2548
    }
2549
2550
    WC_FREE_VAR_EX(path, NULL, DYNAMIC_TYPE_TMP_BUFFER);
2551
    WC_FREE_VAR_EX(domainName, NULL, DYNAMIC_TYPE_TMP_BUFFER);
2552
2553
    return ret;
2554
}
2555
2556
/* in default callback ctx is heap hint */
2557
void EmbedOcspRespFree(void* ctx, byte *resp)
2558
{
2559
    XFREE(resp, ctx, DYNAMIC_TYPE_OCSP);
2560
2561
    (void)ctx;
2562
}
2563
#endif /* HAVE_OCSP */
2564
2565
2566
#if defined(HAVE_CRL) && defined(HAVE_CRL_IO)
2567
2568
int wolfIO_HttpBuildRequestCrl(const char* url, int urlSz,
2569
    const char* domainName, byte* buf, int bufSize)
2570
{
2571
    const char *cacheCtl = "Cache-Control: no-cache";
2572
    return wolfIO_HttpBuildRequest_ex("GET", domainName, url, urlSz, 0, "",
2573
                                   cacheCtl, buf, bufSize);
2574
}
2575
2576
int wolfIO_HttpProcessResponseCrl(WOLFSSL_CRL* crl, int sfd, byte* httpBuf,
2577
    int httpBufSz)
2578
{
2579
    int ret;
2580
    byte *respBuf = NULL;
2581
2582
    const char* appStrList[] = {
2583
        "application/pkix-crl",
2584
        "application/x-pkcs7-crl",
2585
        NULL
2586
    };
2587
2588
2589
    ret = wolfIO_HttpProcessResponse(sfd, appStrList,
2590
        &respBuf, httpBuf, httpBufSz, DYNAMIC_TYPE_CRL, crl->heap);
2591
    if (ret >= 0) {
2592
        ret = BufferLoadCRL(crl, respBuf, ret, WOLFSSL_FILETYPE_ASN1, 0);
2593
    }
2594
    XFREE(respBuf, crl->heap, DYNAMIC_TYPE_CRL);
2595
2596
    return ret;
2597
}
2598
2599
int EmbedCrlLookup(WOLFSSL_CRL* crl, const char* url, int urlSz)
2600
{
2601
    SOCKET_T sfd = SOCKET_INVALID;
2602
    word16   port;
2603
    int      ret = -1;
2604
    WC_DECLARE_VAR(domainName, char, MAX_URL_ITEM_SIZE, 0);
2605
2606
#ifdef WOLFSSL_SMALL_STACK
2607
    domainName = (char*)XMALLOC(MAX_URL_ITEM_SIZE, crl->heap,
2608
                                                       DYNAMIC_TYPE_TMP_BUFFER);
2609
    if (domainName == NULL) {
2610
        return MEMORY_E;
2611
    }
2612
#endif
2613
2614
    if (wolfIO_DecodeUrl(url, urlSz, domainName, NULL, &port) < 0) {
2615
        WOLFSSL_MSG("Unable to decode CRL URL");
2616
    }
2617
    else {
2618
        int   httpBufSz = HTTP_SCRATCH_BUFFER_SIZE;
2619
        byte* httpBuf   = (byte*)XMALLOC((size_t)httpBufSz, crl->heap,
2620
                                                              DYNAMIC_TYPE_CRL);
2621
        if (httpBuf == NULL) {
2622
            WOLFSSL_MSG("Unable to create CRL response buffer");
2623
        }
2624
        else {
2625
            httpBufSz = wolfIO_HttpBuildRequestCrl(url, urlSz, domainName,
2626
                httpBuf, httpBufSz);
2627
2628
            if (httpBufSz <= 0) {
2629
                WOLFSSL_MSG("Unable to build CRL request");
2630
            }
2631
            else if ((ret = wolfIO_TcpConnect(&sfd, domainName, port,
2632
                                              io_timeout_sec)) != 0) {
2633
                WOLFSSL_MSG("CRL connection failed");
2634
            }
2635
            else if (wolfIO_Send(sfd, (char*)httpBuf, httpBufSz, 0)
2636
                                                                 != httpBufSz) {
2637
                WOLFSSL_MSG("CRL http get failed");
2638
            }
2639
            else {
2640
                ret = wolfIO_HttpProcessResponseCrl(crl, sfd, httpBuf,
2641
                                                      HTTP_SCRATCH_BUFFER_SIZE);
2642
            }
2643
            if (sfd != SOCKET_INVALID)
2644
                CloseSocket(sfd);
2645
            XFREE(httpBuf, crl->heap, DYNAMIC_TYPE_CRL);
2646
        }
2647
    }
2648
2649
    WC_FREE_VAR_EX(domainName, crl->heap, DYNAMIC_TYPE_TMP_BUFFER);
2650
2651
    return ret;
2652
}
2653
#endif /* HAVE_CRL && HAVE_CRL_IO */
2654
2655
#endif /* HAVE_HTTP_CLIENT */
2656
2657
2658
2659
void wolfSSL_CTX_SetIORecv(WOLFSSL_CTX *ctx, CallbackIORecv CBIORecv)
2660
48
{
2661
48
    if (ctx) {
2662
48
        ctx->CBIORecv = CBIORecv;
2663
    #ifdef OPENSSL_EXTRA
2664
        ctx->cbioFlag |= WOLFSSL_CBIO_RECV;
2665
    #endif
2666
48
    }
2667
48
}
2668
2669
2670
void wolfSSL_CTX_SetIOSend(WOLFSSL_CTX *ctx, CallbackIOSend CBIOSend)
2671
48
{
2672
48
    if (ctx) {
2673
48
        ctx->CBIOSend = CBIOSend;
2674
    #ifdef OPENSSL_EXTRA
2675
        ctx->cbioFlag |= WOLFSSL_CBIO_SEND;
2676
    #endif
2677
48
    }
2678
48
}
2679
2680
2681
/* sets the IO callback to use for receives at WOLFSSL level */
2682
void wolfSSL_SSLSetIORecv(WOLFSSL *ssl, CallbackIORecv CBIORecv)
2683
0
{
2684
0
    if (ssl) {
2685
0
        ssl->CBIORecv = CBIORecv;
2686
    #ifdef OPENSSL_EXTRA
2687
        ssl->cbioFlag |= WOLFSSL_CBIO_RECV;
2688
    #endif
2689
0
    }
2690
0
}
2691
2692
2693
/* sets the IO callback to use for sends at WOLFSSL level */
2694
void wolfSSL_SSLSetIOSend(WOLFSSL *ssl, CallbackIOSend CBIOSend)
2695
0
{
2696
0
    if (ssl) {
2697
0
        ssl->CBIOSend = CBIOSend;
2698
    #ifdef OPENSSL_EXTRA
2699
        ssl->cbioFlag |= WOLFSSL_CBIO_SEND;
2700
    #endif
2701
0
    }
2702
0
}
2703
2704
void wolfSSL_SSLDisableRead(WOLFSSL *ssl)
2705
0
{
2706
0
    if (ssl) {
2707
0
        ssl->options.disableRead = 1;
2708
0
    }
2709
0
}
2710
2711
void wolfSSL_SSLEnableRead(WOLFSSL *ssl)
2712
0
{
2713
0
    if (ssl) {
2714
0
        ssl->options.disableRead = 0;
2715
0
    }
2716
0
}
2717
2718
2719
void wolfSSL_SetIOReadCtx(WOLFSSL* ssl, void *rctx)
2720
0
{
2721
0
    if (ssl)
2722
0
        ssl->IOCB_ReadCtx = rctx;
2723
0
}
2724
2725
2726
void wolfSSL_SetIOWriteCtx(WOLFSSL* ssl, void *wctx)
2727
0
{
2728
0
    if (ssl)
2729
0
        ssl->IOCB_WriteCtx = wctx;
2730
0
}
2731
2732
2733
void* wolfSSL_GetIOReadCtx(WOLFSSL* ssl)
2734
0
{
2735
0
    if (ssl)
2736
0
        return ssl->IOCB_ReadCtx;
2737
2738
0
    return NULL;
2739
0
}
2740
2741
2742
void* wolfSSL_GetIOWriteCtx(WOLFSSL* ssl)
2743
0
{
2744
0
    if (ssl)
2745
0
        return ssl->IOCB_WriteCtx;
2746
2747
0
    return NULL;
2748
0
}
2749
2750
2751
void wolfSSL_SetIOReadFlags(WOLFSSL* ssl, int flags)
2752
0
{
2753
0
    if (ssl)
2754
0
        ssl->rflags = flags;
2755
0
}
2756
2757
2758
void wolfSSL_SetIOWriteFlags(WOLFSSL* ssl, int flags)
2759
0
{
2760
0
    if (ssl)
2761
0
        ssl->wflags = flags;
2762
0
}
2763
2764
2765
#ifdef WOLFSSL_DTLS
2766
2767
void wolfSSL_CTX_SetGenCookie(WOLFSSL_CTX* ctx, CallbackGenCookie cb)
2768
{
2769
    if (ctx)
2770
        ctx->CBIOCookie = cb;
2771
}
2772
2773
2774
void wolfSSL_SetCookieCtx(WOLFSSL* ssl, void *ctx)
2775
{
2776
    if (ssl)
2777
        ssl->IOCB_CookieCtx = ctx;
2778
}
2779
2780
2781
void* wolfSSL_GetCookieCtx(WOLFSSL* ssl)
2782
{
2783
    if (ssl)
2784
        return ssl->IOCB_CookieCtx;
2785
2786
    return NULL;
2787
}
2788
#endif /* WOLFSSL_DTLS */
2789
2790
#ifdef WOLFSSL_SESSION_EXPORT
2791
2792
void wolfSSL_CTX_SetIOGetPeer(WOLFSSL_CTX* ctx, CallbackGetPeer cb)
2793
{
2794
    if (ctx)
2795
        ctx->CBGetPeer = cb;
2796
}
2797
2798
2799
void wolfSSL_CTX_SetIOSetPeer(WOLFSSL_CTX* ctx, CallbackSetPeer cb)
2800
{
2801
    if (ctx)
2802
        ctx->CBSetPeer = cb;
2803
}
2804
2805
#endif /* WOLFSSL_SESSION_EXPORT */
2806
2807
2808
#ifdef HAVE_NETX
2809
2810
/* The NetX receive callback for TLS
2811
 *  return :  bytes read, or error
2812
 */
2813
int NetX_Receive(WOLFSSL *ssl, char *buf, int sz, void *ctx)
2814
{
2815
    NetX_Ctx* nxCtx = (NetX_Ctx*)ctx;
2816
    ULONG left;
2817
    ULONG total;
2818
    ULONG copied = 0;
2819
    UINT  status;
2820
2821
    (void)ssl;
2822
2823
    if (nxCtx == NULL || nxCtx->nxTcpSocket == NULL) {
2824
        WOLFSSL_MSG("NetX Recv NULL parameters");
2825
        return WOLFSSL_CBIO_ERR_GENERAL;
2826
    }
2827
2828
    if (nxCtx->nxPacket == NULL) {
2829
        status = nx_tcp_socket_receive(nxCtx->nxTcpSocket, &nxCtx->nxPacket,
2830
                                       nxCtx->nxWait);
2831
        if (status != NX_SUCCESS) {
2832
            WOLFSSL_MSG("NetX Recv receive error");
2833
            return WOLFSSL_CBIO_ERR_GENERAL;
2834
        }
2835
    }
2836
2837
    if (nxCtx->nxPacket) {
2838
        status = nx_packet_length_get(nxCtx->nxPacket, &total);
2839
        if (status != NX_SUCCESS) {
2840
            WOLFSSL_MSG("NetX Recv length get error");
2841
            return WOLFSSL_CBIO_ERR_GENERAL;
2842
        }
2843
2844
        left = total - nxCtx->nxOffset;
2845
        status = nx_packet_data_extract_offset(nxCtx->nxPacket, nxCtx->nxOffset,
2846
                                               buf, sz, &copied);
2847
        if (status != NX_SUCCESS) {
2848
            WOLFSSL_MSG("NetX Recv data extract offset error");
2849
            return WOLFSSL_CBIO_ERR_GENERAL;
2850
        }
2851
2852
        nxCtx->nxOffset += copied;
2853
2854
        if (copied == left) {
2855
            WOLFSSL_MSG("NetX Recv Drained packet");
2856
            nx_packet_release(nxCtx->nxPacket);
2857
            nxCtx->nxPacket = NULL;
2858
            nxCtx->nxOffset = 0;
2859
        }
2860
    }
2861
2862
    return copied;
2863
}
2864
2865
2866
/* The NetX send callback for TLS
2867
 *  return : bytes sent, or error
2868
 */
2869
int NetX_Send(WOLFSSL* ssl, char *buf, int sz, void *ctx)
2870
{
2871
    NetX_Ctx*       nxCtx = (NetX_Ctx*)ctx;
2872
    NX_PACKET*      packet;
2873
    NX_PACKET_POOL* pool;   /* shorthand */
2874
    UINT            status;
2875
2876
    (void)ssl;
2877
2878
    if (nxCtx == NULL || nxCtx->nxTcpSocket == NULL) {
2879
        WOLFSSL_MSG("NetX Send NULL parameters");
2880
        return WOLFSSL_CBIO_ERR_GENERAL;
2881
    }
2882
2883
    pool = nxCtx->nxTcpSocket->nx_tcp_socket_ip_ptr->nx_ip_default_packet_pool;
2884
    status = nx_packet_allocate(pool, &packet, NX_TCP_PACKET,
2885
                                nxCtx->nxWait);
2886
    if (status != NX_SUCCESS) {
2887
        WOLFSSL_MSG("NetX Send packet alloc error");
2888
        return WOLFSSL_CBIO_ERR_GENERAL;
2889
    }
2890
2891
    status = nx_packet_data_append(packet, buf, sz, pool, nxCtx->nxWait);
2892
    if (status != NX_SUCCESS) {
2893
        nx_packet_release(packet);
2894
        WOLFSSL_MSG("NetX Send data append error");
2895
        return WOLFSSL_CBIO_ERR_GENERAL;
2896
    }
2897
2898
    status = nx_tcp_socket_send(nxCtx->nxTcpSocket, packet, nxCtx->nxWait);
2899
    if (status != NX_SUCCESS) {
2900
        nx_packet_release(packet);
2901
        WOLFSSL_MSG("NetX Send socket send error");
2902
        return WOLFSSL_CBIO_ERR_GENERAL;
2903
    }
2904
2905
    return sz;
2906
}
2907
2908
/* like set_fd, but for default NetX context */
2909
void wolfSSL_SetIO_NetX(WOLFSSL* ssl, NX_TCP_SOCKET* nxsocket, ULONG waitoption)
2910
{
2911
    if (ssl) {
2912
        ssl->nxCtx.nxTcpSocket  = nxsocket;
2913
        ssl->nxCtx.nxWait       = waitoption;
2914
    }
2915
}
2916
2917
/* WOLFSSL_NETX_DUO: requires ThreadX NetX Duo (NXD_ADDRESS, nxd_udp_socket_send) */
2918
#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_NETX_DUO)
2919
static void NetX_ResetPacket(NetX_Ctx* nxCtx)
2920
{
2921
    if (nxCtx->nxPacket != NULL) {
2922
        nx_packet_release(nxCtx->nxPacket);
2923
        nxCtx->nxPacket = NULL;
2924
    }
2925
    nxCtx->nxOffset = 0;
2926
}
2927
2928
static int NetX_PeerAddrEqual(const NXD_ADDRESS* left, const NXD_ADDRESS* right)
2929
{
2930
    if (left->nxd_ip_version != right->nxd_ip_version)
2931
        return 0;
2932
2933
    if (left->nxd_ip_version == NX_IP_VERSION_V4)
2934
        return left->nxd_ip_address.v4 == right->nxd_ip_address.v4;
2935
2936
    return left->nxd_ip_address.v6[0] == right->nxd_ip_address.v6[0] &&
2937
           left->nxd_ip_address.v6[1] == right->nxd_ip_address.v6[1] &&
2938
           left->nxd_ip_address.v6[2] == right->nxd_ip_address.v6[2] &&
2939
           left->nxd_ip_address.v6[3] == right->nxd_ip_address.v6[3];
2940
}
2941
2942
/* The NetX receive callback for DTLS
2943
 *  return :  bytes read, or error
2944
 */
2945
int NetX_ReceiveFrom(WOLFSSL *ssl, char *buf, int sz, void *ctx)
2946
{
2947
    NetX_Ctx* nxCtx = (NetX_Ctx*)ctx;
2948
    NXD_ADDRESS srcIp;
2949
    ULONG left;
2950
    ULONG total;
2951
    ULONG copied = 0;
2952
    UINT  srcPort;
2953
    UINT  status;
2954
    ULONG waitOption;
2955
    int   dtls_timeout;
2956
    int   usingNonblock;
2957
    byte  doDtlsTimeout;
2958
    word32 invalidPeerPackets = 0;
2959
#if defined(DTLS_RECEIVEFROM_MAX_INVALID_PEER)
2960
    const word32 maxInvalidPeerPackets = DTLS_RECEIVEFROM_MAX_INVALID_PEER;
2961
#else
2962
    const word32 maxInvalidPeerPackets = 10;
2963
#endif
2964
2965
    if (nxCtx == NULL || nxCtx->nxUdpSocket == NULL) {
2966
        WOLFSSL_MSG("NetX Recv NULL parameters");
2967
        return WOLFSSL_CBIO_ERR_GENERAL;
2968
    }
2969
2970
    if (sz < 0)
2971
        return WOLFSSL_CBIO_ERR_GENERAL;
2972
2973
    usingNonblock = wolfSSL_dtls_get_using_nonblock(ssl);
2974
2975
    /* Don't use ssl->options.handShakeDone since it is true even if
2976
     * we are in the process of renegotiation. */
2977
    doDtlsTimeout = ssl->options.handShakeState != HANDSHAKE_DONE;
2978
#ifdef WOLFSSL_DTLS13
2979
    if (ssl->options.dtls && IsAtLeastTLSv1_3(ssl->version)) {
2980
        doDtlsTimeout =
2981
            doDtlsTimeout || ssl->dtls13Rtx.rtxRecords != NULL ||
2982
            (ssl->dtls13FastTimeout && ssl->dtls13Rtx.seenRecords != NULL);
2983
    }
2984
#endif /* WOLFSSL_DTLS13 */
2985
2986
    do {
2987
        if (nxCtx->nxPacket == NULL) {
2988
            /* Compute wait ticks from the DTLS retransmit timeout while a
2989
             * handshake/RTX timer is active, otherwise honor nxWait. */
2990
            if (!usingNonblock) {
2991
                dtls_timeout = wolfSSL_dtls_get_current_timeout(ssl);
2992
                if (!doDtlsTimeout)
2993
                    dtls_timeout = 0;
2994
#ifdef WOLFSSL_DTLS13
2995
                if (dtls_timeout > 0 && wolfSSL_dtls13_use_quick_timeout(ssl) &&
2996
                    IsAtLeastTLSv1_3(ssl->version)) {
2997
                    if (dtls_timeout > 4)
2998
                        dtls_timeout /= 4;
2999
                    else
3000
                        dtls_timeout = 1;
3001
                }
3002
#endif /* WOLFSSL_DTLS13 */
3003
                waitOption = (dtls_timeout > 0)
3004
                             ? (ULONG)dtls_timeout * NX_IP_PERIODIC_RATE
3005
                             : nxCtx->nxWait;
3006
            }
3007
            else {
3008
                waitOption = NX_NO_WAIT; /* non-blocking */
3009
            }
3010
3011
            status = nx_udp_socket_receive(nxCtx->nxUdpSocket, &nxCtx->nxPacket,
3012
                                           waitOption);
3013
            if (status != NX_SUCCESS) {
3014
                if (status == NX_NO_PACKET) {
3015
                    /* Normal receive timeout - allow DTLS to retransmit */
3016
                    WOLFSSL_MSG("NetX Recv timeout");
3017
                    return usingNonblock
3018
                           ? WOLFSSL_CBIO_ERR_WANT_READ
3019
                           : WOLFSSL_CBIO_ERR_TIMEOUT;
3020
                }
3021
                WOLFSSL_MSG("NetX Recv receive error");
3022
                return WOLFSSL_CBIO_ERR_GENERAL;
3023
            }
3024
3025
            status = nxd_udp_source_extract(nxCtx->nxPacket, &srcIp, &srcPort);
3026
            if (status != NX_SUCCESS) {
3027
                NetX_ResetPacket(nxCtx);
3028
                WOLFSSL_MSG("NetX Recv source extract error");
3029
                return WOLFSSL_CBIO_ERR_GENERAL;
3030
            }
3031
3032
            if (nxCtx->nxPort != 0 &&
3033
                (nxCtx->nxdIp.nxd_ip_version == NX_IP_VERSION_V4 ||
3034
                 nxCtx->nxdIp.nxd_ip_version == NX_IP_VERSION_V6)) {
3035
                if ((USHORT)srcPort != nxCtx->nxPort ||
3036
                    !NetX_PeerAddrEqual(&srcIp, &nxCtx->nxdIp)) {
3037
                    WOLFSSL_MSG("NetX Recv ignored packet from invalid peer");
3038
                    NetX_ResetPacket(nxCtx);
3039
                    /* Intentional: bound discard only during handshake/RTX
3040
                     * window (doDtlsTimeout). Post-handshake, spoofed-source
3041
                     * packets loop until a valid one arrives. This matches
3042
                     * the EmbedReceiveFrom behavior. */
3043
                    if (doDtlsTimeout) {
3044
                        invalidPeerPackets++;
3045
                        if (invalidPeerPackets > maxInvalidPeerPackets) {
3046
                            return usingNonblock
3047
                                   ? WOLFSSL_CBIO_ERR_WANT_READ
3048
                                   : WOLFSSL_CBIO_ERR_TIMEOUT;
3049
                        }
3050
                    }
3051
                    continue;
3052
                }
3053
            }
3054
            else {
3055
                /* No peer preset: accept first datagram and lock onto source. */
3056
                nxCtx->nxdIp = srcIp;
3057
                nxCtx->nxPort = (USHORT)srcPort;
3058
            }
3059
        }
3060
3061
        status = nx_packet_length_get(nxCtx->nxPacket, &total);
3062
        if (status != NX_SUCCESS) {
3063
            NetX_ResetPacket(nxCtx);
3064
            WOLFSSL_MSG("NetX Recv length get error");
3065
            return WOLFSSL_CBIO_ERR_GENERAL;
3066
        }
3067
3068
        if (total == 0) {
3069
            WOLFSSL_MSG("Ignoring 0-length datagram");
3070
            NetX_ResetPacket(nxCtx);
3071
            /* Intentional: same discard-bound semantics as invalid-peer
3072
             * handling above and EmbedReceiveFrom: only bounded during
3073
             * handshake, loops post-handshake until a valid datagram
3074
             * arrives. */
3075
            if (doDtlsTimeout) {
3076
                invalidPeerPackets++;
3077
                if (invalidPeerPackets > maxInvalidPeerPackets) {
3078
                    return usingNonblock
3079
                           ? WOLFSSL_CBIO_ERR_WANT_READ
3080
                           : WOLFSSL_CBIO_ERR_TIMEOUT;
3081
                }
3082
            }
3083
            continue;
3084
        }
3085
3086
        if (nxCtx->nxOffset > total) {
3087
            NetX_ResetPacket(nxCtx);
3088
            WOLFSSL_MSG("NetX Recv invalid packet offset");
3089
            return WOLFSSL_CBIO_ERR_GENERAL;
3090
        }
3091
3092
        left = total - nxCtx->nxOffset;
3093
        status = nx_packet_data_extract_offset(nxCtx->nxPacket, nxCtx->nxOffset,
3094
                                               buf, sz, &copied);
3095
        if (status != NX_SUCCESS) {
3096
            NetX_ResetPacket(nxCtx);
3097
            WOLFSSL_MSG("NetX Recv data extract offset error");
3098
            return WOLFSSL_CBIO_ERR_GENERAL;
3099
        }
3100
3101
        /* DTLS datagram semantics: always release the full datagram after one
3102
         * read. If the caller's buffer (sz) is smaller than the datagram,
3103
         * the excess bytes are discarded here, matching EmbedReceiveFrom /
3104
         * recvfrom behavior. Partial-datagram retention would re-introduce
3105
         * TCP stream semantics and could mis-frame DTLS records. */
3106
        if (copied < left) {
3107
            WOLFSSL_MSG("NetX Recv datagram truncated, discarding remainder");
3108
        }
3109
        NetX_ResetPacket(nxCtx);
3110
3111
        return (int)copied;
3112
    } while (1);
3113
}
3114
3115
/* The NetX send callback for DTLS
3116
 *  return : bytes sent, or error
3117
 */
3118
int NetX_SendTo(WOLFSSL* ssl, char *buf, int sz, void *ctx)
3119
{
3120
    NetX_Ctx*       nxCtx = (NetX_Ctx*)ctx;
3121
    NX_PACKET*      packet;
3122
    NX_PACKET_POOL* pool;   /* shorthand */
3123
    UINT            status;
3124
3125
    (void)ssl;
3126
3127
    if (nxCtx == NULL || nxCtx->nxUdpSocket == NULL) {
3128
        WOLFSSL_MSG("NetX Send NULL parameters");
3129
        return WOLFSSL_CBIO_ERR_GENERAL;
3130
    }
3131
3132
    if (sz < 0)
3133
        return WOLFSSL_CBIO_ERR_GENERAL;
3134
3135
    pool = nxCtx->nxUdpSocket->nx_udp_socket_ip_ptr->nx_ip_default_packet_pool;
3136
    status = nx_packet_allocate(pool, &packet, NX_UDP_PACKET,
3137
                                nxCtx->nxWait);
3138
    if (status != NX_SUCCESS) {
3139
        WOLFSSL_MSG("NetX Send packet alloc error");
3140
        return WOLFSSL_CBIO_ERR_GENERAL;
3141
    }
3142
3143
    status = nx_packet_data_append(packet, buf, sz, pool, nxCtx->nxWait);
3144
    if (status != NX_SUCCESS) {
3145
        nx_packet_release(packet);
3146
        WOLFSSL_MSG("NetX Send data append error");
3147
        return WOLFSSL_CBIO_ERR_GENERAL;
3148
    }
3149
3150
    if (nxCtx->nxdIp.nxd_ip_version == NX_IP_VERSION_V4) {
3151
        status = nx_udp_socket_send(nxCtx->nxUdpSocket, packet,
3152
                                    nxCtx->nxdIp.nxd_ip_address.v4,
3153
                                    (UINT)nxCtx->nxPort);
3154
    }
3155
    else {
3156
        status = nxd_udp_socket_send(nxCtx->nxUdpSocket, packet,
3157
                                     &nxCtx->nxdIp, (UINT)nxCtx->nxPort);
3158
    }
3159
    if (status != NX_SUCCESS) {
3160
        nx_packet_release(packet);
3161
        WOLFSSL_MSG("NetX Send socket send error");
3162
        return WOLFSSL_CBIO_ERR_GENERAL;
3163
    }
3164
3165
    return sz;
3166
}
3167
3168
/* like set_fd, but for default NetX Duo UDP context */
3169
void wolfSSL_SetIO_NetX_Dtls(WOLFSSL* ssl, NX_UDP_SOCKET* nxsocket,
3170
                              NXD_ADDRESS nxdip, USHORT nxport,
3171
                              ULONG waitoption)
3172
{
3173
    if (ssl) {
3174
        ssl->nxCtx.nxUdpSocket = nxsocket;
3175
        ssl->nxCtx.nxdIp       = nxdip;
3176
        ssl->nxCtx.nxPort      = nxport;
3177
        ssl->nxCtx.nxWait      = waitoption;
3178
    }
3179
}
3180
#endif /* WOLFSSL_DTLS && WOLFSSL_NETX_DUO */
3181
3182
#endif /* HAVE_NETX */
3183
3184
3185
#ifdef MICRIUM
3186
3187
/* Micrium uTCP/IP port, using the NetSock API
3188
 * TCP and UDP are currently supported with the callbacks below.
3189
 *
3190
 * WOLFSSL_SESSION_EXPORT is not yet supported, would need EmbedGetPeer()
3191
 * and EmbedSetPeer() callbacks implemented.
3192
 *
3193
 * HAVE_CRL is not yet supported, would need an EmbedCrlLookup()
3194
 * callback implemented.
3195
 *
3196
 * HAVE_OCSP is not yet supported, would need an EmbedOCSPLookup()
3197
 * callback implemented.
3198
 */
3199
3200
/* The Micrium uTCP/IP send callback
3201
 * return : bytes sent, or error
3202
 */
3203
int MicriumSend(WOLFSSL* ssl, char* buf, int sz, void* ctx)
3204
{
3205
    NET_SOCK_ID sd = *(int*)ctx;
3206
    NET_SOCK_RTN_CODE ret;
3207
    NET_ERR err;
3208
3209
    ret = NetSock_TxData(sd, buf, sz, ssl->wflags, &err);
3210
    if (ret < 0) {
3211
        WOLFSSL_MSG("Embed Send error");
3212
3213
        if (err == NET_ERR_TX) {
3214
            WOLFSSL_MSG("\tWould block");
3215
            return WOLFSSL_CBIO_ERR_WANT_WRITE;
3216
3217
        } else {
3218
            WOLFSSL_MSG("\tGeneral error");
3219
            return WOLFSSL_CBIO_ERR_GENERAL;
3220
        }
3221
    }
3222
3223
    return ret;
3224
}
3225
3226
/* The Micrium uTCP/IP receive callback
3227
 *  return : nb bytes read, or error
3228
 */
3229
int MicriumReceive(WOLFSSL *ssl, char *buf, int sz, void *ctx)
3230
{
3231
    NET_SOCK_ID sd = *(int*)ctx;
3232
    NET_SOCK_RTN_CODE ret;
3233
    NET_ERR err;
3234
3235
    #ifdef WOLFSSL_DTLS
3236
    {
3237
        int dtls_timeout = wolfSSL_dtls_get_current_timeout(ssl);
3238
        /* Don't use ssl->options.handShakeDone since it is true even if
3239
         * we are in the process of renegotiation */
3240
        byte doDtlsTimeout = ssl->options.handShakeState != HANDSHAKE_DONE;
3241
        #ifdef WOLFSSL_DTLS13
3242
        if (ssl->options.dtls && IsAtLeastTLSv1_3(ssl->version)) {
3243
            doDtlsTimeout =
3244
                doDtlsTimeout || ssl->dtls13Rtx.rtxRecords != NULL ||
3245
                (ssl->dtls13FastTimeout && ssl->dtls13Rtx.seenRecords != NULL);
3246
        }
3247
        #endif /* WOLFSSL_DTLS13 */
3248
3249
        if (!doDtlsTimeout)
3250
            dtls_timeout = 0;
3251
3252
        if (!wolfSSL_dtls_get_using_nonblock(ssl)) {
3253
            /* needs timeout in milliseconds */
3254
            #ifdef WOLFSSL_DTLS13
3255
            if (wolfSSL_dtls13_use_quick_timeout(ssl) &&
3256
                IsAtLeastTLSv1_3(ssl->version)) {
3257
                dtls_timeout = (1000 * dtls_timeout) / 4;
3258
            } else
3259
            #endif /* WOLFSSL_DTLS13 */
3260
                dtls_timeout = 1000 * dtls_timeout;
3261
            NetSock_CfgTimeoutRxQ_Set(sd, dtls_timeout, &err);
3262
            if (err != NET_SOCK_ERR_NONE) {
3263
                WOLFSSL_MSG("NetSock_CfgTimeoutRxQ_Set failed");
3264
            }
3265
        }
3266
    }
3267
    #endif /* WOLFSSL_DTLS */
3268
3269
    ret = NetSock_RxData(sd, buf, sz, ssl->rflags, &err);
3270
    if (ret < 0) {
3271
        WOLFSSL_MSG("Embed Receive error");
3272
3273
        if (err == NET_ERR_RX || err == NET_SOCK_ERR_RX_Q_EMPTY ||
3274
            err == NET_ERR_FAULT_LOCK_ACQUIRE) {
3275
            if (!wolfSSL_dtls(ssl) || wolfSSL_dtls_get_using_nonblock(ssl)) {
3276
                WOLFSSL_MSG("\tWould block");
3277
                return WOLFSSL_CBIO_ERR_WANT_READ;
3278
            }
3279
            else {
3280
                WOLFSSL_MSG("\tSocket timeout");
3281
                return WOLFSSL_CBIO_ERR_TIMEOUT;
3282
            }
3283
3284
        } else if (err == NET_SOCK_ERR_CLOSED) {
3285
            WOLFSSL_MSG("Embed receive connection closed");
3286
            return WOLFSSL_CBIO_ERR_CONN_CLOSE;
3287
3288
        } else {
3289
            WOLFSSL_MSG("\tGeneral error");
3290
            return WOLFSSL_CBIO_ERR_GENERAL;
3291
        }
3292
    }
3293
3294
    return ret;
3295
}
3296
3297
/* The Micrium uTCP/IP receivefrom callback
3298
 *  return : nb bytes read, or error
3299
 */
3300
int MicriumReceiveFrom(WOLFSSL *ssl, char *buf, int sz, void *ctx)
3301
{
3302
    WOLFSSL_DTLS_CTX* dtlsCtx = (WOLFSSL_DTLS_CTX*)ctx;
3303
    NET_SOCK_ID       sd = dtlsCtx->rfd;
3304
    NET_SOCK_ADDR     peer;
3305
    NET_SOCK_ADDR_LEN peerSz = sizeof(peer);
3306
    NET_SOCK_RTN_CODE ret;
3307
    NET_ERR err;
3308
3309
    WOLFSSL_ENTER("MicriumReceiveFrom");
3310
3311
#ifdef WOLFSSL_DTLS
3312
    {
3313
        int dtls_timeout = wolfSSL_dtls_get_current_timeout(ssl);
3314
        /* Don't use ssl->options.handShakeDone since it is true even if
3315
         * we are in the process of renegotiation */
3316
        byte doDtlsTimeout = ssl->options.handShakeState != HANDSHAKE_DONE;
3317
3318
        #ifdef WOLFSSL_DTLS13
3319
        if (ssl->options.dtls && IsAtLeastTLSv1_3(ssl->version)) {
3320
            doDtlsTimeout =
3321
                doDtlsTimeout || ssl->dtls13Rtx.rtxRecords != NULL ||
3322
                (ssl->dtls13FastTimeout && ssl->dtls13Rtx.seenRecords != NULL);
3323
        }
3324
        #endif /* WOLFSSL_DTLS13 */
3325
3326
        if (!doDtlsTimeout)
3327
            dtls_timeout = 0;
3328
3329
        if (!wolfSSL_dtls_get_using_nonblock(ssl)) {
3330
            /* needs timeout in milliseconds */
3331
            #ifdef WOLFSSL_DTLS13
3332
            if (wolfSSL_dtls13_use_quick_timeout(ssl) &&
3333
                IsAtLeastTLSv1_3(ssl->version)) {
3334
                dtls_timeout = (1000 * dtls_timeout) / 4;
3335
            } else
3336
            #endif /* WOLFSSL_DTLS13 */
3337
                dtls_timeout = 1000 * dtls_timeout;
3338
            NetSock_CfgTimeoutRxQ_Set(sd, dtls_timeout, &err);
3339
            if (err != NET_SOCK_ERR_NONE) {
3340
                WOLFSSL_MSG("NetSock_CfgTimeoutRxQ_Set failed");
3341
            }
3342
        }
3343
    }
3344
#endif /* WOLFSSL_DTLS */
3345
3346
    ret = NetSock_RxDataFrom(sd, buf, sz, ssl->rflags, &peer, &peerSz,
3347
                             0, 0, 0, &err);
3348
    if (ret < 0) {
3349
        WOLFSSL_MSG("Embed Receive From error");
3350
3351
        if (err == NET_ERR_RX || err == NET_SOCK_ERR_RX_Q_EMPTY ||
3352
            err == NET_ERR_FAULT_LOCK_ACQUIRE) {
3353
            if (wolfSSL_dtls_get_using_nonblock(ssl)) {
3354
                WOLFSSL_MSG("\tWould block");
3355
                return WOLFSSL_CBIO_ERR_WANT_READ;
3356
            }
3357
            else {
3358
                WOLFSSL_MSG("\tSocket timeout");
3359
                return WOLFSSL_CBIO_ERR_TIMEOUT;
3360
            }
3361
        } else {
3362
            WOLFSSL_MSG("\tGeneral error");
3363
            return WOLFSSL_CBIO_ERR_GENERAL;
3364
        }
3365
    }
3366
    else {
3367
        if (dtlsCtx->peer.sz > 0) {
3368
            NET_SOCK_ADDR_LEN expectedPeerSz =
3369
                (NET_SOCK_ADDR_LEN)dtlsCtx->peer.sz;
3370
            if (dtlsCtx->peer.sa == NULL ||
3371
                peerSz != expectedPeerSz ||
3372
                XMEMCMP(&peer, dtlsCtx->peer.sa, expectedPeerSz) != 0) {
3373
                WOLFSSL_MSG("\tIgnored packet from invalid peer");
3374
                return WOLFSSL_CBIO_ERR_WANT_READ;
3375
            }
3376
        }
3377
    }
3378
3379
    return ret;
3380
}
3381
3382
/* The Micrium uTCP/IP sendto callback
3383
 *  return : nb bytes sent, or error
3384
 */
3385
int MicriumSendTo(WOLFSSL* ssl, char *buf, int sz, void *ctx)
3386
{
3387
    WOLFSSL_DTLS_CTX* dtlsCtx = (WOLFSSL_DTLS_CTX*)ctx;
3388
    NET_SOCK_ID sd = dtlsCtx->wfd;
3389
    NET_SOCK_RTN_CODE ret;
3390
    NET_ERR err;
3391
3392
    WOLFSSL_ENTER("MicriumSendTo");
3393
3394
    ret = NetSock_TxDataTo(sd, buf, sz, ssl->wflags,
3395
                           (NET_SOCK_ADDR*)dtlsCtx->peer.sa,
3396
                           (NET_SOCK_ADDR_LEN)dtlsCtx->peer.sz,
3397
                           &err);
3398
    if (err < 0) {
3399
        WOLFSSL_MSG("Embed Send To error");
3400
3401
        if (err == NET_ERR_TX) {
3402
            WOLFSSL_MSG("\tWould block");
3403
            return WOLFSSL_CBIO_ERR_WANT_WRITE;
3404
3405
        } else {
3406
            WOLFSSL_MSG("\tGeneral error");
3407
            return WOLFSSL_CBIO_ERR_GENERAL;
3408
        }
3409
    }
3410
3411
    return ret;
3412
}
3413
3414
/* Micrium DTLS Generate Cookie callback
3415
 *  return : number of bytes copied into buf, or error
3416
 */
3417
#if defined(NO_SHA) && !defined(NO_SHA256)
3418
    #define MICRIUM_COOKIE_DIGEST_SIZE WC_SHA256_DIGEST_SIZE
3419
#elif !defined(NO_SHA)
3420
    #define MICRIUM_COOKIE_DIGEST_SIZE WC_SHA_DIGEST_SIZE
3421
#else
3422
    #error Must enable either SHA-1 or SHA256 (or both) for Micrium.
3423
#endif
3424
int MicriumGenerateCookie(WOLFSSL* ssl, byte *buf, int sz, void *ctx)
3425
{
3426
    NET_SOCK_ADDR peer;
3427
    NET_SOCK_ADDR_LEN peerSz = sizeof(peer);
3428
    byte digest[MICRIUM_COOKIE_DIGEST_SIZE];
3429
    int  ret = 0;
3430
3431
    (void)ctx;
3432
3433
    XMEMSET(&peer, 0, sizeof(peer));
3434
    if (wolfSSL_dtls_get_peer(ssl, (void*)&peer,
3435
                              (unsigned int*)&peerSz) != WOLFSSL_SUCCESS) {
3436
        WOLFSSL_MSG("getpeername failed in MicriumGenerateCookie");
3437
        return GEN_COOKIE_E;
3438
    }
3439
3440
#if defined(NO_SHA) && !defined(NO_SHA256)
3441
    ret = wc_Sha256Hash((byte*)&peer, peerSz, digest);
3442
#else
3443
    ret = wc_ShaHash((byte*)&peer, peerSz, digest);
3444
#endif
3445
    if (ret != 0)
3446
        return ret;
3447
3448
    if (sz > MICRIUM_COOKIE_DIGEST_SIZE)
3449
        sz = MICRIUM_COOKIE_DIGEST_SIZE;
3450
    XMEMCPY(buf, digest, sz);
3451
3452
    return sz;
3453
}
3454
3455
#endif /* MICRIUM */
3456
3457
#if defined(WOLFSSL_APACHE_MYNEWT) && !defined(WOLFSSL_LWIP)
3458
3459
#include <os/os_error.h>
3460
#include <os/os_mbuf.h>
3461
#include <os/os_mempool.h>
3462
3463
#define MB_NAME "wolfssl_mb"
3464
3465
typedef struct Mynewt_Ctx {
3466
        struct mn_socket *mnSocket;          /* send/recv socket handler */
3467
        struct mn_sockaddr_in mnSockAddrIn;  /* socket address */
3468
        struct os_mbuf *mnPacket;            /* incoming packet handle
3469
                                                for short reads */
3470
        int reading;                         /* reading flag */
3471
3472
        /* private */
3473
        void *mnMemBuffer;                   /* memory buffer for mempool */
3474
        struct os_mempool mnMempool;         /* mempool */
3475
        struct os_mbuf_pool mnMbufpool;      /* mbuf pool */
3476
} Mynewt_Ctx;
3477
3478
void mynewt_ctx_clear(void *ctx) {
3479
    Mynewt_Ctx *mynewt_ctx = (Mynewt_Ctx*)ctx;
3480
    if(!mynewt_ctx) return;
3481
3482
    if(mynewt_ctx->mnPacket) {
3483
        os_mbuf_free_chain(mynewt_ctx->mnPacket);
3484
        mynewt_ctx->mnPacket = NULL;
3485
    }
3486
    os_mempool_clear(&mynewt_ctx->mnMempool);
3487
    XFREE(mynewt_ctx->mnMemBuffer, 0, 0);
3488
    XFREE(mynewt_ctx, 0, 0);
3489
}
3490
3491
/* return Mynewt_Ctx instance */
3492
void* mynewt_ctx_new() {
3493
    int rc = 0;
3494
    Mynewt_Ctx *mynewt_ctx;
3495
    int mem_buf_count = MYNEWT_VAL(WOLFSSL_MNSOCK_MEM_BUF_COUNT);
3496
    int mem_buf_size = MYNEWT_VAL(WOLFSSL_MNSOCK_MEM_BUF_SIZE);
3497
    int mempool_bytes = OS_MEMPOOL_BYTES(mem_buf_count, mem_buf_size);
3498
3499
    mynewt_ctx = (Mynewt_Ctx *)XMALLOC(sizeof(struct Mynewt_Ctx),
3500
                                       NULL, DYNAMIC_TYPE_TMP_BUFFER);
3501
    if(!mynewt_ctx) return NULL;
3502
3503
    XMEMSET(mynewt_ctx, 0, sizeof(Mynewt_Ctx));
3504
    mynewt_ctx->mnMemBuffer = (void *)XMALLOC(mempool_bytes, 0, 0);
3505
    if(!mynewt_ctx->mnMemBuffer) {
3506
        mynewt_ctx_clear((void*)mynewt_ctx);
3507
        return NULL;
3508
    }
3509
3510
    rc = os_mempool_init(&mynewt_ctx->mnMempool,
3511
                         mem_buf_count, mem_buf_size,
3512
                         mynewt_ctx->mnMemBuffer, MB_NAME);
3513
    if(rc != 0) {
3514
        mynewt_ctx_clear((void*)mynewt_ctx);
3515
        return NULL;
3516
    }
3517
    rc = os_mbuf_pool_init(&mynewt_ctx->mnMbufpool, &mynewt_ctx->mnMempool,
3518
                           mem_buf_count, mem_buf_size);
3519
    if(rc != 0) {
3520
        mynewt_ctx_clear((void*)mynewt_ctx);
3521
        return NULL;
3522
    }
3523
3524
    return mynewt_ctx;
3525
}
3526
3527
static void mynewt_sock_writable(void *arg, int err);
3528
static void mynewt_sock_readable(void *arg, int err);
3529
static const union mn_socket_cb mynewt_sock_cbs = {
3530
    .socket.writable = mynewt_sock_writable,
3531
    .socket.readable = mynewt_sock_readable,
3532
};
3533
static void mynewt_sock_writable(void *arg, int err)
3534
{
3535
    /* do nothing */
3536
}
3537
static void mynewt_sock_readable(void *arg, int err)
3538
{
3539
    Mynewt_Ctx *mynewt_ctx = (Mynewt_Ctx *)arg;
3540
    if (err && mynewt_ctx->reading) {
3541
        mynewt_ctx->reading = 0;
3542
    }
3543
}
3544
3545
/* The Mynewt receive callback
3546
 *  return :  bytes read, or error
3547
 */
3548
int Mynewt_Receive(WOLFSSL *ssl, char *buf, int sz, void *ctx)
3549
{
3550
    Mynewt_Ctx *mynewt_ctx = (Mynewt_Ctx*)ctx;
3551
    int rc = 0;
3552
    struct mn_sockaddr_in from;
3553
    struct os_mbuf *m;
3554
    int read_sz = 0;
3555
    word16 total;
3556
3557
    if (mynewt_ctx == NULL || mynewt_ctx->mnSocket == NULL) {
3558
        WOLFSSL_MSG("Mynewt Recv NULL parameters");
3559
        return WOLFSSL_CBIO_ERR_GENERAL;
3560
    }
3561
3562
    if(mynewt_ctx->mnPacket == NULL) {
3563
        mynewt_ctx->mnPacket = os_mbuf_get_pkthdr(&mynewt_ctx->mnMbufpool, 0);
3564
        if(mynewt_ctx->mnPacket == NULL) {
3565
            return MEMORY_E;
3566
        }
3567
3568
        mynewt_ctx->reading = 1;
3569
        while(mynewt_ctx->reading && rc == 0) {
3570
            rc = mn_recvfrom(mynewt_ctx->mnSocket, &m, (struct mn_sockaddr *) &from);
3571
            if(rc == MN_ECONNABORTED) {
3572
                rc = 0;
3573
                mynewt_ctx->reading = 0;
3574
                break;
3575
            }
3576
            if (!(rc == 0 || rc == MN_EAGAIN)) {
3577
                WOLFSSL_MSG("Mynewt Recv receive error");
3578
                mynewt_ctx->reading = 0;
3579
                break;
3580
            }
3581
            if(rc == 0) {
3582
                int len = OS_MBUF_PKTLEN(m);
3583
                if(len == 0) {
3584
                    break;
3585
                }
3586
                rc = os_mbuf_appendfrom(mynewt_ctx->mnPacket, m, 0, len);
3587
                if(rc != 0) {
3588
                    WOLFSSL_MSG("Mynewt Recv os_mbuf_appendfrom error");
3589
                    break;
3590
                }
3591
                os_mbuf_free_chain(m);
3592
                m = NULL;
3593
            } else if(rc == MN_EAGAIN) {
3594
                /* continue to until reading all of packet data. */
3595
                rc = 0;
3596
                break;
3597
            }
3598
        }
3599
        if(rc != 0) {
3600
            mynewt_ctx->reading = 0;
3601
            os_mbuf_free_chain(mynewt_ctx->mnPacket);
3602
            mynewt_ctx->mnPacket = NULL;
3603
            return rc;
3604
        }
3605
    }
3606
3607
    if(mynewt_ctx->mnPacket) {
3608
        total = OS_MBUF_PKTLEN(mynewt_ctx->mnPacket);
3609
        read_sz = (total >= sz)? sz : total;
3610
3611
        os_mbuf_copydata(mynewt_ctx->mnPacket, 0, read_sz, (void*)buf);
3612
        os_mbuf_adj(mynewt_ctx->mnPacket, read_sz);
3613
3614
        if (read_sz == total) {
3615
            WOLFSSL_MSG("Mynewt Recv Drained packet");
3616
            os_mbuf_free_chain(mynewt_ctx->mnPacket);
3617
            mynewt_ctx->mnPacket = NULL;
3618
        }
3619
    }
3620
3621
    return read_sz;
3622
}
3623
3624
/* The Mynewt send callback
3625
 *  return : bytes sent, or error
3626
 */
3627
int Mynewt_Send(WOLFSSL* ssl, char *buf, int sz, void *ctx)
3628
{
3629
    Mynewt_Ctx *mynewt_ctx = (Mynewt_Ctx*)ctx;
3630
    int rc = 0;
3631
    struct os_mbuf *m;
3632
    int write_sz = 0;
3633
    m = os_msys_get_pkthdr(sz, 0);
3634
    if (!m) {
3635
        WOLFSSL_MSG("Mynewt Send os_msys_get_pkthdr error");
3636
        return WOLFSSL_CBIO_ERR_GENERAL;
3637
    }
3638
    rc = os_mbuf_copyinto(m, 0, buf, sz);
3639
    if (rc != 0) {
3640
        WOLFSSL_MSG("Mynewt Send os_mbuf_copyinto error");
3641
        os_mbuf_free_chain(m);
3642
        return rc;
3643
    }
3644
    rc = mn_sendto(mynewt_ctx->mnSocket, m, (struct mn_sockaddr *)&mynewt_ctx->mnSockAddrIn);
3645
    if(rc != 0) {
3646
        WOLFSSL_MSG("Mynewt Send mn_sendto error");
3647
        os_mbuf_free_chain(m);
3648
        return rc;
3649
    }
3650
    write_sz = sz;
3651
    return write_sz;
3652
}
3653
3654
/* like set_fd, but for default NetX context */
3655
void wolfSSL_SetIO_Mynewt(WOLFSSL* ssl, struct mn_socket* mnSocket, struct mn_sockaddr_in* mnSockAddrIn)
3656
{
3657
    if (ssl && ssl->mnCtx) {
3658
        Mynewt_Ctx *mynewt_ctx = (Mynewt_Ctx *)ssl->mnCtx;
3659
        mynewt_ctx->mnSocket = mnSocket;
3660
        XMEMCPY(&mynewt_ctx->mnSockAddrIn, mnSockAddrIn, sizeof(struct mn_sockaddr_in));
3661
        mn_socket_set_cbs(mynewt_ctx->mnSocket, mnSocket, &mynewt_sock_cbs);
3662
    }
3663
}
3664
3665
#endif /* defined(WOLFSSL_APACHE_MYNEWT) && !defined(WOLFSSL_LWIP) */
3666
3667
#ifdef WOLFSSL_UIP
3668
#include <uip.h>
3669
#include <stdio.h>
3670
3671
/* uIP TCP/IP port, using the native tcp/udp socket api.
3672
 * TCP and UDP are currently supported with the callbacks below.
3673
 *
3674
 */
3675
/* The uIP tcp send callback
3676
 * return : bytes sent, or error
3677
 */
3678
int uIPSend(WOLFSSL* ssl, char* buf, int sz, void* _ctx)
3679
{
3680
    uip_wolfssl_ctx *ctx = (struct uip_wolfssl_ctx *)_ctx;
3681
    int total_written = 0;
3682
    (void)ssl;
3683
    do {
3684
        int ret;
3685
        unsigned int bytes_left = sz - total_written;
3686
        unsigned int max_sendlen = tcp_socket_max_sendlen(&ctx->conn.tcp);
3687
        if (bytes_left > max_sendlen) {
3688
            fprintf(stderr, "uIPSend: Send limited by buffer\r\n");
3689
            bytes_left = max_sendlen;
3690
        }
3691
        if (bytes_left == 0) {
3692
            fprintf(stderr, "uIPSend: Buffer full!\r\n");
3693
            break;
3694
        }
3695
        ret = tcp_socket_send(&ctx->conn.tcp, (unsigned char *)buf + total_written, bytes_left);
3696
        if (ret <= 0)
3697
            break;
3698
        total_written += ret;
3699
    } while(total_written < sz);
3700
    if (total_written == 0)
3701
        return WOLFSSL_CBIO_ERR_WANT_WRITE;
3702
    return total_written;
3703
}
3704
3705
int uIPSendTo(WOLFSSL* ssl, char* buf, int sz, void* _ctx)
3706
{
3707
    uip_wolfssl_ctx *ctx = (struct uip_wolfssl_ctx *)_ctx;
3708
    int ret = 0;
3709
    (void)ssl;
3710
    ret = udp_socket_sendto(&ctx->conn.udp, (unsigned char *)buf, sz, &ctx->peer_addr, ctx->peer_port );
3711
    if (ret == 0)
3712
        return WOLFSSL_CBIO_ERR_WANT_WRITE;
3713
    return ret;
3714
}
3715
3716
/* The uIP uTCP/IP receive callback
3717
 *  return : nb bytes read, or error
3718
 */
3719
int uIPReceive(WOLFSSL *ssl, char *buf, int sz, void *_ctx)
3720
{
3721
    uip_wolfssl_ctx *ctx = (uip_wolfssl_ctx *)_ctx;
3722
    if (!ctx || !ctx->ssl_rx_databuf)
3723
        return WOLFSSL_FATAL_ERROR;
3724
    (void)ssl;
3725
    if (ctx->ssl_rb_len > 0) {
3726
        if (sz > ctx->ssl_rb_len - ctx->ssl_rb_off)
3727
            sz = ctx->ssl_rb_len - ctx->ssl_rb_off;
3728
        XMEMCPY(buf, ctx->ssl_rx_databuf + ctx->ssl_rb_off, sz);
3729
        ctx->ssl_rb_off += sz;
3730
        if (ctx->ssl_rb_off >= ctx->ssl_rb_len) {
3731
            ctx->ssl_rb_len = 0;
3732
            ctx->ssl_rb_off = 0;
3733
        }
3734
        return sz;
3735
    } else {
3736
        return WOLFSSL_CBIO_ERR_WANT_READ;
3737
    }
3738
}
3739
3740
/* uIP DTLS Generate Cookie callback
3741
 *  return : number of bytes copied into buf, or error
3742
 */
3743
#if defined(NO_SHA) && !defined(NO_SHA256)
3744
    #define UIP_COOKIE_DIGEST_SIZE WC_SHA256_DIGEST_SIZE
3745
#elif !defined(NO_SHA)
3746
    #define UIP_COOKIE_DIGEST_SIZE WC_SHA_DIGEST_SIZE
3747
#else
3748
    #error Must enable either SHA-1 or SHA256 (or both) for uIP.
3749
#endif
3750
int uIPGenerateCookie(WOLFSSL* ssl, byte *buf, int sz, void *_ctx)
3751
{
3752
    uip_wolfssl_ctx *ctx = (uip_wolfssl_ctx *)_ctx;
3753
    byte token[32];
3754
    byte digest[UIP_COOKIE_DIGEST_SIZE];
3755
    int  ret = 0;
3756
    XMEMSET(token, 0, sizeof(token));
3757
    XMEMCPY(token, &ctx->peer_addr, sizeof(uip_ipaddr_t));
3758
    XMEMCPY(token + sizeof(uip_ipaddr_t), &ctx->peer_port, sizeof(word16));
3759
#if defined(NO_SHA) && !defined(NO_SHA256)
3760
    ret = wc_Sha256Hash(token, sizeof(uip_ipaddr_t) + sizeof(word16), digest);
3761
#else
3762
    ret = wc_ShaHash(token, sizeof(uip_ipaddr_t) + sizeof(word16), digest);
3763
#endif
3764
    if (ret != 0)
3765
        return ret;
3766
    if (sz > UIP_COOKIE_DIGEST_SIZE)
3767
        sz = UIP_COOKIE_DIGEST_SIZE;
3768
    XMEMCPY(buf, digest, sz);
3769
    return sz;
3770
}
3771
3772
#endif /* WOLFSSL_UIP */
3773
3774
#ifdef WOLFSSL_GNRC
3775
3776
#include <net/sock.h>
3777
#include <net/sock/tcp.h>
3778
#include <stdio.h>
3779
3780
/* GNRC TCP/IP port, using the native tcp/udp socket api.
3781
 * TCP and UDP are currently supported with the callbacks below.
3782
 *
3783
 */
3784
/* The GNRC tcp send callback
3785
 * return : bytes sent, or error
3786
 */
3787
3788
int GNRC_SendTo(WOLFSSL* ssl, char* buf, int sz, void* _ctx)
3789
{
3790
    sock_tls_t *ctx = (sock_tls_t *)_ctx;
3791
    int ret = 0;
3792
    (void)ssl;
3793
    if (!ctx)
3794
        return WOLFSSL_CBIO_ERR_GENERAL;
3795
    ret = sock_udp_send(&ctx->conn.udp, (unsigned char *)buf, sz, &ctx->peer_addr);
3796
    if (ret == 0)
3797
        return WOLFSSL_CBIO_ERR_WANT_WRITE;
3798
    return ret;
3799
}
3800
3801
/* The GNRC TCP/IP receive callback
3802
 *  return : nb bytes read, or error
3803
 */
3804
int GNRC_ReceiveFrom(WOLFSSL *ssl, char *buf, int sz, void *_ctx)
3805
{
3806
    sock_udp_ep_t ep;
3807
    int ret;
3808
    word32 timeout = wolfSSL_dtls_get_current_timeout(ssl) * 1000000;
3809
    sock_tls_t *ctx = (sock_tls_t *)_ctx;
3810
    if (!ctx)
3811
        return WOLFSSL_CBIO_ERR_GENERAL;
3812
    (void)ssl;
3813
    if (wolfSSL_get_using_nonblock(ctx->ssl)) {
3814
        timeout = 0;
3815
    }
3816
    ret = sock_udp_recv(&ctx->conn.udp, buf, sz, timeout, &ep);
3817
    if (ret > 0) {
3818
        if (ctx->peer_addr.port == 0)
3819
            XMEMCPY(&ctx->peer_addr, &ep, sizeof(sock_udp_ep_t));
3820
    }
3821
    if (ret == -ETIMEDOUT) {
3822
        return WOLFSSL_CBIO_ERR_WANT_READ;
3823
    }
3824
    return ret;
3825
}
3826
3827
/* GNRC DTLS Generate Cookie callback
3828
 *  return : number of bytes copied into buf, or error
3829
 */
3830
#define GNRC_MAX_TOKEN_SIZE (32)
3831
#if defined(NO_SHA) && !defined(NO_SHA256)
3832
    #define GNRC_COOKIE_DIGEST_SIZE WC_SHA256_DIGEST_SIZE
3833
#elif !defined(NO_SHA)
3834
    #define GNRC_COOKIE_DIGEST_SIZE WC_SHA_DIGEST_SIZE
3835
#else
3836
    #error Must enable either SHA-1 or SHA256 (or both) for GNRC.
3837
#endif
3838
int GNRC_GenerateCookie(WOLFSSL* ssl, byte *buf, int sz, void *_ctx)
3839
{
3840
    sock_tls_t *ctx = (sock_tls_t *)_ctx;
3841
    if (!ctx)
3842
        return WOLFSSL_CBIO_ERR_GENERAL;
3843
    byte token[GNRC_MAX_TOKEN_SIZE];
3844
    byte digest[GNRC_COOKIE_DIGEST_SIZE];
3845
    int  ret = 0;
3846
    size_t token_size = sizeof(sock_udp_ep_t);
3847
    (void)ssl;
3848
    if (token_size > GNRC_MAX_TOKEN_SIZE)
3849
        token_size = GNRC_MAX_TOKEN_SIZE;
3850
    XMEMSET(token, 0, GNRC_MAX_TOKEN_SIZE);
3851
    XMEMCPY(token, &ctx->peer_addr, token_size);
3852
#if defined(NO_SHA) && !defined(NO_SHA256)
3853
    ret = wc_Sha256Hash(token, token_size, digest);
3854
#else
3855
    ret = wc_ShaHash(token, token_size, digest);
3856
#endif
3857
    if (ret != 0)
3858
        return ret;
3859
    if (sz > GNRC_COOKIE_DIGEST_SIZE)
3860
        sz = GNRC_COOKIE_DIGEST_SIZE;
3861
    XMEMCPY(buf, digest, sz);
3862
    return sz;
3863
}
3864
3865
#endif /* WOLFSSL_GNRC */
3866
3867
#ifdef WOLFSSL_LWIP_NATIVE
3868
int LwIPNativeSend(WOLFSSL* ssl, char* buf, int sz, void* ctx)
3869
{
3870
    err_t ret;
3871
    WOLFSSL_LWIP_NATIVE_STATE* nlwip = (WOLFSSL_LWIP_NATIVE_STATE*)ctx;
3872
3873
    if (sz < 0 || sz > (int)WOLFSSL_MAX_16BIT) {
3874
        return BAD_FUNC_ARG;
3875
    }
3876
3877
    ret = tcp_write(nlwip->pcb, buf, (u16_t)sz, TCP_WRITE_FLAG_COPY);
3878
    if (ret != ERR_OK) {
3879
        sz = WOLFSSL_FATAL_ERROR;
3880
    }
3881
3882
    return sz;
3883
}
3884
3885
3886
int LwIPNativeReceive(WOLFSSL* ssl, char* buf, int sz, void* ctx)
3887
{
3888
    struct pbuf *current, *head;
3889
    WOLFSSL_LWIP_NATIVE_STATE* nlwip;
3890
    int ret = 0;
3891
3892
    if (ctx == NULL) {
3893
        return WOLFSSL_CBIO_ERR_GENERAL;
3894
    }
3895
    nlwip = (WOLFSSL_LWIP_NATIVE_STATE*)ctx;
3896
3897
    current = nlwip->pbuf;
3898
    if (current == NULL || sz > current->tot_len) {
3899
        WOLFSSL_MSG("LwIP native pbuf list is null or not enough data, want read");
3900
        ret = WOLFSSL_CBIO_ERR_WANT_READ;
3901
    }
3902
    else {
3903
        int read = 0; /* total amount read */
3904
        head = nlwip->pbuf; /* save pointer to current head */
3905
3906
        /* loop through buffers reading data */
3907
        while (current != NULL) {
3908
            int len; /* current amount to be read */
3909
3910
            len = (current->len - nlwip->pulled < sz) ?
3911
                                            (current->len - nlwip->pulled) : sz;
3912
3913
            if (read + len > sz) {
3914
                /* should never be hit but have sanity check before use */
3915
                return WOLFSSL_CBIO_ERR_GENERAL;
3916
            }
3917
3918
            /* check if is a partial read from before */
3919
            XMEMCPY(&buf[read],
3920
                   (const char *)&(((char *)(current->payload))[nlwip->pulled]),
3921
3922
                    len);
3923
            nlwip->pulled = nlwip->pulled + len;
3924
            if (nlwip->pulled >= current->len) {
3925
                WOLFSSL_MSG("Native LwIP read full pbuf");
3926
                nlwip->pbuf = current->next;
3927
                current = nlwip->pbuf;
3928
                nlwip->pulled = 0;
3929
            }
3930
            read = read + len;
3931
            ret  = read;
3932
3933
            /* read enough break out */
3934
            if (read >= sz) {
3935
                /* if more pbuf's are left in the chain then increment the
3936
                 * ref count for next in chain and free all from beginning till
3937
                 * next */
3938
                if (current != NULL) {
3939
                    pbuf_ref(current);
3940
                }
3941
3942
                /* ack and start free'ing from the current head of the chain */
3943
                pbuf_free(head);
3944
                break;
3945
            }
3946
        }
3947
    }
3948
    WOLFSSL_LEAVE("LwIPNativeReceive", ret);
3949
    return ret;
3950
}
3951
3952
3953
static err_t LwIPNativeReceiveCB(void* cb, struct tcp_pcb* pcb,
3954
                                struct pbuf* pbuf, err_t err)
3955
{
3956
    WOLFSSL_LWIP_NATIVE_STATE* nlwip;
3957
3958
    if (cb == NULL || pcb == NULL) {
3959
        WOLFSSL_MSG("Expected callback was null, abort");
3960
        return ERR_ABRT;
3961
    }
3962
3963
    nlwip = (WOLFSSL_LWIP_NATIVE_STATE*)cb;
3964
    if (pbuf == NULL && err == ERR_OK) {
3965
        return ERR_OK;
3966
    }
3967
3968
    if (nlwip->pbuf == NULL) {
3969
        nlwip->pbuf = pbuf;
3970
    }
3971
    else {
3972
        if (nlwip->pbuf != pbuf) {
3973
            tcp_recved(nlwip->pcb, pbuf->tot_len);
3974
            pbuf_cat(nlwip->pbuf, pbuf); /* add chain to head */
3975
        }
3976
    }
3977
3978
    if (nlwip->recv_fn) {
3979
        return nlwip->recv_fn(nlwip->arg, pcb, pbuf, err);
3980
    }
3981
3982
    WOLFSSL_LEAVE("LwIPNativeReceiveCB", nlwip->pbuf->tot_len);
3983
    return ERR_OK;
3984
}
3985
3986
3987
static err_t LwIPNativeSentCB(void* cb, struct tcp_pcb* pcb, u16_t len)
3988
{
3989
    WOLFSSL_LWIP_NATIVE_STATE* nlwip;
3990
3991
    if (cb == NULL || pcb == NULL) {
3992
        WOLFSSL_MSG("Expected callback was null, abort");
3993
        return ERR_ABRT;
3994
    }
3995
3996
    nlwip = (WOLFSSL_LWIP_NATIVE_STATE*)cb;
3997
    if (nlwip->sent_fn) {
3998
        return nlwip->sent_fn(nlwip->arg, pcb, len);
3999
    }
4000
    return ERR_OK;
4001
}
4002
4003
4004
int wolfSSL_SetIO_LwIP(WOLFSSL* ssl, void* pcb,
4005
                          tcp_recv_fn recv_fn, tcp_sent_fn sent_fn, void *arg)
4006
{
4007
    if (ssl == NULL || pcb == NULL)
4008
        return BAD_FUNC_ARG;
4009
4010
    ssl->lwipCtx.pcb = (struct tcp_pcb *)pcb;
4011
    ssl->lwipCtx.recv_fn = recv_fn; /*  recv user callback */
4012
    ssl->lwipCtx.sent_fn = sent_fn; /*  sent user callback */
4013
    ssl->lwipCtx.arg  = arg;
4014
    ssl->lwipCtx.pbuf = 0;
4015
    ssl->lwipCtx.pulled = 0;
4016
    ssl->lwipCtx.wait   = 0;
4017
4018
    /* wolfSSL_LwIP_recv/sent_cb invokes recv/sent user callback in them. */
4019
    tcp_recv(pcb, LwIPNativeReceiveCB);
4020
    tcp_sent(pcb, LwIPNativeSentCB);
4021
    tcp_arg (pcb, (void *)&ssl->lwipCtx);
4022
    wolfSSL_SetIOReadCtx(ssl, &ssl->lwipCtx);
4023
    wolfSSL_SetIOWriteCtx(ssl, &ssl->lwipCtx);
4024
4025
    return ERR_OK;
4026
}
4027
#endif /* WOLFSSL_LWIP_NATIVE */
4028
4029
#ifdef WOLFSSL_ISOTP
4030
static int isotp_send_single_frame(struct isotp_wolfssl_ctx *ctx, char *buf,
4031
        word16 length)
4032
{
4033
    /* Length will be at most 7 bytes to get here. Packet is length and type
4034
     * for the first byte, then up to 7 bytes of data */
4035
    ctx->frame.data[0] = ((byte)length) | (ISOTP_FRAME_TYPE_SINGLE << 4);
4036
    XMEMCPY(&ctx->frame.data[1], buf, length);
4037
    ctx->frame.length = length + 1;
4038
    return ctx->send_fn(&ctx->frame, ctx->arg);
4039
}
4040
4041
static int isotp_send_flow_control(struct isotp_wolfssl_ctx *ctx,
4042
        byte overflow)
4043
{
4044
    int ret;
4045
    /* Overflow is set it if we have been asked to receive more data than the
4046
     * user allocated a buffer for */
4047
    if (overflow) {
4048
        ctx->frame.data[0] = ISOTP_FLOW_CONTROL_ABORT |
4049
            (ISOTP_FRAME_TYPE_CONTROL << 4);
4050
    } else {
4051
        ctx->frame.data[0] = ISOTP_FLOW_CONTROL_CTS |
4052
            (ISOTP_FRAME_TYPE_CONTROL << 4);
4053
    }
4054
    /* Set the number of frames between flow control to infinite */
4055
    ctx->frame.data[1] = ISOTP_FLOW_CONTROL_FRAMES;
4056
    /* User specified frame delay */
4057
    ctx->frame.data[2] = ctx->receive_delay;
4058
    ctx->frame.length = ISOTP_FLOW_CONTROL_PACKET_SIZE;
4059
    ret = ctx->send_fn(&ctx->frame, ctx->arg);
4060
    return ret;
4061
}
4062
4063
static int isotp_receive_flow_control(struct isotp_wolfssl_ctx *ctx)
4064
{
4065
    int ret;
4066
    enum isotp_frame_type type;
4067
    enum isotp_flow_control flow_control;
4068
    ret = ctx->recv_fn(&ctx->frame, ctx->arg, ISOTP_DEFAULT_TIMEOUT);
4069
    if (ret == 0) {
4070
        return WOLFSSL_CBIO_ERR_TIMEOUT;
4071
    } else if (ret < 0) {
4072
        WOLFSSL_MSG("ISO-TP error receiving flow control packet");
4073
        return WOLFSSL_CBIO_ERR_GENERAL;
4074
    }
4075
    /* Flow control is the frame type and flow response for the first byte,
4076
     * number of frames until the next flow control packet for the second
4077
     * byte, time between frames for the third byte */
4078
    type = ctx->frame.data[0] >> 4;
4079
4080
    if (type != ISOTP_FRAME_TYPE_CONTROL) {
4081
        WOLFSSL_MSG("ISO-TP frames out of sequence");
4082
        return WOLFSSL_CBIO_ERR_GENERAL;
4083
    }
4084
4085
    flow_control = ctx->frame.data[0] & 0xf;
4086
4087
    ctx->flow_counter = 0;
4088
    ctx->flow_packets = ctx->frame.data[1];
4089
    ctx->frame_delay = ctx->frame.data[2];
4090
4091
    return flow_control;
4092
}
4093
4094
static int isotp_send_consecutive_frame(struct isotp_wolfssl_ctx *ctx)
4095
{
4096
    /* Sequence is 0 - 15 and then starts again, the first frame has an
4097
     * implied sequence of '0' */
4098
    ctx->sequence += 1;
4099
    if (ctx->sequence > ISOTP_MAX_SEQUENCE_COUNTER) {
4100
        ctx->sequence = 0;
4101
    }
4102
    ctx->flow_counter++;
4103
    /* First byte it type and sequence number, up to 7 bytes of data */
4104
    ctx->frame.data[0] = ctx->sequence | (ISOTP_FRAME_TYPE_CONSECUTIVE << 4);
4105
    if (ctx->buf_length > ISOTP_MAX_CONSECUTIVE_FRAME_DATA_SIZE) {
4106
        XMEMCPY(&ctx->frame.data[1], ctx->buf_ptr,
4107
                ISOTP_MAX_CONSECUTIVE_FRAME_DATA_SIZE);
4108
        ctx->buf_ptr += ISOTP_MAX_CONSECUTIVE_FRAME_DATA_SIZE;
4109
        ctx->buf_length -= ISOTP_MAX_CONSECUTIVE_FRAME_DATA_SIZE;
4110
        ctx->frame.length = ISOTP_CAN_BUS_PAYLOAD_SIZE;
4111
    } else {
4112
        XMEMCPY(&ctx->frame.data[1], ctx->buf_ptr, ctx->buf_length);
4113
        ctx->frame.length = ctx->buf_length + 1;
4114
        ctx->buf_length = 0;
4115
    }
4116
    return ctx->send_fn(&ctx->frame, ctx->arg);
4117
4118
}
4119
4120
static int isotp_send_first_frame(struct isotp_wolfssl_ctx *ctx, char *buf,
4121
        word16 length)
4122
{
4123
    int ret;
4124
    ctx->sequence = 0;
4125
    /* Set to 1 to trigger a flow control straight away, the flow control
4126
     * packet will set these properly */
4127
    ctx->flow_packets = ctx->flow_counter = 1;
4128
    /* First frame has 1 nibble for type, 3 nibbles for length followed by
4129
     * 6 bytes for data*/
4130
    ctx->frame.data[0] = (length >> 8) | (ISOTP_FRAME_TYPE_FIRST << 4);
4131
    ctx->frame.data[1] = length & 0xff;
4132
    XMEMCPY(&ctx->frame.data[2], buf, ISOTP_FIRST_FRAME_DATA_SIZE);
4133
    ctx->buf_ptr = buf + ISOTP_FIRST_FRAME_DATA_SIZE;
4134
    ctx->buf_length = length - ISOTP_FIRST_FRAME_DATA_SIZE;
4135
    ctx->frame.length = ISOTP_CAN_BUS_PAYLOAD_SIZE;
4136
    ret = ctx->send_fn(&ctx->frame, ctx->arg);
4137
    if (ret <= 0) {
4138
        WOLFSSL_MSG("ISO-TP error sending first frame");
4139
        return WOLFSSL_CBIO_ERR_GENERAL;
4140
    }
4141
    while(ctx->buf_length) {
4142
        /* The receiver can set how often to get a flow control packet. If it
4143
         * is time, then get the packet. Note that this will always happen
4144
         * after the first packet */
4145
        if ((ctx->flow_packets > 0) &&
4146
                (ctx->flow_counter == ctx->flow_packets)) {
4147
            ret = isotp_receive_flow_control(ctx);
4148
        }
4149
        /* Frame delay <= 0x7f is in ms, 0xfX is X * 100 us */
4150
        if (ctx->frame_delay) {
4151
            if (ctx->frame_delay <= ISOTP_MAX_MS_FRAME_DELAY) {
4152
                ctx->delay_fn(ctx->frame_delay * 1000);
4153
            } else {
4154
                ctx->delay_fn((ctx->frame_delay & 0xf) * 100);
4155
            }
4156
        }
4157
        switch (ret) {
4158
            /* Clear to send */
4159
            case ISOTP_FLOW_CONTROL_CTS:
4160
                if (isotp_send_consecutive_frame(ctx) < 0) {
4161
                    WOLFSSL_MSG("ISO-TP error sending consecutive frame");
4162
                    return WOLFSSL_CBIO_ERR_GENERAL;
4163
                }
4164
                break;
4165
            /* Receiver says "WAIT", so we wait for another flow control
4166
             * packet, or abort if we have waited too long */
4167
            case ISOTP_FLOW_CONTROL_WAIT:
4168
                ctx->wait_counter += 1;
4169
                if (ctx->wait_counter > ISOTP_DEFAULT_WAIT_COUNT) {
4170
                    WOLFSSL_MSG("ISO-TP receiver told us to wait too many"
4171
                            " times");
4172
                    return WOLFSSL_CBIO_ERR_WANT_WRITE;
4173
                }
4174
                break;
4175
            /* Receiver is not ready to receive packet, so abort */
4176
            case ISOTP_FLOW_CONTROL_ABORT:
4177
                WOLFSSL_MSG("ISO-TP receiver aborted transmission");
4178
                return WOLFSSL_CBIO_ERR_WANT_WRITE;
4179
            default:
4180
                WOLFSSL_MSG("ISO-TP got unexpected flow control packet");
4181
                return WOLFSSL_CBIO_ERR_GENERAL;
4182
        }
4183
    }
4184
    return 0;
4185
}
4186
4187
int ISOTP_Send(WOLFSSL* ssl, char* buf, int sz, void* ctx)
4188
{
4189
    int ret;
4190
    struct isotp_wolfssl_ctx *isotp_ctx;
4191
    (void) ssl;
4192
4193
    if (!ctx) {
4194
        WOLFSSL_MSG("ISO-TP requires wolfSSL_SetIO_ISOTP to be called first");
4195
        return WOLFSSL_CBIO_ERR_GENERAL;
4196
    }
4197
    isotp_ctx = (struct isotp_wolfssl_ctx*) ctx;
4198
4199
    /* ISO-TP cannot send more than 4095 bytes, this limits the packet size
4200
     * and wolfSSL will try again with the remaining data */
4201
    if (sz > ISOTP_MAX_DATA_SIZE) {
4202
        sz = ISOTP_MAX_DATA_SIZE;
4203
    }
4204
    /* Can't send whilst we are receiving */
4205
    if (isotp_ctx->state != ISOTP_CONN_STATE_IDLE) {
4206
        return WOLFSSL_ERROR_WANT_WRITE;
4207
    }
4208
    isotp_ctx->state = ISOTP_CONN_STATE_SENDING;
4209
4210
    /* Assuming normal addressing */
4211
    if (sz <= ISOTP_SINGLE_FRAME_DATA_SIZE) {
4212
        ret = isotp_send_single_frame(isotp_ctx, buf, (word16)sz);
4213
    } else {
4214
        ret = isotp_send_first_frame(isotp_ctx, buf, (word16)sz);
4215
    }
4216
    isotp_ctx->state = ISOTP_CONN_STATE_IDLE;
4217
4218
    if (ret == 0) {
4219
        return sz;
4220
    }
4221
    return ret;
4222
}
4223
4224
static int isotp_receive_single_frame(struct isotp_wolfssl_ctx *ctx)
4225
{
4226
    byte data_size;
4227
4228
    /* 1 nibble for data size which will be 1 - 7 in a regular 8 byte CAN
4229
     * packet */
4230
    data_size = (byte)ctx->frame.data[0] & 0xf;
4231
    if (ctx->receive_buffer_size < (int)data_size) {
4232
        WOLFSSL_MSG("ISO-TP buffer is too small to receive data");
4233
        return BUFFER_E;
4234
    }
4235
    XMEMCPY(ctx->receive_buffer, &ctx->frame.data[1], data_size);
4236
    return data_size;
4237
}
4238
4239
static int isotp_receive_multi_frame(struct isotp_wolfssl_ctx *ctx)
4240
{
4241
    int ret;
4242
    word16 data_size;
4243
    byte delay = 0;
4244
4245
    /* Increase receive timeout for enforced ms delay */
4246
    if (ctx->receive_delay <= ISOTP_MAX_MS_FRAME_DELAY) {
4247
        delay = ctx->receive_delay;
4248
    }
4249
    /* Still processing first frame.
4250
     * Full data size is lower nibble of first byte for the most significant
4251
     * followed by the second byte for the rest. Last 6 bytes are data */
4252
    data_size = ((ctx->frame.data[0] & 0xf) << 8) + ctx->frame.data[1];
4253
    XMEMCPY(ctx->receive_buffer, &ctx->frame.data[2], ISOTP_FIRST_FRAME_DATA_SIZE);
4254
    /* Need to send a flow control packet to either cancel or continue
4255
     * transmission of data */
4256
    if (ctx->receive_buffer_size < data_size) {
4257
        isotp_send_flow_control(ctx, TRUE);
4258
        WOLFSSL_MSG("ISO-TP buffer is too small to receive data");
4259
        return BUFFER_E;
4260
    }
4261
    isotp_send_flow_control(ctx, FALSE);
4262
4263
    ctx->buf_length = ISOTP_FIRST_FRAME_DATA_SIZE;
4264
    ctx->buf_ptr = ctx->receive_buffer + ISOTP_FIRST_FRAME_DATA_SIZE;
4265
    data_size -= ISOTP_FIRST_FRAME_DATA_SIZE;
4266
    ctx->sequence = 1;
4267
4268
    while(data_size) {
4269
        enum isotp_frame_type type;
4270
        byte sequence;
4271
        byte frame_len;
4272
        ret = ctx->recv_fn(&ctx->frame, ctx->arg, ISOTP_DEFAULT_TIMEOUT +
4273
                (delay / 1000));
4274
        if (ret == 0) {
4275
            return WOLFSSL_CBIO_ERR_TIMEOUT;
4276
        }
4277
        type = ctx->frame.data[0] >> 4;
4278
        /* Consecutive frames have sequence number as lower nibble */
4279
        sequence = ctx->frame.data[0] & 0xf;
4280
        if (type != ISOTP_FRAME_TYPE_CONSECUTIVE) {
4281
            WOLFSSL_MSG("ISO-TP frames out of sequence");
4282
            return WOLFSSL_CBIO_ERR_GENERAL;
4283
        }
4284
        if (sequence != ctx->sequence) {
4285
            WOLFSSL_MSG("ISO-TP frames out of sequence");
4286
            return WOLFSSL_CBIO_ERR_GENERAL;
4287
        }
4288
        /* Last 7 bytes or whatever we got after the first byte is data */
4289
        frame_len = ctx->frame.length - 1;
4290
        XMEMCPY(ctx->buf_ptr, &ctx->frame.data[1], frame_len);
4291
        ctx->buf_ptr += frame_len;
4292
        ctx->buf_length += frame_len;
4293
        data_size -= frame_len;
4294
4295
        /* Sequence is 0 - 15 (first 0 is implied for first packet */
4296
        ctx->sequence++;
4297
        if (ctx->sequence > ISOTP_MAX_SEQUENCE_COUNTER) {
4298
            ctx->sequence = 0;
4299
        }
4300
    }
4301
    return ctx->buf_length;
4302
4303
}
4304
4305
/* The wolfSSL receive callback, needs to buffer because we need to grab all
4306
 * incoming data, even if wolfSSL doesn't want it all yet */
4307
int ISOTP_Receive(WOLFSSL* ssl, char* buf, int sz, void* ctx)
4308
{
4309
    enum isotp_frame_type type;
4310
    int ret;
4311
    struct isotp_wolfssl_ctx *isotp_ctx;
4312
    (void) ssl;
4313
4314
    if (!ctx) {
4315
        WOLFSSL_MSG("ISO-TP requires wolfSSL_SetIO_ISOTP to be called first");
4316
        return WOLFSSL_CBIO_ERR_TIMEOUT;
4317
    }
4318
    isotp_ctx = (struct isotp_wolfssl_ctx*)ctx;
4319
4320
    /* Is buffer empty? If so, fill it */
4321
    if (!isotp_ctx->receive_buffer_len) {
4322
        /* Can't send whilst we are receiving */
4323
        if (isotp_ctx->state != ISOTP_CONN_STATE_IDLE) {
4324
            return WOLFSSL_ERROR_WANT_READ;
4325
        }
4326
        isotp_ctx->state = ISOTP_CONN_STATE_RECEIVING;
4327
        do {
4328
            ret = isotp_ctx->recv_fn(&isotp_ctx->frame, isotp_ctx->arg,
4329
                    ISOTP_DEFAULT_TIMEOUT);
4330
        } while (ret == 0);
4331
        if (ret == 0) {
4332
            isotp_ctx->state = ISOTP_CONN_STATE_IDLE;
4333
            return WOLFSSL_CBIO_ERR_TIMEOUT;
4334
        } else if (ret < 0) {
4335
            isotp_ctx->state = ISOTP_CONN_STATE_IDLE;
4336
            WOLFSSL_MSG("ISO-TP receive error");
4337
            return WOLFSSL_CBIO_ERR_GENERAL;
4338
        }
4339
4340
        type = (enum isotp_frame_type) isotp_ctx->frame.data[0] >> 4;
4341
4342
        if (type == ISOTP_FRAME_TYPE_SINGLE) {
4343
            isotp_ctx->receive_buffer_len =
4344
                isotp_receive_single_frame(isotp_ctx);
4345
        } else if (type == ISOTP_FRAME_TYPE_FIRST) {
4346
            isotp_ctx->receive_buffer_len =
4347
                isotp_receive_multi_frame(isotp_ctx);
4348
        } else {
4349
            /* Should never get here */
4350
            isotp_ctx->state = ISOTP_CONN_STATE_IDLE;
4351
            WOLFSSL_MSG("ISO-TP frames out of sequence");
4352
            return WOLFSSL_CBIO_ERR_GENERAL;
4353
        }
4354
        if (isotp_ctx->receive_buffer_len <= 1) {
4355
            isotp_ctx->state = ISOTP_CONN_STATE_IDLE;
4356
            return isotp_ctx->receive_buffer_len;
4357
        } else {
4358
            isotp_ctx->receive_buffer_ptr = isotp_ctx->receive_buffer;
4359
        }
4360
        isotp_ctx->state = ISOTP_CONN_STATE_IDLE;
4361
    }
4362
4363
    /* Return from the buffer */
4364
    if (isotp_ctx->receive_buffer_len >= sz) {
4365
        XMEMCPY(buf, isotp_ctx->receive_buffer_ptr, sz);
4366
        isotp_ctx->receive_buffer_ptr+= sz;
4367
        isotp_ctx->receive_buffer_len-= sz;
4368
        return sz;
4369
    } else {
4370
        XMEMCPY(buf, isotp_ctx->receive_buffer_ptr,
4371
                isotp_ctx->receive_buffer_len);
4372
        sz = isotp_ctx->receive_buffer_len;
4373
        isotp_ctx->receive_buffer_len = 0;
4374
        return sz;
4375
    }
4376
}
4377
4378
int wolfSSL_SetIO_ISOTP(WOLFSSL *ssl, isotp_wolfssl_ctx *ctx,
4379
        can_recv_fn recv_fn, can_send_fn send_fn, can_delay_fn delay_fn,
4380
        word32 receive_delay, char *receive_buffer, int receive_buffer_size,
4381
        void *arg)
4382
{
4383
    if (!ctx || !recv_fn || !send_fn || !delay_fn || !receive_buffer) {
4384
        WOLFSSL_MSG("ISO-TP has missing required parameter");
4385
        return WOLFSSL_CBIO_ERR_GENERAL;
4386
    }
4387
    ctx->recv_fn = recv_fn;
4388
    ctx->send_fn = send_fn;
4389
    ctx->arg = arg;
4390
    ctx->delay_fn = delay_fn;
4391
    ctx->frame_delay = 0;
4392
    ctx->receive_buffer = receive_buffer;
4393
    ctx->receive_buffer_size = receive_buffer_size;
4394
    ctx->receive_buffer_len = 0;
4395
    ctx->state = ISOTP_CONN_STATE_IDLE;
4396
4397
    wolfSSL_SetIOReadCtx(ssl, ctx);
4398
    wolfSSL_SetIOWriteCtx(ssl, ctx);
4399
4400
    /* Delay of 100 - 900us is 0xfX where X is value / 100. Delay of
4401
     * >= 1000 is divided by 1000. > 127ms is invalid */
4402
    if (receive_delay < 1000) {
4403
        ctx->receive_delay = 0xf0 + (receive_delay / 100);
4404
    } else if (receive_delay <= ISOTP_MAX_MS_FRAME_DELAY * 1000) {
4405
        ctx->receive_delay = receive_delay / 1000;
4406
    } else {
4407
        WOLFSSL_MSG("ISO-TP delay parameter out of bounds");
4408
        return WOLFSSL_CBIO_ERR_GENERAL;
4409
    }
4410
    return 0;
4411
}
4412
#endif /* WOLFSSL_ISOTP */
4413
#endif /* WOLFCRYPT_ONLY */