Coverage Report

Created: 2026-08-15 06:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wolfssl/src/ssl_sess.c
Line
Count
Source
1
/* ssl_sess.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
#include <wolfssl/wolfcrypt/libwolfssl_sources.h>
23
24
#if !defined(WOLFSSL_SSL_SESS_INCLUDED)
25
    #ifndef WOLFSSL_IGNORE_FILE_WARN
26
        #warning ssl_sess.c does not need to be compiled separately from ssl.c
27
    #endif
28
#else
29
30
#ifndef NO_SESSION_CACHE
31
32
    /* basic config gives a cache with 33 sessions, adequate for clients and
33
       embedded servers
34
35
       TITAN_SESSION_CACHE allows just over 2 million sessions, for servers
36
       with titanic amounts of memory with long session ID timeouts and high
37
       levels of traffic.
38
39
       ENABLE_SESSION_CACHE_ROW_LOCK: Allows row level locking for increased
40
       performance with large session caches
41
42
       HUGE_SESSION_CACHE yields 65,791 sessions, for servers under heavy load,
43
       allows over 13,000 new sessions per minute or over 200 new sessions per
44
       second
45
46
       BIG_SESSION_CACHE yields 20,027 sessions
47
48
       MEDIUM_SESSION_CACHE allows 1055 sessions, adequate for servers that
49
       aren't under heavy load, basically allows 200 new sessions per minute
50
51
       SMALL_SESSION_CACHE only stores 6 sessions, good for embedded clients
52
       or systems where the default of is too much RAM.
53
       SessionCache takes about 2K, ClientCache takes about 3Kbytes
54
55
       MICRO_SESSION_CACHE only stores 1 session, good for embedded clients
56
       or systems where memory is at a premium.
57
       SessionCache takes about 400 bytes, ClientCache takes 576 bytes
58
59
       default SESSION_CACHE stores 33 sessions (no XXX_SESSION_CACHE defined)
60
       SessionCache takes about 13K bytes, ClientCache takes 17K bytes
61
    */
62
    #if defined(TITAN_SESSION_CACHE)
63
        #define SESSIONS_PER_ROW 31
64
        #define SESSION_ROWS 64937
65
        #ifndef ENABLE_SESSION_CACHE_ROW_LOCK
66
            #define ENABLE_SESSION_CACHE_ROW_LOCK
67
        #endif
68
    #elif defined(HUGE_SESSION_CACHE)
69
        #define SESSIONS_PER_ROW 11
70
        #define SESSION_ROWS 5981
71
    #elif defined(BIG_SESSION_CACHE)
72
        #define SESSIONS_PER_ROW 7
73
        #define SESSION_ROWS 2861
74
    #elif defined(MEDIUM_SESSION_CACHE)
75
        #define SESSIONS_PER_ROW 5
76
        #define SESSION_ROWS 211
77
    #elif defined(SMALL_SESSION_CACHE)
78
        #define SESSIONS_PER_ROW 2
79
        #define SESSION_ROWS 3
80
    #elif defined(MICRO_SESSION_CACHE)
81
        #define SESSIONS_PER_ROW 1
82
        #define SESSION_ROWS 1
83
    #else
84
213k
        #define SESSIONS_PER_ROW 3
85
58.2k
        #define SESSION_ROWS 11
86
    #endif
87
0
    #define INVALID_SESSION_ROW (-1)
88
89
    #ifdef NO_SESSION_CACHE_ROW_LOCK
90
        #undef ENABLE_SESSION_CACHE_ROW_LOCK
91
    #endif
92
93
    typedef struct SessionRow {
94
        int nextIdx;                           /* where to place next one   */
95
        int totalCount;                        /* sessions ever on this row */
96
#ifdef SESSION_CACHE_DYNAMIC_MEM
97
        WOLFSSL_SESSION* Sessions[SESSIONS_PER_ROW];
98
        void* heap;
99
#else
100
        WOLFSSL_SESSION Sessions[SESSIONS_PER_ROW];
101
#endif
102
103
    #ifdef ENABLE_SESSION_CACHE_ROW_LOCK
104
        /* not included in import/export */
105
        wolfSSL_RwLock row_lock;
106
        int lock_valid;
107
    #endif
108
    } SessionRow;
109
    #define SIZEOF_SESSION_ROW (sizeof(WOLFSSL_SESSION) + (sizeof(int) * 2))
110
111
    static WC_THREADSHARED SessionRow SessionCache[SESSION_ROWS];
112
113
    #if defined(WOLFSSL_SESSION_STATS) && defined(WOLFSSL_PEAK_SESSIONS)
114
        static WC_THREADSHARED word32 PeakSessions;
115
    #endif
116
117
    #ifdef ENABLE_SESSION_CACHE_ROW_LOCK
118
    #define SESSION_ROW_RD_LOCK(row)   wc_LockRwLock_Rd(&(row)->row_lock)
119
    #define SESSION_ROW_WR_LOCK(row)   wc_LockRwLock_Wr(&(row)->row_lock)
120
    #define SESSION_ROW_UNLOCK(row)    wc_UnLockRwLock(&(row)->row_lock);
121
    #else
122
    static WC_THREADSHARED wolfSSL_RwLock session_lock; /* SessionCache lock */
123
    static WC_THREADSHARED int session_lock_valid = 0;
124
244
    #define SESSION_ROW_RD_LOCK(row)   wc_LockRwLock_Rd(&session_lock)
125
98
    #define SESSION_ROW_WR_LOCK(row)   wc_LockRwLock_Wr(&session_lock)
126
342
    #define SESSION_ROW_UNLOCK(row)    wc_UnLockRwLock(&session_lock);
127
    #endif
128
129
    #if !defined(NO_SESSION_CACHE_REF) && defined(NO_CLIENT_CACHE)
130
    #error ClientCache is required when not using NO_SESSION_CACHE_REF
131
    #endif
132
133
    #ifndef NO_CLIENT_CACHE
134
135
        #ifndef CLIENT_SESSIONS_MULTIPLIER
136
            #ifdef NO_SESSION_CACHE_REF
137
                #define CLIENT_SESSIONS_MULTIPLIER 1
138
            #else
139
                /* ClientSession objects are lightweight (compared to
140
                 * WOLFSSL_SESSION) so to decrease chance that user will reuse
141
                 * the wrong session, increase the ClientCache size. This will
142
                 * make the entire ClientCache about the size of one
143
                 * WOLFSSL_SESSION object. */
144
0
                #define CLIENT_SESSIONS_MULTIPLIER 8
145
            #endif
146
        #endif
147
        #define CLIENT_SESSIONS_PER_ROW \
148
0
                                (SESSIONS_PER_ROW * CLIENT_SESSIONS_MULTIPLIER)
149
0
        #define CLIENT_SESSION_ROWS (SESSION_ROWS * CLIENT_SESSIONS_MULTIPLIER)
150
151
        #if CLIENT_SESSIONS_PER_ROW > 65535
152
        #error CLIENT_SESSIONS_PER_ROW too big
153
        #endif
154
        #if CLIENT_SESSION_ROWS > 65535
155
        #error CLIENT_SESSION_ROWS too big
156
        #endif
157
158
        struct ClientSession {
159
            word16 serverRow;            /* SessionCache Row id */
160
            word16 serverIdx;            /* SessionCache Idx (column) */
161
            word32 sessionIDHash;
162
        };
163
    #ifndef WOLFSSL_CLIENT_SESSION_DEFINED
164
        typedef struct ClientSession ClientSession;
165
        #define WOLFSSL_CLIENT_SESSION_DEFINED
166
    #endif
167
168
        typedef struct ClientRow {
169
            int nextIdx;                /* where to place next one   */
170
            int totalCount;             /* sessions ever on this row */
171
            ClientSession Clients[CLIENT_SESSIONS_PER_ROW];
172
        } ClientRow;
173
174
        static WC_THREADSHARED ClientRow ClientCache[CLIENT_SESSION_ROWS];
175
                                                     /* Client Cache */
176
                                                     /* uses session mutex */
177
178
        /* ClientCache mutex */
179
        static WC_THREADSHARED wolfSSL_Mutex clisession_mutex
180
            WOLFSSL_MUTEX_INITIALIZER_CLAUSE(clisession_mutex);
181
        #ifndef WOLFSSL_MUTEX_INITIALIZER
182
        static WC_THREADSHARED int clisession_mutex_valid = 0;
183
        #endif
184
    #endif /* !NO_CLIENT_CACHE */
185
186
    void EvictSessionFromCache(WOLFSSL_SESSION* session)
187
158k
    {
188
#ifdef HAVE_EX_DATA
189
        byte save_ownExData = session->ownExData;
190
        session->ownExData = 1; /* Make sure ex_data access doesn't lead back
191
                                 * into the cache. */
192
#endif
193
#if defined(HAVE_EXT_CACHE) || defined(HAVE_EX_DATA)
194
        if (session->rem_sess_cb != NULL) {
195
            session->rem_sess_cb(NULL, session);
196
            session->rem_sess_cb = NULL;
197
        }
198
#endif
199
158k
        ForceZero(session->masterSecret, SECRET_LEN);
200
158k
        XMEMSET(session->sessionID, 0, ID_LEN);
201
158k
        session->sessionIDSz = 0;
202
#ifdef HAVE_SESSION_TICKET
203
        if (session->ticketLenAlloc > 0) {
204
            XFREE(session->ticket, NULL, DYNAMIC_TYPE_SESSION_TICK);
205
            session->ticket = session->staticTicket;
206
            session->ticketLen = 0;
207
            session->ticketLenAlloc = 0;
208
        }
209
#endif
210
#ifdef HAVE_EX_DATA
211
        session->ownExData = save_ownExData;
212
#endif
213
214
#if defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET) &&                  \
215
    defined(WOLFSSL_TICKET_NONCE_MALLOC) &&                                    \
216
    (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3)))
217
        if ((session->ticketNonce.data != NULL) &&
218
            (session->ticketNonce.data != session->ticketNonce.dataStatic))
219
        {
220
            XFREE(session->ticketNonce.data, NULL, DYNAMIC_TYPE_SESSION_TICK);
221
            session->ticketNonce.data = NULL;
222
        }
223
#endif
224
158k
    }
225
226
WOLFSSL_ABI
227
WOLFSSL_SESSION* wolfSSL_get_session(WOLFSSL* ssl)
228
0
{
229
0
    WOLFSSL_ENTER("wolfSSL_get_session");
230
0
    if (ssl) {
231
#ifdef NO_SESSION_CACHE_REF
232
        return ssl->session;
233
#else
234
0
        if (ssl->options.side == WOLFSSL_CLIENT_END) {
235
            /* On the client side we want to return a persistent reference for
236
             * backwards compatibility. */
237
0
#ifndef NO_CLIENT_CACHE
238
0
            if (ssl->clientSession) {
239
0
                return (WOLFSSL_SESSION*)ssl->clientSession;
240
0
            }
241
0
            else {
242
                /* Try to add a ClientCache entry to associate with the current
243
                 * session. Ignore any session cache options. */
244
0
                int err;
245
0
                const byte* id = ssl->session->sessionID;
246
0
                byte idSz = ssl->session->sessionIDSz;
247
0
                if (ssl->session->haveAltSessionID) {
248
0
                    id = ssl->session->altSessionID;
249
0
                    idSz = ID_LEN;
250
0
                }
251
0
                err = AddSessionToCache(ssl->ctx, ssl->session, id, idSz,
252
0
                        NULL, ssl->session->side,
253
                #ifdef HAVE_SESSION_TICKET
254
                        ssl->session->ticketLen > 0,
255
                #else
256
0
                        0,
257
0
                #endif
258
0
                        &ssl->clientSession);
259
0
                if (err == 0) {
260
0
                    return (WOLFSSL_SESSION*)ssl->clientSession;
261
0
                }
262
0
            }
263
0
#endif
264
0
        }
265
0
        else {
266
0
            return ssl->session;
267
0
        }
268
0
#endif
269
0
    }
270
271
0
    return NULL;
272
0
}
273
274
/* The get1 version requires caller to call SSL_SESSION_free */
275
WOLFSSL_SESSION* wolfSSL_get1_session(WOLFSSL* ssl)
276
0
{
277
0
    WOLFSSL_SESSION* sess = NULL;
278
0
    WOLFSSL_ENTER("wolfSSL_get1_session");
279
0
    if (ssl != NULL) {
280
0
        sess = ssl->session;
281
0
        if (sess != NULL) {
282
            /* increase reference count if allocated session */
283
0
            if (sess->type == WOLFSSL_SESSION_TYPE_HEAP) {
284
0
                if (wolfSSL_SESSION_up_ref(sess) != WOLFSSL_SUCCESS)
285
0
                    sess = NULL;
286
0
            }
287
0
        }
288
0
    }
289
0
    return sess;
290
0
}
291
292
/* session is a private struct, return if it is setup or not */
293
int wolfSSL_SessionIsSetup(WOLFSSL_SESSION* session)
294
0
{
295
0
    if (session != NULL)
296
0
        return session->isSetup;
297
0
    return 0;
298
0
}
299
300
/*
301
 * Sets the session object to use when establishing a TLS/SSL session using
302
 * the ssl object. Therefore, this function must be called before
303
 * wolfSSL_connect. The session object to use can be obtained in a previous
304
 * TLS/SSL connection using wolfSSL_get_session.
305
 *
306
 * This function rejects the session if it has been expired when this function
307
 * is called. Note that this expiration check is wolfSSL specific and differs
308
 * from OpenSSL return code behavior.
309
 *
310
 * By default, wolfSSL_set_session returns WOLFSSL_SUCCESS on successfully
311
 * setting the session, WOLFSSL_FAILURE on failure due to the session cache
312
 * being disabled, or the session has expired.
313
 *
314
 * To match OpenSSL return code behavior when session is expired, define
315
 * OPENSSL_EXTRA and WOLFSSL_ERROR_CODE_OPENSSL. This behavior will return
316
 * WOLFSSL_SUCCESS even when the session is expired and rejected.
317
 */
318
WOLFSSL_ABI
319
int wolfSSL_set_session(WOLFSSL* ssl, WOLFSSL_SESSION* session)
320
0
{
321
0
    WOLFSSL_ENTER("wolfSSL_set_session");
322
0
    if (session)
323
0
        return wolfSSL_SetSession(ssl, session);
324
325
0
    return WOLFSSL_FAILURE;
326
0
}
327
328
329
#ifndef NO_CLIENT_CACHE
330
331
/* Associate client session with serverID, find existing or store for saving
332
   if newSession flag on, don't reuse existing session
333
   WOLFSSL_SUCCESS on ok */
334
int wolfSSL_SetServerID(WOLFSSL* ssl, const byte* id, int len, int newSession)
335
0
{
336
0
    WOLFSSL_SESSION* session = NULL;
337
0
    byte idHash[SERVER_ID_LEN];
338
339
0
    WOLFSSL_ENTER("wolfSSL_SetServerID");
340
341
0
    if (ssl == NULL || id == NULL || len <= 0)
342
0
        return BAD_FUNC_ARG;
343
344
0
    if (len > SERVER_ID_LEN) {
345
#if defined(NO_SHA) && !defined(NO_SHA256)
346
        if (wc_Sha256Hash(id, len, idHash) != 0)
347
            return WOLFSSL_FAILURE;
348
#else
349
0
        if (wc_ShaHash(id, (word32)len, idHash) != 0)
350
0
            return WOLFSSL_FAILURE;
351
0
#endif
352
0
        id = idHash;
353
0
        len = SERVER_ID_LEN;
354
0
    }
355
356
0
    if (newSession == 0) {
357
0
        session = wolfSSL_GetSessionClient(ssl, id, len);
358
0
        if (session) {
359
0
            if (wolfSSL_SetSession(ssl, session) != WOLFSSL_SUCCESS) {
360
            #ifdef HAVE_EXT_CACHE
361
                wolfSSL_FreeSession(ssl->ctx, session);
362
            #endif
363
0
                WOLFSSL_MSG("wolfSSL_SetSession failed");
364
0
                session = NULL;
365
0
            }
366
0
        }
367
0
    }
368
369
0
    if (session == NULL) {
370
0
        WOLFSSL_MSG("Valid ServerID not cached already");
371
372
0
        ssl->session->idLen = (word16)len;
373
0
        XMEMCPY(ssl->session->serverID, id, (size_t)len);
374
0
    }
375
#ifdef HAVE_EXT_CACHE
376
    else {
377
        wolfSSL_FreeSession(ssl->ctx, session);
378
    }
379
#endif
380
381
0
    return WOLFSSL_SUCCESS;
382
0
}
383
384
#endif /* !NO_CLIENT_CACHE */
385
386
/* TODO: Add SESSION_CACHE_DYNAMIC_MEM support for PERSIST_SESSION_CACHE.
387
 * Need a count of current sessions to get an accurate memsize (totalCount is
388
 * not decremented when sessions are removed).
389
 * Need to determine ideal layout for mem/filesave.
390
 * Also need mem/filesave checking to ensure not restoring non DYNAMIC_MEM
391
 * cache.
392
 */
393
#if defined(PERSIST_SESSION_CACHE) && !defined(SESSION_CACHE_DYNAMIC_MEM)
394
395
/* for persistence, if changes to layout need to increment and modify
396
   save_session_cache() and restore_session_cache and memory versions too */
397
#define WOLFSSL_CACHE_VERSION 2
398
399
/* Session Cache Header information */
400
typedef struct {
401
    int version;     /* cache layout version id */
402
    int rows;        /* session rows */
403
    int columns;     /* session columns */
404
    int sessionSz;   /* sizeof WOLFSSL_SESSION */
405
} cache_header_t;
406
407
/* current persistence layout is:
408
409
   1) cache_header_t
410
   2) SessionCache
411
   3) ClientCache
412
413
   update WOLFSSL_CACHE_VERSION if change layout for the following
414
   PERSISTENT_SESSION_CACHE functions
415
*/
416
417
/* get how big the the session cache save buffer needs to be */
418
int wolfSSL_get_session_cache_memsize(void)
419
{
420
    int sz  = (int)(sizeof(SessionCache) + sizeof(cache_header_t));
421
#ifndef NO_CLIENT_CACHE
422
    sz += (int)(sizeof(ClientCache));
423
#endif
424
    return sz;
425
}
426
427
428
/* Persist session cache to memory */
429
int wolfSSL_memsave_session_cache(void* mem, int sz)
430
{
431
    int i;
432
    cache_header_t cache_header;
433
    SessionRow*    row;
434
435
    WOLFSSL_ENTER("wolfSSL_memsave_session_cache");
436
437
    if (mem == NULL) {
438
        return BAD_FUNC_ARG;
439
    }
440
441
    row = (SessionRow*)((byte*)mem + sizeof(cache_header));
442
443
    if (sz < wolfSSL_get_session_cache_memsize()) {
444
        WOLFSSL_MSG("Memory buffer too small");
445
        return BUFFER_E;
446
    }
447
448
    cache_header.version   = WOLFSSL_CACHE_VERSION;
449
    cache_header.rows      = SESSION_ROWS;
450
    cache_header.columns   = SESSIONS_PER_ROW;
451
    cache_header.sessionSz = (int)sizeof(WOLFSSL_SESSION);
452
    XMEMCPY(mem, &cache_header, sizeof(cache_header));
453
454
#ifndef ENABLE_SESSION_CACHE_ROW_LOCK
455
    if (SESSION_ROW_RD_LOCK(row) != 0) {
456
        WOLFSSL_MSG("Session cache mutex lock failed");
457
        return BAD_MUTEX_E;
458
    }
459
#endif
460
    for (i = 0; i < cache_header.rows; ++i) {
461
    #ifdef ENABLE_SESSION_CACHE_ROW_LOCK
462
        if (SESSION_ROW_RD_LOCK(&SessionCache[i]) != 0) {
463
            WOLFSSL_MSG("Session row cache mutex lock failed");
464
            return BAD_MUTEX_E;
465
        }
466
    #endif
467
468
        XMEMCPY(row++, &SessionCache[i], SIZEOF_SESSION_ROW);
469
    #ifdef ENABLE_SESSION_CACHE_ROW_LOCK
470
        SESSION_ROW_UNLOCK(&SessionCache[i]);
471
    #endif
472
    }
473
#ifndef ENABLE_SESSION_CACHE_ROW_LOCK
474
    SESSION_ROW_UNLOCK(row);
475
#endif
476
477
#ifndef NO_CLIENT_CACHE
478
    if (wc_LockMutex(&clisession_mutex) != 0) {
479
        WOLFSSL_MSG("Client cache mutex lock failed");
480
        return BAD_MUTEX_E;
481
    }
482
    XMEMCPY(row, ClientCache, sizeof(ClientCache));
483
    wc_UnLockMutex(&clisession_mutex);
484
#endif
485
486
    WOLFSSL_LEAVE("wolfSSL_memsave_session_cache", WOLFSSL_SUCCESS);
487
488
    return WOLFSSL_SUCCESS;
489
}
490
491
492
#if !defined(SESSION_CACHE_DYNAMIC_MEM) && \
493
    (defined(HAVE_SESSION_TICKET) || \
494
    (defined(SESSION_CERTS) && defined(OPENSSL_EXTRA)))
495
static void SessionSanityPointerSet(SessionRow* row)
496
{
497
    int j;
498
499
    /* Reset pointers to safe values after raw copy */
500
    for (j = 0; j < SESSIONS_PER_ROW; j++) {
501
        WOLFSSL_SESSION* s = &row->Sessions[j];
502
#ifdef HAVE_SESSION_TICKET
503
        s->ticket = s->staticTicket;
504
        s->ticketLenAlloc = 0;
505
        if (s->ticketLen > SESSION_TICKET_LEN) {
506
            s->ticketLen = SESSION_TICKET_LEN;
507
        }
508
#endif
509
#if defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET) &&                 \
510
    defined(WOLFSSL_TICKET_NONCE_MALLOC) &&                                    \
511
    (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3)))
512
        s->ticketNonce.data = s->ticketNonce.dataStatic;
513
        if (s->ticketNonce.len > MAX_TICKET_NONCE_STATIC_SZ) {
514
            s->ticketNonce.len = MAX_TICKET_NONCE_STATIC_SZ;
515
        }
516
#endif
517
#if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA)
518
        s->peer = NULL;
519
#endif
520
    }
