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