michael@0: /* michael@0: * Functions to trace SSL protocol behavior in DEBUG builds. michael@0: * michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: #include michael@0: #include "cert.h" michael@0: #include "ssl.h" michael@0: #include "sslimpl.h" michael@0: #include "sslproto.h" michael@0: #include "prprf.h" michael@0: michael@0: #if defined(DEBUG) || defined(TRACE) michael@0: static const char *hex = "0123456789abcdef"; michael@0: michael@0: static const char printable[257] = { michael@0: "................" /* 0x */ michael@0: "................" /* 1x */ michael@0: " !\"#$%&'()*+,-./" /* 2x */ michael@0: "0123456789:;<=>?" /* 3x */ michael@0: "@ABCDEFGHIJKLMNO" /* 4x */ michael@0: "PQRSTUVWXYZ[\\]^_" /* 5x */ michael@0: "`abcdefghijklmno" /* 6x */ michael@0: "pqrstuvwxyz{|}~." /* 7x */ michael@0: "................" /* 8x */ michael@0: "................" /* 9x */ michael@0: "................" /* ax */ michael@0: "................" /* bx */ michael@0: "................" /* cx */ michael@0: "................" /* dx */ michael@0: "................" /* ex */ michael@0: "................" /* fx */ michael@0: }; michael@0: michael@0: void ssl_PrintBuf(sslSocket *ss, const char *msg, const void *vp, int len) michael@0: { michael@0: const unsigned char *cp = (const unsigned char *)vp; michael@0: char buf[80]; michael@0: char *bp; michael@0: char *ap; michael@0: michael@0: if (ss) { michael@0: SSL_TRACE(("%d: SSL[%d]: %s [Len: %d]", SSL_GETPID(), ss->fd, michael@0: msg, len)); michael@0: } else { michael@0: SSL_TRACE(("%d: SSL: %s [Len: %d]", SSL_GETPID(), msg, len)); michael@0: } michael@0: memset(buf, ' ', sizeof buf); michael@0: bp = buf; michael@0: ap = buf + 50; michael@0: while (--len >= 0) { michael@0: unsigned char ch = *cp++; michael@0: *bp++ = hex[(ch >> 4) & 0xf]; michael@0: *bp++ = hex[ch & 0xf]; michael@0: *bp++ = ' '; michael@0: *ap++ = printable[ch]; michael@0: if (ap - buf >= 66) { michael@0: *ap = 0; michael@0: SSL_TRACE((" %s", buf)); michael@0: memset(buf, ' ', sizeof buf); michael@0: bp = buf; michael@0: ap = buf + 50; michael@0: } michael@0: } michael@0: if (bp > buf) { michael@0: *ap = 0; michael@0: SSL_TRACE((" %s", buf)); michael@0: } michael@0: } michael@0: michael@0: #define LEN(cp) (((cp)[0] << 8) | ((cp)[1])) michael@0: michael@0: static void PrintType(sslSocket *ss, char *msg) michael@0: { michael@0: if (ss) { michael@0: SSL_TRACE(("%d: SSL[%d]: dump-msg: %s", SSL_GETPID(), ss->fd, michael@0: msg)); michael@0: } else { michael@0: SSL_TRACE(("%d: SSL: dump-msg: %s", SSL_GETPID(), msg)); michael@0: } michael@0: } michael@0: michael@0: static void PrintInt(sslSocket *ss, char *msg, unsigned v) michael@0: { michael@0: if (ss) { michael@0: SSL_TRACE(("%d: SSL[%d]: %s=%u", SSL_GETPID(), ss->fd, michael@0: msg, v)); michael@0: } else { michael@0: SSL_TRACE(("%d: SSL: %s=%u", SSL_GETPID(), msg, v)); michael@0: } michael@0: } michael@0: michael@0: /* PrintBuf is just like ssl_PrintBuf above, except that: michael@0: * a) It prefixes each line of the buffer with "XX: SSL[xxx] " michael@0: * b) It dumps only hex, not ASCII. michael@0: */ michael@0: static void PrintBuf(sslSocket *ss, char *msg, unsigned char *cp, int len) michael@0: { michael@0: char buf[80]; michael@0: char *bp; michael@0: michael@0: if (ss) { michael@0: SSL_TRACE(("%d: SSL[%d]: %s [Len: %d]", michael@0: SSL_GETPID(), ss->fd, msg, len)); michael@0: } else { michael@0: SSL_TRACE(("%d: SSL: %s [Len: %d]", michael@0: SSL_GETPID(), msg, len)); michael@0: } michael@0: bp = buf; michael@0: while (--len >= 0) { michael@0: unsigned char ch = *cp++; michael@0: *bp++ = hex[(ch >> 4) & 0xf]; michael@0: *bp++ = hex[ch & 0xf]; michael@0: *bp++ = ' '; michael@0: if (bp + 4 > buf + 50) { michael@0: *bp = 0; michael@0: if (ss) { michael@0: SSL_TRACE(("%d: SSL[%d]: %s", michael@0: SSL_GETPID(), ss->fd, buf)); michael@0: } else { michael@0: SSL_TRACE(("%d: SSL: %s", SSL_GETPID(), buf)); michael@0: } michael@0: bp = buf; michael@0: } michael@0: } michael@0: if (bp > buf) { michael@0: *bp = 0; michael@0: if (ss) { michael@0: SSL_TRACE(("%d: SSL[%d]: %s", michael@0: SSL_GETPID(), ss->fd, buf)); michael@0: } else { michael@0: SSL_TRACE(("%d: SSL: %s", SSL_GETPID(), buf)); michael@0: } michael@0: } michael@0: } michael@0: michael@0: void ssl_DumpMsg(sslSocket *ss, unsigned char *bp, unsigned len) michael@0: { michael@0: switch (bp[0]) { michael@0: case SSL_MT_ERROR: michael@0: PrintType(ss, "Error"); michael@0: PrintInt(ss, "error", LEN(bp+1)); michael@0: break; michael@0: michael@0: case SSL_MT_CLIENT_HELLO: michael@0: { michael@0: unsigned lcs = LEN(bp+3); michael@0: unsigned ls = LEN(bp+5); michael@0: unsigned lc = LEN(bp+7); michael@0: michael@0: PrintType(ss, "Client-Hello"); michael@0: michael@0: PrintInt(ss, "version (Major)", bp[1]); michael@0: PrintInt(ss, "version (minor)", bp[2]); michael@0: michael@0: PrintBuf(ss, "cipher-specs", bp+9, lcs); michael@0: PrintBuf(ss, "session-id", bp+9+lcs, ls); michael@0: PrintBuf(ss, "challenge", bp+9+lcs+ls, lc); michael@0: } michael@0: break; michael@0: case SSL_MT_CLIENT_MASTER_KEY: michael@0: { michael@0: unsigned lck = LEN(bp+4); michael@0: unsigned lek = LEN(bp+6); michael@0: unsigned lka = LEN(bp+8); michael@0: michael@0: PrintType(ss, "Client-Master-Key"); michael@0: michael@0: PrintInt(ss, "cipher-choice", bp[1]); michael@0: PrintInt(ss, "key-length", LEN(bp+2)); michael@0: michael@0: PrintBuf(ss, "clear-key", bp+10, lck); michael@0: PrintBuf(ss, "encrypted-key", bp+10+lck, lek); michael@0: PrintBuf(ss, "key-arg", bp+10+lck+lek, lka); michael@0: } michael@0: break; michael@0: case SSL_MT_CLIENT_FINISHED: michael@0: PrintType(ss, "Client-Finished"); michael@0: PrintBuf(ss, "connection-id", bp+1, len-1); michael@0: break; michael@0: case SSL_MT_SERVER_HELLO: michael@0: { michael@0: unsigned lc = LEN(bp+5); michael@0: unsigned lcs = LEN(bp+7); michael@0: unsigned lci = LEN(bp+9); michael@0: michael@0: PrintType(ss, "Server-Hello"); michael@0: michael@0: PrintInt(ss, "session-id-hit", bp[1]); michael@0: PrintInt(ss, "certificate-type", bp[2]); michael@0: PrintInt(ss, "version (Major)", bp[3]); michael@0: PrintInt(ss, "version (minor)", bp[3]); michael@0: PrintBuf(ss, "certificate", bp+11, lc); michael@0: PrintBuf(ss, "cipher-specs", bp+11+lc, lcs); michael@0: PrintBuf(ss, "connection-id", bp+11+lc+lcs, lci); michael@0: } michael@0: break; michael@0: case SSL_MT_SERVER_VERIFY: michael@0: PrintType(ss, "Server-Verify"); michael@0: PrintBuf(ss, "challenge", bp+1, len-1); michael@0: break; michael@0: case SSL_MT_SERVER_FINISHED: michael@0: PrintType(ss, "Server-Finished"); michael@0: PrintBuf(ss, "session-id", bp+1, len-1); michael@0: break; michael@0: case SSL_MT_REQUEST_CERTIFICATE: michael@0: PrintType(ss, "Request-Certificate"); michael@0: PrintInt(ss, "authentication-type", bp[1]); michael@0: PrintBuf(ss, "certificate-challenge", bp+2, len-2); michael@0: break; michael@0: case SSL_MT_CLIENT_CERTIFICATE: michael@0: { michael@0: unsigned lc = LEN(bp+2); michael@0: unsigned lr = LEN(bp+4); michael@0: PrintType(ss, "Client-Certificate"); michael@0: PrintInt(ss, "certificate-type", bp[1]); michael@0: PrintBuf(ss, "certificate", bp+6, lc); michael@0: PrintBuf(ss, "response", bp+6+lc, lr); michael@0: } michael@0: break; michael@0: default: michael@0: ssl_PrintBuf(ss, "sending *unknown* message type", bp, len); michael@0: return; michael@0: } michael@0: } michael@0: michael@0: void michael@0: ssl_Trace(const char *format, ... ) michael@0: { michael@0: char buf[2000]; michael@0: va_list args; michael@0: michael@0: if (ssl_trace_iob) { michael@0: va_start(args, format); michael@0: PR_vsnprintf(buf, sizeof(buf), format, args); michael@0: va_end(args); michael@0: michael@0: fputs(buf, ssl_trace_iob); michael@0: fputs("\n", ssl_trace_iob); michael@0: } michael@0: } michael@0: #endif