Back to index

lightning-sunbird  0.9+nobinonly
sslt.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Netscape security libraries.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either the GNU General Public License Version 2 or later (the "GPL"), or
00025  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  *
00035  * ***** END LICENSE BLOCK ***** */
00036 
00037 #define VERION_MAJOR 1
00038 #define VERION_MINOR 0
00039 #define VERSION_POINT 7
00040 /* NSPR header files */
00041 #include <prinit.h>
00042 #include <prprf.h>
00043 #include <prsystem.h>
00044 #include <prmem.h>
00045 #include <plstr.h>
00046 #include <prnetdb.h>
00047 #include <prinrval.h>
00048 #include <prmon.h>
00049 #include <prlock.h>
00050 
00051 /* Security library files */
00052 #include "cert.h"
00053 #include "key.h"
00054 #include "secmod.h"
00055 #include "secutil.h"
00056 #include "pk11func.h"
00057 
00058 /* SSL Header Files */
00059 #include "ssl.h"
00060 #include "sslproto.h"
00061 
00062 #define EXIT_OOPS 14
00063 
00064 #include "ssls.h"
00065 #include "sslc.h"
00066 
00067 #ifdef XP_PC
00068 /* Windows VC++ 6.0 Header File required to define EXCEPTION_EXECUTE_HANDLER. */
00069 #include "excpt.h"
00070 #endif
00071 
00072 #ifndef DEBUG_stevep
00073 #define dbmsg(x) if (debug) PR_fprintf x ;
00074 #else
00075 #define dbmsg(x) ;
00076 #endif
00077 
00078 /* Prototypes */
00079 
00080 PRInt32 ServerThread(PRInt32 argc,char **argv);
00081 void ClientThread(void *arg);
00082 void SetupNickNames(void );
00083 int OpenDBs(void);
00084 int ConfigServerSocket(void);
00085 int DoIO(struct ThreadData *);
00086 int Client(void);
00087 int SetClientSecParams(void);
00088 int CreateClientSocket(void);
00089 
00090 #ifdef XP_PC
00091 extern char getopt(int, char**, char*);
00092 #endif
00093 extern int Version2Enable(PRFileDesc *s);
00094 extern int Version3Enable(PRFileDesc *s);
00095 extern int Version23Clear(PRFileDesc *s);
00096 extern void SetupNickNames();
00097 extern int AuthCertificate(void *arg,PRFileDesc *fd,
00098                         PRBool checkSig, PRBool isServer);
00099 extern char *MyPWFunc(void *slot, PRBool retry, void *arg);
00100 
00101 extern char *nicknames[];
00102 extern char *client_nick;
00103 extern char *password, *nickname;
00104 
00105 /* Shared condition variables */
00106 
00107 int rc;            /* rc is the error the process should return */
00108 PRMonitor *rcmon;  /* rcmon protects rc, since it can be set by the client */
00109                    /* or server thread */
00110 
00111 /***** Read-only global variables (initialized in Server Thread)   ****/
00112 
00113 PRInt32 debug   = 0;
00114 PRInt32 verbose = 0;
00115 CERTCertDBHandle *cert_db_handle = NULL;
00116 
00117 struct ThreadData cl,svr;
00118 
00119 /* Include Replacer-generated variables file */
00120 
00121 /* INSERT_TABLES is a special parameter to sslt.h which inserts the
00122    replacer-generated tables. We only want this table to be included
00123    once in the executable, but this header file gets use in several
00124    places */
00125 
00126 #define INSERT_TABLES
00127 #include "sslt.h"
00128 #include "nss.h"
00129 
00130 
00131 
00132 /*
00133  *
00134  * OpenDBs()   -  open databases
00135  * errors(30-39)
00136  */
00137 
00138 int OpenDBs() {
00139   int r;
00140 
00141   NSS_Init(".");
00142   return 0;
00143 }
00144 
00145 
00146 
00147 
00148 
00149 /* 
00150  * CreateServerSocket
00151  * errors (20-29)
00152  */
00153 
00154 
00155 int CreateServerSocket(struct ThreadData *td) {
00156   /* Create server socket s */
00157 
00158   td->fd = PR_NewTCPSocket();
00159   if (td->fd == NULL) return Error(20);
00160 
00161   td->r = SSL_ImportFD(NULL, td->fd);
00162   if (td->r == NULL) return Error(21);
00163 
00164   return 0;
00165 } 
00166 
00167 
00168 int ConfigServerSocket() {
00169 
00170   /* Set up Net address to bind to 'any' */
00171   int r;
00172  
00173   r = PR_InitializeNetAddr(PR_IpAddrAny,0,&svr.na);
00174   if (PR_SUCCESS != r) return Error(2);
00175 
00176   
00177   r = PR_Bind(svr.r,&svr.na);     /* bind to an IP address */
00178   if (PR_SUCCESS != r) return Error(3);
00179 
00180 
00181   r = PR_Listen(svr.r,5);
00182   if (PR_SUCCESS != r) return Error(4);
00183 
00184 
00185   r = PR_GetSockName(svr.r,&svr.na);
00186   if (PR_SUCCESS != r) return Error(5);
00187   return r;
00188 }
00189 
00190 
00191 /* 
00192  * main 
00193  *   returns 255 if 'coredump'-type crash occurs on winNT
00194  *
00195  */
00196 
00197 PRIntn main(PRIntn ac, char **av, char **ev) {
00198   int r;
00199   extern char *optarg;      
00200   extern int optind;
00201   int c;
00202   
00203 
00204   if( ac == 1 ) {
00205      PR_fprintf(PR_STDERR,
00206 "\nSSL Test Suite Version %d.%d.%d\n\
00207 All Rights Reserved\n\
00208 Usage: sslt [-c client_nickname] [-n server_nickname] [-p passwd] [-d] testid\n",
00209 VERION_MAJOR, VERION_MINOR, VERSION_POINT);
00210 
00211     exit(0);
00212   }
00213 
00214   for (c = 1; c<ac; c++) {
00215        if (!PL_strcmp(av[c],"-c")) {
00216        
00217                 c++;
00218                 if (c < ac) {
00219                      client_nick = av[c];
00220                 }
00221                 else {
00222                        PR_fprintf(PR_STDOUT,"must supply argument for -c\n");
00223                        exit(0);
00224                 }
00225        }
00226 
00227        else if (!PL_strcmp(av[c],"-n")) {
00228        
00229                 c++;
00230                 if (c < ac) {
00231                      nickname = av[c];
00232                 }
00233                 else {
00234                        PR_fprintf(PR_STDOUT,"must supply argument for -n\n");
00235                        exit(0);
00236                 }
00237       }
00238          else if (!PL_strcmp(av[c],"-p")) {
00239 
00240                 c++;
00241                 if (c < ac) {
00242                      password = av[c];
00243                 }
00244                 else {
00245                        PR_fprintf(PR_STDOUT,"must supply argument for -p\n");
00246                        exit(0);
00247                 }
00248       }
00249        else if (!PL_strcmp(av[c],"-d")) {
00250                 c++;
00251                 debug++;
00252       }
00253        else 
00254               testId = atoi(av[c]);
00255   }
00256 
00257 
00258 
00259 #ifdef XP_PC
00260     __try {
00261 #endif
00262  
00263   r = PR_Initialize(ServerThread,ac,av,400);         /* is 400 enough? */
00264 
00265   /* returncode 99 means 'no error' */
00266   if (99 == r)  r = 0;
00267 
00268 #ifdef XP_PC
00269     } __except( PR_fprintf(PR_STDERR, "\nCERT-TEST crashed\n"), EXCEPTION_EXECUTE_HANDLER ) {
00270         r = 255;
00271     }
00272 #endif
00273 
00274   return r;
00275 
00276 }
00277 
00278 
00279 
00280 /* 
00281  * ServerThread
00282  * (errors 1-9,150-159)
00283  */
00284 
00285 
00286 PRInt32 ServerThread(PRInt32 argc,char **argv) {
00287 
00288   PRNetAddr na;
00289 
00290   PRStatus r;
00291   SECStatus rv;
00292   
00293   CERTCertDBHandle *cert_db_handle;
00294   PRInt32 i,j;
00295   struct ThreadData * td;
00296 
00297   
00298   /*   if (InvalidTestHack() == PR_TRUE) {
00299     return 0;
00300   }
00301   */
00302 
00303   rcmon = PR_NewMonitor();
00304   if (NULL == rcmon) return Error(140);
00305 
00306   PR_EnterMonitor(rcmon);
00307   rc = 0;
00308   PR_ExitMonitor(rcmon);
00309 
00310   InitCiphers();
00311   SetPolicy();
00312   SetupNickNames();
00313   
00314   cl.peer = &svr;
00315   svr.peer = &cl;
00316 
00317 
00318   r = OpenDBs();            /* open databases and set defaults */
00319   if (PR_SUCCESS != r) return r;
00320 
00321 
00322   r = CreateServerSocket(&svr);
00323   if (PR_SUCCESS != r) return r;
00324 
00325   r = ConfigServerSocket();
00326   if (PR_SUCCESS != r) return r;
00327 
00328   cl.peerport = svr.na.inet.port;
00329 
00330 
00331   r = SetServerSecParms(&svr);  /* configure server socket
00332                                    sid cache, certificate etc. */
00333   if (r) return r;
00334 
00335   r = SSL_HandshakeCallback(svr.r, HandshakeCallback, &svr);
00336   if (PR_SUCCESS != r) return Error(150);
00337 
00338   r = SSL_AuthCertificateHook(svr.r,AuthCertificate,&svr);
00339   if (PR_SUCCESS !=r ) return Error(151);
00340 
00341   /* The server socket is now set up. Now, we must start
00342      the client thread */
00343 
00344   svr.subthread =
00345     PR_CreateThread(PR_SYSTEM_THREAD,   /* Thread Type      */
00346                   ClientThread,       /* Start Function   */
00347                   NULL,               /* Argument         */
00348                   PR_PRIORITY_NORMAL, /* Priority         */
00349                   PR_GLOBAL_THREAD,   /* Scheduling scope */
00350                   PR_JOINABLE_THREAD, /* Thread State     */
00351                   0          /* Stacksize (0=use default) */
00352                   );
00353   if (svr.subthread == NULL) return Error(6);
00354 
00355 
00356   
00357   /* Wait for incoming connection from client thread */
00358 
00359   svr.s = PR_Accept(svr.r, NULL, PR_SecondsToInterval(100)); /* timeout */
00360   if (NULL == svr.s) {
00361     r = PR_GetError();
00362     if (r) {
00363       return Error(7);
00364     }
00365   }
00366 
00367   td = &svr;
00368   td->client = PR_FALSE;
00369   td->xor_reading = CLIENTXOR;
00370   td->xor_writing = 0;
00371   
00372   r = DoIO(td);
00373   dbmsg((PR_STDERR,"Server IO complete - returned %d\n",r));
00374   dbmsg((PR_STDERR,"PR_GetError() = %d\n",PR_GetError()));
00375 
00376 
00377   /* WHY IS THIS HERE???? */
00378   r = 0;
00379   if (r) return r;
00380   
00381 
00382   /* c = SSL_PeerCertificate(s); */
00383 
00384   r = PR_Close(svr.s);   /* close the SSL Socket */
00385   if (r != PR_SUCCESS) return Error(8);
00386 
00387   dbmsg((PR_STDERR,"PR_Close(svr.s) - returned %d\n",r));
00388 
00389   r = PR_Close(svr.r);  /* Close the rendezvous socket */
00390   if (r != PR_SUCCESS) return Error(8);
00391 
00392   dbmsg((PR_STDERR,"PR_Close(svr.r) - returned %d\n",r));
00393 
00394   r = PR_JoinThread(svr.subthread);
00395   if (r != PR_SUCCESS)  return Error(9);
00396 
00397   PR_EnterMonitor(rcmon);
00398   r = rc;
00399   PR_ExitMonitor(rcmon);
00400   
00401   dbmsg((PR_STDERR,"Client Thread Joined. client's returncode=%d\n",r));
00402   dbmsg((PR_STDERR,"Server Thread closing down.\n"));
00403 
00404   return r;
00405   
00406   }
00407 
00408 
00409 /*
00410  * Get security status for this socket
00411  *
00412  */ 
00413 
00414 int GetSecStatus(struct ThreadData *td) {
00415   int r;
00416 
00417   r = SSL_SecurityStatus(td->s,
00418                       &td->status_on,
00419                       &td->status_cipher,
00420                       &td->status_keysize,
00421                       &td->status_skeysize,
00422                       &td->status_issuer,
00423                       &td->status_subject
00424                       );
00425 
00426   return r;
00427   /* SSL_PeerCertificate(); */
00428 
00429 }
00430  
00431 
00432 
00433 
00434 /* Signal an error code for the process to return.
00435    If the peer aborted before us, returns 0.
00436    If the peer did not abort before us, returns the calling argument
00437    (to be used as a returncode) */
00438 int Error(int s)
00439 {
00440   int r;
00441 
00442   PR_EnterMonitor(rcmon);
00443   r = rc;
00444   if (0 == rc) { 
00445     rc = s;
00446   }    
00447   PR_ExitMonitor(rcmon);
00448 
00449   if (r) return s;
00450   else return 0;
00451 }
00452 
00453 
00454 
00455 #define ALLOWEDBYPROTOCOL    1
00456 #define ALLOWEDBYPOLICY      2
00457 #define ALLOWEDBYCIPHERSUITE 4
00458 
00459 /* This returns 0 if the status is what was expected at this point, else a returncode */
00460 
00461 
00462 int VerifyStatus(struct ThreadData *td)
00463 {
00464   int i,j;
00465   int matched =0;
00466 
00467   /* Go through all the ciphers until we find the first one that satisfies */
00468   /* all the criteria. The ciphers are listed in preferred order. So, the first */
00469   /* that matches should be the one. */
00470 
00471   /* because of bug 107086, I have to fudge this. If it weren't for this
00472      bug, SSL2 ciphers may get chosen in preference to SSL3 cipher,
00473      if they were stronger */
00474 
00475 
00476   for (i=0;i<cipher_array_size;i++) {
00477 
00478   /* IF */
00479 
00480     if (
00481 
00482        /* bug 107086. If SSL2 and SSL3 are enabled, ignore the SSL2 ciphers */
00483        (!( /* see above */
00484          (REP_SSLVersion2 && REP_SSLVersion3) && cipher_array[i].sslversion == 2)
00485         )
00486 
00487        &&
00488 
00489 
00490        (  /* Cipher is the right kind for the protocol? */
00491         ((cipher_array[i].sslversion == 2) && REP_SSLVersion2) ||
00492         ((cipher_array[i].sslversion == 3) && REP_SSLVersion3) 
00493         )
00494        
00495        &&  /* Cipher is switched on */
00496 
00497        ((cipher_array[i].on == 1) ||
00498         ((cipher_array[i].on == 2) &&
00499          (REP_ServerCert == SERVER_CERT_VERISIGN_STEPUP)))
00500 
00501        &&  /* Is this cipher enabled under this policy */
00502     
00503        (
00504         (REP_Policy == POLICY_DOMESTIC) ||
00505         ((REP_Policy == POLICY_EXPORT)  && 
00506          (cipher_array[i].exportable == SSL_ALLOWED)))
00507        )
00508 
00509   /* THEN */
00510       {
00511        /* This is the cipher the SSL library should have chosen */
00512        
00513        matched = 1;
00514        break; 
00515       }
00516   }
00517 
00518 GetSecStatus(td);
00519 
00520 
00521 #define SSLT_STATUS_CORRECT           0 /* The status is correct. Continue with test */
00522 #define SSLT_STATUS_WRONG_KEYSIZE     1 /* The reported keysize is incorrect. abort */
00523 #define SSLT_STATUS_WRONG_SKEYSIZE    2 /* The reported secret keysize is incorrect. abort */
00524 #define SSLT_STATUS_WRONG_DESCRIPTION 3 /* The reported description is incorrect. abort*/
00525 #define SSLT_STATUS_WRONG_ERRORCODE   4 /* sec. library error - but wrong one - abort */
00526 #define SSLT_STATUS_CORRECT_ERRORCODE 5 /* security library error - right one - abort with err 99 */
00527 
00528   if (matched) {
00529     if (td->status_keysize  != cipher_array[i].ks) {
00530       PR_fprintf(PR_STDERR,"wrong keysize. seclib: %d,  expected %d\n",
00531                td->status_keysize,cipher_array[i].ks);
00532       return  SSLT_STATUS_WRONG_KEYSIZE;
00533     }
00534     if (td->status_skeysize != cipher_array[i].sks) return SSLT_STATUS_WRONG_SKEYSIZE;
00535     if (PL_strcmp(td->status_cipher,cipher_array[i].name)) {
00536       PR_fprintf(PR_STDERR,"wrong cipher description.  seclib: %s, expected: %s\n",
00537             td->status_cipher,cipher_array[i].name);
00538       return SSLT_STATUS_WRONG_DESCRIPTION;
00539     }
00540 
00541     /* Should also check status_issuer and status_subject */
00542   
00543     return SSLT_STATUS_CORRECT;
00544   }
00545 
00546   else {
00547     /* if SSL wasn't enabled, security library should have returned a failure with
00548        SSL_ERROR_SSL_DISABLED 
00549        */
00550 
00551     /* Since we cannot set the client and server ciphersuites independently,
00552        there's not point in checking for NO_CYPHER_OVERLAP. That's why some
00553        of this is commented out.
00554        */
00555 
00556 #if 0
00557        if (PR_FALSE == REP_SSLVersion2 &&
00558            PR_FALSE == REP_SSLVersion3)
00559 {
00560 if ( (td->secerr_flag == PR_FALSE ) ||
00561           ((td->secerr_flag == PR_TRUE) && 
00562             !((td->secerr == SSL_ERROR_SSL_DISABLED) ||
00563              (td->secerr == SSL_ERROR_NO_CYPHER_OVERLAP))
00564        )) {
00565        return SSLT_STATUS_WRONG_ERRORCODE;
00566      }
00567      else
00568   return SSLT_STATUS_CORRECT_ERRORCODE;
00569    }
00570 
00571        else {
00572 
00573          /* If SSL was enabled, and we get here, then no ciphers were compatible
00574             (matched == 0). So, security library should have returned the error
00575             SSL_ERROR_NO_CYPHER_OVERLAP */
00576 
00577          if ((td->secerr_flag == PR_FALSE) ||
00578              ((td->secerr_flag == PR_TRUE) && (td->secerr != SSL_ERROR_NO_CYPHER_OVERLAP))) {
00579            return SSLT_STATUS_WRONG_ERRORCODE;
00580          }
00581          else return SSLT_STATUS_CORRECT_ERRORCODE;
00582        }
00583 #endif
00584   }
00585        return SSLT_STATUS_CORRECT_ERRORCODE;
00586 }
00587 
00588 
00589 /* 
00590  *  DoRedoHandshake()
00591  *
00592  * errors(90-99)
00593  *  99 means exit gracefully
00594  */
00595 
00596 int DoRedoHandshake(struct ThreadData *td) {
00597   int r;
00598 
00599 
00600   /* figure out if we really should do the RedoHandshake */
00601   if ((td->client  && (PR_TRUE== REP_ClientRedoHandshake)) ||
00602        (!td->client && (PR_TRUE== REP_ServerRedoHandshake))) {
00603 
00604     if ((!td->client && (SSLT_CLIENTAUTH_REDO==REP_ServerDoClientAuth))) {
00605        r = SSL_Enable(td->s, SSL_REQUEST_CERTIFICATE, 1);
00606     }
00607 
00608     r = SSL_RedoHandshake(td->s);          /* .. and redo the handshake */      
00609     if (PR_SUCCESS == r) {                  /* If the handshake succeeded,  */
00610                                             /* make sure that shouldn't have failed... */
00611 
00612        /*** 
00613           If the server is doing ClientAuth
00614            and the wrong certificate in the
00615           client, then the handshake should fail (but it succeeded)
00616           ***/
00617       
00618 #if 0
00619       if (SSLT_CLIENTAUTH_INITIAL == REP_ServerDoClientAuth) {
00620        if ((CLIENT_CERT_SPARK == REP_ClientCert) ||
00621            (SERVER_CERT_HARDCOREII_512       == REP_ClientCert) ||
00622            (NO_CERT                           == REP_ClientCert)
00623            ) 
00624          return Error(90);
00625 
00626       }
00627 #endif
00628       
00629     }
00630     
00631     else {  /* PR_FAILURE:            Make sure the handshake shouldn't have succeeded */
00632       
00633       /* First, abort the peer, since it cannot continue */
00634       r = Error(91);
00635       if (0==r) return 0;  /* peer aborted first */
00636       else {
00637       /***
00638        If the server is doing clientauth and
00639        a valid certificate was presented, the handshake
00640        should have succeeded (but it failed)
00641        ***/
00642       
00643        if (PR_TRUE == REP_ServerDoClientAuth) {
00644          if ((CLIENT_CERT_HARDCOREII_512         == REP_ClientCert) ||
00645              (CLIENT_CERT_HARDCOREII_1024        == REP_ClientCert) ||
00646              (CLIENT_CERT_VERISIGN               == REP_ClientCert) ||
00647              (SERVER_CERT_HARDCOREII_512         == REP_ClientCert)
00648              ) 
00649            return Error(91);
00650        }
00651       }
00652     }
00653   }
00654 }
00655 
00656 
00657 
00658 /* There is a independent State Machine for each of client and server.
00659    They have the following states:
00660 
00661    1. STATE_BEFORE_INITIAL_HANDSHAKE
00662       In this state at the very start. No I/O has been done on the socket,
00663       and no status has been collected. Once I/O has been done, we move on
00664       to state 2.
00665 
00666    2. STATE_BEFORE_REDO_HANDSHAKE
00667       If we won't be doing a redohandshake, move immediately to state3.
00668       Check security status to make sure selected cipher is correct.
00669       If we are doing a redohandshake, adjust the security parameters for
00670       the redo, and move to state 3.
00671    3. STATE_STATUS_COLLECTED
00672       When we move to this state, check security status.
00673       Remain in this state until either reading or writing is complete
00674    4. STATE_DONE_WRITING
00675       Come here when writing is complete. When reading is complete move
00676       to state 6.
00677    5. STATE_DONE_READING
00678       Come here when reading is complete. When writing is complete move
00679       to state 6.
00680    6. STATE_DONE
00681       We're done. Check that the appropriate callbacks were called at the
00682       appropriate times.
00683       */
00684     
00685 /* 
00686  * State Machine
00687  *
00688  * errors(80-89)
00689  */
00690 
00691 int NextState(struct ThreadData *td,
00692               int finishedReading,
00693               int finishedWriting) {
00694   int r;
00695 
00696 
00697 
00698   /* if we were in STATE_BEFORE_INITIAL_HANDSHAKE, and we came here, we must
00699      have just completed a handshake, so we can get status and move on
00700      to next state.  */
00701 
00702   if (STATE_BEFORE_INITIAL_HANDSHAKE == td->state ) {
00703     
00704     td->state = STATE_BEFORE_REDO_HANDSHAKE;  /* first set next state */
00705     
00706     r = GetSecStatus(td);
00707     if (PR_SUCCESS != r) {
00708       return Error(80);
00709     }
00710     
00711 #if 0
00712     r = VerifyStatus(td);   /* Call VerifyStatus to make sure that the connection is
00713                             what was expected */
00714     if (PR_SUCCESS != r) return r;
00715 #endif
00716 
00717       
00718   }
00719   
00720   if (STATE_BEFORE_REDO_HANDSHAKE == td->state) {
00721     /* If we're not going to do a redohandshake, we can just skip over this state */
00722     if (td->client) {
00723       if (PR_FALSE  == REP_ClientRedoHandshake) td->state = STATE_STATUS_COLLECTED;
00724     }
00725     else {
00726       if (PR_FALSE == REP_ServerRedoHandshake) td->state = STATE_STATUS_COLLECTED;
00727     }
00728     r = DoRedoHandshake(td);
00729     if (PR_SUCCESS != r) return r;
00730     td->state = STATE_STATUS_COLLECTED;
00731   }
00732                 
00733 
00734   switch (td->state) {
00735   case STATE_STATUS_COLLECTED:
00736     if (finishedWriting) td->state = STATE_DONE_WRITING;
00737     if (finishedReading) td->state = STATE_DONE_READING;
00738     break;
00739   case STATE_DONE_WRITING:
00740     if (finishedReading) td->state = STATE_DONE;
00741     break;
00742   case STATE_DONE_READING:
00743     if (finishedWriting) td->state = STATE_DONE;
00744     break;
00745   default:
00746     return PR_SUCCESS;
00747   }
00748 }
00749 
00750 
00751 /* CheckSSLEnabled:
00752    If there was an I/O, and SSL was disabled, then check the error
00753    code to make sure that the correct error was returned.
00754    The parameter passed in is the returncode from PR_Read or PR_Write
00755    */
00756 
00757 int CheckSSLEnabled(int j) {
00758   if (PR_FALSE == REP_SSLVersion2 &&
00759       PR_FALSE == REP_SSLVersion3) {
00760     if (( -1 != j ) ||
00761        (( -1 == j) && (PR_GetError() != SSL_ERROR_SSL_DISABLED))) {
00762       return 52;
00763     }
00764     else return 99;
00765   }
00766   else return 0;
00767 }
00768 
00769 
00770 
00771 /* 
00772  * Do I/O
00773  *
00774  * Errors 50-69
00775  */
00776  
00777 int DoIO(struct ThreadData *td) {
00778 
00779 int i,j,r;
00780 
00781   td->pd.fd        = td->s;
00782   td->pd.in_flags  = PR_POLL_READ | PR_POLL_WRITE | PR_POLL_EXCEPT;
00783   td->data_read    = 0;
00784   td->data_sent    = 0;
00785 
00786   td->data_tosend = REP_ServerIOSessionLength;
00787   
00788   td->state = STATE_BEFORE_INITIAL_HANDSHAKE;
00789 
00790 
00791   while (PR_TRUE) {
00792     dbmsg((PR_STDERR,"%s: DoIO loop\n",
00793               &svr==td ? "Server" : "Client"));
00794 
00795     /* pd = polldescriptor, 1 = number of descriptors, 5 = timeout in seconds */
00796     r = PR_Poll(&td->pd,1,PR_SecondsToInterval(5));
00797 
00798     /* Check if peer has already signalled an error condition */ 
00799 
00800     PR_EnterMonitor(rcmon);
00801     if (0 != rc) {
00802       /* got here? - means peer wants to stop. It has set the
00803         exit code */
00804       PR_ExitMonitor(rcmon);
00805       dbmsg((PR_STDERR,"%s: Peer has aborted (error code %d). We should too\n",
00806             &svr==td ? "Server" : "Client",rc));
00807       
00808       return 0;
00809     }
00810     else {
00811       PR_ExitMonitor(rcmon);
00812     }
00813 
00814     if (0 == r) ;   /* timeout occurred */
00815 
00816     if (td->pd.out_flags & PR_POLL_EXCEPT) return Error(50);
00817 
00818     /*******   Process incoming data   *******/
00819     
00820     if (! (STATE_DONE == td->state || STATE_DONE_READING == td->state)) {
00821       if (td->pd.out_flags & PR_POLL_READ) {
00822 
00823        td->secerr = 0;
00824        i = PR_Read(td->s, td->recvbuf, BUFSIZE);
00825 
00826        if (i < 0) {
00827          td->secerr_flag = 1;
00828          td->secerr = PR_GetError();
00829        }
00830        else td->secerr_flag =0;
00831 
00832        r = VerifyStatus(td);
00833 
00834        switch (r) {
00835        case SSLT_STATUS_CORRECT:
00836          break;
00837        case SSLT_STATUS_CORRECT_ERRORCODE:
00838          return Error(99);
00839        default:
00840          return Error(60+r);
00841        }
00842        
00843        r = VerifyBuffer(td->recvbuf, i, td->data_read, td->xor_reading);
00844        if (r) return r;
00845        td->data_read += i;
00846        
00847        /* Invoke State Machine */
00848 
00849        NextState(td, 0==i, 0);  /* if i is zero, signal 'finishedreading' */
00850 
00851       }
00852     }
00853     
00854     if (! (STATE_DONE == td->state || STATE_DONE_WRITING == td->state)) {
00855       if (td->pd.out_flags & PR_POLL_WRITE) {
00856        FillBuffer(td->sendbuf,BUFSIZE,td->data_sent,td->xor_writing);
00857 
00858        i = td->data_tosend - td->data_sent;
00859        if (i > BUFSIZE) i = BUFSIZE;  /* figure out how much
00860                                      data to send */
00861        td->secerr = 0;
00862        j = PR_Write(td->s, td->sendbuf, i);
00863 
00864 
00865        if (j < 0) {
00866          td->secerr_flag = 1;
00867          td->secerr = PR_GetError();
00868        }
00869        else td->secerr_flag =0;
00870 
00871        r = VerifyStatus(td);
00872 
00873        switch (r) {
00874        case SSLT_STATUS_CORRECT:
00875          break;
00876        case SSLT_STATUS_CORRECT_ERRORCODE:
00877          return Error(99);
00878        default:
00879          return Error(60+r);
00880        }
00881 
00882       }
00883       if (j == -1) return Error(53);        /* Error on socket (Not an error
00884                                     if nonblocking IO enabled, and
00885                                     Error is Would Block */
00886       
00887       if (j != i) return Error(54);         /* We didn't write the
00888                                         amount we should have */
00889       
00890       td->data_sent += j;
00891       
00892       if (td->data_sent == td->data_tosend) {
00893        PR_Shutdown(td->s,PR_SHUTDOWN_SEND);
00894       }
00895       
00896       /* next state of state machine */
00897 
00898       NextState(td,
00899               0,
00900               td->data_sent == td->data_tosend  /* finishedwriting */
00901               );      
00902     }
00903 
00904 
00905 
00906     if (STATE_DONE == td->state) break;
00907 
00908   } /* while (1) */
00909     
00910     dbmsg((PR_STDERR,"%s: DoIO loop:returning 0\n",
00911               &svr==td ? "Server" : "Client"));
00912 
00913     return 0;
00914     
00915 }
00916 
00917 
00918 
00919 
00920 /* This is the start of the client thread code */
00921 /* Client Thread errors(100-200) */
00922 
00923 
00924 /* 
00925  * CreateClientSocket()
00926  * errors (120-129)
00927  */
00928 
00929 
00930 int CreateClientSocket() {
00931   /* Create client socket s */
00932 
00933   cl.fd = PR_NewTCPSocket();
00934   if (cl.fd == NULL) return Error(120);  
00935 
00936   cl.s = SSL_ImportFD(NULL, cl.fd);
00937   if (cl.s == NULL) return Error(121);
00938 
00939   return 0;
00940 }  
00941 
00942 
00943 
00944 /* 
00945  * SetClientSecParms
00946  * errors(130-139)
00947  */
00948 
00949 int SetClientSecParams()  {
00950   int rv;
00951   /* SSL Enables */
00952   
00953   rv = SSL_Enable(cl.s, SSL_SECURITY, 1);
00954   if (rv < 0)  return Error(130);
00955 
00956   rv = Version23Clear(cl.s);
00957   if (rv) return rv;
00958 
00959   if (REP_SSLVersion2) {
00960     rv = Version2Enable(cl.s);
00961     if (rv) return rv;
00962   }
00963   if (REP_SSLVersion3) {
00964     rv = Version3Enable(cl.s);
00965     if (rv) return rv;
00966   }
00967 
00968   SSL_SetPKCS11PinArg(cl.s,(void*)MyPWFunc);
00969 
00970   if (REP_ClientCert == NO_CERT) {
00971     return 0;
00972   }
00973   else {
00974     cl.cert = PK11_FindCertFromNickname(client_nick,NULL);
00975   }
00976   if (cl.cert == NULL) return Error(131);
00977   
00978   return 0;
00979 }
00980 
00981 
00982 /*
00983  * Client()
00984  * errors (100-120)
00985  */
00986 
00987 int Client() {
00988   int r;
00989 
00990   r = CreateClientSocket();
00991   if (r) return r;
00992 
00993   r = SetClientSecParams();
00994   if (r) return r;
00995 
00996   /* Set address to connect to: localhost */
00997 
00998   r = PR_InitializeNetAddr(PR_IpAddrLoopback,0,&cl.na);
00999   cl.na.inet.port = cl.peerport;
01000   if (PR_FAILURE == r) return Error(101);
01001 
01002   r = SSL_AuthCertificateHook(cl.s,AuthCertificate,&cl);
01003   if (r) return Error(102);
01004   r = SSL_HandshakeCallback(cl.s,HandshakeCallback,&cl);
01005   if (r) return Error(103);
01006 
01007   r = PR_Connect(cl.s, &cl.na, PR_SecondsToInterval(50));
01008   if (PR_FAILURE == r) {
01009     dbmsg((PR_STDERR, "Client: Seclib error: %s\n",SECU_ErrorString ((int16) PR_GetError())));
01010     return Error(104);
01011   }
01012 
01013 
01014   if (PR_TRUE == REP_ClientForceHandshake) {
01015     r = SSL_ForceHandshake(cl.s);
01016     if (PR_FAILURE == r) {
01017       dbmsg((PR_STDERR, "Client: Seclib error: %s\n",
01018             SECU_ErrorString ((int16) PR_GetError())));
01019       return Error(105);
01020     }
01021   }
01022 
01023   cl.client = PR_TRUE;
01024   cl.xor_reading = 0;
01025   cl.xor_writing = CLIENTXOR;
01026   
01027   r = DoIO(&cl);
01028 
01029   dbmsg((PR_STDERR,"Client Thread done with IO. Returned %d\n",r));
01030 
01031 
01032   if (PR_SUCCESS != r) return r;
01033 
01034   r = PR_Close(cl.s);
01035 
01036   dbmsg((PR_STDERR,"Client Socket closing. Returned %d\n",r));
01037 
01038   return Error(r);
01039   
01040 }
01041 
01042 
01043 
01044  void ClientThread(void *arg) {
01045    int r;
01046 
01047    Error(Client());
01048 
01049    dbmsg((PR_STDERR,"Client Thread returning %d\n",r));
01050    
01051    
01052  }
01053 
01054    
01055 
01056 
01057 
01058 
01059  /* VerifyBuffer() */
01060 
01061 /* verify the data in the buffer. Returns 0 if valid  */
01062 /* recvbuf = start of data to verify
01063  * bufsize = amount of data to verify
01064  * done    = how to offset the reference data. How much 
01065              data we have done in previous sessions
01066  * xor     = xor character 
01067 
01068  * errors 70-79
01069 
01070  */
01071  
01072  int VerifyBuffer(char *recvbuf,int bufsize,int done, char xor) {
01073   int i,j,k;
01074 
01075   while (bufsize) {
01076     i = done % DATABUFSIZE;
01077 
01078     k = DATABUFSIZE;
01079     if (bufsize < k) {
01080       k = bufsize;
01081     }
01082     for (j = i; j < k ; j++) {
01083       if ((data[j] ^ xor) != (*recvbuf)) {
01084        return 71;
01085       }
01086       
01087       recvbuf++;
01088     }
01089     done += k-i;
01090     bufsize -= (k - i);
01091     if (bufsize < 0) return 73;
01092   }
01093   return (0);
01094 }
01095 
01096 
01097 /* fill the buffer.  */
01098 
01099  void FillBuffer(char *sendbuf,int bufsize, int offset, char xor) {
01100    int done=0,i,j;
01101    
01102    while (done < bufsize) {
01103     i = offset % DATABUFSIZE;
01104     for (j = i; j < DATABUFSIZE ; j++) {
01105       *sendbuf = (data[j] ^ xor);
01106       sendbuf++;
01107     }
01108     done += (DATABUFSIZE - i);
01109     offset += (DATABUFSIZE - i);
01110    }
01111  }
01112  
01113  
01114  
01115  
01116 /******     CALLBACKS      *******/
01117  
01118 
01119 
01120 /* HandshakeCallback
01121    This function gets called when a handshake has just completed.
01122    (maybe gets called more than once for example if we RedoHandshake)
01123    */
01124 
01125  void HandshakeCallback(PRFileDesc *s, void *td)   {
01126    int r;
01127 
01128    /*   1. Get status of connection */
01129 
01130    r = GetSecStatus(td);
01131    if (PR_SUCCESS != r) {
01132      /* Abort */
01133    }
01134    else {
01135 
01136    /*   2. Verify status of connection */
01137 
01138 #if 0   
01139   r =VerifyStatus(td); 
01140      if (PR_SUCCESS != r) {
01141        /* Abort */
01142      }
01143 #endif
01144    }
01145 
01146  }
01147  
01148 
01149 
01150 /* This function gets called by the client thread's SSL code to verify
01151    the server's certificate. We cannot use the default AuthCertificate
01152    code because the certificates are used on multiple hosts, so
01153    CERT_VerifyCertNow() would fail with an IP address mismatch error
01154    */
01155 
01156 int
01157 AuthCertificate(void *arg, PRFileDesc *fd, PRBool checkSig, PRBool isServer)
01158 {
01159     SECStatus rv;
01160     CERTCertDBHandle *handle;
01161     /*    PRFileDesc *ss; */
01162     SECCertUsage certUsage;
01163     
01164     /*     ss = ssl_FindSocket(fd);
01165     PORT_Assert(ss != NULL); */
01166 
01167     handle = (CERTCertDBHandle *)arg;
01168 
01169     if ( isServer ) {
01170        certUsage = certUsageSSLClient;
01171     } else {
01172        certUsage = certUsageSSLServer;
01173     }
01174     
01175     /*     rv = CERT_VerifyCertNow(handle, ss->sec->peerCert, checkSig, certUsage, arg); */
01176 
01177     return((int)PR_SUCCESS);
01178 }
01179 
01180 
01181 
01182 
01183 
01184 
01185 
01186