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