Coverage Report

Created: 2025-09-17 07:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/nss/lib/ssl/sslsnce.c
Line
Count
Source
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/* This file implements the SERVER Session ID cache.
3
 * NOTE:  The contents of this file are NOT used by the client.
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
/* Note: ssl_FreeSID() in sslnonce.c gets used for both client and server
10
 * cache sids!
11
 *
12
 * About record locking among different server processes:
13
 *
14
 * All processes that are part of the same conceptual server (serving on
15
 * the same address and port) MUST share a common SSL session cache.
16
 * This code makes the content of the shared cache accessible to all
17
 * processes on the same "server".  This code works on Unix and Win32 only.
18
 *
19
 * We use NSPR anonymous shared memory and move data to & from shared memory.
20
 * We must do explicit locking of the records for all reads and writes.
21
 * The set of Cache entries are divided up into "sets" of 128 entries.
22
 * Each set is protected by a lock.  There may be one or more sets protected
23
 * by each lock.  That is, locks to sets are 1:N.
24
 * There is one lock for the entire cert cache.
25
 * There is one lock for the set of wrapped sym wrap keys.
26
 *
27
 * The anonymous shared memory is laid out as if it were declared like this:
28
 *
29
 * struct {
30
 *     cacheDescriptor          desc;
31
 *     sidCacheLock             sidCacheLocks[ numSIDCacheLocks];
32
 *     sidCacheLock             keyCacheLock;
33
 *     sidCacheLock             certCacheLock;
34
 *     sidCacheSet              sidCacheSets[ numSIDCacheSets ];
35
 *     sidCacheEntry            sidCacheData[ numSIDCacheEntries];
36
 *     certCacheEntry           certCacheData[numCertCacheEntries];
37
 *     SSLWrappedSymWrappingKey keyCacheData[SSL_NUM_WRAP_KEYS][SSL_NUM_WRAP_MECHS];
38
 *     PRUint8                  keyNameSuffix[SELF_ENCRYPT_KEY_VAR_NAME_LEN]
39
 *     encKeyCacheEntry         ticketEncKey; // Wrapped
40
 *     encKeyCacheEntry         ticketMacKey; // Wrapped
41
 *     PRBool                   ticketKeysValid;
42
 *     sidCacheLock             srvNameCacheLock;
43
 *     srvNameCacheEntry        srvNameData[ numSrvNameCacheEntries ];
44
 * } cacheMemCacheData;
45
 */
46
#include "seccomon.h"
47
48
#if defined(XP_UNIX) || defined(XP_WIN32)
49
50
#include "cert.h"
51
#include "ssl.h"
52
#include "sslimpl.h"
53
#include "sslproto.h"
54
#include "pk11func.h"
55
#include "base64.h"
56
#include "keyhi.h"
57
#include "blapit.h"
58
#include "nss.h" /* for NSS_RegisterShutdown */
59
#include "sechash.h"
60
#include "selfencrypt.h"
61
#include <stdio.h>
62
63
#if defined(XP_UNIX)
64
65
#include <syslog.h>
66
#include <fcntl.h>
67
#include <unistd.h>
68
#include <errno.h>
69
#include <signal.h>
70
#include "unix_err.h"
71
72
#else
73
74
#ifdef XP_WIN32
75
#include <wtypes.h>
76
#include "win32err.h"
77
#endif
78
79
#endif
80
#include <sys/types.h>
81
82
#include "nspr.h"
83
#include "sslmutex.h"
84
85
/*
86
** Format of a cache entry in the shared memory.
87
*/
88
PR_STATIC_ASSERT(sizeof(PRTime) == 8);
89
struct sidCacheEntryStr {
90
    /* 16 */ PRIPv6Addr addr; /* client's IP address */
91
    /*  8 */ PRTime creationTime;
92
    /*  8 */ PRTime lastAccessTime;
93
    /*  8 */ PRTime expirationTime;
94
    /*  2 */ PRUint16 version;
95
    /*  1 */ PRUint8 valid;
96
    /*  1 */ PRUint8 sessionIDLength;
97
    /* 32 */ PRUint8 sessionID[SSL3_SESSIONID_BYTES];
98
    /*  2 */ PRUint16 authType;
99
    /*  2 */ PRUint16 authKeyBits;
100
    /*  2 */ PRUint16 keaType;
101
    /*  2 */ PRUint16 keaKeyBits;
102
    /*  4 */ PRUint32 signatureScheme;
103
    /*  4 */ PRUint32 keaGroup;
104
    /* 92  - common header total */
105
106
    union {
107
        struct {
108
            /*  2 */ ssl3CipherSuite cipherSuite;
109
            /* 52 */ ssl3SidKeys keys; /* keys, wrapped as needed. */
110
111
            /*  4 */ PRUint32 masterWrapMech;
112
            /*  4 */ PRInt32 certIndex;
113
            /*  4 */ PRInt32 srvNameIndex;
114
            /* 32 */ PRUint8 srvNameHash[SHA256_LENGTH]; /* SHA256 name hash */
115
            /*  2 */ PRUint16 namedCurve;
116
/*100 */} ssl3;
117
118
/* force sizeof(sidCacheEntry) to be a multiple of cache line size */
119
struct {
120
    /*116 */ PRUint8 filler[116]; /* 92+116==208, a multiple of 16 */
121
} forceSize;
122
    } u;
123
};
124
typedef struct sidCacheEntryStr sidCacheEntry;
125
126
/* The length of this struct is supposed to be a power of 2, e.g. 4KB */
127
struct certCacheEntryStr {
128
    PRUint16 certLength;                     /*    2 */
129
    PRUint16 sessionIDLength;                /*    2 */
130
    PRUint8 sessionID[SSL3_SESSIONID_BYTES]; /*   32 */
131
    PRUint8 cert[SSL_MAX_CACHED_CERT_LEN];   /* 4060 */
132
};                                           /* total   4096 */
133
typedef struct certCacheEntryStr certCacheEntry;
134
135
struct sidCacheLockStr {
136
    PRUint32 timeStamp;
137
    sslMutex mutex;
138
    sslPID pid;
139
};
140
typedef struct sidCacheLockStr sidCacheLock;
141
142
struct sidCacheSetStr {
143
    PRIntn next;
144
};
145
typedef struct sidCacheSetStr sidCacheSet;
146
147
struct encKeyCacheEntryStr {
148
    PRUint8 bytes[512];
149
    PRInt32 length;
150
};
151
typedef struct encKeyCacheEntryStr encKeyCacheEntry;
152
153
0
#define SSL_MAX_DNS_HOST_NAME 1024
154
155
struct srvNameCacheEntryStr {
156
    PRUint16 type;                            /*    2 */
157
    PRUint16 nameLen;                         /*    2 */
158
    PRUint8 name[SSL_MAX_DNS_HOST_NAME + 12]; /* 1034 */
159
    PRUint8 nameHash[SHA256_LENGTH];          /*   32 */
160
                                              /* 1072 */
161
};
162
typedef struct srvNameCacheEntryStr srvNameCacheEntry;
163
164
struct cacheDescStr {
165
166
    PRUint32 cacheMemSize;
167
168
    PRUint32 numSIDCacheLocks;
169
    PRUint32 numSIDCacheSets;
170
    PRUint32 numSIDCacheSetsPerLock;
171
172
    PRUint32 numSIDCacheEntries;
173
    PRUint32 sidCacheSize;
174
175
    PRUint32 numCertCacheEntries;
176
    PRUint32 certCacheSize;
177
178
    PRUint32 numKeyCacheEntries;
179
    PRUint32 keyCacheSize;
180
181
    PRUint32 numSrvNameCacheEntries;
182
    PRUint32 srvNameCacheSize;
183
184
    PRUint32 ssl3Timeout;
185
186
    PRUint32 numSIDCacheLocksInitialized;
187
188
    /* These values are volatile, and are accessed through sharedCache-> */
189
    PRUint32 nextCertCacheEntry; /* certCacheLock protects */
190
    PRBool stopPolling;
191
    PRBool everInherited;
192
193
    /* The private copies of these values are pointers into shared mem */
194
    /* The copies of these values in shared memory are merely offsets */
195
    sidCacheLock *sidCacheLocks;
196
    sidCacheLock *keyCacheLock;
197
    sidCacheLock *certCacheLock;
198
    sidCacheLock *srvNameCacheLock;
199
    sidCacheSet *sidCacheSets;
200
    sidCacheEntry *sidCacheData;
201
    certCacheEntry *certCacheData;
202
    SSLWrappedSymWrappingKey *keyCacheData;
203
    PRUint8 *ticketKeyNameSuffix;
204
    encKeyCacheEntry *ticketEncKey;
205
    encKeyCacheEntry *ticketMacKey;
206
    PRUint32 *ticketKeysValid;
207
    srvNameCacheEntry *srvNameCacheData;
208
209
    /* Only the private copies of these pointers are valid */
210
    char *cacheMem;
211
    struct cacheDescStr *sharedCache; /* shared copy of this struct */
212
    PRFileMap *cacheMemMap;
213
    PRThread *poller;
214
    PRUint32 mutexTimeout;
215
    PRBool shared;
216
};
217
typedef struct cacheDescStr cacheDesc;
218
219
static cacheDesc globalCache;
220
221
static const char envVarName[] = { SSL_ENV_VAR_NAME };
222
223
static PRBool isMultiProcess = PR_FALSE;
224
225
4
#define DEF_SID_CACHE_ENTRIES 10000
226
#define DEF_CERT_CACHE_ENTRIES 250
227
12
#define MIN_CERT_CACHE_ENTRIES 125 /* the effective size in old releases. */
228
#define DEF_KEY_CACHE_ENTRIES 250
229
8
#define DEF_NAME_CACHE_ENTRIES 1000
230
231
1.15M
#define SID_CACHE_ENTRIES_PER_SET 128
232
#define SID_ALIGNMENT 16
233
234
4
#define DEF_SSL3_TIMEOUT 86400L /* 24 hours */
235
0
#define MAX_SSL3_TIMEOUT 86400L /* 24 hours */
236
0
#define MIN_SSL3_TIMEOUT 5      /* seconds  */
237
238
#if defined(AIX) || defined(LINUX) || defined(NETBSD) || defined(OPENBSD)
239
#define MAX_SID_CACHE_LOCKS 8 /* two FDs per lock */
240
#else
241
#define MAX_SID_CACHE_LOCKS 256
242
#endif
243
244
52
#define SID_HOWMANY(val, size) (((val) + ((size)-1)) / (size))
245
44
#define SID_ROUNDUP(val, size) ((size)*SID_HOWMANY((val), (size)))
246
247
static sslPID myPid;
248
static PRUint32 ssl_max_sid_cache_locks = MAX_SID_CACHE_LOCKS;
249
250
/* forward static function declarations */
251
static PRUint32 SIDindex(cacheDesc *cache, const PRIPv6Addr *addr, PRUint8 *s,
252
                         unsigned nl);
253
#if defined(XP_UNIX)
254
static SECStatus LaunchLockPoller(cacheDesc *cache);
255
static SECStatus StopLockPoller(cacheDesc *cache);
256
#endif
257
258
struct inheritanceStr {
259
    PRUint32 cacheMemSize;
260
    PRUint32 fmStrLen;
261
};
262
263
typedef struct inheritanceStr inheritance;
264
265
#if defined(_WIN32)
266
267
#define DEFAULT_CACHE_DIRECTORY "\\temp"
268
269
#endif /* _win32 */
270
271
#if defined(XP_UNIX)
272
273
0
#define DEFAULT_CACHE_DIRECTORY "/tmp"
274
275
#endif /* XP_UNIX */
276
277
/************************************************************************/
278
279
/* SSL Session Cache has a smaller set of functions to initialize than
280
 * ssl does. some ssl_functions can't be initialized before NSS has been
281
 * initialized, and the cache may be configured before NSS is initialized
282
 * so thus the special init function */
283
static SECStatus
284
ssl_InitSessionCache()
285
4
{
286
    /* currently only one function, which is itself idempotent */
287
4
    return ssl_InitializePRErrorTable();
288
4
}
289
290
/* This is used to set locking times for the cache.  It is not used to set the
291
 * PRTime attributes of sessions, which are driven by ss->now(). */
