1/*
2 * Functions to trace SSL protocol behavior in DEBUG builds.
3 *
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7#include <stdarg.h>
8#include "cert.h"
9#include "ssl.h"
10#include "sslimpl.h"
11#include "sslproto.h"
12#include "prprf.h"
13
14#if defined(DEBUG) || defined(TRACE)
15static const char *hex = "0123456789abcdef";
16
17static const char printable[257] = {
18	"................"	/* 0x */
19	"................"	/* 1x */
20	" !\"#$%&'()*+,-./"	/* 2x */
21	"0123456789:;<=>?"	/* 3x */
22	"@ABCDEFGHIJKLMNO"	/* 4x */
23	"PQRSTUVWXYZ[\\]^_"	/* 5x */
24	"`abcdefghijklmno"	/* 6x */
25	"pqrstuvwxyz{|}~."	/* 7x */
26	"................"	/* 8x */
27	"................"	/* 9x */
28	"................"	/* ax */
29	"................"	/* bx */
30	"................"	/* cx */
31	"................"	/* dx */
32	"................"	/* ex */
33	"................"	/* fx */
34};
35
36void ssl_PrintBuf(sslSocket *ss, const char *msg, const void *vp, int len)
37{
38    const unsigned char *cp = (const unsigned char *)vp;
39    char buf[80];
40    char *bp;
41    char *ap;
42
43    if (ss) {
44	SSL_TRACE(("%d: SSL[%d]: %s [Len: %d]", SSL_GETPID(), ss->fd,
45		   msg, len));
46    } else {
47	SSL_TRACE(("%d: SSL: %s [Len: %d]", SSL_GETPID(), msg, len));
48    }
49    memset(buf, ' ', sizeof buf);
50    bp = buf;
51    ap = buf + 50;
52    while (--len >= 0) {
53	unsigned char ch = *cp++;
54	*bp++ = hex[(ch >> 4) & 0xf];
55	*bp++ = hex[ch & 0xf];
56	*bp++ = ' ';
57	*ap++ = printable[ch];
58	if (ap - buf >= 66) {
59	    *ap = 0;
60	    SSL_TRACE(("   %s", buf));
61	    memset(buf, ' ', sizeof buf);
62	    bp = buf;
63	    ap = buf + 50;
64	}
65    }
66    if (bp > buf) {
67	*ap = 0;
68	SSL_TRACE(("   %s", buf));
69    }
70}
71
72#define LEN(cp)		(((cp)[0] << 8) | ((cp)[1]))
73
74static void PrintType(sslSocket *ss, char *msg)
75{
76    if (ss) {
77	SSL_TRACE(("%d: SSL[%d]: dump-msg: %s", SSL_GETPID(), ss->fd,
78		   msg));
79    } else {
80	SSL_TRACE(("%d: SSL: dump-msg: %s", SSL_GETPID(), msg));
81    }
82}
83
84static void PrintInt(sslSocket *ss, char *msg, unsigned v)
85{
86    if (ss) {
87	SSL_TRACE(("%d: SSL[%d]:           %s=%u", SSL_GETPID(), ss->fd,
88		   msg, v));
89    } else {
90	SSL_TRACE(("%d: SSL:           %s=%u", SSL_GETPID(), msg, v));
91    }
92}
93
94/* PrintBuf is just like ssl_PrintBuf above, except that:
95 * a) It prefixes each line of the buffer with "XX: SSL[xxx]           "
96 * b) It dumps only hex, not ASCII.
97 */
98static void PrintBuf(sslSocket *ss, char *msg, unsigned char *cp, int len)
99{
100    char buf[80];
101    char *bp;
102
103    if (ss) {
104	SSL_TRACE(("%d: SSL[%d]:           %s [Len: %d]",
105		   SSL_GETPID(), ss->fd, msg, len));
106    } else {
107	SSL_TRACE(("%d: SSL:           %s [Len: %d]",
108		   SSL_GETPID(), msg, len));
109    }
110    bp = buf;
111    while (--len >= 0) {
112	unsigned char ch = *cp++;
113	*bp++ = hex[(ch >> 4) & 0xf];
114	*bp++ = hex[ch & 0xf];
115	*bp++ = ' ';
116	if (bp + 4 > buf + 50) {
117	    *bp = 0;
118	    if (ss) {
119		SSL_TRACE(("%d: SSL[%d]:             %s",
120			   SSL_GETPID(), ss->fd, buf));
121	    } else {
122		SSL_TRACE(("%d: SSL:             %s", SSL_GETPID(), buf));
123	    }
124	    bp = buf;
125	}
126    }
127    if (bp > buf) {
128	*bp = 0;
129	if (ss) {
130	    SSL_TRACE(("%d: SSL[%d]:             %s",
131		       SSL_GETPID(), ss->fd, buf));
132	} else {
133	    SSL_TRACE(("%d: SSL:             %s", SSL_GETPID(), buf));
134	}
135    }
136}
137
138void ssl_DumpMsg(sslSocket *ss, unsigned char *bp, unsigned len)
139{
140    switch (bp[0]) {
141      case SSL_MT_ERROR:
142	PrintType(ss, "Error");
143	PrintInt(ss, "error", LEN(bp+1));
144	break;
145
146      case SSL_MT_CLIENT_HELLO:
147	{
148	    unsigned lcs = LEN(bp+3);
149	    unsigned ls  = LEN(bp+5);
150	    unsigned lc  = LEN(bp+7);
151
152	    PrintType(ss, "Client-Hello");
153
154	    PrintInt(ss, "version (Major)",                   bp[1]);
155	    PrintInt(ss, "version (minor)",                   bp[2]);
156
157	    PrintBuf(ss, "cipher-specs",         bp+9,        lcs);
158	    PrintBuf(ss, "session-id",           bp+9+lcs,    ls);
159	    PrintBuf(ss, "challenge",            bp+9+lcs+ls, lc);
160	}
161	break;
162      case SSL_MT_CLIENT_MASTER_KEY:
163	{
164	    unsigned lck = LEN(bp+4);
165	    unsigned lek = LEN(bp+6);
166	    unsigned lka = LEN(bp+8);
167
168	    PrintType(ss, "Client-Master-Key");
169
170	    PrintInt(ss, "cipher-choice",                       bp[1]);
171	    PrintInt(ss, "key-length",                          LEN(bp+2));
172
173	    PrintBuf(ss, "clear-key",            bp+10,         lck);
174	    PrintBuf(ss, "encrypted-key",        bp+10+lck,     lek);
175	    PrintBuf(ss, "key-arg",              bp+10+lck+lek, lka);
176	}
177	break;
178      case SSL_MT_CLIENT_FINISHED:
179	PrintType(ss, "Client-Finished");
180	PrintBuf(ss, "connection-id",            bp+1,          len-1);
181	break;
182      case SSL_MT_SERVER_HELLO:
183	{
184	    unsigned lc = LEN(bp+5);
185	    unsigned lcs = LEN(bp+7);
186	    unsigned lci = LEN(bp+9);
187
188	    PrintType(ss, "Server-Hello");
189
190	    PrintInt(ss, "session-id-hit",                     bp[1]);
191	    PrintInt(ss, "certificate-type",                   bp[2]);
192	    PrintInt(ss, "version (Major)",                    bp[3]);
193	    PrintInt(ss, "version (minor)",                    bp[3]);
194	    PrintBuf(ss, "certificate",          bp+11,        lc);
195	    PrintBuf(ss, "cipher-specs",         bp+11+lc,     lcs);
196	    PrintBuf(ss, "connection-id",        bp+11+lc+lcs, lci);
197	}
198	break;
199      case SSL_MT_SERVER_VERIFY:
200	PrintType(ss, "Server-Verify");
201	PrintBuf(ss, "challenge",                bp+1,         len-1);
202	break;
203      case SSL_MT_SERVER_FINISHED:
204	PrintType(ss, "Server-Finished");
205	PrintBuf(ss, "session-id",               bp+1,         len-1);
206	break;
207      case SSL_MT_REQUEST_CERTIFICATE:
208	PrintType(ss, "Request-Certificate");
209	PrintInt(ss, "authentication-type",                    bp[1]);
210	PrintBuf(ss, "certificate-challenge",    bp+2,         len-2);
211	break;
212      case SSL_MT_CLIENT_CERTIFICATE:
213	{
214	    unsigned lc = LEN(bp+2);
215	    unsigned lr = LEN(bp+4);
216	    PrintType(ss, "Client-Certificate");
217	    PrintInt(ss, "certificate-type",                   bp[1]);
218	    PrintBuf(ss, "certificate",          bp+6,         lc);
219	    PrintBuf(ss, "response",             bp+6+lc,      lr);
220	}
221	break;
222      default:
223	ssl_PrintBuf(ss, "sending *unknown* message type", bp, len);
224	return;
225    }
226}
227
228void
229ssl_Trace(const char *format, ... )
230{
231    char buf[2000];
232    va_list args;
233
234    if (ssl_trace_iob) {
235	va_start(args, format);
236	PR_vsnprintf(buf, sizeof(buf), format, args);
237	va_end(args);
238
239	fputs(buf,  ssl_trace_iob);
240	fputs("\n", ssl_trace_iob);
241    }
242}
243#endif
244