wm: dnsparser

ref: 272dec2602bfb557af9464d21426d195b8e8e1a5
dir: /tls.c/

View raw version
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <pcap.h>
#include "common.h"

int
parseTlsRecord(const u_char *pkt, Tls *tls)
{
	get(pkt, TLS_RECORD_CONTENTTYPE, &tls->type);
	get(pkt, TLS_RECORD_VERSION, &tls->version);
	get(pkt, TLS_RECORD_LEN, &tls->len);
	return 1;
}

int
parseTlsClientHello(const u_char *pkt, TlsHandshake *hs)
{
	get(pkt, TLS_HANDSHAKE_VERSION, &hs->version);
	memmove(hs->random, PKTHEAD, TLS_HANDSHAKE_RANDOM);
	pos += TLS_HANDSHAKE_RANDOM;
	
	hs->sessionId = emalloc(sizeof(TlsTuple));
	hs->sessionId->name = "session id";
	hs->sessionId->start = pos;
	get(pkt, TLS_HANDSHAKE_SESSIONID_LEN, &hs->sessionId->len);
	hs->sessionId->data = memdup(PKTHEAD, hs->sessionId->len);
	pos += hs->sessionId->len;
	
	hs->cipherSuits = emalloc(sizeof(TlsTuple));
	hs->cipherSuits->name = "cipher suits";
	get(pkt, TLS_HANDSHAKE_CIPHERS_LEN, &hs->cipherSuits->len);
	hs->cipherSuits->data = memdup(PKTHEAD, hs->cipherSuits->len);
	pos += hs->cipherSuits->len;
	
	hs->compressionMethods = emalloc(sizeof(TlsTuple));
	hs->compressionMethods->name = "compression methods";
	get(pkt, TLS_HANDSHAKE_COMP_LEN, &hs->compressionMethods->len);
	hs->compressionMethods->data = memdup(PKTHEAD, hs->compressionMethods->len);
	pos += hs->compressionMethods->len;
	
	get(pkt, TLS_HANDSHAKE_EXTS_LEN, &hs->extensionsLen);
	parseTlsExtensions(pkt, hs);
	
	return 1;
}

int
parseTlsServerHello(const u_char *pkt, TlsHandshake *hs)
{
	get(pkt, TLS_HANDSHAKE_VERSION, &hs->version);
	memmove(hs->random, PKTHEAD, TLS_HANDSHAKE_RANDOM);
	pos += TLS_HANDSHAKE_RANDOM;
	
	hs->sessionId = emalloc(sizeof(TlsTuple));
	hs->sessionId->name = "session id";
	hs->sessionId->start = pos;
	get(pkt, TLS_HANDSHAKE_SESSIONID_LEN, &hs->sessionId->len);
	hs->sessionId->data = memdup(PKTHEAD, hs->sessionId->len);
	pos += hs->sessionId->len;
	
	get(pkt, TLS_HANDSHAKE_CIPHER, &hs->cipherSuit);
	get(pkt, TLS_HANDSHAKE_COMP, &hs->compressionMethod);
	
	if(pos < hs->start + hs->len)
	{
		get(pkt, TLS_HANDSHAKE_EXTS_LEN, &hs->extensionsLen);
		parseTlsExtensions(pkt, hs);
	}
	else
	{
		hs->extensionsLen = 0;
		hs->nExtensions = 0;
		pos = hs->start + hs->len;
		pos += TLS_HANDSHAKE_TYPE + TLS_HANDSHAKE_LEN;
	}
	
	return 1;
}

int
parseTlsCert(const u_char *pkt, TlsCert *cert)
{
	cert->start = pos;
	get(pkt, TLS_HANDSHAKE_CERT_LEN, &cert->len);

	cert->der = emalloc(sizeof(Der));
	cert->der->len = cert->len;
	parseDer(pkt, cert->der);
	return 1;	
}

int
parseTlsCerts(const u_char *pkt, TlsHandshake *hs)
{
	get(pkt, TLS_HANDSHAKE_CERTS_LEN, &hs->certsLen);
	
	hs->certs = emalloc(sizeof(TlsCert) * hs->certsLen);
	hs->nCerts = 0;
	for(int tmp = pos ; tmp < hs->certsLen + pos ; hs->nCerts++)
	{
		tmp += get4(pkt + tmp) >> 8;
		tmp += TLS_HANDSHAKE_CERT_LEN;
	}
	
	for(int i = 0 ; i < hs->nCerts ; i++)
	{
		parseTlsCert(pkt, hs->certs + i);
	}
	
	return 1;
}