521
}
522
#endif
523
524
/* Restore the persistent session cache from memory */
525
int wolfSSL_memrestore_session_cache(const void* mem, int sz)
526
{
527
    int    i;
528
    cache_header_t cache_header;
529
    SessionRow*    row;
530
531
    WOLFSSL_ENTER("wolfSSL_memrestore_session_cache");
532
533
    if (mem == NULL) {
534
        return BAD_FUNC_ARG;
535
    }
536
537
    row = (SessionRow*)((byte*)mem + sizeof(cache_header));
538
539
    if (sz < wolfSSL_get_session_cache_memsize()) {
540
        WOLFSSL_MSG("Memory buffer too small");
541
        return BUFFER_E;
542
    }
543
544
    XMEMCPY(&cache_header, mem, sizeof(cache_header));
545
    if (cache_header.version   != WOLFSSL_CACHE_VERSION ||
546
        cache_header.rows      != SESSION_ROWS ||
547
        cache_header.columns   != SESSIONS_PER_ROW ||
548
        cache_header.sessionSz != (int)sizeof(WOLFSSL_SESSION)) {
549
550
        WOLFSSL_MSG("Session cache header match failed");
551
        return CACHE_MATCH_ERROR;
552
    }
553
554
#ifndef ENABLE_SESSION_CACHE_ROW_LOCK
555
    if (SESSION_ROW_WR_LOCK(&SessionCache[0]) != 0) {
556
        WOLFSSL_MSG("Session cache mutex lock failed");
557
        return BAD_MUTEX_E;
558
    }
559
#endif
560
    for (i = 0; i < cache_header.rows; ++i) {
561
    #ifdef ENABLE_SESSION_CACHE_ROW_LOCK
562
        if (SESSION_ROW_WR_LOCK(&SessionCache[i]) != 0) {
563
            WOLFSSL_MSG("Session row cache mutex lock failed");
564
            return BAD_MUTEX_E;
565
        }
566
    #endif
567
568
        XMEMCPY(&SessionCache[i], row++, SIZEOF_SESSION_ROW);
569
    #if !defined(SESSION_CACHE_DYNAMIC_MEM) && \
570
        (defined(HAVE_SESSION_TICKET) || \
571
        (defined(SESSION_CERTS) && defined(OPENSSL_EXTRA)))
572
        SessionSanityPointerSet(&SessionCache[i]);
573
    #endif
574
    #ifdef ENABLE_SESSION_CACHE_ROW_LOCK
575
        SESSION_ROW_UNLOCK(&SessionCache[i]);
576
    #endif
577
    }
578
#ifndef ENABLE_SESSION_CACHE_ROW_LOCK
579
    SESSION_ROW_UNLOCK(&SessionCache[0]);
580
#endif
581
582
#ifndef NO_CLIENT_CACHE
583
    if (wc_LockMutex(&clisession_mutex) != 0) {
584
        WOLFSSL_MSG("Client cache mutex lock failed");
585
        return BAD_MUTEX_E;
586
    }
587
    XMEMCPY(ClientCache, row, sizeof(ClientCache));
588
    wc_UnLockMutex(&clisession_mutex);
589
#endif
590
591
    WOLFSSL_LEAVE("wolfSSL_memrestore_session_cache", WOLFSSL_SUCCESS);
592
593
    return WOLFSSL_SUCCESS;
594
}
595
596
#if !defined(NO_FILESYSTEM)
597
598
/* Persist session cache to file */
599
/* doesn't use memsave because of additional memory use */
600
int wolfSSL_save_session_cache(const char *fname)
601
{
602
    XFILE  file;
603
    int    ret;
604
    int    rc = WOLFSSL_SUCCESS;
605
    int    i;
606
    cache_header_t cache_header;
607
608
    WOLFSSL_ENTER("wolfSSL_save_session_cache");
609
610
    file = XFOPEN(fname, "w+b");
611
    if (file == XBADFILE) {
612
        WOLFSSL_MSG("Couldn't open session cache save file");
613
        return WOLFSSL_BAD_FILE;
614
    }
615
    cache_header.version   = WOLFSSL_CACHE_VERSION;
616
    cache_header.rows      = SESSION_ROWS;
617
    cache_header.columns   = SESSIONS_PER_ROW;
618
    cache_header.sessionSz = (int)sizeof(WOLFSSL_SESSION);
619
620
    /* cache header */
621
    ret = (int)XFWRITE(&cache_header, sizeof cache_header, 1, file);
622
    if (ret != 1) {
623
        WOLFSSL_MSG("Session cache header file write failed");
624
        XFCLOSE(file);
625
        return FWRITE_ERROR;
626
    }
627
628
#ifndef ENABLE_SESSION_CACHE_ROW_LOCK
629
    if (SESSION_ROW_RD_LOCK(&SessionCache[0]) != 0) {
630
        WOLFSSL_MSG("Session cache mutex lock failed");
631
        XFCLOSE(file);
632
        return BAD_MUTEX_E;
633
    }
634
#endif
635
    /* session cache */
636
    for (i = 0; i < cache_header.rows; ++i) {
637
    #ifdef ENABLE_SESSION_CACHE_ROW_LOCK
638
        if (SESSION_ROW_RD_LOCK(&SessionCache[i]) != 0) {
639
            WOLFSSL_MSG("Session row cache mutex lock failed");
640
            XFCLOSE(file);
641
            return BAD_MUTEX_E;
642
        }
643
    #endif
644
645
        ret = (int)XFWRITE(&SessionCache[i], SIZEOF_SESSION_ROW, 1, file);
646
    #ifdef ENABLE_SESSION_CACHE_ROW_LOCK
647
        SESSION_ROW_UNLOCK(&SessionCache[i]);
648
    #endif
649
        if (ret != 1) {
650
            WOLFSSL_MSG("Session cache member file write failed");
651
            rc = FWRITE_ERROR;
652
            break;
653
        }
654
    }
655
#ifndef ENABLE_SESSION_CACHE_ROW_LOCK
656
    SESSION_ROW_UNLOCK(&SessionCache[0]);
657
#endif
658
659
#ifndef NO_CLIENT_CACHE
660
    /* client cache */
661
    if (wc_LockMutex(&clisession_mutex) != 0) {
662
        WOLFSSL_MSG("Client cache mutex lock failed");
663
        XFCLOSE(file);
664
        return BAD_MUTEX_E;
665
    }
666
    ret = (int)XFWRITE(ClientCache, sizeof(ClientCache), 1, file);
667
    if (ret != 1) {
668
        WOLFSSL_MSG("Client cache member file write failed");
669
        rc = FWRITE_ERROR;
670
    }
671
    wc_UnLockMutex(&clisession_mutex);
672
#endif /* !NO_CLIENT_CACHE */
673
674
    XFCLOSE(file);
675
    WOLFSSL_LEAVE("wolfSSL_save_session_cache", rc);
676
677
    return rc;
678
}
679
680
681
/* Restore the persistent session cache from file */
682
/* doesn't use memstore because of additional memory use */
683
int wolfSSL_restore_session_cache(const char *fname)
684
{
685
    XFILE  file;
686
    int    rc = WOLFSSL_SUCCESS;
687
    int    ret;
688
    int    i;
689
    cache_header_t cache_header;
690
691
    WOLFSSL_ENTER("wolfSSL_restore_session_cache");
692
693
    file = XFOPEN(fname, "rb");
694
    if (file == XBADFILE) {
695
        WOLFSSL_MSG("Couldn't open session cache save file");
696
        return WOLFSSL_BAD_FILE;
697
    }
698
    /* cache header */
699
    ret = (int)XFREAD(&cache_header, sizeof(cache_header), 1, file);
700
    if (ret != 1) {
701
        WOLFSSL_MSG("Session cache header file read failed");
702
        XFCLOSE(file);
703
        return FREAD_ERROR;
704
    }
705
    if (cache_header.version   != WOLFSSL_CACHE_VERSION ||
706
        cache_header.rows      != SESSION_ROWS ||
707
        cache_header.columns   != SESSIONS_PER_ROW ||
708
        cache_header.sessionSz != (int)sizeof(WOLFSSL_SESSION)) {
709
710
        WOLFSSL_MSG("Session cache header match failed");
711
        XFCLOSE(file);
712
        return CACHE_MATCH_ERROR;
713
    }
714
715
#ifndef ENABLE_SESSION_CACHE_ROW_LOCK
716
    if (SESSION_ROW_WR_LOCK(&SessionCache[0]) != 0) {
717
        WOLFSSL_MSG("Session cache mutex lock failed");
718
        XFCLOSE(file);
719
        return BAD_MUTEX_E;
720
    }
721
#endif
722
    /* session cache */
723
    for (i = 0; i < cache_header.rows; ++i) {
724
    #ifdef ENABLE_SESSION_CACHE_ROW_LOCK
725
        if (SESSION_ROW_WR_LOCK(&SessionCache[i]) != 0) {
726
            WOLFSSL_MSG("Session row cache mutex lock failed");
727
            XFCLOSE(file);
728
            return BAD_MUTEX_E;
729
        }
730
    #endif
731
732
        ret = (int)XFREAD(&SessionCache[i], SIZEOF_SESSION_ROW, 1, file);
733
    #if !defined(SESSION_CACHE_DYNAMIC_MEM) && \
734
        (defined(HAVE_SESSION_TICKET) || \
735
        (defined(SESSION_CERTS) && defined(OPENSSL_EXTRA)))
736
        SessionSanityPointerSet(&SessionCache[i]);
737
    #endif
738
    #ifdef ENABLE_SESSION_CACHE_ROW_LOCK
739
        SESSION_ROW_UNLOCK(&SessionCache[i]);
740
    #endif
741
        if (ret != 1) {
742
            WOLFSSL_MSG("Session cache member file read failed");
743
            XMEMSET(SessionCache, 0, sizeof SessionCache);
744
            rc = FREAD_ERROR;
745
            break;
746
        }
747
    }
748
#ifndef ENABLE_SESSION_CACHE_ROW_LOCK
749
    SESSION_ROW_UNLOCK(&SessionCache[0]);
750
#endif
751
752
#ifndef NO_CLIENT_CACHE
753
    /* client cache */
754
    if (wc_LockMutex(&clisession_mutex) != 0) {
755
        WOLFSSL_MSG("Client cache mutex lock failed");
756
        XFCLOSE(file);
757
        return BAD_MUTEX_E;
758
    }
759
    ret = (int)XFREAD(ClientCache, sizeof(ClientCache), 1, file);
760
    if (ret != 1) {
761
        WOLFSSL_MSG("Client cache member file read failed");
762
        XMEMSET(ClientCache, 0, sizeof ClientCache);
763
        rc = FREAD_ERROR;
764
    }
765
    wc_UnLockMutex(&clisession_mutex);
766
#endif /* !NO_CLIENT_CACHE */
767
768
    XFCLOSE(file);
769
    WOLFSSL_LEAVE("wolfSSL_restore_session_cache", rc);
770
771
    return rc;
772
}
773
774
#endif /* !NO_FILESYSTEM */
775
#endif /* PERSIST_SESSION_CACHE && !SESSION_CACHE_DYNAMIC_MEM */
776
777
778
/* on by default if built in but allow user to turn off */
779
WOLFSSL_ABI
780
long wolfSSL_CTX_set_session_cache_mode(WOLFSSL_CTX* ctx, long mode)
781
0
{
782
0
    WOLFSSL_ENTER("wolfSSL_CTX_set_session_cache_mode");
783
784
0
    if (ctx == NULL)
785
0
        return WOLFSSL_FAILURE;
786
787
0
    if (mode == WOLFSSL_SESS_CACHE_OFF) {
788
0
        ctx->sessionCacheOff = 1;
789
#ifdef HAVE_EXT_CACHE
790
        ctx->internalCacheOff = 1;
791
        ctx->internalCacheLookupOff = 1;
792
#endif
793
0
    }
794
795
0
    if ((mode & WOLFSSL_SESS_CACHE_NO_AUTO_CLEAR) != 0)
796
0
        ctx->sessionCacheFlushOff = 1;
797
798
#ifdef HAVE_EXT_CACHE
799
    /* WOLFSSL_SESS_CACHE_NO_INTERNAL activates both if's */
800
    if ((mode & WOLFSSL_SESS_CACHE_NO_INTERNAL_STORE) != 0)
801
        ctx->internalCacheOff = 1;
802
    if ((mode & WOLFSSL_SESS_CACHE_NO_INTERNAL_LOOKUP) != 0)
803
        ctx->internalCacheLookupOff = 1;
804
#endif
805
806
0
    return WOLFSSL_SUCCESS;
807
0
}
808
809
#ifdef OPENSSL_EXTRA
810
#ifdef HAVE_MAX_FRAGMENT
811
/* return the max fragment size set when handshake was negotiated */
812
unsigned char wolfSSL_SESSION_get_max_fragment_length(WOLFSSL_SESSION* session)
813
{
814
    session = ClientSessionToSession(session);
815
    if (session == NULL) {
816
        return 0;
817
    }
818
819
    return session->mfl;
820
}
821
#endif
822
823
824
/* Get the session cache mode for CTX
825
 *
826
 * ctx  WOLFSSL_CTX struct to get cache mode from
827
 *
828
 * Returns a bit mask that has the session cache mode */
829
long wolfSSL_CTX_get_session_cache_mode(WOLFSSL_CTX* ctx)
830
{
831
    long m = 0;
832
833
    WOLFSSL_ENTER("wolfSSL_CTX_get_session_cache_mode");
834
835
    if (ctx == NULL) {
836
        return m;
837
    }
838
839
    if (ctx->sessionCacheOff != 1) {
840
        m |= WOLFSSL_SESS_CACHE_SERVER;
841
    }
842
843
    if (ctx->sessionCacheFlushOff == 1) {
844
        m |= WOLFSSL_SESS_CACHE_NO_AUTO_CLEAR;
845
    }
846
847
#ifdef HAVE_EXT_CACHE
848
    if (ctx->internalCacheOff == 1) {
849
        m |= WOLFSSL_SESS_CACHE_NO_INTERNAL_STORE;
850
    }
851
    if (ctx->internalCacheLookupOff == 1) {
852
        m |= WOLFSSL_SESS_CACHE_NO_INTERNAL_LOOKUP;
853
    }
854
#endif
855
856
    return m;
857
}
858
#endif /* OPENSSL_EXTRA */
859
860
#endif /* !NO_SESSION_CACHE */
861
862
#ifndef NO_SESSION_CACHE
863
864
WOLFSSL_ABI
865
void wolfSSL_flush_sessions(WOLFSSL_CTX* ctx, long tm)
866
0
{
867
    /* static table now, no flushing needed */
868
0
    (void)ctx;
869
0
    (void)tm;
870
0
}
871
872
void wolfSSL_CTX_flush_sessions(WOLFSSL_CTX* ctx, long tm)
873
0
{
874
0
    int i, j;
875
876
0
    (void)ctx;
877
0
    WOLFSSL_ENTER("wolfSSL_flush_sessions");
878
0
    for (i = 0; i < SESSION_ROWS; ++i) {
879
0
        if (SESSION_ROW_WR_LOCK(&SessionCache[i]) != 0) {
880
0
            WOLFSSL_MSG("Session cache mutex lock failed");
881
0
            return;
882
0
        }
883
0
        for (j = 0; j < SESSIONS_PER_ROW; j++) {
884
#ifdef SESSION_CACHE_DYNAMIC_MEM
885
            WOLFSSL_SESSION* s = SessionCache[i].Sessions[j];
886
#else
887
0
            WOLFSSL_SESSION* s = &SessionCache[i].Sessions[j];
888
0
#endif
889
0
            if (
890
#ifdef SESSION_CACHE_DYNAMIC_MEM
891
                s != NULL &&
892
#endif
893
0
                s->sessionIDSz > 0 &&
894
0
                s->bornOn + s->timeout < (word32)tm
895
0
                )
896
0
            {
897
0
                EvictSessionFromCache(s);
898
#ifdef SESSION_CACHE_DYNAMIC_MEM
899
                XFREE(s, s->heap, DYNAMIC_TYPE_SESSION);
900
                SessionCache[i].Sessions[j] = NULL;
901
#endif
902
0
            }
903
0
        }
904
0
        SESSION_ROW_UNLOCK(&SessionCache[i]);
905
0
    }
906
0
}
907
908
909
/* set ssl session timeout in seconds */
910
WOLFSSL_ABI
911
int wolfSSL_set_timeout(WOLFSSL* ssl, unsigned int to)
912
0
{
913
0
    if (ssl == NULL)
914
0
        return BAD_FUNC_ARG;
915
916
0
    if (to == 0)
917
0
        to = WOLFSSL_SESSION_TIMEOUT;
918
0
    ssl->timeout = to;
919
920
0
    return WOLFSSL_SUCCESS;
921
0
}
922
923
#ifndef NO_TLS
924
/**
925
 * Sets ctx session timeout in seconds.
926
 * The timeout value set here should be reflected in the
927
 * "session ticket lifetime hint" if this API works in the openssl compat-layer.
928
 * Therefore wolfSSL_CTX_set_TicketHint is called internally.
929
 * Arguments:
930
 *  - ctx  WOLFSSL_CTX object which the timeout is set to
931
 *  - to   timeout value in second
932
 * Returns:
933
 *  WOLFSSL_SUCCESS on success, BAD_FUNC_ARG on failure.
934
 *  When WOLFSSL_ERROR_CODE_OPENSSL is defined, returns previous timeout value
935
 *  on success, BAD_FUNC_ARG on failure.
936
 */
937
WOLFSSL_ABI
938
int wolfSSL_CTX_set_timeout(WOLFSSL_CTX* ctx, unsigned int to)
939
0
{
940
    #if defined(WOLFSSL_ERROR_CODE_OPENSSL)
941
    word32 prev_timeout = 0;
942
    #endif
943
944
0
    int ret = WOLFSSL_SUCCESS;
945
0
    (void)ret;
946
947
0
    if (ctx == NULL)
948
0
        ret = BAD_FUNC_ARG;
949
950
0
    if (ret == WOLFSSL_SUCCESS) {
951
    #if defined(WOLFSSL_ERROR_CODE_OPENSSL)
952
        prev_timeout = ctx->timeout;
953
    #endif
954
0
        if (to == 0) {
955
0
            ctx->timeout = WOLFSSL_SESSION_TIMEOUT;
956
0
        }
957
0
        else {
958
0
            ctx->timeout = to;
959
0
        }
960
0
    }
961
#if defined(OPENSSL_EXTRA) && defined(HAVE_SESSION_TICKET) && \
962
   !defined(NO_WOLFSSL_SERVER)
963
    if (ret == WOLFSSL_SUCCESS) {
964
        if (to == 0) {
965
            ret = wolfSSL_CTX_set_TicketHint(ctx, SESSION_TICKET_HINT_DEFAULT);
966
        }
967
        else {
968
            ret = wolfSSL_CTX_set_TicketHint(ctx, (int)to);
969
        }
970
    }
971
#endif /* OPENSSL_EXTRA && HAVE_SESSION_TICKET && !NO_WOLFSSL_SERVER */
972
973
#if defined(WOLFSSL_ERROR_CODE_OPENSSL)
974
    if (ret == WOLFSSL_SUCCESS) {
975
        return (int)prev_timeout;
976
    }
977
    else {
978
        return ret;
979
    }
980
#else
981
0
    return ret;
982
0
#endif /* WOLFSSL_ERROR_CODE_OPENSSL */
983
0
}
984
#endif /* !NO_TLS */
985
986
#ifndef NO_CLIENT_CACHE
987
988
/* Get Session from Client cache based on id/len, return NULL on failure */
989
WOLFSSL_SESSION* wolfSSL_GetSessionClient(WOLFSSL* ssl, const byte* id, int len)
990
0
{
991
0
    WOLFSSL_SESSION* ret = NULL;
992
0
    word32          row;
993
0
    int             idx;
994
0
    int             count;
995
0
    int             error = 0;
996
0
    ClientSession*  clSess;
997
998
0
    WOLFSSL_ENTER("wolfSSL_GetSessionClient");
999
1000
0
    if (ssl->ctx->sessionCacheOff) {
1001
0
        WOLFSSL_MSG("Session Cache off");
1002
0
        return NULL;
1003
0
    }
1004
1005
0
    if (ssl->options.side == WOLFSSL_SERVER_END)
1006
0
        return NULL;
1007
1008
0
    len = (int)min(SERVER_ID_LEN, (word32)len);
1009
1010
    /* Do not access ssl->ctx->get_sess_cb from here. It is using a different
1011
     * set of ID's */
1012
1013
0
    row = HashObject(id, (word32)len, &error) % CLIENT_SESSION_ROWS;
1014
0
    if (error != 0) {
1015
0
        WOLFSSL_MSG("Hash session failed");
1016
0
        return NULL;
1017
0
    }
1018
1019
0
    if (wc_LockMutex(&clisession_mutex) != 0) {
1020
0
        WOLFSSL_MSG("Client cache mutex lock failed");
1021
0
        return NULL;
1022
0
    }
1023
1024
    /* start from most recently used */
1025
0
    count = (int)min((word32)ClientCache[row].totalCount,
1026
0
        CLIENT_SESSIONS_PER_ROW);
1027
0
    idx = ClientCache[row].nextIdx - 1;
1028
0
    if (idx < 0 || idx >= CLIENT_SESSIONS_PER_ROW) {
1029
        /* if back to front, the previous was end */
1030
0
        idx = CLIENT_SESSIONS_PER_ROW - 1;
1031
0
    }
1032
0
    clSess = ClientCache[row].Clients;
1033
1034
0
    for (; count > 0; --count) {
1035
0
        WOLFSSL_SESSION* current;
1036
0
        SessionRow* sessRow;
1037
1038
0
        if (clSess[idx].serverRow >= SESSION_ROWS) {
1039
0
            WOLFSSL_MSG("Client cache serverRow invalid");
1040
0
            break;
1041
0
        }
1042
1043
        /* lock row */
1044
0
        sessRow = &SessionCache[clSess[idx].serverRow];
1045
0
        if (SESSION_ROW_RD_LOCK(sessRow) != 0) {
1046
0
            WOLFSSL_MSG("Session cache row lock failure");
1047
0
            break;
1048
0
        }
1049
1050
#ifdef SESSION_CACHE_DYNAMIC_MEM
1051
        current = sessRow->Sessions[clSess[idx].serverIdx];
1052
#else
1053
0
        current = &sessRow->Sessions[clSess[idx].serverIdx];
1054
0
#endif
1055
0
        if (current && XMEMCMP(current->serverID, id,
1056
0
                                                     (unsigned long)len) == 0) {
1057
0
            WOLFSSL_MSG("Found a serverid match for client");
1058
0
            if (LowResTimer() < (current->bornOn + current->timeout)) {
1059
0
                WOLFSSL_MSG("Session valid");
1060
0
                ret = current;
1061
0
                SESSION_ROW_UNLOCK(sessRow);
1062
0
                break;
1063
0
            } else {
1064
0
                WOLFSSL_MSG("Session timed out");  /* could have more for id */
1065
0
            }
1066
0
        } else {
1067
0
            WOLFSSL_MSG("ServerID not a match from client table");
1068
0
        }
1069
0
        SESSION_ROW_UNLOCK(sessRow);
1070
1071
0
        idx = idx > 0 ? idx - 1 : CLIENT_SESSIONS_PER_ROW - 1;
1072
0
    }
1073
1074
0
    wc_UnLockMutex(&clisession_mutex);
1075
1076
0
    return ret;
1077
0
}
1078
1079
#endif /* !NO_CLIENT_CACHE */
1080
1081
static int SslSessionCacheOff(const WOLFSSL* ssl,
1082
    const WOLFSSL_SESSION* session)
1083
{
1084
    (void)session;
1085
    return ssl->options.sessionCacheOff
1086
    #if defined(HAVE_SESSION_TICKET) && defined(WOLFSSL_FORCE_CACHE_ON_TICKET)
1087
                && session->ticketLen == 0
1088
    #endif
1089
                ;
1090
}
1091
1092
#if defined(HAVE_SESSION_TICKET) && defined(WOLFSSL_TLS13) &&                  \
1093
    defined(WOLFSSL_TICKET_NONCE_MALLOC) && \
1094
    (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3)))
1095
/**
1096
 * SessionTicketNoncePrealloc() - prealloc a buffer for ticket nonces
1097
 * @output: [in] pointer to WOLFSSL_SESSION object that will soon be a
1098
 * destination of a session duplication
1099
 * @buf: [out] address of the preallocated buf
1100
 * @len: [out] len of the preallocated buf
1101
 *
1102
 * prealloc a buffer that will likely suffice to contain a ticket nonce. It's
1103
 * used when copying session under lock, when syscalls need to be avoided. If
1104
 * output already has a dynamic buffer, it's reused.
1105
 */
1106
static int SessionTicketNoncePrealloc(byte** buf, byte* len, void *heap)
1107
{
1108
    (void)heap;
1109
1110
    *buf = (byte*)XMALLOC(PREALLOC_SESSION_TICKET_NONCE_LEN, heap,
1111
        DYNAMIC_TYPE_SESSION_TICK);
1112
    if (*buf == NULL) {
1113
        WOLFSSL_MSG("Failed to preallocate ticket nonce buffer");
1114
        *len = 0;
1115
        return 1;
1116
    }
1117
1118
    *len = PREALLOC_SESSION_TICKET_NONCE_LEN;
1119
    return 0;
1120
}
1121
#endif /* HAVE_SESSION_TICKET && WOLFSSL_TLS13 */
1122
1123
static int wolfSSL_DupSessionEx(const WOLFSSL_SESSION* input,
1124
    WOLFSSL_SESSION* output, int avoidSysCalls, int transferExData,
1125
    byte* ticketNonceBuf, byte* ticketNonceLen, byte* preallocUsed);
1126
1127
void TlsSessionCacheUnlockRow(word32 row)
1128
0
{
1129
0
    SessionRow* sessRow;
1130
1131
0
    sessRow = &SessionCache[row];
1132
0
    (void)sessRow;
1133
0
    SESSION_ROW_UNLOCK(sessRow);
1134
0
}
1135
1136
/* Don't use this function directly. Use TlsSessionCacheGetAndRdLock and
1137
 * TlsSessionCacheGetAndWrLock to fully utilize compiler const support. */
1138
static int TlsSessionCacheGetAndLock(const byte *id,
1139
    const WOLFSSL_SESSION **sess, word32 *lockedRow, byte readOnly, byte side)
1140
355
{
1141
355
    SessionRow *sessRow;
1142
355
    const WOLFSSL_SESSION *s;
1143
355
    word32 row;
1144
355
    int count;
1145
355
    int error;
1146
355
    int idx;
1147
1148
355
    *sess = NULL;
1149
355
    row = HashObject(id, ID_LEN, &error) % SESSION_ROWS;
1150
355
    if (error != 0)
1151
13
        return error;
1152
342
    sessRow = &SessionCache[row];
1153
342
    if (readOnly)
1154
244
        error = SESSION_ROW_RD_LOCK(sessRow);
1155
98
    else
1156
98
        error = SESSION_ROW_WR_LOCK(sessRow);
1157
342
    if (error != 0)
1158
0
        return FATAL_ERROR;
1159
1160
    /* start from most recently used */
1161
342
    count = (int)min((word32)sessRow->totalCount, SESSIONS_PER_ROW);
1162
342
    idx = sessRow->nextIdx - 1;
1163
342
    if (idx < 0 || idx >= SESSIONS_PER_ROW) {
1164
342
        idx = SESSIONS_PER_ROW - 1; /* if back to front, the previous was end */
1165
342
    }
1166
342
    for (; count > 0; --count) {
1167
#ifdef SESSION_CACHE_DYNAMIC_MEM
1168
        s = sessRow->Sessions[idx];
1169
#else
1170
0
        s = &sessRow->Sessions[idx];
1171
0
#endif
1172
        /* match session ID value and length */
1173
0
        if (s && s->sessionIDSz == ID_LEN && s->side == side &&
1174
0
                XMEMCMP(s->sessionID, id, ID_LEN) == 0) {
1175
0
            *sess = s;
1176
0
            break;
1177
0
        }
1178
0
        idx = idx > 0 ? idx - 1 : SESSIONS_PER_ROW - 1;
1179
0
    }
1180
342
    if (*sess == NULL) {
1181
342
        SESSION_ROW_UNLOCK(sessRow);
1182
342
    }
1183
0
    else {
1184
0
        *lockedRow = row;
1185
0
    }
1186
1187
342
    return 0;
1188
342
}
1189
1190
static int CheckSessionMatch(const WOLFSSL* ssl, const WOLFSSL_SESSION* sess)
1191
0
{
1192
0
    if (ssl == NULL || sess == NULL)
1193
0
        return 0;
1194
#ifdef OPENSSL_EXTRA
1195
    if (ssl->sessionCtxSz > 0 && (ssl->sessionCtxSz != sess->sessionCtxSz ||
1196
           XMEMCMP(ssl->sessionCtx, sess->sessionCtx, sess->sessionCtxSz) != 0))
1197
        return 0;
1198
#endif
1199
0
    if (IsAtLeastTLSv1_3(ssl->version) != IsAtLeastTLSv1_3(sess->version))
1200
0
        return 0;
1201
0
    return 1;
1202
0
}
1203
1204
int TlsSessionCacheGetAndRdLock(const byte *id, const WOLFSSL_SESSION **sess,
1205
        word32 *lockedRow, byte side)
