security/nss/cmd/ssltap/ssltap.c

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 /*
michael@0 6 * ssltap.c
michael@0 7 *
michael@0 8 * Version 1.0 : Frederick Roeber : 11 June 1997
michael@0 9 * Version 2.0 : Steve Parkinson : 13 November 1997
michael@0 10 * Version 3.0 : Nelson Bolyard : 22 July 1998
michael@0 11 * Version 3.1 : Nelson Bolyard : 24 May 1999
michael@0 12 *
michael@0 13 * changes in version 2.0:
michael@0 14 * Uses NSPR20
michael@0 15 * Shows structure of SSL negotiation, if enabled.
michael@0 16 *
michael@0 17 * This "proxies" a socket connection (like a socks tunnel), but displays the
michael@0 18 * data is it flies by.
michael@0 19 *
michael@0 20 * In the code, the 'client' socket is the one on the client side of the
michael@0 21 * proxy, and the server socket is on the server side.
michael@0 22 *
michael@0 23 */
michael@0 24
michael@0 25 #include "nspr.h"
michael@0 26 #include "plstr.h"
michael@0 27 #include "secutil.h"
michael@0 28 #include <memory.h> /* for memcpy, etc. */
michael@0 29 #include <string.h>
michael@0 30 #include <time.h>
michael@0 31
michael@0 32 #include "plgetopt.h"
michael@0 33 #include "nss.h"
michael@0 34 #include "cert.h"
michael@0 35 #include "sslproto.h"
michael@0 36 #include "ocsp.h"
michael@0 37 #include "ocspti.h" /* internals for pretty-printing routines *only* */
michael@0 38
michael@0 39 struct _DataBufferList;
michael@0 40 struct _DataBuffer;
michael@0 41
michael@0 42 typedef struct _DataBufferList {
michael@0 43 struct _DataBuffer *first,*last;
michael@0 44 int size;
michael@0 45 int isEncrypted;
michael@0 46 unsigned char * msgBuf;
michael@0 47 int msgBufOffset;
michael@0 48 int msgBufSize;
michael@0 49 int hMACsize;
michael@0 50 } DataBufferList;
michael@0 51
michael@0 52 typedef struct _DataBuffer {
michael@0 53 unsigned char *buffer;
michael@0 54 int length;
michael@0 55 int offset; /* offset of first good byte */
michael@0 56 struct _DataBuffer *next;
michael@0 57 } DataBuffer;
michael@0 58
michael@0 59
michael@0 60
michael@0 61 struct sslhandshake {
michael@0 62 PRUint8 type;
michael@0 63 PRUint32 length;
michael@0 64 };
michael@0 65
michael@0 66 typedef struct _SSLRecord {
michael@0 67 PRUint8 type;
michael@0 68 PRUint8 ver_maj,ver_min;
michael@0 69
michael@0 70 PRUint8 length[2];
michael@0 71 } SSLRecord;
michael@0 72
michael@0 73 typedef struct _ClientHelloV2 {
michael@0 74 PRUint8 length[2];
michael@0 75 PRUint8 type;
michael@0 76 PRUint8 version[2];
michael@0 77 PRUint8 cslength[2];
michael@0 78 PRUint8 sidlength[2];
michael@0 79 PRUint8 rndlength[2];
michael@0 80 PRUint8 csuites[1];
michael@0 81 } ClientHelloV2;
michael@0 82
michael@0 83 typedef struct _ServerHelloV2 {
michael@0 84 PRUint8 length[2];
michael@0 85 PRUint8 type;
michael@0 86 PRUint8 sidhit;
michael@0 87 PRUint8 certtype;
michael@0 88 PRUint8 version[2];
michael@0 89 PRUint8 certlength[2];
michael@0 90 PRUint8 cslength[2];
michael@0 91 PRUint8 cidlength[2];
michael@0 92 } ServerHelloV2;
michael@0 93
michael@0 94 typedef struct _ClientMasterKeyV2 {
michael@0 95 PRUint8 length[2];
michael@0 96 PRUint8 type;
michael@0 97
michael@0 98 PRUint8 cipherkind[3];
michael@0 99 PRUint8 clearkey[2];
michael@0 100 PRUint8 secretkey[2];
michael@0 101
michael@0 102 } ClientMasterKeyV2;
michael@0 103
michael@0 104 /* forward declaration */
michael@0 105 void showErr(const char * msg);
michael@0 106
michael@0 107 #define TAPBUFSIZ 16384
michael@0 108
michael@0 109 #define DEFPORT 1924
michael@0 110 #include <ctype.h>
michael@0 111
michael@0 112 const char * progName;
michael@0 113 int hexparse=0;
michael@0 114 int sslparse=0;
michael@0 115 int sslhexparse=0;
michael@0 116 int looparound=0;
michael@0 117 int fancy=0;
michael@0 118 int isV2Session=0;
michael@0 119 int currentcipher=0;
michael@0 120 DataBufferList clientstream, serverstream;
michael@0 121
michael@0 122 #define PR_FPUTS(x) PR_fprintf(PR_STDOUT, x )
michael@0 123
michael@0 124 #define GET_SHORT(x) ((PRUint16)(((PRUint16)((PRUint8*)x)[0]) << 8) + ((PRUint16)((PRUint8*)x)[1]))
michael@0 125 #define GET_24(x) ((PRUint32) ( \
michael@0 126 (((PRUint32)((PRUint8*)x)[0]) << 16) \
michael@0 127 + \
michael@0 128 (((PRUint32)((PRUint8*)x)[1]) << 8) \
michael@0 129 + \
michael@0 130 (((PRUint32)((PRUint8*)x)[2]) << 0) \
michael@0 131 ) )
michael@0 132 #define GET_32(x) ((PRUint32) ( \
michael@0 133 (((PRUint32)((PRUint8*)x)[0]) << 24) \
michael@0 134 + \
michael@0 135 (((PRUint32)((PRUint8*)x)[1]) << 16) \
michael@0 136 + \
michael@0 137 (((PRUint32)((PRUint8*)x)[2]) << 8) \
michael@0 138 + \
michael@0 139 (((PRUint32)((PRUint8*)x)[3]) << 0) \
michael@0 140 ) )
michael@0 141
michael@0 142 void print_hex(int amt, unsigned char *buf);
michael@0 143 void read_stream_bytes(unsigned char *d, DataBufferList *db, int length);
michael@0 144
michael@0 145 void myhalt(int dblsize,int collectedsize)
michael@0 146 {
michael@0 147
michael@0 148 PR_fprintf(PR_STDERR,"HALTED\n");
michael@0 149 PR_ASSERT(dblsize == collectedsize);
michael@0 150 exit(13);
michael@0 151 }
michael@0 152
michael@0 153 const char *get_error_text(int error)
michael@0 154 {
michael@0 155 switch (error) {
michael@0 156 case PR_IO_TIMEOUT_ERROR:
michael@0 157 return "Timeout";
michael@0 158 break;
michael@0 159 case PR_CONNECT_REFUSED_ERROR:
michael@0 160 return "Connection refused";
michael@0 161 break;
michael@0 162 case PR_NETWORK_UNREACHABLE_ERROR:
michael@0 163 return "Network unreachable";
michael@0 164 break;
michael@0 165 case PR_BAD_ADDRESS_ERROR:
michael@0 166 return "Bad address";
michael@0 167 break;
michael@0 168 case PR_CONNECT_RESET_ERROR:
michael@0 169 return "Connection reset";
michael@0 170 break;
michael@0 171 case PR_PIPE_ERROR:
michael@0 172 return "Pipe error";
michael@0 173 break;
michael@0 174 }
michael@0 175
michael@0 176 return "";
michael@0 177 }
michael@0 178
michael@0 179
michael@0 180
michael@0 181
michael@0 182
michael@0 183 void check_integrity(DataBufferList *dbl)
michael@0 184 {
michael@0 185 DataBuffer *db;
michael@0 186 int i;
michael@0 187
michael@0 188 db = dbl->first;
michael@0 189 i =0;
michael@0 190 while (db) {
michael@0 191 i+= db->length - db->offset;
michael@0 192 db = db->next;
michael@0 193 }
michael@0 194 if (i != dbl->size) {
michael@0 195 myhalt(dbl->size,i);
michael@0 196 }
michael@0 197 }
michael@0 198
michael@0 199 /* Free's the DataBuffer at the head of the list and returns the pointer
michael@0 200 * to the new head of the list.
michael@0 201 */
michael@0 202 DataBuffer *
michael@0 203 free_head(DataBufferList *dbl)
michael@0 204 {
michael@0 205 DataBuffer *db = dbl->first;
michael@0 206 PR_ASSERT(db->offset >= db->length);
michael@0 207 if (db->offset >= db->length) {
michael@0 208 dbl->first = db->next;
michael@0 209 if (dbl->first == NULL) {
michael@0 210 dbl->last = NULL;
michael@0 211 }
michael@0 212 PORT_Free(db->buffer);
michael@0 213 PORT_Free(db);
michael@0 214 db = dbl->first;
michael@0 215 }
michael@0 216 return db;
michael@0 217 }
michael@0 218
michael@0 219 void
michael@0 220 read_stream_bytes(unsigned char *d, DataBufferList *dbl, int length)
michael@0 221 {
michael@0 222 int copied = 0;
michael@0 223 DataBuffer *db = dbl->first;
michael@0 224
michael@0 225 if (!db) {
michael@0 226 PR_fprintf(PR_STDERR,"assert failed - dbl->first is null\n");
michael@0 227 exit(8);
michael@0 228 }
michael@0 229 while (length) {
michael@0 230 int toCopy;
michael@0 231 /* find the number of bytes to copy from the head buffer */
michael@0 232 /* if there's too many in this buffer, then only copy 'length' */
michael@0 233 toCopy = PR_MIN(db->length - db->offset, length);
michael@0 234
michael@0 235 memcpy(d + copied, db->buffer + db->offset, toCopy);
michael@0 236 copied += toCopy;
michael@0 237 db->offset += toCopy;
michael@0 238 length -= toCopy;
michael@0 239 dbl->size -= toCopy;
michael@0 240
michael@0 241 /* if we emptied the head buffer */
michael@0 242 if (db->offset >= db->length) {
michael@0 243 db = free_head(dbl);
michael@0 244 }
michael@0 245 }
michael@0 246
michael@0 247 check_integrity(dbl);
michael@0 248
michael@0 249 }
michael@0 250
michael@0 251 void
michael@0 252 flush_stream(DataBufferList *dbl)
michael@0 253 {
michael@0 254 DataBuffer *db = dbl->first;
michael@0 255 check_integrity(dbl);
michael@0 256 while (db) {
michael@0 257 db->offset = db->length;
michael@0 258 db = free_head(dbl);
michael@0 259 }
michael@0 260 dbl->size = 0;
michael@0 261 check_integrity(dbl);
michael@0 262 if (dbl->msgBuf) {
michael@0 263 PORT_Free(dbl->msgBuf);
michael@0 264 dbl->msgBuf = NULL;
michael@0 265 }
michael@0 266 dbl->msgBufOffset = 0;
michael@0 267 dbl->msgBufSize = 0;
michael@0 268 dbl->hMACsize = 0;
michael@0 269 }
michael@0 270
michael@0 271
michael@0 272 const char * V2CipherString(int cs_int)
michael@0 273 {
michael@0 274 char *cs_str;
michael@0 275 cs_str = NULL;
michael@0 276 switch (cs_int) {
michael@0 277
michael@0 278 case 0x010080: cs_str = "SSL2/RSA/RC4-128/MD5"; break;
michael@0 279 case 0x020080: cs_str = "SSL2/RSA/RC4-40/MD5"; break;
michael@0 280 case 0x030080: cs_str = "SSL2/RSA/RC2CBC128/MD5"; break;
michael@0 281 case 0x040080: cs_str = "SSL2/RSA/RC2CBC40/MD5"; break;
michael@0 282 case 0x050080: cs_str = "SSL2/RSA/IDEA128CBC/MD5"; break;
michael@0 283 case 0x060040: cs_str = "SSL2/RSA/DES56-CBC/MD5"; break;
michael@0 284 case 0x0700C0: cs_str = "SSL2/RSA/3DES192EDE-CBC/MD5"; break;
michael@0 285
michael@0 286 case 0x000001: cs_str = "SSL3/RSA/NULL/MD5"; break;
michael@0 287 case 0x000002: cs_str = "SSL3/RSA/NULL/SHA"; break;
michael@0 288 case 0x000003: cs_str = "SSL3/RSA/RC4-40/MD5"; break;
michael@0 289 case 0x000004: cs_str = "SSL3/RSA/RC4-128/MD5"; break;
michael@0 290 case 0x000005: cs_str = "SSL3/RSA/RC4-128/SHA"; break;
michael@0 291 case 0x000006: cs_str = "SSL3/RSA/RC2CBC40/MD5"; break;
michael@0 292 case 0x000007: cs_str = "SSL3/RSA/IDEA128CBC/SHA"; break;
michael@0 293 case 0x000008: cs_str = "SSL3/RSA/DES40-CBC/SHA"; break;
michael@0 294 case 0x000009: cs_str = "SSL3/RSA/DES56-CBC/SHA"; break;
michael@0 295 case 0x00000A: cs_str = "SSL3/RSA/3DES192EDE-CBC/SHA"; break;
michael@0 296
michael@0 297 case 0x00000B: cs_str = "SSL3/DH-DSS/DES40-CBC/SHA"; break;
michael@0 298 case 0x00000C: cs_str = "SSL3/DH-DSS/DES56-CBC/SHA"; break;
michael@0 299 case 0x00000D: cs_str = "SSL3/DH-DSS/DES192EDE3CBC/SHA"; break;
michael@0 300 case 0x00000E: cs_str = "SSL3/DH-RSA/DES40-CBC/SHA"; break;
michael@0 301 case 0x00000F: cs_str = "SSL3/DH-RSA/DES56-CBC/SHA"; break;
michael@0 302 case 0x000010: cs_str = "SSL3/DH-RSA/3DES192EDE-CBC/SHA"; break;
michael@0 303
michael@0 304 case 0x000011: cs_str = "SSL3/DHE-DSS/DES40-CBC/SHA"; break;
michael@0 305 case 0x000012: cs_str = "SSL3/DHE-DSS/DES56-CBC/SHA"; break;
michael@0 306 case 0x000013: cs_str = "SSL3/DHE-DSS/DES192EDE3CBC/SHA"; break;
michael@0 307 case 0x000014: cs_str = "SSL3/DHE-RSA/DES40-CBC/SHA"; break;
michael@0 308 case 0x000015: cs_str = "SSL3/DHE-RSA/DES56-CBC/SHA"; break;
michael@0 309 case 0x000016: cs_str = "SSL3/DHE-RSA/3DES192EDE-CBC/SHA"; break;
michael@0 310
michael@0 311 case 0x000017: cs_str = "SSL3/DH-anon/RC4-40/MD5"; break;
michael@0 312 case 0x000018: cs_str = "SSL3/DH-anon/RC4-128/MD5"; break;
michael@0 313 case 0x000019: cs_str = "SSL3/DH-anon/DES40-CBC/SHA"; break;
michael@0 314 case 0x00001A: cs_str = "SSL3/DH-anon/DES56-CBC/SHA"; break;
michael@0 315 case 0x00001B: cs_str = "SSL3/DH-anon/3DES192EDE-CBC/SHA"; break;
michael@0 316
michael@0 317 case 0x00001C: cs_str = "SSL3/FORTEZZA-DMS/NULL/SHA"; break;
michael@0 318 case 0x00001D: cs_str = "SSL3/FORTEZZA-DMS/FORTEZZA-CBC/SHA"; break;
michael@0 319 case 0x00001E: cs_str = "SSL3/FORTEZZA-DMS/RC4-128/SHA"; break;
michael@0 320
michael@0 321 case 0x00002F: cs_str = "TLS/RSA/AES128-CBC/SHA"; break;
michael@0 322 case 0x000030: cs_str = "TLS/DH-DSS/AES128-CBC/SHA"; break;
michael@0 323 case 0x000031: cs_str = "TLS/DH-RSA/AES128-CBC/SHA"; break;
michael@0 324 case 0x000032: cs_str = "TLS/DHE-DSS/AES128-CBC/SHA"; break;
michael@0 325 case 0x000033: cs_str = "TLS/DHE-RSA/AES128-CBC/SHA"; break;
michael@0 326 case 0x000034: cs_str = "TLS/DH-ANON/AES128-CBC/SHA"; break;
michael@0 327
michael@0 328 case 0x000035: cs_str = "TLS/RSA/AES256-CBC/SHA"; break;
michael@0 329 case 0x000036: cs_str = "TLS/DH-DSS/AES256-CBC/SHA"; break;
michael@0 330 case 0x000037: cs_str = "TLS/DH-RSA/AES256-CBC/SHA"; break;
michael@0 331 case 0x000038: cs_str = "TLS/DHE-DSS/AES256-CBC/SHA"; break;
michael@0 332 case 0x000039: cs_str = "TLS/DHE-RSA/AES256-CBC/SHA"; break;
michael@0 333 case 0x00003A: cs_str = "TLS/DH-ANON/AES256-CBC/SHA"; break;
michael@0 334
michael@0 335 case 0x00003B: cs_str = "TLS/RSA/NULL/SHA256"; break;
michael@0 336 case 0x00003C: cs_str = "TLS/RSA/AES128-CBC/SHA256"; break;
michael@0 337 case 0x00003D: cs_str = "TLS/RSA/AES256-CBC/SHA256"; break;
michael@0 338 case 0x00003E: cs_str = "TLS/DH-DSS/AES128-CBC/SHA256"; break;
michael@0 339 case 0x00003F: cs_str = "TLS/DH-RSA/AES128-CBC/SHA256"; break;
michael@0 340 case 0x000040: cs_str = "TLS/DHE-DSS/AES128-CBC/SHA256"; break;
michael@0 341
michael@0 342 case 0x000041: cs_str = "TLS/RSA/CAMELLIA128-CBC/SHA"; break;
michael@0 343 case 0x000042: cs_str = "TLS/DH-DSS/CAMELLIA128-CBC/SHA"; break;
michael@0 344 case 0x000043: cs_str = "TLS/DH-RSA/CAMELLIA128-CBC/SHA"; break;
michael@0 345 case 0x000044: cs_str = "TLS/DHE-DSS/CAMELLIA128-CBC/SHA"; break;
michael@0 346 case 0x000045: cs_str = "TLS/DHE-RSA/CAMELLIA128-CBC/SHA"; break;
michael@0 347 case 0x000046: cs_str = "TLS/DH-ANON/CAMELLIA128-CBC/SHA"; break;
michael@0 348
michael@0 349 case 0x000060: cs_str = "TLS/RSA-EXPORT1024/RC4-56/MD5"; break;
michael@0 350 case 0x000061: cs_str = "TLS/RSA-EXPORT1024/RC2CBC56/MD5"; break;
michael@0 351 case 0x000062: cs_str = "TLS/RSA-EXPORT1024/DES56-CBC/SHA"; break;
michael@0 352 case 0x000064: cs_str = "TLS/RSA-EXPORT1024/RC4-56/SHA"; break;
michael@0 353 case 0x000063: cs_str = "TLS/DHE-DSS_EXPORT1024/DES56-CBC/SHA"; break;
michael@0 354 case 0x000065: cs_str = "TLS/DHE-DSS_EXPORT1024/RC4-56/SHA"; break;
michael@0 355 case 0x000066: cs_str = "TLS/DHE-DSS/RC4-128/SHA"; break;
michael@0 356
michael@0 357 case 0x000067: cs_str = "TLS/DHE-RSA/AES128-CBC/SHA256"; break;
michael@0 358 case 0x000068: cs_str = "TLS/DH-DSS/AES256-CBC/SHA256"; break;
michael@0 359 case 0x000069: cs_str = "TLS/DH-RSA/AES256-CBC/SHA256"; break;
michael@0 360 case 0x00006A: cs_str = "TLS/DHE-DSS/AES256-CBC/SHA256"; break;
michael@0 361 case 0x00006B: cs_str = "TLS/DHE-RSA/AES256-CBC/SHA256"; break;
michael@0 362
michael@0 363 case 0x000072: cs_str = "TLS/DHE-DSS/3DESEDE-CBC/RMD160"; break;
michael@0 364 case 0x000073: cs_str = "TLS/DHE-DSS/AES128-CBC/RMD160"; break;
michael@0 365 case 0x000074: cs_str = "TLS/DHE-DSS/AES256-CBC/RMD160"; break;
michael@0 366
michael@0 367 case 0x000079: cs_str = "TLS/DHE-RSA/AES256-CBC/RMD160"; break;
michael@0 368
michael@0 369 case 0x00007C: cs_str = "TLS/RSA/3DESEDE-CBC/RMD160"; break;
michael@0 370 case 0x00007D: cs_str = "TLS/RSA/AES128-CBC/RMD160"; break;
michael@0 371 case 0x00007E: cs_str = "TLS/RSA/AES256-CBC/RMD160"; break;
michael@0 372
michael@0 373 case 0x000080: cs_str = "TLS/GOST341094/GOST28147-OFB/GOST28147"; break;
michael@0 374 case 0x000081: cs_str = "TLS/GOST34102001/GOST28147-OFB/GOST28147"; break;
michael@0 375 case 0x000082: cs_str = "TLS/GOST341094/NULL/GOSTR3411"; break;
michael@0 376 case 0x000083: cs_str = "TLS/GOST34102001/NULL/GOSTR3411"; break;
michael@0 377
michael@0 378 case 0x000084: cs_str = "TLS/RSA/CAMELLIA256-CBC/SHA"; break;
michael@0 379 case 0x000085: cs_str = "TLS/DH-DSS/CAMELLIA256-CBC/SHA"; break;
michael@0 380 case 0x000086: cs_str = "TLS/DH-RSA/CAMELLIA256-CBC/SHA"; break;
michael@0 381 case 0x000087: cs_str = "TLS/DHE-DSS/CAMELLIA256-CBC/SHA"; break;
michael@0 382 case 0x000088: cs_str = "TLS/DHE-RSA/CAMELLIA256-CBC/SHA"; break;
michael@0 383 case 0x000089: cs_str = "TLS/DH-ANON/CAMELLIA256-CBC/SHA"; break;
michael@0 384 case 0x00008A: cs_str = "TLS/PSK/RC4-128/SHA"; break;
michael@0 385 case 0x00008B: cs_str = "TLS/PSK/3DES-EDE-CBC/SHA"; break;
michael@0 386 case 0x00008C: cs_str = "TLS/PSK/AES128-CBC/SHA"; break;
michael@0 387 case 0x00008D: cs_str = "TLS/PSK/AES256-CBC/SHA"; break;
michael@0 388 case 0x00008E: cs_str = "TLS/DHE-PSK/RC4-128/SHA"; break;
michael@0 389 case 0x00008F: cs_str = "TLS/DHE-PSK/3DES-EDE-CBC/SHA"; break;
michael@0 390 case 0x000090: cs_str = "TLS/DHE-PSK/AES128-CBC/SHA"; break;
michael@0 391 case 0x000091: cs_str = "TLS/DHE-PSK/AES256-CBC/SHA"; break;
michael@0 392 case 0x000092: cs_str = "TLS/RSA-PSK/RC4-128/SHA"; break;
michael@0 393 case 0x000093: cs_str = "TLS/RSA-PSK/3DES-EDE-CBC/SHA"; break;
michael@0 394 case 0x000094: cs_str = "TLS/RSA-PSK/AES128-CBC/SHA"; break;
michael@0 395 case 0x000095: cs_str = "TLS/RSA-PSK/AES256-CBC/SHA"; break;
michael@0 396 case 0x000096: cs_str = "TLS/RSA/SEED-CBC/SHA"; break;
michael@0 397 case 0x000097: cs_str = "TLS/DH-DSS/SEED-CBC/SHA"; break;
michael@0 398 case 0x000098: cs_str = "TLS/DH-RSA/SEED-CBC/SHA"; break;
michael@0 399 case 0x000099: cs_str = "TLS/DHE-DSS/SEED-CBC/SHA"; break;
michael@0 400 case 0x00009A: cs_str = "TLS/DHE-RSA/SEED-CBC/SHA"; break;
michael@0 401 case 0x00009B: cs_str = "TLS/DH-ANON/SEED-CBC/SHA"; break;
michael@0 402 case 0x00009C: cs_str = "TLS/RSA/AES128-GCM/SHA256"; break;
michael@0 403 case 0x00009E: cs_str = "TLS/DHE-RSA/AES128-GCM/SHA256"; break;
michael@0 404
michael@0 405 case 0x0000FF: cs_str = "TLS_EMPTY_RENEGOTIATION_INFO_SCSV"; break;
michael@0 406
michael@0 407 case 0x00C001: cs_str = "TLS/ECDH-ECDSA/NULL/SHA"; break;
michael@0 408 case 0x00C002: cs_str = "TLS/ECDH-ECDSA/RC4-128/SHA"; break;
michael@0 409 case 0x00C003: cs_str = "TLS/ECDH-ECDSA/3DES-EDE-CBC/SHA"; break;
michael@0 410 case 0x00C004: cs_str = "TLS/ECDH-ECDSA/AES128-CBC/SHA"; break;
michael@0 411 case 0x00C005: cs_str = "TLS/ECDH-ECDSA/AES256-CBC/SHA"; break;
michael@0 412 case 0x00C006: cs_str = "TLS/ECDHE-ECDSA/NULL/SHA"; break;
michael@0 413 case 0x00C007: cs_str = "TLS/ECDHE-ECDSA/RC4-128/SHA"; break;
michael@0 414 case 0x00C008: cs_str = "TLS/ECDHE-ECDSA/3DES-EDE-CBC/SHA";break;
michael@0 415 case 0x00C009: cs_str = "TLS/ECDHE-ECDSA/AES128-CBC/SHA"; break;
michael@0 416 case 0x00C00A: cs_str = "TLS/ECDHE-ECDSA/AES256-CBC/SHA"; break;
michael@0 417 case 0x00C00B: cs_str = "TLS/ECDH-RSA/NULL/SHA"; break;
michael@0 418 case 0x00C00C: cs_str = "TLS/ECDH-RSA/RC4-128/SHA"; break;
michael@0 419 case 0x00C00D: cs_str = "TLS/ECDH-RSA/3DES-EDE-CBC/SHA"; break;
michael@0 420 case 0x00C00E: cs_str = "TLS/ECDH-RSA/AES128-CBC/SHA"; break;
michael@0 421 case 0x00C00F: cs_str = "TLS/ECDH-RSA/AES256-CBC/SHA"; break;
michael@0 422 case 0x00C010: cs_str = "TLS/ECDHE-RSA/NULL/SHA"; break;
michael@0 423 case 0x00C011: cs_str = "TLS/ECDHE-RSA/RC4-128/SHA"; break;
michael@0 424 case 0x00C012: cs_str = "TLS/ECDHE-RSA/3DES-EDE-CBC/SHA"; break;
michael@0 425 case 0x00C013: cs_str = "TLS/ECDHE-RSA/AES128-CBC/SHA"; break;
michael@0 426 case 0x00C014: cs_str = "TLS/ECDHE-RSA/AES256-CBC/SHA"; break;
michael@0 427 case 0x00C015: cs_str = "TLS/ECDH-anon/NULL/SHA"; break;
michael@0 428 case 0x00C016: cs_str = "TLS/ECDH-anon/RC4-128/SHA"; break;
michael@0 429 case 0x00C017: cs_str = "TLS/ECDH-anon/3DES-EDE-CBC/SHA"; break;
michael@0 430 case 0x00C018: cs_str = "TLS/ECDH-anon/AES128-CBC/SHA"; break;
michael@0 431 case 0x00C019: cs_str = "TLS/ECDH-anon/AES256-CBC/SHA"; break;
michael@0 432
michael@0 433 case 0x00C023: cs_str = "TLS/ECDHE-ECDSA/AES128-CBC/SHA256"; break;
michael@0 434 case 0x00C024: cs_str = "TLS/ECDHE-ECDSA/AES256-CBC/SHA384"; break;
michael@0 435 case 0x00C025: cs_str = "TLS/ECDH-ECDSA/AES128-CBC/SHA256"; break;
michael@0 436 case 0x00C026: cs_str = "TLS/ECDH-ECDSA/AES256-CBC/SHA384"; break;
michael@0 437 case 0x00C027: cs_str = "TLS/ECDHE-RSA/AES128-CBC/SHA256"; break;
michael@0 438 case 0x00C028: cs_str = "TLS/ECDHE-RSA/AES256-CBC/SHA384"; break;
michael@0 439 case 0x00C029: cs_str = "TLS/ECDH-RSA/AES128-CBC/SHA256"; break;
michael@0 440 case 0x00C02A: cs_str = "TLS/ECDH-RSA/AES256-CBC/SHA384"; break;
michael@0 441 case 0x00C02B: cs_str = "TLS/ECDHE-ECDSA/AES128-GCM/SHA256"; break;
michael@0 442 case 0x00C02C: cs_str = "TLS/ECDHE-ECDSA/AES256-GCM/SHA384"; break;
michael@0 443 case 0x00C02F: cs_str = "TLS/ECDHE-RSA/AES128-GCM/SHA256"; break;
michael@0 444
michael@0 445 case 0x00FEFF: cs_str = "SSL3/RSA-FIPS/3DESEDE-CBC/SHA"; break;
michael@0 446 case 0x00FEFE: cs_str = "SSL3/RSA-FIPS/DES-CBC/SHA"; break;
michael@0 447 case 0x00FFE1: cs_str = "SSL3/RSA-FIPS/DES56-CBC/SHA"; break;
michael@0 448 case 0x00FFE0: cs_str = "SSL3/RSA-FIPS/3DES192EDE-CBC/SHA";break;
michael@0 449
michael@0 450 /* the string literal is broken up to avoid trigraphs */
michael@0 451 default: cs_str = "????" "/????????" "/?????????" "/???"; break;
michael@0 452 }
michael@0 453
michael@0 454 return cs_str;
michael@0 455 }
michael@0 456
michael@0 457 const char * CompressionMethodString(int cm_int)
michael@0 458 {
michael@0 459 char *cm_str;
michael@0 460 cm_str = NULL;
michael@0 461 switch (cm_int) {
michael@0 462 case 0: cm_str = "NULL"; break;
michael@0 463 case 1: cm_str = "DEFLATE"; break; /* RFC 3749 */
michael@0 464 case 64: cm_str = "LZS"; break; /* RFC 3943 */
michael@0 465 default: cm_str = "???"; break;
michael@0 466 }
michael@0 467
michael@0 468 return cm_str;
michael@0 469 }
michael@0 470
michael@0 471 const char * helloExtensionNameString(int ex_num)
michael@0 472 {
michael@0 473 const char *ex_name = NULL;
michael@0 474 static char buf[10];
michael@0 475
michael@0 476 switch (ex_num) {
michael@0 477 case 0: ex_name = "server_name"; break;
michael@0 478 case 1: ex_name = "max_fragment_length"; break;
michael@0 479 case 2: ex_name = "client_certificate_url"; break;
michael@0 480 case 3: ex_name = "trusted_ca_keys"; break;
michael@0 481 case 4: ex_name = "truncated_hmac"; break;
michael@0 482 case 5: ex_name = "status_request"; break;
michael@0 483 case 10: ex_name = "elliptic_curves"; break;
michael@0 484 case 11: ex_name = "ec_point_formats"; break;
michael@0 485 case 13: ex_name = "signature_algorithms"; break;
michael@0 486 case 35: ex_name = "session_ticket"; break;
michael@0 487 case 0xff01: ex_name = "renegotiation_info"; break;
michael@0 488 default: sprintf(buf, "%d", ex_num); ex_name = (const char *)buf; break;
michael@0 489 }
michael@0 490
michael@0 491 return ex_name;
michael@0 492 }
michael@0 493
michael@0 494 static int isNULLmac(int cs_int)
michael@0 495 {
michael@0 496 return (cs_int == TLS_NULL_WITH_NULL_NULL);
michael@0 497 }
michael@0 498
michael@0 499 static int isNULLcipher(int cs_int)
michael@0 500 {
michael@0 501 return ((cs_int == TLS_RSA_WITH_NULL_MD5) ||
michael@0 502 (cs_int == TLS_RSA_WITH_NULL_SHA) ||
michael@0 503 (cs_int == SSL_FORTEZZA_DMS_WITH_NULL_SHA) ||
michael@0 504 (cs_int == TLS_ECDH_ECDSA_WITH_NULL_SHA) ||
michael@0 505 (cs_int == TLS_ECDHE_ECDSA_WITH_NULL_SHA) ||
michael@0 506 (cs_int == TLS_ECDH_RSA_WITH_NULL_SHA) ||
michael@0 507 (cs_int == TLS_ECDHE_RSA_WITH_NULL_SHA));
michael@0 508 }
michael@0 509
michael@0 510 void partial_packet(int thispacket, int size, int needed)
michael@0 511 {
michael@0 512 PR_fprintf(PR_STDOUT,"(%u bytes", thispacket);
michael@0 513 if (thispacket < needed) {
michael@0 514 PR_fprintf(PR_STDOUT,", making %u", size);
michael@0 515 }
michael@0 516 PR_fprintf(PR_STDOUT," of %u", needed);
michael@0 517 if (size > needed) {
michael@0 518 PR_fprintf(PR_STDOUT,", with %u left over", size - needed);
michael@0 519 }
michael@0 520 PR_fprintf(PR_STDOUT,")\n");
michael@0 521 }
michael@0 522
michael@0 523 char * get_time_string(void)
michael@0 524 {
michael@0 525 char *cp;
michael@0 526 char *eol;
michael@0 527 time_t tt;
michael@0 528
michael@0 529 time(&tt);
michael@0 530 cp = ctime(&tt);
michael@0 531 eol = strchr(cp, '\n');
michael@0 532 if (eol)
michael@0 533 *eol = 0;
michael@0 534 return cp;
michael@0 535 }
michael@0 536
michael@0 537 void print_sslv2(DataBufferList *s, unsigned char *recordBuf, unsigned int recordLen)
michael@0 538 {
michael@0 539 ClientHelloV2 *chv2;
michael@0 540 ServerHelloV2 *shv2;
michael@0 541 unsigned char *pos;
michael@0 542 unsigned int p;
michael@0 543 unsigned int q;
michael@0 544 PRUint32 len;
michael@0 545
michael@0 546 chv2 = (ClientHelloV2 *)recordBuf;
michael@0 547 shv2 = (ServerHelloV2 *)recordBuf;
michael@0 548 if (s->isEncrypted) {
michael@0 549 PR_fprintf(PR_STDOUT," [ssl2] Encrypted {...}\n");
michael@0 550 return;
michael@0 551 }
michael@0 552 PR_fprintf(PR_STDOUT," [%s]", get_time_string() );
michael@0 553 switch(chv2->type) {
michael@0 554 case 1:
michael@0 555 PR_fprintf(PR_STDOUT," [ssl2] ClientHelloV2 {\n");
michael@0 556 PR_fprintf(PR_STDOUT," version = {0x%02x, 0x%02x}\n",
michael@0 557 (PRUint32)chv2->version[0],(PRUint32)chv2->version[1]);
michael@0 558 PR_fprintf(PR_STDOUT," cipher-specs-length = %d (0x%02x)\n",
michael@0 559 (PRUint32)(GET_SHORT((chv2->cslength))),
michael@0 560 (PRUint32)(GET_SHORT((chv2->cslength))));
michael@0 561 PR_fprintf(PR_STDOUT," sid-length = %d (0x%02x)\n",
michael@0 562 (PRUint32)(GET_SHORT((chv2->sidlength))),
michael@0 563 (PRUint32)(GET_SHORT((chv2->sidlength))));
michael@0 564 PR_fprintf(PR_STDOUT," challenge-length = %d (0x%02x)\n",
michael@0 565 (PRUint32)(GET_SHORT((chv2->rndlength))),
michael@0 566 (PRUint32)(GET_SHORT((chv2->rndlength))));
michael@0 567 PR_fprintf(PR_STDOUT," cipher-suites = { \n");
michael@0 568 for (p=0;p<GET_SHORT((chv2->cslength));p+=3) {
michael@0 569 PRUint32 cs_int = GET_24((&chv2->csuites[p]));
michael@0 570 const char *cs_str = V2CipherString(cs_int);
michael@0 571
michael@0 572 PR_fprintf(PR_STDOUT," (0x%06x) %s\n",
michael@0 573 cs_int, cs_str);
michael@0 574 }
michael@0 575 q = p;
michael@0 576 PR_fprintf(PR_STDOUT," }\n");
michael@0 577 if (chv2->sidlength) {
michael@0 578 PR_fprintf(PR_STDOUT," session-id = { ");
michael@0 579 for (p=0;p<GET_SHORT((chv2->sidlength));p+=2) {
michael@0 580 PR_fprintf(PR_STDOUT,"0x%04x ",(PRUint32)(GET_SHORT((&chv2->csuites[p+q]))));
michael@0 581 }
michael@0 582 }
michael@0 583 q += p;
michael@0 584 PR_fprintf(PR_STDOUT,"}\n");
michael@0 585 if (chv2->rndlength) {
michael@0 586 PR_fprintf(PR_STDOUT," challenge = { ");
michael@0 587 for (p=0;p<GET_SHORT((chv2->rndlength));p+=2) {
michael@0 588 PR_fprintf(PR_STDOUT,"0x%04x ",(PRUint32)(GET_SHORT((&chv2->csuites[p+q]))));
michael@0 589 }
michael@0 590 PR_fprintf(PR_STDOUT,"}\n");
michael@0 591 }
michael@0 592 PR_fprintf(PR_STDOUT,"}\n");
michael@0 593 break;
michael@0 594 /* end of V2 CLientHello Parsing */
michael@0 595
michael@0 596 case 2: /* Client Master Key */
michael@0 597 {
michael@0 598 const char *cs_str=NULL;
michael@0 599 PRUint32 cs_int=0;
michael@0 600 ClientMasterKeyV2 *cmkv2;
michael@0 601 cmkv2 = (ClientMasterKeyV2 *)chv2;
michael@0 602 isV2Session = 1;
michael@0 603
michael@0 604 PR_fprintf(PR_STDOUT," [ssl2] ClientMasterKeyV2 { \n");
michael@0 605
michael@0 606 cs_int = GET_24(&cmkv2->cipherkind[0]);
michael@0 607 cs_str = V2CipherString(cs_int);
michael@0 608 PR_fprintf(PR_STDOUT," cipher-spec-chosen = (0x%06x) %s\n",
michael@0 609 cs_int, cs_str);
michael@0 610
michael@0 611 PR_fprintf(PR_STDOUT," clear-portion = %d bits\n",
michael@0 612 8*(PRUint32)(GET_SHORT((cmkv2->clearkey))));
michael@0 613
michael@0 614 PR_fprintf(PR_STDOUT," }\n");
michael@0 615 clientstream.isEncrypted = 1;
michael@0 616 serverstream.isEncrypted = 1;
michael@0 617 }
michael@0 618 break;
michael@0 619
michael@0 620
michael@0 621 case 3:
michael@0 622 PR_fprintf(PR_STDOUT," [ssl2] Client Finished V2 {...}\n");
michael@0 623 isV2Session = 1;
michael@0 624 break;
michael@0 625
michael@0 626
michael@0 627 case 4: /* V2 Server Hello */
michael@0 628 isV2Session = 1;
michael@0 629
michael@0 630 PR_fprintf(PR_STDOUT," [ssl2] ServerHelloV2 {\n");
michael@0 631 PR_fprintf(PR_STDOUT," sid hit = {0x%02x}\n",
michael@0 632 (PRUintn)shv2->sidhit);
michael@0 633 PR_fprintf(PR_STDOUT," version = {0x%02x, 0x%02x}\n",
michael@0 634 (PRUint32)shv2->version[0],(PRUint32)shv2->version[1]);
michael@0 635 PR_fprintf(PR_STDOUT," cipher-specs-length = %d (0x%02x)\n",
michael@0 636 (PRUint32)(GET_SHORT((shv2->cslength))),
michael@0 637 (PRUint32)(GET_SHORT((shv2->cslength))));
michael@0 638 PR_fprintf(PR_STDOUT," sid-length = %d (0x%02x)\n",
michael@0 639 (PRUint32)(GET_SHORT((shv2->cidlength))),
michael@0 640 (PRUint32)(GET_SHORT((shv2->cidlength))));
michael@0 641
michael@0 642 pos = (unsigned char *)shv2;
michael@0 643 pos += 2; /* skip length header */
michael@0 644 pos += 11; /* position pointer to Certificate data area */
michael@0 645 q = GET_SHORT(&shv2->certlength);
michael@0 646 if (q >recordLen) {
michael@0 647 goto eosh;
michael@0 648 }
michael@0 649 pos += q; /* skip certificate */
michael@0 650
michael@0 651 PR_fprintf(PR_STDOUT," cipher-suites = { ");
michael@0 652 len = GET_SHORT((shv2->cslength));
michael@0 653 for (p = 0; p < len; p += 3) {
michael@0 654 PRUint32 cs_int = GET_24((pos+p));
michael@0 655 const char *cs_str = V2CipherString(cs_int);
michael@0 656 PR_fprintf(PR_STDOUT,"\n ");
michael@0 657 PR_fprintf(PR_STDOUT,"(0x%06x) %s", cs_int, cs_str);
michael@0 658 }
michael@0 659 pos += len;
michael@0 660 PR_fprintf(PR_STDOUT," }\n"); /* End of cipher suites */
michael@0 661 len = (PRUint32)GET_SHORT((shv2->cidlength));
michael@0 662 if (len) {
michael@0 663 PR_fprintf(PR_STDOUT," connection-id = { ");
michael@0 664 for (p = 0; p < len; p += 2) {
michael@0 665 PR_fprintf(PR_STDOUT,"0x%04x ", (PRUint32)(GET_SHORT((pos + p))));
michael@0 666 }
michael@0 667 PR_fprintf(PR_STDOUT," }\n"); /* End of connection id */
michael@0 668 }
michael@0 669 eosh:
michael@0 670 PR_fprintf(PR_STDOUT,"\n }\n"); /* end of ServerHelloV2 */
michael@0 671 if (shv2->sidhit) {
michael@0 672 clientstream.isEncrypted = 1;
michael@0 673 serverstream.isEncrypted = 1;
michael@0 674 }
michael@0 675 break;
michael@0 676
michael@0 677 case 5:
michael@0 678 PR_fprintf(PR_STDOUT," [ssl2] Server Verify V2 {...}\n");
michael@0 679 isV2Session = 1;
michael@0 680 break;
michael@0 681
michael@0 682 case 6:
michael@0 683 PR_fprintf(PR_STDOUT," [ssl2] Server Finished V2 {...}\n");
michael@0 684 isV2Session = 1;
michael@0 685 break;
michael@0 686
michael@0 687 case 7:
michael@0 688 PR_fprintf(PR_STDOUT," [ssl2] Request Certificate V2 {...}\n");
michael@0 689 isV2Session = 1;
michael@0 690 break;
michael@0 691
michael@0 692 case 8:
michael@0 693 PR_fprintf(PR_STDOUT," [ssl2] Client Certificate V2 {...}\n");
michael@0 694 isV2Session = 1;
michael@0 695 break;
michael@0 696
michael@0 697 default:
michael@0 698 PR_fprintf(PR_STDOUT," [ssl2] UnknownType 0x%02x {...}\n",
michael@0 699 (PRUint32)chv2->type);
michael@0 700 break;
michael@0 701 }
michael@0 702 }
michael@0 703
michael@0 704
michael@0 705
michael@0 706 unsigned int print_hello_extension(unsigned char * hsdata,
michael@0 707 unsigned int length,
michael@0 708 unsigned int pos)
michael@0 709 {
michael@0 710 /* pretty print extensions, if any */
michael@0 711 if (pos < length) {
michael@0 712 int exListLen = GET_SHORT((hsdata+pos)); pos += 2;
michael@0 713 PR_fprintf(PR_STDOUT,
michael@0 714 " extensions[%d] = {\n", exListLen);
michael@0 715 while (exListLen > 0 && pos < length) {
michael@0 716 int exLen;
michael@0 717 int exType = GET_SHORT((hsdata+pos)); pos += 2;
michael@0 718 exLen = GET_SHORT((hsdata+pos)); pos += 2;
michael@0 719 /* dump the extension */
michael@0 720 PR_fprintf(PR_STDOUT,
michael@0 721 " extension type %s, length [%d]",
michael@0 722 helloExtensionNameString(exType), exLen);
michael@0 723 if (exLen > 0) {
michael@0 724 PR_fprintf(PR_STDOUT, " = {\n");
michael@0 725 print_hex(exLen, hsdata + pos);
michael@0 726 PR_fprintf(PR_STDOUT, " }\n");
michael@0 727 } else {
michael@0 728 PR_fprintf(PR_STDOUT, "\n");
michael@0 729 }
michael@0 730 pos += exLen;
michael@0 731 exListLen -= 2 + exLen;
michael@0 732 }
michael@0 733 PR_fprintf(PR_STDOUT," }\n");
michael@0 734 }
michael@0 735 return pos;
michael@0 736 }
michael@0 737
michael@0 738 /*
michael@0 739 * Note this must match (exactly) the enumeration ocspResponseStatus.
michael@0 740 */
michael@0 741 static char *responseStatusNames[] = {
michael@0 742 "successful (Response has valid confirmations)",
michael@0 743 "malformedRequest (Illegal confirmation request)",
michael@0 744 "internalError (Internal error in issuer)",
michael@0 745 "tryLater (Try again later)",
michael@0 746 "unused ((4) is not used)",
michael@0 747 "sigRequired (Must sign the request)",
michael@0 748 "unauthorized (Request unauthorized)",
michael@0 749 };
michael@0 750
michael@0 751 static void
michael@0 752 print_ocsp_cert_id (FILE *out_file, CERTOCSPCertID *cert_id, int level)
michael@0 753 {
michael@0 754 SECU_Indent (out_file, level);
michael@0 755 fprintf (out_file, "Cert ID:\n");
michael@0 756 level++;
michael@0 757 /*
michael@0 758 SECU_PrintAlgorithmID (out_file, &(cert_id->hashAlgorithm),
michael@0 759 "Hash Algorithm", level);
michael@0 760 SECU_PrintAsHex (out_file, &(cert_id->issuerNameHash),
michael@0 761 "Issuer Name Hash", level);
michael@0 762 SECU_PrintAsHex (out_file, &(cert_id->issuerKeyHash),
michael@0 763 "Issuer Key Hash", level);
michael@0 764 */
michael@0 765 SECU_PrintInteger (out_file, &(cert_id->serialNumber),
michael@0 766 "Serial Number", level);
michael@0 767 /* XXX lookup the cert; if found, print something nice (nickname?) */
michael@0 768 }
michael@0 769
michael@0 770 static void
michael@0 771 print_ocsp_version (FILE *out_file, SECItem *version, int level)
michael@0 772 {
michael@0 773 if (version->len > 0) {
michael@0 774 SECU_PrintInteger (out_file, version, "Version", level);
michael@0 775 } else {
michael@0 776 SECU_Indent (out_file, level);
michael@0 777 fprintf (out_file, "Version: DEFAULT\n");
michael@0 778 }
michael@0 779 }
michael@0 780
michael@0 781 static void
michael@0 782 print_responder_id (FILE *out_file, ocspResponderID *responderID, int level)
michael@0 783 {
michael@0 784 SECU_Indent (out_file, level);
michael@0 785 fprintf (out_file, "Responder ID ");
michael@0 786
michael@0 787 switch (responderID->responderIDType) {
michael@0 788 case ocspResponderID_byName:
michael@0 789 fprintf (out_file, "(byName):\n");
michael@0 790 SECU_PrintName (out_file, &(responderID->responderIDValue.name),
michael@0 791 "Name", level + 1);
michael@0 792 break;
michael@0 793 case ocspResponderID_byKey:
michael@0 794 fprintf (out_file, "(byKey):\n");
michael@0 795 SECU_PrintAsHex (out_file, &(responderID->responderIDValue.keyHash),
michael@0 796 "Key Hash", level + 1);
michael@0 797 break;
michael@0 798 default:
michael@0 799 fprintf (out_file, "Unrecognized Responder ID Type\n");
michael@0 800 break;
michael@0 801 }
michael@0 802 }
michael@0 803
michael@0 804 static void
michael@0 805 print_ocsp_extensions (FILE *out_file, CERTCertExtension **extensions,
michael@0 806 char *msg, int level)
michael@0 807 {
michael@0 808 if (extensions) {
michael@0 809 SECU_PrintExtensions (out_file, extensions, msg, level);
michael@0 810 } else {
michael@0 811 SECU_Indent (out_file, level);
michael@0 812 fprintf (out_file, "No %s\n", msg);
michael@0 813 }
michael@0 814 }
michael@0 815
michael@0 816 static void
michael@0 817 print_revoked_info (FILE *out_file, ocspRevokedInfo *revoked_info, int level)
michael@0 818 {
michael@0 819 SECU_PrintGeneralizedTime (out_file, &(revoked_info->revocationTime),
michael@0 820 "Revocation Time", level);
michael@0 821
michael@0 822 if (revoked_info->revocationReason != NULL) {
michael@0 823 SECU_PrintAsHex (out_file, revoked_info->revocationReason,
michael@0 824 "Revocation Reason", level);
michael@0 825 } else {
michael@0 826 SECU_Indent (out_file, level);
michael@0 827 fprintf (out_file, "No Revocation Reason.\n");
michael@0 828 }
michael@0 829 }
michael@0 830
michael@0 831 static void
michael@0 832 print_cert_status (FILE *out_file, ocspCertStatus *status, int level)
michael@0 833 {
michael@0 834 SECU_Indent (out_file, level);
michael@0 835 fprintf (out_file, "Status: ");
michael@0 836
michael@0 837 switch (status->certStatusType) {
michael@0 838 case ocspCertStatus_good:
michael@0 839 fprintf (out_file, "Cert is good.\n");
michael@0 840 break;
michael@0 841 case ocspCertStatus_revoked:
michael@0 842 fprintf (out_file, "Cert has been revoked.\n");
michael@0 843 print_revoked_info (out_file, status->certStatusInfo.revokedInfo,
michael@0 844 level + 1);
michael@0 845 break;
michael@0 846 case ocspCertStatus_unknown:
michael@0 847 fprintf (out_file, "Cert is unknown to responder.\n");
michael@0 848 break;
michael@0 849 default:
michael@0 850 fprintf (out_file, "Unrecognized status.\n");
michael@0 851 break;
michael@0 852 }
michael@0 853 }
michael@0 854
michael@0 855 static void
michael@0 856 print_single_response (FILE *out_file, CERTOCSPSingleResponse *single,
michael@0 857 int level)
michael@0 858 {
michael@0 859 print_ocsp_cert_id (out_file, single->certID, level);
michael@0 860
michael@0 861 print_cert_status (out_file, single->certStatus, level);
michael@0 862
michael@0 863 SECU_PrintGeneralizedTime (out_file, &(single->thisUpdate),
michael@0 864 "This Update", level);
michael@0 865
michael@0 866 if (single->nextUpdate != NULL) {
michael@0 867 SECU_PrintGeneralizedTime (out_file, single->nextUpdate,
michael@0 868 "Next Update", level);
michael@0 869 } else {
michael@0 870 SECU_Indent (out_file, level);
michael@0 871 fprintf (out_file, "No Next Update\n");
michael@0 872 }
michael@0 873
michael@0 874 print_ocsp_extensions (out_file, single->singleExtensions,
michael@0 875 "Single Response Extensions", level);
michael@0 876 }
michael@0 877
michael@0 878 static void
michael@0 879 print_response_data (FILE *out_file, ocspResponseData *responseData, int level)
michael@0 880 {
michael@0 881 SECU_Indent (out_file, level);
michael@0 882 fprintf (out_file, "Response Data:\n");
michael@0 883 level++;
michael@0 884
michael@0 885 print_ocsp_version (out_file, &(responseData->version), level);
michael@0 886
michael@0 887 print_responder_id (out_file, responseData->responderID, level);
michael@0 888
michael@0 889 SECU_PrintGeneralizedTime (out_file, &(responseData->producedAt),
michael@0 890 "Produced At", level);
michael@0 891
michael@0 892 if (responseData->responses != NULL) {
michael@0 893 int i;
michael@0 894
michael@0 895 for (i = 0; responseData->responses[i] != NULL; i++) {
michael@0 896 SECU_Indent (out_file, level);
michael@0 897 fprintf (out_file, "Response %d:\n", i);
michael@0 898 print_single_response (out_file, responseData->responses[i],
michael@0 899 level + 1);
michael@0 900 }
michael@0 901 } else {
michael@0 902 fprintf (out_file, "Response list is empty.\n");
michael@0 903 }
michael@0 904
michael@0 905 print_ocsp_extensions (out_file, responseData->responseExtensions,
michael@0 906 "Response Extensions", level);
michael@0 907 }
michael@0 908
michael@0 909 static void
michael@0 910 print_basic_response (FILE *out_file, ocspBasicOCSPResponse *basic, int level)
michael@0 911 {
michael@0 912 SECU_Indent (out_file, level);
michael@0 913 fprintf (out_file, "Basic OCSP Response:\n");
michael@0 914 level++;
michael@0 915
michael@0 916 print_response_data (out_file, basic->tbsResponseData, level);
michael@0 917 }
michael@0 918
michael@0 919 static void
michael@0 920 print_status_response(SECItem *data)
michael@0 921 {
michael@0 922 int level = 2;
michael@0 923 CERTOCSPResponse *response;
michael@0 924 response = CERT_DecodeOCSPResponse (data);
michael@0 925 if (!response) {
michael@0 926 SECU_Indent (stdout, level);
michael@0 927 fprintf(stdout,"unable to decode certificate_status\n");
michael@0 928 return;
michael@0 929 }
michael@0 930
michael@0 931 SECU_Indent (stdout, level);
michael@0 932 if (response->statusValue >= ocspResponse_min &&
michael@0 933 response->statusValue <= ocspResponse_max) {
michael@0 934 fprintf (stdout, "Response Status: %s\n",
michael@0 935 responseStatusNames[response->statusValue]);
michael@0 936 } else {
michael@0 937 fprintf (stdout,
michael@0 938 "Response Status: other (Status value %d out of defined range)\n",
michael@0 939 (int)response->statusValue);
michael@0 940 }
michael@0 941
michael@0 942 if (response->statusValue == ocspResponse_successful) {
michael@0 943 ocspResponseBytes *responseBytes = response->responseBytes;
michael@0 944 PORT_Assert (responseBytes != NULL);
michael@0 945
michael@0 946 level++;
michael@0 947 SECU_PrintObjectID (stdout, &(responseBytes->responseType),
michael@0 948 "Response Type", level);
michael@0 949 switch (response->responseBytes->responseTypeTag) {
michael@0 950 case SEC_OID_PKIX_OCSP_BASIC_RESPONSE:
michael@0 951 print_basic_response (stdout,
michael@0 952 responseBytes->decodedResponse.basic,
michael@0 953 level);
michael@0 954 break;
michael@0 955 default:
michael@0 956 SECU_Indent (stdout, level);
michael@0 957 fprintf (stdout, "Unknown response syntax\n");
michael@0 958 break;
michael@0 959 }
michael@0 960 } else {
michael@0 961 SECU_Indent (stdout, level);
michael@0 962 fprintf (stdout, "Unsuccessful response, no more information.\n");
michael@0 963 }
michael@0 964
michael@0 965 CERT_DestroyOCSPResponse (response);
michael@0 966 }
michael@0 967
michael@0 968 /* In the case of renegotiation, handshakes that occur in an already MAC'ed
michael@0 969 * channel, by the time of this call, the caller has already removed the MAC
michael@0 970 * from input recordLen. The only MAC'ed record that will get here with its
michael@0 971 * MAC intact (not removed) is the first Finished message on the connection.
michael@0 972 */
michael@0 973 void print_ssl3_handshake(unsigned char *recordBuf,
michael@0 974 unsigned int recordLen,
michael@0 975 SSLRecord * sr,
michael@0 976 DataBufferList *s)
michael@0 977 {
michael@0 978 struct sslhandshake sslh;
michael@0 979 unsigned char * hsdata;
michael@0 980 int offset=0;
michael@0 981
michael@0 982 PR_fprintf(PR_STDOUT," handshake {\n");
michael@0 983
michael@0 984 if (s->msgBufOffset && s->msgBuf) {
michael@0 985 /* append recordBuf to msgBuf, then use msgBuf */
michael@0 986 if (s->msgBufOffset + recordLen > s->msgBufSize) {
michael@0 987 int newSize = s->msgBufOffset + recordLen;
michael@0 988 unsigned char * newBuf = PORT_Realloc(s->msgBuf, newSize);
michael@0 989 if (!newBuf) {
michael@0 990 PR_ASSERT(newBuf);
michael@0 991 showErr( "Realloc failed");
michael@0 992 exit(10);
michael@0 993 }
michael@0 994 s->msgBuf = newBuf;
michael@0 995 s->msgBufSize = newSize;
michael@0 996 }
michael@0 997 memcpy(s->msgBuf + s->msgBufOffset, recordBuf, recordLen);
michael@0 998 s->msgBufOffset += recordLen;
michael@0 999 recordLen = s->msgBufOffset;
michael@0 1000 recordBuf = s->msgBuf;
michael@0 1001 }
michael@0 1002 while (offset + 4 <= recordLen) {
michael@0 1003 sslh.type = recordBuf[offset];
michael@0 1004 sslh.length = GET_24(recordBuf+offset+1);
michael@0 1005 if (offset + 4 + sslh.length > recordLen)
michael@0 1006 break;
michael@0 1007 /* finally have a complete message */
michael@0 1008 if (sslhexparse)
michael@0 1009 print_hex(4,recordBuf+offset);
michael@0 1010
michael@0 1011 hsdata = &recordBuf[offset+4];
michael@0 1012
michael@0 1013 PR_fprintf(PR_STDOUT," type = %d (",sslh.type);
michael@0 1014 switch(sslh.type) {
michael@0 1015 case 0: PR_FPUTS("hello_request)\n" ); break;
michael@0 1016 case 1: PR_FPUTS("client_hello)\n" ); break;
michael@0 1017 case 2: PR_FPUTS("server_hello)\n" ); break;
michael@0 1018 case 4: PR_FPUTS("new_session_ticket)\n" ); break;
michael@0 1019 case 11: PR_FPUTS("certificate)\n" ); break;
michael@0 1020 case 12: PR_FPUTS("server_key_exchange)\n" ); break;
michael@0 1021 case 13: PR_FPUTS("certificate_request)\n" ); break;
michael@0 1022 case 14: PR_FPUTS("server_hello_done)\n" ); break;
michael@0 1023 case 15: PR_FPUTS("certificate_verify)\n" ); break;
michael@0 1024 case 16: PR_FPUTS("client_key_exchange)\n" ); break;
michael@0 1025 case 20: PR_FPUTS("finished)\n" ); break;
michael@0 1026 case 22: PR_FPUTS("certificate_status)\n" ); break;
michael@0 1027 default: PR_FPUTS("unknown)\n" ); break;
michael@0 1028 }
michael@0 1029
michael@0 1030 PR_fprintf(PR_STDOUT," length = %d (0x%06x)\n",sslh.length,sslh.length);
michael@0 1031 switch (sslh.type) {
michael@0 1032
michael@0 1033 case 0: /* hello_request */ /* not much to show here. */ break;
michael@0 1034
michael@0 1035 case 1: /* client hello */
michael@0 1036 switch (sr->ver_maj) {
michael@0 1037 case 3: /* ssl version 3 */
michael@0 1038 {
michael@0 1039 unsigned int pos;
michael@0 1040 int w;
michael@0 1041
michael@0 1042 PR_fprintf(PR_STDOUT," ClientHelloV3 {\n");
michael@0 1043 PR_fprintf(PR_STDOUT," client_version = {%d, %d}\n",
michael@0 1044 (PRUint8)hsdata[0],(PRUint8)hsdata[1]);
michael@0 1045 PR_fprintf(PR_STDOUT," random = {...}\n");
michael@0 1046 if (sslhexparse) print_hex(32,&hsdata[2]);
michael@0 1047
michael@0 1048 /* pretty print Session ID */
michael@0 1049 {
michael@0 1050 int sidlength = (int)hsdata[2+32];
michael@0 1051 PR_fprintf(PR_STDOUT," session ID = {\n");
michael@0 1052 PR_fprintf(PR_STDOUT," length = %d\n",sidlength);
michael@0 1053 PR_fprintf(PR_STDOUT," contents = {...}\n");
michael@0 1054 if (sslhexparse) print_hex(sidlength,&hsdata[2+32+1]);
michael@0 1055 PR_fprintf(PR_STDOUT," }\n");
michael@0 1056 pos = 2+32+1+sidlength;
michael@0 1057 }
michael@0 1058
michael@0 1059 /* pretty print cipher suites */
michael@0 1060 {
michael@0 1061 int csuitelength = GET_SHORT((hsdata+pos));
michael@0 1062 PR_fprintf(PR_STDOUT," cipher_suites[%d] = {\n",
michael@0 1063 csuitelength/2);
michael@0 1064 if (csuitelength % 2) {
michael@0 1065 PR_fprintf(PR_STDOUT,
michael@0 1066 "*error in protocol - csuitelength shouldn't be odd*\n");
michael@0 1067 }
michael@0 1068 for (w=0; w<csuitelength; w+=2) {
michael@0 1069 PRUint32 cs_int = GET_SHORT((hsdata+pos+2+w));
michael@0 1070 const char *cs_str = V2CipherString(cs_int);
michael@0 1071 PR_fprintf(PR_STDOUT,
michael@0 1072 " (0x%04x) %s\n", cs_int, cs_str);
michael@0 1073 }
michael@0 1074 pos += 2 + csuitelength;
michael@0 1075 PR_fprintf(PR_STDOUT," }\n");
michael@0 1076 }
michael@0 1077
michael@0 1078 /* pretty print compression methods */
michael@0 1079 {
michael@0 1080 int complength = hsdata[pos];
michael@0 1081 PR_fprintf(PR_STDOUT," compression[%d] = {\n",
michael@0 1082 complength);
michael@0 1083 for (w=0; w < complength; w++) {
michael@0 1084 PRUint32 cm_int = hsdata[pos+1+w];
michael@0 1085 const char *cm_str = CompressionMethodString(cm_int);
michael@0 1086 PR_fprintf(PR_STDOUT,
michael@0 1087 " (%02x) %s\n", cm_int, cm_str);
michael@0 1088 }
michael@0 1089 pos += 1 + complength;
michael@0 1090 PR_fprintf(PR_STDOUT," }\n");
michael@0 1091 }
michael@0 1092
michael@0 1093 /* pretty print extensions, if any */
michael@0 1094 pos = print_hello_extension(hsdata, sslh.length, pos);
michael@0 1095
michael@0 1096 PR_fprintf(PR_STDOUT," }\n");
michael@0 1097 } /* end of ssl version 3 */
michael@0 1098 break;
michael@0 1099 default:
michael@0 1100 PR_fprintf(PR_STDOUT," UNDEFINED VERSION %d.%d {...}\n",
michael@0 1101 sr->ver_maj, sr->ver_min );
michael@0 1102 if (sslhexparse) print_hex(sslh.length, hsdata);
michael@0 1103 break;
michael@0 1104 } /* end of switch sr->ver_maj */
michael@0 1105 break;
michael@0 1106
michael@0 1107 case 2: /* server hello */
michael@0 1108 {
michael@0 1109 unsigned int sidlength, pos;
michael@0 1110
michael@0 1111 PR_fprintf(PR_STDOUT," ServerHello {\n");
michael@0 1112
michael@0 1113 PR_fprintf(PR_STDOUT," server_version = {%d, %d}\n",
michael@0 1114 (PRUint8)hsdata[0],(PRUint8)hsdata[1]);
michael@0 1115 PR_fprintf(PR_STDOUT," random = {...}\n");
michael@0 1116 if (sslhexparse) print_hex(32,&hsdata[2]);
michael@0 1117 PR_fprintf(PR_STDOUT," session ID = {\n");
michael@0 1118 sidlength = (int)hsdata[2+32];
michael@0 1119 PR_fprintf(PR_STDOUT," length = %d\n",sidlength);
michael@0 1120 PR_fprintf(PR_STDOUT," contents = {...}\n");
michael@0 1121 if (sslhexparse) print_hex(sidlength,&hsdata[2+32+1]);
michael@0 1122 PR_fprintf(PR_STDOUT," }\n");
michael@0 1123 pos = 2+32+1+sidlength;
michael@0 1124
michael@0 1125 /* pretty print chosen cipher suite */
michael@0 1126 {
michael@0 1127 PRUint32 cs_int = GET_SHORT((hsdata+pos));
michael@0 1128 const char *cs_str = V2CipherString(cs_int);
michael@0 1129 PR_fprintf(PR_STDOUT," cipher_suite = (0x%04x) %s\n",
michael@0 1130 cs_int, cs_str);
michael@0 1131 currentcipher = cs_int;
michael@0 1132 pos += 2;
michael@0 1133 }
michael@0 1134 /* pretty print chosen compression method */
michael@0 1135 {
michael@0 1136 PRUint32 cm_int = hsdata[pos++];
michael@0 1137 const char *cm_str = CompressionMethodString(cm_int);
michael@0 1138 PR_fprintf(PR_STDOUT," compression method = (%02x) %s\n",
michael@0 1139 cm_int, cm_str);
michael@0 1140 }
michael@0 1141
michael@0 1142 /* pretty print extensions, if any */
michael@0 1143 pos = print_hello_extension(hsdata, sslh.length, pos);
michael@0 1144
michael@0 1145 PR_fprintf(PR_STDOUT," }\n");
michael@0 1146 }
michael@0 1147 break;
michael@0 1148
michael@0 1149 case 4: /* new session ticket */
michael@0 1150 {
michael@0 1151 PRUint32 lifetimehint;
michael@0 1152 PRUint16 ticketlength;
michael@0 1153 char lifetime[32];
michael@0 1154 lifetimehint = GET_32(hsdata);
michael@0 1155 if (lifetimehint) {
michael@0 1156 PRExplodedTime et;
michael@0 1157 PRTime t = lifetimehint;
michael@0 1158 t *= PR_USEC_PER_SEC;
michael@0 1159 PR_ExplodeTime(t, PR_GMTParameters, &et);
michael@0 1160 /* use HTTP Cookie header's date format */
michael@0 1161 PR_FormatTimeUSEnglish(lifetime, sizeof lifetime,
michael@0 1162 "%a, %d-%b-%Y %H:%M:%S GMT", &et);
michael@0 1163 } else {
michael@0 1164 /* 0 means the lifetime of the ticket is unspecified */
michael@0 1165 strcpy(lifetime, "unspecified");
michael@0 1166 }
michael@0 1167 ticketlength = GET_SHORT((hsdata+4));
michael@0 1168 PR_fprintf(PR_STDOUT," NewSessionTicket {\n");
michael@0 1169 PR_fprintf(PR_STDOUT," ticket_lifetime_hint = %s\n",
michael@0 1170 lifetime);
michael@0 1171 PR_fprintf(PR_STDOUT," ticket = {\n");
michael@0 1172 PR_fprintf(PR_STDOUT," length = %d\n",ticketlength);
michael@0 1173 PR_fprintf(PR_STDOUT," contents = {...}\n");
michael@0 1174 if (sslhexparse) print_hex(ticketlength,&hsdata[4+2]);
michael@0 1175 PR_fprintf(PR_STDOUT," }\n");
michael@0 1176 PR_fprintf(PR_STDOUT," }\n");
michael@0 1177 }
michael@0 1178 break;
michael@0 1179
michael@0 1180 case 11: /* certificate */
michael@0 1181 {
michael@0 1182 PRFileDesc *cfd;
michael@0 1183 int pos;
michael@0 1184 int certslength;
michael@0 1185 int certlength;
michael@0 1186 int certbytesread = 0;
michael@0 1187 static int certFileNumber;
michael@0 1188 char certFileName[20];
michael@0 1189
michael@0 1190 PR_fprintf(PR_STDOUT," CertificateChain {\n");
michael@0 1191 certslength = GET_24(hsdata);
michael@0 1192 PR_fprintf(PR_STDOUT," chainlength = %d (0x%04x)\n",
michael@0 1193 certslength,certslength);
michael@0 1194 pos = 3;
michael@0 1195 while (certbytesread < certslength) {
michael@0 1196 certlength = GET_24((hsdata+pos));
michael@0 1197 pos += 3;
michael@0 1198 PR_fprintf(PR_STDOUT," Certificate {\n");
michael@0 1199 PR_fprintf(PR_STDOUT," size = %d (0x%04x)\n",
michael@0 1200 certlength,certlength);
michael@0 1201 certbytesread += certlength+3;
michael@0 1202 if (certbytesread <= certslength) {
michael@0 1203 PR_snprintf(certFileName, sizeof certFileName, "cert.%03d",
michael@0 1204 ++certFileNumber);
michael@0 1205 cfd = PR_Open(certFileName, PR_WRONLY|PR_CREATE_FILE|PR_TRUNCATE,
michael@0 1206 0664);
michael@0 1207 if (!cfd) {
michael@0 1208 PR_fprintf(PR_STDOUT,
michael@0 1209 " data = { couldn't save file '%s' }\n",
michael@0 1210 certFileName);
michael@0 1211 } else {
michael@0 1212 PR_Write(cfd, (hsdata+pos), certlength);
michael@0 1213 PR_fprintf(PR_STDOUT,
michael@0 1214 " data = { saved in file '%s' }\n",
michael@0 1215 certFileName);
michael@0 1216 PR_Close(cfd);
michael@0 1217 }
michael@0 1218 }
michael@0 1219
michael@0 1220 PR_fprintf(PR_STDOUT," }\n");
michael@0 1221 pos += certlength;
michael@0 1222 }
michael@0 1223 PR_fprintf(PR_STDOUT," }\n");
michael@0 1224 }
michael@0 1225 break;
michael@0 1226
michael@0 1227 case 12: /* server_key_exchange */
michael@0 1228 if (sslhexparse) print_hex(sslh.length, hsdata);
michael@0 1229 break;
michael@0 1230
michael@0 1231 case 13: /* certificate request */
michael@0 1232 {
michael@0 1233 unsigned int pos = 0;
michael@0 1234 int w, reqLength;
michael@0 1235
michael@0 1236 PR_fprintf(PR_STDOUT," CertificateRequest {\n");
michael@0 1237
michael@0 1238 /* pretty print requested certificate types */
michael@0 1239 reqLength = hsdata[pos];
michael@0 1240 PR_fprintf(PR_STDOUT," certificate types[%d] = {",
michael@0 1241 reqLength);
michael@0 1242 for (w=0; w < reqLength; w++) {
michael@0 1243 PR_fprintf(PR_STDOUT, " %02x", hsdata[pos+1+w]);
michael@0 1244 }
michael@0 1245 pos += 1 + reqLength;
michael@0 1246 PR_fprintf(PR_STDOUT," }\n");
michael@0 1247
michael@0 1248 /* pretty print CA names, if any */
michael@0 1249 if (pos < sslh.length) {
michael@0 1250 int exListLen = GET_SHORT((hsdata+pos)); pos += 2;
michael@0 1251 PR_fprintf(PR_STDOUT,
michael@0 1252 " certificate_authorities[%d] = {\n",
michael@0 1253 exListLen);
michael@0 1254 while (exListLen > 0 && pos < sslh.length) {
michael@0 1255 char * ca_name;
michael@0 1256 SECItem it;
michael@0 1257 int dnLen = GET_SHORT((hsdata+pos)); pos += 2;
michael@0 1258
michael@0 1259 /* dump the CA name */
michael@0 1260 it.type = siBuffer;
michael@0 1261 it.data = hsdata + pos;
michael@0 1262 it.len = dnLen;
michael@0 1263 ca_name = CERT_DerNameToAscii(&it);
michael@0 1264 if (ca_name) {
michael@0 1265 PR_fprintf(PR_STDOUT," %s\n", ca_name);
michael@0 1266 PORT_Free(ca_name);
michael@0 1267 } else {
michael@0 1268 PR_fprintf(PR_STDOUT,
michael@0 1269 " distinguished name [%d]", dnLen);
michael@0 1270 if (dnLen > 0 && sslhexparse) {
michael@0 1271 PR_fprintf(PR_STDOUT, " = {\n");
michael@0 1272 print_hex(dnLen, hsdata + pos);
michael@0 1273 PR_fprintf(PR_STDOUT, " }\n");
michael@0 1274 } else {
michael@0 1275 PR_fprintf(PR_STDOUT, "\n");
michael@0 1276 }
michael@0 1277 }
michael@0 1278 pos += dnLen;
michael@0 1279 exListLen -= 2 + dnLen;
michael@0 1280 }
michael@0 1281 PR_fprintf(PR_STDOUT," }\n");
michael@0 1282 }
michael@0 1283
michael@0 1284 PR_fprintf(PR_STDOUT," }\n");
michael@0 1285 }
michael@0 1286 break;
michael@0 1287
michael@0 1288 case 14: /* server_hello_done */ /* not much to show here. */ break;
michael@0 1289
michael@0 1290 case 15: /* certificate_verify */
michael@0 1291 if (sslhexparse) print_hex(sslh.length, hsdata);
michael@0 1292 break;
michael@0 1293
michael@0 1294 case 16: /* client key exchange */
michael@0 1295 {
michael@0 1296 PR_fprintf(PR_STDOUT," ClientKeyExchange {\n");
michael@0 1297 PR_fprintf(PR_STDOUT," message = {...}\n");
michael@0 1298 PR_fprintf(PR_STDOUT," }\n");
michael@0 1299 }
michael@0 1300 break;
michael@0 1301
michael@0 1302 case 20: /* finished */
michael@0 1303 PR_fprintf(PR_STDOUT," Finished {\n");
michael@0 1304 PR_fprintf(PR_STDOUT," verify_data = {...}\n");
michael@0 1305 if (sslhexparse) print_hex(sslh.length, hsdata);
michael@0 1306 PR_fprintf(PR_STDOUT," }\n");
michael@0 1307
michael@0 1308 if (!isNULLmac(currentcipher) && !s->hMACsize) {
michael@0 1309 /* To calculate the size of MAC, we subtract the number of known
michael@0 1310 * bytes of message from the number of remaining bytes in the
michael@0 1311 * record. This assumes that this is the first record on the
michael@0 1312 * connection to have a MAC, and that the sender has not put another
michael@0 1313 * message after the finished message in the handshake record.
michael@0 1314 * This is only correct for the first transition from unMACed to
michael@0 1315 * MACed. If the connection switches from one cipher suite to
michael@0 1316 * another one with a different MAC, this logic will not track that
michael@0 1317 * change correctly.
michael@0 1318 */
michael@0 1319 s->hMACsize = recordLen - (sslh.length + 4);
michael@0 1320 sslh.length += s->hMACsize; /* skip over the MAC data */
michael@0 1321 }
michael@0 1322 break;
michael@0 1323
michael@0 1324 case 22: /* certificate_status */
michael@0 1325 {
michael@0 1326 SECItem data;
michael@0 1327 PRFileDesc *ofd;
michael@0 1328 static int ocspFileNumber;
michael@0 1329 char ocspFileName[20];
michael@0 1330
michael@0 1331 /* skip 4 bytes with handshake numbers, as in ssl3_HandleCertificateStatus */
michael@0 1332 data.type = siBuffer;
michael@0 1333 data.data = hsdata + 4;
michael@0 1334 data.len = sslh.length - 4;
michael@0 1335 print_status_response(&data);
michael@0 1336
michael@0 1337 PR_snprintf(ocspFileName, sizeof ocspFileName, "ocsp.%03d",
michael@0 1338 ++ocspFileNumber);
michael@0 1339 ofd = PR_Open(ocspFileName, PR_WRONLY|PR_CREATE_FILE|PR_TRUNCATE,
michael@0 1340 0664);
michael@0 1341 if (!ofd) {
michael@0 1342 PR_fprintf(PR_STDOUT,
michael@0 1343 " data = { couldn't save file '%s' }\n",
michael@0 1344 ocspFileName);
michael@0 1345 } else {
michael@0 1346 PR_Write(ofd, data.data, data.len);
michael@0 1347 PR_fprintf(PR_STDOUT,
michael@0 1348 " data = { saved in file '%s' }\n",
michael@0 1349 ocspFileName);
michael@0 1350 PR_Close(ofd);
michael@0 1351 }
michael@0 1352 }
michael@0 1353 break;
michael@0 1354
michael@0 1355 default:
michael@0 1356 {
michael@0 1357 PR_fprintf(PR_STDOUT," UNKNOWN MESSAGE TYPE %d [%d] {\n",
michael@0 1358 sslh.type, sslh.length);
michael@0 1359 if (sslhexparse) print_hex(sslh.length, hsdata);
michael@0 1360 PR_fprintf(PR_STDOUT," }\n");
michael@0 1361
michael@0 1362 }
michael@0 1363 } /* end of switch sslh.type */
michael@0 1364 offset += sslh.length + 4;
michael@0 1365 } /* while */
michael@0 1366 if (offset < recordLen) { /* stuff left over */
michael@0 1367 int newMsgLen = recordLen - offset;
michael@0 1368 if (!s->msgBuf) {
michael@0 1369 s->msgBuf = PORT_Alloc(newMsgLen);
michael@0 1370 if (!s->msgBuf) {
michael@0 1371 PR_ASSERT(s->msgBuf);
michael@0 1372 showErr( "Malloc failed");
michael@0 1373 exit(11);
michael@0 1374 }
michael@0 1375 s->msgBufSize = newMsgLen;
michael@0 1376 memcpy(s->msgBuf, recordBuf + offset, newMsgLen);
michael@0 1377 } else if (newMsgLen > s->msgBufSize) {
michael@0 1378 unsigned char * newBuf = PORT_Realloc(s->msgBuf, newMsgLen);
michael@0 1379 if (!newBuf) {
michael@0 1380 PR_ASSERT(newBuf);
michael@0 1381 showErr( "Realloc failed");
michael@0 1382 exit(12);
michael@0 1383 }
michael@0 1384 s->msgBuf = newBuf;
michael@0 1385 s->msgBufSize = newMsgLen;
michael@0 1386 } else if (offset || s->msgBuf != recordBuf) {
michael@0 1387 memmove(s->msgBuf, recordBuf + offset, newMsgLen);
michael@0 1388 }
michael@0 1389 s->msgBufOffset = newMsgLen;
michael@0 1390 PR_fprintf(PR_STDOUT," [incomplete handshake message]\n");
michael@0 1391 } else {
michael@0 1392 s->msgBufOffset = 0;
michael@0 1393 }
michael@0 1394 PR_fprintf(PR_STDOUT," }\n");
michael@0 1395 }
michael@0 1396
michael@0 1397
michael@0 1398 void print_ssl(DataBufferList *s, int length, unsigned char *buffer)
michael@0 1399 {
michael@0 1400 /* -------------------------------------------------------- */
michael@0 1401 /* first, create a new buffer object for this piece of data. */
michael@0 1402
michael@0 1403 DataBuffer *db;
michael@0 1404
michael@0 1405 if (s->size == 0 && length > 0 && buffer[0] >= 32 && buffer[0] < 128) {
michael@0 1406 /* Not an SSL record, treat entire buffer as plaintext */
michael@0 1407 PR_Write(PR_STDOUT,buffer,length);
michael@0 1408 return;
michael@0 1409 }
michael@0 1410
michael@0 1411 check_integrity(s);
michael@0 1412
michael@0 1413 db = PR_NEW(struct _DataBuffer);
michael@0 1414
michael@0 1415 db->buffer = (unsigned char*)PORT_Alloc(length);
michael@0 1416 db->length = length;
michael@0 1417 db->offset = 0;
michael@0 1418 memcpy(db->buffer, buffer, length);
michael@0 1419 db->next = NULL;
michael@0 1420
michael@0 1421 /* now, add it to the stream */
michael@0 1422
michael@0 1423 if (s->last != NULL) s->last->next = db;
michael@0 1424 s->last = db;
michael@0 1425 s->size += length;
michael@0 1426 if (s->first == NULL) s->first = db;
michael@0 1427
michael@0 1428 check_integrity(s);
michael@0 1429
michael@0 1430 /*------------------------------------------------------- */
michael@0 1431 /* now we look at the stream to see if we have enough data to
michael@0 1432 decode */
michael@0 1433
michael@0 1434 while (s->size > 0 ) {
michael@0 1435 unsigned char *recordBuf = NULL;
michael@0 1436
michael@0 1437 SSLRecord sr;
michael@0 1438 unsigned recordLen;
michael@0 1439 unsigned recordsize;
michael@0 1440
michael@0 1441 check_integrity(s);
michael@0 1442
michael@0 1443 if ( s->first == NULL) {
michael@0 1444 PR_fprintf(PR_STDOUT,"ERROR: s->first is null\n");
michael@0 1445 exit(9);
michael@0 1446 }
michael@0 1447
michael@0 1448 /* in the case of an SSL 2 client-hello */
michael@0 1449 /* will have the high-bit set, whereas an SSL 3 client-hello will not */
michael@0 1450 /* SSL2 can also send records that begin with the high bit clear.
michael@0 1451 * This code will incorrectly handle them. XXX
michael@0 1452 */
michael@0 1453 if (isV2Session || s->first->buffer[s->first->offset] & 0x80) {
michael@0 1454 /* it's an SSL 2 packet */
michael@0 1455 unsigned char lenbuf[3];
michael@0 1456
michael@0 1457 /* first, we check if there's enough data for it to be an SSL2-type
michael@0 1458 * record. What a pain.*/
michael@0 1459 if (s->size < sizeof lenbuf) {
michael@0 1460 partial_packet(length, s->size, sizeof lenbuf);
michael@0 1461 return;
michael@0 1462 }
michael@0 1463
michael@0 1464 /* read the first two bytes off the stream. */
michael@0 1465 read_stream_bytes(lenbuf, s, sizeof(lenbuf));
michael@0 1466 recordLen = ((unsigned int)(lenbuf[0] & 0x7f) << 8) + lenbuf[1] +
michael@0 1467 ((lenbuf[0] & 0x80) ? 2 : 3);
michael@0 1468 PR_fprintf(PR_STDOUT, "recordLen = %u bytes\n", recordLen);
michael@0 1469
michael@0 1470 /* put 'em back on the head of the stream. */
michael@0 1471 db = PR_NEW(struct _DataBuffer);
michael@0 1472
michael@0 1473 db->length = sizeof lenbuf;
michael@0 1474 db->buffer = (unsigned char*) PORT_Alloc(db->length);
michael@0 1475 db->offset = 0;
michael@0 1476 memcpy(db->buffer, lenbuf, sizeof lenbuf);
michael@0 1477
michael@0 1478 db->next = s->first;
michael@0 1479 s->first = db;
michael@0 1480 if (s->last == NULL)
michael@0 1481 s->last = db;
michael@0 1482 s->size += db->length;
michael@0 1483
michael@0 1484 /* if there wasn't enough, go back for more. */
michael@0 1485 if (s->size < recordLen) {
michael@0 1486 check_integrity(s);
michael@0 1487 partial_packet(length, s->size, recordLen);
michael@0 1488 return;
michael@0 1489 }
michael@0 1490 partial_packet(length, s->size, recordLen);
michael@0 1491
michael@0 1492 /* read in the whole record. */
michael@0 1493 recordBuf = PORT_Alloc(recordLen);
michael@0 1494 read_stream_bytes(recordBuf, s, recordLen);
michael@0 1495
michael@0 1496 print_sslv2(s, recordBuf, recordLen);
michael@0 1497 PR_FREEIF(recordBuf);
michael@0 1498 check_integrity(s);
michael@0 1499
michael@0 1500 continue;
michael@0 1501 }
michael@0 1502
michael@0 1503 /***********************************************************/
michael@0 1504 /* It's SSL v3 */
michael@0 1505 /***********************************************************/
michael@0 1506 check_integrity(s);
michael@0 1507
michael@0 1508 if (s->size < sizeof sr) {
michael@0 1509 partial_packet(length, s->size, sizeof(SSLRecord));
michael@0 1510 return;
michael@0 1511 }
michael@0 1512
michael@0 1513 read_stream_bytes((unsigned char *)&sr, s, sizeof sr);
michael@0 1514
michael@0 1515 /* we have read the stream bytes. Look at the length of
michael@0 1516 the ssl record. If we don't have enough data to satisfy this
michael@0 1517 request, then put the bytes we just took back at the head
michael@0 1518 of the queue */
michael@0 1519 recordsize = GET_SHORT(sr.length);
michael@0 1520
michael@0 1521 if (recordsize > s->size) {
michael@0 1522 db = PR_NEW(struct _DataBuffer);
michael@0 1523
michael@0 1524 db->length = sizeof sr;
michael@0 1525 db->buffer = (unsigned char*) PORT_Alloc(db->length);
michael@0 1526 db->offset = 0;
michael@0 1527 memcpy(db->buffer, &sr, sizeof sr);
michael@0 1528 db->next = s->first;
michael@0 1529
michael@0 1530 /* now, add it back on to the head of the stream */
michael@0 1531
michael@0 1532 s->first = db;
michael@0 1533 if (s->last == NULL)
michael@0 1534 s->last = db;
michael@0 1535 s->size += db->length;
michael@0 1536
michael@0 1537 check_integrity(s);
michael@0 1538 partial_packet(length, s->size, recordsize);
michael@0 1539 return;
michael@0 1540 }
michael@0 1541 partial_packet(length, s->size, recordsize);
michael@0 1542
michael@0 1543
michael@0 1544 PR_fprintf(PR_STDOUT,"SSLRecord { [%s]\n", get_time_string() );
michael@0 1545 if (sslhexparse) {
michael@0 1546 print_hex(5,(unsigned char*)&sr);
michael@0 1547 }
michael@0 1548
michael@0 1549 check_integrity(s);
michael@0 1550
michael@0 1551 PR_fprintf(PR_STDOUT," type = %d (",sr.type);
michael@0 1552 switch(sr.type) {
michael@0 1553 case 20 :
michael@0 1554 PR_fprintf(PR_STDOUT,"change_cipher_spec)\n");
michael@0 1555 break;
michael@0 1556 case 21 :
michael@0 1557 PR_fprintf(PR_STDOUT,"alert)\n");
michael@0 1558 break;
michael@0 1559 case 22 :
michael@0 1560 PR_fprintf(PR_STDOUT,"handshake)\n");
michael@0 1561 break;
michael@0 1562 case 23 :
michael@0 1563 PR_fprintf(PR_STDOUT,"application_data)\n");
michael@0 1564 break;
michael@0 1565 default:
michael@0 1566 PR_fprintf(PR_STDOUT,"unknown)\n");
michael@0 1567 break;
michael@0 1568 }
michael@0 1569 PR_fprintf(PR_STDOUT," version = { %d,%d }\n",
michael@0 1570 (PRUint32)sr.ver_maj,(PRUint32)sr.ver_min);
michael@0 1571 PR_fprintf(PR_STDOUT," length = %d (0x%x)\n",
michael@0 1572 (PRUint32)GET_SHORT(sr.length), (PRUint32)GET_SHORT(sr.length));
michael@0 1573
michael@0 1574
michael@0 1575 recordLen = recordsize;
michael@0 1576 PR_ASSERT(s->size >= recordLen);
michael@0 1577 if (s->size >= recordLen) {
michael@0 1578 recordBuf = (unsigned char*) PORT_Alloc(recordLen);
michael@0 1579 read_stream_bytes(recordBuf, s, recordLen);
michael@0 1580
michael@0 1581 if (s->isEncrypted) {
michael@0 1582 PR_fprintf(PR_STDOUT," < encrypted >\n");
michael@0 1583 } else { /* not encrypted */
michael@0 1584
michael@0 1585 switch(sr.type) {
michael@0 1586 case 20 : /* change_cipher_spec */
michael@0 1587 if (sslhexparse) print_hex(recordLen - s->hMACsize,recordBuf);
michael@0 1588 /* mark to say we can only dump hex form now on
michael@0 1589 * if it is not one on a null cipher */
michael@0 1590 s->isEncrypted = isNULLcipher(currentcipher) ? 0 : 1;
michael@0 1591 break;
michael@0 1592
michael@0 1593 case 21 : /* alert */
michael@0 1594 switch(recordBuf[0]) {
michael@0 1595 case 1: PR_fprintf(PR_STDOUT, " warning: "); break;
michael@0 1596 case 2: PR_fprintf(PR_STDOUT, " fatal: "); break;
michael@0 1597 default: PR_fprintf(PR_STDOUT, " unknown level %d: ", recordBuf[0]); break;
michael@0 1598 }
michael@0 1599
michael@0 1600 switch(recordBuf[1]) {
michael@0 1601 case 0: PR_FPUTS("close_notify\n" ); break;
michael@0 1602 case 10: PR_FPUTS("unexpected_message\n" ); break;
michael@0 1603 case 20: PR_FPUTS("bad_record_mac\n" ); break;
michael@0 1604 case 21: PR_FPUTS("decryption_failed\n" ); break;
michael@0 1605 case 22: PR_FPUTS("record_overflow\n" ); break;
michael@0 1606 case 30: PR_FPUTS("decompression_failure\n" ); break;
michael@0 1607 case 40: PR_FPUTS("handshake_failure\n" ); break;
michael@0 1608 case 41: PR_FPUTS("no_certificate\n" ); break;
michael@0 1609 case 42: PR_FPUTS("bad_certificate\n" ); break;
michael@0 1610 case 43: PR_FPUTS("unsupported_certificate\n" ); break;
michael@0 1611 case 44: PR_FPUTS("certificate_revoked\n" ); break;
michael@0 1612 case 45: PR_FPUTS("certificate_expired\n" ); break;
michael@0 1613 case 46: PR_FPUTS("certificate_unknown\n" ); break;
michael@0 1614 case 47: PR_FPUTS("illegal_parameter\n" ); break;
michael@0 1615 case 48: PR_FPUTS("unknown_ca\n" ); break;
michael@0 1616 case 49: PR_FPUTS("access_denied\n" ); break;
michael@0 1617 case 50: PR_FPUTS("decode_error\n" ); break;
michael@0 1618 case 51: PR_FPUTS("decrypt_error\n" ); break;
michael@0 1619 case 60: PR_FPUTS("export_restriction\n" ); break;
michael@0 1620 case 70: PR_FPUTS("protocol_version\n" ); break;
michael@0 1621 case 71: PR_FPUTS("insufficient_security\n" ); break;
michael@0 1622 case 80: PR_FPUTS("internal_error\n" ); break;
michael@0 1623 case 90: PR_FPUTS("user_canceled\n" ); break;
michael@0 1624 case 100: PR_FPUTS("no_renegotiation\n" ); break;
michael@0 1625 case 110: PR_FPUTS("unsupported_extension\n" ); break;
michael@0 1626 case 111: PR_FPUTS("certificate_unobtainable\n" ); break;
michael@0 1627 case 112: PR_FPUTS("unrecognized_name\n" ); break;
michael@0 1628 case 113: PR_FPUTS("bad_certificate_status_response\n" ); break;
michael@0 1629 case 114: PR_FPUTS("bad_certificate_hash_value\n" ); break;
michael@0 1630
michael@0 1631 default: PR_fprintf(PR_STDOUT, "unknown alert %d\n", recordBuf[1]);
michael@0 1632 break;
michael@0 1633 }
michael@0 1634
michael@0 1635 if (sslhexparse) print_hex(recordLen - s->hMACsize,recordBuf);
michael@0 1636 break;
michael@0 1637
michael@0 1638 case 22 : /* handshake */
michael@0 1639 print_ssl3_handshake( recordBuf, recordLen - s->hMACsize, &sr, s );
michael@0 1640 break;
michael@0 1641
michael@0 1642 case 23 : /* application data */
michael@0 1643 print_hex(recordLen - s->hMACsize,recordBuf);
michael@0 1644 break;
michael@0 1645
michael@0 1646 default:
michael@0 1647 print_hex(recordLen - s->hMACsize,recordBuf);
michael@0 1648 break;
michael@0 1649 }
michael@0 1650 if (s->hMACsize) {
michael@0 1651 PR_fprintf(PR_STDOUT," MAC = {...}\n");
michael@0 1652 if (sslhexparse) {
michael@0 1653 unsigned char *offset = recordBuf + (recordLen - s->hMACsize);
michael@0 1654 print_hex(s->hMACsize, offset);
michael@0 1655 }
michael@0 1656 }
michael@0 1657 } /* not encrypted */
michael@0 1658 }
michael@0 1659 PR_fprintf(PR_STDOUT,"}\n");
michael@0 1660 PR_FREEIF(recordBuf);
michael@0 1661 check_integrity(s);
michael@0 1662 }
michael@0 1663 }
michael@0 1664
michael@0 1665 void print_hex(int amt, unsigned char *buf)
michael@0 1666 {
michael@0 1667 int i,j,k;
michael@0 1668 char t[20];
michael@0 1669 static char string[5000];
michael@0 1670
michael@0 1671
michael@0 1672 for(i=0;i<amt;i++) {
michael@0 1673 t[1] =0;
michael@0 1674
michael@0 1675 if (i%16 ==0) { /* if we are at the beginning of a line */
michael@0 1676 PR_fprintf(PR_STDOUT,"%4x:",i); /* print the line number */
michael@0 1677 strcpy(string,"");
michael@0 1678 }
michael@0 1679
michael@0 1680 if (i%4 == 0) {
michael@0 1681 PR_fprintf(PR_STDOUT," ");
michael@0 1682 }
michael@0 1683
michael@0 1684 j = buf[i];
michael@0 1685
michael@0 1686 t[0] = (j >= 0x20 && j < 0x80) ? j : '.';
michael@0 1687
michael@0 1688 if (fancy) {
michael@0 1689 switch (t[0]) {
michael@0 1690 case '<':
michael@0 1691 strcpy(t,"&lt;");
michael@0 1692 break;
michael@0 1693 case '>':
michael@0 1694 strcpy(t,"&gt;");
michael@0 1695 break;
michael@0 1696 case '&':
michael@0 1697 strcpy(t,"&amp;");
michael@0 1698 break;
michael@0 1699 }
michael@0 1700 }
michael@0 1701 strcat(string,t);
michael@0 1702
michael@0 1703 PR_fprintf(PR_STDOUT,"%02x ",(PRUint8) buf[i]);
michael@0 1704
michael@0 1705 /* if we've reached the end of the line - add the string */
michael@0 1706 if (i%16 == 15) PR_fprintf(PR_STDOUT," | %s\n",string);
michael@0 1707 }
michael@0 1708 /* we reached the end of the buffer,*/
michael@0 1709 /* do we have buffer left over? */
michael@0 1710 j = i%16;
michael@0 1711 if (j > 0) {
michael@0 1712 for (k=0;k<(16-j);k++) {
michael@0 1713 /* print additional space after every four bytes */
michael@0 1714 if ((k + j)%4 == 0) {
michael@0 1715 PR_fprintf(PR_STDOUT," ");
michael@0 1716 }
michael@0 1717 PR_fprintf(PR_STDOUT," ");
michael@0 1718 }
michael@0 1719 PR_fprintf(PR_STDOUT," | %s\n",string);
michael@0 1720 }
michael@0 1721 }
michael@0 1722
michael@0 1723 void Usage(void)
michael@0 1724 {
michael@0 1725 PR_fprintf(PR_STDERR, "SSLTAP (C) 1997, 1998 Netscape Communications Corporation.\n");
michael@0 1726 PR_fprintf(PR_STDERR, "Usage: ssltap [-vhfsxl] [-p port] hostname:port\n");
michael@0 1727 PR_fprintf(PR_STDERR, " -v [prints version string]\n");
michael@0 1728 PR_fprintf(PR_STDERR, " -h [outputs hex instead of ASCII]\n");
michael@0 1729 PR_fprintf(PR_STDERR, " -f [turn on Fancy HTML coloring]\n");
michael@0 1730 PR_fprintf(PR_STDERR, " -s [turn on SSL decoding]\n");
michael@0 1731 PR_fprintf(PR_STDERR, " -x [turn on extra SSL hex dumps]\n");
michael@0 1732 PR_fprintf(PR_STDERR, " -p port [specify rendezvous port (default 1924)]\n");
michael@0 1733 PR_fprintf(PR_STDERR, " -l [loop - continue to wait for more connections]\n");
michael@0 1734
michael@0 1735
michael@0 1736 }
michael@0 1737
michael@0 1738 void
michael@0 1739 showErr(const char * msg)
michael@0 1740 {
michael@0 1741 PRErrorCode err = PR_GetError();
michael@0 1742 const char * errString;
michael@0 1743
michael@0 1744 if (err == PR_UNKNOWN_ERROR)
michael@0 1745 err = PR_CONNECT_RESET_ERROR; /* bug in NSPR. */
michael@0 1746 errString = SECU_Strerror(err);
michael@0 1747
michael@0 1748 if (!errString)
michael@0 1749 errString = "(no text available)";
michael@0 1750 PR_fprintf(PR_STDERR, "%s: Error %d: %s: %s", progName, err, errString, msg);
michael@0 1751 }
michael@0 1752
michael@0 1753 int main(int argc, char *argv[])
michael@0 1754 {
michael@0 1755 char *hostname=NULL;
michael@0 1756 PRUint16 rendport=DEFPORT,port;
michael@0 1757 PRAddrInfo *ai;
michael@0 1758 void *iter;
michael@0 1759 PRStatus r;
michael@0 1760 PRNetAddr na_client,na_server,na_rend;
michael@0 1761 PRFileDesc *s_server,*s_client,*s_rend; /*rendezvous */
michael@0 1762 int c_count=0;
michael@0 1763 PLOptState *optstate;
michael@0 1764 PLOptStatus status;
michael@0 1765 SECStatus rv;
michael@0 1766
michael@0 1767 progName = argv[0];
michael@0 1768 optstate = PL_CreateOptState(argc,argv,"fxhslp:");
michael@0 1769 while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
michael@0 1770 switch (optstate->option) {
michael@0 1771 case 'f':
michael@0 1772 fancy++;
michael@0 1773 break;
michael@0 1774 case 'h':
michael@0 1775 hexparse++;
michael@0 1776 break;
michael@0 1777 case 's':
michael@0 1778 sslparse++;
michael@0 1779 break;
michael@0 1780 case 'x':
michael@0 1781 sslhexparse++;
michael@0 1782 break;
michael@0 1783 case 'l':
michael@0 1784 looparound++;
michael@0 1785 break;
michael@0 1786 case 'p':
michael@0 1787 rendport = atoi(optstate->value);
michael@0 1788 break;
michael@0 1789 case '\0':
michael@0 1790 hostname = PL_strdup(optstate->value);
michael@0 1791 }
michael@0 1792 }
michael@0 1793 if (status == PL_OPT_BAD)
michael@0 1794 Usage();
michael@0 1795
michael@0 1796 if (fancy) {
michael@0 1797 if (!hexparse && !sslparse) {
michael@0 1798 PR_fprintf(PR_STDERR,
michael@0 1799 "Note: use of -f without -s or -h not recommended, \n"
michael@0 1800 "as the output looks a little strange. It may be useful, however\n");
michael@0 1801 }
michael@0 1802 }
michael@0 1803
michael@0 1804 if(! hostname ) Usage(), exit(2);
michael@0 1805
michael@0 1806 {
michael@0 1807 char *colon = (char *)strchr(hostname, ':');
michael@0 1808 if (!colon) {
michael@0 1809 PR_fprintf(PR_STDERR,
michael@0 1810 "You must specify the host AND port you wish to connect to\n");
michael@0 1811 Usage(), exit(3);
michael@0 1812 }
michael@0 1813 port = atoi(&colon[1]);
michael@0 1814 *colon = '\0';
michael@0 1815
michael@0 1816 if (port == 0) {
michael@0 1817 PR_fprintf(PR_STDERR, "Port must be a nonzero number.\n");
michael@0 1818 exit(4);
michael@0 1819 }
michael@0 1820 }
michael@0 1821
michael@0 1822 /* find the 'server' IP address so we don't have to look it up later */
michael@0 1823
michael@0 1824 if (fancy) {
michael@0 1825 PR_fprintf(PR_STDOUT,"<HTML><HEAD><TITLE>SSLTAP output</TITLE></HEAD>\n");
michael@0 1826 PR_fprintf(PR_STDOUT,"<BODY><PRE>\n");
michael@0 1827 }
michael@0 1828 PR_fprintf(PR_STDERR,"Looking up \"%s\"...\n", hostname);
michael@0 1829 ai = PR_GetAddrInfoByName(hostname, PR_AF_UNSPEC, PR_AI_ADDRCONFIG);
michael@0 1830 if (!ai) {
michael@0 1831 showErr("Host Name lookup failed\n");
michael@0 1832 exit(5);
michael@0 1833 }
michael@0 1834
michael@0 1835 iter = NULL;
michael@0 1836 iter = PR_EnumerateAddrInfo(iter, ai, port, &na_server);
michael@0 1837 /* set up the port which the client will connect to */
michael@0 1838
michael@0 1839 r = PR_InitializeNetAddr(PR_IpAddrAny,rendport,&na_rend);
michael@0 1840 if (r == PR_FAILURE) {
michael@0 1841 PR_fprintf(PR_STDERR,
michael@0 1842 "PR_InitializeNetAddr(,%d,) failed with error %d\n",PR_GetError());
michael@0 1843 exit(0);
michael@0 1844 }
michael@0 1845
michael@0 1846 rv = NSS_NoDB_Init("");
michael@0 1847 if (rv != SECSuccess) {
michael@0 1848 PR_fprintf(PR_STDERR,
michael@0 1849 "NSS_NoDB_Init() failed with error %d\n",PR_GetError());
michael@0 1850 exit(5);
michael@0 1851 }
michael@0 1852
michael@0 1853 s_rend = PR_NewTCPSocket();
michael@0 1854 if (!s_rend) {
michael@0 1855 showErr("Couldn't create socket\n");
michael@0 1856 exit(6);
michael@0 1857 }
michael@0 1858
michael@0 1859 if (PR_Bind(s_rend, &na_rend )) {
michael@0 1860 PR_fprintf(PR_STDERR,"Couldn't bind to port %d (error %d)\n",rendport, PR_GetError());
michael@0 1861 exit(-1);
michael@0 1862 }
michael@0 1863
michael@0 1864 if ( PR_Listen(s_rend, 5)) {
michael@0 1865 showErr("Couldn't listen\n");
michael@0 1866 exit(-1);
michael@0 1867 }
michael@0 1868
michael@0 1869 PR_fprintf(PR_STDERR,"Proxy socket ready and listening\n");
michael@0 1870 do { /* accept one connection and process it. */
michael@0 1871 PRPollDesc pds[2];
michael@0 1872
michael@0 1873 s_client = PR_Accept(s_rend,&na_client,PR_SecondsToInterval(3600));
michael@0 1874 if (s_client == NULL) {
michael@0 1875 showErr("accept timed out\n");
michael@0 1876 exit(7);
michael@0 1877 }
michael@0 1878
michael@0 1879 s_server = PR_OpenTCPSocket(na_server.raw.family);
michael@0 1880 if (s_server == NULL) {
michael@0 1881 showErr("couldn't open new socket to connect to server \n");
michael@0 1882 exit(8);
michael@0 1883 }
michael@0 1884
michael@0 1885 r = PR_Connect(s_server,&na_server,PR_SecondsToInterval(5));
michael@0 1886
michael@0 1887 if ( r == PR_FAILURE )
michael@0 1888 {
michael@0 1889 showErr("Couldn't connect\n");
michael@0 1890 return -1;
michael@0 1891 }
michael@0 1892
michael@0 1893 if (looparound) {
michael@0 1894 if (fancy) PR_fprintf(PR_STDOUT,"<p><HR><H2>");
michael@0 1895 PR_fprintf(PR_STDOUT,"Connection #%d [%s]\n", c_count+1,
michael@0 1896 get_time_string());
michael@0 1897 if (fancy) PR_fprintf(PR_STDOUT,"</H2>");
michael@0 1898 }
michael@0 1899
michael@0 1900
michael@0 1901 PR_fprintf(PR_STDOUT,"Connected to %s:%d\n", hostname, port);
michael@0 1902
michael@0 1903 #define PD_C 0
michael@0 1904 #define PD_S 1
michael@0 1905
michael@0 1906 pds[PD_C].fd = s_client;
michael@0 1907 pds[PD_S].fd = s_server;
michael@0 1908 pds[PD_C].in_flags = PR_POLL_READ;
michael@0 1909 pds[PD_S].in_flags = PR_POLL_READ;
michael@0 1910
michael@0 1911 /* make sure the new connections don't start out encrypted. */
michael@0 1912 clientstream.isEncrypted = 0;
michael@0 1913 serverstream.isEncrypted = 0;
michael@0 1914 isV2Session = 0;
michael@0 1915
michael@0 1916 while( (pds[PD_C].in_flags & PR_POLL_READ) != 0 ||
michael@0 1917 (pds[PD_S].in_flags & PR_POLL_READ) != 0 )
michael@0 1918 { /* Handle all messages on the connection */
michael@0 1919 PRInt32 amt;
michael@0 1920 PRInt32 wrote;
michael@0 1921 unsigned char buffer[ TAPBUFSIZ ];
michael@0 1922
michael@0 1923 amt = PR_Poll(pds,2,PR_INTERVAL_NO_TIMEOUT);
michael@0 1924 if (amt <= 0) {
michael@0 1925 if (amt)
michael@0 1926 showErr( "PR_Poll failed.\n");
michael@0 1927 else
michael@0 1928 showErr( "PR_Poll timed out.\n");
michael@0 1929 break;
michael@0 1930 }
michael@0 1931
michael@0 1932 if (pds[PD_C].out_flags & PR_POLL_EXCEPT) {
michael@0 1933 showErr( "Exception on client-side socket.\n");
michael@0 1934 break;
michael@0 1935 }
michael@0 1936
michael@0 1937 if (pds[PD_S].out_flags & PR_POLL_EXCEPT) {
michael@0 1938 showErr( "Exception on server-side socket.\n");
michael@0 1939 break;
michael@0 1940 }
michael@0 1941
michael@0 1942
michael@0 1943 /* read data, copy it to stdout, and write to other socket */
michael@0 1944
michael@0 1945 if ((pds[PD_C].in_flags & PR_POLL_READ) != 0 &&
michael@0 1946 (pds[PD_C].out_flags & PR_POLL_READ) != 0 ) {
michael@0 1947
michael@0 1948 amt = PR_Read(s_client, buffer, sizeof(buffer));
michael@0 1949
michael@0 1950 if ( amt < 0) {
michael@0 1951 showErr( "Client socket read failed.\n");
michael@0 1952 break;
michael@0 1953 }
michael@0 1954
michael@0 1955 if( amt == 0 ) {
michael@0 1956 PR_fprintf(PR_STDOUT, "Read EOF on Client socket. [%s]\n",
michael@0 1957 get_time_string() );
michael@0 1958 pds[PD_C].in_flags &= ~PR_POLL_READ;
michael@0 1959 PR_Shutdown(s_server, PR_SHUTDOWN_SEND);
michael@0 1960 continue;
michael@0 1961 }
michael@0 1962
michael@0 1963 PR_fprintf(PR_STDOUT,"--> [\n");
michael@0 1964 if (fancy) PR_fprintf(PR_STDOUT,"<font color=blue>");
michael@0 1965
michael@0 1966 if (hexparse) print_hex(amt, buffer);
michael@0 1967 if (sslparse) print_ssl(&clientstream,amt,buffer);
michael@0 1968 if (!hexparse && !sslparse) PR_Write(PR_STDOUT,buffer,amt);
michael@0 1969 if (fancy) PR_fprintf(PR_STDOUT,"</font>");
michael@0 1970 PR_fprintf(PR_STDOUT,"]\n");
michael@0 1971
michael@0 1972 wrote = PR_Write(s_server, buffer, amt);
michael@0 1973 if (wrote != amt ) {
michael@0 1974 if (wrote < 0) {
michael@0 1975 showErr("Write to server socket failed.\n");
michael@0 1976 break;
michael@0 1977 } else {
michael@0 1978 PR_fprintf(PR_STDERR, "Short write to server socket!\n");
michael@0 1979 }
michael@0 1980 }
michael@0 1981 } /* end of read from client socket. */
michael@0 1982
michael@0 1983 /* read data, copy it to stdout, and write to other socket */
michael@0 1984 if ((pds[PD_S].in_flags & PR_POLL_READ) != 0 &&
michael@0 1985 (pds[PD_S].out_flags & PR_POLL_READ) != 0 ) {
michael@0 1986
michael@0 1987 amt = PR_Read(s_server, buffer, sizeof(buffer));
michael@0 1988
michael@0 1989 if ( amt < 0) {
michael@0 1990 showErr( "error on server-side socket.\n");
michael@0 1991 break;
michael@0 1992 }
michael@0 1993
michael@0 1994 if( amt == 0 ) {
michael@0 1995 PR_fprintf(PR_STDOUT, "Read EOF on Server socket. [%s]\n",
michael@0 1996 get_time_string() );
michael@0 1997 pds[PD_S].in_flags &= ~PR_POLL_READ;
michael@0 1998 PR_Shutdown(s_client, PR_SHUTDOWN_SEND);
michael@0 1999 continue;
michael@0 2000 }
michael@0 2001
michael@0 2002 PR_fprintf(PR_STDOUT,"<-- [\n");
michael@0 2003 if (fancy) PR_fprintf(PR_STDOUT,"<font color=red>");
michael@0 2004 if (hexparse) print_hex(amt, (unsigned char *)buffer);
michael@0 2005 if (sslparse) print_ssl(&serverstream,amt,(unsigned char *)buffer);
michael@0 2006 if (!hexparse && !sslparse) PR_Write(PR_STDOUT,buffer,amt);
michael@0 2007 if (fancy) PR_fprintf(PR_STDOUT,"</font>");
michael@0 2008 PR_fprintf(PR_STDOUT,"]\n");
michael@0 2009
michael@0 2010
michael@0 2011 wrote = PR_Write(s_client, buffer, amt);
michael@0 2012 if (wrote != amt ) {
michael@0 2013 if (wrote < 0) {
michael@0 2014 showErr("Write to client socket failed.\n");
michael@0 2015 break;
michael@0 2016 } else {
michael@0 2017 PR_fprintf(PR_STDERR, "Short write to client socket!\n");
michael@0 2018 }
michael@0 2019 }
michael@0 2020
michael@0 2021 } /* end of read from server socket. */
michael@0 2022
michael@0 2023 /* Loop, handle next message. */
michael@0 2024
michael@0 2025 } /* handle messages during a connection loop */
michael@0 2026 PR_Close(s_client);
michael@0 2027 PR_Close(s_server);
michael@0 2028 flush_stream(&clientstream);
michael@0 2029 flush_stream(&serverstream);
michael@0 2030 /* Connection is closed, so reset the current cipher */
michael@0 2031 currentcipher = 0;
michael@0 2032 c_count++;
michael@0 2033 PR_fprintf(PR_STDERR,"Connection %d Complete [%s]\n", c_count,
michael@0 2034 get_time_string() );
michael@0 2035 } while (looparound); /* accept connection and process it. */
michael@0 2036 PR_Close(s_rend);
michael@0 2037 NSS_Shutdown();
michael@0 2038 return 0;
michael@0 2039 }

mercurial