Wed, 31 Dec 2014 06:55:50 +0100
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,"<"); |
michael@0 | 1692 | break; |
michael@0 | 1693 | case '>': |
michael@0 | 1694 | strcpy(t,">"); |
michael@0 | 1695 | break; |
michael@0 | 1696 | case '&': |
michael@0 | 1697 | strcpy(t,"&"); |
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 | } |