int
parseExtensionData(const u_char *pkt, TlsExtension *e)
{
	switch(e->type)
	{
		case TLS_EXT_SNI:
			e->sni = emalloc(sizeof(TlsExtensionSni));
			get(pkt, TLS_SNI_LISTLEN, &e->sni->listLen);
			get(pkt, TLS_SNI_TYPE, &e->sni->type);
			get(pkt, TLS_SNI_LEN, &e->sni->len);
			
			e->sni->name = emalloc(e->sni->len);
			strncpy(e->sni->name, PKTHEAD, e->sni->len);
			pos += e->sni->len;
			break;
			
		case TLS_EXT_SUPPORTED_VERS:
			e->sv = emalloc(sizeof(TlsExtensionSv));
			get(pkt, TLS_SV_LEN, &e->sv->len);
			
			e->sv->vers = emalloc(e->sv->len);
			for(int i = 0 ; i < e->sv->len / 2 ; i++)
			{
				get(pkt, TLS_SV_DATA, &e->sv->vers[i]); 
			}
			break;
			
		default:
			e->data = memdup(PKTHEAD, e->len);
			pos += e->len;
			break;
	}

	return 1;
}

int
parseTlsExtensions(const u_char *pkt, TlsHandshake *hs)
{
	hs->nExtensions = 0;
	
	for(int tmp = pos ; tmp < hs->extensionsLen + pos ; hs->nExtensions++)
	{
		tmp += TLS_HANDSHAKE_EXT_TYPE;
		tmp += get2(pkt + tmp);
		tmp += TLS_HANDSHAKE_EXT_LEN;
	}
	
	hs->extensions = emalloc(hs->nExtensions * sizeof(TlsExtension));
	for(int i = 0 ; i < hs->nExtensions ; i++)
	{
		hs->extensions[i].start = pos;
		get(pkt, TLS_HANDSHAKE_EXT_TYPE, &hs->extensions[i].type);
		get(pkt, TLS_HANDSHAKE_EXT_LEN, &hs->extensions[i].len);
		
		if(hs->extensions[i].len > 0)
		{
			parseExtensionData(pkt, &hs->extensions[i]);
		}
	}
	
	return 1;
}

int
parseTlsHandshake(const u_char *pkt, TlsHandshake *hs)
{
	hs->start = pos;
	get(pkt, TLS_HANDSHAKE_TYPE, &hs->type);
	
	/* len is 3 bytes */
	get(pkt, TLS_HANDSHAKE_LEN, &hs->len);
	
	switch(hs->type)
	{
		case TLS_CLIENT_HELLO:
			parseTlsClientHello(pkt, hs);
			break;
		case TLS_SERVER_HELLO:
			parseTlsServerHello(pkt, hs);
			break;
		case TLS_CERT:
			parseTlsCerts(pkt, hs);
			break;
		case TLS_NEW_TICKET:
		case TLS_CLIENT_KEY_EXCH:
		case TLS_CERT_STATUS:
		default:
			pos += hs->len;
	}
	return 1;
}

int
parseTls(const u_char *pkt, Tls *tls)
{
	tls->start = pos;
	parseTlsRecord(pkt, tls);
	
	tls->nHandshakes = 0;
	if(tls->type != TLS_CTYPE_HANDSHAKE || (pktlen < tls->len && pktlen))
		return 0;
	
	/* count number of handshakes */
	for(int tmp = pos ; tmp < tls->len + tls->start + TLS_RECORD ; tls->nHandshakes++)
	{
		tmp += TLS_HANDSHAKE_TYPE;
		tmp += get4(pkt + tmp) >> 8;
		tmp += TLS_HANDSHAKE_LEN;	
	}
	
	tls->handshakes = emalloc(tls->nHandshakes * sizeof(TlsHandshake));
	for(int i = 0 ; i < tls->nHandshakes ; i++)
	{
		parseTlsHandshake(pkt, tls->handshakes + i);
	}
	
	return 1;
}

char*
tlsVersionToStr(uint16_t ver)
{
	switch(ver)
	{
		case SSL_30:
			return "SSL v3";
		case TLS_10:
			return "TLS v1.0";
		case TLS_11:
			return "TLS v1.1";
		case TLS_12:
			return "TLS v1.2";
		case TLS_13:
			return "TLS v1.3";
		default:
			return "Unknown";
	}
}