1206
246
{
1207
246
    return TlsSessionCacheGetAndLock(id, sess, lockedRow, 1, side);
1208
246
}
1209
1210
int TlsSessionCacheGetAndWrLock(const byte *id, WOLFSSL_SESSION **sess,
1211
        word32 *lockedRow, byte side)
1212
109
{
1213
109
    return TlsSessionCacheGetAndLock(id, (const WOLFSSL_SESSION**)sess,
1214
109
            lockedRow, 0, side);
1215
109
}
1216
1217
int wolfSSL_GetSessionFromCache(WOLFSSL* ssl, WOLFSSL_SESSION* output)
1218
{
1219
    const WOLFSSL_SESSION* sess = NULL;
1220
    const byte*  id = NULL;
1221
    word32       row;
1222
    int          error = 0;
1223
#ifdef HAVE_SESSION_TICKET
1224
    WC_DECLARE_VAR(tmpTicket, byte, PREALLOC_SESSION_TICKET_LEN, 0);
1225
#ifdef WOLFSSL_TLS13
1226
    byte *preallocNonce = NULL;
1227
    byte preallocNonceLen = 0;
1228
    byte preallocNonceUsed = 0;
1229
#endif /* WOLFSSL_TLS13 */
1230
    byte         tmpBufSet = 0;
1231
#endif
1232
    byte         bogusID[ID_LEN];
1233
    byte         bogusIDSz = 0;
1234
1235
    WOLFSSL_ENTER("wolfSSL_GetSessionFromCache");
1236
1237
    if (output == NULL) {
1238
        WOLFSSL_MSG("NULL output");
1239
        return WOLFSSL_FAILURE;
1240
    }
1241
1242
    if (SslSessionCacheOff(ssl, ssl->session))
1243
        return WOLFSSL_FAILURE;
1244
1245
    if (ssl->options.haveSessionId == 0 && !ssl->session->haveAltSessionID)
1246
        return WOLFSSL_FAILURE;
1247
1248
#ifdef HAVE_SESSION_TICKET
1249
    if (ssl->options.side == WOLFSSL_SERVER_END && ssl->options.useTicket == 1)
1250
        return WOLFSSL_FAILURE;
1251
#endif
1252
1253
    XMEMSET(bogusID, 0, sizeof(bogusID));
1254
    if (!IsAtLeastTLSv1_3(ssl->version) && ssl->arrays != NULL
1255
            && !ssl->session->haveAltSessionID)
1256
        id = ssl->arrays->sessionID;
1257
    else if (ssl->session->haveAltSessionID) {
1258
        id = ssl->session->altSessionID;
1259
        /* We want to restore the bogus ID for TLS compatibility */
1260
        if (output == ssl->session) {
1261
            XMEMCPY(bogusID, ssl->session->sessionID, ID_LEN);
1262
            bogusIDSz = ssl->session->sessionIDSz;
1263
        }
1264
    }
1265
    else
1266
        id = ssl->session->sessionID;
1267
1268
1269
#ifdef HAVE_EXT_CACHE
1270
    if (ssl->ctx->get_sess_cb != NULL) {
1271
        int copy = 0;
1272
        int found = 0;
1273
        WOLFSSL_SESSION* extSess;
1274
        /* Attempt to retrieve the session from the external cache. */
1275
        WOLFSSL_MSG("Calling external session cache");
1276
        extSess = ssl->ctx->get_sess_cb(ssl, (byte*)id, ID_LEN, &copy);
1277
        if ((extSess != NULL)
1278
                && CheckSessionMatch(ssl, extSess)
1279
            ) {
1280
            WOLFSSL_MSG("Session found in external cache");
1281
            found = 1;
1282
1283
            error = wolfSSL_DupSession(extSess, output, 0);
1284
#ifdef HAVE_EX_DATA
1285
            extSess->ownExData = 1;
1286
            output->ownExData = 0;
1287
#endif
1288
            /* We want to restore the bogus ID for TLS compatibility */
1289
            if (ssl->session->haveAltSessionID &&
1290
                    output == ssl->session) {
1291
                XMEMCPY(ssl->session->sessionID, bogusID, ID_LEN);
1292
                ssl->session->sessionIDSz = bogusIDSz;
1293
            }
1294
        }
1295
        /* If copy not set then free immediately */
1296
        if (extSess != NULL && !copy)
1297
            wolfSSL_FreeSession(ssl->ctx, extSess);
1298
        if (found)
1299
            return error;
1300
        WOLFSSL_MSG("Session not found in external cache");
1301
    }
1302
1303
    if (ssl->options.internalCacheLookupOff) {
1304
        WOLFSSL_MSG("Internal cache lookup turned off");
1305
        return WOLFSSL_FAILURE;
1306
    }
1307
#endif
1308
1309
#ifdef HAVE_SESSION_TICKET
1310
    if (output->ticket == NULL ||
1311
            output->ticketLenAlloc < PREALLOC_SESSION_TICKET_LEN) {
1312
#ifdef WOLFSSL_SMALL_STACK
1313
        tmpTicket = (byte*)XMALLOC(PREALLOC_SESSION_TICKET_LEN, output->heap,
1314
                DYNAMIC_TYPE_TMP_BUFFER);
1315
        if (tmpTicket == NULL) {
1316
            WOLFSSL_MSG("tmpTicket malloc failed");
1317
            return WOLFSSL_FAILURE;
1318
        }
1319
#endif
1320
        if (output->ticketLenAlloc)
1321
            XFREE(output->ticket, output->heap, DYNAMIC_TYPE_SESSION_TICK);
1322
        /* cppcheck-suppress autoVariables */
1323
        output->ticket = tmpTicket;
1324
        output->ticketLenAlloc = PREALLOC_SESSION_TICKET_LEN;
1325
        output->ticketLen = 0;
1326
        tmpBufSet = 1;
1327
    }
1328
#endif
1329
1330
#if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA)
1331
    if (output->peer != NULL) {
1332
        wolfSSL_X509_free(output->peer);
1333
        output->peer = NULL;
1334
    }
1335
#endif
1336
1337
#if defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET) &&                  \
1338
    defined(WOLFSSL_TICKET_NONCE_MALLOC) &&                                    \
1339
    (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3)))
1340
    if (output->ticketNonce.data != output->ticketNonce.dataStatic) {
1341
        XFREE(output->ticketNonce.data, output->heap,
1342
            DYNAMIC_TYPE_SESSION_TICK);
1343
        output->ticketNonce.data = output->ticketNonce.dataStatic;
1344
        output->ticketNonce.len = 0;
1345
    }
1346
    error = SessionTicketNoncePrealloc(&preallocNonce, &preallocNonceLen,
1347
        output->heap);
1348
    if (error != 0) {
1349
        if (tmpBufSet) {
1350
            output->ticket = output->staticTicket;
1351
            output->ticketLenAlloc = 0;
1352
        }
1353
        WC_FREE_VAR_EX(tmpTicket, output->heap, DYNAMIC_TYPE_TMP_BUFFER);
1354
        return WOLFSSL_FAILURE;
1355
    }
1356
#endif /* WOLFSSL_TLS13 && HAVE_SESSION_TICKET*/
1357
1358
    /* init to avoid clang static analyzer false positive */
1359
    row = 0;
1360
    error = TlsSessionCacheGetAndRdLock(id, &sess, &row,
1361
        (byte)ssl->options.side);
1362
    error = (error == 0) ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE;
1363
    if (error != WOLFSSL_SUCCESS || sess == NULL) {
1364
        WOLFSSL_MSG("Get Session from cache failed");
1365
        error = WOLFSSL_FAILURE;
1366
#ifdef HAVE_SESSION_TICKET
1367
        if (tmpBufSet) {
1368
            output->ticket = output->staticTicket;
1369
            output->ticketLenAlloc = 0;
1370
        }
1371
#ifdef WOLFSSL_TLS13
1372
        XFREE(preallocNonce, output->heap, DYNAMIC_TYPE_SESSION_TICK);
1373
        preallocNonce = NULL;
1374
#endif /* WOLFSSL_TLS13 */
1375
#ifdef WOLFSSL_SMALL_STACK
1376
        XFREE(tmpTicket, output->heap, DYNAMIC_TYPE_TMP_BUFFER);
1377
        tmpTicket = NULL;
1378
#endif
1379
#endif
1380
    }
1381
    else {
1382
        if (!CheckSessionMatch(ssl, sess)) {
1383
            WOLFSSL_MSG("Invalid session: can't be used in this context");
1384
            TlsSessionCacheUnlockRow(row);
1385
            error = WOLFSSL_FAILURE;
1386
        }
1387
        else if (LowResTimer() >= (sess->bornOn + sess->timeout)) {
1388
            WOLFSSL_SESSION* wrSess = NULL;
1389
            WOLFSSL_MSG("Invalid session: timed out");
1390
            sess = NULL;
1391
            TlsSessionCacheUnlockRow(row);
1392
            /* Attempt to get a write lock */
1393
            error = TlsSessionCacheGetAndWrLock(id, &wrSess, &row,
1394
                    (byte)ssl->options.side);
1395
            if (error == 0 && wrSess != NULL) {
1396
                EvictSessionFromCache(wrSess);
1397
                TlsSessionCacheUnlockRow(row);
1398
            }
1399
            error = WOLFSSL_FAILURE;
1400
        }
1401
    }
1402
1403
    /* mollify confused cppcheck nullPointer warning. */
1404
    if (sess == NULL)
1405
        error = WOLFSSL_FAILURE;
1406
1407
    if (error == WOLFSSL_SUCCESS) {
1408
#if defined(HAVE_SESSION_TICKET) && defined(WOLFSSL_TLS13)
1409
        error = wolfSSL_DupSessionEx(sess, output, 1, 1,
1410
            preallocNonce, &preallocNonceLen, &preallocNonceUsed);
1411
#else
1412
        error = wolfSSL_DupSession(sess, output, 1);
1413
#endif /* HAVE_SESSION_TICKET && WOLFSSL_TLS13 */
1414
#ifdef HAVE_EX_DATA
1415
        output->ownExData = !sess->ownExData; /* Session may own ex_data */
1416
#endif
1417
        TlsSessionCacheUnlockRow(row);
1418
    }
1419
1420
    /* We want to restore the bogus ID for TLS compatibility */
1421
    if (ssl->session->haveAltSessionID &&
1422
            output == ssl->session) {
1423
        XMEMCPY(ssl->session->sessionID, bogusID, ID_LEN);
1424
        ssl->session->sessionIDSz = bogusIDSz;
1425
    }
1426
1427
#ifdef HAVE_SESSION_TICKET
1428
    if (tmpBufSet) {
1429
        if (error == WOLFSSL_SUCCESS) {
1430
            if (output->ticketLen > SESSION_TICKET_LEN) {
1431
                output->ticket = (byte*)XMALLOC(output->ticketLen, output->heap,
1432
                        DYNAMIC_TYPE_SESSION_TICK);
1433
                if (output->ticket == NULL) {
1434
                    error = WOLFSSL_FAILURE;
1435
                    output->ticket = output->staticTicket;
1436
                    output->ticketLenAlloc = 0;
1437
                    output->ticketLen = 0;
1438
                }
1439
            }
1440
            else {
1441
                output->ticket = output->staticTicket;
1442
                output->ticketLenAlloc = 0;
1443
            }
1444
        }
1445
        else {
1446
            output->ticket = output->staticTicket;
1447
            output->ticketLenAlloc = 0;
1448
            output->ticketLen = 0;
1449
        }
1450
        if (error == WOLFSSL_SUCCESS) {
1451
            /* cppcheck-suppress uninitvar */
1452
            XMEMCPY(output->ticket, tmpTicket, output->ticketLen);
1453
        }
1454
    }
1455
    WC_FREE_VAR_EX(tmpTicket, output->heap, DYNAMIC_TYPE_TMP_BUFFER);
1456
1457
#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_TICKET_NONCE_MALLOC) &&          \
1458
    (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3)))
1459
    if (error == WOLFSSL_SUCCESS && preallocNonceUsed) {
1460
        if (preallocNonceLen < PREALLOC_SESSION_TICKET_NONCE_LEN) {
1461
            /* buffer bigger than needed */
1462
#ifndef XREALLOC
1463
            output->ticketNonce.data = (byte*)XMALLOC(preallocNonceLen,
1464
                output->heap, DYNAMIC_TYPE_SESSION_TICK);
1465
            if (output->ticketNonce.data != NULL)
1466
                XMEMCPY(output->ticketNonce.data, preallocNonce,
1467
                    preallocNonceLen);
1468
            XFREE(preallocNonce, output->heap, DYNAMIC_TYPE_SESSION_TICK);
1469
            preallocNonce = NULL;
1470
#else
1471
            output->ticketNonce.data = (byte*)XREALLOC(preallocNonce,
1472
                preallocNonceLen, output->heap, DYNAMIC_TYPE_SESSION_TICK);
1473
            if (output->ticketNonce.data != NULL) {
1474
                /* don't free the reallocated pointer */
1475
                preallocNonce = NULL;
1476
            }
1477
#endif /* !XREALLOC */
1478
            if (output->ticketNonce.data == NULL) {
1479
                output->ticketNonce.data = output->ticketNonce.dataStatic;
1480
                output->ticketNonce.len = 0;
1481
                error = WOLFSSL_FAILURE;
1482
                /* preallocNonce will be free'd after the if */
1483
            }
1484
        }
1485
        else {
1486
            output->ticketNonce.data = preallocNonce;
1487
            output->ticketNonce.len = preallocNonceLen;
1488
            preallocNonce = NULL;
1489
        }
1490
    }
1491
    XFREE(preallocNonce, output->heap, DYNAMIC_TYPE_SESSION_TICK);
1492
#endif /* WOLFSSL_TLS13 && WOLFSSL_TICKET_NONCE_MALLOC && FIPS_VERSION_GE(5,3)*/
1493
1494
#endif
1495
1496
    return error;
1497
}
1498
1499
WOLFSSL_SESSION* wolfSSL_GetSession(WOLFSSL* ssl, byte* masterSecret,
1500
        byte restoreSessionCerts)
1501
248
{
1502
248
    WOLFSSL_SESSION* ret = NULL;
1503
1504
248
    (void)restoreSessionCerts; /* Kept for compatibility */
1505
1506
248
    if (wolfSSL_GetSessionFromCache(ssl, ssl->session) == WOLFSSL_SUCCESS) {
1507
0
        ret = ssl->session;
1508
0
    }
1509
248
    else {
1510
248
        WOLFSSL_MSG("wolfSSL_GetSessionFromCache did not return a session");
1511
248
    }
1512
1513
248
    if (ret != NULL && masterSecret != NULL)
1514
0
        XMEMCPY(masterSecret, ret->masterSecret, SECRET_LEN);
1515
1516
248
    return ret;
1517
248
}
1518
1519
int wolfSSL_SetSession(WOLFSSL* ssl, WOLFSSL_SESSION* session)
1520
0
{
1521
0
    SessionRow* sessRow = NULL;
1522
0
    int ret = WOLFSSL_SUCCESS;
1523
1524
0
    session = ClientSessionToSession(session);
1525
1526
0
    if (ssl == NULL || session == NULL || !session->isSetup) {
1527
0
        WOLFSSL_MSG("ssl or session NULL or not set up");
1528
0
        return WOLFSSL_FAILURE;
1529
0
    }
1530
1531
    /* We need to lock the session as the first step if its in the cache */
1532
0
    if (session->type == WOLFSSL_SESSION_TYPE_CACHE) {
1533
0
        if (session->cacheRow < SESSION_ROWS) {
1534
0
            sessRow = &SessionCache[session->cacheRow];
1535
0
            if (SESSION_ROW_RD_LOCK(sessRow) != 0) {
1536
0
                WOLFSSL_MSG("Session row lock failed");
1537
0
                return WOLFSSL_FAILURE;
1538
0
            }
1539
0
        }
1540
0
    }
1541
1542
0
    if (ret == WOLFSSL_SUCCESS && ssl->options.side != WOLFSSL_NEITHER_END &&
1543
0
            (byte)ssl->options.side != session->side) {
1544
0
        WOLFSSL_MSG("Setting session for wrong role");
1545
0
        ret = WOLFSSL_FAILURE;
1546
0
    }
1547
1548
0
    if (ret == WOLFSSL_SUCCESS) {
1549
0
        if (ssl->session == session) {
1550
0
            WOLFSSL_MSG("ssl->session and session same");
1551
0
        }
1552
0
        else if (session->type != WOLFSSL_SESSION_TYPE_CACHE) {
1553
0
            if (wolfSSL_SESSION_up_ref(session) == WOLFSSL_SUCCESS) {
1554
0
                wolfSSL_FreeSession(ssl->ctx, ssl->session);
1555
0
                ssl->session = session;
1556
0
            }
1557
0
            else
1558
0
                ret = WOLFSSL_FAILURE;
1559
0
        }
1560
0
        else {
1561
0
            ret = wolfSSL_DupSession(session, ssl->session, 0);
1562
0
            if (ret != WOLFSSL_SUCCESS)
1563
0
                WOLFSSL_MSG("Session duplicate failed");
1564
0
        }
1565
0
    }
1566
1567
    /* Let's copy over the altSessionID for local cache purposes */
1568
0
    if (ret == WOLFSSL_SUCCESS && session->haveAltSessionID &&
1569
0
            ssl->session != session) {
1570
0
        ssl->session->haveAltSessionID = 1;
1571
0
        XMEMCPY(ssl->session->altSessionID, session->altSessionID, ID_LEN);
1572
0
    }
1573
1574
0
    if (sessRow != NULL) {
1575
0
        SESSION_ROW_UNLOCK(sessRow);
1576
0
        sessRow = NULL;
1577
0
    }
1578
1579
    /* Note: the `session` variable cannot be used below, since the row is
1580
     * un-locked */
1581
1582
0
    if (ret != WOLFSSL_SUCCESS)
1583
0
        return ret;
1584
1585
#ifdef WOLFSSL_SESSION_ID_CTX
1586
    /* check for application context id */
1587
    if (ssl->sessionCtxSz > 0) {
1588
        if (XMEMCMP(ssl->sessionCtx, ssl->session->sessionCtx,
1589
                ssl->sessionCtxSz)) {
1590
            /* context id did not match! */
1591
            WOLFSSL_MSG("Session context did not match");
1592
            return WOLFSSL_FAILURE;
1593
        }
1594
    }
1595
#endif /* WOLFSSL_SESSION_ID_CTX */
1596
1597
0
    if (LowResTimer() >= (ssl->session->bornOn + ssl->session->timeout)) {
1598
0
#if !defined(OPENSSL_EXTRA) || !defined(WOLFSSL_ERROR_CODE_OPENSSL)
1599
0
        return WOLFSSL_FAILURE;  /* session timed out */
1600
#else /* defined(OPENSSL_EXTRA) && defined(WOLFSSL_ERROR_CODE_OPENSSL) */
1601
        /* Return success for OpenSSL compatibility but do not carry the
1602
         * expired session's version/cipher into ssl state, which would
1603
         * otherwise pin the ClientHello to stale values. */
1604
        WOLFSSL_MSG("Session is expired but return success for "
1605
                    "OpenSSL compatibility");
1606
        return WOLFSSL_SUCCESS;
1607
#endif
1608
0
    }
1609
0
    ssl->options.resuming = 1;
1610
0
    ssl->options.haveEMS = (ssl->session->haveEMS) ? 1 : 0;
1611
1612
0
    if (ssl->session->version.major != 0) {
1613
        /* Reject sessions whose protocol version is below the configured
1614
         * minimum so a stale cached session cannot make the client send a
1615
         * ClientHello advertising a version it isn't allowed to negotiate.
1616
         * DTLS minor versions are inverted: a higher minor means an older
1617
         * protocol, so the comparison flips. */
1618
0
        byte belowMinDowngrade;
1619
0
        if (ssl->options.dtls)
1620
0
            belowMinDowngrade = ssl->session->version.minor >
1621
0
                                ssl->options.minDowngrade;
1622
0
        else
1623
0
            belowMinDowngrade = ssl->session->version.minor <
1624
0
                                ssl->options.minDowngrade;
1625
0
        if (belowMinDowngrade) {
1626
0
            WOLFSSL_MSG("Session version below configured minDowngrade");
1627
0
            ssl->options.resuming = 0;
1628
0
            return WOLFSSL_FAILURE;
1629
0
        }
1630
0
        ssl->version              = ssl->session->version;
1631
0
        if (IsAtLeastTLSv1_3(ssl->version))
1632
0
            ssl->options.tls1_3 = 1;
1633
0
    }
1634
0
#if defined(SESSION_CERTS) || !defined(NO_RESUME_SUITE_CHECK) || \
1635
0
                    (defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET))
1636
0
    ssl->options.cipherSuite0 = ssl->session->cipherSuite0;
1637
0
    ssl->options.cipherSuite  = ssl->session->cipherSuite;
1638
0
#endif
1639
#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
1640
    ssl->peerVerifyRet = (unsigned long)ssl->session->peerVerifyRet;
1641
#endif
1642
1643
0
    return WOLFSSL_SUCCESS;
1644
0
}
1645
1646
1647
#ifdef WOLFSSL_SESSION_STATS
1648
static int get_locked_session_stats(word32* active, word32* total,
1649
                                    word32* peak);
1650
#endif
1651
1652
#ifndef NO_CLIENT_CACHE
1653
ClientSession* AddSessionToClientCache(int side, int row, int idx,
1654
    byte* serverID, word16 idLen, const byte* sessionID, word16 useTicket)
1655
0
{
1656
0
    int error = -1;
1657
0
    word32 clientRow = 0, clientIdx = 0;
1658
0
    ClientSession* ret = NULL;
1659
1660
0
    (void)useTicket;
1661
0
    if (side == WOLFSSL_CLIENT_END
1662
0
            && row != INVALID_SESSION_ROW
1663
0
            && (idLen
1664
#ifdef HAVE_SESSION_TICKET
1665
                || useTicket == 1
1666
#endif
1667
0
                || serverID != NULL
1668
0
                )) {
1669
1670
0
        WOLFSSL_MSG("Trying to add client cache entry");
1671
1672
0
        if (idLen) {
1673
0
            clientRow = HashObject(serverID,
1674
0
                    idLen, &error) % CLIENT_SESSION_ROWS;
1675
0
        }
1676
0
        else if (serverID != NULL) {
1677
0
            clientRow = HashObject(sessionID,
1678
0
                    ID_LEN, &error) % CLIENT_SESSION_ROWS;
1679
0
        }
1680
0
        else {
1681
0
            error = WOLFSSL_FATAL_ERROR;
1682
0
        }
1683
0
        if (error == 0 && wc_LockMutex(&clisession_mutex) == 0) {
1684
0
            clientIdx = (word32)ClientCache[clientRow].nextIdx;
1685
0
            if (clientIdx < CLIENT_SESSIONS_PER_ROW) {
1686
0
                ClientCache[clientRow].Clients[clientIdx].serverRow =
1687
0
                                                                (word16)row;
1688
0
                ClientCache[clientRow].Clients[clientIdx].serverIdx =
1689
0
                                                                (word16)idx;
1690
0
                if (sessionID != NULL) {
1691
0
                    word32 sessionIDHash = HashObject(sessionID, ID_LEN,
1692
0
                                                      &error);
1693
0
                    if (error == 0) {
1694
0
                        ClientCache[clientRow].Clients[clientIdx].sessionIDHash
1695
0
                            = sessionIDHash;
1696
0
                    }
1697
0
                }
1698
0
            }
1699
0
            else {
1700
0
                error = WOLFSSL_FATAL_ERROR;
1701
0
                ClientCache[clientRow].nextIdx = 0; /* reset index as safety */
1702
0
                WOLFSSL_MSG("Invalid client cache index! "
1703
0
                            "Possible corrupted memory");
1704
0
            }
1705
0
            if (error == 0) {
1706
0
                WOLFSSL_MSG("Adding client cache entry");
1707
1708
0
                ret = &ClientCache[clientRow].Clients[clientIdx];
1709
1710
0
                if (ClientCache[clientRow].totalCount < CLIENT_SESSIONS_PER_ROW)
1711
0
                    ClientCache[clientRow].totalCount++;
1712
0
                ClientCache[clientRow].nextIdx++;
1713
0
                ClientCache[clientRow].nextIdx %= CLIENT_SESSIONS_PER_ROW;
1714
0
            }
1715
1716
0
            wc_UnLockMutex(&clisession_mutex);
1717
0
        }
1718
0
        else {
1719
0
            WOLFSSL_MSG("Hash session or lock failed");
1720
0
        }
1721
0
    }
1722
0
    else {
1723
0
        WOLFSSL_MSG("Skipping client cache");
1724
0
    }
1725
1726
0
    return ret;
1727
0
}
1728
#endif /* !NO_CLIENT_CACHE */
1729
1730
/**
1731
 * For backwards compatibility, this API needs to be used in *ALL* functions
1732
 * that access the WOLFSSL_SESSION members directly.
1733
 *
1734
 * This API checks if the passed in session is actually a ClientSession object
1735
 * and returns the matching session cache object. Otherwise just return the
1736
 * input. ClientSession objects only occur in the ClientCache. They are not
1737
 * allocated anywhere else.
1738
 */
