Coverage Report

Created: 2026-02-14 07:18

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