Browse Source

computed master secret

cbocovic 9 years ago
parent
commit
a2d85ce0d4
5 changed files with 283 additions and 34 deletions
  1. 1 1
      server/Makefile
  2. 242 15
      server/flow.c
  3. 18 3
      server/flow.h
  4. 21 14
      server/slitheen-proxy.c
  5. 1 1
      server/slitheen.h

+ 1 - 1
server/Makefile

@@ -10,7 +10,7 @@ rserv: rserv.o ptwist168.o
 	gcc -g -o $@ $^ -lssl -lcrypto
 
 slitheen-proxy: slitheen-proxy.o flow.o rserv.o ptwist168.o util.o util.h ptwist.h rserv.h flow.h slitheen.h
-	gcc -g -o $@ $^ -I/home/slitheen/Documents/include/openssl libssl.a libcrypto.a -lpcap -lpthread
+	gcc -g -o $@ $^ -I/home/slitheen/Documents/include/openssl libssl.a libcrypto.a -lpcap -lpthread -ldl
 
 clean:
 	-rm *.o

+ 242 - 15
server/flow.c

@@ -2,8 +2,15 @@
 #include <stdlib.h>
 #include <stdint.h>
 #include "flow.h"
+#include <openssl/dh.h>
+#include <openssl/bn.h>
+#include <openssl/err.h>
+#include <openssl/rand.h>
+#include <openssl/ssl.h>
 #include "slitheen.h"
 
+#define PRE_MASTER_LEN 256
+
 static flow_table *table;
 
 /* Initialize the table of tagged flows */
