First import of the JSON output code (https://github.com/adulau/ssldump/issues/41)

This commit is contained in:
William Robinet 2021-01-06 17:52:45 +01:00
parent 28b4915099
commit d0ca1a8adc
15 changed files with 454 additions and 233 deletions

View file

@ -36,7 +36,7 @@ Additional back-end code available is in the [crl-monitor ](https://github.com/a
On Debian & Ubuntu:
```
apt install build-essential autoconf libssl-dev libpcap-dev libnet1-dev
apt install build-essential autoconf libssl-dev libpcap-dev libnet1-dev libjson-c-dev
./autogen.sh
./configure --prefix=/usr/local
make
@ -45,7 +45,7 @@ make
On Fedora, Centos & RHEL:
```
dnf install autoconf automake gcc make openssl-devel libpcap-devel libnet-devel
dnf install autoconf automake gcc make openssl-devel libpcap-devel libnet-devel json-c-devel
./autogen.sh
./configure --prefix=/usr/local
make

View file

@ -135,8 +135,9 @@ int network_process_packet(handler,timestamp,data,length)
p.len = ntohs(p.ip->ip_len);
if(p.len > length) {
if(!(NET_print_flags & NET_PRINT_JSON))
printf("Malformed packet, size from IP header is larger than size reported by libpcap, skipping ...\n");
return(0);
return(0);
}
if (p.len == 0) {

View file

@ -106,5 +106,6 @@ extern UINT4 NET_print_flags;
#define NET_PRINT_TYPESET 2
#define NET_PRINT_ACKS 4
#define NET_PRINT_NO_RESOLVE 8
#define NET_PRINT_JSON 16
#endif

View file

@ -135,7 +135,7 @@ void sig_handler(int sig)
logger->vtbl->deinit();
freed_conn = destroy_all_conn();
if(freed_conn)
if(freed_conn && !(NET_print_flags & NET_PRINT_JSON))
printf("Cleaned %d remaining connection(s) from connection pool\n", freed_conn);
if(p)
@ -258,7 +258,7 @@ void pcap_cb(ptr,hdr,data)
if(packet_cnt == conn_freq) {
packet_cnt = 0;
memcpy(&last_packet_seen_time,&hdr->ts,sizeof(struct timeval));
if((cleaned_conn = clean_old_conn()))
if((cleaned_conn = clean_old_conn()) && !(NET_print_flags & NET_PRINT_JSON))
printf("%d inactive connection(s) cleaned from connection pool\n", cleaned_conn);
} else {
packet_cnt++;
@ -310,7 +310,7 @@ int main(argc,argv)
signal(SIGINT,sig_handler);
while((c=getopt(argc,argv,"vr:F:f:S:yTt:ai:k:l:w:p:nsAxXhHVNdqem:P"))!=EOF){
while((c=getopt(argc,argv,"vr:F:f:S:jyTt:ai:k:l:w:p:nsAxXhHVNdqem:P"))!=EOF){
switch(c){
case 'v':
print_version();
@ -328,6 +328,10 @@ int main(argc,argv)
/*Kludge*/
SSL_print_flags |= SSL_PRINT_NROFF;
break;
case 'j':
NET_print_flags |= NET_PRINT_JSON;
SSL_print_flags |= SSL_PRINT_JSON;
break;
case 'a':
NET_print_flags |= NET_PRINT_ACKS;
break;
@ -471,20 +475,22 @@ int main(argc,argv)
}
pcap_if_type=pcap_datalink(p);
if(NET_print_flags & NET_PRINT_TYPESET)
printf("\n.nf\n.ps -2\n");
if(!(NET_print_flags & NET_PRINT_JSON))
if(NET_print_flags & NET_PRINT_TYPESET)
printf("\n.nf\n.ps -2\n");
if((r=network_handler_create(mod,&n)))
err_exit("Couldn't create network handler",r);
pcap_loop(p,-1,pcap_cb,(u_char *)n);
if(NET_print_flags & NET_PRINT_TYPESET)
printf("\n.ps\n.fi\n");
if(!(NET_print_flags & NET_PRINT_JSON))
if(NET_print_flags & NET_PRINT_TYPESET)
printf("\n.ps\n.fi\n");
freed_conn = destroy_all_conn();
if(freed_conn)
if(freed_conn && !(NET_print_flags & NET_PRINT_JSON))
printf("Cleaned %d remaining connection(s) from connection pool\n", freed_conn);
pcap_close(p);

View file

@ -74,13 +74,13 @@ int exdump(name,data)
for(i=0;i<data->len;i++){
if(!i && (data->len>8)) INDENT;
if((data->len>8) && i && !(i%12)){
printf("\n"); INDENT;
LF;INDENT;
}
printf("%.2x ",data->data[i]&255);
}
if(name) INDENT_POP;
if(data->len>8 && i%12)
printf("\n");
LF;
return(0);
}

View file

@ -130,15 +130,16 @@ int process_tcp_packet(handler,ctx,p)
conn->i2r.ack=ntohl(p->tcp->th_ack)+1;
lookuphostname(&conn->i_addr,&sn);
lookuphostname(&conn->r_addr,&dn);
if(NET_print_flags & NET_PRINT_TYPESET)
printf("\\fC");
printf("New TCP connection #%d: %s(%d) <-> %s(%d)\n",
conn->conn_number,
sn,conn->i_port,
dn,conn->r_port);
if(NET_print_flags & NET_PRINT_TYPESET)
printf("\\fR");
if(!(NET_print_flags & NET_PRINT_JSON)) {
if(NET_print_flags & NET_PRINT_TYPESET)
printf("\\fC");
printf("New TCP connection #%d: %s(%d) <-> %s(%d)\n",
conn->conn_number,
sn,conn->i_port,
dn,conn->r_port);
if(NET_print_flags & NET_PRINT_TYPESET)
printf("\\fR");
}
conn->state=TCP_STATE_ESTABLISHED;
free(sn);
free(dn);
@ -240,7 +241,8 @@ static int process_data_segment(conn,handler,p,stream,direction)
l=p->len - p->tcp->th_off * 4;
if(l < 0) {
printf("Malformed packet, computed TCP segment size is negative, skipping ...\n");
if(!(NET_print_flags & NET_PRINT_JSON))
printf("Malformed packet, computed TCP segment size is negative, skipping ...\n");
return(0);
}
@ -400,32 +402,33 @@ static int print_tcp_packet(p)
lookuphostname(&p->ip->ip_src,&src);
lookuphostname(&p->ip->ip_dst,&dst);
printf("TCP: %s(%d) -> %s(%d) ",
src,
ntohs(p->tcp->th_sport),
dst,
ntohs(p->tcp->th_dport));
if(!(NET_print_flags & NET_PRINT_JSON)) {
printf("TCP: %s(%d) -> %s(%d) ",
src,
ntohs(p->tcp->th_sport),
dst,
ntohs(p->tcp->th_dport));
printf("Seq %u.(%d) ",
ntohl(p->tcp->th_seq),
p->len - p->tcp->th_off *4);
printf("Seq %u.(%d) ",
ntohl(p->tcp->th_seq),
p->len - p->tcp->th_off *4);
if(p->tcp->th_flags & TH_ACK)
printf("ACK %u ",ntohl(p->tcp->th_ack));
if(p->tcp->th_flags & TH_ACK)
printf("ACK %u ",ntohl(p->tcp->th_ack));
if(p->tcp->th_flags & TH_FIN)
printf("FIN ");
if(p->tcp->th_flags & TH_SYN)
printf("SYN ");
if(p->tcp->th_flags & TH_RST)
printf("RST ");
if(p->tcp->th_flags & TH_PUSH)
printf("PUSH ");
if(p->tcp->th_flags & TH_URG)
printf("URG ");
printf("\n");
if(p->tcp->th_flags & TH_FIN)
printf("FIN ");
if(p->tcp->th_flags & TH_SYN)
printf("SYN ");
if(p->tcp->th_flags & TH_RST)
printf("RST ");
if(p->tcp->th_flags & TH_PUSH)
printf("PUSH ");
if(p->tcp->th_flags & TH_URG)
printf("URG ");
printf("\n");
}
free(src);
free(dst);
return(0);

View file

@ -1,3 +1,4 @@
#include <json-c/json.h>
#include "network.h"
#include "ssl_h.h"
#include "sslprint.h"
@ -15,6 +16,10 @@ static int decode_ContentType_ChangeCipherSpec(ssl,dir,seg,data)
Data *data;
{
struct json_object *jobj;
jobj = ssl->cur_json_st;
json_object_object_add(jobj, "msg_type", json_object_new_string("ChangeCipherSpec"));
ssl_process_change_cipher_spec(ssl,ssl->decoder,dir);
@ -25,7 +30,7 @@ static int decode_ContentType_ChangeCipherSpec(ssl,dir,seg,data)
ssl->r_state=SSL_ST_SENT_CHANGE_CIPHER_SPEC;
}
printf("\n");
LF;
return(0);
}
@ -37,9 +42,10 @@ static int decode_ContentType_Alert(ssl,dir,seg,data)
{
int r;
struct json_object *jobj;
if(ssl->record_encryption==REC_CIPHERTEXT){
printf("\n");
LF;
return(0);
}
@ -49,17 +55,20 @@ static int decode_ContentType_Alert(ssl,dir,seg,data)
ERETURN(R_EOD);
}
jobj = ssl->cur_json_st;
json_object_object_add(jobj, "msg_type", json_object_new_string("Alert"));
P_(P_HL){
printf("\n");
LF;
SSL_DECODE_ENUM(ssl,"level",1,AlertLevel_decoder,P_HL,data,0);
printf("\n");
LF;
SSL_DECODE_ENUM(ssl,"value",1,AlertDescription_decoder,P_HL,data,0);
printf("\n");
LF;
}
else {
SSL_DECODE_ENUM(ssl,0,1,AlertLevel_decoder,SSL_PRINT_ALL,data,0);
SSL_DECODE_ENUM(ssl,0,1,AlertDescription_decoder,SSL_PRINT_ALL,data,0);
printf("\n");
LF;
}
return(0);
@ -77,9 +86,10 @@ static int decode_ContentType_Handshake(ssl,dir,seg,data)
UINT4 t,l;
int rs=0;
Data d;
struct json_object *jobj;
if(ssl->record_encryption==REC_CIPHERTEXT){
printf("\n");
LF;
return(0);
}
@ -93,13 +103,16 @@ static int decode_ContentType_Handshake(ssl,dir,seg,data)
ERETURN(R_EOD);
}
jobj = ssl->cur_json_st;
json_object_object_add(jobj, "msg_type", json_object_new_string("Handshake"));
d.data=data->data;
d.len=l;
data->len-=l;
data->data+=l;
P_(P_HL){
if(!rs){
printf("\n");
LF;
rs=1;
}
}
@ -118,6 +131,9 @@ static int decode_ContentType_application_data(ssl,dir,seg,data)
int r;
Data d;
struct json_object *jobj;
jobj = ssl->cur_json_st;
json_object_object_add(jobj, "msg_type", json_object_new_string("application data"));
SSL_DECODE_OPAQUE_ARRAY(ssl,"data",data->len,0,data,&d);
@ -125,7 +141,7 @@ static int decode_ContentType_application_data(ssl,dir,seg,data)
print_data(ssl,&d);
}
else {
printf("\n");
LF;
}
return(0);
@ -160,9 +176,12 @@ static int decode_HandshakeType_HelloRequest(ssl,dir,seg,data)
segment *seg;
Data *data;
{
struct json_object *jobj;
jobj = ssl->cur_json_st;
json_object_object_add(jobj, "handshake_type", json_object_new_string("HelloRequest"));
printf("\n");
LF;
return(0);
}
@ -173,6 +192,9 @@ static int decode_HandshakeType_ClientHello(ssl,dir,seg,data)
Data *data;
{
struct json_object *jobj;
jobj = ssl->cur_json_st;
json_object_object_add(jobj, "handshake_type", json_object_new_string("ClientHello"));
UINT4 vj,vn,cs,cslen,complen,comp,odd,exlen,ex;
Data session_id,random;
@ -182,14 +204,14 @@ static int decode_HandshakeType_ClientHello(ssl,dir,seg,data)
extern decoder compression_method_decoder[];
extern decoder extension_decoder[];
printf("\n");
LF;
ssl_update_handshake_messages(ssl,data);
SSL_DECODE_UINT8(ssl,0,0,data,&vj);
SSL_DECODE_UINT8(ssl,0,0,data,&vn);
P_(P_HL) {explain(ssl,"Version %d.%d ",vj,vn);
printf("\n");
}
LF;
}
SSL_DECODE_OPAQUE_ARRAY(ssl,"random",32,P_ND,data,&random);
ssl_set_client_random(ssl->decoder,random.data,random.len);
@ -219,7 +241,7 @@ static int decode_HandshakeType_ClientHello(ssl,dir,seg,data)
ssl_decode_enum(ssl,0,2,cipher_suite_decoder,
0,data,&cs);
ssl_print_cipher_suite(ssl,(vj<<8)|vn,P_HL,cs);
printf("\n");
LF;
}
}
@ -228,7 +250,7 @@ static int decode_HandshakeType_ClientHello(ssl,dir,seg,data)
explain(ssl,"compression methods\n");
for(;complen;complen--){
SSL_DECODE_ENUM(ssl,0,1,compression_method_decoder,P_HL,data,&comp);
printf("\n");
LF;
}
}
@ -244,7 +266,7 @@ static int decode_HandshakeType_ClientHello(ssl,dir,seg,data)
}
continue;
}
printf("\n");
LF;
}
}
return(0);
@ -263,14 +285,18 @@ static int decode_HandshakeType_ServerHello(ssl,dir,seg,data)
extern decoder extension_decoder[];
printf("\n");
struct json_object *jobj;
jobj = ssl->cur_json_st;
json_object_object_add(jobj, "handshake_type", json_object_new_string("ServerHello"));
LF;
ssl_update_handshake_messages(ssl,data);
SSL_DECODE_UINT8(ssl,0,0,data,&vj);
SSL_DECODE_UINT8(ssl,0,0,data,&vn);
ssl->version=vj*256+vn;
P_(P_HL) {explain(ssl,"Version %d.%d ",vj,vn);
printf("\n");
LF;
}
@ -288,9 +314,9 @@ static int decode_HandshakeType_ServerHello(ssl,dir,seg,data)
ssl_process_server_session_id(ssl,ssl->decoder,session_id.data,
session_id.len);
P_(P_HL) printf("\n");
P_(P_HL) LF;
SSL_DECODE_ENUM(ssl,"compressionMethod",1,compression_method_decoder,P_HL,data,0);
P_(P_HL) printf("\n");
P_(P_HL) LF;
SSL_DECODE_UINT16(ssl,"extensions len",0,data,&exlen);
if (exlen) {
@ -304,7 +330,7 @@ static int decode_HandshakeType_ServerHello(ssl,dir,seg,data)
}
continue;
}
printf("\n");
LF;
}
}
@ -323,10 +349,16 @@ static int decode_HandshakeType_Certificate(ssl,dir,seg,data)
Data cert;
int r;
printf("\n");
struct json_object *jobj;
jobj = ssl->cur_json_st;
json_object_object_add(jobj, "handshake_type", json_object_new_string("Certificate"));
LF;
ssl_update_handshake_messages(ssl,data);
SSL_DECODE_UINT24(ssl,"certificates len",0,data,&len);
json_object_object_add(jobj, "cert_chain", json_object_new_array());
while(len){
SSL_DECODE_OPAQUE_ARRAY(ssl,"certificate",-((1<<23)-1),
0,data,&cert);
@ -347,7 +379,11 @@ static int decode_HandshakeType_ServerKeyExchange(ssl,dir,seg,data)
int r;
printf("\n");
struct json_object *jobj;
jobj = ssl->cur_json_st;
json_object_object_add(jobj, "handshake_type", json_object_new_string("ServerKeyExchange"));
LF;
ssl_update_handshake_messages(ssl,data);
if(ssl->cs){
P_(P_ND){
@ -385,14 +421,18 @@ static int decode_HandshakeType_CertificateRequest(ssl,dir,seg,data)
Data ca;
int r;
printf("\n");
struct json_object *jobj;
jobj = ssl->cur_json_st;
json_object_object_add(jobj, "handshake_type", json_object_new_string("CertificateRequest"));
LF;
ssl_update_handshake_messages(ssl,data);
SSL_DECODE_UINT8(ssl,"certificate_types len",0,data,&len);
for(;len;len--){
SSL_DECODE_ENUM(ssl,"certificate_types",1,
client_certificate_type_decoder, P_HL,data,0);
P_(P_HL){
printf("\n");
LF;
}
};
@ -416,8 +456,11 @@ static int decode_HandshakeType_ServerHelloDone(ssl,dir,seg,data)
Data *data;
{
struct json_object *jobj;
jobj = ssl->cur_json_st;
json_object_object_add(jobj, "handshake_type", json_object_new_string("ServerHelloDone"));
printf("\n");
LF;
ssl_update_handshake_messages(ssl,data);
return(0);
@ -431,7 +474,12 @@ static int decode_HandshakeType_CertificateVerify(ssl,dir,seg,data)
int r;
printf("\n");
struct json_object *jobj;
jobj = ssl->cur_json_st;
json_object_object_add(jobj, "handshake_type", json_object_new_string("CertificateVerify"));
LF;
ssl_update_handshake_messages(ssl,data);
SSL_DECODE_OPAQUE_ARRAY(ssl,"Signature",-((1<<15)-1),P_HL,data,0);
return(0);
@ -448,7 +496,11 @@ static int decode_HandshakeType_ClientKeyExchange(ssl,dir,seg,data)
int r;
Data pms;
printf("\n");
struct json_object *jobj;
jobj = ssl->cur_json_st;
json_object_object_add(jobj, "handshake_type", json_object_new_string("ClientKeyExchange"));
LF;
ssl_update_handshake_messages(ssl,data);
if(ssl->cs){
switch(ssl->cs->kex){
@ -486,7 +538,11 @@ static int decode_HandshakeType_Finished(ssl,dir,seg,data)
int r;
printf("\n");
struct json_object *jobj;
jobj = ssl->cur_json_st;
json_object_object_add(jobj, "handshake_type", json_object_new_string("Finished"));
LF;
switch(ssl->version){
case 0x300:
SSL_DECODE_OPAQUE_ARRAY(ssl,"md5_hash",16,P_ND,data,0);
@ -496,7 +552,7 @@ static int decode_HandshakeType_Finished(ssl,dir,seg,data)
case 0x301:
SSL_DECODE_OPAQUE_ARRAY(ssl,"verify_data",12,P_ND,data,0);
P_(P_ND)
printf("\n");
LF;
break;
}
@ -2124,6 +2180,9 @@ static int decode_AlertLevel_warning(ssl,dir,seg,data)
segment *seg;
Data *data;
{
struct json_object *jobj;
jobj = ssl->cur_json_st;
json_object_object_add(jobj, "alert_level", json_object_new_string("warning"));
return(0);
}
static int decode_AlertLevel_fatal(ssl,dir,seg,data)
@ -2132,6 +2191,9 @@ static int decode_AlertLevel_fatal(ssl,dir,seg,data)
segment *seg;
Data *data;
{
struct json_object *jobj;
jobj = ssl->cur_json_st;
json_object_object_add(jobj, "alert_level", json_object_new_string("fatal"));
return(0);
}
decoder AlertLevel_decoder[]={
@ -2530,7 +2592,7 @@ static int decode_extension_server_name(ssl,dir,seg,data)
if(dir==DIR_I2R){
SSL_DECODE_UINT16(ssl,"server name list length",0,data,&l);
printf("\n");
LF;
while(l) {
p=data->len;
SSL_DECODE_UINT8(ssl, "server name type", 0, data, &t);
@ -2896,7 +2958,8 @@ static int decode_server_name_type_host_name(ssl,dir,seg,data)
int r;
UINT4 l;
SSL_DECODE_UINT16(ssl,"server name length",0,data,&l);
printf(": %.*s",l,data->data);
if(!(NET_print_flags & NET_PRINT_JSON))
printf(": %.*s",l,data->data);
/* Possibly use data->data to set/modify ssl->server_name */
if (l!=0)

View file

@ -44,7 +44,8 @@
*/
#include <json-c/json.h>
#include <arpa/inet.h>
#include "network.h"
#include "debug.h"
#include "sslprint.h"
@ -246,8 +247,14 @@ static int create_ssl_analyzer(void *handle, proto_ctx *ctx, tcp_conn *conn,
ABORT(r);
lookuphostname(i_addr,&obj->client_name);
if(!(obj->client_ip=(char *)calloc(1,INET_ADDRSTRLEN)))
ABORT(R_NO_MEMORY);
inet_ntop(AF_INET, i_addr, obj->client_ip, INET_ADDRSTRLEN);
obj->client_port=i_port;
lookuphostname(r_addr,&obj->server_name);
lookuphostname(r_addr,&obj->server_name);
if(!(obj->server_ip=(char *)calloc(1,INET_ADDRSTRLEN)))
ABORT(R_NO_MEMORY);
inet_ntop(AF_INET, r_addr, obj->server_ip, INET_ADDRSTRLEN);
obj->server_port=r_port;
obj->i_state=SSL_ST_SENT_NOTHING;
@ -573,7 +580,9 @@ static int print_ssl_record(obj,direction,q,data,len)
int len;
{
int r;
obj->cur_json_st = json_object_new_object();
if((r=print_ssl_header(obj,direction,q,data,len)))
ERETURN(r);
@ -583,8 +592,13 @@ static int print_ssl_record(obj,direction,q,data,len)
INIT_DATA(d,data,len);
exdump(obj,"Packet data",&d);
printf("\n\n");
LF;LF;
}
if(SSL_print_flags & SSL_PRINT_JSON)
printf("%s\n", json_object_to_json_string(obj->cur_json_st));
json_object_put(obj->cur_json_st);
obj->cur_json_st = NULL;
return(0);
}
@ -609,8 +623,7 @@ int close_ssl_analyzer(_obj,p,dir)
ssl_print_timestamp(ssl,&p->ts);
ssl_print_direction_indicator(ssl,dir);
explain(ssl," TCP %s",what);
printf("\n");
LF;
return(0);
}

View file

@ -62,6 +62,7 @@ extern proto_mod ssl_mod;
#define P_TSA (1<<12)
#define P_QT (1<<13)
#define P_HO (1<<14)
#define P_JS (1<<15)
#define SSL_PRINT_TIMESTAMP (1) /*Timestamp records*/
#define SSL_PRINT_HEXDUMP (1<<2) /*Print the whole record in hex*/
@ -77,6 +78,7 @@ extern proto_mod ssl_mod;
#define SSL_PRINT_TIMESTAMP_ABSOLUTE (P_TSA)
#define SSL_PRINT_QUIET (P_QT)
#define SSL_PRINT_HEX_ONLY (P_HO)
#define SSL_PRINT_JSON (P_JS)
#define SSL_PRINT_ALL 0xfffffff
extern UINT4 SSL_print_flags;

View file

@ -81,8 +81,10 @@ typedef struct ssl_obj_ {
UINT4 cipher_suite;
char *client_name;
char *client_ip;
int client_port;
char *server_name;
char *server_ip;
int server_port;
struct SSL_CipherSuite_ *cs;
@ -106,6 +108,7 @@ typedef struct ssl_obj_ {
int record_count;
int indent_depth;
int indent_name_len;
struct json_object *cur_json_st;
} ssl_obj;
typedef struct decoder_ {

View file

@ -47,8 +47,8 @@
#ifndef _ssldecode_h
#define _ssldecode_h
#define CRDUMP(a,b,c) P_(P_CR) {Data d; d.data=b; d.len=c; exdump(ssl,a,&d); printf("\n");}
#define CRDUMPD(a,b) P_(P_CR) {exdump(ssl,a,b);printf("\n");}
#define CRDUMP(a,b,c) P_(P_CR) {Data d; d.data=b; d.len=c; exdump(ssl,a,&d); LF;}
#define CRDUMPD(a,b) P_(P_CR) {exdump(ssl,a,b);LF;}
int ssl_decode_ctx_create PROTO_LIST((ssl_decode_ctx **ctx,
char *keyfile,char *password,char *keylogfile));

View file

@ -44,7 +44,7 @@
*/
#include <json-c/json.h>
#include <ctype.h>
#include <stdarg.h>
#include "network.h"
@ -83,7 +83,7 @@ int process_beginning_plaintext(ssl,seg,direction)
ssl_print_direction_indicator(ssl,direction);
print_data(ssl,&d);
printf("\n");
LF;
}
return(0);
@ -140,7 +140,7 @@ int process_v2_hello(ssl,seg)
P_(P_HL) {
explain(ssl,"Version %d.%d ",(ver>>8)&0xff,
ver&0xff);
printf("\n");
LF;
}
SSL_DECODE_UINT16(ssl,"cipher_spec_length",P_DC,&d,&cs_len);
SSL_DECODE_UINT16(ssl,"session_id_length",P_DC,&d,&sid_len);
@ -191,7 +191,7 @@ int process_v2_hello(ssl,seg)
INIT_DATA(d,seg->data,seg->len);
exdump(ssl,"Packet data",&d);
printf("\n\n");
LF;LF;
}
INDENT_POP;
@ -235,6 +235,11 @@ int ssl_expand_record(ssl,q,direction,data,len)
Data d;
UINT4 ct,vermaj,vermin,length;
int version;
char verstr[4];
char enumstr[20];
struct json_object *jobj;
jobj = ssl->cur_json_st;
d.data=data;
d.len=len;
@ -251,9 +256,11 @@ int ssl_expand_record(ssl,q,direction,data,len)
P_(P_RH){
explain(ssl," V%d.%d(%d)",vermaj,vermin,length);
json_object_object_add(jobj, "record_len", json_object_new_int(length));
snprintf(verstr,4,"%d.%d",vermaj,vermin);
json_object_object_add(jobj, "record_ver", json_object_new_string(verstr));
}
version=vermaj*256+vermin;
r=ssl_decode_record(ssl,ssl->decoder,direction,ct,version,&d);
@ -264,11 +271,16 @@ int ssl_expand_record(ssl,q,direction,data,len)
}
if(r){
if((r=ssl_print_enum(ssl,0,ContentType_decoder,ct))) {
printf(" unknown record type: %d\n", ct);
ERETURN(r);
}
printf("\n");
if(!(SSL_print_flags & SSL_PRINT_JSON))
if((r=ssl_print_enum(ssl,0,ContentType_decoder,ct))) {
printf(" unknown record type: %d\n", ct);
ERETURN(r);
}
ssl_get_enum_str(ssl,enumstr,ContentType_decoder,ct);
json_object_object_add(jobj, "msg_type", json_object_new_string(enumstr));
if(!(SSL_print_flags & SSL_PRINT_JSON))
LF;
}
else{
//try to save unencrypted data to logger
@ -276,7 +288,8 @@ int ssl_expand_record(ssl,q,direction,data,len)
if ((ct == 23) && (logger)) logger->vtbl->data(ssl->logger_obj,d.data,d.len,direction);
if((r=ssl_decode_switch(ssl,ContentType_decoder,data[0],direction,q, &d))) {
printf(" unknown record type: %d\n", ct);
if(!(SSL_print_flags & SSL_PRINT_JSON))
printf(" unknown record type: %d\n", ct);
ERETURN(r);
}
}
@ -394,8 +407,9 @@ int ssl_decode_enum(ssl,name,size,dtable,p,data,x)
ERETURN(r);
P_(p){
if((r=ssl_print_enum(ssl,name,dtable,*x)))
ERETURN(r);
if(!(SSL_print_flags & SSL_PRINT_JSON))
if((r=ssl_print_enum(ssl,name,dtable,*x)))
ERETURN(r);
}
return(0);
@ -407,6 +421,7 @@ int ssl_print_enum(ssl,name,dtable,value)
decoder *dtable;
UINT4 value;
{
if(name) explain(ssl,"%s ",name);
INDENT;
@ -419,26 +434,43 @@ int ssl_print_enum(ssl,name,dtable,value)
}
dtable++;
}
printf("\n");
LF;
return(R_NOT_FOUND);
}
int ssl_get_enum_str(ssl,outstr,dtable,value)
ssl_obj *ssl;
char *outstr;
decoder *dtable;
UINT4 value;
{
while(dtable && dtable->type!=-1){
if(dtable->type == value){
strncpy(outstr, dtable->name, 20);
return(0);
}
dtable++;
}
return(R_NOT_FOUND);
}
int explain(ssl_obj *ssl,char *format,...)
{
va_list ap;
if(!(SSL_print_flags & SSL_PRINT_JSON)) {
va_start(ap,format);
va_start(ap,format);
P_(P_NR){
if(ssl->record_encryption==REC_DECRYPTED_CIPHERTEXT)
printf("\\f(CI");
else
printf("\\fC");
}
INDENT;
P_(P_NR){
if(ssl->record_encryption==REC_DECRYPTED_CIPHERTEXT)
printf("\\f(CI");
else
printf("\\fC");
vprintf(format,ap);
va_end(ap);
}
INDENT;
vprintf(format,ap);
va_end(ap);
return(0);
}
@ -448,31 +480,52 @@ int exdump(ssl,name,data)
Data *data;
{
int i;
if(name){
explain(ssl,"%s[%d]=\n",name,data->len);
INDENT_INCR;
}
P_(P_NR){
printf("\\f(CB");
}
for(i=0;i<data->len;i++){
if(!i) INDENT;
if((data->len>8) && i && !(i%16)){
printf("\n"); INDENT;
if(!(SSL_print_flags & SSL_PRINT_JSON)) {
if(name){
explain(ssl,"%s[%d]=\n",name,data->len);
INDENT_INCR;
}
printf("%.2x ",data->data[i]&255);
P_(P_NR){
printf("\\f(CB");
}
for(i=0;i<data->len;i++){
if(!i) INDENT;
if((data->len>8) && i && !(i%16)){
LF; INDENT;
}
printf("%.2x ",data->data[i]&255);
}
P_(P_NR){
printf("\\fR");
}
if(name) INDENT_POP;
LF;
}
P_(P_NR){
printf("\\fR");
}
if(name) INDENT_POP;
printf("\n");
return(0);
}
int exstr(ssl,outstr,data)
ssl_obj *ssl;
char *outstr;
Data *data;
{
int i;
char *ptr = outstr;
for(i=0;i<data->len;i++){
sprintf(ptr, "%.2x",data->data[i]&255);
ptr+=2;
if(i<data->len - 1) {
sprintf(ptr, ":");
++ptr;
}
}
return(0);
}
int combodump(ssl,name,data)
ssl_obj *ssl;
char *name;
@ -518,7 +571,7 @@ int combodump(ssl,name,data)
else
printf(".");
}
printf("\n");
LF;
len-=bytes;
ptr+=bytes;
@ -536,7 +589,7 @@ int print_data(ssl,d)
{
int i,bit8=0;
printf("\n");
LF;
for(i=0;i<d->len;i++){
if(d->data[i] == 0 || (!isprint(d->data[i]) && !strchr("\r\n\t",d->data[i]))){
bit8=1;
@ -590,6 +643,7 @@ int ssl_print_direction_indicator(ssl,dir)
ssl_obj *ssl;
int dir;
{
struct json_object *jobj;
#if 0
if(dir==DIR_I2R){
explain(ssl,"%s(%d) > %s>%d",
@ -600,11 +654,30 @@ int ssl_print_direction_indicator(ssl,dir)
ssl->client_name,ssl->client_port,ssl->server_name,ssl->server_port);
}
#else
jobj = ssl->cur_json_st;
if(dir==DIR_I2R){
explain(ssl,"C>S");
if(jobj) {
json_object_object_add(jobj, "src_name", json_object_new_string(ssl->client_name));
json_object_object_add(jobj, "src_ip", json_object_new_string(ssl->client_ip));
json_object_object_add(jobj, "src_port", json_object_new_int(ssl->client_port));
json_object_object_add(jobj, "dst_name", json_object_new_string(ssl->server_name));
json_object_object_add(jobj, "dst_ip", json_object_new_string(ssl->server_ip));
json_object_object_add(jobj, "dst_port", json_object_new_int(ssl->server_port));
}
}
else{
explain(ssl,"S>C");
if(jobj) {
json_object_object_add(jobj, "src_name", json_object_new_string(ssl->server_name));
json_object_object_add(jobj, "src_ip", json_object_new_string(ssl->server_ip));
json_object_object_add(jobj, "src_port", json_object_new_int(ssl->server_port));
json_object_object_add(jobj, "dst_name", json_object_new_string(ssl->client_name));
json_object_object_add(jobj, "dst_ip", json_object_new_string(ssl->client_ip));
json_object_object_add(jobj, "dst_port", json_object_new_int(ssl->client_port));
}
}
#endif
@ -617,23 +690,35 @@ int ssl_print_timestamp(ssl,ts)
{
struct timeval dt;
int r;
char ts_str[16];
struct json_object *jobj;
jobj = ssl->cur_json_st;
if(jobj) {
snprintf(ts_str,16, "%d%c%4.4d",ts->tv_sec,'.',ts->tv_usec/100);
json_object *j_ts_str = json_object_new_string(ts_str);
json_object_object_add(jobj, "timestamp", j_ts_str);
}
if(SSL_print_flags & SSL_PRINT_TIMESTAMP_ABSOLUTE) {
explain(ssl,"%d%c%4.4d ",ts->tv_sec,'.',ts->tv_usec/100);
if(!(SSL_print_flags & SSL_PRINT_JSON))
explain(ssl,"%d%c%4.4d ",ts->tv_sec,'.',ts->tv_usec/100);
}
else{
if((r=timestamp_diff(ts,&ssl->time_start,&dt)))
ERETURN(r);
explain(ssl,"%d%c%4.4d ",dt.tv_sec,'.',dt.tv_usec/100);
if(!(SSL_print_flags & SSL_PRINT_JSON))
explain(ssl,"%d%c%4.4d ",dt.tv_sec,'.',dt.tv_usec/100);
}
if((r=timestamp_diff(ts,&ssl->time_last,&dt))){
ERETURN(r);
}
explain(ssl,"(%d%c%4.4d) ",dt.tv_sec,'.',dt.tv_usec/100);
if(!(SSL_print_flags & SSL_PRINT_JSON))
explain(ssl,"(%d%c%4.4d) ",dt.tv_sec,'.',dt.tv_usec/100);
memcpy(&ssl->time_last,ts,sizeof(struct timeval));
return(0);
}
@ -641,16 +726,23 @@ int ssl_print_timestamp(ssl,ts)
int ssl_print_record_num(ssl)
ssl_obj *ssl;
{
struct json_object *jobj;
jobj = ssl->cur_json_st;
ssl->record_count++;
if(SSL_print_flags & SSL_PRINT_NROFF){
printf("\\fI%d %d\\fR %s",
ssl->conn->conn_number,
ssl->record_count,ssl->record_count<10?" ":"");
}
else{
printf("%d %d %s",ssl->conn->conn_number,
ssl->record_count,ssl->record_count<10?" ":"");
}
if(!(SSL_print_flags & SSL_PRINT_JSON))
if(SSL_print_flags & SSL_PRINT_NROFF){
printf("\\fI%d %d\\fR %s",
ssl->conn->conn_number,
ssl->record_count,ssl->record_count<10?" ":"");
}
else{
printf("%d %d %s",ssl->conn->conn_number,
ssl->record_count,ssl->record_count<10?" ":"");
}
json_object_object_add(jobj, "connection_number", json_object_new_int(ssl->conn->conn_number));
json_object_object_add(jobj, "record_count", json_object_new_int(ssl->record_count));
return(0);
}

View file

@ -65,6 +65,8 @@ int ssl_lookup_enum PROTO_LIST((ssl_obj *ssl,decoder *dtable,
UINT4 val,char **ptr));
int ssl_print_enum PROTO_LIST((ssl_obj *obj,char *name,
decoder *decode,UINT4 value));
int ssl_get_enum_str PROTO_LIST((ssl_obj *obj,char *outstr,
decoder *decode,UINT4 value));
int print_data PROTO_LIST((ssl_obj *ssl,Data *d));
int process_v2_hello PROTO_LIST((ssl_obj *ssl,segment *seg));
int process_beginning_plaintext PROTO_LIST((ssl_obj *ssl,
@ -77,6 +79,7 @@ int ssl_print_cipher_suite PROTO_LIST((ssl_obj *ssl,int version,int p,
int explain PROTO_LIST((ssl_obj *ssl,char *format,...));
int exdump PROTO_LIST((ssl_obj *ssl,char *name,Data *data));
int exstr PROTO_LIST((ssl_obj *ssl,char *name,Data *data));
#define SSL_DECODE_UINT8(a,n,b,c,d) if((r=ssl_decode_uintX(a,n,1,b,c,d))) ERETURN(r)
@ -87,13 +90,13 @@ int exdump PROTO_LIST((ssl_obj *ssl,char *name,Data *data));
#define SSL_DECODE_ENUM(a,b,c,d,e,f,g) if((r=ssl_decode_enum(a,b,c,d,e,f,g))) ERETURN(r)
#define P_(p) if((p==SSL_PRINT_ALL) || (p & SSL_print_flags))
#define INDENT do {int i; for(i=0;i<(ssl->indent_depth + ssl->indent_name_len);i++) printf("%s",SSL_print_flags & SSL_PRINT_NROFF?" ":" ");} while(0)
#define INDENT if(!(NET_print_flags & NET_PRINT_JSON)) do {int i; for(i=0;i<(ssl->indent_depth + ssl->indent_name_len);i++) printf("%s",SSL_print_flags & SSL_PRINT_NROFF?" ":" ");} while(0)
#define INDENT_INCR ssl->indent_depth+=2
#define INDENT_POP ssl->indent_depth-=2
#define INDENT_NAME(x) ssl->indent_name_len += strlen(x)
#define INDENT_NAME_POP ssl->indent_name_len=0
#define LINE_LEFT (80-(ssl->indent_name_len + ssl->indent_depth)
#define LF printf("\n")
#define LF if(!(NET_print_flags & NET_PRINT_JSON)) printf("\n")
#endif

View file

@ -44,7 +44,7 @@
*/
#include <json-c/json.h>
#include "network.h"
#include "ssl_h.h"
#include "sslprint.h"
@ -78,9 +78,25 @@ int sslx_print_certificate(ssl,data,pf)
P_(P_ASN){
char buf[BUFSIZE];
int ext;
char *b64_cert;
char *serial_str = NULL;
Data data_tmp;
struct json_object *jobj;
jobj = ssl->cur_json_st;
struct json_object *cert_obj;
cert_obj = json_object_new_object();
d=data->data;
if(!(b64_cert=(char *)calloc(1,sizeof(char) * ((((data->len) + 3 - 1)/3) * 4 + 1))))
ABORT(R_NO_MEMORY);
EVP_EncodeBlock((unsigned char *)b64_cert, d, data->len);
json_object_object_add(cert_obj, "cert_der", json_object_new_string(b64_cert));
if(!(x=d2i_X509(0,(const unsigned char **) &d,data->len))){
explain(ssl,"Bad certificate");
ABORT(R_BAD_DATA);
@ -89,16 +105,24 @@ int sslx_print_certificate(ssl,data,pf)
BUFSIZE);
explain(ssl,"Subject\n");
INDENT_INCR;
json_object_object_add(cert_obj, "cert_subject", json_object_new_string(buf));
sslx__print_dn(ssl,buf);
INDENT_POP;
X509_NAME_oneline(X509_get_issuer_name(x),buf,
BUFSIZE);
explain(ssl,"Issuer\n");
INDENT_INCR;
json_object_object_add(cert_obj, "cert_issuer", json_object_new_string(buf));
sslx__print_dn(ssl,buf);
INDENT_POP;
a=X509_get_serialNumber(x);
explain(ssl,"Serial ");
if(!(serial_str=(char *)calloc(1,sizeof(char) * (a->length * 3))))
ABORT(R_NO_MEMORY);
INIT_DATA(data_tmp,a->data,a->length);
exstr(ssl, serial_str, &data_tmp);
json_object_object_add(cert_obj, "cert_serial", json_object_new_string(serial_str));
sslx__print_serial(ssl,a);
ext=X509_get_ext_count(x);
@ -147,6 +171,10 @@ int sslx_print_certificate(ssl,data,pf)
}
#ifdef OPENSSL
}
struct json_object *certs_array;
json_object_object_get_ex(jobj, "cert_chain", &certs_array);
json_object_array_add(certs_array,cert_obj);
}
#endif

168
ssldump.1
View file

@ -61,8 +61,7 @@ ssldump \- dump SSL traffic on a network
.na
.B ssldump
[
.B \-vTshVq
.B \-aAdeHnNqTxXvy
.B \-aAdeFHjnNPqtTvxXy
] [
.B \-i
.I interface
@ -110,14 +109,14 @@ form to stdout. If provided with the appropriate keying material,
it will also decrypt the connections and display the application
data traffic.
.LP
ssldump has been tested on FreeBSD, Linux, Solaris, and HP/UX. Since
\fIssldump\fP has been tested on FreeBSD, Linux, Solaris, and HP/UX. Since
it's based on PCAP, it should work on most platforms. However, unlike
tcpdump, ssldump needs to be able to see both sides of the data
tcpdump, \fIssldump\fP needs to be able to see both sides of the data
transmission so you may have trouble using it with network taps such
as SunOS nit that don't permit you to see transmitted data.
.B Under SunOS with nit or bpf:
To run
.I tcpdump
.I ssldump
you must have read access to
.I /dev/nit
or
@ -135,46 +134,65 @@ You must be root or it must be installed setuid to root.
Once the super-user has enabled promiscuous-mode operation using
.IR pfconfig (8),
any user may run
.BR ssldump
.I ssldump
.B Under BSD:
You must have read access to
.IR /dev/bpf* .
.SH OPTIONS
.TP
.B \-a
Print bare TCP ACKs (useful for observing Nagle behavior)
Print bare TCP ACKs (useful for observing Nagle behavior).
.TP
.B \-A
Print all record fields (by default ssldump chooses
the most interesting fields)
Print all record fields (by default \fIssldump\fP chooses
the most interesting fields).
.TP
.B \-d
Display the application data traffic. This usually means
decrypting it, but when -d is used ssldump will also decode
decrypting it, but when -d is used \fIssldump\fP will also decode
application data traffic \fIbefore\fP the SSL session initiates.
This allows you to see HTTPS CONNECT behavior as well as
SMTP STARTTLS. As a side effect, since ssldump can't tell
SMTP STARTTLS. As a side effect, since \fIssldump\fP can't tell
whether plaintext is traffic before the initiation of an
SSL connection or just a regular TCP connection, this allows
you to use ssldump to sniff any TCP connection.
ssldump will automatically detect ASCII data and display it
you to use \fIssldump\fP to sniff any TCP connection.
\fIssldump\fP will automatically detect ASCII data and display it
directly to the screen. non-ASCII data is displayed as hex