1739
WOLFSSL_SESSION* ClientSessionToSession(const WOLFSSL_SESSION* session)
1740
80.0k
{
1741
80.0k
    WOLFSSL_ENTER("ClientSessionToSession");
1742
#ifdef NO_SESSION_CACHE_REF
1743
    return (WOLFSSL_SESSION*)session;
1744
#else
1745
80.0k
#ifndef NO_CLIENT_CACHE
1746
80.0k
    if (session == NULL)
1747
0
        return NULL;
1748
    /* Check if session points into ClientCache */
1749
80.0k
    if ((byte*)session >= (byte*)ClientCache &&
1750
            /* Cast to byte* to make pointer arithmetic work per byte */
1751
80.0k
            (byte*)session < ((byte*)ClientCache) + sizeof(ClientCache)) {
1752
0
        ClientSession* clientSession = (ClientSession*)session;
1753
0
        SessionRow* sessRow = NULL;
1754
0
        WOLFSSL_SESSION* cacheSession = NULL;
1755
0
        word32 sessionIDHash = 0;
1756
0
        int error = 0;
1757
0
        session = NULL; /* Default to NULL for failure case */
1758
0
        if (wc_LockMutex(&clisession_mutex) != 0) {
1759
0
            WOLFSSL_MSG("Client cache mutex lock failed");
1760
0
            return NULL;
1761
0
        }
1762
0
        if (clientSession->serverRow >= SESSION_ROWS ||
1763
0
                clientSession->serverIdx >= SESSIONS_PER_ROW) {
1764
0
            WOLFSSL_MSG("Client cache serverRow or serverIdx invalid");
1765
0
            error = WOLFSSL_FATAL_ERROR;
1766
0
        }
1767
0
        if (error == 0) {
1768
            /* Lock row */
1769
0
            sessRow = &SessionCache[clientSession->serverRow];
1770
            /* Prevent memory access before clientSession->serverRow and
1771
             * clientSession->serverIdx are sanitized. */
1772
0
            XFENCE();
1773
0
            error = SESSION_ROW_RD_LOCK(sessRow);
1774
0
            if (error != 0) {
1775
0
                WOLFSSL_MSG("Session cache row lock failure");
1776
0
                sessRow = NULL;
1777
0
            }
1778
0
        }
1779
0
        if (error == 0) {
1780
#ifdef SESSION_CACHE_DYNAMIC_MEM
1781
            cacheSession = sessRow->Sessions[clientSession->serverIdx];
1782
#else
1783
0
            cacheSession = &sessRow->Sessions[clientSession->serverIdx];
1784
0
#endif
1785
            /* Prevent memory access */
1786
0
            XFENCE();
1787
0
            if (cacheSession && cacheSession->sessionIDSz == 0) {
1788
0
                cacheSession = NULL;
1789
0
                WOLFSSL_MSG("Session cache entry not set");
1790
0
                error = WOLFSSL_FATAL_ERROR;
1791
0
            }
1792
0
        }
1793
0
        if (error == 0) {
1794
            /* Calculate the hash of the session ID */
1795
0
            sessionIDHash = HashObject(cacheSession->sessionID, ID_LEN,
1796
0
                    &error);
1797
0
        }
1798
0
        if (error == 0) {
1799
            /* Check the session ID hash matches */
1800
0
            error = clientSession->sessionIDHash != sessionIDHash;
1801
0
            if (error != 0)
1802
0
                WOLFSSL_MSG("session ID hashes don't match");
1803
0
        }
1804
0
        if (error == 0) {
1805
            /* Hashes match */
1806
0
            session = cacheSession;
1807
0
            WOLFSSL_MSG("Found session cache matching client session object");
1808
0
        }
1809
0
        if (sessRow != NULL) {
1810
0
            SESSION_ROW_UNLOCK(sessRow);
1811
0
        }
1812
0
        wc_UnLockMutex(&clisession_mutex);
1813
0
        return (WOLFSSL_SESSION*)session;
1814
0
    }
1815
80.0k
    else {
1816
        /* Plain WOLFSSL_SESSION object */
1817
80.0k
        return (WOLFSSL_SESSION*)session;
1818
80.0k
    }
1819
#else
1820
    return (WOLFSSL_SESSION*)session;
1821
#endif
1822
80.0k
#endif
1823
80.0k
}
1824
1825
int AddSessionToCache(WOLFSSL_CTX* ctx, WOLFSSL_SESSION* addSession,
1826
        const byte* id, byte idSz, int* sessionIndex, int side,
1827
        word16 useTicket, ClientSession** clientCacheEntry)
1828
{
1829
    WOLFSSL_SESSION* cacheSession = NULL;
1830
    SessionRow* sessRow = NULL;
1831
    word32 idx = 0;
1832
#if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA)
1833
    WOLFSSL_X509* cachePeer = NULL;
1834
    WOLFSSL_X509* addPeer = NULL;
1835
#endif
1836
#ifdef HAVE_SESSION_TICKET
1837
    byte*  cacheTicBuff = NULL;
1838
    byte   ticBuffUsed = 0;
1839
    byte*  ticBuff = NULL;
1840
    int    ticLen  = 0;
1841
#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_TICKET_NONCE_MALLOC) &&          \
1842
    (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3)))
1843
    byte *preallocNonce = NULL;
1844
    byte preallocNonceLen = 0;
1845
    byte preallocNonceUsed = 0;
1846
    byte *toFree = NULL;
1847
#endif /* WOLFSSL_TLS13 && WOLFSSL_TICKET_NONCE_MALLOC */
1848
#endif /* HAVE_SESSION_TICKET */
1849
    int ret = 0;
1850
    int row;
1851
    int i;
1852
    int overwrite = 0;
1853
    (void)ctx;
1854
    (void)sessionIndex;
1855
    (void)useTicket;
1856
    (void)clientCacheEntry;
1857
1858
    WOLFSSL_ENTER("AddSessionToCache");
1859
1860
    if (idSz == 0) {
1861
        WOLFSSL_MSG("AddSessionToCache idSz == 0");
1862
        return BAD_FUNC_ARG;
1863
    }
1864
1865
    addSession = ClientSessionToSession(addSession);
1866
    if (addSession == NULL) {
1867
        WOLFSSL_MSG("AddSessionToCache is NULL");
1868
        return MEMORY_E;
1869
    }
1870
1871
#ifdef HAVE_SESSION_TICKET
1872
    ticLen = addSession->ticketLen;
1873
    /* Alloc Memory here to avoid syscalls during lock */
1874
    if (ticLen > SESSION_TICKET_LEN) {
1875
        ticBuff = (byte*)XMALLOC((size_t)ticLen, NULL,
1876
                DYNAMIC_TYPE_SESSION_TICK);
1877
        if (ticBuff == NULL) {
1878
            return MEMORY_E;
1879
        }
1880
    }
1881
#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_TICKET_NONCE_MALLOC) &&          \
1882
    (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3)))
1883
    if (addSession->ticketNonce.data != addSession->ticketNonce.dataStatic) {
1884
        /* use the AddSession->heap even if the buffer maybe saved in
1885
         * CachedSession objects. CachedSession heap and AddSession heap should
1886
         * be the same */
1887
        preallocNonce = (byte*)XMALLOC(addSession->ticketNonce.len,
1888
            addSession->heap, DYNAMIC_TYPE_SESSION_TICK);
1889
        if (preallocNonce == NULL) {
1890
            XFREE(ticBuff, addSession->heap, DYNAMIC_TYPE_SESSION_TICK);
1891
            return MEMORY_E;
1892
        }
1893
        preallocNonceLen = addSession->ticketNonce.len;
1894
    }
1895
#endif /* WOLFSSL_TLS13 && WOLFSSL_TICKET_NONCE_MALLOC && FIPS_VERSION_GE(5,3)*/
1896
#endif /* HAVE_SESSION_TICKET */
1897
1898
    /* Find a position for the new session in cache and use that */
1899
    /* Use the session object in the cache for external cache if required */
1900
    row = (int)(HashObject(id, ID_LEN, &ret) % SESSION_ROWS);
1901
    if (ret != 0) {
1902
        WOLFSSL_MSG("Hash session failed");
1903
    #ifdef HAVE_SESSION_TICKET
1904
        XFREE(ticBuff, NULL, DYNAMIC_TYPE_SESSION_TICK);
1905
    #if defined(WOLFSSL_TLS13) && defined(WOLFSSL_TICKET_NONCE_MALLOC) &&      \
1906
    (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3)))
1907
        XFREE(preallocNonce, addSession->heap, DYNAMIC_TYPE_SESSION_TICK);
1908
    #endif
1909
    #endif
1910
        return ret;
1911
    }
1912
1913
    sessRow = &SessionCache[row];
1914
    if (SESSION_ROW_WR_LOCK(sessRow) != 0) {
1915
    #ifdef HAVE_SESSION_TICKET
1916
        XFREE(ticBuff, NULL, DYNAMIC_TYPE_SESSION_TICK);
1917
    #if defined(WOLFSSL_TLS13) && defined(WOLFSSL_TICKET_NONCE_MALLOC) && \
1918
        (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && \
1919
                                 FIPS_VERSION_GE(5,3)))
1920
        XFREE(preallocNonce, addSession->heap, DYNAMIC_TYPE_SESSION_TICK);
1921
    #endif
1922
    #endif
1923
        WOLFSSL_MSG("Session row lock failed");
1924
        return BAD_MUTEX_E;
1925
    }
1926
1927
    for (i = 0; i < SESSIONS_PER_ROW && i < sessRow->totalCount; i++) {
1928
#ifdef SESSION_CACHE_DYNAMIC_MEM
1929
        cacheSession = sessRow->Sessions[i];
1930
#else
1931
        cacheSession = &sessRow->Sessions[i];
1932
#endif
1933
        if (cacheSession && XMEMCMP(id,
1934
                cacheSession->sessionID, ID_LEN) == 0 &&
1935
                cacheSession->side == side) {
1936
            WOLFSSL_MSG("Session already exists. Overwriting.");
1937
            overwrite = 1;
1938
            idx = (word32)i;
1939
            break;
1940
        }
1941
    }
1942
1943
    if (!overwrite)
1944
        idx = (word32)sessRow->nextIdx;
1945
#ifdef SESSION_INDEX
1946
    if (sessionIndex != NULL)
1947
        *sessionIndex = (row << SESSIDX_ROW_SHIFT) | idx;
1948
#endif
1949
1950
#ifdef SESSION_CACHE_DYNAMIC_MEM
1951
    cacheSession = sessRow->Sessions[idx];
1952
    if (cacheSession == NULL) {
1953
        cacheSession = (WOLFSSL_SESSION*) XMALLOC(sizeof(WOLFSSL_SESSION),
1954
                                         sessRow->heap, DYNAMIC_TYPE_SESSION);
1955
        if (cacheSession == NULL) {
1956
        #ifdef HAVE_SESSION_TICKET
1957
            XFREE(ticBuff, NULL, DYNAMIC_TYPE_SESSION_TICK);
1958
        #if defined(WOLFSSL_TLS13) && defined(WOLFSSL_TICKET_NONCE_MALLOC) && \
1959
            (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && \
1960
                                     FIPS_VERSION_GE(5,3)))
1961
            XFREE(preallocNonce, addSession->heap, DYNAMIC_TYPE_SESSION_TICK);
1962
        #endif
1963
        #endif
1964
            SESSION_ROW_UNLOCK(sessRow);
1965
            return MEMORY_E;
1966
        }
1967
        XMEMSET(cacheSession, 0, sizeof(WOLFSSL_SESSION));
1968
        sessRow->Sessions[idx] = cacheSession;
1969
    }
1970
#else
1971
    cacheSession = &sessRow->Sessions[idx];
1972
#endif
1973
1974
#ifdef HAVE_EX_DATA_CRYPTO
1975
    if (overwrite) {
1976
        /* Figure out who owns the ex_data */
1977
        if (cacheSession->ownExData) {
1978
            /* Prioritize cacheSession copy */
1979
            XMEMCPY(&addSession->ex_data, &cacheSession->ex_data,
1980
                    sizeof(WOLFSSL_CRYPTO_EX_DATA));
1981
        }
1982
        /* else will be copied in wolfSSL_DupSession call */
1983
    }
1984
    else if (cacheSession->ownExData) {
1985
        crypto_ex_cb_free_data(cacheSession, crypto_ex_cb_ctx_session,
1986
                               &cacheSession->ex_data);
1987
        cacheSession->ownExData = 0;
1988
    }
1989
#endif
1990
1991
    if (!overwrite)
1992
        EvictSessionFromCache(cacheSession);
1993
1994
    cacheSession->type = WOLFSSL_SESSION_TYPE_CACHE;
1995
    cacheSession->cacheRow = row;
1996
1997
#if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA)
1998
    /* Save the peer field to free after unlocking the row */
1999
    if (cacheSession->peer != NULL)
2000
        cachePeer = cacheSession->peer;
2001
    cacheSession->peer = NULL;
2002
#endif
2003
#ifdef HAVE_SESSION_TICKET
2004
    /* If we can reuse the existing buffer in cacheSession then we won't touch
2005
     * ticBuff at all making it a very cheap malloc/free. The page on a modern
2006
     * OS will most likely not even be allocated to the process. */
2007
    if (ticBuff != NULL && cacheSession->ticketLenAlloc < ticLen) {
2008
        /* Save pointer only if separately allocated */
2009
        if (cacheSession->ticket != cacheSession->staticTicket)
2010
            cacheTicBuff = cacheSession->ticket;
2011
        ticBuffUsed = 1;
2012
        cacheSession->ticket = ticBuff;
2013
        cacheSession->ticketLenAlloc = (word16) ticLen;
2014
    }
2015
#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_TICKET_NONCE_MALLOC) &&          \
2016
    (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3)))
2017
    /* cache entry never used */
2018
    if (cacheSession->ticketNonce.data == NULL)
2019
        cacheSession->ticketNonce.data = cacheSession->ticketNonce.dataStatic;
2020
2021
    if (cacheSession->ticketNonce.data !=
2022
            cacheSession->ticketNonce.dataStatic) {
2023
        toFree = cacheSession->ticketNonce.data;
2024
        cacheSession->ticketNonce.data = cacheSession->ticketNonce.dataStatic;
2025
        cacheSession->ticketNonce.len = 0;
2026
    }
2027
#endif /* WOLFSSL_TLS13 && WOLFSSL_TICKET_NONCE_MALLOC && FIPS_VERSION_GE(5,3)*/
2028
#endif
2029
#ifdef SESSION_CERTS
2030
    if (overwrite &&
2031
            addSession->chain.count == 0 &&
2032
            cacheSession->chain.count > 0) {
2033
        /* Copy in the certs from the session */
2034
        addSession->chain.count = cacheSession->chain.count;
2035
        XMEMCPY(addSession->chain.certs, cacheSession->chain.certs,
2036
                sizeof(x509_buffer) * (size_t)cacheSession->chain.count);
2037
    }
2038
#endif /* SESSION_CERTS */
2039
#if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA)
2040
    /* Don't copy the peer cert into cache */
2041
    addPeer = addSession->peer;
2042
    addSession->peer = NULL;
2043
#endif
2044
    cacheSession->heap = NULL;
2045
    /* Copy data into the cache object */
2046
#if defined(HAVE_SESSION_TICKET) && defined(WOLFSSL_TLS13) &&                  \
2047
    defined(WOLFSSL_TICKET_NONCE_MALLOC) &&                                   \
2048
    (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3)))
2049
    ret = (wolfSSL_DupSessionEx(addSession, cacheSession, 1, 1, preallocNonce,
2050
                                &preallocNonceLen, &preallocNonceUsed)
2051
           == WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
2052
#else
2053
    ret = (wolfSSL_DupSession(addSession, cacheSession, 1)
2054
           == WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
2055
#endif /* HAVE_SESSION_TICKET && WOLFSSL_TLS13 && WOLFSSL_TICKET_NONCE_MALLOC
2056
          && FIPS_VERSION_GE(5,3)*/
2057
#if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA)
2058
    addSession->peer = addPeer;
2059
#endif
2060
2061
    if (ret == 0) {
2062
        if (!overwrite) {
2063
            /* Increment the totalCount and the nextIdx */
2064
            if (sessRow->totalCount < SESSIONS_PER_ROW)
2065
                sessRow->totalCount++;
2066
            sessRow->nextIdx = (sessRow->nextIdx + 1) % SESSIONS_PER_ROW;
2067
        }
2068
        if (id != addSession->sessionID) {
2069
            /* ssl->session->sessionID may contain the bogus ID or we want the
2070
             * ID from the arrays object */
2071
            XMEMCPY(cacheSession->sessionID, id, ID_LEN);
2072
            cacheSession->sessionIDSz = ID_LEN;
2073
        }
2074
#if defined(HAVE_EXT_CACHE) || defined(HAVE_EX_DATA)
2075
        if (ctx->rem_sess_cb != NULL)
2076
            cacheSession->rem_sess_cb = ctx->rem_sess_cb;
2077
#endif
2078
#ifdef HAVE_EX_DATA
2079
        /* The session in cache now owns the ex_data */
2080
        addSession->ownExData = 0;
2081
        cacheSession->ownExData = 1;
2082
#endif
2083
#if defined(HAVE_SESSION_TICKET) && defined(WOLFSSL_TLS13) &&                  \
2084
    defined(WOLFSSL_TICKET_NONCE_MALLOC) &&                                    \
2085
    (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3)))
2086
        if (preallocNonce != NULL && preallocNonceUsed) {
2087
            cacheSession->ticketNonce.data = preallocNonce;
2088
            cacheSession->ticketNonce.len = preallocNonceLen;
2089
            preallocNonce = NULL;
2090
            preallocNonceLen = 0;
2091
        }
2092
#endif /* HAVE_SESSION_TICKET && WOLFSSL_TLS13 && WOLFSSL_TICKET_NONCE_MALLOC
2093
        * && FIPS_VERSION_GE(5,3)*/
2094
    }
2095
#ifdef HAVE_SESSION_TICKET
2096
    else if (ticBuffUsed) {
2097
        /* Error occurred. Need to clean up the ticket buffer. */
2098
        cacheSession->ticket = cacheSession->staticTicket;
2099
        cacheSession->ticketLenAlloc = 0;
2100
        cacheSession->ticketLen = 0;
2101
    }
2102
#endif
2103
    SESSION_ROW_UNLOCK(sessRow);
2104
    cacheSession = NULL; /* Can't access after unlocked */
2105
2106
#ifndef NO_CLIENT_CACHE
2107
    if (ret == 0 && clientCacheEntry != NULL) {
2108
        ClientSession* clientCache = AddSessionToClientCache(side, row,
2109
            (int)idx, addSession->serverID, addSession->idLen, id, useTicket);
2110
        if (clientCache != NULL)
2111
            *clientCacheEntry = clientCache;
2112
    }
2113
#endif
2114
2115
#ifdef HAVE_SESSION_TICKET
2116
    if (ticBuff != NULL && !ticBuffUsed)
2117
        XFREE(ticBuff, NULL, DYNAMIC_TYPE_SESSION_TICK);
2118
    XFREE(cacheTicBuff, NULL, DYNAMIC_TYPE_SESSION_TICK);
2119
#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_TICKET_NONCE_MALLOC) &&         \
2120
    (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3)))
2121
    XFREE(preallocNonce, addSession->heap, DYNAMIC_TYPE_SESSION_TICK);
2122
    XFREE(toFree, addSession->heap, DYNAMIC_TYPE_SESSION_TICK);
2123
#endif /* WOLFSSL_TLS13 && WOLFSSL_TICKET_NONCE_MALLOC && FIPS_VERSION_GE(5,3)*/
2124
#endif
2125
2126
#if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA)
2127
    if (cachePeer != NULL) {
2128
        wolfSSL_X509_free(cachePeer);
2129
        cachePeer = NULL; /* Make sure not use after this point */
2130
    }
2131
#endif
2132
2133
    return ret;
2134
}
2135
2136
void AddSession(WOLFSSL* ssl)
2137
0
{
2138
0
    int    error = 0;
2139
0
    const byte* id = NULL;
2140
0
    byte idSz = 0;
2141
0
    WOLFSSL_SESSION* session = ssl->session;
2142
2143
0
    (void)error;
2144
2145
0
    WOLFSSL_ENTER("AddSession");
2146
2147
0
    if (SslSessionCacheOff(ssl, session)) {
2148
0
        WOLFSSL_MSG("Cache off");
2149
0
        return;
2150
0
    }
2151
2152
0
    if (session->haveAltSessionID) {
2153
0
        id = session->altSessionID;
2154
0
        idSz = ID_LEN;
2155
0
    }
2156
0
    else {
2157
0
        id = session->sessionID;
2158
0
        idSz = session->sessionIDSz;
2159
0
    }
2160
2161
    /* Do this only for the client because if the server doesn't have an ID at
2162
     * this point, it won't on resumption. */
2163
0
    if (idSz == 0 && ssl->options.side == WOLFSSL_CLIENT_END) {
2164
0
        WC_RNG* rng = NULL;
2165
0
        int genRet;
2166
#if defined(HAVE_GLOBAL_RNG) && defined(OPENSSL_EXTRA)
2167
        int rngLocked = 0;
2168
#endif
2169
0
        if (ssl->rng != NULL)
2170
0
            rng = ssl->rng;
2171
#if defined(HAVE_GLOBAL_RNG) && defined(OPENSSL_EXTRA)
2172
        else if (initGlobalRNG == 1 || wolfSSL_RAND_Init() == WOLFSSL_SUCCESS) {
2173
            /* Global RNG is shared, lock it while generating. */
2174
            if (wc_LockMutex(&globalRNGMutex) != 0) {
2175
                WOLFSSL_MSG("Bad Lock Mutex rng");
2176
                return;
2177
            }
2178
            rng = &globalRNG;
2179
            rngLocked = 1;
2180
        }
2181
#endif
2182
0
        genRet = wc_RNG_GenerateBlock(rng, ssl->session->altSessionID, ID_LEN);
2183
#if defined(HAVE_GLOBAL_RNG) && defined(OPENSSL_EXTRA)
2184
        if (rngLocked)
2185
            wc_UnLockMutex(&globalRNGMutex);
2186
#endif
2187
0
        if (genRet != 0)
2188
0
            return;
2189
0
        ssl->session->haveAltSessionID = 1;
2190
0
        id = ssl->session->altSessionID;
2191
0
        idSz = ID_LEN;
2192
0
    }
2193
2194
#ifdef HAVE_EXT_CACHE
2195
    if (!ssl->options.internalCacheOff)
2196
#endif
2197
0
    {
2198
        /* Try to add the session to internal cache or external cache
2199
        if a new_sess_cb is set. Its ok if we don't succeed. */
2200
0
        (void)AddSessionToCache(ssl->ctx, session, id, idSz,
2201
#ifdef SESSION_INDEX
2202
                &ssl->sessionIndex,
2203
#else
2204
0
                NULL,
2205
0
#endif
2206
0
                ssl->options.side,
2207
#ifdef HAVE_SESSION_TICKET
2208
                ssl->options.useTicket,
2209
#else
2210
0
                0,
2211
0
#endif
2212
#ifdef NO_SESSION_CACHE_REF
2213
                NULL
2214
#else
2215
0
                (ssl->options.side == WOLFSSL_CLIENT_END) ?
2216
0
                        &ssl->clientSession : NULL
2217
0
#endif
2218
0
                        );
2219
0
    }
2220
2221
#ifdef HAVE_EXT_CACHE
2222
    if (error == 0 && ssl->ctx->new_sess_cb != NULL) {
2223
        int cbRet = 0;
2224
        wolfSSL_SESSION_up_ref(session);
2225
        cbRet = ssl->ctx->new_sess_cb(ssl, session);
2226
        if (cbRet == 0)
2227
            wolfSSL_FreeSession(ssl->ctx, session);
2228
    }
2229
#endif
2230
2231
#if defined(WOLFSSL_SESSION_STATS) && defined(WOLFSSL_PEAK_SESSIONS)
2232
    if (error == 0) {
2233
        word32 active = 0;
2234
2235
        error = get_locked_session_stats(&active, NULL, NULL);
2236
        if (error == WOLFSSL_SUCCESS) {
2237
            error = 0;  /* back to this function ok */
2238
2239
            if (PeakSessions < active) {
2240
                PeakSessions = active;
2241
            }
2242
        }
2243
    }
2244
#endif /* WOLFSSL_SESSION_STATS && WOLFSSL_PEAK_SESSIONS */
2245
0
    (void)error;
2246
0
}
2247
2248
2249
#ifdef SESSION_INDEX
2250
2251
int wolfSSL_GetSessionIndex(WOLFSSL* ssl)
2252
{
2253
    WOLFSSL_ENTER("wolfSSL_GetSessionIndex");
2254
    WOLFSSL_LEAVE("wolfSSL_GetSessionIndex", ssl->sessionIndex);
2255
    return ssl->sessionIndex;
2256
}
2257
2258
2259
int wolfSSL_GetSessionAtIndex(int idx, WOLFSSL_SESSION* session)
2260
{
2261
    int row, col, result = WOLFSSL_FAILURE;
2262
    SessionRow* sessRow;
2263
    WOLFSSL_SESSION* cacheSession;
2264
2265
    WOLFSSL_ENTER("wolfSSL_GetSessionAtIndex");
2266
2267
    session = ClientSessionToSession(session);
2268
2269
    row = idx >> SESSIDX_ROW_SHIFT;
2270
    col = idx & SESSIDX_IDX_MASK;
2271
2272
    if (session == NULL ||
2273
            row < 0 || row >= SESSION_ROWS || col >= SESSIONS_PER_ROW) {
2274
        return WOLFSSL_FAILURE;
2275
    }
2276
2277
    sessRow = &SessionCache[row];
2278
    if (SESSION_ROW_RD_LOCK(sessRow) != 0) {
2279
        return BAD_MUTEX_E;
2280
    }
2281
2282
#ifdef SESSION_CACHE_DYNAMIC_MEM
2283
    cacheSession = sessRow->Sessions[col];
2284
#else
2285
    cacheSession = &sessRow->Sessions[col];
2286
#endif
2287
    if (cacheSession) {
2288
        /* Must not alias the ticket, peer cert and ex_data the cache owns and
2289
         * frees on overwrite or eviction. The caller keeps this copy, so it
2290
         * does not take over the cache's ex_data either. */
2291
        result = wolfSSL_DupSessionEx(cacheSession, session, 0, 0, NULL, NULL,
2292
            NULL);
2293
    }
2294
    else {
2295
        result = WOLFSSL_FAILURE;
2296
    }
2297
2298
    SESSION_ROW_UNLOCK(sessRow);
2299
2300
    WOLFSSL_LEAVE("wolfSSL_GetSessionAtIndex", result);
2301
    return result;
2302
}
2303
2304
#endif /* SESSION_INDEX */
2305
2306
#if defined(SESSION_CERTS)
2307
2308
WOLFSSL_X509_CHAIN* wolfSSL_SESSION_get_peer_chain(WOLFSSL_SESSION* session)
2309
{
2310
    WOLFSSL_X509_CHAIN* chain = NULL;
2311
2312
    WOLFSSL_ENTER("wolfSSL_SESSION_get_peer_chain");
2313
2314
    session = ClientSessionToSession(session);
2315
2316
    if (session)
2317
        chain = &session->chain;
2318
2319
    WOLFSSL_LEAVE("wolfSSL_SESSION_get_peer_chain", chain ? 1 : 0);
2320
    return chain;
2321
}
2322
2323
2324
#ifdef OPENSSL_EXTRA
2325
/* gets the peer certificate associated with the session passed in
2326
 * returns null on failure, the caller should not free the returned pointer */
