Coverage Report

Created: 2026-04-05 07:22

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