1
/* ***** BEGIN LICENSE BLOCK *****
2
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
4
* The contents of this file are subject to the Mozilla Public License Version
5
* 1.1 (the "License"); you may not use this file except in compliance with
6
* the License. You may obtain a copy of the License at
7
* http://www.mozilla.org/MPL/
9
* Software distributed under the License is distributed on an "AS IS" basis,
10
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11
* for the specific language governing rights and limitations under the
14
* The Original Code is the Netscape security libraries.
16
* The Initial Developer of the Original Code is
17
* Netscape Communications Corporation.
18
* Portions created by the Initial Developer are Copyright (C) 1994-2000
19
* the Initial Developer. All Rights Reserved.
23
* Alternatively, the contents of this file may be used under the terms of
24
* either the GNU General Public License Version 2 or later (the "GPL"), or
25
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26
* in which case the provisions of the GPL or the LGPL are applicable instead
27
* of those above. If you wish to allow use of your version of this file only
28
* under the terms of either the GPL or the LGPL, and not to allow others to
29
* use your version of this file under the terms of the MPL, indicate your
30
* decision by deleting the provisions above and replace them with the notice
31
* and other provisions required by the GPL or the LGPL. If you do not delete
32
* the provisions above, a recipient may use your version of this file under
33
* the terms of any one of the MPL, the GPL or the LGPL.
35
* ***** END LICENSE BLOCK ***** */
44
extern PRBool dumpChain;
45
extern void dumpCertChain(CERTCertificate *, SECCertUsage);
47
/* Declare SSL cipher suites. */
49
int ssl2CipherSuites[] = {
50
SSL_EN_RC4_128_WITH_MD5, /* A */
51
SSL_EN_RC4_128_EXPORT40_WITH_MD5, /* B */
52
SSL_EN_RC2_128_CBC_WITH_MD5, /* C */
53
SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5, /* D */
54
SSL_EN_DES_64_CBC_WITH_MD5, /* E */
55
SSL_EN_DES_192_EDE3_CBC_WITH_MD5, /* F */
59
int ssl3CipherSuites[] = {
60
-1, /* SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA* a */
61
-1, /* SSL_FORTEZZA_DMS_WITH_RC4_128_SHA, * b */
62
SSL_RSA_WITH_RC4_128_MD5, /* c */
63
SSL_RSA_WITH_3DES_EDE_CBC_SHA, /* d */
64
SSL_RSA_WITH_DES_CBC_SHA, /* e */
65
SSL_RSA_EXPORT_WITH_RC4_40_MD5, /* f */
66
SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5, /* g */
67
-1, /* SSL_FORTEZZA_DMS_WITH_NULL_SHA, * h */
68
SSL_RSA_WITH_NULL_MD5, /* i */
69
SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA, /* j */
70
SSL_RSA_FIPS_WITH_DES_CBC_SHA, /* k */
71
TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA, /* l */
72
TLS_RSA_EXPORT1024_WITH_RC4_56_SHA, /* m */
73
SSL_RSA_WITH_RC4_128_SHA, /* n */
74
TLS_DHE_DSS_WITH_RC4_128_SHA, /* o */
75
SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, /* p */
76
SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, /* q */
77
SSL_DHE_RSA_WITH_DES_CBC_SHA, /* r */
78
SSL_DHE_DSS_WITH_DES_CBC_SHA, /* s */
79
TLS_DHE_DSS_WITH_AES_128_CBC_SHA, /* t */
80
TLS_DHE_RSA_WITH_AES_128_CBC_SHA, /* u */
81
TLS_RSA_WITH_AES_128_CBC_SHA, /* v */
82
TLS_DHE_DSS_WITH_AES_256_CBC_SHA, /* w */
83
TLS_DHE_RSA_WITH_AES_256_CBC_SHA, /* x */
84
TLS_RSA_WITH_AES_256_CBC_SHA, /* y */
85
SSL_RSA_WITH_NULL_SHA, /* z */
89
/**************************************************************************
91
** SSL callback routines.
93
**************************************************************************/
95
/* Function: char * myPasswd()
97
* Purpose: This function is our custom password handler that is called by
98
* SSL when retreiving private certs and keys from the database. Returns a
99
* pointer to a string that with a password for the database. Password pointer
100
* should point to dynamically allocated memory that will be freed later.
103
myPasswd(PK11SlotInfo *info, PRBool retry, void *arg)
105
char * passwd = NULL;
107
if ( (!retry) && arg ) {
108
passwd = PORT_Strdup((char *)arg);
113
/* Function: SECStatus myAuthCertificate()
115
* Purpose: This function is our custom certificate authentication handler.
117
* Note: This implementation is essentially the same as the default
118
* SSL_AuthCertificate().
121
myAuthCertificate(void *arg, PRFileDesc *socket,
122
PRBool checksig, PRBool isServer)
125
SECCertificateUsage certUsage;
126
CERTCertificate * cert;
131
if (!arg || !socket) {
132
errWarn("myAuthCertificate");
136
/* Define how the cert is being used based upon the isServer flag. */
138
certUsage = isServer ? certificateUsageSSLClient : certificateUsageSSLServer;
140
cert = SSL_PeerCertificate(socket);
142
pinArg = SSL_RevealPinArg(socket);
144
if (dumpChain == PR_TRUE) {
145
dumpCertChain(cert, certUsage);
148
secStatus = CERT_VerifyCertificateNow((CERTCertDBHandle *)arg,
155
/* If this is a server, we're finished. */
156
if (isServer || secStatus != SECSuccess) {
157
SECU_printCertProblems(stderr, (CERTCertDBHandle *)arg, cert,
158
checksig, certUsage, pinArg, PR_FALSE);
159
CERT_DestroyCertificate(cert);
163
/* Certificate is OK. Since this is the client side of an SSL
164
* connection, we need to verify that the name field in the cert
165
* matches the desired hostname. This is our defense against
166
* man-in-the-middle attacks.
169
/* SSL_RevealURL returns a hostName, not an URL. */
170
hostName = SSL_RevealURL(socket);
172
if (hostName && hostName[0]) {
173
secStatus = CERT_VerifyCertName(cert, hostName);
175
PR_SetError(SSL_ERROR_BAD_CERT_DOMAIN, 0);
176
secStatus = SECFailure;
182
CERT_DestroyCertificate(cert);
186
/* Function: SECStatus myBadCertHandler()
188
* Purpose: This callback is called when the incoming certificate is not
189
* valid. We define a certain set of parameters that still cause the
190
* certificate to be "valid" for this session, and return SECSuccess to cause
191
* the server to continue processing the request when any of these conditions
192
* are met. Otherwise, SECFailure is return and the server rejects the
196
myBadCertHandler(void *arg, PRFileDesc *socket)
199
SECStatus secStatus = SECFailure;
202
/* log invalid cert here */
208
*(PRErrorCode *)arg = err = PORT_GetError();
210
/* If any of the cases in the switch are met, then we will proceed */
211
/* with the processing of the request anyway. Otherwise, the default */
212
/* case will be reached and we will reject the request. */
215
case SEC_ERROR_INVALID_AVA:
216
case SEC_ERROR_INVALID_TIME:
217
case SEC_ERROR_BAD_SIGNATURE:
218
case SEC_ERROR_EXPIRED_CERTIFICATE:
219
case SEC_ERROR_UNKNOWN_ISSUER:
220
case SEC_ERROR_UNTRUSTED_CERT:
221
case SEC_ERROR_CERT_VALID:
222
case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
223
case SEC_ERROR_CRL_EXPIRED:
224
case SEC_ERROR_CRL_BAD_SIGNATURE:
225
case SEC_ERROR_EXTENSION_VALUE_INVALID:
226
case SEC_ERROR_CA_CERT_INVALID:
227
case SEC_ERROR_CERT_USAGES_INVALID:
228
case SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION:
229
secStatus = SECSuccess;
232
secStatus = SECFailure;
236
fprintf(stderr, "Bad certificate: %d, %s\n", err, SECU_Strerror(err));
241
/* Function: SECStatus ownGetClientAuthData()
243
* Purpose: This callback is used by SSL to pull client certificate
244
* information upon server request.
247
myGetClientAuthData(void *arg,
249
struct CERTDistNamesStr *caNames,
250
struct CERTCertificateStr **pRetCert,
251
struct SECKEYPrivateKeyStr **pRetKey)
254
CERTCertificate * cert;
255
SECKEYPrivateKey * privKey;
256
char * chosenNickName = (char *)arg;
257
void * proto_win = NULL;
258
SECStatus secStatus = SECFailure;
260
proto_win = SSL_RevealPinArg(socket);
262
if (chosenNickName) {
263
cert = PK11_FindCertFromNickname(chosenNickName, proto_win);
265
privKey = PK11_FindKeyByAnyCert(cert, proto_win);
267
secStatus = SECSuccess;
269
CERT_DestroyCertificate(cert);
272
} else { /* no nickname given, automatically find the right cert */
273
CERTCertNicknames *names;
276
names = CERT_GetCertNicknames(CERT_GetDefaultCertDB(),
277
SEC_CERT_NICKNAMES_USER, proto_win);
280
for(i = 0; i < names->numnicknames; i++ ) {
282
cert = PK11_FindCertFromNickname(names->nicknames[i],
288
/* Only check unexpired certs */
289
if (CERT_CheckCertValidTimes(cert, PR_Now(), PR_FALSE)
290
!= secCertTimeValid ) {
291
CERT_DestroyCertificate(cert);
295
secStatus = NSS_CmpCertChainWCANames(cert, caNames);
296
if (secStatus == SECSuccess) {
297
privKey = PK11_FindKeyByAnyCert(cert, proto_win);
301
secStatus = SECFailure;
303
CERT_DestroyCertificate(cert);
305
CERT_FreeNicknames(names);
309
if (secStatus == SECSuccess) {
317
/* Function: SECStatus myHandshakeCallback()
319
* Purpose: Called by SSL to inform application that the handshake is
320
* complete. This function is mostly used on the server side of an SSL
321
* connection, although it is provided for a client as well.
322
* Useful when a non-blocking SSL_ReHandshake or SSL_ResetHandshake
323
* is used to initiate a handshake.
325
* A typical scenario would be:
327
* 1. Server accepts an SSL connection from the client without client auth.
328
* 2. Client sends a request.
329
* 3. Server determines that to service request it needs to authenticate the
330
* client and initiates another handshake requesting client auth.
331
* 4. While handshake is in progress, server can do other work or spin waiting
332
* for the handshake to complete.
333
* 5. Server is notified that handshake has been successfully completed by
334
* the custom handshake callback function and it can service the client's
337
* Note: This function is not implemented in this sample, as we are using
341
myHandshakeCallback(PRFileDesc *socket, void *arg)
343
fprintf(stderr,"Handshake Complete: SERVER CONFIGURED CORRECTLY\n");
348
/**************************************************************************
350
** Routines for disabling SSL ciphers.
352
**************************************************************************/
355
disableAllSSLCiphers(void)
357
const PRUint16 *cipherSuites = SSL_ImplementedCiphers;
358
int i = SSL_NumImplementedCiphers;
361
/* disable all the SSL3 cipher suites */
363
PRUint16 suite = cipherSuites[i];
364
rv = SSL_CipherPrefSetDefault(suite, PR_FALSE);
365
if (rv != SECSuccess) {
367
"SSL_CipherPrefSetDefault didn't like value 0x%04x (i = %d)\n",
369
errWarn("SSL_CipherPrefSetDefault");
375
/**************************************************************************
377
** Error and information routines.
379
**************************************************************************/
382
errWarn(char *function)
384
PRErrorCode errorNumber = PR_GetError();
385
const char * errorString = SECU_Strerror(errorNumber);
387
fprintf(stderr, "Error in function %s: %d\n - %s\n",
388
function, errorNumber, errorString);
392
exitErr(char *function)
395
/* Exit gracefully. */
396
/* ignoring return value of NSS_Shutdown as code exits with 1 anyway*/
397
(void) NSS_Shutdown();
403
printSecurityInfo(FILE *outfile, PRFileDesc *fd)
405
char * cp; /* bulk cipher name */
406
char * ip; /* cert issuer DN */
407
char * sp; /* cert subject DN */
408
int op; /* High, Low, Off */
409
int kp0; /* total key bits */
410
int kp1; /* secret key bits */
412
SSL3Statistics * ssl3stats = SSL_GetStatistics();
418
result = SSL_SecurityStatus(fd, &op, &cp, &kp0, &kp1, &ip, &sp);
419
if (result != SECSuccess)
422
" bulk cipher %s, %d secret key bits, %d key bits, status: %d\n"
423
" subject DN:\n %s\n"
424
" issuer DN:\n %s\n", cp, kp1, kp0, op, sp, ip);
430
" %ld cache hits; %ld cache misses, %ld cache not reusable\n",
431
ssl3stats->hch_sid_cache_hits, ssl3stats->hch_sid_cache_misses,
432
ssl3stats->hch_sid_cache_not_ok);
437
/**************************************************************************
438
** Begin thread management routines and data.
439
**************************************************************************/
442
thread_wrapper(void * arg)
444
GlobalThreadMgr *threadMGR = (GlobalThreadMgr *)arg;
445
perThread *slot = &threadMGR->threads[threadMGR->index];
447
/* wait for parent to finish launching us before proceeding. */
448
PR_Lock(threadMGR->threadLock);
449
PR_Unlock(threadMGR->threadLock);
451
slot->rv = (* slot->startFunc)(slot->a, slot->b);
453
PR_Lock(threadMGR->threadLock);
454
slot->running = rs_zombie;
456
/* notify the thread exit handler. */
457
PR_NotifyCondVar(threadMGR->threadEndQ);
459
PR_Unlock(threadMGR->threadLock);
463
launch_thread(GlobalThreadMgr *threadMGR,
471
if (!threadMGR->threadStartQ) {
472
threadMGR->threadLock = PR_NewLock();
473
threadMGR->threadStartQ = PR_NewCondVar(threadMGR->threadLock);
474
threadMGR->threadEndQ = PR_NewCondVar(threadMGR->threadLock);
476
PR_Lock(threadMGR->threadLock);
477
while (threadMGR->numRunning >= MAX_THREADS) {
478
PR_WaitCondVar(threadMGR->threadStartQ, PR_INTERVAL_NO_TIMEOUT);
480
for (i = 0; i < threadMGR->numUsed; ++i) {
481
slot = &threadMGR->threads[i];
482
if (slot->running == rs_idle)
485
if (i >= threadMGR->numUsed) {
486
if (i >= MAX_THREADS) {
487
/* something's really wrong here. */
488
PORT_Assert(i < MAX_THREADS);
489
PR_Unlock(threadMGR->threadLock);
492
++(threadMGR->numUsed);
493
PORT_Assert(threadMGR->numUsed == i + 1);
494
slot = &threadMGR->threads[i];
499
slot->startFunc = startFunc;
501
threadMGR->index = i;
503
slot->prThread = PR_CreateThread(PR_USER_THREAD,
504
thread_wrapper, threadMGR,
505
PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
506
PR_JOINABLE_THREAD, 0);
508
if (slot->prThread == NULL) {
509
PR_Unlock(threadMGR->threadLock);
510
printf("Failed to launch thread!\n");
516
++(threadMGR->numRunning);
517
PR_Unlock(threadMGR->threadLock);
523
reap_threads(GlobalThreadMgr *threadMGR)
528
if (!threadMGR->threadLock)
530
PR_Lock(threadMGR->threadLock);
531
while (threadMGR->numRunning > 0) {
532
PR_WaitCondVar(threadMGR->threadEndQ, PR_INTERVAL_NO_TIMEOUT);
533
for (i = 0; i < threadMGR->numUsed; ++i) {
534
slot = &threadMGR->threads[i];
535
if (slot->running == rs_zombie) {
536
/* Handle cleanup of thread here. */
538
/* Now make sure the thread has ended OK. */
539
PR_JoinThread(slot->prThread);
540
slot->running = rs_idle;
541
--threadMGR->numRunning;
543
/* notify the thread launcher. */
544
PR_NotifyCondVar(threadMGR->threadStartQ);
549
/* Safety Sam sez: make sure count is right. */
550
for (i = 0; i < threadMGR->numUsed; ++i) {
551
slot = &threadMGR->threads[i];
552
if (slot->running != rs_idle) {
553
fprintf(stderr, "Thread in slot %d is in state %d!\n",
557
PR_Unlock(threadMGR->threadLock);
562
destroy_thread_data(GlobalThreadMgr *threadMGR)
564
PORT_Memset(threadMGR->threads, 0, sizeof(threadMGR->threads));
566
if (threadMGR->threadEndQ) {
567
PR_DestroyCondVar(threadMGR->threadEndQ);
568
threadMGR->threadEndQ = NULL;
570
if (threadMGR->threadStartQ) {
571
PR_DestroyCondVar(threadMGR->threadStartQ);
572
threadMGR->threadStartQ = NULL;
574
if (threadMGR->threadLock) {
575
PR_DestroyLock(threadMGR->threadLock);
576
threadMGR->threadLock = NULL;
580
/**************************************************************************
581
** End thread management routines.
582
**************************************************************************/
585
lockedVars_Init( lockedVars * lv)
589
lv->lock = PR_NewLock();
590
lv->condVar = PR_NewCondVar(lv->lock);
594
lockedVars_Destroy( lockedVars * lv)
596
PR_DestroyCondVar(lv->condVar);
599
PR_DestroyLock(lv->lock);
604
lockedVars_WaitForDone(lockedVars * lv)
607
while (lv->count > 0) {
608
PR_WaitCondVar(lv->condVar, PR_INTERVAL_NO_TIMEOUT);
613
int /* returns count */
614
lockedVars_AddToCount(lockedVars * lv, int addend)
619
rv = lv->count += addend;
621
PR_NotifyCondVar(lv->condVar);
629
* Dump cert chain in to cert.* files. This function is will
630
* create collisions while dumping cert chains if called from
631
* multiple treads. But it should not be a problem since we
632
* consider vfyserv to be single threaded(see bug 353477).
636
dumpCertChain(CERTCertificate *cert, SECCertUsage usage)
638
CERTCertificateList *certList;
641
certList = CERT_CertChainFromCert(cert, usage, PR_TRUE);
642
if (certList == NULL) {
643
errWarn("CERT_CertChainFromCert");
647
for(count = 0; count < (unsigned int)certList->len; count++) {
648
char certFileName[16];
651
PR_snprintf(certFileName, sizeof certFileName, "cert.%03d",
653
cfd = PR_Open(certFileName, PR_WRONLY|PR_CREATE_FILE|PR_TRUNCATE,
656
PR_fprintf(PR_STDOUT,
657
"Error: couldn't save cert der in file '%s'\n",
660
PR_Write(cfd, certList->certs[count].data, certList->certs[count].len);
662
PR_fprintf(PR_STDOUT, "Cert file %s was created.\n", certFileName);
665
CERT_DestroyCertificateList(certList);