2327
WOLFSSL_X509* wolfSSL_SESSION_get0_peer(WOLFSSL_SESSION* session)
2328
{
2329
    WOLFSSL_ENTER("wolfSSL_SESSION_get_peer_chain");
2330
2331
    session = ClientSessionToSession(session);
2332
    if (session) {
2333
        int count;
2334
2335
        count = wolfSSL_get_chain_count(&session->chain);
2336
        if (count < 1 || count >= MAX_CHAIN_DEPTH) {
2337
            WOLFSSL_MSG("bad count found");
2338
            return NULL;
2339
        }
2340
2341
        if (session->peer == NULL) {
2342
            session->peer = wolfSSL_get_chain_X509(&session->chain, 0);
2343
        }
2344
        return session->peer;
2345
    }
2346
    WOLFSSL_MSG("No session passed in");
2347
2348
    return NULL;
2349
}
2350
#endif /* OPENSSL_EXTRA */
2351
#endif /* SESSION_INDEX && SESSION_CERTS */
2352
2353
2354
#ifdef WOLFSSL_SESSION_STATS
2355
2356
static int get_locked_session_stats(word32* active, word32* total, word32* peak)
2357
{
2358
    int result = WOLFSSL_SUCCESS;
2359
    int i;
2360
    int count;
2361
    int idx;
2362
    word32 now   = 0;
2363
    word32 seen  = 0;
2364
    word32 ticks = LowResTimer();
2365
2366
    WOLFSSL_ENTER("get_locked_session_stats");
2367
2368
#ifndef ENABLE_SESSION_CACHE_ROW_LOCK
2369
    SESSION_ROW_RD_LOCK(&SessionCache[0]);
2370
#endif
2371
    for (i = 0; i < SESSION_ROWS; i++) {
2372
        SessionRow* row = &SessionCache[i];
2373
    #ifdef ENABLE_SESSION_CACHE_ROW_LOCK
2374
        if (SESSION_ROW_RD_LOCK(row) != 0) {
2375
            WOLFSSL_MSG("Session row cache mutex lock failed");
2376
            return BAD_MUTEX_E;
2377
        }
2378
    #endif
2379
2380
        seen += row->totalCount;
2381
2382
        if (active == NULL) {
2383
            SESSION_ROW_UNLOCK(row);
2384
            continue;
2385
        }
2386
2387
        count = min((word32)row->totalCount, SESSIONS_PER_ROW);
2388
        idx   = row->nextIdx - 1;
2389
        if (idx < 0 || idx >= SESSIONS_PER_ROW) {
2390
            idx = SESSIONS_PER_ROW - 1; /* if back to front previous was end */
2391
        }
2392
2393
        for (; count > 0; --count) {
2394
            /* if not expired then good */
2395
#ifdef SESSION_CACHE_DYNAMIC_MEM
2396
            if (row->Sessions[idx] &&
2397
                ticks < (row->Sessions[idx]->bornOn +
2398
                            row->Sessions[idx]->timeout) )
2399
#else
2400
            if (ticks < (row->Sessions[idx].bornOn +
2401
                            row->Sessions[idx].timeout) )
2402
#endif
2403
            {
2404
                now++;
2405
            }
2406
2407
            idx = idx > 0 ? idx - 1 : SESSIONS_PER_ROW - 1;
2408
        }
2409
2410
    #ifdef ENABLE_SESSION_CACHE_ROW_LOCK
2411
        SESSION_ROW_UNLOCK(row);
2412
    #endif
2413
    }
2414
#ifndef ENABLE_SESSION_CACHE_ROW_LOCK
2415
    SESSION_ROW_UNLOCK(&SessionCache[0]);
2416
#endif
2417
2418
    if (active) {
2419
        *active = now;
2420
    }
2421
    if (total) {
2422
        *total = seen;
2423
    }
2424
2425
#ifdef WOLFSSL_PEAK_SESSIONS
2426
    if (peak) {
2427
        *peak = PeakSessions;
2428
    }
2429
#else
2430
    (void)peak;
2431
#endif
2432
2433
    WOLFSSL_LEAVE("get_locked_session_stats", result);
2434
2435
    return result;
2436
}
2437
2438
2439
/* return WOLFSSL_SUCCESS on ok */
2440
int wolfSSL_get_session_stats(word32* active, word32* total, word32* peak,
2441
                              word32* maxSessions)
2442
{
2443
    int result = WOLFSSL_SUCCESS;
2444
2445
    WOLFSSL_ENTER("wolfSSL_get_session_stats");
2446
2447
    if (maxSessions) {
2448
        *maxSessions = SESSIONS_PER_ROW * SESSION_ROWS;
2449
2450
        if (active == NULL && total == NULL && peak == NULL)
2451
            return result;  /* we're done */
2452
    }
2453
2454
    /* user must provide at least one query value */
2455
    if (active == NULL && total == NULL && peak == NULL) {
2456
        return BAD_FUNC_ARG;
2457
    }
2458
2459
    result = get_locked_session_stats(active, total, peak);
2460
2461
    WOLFSSL_LEAVE("wolfSSL_get_session_stats", result);
2462
2463
    return result;
2464
}
2465
2466
#endif /* WOLFSSL_SESSION_STATS */
2467
2468
2469
    #ifdef PRINT_SESSION_STATS
2470
2471
    /* WOLFSSL_SUCCESS on ok */
2472
    int wolfSSL_PrintSessionStats(void)
2473
    {
2474
        word32 totalSessionsSeen = 0;
2475
        word32 totalSessionsNow = 0;
2476
        word32 peak = 0;
2477
        word32 maxSessions = 0;
2478
        int    i;
2479
        int    ret;
2480
        double E;               /* expected freq */
2481
        double chiSquare = 0;
2482
2483
        ret = wolfSSL_get_session_stats(&totalSessionsNow, &totalSessionsSeen,
2484
                                        &peak, &maxSessions);
2485
        if (ret != WOLFSSL_SUCCESS)
2486
            return ret;
2487
        printf("Total Sessions Seen = %u\n", totalSessionsSeen);
2488
        printf("Total Sessions Now  = %u\n", totalSessionsNow);
2489
#ifdef WOLFSSL_PEAK_SESSIONS
2490
        printf("Peak  Sessions      = %u\n", peak);
2491
#endif
2492
        printf("Max   Sessions      = %u\n", maxSessions);
2493
2494
        E = (double)totalSessionsSeen / SESSION_ROWS;
2495
2496
        for (i = 0; i < SESSION_ROWS; i++) {
2497
            double diff = SessionCache[i].totalCount - E;
2498
            diff *= diff;                /* square    */
2499
            diff /= E;                   /* normalize */
2500
2501
            chiSquare += diff;
2502
        }
2503
        printf("  chi-square = %5.1f, d.f. = %d\n", chiSquare,
2504
                                                     SESSION_ROWS - 1);
2505
        #if (SESSION_ROWS == 11)
2506
            printf(" .05 p value =  18.3, chi-square should be less\n");
2507
        #elif (SESSION_ROWS == 211)
2508
            printf(".05 p value  = 244.8, chi-square should be less\n");
2509
        #elif (SESSION_ROWS == 5981)
2510
            printf(".05 p value  = 6161.0, chi-square should be less\n");
2511
        #elif (SESSION_ROWS == 3)
2512
            printf(".05 p value  =   6.0, chi-square should be less\n");
2513
        #elif (SESSION_ROWS == 2861)
2514
            printf(".05 p value  = 2985.5, chi-square should be less\n");
2515
        #endif
2516
        printf("\n");
2517
2518
        return ret;
2519
    }
2520
2521
    #endif /* SESSION_STATS */
2522
2523
#else  /* NO_SESSION_CACHE */
2524
2525
WOLFSSL_SESSION* ClientSessionToSession(const WOLFSSL_SESSION* session)
2526
{
2527
    return (WOLFSSL_SESSION*)session;
2528
}
2529
2530
/* No session cache version */
2531
WOLFSSL_SESSION* wolfSSL_GetSession(WOLFSSL* ssl, byte* masterSecret,
2532
        byte restoreSessionCerts)
2533
{
2534
    (void)ssl;
2535
    (void)masterSecret;
2536
    (void)restoreSessionCerts;
2537
2538
    return NULL;
2539
}
2540
2541
#endif /* NO_SESSION_CACHE */
2542
2543
#ifdef OPENSSL_EXTRA
2544
2545
   /* returns previous set cache size which stays constant */
2546
    long wolfSSL_CTX_sess_set_cache_size(WOLFSSL_CTX* ctx, long sz)
2547
    {
2548
        /* cache size fixed at compile time in wolfSSL */
2549
        (void)ctx;
2550
        (void)sz;
2551
        WOLFSSL_MSG("session cache is set at compile time");
2552
        #ifndef NO_SESSION_CACHE
2553
            return (long)(SESSIONS_PER_ROW * SESSION_ROWS);
2554
        #else
2555
            return 0;
2556
        #endif
2557
    }
2558
2559
2560
    long wolfSSL_CTX_sess_get_cache_size(WOLFSSL_CTX* ctx)
2561
    {
2562
        (void)ctx;
2563
        #ifndef NO_SESSION_CACHE
2564
            return (long)(SESSIONS_PER_ROW * SESSION_ROWS);
2565
        #else
2566
            return 0;
2567
        #endif
2568
    }
2569
2570
#endif
2571
2572
#ifndef NO_SESSION_CACHE
2573
int wolfSSL_CTX_add_session(WOLFSSL_CTX* ctx, WOLFSSL_SESSION* session)
2574
0
{
2575
0
    int    error = 0;
2576
0
    const byte* id = NULL;
2577
0
    byte idSz = 0;
2578
2579
0
    WOLFSSL_ENTER("wolfSSL_CTX_add_session");
2580
2581
0
    session = ClientSessionToSession(session);
2582
0
    if (session == NULL)
2583
0
        return WOLFSSL_FAILURE;
2584
2585
    /* Session cache is global */
2586
0
    (void)ctx;
2587
2588
0
    if (session->haveAltSessionID) {
2589
0
        id = session->altSessionID;
2590
0
        idSz = ID_LEN;
2591
0
    }
2592
0
    else {
2593
0
        id = session->sessionID;
2594
0
        idSz = session->sessionIDSz;
2595
0
    }
2596
2597
0
    error = AddSessionToCache(ctx, session, id, idSz,
2598
0
            NULL, session->side,
2599
#ifdef HAVE_SESSION_TICKET
2600
            session->ticketLen > 0,
2601
#else
2602
0
            0,
2603
0
#endif
2604
0
            NULL);
2605
2606
0
    return error == 0 ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE;
2607
0
}
2608
#endif
2609
2610
#if !defined(NO_SESSION_CACHE) && (defined(OPENSSL_EXTRA) || \
2611
        defined(HAVE_EXT_CACHE))
2612
/* stunnel 4.28 needs
2613
 *
2614
 * Callback that is called if a session tries to resume but could not find
2615
 * the session to resume it.
2616
 */
2617
void wolfSSL_CTX_sess_set_get_cb(WOLFSSL_CTX* ctx,
2618
    WOLFSSL_SESSION*(*f)(WOLFSSL*, const unsigned char*, int, int*))
2619
{
2620
    if (ctx == NULL)
2621
        return;
2622
2623
#ifdef HAVE_EXT_CACHE
2624
    ctx->get_sess_cb = f;
2625
#else
2626
    (void)f;
2627
#endif
2628
}
2629
2630
void wolfSSL_CTX_sess_set_new_cb(WOLFSSL_CTX* ctx,
2631
                             int (*f)(WOLFSSL*, WOLFSSL_SESSION*))
2632
{
2633
    if (ctx == NULL)
2634
        return;
2635
2636
#ifdef HAVE_EXT_CACHE
2637
    ctx->new_sess_cb = f;
2638
#else
2639
    (void)f;
2640
#endif
2641
}
2642
2643
void wolfSSL_CTX_sess_set_remove_cb(WOLFSSL_CTX* ctx, void (*f)(WOLFSSL_CTX*,
2644
                                                        WOLFSSL_SESSION*))
2645
{
2646
    if (ctx == NULL)
2647
        return;
2648
2649
#if defined(HAVE_EXT_CACHE) || defined(HAVE_EX_DATA)
2650
    ctx->rem_sess_cb = f;
2651
#else
2652
    (void)f;
2653
#endif
2654
}
2655
2656
2657
/*
2658
 *
2659
 * Note: It is expected that the importing and exporting function have been
2660
 *       built with the same settings. For example if session tickets was
2661
 *       enabled with the wolfSSL library exporting a session then it is
2662
 *       expected to be turned on with the wolfSSL library importing the
2663
 *       session.
2664
 */
2665
int wolfSSL_i2d_SSL_SESSION(WOLFSSL_SESSION* sess, unsigned char** p)
2666
{
2667
    int size = 0;
2668
#ifdef HAVE_EXT_CACHE
2669
    int idx = 0;
2670
#ifdef SESSION_CERTS
2671
    int i;
2672
#endif
2673
2674
    WOLFSSL_ENTER("wolfSSL_i2d_SSL_SESSION");
2675
2676
    sess = ClientSessionToSession(sess);
2677
    if (sess == NULL) {
2678
        return BAD_FUNC_ARG;
2679
    }
2680
2681
    /* side | bornOn | timeout | sessionID len | sessionID | masterSecret |
2682
     * haveEMS  */
2683
    size += OPAQUE8_LEN + OPAQUE32_LEN + OPAQUE32_LEN + OPAQUE8_LEN +
2684
            sess->sessionIDSz + SECRET_LEN + OPAQUE8_LEN;
2685
    /* altSessionID */
2686
    size += OPAQUE8_LEN + (sess->haveAltSessionID ? ID_LEN : 0);
2687
#ifdef SESSION_CERTS
2688
    /* Peer chain */
2689
    size += OPAQUE8_LEN;
2690
    for (i = 0; i < sess->chain.count; i++)
2691
        size += OPAQUE16_LEN + sess->chain.certs[i].length;
2692
#endif
2693
    /* Protocol version */
2694
    size += OPAQUE16_LEN;
2695
#if defined(SESSION_CERTS) || !defined(NO_RESUME_SUITE_CHECK) || \
2696
                        (defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET))
2697
    /* cipher suite */
2698
    size += OPAQUE16_LEN;
2699
#endif
2700
#ifndef NO_CLIENT_CACHE
2701
    /* ServerID len | ServerID */
2702
    size += OPAQUE16_LEN + sess->idLen;
2703
#endif
2704
#ifdef WOLFSSL_SESSION_ID_CTX
2705
    /* session context ID len | session context ID */
2706
    size += OPAQUE8_LEN + sess->sessionCtxSz;
2707
#endif
2708
#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
2709
    /* peerVerifyRet */
2710
    size += OPAQUE8_LEN;
2711
#endif
2712
#ifdef WOLFSSL_TLS13
2713
    /* namedGroup */
2714
    size += OPAQUE16_LEN;
2715
#endif
2716
#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
2717
#ifdef WOLFSSL_TLS13
2718
#ifdef WOLFSSL_32BIT_MILLI_TIME
2719
    /* ticketSeen | ticketAdd */
2720
    size += OPAQUE32_LEN + OPAQUE32_LEN;
2721
#else
2722
    /* ticketSeen Hi 32 bits | ticketSeen Lo 32 bits | ticketAdd */
2723
    size += OPAQUE32_LEN + OPAQUE32_LEN + OPAQUE32_LEN;
2724
#endif
2725
    /* ticketNonce */
2726
    size += OPAQUE8_LEN + sess->ticketNonce.len;
2727
#endif
2728
#ifdef WOLFSSL_EARLY_DATA
2729
    size += OPAQUE32_LEN;
2730
#endif
2731
#endif
2732
#ifdef HAVE_SESSION_TICKET
2733
    /* ticket len | ticket */
2734
    size += OPAQUE16_LEN + sess->ticketLen;
2735
#if !defined(NO_WOLFSSL_SERVER) && !defined(NO_TLS)
2736
#ifdef HAVE_SNI
2737
    /* sniHash */
2738
    size += TICKET_BINDING_HASH_SZ;
2739
#endif
2740
#ifdef HAVE_ALPN
2741
    /* alpnHash */
2742
    size += TICKET_BINDING_HASH_SZ;
2743
#endif
2744
#endif /* !NO_WOLFSSL_SERVER && !NO_TLS */
2745
#endif
2746
2747
    if (p != NULL) {
2748
        unsigned char *data;
2749
2750
        if (*p == NULL)
2751
            *p = (unsigned char*)XMALLOC((size_t)size, NULL,
2752
                                                DYNAMIC_TYPE_OPENSSL);
2753
        if (*p == NULL)
2754
            return 0;
2755
        data = *p;
2756
2757
        data[idx++] = sess->side;
2758
        c32toa(sess->bornOn, data + idx); idx += OPAQUE32_LEN;
2759
        c32toa(sess->timeout, data + idx); idx += OPAQUE32_LEN;
2760
        data[idx++] = sess->sessionIDSz;
2761
        XMEMCPY(data + idx, sess->sessionID, sess->sessionIDSz);
2762
        idx += sess->sessionIDSz;
2763
        XMEMCPY(data + idx, sess->masterSecret, SECRET_LEN); idx += SECRET_LEN;
2764
        data[idx++] = (byte)sess->haveEMS;
2765
        data[idx++] = sess->haveAltSessionID ? ID_LEN : 0;
2766
        if (sess->haveAltSessionID) {
2767
            XMEMCPY(data + idx, sess->altSessionID, ID_LEN);
2768
            idx += ID_LEN;
2769
        }
2770
#ifdef SESSION_CERTS
2771
        data[idx++] = (byte)sess->chain.count;
2772
        for (i = 0; i < sess->chain.count; i++) {
2773
            c16toa((word16)sess->chain.certs[i].length, data + idx);
2774
            idx += OPAQUE16_LEN;
2775
            XMEMCPY(data + idx, sess->chain.certs[i].buffer,
2776
                    (size_t)sess->chain.certs[i].length);
2777
            idx += sess->chain.certs[i].length;
2778
        }
2779
#endif
2780
        data[idx++] = sess->version.major;
2781
        data[idx++] = sess->version.minor;
2782
#if defined(SESSION_CERTS) || !defined(NO_RESUME_SUITE_CHECK) || \
2783
                        (defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET))
2784
        data[idx++] = sess->cipherSuite0;
2785
        data[idx++] = sess->cipherSuite;
2786
#endif
2787
#ifndef NO_CLIENT_CACHE
2788
        c16toa(sess->idLen, data + idx); idx += OPAQUE16_LEN;
2789
        XMEMCPY(data + idx, sess->serverID, sess->idLen);
2790
        idx += sess->idLen;
2791
#endif
2792
#ifdef WOLFSSL_SESSION_ID_CTX
2793
        data[idx++] = sess->sessionCtxSz;
2794
        XMEMCPY(data + idx, sess->sessionCtx, sess->sessionCtxSz);
2795
        idx += sess->sessionCtxSz;
2796
#endif
2797
#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
2798
        data[idx++] = sess->peerVerifyRet;
2799
#endif
2800
#ifdef WOLFSSL_TLS13
2801
        c16toa(sess->namedGroup, data + idx);
2802
        idx += OPAQUE16_LEN;
2803
#endif
2804
#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
2805
#ifdef WOLFSSL_TLS13
2806
#ifdef WOLFSSL_32BIT_MILLI_TIME
2807
        c32toa(sess->ticketSeen, data + idx);
2808
        idx += OPAQUE32_LEN;
2809
#else
2810
        c32toa((word32)(sess->ticketSeen >> 32), data + idx);
2811
        idx += OPAQUE32_LEN;
2812
        c32toa((word32)sess->ticketSeen, data + idx);
2813
        idx += OPAQUE32_LEN;
2814
#endif
2815
        c32toa(sess->ticketAdd, data + idx);
2816
        idx += OPAQUE32_LEN;
2817
        data[idx++] = sess->ticketNonce.len;
2818
        XMEMCPY(data + idx, sess->ticketNonce.data, sess->ticketNonce.len);
2819
        idx += sess->ticketNonce.len;
2820
#endif
2821
#ifdef WOLFSSL_EARLY_DATA
2822
        c32toa(sess->maxEarlyDataSz, data + idx);
2823
        idx += OPAQUE32_LEN;
2824
#endif
2825
#endif
2826
#ifdef HAVE_SESSION_TICKET
2827
        c16toa(sess->ticketLen, data + idx); idx += OPAQUE16_LEN;
2828
        XMEMCPY(data + idx, sess->ticket, sess->ticketLen);
2829
        idx += sess->ticketLen;
2830
#if !defined(NO_WOLFSSL_SERVER) && !defined(NO_TLS)
2831
#ifdef HAVE_SNI
2832
        XMEMCPY(data + idx, sess->sniHash, TICKET_BINDING_HASH_SZ);
2833
        idx += TICKET_BINDING_HASH_SZ;
2834
#endif
2835
#ifdef HAVE_ALPN
2836
        XMEMCPY(data + idx, sess->alpnHash, TICKET_BINDING_HASH_SZ);
2837
        idx += TICKET_BINDING_HASH_SZ;
2838
#endif
2839
#endif /* !NO_WOLFSSL_SERVER && !NO_TLS */
2840
#endif
2841
    }
2842
#endif
2843
2844
    (void)sess;
2845
    (void)p;
2846
#ifdef HAVE_EXT_CACHE
2847
    (void)idx;
2848
#endif
2849
2850
    return size;
2851
}
2852
2853
2854
/* TODO: no function to free new session.
2855
 *
2856
 * Note: It is expected that the importing and exporting function have been
2857
 *       built with the same settings. For example if session tickets was
2858
 *       enabled with the wolfSSL library exporting a session then it is
2859
 *       expected to be turned on with the wolfSSL library importing the
2860
 *       session.
2861
 */
2862
WOLFSSL_SESSION* wolfSSL_d2i_SSL_SESSION(WOLFSSL_SESSION** sess,
2863
                                const unsigned char** p, long i)
2864
{
2865
    WOLFSSL_SESSION* s = NULL;
2866
    int ret = 0;
2867
#if defined(HAVE_EXT_CACHE)
2868
    int idx = 0;
2869
    byte* data;
2870
#ifdef SESSION_CERTS
2871
    int j;
2872
    word16 length;
2873
#endif
2874
#endif /* HAVE_EXT_CACHE */
2875
2876
    (void)p;
2877
    (void)i;
2878
    (void)ret;
2879
    (void)sess;
2880
2881
#ifdef HAVE_EXT_CACHE
2882
    if (p == NULL || *p == NULL)
2883
        return NULL;
2884
2885
    s = wolfSSL_SESSION_new();
2886
    if (s == NULL)
2887
        return NULL;
2888
2889
    idx = 0;
2890
    data = (byte*)*p;
2891
2892
    /* side | bornOn | timeout | sessionID len */
2893
    if (i < OPAQUE8_LEN + OPAQUE32_LEN + OPAQUE32_LEN + OPAQUE8_LEN) {
2894
        ret = BUFFER_ERROR;
2895
        goto end;
2896
    }
2897
    s->side = data[idx++];
2898
    ato32(data + idx, &s->bornOn); idx += OPAQUE32_LEN;
2899
    ato32(data + idx, &s->timeout); idx += OPAQUE32_LEN;
2900
    s->sessionIDSz = data[idx++];
2901
    if (s->sessionIDSz > ID_LEN) {
2902
        ret = BUFFER_ERROR;
2903
        goto end;
2904
    }
2905
2906
    /* sessionID | secret | haveEMS | haveAltSessionID */
2907
    if (i - idx < s->sessionIDSz + SECRET_LEN + OPAQUE8_LEN + OPAQUE8_LEN) {
2908
        ret = BUFFER_ERROR;
2909
        goto end;
2910
    }
2911
    XMEMCPY(s->sessionID, data + idx, s->sessionIDSz);
2912
    idx  += s->sessionIDSz;
2913
    XMEMCPY(s->masterSecret, data + idx, SECRET_LEN); idx += SECRET_LEN;
2914
    s->haveEMS = data[idx++];
2915
    if (data[idx] != ID_LEN && data[idx] != 0) {
2916
        ret = BUFFER_ERROR;
2917
        goto end;
2918
    }
2919
    s->haveAltSessionID = data[idx++] == ID_LEN;
2920
2921
    /* altSessionID */
2922
    if (s->haveAltSessionID) {
2923
        if (i - idx < ID_LEN) {
2924
            ret = BUFFER_ERROR;
2925
            goto end;
2926
        }
2927
        XMEMCPY(s->altSessionID, data + idx, ID_LEN); idx += ID_LEN;
2928
    }
2929
2930
#ifdef SESSION_CERTS
2931
    /* Certificate chain */
2932
    if (i - idx == 0) {
2933
        ret = BUFFER_ERROR;
2934
        goto end;
2935
    }
2936
    s->chain.count = data[idx++];
2937
    if (s->chain.count > MAX_CHAIN_DEPTH) {
2938
        ret = BUFFER_ERROR;
2939
        goto end;
2940
    }
2941
    for (j = 0; j < s->chain.count; j++) {
2942
        if (i - idx < OPAQUE16_LEN) {
2943
            ret = BUFFER_ERROR;
2944
            goto end;
2945
        }
2946
        ato16(data + idx, &length); idx += OPAQUE16_LEN;
2947
        if (length > MAX_X509_SIZE) {
2948
            ret = BUFFER_ERROR;
2949
            goto end;
2950
        }
2951
        s->chain.certs[j].length = length;
2952
        if (i - idx < length) {
2953
            ret = BUFFER_ERROR;
2954
            goto end;
2955
        }
2956
        XMEMCPY(s->chain.certs[j].buffer, data + idx, length);
2957
        idx += length;
2958
    }
2959
#endif
2960
    /* Protocol Version */
2961
    if (i - idx < OPAQUE16_LEN) {
2962
        ret = BUFFER_ERROR;
2963
        goto end;
2964
    }
2965
    s->version.major = data[idx++];
2966
    s->version.minor = data[idx++];
2967
#if defined(SESSION_CERTS) || !defined(NO_RESUME_SUITE_CHECK) || \
2968
                        (defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET))
