strsclnt.c

来自「支持SSL v2/v3, TLS, PKCS #5, PKCS #7, PKCS」· C语言 代码 · 共 1,128 行 · 第 1/2 页

C
1,128
字号
/* * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ *  * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. *  * The Original Code is the Netscape security libraries. *  * The Initial Developer of the Original Code is Netscape * Communications Corporation.  Portions created by Netscape are  * Copyright (C) 1994-2000 Netscape Communications Corporation.  All * Rights Reserved. *  * Contributor(s): *  * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the * "GPL"), in which case the provisions of the GPL are applicable  * instead of those above.  If you wish to allow use of your  * version of this file only under the terms of the GPL and not to * allow others to use your version of this file under the MPL, * indicate your decision by deleting the provisions above and * replace them with the notice and other provisions required by * the GPL.  If you do not delete the provisions above, a recipient * may use your version of this file under either the MPL or the * GPL. */#include <stdio.h>#include <string.h>#include "secutil.h"#if defined(XP_UNIX)#include <unistd.h>#endif#include <stdlib.h>#include <errno.h>#include <fcntl.h>#include <stdarg.h>#include "plgetopt.h"#include "nspr.h"#include "prio.h"#include "prnetdb.h"#include "prerror.h"#include "pk11func.h"#include "secitem.h"#include "sslproto.h"#include "nss.h"#include "ssl.h"#ifndef PORT_Sprintf#define PORT_Sprintf sprintf#endif#ifndef PORT_Strstr#define PORT_Strstr strstr#endif#ifndef PORT_Malloc#define PORT_Malloc PR_Malloc#endif#define RD_BUF_SIZE (60 * 1024)/* Include these cipher suite arrays to re-use tstclnt's  * cipher selection code. */int ssl2CipherSuites[] = {    SSL_EN_RC4_128_WITH_MD5,                    /* A */    SSL_EN_RC4_128_EXPORT40_WITH_MD5,           /* B */    SSL_EN_RC2_128_CBC_WITH_MD5,                /* C */    SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5,       /* D */    SSL_EN_DES_64_CBC_WITH_MD5,                 /* E */    SSL_EN_DES_192_EDE3_CBC_WITH_MD5,           /* F */    0};int ssl3CipherSuites[] = {    SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA,     /* a */    SSL_FORTEZZA_DMS_WITH_RC4_128_SHA,          /* b */    SSL_RSA_WITH_RC4_128_MD5,                   /* c */    SSL_RSA_WITH_3DES_EDE_CBC_SHA,              /* d */    SSL_RSA_WITH_DES_CBC_SHA,                   /* e */    SSL_RSA_EXPORT_WITH_RC4_40_MD5,             /* f */    SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5,         /* g */    SSL_FORTEZZA_DMS_WITH_NULL_SHA,             /* h */    SSL_RSA_WITH_NULL_MD5,                      /* i */    SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA,         /* j */    SSL_RSA_FIPS_WITH_DES_CBC_SHA,              /* k */    TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA, 	/* l */    TLS_RSA_EXPORT1024_WITH_RC4_56_SHA,		/* m */    0};/* This global string is so that client main can see  * which ciphers to use.  */const char *cipherString;int certsTested;int MakeCertOK;voiddisableSSL2Ciphers(void){    int i;    /* disable all the SSL2 cipher suites */    for (i = 0; ssl2CipherSuites[i] != 0;  ++i) {	SECStatus rv;        rv = SSL_EnableCipher(ssl2CipherSuites[i], SSL_NOT_ALLOWED);	if (rv != SECSuccess) {	    fprintf(stderr, 		    "strsclnt: SSL_EnableCipher failed with value 0x%04x\n",		    ssl2CipherSuites[i]);	    exit(1);	}    }}voiddisableSSL3Ciphers(void){    int i;    /* disable all the SSL3 cipher suites */    for (i = 0; ssl3CipherSuites[i] != 0;  ++i) {	SECStatus rv;        rv = SSL_EnableCipher(ssl3CipherSuites[i], SSL_NOT_ALLOWED);	if (rv != SECSuccess) {	    fprintf(stderr, 		    "strsclnt: SSL_EnableCipher failed with value 0x%04x\n",		    ssl3CipherSuites[i]);	    exit(1);	}    }}char * ownPasswd( PK11SlotInfo *slot, PRBool retry, void *arg){        char *passwd = NULL;        if ( (!retry) && arg ) {                passwd = PL_strdup((char *)arg);        }        return passwd;}int	stopping;int	verbose;SECItem	bigBuf;#define PRINTF  if (verbose)  printf#define FPRINTF if (verbose) fprintfstatic voidUsage(const char *progName){    fprintf(stderr,     	"Usage: %s [-n rsa_nickname] [-p port] [-d dbdir] [-c connections]\n"	"          [-v] [-f fortezza_nickname] [-2 filename]\n"	"          [-w dbpasswd] [-C cipher(s)] hostname\n",	progName);    exit(1);}static voidnetworkStart(void){#if defined(XP_WIN) && !defined(NSPR20)    WORD wVersionRequested;      WSADATA wsaData;     int err;     wVersionRequested = MAKEWORD(1, 1);      err = WSAStartup(wVersionRequested, &wsaData);      if (err != 0) {	/* Tell the user that we couldn't find a useable winsock.dll. */ 	fputs("WSAStartup failed!\n", stderr);	exit(1);    }/* Confirm that the Windows Sockets DLL supports 1.1.*/ /* Note that if the DLL supports versions greater */ /* than 1.1 in addition to 1.1, it will still return */ /* 1.1 in wVersion since that is the version we */ /* requested. */      if ( LOBYTE( wsaData.wVersion ) != 1 ||          HIBYTE( wsaData.wVersion ) != 1 ) { 	/* Tell the user that we couldn't find a useable winsock.dll. */ 	fputs("wrong winsock version\n", stderr);	WSACleanup(); 	exit(1);     }     /* The Windows Sockets DLL is acceptable. Proceed. */ #endif}static voidnetworkEnd(void){#if defined(XP_WIN) && !defined(NSPR20)    WSACleanup();#endif}static voiderrWarn(char * funcString){    PRErrorCode  perr      = PR_GetError();    const char * errString = SECU_Strerror(perr);    fprintf(stderr, "strsclnt: %s returned error %d:\n%s\n",            funcString, perr, errString);}static voiderrExit(char * funcString){#if defined (XP_WIN) && !defined(NSPR20)    int          err;    LPVOID       lpMsgBuf;    err = WSAGetLastError();     FormatMessage(	FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,	NULL,	err,	MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language	(LPTSTR) &lpMsgBuf,	0,	NULL     );    /* Display the string. */  /*MessageBox( NULL, lpMsgBuf, "GetLastError", MB_OK|MB_ICONINFORMATION ); */    fprintf(stderr, "%s\n", lpMsgBuf);    /* Free the buffer. */    LocalFree( lpMsgBuf );#endif    errWarn(funcString);    exit(1);}/* This invokes the "default" AuthCert handler in libssl.** The only reason to use this one is that it prints out info as it goes. */static intmySSLAuthCertificate(void *arg, PRFileDesc *fd, PRBool checkSig,		     PRBool isServer){    SECStatus rv;    CERTCertificate *    peerCert;    peerCert = SSL_PeerCertificate(fd);    PRINTF("strsclnt: Subject: %s\nstrsclnt: Issuer : %s\n",            peerCert->subjectName, peerCert->issuerName);     /* invoke the "default" AuthCert handler. */    rv = SSL_AuthCertificate(arg, fd, checkSig, isServer);    ++certsTested;    if (rv == SECSuccess) {	fputs("strsclnt: -- SSL: Server Certificate Validated.\n", stderr);    }     /* error, if any, will be displayed by the Bad Cert Handler. */    return rv;  }static int /* should be SECStatus but public prototype says int. */myBadCertHandler( void *arg, PRFileDesc *fd){    int err = PR_GetError();    fprintf(stderr, 	    "strsclnt: -- SSL: Server Certificate Invalid, err %d.\n%s\n",             err, SECU_Strerror(err));    return (MakeCertOK ? SECSuccess : SECFailure);}/* statistics from ssl3_SendClientHello (sch) */extern long ssl3_sch_sid_cache_hits;extern long ssl3_sch_sid_cache_misses;extern long ssl3_sch_sid_cache_not_ok;/* statistics from ssl3_HandleServerHello (hsh) */extern long ssl3_hsh_sid_cache_hits;extern long ssl3_hsh_sid_cache_misses;extern long ssl3_hsh_sid_cache_not_ok;/* statistics from ssl3_HandleClientHello (hch) */extern long ssl3_hch_sid_cache_hits;extern long ssl3_hch_sid_cache_misses;extern long ssl3_hch_sid_cache_not_ok;void printSecurityInfo(PRFileDesc *fd){    char * cp;	/* bulk cipher name */    char * ip;	/* cert issuer DN */    char * sp;	/* cert subject DN */    int    op;	/* High, Low, Off */    int    kp0;	/* total key bits */    int    kp1;	/* secret key bits */    int    result;    static int only_once;    if (! only_once++ && fd) {	result = SSL_SecurityStatus(fd, &op, &cp, &kp0, &kp1, &ip, &sp);	if (result != SECSuccess)	    return;	PRINTF(	"strsclnt: cipher %s, %d secret key bits, %d key bits, status: %d\n",	       cp, kp1, kp0, op);	PR_Free(cp);	PR_Free(ip);	PR_Free(sp);    }    PRINTF(    "strsclnt: %ld cache hits; %ld cache misses, %ld cache not reusable\n",    	ssl3_hsh_sid_cache_hits, 	ssl3_hsh_sid_cache_misses,	ssl3_hsh_sid_cache_not_ok);}/**************************************************************************** Begin thread management routines and data.**************************************************************************/#define MAX_THREADS 32typedef int startFn(void *a, void *b, int c);PRLock    * threadLock;PRCondVar * threadStartQ;PRCondVar * threadEndQ;int         numUsed;int         numRunning;typedef enum { rs_idle = 0, rs_running = 1, rs_zombie = 2 } runState;typedef struct perThreadStr {    void *	a;    void *	b;    int         c;    int         rv;    startFn  *  startFunc;    PRThread *  prThread;    PRBool	inUse;    runState	running;} perThread;perThread threads[MAX_THREADS];voidthread_wrapper(void * arg){    perThread * slot = (perThread *)arg;    /* wait for parent to finish launching us before proceeding. */    PR_Lock(threadLock);    PR_Unlock(threadLock);    slot->rv = (* slot->startFunc)(slot->a, slot->b, slot->c);    /* Handle cleanup of thread here. */    PRINTF("strsclnt: Thread in slot %d returned %d\n", 	   slot - threads, slot->rv);    PR_Lock(threadLock);    slot->running = rs_idle;    --numRunning;    /* notify the thread launcher. */    PR_NotifyCondVar(threadStartQ);    PR_Unlock(threadLock);}SECStatuslaunch_thread(    startFn *	startFunc,    void *	a,    void *	b,    int         c){    perThread * slot;    int         i;    if (!threadStartQ) {	threadLock = PR_NewLock();	threadStartQ = PR_NewCondVar(threadLock);	threadEndQ   = PR_NewCondVar(threadLock);    }    PR_Lock(threadLock);    while (numRunning >= MAX_THREADS) {    	PR_WaitCondVar(threadStartQ, PR_INTERVAL_NO_TIMEOUT);    }    for (i = 0; i < numUsed; ++i) {	slot = threads + i;    	if (slot->running == rs_idle) 	    break;    }    if (i >= numUsed) {	if (i >= MAX_THREADS) {	    /* something's really wrong here. */	    PORT_Assert(i < MAX_THREADS);	    PR_Unlock(threadLock);	    return SECFailure;	}	++numUsed;	PORT_Assert(numUsed == i + 1);	slot = threads + i;    }    slot->a = a;    slot->b = b;    slot->c = c;    slot->startFunc = startFunc;    slot->prThread      = PR_CreateThread(PR_USER_THREAD,                                      thread_wrapper, slot,				      PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,				      PR_UNJOINABLE_THREAD, 0);    if (slot->prThread == NULL) {	PR_Unlock(threadLock);	printf("strsclnt: Failed to launch thread!\n");	return SECFailure;    }     slot->inUse   = 1;    slot->running = 1;    ++numRunning;    PR_Unlock(threadLock);    PRINTF("strsclnt: Launched thread in slot %d \n", i);    return SECSuccess;}/* Wait until num_running == 0 */int reap_threads(void){    perThread * slot;    int         i;    if (!threadLock)    	return 0;    PR_Lock(threadLock);    while (numRunning > 0) {    	PR_WaitCondVar(threadStartQ, PR_INTERVAL_NO_TIMEOUT);    }    /* Safety Sam sez: make sure count is right. */    for (i = 0; i < numUsed; ++i) {	slot = threads + i;    	if (slot->running != rs_idle)  {	    FPRINTF(stderr, "strsclnt: Thread in slot %d is in state %d!\n", 	            i, slot->running);    	}    }    PR_Unlock(threadLock);    return 0;}voiddestroy_thread_data(void){    PORT_Memset(threads, 0, sizeof threads);    if (threadEndQ) {    	PR_DestroyCondVar(threadEndQ);	threadEndQ = NULL;    }    if (threadStartQ) {    	PR_DestroyCondVar(threadStartQ);	threadStartQ = NULL;    }    if (threadLock) {    	PR_DestroyLock(threadLock);	threadLock = NULL;    }}/**************************************************************************** End   thread management routines.**************************************************************************/PRBool useModelSocket = PR_TRUE;static const char stopCmd[] = { "GET /stop " };static const char outHeader[] = {    "HTTP/1.0 200 OK\r\n"    "Server: Netscape-Enterprise/2.0a\r\n"    "Date: Tue, 26 Aug 1997 22:10:05 GMT\r\n"    "Content-type: text/plain\r\n"    "\r\n"};struct lockedVarsStr {    PRLock *	lock;    int		count;    int		waiters;    PRCondVar *	condVar;};typedef struct lockedVarsStr lockedVars;void lockedVars_Init( lockedVars * lv){    lv->count   = 0;    lv->waiters = 0;    lv->lock    = PR_NewLock();    lv->condVar = PR_NewCondVar(lv->lock);}voidlockedVars_Destroy( lockedVars * lv){    PR_DestroyCondVar(lv->condVar);    lv->condVar = NULL;    PR_DestroyLock(lv->lock);    lv->lock = NULL;}voidlockedVars_WaitForDone(lockedVars * lv){    PR_Lock(lv->lock);    while (lv->count > 0) {    	PR_WaitCondVar(lv->condVar, PR_INTERVAL_NO_TIMEOUT);    }    PR_Unlock(lv->lock);}int	/* returns count */lockedVars_AddToCount(lockedVars * lv, int addend){    int rv;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?