char*
tlsContentTypeToStr(uint8_t type)
{
	switch(type)
	{
		case TLS_CTYPE_ALERT:
			return "Alert";
		case TLS_CTYPE_HANDSHAKE:
			return "Handshake";
		case TLS_CTYPE_APPLICATION_DATA:
			return "Application data";
		case TLS_CTYPE_HEARTBEAT:
			return "heart beat";
		default:
			return "Unkown";
	}
}

char*
tlsHandshakeTypeToStr(uint8_t type)
{
	switch(type)
	{
		case TLS_HELLO_REQ:
			return "Hello Request";
		case TLS_CLIENT_HELLO:
			return "Client Hello ☺";
		case TLS_SERVER_HELLO:
			return "Server Hello ☺";
		case TLS_NEW_TICKET:
			return "New session ticket";
		case TLS_CERT:
			return "Certificate";
		case TLS_SERVER_KEY_EXCH:
			return "Server key exchange";
		case TLS_SERVER_HELLO_DONE:
			return "Server hello done";
		case TLS_CLIENT_KEY_EXCH:
			return "Client key exchange";
		case TLS_CERT_STATUS:
			return "OCSP";
		default:
			err(1, "tlsHandshakeTypeToStr(%d): unkown type", type);
			return NULL;
	}
}

char*
tlsExtensionsTypeToStr(uint16_t type)
{
	switch(type)
	{
		case TLS_EXT_SNI:
			return "SNI (Server name)";
		case TLS_EXT_SUPPORTED_VERS:
			return "Supported versions";
		case TLS_EXT_PADDING:
			return "Padding";
		default:
			return "Unkown";
	}
}

void
printTlsTuple(TlsTuple tuple)
{
		printf("\ttls tuple (%s):\n"
		"\t\tlen: %d (%#x)\n",
		tuple.name,
		tuple.len, tuple.len);
		
		printf("\t\tdata: ");
		for(int i = 0 ; i < tuple.len ; i++)
			printf("%0x", tuple.data[i]);
		
		printf("\n");
}

void
printTlsExtension(TlsExtension e)
{
	if(debug)
	{
		switch(e.type)
		{
			case TLS_EXT_SNI:
				printf("list len: %d\ttype: %d\tlen: %d\tname: %s",
				e.sni->listLen, e.sni->type, e.sni->len, e.sni->name);
				
				break;
			case TLS_EXT_SUPPORTED_VERS:
				printf("len: %d (%#x)\tdata: ", e.sv->len, e.sv->len);
				for(int i = 0 ; i < e.sv->len / 2; i++)
					printf("%#x ", e.sv->vers[i]);
				break;
			default:
				printf("data: ");
				for(int i = 0 ; i < e.len ; i++)
					printf("%x", e.data[i]);
				break;
		}
	}
	else
	{
		switch(e.type)
		{
			case TLS_EXT_SNI:
				printf("name: %s", e.sni->name);
				break;
			
			case TLS_EXT_SUPPORTED_VERS:
				for(int i = 0 ; i < e.sv->len / 2; i++)
					printf("%s (%#x) ", tlsVersionToStr(e.sv->vers[i]), e.sv->vers[i]);
				break;
			default:
				break;
		}
	}
	printf("\n");
}

void
printTlsExtensions(TlsHandshake hs)
{
	TlsExtension *e = hs.extensions;
	
	if(debug)
	{
		printf("\t\ttls extensions:\n"
		"\t\tlen: %d\tnExtensions: %d (%#x)\n",
		hs.extensionsLen, hs.nExtensions, hs.nExtensions);
		
		for(int i = 0 ; i < hs.nExtensions ; i++)
		{
			//if(strcmp("Unkown", tlsExtensionsTypeToStr(e->type)) && e->len > 0)
			{
				printf("\t\t\textension %i: start: %d (%#x)\n"
				"\t\t\t\ttype: %d (%s)\tlen: %d (%#x)\n"
				"\t\t\t\t",
				
				i, e->start, e->start,
				e->type, tlsExtensionsTypeToStr(e->type), e->len, e->len);
				
				printTlsExtension(*e);
			}
			e++;	
		}
	}
	else
	{
		printf("\t\ttls extensions:\tnExtensions: %d\n",
		hs.nExtensions);
		
		for(int i = 0 ; i < hs.nExtensions ; i++)
		{
			if((e->type == TLS_EXT_SNI || e->type == TLS_EXT_SUPPORTED_VERS) && e->len > 0)
			{
				printf("\t\t\textension %i: type: %s\t",
				i, tlsExtensionsTypeToStr(e->type));
				
				printTlsExtension(*e);
			}
			e++;	
		}
	}
}