292
static PRUint32
293
ssl_CacheNow()
294
42.8k
{
295
42.8k
    return PR_Now() / PR_USEC_PER_SEC;
296
42.8k
}
297
298
static PRUint32
299
LockSidCacheLock(sidCacheLock *lock, PRUint32 now)
300
46.6k
{
301
46.6k
    SECStatus rv = sslMutex_Lock(&lock->mutex);
302
46.6k
    if (rv != SECSuccess)
303
0
        return 0;
304
46.6k
    if (!now) {
305
42.8k
        now = ssl_CacheNow();
306
42.8k
    }
307
308
46.6k
    lock->timeStamp = now;
309
46.6k
    lock->pid = myPid;
310
46.6k
    return now;
311
46.6k
}
312
313
static SECStatus
314
UnlockSidCacheLock(sidCacheLock *lock)
315
46.6k
{
316
46.6k
    SECStatus rv;
317
318
46.6k
    lock->pid = 0;
319
46.6k
    rv = sslMutex_Unlock(&lock->mutex);
320
46.6k
    return rv;
321
46.6k
}
322
323
/* Returns non-zero |now| or ssl_CacheNow() on success, zero on failure. */
324
static PRUint32
325
LockSet(cacheDesc *cache, PRUint32 set, PRUint32 now)
326
37.3k
{
327
37.3k
    PRUint32 lockNum = set % cache->numSIDCacheLocks;
328
37.3k
    sidCacheLock *lock = cache->sidCacheLocks + lockNum;
329
330
37.3k
    return LockSidCacheLock(lock, now);
331
37.3k
}
332
333
static SECStatus
334
UnlockSet(cacheDesc *cache, PRUint32 set)
335
37.3k
{
336
37.3k
    PRUint32 lockNum = set % cache->numSIDCacheLocks;
337
37.3k
    sidCacheLock *lock = cache->sidCacheLocks + lockNum;
338
339
37.3k
    return UnlockSidCacheLock(lock);
340
37.3k
}
341
342
/************************************************************************/
343
344
/* Put a certificate in the cache.  Update the cert index in the sce.
345
 */
346
static PRUint32
347
CacheCert(cacheDesc *cache, CERTCertificate *cert, sidCacheEntry *sce)
348
3.75k
{
349
3.75k
    PRUint32 now;
350
3.75k
    certCacheEntry cce;
351
352
3.75k
    if ((cert->derCert.len > SSL_MAX_CACHED_CERT_LEN) ||
353
3.75k
        (cert->derCert.len <= 0) ||
354
3.75k
        (cert->derCert.data == NULL)) {
355
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
356
0
        return 0;
357
0
    }
358
359
3.75k
    cce.sessionIDLength = sce->sessionIDLength;
360
3.75k
    PORT_Memcpy(cce.sessionID, sce->sessionID, cce.sessionIDLength);
361
362
3.75k
    cce.certLength = cert->derCert.len;
363
3.75k
    PORT_Memcpy(cce.cert, cert->derCert.data, cce.certLength);
364
365
    /* get lock on cert cache */
366
3.75k
    now = LockSidCacheLock(cache->certCacheLock, 0);
367
3.75k
    if (now) {
368
369
        /* Find where to place the next cert cache entry. */
370
3.75k
        cacheDesc *sharedCache = cache->sharedCache;
371
3.75k
        PRUint32 ndx = sharedCache->nextCertCacheEntry;
372
373
        /* write the entry */
374
3.75k
        cache->certCacheData[ndx] = cce;
375
376
        /* remember where we put it. */
377
3.75k
        sce->u.ssl3.certIndex = ndx;
378
379
        /* update the "next" cache entry index */
380
3.75k
        sharedCache->nextCertCacheEntry =
381
3.75k
            (ndx + 1) % cache->numCertCacheEntries;
382
383
3.75k
        UnlockSidCacheLock(cache->certCacheLock);
384
3.75k
    }
385
3.75k
    return now;
386
3.75k
}
387
388
/* Server configuration hash tables need to account the SECITEM.type
389
 * field as well. These functions accomplish that. */
390
static PLHashNumber
391
Get32BitNameHash(const SECItem *name)
392
0
{
393
0
    PLHashNumber rv = SECITEM_Hash(name);
394
395
0
    PRUint8 *rvc = (PRUint8 *)&rv;
396
0
    rvc[name->len % sizeof(rv)] ^= name->type;
397
398
0
    return rv;
399
0
}
400
401
/* Put a name in the cache.  Update the cert index in the sce.
402
 */
403
static PRUint32
404
CacheSrvName(cacheDesc *cache, SECItem *name, sidCacheEntry *sce)
405
0
{
406
0
    PRUint32 now;
407
0
    PRUint32 ndx;
408
0
    srvNameCacheEntry snce;
409
410
0
    if (!name || name->len <= 0 ||
411
0
        name->len > SSL_MAX_DNS_HOST_NAME) {
412
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
413
0
        return 0;
414
0
    }
415
416
0
    snce.type = name->type;
417
0
    snce.nameLen = name->len;
418
0
    PORT_Memcpy(snce.name, name->data, snce.nameLen);
419
0
    HASH_HashBuf(HASH_AlgSHA256, snce.nameHash, name->data, name->len);
420
421
    /* get index of the next name */
422
0
    ndx = Get32BitNameHash(name);
423
    /* get lock on cert cache */
424
0
    now = LockSidCacheLock(cache->srvNameCacheLock, 0);
425
0
    if (now) {
426
0
        if (cache->numSrvNameCacheEntries > 0) {
427
            /* Fit the index into array */
428
0
            ndx %= cache->numSrvNameCacheEntries;
429
            /* write the entry */
430
0
            cache->srvNameCacheData[ndx] = snce;
431
            /* remember where we put it. */
432
0
            sce->u.ssl3.srvNameIndex = ndx;
433
            /* Copy hash into sid hash */
434
0
            PORT_Memcpy(sce->u.ssl3.srvNameHash, snce.nameHash, SHA256_LENGTH);
435
0
        }
436
0
        UnlockSidCacheLock(cache->srvNameCacheLock);
437
0
    }
438
0
    return now;
439
0
}
440
441
/*
442
** Convert local SID to shared memory one
443
*/
444
static void
445
ConvertFromSID(sidCacheEntry *to, sslSessionID *from)
446
27.9k
{
447
27.9k
    to->valid = 1;
448
27.9k
    to->version = from->version;
449
27.9k
    to->addr = from->addr;
450
27.9k
    to->creationTime = from->creationTime;
451
27.9k
    to->lastAccessTime = from->lastAccessTime;
452
27.9k
    to->expirationTime = from->expirationTime;
453
27.9k
    to->authType = from->authType;
454
27.9k
    to->authKeyBits = from->authKeyBits;
455
27.9k
    to->keaType = from->keaType;
456
27.9k
    to->keaKeyBits = from->keaKeyBits;
457
27.9k
    to->keaGroup = from->keaGroup;
458
27.9k
    to->signatureScheme = from->sigScheme;
459
460
27.9k
    to->u.ssl3.cipherSuite = from->u.ssl3.cipherSuite;
461
27.9k
    to->u.ssl3.keys = from->u.ssl3.keys;
462
27.9k
    to->u.ssl3.masterWrapMech = from->u.ssl3.masterWrapMech;
463
27.9k
    to->sessionIDLength = from->u.ssl3.sessionIDLength;
464
27.9k
    to->u.ssl3.certIndex = -1;
465
27.9k
    to->u.ssl3.srvNameIndex = -1;
466
27.9k
    PORT_Memcpy(to->sessionID, from->u.ssl3.sessionID,
467
27.9k
                to->sessionIDLength);
468
27.9k
    to->u.ssl3.namedCurve = 0U;
469
27.9k
    if (from->authType == ssl_auth_ecdsa ||
470
22.5k
        from->authType == ssl_auth_ecdh_rsa ||
471
22.5k
        from->authType == ssl_auth_ecdh_ecdsa) {
472
5.40k
        PORT_Assert(from->namedCurve);
473
5.40k
        to->u.ssl3.namedCurve = (PRUint16)from->namedCurve->name;
474
5.40k
    }
475
476
27.9k
    SSL_TRC(8, ("%d: SSL3: ConvertSID: time=%d addr=0x%08x%08x%08x%08x "
477
27.9k
                "cipherSuite=%d",
478
27.9k
                myPid, to->creationTime / PR_USEC_PER_SEC,
479
27.9k
                to->addr.pr_s6_addr32[0], to->addr.pr_s6_addr32[1],
480
27.9k
                to->addr.pr_s6_addr32[2], to->addr.pr_s6_addr32[3],
481
27.9k
                to->u.ssl3.cipherSuite));
482
27.9k
}
483
484
/*
485
** Convert shared memory cache-entry to local memory based one
486
** This is only called from ServerSessionIDLookup().
487
*/
488
static sslSessionID *
489
ConvertToSID(sidCacheEntry *from,
490
             certCacheEntry *pcce,
491
             srvNameCacheEntry *psnce,
492
             CERTCertDBHandle *dbHandle)
493
0
{
494
0
    sslSessionID *to;
495
496
0
    to = PORT_ZNew(sslSessionID);
497
0
    if (!to) {
498
0
        return 0;
499
0
    }
500
501
0
    to->u.ssl3.sessionIDLength = from->sessionIDLength;
502
0
    to->u.ssl3.cipherSuite = from->u.ssl3.cipherSuite;
503
0
    to->u.ssl3.keys = from->u.ssl3.keys;
504
0
    to->u.ssl3.masterWrapMech = from->u.ssl3.masterWrapMech;
505
0
    if (from->u.ssl3.srvNameIndex != -1 && psnce) {
506
0
        SECItem name;
507
0
        SECStatus rv;
508
0
        name.type = psnce->type;
509
0
        name.len = psnce->nameLen;
510
0
        name.data = psnce->name;
511
0
        rv = SECITEM_CopyItem(NULL, &to->u.ssl3.srvName, &name);
512
0
        if (rv != SECSuccess) {
513
0
            goto loser;
514
0
        }
515
0
    }
516
517
0
    PORT_Memcpy(to->u.ssl3.sessionID, from->sessionID, from->sessionIDLength);
518
519
0
    to->urlSvrName = NULL;
520
521
0
    to->u.ssl3.masterModuleID = (SECMODModuleID)-1; /* invalid value */
522
0
    to->u.ssl3.masterSlotID = (CK_SLOT_ID)-1;       /* invalid value */
523
0
    to->u.ssl3.masterWrapIndex = 0;
524
0
    to->u.ssl3.masterWrapSeries = 0;
525
0
    to->u.ssl3.masterValid = PR_FALSE;
526
527
0
    to->u.ssl3.clAuthModuleID = (SECMODModuleID)-1; /* invalid value */
528
0
    to->u.ssl3.clAuthSlotID = (CK_SLOT_ID)-1;       /* invalid value */
529
0
    to->u.ssl3.clAuthSeries = 0;
530
0
    to->u.ssl3.clAuthValid = PR_FALSE;
531
532
0
    if (from->u.ssl3.certIndex != -1 && pcce) {
533
0
        SECItem derCert;
534
535
0
        derCert.len = pcce->certLength;
536
0
        derCert.data = pcce->cert;
537
538
0
        to->peerCert = CERT_NewTempCertificate(dbHandle, &derCert, NULL,
539
0
                                               PR_FALSE, PR_TRUE);
540
0
        if (to->peerCert == NULL)
541
0
            goto loser;
542
0
    }
543
0
    if (from->authType == ssl_auth_ecdsa ||
544
0
        from->authType == ssl_auth_ecdh_rsa ||
545
0
        from->authType == ssl_auth_ecdh_ecdsa) {
546
0
        to->namedCurve =
547
0
            ssl_LookupNamedGroup((SSLNamedGroup)from->u.ssl3.namedCurve);
548
0
    }
549
550
0
    to->version = from->version;
551
0
    to->creationTime = from->creationTime;
552
0
    to->lastAccessTime = from->lastAccessTime;
553
0
    to->expirationTime = from->expirationTime;
554
0
    to->cached = in_server_cache;
555
0
    to->addr = from->addr;
556
0
    to->references = 1;
557
0
    to->authType = from->authType;
558
0
    to->authKeyBits = from->authKeyBits;
559
0
    to->keaType = from->keaType;
560
0
    to->keaKeyBits = from->keaKeyBits;
561
0
    to->keaGroup = from->keaGroup;
562
0
    to->sigScheme = from->signatureScheme;
563
564
0
    return to;
565
566
0
loser:
567
0
    if (to) {
568
0
        SECITEM_FreeItem(&to->u.ssl3.srvName, PR_FALSE);
569
0
        PORT_Free(to);
570
0
    }
571
0
    return NULL;
572
0
}
573
574
/*
575
** Perform some mumbo jumbo on the ip-address and the session-id value to
576
** compute a hash value.
577
*/
578
static PRUint32
579
SIDindex(cacheDesc *cache, const PRIPv6Addr *addr, PRUint8 *s, unsigned nl)
580
37.3k
{
581
37.3k
    PRUint32 rv;
582
37.3k
    PRUint32 x[8];
583
584
37.3k
    memset(x, 0, sizeof x);
585
37.3k
    if (nl > sizeof x)
586
0
        nl = sizeof x;
587
37.3k
    memcpy(x, s, nl);
588
589
37.3k
    rv = (addr->pr_s6_addr32[0] ^ addr->pr_s6_addr32[1] ^
590
37.3k
          addr->pr_s6_addr32[2] ^ addr->pr_s6_addr32[3] ^
591
37.3k
          x[0] ^ x[1] ^ x[2] ^ x[3] ^ x[4] ^ x[5] ^ x[6] ^ x[7]) %
592
37.3k
         cache->numSIDCacheSets;
593
37.3k
    return rv;
594
37.3k
}
595
596
/*
597
** Look something up in the cache. This will invalidate old entries
598
** in the process. Caller has locked the cache set!
599
** Returns PR_TRUE if found a valid match.  PR_FALSE otherwise.
600
*/
601
static sidCacheEntry *
602
FindSID(cacheDesc *cache, PRUint32 setNum, PRUint32 now,
603
        const PRIPv6Addr *addr, unsigned char *sessionID,
604
        unsigned sessionIDLength)
