Back to index

lightning-sunbird  0.9+nobinonly
ssltap.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 /*
00038  * ssltap.c
00039  *
00040  * Version 1.0 : Frederick Roeber : 11 June 1997
00041  * Version 2.0 : Steve Parkinson  : 13 November 1997
00042  * Version 3.0 : Nelson Bolyard   : 22 July 1998
00043  * Version 3.1 : Nelson Bolyard   : 24 May  1999
00044  *
00045  * changes in version 2.0:
00046  *  Uses NSPR20
00047  *  Shows structure of SSL negotiation, if enabled.
00048  *
00049  * This "proxies" a socket connection (like a socks tunnel), but displays the
00050  * data is it flies by.
00051  *
00052  * In the code, the 'client' socket is the one on the client side of the
00053  * proxy, and the server socket is on the server side.
00054  *
00055  */
00056 
00057 #include "nspr.h"
00058 #include "plstr.h"
00059 #include "secutil.h"
00060 #include <memory.h>  /* for memcpy, etc. */
00061 #include <string.h>
00062 #include <time.h>
00063 
00064 #include "plgetopt.h"
00065 #include "nss.h"
00066 #include "cert.h"
00067 
00068 #define VERSIONSTRING "$Revision: 1.7.2.2 $ ($Date: 2006/07/19 01:18:33 $) $Author: nelson%bolyard.com $"
00069 
00070 
00071 struct _DataBufferList;
00072 struct _DataBuffer;
00073 
00074 typedef struct _DataBufferList {
00075   struct _DataBuffer *first,*last;
00076   int size;
00077   int isEncrypted;
00078 } DataBufferList;
00079 
00080 typedef struct _DataBuffer {
00081   unsigned char *buffer;
00082   int length;
00083   int offset;  /* offset of first good byte */
00084   struct _DataBuffer *next;
00085 } DataBuffer;
00086 
00087 
00088 DataBufferList
00089   clientstream = {NULL, NULL, 0, 0},
00090   serverstream = {NULL, NULL, 0, 0};
00091 
00092 struct sslhandshake {
00093   PRUint8 type;
00094   PRUint32 length;
00095 };
00096 
00097 typedef struct _SSLRecord {
00098   PRUint8 type;
00099   PRUint8 ver_maj,ver_min;
00100 
00101   PRUint8 length[2];
00102 } SSLRecord;
00103 
00104 typedef struct _ClientHelloV2 {
00105   PRUint8 length[2];
00106   PRUint8 type;
00107   PRUint8 version[2];
00108   PRUint8 cslength[2];
00109   PRUint8 sidlength[2];
00110   PRUint8 rndlength[2];
00111   PRUint8 csuites[1];
00112 } ClientHelloV2;
00113 
00114 typedef struct _ServerHelloV2 {
00115   PRUint8 length[2];
00116   PRUint8 type;
00117   PRUint8 sidhit;
00118   PRUint8 certtype;
00119   PRUint8 version[2];
00120   PRUint8 certlength[2];
00121   PRUint8 cslength[2];
00122   PRUint8 cidlength[2];
00123 } ServerHelloV2;
00124 
00125 typedef struct _ClientMasterKeyV2 {
00126   PRUint8 length[2];
00127   PRUint8 type;
00128 
00129   PRUint8 cipherkind[3];
00130   PRUint8 clearkey[2];
00131   PRUint8 secretkey[2];
00132 
00133 } ClientMasterKeyV2;
00134 
00135 
00136 
00137 #define TAPBUFSIZ 16384
00138 
00139 #define DEFPORT 1924
00140 #include <ctype.h>
00141 
00142 int hexparse=0;
00143 int sslparse=0;
00144 int sslhexparse=0;
00145 int looparound=0;
00146 int fancy=0;
00147 int isV2Session=0;
00148 
00149 #define PR_FPUTS(x) PR_fprintf(PR_STDOUT, x )
00150 
00151 #define GET_SHORT(x) ((PRUint16)(((PRUint16)((PRUint8*)x)[0]) << 8) + ((PRUint16)((PRUint8*)x)[1]))
00152 #define GET_24(x) ((PRUint32)   (  \
00153                              (((PRUint32)((PRUint8*)x)[0]) << 16) \
00154                              +                          \
00155                              (((PRUint32)((PRUint8*)x)[1]) << 8)  \
00156                              +                          \
00157                              (((PRUint32)((PRUint8*)x)[2]) << 0)  \
00158                              ) )
00159 
00160 void print_hex(int amt, unsigned char *buf);
00161 void read_stream_bytes(unsigned char *d, DataBufferList *db, int length);
00162 
00163 void myhalt(int dblsize,int collectedsize) {
00164 
00165   while(1) ;
00166 
00167 }
00168 
00169 const char *get_error_text(int error) {
00170   switch (error) {
00171   case PR_IO_TIMEOUT_ERROR:
00172     return "Timeout";
00173     break;
00174   case PR_CONNECT_REFUSED_ERROR:
00175     return "Connection refused";
00176     break;
00177   case PR_NETWORK_UNREACHABLE_ERROR:
00178     return "Network unreachable";
00179     break;
00180   case PR_BAD_ADDRESS_ERROR:
00181     return "Bad address";
00182     break;
00183   case PR_CONNECT_RESET_ERROR:
00184     return "Connection reset";
00185     break;
00186   case PR_PIPE_ERROR:
00187     return "Pipe error";
00188     break;
00189   }
00190 
00191   return "";
00192 }
00193 
00194 
00195 
00196 
00197 
00198 void check_integrity(DataBufferList *dbl) {
00199   DataBuffer *db;
00200   int i;
00201 
00202   db = dbl->first;
00203   i =0;
00204   while (db) {
00205     i+= db->length - db->offset;
00206     db = db->next;
00207   }
00208   if (i != dbl->size) {
00209     myhalt(dbl->size,i);
00210   }
00211 }
00212 
00213 /* Free's the DataBuffer at the head of the list and returns the pointer
00214  * to the new head of the list.
00215  */
00216 DataBuffer * 
00217 free_head(DataBufferList *dbl)
00218 {
00219   DataBuffer *db       = dbl->first;
00220   PR_ASSERT(db->offset >= db->length);
00221   if (db->offset >= db->length) {
00222     dbl->first = db->next;
00223     if (dbl->first == NULL) {
00224       dbl->last = NULL;
00225     }
00226     PR_Free(db->buffer);
00227     PR_Free(db);
00228     db = dbl->first;
00229   }
00230   return db;
00231 }
00232 
00233 void 
00234 read_stream_bytes(unsigned char *d, DataBufferList *dbl, int length) {
00235   int         copied        = 0;
00236   DataBuffer *db     = dbl->first;
00237 
00238   if (!db) {
00239     PR_fprintf(PR_STDERR,"assert failed - dbl->first is null\n");
00240     exit(8);
00241   }
00242   while (length) {
00243     int         toCopy;
00244     /* find the number of bytes to copy from the head buffer */
00245     /* if there's too many in this buffer, then only copy 'length' */
00246     toCopy = PR_MIN(db->length - db->offset, length);
00247 
00248     memcpy(d + copied, db->buffer + db->offset, toCopy);
00249     copied     += toCopy;
00250     db->offset += toCopy;
00251     length     -= toCopy;
00252     dbl->size  -= toCopy;
00253 
00254     /* if we emptied the head buffer */
00255     if (db->offset >= db->length) {
00256       db = free_head(dbl);
00257     }
00258   }
00259 
00260   check_integrity(dbl);
00261 
00262 }
00263 
00264 void
00265 flush_stream(DataBufferList *dbl)
00266 {
00267     DataBuffer *db = dbl->first;
00268     check_integrity(dbl);
00269     while (db) {
00270        db->offset = db->length;
00271        db = free_head(dbl);
00272     }
00273     dbl->size = 0;
00274     check_integrity(dbl);
00275 }
00276 
00277 
00278 const char * V2CipherString(int cs_int) {
00279   char *cs_str;
00280   cs_str = NULL;
00281   switch (cs_int) {
00282 
00283   case 0x010080:    cs_str = "SSL2/RSA/RC4-128/MD5";       break;
00284   case 0x020080:    cs_str = "SSL2/RSA/RC4-40/MD5";    break;
00285   case 0x030080:    cs_str = "SSL2/RSA/RC2CBC128/MD5";     break;
00286   case 0x040080:    cs_str = "SSL2/RSA/RC2CBC40/MD5";  break;
00287   case 0x050080:    cs_str = "SSL2/RSA/IDEA128CBC/MD5";    break;
00288   case 0x060040:    cs_str = "SSL2/RSA/DES56-CBC/MD5";      break;
00289   case 0x0700C0:    cs_str = "SSL2/RSA/3DES192EDE-CBC/MD5"; break;
00290 
00291   case 0x000001:    cs_str = "SSL3/RSA/NULL/MD5";             break;
00292   case 0x000002:    cs_str = "SSL3/RSA/NULL/SHA";             break;
00293   case 0x000003:    cs_str = "SSL3/RSA/RC4-40/MD5";       break;
00294   case 0x000004:    cs_str = "SSL3/RSA/RC4-128/MD5";          break;
00295   case 0x000005:    cs_str = "SSL3/RSA/RC4-128/SHA";          break;
00296   case 0x000006:    cs_str = "SSL3/RSA/RC2CBC40/MD5";     break;
00297   case 0x000007:    cs_str = "SSL3/RSA/IDEA128CBC/SHA";       break;
00298   case 0x000008:    cs_str = "SSL3/RSA/DES40-CBC/SHA";         break;
00299   case 0x000009:    cs_str = "SSL3/RSA/DES56-CBC/SHA";         break;
00300   case 0x00000A:    cs_str = "SSL3/RSA/3DES192EDE-CBC/SHA";    break;
00301 
00302   case 0x00000B:    cs_str = "SSL3/DH-DSS/DES40-CBC/SHA";      break;
00303   case 0x00000C:    cs_str = "SSL3/DH-DSS/DES56-CBC/SHA";      break;
00304   case 0x00000D:    cs_str = "SSL3/DH-DSS/DES192EDE3CBC/SHA"; break;
00305   case 0x00000E:    cs_str = "SSL3/DH-RSA/DES40-CBC/SHA";      break;
00306   case 0x00000F:    cs_str = "SSL3/DH-RSA/DES56-CBC/SHA";      break;
00307   case 0x000010:    cs_str = "SSL3/DH-RSA/3DES192EDE-CBC/SHA"; break;
00308 
00309   case 0x000011:    cs_str = "SSL3/DHE-DSS/DES40-CBC/SHA";      break;
00310   case 0x000012:    cs_str = "SSL3/DHE-DSS/DES56-CBC/SHA";      break;
00311   case 0x000013:    cs_str = "SSL3/DHE-DSS/DES192EDE3CBC/SHA"; break;
00312   case 0x000014:    cs_str = "SSL3/DHE-RSA/DES40-CBC/SHA";      break;
00313   case 0x000015:    cs_str = "SSL3/DHE-RSA/DES56-CBC/SHA";      break;
00314   case 0x000016:    cs_str = "SSL3/DHE-RSA/3DES192EDE-CBC/SHA"; break;
00315 
00316   case 0x000017:    cs_str = "SSL3/DH-anon/RC4-40/MD5";     break;
00317   case 0x000018:    cs_str = "SSL3/DH-anon/RC4-128/MD5";        break;
00318   case 0x000019:    cs_str = "SSL3/DH-anon/DES40-CBC/SHA";       break;
00319   case 0x00001A:    cs_str = "SSL3/DH-anon/DES56-CBC/SHA";       break;
00320   case 0x00001B:    cs_str = "SSL3/DH-anon/3DES192EDE-CBC/SHA"; break;
00321 
00322   case 0x00001C:    cs_str = "SSL3/FORTEZZA-DMS/NULL/SHA";      break;
00323   case 0x00001D:    cs_str = "SSL3/FORTEZZA-DMS/FORTEZZA-CBC/SHA";  break;
00324   case 0x00001E:    cs_str = "SSL3/FORTEZZA-DMS/RC4-128/SHA";  break;
00325 
00326   case 0x00002F:    cs_str = "TLS/RSA/AES128-CBC/SHA";         break;
00327   case 0x000030:    cs_str = "TLS/DH-DSS/AES128-CBC/SHA";      break;
00328   case 0x000031:    cs_str = "TLS/DH-RSA/AES128-CBC/SHA";      break;
00329   case 0x000032:    cs_str = "TLS/DHE-DSS/AES128-CBC/SHA";     break;
00330   case 0x000033:    cs_str = "TLS/DHE-RSA/AES128-CBC/SHA";     break;
00331   case 0x000034:    cs_str = "TLS/DH-ANON/AES128-CBC/SHA";     break;
00332 
00333   case 0x000035:    cs_str = "TLS/RSA/AES256-CBC/SHA";         break;
00334   case 0x000036:    cs_str = "TLS/DH-DSS/AES256-CBC/SHA";      break;
00335   case 0x000037:    cs_str = "TLS/DH-RSA/AES256-CBC/SHA";      break;
00336   case 0x000038:    cs_str = "TLS/DHE-DSS/AES256-CBC/SHA";     break;
00337   case 0x000039:    cs_str = "TLS/DHE-RSA/AES256-CBC/SHA";     break;
00338   case 0x00003A:    cs_str = "TLS/DH-ANON/AES256-CBC/SHA";     break;
00339 
00340   case 0x000041:    cs_str = "TLS/RSA/CAMELLIA128-CBC/SHA";    break;
00341   case 0x000042:    cs_str = "TLS/DH-DSS/CAMELLIA128-CBC/SHA"; break;
00342   case 0x000043:    cs_str = "TLS/DH-RSA/CAMELLIA128-CBC/SHA"; break;
00343   case 0x000044:    cs_str = "TLS/DHE-DSS/CAMELLIA128-CBC/SHA";       break;
00344   case 0x000045:    cs_str = "TLS/DHE-RSA/CAMELLIA128-CBC/SHA";       break;
00345   case 0x000046:    cs_str = "TLS/DH-ANON/CAMELLIA128-CBC/SHA";       break;
00346 
00347   case 0x000047:    cs_str = "TLS/ECDH-ECDSA/NULL/SHA";        break;
00348   case 0x000048:    cs_str = "TLS/ECDH-ECDSA/RC4-128/SHA";     break;
00349   case 0x000049:    cs_str = "TLS/ECDH-ECDSA/DES-CBC/SHA";     break;
00350   case 0x00004A:    cs_str = "TLS/ECDH-ECDSA/3DESEDE-CBC/SHA"; break;
00351   case 0x00004B:    cs_str = "TLS/ECDH-ECDSA/AES128-CBC/SHA";  break;
00352   case 0x00004C:    cs_str = "TLS/ECDH-ECDSA/AES256-CBC/SHA";  break;
00353 
00354   case 0x00004D:    cs_str = "TLS/ECDH-RSA/NULL/SHA";          break;
00355   case 0x00004E:    cs_str = "TLS/ECDH-RSA/RC4-128/SHA";       break;
00356   case 0x00004F:    cs_str = "TLS/ECDH-RSA/DES-CBC/SHA";       break;
00357   case 0x000050:    cs_str = "TLS/ECDH-RSA/3DESEDE-CBC/SHA";   break;
00358   case 0x000051:    cs_str = "TLS/ECDH-RSA/AES128-CBC/SHA";    break;
00359   case 0x000052:    cs_str = "TLS/ECDH-RSA/AES256-CBC/SHA";    break;
00360 
00361   case 0x000060:    cs_str = "TLS/RSA-EXPORT1024/RC4-56/MD5";  break;
00362   case 0x000061:    cs_str = "TLS/RSA-EXPORT1024/RC2CBC56/MD5";       break;
00363   case 0x000062:    cs_str = "TLS/RSA-EXPORT1024/DES56-CBC/SHA";   break;
00364   case 0x000064:    cs_str = "TLS/RSA-EXPORT1024/RC4-56/SHA";     break;
00365   case 0x000063:    cs_str = "TLS/DHE-DSS_EXPORT1024/DES56-CBC/SHA"; break;
00366   case 0x000065:    cs_str = "TLS/DHE-DSS_EXPORT1024/RC4-56/SHA";  break;
00367   case 0x000066:    cs_str = "TLS/DHE-DSS/RC4-128/SHA";           break;
00368 
00369   case 0x000072:    cs_str = "TLS/DHE-DSS/3DESEDE-CBC/RMD160"; break;
00370   case 0x000073:    cs_str = "TLS/DHE-DSS/AES128-CBC/RMD160";  break;
00371   case 0x000074:    cs_str = "TLS/DHE-DSS/AES256-CBC/RMD160";  break;
00372 
00373   case 0x000077:    cs_str = "TLS/ECDHE-ECDSA/AES128-CBC/SHA"; break;
00374   case 0x000078:    cs_str = "TLS/ECDHE-RSA/AES128-CBC/SHA";   break;
00375 
00376   case 0x000079:    cs_str = "TLS/DHE-RSA/AES256-CBC/RMD160";  break;
00377 
00378   case 0x00007C:    cs_str = "TLS/RSA/3DESEDE-CBC/RMD160"; break;
00379   case 0x00007D:    cs_str = "TLS/RSA/AES128-CBC/RMD160"; break;
00380   case 0x00007E:    cs_str = "TLS/RSA/AES256-CBC/RMD160"; break;
00381 
00382   case 0x000080:    cs_str = "TLS/GOST341094/GOST28147-OFB/GOST28147"; break;
00383   case 0x000081:    cs_str = "TLS/GOST34102001/GOST28147-OFB/GOST28147"; break;
00384   case 0x000082:    cs_str = "TLS/GOST341094/NULL/GOSTR3411"; break;
00385   case 0x000083:    cs_str = "TLS/GOST34102001/NULL/GOSTR3411"; break;
00386 
00387   case 0x000084:    cs_str = "TLS/RSA/CAMELLIA256-CBC/SHA";    break;
00388   case 0x000085:    cs_str = "TLS/DH-DSS/CAMELLIA256-CBC/SHA"; break;
00389   case 0x000086:    cs_str = "TLS/DH-RSA/CAMELLIA256-CBC/SHA"; break;
00390   case 0x000087:    cs_str = "TLS/DHE-DSS/CAMELLIA256-CBC/SHA";       break;
00391   case 0x000088:    cs_str = "TLS/DHE-RSA/CAMELLIA256-CBC/SHA";       break;
00392   case 0x000089:    cs_str = "TLS/DH-ANON/CAMELLIA256-CBC/SHA";       break;
00393   case 0x00008A:    cs_str = "TLS/PSK/RC4-128/SHA";            break;
00394   case 0x00008B:    cs_str = "TLS/PSK/3DES-EDE-CBC/SHA";       break;
00395   case 0x00008C:    cs_str = "TLS/PSK/AES128-CBC/SHA";         break;      
00396   case 0x00008D:    cs_str = "TLS/PSK/AES256-CBC/SHA";         break;      
00397   case 0x00008E:    cs_str = "TLS/DHE-PSK/RC4-128/SHA";        break;      
00398   case 0x00008F:    cs_str = "TLS/DHE-PSK/3DES-EDE-CBC/SHA";   break; 
00399   case 0x000090:    cs_str = "TLS/DHE-PSK/AES128-CBC/SHA";     break;  
00400   case 0x000091:    cs_str = "TLS/DHE-PSK/AES256-CBC/SHA";     break;  
00401   case 0x000092:    cs_str = "TLS/RSA-PSK/RC4-128/SHA";        break;      
00402   case 0x000093:    cs_str = "TLS/RSA-PSK/3DES-EDE-CBC/SHA";   break; 
00403   case 0x000094:    cs_str = "TLS/RSA-PSK/AES128-CBC/SHA";     break;  
00404   case 0x000095:    cs_str = "TLS/RSA-PSK/AES256-CBC/SHA";     break;  
00405   case 0x000096:    cs_str = "TLS/RSA/SEED-CBC/SHA";           break;         
00406   case 0x000097:    cs_str = "TLS/DH-DSS/SEED-CBC/SHA";        break;      
00407   case 0x000098:    cs_str = "TLS/DH-RSA/SEED-CBC/SHA";        break;      
00408   case 0x000099:    cs_str = "TLS/DHE-DSS/SEED-CBC/SHA";       break;     
00409   case 0x00009A:    cs_str = "TLS/DHE-RSA/SEED-CBC/SHA";       break;     
00410   case 0x00009B:    cs_str = "TLS/DH-ANON/SEED-CBC/SHA";       break;     
00411 
00412   case 0x00C001:    cs_str = "TLS/ECDH-ECDSA/NULL/SHA";         break;
00413   case 0x00C002:    cs_str = "TLS/ECDH-ECDSA/RC4-128/SHA";      break;
00414   case 0x00C003:    cs_str = "TLS/ECDH-ECDSA/3DES-EDE-CBC/SHA"; break;
00415   case 0x00C004:    cs_str = "TLS/ECDH-ECDSA/AES128-CBC/SHA";   break;
00416   case 0x00C005:    cs_str = "TLS/ECDH-ECDSA/AES256-CBC/SHA";   break;
00417   case 0x00C006:    cs_str = "TLS/ECDHE-ECDSA/NULL/SHA";        break;
00418   case 0x00C007:    cs_str = "TLS/ECDHE-ECDSA/RC4-128/SHA";     break;
00419   case 0x00C008:    cs_str = "TLS/ECDHE-ECDSA/3DES-EDE-CBC/SHA";break;
00420   case 0x00C009:    cs_str = "TLS/ECDHE-ECDSA/AES128-CBC/SHA";  break;
00421   case 0x00C00A:    cs_str = "TLS/ECDHE-ECDSA/AES256-CBC/SHA";  break;
00422   case 0x00C00B:    cs_str = "TLS/ECDH-RSA/NULL/SHA";           break;
00423   case 0x00C00C:    cs_str = "TLS/ECDH-RSA/RC4-128/SHA";        break;
00424   case 0x00C00D:    cs_str = "TLS/ECDH-RSA/3DES-EDE-CBC/SHA";   break;
00425   case 0x00C00E:    cs_str = "TLS/ECDH-RSA/AES128-CBC/SHA";     break;
00426   case 0x00C00F:    cs_str = "TLS/ECDH-RSA/AES256-CBC/SHA";     break;
00427   case 0x00C010:    cs_str = "TLS/ECDHE-RSA/NULL/SHA";          break;
00428   case 0x00C011:    cs_str = "TLS/ECDHE-RSA/RC4-128/SHA";       break;
00429   case 0x00C012:    cs_str = "TLS/ECDHE-RSA/3DES-EDE-CBC/SHA";  break;
00430   case 0x00C013:    cs_str = "TLS/ECDHE-RSA/AES128-CBC/SHA";    break;
00431   case 0x00C014:    cs_str = "TLS/ECDHE-RSA/AES256-CBC/SHA";    break;
00432   case 0x00C015:    cs_str = "TLS/ECDH-anon/NULL/SHA";          break;
00433   case 0x00C016:    cs_str = "TLS/ECDH-anon/RC4-128/SHA";       break;
00434   case 0x00C017:    cs_str = "TLS/ECDH-anon/3DES-EDE-CBC/SHA";  break;
00435   case 0x00C018:    cs_str = "TLS/ECDH-anon/AES128-CBC/SHA";    break;
00436   case 0x00C019:    cs_str = "TLS/ECDH-anon/AES256-CBC/SHA";    break;
00437 
00438   case 0x00feff:    cs_str = "SSL3/RSA-FIPS/3DESEDE-CBC/SHA";  break;
00439   case 0x00fefe:    cs_str = "SSL3/RSA-FIPS/DES-CBC/SHA";      break;
00440   case 0x00ffe1:    cs_str = "SSL3/RSA-FIPS/DES56-CBC/SHA";     break;
00441   case 0x00ffe0:    cs_str = "SSL3/RSA-FIPS/3DES192EDE-CBC/SHA";break;
00442 
00443   /* the string literal is broken up to avoid trigraphs */
00444   default:          cs_str = "????" "/????????" "/?????????" "/???"; break;
00445   }
00446 
00447   return cs_str;
00448 }
00449 
00450 const char * helloExtensionNameString(int ex_num) {
00451   const char *ex_name = NULL;
00452   static char buf[10];
00453 
00454   switch (ex_num) {
00455   case  0: ex_name = "server_name";                    break;
00456   case  1: ex_name = "max_fragment_length";            break;
00457   case  2: ex_name = "client_certificate_url";         break;
00458   case  3: ex_name = "trusted_ca_keys";                break;
00459   case  4: ex_name = "truncated_hmac";                 break;
00460   case  5: ex_name = "status_request";                 break;
00461   case 10: ex_name = "elliptic_curves";                break;
00462   case 11: ex_name = "ec_point_formats";               break;
00463   default: sprintf(buf, "%d", ex_num);  ex_name = (const char *)buf; break;
00464   }
00465 
00466   return ex_name;
00467 }
00468 
00469 void partial_packet(int thispacket, int size, int needed)
00470 {
00471   PR_fprintf(PR_STDOUT,"(%u bytes", thispacket);
00472   if (thispacket < needed) {
00473     PR_fprintf(PR_STDOUT,", making %u", size);
00474   }
00475   PR_fprintf(PR_STDOUT," of %u", needed);
00476   if (size > needed) {
00477     PR_fprintf(PR_STDOUT,", with %u left over", size - needed);
00478   }
00479   PR_fprintf(PR_STDOUT,")\n");
00480 }
00481 
00482 char * get_time_string(void)
00483 {
00484   char      *cp;
00485   char      *eol;
00486   time_t     tt;
00487 
00488   time(&tt);
00489   cp = ctime(&tt);
00490   eol = strchr(cp, '\n');
00491   if (eol) 
00492     *eol = 0;
00493   return cp;
00494 }
00495 
00496 void print_sslv2(DataBufferList *s, unsigned char *tbuf, unsigned int alloclen)
00497 {
00498   ClientHelloV2 *chv2;
00499   ServerHelloV2 *shv2;
00500   unsigned char *pos;
00501   unsigned int   p;
00502   unsigned int   q;
00503   PRUint32       len;
00504 
00505   chv2 = (ClientHelloV2 *)tbuf;
00506   shv2 = (ServerHelloV2 *)tbuf;
00507   if (s->isEncrypted) {
00508     PR_fprintf(PR_STDOUT," [ssl2]  Encrypted {...}\n");
00509     return;
00510   }
00511   PR_fprintf(PR_STDOUT," [%s]", get_time_string() );
00512   switch(chv2->type) {
00513   case 1:
00514     PR_fprintf(PR_STDOUT," [ssl2]  ClientHelloV2 {\n");
00515     PR_fprintf(PR_STDOUT,"           version = {0x%02x, 0x%02x}\n",
00516               (PRUint32)chv2->version[0],(PRUint32)chv2->version[1]);
00517     PR_fprintf(PR_STDOUT,"           cipher-specs-length = %d (0x%02x)\n",
00518               (PRUint32)(GET_SHORT((chv2->cslength))),
00519               (PRUint32)(GET_SHORT((chv2->cslength))));
00520     PR_fprintf(PR_STDOUT,"           sid-length = %d (0x%02x)\n",
00521               (PRUint32)(GET_SHORT((chv2->sidlength))),
00522               (PRUint32)(GET_SHORT((chv2->sidlength))));
00523     PR_fprintf(PR_STDOUT,"           challenge-length = %d (0x%02x)\n",
00524               (PRUint32)(GET_SHORT((chv2->rndlength))),
00525               (PRUint32)(GET_SHORT((chv2->rndlength))));
00526     PR_fprintf(PR_STDOUT,"           cipher-suites = { \n");
00527     for (p=0;p<GET_SHORT((chv2->cslength));p+=3) {
00528       const char *cs_str=NULL;
00529       PRUint32 cs_int=0;
00530       cs_int = GET_24((&chv2->csuites[p]));
00531       cs_str = V2CipherString(cs_int);
00532 
00533       PR_fprintf(PR_STDOUT,"                (0x%06x) %s\n",
00534                 cs_int, cs_str);
00535     }
00536     q = p;
00537     PR_fprintf(PR_STDOUT,"                }\n");
00538     if (chv2->sidlength) {
00539       PR_fprintf(PR_STDOUT,"           session-id = { ");
00540       for (p=0;p<GET_SHORT((chv2->sidlength));p+=2) {
00541        PR_fprintf(PR_STDOUT,"0x%04x ",(PRUint32)(GET_SHORT((&chv2->csuites[p+q]))));
00542       }
00543     }
00544     q += p;
00545     PR_fprintf(PR_STDOUT,"}\n");
00546     if (chv2->rndlength) {
00547       PR_fprintf(PR_STDOUT,"           challenge = { ");
00548       for (p=0;p<GET_SHORT((chv2->rndlength));p+=2) {
00549        PR_fprintf(PR_STDOUT,"0x%04x ",(PRUint32)(GET_SHORT((&chv2->csuites[p+q]))));
00550       }
00551       PR_fprintf(PR_STDOUT,"}\n");
00552     }
00553     PR_fprintf(PR_STDOUT,"}\n");
00554     break;
00555     /* end of V2 CLientHello Parsing */
00556 
00557   case 2:  /* Client Master Key  */
00558     {
00559     const char *cs_str=NULL;
00560     PRUint32 cs_int=0;
00561     ClientMasterKeyV2 *cmkv2;
00562     cmkv2 = (ClientMasterKeyV2 *)chv2;
00563     isV2Session = 1;
00564 
00565     PR_fprintf(PR_STDOUT," [ssl2]  ClientMasterKeyV2 { \n");
00566 
00567     cs_int = GET_24(&cmkv2->cipherkind[0]);
00568     cs_str = V2CipherString(cs_int);
00569     PR_fprintf(PR_STDOUT,"         cipher-spec-chosen = (0x%06x) %s\n",
00570               cs_int, cs_str);
00571 
00572     PR_fprintf(PR_STDOUT,"         clear-portion = %d bits\n",
00573               8*(PRUint32)(GET_SHORT((cmkv2->clearkey))));
00574 
00575     PR_fprintf(PR_STDOUT,"      }\n");
00576     clientstream.isEncrypted = 1;
00577     serverstream.isEncrypted = 1;
00578     }
00579     break;
00580 
00581 
00582   case 3:
00583     PR_fprintf(PR_STDOUT," [ssl2]  Client Finished V2 {...}\n");
00584     isV2Session = 1;
00585     break;
00586 
00587 
00588   case 4:  /* V2 Server Hello */
00589     isV2Session = 1;
00590 
00591     PR_fprintf(PR_STDOUT," [ssl2]  ServerHelloV2 {\n");
00592     PR_fprintf(PR_STDOUT,"           sid hit = {0x%02x}\n",
00593               (PRUintn)shv2->sidhit);
00594     PR_fprintf(PR_STDOUT,"           version = {0x%02x, 0x%02x}\n",
00595               (PRUint32)shv2->version[0],(PRUint32)shv2->version[1]);
00596     PR_fprintf(PR_STDOUT,"           cipher-specs-length = %d (0x%02x)\n",
00597               (PRUint32)(GET_SHORT((shv2->cslength))),
00598               (PRUint32)(GET_SHORT((shv2->cslength))));
00599     PR_fprintf(PR_STDOUT,"           sid-length = %d (0x%02x)\n",
00600               (PRUint32)(GET_SHORT((shv2->cidlength))),
00601               (PRUint32)(GET_SHORT((shv2->cidlength))));
00602 
00603     pos = (unsigned char *)shv2;
00604     pos += 2;   /* skip length header */
00605     pos += 11;  /* position pointer to Certificate data area */
00606     q = GET_SHORT(&shv2->certlength);
00607     if (q >alloclen) {
00608       goto eosh;
00609     }
00610     pos += q;                      /* skip certificate */
00611 
00612     PR_fprintf(PR_STDOUT,"           cipher-suites = { ");
00613     len = GET_SHORT((shv2->cslength));
00614     for (p = 0; p < len; p += 3) {
00615       const char *cs_str=NULL;
00616       PRUint32 cs_int=0;
00617       cs_int = GET_24((pos+p));
00618       cs_str = V2CipherString(cs_int);
00619       PR_fprintf(PR_STDOUT,"\n              ");
00620       PR_fprintf(PR_STDOUT,"(0x%06x) %s", cs_int, cs_str);
00621     }
00622     pos += len;
00623     PR_fprintf(PR_STDOUT,"   }\n");       /* End of cipher suites */
00624     len = (PRUint32)GET_SHORT((shv2->cidlength));
00625     if (len) {
00626       PR_fprintf(PR_STDOUT,"           connection-id = { ");
00627       for (p = 0; p < len; p += 2) {
00628        PR_fprintf(PR_STDOUT,"0x%04x ", (PRUint32)(GET_SHORT((pos + p))));
00629       }
00630       PR_fprintf(PR_STDOUT,"   }\n");     /* End of connection id */
00631     }
00632 eosh:
00633     PR_fprintf(PR_STDOUT,"\n              }\n"); /* end of ServerHelloV2 */
00634     if (shv2->sidhit) {
00635       clientstream.isEncrypted = 1;
00636       serverstream.isEncrypted = 1;
00637     }
00638     break;
00639 
00640   case 5:
00641     PR_fprintf(PR_STDOUT," [ssl2]  Server Verify V2 {...}\n");
00642     isV2Session = 1;
00643     break;
00644 
00645   case 6:
00646     PR_fprintf(PR_STDOUT," [ssl2]  Server Finished V2 {...}\n");
00647     isV2Session = 1;
00648     break;
00649 
00650   case 7:
00651     PR_fprintf(PR_STDOUT," [ssl2]  Request Certificate V2 {...}\n");
00652     isV2Session = 1;
00653     break;
00654 
00655   case 8:
00656     PR_fprintf(PR_STDOUT," [ssl2]  Client Certificate V2 {...}\n");
00657     isV2Session = 1;
00658     break;
00659 
00660   default:
00661     PR_fprintf(PR_STDOUT," [ssl2]  UnknownType 0x%02x {...}\n",
00662          (PRUint32)chv2->type);
00663     break;
00664   }
00665 }
00666 
00667 
00668 
00669 unsigned int print_hello_extension(unsigned char *  hsdata,
00670                                unsigned int     length,
00671                                unsigned int     pos)
00672 {
00673   /* pretty print extensions, if any */
00674   if (pos < length) {
00675     int exListLen = GET_SHORT((hsdata+pos)); pos += 2;
00676     PR_fprintf(PR_STDOUT,
00677               "            extensions[%d] = {\n", exListLen);
00678     while (exListLen > 0 && pos < length) {
00679       int exLen;
00680       int exType = GET_SHORT((hsdata+pos)); pos += 2;
00681       exLen = GET_SHORT((hsdata+pos)); pos += 2;
00682       /* dump the extension */
00683       PR_fprintf(PR_STDOUT,
00684                "              extension type %s, length [%d]",
00685                helloExtensionNameString(exType), exLen);
00686       if (exLen > 0) {
00687          PR_fprintf(PR_STDOUT, " = {\n");
00688          print_hex(exLen, hsdata + pos);
00689          PR_fprintf(PR_STDOUT, "              }\n");
00690       } else {
00691          PR_fprintf(PR_STDOUT, "\n");
00692       }
00693       pos += exLen;
00694       exListLen -= 2 + exLen;
00695     }
00696     PR_fprintf(PR_STDOUT,"            }\n");
00697   }
00698   return pos;
00699 }
00700 
00701 
00702 void print_ssl3_handshake(unsigned char *tbuf, 
00703                           unsigned int   alloclen,
00704                           SSLRecord *    sr)
00705 {
00706   struct sslhandshake sslh; 
00707   unsigned char *     hsdata;  
00708   int                 offset=0;
00709 
00710   PR_fprintf(PR_STDOUT,"   handshake {\n");
00711 
00712   while (offset < alloclen) {
00713     sslh.type = tbuf[offset]; 
00714     sslh.length = GET_24(tbuf+offset+1);
00715     hsdata= &tbuf[offset+4];
00716 
00717     if (sslhexparse) print_hex(4,tbuf+offset);
00718 
00719     PR_fprintf(PR_STDOUT,"      type = %d (",sslh.type);
00720     switch(sslh.type) {
00721     case 0:  PR_FPUTS("hello_request)\n"               ); break;
00722     case 1:  PR_FPUTS("client_hello)\n"                ); break;
00723     case 2:  PR_FPUTS("server_hello)\n"                ); break;
00724     case 11: PR_FPUTS("certificate)\n"                 ); break;
00725     case 12: PR_FPUTS("server_key_exchange)\n"         ); break;
00726     case 13: PR_FPUTS("certificate_request)\n"         ); break;
00727     case 14: PR_FPUTS("server_hello_done)\n"           ); break;
00728     case 15: PR_FPUTS("certificate_verify)\n"          ); break;
00729     case 16: PR_FPUTS("client_key_exchange)\n"         ); break;
00730     case 20: PR_FPUTS("finished)\n"                    ); break;
00731     default: PR_FPUTS("unknown)\n"                     ); break;
00732     }
00733 
00734     PR_fprintf(PR_STDOUT,"      length = %d (0x%06x)\n",sslh.length,sslh.length);
00735     switch (sslh.type) {
00736 
00737     case 0: /* hello_request */ /* not much to show here. */ break;
00738 
00739     case 1: /* client hello */
00740       switch (sr->ver_maj)  {
00741       case 3:  /* ssl version 3 */
00742        {
00743          unsigned int pos;
00744          int w;
00745 
00746          PR_fprintf(PR_STDOUT,"         ClientHelloV3 {\n");
00747          PR_fprintf(PR_STDOUT,"            client_version = {%d, %d}\n",
00748                    (PRUint8)hsdata[0],(PRUint8)hsdata[1]);
00749          PR_fprintf(PR_STDOUT,"            random = {...}\n");
00750          if (sslhexparse) print_hex(32,&hsdata[2]);
00751 
00752          /* pretty print Session ID */
00753          {
00754            int sidlength = (int)hsdata[2+32];
00755            PR_fprintf(PR_STDOUT,"            session ID = {\n");
00756            PR_fprintf(PR_STDOUT,"                length = %d\n",sidlength);
00757            PR_fprintf(PR_STDOUT,"                contents = {..}\n");
00758            if (sslhexparse) print_hex(sidlength,&hsdata[2+32+1]);
00759            PR_fprintf(PR_STDOUT,"            }\n");
00760            pos = 2+32+1+sidlength;
00761          }
00762 
00763          /* pretty print cipher suites */
00764          {
00765            int csuitelength = GET_SHORT((hsdata+pos));
00766            PR_fprintf(PR_STDOUT,"            cipher_suites[%d] = { \n",
00767                      csuitelength/2);
00768            if (csuitelength % 2) {
00769              PR_fprintf(PR_STDOUT,
00770                "*error in protocol - csuitelength shouldn't be odd*\n");
00771            }
00772            for (w=0; w<csuitelength; w+=2) {
00773              const char *cs_str=NULL;
00774              PRUint32 cs_int=0;
00775              cs_int = GET_SHORT((hsdata+pos+2+w));
00776              cs_str = V2CipherString(cs_int);
00777              PR_fprintf(PR_STDOUT,
00778               "                (0x%04x) %s\n", cs_int, cs_str);
00779            }
00780            pos += 2 + csuitelength;
00781            PR_fprintf(PR_STDOUT,"            }\n");
00782          }
00783 
00784          /* pretty print compression methods */
00785          {
00786            int complength = hsdata[pos];
00787            PR_fprintf(PR_STDOUT,"            compression[%d] = {",
00788                       complength);
00789            for (w=0; w < complength; w++) {
00790              PR_fprintf(PR_STDOUT, " %02x", hsdata[pos+1+w]);
00791            }
00792            pos += 1 + complength;
00793            PR_fprintf(PR_STDOUT," }\n");
00794          }
00795 
00796          /* pretty print extensions, if any */
00797          pos = print_hello_extension(hsdata, sslh.length, pos);
00798 
00799          PR_fprintf(PR_STDOUT,"         }\n");
00800        } /* end of ssl version 3 */
00801        break;
00802       default:
00803        PR_fprintf(PR_STDOUT,"         UNDEFINED VERSION %d.%d {...}\n",
00804                             sr->ver_maj, sr->ver_min );
00805        if (sslhexparse) print_hex(sslh.length, hsdata);
00806        break;
00807       } /* end of switch sr->ver_maj */
00808       break;
00809 
00810     case 2: /* server hello */
00811       {
00812        unsigned int sidlength, pos;
00813 
00814        PR_fprintf(PR_STDOUT,"         ServerHello {\n");
00815 
00816        PR_fprintf(PR_STDOUT,"            server_version = {%d, %d}\n",
00817                  (PRUint8)hsdata[0],(PRUint8)hsdata[1]);
00818        PR_fprintf(PR_STDOUT,"            random = {...}\n");
00819        if (sslhexparse) print_hex(32,&hsdata[2]);
00820        PR_fprintf(PR_STDOUT,"            session ID = {\n");
00821        sidlength = (int)hsdata[2+32];
00822        PR_fprintf(PR_STDOUT,"                length = %d\n",sidlength);
00823        PR_fprintf(PR_STDOUT,"                contents = {..}\n");
00824        if (sslhexparse) print_hex(sidlength,&hsdata[2+32+1]);
00825        PR_fprintf(PR_STDOUT,"            }\n");
00826        pos = 2+32+1+sidlength;
00827 
00828        /* pretty print chosen cipher suite */
00829        {
00830          PRUint32 cs_int    = GET_SHORT((hsdata+pos));
00831          const char *cs_str = V2CipherString(cs_int);
00832          PR_fprintf(PR_STDOUT,"            cipher_suite = (0x%04x) %s\n",
00833                    cs_int, cs_str);
00834          pos += 2;
00835        }
00836        PR_fprintf(PR_STDOUT,  "            compression method = %02x\n", 
00837                  hsdata[pos++]);
00838 
00839        /* pretty print extensions, if any */
00840        pos = print_hello_extension(hsdata, sslh.length, pos);
00841 
00842        PR_fprintf(PR_STDOUT,"         }\n");
00843       }
00844       break;
00845 
00846     case 11: /* certificate */
00847       {
00848        PRFileDesc *cfd;
00849        int         pos;
00850        int         certslength;
00851        int         certlength;
00852        int         certbytesread   = 0;
00853        static int  certFileNumber;
00854        char        certFileName[20];
00855 
00856        PR_fprintf(PR_STDOUT,"         CertificateChain {\n");
00857        certslength = GET_24(hsdata);
00858        PR_fprintf(PR_STDOUT,"            chainlength = %d (0x%04x)\n",
00859               certslength,certslength);
00860        pos = 3;
00861        while (certbytesread < certslength) {
00862          certlength = GET_24((hsdata+pos));
00863          pos += 3;
00864          PR_fprintf(PR_STDOUT,"            Certificate {\n");
00865          PR_fprintf(PR_STDOUT,"               size = %d (0x%04x)\n",
00866               certlength,certlength);
00867 
00868          PR_snprintf(certFileName, sizeof certFileName, "cert.%03d",
00869                      ++certFileNumber);
00870          cfd = PR_Open(certFileName, PR_WRONLY|PR_CREATE_FILE|PR_TRUNCATE, 
00871                        0664);
00872          if (!cfd) {
00873            PR_fprintf(PR_STDOUT,
00874                       "               data = { couldn't save file '%s' }\n",
00875                      certFileName);
00876          } else {
00877            PR_Write(cfd, (hsdata+pos), certlength);
00878            PR_fprintf(PR_STDOUT,
00879                       "               data = { saved in file '%s' }\n",
00880                      certFileName);
00881            PR_Close(cfd);
00882          }
00883 
00884          PR_fprintf(PR_STDOUT,"            }\n");
00885          pos           += certlength;
00886          certbytesread += certlength+3;
00887        }
00888        PR_fprintf(PR_STDOUT,"         }\n");
00889       }
00890       break;
00891 
00892     case 12: /* server_key_exchange */                    
00893       if (sslhexparse) print_hex(sslh.length, hsdata);
00894       break;
00895 
00896     case 13: /* certificate request */
00897       { 
00898        unsigned int pos = 0;
00899        int w, reqLength;
00900 
00901        PR_fprintf(PR_STDOUT,"         CertificateRequest {\n");
00902 
00903        /* pretty print requested certificate types */
00904        reqLength = hsdata[pos];
00905        PR_fprintf(PR_STDOUT,"            certificate types[%d] = {",
00906                  reqLength);
00907        for (w=0; w < reqLength; w++) {
00908          PR_fprintf(PR_STDOUT, " %02x", hsdata[pos+1+w]);
00909        }
00910        pos += 1 + reqLength;
00911        PR_fprintf(PR_STDOUT," }\n");
00912 
00913        /* pretty print CA names, if any */
00914        if (pos < sslh.length) {
00915          int exListLen = GET_SHORT((hsdata+pos)); pos += 2;
00916          PR_fprintf(PR_STDOUT,
00917                    "            certificate_authorities[%d] = {\n", 
00918                    exListLen);
00919          while (exListLen > 0 && pos < sslh.length) {
00920            char *  ca_name;
00921            SECItem it;
00922            int     dnLen = GET_SHORT((hsdata+pos)); pos += 2;
00923 
00924            /* dump the CA name */
00925            it.type = siBuffer;
00926            it.data = hsdata + pos;
00927            it.len  = dnLen;
00928            ca_name = CERT_DerNameToAscii(&it);
00929            if (ca_name) {
00930              PR_fprintf(PR_STDOUT,"   %s\n", ca_name);
00931              PORT_Free(ca_name);
00932            } else {
00933              PR_fprintf(PR_STDOUT,
00934                       "              distinguished name [%d]", dnLen);
00935              if (dnLen > 0 && sslhexparse) {
00936                 PR_fprintf(PR_STDOUT, " = {\n");
00937                 print_hex(dnLen, hsdata + pos);
00938                 PR_fprintf(PR_STDOUT, "              }\n");
00939              } else {
00940                 PR_fprintf(PR_STDOUT, "\n");
00941              }
00942             }
00943            pos += dnLen;
00944            exListLen -= 2 + dnLen;
00945          }
00946          PR_fprintf(PR_STDOUT,"            }\n");
00947        }
00948 
00949        PR_fprintf(PR_STDOUT,"         }\n");
00950       }
00951       break;
00952 
00953     case 14: /* server_hello_done */ /* not much to show here. */ break;
00954 
00955     case 15: /* certificate_verify */                
00956       if (sslhexparse) print_hex(sslh.length, hsdata);
00957       break;
00958 
00959     case 16: /* client key exchange */
00960       {
00961        PR_fprintf(PR_STDOUT,"         ClientKeyExchange {\n");
00962        PR_fprintf(PR_STDOUT,"            message = {...}\n");
00963        PR_fprintf(PR_STDOUT,"         }\n");
00964       }
00965       break;
00966 
00967     case 20: /* finished */                
00968       if (sslhexparse) print_hex(sslh.length, hsdata);
00969       break;
00970 
00971     default:
00972       {
00973        PR_fprintf(PR_STDOUT,"         UNKNOWN MESSAGE TYPE %d [%d] {\n",
00974                             sslh.type, sslh.length);
00975        if (sslhexparse) print_hex(sslh.length, hsdata);
00976        PR_fprintf(PR_STDOUT,"         }\n");
00977 
00978       }
00979     }  /* end of switch sslh.type */
00980     offset += sslh.length + 4; /* +4 because of length (3 bytes) and type (1 byte) */
00981   } /* while */
00982   PR_fprintf(PR_STDOUT,"   }\n");
00983 }
00984 
00985 
00986 void print_ssl(DataBufferList *s, int length, unsigned char *buffer)
00987 {
00988   /* --------------------------------------------------------  */
00989   /* first, create a new buffer object for this piece of data. */
00990 
00991   DataBuffer *db;
00992   int i,l;
00993 
00994   if (s->size == 0 && length > 0 && buffer[0] >= 32 && buffer[0] < 128) {
00995     /* Not an SSL record, treat entire buffer as plaintext */
00996     PR_Write(PR_STDOUT,buffer,length);
00997     return;
00998   }
00999 
01000 
01001   check_integrity(s);
01002 
01003   i = 0;
01004   l = length;
01005 
01006   db = PR_NEW(struct _DataBuffer);
01007 
01008   db->buffer = (unsigned char*)PR_Malloc(length);
01009   db->length = length;
01010   db->offset = 0;
01011   memcpy(db->buffer, buffer, length);
01012   db->next = NULL;
01013 
01014   /* now, add it to the stream */
01015 
01016   if (s->last != NULL) s->last->next = db;
01017   s->last = db;
01018   s->size += length;
01019   if (s->first == NULL) s->first = db;
01020 
01021   check_integrity(s);
01022 
01023   /*------------------------------------------------------- */
01024   /* now we look at the stream to see if we have enough data to
01025      decode  */
01026 
01027   while (s->size > 0 ) {
01028     unsigned char *tbuf = NULL;
01029 
01030     SSLRecord sr;
01031     unsigned alloclen;
01032     unsigned recordsize;
01033 
01034     check_integrity(s);
01035 
01036     if ( s->first == NULL) {
01037       PR_fprintf(PR_STDOUT,"ERROR: s->first is null\n");
01038       exit(9);
01039     }
01040 
01041     /* in the case of an SSL 2 client-hello (which is all ssltap supports) */
01042     /* will have the high-bit set, whereas an SSL 3 client-hello will not  */
01043     /* SSL2 can also send records that begin with the high bit clear.
01044      * This code will incorrectly handle them. XXX
01045      */
01046     if (isV2Session || s->first->buffer[s->first->offset] & 0x80) {
01047       /* it's an SSL 2 packet */
01048       unsigned char lenbuf[3];
01049 
01050       /* first, we check if there's enough data for it to be an SSL2-type
01051        * record.  What a pain.*/
01052       if (s->size < sizeof lenbuf) {
01053        partial_packet(length, s->size, sizeof lenbuf);
01054        return;
01055       }
01056 
01057       /* read the first two bytes off the stream. */
01058       read_stream_bytes(lenbuf, s, sizeof(lenbuf));
01059       alloclen = ((unsigned int)(lenbuf[0] & 0x7f) << 8) + lenbuf[1] + 
01060                  ((lenbuf[0] & 0x80) ? 2 : 3);
01061       PR_fprintf(PR_STDOUT, "alloclen = %u bytes\n", alloclen);
01062 
01063       /* put 'em back on the head of the stream. */
01064       db = PR_NEW(struct _DataBuffer);
01065 
01066       db->length = sizeof lenbuf;
01067       db->buffer = (unsigned char*) PR_Malloc(db->length);
01068       db->offset = 0;
01069       memcpy(db->buffer, lenbuf, sizeof lenbuf);
01070 
01071       db->next = s->first;
01072       s->first = db;
01073       if (s->last == NULL) 
01074        s->last = db;
01075       s->size += db->length;
01076 
01077       /* if there wasn't enough, go back for more. */
01078       if (s->size < alloclen) {
01079        check_integrity(s);
01080        partial_packet(length, s->size, alloclen);
01081        return;
01082       }
01083       partial_packet(length, s->size, alloclen);
01084 
01085       /* read in the whole record. */
01086       tbuf = PR_Malloc(alloclen);
01087       read_stream_bytes(tbuf, s, alloclen);
01088 
01089       print_sslv2(s, tbuf, alloclen);
01090       PR_FREEIF(tbuf);
01091       check_integrity(s);
01092 
01093       continue;
01094     }
01095 
01096     /***********************************************************/
01097     /* It's SSL v3 */
01098     /***********************************************************/
01099     check_integrity(s);
01100 
01101     if (s->size < sizeof(SSLRecord)) {
01102       partial_packet(length, s->size, sizeof(SSLRecord));
01103       return;
01104     }
01105 
01106     read_stream_bytes((unsigned char *)&sr, s, sizeof sr);
01107 
01108     /* we have read the stream bytes. Look at the length of
01109        the ssl record. If we don't have enough data to satisfy this
01110        request, then put the bytes we just took back at the head
01111        of the queue */
01112     recordsize = GET_SHORT(sr.length);
01113 
01114     if (recordsize > s->size) {
01115       db = PR_NEW(struct _DataBuffer);
01116 
01117       db->length = sizeof sr;
01118       db->buffer = (unsigned char*) PR_Malloc(db->length);
01119       db->offset = 0;
01120       memcpy(db->buffer, &sr, sizeof sr);
01121       db->next = s->first;
01122 
01123       /* now, add it back on to the head of the stream */
01124 
01125       s->first = db;
01126       if (s->last == NULL) 
01127         s->last = db;
01128       s->size += db->length;
01129 
01130       check_integrity(s);
01131       partial_packet(length, s->size, recordsize);
01132       return;
01133     }
01134     partial_packet(length, s->size, recordsize);
01135 
01136 
01137     PR_fprintf(PR_STDOUT,"SSLRecord { [%s]\n", get_time_string() );
01138     if (sslhexparse) {
01139       print_hex(5,(unsigned char*)&sr);
01140     }
01141 
01142     check_integrity(s);
01143 
01144     PR_fprintf(PR_STDOUT,"   type    = %d (",sr.type);
01145     switch(sr.type) {
01146     case 20 :
01147       PR_fprintf(PR_STDOUT,"change_cipher_spec)\n");
01148       break;
01149     case 21 :
01150       PR_fprintf(PR_STDOUT,"alert)\n");
01151       break;
01152     case 22 :
01153       PR_fprintf(PR_STDOUT,"handshake)\n");
01154       break;
01155     case 23 :
01156       PR_fprintf(PR_STDOUT,"application_data)\n");
01157       break;
01158     default:
01159       PR_fprintf(PR_STDOUT,"unknown)\n");
01160       break;
01161     }
01162     PR_fprintf(PR_STDOUT,"   version = { %d,%d }\n",
01163               (PRUint32)sr.ver_maj,(PRUint32)sr.ver_min);
01164     PR_fprintf(PR_STDOUT,"   length  = %d (0x%x)\n",
01165        (PRUint32)GET_SHORT(sr.length), (PRUint32)GET_SHORT(sr.length));
01166 
01167 
01168     alloclen = recordsize;
01169     PR_ASSERT(s->size >= alloclen);
01170     if (s->size >= alloclen) {
01171       tbuf = (unsigned char*) PR_Malloc(alloclen);
01172       read_stream_bytes(tbuf, s, alloclen);
01173 
01174       if (s->isEncrypted) {
01175        PR_fprintf(PR_STDOUT,"            < encrypted >\n");
01176       } else 
01177 
01178       switch(sr.type) {
01179       case 20 : /* change_cipher_spec */
01180        if (sslhexparse) print_hex(alloclen,tbuf);
01181        s->isEncrypted = 1;  /* mark to say we can only dump hex form now on */
01182        break;
01183 
01184       case 21 : /* alert */
01185        switch(tbuf[0]) {
01186        case 1: PR_fprintf(PR_STDOUT, "   warning: "); break;
01187        case 2: PR_fprintf(PR_STDOUT, "   fatal: "); break;
01188        default: PR_fprintf(PR_STDOUT, "   unknown level %d: ", tbuf[0]); break;
01189        }
01190 
01191        switch(tbuf[1]) {
01192        case 0:   PR_FPUTS("close_notify\n"                    ); break;
01193        case 10:  PR_FPUTS("unexpected_message\n"              ); break;
01194        case 20:  PR_FPUTS("bad_record_mac\n"                  ); break;
01195        case 21:  PR_FPUTS("decryption_failed\n"               ); break;
01196        case 22:  PR_FPUTS("record_overflow\n"                 ); break;
01197        case 30:  PR_FPUTS("decompression_failure\n"           ); break;
01198        case 40:  PR_FPUTS("handshake_failure\n"               ); break;
01199        case 41:  PR_FPUTS("no_certificate\n"                  ); break;
01200        case 42:  PR_FPUTS("bad_certificate\n"                 ); break;
01201        case 43:  PR_FPUTS("unsupported_certificate\n"         ); break;
01202        case 44:  PR_FPUTS("certificate_revoked\n"             ); break;
01203        case 45:  PR_FPUTS("certificate_expired\n"             ); break;
01204        case 46:  PR_FPUTS("certificate_unknown\n"             ); break;
01205        case 47:  PR_FPUTS("illegal_parameter\n"               ); break;
01206        case 48:  PR_FPUTS("unknown_ca\n"                      ); break;
01207        case 49:  PR_FPUTS("access_denied\n"                   ); break;
01208        case 50:  PR_FPUTS("decode_error\n"                    ); break;
01209        case 51:  PR_FPUTS("decrypt_error\n"                   ); break;
01210        case 60:  PR_FPUTS("export_restriction\n"              ); break;
01211        case 70:  PR_FPUTS("protocol_version\n"                ); break;
01212        case 71:  PR_FPUTS("insufficient_security\n"           ); break;
01213        case 80:  PR_FPUTS("internal_error\n"                  ); break;
01214        case 90:  PR_FPUTS("user_canceled\n"                   ); break;
01215        case 100: PR_FPUTS("no_renegotiation\n"                ); break;
01216        case 110: PR_FPUTS("unsupported_extension\n"           ); break;
01217        case 111: PR_FPUTS("certificate_unobtainable\n"        ); break;
01218        case 112: PR_FPUTS("unrecognized_name\n"               ); break;
01219        case 113: PR_FPUTS("bad_certificate_status_response\n" ); break;
01220        case 114: PR_FPUTS("bad_certificate_hash_value\n"      ); break;
01221 
01222        default:  PR_fprintf(PR_STDOUT, "unknown alert %d\n", tbuf[1]); break;
01223        }
01224 
01225        if (sslhexparse) print_hex(alloclen,tbuf);
01226        break;
01227 
01228       case 22 : /* handshake */    
01229         print_ssl3_handshake( tbuf, alloclen, &sr );
01230        break;
01231 
01232       case 23 : /* application data */
01233       default:
01234        print_hex(alloclen,tbuf);
01235        break;
01236       }
01237     }
01238     PR_fprintf(PR_STDOUT,"}\n");
01239     PR_FREEIF(tbuf);
01240     check_integrity(s);
01241   }
01242 }
01243 
01244 void print_hex(int amt, unsigned char *buf) {
01245   int i,j,k;
01246   char t[20];
01247   static char string[5000];
01248 
01249 
01250   for(i=0;i<amt;i++) {
01251     t[1] =0;
01252 
01253     if (i%16 ==0) {  /* if we are at the beginning of a line */
01254       PR_fprintf(PR_STDOUT,"%4x:",i); /* print the line number  */
01255       strcpy(string,"");
01256     }
01257 
01258     if (i%4 == 0) {
01259       PR_fprintf(PR_STDOUT," ");
01260     }
01261 
01262     j = buf[i];
01263 
01264     t[0] = (j >= 0x20 && j < 0x80) ? j : '.';
01265 
01266     if (fancy)  {
01267       switch (t[0]) {
01268       case '<':
01269         strcpy(t,"&lt;");
01270         break;
01271       case '>':
01272         strcpy(t,"&gt;");
01273         break;
01274       case '&':
01275         strcpy(t,"&amp;");
01276         break;
01277       }
01278     }
01279     strcat(string,t);
01280 
01281     PR_fprintf(PR_STDOUT,"%02x ",(PRUint8) buf[i]);
01282 
01283     /* if we've reached the end of the line - add the string */
01284     if (i%16 == 15) PR_fprintf(PR_STDOUT," | %s\n",string);
01285   }
01286   /* we reached the end of the buffer,*/
01287   /* do we have buffer left over? */
01288   j = i%16;
01289   if (j > 0) {
01290     for (k=0;k<(16-j);k++) PR_fprintf(PR_STDOUT,"   ");
01291     PR_fprintf(PR_STDOUT," |%s\n",string);
01292   }
01293 }
01294 
01295 void Usage(void) {
01296   PR_fprintf(PR_STDERR, "SSLTAP (C) 1997, 1998 Netscape Communications Corporation.\n");
01297   PR_fprintf(PR_STDERR, "Usage: ssltap [-vhfsxl] [-p port] hostname:port\n");
01298   PR_fprintf(PR_STDERR, "   -v      [prints version string]\n");
01299   PR_fprintf(PR_STDERR, "   -h      [outputs hex instead of ASCII]\n");
01300   PR_fprintf(PR_STDERR, "   -f      [turn on Fancy HTML coloring]\n");
01301   PR_fprintf(PR_STDERR, "   -s      [turn on SSL decoding]\n");
01302   PR_fprintf(PR_STDERR, "   -x      [turn on extra SSL hex dumps]\n");
01303   PR_fprintf(PR_STDERR, "   -p port [specify rendezvous port (default 1924)]\n");
01304   PR_fprintf(PR_STDERR, "   -l      [loop - continue to wait for more connections]\n");
01305 
01306 
01307 }
01308 
01309 void
01310 showErr(const char * msg) {
01311   PRErrorCode  err       = PR_GetError();
01312   const char * errString;
01313 
01314   if (err == PR_UNKNOWN_ERROR)
01315     err = PR_CONNECT_RESET_ERROR;  /* bug in NSPR. */
01316   errString = SECU_Strerror(err);
01317 
01318   if (!errString)
01319     errString = "(no text available)";
01320   PR_fprintf(PR_STDERR, "Error %d: %s: %s", err, errString, msg);
01321 }
01322 
01323 int main(int argc,  char *argv[])
01324 {
01325   char *hostname=NULL;
01326   PRUint16 rendport=DEFPORT,port;
01327   PRHostEnt hp;
01328   PRStatus r;
01329   PRNetAddr na_client,na_server,na_rend;
01330   PRFileDesc *s_server,*s_client,*s_rend; /*rendezvous */
01331   char netdbbuf[PR_NETDB_BUF_SIZE];
01332   int c_count=0;
01333   PLOptState *optstate;
01334   PLOptStatus status;
01335   SECStatus   rv;
01336 
01337   optstate = PL_CreateOptState(argc,argv,"fvxhslp:");
01338     while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
01339     switch (optstate->option) {
01340     case 'f':
01341       fancy++;
01342       break;
01343     case 'h':
01344       hexparse++;
01345       break;
01346     case 'v':
01347       PR_fprintf(PR_STDOUT,"Version: %s\n",VERSIONSTRING);
01348       break;
01349     case 's':
01350       sslparse++;
01351       break;
01352     case 'x':
01353       sslhexparse++;
01354       break;
01355     case 'l':
01356       looparound++;
01357       break;
01358     case 'p':
01359       rendport = atoi(optstate->value);
01360       break;
01361     case '\0':
01362       hostname = PL_strdup(optstate->value);
01363     }
01364   }
01365   if (status == PL_OPT_BAD)
01366     Usage();
01367 
01368   if (fancy) {
01369     if (!hexparse && !sslparse) {
01370       PR_fprintf(PR_STDERR,
01371 "Note: use of -f without -s or -h not recommended, \n"
01372 "as the output looks a little strange. It may be useful, however\n");
01373     }
01374   }
01375 
01376   if(! hostname ) Usage(), exit(2);
01377 
01378   {
01379     char *colon = (char *)strchr(hostname, ':');
01380     if (!colon) {
01381       PR_fprintf(PR_STDERR,
01382       "You must specify the host AND port you wish to connect to\n");
01383       Usage(), exit(3);
01384     }
01385     port = atoi(&colon[1]);
01386     *colon = '\0';
01387 
01388     if (port == 0) {
01389        PR_fprintf(PR_STDERR, "Port must be a nonzero number.\n");
01390        exit(4);
01391       }
01392   }
01393 
01394   /* find the 'server' IP address so we don't have to look it up later */
01395 
01396   if (fancy) {
01397       PR_fprintf(PR_STDOUT,"<HTML><HEAD><TITLE>SSLTAP output</TITLE></HEAD>\n");
01398       PR_fprintf(PR_STDOUT,"<BODY><PRE>\n");
01399     }
01400   PR_fprintf(PR_STDERR,"Looking up \"%s\"...\n", hostname);
01401   r = PR_GetHostByName(hostname,netdbbuf,PR_NETDB_BUF_SIZE,&hp);
01402   if (r) {
01403     showErr("Host Name lookup failed\n");
01404     exit(5);
01405   }
01406 
01407   PR_EnumerateHostEnt(0,&hp,0,&na_server);
01408   PR_InitializeNetAddr(PR_IpAddrNull,port,&na_server);
01409   /* set up the port which the client will connect to */
01410 
01411   r = PR_InitializeNetAddr(PR_IpAddrAny,rendport,&na_rend);
01412   if (r == PR_FAILURE) {
01413     PR_fprintf(PR_STDERR,
01414     "PR_InitializeNetAddr(,%d,) failed with error %d\n",PR_GetError());
01415     exit(0);
01416   }
01417 
01418   rv = NSS_NoDB_Init("");
01419   if (rv != SECSuccess) {
01420     PR_fprintf(PR_STDERR,
01421     "NSS_NoDB_Init() failed with error %d\n",PR_GetError());
01422     exit(5);
01423   }
01424 
01425   s_rend = PR_NewTCPSocket();
01426   if (!s_rend) {
01427     showErr("Couldn't create socket\n");
01428     exit(6);
01429   }
01430 
01431   if (PR_Bind(s_rend, &na_rend )) {
01432     PR_fprintf(PR_STDERR,"Couldn't bind to port %d (error %d)\n",rendport, PR_GetError());
01433     exit(-1);
01434   }
01435 
01436   if ( PR_Listen(s_rend, 5)) {
01437     showErr("Couldn't listen\n");
01438     exit(-1);
01439   }
01440 
01441   PR_fprintf(PR_STDERR,"Proxy socket ready and listening\n");
01442   do { /* accept one connection and process it. */
01443       PRPollDesc pds[2];
01444 
01445       s_client = PR_Accept(s_rend,&na_client,PR_SecondsToInterval(3600));
01446       if (s_client == NULL) {
01447        showErr("accept timed out\n");
01448        exit(7);
01449       }
01450 
01451       s_server = PR_NewTCPSocket();
01452       if (s_server == NULL) {
01453        showErr("couldn't open new socket to connect to server \n");
01454        exit(8);
01455       }
01456 
01457       r = PR_Connect(s_server,&na_server,PR_SecondsToInterval(5));
01458 
01459       if ( r == PR_FAILURE )
01460         {
01461          showErr("Couldn't connect\n");
01462          return -1;
01463         }
01464 
01465       if (looparound) {
01466        if (fancy)  PR_fprintf(PR_STDOUT,"<p><HR><H2>");
01467        PR_fprintf(PR_STDOUT,"Connection #%d [%s]\n", c_count+1,
01468                             get_time_string());
01469        if (fancy)  PR_fprintf(PR_STDOUT,"</H2>");
01470        }
01471 
01472 
01473       PR_fprintf(PR_STDOUT,"Connected to %s:%d\n", hostname, port);
01474 
01475 #define PD_C 0
01476 #define PD_S 1
01477 
01478       pds[PD_C].fd = s_client;
01479       pds[PD_S].fd = s_server;
01480       pds[PD_C].in_flags = PR_POLL_READ;
01481       pds[PD_S].in_flags = PR_POLL_READ;
01482 
01483       /* make sure the new connections don't start out encrypted. */
01484       clientstream.isEncrypted = 0;
01485       serverstream.isEncrypted = 0;
01486       isV2Session = 0;
01487 
01488       while( (pds[PD_C].in_flags & PR_POLL_READ) != 0 ||
01489              (pds[PD_S].in_flags & PR_POLL_READ) != 0 )
01490         {  /* Handle all messages on the connection */
01491          PRInt32 amt;
01492          PRInt32 wrote;
01493          unsigned char buffer[ TAPBUFSIZ ];
01494 
01495          amt = PR_Poll(pds,2,PR_INTERVAL_NO_TIMEOUT);
01496          if (amt <= 0) {
01497            if (amt)
01498               showErr( "PR_Poll failed.\n");
01499            else
01500               showErr( "PR_Poll timed out.\n");
01501            break;
01502          }
01503 
01504          if (pds[PD_C].out_flags & PR_POLL_EXCEPT) {
01505            showErr( "Exception on client-side socket.\n");
01506            break;
01507          }
01508 
01509          if (pds[PD_S].out_flags & PR_POLL_EXCEPT) {
01510            showErr( "Exception on server-side socket.\n");
01511            break;
01512          }
01513 
01514 
01515 /* read data, copy it to stdout, and write to other socket */
01516 
01517          if ((pds[PD_C].in_flags  & PR_POLL_READ) != 0 &&
01518              (pds[PD_C].out_flags & PR_POLL_READ) != 0 ) {
01519 
01520            amt = PR_Read(s_client, buffer, sizeof(buffer));
01521 
01522            if ( amt < 0)  {
01523              showErr( "Client socket read failed.\n");
01524              break;
01525            }
01526 
01527            if( amt == 0 ) {
01528              PR_fprintf(PR_STDOUT, "Read EOF on Client socket. [%s]\n",
01529                                    get_time_string() );
01530              pds[PD_C].in_flags &= ~PR_POLL_READ;
01531              PR_Shutdown(s_server, PR_SHUTDOWN_SEND);
01532              continue;
01533            }
01534 
01535            PR_fprintf(PR_STDOUT,"--> [\n");
01536            if (fancy) PR_fprintf(PR_STDOUT,"<font color=blue>");
01537 
01538            if (hexparse)  print_hex(amt, buffer);
01539            if (sslparse)  print_ssl(&clientstream,amt,buffer);
01540            if (!hexparse && !sslparse)  PR_Write(PR_STDOUT,buffer,amt);
01541            if (fancy) PR_fprintf(PR_STDOUT,"</font>");
01542            PR_fprintf(PR_STDOUT,"]\n");
01543 
01544            wrote = PR_Write(s_server, buffer, amt);
01545            if (wrote != amt )  {
01546              if (wrote < 0) {
01547                showErr("Write to server socket failed.\n");
01548               break;
01549              } else {
01550               PR_fprintf(PR_STDERR, "Short write to server socket!\n");
01551              }
01552            }
01553          }  /* end of read from client socket. */
01554 
01555 /* read data, copy it to stdout, and write to other socket */
01556          if ((pds[PD_S].in_flags  & PR_POLL_READ) != 0 &&
01557              (pds[PD_S].out_flags & PR_POLL_READ) != 0 ) {
01558 
01559            amt = PR_Read(s_server, buffer, sizeof(buffer));
01560 
01561            if ( amt < 0)  {
01562              showErr( "error on server-side socket.\n");
01563              break;
01564            }
01565 
01566            if( amt == 0 ) {
01567              PR_fprintf(PR_STDOUT, "Read EOF on Server socket. [%s]\n",
01568                                    get_time_string() );
01569              pds[PD_S].in_flags &= ~PR_POLL_READ;
01570              PR_Shutdown(s_client, PR_SHUTDOWN_SEND);
01571              continue;
01572            } 
01573 
01574            PR_fprintf(PR_STDOUT,"<-- [\n");
01575            if (fancy) PR_fprintf(PR_STDOUT,"<font color=red>");
01576            if (hexparse)  print_hex(amt, (unsigned char *)buffer);
01577            if (sslparse)  print_ssl(&serverstream,amt,(unsigned char *)buffer);
01578            if (!hexparse && !sslparse)  PR_Write(PR_STDOUT,buffer,amt);
01579            if (fancy) PR_fprintf(PR_STDOUT,"</font>");
01580            PR_fprintf(PR_STDOUT,"]\n");
01581 
01582 
01583            wrote = PR_Write(s_client, buffer, amt);
01584            if (wrote != amt )  {
01585              if (wrote < 0) {
01586                showErr("Write to client socket failed.\n");
01587               break;
01588              } else {
01589               PR_fprintf(PR_STDERR, "Short write to client socket!\n");
01590              }
01591            }
01592 
01593          } /* end of read from server socket. */
01594 
01595 /* Loop, handle next message. */
01596 
01597         }     /* handle messages during a connection loop */
01598       PR_Close(s_client);
01599       PR_Close(s_server);
01600       flush_stream(&clientstream);
01601       flush_stream(&serverstream);
01602 
01603       c_count++;
01604       PR_fprintf(PR_STDERR,"Connection %d Complete [%s]\n", c_count,
01605                             get_time_string() );
01606     }  while (looparound); /* accept connection and process it. */
01607     PR_Close(s_rend);
01608     NSS_Shutdown();
01609     return 0;
01610 }