summaryrefslogtreecommitdiff
path: root/security/nss/tests/pkcs11/netscape/suites/security/ssl/sslt.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/nss/tests/pkcs11/netscape/suites/security/ssl/sslt.c')
-rwxr-xr-xsecurity/nss/tests/pkcs11/netscape/suites/security/ssl/sslt.c1186
1 files changed, 1186 insertions, 0 deletions
diff --git a/security/nss/tests/pkcs11/netscape/suites/security/ssl/sslt.c b/security/nss/tests/pkcs11/netscape/suites/security/ssl/sslt.c
new file mode 100755
index 000000000..a3150ac6e
--- /dev/null
+++ b/security/nss/tests/pkcs11/netscape/suites/security/ssl/sslt.c
@@ -0,0 +1,1186 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * 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 the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#define VERION_MAJOR 1
+#define VERION_MINOR 0
+#define VERSION_POINT 7
+/* NSPR header files */
+#include <prinit.h>
+#include <prprf.h>
+#include <prsystem.h>
+#include <prmem.h>
+#include <plstr.h>
+#include <prnetdb.h>
+#include <prinrval.h>
+#include <prmon.h>
+#include <prlock.h>
+
+/* Security library files */
+#include "cert.h"
+#include "key.h"
+#include "secmod.h"
+#include "secutil.h"
+#include "pk11func.h"
+
+/* SSL Header Files */
+#include "ssl.h"
+#include "sslproto.h"
+
+#define EXIT_OOPS 14
+
+#include "ssls.h"
+#include "sslc.h"
+
+#ifdef XP_PC
+/* Windows VC++ 6.0 Header File required to define EXCEPTION_EXECUTE_HANDLER. */
+#include "excpt.h"
+#endif
+
+#ifndef DEBUG_stevep
+#define dbmsg(x) if (debug) PR_fprintf x ;
+#else
+#define dbmsg(x) ;
+#endif
+
+/* Prototypes */
+
+PRInt32 ServerThread(PRInt32 argc,char **argv);
+void ClientThread(void *arg);
+void SetupNickNames(void );
+int OpenDBs(void);
+int ConfigServerSocket(void);
+int DoIO(struct ThreadData *);
+int Client(void);
+int SetClientSecParams(void);
+int CreateClientSocket(void);
+
+#ifdef XP_PC
+extern char getopt(int, char**, char*);
+#endif
+extern int Version2Enable(PRFileDesc *s);
+extern int Version3Enable(PRFileDesc *s);
+extern int Version23Clear(PRFileDesc *s);
+extern void SetupNickNames();
+extern int AuthCertificate(void *arg,PRFileDesc *fd,
+ PRBool checkSig, PRBool isServer);
+extern char *MyPWFunc(void *slot, PRBool retry, void *arg);
+
+extern char *nicknames[];
+extern char *client_nick;
+extern char *password, *nickname;
+
+/* Shared condition variables */
+
+int rc; /* rc is the error the process should return */
+PRMonitor *rcmon; /* rcmon protects rc, since it can be set by the client */
+ /* or server thread */
+
+/***** Read-only global variables (initialized in Server Thread) ****/
+
+PRInt32 debug = 0;
+PRInt32 verbose = 0;
+CERTCertDBHandle *cert_db_handle = NULL;
+
+struct ThreadData cl,svr;
+
+/* Include Replacer-generated variables file */
+
+/* INSERT_TABLES is a special parameter to sslt.h which inserts the
+ replacer-generated tables. We only want this table to be included
+ once in the executable, but this header file gets use in several
+ places */
+
+#define INSERT_TABLES
+#include "sslt.h"
+#include "nss.h"
+
+
+
+/*
+ *
+ * OpenDBs() - open databases
+ * errors(30-39)
+ */
+
+int OpenDBs() {
+ int r;
+
+ NSS_Init(".");
+ return 0;
+}
+
+
+
+
+
+/*
+ * CreateServerSocket
+ * errors (20-29)
+ */
+
+
+int CreateServerSocket(struct ThreadData *td) {
+ /* Create server socket s */
+
+ td->fd = PR_NewTCPSocket();
+ if (td->fd == NULL) return Error(20);
+
+ td->r = SSL_ImportFD(NULL, td->fd);
+ if (td->r == NULL) return Error(21);
+
+ return 0;
+}
+
+
+int ConfigServerSocket() {
+
+ /* Set up Net address to bind to 'any' */
+ int r;
+
+ r = PR_InitializeNetAddr(PR_IpAddrAny,0,&svr.na);
+ if (PR_SUCCESS != r) return Error(2);
+
+
+ r = PR_Bind(svr.r,&svr.na); /* bind to an IP address */
+ if (PR_SUCCESS != r) return Error(3);
+
+
+ r = PR_Listen(svr.r,5);
+ if (PR_SUCCESS != r) return Error(4);
+
+
+ r = PR_GetSockName(svr.r,&svr.na);
+ if (PR_SUCCESS != r) return Error(5);
+ return r;
+}
+
+
+/*
+ * main
+ * returns 255 if 'coredump'-type crash occurs on winNT
+ *
+ */
+
+PRIntn main(PRIntn ac, char **av, char **ev) {
+ int r;
+ extern char *optarg;
+ extern int optind;
+ int c;
+
+
+ if( ac == 1 ) {
+ PR_fprintf(PR_STDERR,
+"\nSSL Test Suite Version %d.%d.%d\n\
+All Rights Reserved\n\
+Usage: sslt [-c client_nickname] [-n server_nickname] [-p passwd] [-d] testid\n",
+VERION_MAJOR, VERION_MINOR, VERSION_POINT);
+
+ exit(0);
+ }
+
+ for (c = 1; c<ac; c++) {
+ if (!PL_strcmp(av[c],"-c")) {
+
+ c++;
+ if (c < ac) {
+ client_nick = av[c];
+ }
+ else {
+ PR_fprintf(PR_STDOUT,"must supply argument for -c\n");
+ exit(0);
+ }
+ }
+
+ else if (!PL_strcmp(av[c],"-n")) {
+
+ c++;
+ if (c < ac) {
+ nickname = av[c];
+ }
+ else {
+ PR_fprintf(PR_STDOUT,"must supply argument for -n\n");
+ exit(0);
+ }
+ }
+ else if (!PL_strcmp(av[c],"-p")) {
+
+ c++;
+ if (c < ac) {
+ password = av[c];
+ }
+ else {
+ PR_fprintf(PR_STDOUT,"must supply argument for -p\n");
+ exit(0);
+ }
+ }
+ else if (!PL_strcmp(av[c],"-d")) {
+ c++;
+ debug++;
+ }
+ else
+ testId = atoi(av[c]);
+ }
+
+
+
+#ifdef XP_PC
+ __try {
+#endif
+
+ r = PR_Initialize(ServerThread,ac,av,400); /* is 400 enough? */
+
+ /* returncode 99 means 'no error' */
+ if (99 == r) r = 0;
+
+#ifdef XP_PC
+ } __except( PR_fprintf(PR_STDERR, "\nCERT-TEST crashed\n"), EXCEPTION_EXECUTE_HANDLER ) {
+ r = 255;
+ }
+#endif
+
+ return r;
+
+}
+
+
+
+/*
+ * ServerThread
+ * (errors 1-9,150-159)
+ */
+
+
+PRInt32 ServerThread(PRInt32 argc,char **argv) {
+
+ PRNetAddr na;
+
+ PRStatus r;
+ SECStatus rv;
+
+ CERTCertDBHandle *cert_db_handle;
+ PRInt32 i,j;
+ struct ThreadData * td;
+
+
+ /* if (InvalidTestHack() == PR_TRUE) {
+ return 0;
+ }
+ */
+
+ rcmon = PR_NewMonitor();
+ if (NULL == rcmon) return Error(140);
+
+ PR_EnterMonitor(rcmon);
+ rc = 0;
+ PR_ExitMonitor(rcmon);
+
+ InitCiphers();
+ SetPolicy();
+ SetupNickNames();
+
+ cl.peer = &svr;
+ svr.peer = &cl;
+
+
+ r = OpenDBs(); /* open databases and set defaults */
+ if (PR_SUCCESS != r) return r;
+
+
+ r = CreateServerSocket(&svr);
+ if (PR_SUCCESS != r) return r;
+
+ r = ConfigServerSocket();
+ if (PR_SUCCESS != r) return r;
+
+ cl.peerport = svr.na.inet.port;
+
+
+ r = SetServerSecParms(&svr); /* configure server socket
+ sid cache, certificate etc. */
+ if (r) return r;
+
+ r = SSL_HandshakeCallback(svr.r, HandshakeCallback, &svr);
+ if (PR_SUCCESS != r) return Error(150);
+
+ r = SSL_AuthCertificateHook(svr.r,AuthCertificate,&svr);
+ if (PR_SUCCESS !=r ) return Error(151);
+
+ /* The server socket is now set up. Now, we must start
+ the client thread */
+
+ svr.subthread =
+ PR_CreateThread(PR_SYSTEM_THREAD, /* Thread Type */
+ ClientThread, /* Start Function */
+ NULL, /* Argument */
+ PR_PRIORITY_NORMAL, /* Priority */
+ PR_GLOBAL_THREAD, /* Scheduling scope */
+ PR_JOINABLE_THREAD, /* Thread State */
+ 0 /* Stacksize (0=use default) */
+ );
+ if (svr.subthread == NULL) return Error(6);
+
+
+
+ /* Wait for incoming connection from client thread */
+
+ svr.s = PR_Accept(svr.r, NULL, PR_SecondsToInterval(100)); /* timeout */
+ if (NULL == svr.s) {
+ r = PR_GetError();
+ if (r) {
+ return Error(7);
+ }
+ }
+
+ td = &svr;
+ td->client = PR_FALSE;
+ td->xor_reading = CLIENTXOR;
+ td->xor_writing = 0;
+
+ r = DoIO(td);
+ dbmsg((PR_STDERR,"Server IO complete - returned %d\n",r));
+ dbmsg((PR_STDERR,"PR_GetError() = %d\n",PR_GetError()));
+
+
+ /* WHY IS THIS HERE???? */
+ r = 0;
+ if (r) return r;
+
+
+ /* c = SSL_PeerCertificate(s); */
+
+ r = PR_Close(svr.s); /* close the SSL Socket */
+ if (r != PR_SUCCESS) return Error(8);
+
+ dbmsg((PR_STDERR,"PR_Close(svr.s) - returned %d\n",r));
+
+ r = PR_Close(svr.r); /* Close the rendezvous socket */
+ if (r != PR_SUCCESS) return Error(8);
+
+ dbmsg((PR_STDERR,"PR_Close(svr.r) - returned %d\n",r));
+
+ r = PR_JoinThread(svr.subthread);
+ if (r != PR_SUCCESS) return Error(9);
+
+ PR_EnterMonitor(rcmon);
+ r = rc;
+ PR_ExitMonitor(rcmon);
+
+ dbmsg((PR_STDERR,"Client Thread Joined. client's returncode=%d\n",r));
+ dbmsg((PR_STDERR,"Server Thread closing down.\n"));
+
+ return r;
+
+ }
+
+
+/*
+ * Get security status for this socket
+ *
+ */
+
+int GetSecStatus(struct ThreadData *td) {
+ int r;
+
+ r = SSL_SecurityStatus(td->s,
+ &td->status_on,
+ &td->status_cipher,
+ &td->status_keysize,
+ &td->status_skeysize,
+ &td->status_issuer,
+ &td->status_subject
+ );
+
+ return r;
+ /* SSL_PeerCertificate(); */
+
+}
+
+
+
+
+/* Signal an error code for the process to return.
+ If the peer aborted before us, returns 0.
+ If the peer did not abort before us, returns the calling argument
+ (to be used as a returncode) */
+int Error(int s)
+{
+ int r;
+
+ PR_EnterMonitor(rcmon);
+ r = rc;
+ if (0 == rc) {
+ rc = s;
+ }
+ PR_ExitMonitor(rcmon);
+
+ if (r) return s;
+ else return 0;
+}
+
+
+
+#define ALLOWEDBYPROTOCOL 1
+#define ALLOWEDBYPOLICY 2
+#define ALLOWEDBYCIPHERSUITE 4
+
+/* This returns 0 if the status is what was expected at this point, else a returncode */
+
+
+int VerifyStatus(struct ThreadData *td)
+{
+ int i,j;
+ int matched =0;
+
+ /* Go through all the ciphers until we find the first one that satisfies */
+ /* all the criteria. The ciphers are listed in preferred order. So, the first */
+ /* that matches should be the one. */
+
+ /* because of bug 107086, I have to fudge this. If it weren't for this
+ bug, SSL2 ciphers may get chosen in preference to SSL3 cipher,
+ if they were stronger */
+
+
+ for (i=0;i<cipher_array_size;i++) {
+
+ /* IF */
+
+ if (
+
+ /* bug 107086. If SSL2 and SSL3 are enabled, ignore the SSL2 ciphers */
+ (!( /* see above */
+ (REP_SSLVersion2 && REP_SSLVersion3) && cipher_array[i].sslversion == 2)
+ )
+
+ &&
+
+
+ ( /* Cipher is the right kind for the protocol? */
+ ((cipher_array[i].sslversion == 2) && REP_SSLVersion2) ||
+ ((cipher_array[i].sslversion == 3) && REP_SSLVersion3)
+ )
+
+ && /* Cipher is switched on */
+
+ ((cipher_array[i].on == 1) ||
+ ((cipher_array[i].on == 2) &&
+ (REP_ServerCert == SERVER_CERT_VERISIGN_STEPUP)))
+
+ && /* Is this cipher enabled under this policy */
+
+ (
+ (REP_Policy == POLICY_DOMESTIC) ||
+ ((REP_Policy == POLICY_EXPORT) &&
+ (cipher_array[i].exportable == SSL_ALLOWED)))
+ )
+
+ /* THEN */
+ {
+ /* This is the cipher the SSL library should have chosen */
+
+ matched = 1;
+ break;
+ }
+ }
+
+GetSecStatus(td);
+
+
+#define SSLT_STATUS_CORRECT 0 /* The status is correct. Continue with test */
+#define SSLT_STATUS_WRONG_KEYSIZE 1 /* The reported keysize is incorrect. abort */
+#define SSLT_STATUS_WRONG_SKEYSIZE 2 /* The reported secret keysize is incorrect. abort */
+#define SSLT_STATUS_WRONG_DESCRIPTION 3 /* The reported description is incorrect. abort*/
+#define SSLT_STATUS_WRONG_ERRORCODE 4 /* sec. library error - but wrong one - abort */
+#define SSLT_STATUS_CORRECT_ERRORCODE 5 /* security library error - right one - abort with err 99 */
+
+ if (matched) {
+ if (td->status_keysize != cipher_array[i].ks) {
+ PR_fprintf(PR_STDERR,"wrong keysize. seclib: %d, expected %d\n",
+ td->status_keysize,cipher_array[i].ks);
+ return SSLT_STATUS_WRONG_KEYSIZE;
+ }
+ if (td->status_skeysize != cipher_array[i].sks) return SSLT_STATUS_WRONG_SKEYSIZE;
+ if (PL_strcmp(td->status_cipher,cipher_array[i].name)) {
+ PR_fprintf(PR_STDERR,"wrong cipher description. seclib: %s, expected: %s\n",
+ td->status_cipher,cipher_array[i].name);
+ return SSLT_STATUS_WRONG_DESCRIPTION;
+ }
+
+ /* Should also check status_issuer and status_subject */
+
+ return SSLT_STATUS_CORRECT;
+ }
+
+ else {
+ /* if SSL wasn't enabled, security library should have returned a failure with
+ SSL_ERROR_SSL_DISABLED
+ */
+
+ /* Since we cannot set the client and server ciphersuites independently,
+ there's not point in checking for NO_CYPHER_OVERLAP. That's why some
+ of this is commented out.
+ */
+
+#if 0
+ if (PR_FALSE == REP_SSLVersion2 &&
+ PR_FALSE == REP_SSLVersion3)
+{
+if ( (td->secerr_flag == PR_FALSE ) ||
+ ((td->secerr_flag == PR_TRUE) &&
+ !((td->secerr == SSL_ERROR_SSL_DISABLED) ||
+ (td->secerr == SSL_ERROR_NO_CYPHER_OVERLAP))
+ )) {
+ return SSLT_STATUS_WRONG_ERRORCODE;
+ }
+ else
+ return SSLT_STATUS_CORRECT_ERRORCODE;
+ }
+
+ else {
+
+ /* If SSL was enabled, and we get here, then no ciphers were compatible
+ (matched == 0). So, security library should have returned the error
+ SSL_ERROR_NO_CYPHER_OVERLAP */
+
+ if ((td->secerr_flag == PR_FALSE) ||
+ ((td->secerr_flag == PR_TRUE) && (td->secerr != SSL_ERROR_NO_CYPHER_OVERLAP))) {
+ return SSLT_STATUS_WRONG_ERRORCODE;
+ }
+ else return SSLT_STATUS_CORRECT_ERRORCODE;
+ }
+#endif
+ }
+ return SSLT_STATUS_CORRECT_ERRORCODE;
+}
+
+
+/*
+ * DoRedoHandshake()
+ *
+ * errors(90-99)
+ * 99 means exit gracefully
+ */
+
+int DoRedoHandshake(struct ThreadData *td) {
+ int r;
+
+
+ /* figure out if we really should do the RedoHandshake */
+ if ((td->client && (PR_TRUE== REP_ClientRedoHandshake)) ||
+ (!td->client && (PR_TRUE== REP_ServerRedoHandshake))) {
+
+ if ((!td->client && (SSLT_CLIENTAUTH_REDO==REP_ServerDoClientAuth))) {
+ r = SSL_Enable(td->s, SSL_REQUEST_CERTIFICATE, 1);
+ }
+
+ r = SSL_RedoHandshake(td->s); /* .. and redo the handshake */
+ if (PR_SUCCESS == r) { /* If the handshake succeeded, */
+ /* make sure that shouldn't have failed... */
+
+ /***
+ If the server is doing ClientAuth
+ and the wrong certificate in the
+ client, then the handshake should fail (but it succeeded)
+ ***/
+
+#if 0
+ if (SSLT_CLIENTAUTH_INITIAL == REP_ServerDoClientAuth) {
+ if ((CLIENT_CERT_SPARK == REP_ClientCert) ||
+ (SERVER_CERT_HARDCOREII_512 == REP_ClientCert) ||
+ (NO_CERT == REP_ClientCert)
+ )
+ return Error(90);
+
+ }
+#endif
+
+ }
+
+ else { /* PR_FAILURE: Make sure the handshake shouldn't have succeeded */
+
+ /* First, abort the peer, since it cannot continue */
+ r = Error(91);
+ if (0==r) return 0; /* peer aborted first */
+ else {
+ /***
+ If the server is doing clientauth and
+ a valid certificate was presented, the handshake
+ should have succeeded (but it failed)
+ ***/
+
+ if (PR_TRUE == REP_ServerDoClientAuth) {
+ if ((CLIENT_CERT_HARDCOREII_512 == REP_ClientCert) ||
+ (CLIENT_CERT_HARDCOREII_1024 == REP_ClientCert) ||
+ (CLIENT_CERT_VERISIGN == REP_ClientCert) ||
+ (SERVER_CERT_HARDCOREII_512 == REP_ClientCert)
+ )
+ return Error(91);
+ }
+ }
+ }
+ }
+}
+
+
+
+/* There is a independent State Machine for each of client and server.
+ They have the following states:
+
+ 1. STATE_BEFORE_INITIAL_HANDSHAKE
+ In this state at the very start. No I/O has been done on the socket,
+ and no status has been collected. Once I/O has been done, we move on
+ to state 2.
+
+ 2. STATE_BEFORE_REDO_HANDSHAKE
+ If we won't be doing a redohandshake, move immediately to state3.
+ Check security status to make sure selected cipher is correct.
+ If we are doing a redohandshake, adjust the security parameters for
+ the redo, and move to state 3.
+ 3. STATE_STATUS_COLLECTED
+ When we move to this state, check security status.
+ Remain in this state until either reading or writing is complete
+ 4. STATE_DONE_WRITING
+ Come here when writing is complete. When reading is complete move
+ to state 6.
+ 5. STATE_DONE_READING
+ Come here when reading is complete. When writing is complete move
+ to state 6.
+ 6. STATE_DONE
+ We're done. Check that the appropriate callbacks were called at the
+ appropriate times.
+ */
+
+/*
+ * State Machine
+ *
+ * errors(80-89)
+ */
+
+int NextState(struct ThreadData *td,
+ int finishedReading,
+ int finishedWriting) {
+ int r;
+
+
+
+ /* if we were in STATE_BEFORE_INITIAL_HANDSHAKE, and we came here, we must
+ have just completed a handshake, so we can get status and move on
+ to next state. */
+
+ if (STATE_BEFORE_INITIAL_HANDSHAKE == td->state ) {
+
+ td->state = STATE_BEFORE_REDO_HANDSHAKE; /* first set next state */
+
+ r = GetSecStatus(td);
+ if (PR_SUCCESS != r) {
+ return Error(80);
+ }
+
+#if 0
+ r = VerifyStatus(td); /* Call VerifyStatus to make sure that the connection is
+ what was expected */
+ if (PR_SUCCESS != r) return r;
+#endif
+
+
+ }
+
+ if (STATE_BEFORE_REDO_HANDSHAKE == td->state) {
+ /* If we're not going to do a redohandshake, we can just skip over this state */
+ if (td->client) {
+ if (PR_FALSE == REP_ClientRedoHandshake) td->state = STATE_STATUS_COLLECTED;
+ }
+ else {
+ if (PR_FALSE == REP_ServerRedoHandshake) td->state = STATE_STATUS_COLLECTED;
+ }
+ r = DoRedoHandshake(td);
+ if (PR_SUCCESS != r) return r;
+ td->state = STATE_STATUS_COLLECTED;
+ }
+
+
+ switch (td->state) {
+ case STATE_STATUS_COLLECTED:
+ if (finishedWriting) td->state = STATE_DONE_WRITING;
+ if (finishedReading) td->state = STATE_DONE_READING;
+ break;
+ case STATE_DONE_WRITING:
+ if (finishedReading) td->state = STATE_DONE;
+ break;
+ case STATE_DONE_READING:
+ if (finishedWriting) td->state = STATE_DONE;
+ break;
+ default:
+ return PR_SUCCESS;
+ }
+}
+
+
+/* CheckSSLEnabled:
+ If there was an I/O, and SSL was disabled, then check the error
+ code to make sure that the correct error was returned.
+ The parameter passed in is the returncode from PR_Read or PR_Write
+ */
+
+int CheckSSLEnabled(int j) {
+ if (PR_FALSE == REP_SSLVersion2 &&
+ PR_FALSE == REP_SSLVersion3) {
+ if (( -1 != j ) ||
+ (( -1 == j) && (PR_GetError() != SSL_ERROR_SSL_DISABLED))) {
+ return 52;
+ }
+ else return 99;
+ }
+ else return 0;
+}
+
+
+
+/*
+ * Do I/O
+ *
+ * Errors 50-69
+ */
+
+int DoIO(struct ThreadData *td) {
+
+int i,j,r;
+
+ td->pd.fd = td->s;
+ td->pd.in_flags = PR_POLL_READ | PR_POLL_WRITE | PR_POLL_EXCEPT;
+ td->data_read = 0;
+ td->data_sent = 0;
+
+ td->data_tosend = REP_ServerIOSessionLength;
+
+ td->state = STATE_BEFORE_INITIAL_HANDSHAKE;
+
+
+ while (PR_TRUE) {
+ dbmsg((PR_STDERR,"%s: DoIO loop\n",
+ &svr==td ? "Server" : "Client"));
+
+ /* pd = polldescriptor, 1 = number of descriptors, 5 = timeout in seconds */
+ r = PR_Poll(&td->pd,1,PR_SecondsToInterval(5));
+
+ /* Check if peer has already signalled an error condition */
+
+ PR_EnterMonitor(rcmon);
+ if (0 != rc) {
+ /* got here? - means peer wants to stop. It has set the
+ exit code */
+ PR_ExitMonitor(rcmon);
+ dbmsg((PR_STDERR,"%s: Peer has aborted (error code %d). We should too\n",
+ &svr==td ? "Server" : "Client",rc));
+
+ return 0;
+ }
+ else {
+ PR_ExitMonitor(rcmon);
+ }
+
+ if (0 == r) ; /* timeout occurred */
+
+ if (td->pd.out_flags & PR_POLL_EXCEPT) return Error(50);
+
+ /******* Process incoming data *******/
+
+ if (! (STATE_DONE == td->state || STATE_DONE_READING == td->state)) {
+ if (td->pd.out_flags & PR_POLL_READ) {
+
+ td->secerr = 0;
+ i = PR_Read(td->s, td->recvbuf, BUFSIZE);
+
+ if (i < 0) {
+ td->secerr_flag = 1;
+ td->secerr = PR_GetError();
+ }
+ else td->secerr_flag =0;
+
+ r = VerifyStatus(td);
+
+ switch (r) {
+ case SSLT_STATUS_CORRECT:
+ break;
+ case SSLT_STATUS_CORRECT_ERRORCODE:
+ return Error(99);
+ default:
+ return Error(60+r);
+ }
+
+ r = VerifyBuffer(td->recvbuf, i, td->data_read, td->xor_reading);
+ if (r) return r;
+ td->data_read += i;
+
+ /* Invoke State Machine */
+
+ NextState(td, 0==i, 0); /* if i is zero, signal 'finishedreading' */
+
+ }
+ }
+
+ if (! (STATE_DONE == td->state || STATE_DONE_WRITING == td->state)) {
+ if (td->pd.out_flags & PR_POLL_WRITE) {
+ FillBuffer(td->sendbuf,BUFSIZE,td->data_sent,td->xor_writing);
+
+ i = td->data_tosend - td->data_sent;
+ if (i > BUFSIZE) i = BUFSIZE; /* figure out how much
+ data to send */
+ td->secerr = 0;
+ j = PR_Write(td->s, td->sendbuf, i);
+
+
+ if (j < 0) {
+ td->secerr_flag = 1;
+ td->secerr = PR_GetError();
+ }
+ else td->secerr_flag =0;
+
+ r = VerifyStatus(td);
+
+ switch (r) {
+ case SSLT_STATUS_CORRECT:
+ break;
+ case SSLT_STATUS_CORRECT_ERRORCODE:
+ return Error(99);
+ default:
+ return Error(60+r);
+ }
+
+ }
+ if (j == -1) return Error(53); /* Error on socket (Not an error
+ if nonblocking IO enabled, and
+ Error is Would Block */
+
+ if (j != i) return Error(54); /* We didn't write the
+ amount we should have */
+
+ td->data_sent += j;
+
+ if (td->data_sent == td->data_tosend) {
+ PR_Shutdown(td->s,PR_SHUTDOWN_SEND);
+ }
+
+ /* next state of state machine */
+
+ NextState(td,
+ 0,
+ td->data_sent == td->data_tosend /* finishedwriting */
+ );
+ }
+
+
+
+ if (STATE_DONE == td->state) break;
+
+ } /* while (1) */
+
+ dbmsg((PR_STDERR,"%s: DoIO loop:returning 0\n",
+ &svr==td ? "Server" : "Client"));
+
+ return 0;
+
+}
+
+
+
+
+/* This is the start of the client thread code */
+/* Client Thread errors(100-200) */
+
+
+/*
+ * CreateClientSocket()
+ * errors (120-129)
+ */
+
+
+int CreateClientSocket() {
+ /* Create client socket s */
+
+ cl.fd = PR_NewTCPSocket();
+ if (cl.fd == NULL) return Error(120);
+
+ cl.s = SSL_ImportFD(NULL, cl.fd);
+ if (cl.s == NULL) return Error(121);
+
+ return 0;
+}
+
+
+
+/*
+ * SetClientSecParms
+ * errors(130-139)
+ */
+
+int SetClientSecParams() {
+ int rv;
+ /* SSL Enables */
+
+ rv = SSL_Enable(cl.s, SSL_SECURITY, 1);
+ if (rv < 0) return Error(130);
+
+ rv = Version23Clear(cl.s);
+ if (rv) return rv;
+
+ if (REP_SSLVersion2) {
+ rv = Version2Enable(cl.s);
+ if (rv) return rv;
+ }
+ if (REP_SSLVersion3) {
+ rv = Version3Enable(cl.s);
+ if (rv) return rv;
+ }
+
+ SSL_SetPKCS11PinArg(cl.s,(void*)MyPWFunc);
+
+ if (REP_ClientCert == NO_CERT) {
+ return 0;
+ }
+ else {
+ cl.cert = PK11_FindCertFromNickname(client_nick,NULL);
+ }
+ if (cl.cert == NULL) return Error(131);
+
+ return 0;
+}
+
+
+/*
+ * Client()
+ * errors (100-120)
+ */
+
+int Client() {
+ int r;
+
+ r = CreateClientSocket();
+ if (r) return r;
+
+ r = SetClientSecParams();
+ if (r) return r;
+
+ /* Set address to connect to: localhost */
+
+ r = PR_InitializeNetAddr(PR_IpAddrLoopback,0,&cl.na);
+ cl.na.inet.port = cl.peerport;
+ if (PR_FAILURE == r) return Error(101);
+
+ r = SSL_AuthCertificateHook(cl.s,AuthCertificate,&cl);
+ if (r) return Error(102);
+ r = SSL_HandshakeCallback(cl.s,HandshakeCallback,&cl);
+ if (r) return Error(103);
+
+ r = PR_Connect(cl.s, &cl.na, PR_SecondsToInterval(50));
+ if (PR_FAILURE == r) {
+ dbmsg((PR_STDERR, "Client: Seclib error: %s\n",SECU_ErrorString ((int16) PR_GetError())));
+ return Error(104);
+ }
+
+
+ if (PR_TRUE == REP_ClientForceHandshake) {
+ r = SSL_ForceHandshake(cl.s);
+ if (PR_FAILURE == r) {
+ dbmsg((PR_STDERR, "Client: Seclib error: %s\n",
+ SECU_ErrorString ((int16) PR_GetError())));
+ return Error(105);
+ }
+ }
+
+ cl.client = PR_TRUE;
+ cl.xor_reading = 0;
+ cl.xor_writing = CLIENTXOR;
+
+ r = DoIO(&cl);
+
+ dbmsg((PR_STDERR,"Client Thread done with IO. Returned %d\n",r));
+
+
+ if (PR_SUCCESS != r) return r;
+
+ r = PR_Close(cl.s);
+
+ dbmsg((PR_STDERR,"Client Socket closing. Returned %d\n",r));
+
+ return Error(r);
+
+}
+
+
+
+ void ClientThread(void *arg) {
+ int r;
+
+ Error(Client());
+
+ dbmsg((PR_STDERR,"Client Thread returning %d\n",r));
+
+
+ }
+
+
+
+
+
+
+ /* VerifyBuffer() */
+
+/* verify the data in the buffer. Returns 0 if valid */
+/* recvbuf = start of data to verify
+ * bufsize = amount of data to verify
+ * done = how to offset the reference data. How much
+ data we have done in previous sessions
+ * xor = xor character
+
+ * errors 70-79
+
+ */
+
+ int VerifyBuffer(char *recvbuf,int bufsize,int done, char xor) {
+ int i,j,k;
+
+ while (bufsize) {
+ i = done % DATABUFSIZE;
+
+ k = DATABUFSIZE;
+ if (bufsize < k) {
+ k = bufsize;
+ }
+ for (j = i; j < k ; j++) {
+ if ((data[j] ^ xor) != (*recvbuf)) {
+ return 71;
+ }
+
+ recvbuf++;
+ }
+ done += k-i;
+ bufsize -= (k - i);
+ if (bufsize < 0) return 73;
+ }
+ return (0);
+}
+
+
+/* fill the buffer. */
+
+ void FillBuffer(char *sendbuf,int bufsize, int offset, char xor) {
+ int done=0,i,j;
+
+ while (done < bufsize) {
+ i = offset % DATABUFSIZE;
+ for (j = i; j < DATABUFSIZE ; j++) {
+ *sendbuf = (data[j] ^ xor);
+ sendbuf++;
+ }
+ done += (DATABUFSIZE - i);
+ offset += (DATABUFSIZE - i);
+ }
+ }
+
+
+
+
+/****** CALLBACKS *******/
+
+
+
+/* HandshakeCallback
+ This function gets called when a handshake has just completed.
+ (maybe gets called more than once for example if we RedoHandshake)
+ */
+
+ void HandshakeCallback(PRFileDesc *s, void *td) {
+ int r;
+
+ /* 1. Get status of connection */
+
+ r = GetSecStatus(td);
+ if (PR_SUCCESS != r) {
+ /* Abort */
+ }
+ else {
+
+ /* 2. Verify status of connection */
+
+#if 0
+ r =VerifyStatus(td);
+ if (PR_SUCCESS != r) {
+ /* Abort */
+ }
+#endif
+ }
+
+ }
+
+
+
+/* This function gets called by the client thread's SSL code to verify
+ the server's certificate. We cannot use the default AuthCertificate
+ code because the certificates are used on multiple hosts, so
+ CERT_VerifyCertNow() would fail with an IP address mismatch error
+ */
+
+int
+AuthCertificate(void *arg, PRFileDesc *fd, PRBool checkSig, PRBool isServer)
+{
+ SECStatus rv;
+ CERTCertDBHandle *handle;
+ /* PRFileDesc *ss; */
+ SECCertUsage certUsage;
+
+ /* ss = ssl_FindSocket(fd);
+ PORT_Assert(ss != NULL); */
+
+ handle = (CERTCertDBHandle *)arg;
+
+ if ( isServer ) {
+ certUsage = certUsageSSLClient;
+ } else {
+ certUsage = certUsageSSLServer;
+ }
+
+ /* rv = CERT_VerifyCertNow(handle, ss->sec->peerCert, checkSig, certUsage, arg); */
+
+ return((int)PR_SUCCESS);
+}
+
+
+
+
+
+
+
+