605
9.40k
{
606
9.40k
    PRUint32 ndx = cache->sidCacheSets[setNum].next;
607
9.40k
    int i;
608
609
9.40k
    sidCacheEntry *set = cache->sidCacheData +
610
9.40k
                         (setNum * SID_CACHE_ENTRIES_PER_SET);
611
612
1.08M
    for (i = SID_CACHE_ENTRIES_PER_SET; i > 0; --i) {
613
1.07M
        sidCacheEntry *sce;
614
615
1.07M
        ndx = (ndx - 1) % SID_CACHE_ENTRIES_PER_SET;
616
1.07M
        sce = set + ndx;
617
618
1.07M
        if (!sce->valid)
619
937k
            continue;
620
621
140k
        if (now > sce->expirationTime) {
622
            /* SessionID has timed out. Invalidate the entry. */
623
0
            SSL_TRC(7, ("%d: timed out sid entry addr=%08x%08x%08x%08x now=%x "
624
0
                        "time+=%x",
625
0
                        myPid, sce->addr.pr_s6_addr32[0],
626
0
                        sce->addr.pr_s6_addr32[1], sce->addr.pr_s6_addr32[2],
627
0
                        sce->addr.pr_s6_addr32[3], now,
628
0
                        sce->expirationTime));
629
0
            sce->valid = 0;
630
0
            continue;
631
0
        }
632
633
        /*
634
        ** Next, examine specific session-id/addr data to see if the cache
635
        ** entry matches our addr+session-id value
636
        */
637
140k
        if (sessionIDLength == sce->sessionIDLength &&
638
25.0k
            !memcmp(&sce->addr, addr, sizeof(PRIPv6Addr)) &&
639
25.0k
            !memcmp(sce->sessionID, sessionID, sessionIDLength)) {
640
            /* Found it */
641
1.12k
            return sce;
642
1.12k
        }
643
140k
    }
644
645
8.28k
    PORT_SetError(SSL_ERROR_SESSION_NOT_FOUND);
646
8.28k
    return NULL;
647
9.40k
}
648
649
/************************************************************************/
650
651
/* This is the primary function for finding entries in the server's sid cache.
652
 * Although it is static, this function is called via the global function
653
 * pointer ssl_sid_lookup.
654
 *
655
 * sslNow is the time that the calling socket understands, which might be
656
 * different than what the cache uses to maintain its locks.
657
 */
658
static sslSessionID *
659
ServerSessionIDLookup(PRTime sslNow, const PRIPv6Addr *addr,
660
                      unsigned char *sessionID,
661
                      unsigned int sessionIDLength,
662
                      CERTCertDBHandle *dbHandle)
663
4.39k
{
664
4.39k
    sslSessionID *sid = 0;
665
4.39k
    sidCacheEntry *psce;
666
4.39k
    certCacheEntry *pcce = 0;
667
4.39k
    srvNameCacheEntry *psnce = 0;
668
4.39k
    cacheDesc *cache = &globalCache;
669
4.39k
    PRUint32 now;
670
4.39k
    PRUint32 set;
671
4.39k
    PRInt32 cndx;
672
4.39k
    sidCacheEntry sce;
673
4.39k
    certCacheEntry cce;
674
4.39k
    srvNameCacheEntry snce;
675
676
4.39k
    set = SIDindex(cache, addr, sessionID, sessionIDLength);
677
4.39k
    now = LockSet(cache, set, 0);
678
4.39k
    if (!now)
679
0
        return NULL;
680
681
4.39k
    psce = FindSID(cache, set, now, addr, sessionID, sessionIDLength);
682
4.39k
    if (psce) {
683
0
        if ((cndx = psce->u.ssl3.certIndex) != -1) {
684
0
            PRUint32 gotLock = LockSidCacheLock(cache->certCacheLock, now);
685
0
            if (gotLock) {
686
0
                pcce = &cache->certCacheData[cndx];
687
688
                /* See if the cert's session ID matches the sce cache. */
689
0
                if ((pcce->sessionIDLength == psce->sessionIDLength) &&
690
0
                    !PORT_Memcmp(pcce->sessionID, psce->sessionID,
691
0
                                 pcce->sessionIDLength)) {
692
0
                    cce = *pcce;
693
0
                } else {
694
                    /* The cert doesen't match the SID cache entry,
695
                    ** so invalidate the SID cache entry.
696
                    */
697
0
                    psce->valid = 0;
698
0
                    psce = 0;
699
0
                    pcce = 0;
700
0
                }
701
0
                UnlockSidCacheLock(cache->certCacheLock);
702
0
            } else {
703
                /* what the ??.  Didn't get the cert cache lock.
704
                ** Don't invalidate the SID cache entry, but don't find it.
705
                */
706
0
                PORT_AssertNotReached("Didn't get cert Cache Lock!");
707
0
                psce = 0;
708
0
                pcce = 0;
709
0
            }
710
0
        }
711
0
        if (psce && ((cndx = psce->u.ssl3.srvNameIndex) != -1)) {
712
0
            PRUint32 gotLock = LockSidCacheLock(cache->srvNameCacheLock,
713
0
                                                now);
714
0
            if (gotLock) {
715
0
                psnce = &cache->srvNameCacheData[cndx];
716
717
0
                if (!PORT_Memcmp(psnce->nameHash, psce->u.ssl3.srvNameHash,
718
0
                                 SHA256_LENGTH)) {
719
0
                    snce = *psnce;
720
0
                } else {
721
                    /* The name doesen't match the SID cache entry,
722
                    ** so invalidate the SID cache entry.
723
                    */
724
0
                    psce->valid = 0;
725
0
                    psce = 0;
726
0
                    psnce = 0;
727
0
                }
728
0
                UnlockSidCacheLock(cache->srvNameCacheLock);
729
0
            } else {
730
                /* what the ??.  Didn't get the cert cache lock.
731
                ** Don't invalidate the SID cache entry, but don't find it.
732
                */
733
0
                PORT_AssertNotReached("Didn't get name Cache Lock!");
734
0
                psce = 0;
735
0
                psnce = 0;
736
0
            }
737
0
        }
738
0
        if (psce) {
739
0
            psce->lastAccessTime = sslNow;
740
0
            sce = *psce; /* grab a copy while holding the lock */
741
0
        }
742
0
    }
743
4.39k
    UnlockSet(cache, set);
744
4.39k
    if (psce) {
745
        /* sce conains a copy of the cache entry.
746
        ** Convert shared memory format to local format
747
        */
748
0
        sid = ConvertToSID(&sce, pcce ? &cce : 0, psnce ? &snce : 0, dbHandle);
749
0
    }
750
4.39k
    return sid;
751
4.39k
}
752
753
/*
754
** Place a sid into the cache, if it isn't already there.
755
*/
756
void
757
ssl_ServerCacheSessionID(sslSessionID *sid, PRTime creationTime)
758
27.9k
{
759
27.9k
    PORT_Assert(sid);
760
761
27.9k
    sidCacheEntry sce;
762
27.9k
    PRUint32 now = 0;
763
27.9k
    cacheDesc *cache = &globalCache;
764
765
27.9k
    if (sid->u.ssl3.sessionIDLength == 0) {
766
0
        return;
767
0
    }
768
769
27.9k
    if (sid->cached == never_cached || sid->cached == invalid_cache) {
770
27.9k
        PRUint32 set;
771
27.9k
        SECItem *name;
772
773
27.9k
        PORT_Assert(sid->creationTime != 0);
774
27.9k
        if (!sid->creationTime)
775
0
            sid->lastAccessTime = sid->creationTime = creationTime;
776
        /* override caller's expiration time, which uses client timeout
777
         * duration, not server timeout duration.
778
         */
779
27.9k
        sid->expirationTime =
780
27.9k
            sid->creationTime + cache->ssl3Timeout * PR_USEC_PER_SEC;
781
27.9k
        SSL_TRC(8, ("%d: SSL: CacheMT: cached=%d addr=0x%08x%08x%08x%08x time=%x "
782
27.9k
                    "cipherSuite=%d",
783
27.9k
                    myPid, sid->cached,
784
27.9k
                    sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1],
785
27.9k
                    sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3],
786
27.9k
                    sid->creationTime / PR_USEC_PER_SEC,
787
27.9k
                    sid->u.ssl3.cipherSuite));
788
27.9k
        PRINT_BUF(8, (0, "sessionID:", sid->u.ssl3.sessionID,
789
27.9k
                      sid->u.ssl3.sessionIDLength));
790
791
27.9k
        ConvertFromSID(&sce, sid);
792
793
27.9k
        name = &sid->u.ssl3.srvName;
794
27.9k
        if (name->len && name->data) {
795
0
            now = CacheSrvName(cache, name, &sce);
796
0
        }
797
27.9k
        if (sid->peerCert != NULL) {
798
3.75k
            now = CacheCert(cache, sid->peerCert, &sce);
799
3.75k
        }
800
801
27.9k
        set = SIDindex(cache, &sce.addr, sce.sessionID, sce.sessionIDLength);
802
27.9k
        now = LockSet(cache, set, now);
803
27.9k
        if (now) {
804
27.9k
            PRUint32 next = cache->sidCacheSets[set].next;
805
27.9k
            PRUint32 ndx = set * SID_CACHE_ENTRIES_PER_SET + next;
806
807
            /* Write out new cache entry */
808
27.9k
            cache->sidCacheData[ndx] = sce;
809
810
27.9k
            cache->sidCacheSets[set].next =
811
27.9k
                (next + 1) % SID_CACHE_ENTRIES_PER_SET;
812
813
27.9k
            UnlockSet(cache, set);
814
27.9k
            sid->cached = in_server_cache;
815
27.9k
        }
816
27.9k
    }
817
27.9k
}
818
819
/*
820
** Although this is static, it is called from ssl via global function pointer
821
**  ssl_sid_uncache.  This invalidates the referenced cache entry.
822
*/
823
void
824
ssl_ServerUncacheSessionID(sslSessionID *sid)
825
5.01k
{
826
5.01k
    cacheDesc *cache = &globalCache;
827
5.01k
    PRUint8 *sessionID;
828
5.01k
    unsigned int sessionIDLength;
829
5.01k
    PRErrorCode err;
830
5.01k
    PRUint32 set;
831
5.01k
    PRUint32 now;
832
5.01k
    sidCacheEntry *psce;
833
834
5.01k
    if (sid == NULL)
835
0
        return;
836
837
    /* Uncaching a SID should never change the error code.
838
    ** So save it here and restore it before exiting.
839
    */
840
5.01k
    err = PR_GetError();
841
842
5.01k
    sessionID = sid->u.ssl3.sessionID;
843
5.01k
    sessionIDLength = sid->u.ssl3.sessionIDLength;
844
5.01k
    SSL_TRC(8, ("%d: SSL3: UncacheMT: valid=%d addr=0x%08x%08x%08x%08x time=%x "
845
5.01k
                "cipherSuite=%d",
846
5.01k
                myPid, sid->cached,
847
5.01k
                sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1],
848
5.01k
                sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3],
849
5.01k
                sid->creationTime / PR_USEC_PER_SEC,
850
5.01k
                sid->u.ssl3.cipherSuite));
851
5.01k
    PRINT_BUF(8, (0, "sessionID:", sessionID, sessionIDLength));
852
5.01k
    set = SIDindex(cache, &sid->addr, sessionID, sessionIDLength);
853
5.01k
    now = LockSet(cache, set, 0);
854
5.01k
    if (now) {
855
5.01k
        psce = FindSID(cache, set, now, &sid->addr, sessionID, sessionIDLength);
856
5.01k
        if (psce) {
857
1.12k
            psce->valid = 0;
858
1.12k
        }
859
5.01k
        UnlockSet(cache, set);
860
5.01k
    }
861
5.01k
    sid->cached = invalid_cache;
862
5.01k
    PORT_SetError(err);
863
5.01k
}
864
865
static void
866
CloseCache(cacheDesc *cache)
867
4
{
868
4
    int locks_initialized = cache->numSIDCacheLocksInitialized;
869
870
4
    if (cache->cacheMem) {
871
4
        if (cache->sharedCache) {
872
4
            sidCacheLock *pLock = cache->sidCacheLocks;
873
48
            for (; locks_initialized > 0; --locks_initialized, ++pLock) {
874
                /* If everInherited is true, this shared cache was (and may
875
                ** still be) in use by multiple processes.  We do not wish to
876
                ** destroy the mutexes while they are still in use, but we do
877
                ** want to free mutex resources associated with this process.
878
                */
879
44
                sslMutex_Destroy(&pLock->mutex,
880
44
                                 cache->sharedCache->everInherited);
881
44
            }
882
4
        }
883
4
        if (cache->shared) {
884
0
            PR_MemUnmap(cache->cacheMem, cache->cacheMemSize);
885
4
        } else {
886
4
            PORT_Free(cache->cacheMem);
887
4
        }
888
4
        cache->cacheMem = NULL;
889
4
    }
890
4
    if (cache->cacheMemMap) {
891
0
        PR_CloseFileMap(cache->cacheMemMap);
892
0
        cache->cacheMemMap = NULL;
893
0
    }
894
4
    memset(cache, 0, sizeof *cache);
895
4
}
896
897
static SECStatus
898
InitCache(cacheDesc *cache, int maxCacheEntries, int maxCertCacheEntries,
899
          int maxSrvNameCacheEntries, PRUint32 ssl3_timeout,
900
          const char *directory, PRBool shared)