void
printTlsHandshake(TlsHandshake hs)
{
	if(debug)
	{
		printf("tls handshake:\n"
		"\ttype: %s (%d)\tlen: %d (%#x)\tstart: %d (%#x)\n",
		
		tlsHandshakeTypeToStr(hs.type), hs.type, hs.len,  hs.len, hs.start, hs.start);		
		switch(hs.type)
		{
			case TLS_CLIENT_HELLO:
		
				printf("\tversion: %#04x\n", hs.version);
					
				printTlsTuple(*(hs.sessionId));
				
				printf("\trandom: ");
				for(int i = 0 ; i < TLS_HANDSHAKE_RANDOM ; i++)
					printf("%x", hs.random[i]);
					
				printTlsTuple(*hs.cipherSuits);
				printTlsTuple(*hs.compressionMethods);
				printTlsExtensions(hs);
				break;
				
			case TLS_SERVER_HELLO:
				printf("\tversion: %#04x\n", hs.version);
				
				printTlsTuple(*(hs.sessionId));
				
				printf("\trandom: ");
				for(int i = 0 ; i < TLS_HANDSHAKE_RANDOM ; i++)
					printf("%x", hs.random[i]);
			
				printf("\tcipherSuit: %#x\tcompressionMethod: %#x\n",
				hs.cipherSuit, hs.compressionMethod);
				printTlsExtensions(hs);
				break;
			
			case TLS_CERT:
				printf("\tcertsLen: %d (%#x), nCerts: %d (%#x)\n",
				hs.certsLen, hs.certsLen, hs.nCerts, hs.nCerts);
				
				printf("\tcerts:\n");
				for(int i = 0 ; i < hs.nCerts ; i++)
				{
					printf("\t\t cert %d:\n", i);
					printf("\t\t\tstart: %d (%#x)\t len: %d (%#x)\n",
					hs.certs->start, hs.certs->start, hs.certs->len, hs.certs->len);
					printDer(*hs.certs[i].der);
				}
				break;
		default:
				break;
		}
	}
	else
	{
		printf("tls handshake:\ttype: %s\n",
		tlsHandshakeTypeToStr(hs.type));
		
		switch(hs.type)
		{
			case TLS_CLIENT_HELLO:
		
				printf("\n\tversion: %s\n", tlsVersionToStr(hs.version));
				printTlsExtensions(hs);
				break;
				
			case TLS_SERVER_HELLO:
				printf("\n\tversion: %s\n", tlsVersionToStr(hs.version));
				printTlsExtensions(hs);
				break;
			
			case TLS_CERT:
				printf("\tnCerts: %d\n",
				hs.nCerts);
				
				printf("\tcerts:\n");
				for(int i = 0 ; i < hs.nCerts ; i++)
				{
					printf("\t\t***** cert %d:*****\n", i);
					printDer(*hs.certs[i].der);
				}
				break;
			default:
				break;
		}
	}
}

void
printTlsRecord(Tls tls)
{
	if(debug)
	{
		printf("tls record:\n"
		"\ttype: %d\t\tversion: %#x\t"
		"len: %d (%#x), nHandshakes: %d\n",
		
		tls.type, tls.version,
		tls.len, tls.len, tls.nHandshakes);
	}
	else
	{
		printf("tls: content type: %s\tversion %s\n",
		tlsContentTypeToStr(tls.type), tlsVersionToStr(tls.version));
	}
}

void
printTls(Tls tls)
{

	if(tls.type == TLS_CTYPE_HANDSHAKE)
	{
		printTlsRecord(tls);
		for(int i = 0 ; i < tls.nHandshakes ; i++)
		{
			printTlsHandshake(tls.handshakes[i]);
		}
	}
}

/* keep this with sync with parsers */
void
freeTls(Tls *tls)
{
	TlsHandshake *hs;
	TlsExtension *e;
	
	for(int i = 0 ; i < tls->nHandshakes ; i++)
	{
		hs = tls->handshakes + i;
		for(int j = 0 ; j < hs->nExtensions ; j++)
		{
			e = hs->extensions + j;
			switch(e->type)
			{
				case TLS_EXT_SNI:
				case TLS_EXT_SUPPORTED_VERS:
					break;
				default:
			//		free(e->data);
			}
		//	free(e);
		}
		free(hs);
	}
	/* do not free tls! */
}

Parser tlsParser = {
	.name = "tls",
	.parse = parseTls,
	.print = printTls,
	.free = freeTls,
};