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