901
4
{
902
4
    ptrdiff_t ptr;
903
4
    sidCacheLock *pLock;
904
4
    char *cacheMem;
905
4
    PRFileMap *cacheMemMap;
906
4
    char *cfn = NULL; /* cache file name */
907
4
    int locks_initialized = 0;
908
4
    int locks_to_initialize = 0;
909
4
    PRUint32 init_time;
910
911
4
    if ((!cache) || (maxCacheEntries < 0) || (!directory)) {
912
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
913
0
        return SECFailure;
914
0
    }
915
916
4
    if (cache->cacheMem) {
917
        /* Already done */
918
0
        return SECSuccess;
919
0
    }
920
921
    /* make sure loser can clean up properly */
922
4
    cache->shared = shared;
923
4
    cache->cacheMem = cacheMem = NULL;
924
4
    cache->cacheMemMap = cacheMemMap = NULL;
925
4
    cache->sharedCache = (cacheDesc *)0;
926
927
4
    cache->numSIDCacheLocksInitialized = 0;
928
4
    cache->nextCertCacheEntry = 0;
929
4
    cache->stopPolling = PR_FALSE;
930
4
    cache->everInherited = PR_FALSE;
931
4
    cache->poller = NULL;
932
4
    cache->mutexTimeout = 0;
933
934
4
    cache->numSIDCacheEntries = maxCacheEntries ? maxCacheEntries
935
4
                                                : DEF_SID_CACHE_ENTRIES;
936
4
    cache->numSIDCacheSets =
937
4
        SID_HOWMANY(cache->numSIDCacheEntries, SID_CACHE_ENTRIES_PER_SET);
938
939
4
    cache->numSIDCacheEntries =
940
4
        cache->numSIDCacheSets * SID_CACHE_ENTRIES_PER_SET;
941
942
4
    cache->numSIDCacheLocks =
943
4
        PR_MIN(cache->numSIDCacheSets, ssl_max_sid_cache_locks);
944
945
4
    cache->numSIDCacheSetsPerLock =
946
4
        SID_HOWMANY(cache->numSIDCacheSets, cache->numSIDCacheLocks);
947
948
4
    cache->numCertCacheEntries = (maxCertCacheEntries > 0) ? maxCertCacheEntries
949
4
                                                           : 0;
950
4
    cache->numSrvNameCacheEntries = (maxSrvNameCacheEntries >= 0) ? maxSrvNameCacheEntries
951
4
                                                                  : DEF_NAME_CACHE_ENTRIES;
952
953
    /* compute size of shared memory, and offsets of all pointers */
954
4
    ptr = 0;
955
4
    cache->cacheMem = (char *)ptr;
956
4
    ptr += SID_ROUNDUP(sizeof(cacheDesc), SID_ALIGNMENT);
957
958
4
    cache->sidCacheLocks = (sidCacheLock *)ptr;
959
4
    cache->keyCacheLock = cache->sidCacheLocks + cache->numSIDCacheLocks;
960
4
    cache->certCacheLock = cache->keyCacheLock + 1;
961
4
    cache->srvNameCacheLock = cache->certCacheLock + 1;
962
4
    ptr = (ptrdiff_t)(cache->srvNameCacheLock + 1);
963
4
    ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
964
965
4
    cache->sidCacheSets = (sidCacheSet *)ptr;
966
4
    ptr = (ptrdiff_t)(cache->sidCacheSets + cache->numSIDCacheSets);
967
4
    ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
968
969
4
    cache->sidCacheData = (sidCacheEntry *)ptr;
970
4
    ptr = (ptrdiff_t)(cache->sidCacheData + cache->numSIDCacheEntries);
971
4
    ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
972
973
4
    cache->certCacheData = (certCacheEntry *)ptr;
974
4
    cache->sidCacheSize =
975
4
        (char *)cache->certCacheData - (char *)cache->sidCacheData;
976
977
4
    if (cache->numCertCacheEntries < MIN_CERT_CACHE_ENTRIES) {
978
        /* This is really a poor way to computer this! */
979
4
        cache->numCertCacheEntries = cache->sidCacheSize / sizeof(certCacheEntry);
980
4
        if (cache->numCertCacheEntries < MIN_CERT_CACHE_ENTRIES)
981
4
            cache->numCertCacheEntries = MIN_CERT_CACHE_ENTRIES;
982
4
    }
983
4
    ptr = (ptrdiff_t)(cache->certCacheData + cache->numCertCacheEntries);
984
4
    ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
985
986
4
    cache->keyCacheData = (SSLWrappedSymWrappingKey *)ptr;
987
4
    cache->certCacheSize =
988
4
        (char *)cache->keyCacheData - (char *)cache->certCacheData;
989
990
4
    cache->numKeyCacheEntries = SSL_NUM_WRAP_KEYS * SSL_NUM_WRAP_MECHS;
991
4
    ptr = (ptrdiff_t)(cache->keyCacheData + cache->numKeyCacheEntries);
992
4
    ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
993
994
4
    cache->keyCacheSize = (char *)ptr - (char *)cache->keyCacheData;
995
996
4
    cache->ticketKeyNameSuffix = (PRUint8 *)ptr;
997
4
    ptr = (ptrdiff_t)(cache->ticketKeyNameSuffix +
998
4
                      SELF_ENCRYPT_KEY_VAR_NAME_LEN);
999
4
    ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
1000
1001
4
    cache->ticketEncKey = (encKeyCacheEntry *)ptr;
1002
4
    ptr = (ptrdiff_t)(cache->ticketEncKey + 1);
1003
4
    ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
1004
1005
4
    cache->ticketMacKey = (encKeyCacheEntry *)ptr;
1006
4
    ptr = (ptrdiff_t)(cache->ticketMacKey + 1);
1007
4
    ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
1008
1009
4
    cache->ticketKeysValid = (PRUint32 *)ptr;
1010
4
    ptr = (ptrdiff_t)(cache->ticketKeysValid + 1);
1011
4
    ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
1012
1013
4
    cache->srvNameCacheData = (srvNameCacheEntry *)ptr;
1014
4
    cache->srvNameCacheSize =
1015
4
        cache->numSrvNameCacheEntries * sizeof(srvNameCacheEntry);
1016
4
    ptr = (ptrdiff_t)(cache->srvNameCacheData + cache->numSrvNameCacheEntries);
1017
4
    ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
1018
1019
4
    cache->cacheMemSize = ptr;
1020
1021
4
    if (ssl3_timeout) {
1022
0
        if (ssl3_timeout > MAX_SSL3_TIMEOUT) {
1023
0
            ssl3_timeout = MAX_SSL3_TIMEOUT;
1024
0
        }
1025
0
        if (ssl3_timeout < MIN_SSL3_TIMEOUT) {
1026
0
            ssl3_timeout = MIN_SSL3_TIMEOUT;
1027
0
        }
1028
0
        cache->ssl3Timeout = ssl3_timeout;
1029
4
    } else {
1030
4
        cache->ssl3Timeout = DEF_SSL3_TIMEOUT;
1031
4
    }
1032
1033
4
    if (shared) {
1034
/* Create file names */
1035
0
#if defined(XP_UNIX)
1036
        /* there's some confusion here about whether PR_OpenAnonFileMap wants
1037
        ** a directory name or a file name for its first argument.
1038
        cfn = PR_smprintf("%s/.sslsvrcache.%d", directory, myPid);
1039
        */
1040
0
        cfn = PR_smprintf("%s", directory);
1041
#elif defined(XP_WIN32)
1042
        cfn = PR_smprintf("%s/svrcache_%d_%x.ssl", directory, myPid,
1043
                          GetCurrentThreadId());
1044
#else
1045
#error "Don't know how to create file name for this platform!"
1046
#endif
1047
0
        if (!cfn) {
1048
0
            goto loser;
1049
0
        }
1050
1051
        /* Create cache */
1052
0
        cacheMemMap = PR_OpenAnonFileMap(cfn, cache->cacheMemSize,
1053
0
                                         PR_PROT_READWRITE);
1054
1055
0
        PR_smprintf_free(cfn);
1056
0
        if (!cacheMemMap) {
1057
0
            goto loser;
1058
0
        }
1059
1060
0
        cacheMem = PR_MemMap(cacheMemMap, 0, cache->cacheMemSize);
1061
4
    } else {
1062
4
        cacheMem = PORT_Alloc(cache->cacheMemSize);
1063
4
    }
1064
1065
4
    if (!cacheMem) {
1066
0
        goto loser;
1067
0
    }
1068
1069
    /* Initialize shared memory. This may not be necessary on all platforms */
1070
4
    memset(cacheMem, 0, cache->cacheMemSize);
1071
1072
    /* Copy cache descriptor header into shared memory */
1073
4
    memcpy(cacheMem, cache, sizeof *cache);
1074
1075
    /* save private copies of these values */
1076
4
    cache->cacheMemMap = cacheMemMap;
1077
4
    cache->cacheMem = cacheMem;
1078
4
    cache->sharedCache = (cacheDesc *)cacheMem;
1079
1080
    /* Fix pointers in our private copy of cache descriptor to point to
1081
    ** spaces in shared memory
1082
    */
1083
4
    cache->sidCacheLocks = (sidCacheLock *)(cache->cacheMem + (ptrdiff_t)cache->sidCacheLocks);
1084
4
    cache->keyCacheLock = (sidCacheLock *)(cache->cacheMem + (ptrdiff_t)cache->keyCacheLock);
1085
4
    cache->certCacheLock = (sidCacheLock *)(cache->cacheMem + (ptrdiff_t)cache->certCacheLock);
1086
4
    cache->srvNameCacheLock = (sidCacheLock *)(cache->cacheMem + (ptrdiff_t)cache->srvNameCacheLock);
1087
4
    cache->sidCacheSets = (sidCacheSet *)(cache->cacheMem + (ptrdiff_t)cache->sidCacheSets);
1088
4
    cache->sidCacheData = (sidCacheEntry *)(cache->cacheMem + (ptrdiff_t)cache->sidCacheData);
1089
4
    cache->certCacheData = (certCacheEntry *)(cache->cacheMem + (ptrdiff_t)cache->certCacheData);
1090
4
    cache->keyCacheData = (SSLWrappedSymWrappingKey *)(cache->cacheMem + (ptrdiff_t)cache->keyCacheData);
1091
4
    cache->ticketKeyNameSuffix = (PRUint8 *)(cache->cacheMem + (ptrdiff_t)cache->ticketKeyNameSuffix);
1092
4
    cache->ticketEncKey = (encKeyCacheEntry *)(cache->cacheMem + (ptrdiff_t)cache->ticketEncKey);
1093
4
    cache->ticketMacKey = (encKeyCacheEntry *)(cache->cacheMem + (ptrdiff_t)cache->ticketMacKey);
1094
4
    cache->ticketKeysValid = (PRUint32 *)(cache->cacheMem + (ptrdiff_t)cache->ticketKeysValid);
1095
4
    cache->srvNameCacheData = (srvNameCacheEntry *)(cache->cacheMem + (ptrdiff_t)cache->srvNameCacheData);
1096
1097
    /* initialize the locks */
1098
4
    init_time = ssl_CacheNow();
1099
4
    pLock = cache->sidCacheLocks;
1100
4
    for (locks_to_initialize = cache->numSIDCacheLocks + 3;
1101
48
         locks_initialized < locks_to_initialize;
1102
44
         ++locks_initialized, ++pLock) {
1103
1104
44
        SECStatus err = sslMutex_Init(&pLock->mutex, shared);
1105
44
        if (err) {
1106
0
            cache->numSIDCacheLocksInitialized = locks_initialized;
1107
0
            goto loser;
1108
0
        }
1109
44
        pLock->timeStamp = init_time;
1110
44
        pLock->pid = 0;
1111
44
    }
1112
4
    cache->numSIDCacheLocksInitialized = locks_initialized;
1113
1114
4
    return SECSuccess;
1115
1116
0
loser:
1117
0
    CloseCache(cache);
1118
0
    PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1119
0
    return SECFailure;
1120
4
}
1121
1122
PRUint32
1123
SSL_GetMaxServerCacheLocks(void)
1124
0
{
1125
0
    return ssl_max_sid_cache_locks + 2;
1126
    /* The extra two are the cert cache lock and the key cache lock. */
1127
0
}
1128
1129
SECStatus
1130
SSL_SetMaxServerCacheLocks(PRUint32 maxLocks)
1131
0
{
1132
    /* Minimum is 1 sid cache lock, 1 cert cache lock and 1 key cache lock.
1133
    ** We'd like to test for a maximum value, but not all platforms' header
1134
    ** files provide a symbol or function or other means of determining
1135
    ** the maximum, other than trial and error.
1136
    */
1137
0
    if (maxLocks < 3) {
1138
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
1139
0
        return SECFailure;
1140
0
    }
1141
0
    ssl_max_sid_cache_locks = maxLocks - 2;
1142
    /* The extra two are the cert cache lock and the key cache lock. */
1143
0
    return SECSuccess;
1144
0
}
1145
1146
PR_STATIC_ASSERT(sizeof(sidCacheEntry) % 16 == 0);
1147
PR_STATIC_ASSERT(sizeof(certCacheEntry) == 4096);
1148
PR_STATIC_ASSERT(sizeof(srvNameCacheEntry) == 1072);
1149
1150
static SECStatus
1151
ssl_ConfigServerSessionIDCacheInstanceWithOpt(cacheDesc *cache,
1152
                                              PRUint32 ssl3_timeout,
1153
                                              const char *directory,
1154
                                              PRBool shared,
1155
                                              int maxCacheEntries,
1156
                                              int maxCertCacheEntries,
1157
                                              int maxSrvNameCacheEntries)
