Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include "vfyserv.h"
6 #include "secerr.h"
7 #include "sslerr.h"
8 #include "nspr.h"
9 #include "secutil.h"
12 extern PRBool dumpChain;
13 extern void dumpCertChain(CERTCertificate *, SECCertUsage);
15 /* Declare SSL cipher suites. */
17 int ssl2CipherSuites[] = {
18 SSL_EN_RC4_128_WITH_MD5, /* A */
19 SSL_EN_RC4_128_EXPORT40_WITH_MD5, /* B */
20 SSL_EN_RC2_128_CBC_WITH_MD5, /* C */
21 SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5, /* D */
22 SSL_EN_DES_64_CBC_WITH_MD5, /* E */
23 SSL_EN_DES_192_EDE3_CBC_WITH_MD5, /* F */
24 0
25 };
27 int ssl3CipherSuites[] = {
28 -1, /* SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA* a */
29 -1, /* SSL_FORTEZZA_DMS_WITH_RC4_128_SHA, * b */
30 TLS_RSA_WITH_RC4_128_MD5, /* c */
31 TLS_RSA_WITH_3DES_EDE_CBC_SHA, /* d */
32 TLS_RSA_WITH_DES_CBC_SHA, /* e */
33 TLS_RSA_EXPORT_WITH_RC4_40_MD5, /* f */
34 TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5, /* g */
35 -1, /* SSL_FORTEZZA_DMS_WITH_NULL_SHA, * h */
36 TLS_RSA_WITH_NULL_MD5, /* i */
37 SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA, /* j */
38 SSL_RSA_FIPS_WITH_DES_CBC_SHA, /* k */
39 TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA, /* l */
40 TLS_RSA_EXPORT1024_WITH_RC4_56_SHA, /* m */
41 TLS_RSA_WITH_RC4_128_SHA, /* n */
42 TLS_DHE_DSS_WITH_RC4_128_SHA, /* o */
43 TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, /* p */
44 TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA, /* q */
45 TLS_DHE_RSA_WITH_DES_CBC_SHA, /* r */
46 TLS_DHE_DSS_WITH_DES_CBC_SHA, /* s */
47 TLS_DHE_DSS_WITH_AES_128_CBC_SHA, /* t */
48 TLS_DHE_RSA_WITH_AES_128_CBC_SHA, /* u */
49 TLS_RSA_WITH_AES_128_CBC_SHA, /* v */
50 TLS_DHE_DSS_WITH_AES_256_CBC_SHA, /* w */
51 TLS_DHE_RSA_WITH_AES_256_CBC_SHA, /* x */
52 TLS_RSA_WITH_AES_256_CBC_SHA, /* y */
53 TLS_RSA_WITH_NULL_SHA, /* z */
54 0
55 };
57 /**************************************************************************
58 **
59 ** SSL callback routines.
60 **
61 **************************************************************************/
63 /* Function: char * myPasswd()
64 *
65 * Purpose: This function is our custom password handler that is called by
66 * SSL when retreiving private certs and keys from the database. Returns a
67 * pointer to a string that with a password for the database. Password pointer
68 * should point to dynamically allocated memory that will be freed later.
69 */
70 char *
71 myPasswd(PK11SlotInfo *info, PRBool retry, void *arg)
72 {
73 char * passwd = NULL;
75 if ( (!retry) && arg ) {
76 passwd = PORT_Strdup((char *)arg);
77 }
78 return passwd;
79 }
81 /* Function: SECStatus myAuthCertificate()
82 *
83 * Purpose: This function is our custom certificate authentication handler.
84 *
85 * Note: This implementation is essentially the same as the default
86 * SSL_AuthCertificate().
87 */
88 SECStatus
89 myAuthCertificate(void *arg, PRFileDesc *socket,
90 PRBool checksig, PRBool isServer)
91 {
93 SECCertificateUsage certUsage;
94 CERTCertificate * cert;
95 void * pinArg;
96 char * hostName;
97 SECStatus secStatus;
99 if (!arg || !socket) {
100 errWarn("myAuthCertificate");
101 return SECFailure;
102 }
104 /* Define how the cert is being used based upon the isServer flag. */
106 certUsage = isServer ? certificateUsageSSLClient : certificateUsageSSLServer;
108 cert = SSL_PeerCertificate(socket);
110 pinArg = SSL_RevealPinArg(socket);
112 if (dumpChain == PR_TRUE) {
113 dumpCertChain(cert, certUsage);
114 }
116 secStatus = CERT_VerifyCertificateNow((CERTCertDBHandle *)arg,
117 cert,
118 checksig,
119 certUsage,
120 pinArg,
121 NULL);
123 /* If this is a server, we're finished. */
124 if (isServer || secStatus != SECSuccess) {
125 SECU_printCertProblems(stderr, (CERTCertDBHandle *)arg, cert,
126 checksig, certUsage, pinArg, PR_FALSE);
127 CERT_DestroyCertificate(cert);
128 return secStatus;
129 }
131 /* Certificate is OK. Since this is the client side of an SSL
132 * connection, we need to verify that the name field in the cert
133 * matches the desired hostname. This is our defense against
134 * man-in-the-middle attacks.
135 */
137 /* SSL_RevealURL returns a hostName, not an URL. */
138 hostName = SSL_RevealURL(socket);
140 if (hostName && hostName[0]) {
141 secStatus = CERT_VerifyCertName(cert, hostName);
142 } else {
143 PR_SetError(SSL_ERROR_BAD_CERT_DOMAIN, 0);
144 secStatus = SECFailure;
145 }
147 if (hostName)
148 PR_Free(hostName);
150 CERT_DestroyCertificate(cert);
151 return secStatus;
152 }
154 /* Function: SECStatus myBadCertHandler()
155 *
156 * Purpose: This callback is called when the incoming certificate is not
157 * valid. We define a certain set of parameters that still cause the
158 * certificate to be "valid" for this session, and return SECSuccess to cause
159 * the server to continue processing the request when any of these conditions
160 * are met. Otherwise, SECFailure is return and the server rejects the
161 * request.
162 */
163 SECStatus
164 myBadCertHandler(void *arg, PRFileDesc *socket)
165 {
167 SECStatus secStatus = SECFailure;
168 PRErrorCode err;
170 /* log invalid cert here */
172 if (!arg) {
173 return secStatus;
174 }
176 *(PRErrorCode *)arg = err = PORT_GetError();
178 /* If any of the cases in the switch are met, then we will proceed */
179 /* with the processing of the request anyway. Otherwise, the default */
180 /* case will be reached and we will reject the request. */
182 switch (err) {
183 case SEC_ERROR_INVALID_AVA:
184 case SEC_ERROR_INVALID_TIME:
185 case SEC_ERROR_BAD_SIGNATURE:
186 case SEC_ERROR_EXPIRED_CERTIFICATE:
187 case SEC_ERROR_UNKNOWN_ISSUER:
188 case SEC_ERROR_UNTRUSTED_CERT:
189 case SEC_ERROR_CERT_VALID:
190 case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
191 case SEC_ERROR_CRL_EXPIRED:
192 case SEC_ERROR_CRL_BAD_SIGNATURE:
193 case SEC_ERROR_EXTENSION_VALUE_INVALID:
194 case SEC_ERROR_CA_CERT_INVALID:
195 case SEC_ERROR_CERT_USAGES_INVALID:
196 case SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION:
197 secStatus = SECSuccess;
198 break;
199 default:
200 secStatus = SECFailure;
201 break;
202 }
204 fprintf(stderr, "Bad certificate: %d, %s\n", err, SECU_Strerror(err));
206 return secStatus;
207 }
209 /* Function: SECStatus ownGetClientAuthData()
210 *
211 * Purpose: This callback is used by SSL to pull client certificate
212 * information upon server request.
213 */
214 SECStatus
215 myGetClientAuthData(void *arg,
216 PRFileDesc *socket,
217 struct CERTDistNamesStr *caNames,
218 struct CERTCertificateStr **pRetCert,
219 struct SECKEYPrivateKeyStr **pRetKey)
220 {
222 CERTCertificate * cert;
223 SECKEYPrivateKey * privKey;
224 char * chosenNickName = (char *)arg;
225 void * proto_win = NULL;
226 SECStatus secStatus = SECFailure;
228 proto_win = SSL_RevealPinArg(socket);
230 if (chosenNickName) {
231 cert = PK11_FindCertFromNickname(chosenNickName, proto_win);
232 if (cert) {
233 privKey = PK11_FindKeyByAnyCert(cert, proto_win);
234 if (privKey) {
235 secStatus = SECSuccess;
236 } else {
237 CERT_DestroyCertificate(cert);
238 }
239 }
240 } else { /* no nickname given, automatically find the right cert */
241 CERTCertNicknames *names;
242 int i;
244 names = CERT_GetCertNicknames(CERT_GetDefaultCertDB(),
245 SEC_CERT_NICKNAMES_USER, proto_win);
247 if (names != NULL) {
248 for(i = 0; i < names->numnicknames; i++ ) {
250 cert = PK11_FindCertFromNickname(names->nicknames[i],
251 proto_win);
252 if (!cert) {
253 continue;
254 }
256 /* Only check unexpired certs */
257 if (CERT_CheckCertValidTimes(cert, PR_Now(), PR_FALSE)
258 != secCertTimeValid ) {
259 CERT_DestroyCertificate(cert);
260 continue;
261 }
263 secStatus = NSS_CmpCertChainWCANames(cert, caNames);
264 if (secStatus == SECSuccess) {
265 privKey = PK11_FindKeyByAnyCert(cert, proto_win);
266 if (privKey) {
267 break;
268 }
269 secStatus = SECFailure;
270 }
271 CERT_DestroyCertificate(cert);
272 } /* for loop */
273 CERT_FreeNicknames(names);
274 }
275 }
277 if (secStatus == SECSuccess) {
278 *pRetCert = cert;
279 *pRetKey = privKey;
280 }
282 return secStatus;
283 }
285 /* Function: void myHandshakeCallback()
286 *
287 * Purpose: Called by SSL to inform application that the handshake is
288 * complete. This function is mostly used on the server side of an SSL
289 * connection, although it is provided for a client as well.
290 * Useful when a non-blocking SSL_ReHandshake or SSL_ResetHandshake
291 * is used to initiate a handshake.
292 *
293 * A typical scenario would be:
294 *
295 * 1. Server accepts an SSL connection from the client without client auth.
296 * 2. Client sends a request.
297 * 3. Server determines that to service request it needs to authenticate the
298 * client and initiates another handshake requesting client auth.
299 * 4. While handshake is in progress, server can do other work or spin waiting
300 * for the handshake to complete.
301 * 5. Server is notified that handshake has been successfully completed by
302 * the custom handshake callback function and it can service the client's
303 * request.
304 *
305 * Note: This function is not implemented in this sample, as we are using
306 * blocking sockets.
307 */
308 void
309 myHandshakeCallback(PRFileDesc *socket, void *arg)
310 {
311 fprintf(stderr,"Handshake Complete: SERVER CONFIGURED CORRECTLY\n");
312 }
315 /**************************************************************************
316 **
317 ** Routines for disabling SSL ciphers.
318 **
319 **************************************************************************/
321 void
322 disableAllSSLCiphers(void)
323 {
324 const PRUint16 *cipherSuites = SSL_ImplementedCiphers;
325 int i = SSL_NumImplementedCiphers;
326 SECStatus rv;
328 /* disable all the SSL3 cipher suites */
329 while (--i >= 0) {
330 PRUint16 suite = cipherSuites[i];
331 rv = SSL_CipherPrefSetDefault(suite, PR_FALSE);
332 if (rv != SECSuccess) {
333 fprintf(stderr,
334 "SSL_CipherPrefSetDefault didn't like value 0x%04x (i = %d)\n",
335 suite, i);
336 errWarn("SSL_CipherPrefSetDefault");
337 exit(2);
338 }
339 }
340 }
342 /**************************************************************************
343 **
344 ** Error and information routines.
345 **
346 **************************************************************************/
348 void
349 errWarn(char *function)
350 {
351 PRErrorCode errorNumber = PR_GetError();
352 const char * errorString = SECU_Strerror(errorNumber);
354 fprintf(stderr, "Error in function %s: %d\n - %s\n",
355 function, errorNumber, errorString);
356 }
358 void
359 exitErr(char *function)
360 {
361 errWarn(function);
362 /* Exit gracefully. */
363 /* ignoring return value of NSS_Shutdown as code exits with 1 anyway*/
364 (void) NSS_Shutdown();
365 PR_Cleanup();
366 exit(1);
367 }
369 void
370 printSecurityInfo(FILE *outfile, PRFileDesc *fd)
371 {
372 char * cp; /* bulk cipher name */
373 char * ip; /* cert issuer DN */
374 char * sp; /* cert subject DN */
375 int op; /* High, Low, Off */
376 int kp0; /* total key bits */
377 int kp1; /* secret key bits */
378 int result;
379 SSL3Statistics * ssl3stats = SSL_GetStatistics();
381 if (!outfile) {
382 outfile = stdout;
383 }
385 result = SSL_SecurityStatus(fd, &op, &cp, &kp0, &kp1, &ip, &sp);
386 if (result != SECSuccess)
387 return;
388 fprintf(outfile,
389 " bulk cipher %s, %d secret key bits, %d key bits, status: %d\n"
390 " subject DN:\n %s\n"
391 " issuer DN:\n %s\n", cp, kp1, kp0, op, sp, ip);
392 PR_Free(cp);
393 PR_Free(ip);
394 PR_Free(sp);
396 fprintf(outfile,
397 " %ld cache hits; %ld cache misses, %ld cache not reusable\n",
398 ssl3stats->hch_sid_cache_hits, ssl3stats->hch_sid_cache_misses,
399 ssl3stats->hch_sid_cache_not_ok);
401 }
404 /**************************************************************************
405 ** Begin thread management routines and data.
406 **************************************************************************/
408 void
409 thread_wrapper(void * arg)
410 {
411 GlobalThreadMgr *threadMGR = (GlobalThreadMgr *)arg;
412 perThread *slot = &threadMGR->threads[threadMGR->index];
414 /* wait for parent to finish launching us before proceeding. */
415 PR_Lock(threadMGR->threadLock);
416 PR_Unlock(threadMGR->threadLock);
418 slot->rv = (* slot->startFunc)(slot->a, slot->b);
420 PR_Lock(threadMGR->threadLock);
421 slot->running = rs_zombie;
423 /* notify the thread exit handler. */
424 PR_NotifyCondVar(threadMGR->threadEndQ);
426 PR_Unlock(threadMGR->threadLock);
427 }
429 SECStatus
430 launch_thread(GlobalThreadMgr *threadMGR,
431 startFn *startFunc,
432 void *a,
433 int b)
434 {
435 perThread *slot;
436 int i;
438 if (!threadMGR->threadStartQ) {
439 threadMGR->threadLock = PR_NewLock();
440 threadMGR->threadStartQ = PR_NewCondVar(threadMGR->threadLock);
441 threadMGR->threadEndQ = PR_NewCondVar(threadMGR->threadLock);
442 }
443 PR_Lock(threadMGR->threadLock);
444 while (threadMGR->numRunning >= MAX_THREADS) {
445 PR_WaitCondVar(threadMGR->threadStartQ, PR_INTERVAL_NO_TIMEOUT);
446 }
447 for (i = 0; i < threadMGR->numUsed; ++i) {
448 slot = &threadMGR->threads[i];
449 if (slot->running == rs_idle)
450 break;
451 }
452 if (i >= threadMGR->numUsed) {
453 if (i >= MAX_THREADS) {
454 /* something's really wrong here. */
455 PORT_Assert(i < MAX_THREADS);
456 PR_Unlock(threadMGR->threadLock);
457 return SECFailure;
458 }
459 ++(threadMGR->numUsed);
460 PORT_Assert(threadMGR->numUsed == i + 1);
461 slot = &threadMGR->threads[i];
462 }
464 slot->a = a;
465 slot->b = b;
466 slot->startFunc = startFunc;
468 threadMGR->index = i;
470 slot->prThread = PR_CreateThread(PR_USER_THREAD,
471 thread_wrapper, threadMGR,
472 PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
473 PR_JOINABLE_THREAD, 0);
475 if (slot->prThread == NULL) {
476 PR_Unlock(threadMGR->threadLock);
477 printf("Failed to launch thread!\n");
478 return SECFailure;
479 }
481 slot->inUse = 1;
482 slot->running = 1;
483 ++(threadMGR->numRunning);
484 PR_Unlock(threadMGR->threadLock);
486 return SECSuccess;
487 }
489 SECStatus
490 reap_threads(GlobalThreadMgr *threadMGR)
491 {
492 perThread * slot;
493 int i;
495 if (!threadMGR->threadLock)
496 return SECSuccess;
497 PR_Lock(threadMGR->threadLock);
498 while (threadMGR->numRunning > 0) {
499 PR_WaitCondVar(threadMGR->threadEndQ, PR_INTERVAL_NO_TIMEOUT);
500 for (i = 0; i < threadMGR->numUsed; ++i) {
501 slot = &threadMGR->threads[i];
502 if (slot->running == rs_zombie) {
503 /* Handle cleanup of thread here. */
505 /* Now make sure the thread has ended OK. */
506 PR_JoinThread(slot->prThread);
507 slot->running = rs_idle;
508 --threadMGR->numRunning;
510 /* notify the thread launcher. */
511 PR_NotifyCondVar(threadMGR->threadStartQ);
512 }
513 }
514 }
516 /* Safety Sam sez: make sure count is right. */
517 for (i = 0; i < threadMGR->numUsed; ++i) {
518 slot = &threadMGR->threads[i];
519 if (slot->running != rs_idle) {
520 fprintf(stderr, "Thread in slot %d is in state %d!\n",
521 i, slot->running);
522 }
523 }
524 PR_Unlock(threadMGR->threadLock);
525 return SECSuccess;
526 }
528 void
529 destroy_thread_data(GlobalThreadMgr *threadMGR)
530 {
531 PORT_Memset(threadMGR->threads, 0, sizeof(threadMGR->threads));
533 if (threadMGR->threadEndQ) {
534 PR_DestroyCondVar(threadMGR->threadEndQ);
535 threadMGR->threadEndQ = NULL;
536 }
537 if (threadMGR->threadStartQ) {
538 PR_DestroyCondVar(threadMGR->threadStartQ);
539 threadMGR->threadStartQ = NULL;
540 }
541 if (threadMGR->threadLock) {
542 PR_DestroyLock(threadMGR->threadLock);
543 threadMGR->threadLock = NULL;
544 }
545 }
547 /**************************************************************************
548 ** End thread management routines.
549 **************************************************************************/
551 void
552 lockedVars_Init( lockedVars * lv)
553 {
554 lv->count = 0;
555 lv->waiters = 0;
556 lv->lock = PR_NewLock();
557 lv->condVar = PR_NewCondVar(lv->lock);
558 }
560 void
561 lockedVars_Destroy( lockedVars * lv)
562 {
563 PR_DestroyCondVar(lv->condVar);
564 lv->condVar = NULL;
566 PR_DestroyLock(lv->lock);
567 lv->lock = NULL;
568 }
570 void
571 lockedVars_WaitForDone(lockedVars * lv)
572 {
573 PR_Lock(lv->lock);
574 while (lv->count > 0) {
575 PR_WaitCondVar(lv->condVar, PR_INTERVAL_NO_TIMEOUT);
576 }
577 PR_Unlock(lv->lock);
578 }
580 int /* returns count */
581 lockedVars_AddToCount(lockedVars * lv, int addend)
582 {
583 int rv;
585 PR_Lock(lv->lock);
586 rv = lv->count += addend;
587 if (rv <= 0) {
588 PR_NotifyCondVar(lv->condVar);
589 }
590 PR_Unlock(lv->lock);
591 return rv;
592 }
595 /*
596 * Dump cert chain in to cert.* files. This function is will
597 * create collisions while dumping cert chains if called from
598 * multiple treads. But it should not be a problem since we
599 * consider vfyserv to be single threaded(see bug 353477).
600 */
602 void
603 dumpCertChain(CERTCertificate *cert, SECCertUsage usage)
604 {
605 CERTCertificateList *certList;
606 int count = 0;
608 certList = CERT_CertChainFromCert(cert, usage, PR_TRUE);
609 if (certList == NULL) {
610 errWarn("CERT_CertChainFromCert");
611 return;
612 }
614 for(count = 0; count < (unsigned int)certList->len; count++) {
615 char certFileName[16];
616 PRFileDesc *cfd;
618 PR_snprintf(certFileName, sizeof certFileName, "cert.%03d",
619 count);
620 cfd = PR_Open(certFileName, PR_WRONLY|PR_CREATE_FILE|PR_TRUNCATE,
621 0664);
622 if (!cfd) {
623 PR_fprintf(PR_STDOUT,
624 "Error: couldn't save cert der in file '%s'\n",
625 certFileName);
626 } else {
627 PR_Write(cfd, certList->certs[count].data, certList->certs[count].len);
628 PR_Close(cfd);
629 PR_fprintf(PR_STDOUT, "Cert file %s was created.\n", certFileName);
630 }
631 }
632 CERT_DestroyCertificateList(certList);
633 }