1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file implements the CLIENT Session ID cache.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8
9 #include "cert.h"
10 #include "pk11pub.h"
11 #include "secitem.h"
12 #include "ssl.h"
13 #include "nss.h"
14
15 #include "sslimpl.h"
16 #include "sslproto.h"
17 #include "nssilock.h"
18 #include "sslencode.h"
19 #if defined(XP_UNIX) || defined(XP_WIN) || defined(_WINDOWS) || defined(XP_BEOS)
20 #include <time.h>
21 #endif
22
23 PRUint32 ssl3_sid_timeout = 86400L; /* 24 hours */
24
25 static sslSessionID *cache = NULL;
26 static PZLock *cacheLock = NULL;
27
28 /* sids can be in one of 5 states:
29 *
30 * never_cached, created, but not yet put into cache.
31 * in_client_cache, in the client cache's linked list.
32 * in_server_cache, entry came from the server's cache file.
33 * invalid_cache has been removed from the cache.
34 * in_external_cache sid comes from an external cache.
35 */
36
37 #define LOCK_CACHE lock_cache()
38 #define UNLOCK_CACHE PZ_Unlock(cacheLock)
39
40 static SECStatus
ssl_InitClientSessionCacheLock(void)41 ssl_InitClientSessionCacheLock(void)
42 {
43 cacheLock = PZ_NewLock(nssILockCache);
44 return cacheLock ? SECSuccess : SECFailure;
45 }
46
47 static SECStatus
ssl_FreeClientSessionCacheLock(void)48 ssl_FreeClientSessionCacheLock(void)
49 {
50 if (cacheLock) {
51 PZ_DestroyLock(cacheLock);
52 cacheLock = NULL;
53 return SECSuccess;
54 }
55 PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
56 return SECFailure;
57 }
58
59 static PRBool LocksInitializedEarly = PR_FALSE;
60
61 static SECStatus
FreeSessionCacheLocks()62 FreeSessionCacheLocks()
63 {
64 SECStatus rv1, rv2;
65 rv1 = ssl_FreeSymWrapKeysLock();
66 rv2 = ssl_FreeClientSessionCacheLock();
67 if ((SECSuccess == rv1) && (SECSuccess == rv2)) {
68 return SECSuccess;
69 }
70 return SECFailure;
71 }
72
73 static SECStatus
InitSessionCacheLocks(void)74 InitSessionCacheLocks(void)
75 {
76 SECStatus rv1, rv2;
77 PRErrorCode rc;
78 rv1 = ssl_InitSymWrapKeysLock();
79 rv2 = ssl_InitClientSessionCacheLock();
80 if ((SECSuccess == rv1) && (SECSuccess == rv2)) {
81 return SECSuccess;
82 }
83 rc = PORT_GetError();
84 FreeSessionCacheLocks();
85 PORT_SetError(rc);
86 return SECFailure;
87 }
88
89 /* free the session cache locks if they were initialized early */
90 SECStatus
ssl_FreeSessionCacheLocks()91 ssl_FreeSessionCacheLocks()
92 {
93 PORT_Assert(PR_TRUE == LocksInitializedEarly);
94 if (!LocksInitializedEarly) {
95 PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
96 return SECFailure;
97 }
98 FreeSessionCacheLocks();
99 LocksInitializedEarly = PR_FALSE;
100 return SECSuccess;
101 }
102
103 static PRCallOnceType lockOnce;
104
105 /* free the session cache locks if they were initialized lazily */
106 static SECStatus
ssl_ShutdownLocks(void * appData,void * nssData)107 ssl_ShutdownLocks(void *appData, void *nssData)
108 {
109 PORT_Assert(PR_FALSE == LocksInitializedEarly);
110 if (LocksInitializedEarly) {
111 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
112 return SECFailure;
113 }
114 FreeSessionCacheLocks();
115 memset(&lockOnce, 0, sizeof(lockOnce));
116 return SECSuccess;
117 }
118
119 static PRStatus
initSessionCacheLocksLazily(void)120 initSessionCacheLocksLazily(void)
121 {
122 SECStatus rv = InitSessionCacheLocks();
123 if (SECSuccess != rv) {
124 return PR_FAILURE;
125 }
126 rv = NSS_RegisterShutdown(ssl_ShutdownLocks, NULL);
127 PORT_Assert(SECSuccess == rv);
128 if (SECSuccess != rv) {
129 return PR_FAILURE;
130 }
131 return PR_SUCCESS;
132 }
133
134 /* lazyInit means that the call is not happening during a 1-time
135 * initialization function, but rather during dynamic, lazy initialization
136 */
137 SECStatus
ssl_InitSessionCacheLocks(PRBool lazyInit)138 ssl_InitSessionCacheLocks(PRBool lazyInit)
139 {
140 if (LocksInitializedEarly) {
141 return SECSuccess;
142 }
143
144 if (lazyInit) {
145 return (PR_SUCCESS ==
146 PR_CallOnce(&lockOnce, initSessionCacheLocksLazily))
147 ? SECSuccess
148 : SECFailure;
149 }
150
151 if (SECSuccess == InitSessionCacheLocks()) {
152 LocksInitializedEarly = PR_TRUE;
153 return SECSuccess;
154 }
155
156 return SECFailure;
157 }
158
159 static void
lock_cache(void)160 lock_cache(void)
161 {
162 ssl_InitSessionCacheLocks(PR_TRUE);
163 PZ_Lock(cacheLock);
164 }
165
166 /* BEWARE: This function gets called for both client and server SIDs !!
167 * If the unreferenced sid is not in the cache, Free sid and its contents.
168 */
169 void
ssl_DestroySID(sslSessionID * sid,PRBool freeIt)170 ssl_DestroySID(sslSessionID *sid, PRBool freeIt)
171 {
172 SSL_TRC(8, ("SSL: destroy sid: sid=0x%x cached=%d", sid, sid->cached));
173 PORT_Assert(sid->references == 0);
174 PORT_Assert(sid->cached != in_client_cache);
175
176 if (sid->u.ssl3.locked.sessionTicket.ticket.data) {
177 SECITEM_FreeItem(&sid->u.ssl3.locked.sessionTicket.ticket,
178 PR_FALSE);
179 }
180 if (sid->u.ssl3.srvName.data) {
181 SECITEM_FreeItem(&sid->u.ssl3.srvName, PR_FALSE);
182 }
183 if (sid->u.ssl3.signedCertTimestamps.data) {
184 SECITEM_FreeItem(&sid->u.ssl3.signedCertTimestamps, PR_FALSE);
185 }
186
187 if (sid->u.ssl3.lock) {
188 PR_DestroyRWLock(sid->u.ssl3.lock);
189 }
190
191 PORT_Free((void *)sid->peerID);
192 PORT_Free((void *)sid->urlSvrName);
193
194 if (sid->peerCert) {
195 CERT_DestroyCertificate(sid->peerCert);
196 }
197 if (sid->peerCertStatus.items) {
198 SECITEM_FreeArray(&sid->peerCertStatus, PR_FALSE);
199 }
200
201 if (sid->localCert) {
202 CERT_DestroyCertificate(sid->localCert);
203 }
204
205 SECITEM_FreeItem(&sid->u.ssl3.alpnSelection, PR_FALSE);
206
207 if (freeIt) {
208 PORT_ZFree(sid, sizeof(sslSessionID));
209 }
210 }
211
212 /* BEWARE: This function gets called for both client and server SIDs !!
213 * Decrement reference count, and
214 * free sid if ref count is zero, and sid is not in the cache.
215 * Does NOT remove from the cache first.
216 * If the sid is still in the cache, it is left there until next time
217 * the cache list is traversed.
218 */
219 static void
ssl_FreeLockedSID(sslSessionID * sid)220 ssl_FreeLockedSID(sslSessionID *sid)
221 {
222 PORT_Assert(sid->references >= 1);
223 if (--sid->references == 0) {
224 ssl_DestroySID(sid, PR_TRUE);
225 }
226 }
227
228 /* BEWARE: This function gets called for both client and server SIDs !!
229 * Decrement reference count, and
230 * free sid if ref count is zero, and sid is not in the cache.
231 * Does NOT remove from the cache first.
232 * These locks are necessary because the sid _might_ be in the cache list.
233 */
234 void
ssl_FreeSID(sslSessionID * sid)235 ssl_FreeSID(sslSessionID *sid)
236 {
237 LOCK_CACHE;
238 ssl_FreeLockedSID(sid);
239 UNLOCK_CACHE;
240 }
241
242 /************************************************************************/
243
244 /*
245 ** Lookup sid entry in cache by Address, port, and peerID string.
246 ** If found, Increment reference count, and return pointer to caller.
247 ** If it has timed out or ref count is zero, remove from list and free it.
248 */
249
250 sslSessionID *
ssl_LookupSID(const PRIPv6Addr * addr,PRUint16 port,const char * peerID,const char * urlSvrName)251 ssl_LookupSID(const PRIPv6Addr *addr, PRUint16 port, const char *peerID,
252 const char *urlSvrName)
253 {
254 sslSessionID **sidp;
255 sslSessionID *sid;
256 PRUint32 now;
257
258 if (!urlSvrName)
259 return NULL;
260 now = ssl_TimeSec();
261 LOCK_CACHE;
262 sidp = &cache;
263 while ((sid = *sidp) != 0) {
264 PORT_Assert(sid->cached == in_client_cache);
265 PORT_Assert(sid->references >= 1);
266
267 SSL_TRC(8, ("SSL: Lookup1: sid=0x%x", sid));
268
269 if (sid->expirationTime < now) {
270 /*
271 ** This session-id timed out.
272 ** Don't even care who it belongs to, blow it out of our cache.
273 */
274 SSL_TRC(7, ("SSL: lookup1, throwing sid out, age=%d refs=%d",
275 now - sid->creationTime, sid->references));
276
277 *sidp = sid->next; /* delink it from the list. */
278 sid->cached = invalid_cache; /* mark not on list. */
279 ssl_FreeLockedSID(sid); /* drop ref count, free. */
280 } else if (!memcmp(&sid->addr, addr, sizeof(PRIPv6Addr)) && /* server IP addr matches */
281 (sid->port == port) && /* server port matches */
282 /* proxy (peerID) matches */
283 (((peerID == NULL) && (sid->peerID == NULL)) ||
284 ((peerID != NULL) && (sid->peerID != NULL) &&
285 PORT_Strcmp(sid->peerID, peerID) == 0)) &&
286 /* is cacheable */
287 (sid->u.ssl3.keys.resumable) &&
288 /* server hostname matches. */
289 (sid->urlSvrName != NULL) &&
290 (0 == PORT_Strcmp(urlSvrName, sid->urlSvrName))) {
291 /* Hit */
292 sid->lastAccessTime = now;
293 sid->references++;
294 break;
295 } else {
296 sidp = &sid->next;
297 }
298 }
299 UNLOCK_CACHE;
300 return sid;
301 }
302
303 /*
304 ** Add an sid to the cache or return a previously cached entry to the cache.
305 ** Although this is static, it is called via ss->sec.cache().
306 */
307 static void
CacheSID(sslSessionID * sid)308 CacheSID(sslSessionID *sid)
309 {
310 PORT_Assert(sid);
311 PORT_Assert(sid->cached == never_cached);
312
313 SSL_TRC(8, ("SSL: Cache: sid=0x%x cached=%d addr=0x%08x%08x%08x%08x port=0x%04x "
314 "time=%x cached=%d",
315 sid, sid->cached, sid->addr.pr_s6_addr32[0],
316 sid->addr.pr_s6_addr32[1], sid->addr.pr_s6_addr32[2],
317 sid->addr.pr_s6_addr32[3], sid->port, sid->creationTime,
318 sid->cached));
319
320 if (!sid->urlSvrName) {
321 /* don't cache this SID because it can never be matched */
322 return;
323 }
324
325 if (sid->u.ssl3.sessionIDLength == 0 &&
326 sid->u.ssl3.locked.sessionTicket.ticket.data == NULL)
327 return;
328
329 /* Client generates the SessionID if this was a stateless resume. */
330 if (sid->u.ssl3.sessionIDLength == 0) {
331 SECStatus rv;
332 rv = PK11_GenerateRandom(sid->u.ssl3.sessionID,
333 SSL3_SESSIONID_BYTES);
334 if (rv != SECSuccess)
335 return;
336 sid->u.ssl3.sessionIDLength = SSL3_SESSIONID_BYTES;
337 }
338 PRINT_BUF(8, (0, "sessionID:",
339 sid->u.ssl3.sessionID, sid->u.ssl3.sessionIDLength));
340
341 sid->u.ssl3.lock = PR_NewRWLock(PR_RWLOCK_RANK_NONE, NULL);
342 if (!sid->u.ssl3.lock) {
343 return;
344 }
345 PORT_Assert(sid->creationTime != 0 && sid->expirationTime != 0);
346 if (!sid->creationTime)
347 sid->lastAccessTime = sid->creationTime = ssl_TimeUsec();
348 if (!sid->expirationTime)
349 sid->expirationTime = sid->creationTime + ssl3_sid_timeout * PR_USEC_PER_SEC;
350
351 /*
352 * Put sid into the cache. Bump reference count to indicate that
353 * cache is holding a reference. Uncache will reduce the cache
354 * reference.
355 */
356 LOCK_CACHE;
357 sid->references++;
358 sid->cached = in_client_cache;
359 sid->next = cache;
360 cache = sid;
361 UNLOCK_CACHE;
362 }
363
364 /*
365 * If sid "zap" is in the cache,
366 * removes sid from cache, and decrements reference count.
367 * Caller must hold cache lock.
368 */
369 static void
UncacheSID(sslSessionID * zap)370 UncacheSID(sslSessionID *zap)
371 {
372 sslSessionID **sidp = &cache;
373 sslSessionID *sid;
374
375 if (zap->cached != in_client_cache) {
376 return;
377 }
378
379 SSL_TRC(8, ("SSL: Uncache: zap=0x%x cached=%d addr=0x%08x%08x%08x%08x port=0x%04x "
380 "time=%x cipherSuite=%d",
381 zap, zap->cached, zap->addr.pr_s6_addr32[0],
382 zap->addr.pr_s6_addr32[1], zap->addr.pr_s6_addr32[2],
383 zap->addr.pr_s6_addr32[3], zap->port, zap->creationTime,
384 zap->u.ssl3.cipherSuite));
385
386 /* See if it's in the cache, if so nuke it */
387 while ((sid = *sidp) != 0) {
388 if (sid == zap) {
389 /*
390 ** Bingo. Reduce reference count by one so that when
391 ** everyone is done with the sid we can free it up.
392 */
393 *sidp = zap->next;
394 zap->cached = invalid_cache;
395 ssl_FreeLockedSID(zap);
396 return;
397 }
398 sidp = &sid->next;
399 }
400 }
401
402 /* If sid "zap" is in the cache,
403 * removes sid from cache, and decrements reference count.
404 * Although this function is static, it is called externally via
405 * ssl_UncacheSessionID.
406 */
407 static void
LockAndUncacheSID(sslSessionID * zap)408 LockAndUncacheSID(sslSessionID *zap)
409 {
410 LOCK_CACHE;
411 UncacheSID(zap);
412 UNLOCK_CACHE;
413 }
414
415 SECStatus
ReadVariableFromBuffer(sslReader * reader,sslReadBuffer * readerBuffer,uint8_t lenBytes,SECItem * dest)416 ReadVariableFromBuffer(sslReader *reader, sslReadBuffer *readerBuffer,
417 uint8_t lenBytes, SECItem *dest)
418 {
419 if (sslRead_ReadVariable(reader, lenBytes, readerBuffer) != SECSuccess) {
420 PORT_SetError(SEC_ERROR_INVALID_ARGS);
421 return SECFailure;
422 }
423 if (readerBuffer->len) {
424 SECItem tempItem = { siBuffer, (unsigned char *)readerBuffer->buf,
425 readerBuffer->len };
426 SECStatus rv = SECITEM_CopyItem(NULL, dest, &tempItem);
427 if (rv != SECSuccess) {
428 return rv;
429 }
430 }
431 return SECSuccess;
432 }
433
434 /* Fill sid with the values from the encoded resumption token.
435 * sid has to be allocated.
436 * We don't care about locks here as this cache entry is externally stored.
437 */
438 SECStatus
ssl_DecodeResumptionToken(sslSessionID * sid,const PRUint8 * encodedToken,PRUint32 encodedTokenLen)439 ssl_DecodeResumptionToken(sslSessionID *sid, const PRUint8 *encodedToken,
440 PRUint32 encodedTokenLen)
441 {
442 PORT_Assert(encodedTokenLen);
443 PORT_Assert(encodedToken);
444 PORT_Assert(sid);
445 if (!sid || !encodedToken || !encodedTokenLen) {
446 PORT_SetError(SEC_ERROR_INVALID_ARGS);
447 return SECFailure;
448 }
449
450 if (encodedToken[0] != SSLResumptionTokenVersion) {
451 /* Unknown token format version. */
452 PORT_SetError(SSL_ERROR_BAD_RESUMPTION_TOKEN_ERROR);
453 return SECFailure;
454 }
455
456 /* These variables are used across macros. Don't use them outside. */
457 sslReader reader = SSL_READER(encodedToken, encodedTokenLen);
458 reader.offset += 1; // We read the version already. Skip the first byte.
459 sslReadBuffer readerBuffer = { 0 };
460 PRUint64 tmpInt = 0;
461
462 if (sslRead_ReadNumber(&reader, 8, &tmpInt) != SECSuccess) {
463 return SECFailure;
464 }
465 sid->lastAccessTime = (PRTime)tmpInt;
466 if (sslRead_ReadNumber(&reader, 8, &tmpInt) != SECSuccess) {
467 return SECFailure;
468 }
469 sid->expirationTime = (PRTime)tmpInt;
470 if (sslRead_ReadNumber(&reader, 8, &tmpInt) != SECSuccess) {
471 return SECFailure;
472 }
473 sid->u.ssl3.locked.sessionTicket.received_timestamp = (PRTime)tmpInt;
474
475 if (sslRead_ReadNumber(&reader, 4, &tmpInt) != SECSuccess) {
476 return SECFailure;
477 }
478 sid->u.ssl3.locked.sessionTicket.ticket_lifetime_hint = (PRUint32)tmpInt;
479 if (sslRead_ReadNumber(&reader, 4, &tmpInt) != SECSuccess) {
480 return SECFailure;
481 }
482 sid->u.ssl3.locked.sessionTicket.flags = (PRUint32)tmpInt;
483 if (sslRead_ReadNumber(&reader, 4, &tmpInt) != SECSuccess) {
484 return SECFailure;
485 }
486 sid->u.ssl3.locked.sessionTicket.ticket_age_add = (PRUint32)tmpInt;
487 if (sslRead_ReadNumber(&reader, 4, &tmpInt) != SECSuccess) {
488 return SECFailure;
489 }
490 sid->u.ssl3.locked.sessionTicket.max_early_data_size = (PRUint32)tmpInt;
491
492 if (sslRead_ReadVariable(&reader, 3, &readerBuffer) != SECSuccess) {
493 PORT_SetError(SEC_ERROR_INVALID_ARGS);
494 return SECFailure;
495 }
496 if (readerBuffer.len) {
497 PORT_Assert(!sid->peerCert);
498 SECItem tempItem = { siBuffer, (unsigned char *)readerBuffer.buf,
499 readerBuffer.len };
500 sid->peerCert = CERT_NewTempCertificate(NULL, /* dbHandle */
501 &tempItem,
502 NULL, PR_FALSE, PR_TRUE);
503 if (!sid->peerCert) {
504 return SECFailure;
505 }
506 }
507
508 if (sslRead_ReadVariable(&reader, 2, &readerBuffer) != SECSuccess) {
509 PORT_SetError(SEC_ERROR_INVALID_ARGS);
510 return SECFailure;
511 }
512 if (readerBuffer.len) {
513 SECITEM_AllocArray(NULL, &sid->peerCertStatus, 1);
514 if (!sid->peerCertStatus.items) {
515 return SECFailure;
516 }
517 SECItem tempItem = { siBuffer, (unsigned char *)readerBuffer.buf,
518 readerBuffer.len };
519 SECITEM_CopyItem(NULL, &sid->peerCertStatus.items[0], &tempItem);
520 }
521
522 if (sslRead_ReadVariable(&reader, 1, &readerBuffer) != SECSuccess) {
523 PORT_SetError(SEC_ERROR_INVALID_ARGS);
524 return SECFailure;
525 }
526 if (readerBuffer.len) {
527 PORT_Assert(readerBuffer.buf);
528 sid->peerID = PORT_Strdup((const char *)readerBuffer.buf);
529 }
530
531 if (sslRead_ReadVariable(&reader, 1, &readerBuffer) != SECSuccess) {
532 PORT_SetError(SEC_ERROR_INVALID_ARGS);
533 return SECFailure;
534 }
535 if (readerBuffer.len) {
536 if (sid->urlSvrName) {
537 PORT_Free((void *)sid->urlSvrName);
538 }
539 PORT_Assert(readerBuffer.buf);
540 sid->urlSvrName = PORT_Strdup((const char *)readerBuffer.buf);
541 }
542
543 if (sslRead_ReadVariable(&reader, 3, &readerBuffer) != SECSuccess) {
544 PORT_SetError(SEC_ERROR_INVALID_ARGS);
545 return SECFailure;
546 }
547 if (readerBuffer.len) {
548 PORT_Assert(!sid->localCert);
549 SECItem tempItem = { siBuffer, (unsigned char *)readerBuffer.buf,
550 readerBuffer.len };
551 sid->localCert = CERT_NewTempCertificate(NULL, /* dbHandle */
552 &tempItem,
553 NULL, PR_FALSE, PR_TRUE);
554 }
555
556 if (sslRead_ReadNumber(&reader, 8, &sid->addr.pr_s6_addr64[0]) != SECSuccess) {
557 return SECFailure;
558 }
559 if (sslRead_ReadNumber(&reader, 8, &sid->addr.pr_s6_addr64[1]) != SECSuccess) {
560 return SECFailure;
561 }
562
563 if (sslRead_ReadNumber(&reader, 2, &tmpInt) != SECSuccess) {
564 return SECFailure;
565 }
566 sid->port = (PRUint16)tmpInt;
567 if (sslRead_ReadNumber(&reader, 2, &tmpInt) != SECSuccess) {
568 return SECFailure;
569 }
570 sid->version = (PRUint16)tmpInt;
571
572 if (sslRead_ReadNumber(&reader, 8, &tmpInt) != SECSuccess) {
573 return SECFailure;
574 }
575 sid->creationTime = (PRTime)tmpInt;
576
577 if (sslRead_ReadNumber(&reader, 2, &tmpInt) != SECSuccess) {
578 return SECFailure;
579 }
580 sid->authType = (SSLAuthType)tmpInt;
581 if (sslRead_ReadNumber(&reader, 4, &tmpInt) != SECSuccess) {
582 return SECFailure;
583 }
584 sid->authKeyBits = (PRUint32)tmpInt;
585 if (sslRead_ReadNumber(&reader, 2, &tmpInt) != SECSuccess) {
586 return SECFailure;
587 }
588 sid->keaType = (SSLKEAType)tmpInt;
589 if (sslRead_ReadNumber(&reader, 4, &tmpInt) != SECSuccess) {
590 return SECFailure;
591 }
592 sid->keaKeyBits = (PRUint32)tmpInt;
593 if (sslRead_ReadNumber(&reader, 3, &tmpInt) != SECSuccess) {
594 return SECFailure;
595 }
596 sid->keaGroup = (SSLNamedGroup)tmpInt;
597
598 if (sslRead_ReadNumber(&reader, 3, &tmpInt) != SECSuccess) {
599 return SECFailure;
600 }
601 sid->sigScheme = (SSLSignatureScheme)tmpInt;
602
603 if (sslRead_ReadNumber(&reader, 1, &tmpInt) != SECSuccess) {
604 return SECFailure;
605 }
606 sid->u.ssl3.sessionIDLength = (PRUint8)tmpInt;
607
608 if (sslRead_ReadVariable(&reader, 1, &readerBuffer) != SECSuccess) {
609 PORT_SetError(SEC_ERROR_INVALID_ARGS);
610 return SECFailure;
611 }
612 if (readerBuffer.len) {
613 PORT_Assert(readerBuffer.buf);
614 PORT_Memcpy(sid->u.ssl3.sessionID, readerBuffer.buf, readerBuffer.len);
615 }
616
617 if (sslRead_ReadNumber(&reader, 2, &tmpInt) != SECSuccess) {
618 return SECFailure;
619 }
620 sid->u.ssl3.cipherSuite = (PRUint16)tmpInt;
621 if (sslRead_ReadNumber(&reader, 1, &tmpInt) != SECSuccess) {
622 return SECFailure;
623 }
624 sid->u.ssl3.policy = (PRUint8)tmpInt;
625
626 if (sslRead_ReadVariable(&reader, 1, &readerBuffer) != SECSuccess) {
627 PORT_SetError(SEC_ERROR_INVALID_ARGS);
628 return SECFailure;
629 }
630 PORT_Assert(readerBuffer.len == WRAPPED_MASTER_SECRET_SIZE);
631 if (readerBuffer.len != WRAPPED_MASTER_SECRET_SIZE) {
632 PORT_SetError(SEC_ERROR_INVALID_ARGS);
633 return SECFailure;
634 }
635 PORT_Assert(readerBuffer.buf);
636 PORT_Memcpy(sid->u.ssl3.keys.wrapped_master_secret, readerBuffer.buf,
637 readerBuffer.len);
638
639 if (sslRead_ReadNumber(&reader, 1, &tmpInt) != SECSuccess) {
640 return SECFailure;
641 }
642 sid->u.ssl3.keys.wrapped_master_secret_len = (PRUint8)tmpInt;
643 if (sslRead_ReadNumber(&reader, 1, &tmpInt) != SECSuccess) {
644 return SECFailure;
645 }
646 sid->u.ssl3.keys.extendedMasterSecretUsed = (PRUint8)tmpInt;
647
648 if (sslRead_ReadNumber(&reader, 8, &tmpInt) != SECSuccess) {
649 return SECFailure;
650 }
651 sid->u.ssl3.masterWrapMech = (unsigned long)tmpInt;
652 if (sslRead_ReadNumber(&reader, 8, &tmpInt) != SECSuccess) {
653 return SECFailure;
654 }
655 sid->u.ssl3.masterModuleID = (unsigned long)tmpInt;
656 if (sslRead_ReadNumber(&reader, 8, &tmpInt) != SECSuccess) {
657 return SECFailure;
658 }
659 sid->u.ssl3.masterSlotID = (unsigned long)tmpInt;
660
661 if (sslRead_ReadNumber(&reader, 4, &tmpInt) != SECSuccess) {
662 return SECFailure;
663 }
664 sid->u.ssl3.masterWrapIndex = (PRUint32)tmpInt;
665 if (sslRead_ReadNumber(&reader, 2, &tmpInt) != SECSuccess) {
666 return SECFailure;
667 }
668 sid->u.ssl3.masterWrapSeries = (PRUint16)tmpInt;
669
670 if (sslRead_ReadNumber(&reader, 1, &tmpInt) != SECSuccess) {
671 return SECFailure;
672 }
673 sid->u.ssl3.masterValid = (char)tmpInt;
674
675 if (ReadVariableFromBuffer(&reader, &readerBuffer, 1,
676 &sid->u.ssl3.srvName) != SECSuccess) {
677 return SECFailure;
678 }
679 if (ReadVariableFromBuffer(&reader, &readerBuffer, 2,
680 &sid->u.ssl3.signedCertTimestamps) != SECSuccess) {
681 return SECFailure;
682 }
683 if (ReadVariableFromBuffer(&reader, &readerBuffer, 1,
684 &sid->u.ssl3.alpnSelection) != SECSuccess) {
685 return SECFailure;
686 }
687 if (ReadVariableFromBuffer(&reader, &readerBuffer, 2,
688 &sid->u.ssl3.locked.sessionTicket.ticket) != SECSuccess) {
689 return SECFailure;
690 }
691 if (!sid->u.ssl3.locked.sessionTicket.ticket.len) {
692 PORT_SetError(SEC_ERROR_INVALID_ARGS);
693 return SECFailure;
694 }
695
696 /* At this point we must have read everything. */
697 PORT_Assert(reader.offset == reader.buf.len);
698 if (reader.offset != reader.buf.len) {
699 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
700 return SECFailure;
701 }
702
703 return SECSuccess;
704 }
705
706 PRBool
ssl_IsResumptionTokenValid(sslSocket * ss)707 ssl_IsResumptionTokenValid(sslSocket *ss)
708 {
709 PORT_Assert(ss);
710 sslSessionID *sid = ss->sec.ci.sid;
711 PORT_Assert(sid);
712
713 // Check that the ticket didn't expire.
714 PRTime endTime = 0;
715 NewSessionTicket *ticket = &sid->u.ssl3.locked.sessionTicket;
716 if (ticket->ticket_lifetime_hint != 0) {
717 endTime = ticket->received_timestamp +
718 (PRTime)(ticket->ticket_lifetime_hint * PR_USEC_PER_SEC);
719 if (endTime < ssl_TimeUsec()) {
720 return PR_FALSE;
721 }
722 }
723
724 // Check that the session entry didn't expire.
725 if (sid->expirationTime < ssl_TimeUsec()) {
726 return PR_FALSE;
727 }
728
729 // Check that the server name (SNI) matches the one set for this session.
730 // Don't use the token if there's no server name.
731 if (sid->urlSvrName == NULL || PORT_Strcmp(ss->url, sid->urlSvrName) != 0) {
732 return PR_FALSE;
733 }
734
735 // This shouldn't be false, but let's check it anyway.
736 if (!sid->u.ssl3.keys.resumable) {
737 return PR_FALSE;
738 }
739
740 return PR_TRUE;
741 }
742
743 /* Encode a session ticket into a byte array that can be handed out to a cache.
744 * Needed memory in encodedToken has to be allocated according to
745 * *encodedTokenLen. */
746 static SECStatus
ssl_EncodeResumptionToken(sslSessionID * sid,sslBuffer * encodedTokenBuf)747 ssl_EncodeResumptionToken(sslSessionID *sid, sslBuffer *encodedTokenBuf)
748 {
749 PORT_Assert(encodedTokenBuf);
750 PORT_Assert(sid);
751 if (!sid || !sid->u.ssl3.locked.sessionTicket.ticket.len ||
752 !encodedTokenBuf || !sid->u.ssl3.keys.resumable || !sid->urlSvrName) {
753 PORT_SetError(SEC_ERROR_INVALID_ARGS);
754 return SECFailure;
755 }
756
757 /* Encoding format:
758 * 0-byte: version
759 * Integers are encoded according to their length.
760 * SECItems are prepended with a 64-bit length field followed by the bytes.
761 * Optional bytes are encoded as a 0-length item if not present.
762 */
763 SECStatus rv = sslBuffer_AppendNumber(encodedTokenBuf,
764 SSLResumptionTokenVersion, 1);
765 if (rv != SECSuccess) {
766 return SECFailure;
767 }
768
769 rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->lastAccessTime, 8);
770 if (rv != SECSuccess) {
771 PORT_SetError(SEC_ERROR_INVALID_ARGS);
772 return SECFailure;
773 }
774 rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->expirationTime, 8);
775 if (rv != SECSuccess) {
776 PORT_SetError(SEC_ERROR_INVALID_ARGS);
777 return SECFailure;
778 }
779
780 // session ticket
781 rv = sslBuffer_AppendNumber(encodedTokenBuf,
782 sid->u.ssl3.locked.sessionTicket.received_timestamp,
783 8);
784 if (rv != SECSuccess) {
785 PORT_SetError(SEC_ERROR_INVALID_ARGS);
786 return SECFailure;
787 }
788 rv = sslBuffer_AppendNumber(encodedTokenBuf,
789 sid->u.ssl3.locked.sessionTicket.ticket_lifetime_hint,
790 4);
791 if (rv != SECSuccess) {
792 PORT_SetError(SEC_ERROR_INVALID_ARGS);
793 return SECFailure;
794 }
795 rv = sslBuffer_AppendNumber(encodedTokenBuf,
796 sid->u.ssl3.locked.sessionTicket.flags,
797 4);
798 if (rv != SECSuccess) {
799 PORT_SetError(SEC_ERROR_INVALID_ARGS);
800 return SECFailure;
801 }
802 rv = sslBuffer_AppendNumber(encodedTokenBuf,
803 sid->u.ssl3.locked.sessionTicket.ticket_age_add,
804 4);
805 if (rv != SECSuccess) {
806 PORT_SetError(SEC_ERROR_INVALID_ARGS);
807 return SECFailure;
808 }
809 rv = sslBuffer_AppendNumber(encodedTokenBuf,
810 sid->u.ssl3.locked.sessionTicket.max_early_data_size,
811 4);
812 if (rv != SECSuccess) {
813 PORT_SetError(SEC_ERROR_INVALID_ARGS);
814 return SECFailure;
815 }
816
817 rv = sslBuffer_AppendVariable(encodedTokenBuf, sid->peerCert->derCert.data,
818 sid->peerCert->derCert.len, 3);
819 if (rv != SECSuccess) {
820 return SECFailure;
821 }
822
823 if (sid->peerCertStatus.len > 1) {
824 /* This is not implemented so it shouldn't happen.
825 * If it gets implemented, this has to change.
826 */
827 PORT_Assert(0);
828 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
829 return SECFailure;
830 }
831
832 if (sid->peerCertStatus.len == 1 && sid->peerCertStatus.items[0].len) {
833 rv = sslBuffer_AppendVariable(encodedTokenBuf,
834 sid->peerCertStatus.items[0].data,
835 sid->peerCertStatus.items[0].len, 2);
836 if (rv != SECSuccess) {
837 return SECFailure;
838 }
839 } else {
840 rv = sslBuffer_AppendVariable(encodedTokenBuf, NULL, 0, 2);
841 if (rv != SECSuccess) {
842 return SECFailure;
843 }
844 }
845
846 PRUint64 len = sid->peerID ? strlen(sid->peerID) : 0;
847 if (len > PR_UINT8_MAX) {
848 // This string really shouldn't be that long.
849 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
850 return SECFailure;
851 }
852 rv = sslBuffer_AppendVariable(encodedTokenBuf,
853 (const unsigned char *)sid->peerID, len, 1);
854 if (rv != SECSuccess) {
855 return SECFailure;
856 }
857
858 len = sid->urlSvrName ? strlen(sid->urlSvrName) : 0;
859 if (!len) {
860 PORT_SetError(SEC_ERROR_INVALID_ARGS);
861 return SECFailure;
862 }
863 if (len > PR_UINT8_MAX) {
864 // This string really shouldn't be that long.
865 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
866 return SECFailure;
867 }
868 rv = sslBuffer_AppendVariable(encodedTokenBuf,
869 (const unsigned char *)sid->urlSvrName,
870 len, 1);
871 if (rv != SECSuccess) {
872 return SECFailure;
873 }
874
875 if (sid->localCert) {
876 rv = sslBuffer_AppendVariable(encodedTokenBuf,
877 sid->localCert->derCert.data,
878 sid->localCert->derCert.len, 3);
879 if (rv != SECSuccess) {
880 return SECFailure;
881 }
882 } else {
883 rv = sslBuffer_AppendVariable(encodedTokenBuf, NULL, 0, 3);
884 if (rv != SECSuccess) {
885 return SECFailure;
886 }
887 }
888
889 rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->addr.pr_s6_addr64[0], 8);
890 if (rv != SECSuccess) {
891 PORT_SetError(SEC_ERROR_INVALID_ARGS);
892 return SECFailure;
893 }
894 rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->addr.pr_s6_addr64[1], 8);
895 if (rv != SECSuccess) {
896 PORT_SetError(SEC_ERROR_INVALID_ARGS);
897 return SECFailure;
898 }
899 rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->port, 2);
900 if (rv != SECSuccess) {
901 PORT_SetError(SEC_ERROR_INVALID_ARGS);
902 return SECFailure;
903 }
904 rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->version, 2);
905 if (rv != SECSuccess) {
906 PORT_SetError(SEC_ERROR_INVALID_ARGS);
907 return SECFailure;
908 }
909 rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->creationTime, 8);
910 if (rv != SECSuccess) {
911 PORT_SetError(SEC_ERROR_INVALID_ARGS);
912 return SECFailure;
913 }
914 rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->authType, 2);
915 if (rv != SECSuccess) {
916 PORT_SetError(SEC_ERROR_INVALID_ARGS);
917 return SECFailure;
918 }
919 rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->authKeyBits, 4);
920 if (rv != SECSuccess) {
921 PORT_SetError(SEC_ERROR_INVALID_ARGS);
922 return SECFailure;
923 }
924 rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->keaType, 2);
925 if (rv != SECSuccess) {
926 PORT_SetError(SEC_ERROR_INVALID_ARGS);
927 return SECFailure;
928 }
929 rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->keaKeyBits, 4);
930 if (rv != SECSuccess) {
931 PORT_SetError(SEC_ERROR_INVALID_ARGS);
932 return SECFailure;
933 }
934 rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->keaGroup, 3);
935 if (rv != SECSuccess) {
936 PORT_SetError(SEC_ERROR_INVALID_ARGS);
937 return SECFailure;
938 }
939 rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->sigScheme, 3);
940 if (rv != SECSuccess) {
941 PORT_SetError(SEC_ERROR_INVALID_ARGS);
942 return SECFailure;
943 }
944
945 rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->u.ssl3.sessionIDLength, 1);
946 if (rv != SECSuccess) {
947 PORT_SetError(SEC_ERROR_INVALID_ARGS);
948 return SECFailure;
949 }
950 rv = sslBuffer_AppendVariable(encodedTokenBuf, sid->u.ssl3.sessionID,
951 SSL3_SESSIONID_BYTES, 1);
952 if (rv != SECSuccess) {
953 return SECFailure;
954 }
955
956 rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->u.ssl3.cipherSuite, 2);
957 if (rv != SECSuccess) {
958 PORT_SetError(SEC_ERROR_INVALID_ARGS);
959 return SECFailure;
960 }
961 rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->u.ssl3.policy, 1);
962 if (rv != SECSuccess) {
963 PORT_SetError(SEC_ERROR_INVALID_ARGS);
964 return SECFailure;
965 }
966
967 rv = sslBuffer_AppendVariable(encodedTokenBuf,
968 sid->u.ssl3.keys.wrapped_master_secret,
969 WRAPPED_MASTER_SECRET_SIZE, 1);
970 if (rv != SECSuccess) {
971 return SECFailure;
972 }
973
974 rv = sslBuffer_AppendNumber(encodedTokenBuf,
975 sid->u.ssl3.keys.wrapped_master_secret_len,
976 1);
977 if (rv != SECSuccess) {
978 PORT_SetError(SEC_ERROR_INVALID_ARGS);
979 return SECFailure;
980 }
981 rv = sslBuffer_AppendNumber(encodedTokenBuf,
982 sid->u.ssl3.keys.extendedMasterSecretUsed,
983 1);
984 if (rv != SECSuccess) {
985 PORT_SetError(SEC_ERROR_INVALID_ARGS);
986 return SECFailure;
987 }
988
989 rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->u.ssl3.masterWrapMech, 8);
990 if (rv != SECSuccess) {
991 PORT_SetError(SEC_ERROR_INVALID_ARGS);
992 return SECFailure;
993 }
994 rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->u.ssl3.masterModuleID, 8);
995 if (rv != SECSuccess) {
996 PORT_SetError(SEC_ERROR_INVALID_ARGS);
997 return SECFailure;
998 }
999 rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->u.ssl3.masterSlotID, 8);
1000 if (rv != SECSuccess) {
1001 PORT_SetError(SEC_ERROR_INVALID_ARGS);
1002 return SECFailure;
1003 }
1004 rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->u.ssl3.masterWrapIndex, 4);
1005 if (rv != SECSuccess) {
1006 PORT_SetError(SEC_ERROR_INVALID_ARGS);
1007 return SECFailure;
1008 }
1009 rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->u.ssl3.masterWrapSeries, 2);
1010 if (rv != SECSuccess) {
1011 PORT_SetError(SEC_ERROR_INVALID_ARGS);
1012 return SECFailure;
1013 }
1014
1015 rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->u.ssl3.masterValid, 1);
1016 if (rv != SECSuccess) {
1017 PORT_SetError(SEC_ERROR_INVALID_ARGS);
1018 return SECFailure;
1019 }
1020
1021 rv = sslBuffer_AppendVariable(encodedTokenBuf, sid->u.ssl3.srvName.data,
1022 sid->u.ssl3.srvName.len, 1);
1023 if (rv != SECSuccess) {
1024 return SECFailure;
1025 }
1026 rv = sslBuffer_AppendVariable(encodedTokenBuf,
1027 sid->u.ssl3.signedCertTimestamps.data,
1028 sid->u.ssl3.signedCertTimestamps.len, 2);
1029 if (rv != SECSuccess) {
1030 return SECFailure;
1031 }
1032
1033 rv = sslBuffer_AppendVariable(encodedTokenBuf,
1034 sid->u.ssl3.alpnSelection.data,
1035 sid->u.ssl3.alpnSelection.len, 1);
1036 if (rv != SECSuccess) {
1037 return SECFailure;
1038 }
1039
1040 PORT_Assert(sid->u.ssl3.locked.sessionTicket.ticket.len > 1);
1041 rv = sslBuffer_AppendVariable(encodedTokenBuf,
1042 sid->u.ssl3.locked.sessionTicket.ticket.data,
1043 sid->u.ssl3.locked.sessionTicket.ticket.len,
1044 2);
1045 if (rv != SECSuccess) {
1046 return SECFailure;
1047 }
1048
1049 return SECSuccess;
1050 }
1051
1052 void
ssl_CacheExternalToken(sslSocket * ss)1053 ssl_CacheExternalToken(sslSocket *ss)
1054 {
1055 PORT_Assert(ss);
1056 sslSessionID *sid = ss->sec.ci.sid;
1057 PORT_Assert(sid);
1058 PORT_Assert(sid->cached == never_cached);
1059 PORT_Assert(ss->resumptionTokenCallback);
1060
1061 SSL_TRC(8, ("SSL [%d]: Cache External: sid=0x%x cached=%d "
1062 "addr=0x%08x%08x%08x%08x port=0x%04x time=%x cached=%d",
1063 ss->fd,
1064 sid, sid->cached, sid->addr.pr_s6_addr32[0],
1065 sid->addr.pr_s6_addr32[1], sid->addr.pr_s6_addr32[2],
1066 sid->addr.pr_s6_addr32[3], sid->port, sid->creationTime,
1067 sid->cached));
1068
1069 /* This is only available for stateless resumption. */
1070 if (sid->u.ssl3.locked.sessionTicket.ticket.data == NULL) {
1071 return;
1072 }
1073
1074 /* Don't export token if the session used client authentication. */
1075 if (sid->u.ssl3.clAuthValid) {
1076 return;
1077 }
1078
1079 if (!sid->creationTime) {
1080 sid->lastAccessTime = sid->creationTime = ssl_TimeUsec();
1081 }
1082 if (!sid->expirationTime) {
1083 sid->expirationTime = sid->creationTime + ssl3_sid_timeout;
1084 }
1085
1086 sslBuffer encodedToken = SSL_BUFFER_EMPTY;
1087
1088 if (ssl_EncodeResumptionToken(sid, &encodedToken) != SECSuccess) {
1089 SSL_TRC(3, ("SSL [%d]: encoding resumption token failed", ss->fd));
1090 return;
1091 }
1092 PORT_Assert(SSL_BUFFER_LEN(&encodedToken) > 0);
1093 PRINT_BUF(40, (ss, "SSL: encoded resumption token",
1094 SSL_BUFFER_BASE(&encodedToken),
1095 SSL_BUFFER_LEN(&encodedToken)));
1096 ss->resumptionTokenCallback(ss->fd, SSL_BUFFER_BASE(&encodedToken),
1097 SSL_BUFFER_LEN(&encodedToken),
1098 ss->resumptionTokenContext);
1099
1100 sslBuffer_Clear(&encodedToken);
1101 }
1102
1103 void
ssl_CacheSessionID(sslSocket * ss)1104 ssl_CacheSessionID(sslSocket *ss)
1105 {
1106 sslSecurityInfo *sec = &ss->sec;
1107 PORT_Assert(sec);
1108
1109 if (sec->ci.sid && !sec->ci.sid->u.ssl3.keys.resumable) {
1110 return;
1111 }
1112
1113 if (!ss->sec.isServer && ss->resumptionTokenCallback) {
1114 ssl_CacheExternalToken(ss);
1115 return;
1116 }
1117
1118 PORT_Assert(!ss->resumptionTokenCallback);
1119 if (sec->isServer) {
1120 ssl_ServerCacheSessionID(sec->ci.sid);
1121 return;
1122 }
1123
1124 CacheSID(sec->ci.sid);
1125 }
1126
1127 void
ssl_UncacheSessionID(sslSocket * ss)1128 ssl_UncacheSessionID(sslSocket *ss)
1129 {
1130 if (ss->opt.noCache) {
1131 return;
1132 }
1133
1134 sslSecurityInfo *sec = &ss->sec;
1135 PORT_Assert(sec);
1136
1137 if (sec->ci.sid) {
1138 if (sec->isServer) {
1139 ssl_ServerUncacheSessionID(sec->ci.sid);
1140 } else if (!ss->resumptionTokenCallback) {
1141 LockAndUncacheSID(sec->ci.sid);
1142 }
1143 }
1144 }
1145
1146 /* wipe out the entire client session cache. */
1147 void
SSL_ClearSessionCache(void)1148 SSL_ClearSessionCache(void)
1149 {
1150 LOCK_CACHE;
1151 while (cache != NULL)
1152 UncacheSID(cache);
1153 UNLOCK_CACHE;
1154 }
1155
1156 /* returns an unsigned int containing the number of seconds in PR_Now() */
1157 PRUint32
ssl_TimeSec(void)1158 ssl_TimeSec(void)
1159 {
1160 #ifdef UNSAFE_FUZZER_MODE
1161 return 1234;
1162 #endif
1163
1164 PRUint32 myTime;
1165 #if defined(XP_UNIX) || defined(XP_WIN) || defined(_WINDOWS) || defined(XP_BEOS)
1166 myTime = time(NULL); /* accurate until the year 2038. */
1167 #else
1168 /* portable, but possibly slower */
1169 PRTime now;
1170 PRInt64 ll;
1171
1172 now = PR_Now();
1173 LL_I2L(ll, 1000000L);
1174 LL_DIV(now, now, ll);
1175 LL_L2UI(myTime, now);
1176 #endif
1177 return myTime;
1178 }
1179
1180 PRBool
ssl_TicketTimeValid(const NewSessionTicket * ticket)1181 ssl_TicketTimeValid(const NewSessionTicket *ticket)
1182 {
1183 PRTime endTime;
1184
1185 if (ticket->ticket_lifetime_hint == 0) {
1186 return PR_TRUE;
1187 }
1188
1189 endTime = ticket->received_timestamp +
1190 (PRTime)(ticket->ticket_lifetime_hint * PR_USEC_PER_SEC);
1191 return endTime > ssl_TimeUsec();
1192 }
1193
1194 void
ssl3_SetSIDSessionTicket(sslSessionID * sid,NewSessionTicket * newSessionTicket)1195 ssl3_SetSIDSessionTicket(sslSessionID *sid,
1196 /*in/out*/ NewSessionTicket *newSessionTicket)
1197 {
1198 PORT_Assert(sid);
1199 PORT_Assert(newSessionTicket);
1200 PORT_Assert(newSessionTicket->ticket.data);
1201 PORT_Assert(newSessionTicket->ticket.len != 0);
1202
1203 /* if sid->u.ssl3.lock, we are updating an existing entry that is already
1204 * cached or was once cached, so we need to acquire and release the write
1205 * lock. Otherwise, this is a new session that isn't shared with anything
1206 * yet, so no locking is needed.
1207 */
1208 if (sid->u.ssl3.lock) {
1209 PR_RWLock_Wlock(sid->u.ssl3.lock);
1210 if (sid->u.ssl3.locked.sessionTicket.ticket.data) {
1211 SECITEM_FreeItem(&sid->u.ssl3.locked.sessionTicket.ticket,
1212 PR_FALSE);
1213 }
1214 }
1215
1216 PORT_Assert(!sid->u.ssl3.locked.sessionTicket.ticket.data);
1217
1218 /* Do a shallow copy, moving the ticket data. */
1219 sid->u.ssl3.locked.sessionTicket = *newSessionTicket;
1220 newSessionTicket->ticket.data = NULL;
1221 newSessionTicket->ticket.len = 0;
1222
1223 if (sid->u.ssl3.lock) {
1224 PR_RWLock_Unlock(sid->u.ssl3.lock);
1225 }
1226 }
1227