Coverage Report

Created: 2026-11-12 06:59

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