Coverage Report

Created: 2025-07-23 06:53

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