Coverage Report

Created: 2025-12-31 07:08

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