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