1158
4
{
1159
4
    SECStatus rv;
1160
1161
4
    rv = ssl_InitSessionCache();
1162
4
    if (rv != SECSuccess) {
1163
0
        return rv;
1164
0
    }
1165
1166
4
    myPid = SSL_GETPID();
1167
4
    if (!directory) {
1168
0
        directory = DEFAULT_CACHE_DIRECTORY;
1169
0
    }
1170
4
    rv = InitCache(cache, maxCacheEntries, maxCertCacheEntries,
1171
4
                   maxSrvNameCacheEntries, ssl3_timeout, directory, shared);
1172
4
    if (rv) {
1173
0
        return SECFailure;
1174
0
    }
1175
1176
4
    ssl_sid_lookup = ServerSessionIDLookup;
1177
4
    return SECSuccess;
1178
4
}
1179
1180
SECStatus
1181
SSL_ConfigServerSessionIDCacheInstance(cacheDesc *cache,
1182
                                       int maxCacheEntries,
1183
                                       PRUint32 ssl2_timeout,
1184
                                       PRUint32 ssl3_timeout,
1185
                                       const char *directory, PRBool shared)
1186
4
{
1187
4
    return ssl_ConfigServerSessionIDCacheInstanceWithOpt(cache,
1188
4
                                                         ssl3_timeout,
1189
4
                                                         directory,
1190
4
                                                         shared,
1191
4
                                                         maxCacheEntries,
1192
4
                                                         -1, -1);
1193
4
}
1194
1195
SECStatus
1196
SSL_ConfigServerSessionIDCache(int maxCacheEntries,
1197
                               PRUint32 ssl2_timeout,
1198
                               PRUint32 ssl3_timeout,
1199
                               const char *directory)
1200
4
{
1201
4
    ssl_InitSessionCacheLocks(PR_FALSE);
1202
4
    return SSL_ConfigServerSessionIDCacheInstance(&globalCache,
1203
4
                                                  maxCacheEntries, ssl2_timeout, ssl3_timeout, directory, PR_FALSE);
1204
4
}
1205
1206
SECStatus
1207
SSL_ShutdownServerSessionIDCacheInstance(cacheDesc *cache)
1208
4
{
1209
4
    CloseCache(cache);
1210
4
    return SECSuccess;
1211
4
}
1212
1213
SECStatus
1214
SSL_ShutdownServerSessionIDCache(void)
1215
4
{
1216
4
#if defined(XP_UNIX)
1217
    /* Stop the thread that polls cache for expired locks on Unix */
1218
4
    StopLockPoller(&globalCache);
1219
4
#endif
1220
4
    SSL3_ShutdownServerCache();
1221
4
    return SSL_ShutdownServerSessionIDCacheInstance(&globalCache);
1222
4
}
1223
1224
/* Use this function, instead of SSL_ConfigServerSessionIDCache,
1225
 * if the cache will be shared by multiple processes.
1226
 */
1227
static SECStatus
1228
ssl_ConfigMPServerSIDCacheWithOpt(PRUint32 ssl3_timeout,
1229
                                  const char *directory,
1230
                                  int maxCacheEntries,
1231
                                  int maxCertCacheEntries,
1232
                                  int maxSrvNameCacheEntries)
1233
0
{
1234
0
    char *envValue;
1235
0
    char *inhValue;
1236
0
    cacheDesc *cache = &globalCache;
1237
0
    PRUint32 fmStrLen;
1238
0
    SECStatus result;
1239
0
    PRStatus prStatus;
1240
0
    SECStatus putEnvFailed;
1241
0
    inheritance inherit;
1242
0
    char fmString[PR_FILEMAP_STRING_BUFSIZE];
1243
1244
0
    isMultiProcess = PR_TRUE;
1245
0
    result = ssl_ConfigServerSessionIDCacheInstanceWithOpt(cache,
1246
0
                                                           ssl3_timeout, directory, PR_TRUE,
1247
0
                                                           maxCacheEntries, maxCacheEntries, maxSrvNameCacheEntries);
1248
0
    if (result != SECSuccess)
1249
0
        return result;
1250
1251
0
    prStatus = PR_ExportFileMapAsString(cache->cacheMemMap,
1252
0
                                        sizeof fmString, fmString);
1253
0
    if ((prStatus != PR_SUCCESS) || !(fmStrLen = strlen(fmString))) {
1254
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1255
0
        return SECFailure;
1256
0
    }
1257
1258
0
    inherit.cacheMemSize = cache->cacheMemSize;
1259
0
    inherit.fmStrLen = fmStrLen;
1260
1261
0
    inhValue = BTOA_DataToAscii((unsigned char *)&inherit, sizeof inherit);
1262
0
    if (!inhValue || !strlen(inhValue)) {
1263
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1264
0
        return SECFailure;
1265
0
    }
1266
0
    envValue = PR_smprintf("%s,%s", inhValue, fmString);
1267
0
    if (!envValue || !strlen(envValue)) {
1268
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1269
0
        return SECFailure;
1270
0
    }
1271
0
    PORT_Free(inhValue);
1272
1273
0
    putEnvFailed = (SECStatus)NSS_PutEnv(envVarName, envValue);
1274
0
    PR_smprintf_free(envValue);
1275
0
    if (putEnvFailed) {
1276
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1277
0
        result = SECFailure;
1278
0
    }
1279
1280
0
#if defined(XP_UNIX)
1281
    /* Launch thread to poll cache for expired locks on Unix */
1282
0
    LaunchLockPoller(cache);
1283
0
#endif
1284
0
    return result;
1285
0
}
1286
1287
/* Use this function, instead of SSL_ConfigServerSessionIDCache,
1288
 * if the cache will be shared by multiple processes.
1289
 */
1290
SECStatus
1291
SSL_ConfigMPServerSIDCache(int maxCacheEntries,
1292
                           PRUint32 ssl2_timeout,
1293
                           PRUint32 ssl3_timeout,
1294
                           const char *directory)
1295
0
{
1296
0
    return ssl_ConfigMPServerSIDCacheWithOpt(ssl3_timeout,
1297
0
                                             directory,
1298
0
                                             maxCacheEntries,
1299
0
                                             -1, -1);
1300
0
}
1301
1302
SECStatus
1303
SSL_ConfigServerSessionIDCacheWithOpt(
1304
    PRUint32 ssl2_timeout,
1305
    PRUint32 ssl3_timeout,
1306
    const char *directory,
1307
    int maxCacheEntries,
1308
    int maxCertCacheEntries,
1309
    int maxSrvNameCacheEntries,
1310
    PRBool enableMPCache)
