security/nss/cmd/vfyserv/vfyutil.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

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 }

mercurial