ref: 272dec2602bfb557af9464d21426d195b8e8e1a5
dir: /tls.c/
#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,
};