1311
0
{
1312
0
    if (!enableMPCache) {
1313
0
        ssl_InitSessionCacheLocks(PR_FALSE);
1314
0
        return ssl_ConfigServerSessionIDCacheInstanceWithOpt(&globalCache,
1315
0
                                                             ssl3_timeout, directory, PR_FALSE,
1316
0
                                                             maxCacheEntries, maxCertCacheEntries, maxSrvNameCacheEntries);
1317
0
    } else {
1318
0
        return ssl_ConfigMPServerSIDCacheWithOpt(ssl3_timeout, directory,
1319
0
                                                 maxCacheEntries, maxCertCacheEntries, maxSrvNameCacheEntries);
1320
0
    }
1321
0
}
1322
1323
SECStatus
1324
SSL_InheritMPServerSIDCacheInstance(cacheDesc *cache, const char *envString)
1325
0
{
1326
0
    unsigned char *decoString = NULL;
1327
0
    char *fmString = NULL;
1328
0
    char *myEnvString = NULL;
1329
0
    unsigned int decoLen;
1330
0
    inheritance inherit;
1331
0
    cacheDesc my;
1332
#ifdef WINNT
1333
    sidCacheLock *newLocks;
1334
    int locks_initialized = 0;
1335
    int locks_to_initialize = 0;
1336
#endif
1337
0
    SECStatus status = ssl_InitSessionCache();
1338
1339
0
    if (status != SECSuccess) {
1340
0
        return status;
1341
0
    }
1342
1343
0
    myPid = SSL_GETPID();
1344
1345
    /* If this child was created by fork(), and not by exec() on unix,
1346
    ** then isMultiProcess will already be set.
1347
    ** If not, we'll set it below.
1348
    */
1349
0
    if (isMultiProcess) {
1350
0
        if (cache && cache->sharedCache) {
1351
0
            cache->sharedCache->everInherited = PR_TRUE;
1352
0
        }
1353
0
        return SECSuccess; /* already done. */
1354
0
    }
1355
1356
0
    ssl_InitSessionCacheLocks(PR_FALSE);
1357
1358
0
    ssl_sid_lookup = ServerSessionIDLookup;
1359
1360
0
    if (!envString) {
1361
0
        envString = PR_GetEnvSecure(envVarName);
1362
0
        if (!envString) {
1363
0
            PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1364
0
            return SECFailure;
1365
0
        }
1366
0
    }
1367
0
    myEnvString = PORT_Strdup(envString);
1368
0
    if (!myEnvString)
1369
0
        return SECFailure;
1370
0
    fmString = strchr(myEnvString, ',');
1371
0
    if (!fmString)
1372
0
        goto loser;
1373
0
    *fmString++ = 0;
1374
1375
0
    decoString = ATOB_AsciiToData(myEnvString, &decoLen);
1376
0
    if (!decoString) {
1377
0
        goto loser;
1378
0
    }
1379
0
    if (decoLen != sizeof inherit) {
1380
0
        goto loser;
1381
0
    }
1382
1383
0
    PORT_Memcpy(&inherit, decoString, sizeof inherit);
1384
1385
0
    if (strlen(fmString) != inherit.fmStrLen) {
1386
0
        goto loser;
1387
0
    }
1388
1389
0
    memset(cache, 0, sizeof *cache);
1390
0
    cache->cacheMemSize = inherit.cacheMemSize;
1391
1392
    /* Create cache */
1393
0
    cache->cacheMemMap = PR_ImportFileMapFromString(fmString);
1394
0
    if (!cache->cacheMemMap) {
1395
0
        goto loser;
1396
0
    }
1397
0
    cache->cacheMem = PR_MemMap(cache->cacheMemMap, 0, cache->cacheMemSize);
1398
0
    if (!cache->cacheMem) {
1399
0
        goto loser;
1400
0
    }
1401
0
    cache->sharedCache = (cacheDesc *)cache->cacheMem;
1402
1403
0
    if (cache->sharedCache->cacheMemSize != cache->cacheMemSize) {
1404
0
        goto loser;
1405
0
    }
1406
1407
    /* We're now going to overwrite the local cache instance with the
1408
    ** shared copy of the cache struct, then update several values in
1409
    ** the local cache using the values for cache->cacheMemMap and
1410
    ** cache->cacheMem computed just above.  So, we copy cache into
1411
    ** the automatic variable "my", to preserve the variables while
1412
    ** cache is overwritten.
1413
    */
1414
0
    my = *cache;                                      /* save values computed above. */
1415
0
    memcpy(cache, cache->sharedCache, sizeof *cache); /* overwrite */
1416
1417
    /* Fix pointers in our private copy of cache descriptor to point to
1418
    ** spaces in shared memory, whose address is now in "my".
1419
    */
1420
0
    cache->sidCacheLocks = (sidCacheLock *)(my.cacheMem + (ptrdiff_t)cache->sidCacheLocks);
1421
0
    cache->keyCacheLock = (sidCacheLock *)(my.cacheMem + (ptrdiff_t)cache->keyCacheLock);
1422
0
    cache->certCacheLock = (sidCacheLock *)(my.cacheMem + (ptrdiff_t)cache->certCacheLock);
1423
0
    cache->srvNameCacheLock = (sidCacheLock *)(my.cacheMem + (ptrdiff_t)cache->srvNameCacheLock);
1424
0
    cache->sidCacheSets = (sidCacheSet *)(my.cacheMem + (ptrdiff_t)cache->sidCacheSets);
1425
0
    cache->sidCacheData = (sidCacheEntry *)(my.cacheMem + (ptrdiff_t)cache->sidCacheData);
1426
0
    cache->certCacheData = (certCacheEntry *)(my.cacheMem + (ptrdiff_t)cache->certCacheData);
1427
0
    cache->keyCacheData = (SSLWrappedSymWrappingKey *)(my.cacheMem + (ptrdiff_t)cache->keyCacheData);
1428
0
    cache->ticketKeyNameSuffix = (PRUint8 *)(my.cacheMem + (ptrdiff_t)cache->ticketKeyNameSuffix);
1429
0
    cache->ticketEncKey = (encKeyCacheEntry *)(my.cacheMem + (ptrdiff_t)cache->ticketEncKey);
1430
0
    cache->ticketMacKey = (encKeyCacheEntry *)(my.cacheMem + (ptrdiff_t)cache->ticketMacKey);
1431
0
    cache->ticketKeysValid = (PRUint32 *)(my.cacheMem + (ptrdiff_t)cache->ticketKeysValid);
1432
0
    cache->srvNameCacheData = (srvNameCacheEntry *)(my.cacheMem + (ptrdiff_t)cache->srvNameCacheData);
1433
1434
0
    cache->cacheMemMap = my.cacheMemMap;
1435
0
    cache->cacheMem = my.cacheMem;
1436
0
    cache->sharedCache = (cacheDesc *)cache->cacheMem;
1437
1438
#ifdef WINNT
1439
    /*  On Windows NT we need to "fix" the sidCacheLocks here to support fibers
1440
    **  When NT fibers are used in a multi-process server, a second level of
1441
    **  locking is needed to prevent a deadlock, in case a fiber acquires the
1442
    **  cross-process mutex, yields, and another fiber is later scheduled on
1443
    **  the same native thread and tries to acquire the cross-process mutex.
1444
    **  We do this by using a PRLock in the sslMutex. However, it is stored in
1445
    **  shared memory as part of sidCacheLocks, and we don't want to overwrite
1446
    **  the PRLock of the parent process. So we need to make new, private
1447
    **  copies of sidCacheLocks before modifying the sslMutex with our own
1448
    **  PRLock
1449
    */
1450
1451
    /* note from jpierre : this should be free'd in child processes when
1452
    ** a function is added to delete the SSL session cache in the future.
1453
    */
1454
    locks_to_initialize = cache->numSIDCacheLocks + 3;
1455
    newLocks = PORT_NewArray(sidCacheLock, locks_to_initialize);
1456
    if (!newLocks)
1457
        goto loser;
1458
    /* copy the old locks */
1459
    memcpy(newLocks, cache->sidCacheLocks,
1460
           locks_to_initialize * sizeof(sidCacheLock));
1461
    cache->sidCacheLocks = newLocks;
1462
    /* fix the locks */
1463
    for (; locks_initialized < locks_to_initialize; ++locks_initialized) {
1464
        /* now, make a local PRLock in this sslMutex for this child process */
1465
        SECStatus err;
1466
        err = sslMutex_2LevelInit(&newLocks[locks_initialized].mutex);
1467
        if (err != SECSuccess) {
1468
            cache->numSIDCacheLocksInitialized = locks_initialized;
1469
            goto loser;
1470
        }
1471
    }
1472
    cache->numSIDCacheLocksInitialized = locks_initialized;
1473
1474
    /* also fix the key and cert cache which use the last 2 lock entries */
1475
    cache->keyCacheLock = cache->sidCacheLocks + cache->numSIDCacheLocks;
1476
    cache->certCacheLock = cache->keyCacheLock + 1;
1477
    cache->srvNameCacheLock = cache->certCacheLock + 1;
1478
#endif
1479
1480
0
    PORT_Free(myEnvString);
1481
0
    PORT_Free(decoString);
1482
1483
    /* mark that we have inherited this. */
1484
0
    cache->sharedCache->everInherited = PR_TRUE;
1485
0
    isMultiProcess = PR_TRUE;
1486
1487
0
    return SECSuccess;
1488
1489
0
loser:
1490
0
    PORT_Free(myEnvString);
1491
0
    if (decoString)
1492
0
        PORT_Free(decoString);
1493
0
    CloseCache(cache);
1494
0
    PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1495
0
    return SECFailure;
1496
0
}
1497
1498
SECStatus
1499
SSL_InheritMPServerSIDCache(const char *envString)
1500
0
{
1501
0
    return SSL_InheritMPServerSIDCacheInstance(&globalCache, envString);
1502
0
}
1503
1504
#if defined(XP_UNIX)
1505
1506
0
#define SID_LOCK_EXPIRATION_TIMEOUT 30 /* seconds */
1507
1508
static void
1509
LockPoller(void *arg)
1510
0
{
1511
0
    cacheDesc *cache = (cacheDesc *)arg;
1512
0
    cacheDesc *sharedCache = cache->sharedCache;
1513
0
    sidCacheLock *pLock;
1514
0
    PRIntervalTime timeout;
1515
0
    PRUint32 now;
1516
0
    PRUint32 then;
1517
0
    int locks_polled = 0;
1518
0
    int locks_to_poll = cache->numSIDCacheLocks + 2;
1519
0
    PRUint32 expiration = cache->mutexTimeout;
1520
1521
0
    timeout = PR_SecondsToInterval(expiration);
1522
0
    while (!sharedCache->stopPolling) {
1523
0
        PR_Sleep(timeout);
1524
0
        if (sharedCache->stopPolling)
1525
0
            break;
1526
1527
0
        now = ssl_CacheNow();
1528
0
        then = now - expiration;
1529
0
        for (pLock = cache->sidCacheLocks, locks_polled = 0;
1530
0
             locks_to_poll > locks_polled && !sharedCache->stopPolling;
1531
0
             ++locks_polled, ++pLock) {
1532
0
            pid_t pid;
1533
1534
0
            if (pLock->timeStamp < then &&
1535
0
                pLock->timeStamp != 0 &&
1536
0
                (pid = pLock->pid) != 0) {
1537
1538
                /* maybe we should try the lock? */
1539
0
                int result = kill(pid, 0);
1540
0
                if (result < 0 && errno == ESRCH) {
1541
0
                    SECStatus rv;
1542
                    /* No process exists by that pid any more.
1543
                    ** Treat this mutex as abandoned.
1544
                    */
1545
0
                    pLock->timeStamp = now;
1546
0
                    pLock->pid = 0;
1547
0
                    rv = sslMutex_Unlock(&pLock->mutex);
1548
0
                    if (rv != SECSuccess) {
1549
                        /* Now what? */
1550
0
                    }
1551
0
                }
1552
0
            }
1553
0
        } /* end of loop over locks */
1554
0
    }     /* end of entire polling loop */
1555
0
}
1556
1557
/* Launch thread to poll cache for expired locks */
1558
static SECStatus
1559
LaunchLockPoller(cacheDesc *cache)
1560
0
{
1561
0
    const char *timeoutString;
1562
0
    PRThread *pollerThread;
1563
1564
0
    cache->mutexTimeout = SID_LOCK_EXPIRATION_TIMEOUT;
1565
0
    timeoutString = PR_GetEnvSecure("NSS_SSL_SERVER_CACHE_MUTEX_TIMEOUT");
1566
0
    if (timeoutString) {
1567
0
        long newTime = strtol(timeoutString, 0, 0);
1568
0
        if (newTime == 0)
1569
0
            return SECSuccess; /* application doesn't want poller thread */
1570
0
        if (newTime > 0)
1571
0
            cache->mutexTimeout = (PRUint32)newTime;
1572
        /* if error (newTime < 0) ignore it and use default */
1573
0
    }
1574
1575
0
    pollerThread =
1576
0
        PR_CreateThread(PR_USER_THREAD, LockPoller, cache, PR_PRIORITY_NORMAL,
1577
0
                        PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0);
1578
0
    if (!pollerThread) {
1579
0
        return SECFailure;
1580
0
    }
1581
0
    cache->poller = pollerThread;
1582
0
    return SECSuccess;
1583
0
}
1584
1585
/* Stop the thread that polls cache for expired locks */
1586
static SECStatus
1587
StopLockPoller(cacheDesc *cache)
1588
4
{
1589
4
    if (!cache->poller) {
1590
4
        return SECSuccess;
1591
4
    }
1592
0
    cache->sharedCache->stopPolling = PR_TRUE;
1593
0
    if (PR_Interrupt(cache->poller) != PR_SUCCESS) {
1594
0
        return SECFailure;
1595
0
    }
1596
0
    if (PR_JoinThread(cache->poller) != PR_SUCCESS) {
1597
0
        return SECFailure;
1598
0
    }
1599
0
    cache->poller = NULL;
1600
0
    return SECSuccess;
1601
0
}
1602
#endif
1603
1604
/************************************************************************
1605
 *  Code dealing with shared wrapped symmetric wrapping keys below      *
1606
 ************************************************************************/
1607
1608
/* The asymmetric key we use for wrapping the self-encryption keys. This is a
1609
 * global structure that can be initialized without a socket. Access is
1610
 * synchronized on the reader-writer lock. This is setup either by calling
1611
 * SSL_SetSessionTicketKeyPair() or by configuring a certificate of the
1612
 * ssl_auth_rsa_decrypt type. */
1613
static struct {
1614
    PRCallOnceType setup;
1615
    PRRWLock *lock;
1616
    SECKEYPublicKey *pubKey;
1617
    SECKEYPrivateKey *privKey;
1618
    PRBool configured;
1619
} ssl_self_encrypt_key_pair;
1620
1621
/* The symmetric self-encryption keys. This requires a socket to construct
1622
 * and requires that the global structure be initialized before use.
1623
 */
1624
static sslSelfEncryptKeys ssl_self_encrypt_keys;
1625
1626
/* Externalize the self encrypt keys. Purely used for testing. */
1627
sslSelfEncryptKeys *
1628
ssl_GetSelfEncryptKeysInt()
1629
0
{
1630
0
    return &ssl_self_encrypt_keys;
1631
0
}
1632
1633
static void
1634
ssl_CleanupSelfEncryptKeyPair()
1635
4
{
1636
4
    if (ssl_self_encrypt_key_pair.pubKey) {
1637
4
        PORT_Assert(ssl_self_encrypt_key_pair.privKey);
1638
4
        SECKEY_DestroyPublicKey(ssl_self_encrypt_key_pair.pubKey);
1639
4
        SECKEY_DestroyPrivateKey(ssl_self_encrypt_key_pair.privKey);
1640
4
    }
1641
4
}
1642
1643
void
1644
ssl_ResetSelfEncryptKeys()
1645
4
{
1646
4
    if (ssl_self_encrypt_keys.encKey) {
1647
4
        PORT_Assert(ssl_self_encrypt_keys.macKey);
1648
4
        PK11_FreeSymKey(ssl_self_encrypt_keys.encKey);
1649
4
        PK11_FreeSymKey(ssl_self_encrypt_keys.macKey);
1650
4
    }
1651
4
    PORT_Memset(&ssl_self_encrypt_keys, 0,
1652
4
                sizeof(ssl_self_encrypt_keys));
1653
4
}
1654
1655
static SECStatus
1656
ssl_SelfEncryptShutdown(void *appData, void *nssData)
1657
4
{
1658
4
    ssl_CleanupSelfEncryptKeyPair();
1659
4
    PR_DestroyRWLock(ssl_self_encrypt_key_pair.lock);
1660
4
    PORT_Memset(&ssl_self_encrypt_key_pair, 0,
1661
4
                sizeof(ssl_self_encrypt_key_pair));
1662
1663
4
    ssl_ResetSelfEncryptKeys();
1664
4
    return SECSuccess;
1665
4
}
1666
1667
static PRStatus
1668
ssl_SelfEncryptSetup(void)
1669
4
{
1670
4
    SECStatus rv = NSS_RegisterShutdown(ssl_SelfEncryptShutdown, NULL);
1671
4
    if (rv != SECSuccess) {
1672
0
        return PR_FAILURE;
1673
0
    }
1674
4
    ssl_self_encrypt_key_pair.lock = PR_NewRWLock(PR_RWLOCK_RANK_NONE, NULL);
1675
4
    if (!ssl_self_encrypt_key_pair.lock) {
1676
0
        return PR_FAILURE;
1677
0
    }
1678
4
    return PR_SUCCESS;
1679
4
}
1680
1681
/* Configure a self encryption key pair.  |explicitConfig| is set to true for
1682
 * calls to SSL_SetSessionTicketKeyPair(), false for implicit configuration.
1683
 * This assumes that the setup has been run. */
1684
static SECStatus
1685
ssl_SetSelfEncryptKeyPair(SECKEYPublicKey *pubKey,
1686
                          SECKEYPrivateKey *privKey,
1687
                          PRBool explicitConfig)
1688
4
{
1689
4
    SECKEYPublicKey *pubKeyCopy, *oldPubKey;
1690
4
    SECKEYPrivateKey *privKeyCopy, *oldPrivKey;
1691
1692
4
    PORT_Assert(ssl_self_encrypt_key_pair.lock);
1693
4
    pubKeyCopy = SECKEY_CopyPublicKey(pubKey);
1694
4
    privKeyCopy = SECKEY_CopyPrivateKey(privKey);
1695
1696
4
    if (!pubKeyCopy || !privKeyCopy) {
1697
0
        SECKEY_DestroyPublicKey(pubKeyCopy);
1698
0
        SECKEY_DestroyPrivateKey(privKeyCopy);
1699
0
        PORT_SetError(SEC_ERROR_NO_MEMORY);
1700
0
        return SECFailure;
1701
0
    }
1702
1703
4
    PR_RWLock_Wlock(ssl_self_encrypt_key_pair.lock);
1704
4
    oldPubKey = ssl_self_encrypt_key_pair.pubKey;
1705
4
    oldPrivKey = ssl_self_encrypt_key_pair.privKey;
1706
4
    ssl_self_encrypt_key_pair.pubKey = pubKeyCopy;
1707
4
    ssl_self_encrypt_key_pair.privKey = privKeyCopy;
1708
4
    ssl_self_encrypt_key_pair.configured = explicitConfig;
1709
4
    PR_RWLock_Unlock(ssl_self_encrypt_key_pair.lock);
1710
1711
4
    if (oldPubKey) {
1712
0
        PORT_Assert(oldPrivKey);
1713
0
        SECKEY_DestroyPublicKey(oldPubKey);
1714
0
        SECKEY_DestroyPrivateKey(oldPrivKey);
1715
0
    }
1716
1717
4
    return SECSuccess;
1718
4
}
1719
1720
/* This is really the self-encryption keys but it has the
1721
 * wrong name for historical API stability reasons. */