2969
    /* Cipher suite */
2970
    if (i - idx < OPAQUE16_LEN) {
2971
        ret = BUFFER_ERROR;
2972
        goto end;
2973
    }
2974
    s->cipherSuite0 = data[idx++];
2975
    s->cipherSuite = data[idx++];
2976
#endif
2977
#ifndef NO_CLIENT_CACHE
2978
    /* ServerID len */
2979
    if (i - idx < OPAQUE16_LEN) {
2980
        ret = BUFFER_ERROR;
2981
        goto end;
2982
    }
2983
    ato16(data + idx, &s->idLen); idx += OPAQUE16_LEN;
2984
    if (s->idLen > SERVER_ID_LEN) {
2985
        ret = BUFFER_ERROR;
2986
        goto end;
2987
    }
2988
2989
    /* ServerID */
2990
    if (i - idx < s->idLen) {
2991
        ret = BUFFER_ERROR;
2992
        goto end;
2993
    }
2994
    XMEMCPY(s->serverID, data + idx, s->idLen); idx += s->idLen;
2995
#endif
2996
#ifdef WOLFSSL_SESSION_ID_CTX
2997
    /* byte for length of session context ID */
2998
    if (i - idx < OPAQUE8_LEN) {
2999
        ret = BUFFER_ERROR;
3000
        goto end;
3001
    }
3002
    s->sessionCtxSz = data[idx++];
3003
    if (s->sessionCtxSz > ID_LEN) {
3004
        ret = BUFFER_ERROR;
3005
        goto end;
3006
    }
3007
3008
    /* app session context ID */
3009
    if (i - idx < s->sessionCtxSz) {
3010
        ret = BUFFER_ERROR;
3011
        goto end;
3012
    }
3013
    XMEMCPY(s->sessionCtx, data + idx, s->sessionCtxSz); idx += s->sessionCtxSz;
3014
#endif
3015
#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
3016
    /* byte for peerVerifyRet */
3017
    if (i - idx < OPAQUE8_LEN) {
3018
        ret = BUFFER_ERROR;
3019
        goto end;
3020
    }
3021
    s->peerVerifyRet = data[idx++];
3022
#endif
3023
#ifdef WOLFSSL_TLS13
3024
    if (i - idx < OPAQUE16_LEN) {
3025
        ret = BUFFER_ERROR;
3026
        goto end;
3027
    }
3028
    ato16(data + idx, &s->namedGroup);
3029
    idx += OPAQUE16_LEN;
3030
#endif
3031
#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
3032
#ifdef WOLFSSL_TLS13
3033
3034
#ifdef WOLFSSL_32BIT_MILLI_TIME
3035
    if (i - idx < OPAQUE32_LEN) {
3036
        ret = BUFFER_ERROR;
3037
        goto end;
3038
    }
3039
    ato32(data + idx, &s->ticketSeen);
3040
    idx += OPAQUE32_LEN;
3041
#else
3042
    if (i - idx < (OPAQUE32_LEN * 2)) {
3043
        ret = BUFFER_ERROR;
3044
        goto end;
3045
    }
3046
    {
3047
        word32 seenHi, seenLo;
3048
        ato32(data + idx, &seenHi);
3049
        idx += OPAQUE32_LEN;
3050
        ato32(data + idx, &seenLo);
3051
        idx += OPAQUE32_LEN;
3052
        s->ticketSeen = ((sword64)seenHi << 32) + seenLo;
3053
    }
3054
#endif
3055
3056
    if (i - idx < OPAQUE32_LEN) {
3057
        ret = BUFFER_ERROR;
3058
        goto end;
3059
    }
3060
    ato32(data + idx, &s->ticketAdd);
3061
    idx += OPAQUE32_LEN;
3062
    if (i - idx < OPAQUE8_LEN) {
3063
        ret = BUFFER_ERROR;
3064
        goto end;
3065
    }
3066
    s->ticketNonce.len = data[idx++];
3067
3068
    if (i - idx < s->ticketNonce.len) {
3069
        ret = BUFFER_ERROR;
3070
        goto end;
3071
    }
3072
#if defined(WOLFSSL_TICKET_NONCE_MALLOC) &&                     \
3073
    (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3)))
3074
    ret = SessionTicketNoncePopulate(s, data + idx, s->ticketNonce.len);
3075
    if (ret != 0)
3076
        goto end;
3077
#else
3078
    if (s->ticketNonce.len > MAX_TICKET_NONCE_STATIC_SZ) {
3079
        ret = BUFFER_ERROR;
3080
        goto end;
3081
    }
3082
    XMEMCPY(s->ticketNonce.data, data + idx, s->ticketNonce.len);
3083
#endif /* defined(WOLFSSL_TICKET_NONCE_MALLOC) && FIPS_VERSION_GE(5,3) */
3084
3085
    idx += s->ticketNonce.len;
3086
#endif
3087
#ifdef WOLFSSL_EARLY_DATA
3088
    if (i - idx < OPAQUE32_LEN) {
3089
        ret = BUFFER_ERROR;
3090
        goto end;
3091
    }
3092
    ato32(data + idx, &s->maxEarlyDataSz);
3093
    idx += OPAQUE32_LEN;
3094
#endif
3095
#endif
3096
#ifdef HAVE_SESSION_TICKET
3097
    /* ticket len */
3098
    if (i - idx < OPAQUE16_LEN) {
3099
        ret = BUFFER_ERROR;
3100
        goto end;
3101
    }
3102
    ato16(data + idx, &s->ticketLen); idx += OPAQUE16_LEN;
3103
3104
    /* Dispose of ol dynamic ticket and ensure space for new ticket. */
3105
    if (s->ticketLenAlloc > 0) {
3106
        XFREE(s->ticket, NULL, DYNAMIC_TYPE_SESSION_TICK);
3107
    }
3108
    if (s->ticketLen <= SESSION_TICKET_LEN)
3109
        s->ticket = s->staticTicket;
3110
    else {
3111
        s->ticket = (byte*)XMALLOC(s->ticketLen, NULL,
3112
                                   DYNAMIC_TYPE_SESSION_TICK);
3113
        if (s->ticket == NULL) {
3114
            ret = MEMORY_ERROR;
3115
            goto end;
3116
        }
3117
        s->ticketLenAlloc = (word16)s->ticketLen;
3118
    }
3119
3120
    /* ticket */
3121
    if (i - idx < s->ticketLen) {
3122
        ret = BUFFER_ERROR;
3123
        goto end;
3124
    }
3125
    XMEMCPY(s->ticket, data + idx, s->ticketLen); idx += s->ticketLen;
3126
#if !defined(NO_WOLFSSL_SERVER) && !defined(NO_TLS)
3127
#ifdef HAVE_SNI
3128
    /* sniHash - SNI binding for stateful resumption (RFC 6066 section 3) */
3129
    if (i - idx < TICKET_BINDING_HASH_SZ) {
3130
        ret = BUFFER_ERROR;
3131
        goto end;
3132
    }
3133
    XMEMCPY(s->sniHash, data + idx, TICKET_BINDING_HASH_SZ);
3134
    idx += TICKET_BINDING_HASH_SZ;
3135
#endif
3136
#ifdef HAVE_ALPN
3137
    /* alpnHash - ALPN binding for stateful resumption */
3138
    if (i - idx < TICKET_BINDING_HASH_SZ) {
3139
        ret = BUFFER_ERROR;
3140
        goto end;
3141
    }
3142
    XMEMCPY(s->alpnHash, data + idx, TICKET_BINDING_HASH_SZ);
3143
    idx += TICKET_BINDING_HASH_SZ;
3144
#endif
3145
#endif /* !NO_WOLFSSL_SERVER && !NO_TLS */
3146
#endif
3147
    (void)idx;
3148
3149
    if (sess != NULL) {
3150
        wolfSSL_FreeSession(NULL, *sess);
3151
        *sess = s;
3152
    }
3153
3154
    s->isSetup = 1;
3155
3156
    *p += idx;
3157
3158
end:
3159
    if (ret != 0 && (sess == NULL || *sess != s)) {
3160
        wolfSSL_FreeSession(NULL, s);
3161
        s = NULL;
3162
    }
3163
#endif /* HAVE_EXT_CACHE */
3164
    return s;
3165
}
3166
3167
/* Check if there is a session ticket associated with this WOLFSSL_SESSION.
3168
 *
3169
 * sess - pointer to WOLFSSL_SESSION struct
3170
 *
3171
 * Returns 1 if has session ticket, otherwise 0 */
3172
int wolfSSL_SESSION_has_ticket(const WOLFSSL_SESSION* sess)
3173
{
3174
    WOLFSSL_ENTER("wolfSSL_SESSION_has_ticket");
3175
#ifdef HAVE_SESSION_TICKET
3176
    sess = ClientSessionToSession(sess);
3177
    if (sess) {
3178
        if ((sess->ticketLen > 0) && (sess->ticket != NULL)) {
3179
            return WOLFSSL_SUCCESS;
3180
        }
3181
    }
3182
#else
3183
    (void)sess;
3184
#endif
3185
    return WOLFSSL_FAILURE;
3186
}
3187
3188
unsigned long wolfSSL_SESSION_get_ticket_lifetime_hint(
3189
                  const WOLFSSL_SESSION* sess)
3190
{
3191
    WOLFSSL_ENTER("wolfSSL_SESSION_get_ticket_lifetime_hint");
3192
    sess = ClientSessionToSession(sess);
3193
    if (sess) {
3194
        return sess->timeout;
3195
    }
3196
    return 0;
3197
}
3198
3199
long wolfSSL_SESSION_get_timeout(const WOLFSSL_SESSION* sess)
3200
{
3201
    long timeout = 0;
3202
    WOLFSSL_ENTER("wolfSSL_SESSION_get_timeout");
3203
    sess = ClientSessionToSession(sess);
3204
    if (sess)
3205
        timeout = sess->timeout;
3206
    return timeout;
3207
}
3208
3209
long wolfSSL_SSL_SESSION_set_timeout(WOLFSSL_SESSION* ses, long t)
3210
{
3211
    word32 tmptime;
3212
3213
    ses = ClientSessionToSession(ses);
3214
    if (ses == NULL || t < 0) {
3215
        return BAD_FUNC_ARG;
3216
    }
3217
3218
    tmptime = t & 0xFFFFFFFF;
3219
    ses->timeout = tmptime;
3220
3221
    return WOLFSSL_SUCCESS;
3222
}
3223
3224
long wolfSSL_SESSION_get_time(const WOLFSSL_SESSION* sess)
3225
{
3226
    long bornOn = 0;
3227
    WOLFSSL_ENTER("wolfSSL_SESSION_get_time");
3228
    sess = ClientSessionToSession(sess);
3229
    if (sess)
3230
        bornOn = sess->bornOn;
3231
    return bornOn;
3232
}
3233
3234
long wolfSSL_SESSION_set_time(WOLFSSL_SESSION *ses, long t)
3235
{
3236
3237
    ses = ClientSessionToSession(ses);
3238
    if (ses == NULL || t < 0) {
3239
        return 0;
3240
    }
3241
    ses->bornOn = (word32)t;
3242
    return t;
3243
}
3244
3245
#endif /* !NO_SESSION_CACHE && (OPENSSL_EXTRA || HAVE_EXT_CACHE) */
3246
3247
#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) || \
3248
    defined(HAVE_EX_DATA)
3249
3250
#if defined(HAVE_EX_DATA) && !defined(NO_SESSION_CACHE)
3251
static void SESSION_ex_data_cache_update(WOLFSSL_SESSION* session, int idx,
3252
        void* data, byte get, void** getRet, int* setRet)
3253
{
3254
    int row;
3255
    int i;
3256
    int error = 0;
3257
    SessionRow* sessRow = NULL;
3258
    const byte* id;
3259
    byte foundCache = 0;
3260
3261
    if (getRet != NULL)
3262
        *getRet = NULL;
3263
    if (setRet != NULL)
3264
        *setRet = WOLFSSL_FAILURE;
3265
3266
    id = session->sessionID;
3267
    if (session->haveAltSessionID)
3268
        id = session->altSessionID;
3269
    else if (session->sessionIDSz != ID_LEN) {
3270
        WOLFSSL_MSG("Incorrect sessionIDSz");
3271
        return;
3272
    }
3273
3274
    row = (int)(HashObject(id, ID_LEN, &error) % SESSION_ROWS);
3275
    if (error != 0) {
3276
        WOLFSSL_MSG("Hash session failed");
3277
        return;
3278
    }
3279
3280
    sessRow = &SessionCache[row];
3281
    if (get)
3282
        error = SESSION_ROW_RD_LOCK(sessRow);
3283
    else
3284
        error = SESSION_ROW_WR_LOCK(sessRow);
3285
    if (error != 0) {
3286
        WOLFSSL_MSG("Session row lock failed");
3287
        return;
3288
    }
3289
3290
    for (i = 0; i < SESSIONS_PER_ROW && i < sessRow->totalCount; i++) {
3291
        WOLFSSL_SESSION* cacheSession;
3292
#ifdef SESSION_CACHE_DYNAMIC_MEM
3293
        cacheSession = sessRow->Sessions[i];
3294
#else
3295
        cacheSession = &sessRow->Sessions[i];
3296
#endif
3297
        if (cacheSession && cacheSession->sessionIDSz == ID_LEN &&
3298
                XMEMCMP(id, cacheSession->sessionID, ID_LEN) == 0
3299
                && session->side == cacheSession->side
3300
                && (IsAtLeastTLSv1_3(session->version) ==
3301
                    IsAtLeastTLSv1_3(cacheSession->version))
3302
            ) {
3303
            if (get) {
3304
                if (getRet) {
3305
                    *getRet = wolfSSL_CRYPTO_get_ex_data(
3306
                        &cacheSession->ex_data, idx);
3307
                }
3308
            }
3309
            else {
3310
                if (setRet) {
3311
                    *setRet = wolfSSL_CRYPTO_set_ex_data(
3312
                        &cacheSession->ex_data, idx, data);
3313
                }
3314
            }
3315
            foundCache = 1;
3316
            break;
3317
        }
3318
    }
3319
    SESSION_ROW_UNLOCK(sessRow);
3320
    /* If we don't have a session in cache then clear the ex_data and
3321
     * own it */
3322
    if (!foundCache) {
3323
        XMEMSET(&session->ex_data, 0, sizeof(WOLFSSL_CRYPTO_EX_DATA));
3324
        session->ownExData = 1;
3325
        if (!get) {
3326
            *setRet = wolfSSL_CRYPTO_set_ex_data(&session->ex_data, idx,
3327
                    data);
3328
        }
3329
    }
3330
3331
}
3332
#endif
3333
3334
#endif
3335
3336
#ifndef NO_SESSION_CACHE
3337
/* OpenSSL-compatible return: 1 if the session was found and removed from the
3338
 * internal cache, or if the external remove callback (rem_sess_cb) was
3339
 * invoked. 0 if neither applied (not present, or null arguments). */
3340
int wolfSSL_SSL_CTX_remove_session(WOLFSSL_CTX *ctx, WOLFSSL_SESSION *s)
3341
{
3342
    int found = 0;
3343
#if defined(HAVE_EXT_CACHE) || defined(HAVE_EX_DATA)
3344
    int rem_called = FALSE;
3345
#endif
3346
3347
    WOLFSSL_ENTER("wolfSSL_SSL_CTX_remove_session");
3348
3349
    s = ClientSessionToSession(s);
3350
    if (ctx == NULL || s == NULL)
3351
        return 0;
3352
3353
#ifdef HAVE_EXT_CACHE
3354
    if (!ctx->internalCacheOff)
3355
#endif
3356
    {
3357
        const byte* id;
3358
        WOLFSSL_SESSION *sess = NULL;
3359
        word32 row = 0;
3360
        int ret;
3361
3362
        id = s->sessionID;
3363
        if (s->haveAltSessionID)
3364
            id = s->altSessionID;
3365
3366
        ret = TlsSessionCacheGetAndWrLock(id, &sess, &row, ctx->method->side);
3367
        if (ret == 0 && sess != NULL) {
3368
            found = 1;
3369
#if defined(HAVE_EXT_CACHE) || defined(HAVE_EX_DATA)
3370
            if (sess->rem_sess_cb != NULL) {
3371
                rem_called = TRUE;
3372
            }
3373
#endif
3374
            /* Call this before changing ownExData so that calls to ex_data
3375
             * don't try to access the SessionCache again. */
3376
            EvictSessionFromCache(sess);
3377
#ifdef HAVE_EX_DATA
3378
            if (sess->ownExData) {
3379
                /* Most recent version of ex data is in cache. Copy it
3380
                 * over so the user can free it. */
3381
                XMEMCPY(&s->ex_data, &sess->ex_data,
3382
                        sizeof(WOLFSSL_CRYPTO_EX_DATA));
3383
                s->ownExData = 1;
3384
                sess->ownExData = 0;
3385
            }
3386
#endif
3387
#ifdef SESSION_CACHE_DYNAMIC_MEM
3388
            {
3389
                /* Find and clear entry. Row is locked so we are good to go. */
3390
                int idx;
3391
                for (idx = 0; idx < SESSIONS_PER_ROW; idx++) {
3392
                    if (sess == SessionCache[row].Sessions[idx]) {
3393
                        XFREE(sess, sess->heap, DYNAMIC_TYPE_SESSION);
3394
                        SessionCache[row].Sessions[idx] = NULL;
3395
                        break;
3396
                    }
3397
                }
3398
            }
3399
#endif
3400
            TlsSessionCacheUnlockRow(row);
3401
        }
3402
    }
3403
3404
#if defined(HAVE_EXT_CACHE) || defined(HAVE_EX_DATA)
3405
    if (ctx->rem_sess_cb != NULL && !rem_called) {
3406
        ctx->rem_sess_cb(ctx, s);
3407
        /* Assume the external cache had the session. */
3408
        found = 1;
3409
    }
3410
#endif
3411
3412
    return found;
3413
}
3414
3415
#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) \
3416
    || defined(OPENSSL_EXTRA) || defined(HAVE_LIGHTY)
3417
WOLFSSL_SESSION *wolfSSL_SSL_get0_session(const WOLFSSL *ssl)
3418
{
3419
    WOLFSSL_ENTER("wolfSSL_SSL_get0_session");
3420
3421
    return ssl->session;
3422
}
3423
#endif /* OPENSSL_ALL || WOLFSSL_NGINX || WOLFSSL_HAPROXY ||
3424
    OPENSSL_EXTRA || HAVE_LIGHTY */
3425
3426
#endif /* NO_SESSION_CACHE */
3427
3428
#ifdef WOLFSSL_SESSION_EXPORT
3429
/* Used to import a serialized TLS session.
3430
 * WARNING: buf contains sensitive information about the state and is best to be
3431
 *          encrypted before storing if stored.
3432
 *
3433
 * @param ssl WOLFSSL structure to import the session into
3434
 * @param buf serialized session
3435
 * @param sz  size of buffer 'buf'
3436
 * @return the number of bytes read from buffer 'buf'
3437
 */
3438
int wolfSSL_tls_import(WOLFSSL* ssl, const unsigned char* buf, unsigned int sz)
3439
{
3440
    if (ssl == NULL || buf == NULL) {
3441
        return BAD_FUNC_ARG;
3442
    }
3443
    return wolfSSL_session_import_internal(ssl, buf, sz, WOLFSSL_EXPORT_TLS);
3444
}
3445
3446
3447
/* Used to export a serialized TLS session.
3448
 * WARNING: buf contains sensitive information about the state and is best to be
3449
 *          encrypted before storing if stored.
3450
 *
3451
 * @param ssl WOLFSSL structure to export the session from
3452
 * @param buf output of serialized session
3453
 * @param sz  size in bytes set in 'buf'
3454
 * @return the number of bytes written into buffer 'buf'
3455
 */
3456
int wolfSSL_tls_export(WOLFSSL* ssl, unsigned char* buf, unsigned int* sz)
3457
{
3458
    if (ssl == NULL || sz == NULL) {
3459
        return BAD_FUNC_ARG;
3460
    }
3461
    return wolfSSL_session_export_internal(ssl, buf, sz, WOLFSSL_EXPORT_TLS);
3462
}
3463
3464
#ifdef WOLFSSL_DTLS
3465
int wolfSSL_dtls_import(WOLFSSL* ssl, const unsigned char* buf, unsigned int sz)
3466
{
3467
    WOLFSSL_ENTER("wolfSSL_session_import");
3468
3469
    if (ssl == NULL || buf == NULL) {
3470
        return BAD_FUNC_ARG;
3471
    }
3472
3473
    /* sanity checks on buffer and protocol are done in internal function */
3474
    return wolfSSL_session_import_internal(ssl, buf, sz, WOLFSSL_EXPORT_DTLS);
3475
}
3476
3477
3478
/* Sets the function to call for serializing the session. This function is
3479
 * called right after the handshake is completed. */
3480
int wolfSSL_CTX_dtls_set_export(WOLFSSL_CTX* ctx, wc_dtls_export func)
3481
{
3482
3483
    WOLFSSL_ENTER("wolfSSL_CTX_dtls_set_export");
3484
3485
    /* purposefully allow func to be NULL */
3486
    if (ctx == NULL) {
3487
        return BAD_FUNC_ARG;
3488
    }
3489
3490
    ctx->dtls_export = func;
3491
3492
    return WOLFSSL_SUCCESS;
3493
}
3494
3495
/* Sets the function in WOLFSSL struct to call for serializing the session. This
3496
 * function is called right after the handshake is completed. */
3497
int wolfSSL_dtls_set_export(WOLFSSL* ssl, wc_dtls_export func)
3498
{
3499
3500
    WOLFSSL_ENTER("wolfSSL_dtls_set_export");
3501
3502
    /* purposefully allow func to be NULL */
3503
    if (ssl == NULL) {
3504
        return BAD_FUNC_ARG;
3505
    }
3506
3507
    ssl->dtls_export = func;
3508
3509
    return WOLFSSL_SUCCESS;
3510
}
3511
3512
3513
/* This function allows for directly serializing a session rather than using
3514
 * callbacks. It has less overhead by removing a temporary buffer and gives
3515
 * control over when the session gets serialized. When using callbacks the
3516
 * session is always serialized immediately after the handshake is finished.
3517
 *
3518
 * buf is the argument to contain the serialized session
3519
 * sz  is the size of the buffer passed in
3520
 * ssl is the WOLFSSL struct to serialize
3521
 * returns the size of serialized session on success, 0 on no action, and
3522
 *         negative value on error */
3523
int wolfSSL_dtls_export(WOLFSSL* ssl, unsigned char* buf, unsigned int* sz)
3524
{
3525
    WOLFSSL_ENTER("wolfSSL_dtls_export");
3526
3527
    if (ssl == NULL || sz == NULL) {
3528
        return BAD_FUNC_ARG;
3529
    }
3530
3531
    if (buf == NULL) {
3532
        *sz = MAX_EXPORT_BUFFER;
3533
        return 0;
3534
    }
3535
3536
    /* if not DTLS do nothing */
3537
    if (!ssl->options.dtls) {
3538
        WOLFSSL_MSG("Currently only DTLS export is supported");
3539
        return 0;
3540
    }
3541
3542
    /* copy over keys, options, and dtls state struct */
3543
    return wolfSSL_session_export_internal(ssl, buf, sz, WOLFSSL_EXPORT_DTLS);
3544
}
3545
3546
3547
/* This function is similar to wolfSSL_dtls_export but only exports the portion
3548
 * of the WOLFSSL structure related to the state of the connection, i.e. peer
3549
 * sequence number, epoch, AEAD state etc.
3550
 *
3551
 * buf is the argument to contain the serialized state, if null then set "sz" to
3552
 *     buffer size required
3553
 * sz  is the size of the buffer passed in
3554
 * ssl is the WOLFSSL struct to serialize
3555
 * returns the size of serialized session on success, 0 on no action, and
3556
 *         negative value on error */
3557
int wolfSSL_dtls_export_state_only(WOLFSSL* ssl, unsigned char* buf,
3558
        unsigned int* sz)
