Coverage Report

Created: 2018-09-25 14:53

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