1722
SECStatus
1723
SSL_SetSessionTicketKeyPair(SECKEYPublicKey *pubKey,
1724
                            SECKEYPrivateKey *privKey)
1725
0
{
1726
0
    if (SECKEY_GetPublicKeyType(pubKey) != rsaKey ||
1727
0
        SECKEY_GetPrivateKeyType(privKey) != rsaKey) {
1728
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
1729
0
        return SECFailure;
1730
0
    }
1731
1732
0
    if (PR_SUCCESS != PR_CallOnce(&ssl_self_encrypt_key_pair.setup,
1733
0
                                  &ssl_SelfEncryptSetup)) {
1734
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1735
0
        return SECFailure;
1736
0
    }
1737
1738
0
    return ssl_SetSelfEncryptKeyPair(pubKey, privKey, PR_TRUE);
1739
0
}
1740
1741
/* When configuring a server cert, we should save the RSA key in case it is
1742
 * needed for self-encryption. This saves the latest copy, unless there has
1743
 * been an explicit call to SSL_SetSessionTicketKeyPair(). */
1744
SECStatus
1745
ssl_MaybeSetSelfEncryptKeyPair(const sslKeyPair *keyPair)
1746
4
{
1747
4
    PRBool configured;
1748
1749
4
    if (PR_SUCCESS != PR_CallOnce(&ssl_self_encrypt_key_pair.setup,
1750
4
                                  &ssl_SelfEncryptSetup)) {
1751
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1752
0
        return SECFailure;
1753
0
    }
1754
1755
4
    PR_RWLock_Rlock(ssl_self_encrypt_key_pair.lock);
1756
4
    configured = ssl_self_encrypt_key_pair.configured;
1757
4
    PR_RWLock_Unlock(ssl_self_encrypt_key_pair.lock);
1758
4
    if (configured) {
1759
0
        return SECSuccess;
1760
0
    }
1761
4
    return ssl_SetSelfEncryptKeyPair(keyPair->pubKey,
1762
4
                                     keyPair->privKey, PR_FALSE);
1763
4
}
1764
1765
static SECStatus
1766
ssl_GetSelfEncryptKeyPair(SECKEYPublicKey **pubKey,
1767
                          SECKEYPrivateKey **privKey)
1768
4
{
1769
4
    if (PR_SUCCESS != PR_CallOnce(&ssl_self_encrypt_key_pair.setup,
1770
4
                                  &ssl_SelfEncryptSetup)) {
1771
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1772
0
        return SECFailure;
1773
0
    }
1774
1775
4
    SECKEYPublicKey *pubKeyCopy = NULL;
1776
4
    SECKEYPrivateKey *privKeyCopy = NULL;
1777
4
    PRBool noKey = PR_FALSE;
1778
1779
4
    PR_RWLock_Rlock(ssl_self_encrypt_key_pair.lock);
1780
4
    if (ssl_self_encrypt_key_pair.pubKey && ssl_self_encrypt_key_pair.privKey) {
1781
4
        pubKeyCopy = SECKEY_CopyPublicKey(ssl_self_encrypt_key_pair.pubKey);
1782
4
        privKeyCopy = SECKEY_CopyPrivateKey(ssl_self_encrypt_key_pair.privKey);
1783
4
    } else {
1784
0
        noKey = PR_TRUE;
1785
0
    }
1786
4
    PR_RWLock_Unlock(ssl_self_encrypt_key_pair.lock);
1787
1788
4
    if (noKey) {
1789
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1790
0
        return SECFailure;
1791
0
    }
1792
1793
4
    if (!pubKeyCopy || !privKeyCopy) {
1794
0
        SECKEY_DestroyPublicKey(pubKeyCopy);
1795
0
        SECKEY_DestroyPrivateKey(privKeyCopy);
1796
0
        PORT_SetError(SEC_ERROR_NO_MEMORY);
1797
0
        return SECFailure;
1798
0
    }
1799
1800
4
    *pubKey = pubKeyCopy;
1801
4
    *privKey = privKeyCopy;
1802
4
    return SECSuccess;
1803
4
}
1804
1805
static SECStatus
1806
ssl_GenerateSelfEncryptKeys(void *pwArg, PRUint8 *keyName,
1807
                            PK11SymKey **aesKey, PK11SymKey **macKey);
1808
1809
static PRStatus
1810
ssl_GenerateSelfEncryptKeysOnce(void *arg)
1811
4
{
1812
4
    SECStatus rv;
1813
1814
    /* Get a copy of the session keys from shared memory. */
1815
4
    PORT_Memcpy(ssl_self_encrypt_keys.keyName,
1816
4
                SELF_ENCRYPT_KEY_NAME_PREFIX,
1817
4
                sizeof(SELF_ENCRYPT_KEY_NAME_PREFIX));
1818
    /* This function calls ssl_GetSelfEncryptKeyPair(), which initializes the
1819
     * key pair stuff.  That allows this to use the same shutdown function. */
1820
4
    rv = ssl_GenerateSelfEncryptKeys(arg, ssl_self_encrypt_keys.keyName,
1821
4
                                     &ssl_self_encrypt_keys.encKey,
1822
4
                                     &ssl_self_encrypt_keys.macKey);
1823
4
    if (rv != SECSuccess) {
1824
0
        return PR_FAILURE;
1825
0
    }
1826
1827
4
    return PR_SUCCESS;
1828
4
}
1829
1830
SECStatus
1831
ssl_GetSelfEncryptKeys(sslSocket *ss, PRUint8 *keyName,
1832
                       PK11SymKey **encKey, PK11SymKey **macKey)
1833
3.82k
{
1834
3.82k
    if (PR_SUCCESS != PR_CallOnceWithArg(&ssl_self_encrypt_keys.setup,
1835
3.82k
                                         &ssl_GenerateSelfEncryptKeysOnce,
1836
3.82k
                                         ss->pkcs11PinArg)) {
1837
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1838
0
        return SECFailure;
1839
0
    }
1840
1841
3.82k
    if (!ssl_self_encrypt_keys.encKey || !ssl_self_encrypt_keys.macKey) {
1842
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1843
0
        return SECFailure;
1844
0
    }
1845
1846
3.82k
    PORT_Memcpy(keyName, ssl_self_encrypt_keys.keyName,
1847
3.82k
                sizeof(ssl_self_encrypt_keys.keyName));
1848
3.82k
    *encKey = ssl_self_encrypt_keys.encKey;
1849
3.82k
    *macKey = ssl_self_encrypt_keys.macKey;
1850
3.82k
    return SECSuccess;
1851
3.82k
}
1852
1853
/* If lockTime is zero, it implies that the lock is not held, and must be
1854
 * aquired here.
1855
 */
1856
static SECStatus
1857
getSvrWrappingKey(unsigned int symWrapMechIndex,
1858
                  unsigned int wrapKeyIndex,
1859
                  SSLWrappedSymWrappingKey *wswk,
1860
                  cacheDesc *cache,
1861
                  PRUint32 lockTime)
1862
5.54k
{
1863
5.54k
    PRUint32 now = 0;
1864
5.54k
    PRBool rv = SECFailure;
1865
1866
5.54k
    if (!cache->cacheMem) { /* cache is uninitialized */
1867
0
        PORT_SetError(SSL_ERROR_SERVER_CACHE_NOT_CONFIGURED);
1868
0
        return SECFailure;
1869
0
    }
1870
1871
5.54k
    PRUint32 ndx = (wrapKeyIndex * SSL_NUM_WRAP_MECHS) + symWrapMechIndex;
1872
5.54k
    SSLWrappedSymWrappingKey *pwswk = cache->keyCacheData + ndx;
1873
1874
5.54k
    if (!lockTime) {
1875
5.53k
        now = LockSidCacheLock(cache->keyCacheLock, 0);
1876
5.53k
        if (!now) {
1877
0
            return SECFailure;
1878
0
        }
1879
5.53k
    }
1880
5.54k
    if (pwswk->wrapKeyIndex == wrapKeyIndex &&
1881
4
        pwswk->wrapMechIndex == symWrapMechIndex &&
1882
4
        pwswk->wrappedSymKeyLen != 0) {
1883
0
        *wswk = *pwswk;
1884
0
        rv = SECSuccess;
1885
0
    }
1886
5.54k
    if (now) {
1887
5.53k
        UnlockSidCacheLock(cache->keyCacheLock);
1888
5.53k
    }
1889
5.54k
    return rv;
1890
5.54k
}
1891
1892
SECStatus
1893
ssl_GetWrappingKey(unsigned int wrapMechIndex,
1894
                   unsigned int wrapKeyIndex,
1895
                   SSLWrappedSymWrappingKey *wswk)
1896
5.53k
{
1897
5.53k
    PORT_Assert(wrapMechIndex < SSL_NUM_WRAP_MECHS);
1898
5.53k
    PORT_Assert(wrapKeyIndex < SSL_NUM_WRAP_KEYS);
1899
5.53k
    if (wrapMechIndex >= SSL_NUM_WRAP_MECHS ||
1900
5.53k
        wrapKeyIndex >= SSL_NUM_WRAP_KEYS) {
1901
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
1902
0
        return SECFailure;
1903
0
    }
1904
1905
5.53k
    return getSvrWrappingKey(wrapMechIndex, wrapKeyIndex, wswk,
1906
5.53k
                             &globalCache, 0);
1907
5.53k
}
1908
1909
/* Wrap and cache a session ticket key. */
1910
static SECStatus
1911
WrapSelfEncryptKey(SECKEYPublicKey *svrPubKey, PK11SymKey *symKey,
1912
                   const char *keyName, encKeyCacheEntry *cacheEntry)
1913
8
{
1914
8
    SECItem wrappedKey = { siBuffer, NULL, 0 };
1915
1916
8
    wrappedKey.len = SECKEY_PublicKeyStrength(svrPubKey);
1917
8
    PORT_Assert(wrappedKey.len <= sizeof(cacheEntry->bytes));
1918
8
    if (wrappedKey.len > sizeof(cacheEntry->bytes))
1919
0
        return PR_FALSE;
1920
8
    wrappedKey.data = cacheEntry->bytes;
1921
1922
8
    if (PK11_PubWrapSymKey(CKM_RSA_PKCS, svrPubKey, symKey, &wrappedKey) !=
1923
8
        SECSuccess) {
1924
0
        SSL_DBG(("%d: SSL[%s]: Unable to wrap self encrypt key %s.",
1925
0
                 SSL_GETPID(), "unknown", keyName));
1926
0
        return SECFailure;
1927
0
    }
1928
8
    cacheEntry->length = wrappedKey.len;
1929
8
    return SECSuccess;
1930
8
}
1931
1932
static SECStatus
1933
GenerateSelfEncryptKeys(void *pwArg, PRUint8 *keyName, PK11SymKey **aesKey,
1934
                        PK11SymKey **macKey)
1935
4
{
1936
4
    PK11SlotInfo *slot;
1937
4
    CK_MECHANISM_TYPE mechanismArray[2];
1938
4
    PK11SymKey *aesKeyTmp = NULL;
1939
4
    PK11SymKey *macKeyTmp = NULL;
1940
4
    cacheDesc *cache = &globalCache;
1941
4
    PRUint8 ticketKeyNameSuffixLocal[SELF_ENCRYPT_KEY_VAR_NAME_LEN];
1942
4
    PRUint8 *ticketKeyNameSuffix;
1943
1944
4
    if (!cache->cacheMem) {
1945
        /* cache is not initalized. Use stack buffer */
1946
0
        ticketKeyNameSuffix = ticketKeyNameSuffixLocal;
1947
4
    } else {
1948
4
        ticketKeyNameSuffix = cache->ticketKeyNameSuffix;
1949
4
    }
1950
1951
4
    if (PK11_GenerateRandom(ticketKeyNameSuffix,
1952
4
                            SELF_ENCRYPT_KEY_VAR_NAME_LEN) !=
1953
4
        SECSuccess) {
1954
0
        SSL_DBG(("%d: SSL[%s]: Unable to generate random key name bytes.",
1955
0
                 SSL_GETPID(), "unknown"));
1956
0
        return SECFailure;
1957
0
    }
1958
1959
4
    mechanismArray[0] = CKM_AES_CBC;
1960
4
    mechanismArray[1] = CKM_SHA256_HMAC;
1961
1962
4
    slot = PK11_GetBestSlotMultiple(mechanismArray, 2, pwArg);
1963
4
    if (slot) {
1964
4
        aesKeyTmp = PK11_KeyGen(slot, mechanismArray[0], NULL,
1965
4
                                AES_256_KEY_LENGTH, pwArg);
1966
4
        macKeyTmp = PK11_KeyGen(slot, mechanismArray[1], NULL,
1967
4
                                SHA256_LENGTH, pwArg);
1968
4
        PK11_FreeSlot(slot);
1969
4
    }
1970
1971
4
    if (aesKeyTmp == NULL || macKeyTmp == NULL) {
1972
0
        SSL_DBG(("%d: SSL[%s]: Unable to generate session ticket keys.",
1973
0
                 SSL_GETPID(), "unknown"));
1974
0
        goto loser;
1975
0
    }
1976
4
    PORT_Memcpy(keyName, ticketKeyNameSuffix, SELF_ENCRYPT_KEY_VAR_NAME_LEN);
1977
4
    *aesKey = aesKeyTmp;
1978
4
    *macKey = macKeyTmp;
1979
4
    return SECSuccess;
1980
1981
0
loser:
1982
0
    if (aesKeyTmp)
1983
0
        PK11_FreeSymKey(aesKeyTmp);
1984
0
    if (macKeyTmp)
1985
0
        PK11_FreeSymKey(macKeyTmp);
1986
0
    return SECFailure;
1987
4
}
1988
1989
static SECStatus
1990
GenerateAndWrapSelfEncryptKeys(SECKEYPublicKey *svrPubKey, void *pwArg,
1991
                               PRUint8 *keyName, PK11SymKey **aesKey,
1992
                               PK11SymKey **macKey)