3559
{
3560
    WOLFSSL_ENTER("wolfSSL_dtls_export_state_only");
3561
3562
    if (ssl == NULL || sz == NULL) {
3563
        return BAD_FUNC_ARG;
3564
    }
3565
3566
    if (buf == NULL) {
3567
        *sz = MAX_EXPORT_STATE_BUFFER;
3568
        return 0;
3569
    }
3570
3571
    /* if not DTLS do nothing */
3572
    if (!ssl->options.dtls) {
3573
        WOLFSSL_MSG("Currently only DTLS export state is supported");
3574
        return 0;
3575
    }
3576
3577
    /* copy over keys, options, and dtls state struct */
3578
    return wolfSSL_dtls_export_state_internal(ssl, buf, *sz);
3579
}
3580
3581
3582
/* returns 0 on success */
3583
int wolfSSL_send_session(WOLFSSL* ssl)
3584
{
3585
    int ret;
3586
    byte* buf;
3587
    word32 bufSz = MAX_EXPORT_BUFFER;
3588
3589
    WOLFSSL_ENTER("wolfSSL_send_session");
3590
3591
    if (ssl == NULL) {
3592
        return BAD_FUNC_ARG;
3593
    }
3594
3595
    buf = (byte*)XMALLOC(bufSz, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
3596
    if (buf == NULL) {
3597
        return MEMORY_E;
3598
    }
3599
3600
    /* if not DTLS do nothing */
3601
    if (!ssl->options.dtls) {
3602
        XFREE(buf, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
3603
        WOLFSSL_MSG("Currently only DTLS export is supported");
3604
        return 0;
3605
    }
3606
3607
    /* copy over keys, options, and dtls state struct */
3608
    ret = wolfSSL_session_export_internal(ssl, buf, &bufSz,
3609
        WOLFSSL_EXPORT_DTLS);
3610
    if (ret < 0) {
3611
        XFREE(buf, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
3612
        return ret;
3613
    }
3614
3615
    /* if no error ret has size of buffer */
3616
    ret = ssl->dtls_export(ssl, buf, ret, NULL);
3617
    if (ret != WOLFSSL_SUCCESS) {
3618
        XFREE(buf, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
3619
        return ret;
3620
    }
3621
3622
    XFREE(buf, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
3623
    return 0;
3624
}
3625
#endif /* WOLFSSL_DTLS */
3626
#endif /* WOLFSSL_SESSION_EXPORT */
3627
3628
#ifdef OPENSSL_EXTRA
3629
3630
/* Copies the master secret over to out buffer. If outSz is 0 returns the size
3631
 * of master secret.
3632
 *
3633
 * ses : a session from completed TLS/SSL handshake
3634
 * out : buffer to hold copy of master secret
3635
 * outSz : size of out buffer
3636
 * returns : number of bytes copied into out buffer on success
3637
 *           less then or equal to 0 is considered a failure case
3638
 */
3639
int wolfSSL_SESSION_get_master_key(const WOLFSSL_SESSION* ses,
3640
        unsigned char* out, int outSz)
3641
{
3642
    int size;
3643
3644
    ses = ClientSessionToSession(ses);
3645
3646
    if (outSz == 0) {
3647
        return SECRET_LEN;
3648
    }
3649
3650
    if (ses == NULL || out == NULL || outSz < 0) {
3651
        return 0;
3652
    }
3653
3654
    if (outSz > SECRET_LEN) {
3655
        size = SECRET_LEN;
3656
    }
3657
    else {
3658
        size = outSz;
3659
    }
3660
3661
    XMEMCPY(out, ses->masterSecret, (size_t)size);
3662
    return size;
3663
}
3664
3665
3666
int wolfSSL_SESSION_get_master_key_length(const WOLFSSL_SESSION* ses)
3667
{
3668
    (void)ses;
3669
    return SECRET_LEN;
3670
}
3671
3672
#ifdef WOLFSSL_EARLY_DATA
3673
unsigned int wolfSSL_SESSION_get_max_early_data(const WOLFSSL_SESSION *session)
3674
{
3675
    if (session == NULL) {
3676
        return BAD_FUNC_ARG;
3677
    }
3678
3679
    return session->maxEarlyDataSz;
3680
}
3681
#endif /* WOLFSSL_EARLY_DATA */
3682
3683
#endif /* OPENSSL_EXTRA */
3684
3685
void SetupSession(WOLFSSL* ssl)
3686
{
3687
    WOLFSSL_SESSION* session = ssl->session;
3688
3689
    WOLFSSL_ENTER("SetupSession");
3690
3691
    if (!IsAtLeastTLSv1_3(ssl->version) && ssl->arrays != NULL) {
3692
        /* Make sure the session ID is available when the user calls any
3693
         * get_session API */
3694
        if (!session->haveAltSessionID) {
3695
            XMEMCPY(session->sessionID, ssl->arrays->sessionID, ID_LEN);
3696
            session->sessionIDSz = ssl->arrays->sessionIDSz;
3697
        }
3698
        else {
3699
            XMEMCPY(session->sessionID, session->altSessionID, ID_LEN);
3700
            session->sessionIDSz = ID_LEN;
3701
        }
3702
    }
3703
    session->side = (byte)ssl->options.side;
3704
    if (!IsAtLeastTLSv1_3(ssl->version) && ssl->arrays != NULL)
3705
        XMEMCPY(session->masterSecret, ssl->arrays->masterSecret, SECRET_LEN);
3706
    /* RFC8446 Appendix D.
3707
     *   implementations which support both TLS 1.3 and earlier versions SHOULD
3708
     *   indicate the use of the Extended Master Secret extension in their APIs
3709
     *   whenever TLS 1.3 is used.
3710
     * Set haveEMS so that we send the extension in subsequent connections that
3711
     * offer downgrades. */
3712
    if (IsAtLeastTLSv1_3(ssl->version))
3713
        session->haveEMS = 1;
3714
    else
3715
        session->haveEMS = ssl->options.haveEMS;
3716
#ifdef WOLFSSL_SESSION_ID_CTX
3717
    /* If using compatibility layer then check for and copy over session context
3718
     * id. */
3719
    if (ssl->sessionCtxSz > 0 && ssl->sessionCtxSz < ID_LEN) {
3720
        XMEMCPY(ssl->session->sessionCtx, ssl->sessionCtx, ssl->sessionCtxSz);
3721
        session->sessionCtxSz = ssl->sessionCtxSz;
3722
    }
3723
#endif
3724
#if defined(HAVE_SESSION_TICKET) && \
3725
    !defined(NO_WOLFSSL_SERVER) && !defined(NO_TLS)
3726
    /* Bind the current SNI/ALPN to the session to verify on later resumption */
3727
#ifdef HAVE_SNI
3728
    (void)TicketSniHash(ssl, session->sniHash);
3729
#endif
3730
#ifdef HAVE_ALPN
3731
    (void)TicketAlpnHash(ssl, session->alpnHash);
3732
#endif
3733
#endif /* HAVE_SESSION_TICKET && !NO_WOLFSSL_SERVER && !NO_TLS */
3734
    session->timeout = ssl->timeout;
3735
#ifndef NO_ASN_TIME
3736
    session->bornOn  = LowResTimer();
3737
#endif
3738
    session->version = ssl->version;
3739
#if defined(SESSION_CERTS) || !defined(NO_RESUME_SUITE_CHECK) || \
3740
                        (defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET))
3741
    session->cipherSuite0 = ssl->options.cipherSuite0;
3742
    session->cipherSuite = ssl->options.cipherSuite;
3743
#endif
3744
#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
3745
    session->peerVerifyRet = (byte)ssl->peerVerifyRet;
3746
#endif
3747
    session->isSetup = 1;
3748
}
3749
3750
#ifdef WOLFSSL_SESSION_ID_CTX
3751
    /* Storing app session context id, this value is inherited by WOLFSSL
3752
     * objects created from WOLFSSL_CTX. Any session that is imported with a
3753
     * different session context id will be rejected.
3754
     *
3755
     * ctx         structure to set context in
3756
     * sid_ctx     value of context to set
3757
     * sid_ctx_len length of sid_ctx buffer
3758
     *
3759
     * Returns WOLFSSL_SUCCESS in success case and WOLFSSL_FAILURE when failing
3760
     */
3761
    int wolfSSL_CTX_set_session_id_context(WOLFSSL_CTX* ctx,
3762
                                           const unsigned char* sid_ctx,
3763
                                           unsigned int sid_ctx_len)
3764
    {
3765
        WOLFSSL_ENTER("wolfSSL_CTX_set_session_id_context");
3766
3767
        /* No application specific context needed for wolfSSL */
3768
        if (sid_ctx_len > ID_LEN || ctx == NULL || sid_ctx == NULL) {
3769
            return WOLFSSL_FAILURE;
3770
        }
3771
        XMEMCPY(ctx->sessionCtx, sid_ctx, sid_ctx_len);
3772
        ctx->sessionCtxSz = (byte)sid_ctx_len;
3773
3774
        return WOLFSSL_SUCCESS;
3775
    }
3776
3777
3778
3779
    /* Storing app session context id. Any session that is imported with a
3780
     * different session context id will be rejected.
3781
     *
3782
     * ssl  structure to set context in
3783
     * id   value of context to set
3784
     * len  length of sid_ctx buffer
3785
     *
3786
     * Returns WOLFSSL_SUCCESS in success case and WOLFSSL_FAILURE when failing
3787
     */
3788
    int wolfSSL_set_session_id_context(WOLFSSL* ssl, const unsigned char* id,
3789
                                   unsigned int len)
3790
    {
3791
        WOLFSSL_ENTER("wolfSSL_set_session_id_context");
3792
3793
        if (len > ID_LEN || ssl == NULL || id == NULL) {
3794
            return WOLFSSL_FAILURE;
3795
        }
3796
        XMEMCPY(ssl->sessionCtx, id, len);
3797
        ssl->sessionCtxSz = (byte)len;
3798
3799
        return WOLFSSL_SUCCESS;
3800
    }
3801
#endif
3802
3803
/* return a new malloc'd session with default settings on success */
3804
WOLFSSL_SESSION* wolfSSL_NewSession(void* heap)
3805
0
{
3806
0
    WOLFSSL_SESSION* ret = NULL;
3807
3808
0
    WOLFSSL_ENTER("wolfSSL_NewSession");
3809
3810
0
    ret = (WOLFSSL_SESSION*)XMALLOC(sizeof(WOLFSSL_SESSION), heap,
3811
0
            DYNAMIC_TYPE_SESSION);
3812
0
    if (ret != NULL) {
3813
0
        int err;
3814
0
        XMEMSET(ret, 0, sizeof(WOLFSSL_SESSION));
3815
0
        wolfSSL_RefInit(&ret->ref, &err);
3816
    #ifdef WOLFSSL_REFCNT_ERROR_RETURN
3817
        if (err != 0) {
3818
            WOLFSSL_MSG("Error setting up session reference mutex");
3819
            XFREE(ret, ret->heap, DYNAMIC_TYPE_SESSION);
3820
            return NULL;
3821
        }
3822
    #else
3823
0
        (void)err;
3824
0
    #endif
3825
0
#ifndef NO_SESSION_CACHE
3826
0
        ret->cacheRow = INVALID_SESSION_ROW; /* not in cache */
3827
0
#endif
3828
0
        ret->type = WOLFSSL_SESSION_TYPE_HEAP;
3829
0
        ret->heap = heap;
3830
#ifdef WOLFSSL_CHECK_MEM_ZERO
3831
        wc_MemZero_Add("SESSION master secret", ret->masterSecret, SECRET_LEN);
3832
        wc_MemZero_Add("SESSION id", ret->sessionID, ID_LEN);
3833
#endif
3834
    #ifdef HAVE_SESSION_TICKET
3835
        ret->ticket = ret->staticTicket;
3836
        #if defined(WOLFSSL_TLS13) && defined(WOLFSSL_TICKET_NONCE_MALLOC) &&  \
3837
    (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3)))
3838
        ret->ticketNonce.data = ret->ticketNonce.dataStatic;
3839
        #endif
3840
    #endif
3841
#ifdef HAVE_EX_DATA
3842
        ret->ownExData = 1;
3843
        #ifdef HAVE_EX_DATA_CRYPTO
3844
        if (crypto_ex_cb_ctx_session != NULL) {
3845
            crypto_ex_cb_setup_new_data(ret, crypto_ex_cb_ctx_session,
3846
                    &ret->ex_data);
3847
        }
3848
        #endif
3849
#endif
3850
0
    }
3851
0
    return ret;
3852
0
}
3853
3854
3855
WOLFSSL_SESSION* wolfSSL_SESSION_new_ex(void* heap)
3856
0
{
3857
0
    return wolfSSL_NewSession(heap);
3858
0
}
3859
3860
WOLFSSL_SESSION* wolfSSL_SESSION_new(void)
3861
0
{
3862
0
    return wolfSSL_SESSION_new_ex(NULL);
3863
0
}
3864
3865
/* add one to session reference count
3866
 * return WOLFSSL_SUCCESS on success and WOLFSSL_FAILURE on error */
3867
int wolfSSL_SESSION_up_ref(WOLFSSL_SESSION* session)
3868
0
{
3869
0
    int ret;
3870
3871
0
    session = ClientSessionToSession(session);
3872
3873
0
    if (session == NULL || session->type != WOLFSSL_SESSION_TYPE_HEAP)
3874
0
        return WOLFSSL_FAILURE;
3875
3876
0
    wolfSSL_RefInc(&session->ref, &ret);
3877
#ifdef WOLFSSL_REFCNT_ERROR_RETURN
3878
    if (ret != 0) {
3879
        WOLFSSL_MSG("Failed to lock session mutex");
3880
        return WOLFSSL_FAILURE;
3881
    }
3882
#else
3883
0
    (void)ret;
3884
0
#endif
3885
3886
0
    return WOLFSSL_SUCCESS;
3887
0
}
3888
3889
/**
3890
 * Deep copy the contents from input to output.
3891
 * @param input         The source of the copy.
3892
 * @param output        The destination of the copy.
3893
 * @param avoidSysCalls If true, then system calls will be avoided or an error
3894
 *                      will be returned if it is not possible to proceed
3895
 *                      without a system call. This is useful for fetching
3896
 *                      sessions from cache. When a cache row is locked, we
3897
 *                      don't want to block other threads with long running
3898
 *                      system calls.
3899
 * @param transferExData If true, the output takes over the input's ex_data.
3900
 *                      Set false when the caller keeps the output and the
3901
 *                      input's ex_data stays owned elsewhere, e.g. the cache.
3902
 * @param ticketNonceBuf If not null and @avoidSysCalls is true, the copy of the
3903
 *                      ticketNonce will happen in this pre allocated buffer
3904
 * @param ticketNonceLen @ticketNonceBuf len as input, used length on output
3905
 * @param ticketNonceUsed if @ticketNonceBuf was used to copy the ticket nonce
3906
 * @return              WOLFSSL_SUCCESS on success
3907
 *                      WOLFSSL_FAILURE on failure
3908
 */
3909
static int wolfSSL_DupSessionEx(const WOLFSSL_SESSION* input,
3910
    WOLFSSL_SESSION* output, int avoidSysCalls, int transferExData,
3911
    byte* ticketNonceBuf, byte* ticketNonceLen, byte* preallocUsed)
3912
0
{
3913
#ifdef HAVE_SESSION_TICKET
3914
    word16 ticLenAlloc = 0;
3915
    byte *ticBuff = NULL;
3916
#endif
3917
#ifdef HAVE_EX_DATA
3918
    WOLFSSL_CRYPTO_EX_DATA exData;
3919
#endif
3920
0
    const size_t copyOffset = WC_OFFSETOF(WOLFSSL_SESSION, heap) +
3921
0
        sizeof(input->heap);
3922
0
    int ret = WOLFSSL_SUCCESS;
3923
3924
0
    (void)avoidSysCalls;
3925
0
    (void)transferExData;
3926
0
    (void)ticketNonceBuf;
3927
0
    (void)ticketNonceLen;
3928
0
    (void)preallocUsed;
3929
3930
0
    input = ClientSessionToSession(input);
3931
0
    output = ClientSessionToSession(output);
3932
3933
0
    if (input == NULL || output == NULL || input == output) {
3934
0
        WOLFSSL_MSG("input or output are null or same");
3935
0
        return WOLFSSL_FAILURE;
3936
0
    }
3937
3938
#ifdef HAVE_SESSION_TICKET
3939
    if (output->ticket != output->staticTicket) {
3940
        ticBuff = output->ticket;
3941
        ticLenAlloc = output->ticketLenAlloc;
3942
    }
3943
#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_TICKET_NONCE_MALLOC) &&          \
3944
    (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3)))
3945
        /* free the data, it would be better to reuse the buffer but this
3946
         * maintain the code simpler. A smart allocator should reuse the free'd
3947
         * buffer in the next malloc without much performance penalties. */
3948
    if (output->ticketNonce.data != output->ticketNonce.dataStatic) {
3949
3950
        /*  Callers that avoid syscall should never calls this with
3951
         * output->tickeNonce.data being a dynamic buffer.*/
3952
        if (avoidSysCalls) {
3953
            WOLFSSL_MSG("can't avoid syscalls with dynamic TicketNonce buffer");
3954
            return WOLFSSL_FAILURE;
3955
        }
3956
3957
        XFREE(output->ticketNonce.data,
3958
            output->heap, DYNAMIC_TYPE_SESSION_TICK);
3959
        output->ticketNonce.data = output->ticketNonce.dataStatic;
3960
        output->ticketNonce.len = 0;
3961
    }
3962
#endif /* WOLFSSL_TLS13 && WOLFSSL_TICKET_NONCE_MALLOC && FIPS_VERSION_GE(5,3)*/
3963
#endif /* HAVE_SESSION_TICKET */
3964
3965
#if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA)
3966
    if (output->peer != NULL) {
3967
        if (avoidSysCalls) {
3968
            WOLFSSL_MSG("Can't free cert when avoiding syscalls");
3969
            return WOLFSSL_FAILURE;
3970
        }
3971
        wolfSSL_X509_free(output->peer);
3972
        output->peer = NULL;
3973
    }
3974
#endif
3975
3976
#ifdef HAVE_EX_DATA
3977
    /* ex_data sits after the heap member so the copy below carries over the
3978
     * input's pointers. Stash the output's to put them back. */
3979
    if (!transferExData)
3980
        XMEMCPY(&exData, &output->ex_data, sizeof(exData));
3981
#endif
3982
3983
0
    XMEMCPY((byte*)output + copyOffset, (byte*)input + copyOffset,
3984
0
            sizeof(WOLFSSL_SESSION) - copyOffset);
3985
3986
#if defined(HAVE_SESSION_TICKET) && defined(WOLFSSL_TLS13) &&                  \
3987
    defined(WOLFSSL_TICKET_NONCE_MALLOC) &&                                    \
3988
    (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3)))
3989
    /* fix pointer to static after the copy  */
3990
    output->ticketNonce.data = output->ticketNonce.dataStatic;
3991
#endif
3992
    /* Set sane values for copy */
3993
0
#ifndef NO_SESSION_CACHE
3994
0
    if (output->type != WOLFSSL_SESSION_TYPE_CACHE)
3995
0
        output->cacheRow = INVALID_SESSION_ROW;
3996
0
#endif
3997
#if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA)
3998
    if (input->peer != NULL && input->peer->dynamicMemory) {
3999
        if (wolfSSL_X509_up_ref(input->peer) != WOLFSSL_SUCCESS) {
4000
            WOLFSSL_MSG("Can't increase peer cert ref count");
4001
            output->peer = NULL;
4002
        }
4003
    }
4004
    else if (!avoidSysCalls)
4005
        output->peer = wolfSSL_X509_dup(input->peer);
4006
    else
4007
        /* output->peer is not that important to copy */
4008
        output->peer = NULL;
4009
#endif
4010
#ifdef HAVE_SESSION_TICKET
4011
    if (input->ticketLen > SESSION_TICKET_LEN) {
4012
        /* Need dynamic buffer */
4013
        if (ticBuff == NULL || ticLenAlloc < input->ticketLen) {
4014
            /* allocate new one */
4015
            byte* tmp;
4016
            if (avoidSysCalls) {
4017
                WOLFSSL_MSG("Failed to allocate memory for ticket when avoiding"
4018
                        " syscalls");
4019
                output->ticket = ticBuff;
4020
                output->ticketLenAlloc = (word16) ticLenAlloc;
4021
                output->ticketLen = 0;
4022
                ret = WOLFSSL_FAILURE;
4023
            }
4024
            else {
4025
#ifdef WOLFSSL_NO_REALLOC
4026
                tmp = (byte*)XMALLOC(input->ticketLen,
4027
                        output->heap, DYNAMIC_TYPE_SESSION_TICK);
4028
                XFREE(ticBuff, output->heap, DYNAMIC_TYPE_SESSION_TICK);
4029
                ticBuff = NULL;
4030
#else
4031
                tmp = (byte*)XREALLOC(ticBuff, input->ticketLen,
4032
                        output->heap, DYNAMIC_TYPE_SESSION_TICK);
4033
#endif /* WOLFSSL_NO_REALLOC */
4034
                if (tmp == NULL) {
4035
                    WOLFSSL_MSG("Failed to allocate memory for ticket");
4036
#ifndef WOLFSSL_NO_REALLOC
4037
                    XFREE(ticBuff, output->heap, DYNAMIC_TYPE_SESSION_TICK);
4038
                    ticBuff = NULL;
4039
#endif /* WOLFSSL_NO_REALLOC */
4040
                    output->ticket = NULL;
4041
                    output->ticketLen = 0;
4042
                    output->ticketLenAlloc = 0;
4043
                    ret = WOLFSSL_FAILURE;
4044
                }
4045
                else {
4046
                    ticBuff = tmp;
4047
                    ticLenAlloc = input->ticketLen;
4048
                }
4049
            }
4050
        }
4051
        if (ticBuff != NULL && ret == WOLFSSL_SUCCESS) {
4052
            XMEMCPY(ticBuff, input->ticket, input->ticketLen);
4053
            output->ticket = ticBuff;
4054
            output->ticketLenAlloc = (word16) ticLenAlloc;
4055
        }
4056
    }
4057
    else {
4058
        /* Default ticket to non dynamic */
4059
        if (avoidSysCalls) {
4060
            /* Try to use ticBuf if available. Caller can later move it to
4061
             * the static buffer. */
4062
            if (ticBuff != NULL) {
4063
                if (ticLenAlloc >= input->ticketLen) {
4064
                    output->ticket = ticBuff;
4065
                    output->ticketLenAlloc = ticLenAlloc;
4066
                }
4067
                else {
4068
                    WOLFSSL_MSG("ticket dynamic buffer too small but we are "
4069
                                "avoiding system calls");
4070
                    ret = WOLFSSL_FAILURE;
4071
                    output->ticket = ticBuff;
4072
                    output->ticketLenAlloc = (word16) ticLenAlloc;
4073
                    output->ticketLen = 0;
4074
                }
4075
            }
4076
            else {
4077
                output->ticket = output->staticTicket;
4078
                output->ticketLenAlloc = 0;
4079
            }
4080
        }
4081
        else {
4082
            XFREE(ticBuff, output->heap, DYNAMIC_TYPE_SESSION_TICK);
4083
            output->ticket = output->staticTicket;
4084
            output->ticketLenAlloc = 0;
4085
        }
4086
        if (input->ticketLenAlloc > 0 && ret == WOLFSSL_SUCCESS) {
4087
            /* Shouldn't happen as session should have placed this in
4088
             * the static buffer */
4089
            XMEMCPY(output->ticket, input->ticket,
4090
                    input->ticketLen);
4091
        }
4092
    }
4093
    ticBuff = NULL;
4094
4095
#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_TICKET_NONCE_MALLOC) &&          \
4096
    (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3)))
4097
    if (preallocUsed != NULL)
4098
        *preallocUsed = 0;
4099
4100
    if (input->ticketNonce.len > MAX_TICKET_NONCE_STATIC_SZ &&
4101
        ret == WOLFSSL_SUCCESS) {
4102
        /* TicketNonce does not fit in the static buffer */
4103
        if (!avoidSysCalls) {
4104
            output->ticketNonce.data = (byte*)XMALLOC(input->ticketNonce.len,
4105
                output->heap, DYNAMIC_TYPE_SESSION_TICK);
4106
4107
            if (output->ticketNonce.data == NULL) {
4108
                WOLFSSL_MSG("Failed to allocate space for ticket nonce");
4109
                output->ticketNonce.data = output->ticketNonce.dataStatic;
4110
                output->ticketNonce.len = 0;
4111
                ret = WOLFSSL_FAILURE;
4112
            }
4113
            else {
4114
                output->ticketNonce.len = input->ticketNonce.len;
4115
                XMEMCPY(output->ticketNonce.data, input->ticketNonce.data,
4116
                    input->ticketNonce.len);
4117
                ret = WOLFSSL_SUCCESS;
4118
            }
4119
        }
4120
        /* we can't do syscalls. Use prealloc buffers if provided from the
4121
         * caller. */
4122
        else if (ticketNonceBuf != NULL &&
4123
                 *ticketNonceLen >= input->ticketNonce.len) {
4124
            XMEMCPY(ticketNonceBuf, input->ticketNonce.data,
4125
                input->ticketNonce.len);
4126
            *ticketNonceLen = input->ticketNonce.len;
4127
            if (preallocUsed != NULL)
4128
                *preallocUsed = 1;
4129
            ret = WOLFSSL_SUCCESS;
4130
        }
4131
        else {
4132
            WOLFSSL_MSG("TicketNonce bigger than static buffer, and we can't "
4133
                        "do syscalls");
4134
            ret = WOLFSSL_FAILURE;
4135
        }
4136
    }
4137
#endif /* WOLFSSL_TLS13 && WOLFSSL_TICKET_NONCE_MALLOC && FIPS_VERSION_GE(5,3)*/
4138
4139
#endif /* HAVE_SESSION_TICKET */
4140
4141
#ifdef HAVE_EX_DATA_CRYPTO
4142
    if (transferExData && input->type != WOLFSSL_SESSION_TYPE_CACHE &&
4143
            output->type != WOLFSSL_SESSION_TYPE_CACHE) {
4144
        /* Not called with cache as that passes ownership of ex_data */
4145
        ret = crypto_ex_cb_dup_data(&input->ex_data, &output->ex_data,
4146
                                    crypto_ex_cb_ctx_session);
4147
    }
