From 621d9e5c413e561293d7484b93882d985b3fe15f Mon Sep 17 00:00:00 2001 From: Endi Sukma Dewata Date: Sat, 24 Mar 2012 02:27:47 -0500 Subject: Removed unnecessary pki folder. Previously the source code was located inside a pki folder. This folder was created during svn migration and is no longer needed. This folder has now been removed and the contents have been moved up one level. Ticket #131 --- base/native-tools/src/sslget/CMakeLists.txt | 30 + base/native-tools/src/sslget/getopt.c | 126 +++++ base/native-tools/src/sslget/sslget.c | 836 ++++++++++++++++++++++++++++ 3 files changed, 992 insertions(+) create mode 100644 base/native-tools/src/sslget/CMakeLists.txt create mode 100644 base/native-tools/src/sslget/getopt.c create mode 100644 base/native-tools/src/sslget/sslget.c (limited to 'base/native-tools/src/sslget') diff --git a/base/native-tools/src/sslget/CMakeLists.txt b/base/native-tools/src/sslget/CMakeLists.txt new file mode 100644 index 000000000..ec4bd85f9 --- /dev/null +++ b/base/native-tools/src/sslget/CMakeLists.txt @@ -0,0 +1,30 @@ +project(sslget C) + +set(SSLGET_PRIVATE_INCLUDE_DIRS + ${CMAKE_BINARY_DIR} + ${NSPR_INCLUDE_DIRS} + ${NSS_INCLUDE_DIRS} +) + +set(SSLGET_LINK_LIBRARIES + ${NSPR_LIBRARIES} + ${NSS_LIBRARIES} +) + +set(sslget_SRCS + sslget.c + getopt.c +) + +include_directories(${SSLGET_PRIVATE_INCLUDE_DIRS}) + +add_executable(sslget ${sslget_SRCS}) + +target_link_libraries(sslget ${SSLGET_LINK_LIBRARIES}) + +install( + TARGETS sslget + RUNTIME DESTINATION ${BIN_INSTALL_DIR} + LIBRARY DESTINATION ${LIB_INSTALL_DIR} + ARCHIVE DESTINATION ${LIB_INSTALL_DIR} +) diff --git a/base/native-tools/src/sslget/getopt.c b/base/native-tools/src/sslget/getopt.c new file mode 100644 index 000000000..7554e1a14 --- /dev/null +++ b/base/native-tools/src/sslget/getopt.c @@ -0,0 +1,126 @@ +/** BEGIN COPYRIGHT BLOCK + * + * 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. + * + * END COPYRIGHT BLOCK **/ +#ifdef XP_PC + +/* +** This comes from the AT&T public-domain getopt published in mod.sources +** (i.e., comp.sources.unix before the great Usenet renaming). +*/ + +#include +#include /* for str*() */ +#include /* for write() */ + +int opterr = 1; /* boolean flag, says "report error on stderr." */ +int optind = 1; /* index to element of argv from which options are + ** being parsed. */ +int optopt = 0; /* option character */ +char *optarg; /* ptr to option's parameter arg. */ + +#ifdef _WIN32 +static void +do_opterr(const char *s, int c, char * const av[]) +{ + if (opterr) { + char buff[2]; + int fd = _fileno(stderr); + + buff[0] = (char)c; + buff[1] = '\n'; + (void)write(fd, av[0], strlen(av[0])); + (void)write(fd, s, strlen(s)); + (void)write(fd, buff, 2); + } +} +#define ERR(s, c) do_opterr(s, c, av) +#else +#define ERR(s, c) /* Win16 doesn't do stderr */ +#endif + +/* +** Return options and their values from the command line. +*/ +int +getopt(int ac, char * const av[], const char * opts) +{ + static int i = 1; /* offset of current option char in current arg. */ + char *p; /* opt char in opts that matched. */ + + /* Move to next value from argv? */ + if (i == 1) { + if (optind >= ac || av[optind][0] != '-' || av[optind][1] == '\0') + return EOF; + if (strcmp(av[optind], "--") == 0) { + optind++; + return EOF; + } + } + + /* Get next option character. */ + if ((optopt = av[optind][i]) == ':' || + (p = strchr(opts, optopt)) == NULL) { + ERR(": illegal option -- ", optopt); + if (av[optind][++i] == '\0') { + optind++; + i = 1; + } + return '?'; + } + + /* Snarf argument? */ + if (*++p == ':') { + if (av[optind][i + 1] != '\0') + optarg = &av[optind++][i + 1]; + else { + if (++optind >= ac) { + ERR(": option requires an argument -- ", optopt); + i = 1; + return '?'; + } + optarg = av[optind++]; + } + i = 1; + } else { + if (av[optind][++i] == '\0') { + i = 1; + optind++; + } + optarg = NULL; + } + + return optopt; +} + +#endif /* XP_PC */ diff --git a/base/native-tools/src/sslget/sslget.c b/base/native-tools/src/sslget/sslget.c new file mode 100644 index 000000000..7288a1c58 --- /dev/null +++ b/base/native-tools/src/sslget/sslget.c @@ -0,0 +1,836 @@ +/* --- BEGIN COPYRIGHT BLOCK --- + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2007 Red Hat, Inc. + * All rights reserved. + * --- END COPYRIGHT BLOCK --- + */ + +/* vi: set ts=4 sw=4 : */ +#ifdef HAVE_CONFIG_H +#ifndef AUTOTOOLS_CONFIG_H +#define AUTOTOOLS_CONFIG_H + +/* Eliminate warnings when using Autotools */ +#undef PACKAGE_BUGREPORT +#undef PACKAGE_NAME +#undef PACKAGE_STRING +#undef PACKAGE_TARNAME +#undef PACKAGE_VERSION + +#include +#endif /* AUTOTOOLS_CONFIG_H */ +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +#if defined(XP_UNIX) +#include +#endif + +#include "ssl.h" + +#include "prerror.h" + +#include "pk11func.h" +#include "secitem.h" + + +#include +#include +#include +#include + +#include "nspr.h" +#include "prio.h" +#include "prnetdb.h" +#include "nss.h" + + +/* set Tabs to 8 */ + + +/*from nss2.8.4 secopt.h*/ +#ifdef XP_PC + +/* +** This comes from the AT&T public-domain getopt published in mod.sources +** (i.e., comp.sources.unix before the great Usenet renaming). +*/ + +extern int opterr; +extern int optind; +extern int optopt; +extern char *optarg; + +#ifdef _WIN32 +static void do_opterr(const char *s, int c, char * const av[]); +#define ERR(s, c) do_opterr(s, c, av) +#else +#define ERR(s, c) /* Win16 doesn't do stderr */ +#endif + +/* +** Return options and their values from the command line. +*/ +int getopt(int ac, char * const av[], const char * opts); +#else +#if defined(LINUX) +#include +#endif +#endif /* XP_PC */ +/*end secopt.h*/ + +#define VERSIONSTRING "$Revision$ ($Date$)" + +#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) + +#define PRINTF if (verbose) printf +#define FPRINTF if (verbose) fprintf +#define FPUTS if (verbose) fputs + +#define MAX_SERIAL_LEN 8192 + +int MakeCertOK=1; + +int verbose; +SECItem bigBuf; + + +char * ownPasswd( PK11SlotInfo *slot, PRBool retry, void *arg) +{ + char *passwd = NULL; + + if ( (!retry) && arg ) { + passwd = PL_strdup((char *)arg); + } + + return passwd; +} + +static void +Usage(const char *progName) +{ + fprintf(stderr, + "Usage: %s [-n nickname] [-p password | -w pwfile ] [-d dbdir] \n" + " [-e post] [-v] [-V] -r url hostname[:port]\n" + " -n : nickname or hsm:nickname\n" + " -v : verbose\n" + " -V : report version information\n", + progName); + exit(1); +} + + +static void +errWarn(char * funcString) +{ + PRErrorCode perr = PR_GetError(); + + FPRINTF(stderr, "exit after %s with error %d:\n", funcString,perr ); +} + +static void +errExit(char * funcString) +{ + 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 SECStatus +mySSLAuthCertificate(void *arg, PRFileDesc *fd, PRBool checkSig, + PRBool isServer) +{ + SECStatus rv; + CERTCertificate * peerCert; + + peerCert = SSL_PeerCertificate(fd); + + PRINTF("Subject: %s\nIssuer : %s\n", + peerCert->subjectName, peerCert->issuerName); + /* invoke the "default" AuthCert handler. */ + rv = SSL_AuthCertificate(arg, fd, checkSig, isServer); + + if (rv == SECSuccess) { + FPUTS("-- SSL3: Server Certificate Validated.\n", stderr); + } + /* error, if any, will be displayed by the Bad Cert Handler. */ + return rv; +} + +static SECStatus +myBadCertHandler( void *arg, PRFileDesc *fd) +{ + /* int err = PR_GetError(); */ + /* fprintf(stderr, "-- SSL: Server Certificate Invalid, err %d.\n%s\n", + err, SECU_Strerror(err)); */ + return (MakeCertOK ? SECSuccess : SECFailure); +} + + +SECStatus +my_GetClientAuthData(void * arg, + PRFileDesc * socket, + struct CERTDistNamesStr * caNames, + struct CERTCertificateStr ** pRetCert, + struct SECKEYPrivateKeyStr **pRetKey) +{ + CERTCertificate * cert = NULL; + SECKEYPrivateKey * privkey = NULL; + char * chosenNickName = (char *)arg; /* CONST */ + void * proto_win = NULL; + SECStatus rv = SECFailure; + + FPRINTF(stderr,"Called mygetclientauthdata - nickname = %s\n",chosenNickName); + + proto_win = SSL_RevealPinArg(socket); + + if (chosenNickName) { + cert = PK11_FindCertFromNickname(chosenNickName, proto_win); + FPRINTF(stderr," mygetclientauthdata - cert = %x\n",(unsigned int)cert); + if ( cert ) { + privkey = PK11_FindKeyByAnyCert(cert, proto_win); + FPRINTF(stderr," mygetclientauthdata - privkey = %x\n",(unsigned int)privkey); + if ( privkey ) { + rv = SECSuccess; + } else { + CERT_DestroyCertificate(cert); + } + } + } else { /* no name given, automatically find the right cert. */ + CERTCertNicknames * names; + int i; + + names = CERT_GetCertNicknames(CERT_GetDefaultCertDB(), + SEC_CERT_NICKNAMES_USER, proto_win); + if (names != NULL) { + for (i = 0; i < names->numnicknames; i++) { + cert = PK11_FindCertFromNickname(names->nicknames[i],proto_win); + if ( !cert ) + continue; + /* Only check unexpired certs */ + if (CERT_CheckCertValidTimes(cert, PR_Now(), PR_TRUE) != + secCertTimeValid ) { + CERT_DestroyCertificate(cert); + continue; + } + rv = NSS_CmpCertChainWCANames(cert, caNames); + if ( rv == SECSuccess ) { + privkey = PK11_FindKeyByAnyCert(cert, proto_win); + if ( privkey ) + break; + } + rv = SECFailure; + CERT_DestroyCertificate(cert); + } + CERT_FreeNicknames(names); + } + } + if (rv == SECSuccess) { + *pRetCert = cert; + *pRetKey = privkey; + } + return rv; +} + + + + +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; +#if 0 + PRINTF("bulk cipher %s, %d secret key bits, %d key bits, status: %d\n" + "subject DN: %s\n" + "issuer DN: %s\n", cp, kp1, kp0, op, sp, ip); +#else + PRINTF("bulk cipher %s, %d secret key bits, %d key bits, status: %d\n", + cp, kp1, kp0, op); +#endif + PR_Free(cp); + PR_Free(ip); + PR_Free(sp); + } + +} + + +PRBool useModelSocket = PR_TRUE; + +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" +}; + + +PRInt32 +do_writes( + void * a +) +{ + PRFileDesc * ssl_sock = (PRFileDesc *)a; + PRUint32 sent = 0; + PRInt32 count = 0; + + while (sent < bigBuf.len) { + + count = PR_Write(ssl_sock, bigBuf.data + sent, bigBuf.len - sent); + if (count < 0) { + errWarn("PR_Write bigBuf"); + exit(4); + break; + } + FPRINTF(stderr, "PR_Write wrote %d bytes from bigBuf\n", count ); + FPRINTF(stderr, "bytes: [%*s]\n",count,bigBuf.data); + + sent += (PRUint32)count; + } + if (count >= 0) { /* last write didn't fail. */ + FPRINTF(stderr, "do_writes shutting down send socket\n"); + /* PR_Shutdown(ssl_sock, PR_SHUTDOWN_SEND); */ + } + + FPRINTF(stderr, "do_writes exiting with (failure = %d)\n",sent %d.%d.%d.%d\n", hostName, p[0], p[1], p[2], p[3]); + rv = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; + return rv; +} + +void +client_main( + unsigned short port, + int connections, + SECKEYPrivateKey ** privKey, + CERTCertificate ** cert, + const char * hostName, + char * nickName) +{ + PRFileDesc *model_sock = NULL; + int rv; + + + FPRINTF(stderr, "port: %d\n", port); + + /* all suites except RSA_NULL_MD5 are enabled by Domestic Policy */ + NSS_SetDomesticPolicy(); + + /* all the SSL2 and SSL3 cipher suites are enabled by default. */ + + /* enable FIPS ciphers */ + SSL_CipherPrefSetDefault(0xc004 /* TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA */, PR_TRUE); + SSL_CipherPrefSetDefault(0xc003 /* TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA */, PR_TRUE); + SSL_CipherPrefSetDefault(0xC005 /* TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA */, PR_TRUE); + SSL_CipherPrefSetDefault(0xc00a /* TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA */, PR_TRUE); + SSL_CipherPrefSetDefault(0x2f /* TLS_RSA_WITH_AES_128_CBC_SHA */, PR_TRUE); + SSL_CipherPrefSetDefault(0x35 /* TLS_RSA_WITH_AES_256_CBC_SHA */, PR_TRUE); + SSL_CipherPrefSetDefault(0xc008 /* TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA */, PR_TRUE); + SSL_CipherPrefSetDefault(0xc009 /* TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA */, PR_TRUE); + SSL_CipherPrefSetDefault(0xc012 /* TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA */, PR_TRUE); + SSL_CipherPrefSetDefault(0xc013 /* TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA */, PR_TRUE); + SSL_CipherPrefSetDefault(0xc014 /* TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA */, PR_TRUE); + SSL_CipherPrefSetDefault(0x32 /* TLS_DHE_DSS_WITH_AES_128_CBC_SHA */, PR_TRUE); + SSL_CipherPrefSetDefault(0x38 /* TLS_DHE_DSS_WITH_AES_256_CBC_SHA */, PR_TRUE); + SSL_CipherPrefSetDefault(0x33 /* TLS_DHE_RSA_WITH_AES_128_CBC_SHA */, PR_TRUE); + SSL_CipherPrefSetDefault(0x39 /* TLS_DHE_RSA_WITH_AES_256_CBC_SHA */, PR_TRUE); + + /* + * Rifle through the values for the host + */ + + PRAddrInfo *ai; + void *iter; + PRNetAddr addr; + int family = PR_AF_INET; + + ai = PR_GetAddrInfoByName(hostName, PR_AF_UNSPEC, PR_AI_ADDRCONFIG); + if (ai) { + FPRINTF( stderr, "addr='%s'\n", PR_GetCanonNameFromAddrInfo( ai ) ); + iter = NULL; + while ((iter = PR_EnumerateAddrInfo(iter, ai, 0, &addr)) != NULL) { + family = PR_NetAddrFamily(&addr); + FPRINTF( stderr, "family='%d'\n", family ); + break; + } + PR_FreeAddrInfo(ai); + } + + PR_SetNetAddr( PR_IpAddrNull, family, port, &addr ); + + model_sock = PR_OpenTCPSocket( family ); + if (model_sock == NULL) { + errExit("PR_OpenTCPSocket on tcp socket"); + } + + /* Should we really be re-using the same socket? */ + model_sock = SSL_ImportFD(NULL, model_sock); + + + /* check on success of call to SSL_ImportFD() */ + if (model_sock == NULL) { + errExit("SSL_ImportFD"); + } + + /* enable ECC cipher also */ + + /* do SSL configuration. */ + + rv = SSL_OptionSet(model_sock, SSL_SECURITY, 1); + if (rv < 0) { + if( model_sock != NULL ) { + PR_Close( model_sock ); + model_sock = NULL; + } + errExit("SSL_OptionSet SSL_SECURITY"); + } + + SSL_SetURL(model_sock, hostName); + + SSL_AuthCertificateHook(model_sock, mySSLAuthCertificate, + (void *)CERT_GetDefaultCertDB()); + + SSL_BadCertHook(model_sock, myBadCertHandler, NULL); + + if( nickName) { + SSL_GetClientAuthDataHook(model_sock, + (SSLGetClientAuthData)my_GetClientAuthData, + nickName); + } + + /* I'm not going to set the HandshakeCallback function. */ + + /* end of ssl configuration. */ + + rv = do_connect(&addr, model_sock, 1); + + if( model_sock != NULL ) { + PR_Close( model_sock ); + model_sock = NULL; + } +} + + +SECStatus +createRequest(char * url, char *post) +{ + char * newstr; + + if (post == NULL) { + newstr = PR_smprintf( + "GET %s HTTP/1.0\r\n\r\n", + url); + } else { + int len = strlen(post); + newstr = PR_smprintf( + "POST %s HTTP/1.0\r\nContent-Length: %d\r\nContent-Type: application/x-www-form-urlencoded\r\n\r\n%s", url, len, post); + } + + bigBuf.data = (unsigned char *)newstr; + + FPUTS((char *)bigBuf.data, stderr); + + bigBuf.len = PORT_Strlen((char *)bigBuf.data); + + return SECSuccess; +} + +int +main(int argc, char **argv) +{ + char * dir = "."; + char * hostName = NULL; + char * nickName = NULL; + char * progName = NULL; + char * tmp = NULL; + char * post = NULL; + CERTCertificate * cert [kt_kea_size] = { NULL }; + SECKEYPrivateKey * privKey[kt_kea_size] = { NULL }; + int optchar; + int connections = 1; + int tmpI; + unsigned short port = 443; + SECStatus rv; + char * passwd = NULL; + char * passwdfile = NULL; + char * url = NULL; + FILE *fp; + char pwbuf[256]; + int co; + char *crlf; + + /* Call the NSPR initialization routines */ + PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); + + tmp = strrchr(argv[0], '/'); + tmp = tmp ? tmp + 1 : argv[0]; + progName = strrchr(tmp, '\\'); + progName = progName ? progName + 1 : tmp; + + + while ((optchar = getopt(argc, argv, "Vd:e:n:p:r:w:v")) != -1) { + switch(optchar) { + +/* Version */ + case 'V': + printf("%s\n",VERSIONSTRING); + PR_Cleanup(); + return 0; + +/* Directory which holds cert8.db and key3.db */ + case 'd': + dir = optarg; + break; + +/* Nickname of certificate to use */ + case 'n': + nickName = optarg; + break; + +/* password to open key3.db */ + case 'p': + passwd = optarg; + break; + +/* name of file holding password for key3.db */ + case 'w': + passwdfile = optarg; + break; + +/* url */ + case 'r': + url = optarg; + break; + +/* post parameters */ + case 'e': + post = optarg; + break; + + case 'v': + verbose++; + break; + + default: + case '?': + fprintf( stderr, "ERROR: Invalid option!\n" ); + Usage(progName); + break; + + } + } + + if (optind != argc - 1) { + fprintf( stderr, "ERROR: Invalid number of arguments!\n" ); + Usage(progName); + } + + hostName = argv[optind]; + tmp = strchr(hostName, ':'); + if (tmp) { + *tmp++ = 0; + tmpI = atoi(tmp); + if (tmpI <= 0) { + fprintf( stderr, "ERROR: Invalid port!\n" ); + Usage(progName); + } + port = (unsigned short)tmpI; + } + + if ( !url) { + fprintf( stderr, "ERROR: Invalid url!\n" ); + Usage(progName); + } + + createRequest(url, post); + + if (passwdfile) { + fp = fopen(passwdfile,"r"); + if (!fp) { fprintf(stderr, "Couldn't open password file\n"); exit(7); } + co = fread(pwbuf,1,256,fp); + pwbuf[co] = '\0'; + crlf = PL_strchr(pwbuf,'\n'); + if (crlf) { + *crlf = '\0'; + } + passwd = pwbuf; + } + + /* set our password function */ + if (passwd == NULL) { + fprintf( stderr, "ERROR: Invalid password!\n" ); + PRINTF("Password must be provided on command line in this version of revoker.\n"); + Usage(progName); + } + PK11_SetPasswordFunc(ownPasswd); + + /* Call the libsec initialization routines */ + rv = NSS_Init(dir); + if (rv != SECSuccess) { + fputs("NSS_Init failed.\n", stderr); + exit(1); + } + + if(nickName) { + cert[kt_rsa] = PK11_FindCertFromNickname(nickName, passwd); + if (cert[kt_rsa] == NULL) { + fprintf(stderr, "Can't find certificate %s\n", nickName); + exit(1); + } + + privKey[kt_rsa] = PK11_FindKeyByAnyCert(cert[kt_rsa], passwd); + if (privKey[kt_rsa] == NULL) { + fprintf(stderr, "Can't find Private Key for cert %s (possibly incorrect password)\n", nickName); + exit(1); + } + } + + client_main(port, connections, privKey, cert, hostName, nickName); + + NSS_Shutdown(); + PR_Cleanup(); + return 0; +} + -- cgit