Coverage Report

Created: 2025-06-23 06:10

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