security/nss/lib/ssl/sslnonce.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/security/nss/lib/ssl/sslnonce.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,512 @@
     1.4 +/* 
     1.5 + * This file implements the CLIENT Session ID cache.  
     1.6 + *
     1.7 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.8 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.9 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
    1.10 +
    1.11 +#include "cert.h"
    1.12 +#include "pk11pub.h"
    1.13 +#include "secitem.h"
    1.14 +#include "ssl.h"
    1.15 +#include "nss.h"
    1.16 +
    1.17 +#include "sslimpl.h"
    1.18 +#include "sslproto.h"
    1.19 +#include "nssilock.h"
    1.20 +#if defined(XP_UNIX) || defined(XP_WIN) || defined(_WINDOWS) || defined(XP_BEOS)
    1.21 +#include <time.h>
    1.22 +#endif
    1.23 +
    1.24 +PRUint32 ssl_sid_timeout = 100;
    1.25 +PRUint32 ssl3_sid_timeout = 86400L; /* 24 hours */
    1.26 +
    1.27 +static sslSessionID *cache = NULL;
    1.28 +static PZLock *      cacheLock = NULL;
    1.29 +
    1.30 +/* sids can be in one of 4 states:
    1.31 + *
    1.32 + * never_cached, 	created, but not yet put into cache. 
    1.33 + * in_client_cache, 	in the client cache's linked list.
    1.34 + * in_server_cache, 	entry came from the server's cache file.
    1.35 + * invalid_cache	has been removed from the cache. 
    1.36 + */
    1.37 +
    1.38 +#define LOCK_CACHE 	lock_cache()
    1.39 +#define UNLOCK_CACHE	PZ_Unlock(cacheLock)
    1.40 +
    1.41 +static SECStatus
    1.42 +ssl_InitClientSessionCacheLock(void)
    1.43 +{
    1.44 +    cacheLock = PZ_NewLock(nssILockCache);
    1.45 +    return cacheLock ? SECSuccess : SECFailure;
    1.46 +}
    1.47 +
    1.48 +static SECStatus
    1.49 +ssl_FreeClientSessionCacheLock(void)
    1.50 +{
    1.51 +    if (cacheLock) {
    1.52 +        PZ_DestroyLock(cacheLock);
    1.53 +        cacheLock = NULL;
    1.54 +        return SECSuccess;
    1.55 +    }
    1.56 +    PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
    1.57 +    return SECFailure;
    1.58 +}
    1.59 +
    1.60 +static PRBool LocksInitializedEarly = PR_FALSE;
    1.61 +
    1.62 +static SECStatus
    1.63 +FreeSessionCacheLocks()
    1.64 +{
    1.65 +    SECStatus rv1, rv2;
    1.66 +    rv1 = ssl_FreeSymWrapKeysLock();
    1.67 +    rv2 = ssl_FreeClientSessionCacheLock();
    1.68 +    if ( (SECSuccess == rv1) && (SECSuccess == rv2) ) {
    1.69 +        return SECSuccess;
    1.70 +    }
    1.71 +    return SECFailure;
    1.72 +}
    1.73 +
    1.74 +static SECStatus
    1.75 +InitSessionCacheLocks(void)
    1.76 +{
    1.77 +    SECStatus rv1, rv2;
    1.78 +    PRErrorCode rc;
    1.79 +    rv1 = ssl_InitSymWrapKeysLock();
    1.80 +    rv2 = ssl_InitClientSessionCacheLock();
    1.81 +    if ( (SECSuccess == rv1) && (SECSuccess == rv2) ) {
    1.82 +        return SECSuccess;
    1.83 +    }
    1.84 +    rc = PORT_GetError();
    1.85 +    FreeSessionCacheLocks();
    1.86 +    PORT_SetError(rc);
    1.87 +    return SECFailure;
    1.88 +}
    1.89 +
    1.90 +/* free the session cache locks if they were initialized early */
    1.91 +SECStatus
    1.92 +ssl_FreeSessionCacheLocks()
    1.93 +{
    1.94 +    PORT_Assert(PR_TRUE == LocksInitializedEarly);
    1.95 +    if (!LocksInitializedEarly) {
    1.96 +        PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
    1.97 +        return SECFailure;
    1.98 +    }
    1.99 +    FreeSessionCacheLocks();
   1.100 +    LocksInitializedEarly = PR_FALSE;
   1.101 +    return SECSuccess;
   1.102 +}
   1.103 +
   1.104 +static PRCallOnceType lockOnce;
   1.105 +
   1.106 +/* free the session cache locks if they were initialized lazily */
   1.107 +static SECStatus ssl_ShutdownLocks(void* appData, void* nssData)
   1.108 +{
   1.109 +    PORT_Assert(PR_FALSE == LocksInitializedEarly);
   1.110 +    if (LocksInitializedEarly) {
   1.111 +        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
   1.112 +        return SECFailure;
   1.113 +    }
   1.114 +    FreeSessionCacheLocks();
   1.115 +    memset(&lockOnce, 0, sizeof(lockOnce));
   1.116 +    return SECSuccess;
   1.117 +}
   1.118 +
   1.119 +static PRStatus initSessionCacheLocksLazily(void)
   1.120 +{
   1.121 +    SECStatus rv = InitSessionCacheLocks();
   1.122 +    if (SECSuccess != rv) {
   1.123 +        return PR_FAILURE;
   1.124 +    }
   1.125 +    rv = NSS_RegisterShutdown(ssl_ShutdownLocks, NULL);
   1.126 +    PORT_Assert(SECSuccess == rv);
   1.127 +    if (SECSuccess != rv) {
   1.128 +        return PR_FAILURE;
   1.129 +    }
   1.130 +    return PR_SUCCESS;
   1.131 +}
   1.132 +
   1.133 +/* lazyInit means that the call is not happening during a 1-time
   1.134 + * initialization function, but rather during dynamic, lazy initialization
   1.135 + */
   1.136 +SECStatus
   1.137 +ssl_InitSessionCacheLocks(PRBool lazyInit)
   1.138 +{
   1.139 +    if (LocksInitializedEarly) {
   1.140 +        return SECSuccess;
   1.141 +    }
   1.142 +
   1.143 +    if (lazyInit) {
   1.144 +        return (PR_SUCCESS ==
   1.145 +                PR_CallOnce(&lockOnce, initSessionCacheLocksLazily)) ?
   1.146 +               SECSuccess : SECFailure;
   1.147 +    }
   1.148 +     
   1.149 +    if (SECSuccess == InitSessionCacheLocks()) {
   1.150 +        LocksInitializedEarly = PR_TRUE;
   1.151 +        return SECSuccess;
   1.152 +    }
   1.153 +
   1.154 +    return SECFailure;
   1.155 +}
   1.156 +
   1.157 +static void 
   1.158 +lock_cache(void)
   1.159 +{
   1.160 +    ssl_InitSessionCacheLocks(PR_TRUE);
   1.161 +    PZ_Lock(cacheLock);
   1.162 +}
   1.163 +
   1.164 +/* BEWARE: This function gets called for both client and server SIDs !!
   1.165 + * If the unreferenced sid is not in the cache, Free sid and its contents.
   1.166 + */
   1.167 +static void
   1.168 +ssl_DestroySID(sslSessionID *sid)
   1.169 +{
   1.170 +    SSL_TRC(8, ("SSL: destroy sid: sid=0x%x cached=%d", sid, sid->cached));
   1.171 +    PORT_Assert(sid->references == 0);
   1.172 +    PORT_Assert(sid->cached != in_client_cache);
   1.173 +
   1.174 +    if (sid->version < SSL_LIBRARY_VERSION_3_0) {
   1.175 +	SECITEM_ZfreeItem(&sid->u.ssl2.masterKey, PR_FALSE);
   1.176 +	SECITEM_ZfreeItem(&sid->u.ssl2.cipherArg, PR_FALSE);
   1.177 +    } else {
   1.178 +        if (sid->u.ssl3.locked.sessionTicket.ticket.data) {
   1.179 +            SECITEM_FreeItem(&sid->u.ssl3.locked.sessionTicket.ticket,
   1.180 +                             PR_FALSE);
   1.181 +        }
   1.182 +        if (sid->u.ssl3.srvName.data) {
   1.183 +            SECITEM_FreeItem(&sid->u.ssl3.srvName, PR_FALSE);
   1.184 +        }
   1.185 +
   1.186 +        if (sid->u.ssl3.lock) {
   1.187 +            PR_DestroyRWLock(sid->u.ssl3.lock);
   1.188 +        }
   1.189 +    }
   1.190 +
   1.191 +    if (sid->peerID != NULL)
   1.192 +	PORT_Free((void *)sid->peerID);		/* CONST */
   1.193 +
   1.194 +    if (sid->urlSvrName != NULL)
   1.195 +	PORT_Free((void *)sid->urlSvrName);	/* CONST */
   1.196 +
   1.197 +    if ( sid->peerCert ) {
   1.198 +	CERT_DestroyCertificate(sid->peerCert);
   1.199 +    }
   1.200 +    if (sid->peerCertStatus.items) {
   1.201 +        SECITEM_FreeArray(&sid->peerCertStatus, PR_FALSE);
   1.202 +    }
   1.203 +
   1.204 +    if ( sid->localCert ) {
   1.205 +	CERT_DestroyCertificate(sid->localCert);
   1.206 +    }
   1.207 +    
   1.208 +    PORT_ZFree(sid, sizeof(sslSessionID));
   1.209 +}
   1.210 +
   1.211 +/* BEWARE: This function gets called for both client and server SIDs !!
   1.212 + * Decrement reference count, and 
   1.213 + *    free sid if ref count is zero, and sid is not in the cache. 
   1.214 + * Does NOT remove from the cache first.  
   1.215 + * If the sid is still in the cache, it is left there until next time
   1.216 + * the cache list is traversed.
   1.217 + */
   1.218 +static void 
   1.219 +ssl_FreeLockedSID(sslSessionID *sid)
   1.220 +{
   1.221 +    PORT_Assert(sid->references >= 1);
   1.222 +    if (--sid->references == 0) {
   1.223 +	ssl_DestroySID(sid);
   1.224 +    }
   1.225 +}
   1.226 +
   1.227 +/* BEWARE: This function gets called for both client and server SIDs !!
   1.228 + * Decrement reference count, and 
   1.229 + *    free sid if ref count is zero, and sid is not in the cache. 
   1.230 + * Does NOT remove from the cache first.  
   1.231 + * These locks are necessary because the sid _might_ be in the cache list.
   1.232 + */
   1.233 +void
   1.234 +ssl_FreeSID(sslSessionID *sid)
   1.235 +{
   1.236 +    LOCK_CACHE;
   1.237 +    ssl_FreeLockedSID(sid);
   1.238 +    UNLOCK_CACHE;
   1.239 +}
   1.240 +
   1.241 +/************************************************************************/
   1.242 +
   1.243 +/*
   1.244 +**  Lookup sid entry in cache by Address, port, and peerID string.
   1.245 +**  If found, Increment reference count, and return pointer to caller.
   1.246 +**  If it has timed out or ref count is zero, remove from list and free it.
   1.247 +*/
   1.248 +
   1.249 +sslSessionID *
   1.250 +ssl_LookupSID(const PRIPv6Addr *addr, PRUint16 port, const char *peerID, 
   1.251 +              const char * urlSvrName)
   1.252 +{
   1.253 +    sslSessionID **sidp;
   1.254 +    sslSessionID * sid;
   1.255 +    PRUint32       now;
   1.256 +
   1.257 +    if (!urlSvrName)
   1.258 +    	return NULL;
   1.259 +    now = ssl_Time();
   1.260 +    LOCK_CACHE;
   1.261 +    sidp = &cache;
   1.262 +    while ((sid = *sidp) != 0) {
   1.263 +	PORT_Assert(sid->cached == in_client_cache);
   1.264 +	PORT_Assert(sid->references >= 1);
   1.265 +
   1.266 +	SSL_TRC(8, ("SSL: Lookup1: sid=0x%x", sid));
   1.267 +
   1.268 +	if (sid->expirationTime < now) {
   1.269 +	    /*
   1.270 +	    ** This session-id timed out.
   1.271 +	    ** Don't even care who it belongs to, blow it out of our cache.
   1.272 +	    */
   1.273 +	    SSL_TRC(7, ("SSL: lookup1, throwing sid out, age=%d refs=%d",
   1.274 +			now - sid->creationTime, sid->references));
   1.275 +
   1.276 +	    *sidp = sid->next; 			/* delink it from the list. */
   1.277 +	    sid->cached = invalid_cache;	/* mark not on list. */
   1.278 +	    ssl_FreeLockedSID(sid);		/* drop ref count, free. */
   1.279 +	} else if (!memcmp(&sid->addr, addr, sizeof(PRIPv6Addr)) && /* server IP addr matches */
   1.280 +	           (sid->port == port) && /* server port matches */
   1.281 +		   /* proxy (peerID) matches */
   1.282 +		   (((peerID == NULL) && (sid->peerID == NULL)) ||
   1.283 +		    ((peerID != NULL) && (sid->peerID != NULL) &&
   1.284 +		     PORT_Strcmp(sid->peerID, peerID) == 0)) &&
   1.285 +		   /* is cacheable */
   1.286 +		   (sid->version < SSL_LIBRARY_VERSION_3_0 ||
   1.287 +		    sid->u.ssl3.keys.resumable) &&
   1.288 +		   /* server hostname matches. */
   1.289 +	           (sid->urlSvrName != NULL) &&
   1.290 +		   ((0 == PORT_Strcmp(urlSvrName, sid->urlSvrName)) ||
   1.291 +		    ((sid->peerCert != NULL) && (SECSuccess == 
   1.292 +		      CERT_VerifyCertName(sid->peerCert, urlSvrName))) )
   1.293 +		  ) {
   1.294 +	    /* Hit */
   1.295 +	    sid->lastAccessTime = now;
   1.296 +	    sid->references++;
   1.297 +	    break;
   1.298 +	} else {
   1.299 +	    sidp = &sid->next;
   1.300 +	}
   1.301 +    }
   1.302 +    UNLOCK_CACHE;
   1.303 +    return sid;
   1.304 +}
   1.305 +
   1.306 +/*
   1.307 +** Add an sid to the cache or return a previously cached entry to the cache.
   1.308 +** Although this is static, it is called via ss->sec.cache().
   1.309 +*/
   1.310 +static void 
   1.311 +CacheSID(sslSessionID *sid)
   1.312 +{
   1.313 +    PRUint32  expirationPeriod;
   1.314 +
   1.315 +    PORT_Assert(sid->cached == never_cached);
   1.316 +
   1.317 +    SSL_TRC(8, ("SSL: Cache: sid=0x%x cached=%d addr=0x%08x%08x%08x%08x port=0x%04x "
   1.318 +		"time=%x cached=%d",
   1.319 +		sid, sid->cached, sid->addr.pr_s6_addr32[0], 
   1.320 +		sid->addr.pr_s6_addr32[1], sid->addr.pr_s6_addr32[2],
   1.321 +		sid->addr.pr_s6_addr32[3],  sid->port, sid->creationTime,
   1.322 +		sid->cached));
   1.323 +
   1.324 +    if (!sid->urlSvrName) {
   1.325 +        /* don't cache this SID because it can never be matched */
   1.326 +        return;
   1.327 +    }
   1.328 +
   1.329 +    /* XXX should be different trace for version 2 vs. version 3 */
   1.330 +    if (sid->version < SSL_LIBRARY_VERSION_3_0) {
   1.331 +	expirationPeriod = ssl_sid_timeout;
   1.332 +	PRINT_BUF(8, (0, "sessionID:",
   1.333 +		  sid->u.ssl2.sessionID, sizeof(sid->u.ssl2.sessionID)));
   1.334 +	PRINT_BUF(8, (0, "masterKey:",
   1.335 +		  sid->u.ssl2.masterKey.data, sid->u.ssl2.masterKey.len));
   1.336 +	PRINT_BUF(8, (0, "cipherArg:",
   1.337 +		  sid->u.ssl2.cipherArg.data, sid->u.ssl2.cipherArg.len));
   1.338 +    } else {
   1.339 +	if (sid->u.ssl3.sessionIDLength == 0 &&
   1.340 +	    sid->u.ssl3.locked.sessionTicket.ticket.data == NULL)
   1.341 +	    return;
   1.342 +
   1.343 +	/* Client generates the SessionID if this was a stateless resume. */
   1.344 +	if (sid->u.ssl3.sessionIDLength == 0) {
   1.345 +	    SECStatus rv;
   1.346 +	    rv = PK11_GenerateRandom(sid->u.ssl3.sessionID,
   1.347 +		SSL3_SESSIONID_BYTES);
   1.348 +	    if (rv != SECSuccess)
   1.349 +		return;
   1.350 +	    sid->u.ssl3.sessionIDLength = SSL3_SESSIONID_BYTES;
   1.351 +	}
   1.352 +	expirationPeriod = ssl3_sid_timeout;
   1.353 +	PRINT_BUF(8, (0, "sessionID:",
   1.354 +		      sid->u.ssl3.sessionID, sid->u.ssl3.sessionIDLength));
   1.355 +
   1.356 +	sid->u.ssl3.lock = PR_NewRWLock(PR_RWLOCK_RANK_NONE, NULL);
   1.357 +	if (!sid->u.ssl3.lock) {
   1.358 +	    return;
   1.359 +	}
   1.360 +    }
   1.361 +    PORT_Assert(sid->creationTime != 0 && sid->expirationTime != 0);
   1.362 +    if (!sid->creationTime)
   1.363 +	sid->lastAccessTime = sid->creationTime = ssl_Time();
   1.364 +    if (!sid->expirationTime)
   1.365 +	sid->expirationTime = sid->creationTime + expirationPeriod;
   1.366 +
   1.367 +    /*
   1.368 +     * Put sid into the cache.  Bump reference count to indicate that
   1.369 +     * cache is holding a reference. Uncache will reduce the cache
   1.370 +     * reference.
   1.371 +     */
   1.372 +    LOCK_CACHE;
   1.373 +    sid->references++;
   1.374 +    sid->cached = in_client_cache;
   1.375 +    sid->next   = cache;
   1.376 +    cache       = sid;
   1.377 +    UNLOCK_CACHE;
   1.378 +}
   1.379 +
   1.380 +/* 
   1.381 + * If sid "zap" is in the cache,
   1.382 + *    removes sid from cache, and decrements reference count.
   1.383 + * Caller must hold cache lock.
   1.384 + */
   1.385 +static void
   1.386 +UncacheSID(sslSessionID *zap)
   1.387 +{
   1.388 +    sslSessionID **sidp = &cache;
   1.389 +    sslSessionID *sid;
   1.390 +
   1.391 +    if (zap->cached != in_client_cache) {
   1.392 +	return;
   1.393 +    }
   1.394 +
   1.395 +    SSL_TRC(8,("SSL: Uncache: zap=0x%x cached=%d addr=0x%08x%08x%08x%08x port=0x%04x "
   1.396 +	       "time=%x cipher=%d",
   1.397 +	       zap, zap->cached, zap->addr.pr_s6_addr32[0],
   1.398 +	       zap->addr.pr_s6_addr32[1], zap->addr.pr_s6_addr32[2],
   1.399 +	       zap->addr.pr_s6_addr32[3], zap->port, zap->creationTime,
   1.400 +	       zap->u.ssl2.cipherType));
   1.401 +    if (zap->version < SSL_LIBRARY_VERSION_3_0) {
   1.402 +	PRINT_BUF(8, (0, "sessionID:",
   1.403 +		      zap->u.ssl2.sessionID, sizeof(zap->u.ssl2.sessionID)));
   1.404 +	PRINT_BUF(8, (0, "masterKey:",
   1.405 +		      zap->u.ssl2.masterKey.data, zap->u.ssl2.masterKey.len));
   1.406 +	PRINT_BUF(8, (0, "cipherArg:",
   1.407 +		      zap->u.ssl2.cipherArg.data, zap->u.ssl2.cipherArg.len));
   1.408 +    }
   1.409 +
   1.410 +    /* See if it's in the cache, if so nuke it */
   1.411 +    while ((sid = *sidp) != 0) {
   1.412 +	if (sid == zap) {
   1.413 +	    /*
   1.414 +	    ** Bingo. Reduce reference count by one so that when
   1.415 +	    ** everyone is done with the sid we can free it up.
   1.416 +	    */
   1.417 +	    *sidp = zap->next;
   1.418 +	    zap->cached = invalid_cache;
   1.419 +	    ssl_FreeLockedSID(zap);
   1.420 +	    return;
   1.421 +	}
   1.422 +	sidp = &sid->next;
   1.423 +    }
   1.424 +}
   1.425 +
   1.426 +/* If sid "zap" is in the cache,
   1.427 + *    removes sid from cache, and decrements reference count.
   1.428 + * Although this function is static, it is called externally via 
   1.429 + *    ss->sec.uncache().
   1.430 + */
   1.431 +static void
   1.432 +LockAndUncacheSID(sslSessionID *zap)
   1.433 +{
   1.434 +    LOCK_CACHE;
   1.435 +    UncacheSID(zap);
   1.436 +    UNLOCK_CACHE;
   1.437 +
   1.438 +}
   1.439 +
   1.440 +/* choose client or server cache functions for this sslsocket. */
   1.441 +void 
   1.442 +ssl_ChooseSessionIDProcs(sslSecurityInfo *sec)
   1.443 +{
   1.444 +    if (sec->isServer) {
   1.445 +	sec->cache   = ssl_sid_cache;
   1.446 +	sec->uncache = ssl_sid_uncache;
   1.447 +    } else {
   1.448 +	sec->cache   = CacheSID;
   1.449 +	sec->uncache = LockAndUncacheSID;
   1.450 +    }
   1.451 +}
   1.452 +
   1.453 +/* wipe out the entire client session cache. */
   1.454 +void
   1.455 +SSL_ClearSessionCache(void)
   1.456 +{
   1.457 +    LOCK_CACHE;
   1.458 +    while(cache != NULL)
   1.459 +	UncacheSID(cache);
   1.460 +    UNLOCK_CACHE;
   1.461 +}
   1.462 +
   1.463 +/* returns an unsigned int containing the number of seconds in PR_Now() */
   1.464 +PRUint32
   1.465 +ssl_Time(void)
   1.466 +{
   1.467 +    PRUint32 myTime;
   1.468 +#if defined(XP_UNIX) || defined(XP_WIN) || defined(_WINDOWS) || defined(XP_BEOS)
   1.469 +    myTime = time(NULL);	/* accurate until the year 2038. */
   1.470 +#else
   1.471 +    /* portable, but possibly slower */
   1.472 +    PRTime now;
   1.473 +    PRInt64 ll;
   1.474 +
   1.475 +    now = PR_Now();
   1.476 +    LL_I2L(ll, 1000000L);
   1.477 +    LL_DIV(now, now, ll);
   1.478 +    LL_L2UI(myTime, now);
   1.479 +#endif
   1.480 +    return myTime;
   1.481 +}
   1.482 +
   1.483 +void
   1.484 +ssl3_SetSIDSessionTicket(sslSessionID *sid,
   1.485 +                         /*in/out*/ NewSessionTicket *newSessionTicket)
   1.486 +{
   1.487 +    PORT_Assert(sid);
   1.488 +    PORT_Assert(newSessionTicket);
   1.489 +    PORT_Assert(newSessionTicket->ticket.data);
   1.490 +    PORT_Assert(newSessionTicket->ticket.len != 0);
   1.491 +
   1.492 +    /* if sid->u.ssl3.lock, we are updating an existing entry that is already
   1.493 +     * cached or was once cached, so we need to acquire and release the write
   1.494 +     * lock. Otherwise, this is a new session that isn't shared with anything
   1.495 +     * yet, so no locking is needed.
   1.496 +     */
   1.497 +    if (sid->u.ssl3.lock) {
   1.498 +	PR_RWLock_Wlock(sid->u.ssl3.lock);
   1.499 +	if (sid->u.ssl3.locked.sessionTicket.ticket.data) {
   1.500 +	    SECITEM_FreeItem(&sid->u.ssl3.locked.sessionTicket.ticket,
   1.501 +			     PR_FALSE);
   1.502 +	}
   1.503 +    }
   1.504 +
   1.505 +    PORT_Assert(!sid->u.ssl3.locked.sessionTicket.ticket.data);
   1.506 +
   1.507 +    /* Do a shallow copy, moving the ticket data. */
   1.508 +    sid->u.ssl3.locked.sessionTicket = *newSessionTicket;
   1.509 +    newSessionTicket->ticket.data = NULL;
   1.510 +    newSessionTicket->ticket.len = 0;
   1.511 +
   1.512 +    if (sid->u.ssl3.lock) {
   1.513 +	PR_RWLock_Unlock(sid->u.ssl3.lock);
   1.514 +    }
   1.515 +}

mercurial