Coverage Report

Created: 2026-07-07 06:15

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