|
@@ -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;
|
|
|
+}
|
|
|
+
|