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