1993
4
{
1994
4
    PK11SymKey *aesKeyTmp = NULL;
1995
4
    PK11SymKey *macKeyTmp = NULL;
1996
4
    cacheDesc *cache = &globalCache;
1997
4
    SECStatus rv;
1998
1999
4
    rv = GenerateSelfEncryptKeys(pwArg, keyName, &aesKeyTmp, &macKeyTmp);
2000
4
    if (rv != SECSuccess) {
2001
0
        return SECFailure;
2002
0
    }
2003
2004
4
    if (cache->cacheMem) {
2005
        /* Export the keys to the shared cache in wrapped form. */
2006
4
        rv = WrapSelfEncryptKey(svrPubKey, aesKeyTmp, "enc key", cache->ticketEncKey);
2007
4
        if (rv != SECSuccess) {
2008
0
            goto loser;
2009
0
        }
2010
4
        rv = WrapSelfEncryptKey(svrPubKey, macKeyTmp, "mac key", cache->ticketMacKey);
2011
4
        if (rv != SECSuccess) {
2012
0
            goto loser;
2013
0
        }
2014
4
    }
2015
4
    *aesKey = aesKeyTmp;
2016
4
    *macKey = macKeyTmp;
2017
4
    return SECSuccess;
2018
2019
0
loser:
2020
0
    PK11_FreeSymKey(aesKeyTmp);
2021
0
    PK11_FreeSymKey(macKeyTmp);
2022
0
    return SECFailure;
2023
4
}
2024
2025
static SECStatus
2026
UnwrapCachedSelfEncryptKeys(SECKEYPrivateKey *svrPrivKey, PRUint8 *keyName,
2027
                            PK11SymKey **aesKey, PK11SymKey **macKey)
2028
0
{
2029
0
    SECItem wrappedKey = { siBuffer, NULL, 0 };
2030
0
    PK11SymKey *aesKeyTmp = NULL;
2031
0
    PK11SymKey *macKeyTmp = NULL;
2032
0
    cacheDesc *cache = &globalCache;
2033
2034
0
    wrappedKey.data = cache->ticketEncKey->bytes;
2035
0
    wrappedKey.len = cache->ticketEncKey->length;
2036
0
    PORT_Assert(wrappedKey.len <= sizeof(cache->ticketEncKey->bytes));
2037
0
    aesKeyTmp = PK11_PubUnwrapSymKey(svrPrivKey, &wrappedKey,
2038
0
                                     CKM_AES_CBC, CKA_DECRYPT, 0);
2039
2040
0
    wrappedKey.data = cache->ticketMacKey->bytes;
2041
0
    wrappedKey.len = cache->ticketMacKey->length;
2042
0
    PORT_Assert(wrappedKey.len <= sizeof(cache->ticketMacKey->bytes));
2043
0
    macKeyTmp = PK11_PubUnwrapSymKey(svrPrivKey, &wrappedKey,
2044
0
                                     CKM_SHA256_HMAC, CKA_SIGN, 0);
2045
2046
0
    if (aesKeyTmp == NULL || macKeyTmp == NULL) {
2047
0
        SSL_DBG(("%d: SSL[%s]: Unable to unwrap session ticket keys.",
2048
0
                 SSL_GETPID(), "unknown"));
2049
0
        goto loser;
2050
0
    }
2051
0
    SSL_DBG(("%d: SSL[%s]: Successfully unwrapped session ticket keys.",
2052
0
             SSL_GETPID(), "unknown"));
2053
2054
0
    PORT_Memcpy(keyName, cache->ticketKeyNameSuffix,
2055
0
                SELF_ENCRYPT_KEY_VAR_NAME_LEN);
2056
0
    *aesKey = aesKeyTmp;
2057
0
    *macKey = macKeyTmp;
2058
0
    return SECSuccess;
2059
2060
0
loser:
2061
0
    if (aesKeyTmp)
2062
0
        PK11_FreeSymKey(aesKeyTmp);
2063
0
    if (macKeyTmp)
2064
0
        PK11_FreeSymKey(macKeyTmp);
2065
0
    return SECFailure;
2066
0
}
2067
2068
static SECStatus
2069
ssl_GenerateSelfEncryptKeys(void *pwArg, PRUint8 *keyName,
2070
                            PK11SymKey **encKey, PK11SymKey **macKey)
2071
4
{
2072
4
    SECKEYPrivateKey *svrPrivKey = NULL;
2073
4
    SECKEYPublicKey *svrPubKey = NULL;
2074
4
    PRUint32 now;
2075
4
    cacheDesc *cache = &globalCache;
2076
2077
4
    SECStatus rv = ssl_GetSelfEncryptKeyPair(&svrPubKey, &svrPrivKey);
2078
4
    if (rv != SECSuccess || !cache->cacheMem) {
2079
        /* No key pair for wrapping, or the cache is uninitialized. Generate
2080
         * keys and return them without caching. */
2081
0
        rv = GenerateSelfEncryptKeys(pwArg, keyName, encKey, macKey);
2082
4
    } else {
2083
4
        now = LockSidCacheLock(cache->keyCacheLock, 0);
2084
4
        if (!now) {
2085
0
            goto loser;
2086
0
        }
2087
2088
4
        if (*(cache->ticketKeysValid)) {
2089
0
            rv = UnwrapCachedSelfEncryptKeys(svrPrivKey, keyName, encKey, macKey);
2090
4
        } else {
2091
            /* Keys do not exist, create them. */
2092
4
            rv = GenerateAndWrapSelfEncryptKeys(svrPubKey, pwArg, keyName,
2093
4
                                                encKey, macKey);
2094
4
            if (rv == SECSuccess) {
2095
4
                *(cache->ticketKeysValid) = 1;
2096
4
            }
2097
4
        }
2098
4
        UnlockSidCacheLock(cache->keyCacheLock);
2099
4
    }
2100
4
    SECKEY_DestroyPublicKey(svrPubKey);
2101
4
    SECKEY_DestroyPrivateKey(svrPrivKey);
2102
4
    return rv;
2103
2104
0
loser:
2105
0
    UnlockSidCacheLock(cache->keyCacheLock);
2106
0
    SECKEY_DestroyPublicKey(svrPubKey);
2107
0
    SECKEY_DestroyPrivateKey(svrPrivKey);
2108
0
    return SECFailure;
2109
4
}
2110
2111
/* The caller passes in the new value it wants
2112
 * to set.  This code tests the wrapped sym key entry in the shared memory.
2113
 * If it is uninitialized, this function writes the caller's value into
2114
 * the disk entry, and returns false.
2115
 * Otherwise, it overwrites the caller's wswk with the value obtained from
2116
 * the disk, and returns PR_TRUE.
2117
 * This is all done while holding the locks/mutexes necessary to make
2118
 * the operation atomic.
2119
 */
2120
SECStatus
2121
ssl_SetWrappingKey(SSLWrappedSymWrappingKey *wswk)
2122
2
{
2123
2
    cacheDesc *cache = &globalCache;
2124
2
    PRBool rv = SECFailure;
2125
2
    PRUint32 ndx;
2126
2
    PRUint32 now;
2127
2
    SSLWrappedSymWrappingKey myWswk;
2128
2129
2
    if (!cache->cacheMem) { /* cache is uninitialized */
2130
0
        PORT_SetError(SSL_ERROR_SERVER_CACHE_NOT_CONFIGURED);
2131
0
        return SECFailure;
2132
0
    }
2133
2134
2
    PORT_Assert(wswk->wrapMechIndex < SSL_NUM_WRAP_MECHS);
2135
2
    PORT_Assert(wswk->wrapKeyIndex < SSL_NUM_WRAP_KEYS);
2136
2
    if (wswk->wrapMechIndex >= SSL_NUM_WRAP_MECHS ||
2137
2
        wswk->wrapKeyIndex >= SSL_NUM_WRAP_KEYS) {
2138
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2139
0
        return SECFailure;
2140
0
    }
2141
2142
2
    ndx = (wswk->wrapKeyIndex * SSL_NUM_WRAP_MECHS) + wswk->wrapMechIndex;
2143
2
    PORT_Memset(&myWswk, 0, sizeof myWswk); /* eliminate UMRs. */
2144
2145
2
    now = LockSidCacheLock(cache->keyCacheLock, 0);
2146
2
    if (!now) {
2147
0
        return SECFailure;
2148
0
    }
2149
2
    rv = getSvrWrappingKey(wswk->wrapMechIndex, wswk->wrapKeyIndex,
2150
2
                           &myWswk, cache, now);
2151
2
    if (rv == SECSuccess) {
2152
        /* we found it on disk, copy it out to the caller. */
2153
0
        PORT_Memcpy(wswk, &myWswk, sizeof *wswk);
2154
2
    } else {
2155
        /* Wasn't on disk, and we're still holding the lock, so write it. */
2156
2
        cache->keyCacheData[ndx] = *wswk;
2157
2
    }
2158
2
    UnlockSidCacheLock(cache->keyCacheLock);
2159
2
    return rv;
2160
2
}
2161
2162
#else /* MAC version or other platform */
2163
2164
#include "seccomon.h"
2165
#include "cert.h"
2166
#include "ssl.h"
2167
#include "sslimpl.h"
2168
2169
SECStatus
2170
SSL_ConfigServerSessionIDCache(int maxCacheEntries,
2171
                               PRUint32 ssl2_timeout,
2172
                               PRUint32 ssl3_timeout,
2173
                               const char *directory)
2174
{
2175
    PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_ConfigServerSessionIDCache)");
2176
    return SECFailure;
2177
}
2178
2179
SECStatus
2180
SSL_ConfigMPServerSIDCache(int maxCacheEntries,
2181
                           PRUint32 ssl2_timeout,
2182
                           PRUint32 ssl3_timeout,
2183
                           const char *directory)
2184
{
2185
    PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_ConfigMPServerSIDCache)");
2186
    return SECFailure;
2187
}
2188
2189
SECStatus
2190
SSL_InheritMPServerSIDCache(const char *envString)
2191
{
2192
    PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_InheritMPServerSIDCache)");
2193
    return SECFailure;
2194
}
2195
2196
SECStatus
2197
ssl_GetWrappingKey(unsigned int wrapMechIndex,
2198
                   unsigned int wrapKeyIndex,
2199
                   SSLWrappedSymWrappingKey *wswk)
2200
{
2201
    PR_ASSERT(!"SSL servers are not supported on this platform. (ssl_GetWrappingKey)");
2202
    return SECFailure;
2203
}
2204
2205
/* This is a kind of test-and-set.  The caller passes in the new value it wants
2206
 * to set.  This code tests the wrapped sym key entry in the shared memory.
2207
 * If it is uninitialized, this function writes the caller's value into
2208
 * the disk entry, and returns false.
2209
 * Otherwise, it overwrites the caller's wswk with the value obtained from
2210
 * the disk, and returns PR_TRUE.
2211
 * This is all done while holding the locks/mutexes necessary to make
2212
 * the operation atomic.
2213
 */
2214
SECStatus
2215
ssl_SetWrappingKey(SSLWrappedSymWrappingKey *wswk)
2216
{
2217
    PR_ASSERT(!"SSL servers are not supported on this platform. (ssl_SetWrappingKey)");
2218
    return SECFailure;
2219
}
2220
2221
PRUint32
2222
SSL_GetMaxServerCacheLocks(void)
2223
{
2224
    PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_GetMaxServerCacheLocks)");
2225
    return -1;
2226
}
2227
2228
SECStatus
2229
SSL_SetMaxServerCacheLocks(PRUint32 maxLocks)
2230
{
2231
    PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_SetMaxServerCacheLocks)");
2232
    return SECFailure;
2233
}
2234
2235
#endif /* XP_UNIX || XP_WIN32 */