diff options
Diffstat (limited to 'security/nss/tests/pkcs11/netscape/suites/security/ssl/sslt.c')
-rwxr-xr-x | security/nss/tests/pkcs11/netscape/suites/security/ssl/sslt.c | 1186 |
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); +} + + + + + + + + |