@@ -24,24 +31,25 @@ int init_flow_table(void) {
 
 
 /* Add a new flow to the tagged flow table */
-int add_flow(flow newFlow) {
+flow *add_flow(flow newFlow) {
 	flow *ptr;
 
 	if(table->len == table->max_len){
 		//grow_table();
-		return(1);
+		NULL;
 	}
 	printf("there are %d flows in the table\n", table->len);
 
 	ptr = table->table + table->len;
 	newFlow.state = TLS_CLNT_HELLO;
-	newFlow.encrypted = 0;
+	newFlow.in_encrypted = 0;
+	newFlow.out_encrypted = 0;
 	newFlow.packet_chain = NULL;
 	*ptr = newFlow;
 
 	table->len ++;
 
-	return(0);
+	return ptr;
 }
 
 /* Updates the flow state */
@@ -64,6 +72,7 @@ int update_flow(flow *f) {
 	record_len = RECORD_LEN(record_hdr)+RECORD_HEADER_LEN;
 	data_len = f->packet_chain->data_len;
 	packet *current = f->packet_chain;
+	int incoming = current->incoming;
 	record = calloc(1, record_len);
 	for(int i=0; (i<data_len) && (i<record_len); i++){
 		record[i] = p[i];
@@ -98,10 +107,14 @@ int update_flow(flow *f) {
 			p += RECORD_HEADER_LEN;
 			handshake_hdr = (struct handshake_header*) p;
 
-			int size_hs = HANDSHAKE_MESSAGE_LEN(handshake_hdr);
+			//int size_hs = HANDSHAKE_MESSAGE_LEN(handshake_hdr);
 			printf("Handshake Message:\n");
 			f->state = handshake_hdr->type;
 
+			if((incoming && f->in_encrypted) || (!incoming && f->out_encrypted)){
+				decrypt_fin(f, p);
+			}
+
 			/* Now see if there's anything extra to do */
 			switch(f->state){
 			/* Checks to see if this is a possibly tagged hello msg */
@@ -110,6 +123,7 @@ int update_flow(flow *f) {
 					printf("Received client hello!\n");
 					break;
 				case TLS_SERV_HELLO:
+					extract_server_random(f, p);
 					printf("Received server hello!\n");
 					break;
 				case TLS_NEW_SESS:
@@ -117,10 +131,16 @@ int update_flow(flow *f) {
 					break;
 				case TLS_CERT:
 					printf("Received certificate!\n");
-					/* Need to extract server params */
 					break;
 				case TLS_SRVR_KEYEX:
 					printf("Received server key exchange!\n");
+					/* Need to extract server params */
+					if(extract_parameters(f, p)){
+						printf("Error extracting params\n");
+					}
+					if(compute_master_secret(f)){
+						printf("Error computing master secret\n");
+					}
 					break;
 				case TLS_CERT_REQ:
 					printf("Received certificate request!\n");
@@ -138,11 +158,7 @@ int update_flow(flow *f) {
 					printf("Received finished message!\n");
 					break;
 				default:
-					if(f->encrypted){
-						printf("Received encrypted finished!\n");
-					} else {
-						printf("Error?\n");
-					}
+					printf("Error?\n");
 					break;
 			}
 			break;
@@ -151,9 +167,13 @@ int update_flow(flow *f) {
 			break;
 		case CCS:
 			printf("Change of Cipher Spec\n");
-			f->encrypted = 1;
+			if(incoming){
+				f->in_encrypted = 1;
+			} else {
+				f->out_encrypted = 1;
+			}
 			break;
-		case A:
+		case ALERT:
 			printf("Alert\n");
 			break;
 		case HB:
@@ -178,7 +198,6 @@ int update_flow(flow *f) {
 		f->packet_chain = current; //TODO: make current
 		current->data = current->data + (current->data_len - (data_len - record_len));
 		current->data_len = data_len - record_len;
-		printf("more records? extra: %d\n", current->data_len);
 		update_flow(f);
 	}
 
@@ -284,6 +303,8 @@ int add_packet(flow *f, uint8_t *p){
 	new_packet->data = p;
 	new_packet->data_len = htons(ip_hdr->len) - (size_ip + size_tcp);
 	new_packet->next = NULL;
+	new_packet->incoming = 
+		(ip_hdr->src.s_addr == f->src_ip.s_addr) ? 0 : 1;
 
 	/* Find appropriate place in chain */
 	if(new_packet->data_len > 0){
@@ -304,7 +325,7 @@ int add_packet(flow *f, uint8_t *p){
 			new_packet->next = next;
 			previous->next = new_packet;
 		}
-		printf("Flow: %d > %d\n", ip_hdr->src.s_addr, ip_hdr->dst.s_addr);
+		printf("Flow: %d > %d (%s)\n", ip_hdr->src.s_addr, ip_hdr->dst.s_addr, (new_packet->incoming)? "incoming":"outgoing");
 		printf("ID number: %u\n", htonl(ip_hdr->id));
 		printf("Sequence number: %u\n", htonl(tcp_hdr->sequence_num));
 		printf("Acknowledgement number: %u\n", htonl(tcp_hdr->ack_num));
@@ -315,3 +336,209 @@ int add_packet(flow *f, uint8_t *p){
 	return 0;
 
 }
+
+/** UTILITY **/
+
+int extract_parameters(flow *f, uint8_t *hs){
+	DH *dh;
+	uint8_t *p;
+	long i;
+
+	p = hs + HANDSHAKE_HEADER_LEN;
+
+	if((dh = DH_new()) == NULL){
+		return 1;
+	}
+
+	/* Extract prime modulus */
+	n2s(p,i);
+
+	printf("Server p:\n");
+	for(int j=0; j<i; j++){
+		printf("%02x ",p[j]);
+	}
+	printf("\n");
+	if(!(dh->p = BN_bin2bn(p,i,NULL))){
+		return 1;
+	}
+	p += i;
+
+	/* Extract generator */
+	n2s(p,i);
+
+	printf("Server g:\n");
+	for(int j=0; j<i; j++){
+		printf("%02x ",p[j]);
+	}
+	printf("\n");
+	if(!(dh->g = BN_bin2bn(p,i,NULL))){
+		return 1;
+	}
+	p += i;
+
+	/* Extract server public value */
+	n2s(p,i);
+
+	printf("Server pub_key:\n");
+	for(int j=0; j<i; j++){
+		printf("%02x ",p[j]);
+	}
+	printf("\n");
+	if(!(dh->pub_key = BN_bin2bn(p,i,NULL))){
+		return 1;
+	}
+
+	f->dh = dh;
+	printf("Param extraction: success!\n");
+	return 0;
+}
+
+/* Decrypt the TLS FINISHED message */
+int decrypt_fin(flow *f, uint8_t *hs){
+	return 1;
+}
+
+int compute_master_secret(flow *f){
+	DH *dh_srvr = NULL;
+	DH *dh_clnt = NULL;
+	BN_CTX *ctx;
+	BN_MONT_CTX *mont = NULL;
+	BIGNUM *pub_key = NULL, *priv_key = NULL;
+
+	ctx = BN_CTX_new();
+
+	dh_srvr = f->dh;
+	dh_clnt = DHparams_dup(dh_srvr);
+
+    uint32_t l = dh_clnt->length ? dh_clnt->length : BN_num_bits(dh_clnt->p) - 1;
+    int32_t bytes = (l+7) / 8;
+
+    uint8_t *buf = (uint8_t *)OPENSSL_malloc(bytes);
+    if (buf == NULL){
+        BNerr(BN_F_BNRAND, ERR_R_MALLOC_FAILURE);
+        return 1;
+    }
+
+	pub_key = BN_new();
+	priv_key = BN_new();
+
+	for(int i=0; i<bytes; i++){
+		buf[i] = f->key[i%16];
+	}
+
+    if (!BN_bin2bn(buf, bytes, priv_key))
+		return 1;
+
+    {
+        BIGNUM *prk;
+
+		prk = priv_key;
+
+        if (!dh_clnt->meth->bn_mod_exp(dh_clnt, pub_key, dh_clnt->g, prk, dh_clnt->p, ctx, mont)){
+			printf("FAIL\n");
+            return 1;
+		}
+		printf("here\n");
+    }
+
+    dh_clnt->pub_key = pub_key;
+    dh_clnt->priv_key = priv_key;
+
+	// Compute master key 
+	uint8_t master_secret[SSL3_MASTER_SECRET_SIZE];
+	uint8_t *pre_master_secret = calloc(1, 256);//TODO: find right length
+
+	int32_t len = DH_compute_key(pre_master_secret, dh_srvr->pub_key, dh_clnt);
+	
+	printf("Output of compute key:\n");
+	for(int j=0; j<len; j++){
+		printf("%02x ", pre_master_secret[j]);
+	}
+	printf("\n");
+
+	PRF(pre_master_secret, f->client_random, f->server_random,
+			master_secret);
+
+	//remove pre_master_secret from memory
+	memset(pre_master_secret, 0, PRE_MASTER_LEN);
+
+	printf("master secret:\n");
+	for(int i=0; i< 48; i++){
+		printf("%02x ", master_secret[i]);
+	}
+	printf("\n");
+	
+	free(pre_master_secret);
+	DH_free(dh_srvr);
+	DH_free(dh_clnt);
+	return 0;
+}
+
+void extract_server_random(flow *f, uint8_t *hs){
+
+	uint8_t *p;
+
+	p = hs + HANDSHAKE_HEADER_LEN;
+
+	p+=2; //skip version
+
+	memcpy(f->server_random, p, SSL3_RANDOM_SIZE);
+	printf("got server random\n");
+
+}
+
+/* PRF using sha384, as defined in RFC 5246 */
+int PRF(uint8_t *secret, uint8_t *client_random, uint8_t *server_random, uint8_t *output){
+
+	EVP_MD_CTX ctx, ctx_tmp, ctx_init;
+	EVP_PKEY *mac_key;
+	const EVP_MD *md = EVP_sha384();
+
+	uint8_t A[EVP_MAX_MD_SIZE];
+	size_t len, A_len;
+	int chunk = EVP_MD_size(md);
+	int remaining = SSL_MAX_MASTER_KEY_LENGTH;
+
+	uint8_t *out = output;
+
+	EVP_MD_CTX_init(&ctx);
+	EVP_MD_CTX_init(&ctx_tmp);
+	EVP_MD_CTX_init(&ctx_init);
+	EVP_MD_CTX_set_flags(&ctx_init, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
+
+	mac_key = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, secret, PRE_MASTER_LEN);
+
+	/* Calculate first A value */
+	EVP_DigestSignInit(&ctx_init, NULL, md, NULL, mac_key);
+	EVP_MD_CTX_copy_ex(&ctx, &ctx_init);
+	EVP_DigestSignUpdate(&ctx, TLS_MD_MASTER_SECRET_CONST, TLS_MD_MASTER_SECRET_CONST_SIZE);
+	EVP_DigestSignUpdate(&ctx, client_random, SSL3_RANDOM_SIZE);
+	EVP_DigestSignUpdate(&ctx, server_random, SSL3_RANDOM_SIZE);
+	EVP_DigestSignFinal(&ctx, A, &A_len);
+
+	//iterate until desired length is achieved
+	while(remaining > 0){
+		/* Now compute SHA384(secret, A) */
+		EVP_MD_CTX_copy_ex(&ctx, &ctx_init);
+		EVP_DigestSignUpdate(&ctx, A, A_len);
+		EVP_MD_CTX_copy_ex(&ctx_tmp, &ctx);
+		EVP_DigestSignUpdate(&ctx, TLS_MD_MASTER_SECRET_CONST, TLS_MD_MASTER_SECRET_CONST_SIZE);
+		EVP_DigestSignUpdate(&ctx, client_random, SSL3_RANDOM_SIZE);
+		EVP_DigestSignUpdate(&ctx, server_random, SSL3_RANDOM_SIZE);
+		
+		if(remaining > chunk){
+			EVP_DigestSignFinal(&ctx, out, &len);
+			out += len;
+			remaining -= len;
+
+			/* Next A value */
+			EVP_DigestSignFinal(&ctx_tmp, A, &A_len);
+		} else {
+			EVP_DigestSignFinal(&ctx, A, &A_len);
+			memcpy(out, A, remaining);
+			remaining -= remaining;
+		}
+	}
+	return 1;
+}
+

+ 18 - 3
server/flow.h

@@ -2,6 +2,8 @@
 #define __RELAY_H__
 
 #include <netinet/in.h>
+#include <openssl/bn.h>
+#include <openssl/ssl.h>
 #include "ptwist.h"
 
 #define MAX_FLOWS 10
@@ -18,26 +20,35 @@
 #define TLS_CLNT_KEYEX 0x10
 #define TLS_FINISHED 0x14
 
+# define n2s(c,s)        ((s=(((unsigned int)(c[0]))<< 8)| \
+							(((unsigned int)(c[1]))    )),c+=2)
+
 struct packet_st{
 	uint32_t seq_num;
 	uint16_t len;
 	uint16_t data_len;
 	uint8_t *data;
 	struct packet_st *next;
+	int incoming; //0 for outgoing, 1 for incoming
 };
 
 typedef struct packet_st packet;
 
 typedef struct flow_st {
-	struct in_addr src_ip, dst_ip; /* Source and Destination addresses */
+	struct in_addr src_ip, dst_ip; /* Source (client) and Destination (server) addresses */
 	uint16_t src_port, dst_port;	/* Source and Destination ports */
 
 	uint32_t seq_num;		/* sequence number */
 
 	byte key[16];		/* negotiated key */
 	int state;		/* TLS handshake state */
-	int encrypted;		/* indicates whether flow is encrypted */
+	int in_encrypted;		/* indicates whether incoming flow is encrypted */
+	int out_encrypted;		/* indicates whether outgoing flow is encrypted */
 	packet *packet_chain; /* currently held data */
+	DH *dh;
+
+	uint8_t client_random[SSL3_RANDOM_SIZE];
+	uint8_t server_random[SSL3_RANDOM_SIZE];
 
 } flow;
 
@@ -49,7 +60,7 @@ typedef struct flow_table_st {
 
 
 int init_flow_table (void);
-int add_flow(flow newFlow);
+flow *add_flow(flow newFlow);
 int update_flow(flow *f);
 int remove_flow(int index);
 int check_flow(flow observed);
@@ -57,4 +68,8 @@ flow *get_flow(int index);
 
 int add_packet(flow *f, uint8_t *data);
 
+int extract_parameters(flow *f, uint8_t *hs);
+int decrypt_fin(flow *f, uint8_t *hs);
+void extract_server_random(flow *f, uint8_t *hs);
+int compute_master_secret(flow *f);
 #endif /* __RELAY_H__ */

+ 21 - 14
server/slitheen-proxy.c

@@ -4,7 +4,7 @@
 #include <unistd.h>
 #include <string.h>
 #include <pthread.h>
-#include "ptwist.h"
+#include <openssl/ssl.h>
 #include "rserv.h"
 #include "flow.h"
 #include "slitheen.h"
@@ -25,8 +25,9 @@ void check_handshake(const struct tcp_header *tcp_hdr, flow f, unsigned char *pt
 
 	FILE *fp;
 	int res, i, code;
-	u_int size_hs;
+	//u_int size_hs;
 	unsigned char *p;
+	unsigned char *hello_rand;
 	const struct handshake_header *handshake_hdr;
 
     byte privkey[PTWIST_BYTES];
@@ -36,11 +37,12 @@ void check_handshake(const struct tcp_header *tcp_hdr, flow f, unsigned char *pt
 	handshake_hdr = (struct handshake_header*) p;
 
 	code = handshake_hdr->type;
-	size_hs = HANDSHAKE_MESSAGE_LEN(handshake_hdr);
+	//size_hs = HANDSHAKE_MESSAGE_LEN(handshake_hdr);
 
 	if (code == 0x01){
 		p += CLIENT_HELLO_HEADER_LEN;
 		//now pointing to hello random :D
+		hello_rand = p;
 		p += 4; //skipping time bytes
 		/* Load the private key */
 		fp = fopen("privkey", "rb");
@@ -70,8 +72,6 @@ void check_handshake(const struct tcp_header *tcp_hdr, flow f, unsigned char *pt
 				fprintf(fp, "%02x ", p[i]);
 			}
 			fclose(fp);
-			//TODO: this might not be okay...
-			strncpy((char *) f.key, (char *) key, 16);
 
 			//Write key to file
 			fp = fopen("sharedkey", "wb");
@@ -85,7 +85,18 @@ void check_handshake(const struct tcp_header *tcp_hdr, flow f, unsigned char *pt
 			fclose(fp);
 
 			/* Save flow in table */
-			add_flow(f);
+			flow *flow_ptr = add_flow(f);
+			for(int i=0; i<16; i++){
+				flow_ptr->key[i] = key[i];
+			}
+
+			printf("KEY \n");
+			for(int i=0; i< 16; i++){
+				printf("%02x ", flow_ptr->key[i]);
+			}
+			printf("\n");
+			memcpy(flow_ptr->client_random, hello_rand, SSL3_RANDOM_SIZE);
+			
 			printf("Saved new flow\n");
 
 		}
@@ -100,7 +111,7 @@ void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *pa
 	unsigned char *p;
 
 	const struct ip_header *ip_hdr;
-	const struct tcp_header *tcp_hdr;
+	//const struct tcp_header *tcp_hdr;
 
 	handle = pcap_open_live(writedev, BUFSIZ, 1, 1000, errbuf);
 	if (handle == NULL){
@@ -111,7 +122,7 @@ void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *pa
 	p += ETHER_HEADER_LEN; //skip ethernet header
 	ip_hdr = (struct ip_header*) p;
 	p += IP_HEADER_LEN(ip_hdr);//TODO: remove
-	tcp_hdr = (struct tcp_header*) p;//TODO: remove
+	//tcp_hdr = (struct tcp_header*) p;//TODO: remove
 
 	/* Check to make sure it is an IP packet */
 	if( (ip_hdr->versionihl >>4) != 4)
@@ -251,7 +262,7 @@ void *sniff_packets(void *args){
  */
 void process_packet(const u_char *packet){
 	unsigned char *p;
-	int index, i;
+	int index;
 
 	const struct ip_header *ip_hdr;
 	const struct tcp_header *tcp_hdr;
@@ -324,13 +335,9 @@ void process_packet(const u_char *packet){
 			printf("TLS finished received.\n");
 		} else {
 			//check to see if tls_finished message
-			if(observed->encrypted){ /* decrypt tls finished message */
+			if(observed->in_encrypted && observed->out_encrypted){ /* decrypt tls finished message */
 				printf("MESSAGE ENCRYPTED\n");
 			}
-			if((observed->state == TLS_NEW_SESS) && !observed->encrypted){
-				//next packet should be encrypted
-				observed->encrypted = 1;
-			}
 
 		}
 	}

+ 1 - 1
server/slitheen.h

@@ -44,7 +44,7 @@ struct tcp_header {
 struct tls_header {
 	u_char type; /* Content Type */
 #define CCS 0x14
-#define A   0x15
+#define ALERT   0x15
 #define HS  0x16
 #define APP 0x17
 #define HB  0x18