4148
#endif
4149
4150
#ifdef HAVE_EX_DATA
4151
    if (!transferExData)
4152
        XMEMCPY(&output->ex_data, &exData, sizeof(exData));
4153
#endif
4154
4155
0
    return ret;
4156
0
}
4157
4158
/**
4159
 * Deep copy the contents from input to output.
4160
 * @param input         The source of the copy.
4161
 * @param output        The destination of the copy.
4162
 * @param avoidSysCalls If true, then system calls will be avoided or an error
4163
 *                      will be returned if it is not possible to proceed
4164
 *                      without a system call. This is useful for fetching
4165
 *                      sessions from cache. When a cache row is locked, we
4166
 *                      don't want to block other threads with long running
4167
 *                      system calls.
4168
 * @return              WOLFSSL_SUCCESS on success
4169
 *                      WOLFSSL_FAILURE on failure
4170
 */
4171
int wolfSSL_DupSession(const WOLFSSL_SESSION* input, WOLFSSL_SESSION* output,
4172
        int avoidSysCalls)
4173
0
{
4174
0
    return wolfSSL_DupSessionEx(input, output, avoidSysCalls, 1, NULL, NULL,
4175
0
        NULL);
4176
0
}
4177
4178
WOLFSSL_SESSION* wolfSSL_SESSION_dup(WOLFSSL_SESSION* session)
4179
0
{
4180
0
    WOLFSSL_SESSION* copy;
4181
4182
0
    WOLFSSL_ENTER("wolfSSL_SESSION_dup");
4183
4184
0
    session = ClientSessionToSession(session);
4185
0
    if (session == NULL)
4186
0
        return NULL;
4187
4188
#ifdef HAVE_SESSION_TICKET
4189
    if (session->ticketLenAlloc > 0 && !session->ticket) {
4190
        WOLFSSL_MSG("Session dynamic flag is set but ticket pointer is null");
4191
        return NULL;
4192
    }
4193
#endif
4194
4195
0
    copy = wolfSSL_NewSession(session->heap);
4196
0
    if (copy != NULL &&
4197
0
            wolfSSL_DupSession(session, copy, 0) != WOLFSSL_SUCCESS) {
4198
0
        wolfSSL_FreeSession(NULL, copy);
4199
0
        copy = NULL;
4200
0
    }
4201
0
    return copy;
4202
0
}
4203
4204
void wolfSSL_FreeSession(WOLFSSL_CTX* ctx, WOLFSSL_SESSION* session)
4205
{
4206
    session = ClientSessionToSession(session);
4207
    if (session == NULL)
4208
        return;
4209
4210
    (void)ctx;
4211
4212
    WOLFSSL_ENTER("wolfSSL_FreeSession");
4213
4214
    if (session->ref.count > 0) {
4215
        int ret;
4216
        int isZero;
4217
        wolfSSL_RefDec(&session->ref, &isZero, &ret);
4218
        (void)ret;
4219
        if (!isZero) {
4220
            return;
4221
        }
4222
        wolfSSL_RefFree(&session->ref);
4223
    }
4224
4225
    WOLFSSL_MSG("wolfSSL_FreeSession full free");
4226
4227
#ifdef HAVE_EX_DATA_CRYPTO
4228
    if (session->ownExData) {
4229
        crypto_ex_cb_free_data(session, crypto_ex_cb_ctx_session,
4230
                &session->ex_data);
4231
    }
4232
#endif
4233
4234
#ifdef HAVE_EX_DATA_CLEANUP_HOOKS
4235
    wolfSSL_CRYPTO_cleanup_ex_data(&session->ex_data);
4236
#endif
4237
4238
#if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA)
4239
    if (session->peer) {
4240
        wolfSSL_X509_free(session->peer);
4241
        session->peer = NULL;
4242
    }
4243
#endif
4244
4245
#ifdef HAVE_SESSION_TICKET
4246
    if (session->ticketLenAlloc > 0) {
4247
        XFREE(session->ticket, session->heap, DYNAMIC_TYPE_SESSION_TICK);
4248
        session->ticket = session->staticTicket;
4249
        session->ticketLen = 0;
4250
        session->ticketLenAlloc = 0;
4251
    }
4252
#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_TICKET_NONCE_MALLOC) &&          \
4253
    (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3)))
4254
    if (session->ticketNonce.data != session->ticketNonce.dataStatic) {
4255
        XFREE(session->ticketNonce.data, session->heap,
4256
            DYNAMIC_TYPE_SESSION_TICK);
4257
        session->ticketNonce.data = session->ticketNonce.dataStatic;
4258
        session->ticketNonce.len = 0;
4259
    }
4260
#endif /* WOLFSSL_TLS13 && WOLFSSL_TICKET_NONCE_MALLOC && FIPS_VERSION_GE(5,3)*/
4261
#endif
4262
4263
#ifdef HAVE_EX_DATA_CLEANUP_HOOKS
4264
    wolfSSL_CRYPTO_cleanup_ex_data(&session->ex_data);
4265
#endif
4266
4267
    /* Make sure masterSecret is zeroed. */
4268
    ForceZero(session->masterSecret, SECRET_LEN);
4269
    /* Session ID is sensitive information too. */
4270
    ForceZero(session->sessionID, ID_LEN);
4271
4272
    if (session->type == WOLFSSL_SESSION_TYPE_HEAP) {
4273
        /* // NOLINTNEXTLINE(clang-analyzer-unix.Malloc) */
4274
        XFREE(session, session->heap, DYNAMIC_TYPE_SESSION);
4275
    }
4276
}
4277
4278
/* DO NOT use this API internally. Use wolfSSL_FreeSession directly instead
4279
 * and pass in the ctx parameter if possible (like from ssl->ctx). */
4280
void wolfSSL_SESSION_free(WOLFSSL_SESSION* session)
4281
0
{
4282
0
    session = ClientSessionToSession(session);
4283
0
    wolfSSL_FreeSession(NULL, session);
4284
0
}
4285
4286
#if defined(OPENSSL_EXTRA) || defined(HAVE_EXT_CACHE)
4287
4288
/**
4289
* set cipher to WOLFSSL_SESSION from WOLFSSL_CIPHER
4290
* @param session  a pointer to WOLFSSL_SESSION structure
4291
* @param cipher   a function pointer to WOLFSSL_CIPHER
4292
* @return WOLFSSL_SUCCESS on success, otherwise WOLFSSL_FAILURE
4293
*/
4294
int wolfSSL_SESSION_set_cipher(WOLFSSL_SESSION* session,
4295
                                            const WOLFSSL_CIPHER* cipher)
4296
{
4297
    WOLFSSL_ENTER("wolfSSL_SESSION_set_cipher");
4298
4299
    session = ClientSessionToSession(session);
4300
    /* sanity check */
4301
    if (session == NULL || cipher == NULL) {
4302
        WOLFSSL_MSG("bad argument");
4303
        return WOLFSSL_FAILURE;
4304
    }
4305
    session->cipherSuite0 = cipher->cipherSuite0;
4306
    session->cipherSuite  = cipher->cipherSuite;
4307
4308
    WOLFSSL_LEAVE("wolfSSL_SESSION_set_cipher", WOLFSSL_SUCCESS);
4309
    return WOLFSSL_SUCCESS;
4310
}
4311
#endif /* OPENSSL_EXTRA || HAVE_EXT_CACHE */
4312
4313
const char* wolfSSL_SESSION_CIPHER_get_name(const WOLFSSL_SESSION* session)
4314
0
{
4315
0
    session = ClientSessionToSession(session);
4316
0
    if (session == NULL) {
4317
0
        return NULL;
4318
0
    }
4319
4320
0
#if defined(SESSION_CERTS) || !defined(NO_RESUME_SUITE_CHECK) || \
4321
0
                        (defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET))
4322
0
    #if !defined(WOLFSSL_CIPHER_INTERNALNAME) && !defined(NO_ERROR_STRINGS)
4323
0
        return GetCipherNameIana(session->cipherSuite0, session->cipherSuite);
4324
    #else
4325
        return GetCipherNameInternal(session->cipherSuite0,
4326
            session->cipherSuite);
4327
    #endif
4328
#else
4329
    return NULL;
4330
#endif
4331
0
}
4332
4333
#if defined(OPENSSL_ALL) || defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_NGINX)
4334
const unsigned char *wolfSSL_SESSION_get0_id_context(
4335
                      const WOLFSSL_SESSION *sess, unsigned int *sid_ctx_length)
4336
{
4337
    return wolfSSL_SESSION_get_id((WOLFSSL_SESSION *)sess, sid_ctx_length);
4338
}
4339
int wolfSSL_SESSION_set1_id(WOLFSSL_SESSION *s,
4340
                                 const unsigned char *sid, unsigned int sid_len)
4341
{
4342
    if (s == NULL) {
4343
        return WOLFSSL_FAILURE;
4344
    }
4345
    if (sid_len > ID_LEN) {
4346
        return WOLFSSL_FAILURE;
4347
    }
4348
4349
    s->sessionIDSz = (byte)sid_len;
4350
    if (sid != s->sessionID) {
4351
        XMEMCPY(s->sessionID, sid, sid_len);
4352
    }
4353
    return WOLFSSL_SUCCESS;
4354
}
4355
4356
int wolfSSL_SESSION_set1_id_context(WOLFSSL_SESSION *s,
4357
                         const unsigned char *sid_ctx, unsigned int sid_ctx_len)
4358
{
4359
    if (s == NULL) {
4360
        return WOLFSSL_FAILURE;
4361
    }
4362
    if (sid_ctx_len > ID_LEN) {
4363
        return WOLFSSL_FAILURE;
4364
    }
4365
    s->sessionCtxSz = (byte)sid_ctx_len;
4366
    if (sid_ctx != s->sessionCtx) {
4367
        XMEMCPY(s->sessionCtx, sid_ctx, sid_ctx_len);
4368
    }
4369
4370
    return WOLFSSL_SUCCESS;
4371
}
4372
4373
#endif
4374
4375
#ifdef OPENSSL_EXTRA
4376
4377
/* Return the total number of sessions */
4378
long wolfSSL_CTX_sess_number(WOLFSSL_CTX* ctx)
4379
{
4380
    word32 total = 0;
4381
4382
    WOLFSSL_ENTER("wolfSSL_CTX_sess_number");
4383
    (void)ctx;
4384
4385
#if defined(WOLFSSL_SESSION_STATS) && !defined(NO_SESSION_CACHE)
4386
    if (wolfSSL_get_session_stats(NULL, &total, NULL, NULL) !=
4387
            WOLFSSL_SUCCESS) {
4388
        WOLFSSL_MSG("Error getting session stats");
4389
    }
4390
#else
4391
    WOLFSSL_MSG("Please use macro WOLFSSL_SESSION_STATS for session stats");
4392
#endif
4393
4394
    return (long)total;
4395
}
4396
4397
#endif
4398
4399
#ifdef SESSION_CERTS
4400
4401
/* get session ID */
4402
WOLFSSL_ABI
4403
const byte* wolfSSL_get_sessionID(const WOLFSSL_SESSION* session)
4404
{
4405
    WOLFSSL_ENTER("wolfSSL_get_sessionID");
4406
    session = ClientSessionToSession(session);
4407
    if (session)
4408
        return session->sessionID;
4409
4410
    return NULL;
4411
}
4412
4413
#endif
4414
4415
#ifdef HAVE_EX_DATA
4416
4417
int wolfSSL_SESSION_set_ex_data(WOLFSSL_SESSION* session, int idx, void* data)
4418
{
4419
    int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE);
4420
    WOLFSSL_ENTER("wolfSSL_SESSION_set_ex_data");
4421
#ifdef HAVE_EX_DATA
4422
    session = ClientSessionToSession(session);
4423
    if (session != NULL) {
4424
#ifndef NO_SESSION_CACHE
4425
        if (!session->ownExData) {
4426
            /* Need to update in cache */
4427
            SESSION_ex_data_cache_update(session, idx, data, 0, NULL, &ret);
4428
        }
4429
        else
4430
#endif
4431
        {
4432
            ret = wolfSSL_CRYPTO_set_ex_data(&session->ex_data, idx, data);
4433
        }
4434
    }
4435
#else
4436
    (void)session;
4437
    (void)idx;
4438
    (void)data;
4439
#endif
4440
    return ret;
4441
}
4442
4443
#ifdef HAVE_EX_DATA_CLEANUP_HOOKS
4444
int wolfSSL_SESSION_set_ex_data_with_cleanup(
4445
    WOLFSSL_SESSION* session,
4446
    int idx,
4447
    void* data,
4448
    wolfSSL_ex_data_cleanup_routine_t cleanup_routine)
4449
{
4450
    WOLFSSL_ENTER("wolfSSL_SESSION_set_ex_data_with_cleanup");
4451
    session = ClientSessionToSession(session);
4452
    if(session != NULL) {
4453
        return wolfSSL_CRYPTO_set_ex_data_with_cleanup(&session->ex_data, idx,
4454
                                                       data, cleanup_routine);
4455
    }
4456
    return WOLFSSL_FAILURE;
4457
}
4458
#endif /* HAVE_EX_DATA_CLEANUP_HOOKS */
4459
4460
void* wolfSSL_SESSION_get_ex_data(const WOLFSSL_SESSION* session, int idx)
4461
{
4462
    void* ret = NULL;
4463
    WOLFSSL_ENTER("wolfSSL_SESSION_get_ex_data");
4464
#ifdef HAVE_EX_DATA
4465
    session = ClientSessionToSession(session);
4466
    if (session != NULL) {
4467
#ifndef NO_SESSION_CACHE
4468
        if (!session->ownExData) {
4469
            /* Need to retrieve the data from the session cache */
4470
            SESSION_ex_data_cache_update((WOLFSSL_SESSION*)session, idx, NULL,
4471
                                         1, &ret, NULL);
4472
        }
4473
        else
4474
#endif
4475
        {
4476
            ret = wolfSSL_CRYPTO_get_ex_data(&session->ex_data, idx);
4477
        }
4478
    }
4479
#else
4480
    (void)session;
4481
    (void)idx;
4482
#endif
4483
    return ret;
4484
}
4485
4486
#ifdef HAVE_EX_DATA_CRYPTO
4487
int wolfSSL_SESSION_get_ex_new_index(long ctx_l,void* ctx_ptr,
4488
        WOLFSSL_CRYPTO_EX_new* new_func, WOLFSSL_CRYPTO_EX_dup* dup_func,
4489
        WOLFSSL_CRYPTO_EX_free* free_func)
4490
{
4491
    WOLFSSL_ENTER("wolfSSL_SESSION_get_ex_new_index");
4492
    return wolfssl_local_get_ex_new_index(WOLF_CRYPTO_EX_INDEX_SSL_SESSION,
4493
            ctx_l, ctx_ptr, new_func, dup_func, free_func);
4494
}
4495
#endif /* HAVE_EX_DATA_CRYPTO */
4496
#endif /* HAVE_EX_DATA */
4497
4498
#if defined(OPENSSL_ALL) || \
4499
    defined(OPENSSL_EXTRA) || defined(HAVE_STUNNEL) || \
4500
    defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
4501
4502
const byte* wolfSSL_SESSION_get_id(const WOLFSSL_SESSION* sess,
4503
        unsigned int* idLen)
4504
{
4505
    WOLFSSL_ENTER("wolfSSL_SESSION_get_id");
4506
    sess = ClientSessionToSession(sess);
4507
    if (sess == NULL || idLen == NULL) {
4508
        WOLFSSL_MSG("Bad func args. Please provide idLen");
4509
        return NULL;
4510
    }
4511
#ifdef HAVE_SESSION_TICKET
4512
    if (sess->haveAltSessionID) {
4513
        *idLen = ID_LEN;
4514
        return sess->altSessionID;
4515
    }
4516
#endif
4517
    *idLen = sess->sessionIDSz;
4518
    return sess->sessionID;
4519
}
4520
4521
#if (defined(HAVE_SESSION_TICKET) || defined(SESSION_CERTS)) && \
4522
    !defined(NO_FILESYSTEM)
4523
4524
#ifndef NO_BIO
4525
4526
#if defined(SESSION_CERTS) || \
4527
   (defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET))
4528
static const char* wolfSSL_internal_get_version(const ProtocolVersion* version);
4529
4530
/* returns a pointer to the protocol used by the session */
4531
static const char* wolfSSL_SESSION_get_protocol(const WOLFSSL_SESSION* in)
4532
{
4533
    in = ClientSessionToSession(in);
4534
    return wolfSSL_internal_get_version((ProtocolVersion*)&in->version);
4535
}
4536
#endif
4537
4538
/* returns true (non 0) if the session has EMS (extended master secret) */
4539
static int wolfSSL_SESSION_haveEMS(const WOLFSSL_SESSION* in)
4540
{
4541
    in = ClientSessionToSession(in);
4542
    if (in == NULL)
4543
        return 0;
4544
    return in->haveEMS;
4545
}
4546
4547
#if defined(HAVE_SESSION_TICKET)
4548
/* prints out the ticket to bio passed in
4549
 * return WOLFSSL_SUCCESS on success
4550
 */
4551
static int wolfSSL_SESSION_print_ticket(WOLFSSL_BIO* bio,
4552
        const WOLFSSL_SESSION* in, const char* tab)
4553
{
4554
    unsigned short i, j, z, sz;
4555
    short tag = 0;
4556
    byte* pt;
4557
4558
4559
    in = ClientSessionToSession(in);
4560
    if (in == NULL || bio == NULL) {
4561
        return BAD_FUNC_ARG;
4562
    }
4563
4564
    sz = in->ticketLen;
4565
    pt = in->ticket;
4566
4567
    if (wolfSSL_BIO_printf(bio, "%s\n", (sz == 0)? " NONE": "") <= 0)
4568
        return WOLFSSL_FAILURE;
4569
4570
    for (i = 0; i < sz;) {
4571
        char asc[16];
4572
        XMEMSET(asc, 0, sizeof(asc));
4573
4574
        if (sz - i < 16) {
4575
            if (wolfSSL_BIO_printf(bio, "%s%04X -", tab, tag + (sz - i)) <= 0)
4576
                return WOLFSSL_FAILURE;
4577
        }
4578
        else {
4579
            if (wolfSSL_BIO_printf(bio, "%s%04X -", tab, tag) <= 0)
4580
                return WOLFSSL_FAILURE;
4581
        }
4582
        for (j = 0; i < sz && j < 8; j++,i++) {
4583
            asc[j] =  ((pt[i])&0x6f)>='A'?((pt[i])&0x6f):'.';
4584
            if (wolfSSL_BIO_printf(bio, " %02X", pt[i]) <= 0)
4585
                return WOLFSSL_FAILURE;
4586
        }
4587
4588
        if (i < sz) {
4589
            asc[j] =  ((pt[i])&0x6f)>='A'?((pt[i])&0x6f):'.';
4590
            if (wolfSSL_BIO_printf(bio, "-%02X", pt[i]) <= 0)
4591
                return WOLFSSL_FAILURE;
4592
            j++;
4593
            i++;
4594
        }
4595
4596
        for (; i < sz && j < 16; j++,i++) {
4597
            asc[j] =  ((pt[i])&0x6f)>='A'?((pt[i])&0x6f):'.';
4598
            if (wolfSSL_BIO_printf(bio, " %02X", pt[i]) <= 0)
4599
                return WOLFSSL_FAILURE;
4600
        }
4601
4602
        /* pad out spacing */
4603
        for (z = j; z < 17; z++) {
4604
            if (wolfSSL_BIO_printf(bio, "   ") <= 0)
4605
                return WOLFSSL_FAILURE;
4606
        }
4607
4608
        for (z = 0; z < j; z++) {
4609
            if (wolfSSL_BIO_printf(bio, "%c", asc[z]) <= 0)
4610
                return WOLFSSL_FAILURE;
4611
        }
4612
        if (wolfSSL_BIO_printf(bio, "\n") <= 0)
4613
            return WOLFSSL_FAILURE;
4614
4615
        tag += 16;
4616
    }
4617
    return WOLFSSL_SUCCESS;
4618
}
4619
#endif /* HAVE_SESSION_TICKET */
4620
4621
4622
/* prints out the session information in human readable form
4623
 * return WOLFSSL_SUCCESS on success
4624
 */
4625
int wolfSSL_SESSION_print(WOLFSSL_BIO *bp, const WOLFSSL_SESSION *session)
4626
{
4627
    const unsigned char* pt;
4628
    unsigned char buf[SECRET_LEN];
4629
    unsigned int sz = 0, i;
4630
    int ret;
4631
4632
    session = ClientSessionToSession(session);
4633
    if (session == NULL) {
4634
        return WOLFSSL_FAILURE;
4635
    }
4636
4637
    if (wolfSSL_BIO_printf(bp, "%s\n", "SSL-Session:") <= 0)
4638
        return WOLFSSL_FAILURE;
4639
4640
#if defined(SESSION_CERTS) || (defined(WOLFSSL_TLS13) && \
4641
                               defined(HAVE_SESSION_TICKET))
4642
    if (wolfSSL_BIO_printf(bp, "    Protocol  : %s\n",
4643
            wolfSSL_SESSION_get_protocol(session)) <= 0)
4644
        return WOLFSSL_FAILURE;
4645
#endif
4646
4647
    if (wolfSSL_BIO_printf(bp, "    Cipher    : %s\n",
4648
            wolfSSL_SESSION_CIPHER_get_name(session)) <= 0)
4649
        return WOLFSSL_FAILURE;
4650
4651
    pt = wolfSSL_SESSION_get_id(session, &sz);
4652
    if (wolfSSL_BIO_printf(bp, "    Session-ID: ") <= 0)
4653
        return WOLFSSL_FAILURE;
4654
4655
    for (i = 0; i < sz; i++) {
4656
        if (wolfSSL_BIO_printf(bp, "%02X", pt[i]) <= 0)
4657
            return WOLFSSL_FAILURE;
4658
    }
4659
    if (wolfSSL_BIO_printf(bp, "\n") <= 0)
4660
        return WOLFSSL_FAILURE;
4661
4662
    if (wolfSSL_BIO_printf(bp, "    Session-ID-ctx: \n") <= 0)
4663
        return WOLFSSL_FAILURE;
4664
4665
    ret = wolfSSL_SESSION_get_master_key(session, buf, sizeof(buf));
4666
    if (wolfSSL_BIO_printf(bp, "    Master-Key: ") <= 0)
4667
        return WOLFSSL_FAILURE;
4668
4669
    if (ret > 0) {
4670
        sz = (unsigned int)ret;
4671
        for (i = 0; i < sz; i++) {
4672
            if (wolfSSL_BIO_printf(bp, "%02X", buf[i]) <= 0)
4673
                return WOLFSSL_FAILURE;
4674
        }
4675
    }
4676
    if (wolfSSL_BIO_printf(bp, "\n") <= 0)
4677
        return WOLFSSL_FAILURE;
4678
4679
    /* @TODO PSK identity hint and SRP */
4680
4681
    if (wolfSSL_BIO_printf(bp, "    TLS session ticket:") <= 0)
4682
        return WOLFSSL_FAILURE;
4683
4684
#ifdef HAVE_SESSION_TICKET
4685
    if (wolfSSL_SESSION_print_ticket(bp, session, "    ") != WOLFSSL_SUCCESS)
4686
        return WOLFSSL_FAILURE;
4687
#endif
4688
4689
#if !defined(NO_SESSION_CACHE) && (defined(OPENSSL_EXTRA) || \
4690
        defined(HAVE_EXT_CACHE))
4691
    if (wolfSSL_BIO_printf(bp, "    Start Time: %ld\n",
4692
                wolfSSL_SESSION_get_time(session)) <= 0)
4693
        return WOLFSSL_FAILURE;
4694
4695
    if (wolfSSL_BIO_printf(bp, "    Timeout   : %ld (sec)\n",
4696
            wolfSSL_SESSION_get_timeout(session)) <= 0)
4697
        return WOLFSSL_FAILURE;
4698
#endif /* !NO_SESSION_CACHE && OPENSSL_EXTRA || HAVE_EXT_CACHE */
4699
4700
    /* @TODO verify return code print */
4701
4702
    if (wolfSSL_BIO_printf(bp, "    Extended master secret: %s\n",
4703
            (wolfSSL_SESSION_haveEMS(session) == 0)? "no" : "yes") <= 0)
4704
        return WOLFSSL_FAILURE;
4705
4706
    return WOLFSSL_SUCCESS;
4707
}
4708
4709
#endif /* !NO_BIO */
4710
#endif /* (HAVE_SESSION_TICKET || SESSION_CERTS) && !NO_FILESYSTEM */
4711
4712
#endif /* OPENSSL_ALL || OPENSSL_EXTRA || HAVE_STUNNEL || WOLFSSL_NGINX ||
4713
        * WOLFSSL_HAPROXY */
4714
4715
#ifdef OPENSSL_EXTRA
4716
/**
4717
 * Determine whether a WOLFSSL_SESSION object can be used for resumption
4718
 * @param s  a pointer to WOLFSSL_SESSION structure
4719
 * @return return 1 if session is resumable, otherwise 0.
4720
 */
4721
int wolfSSL_SESSION_is_resumable(const WOLFSSL_SESSION *s)
4722
{
4723
    s = ClientSessionToSession(s);
4724
    if (s == NULL)
4725
        return 0;
4726
4727
#ifdef HAVE_SESSION_TICKET
4728
    if (s->ticketLen > 0)
4729
        return 1;
4730
#endif
4731
4732
    if (s->sessionIDSz > 0)
4733
        return 1;
4734
4735
    return 0;
4736
}
4737
#endif /* OPENSSL_EXTRA */
4738
4739
#endif /* !WOLFSSL_SSL_SESS_INCLUDED */
4740