ref: 13738d2aa200eeb5859525225ec1d7bec7e8134e
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, };