Browse Source

Update the incoming Finished message in the new way

Changes the finished hash to
SHA256_HMAC_96(shared_key, "SLITHEEN_FINISHED" || old_finished_hash)

This feature detects and prevents suspicious behaviour in the event
of a MiTM or RAD attack.
Ian Goldberg 7 years ago
parent
commit
070ce0865d
4 changed files with 54 additions and 8 deletions
  1. 1 1
      relay_station/Makefile
  2. 43 0
      relay_station/crypto.c
  3. 3 3
      relay_station/crypto.h
  4. 7 4
      relay_station/flow.c

+ 1 - 1
relay_station/Makefile

@@ -1,4 +1,4 @@
-CFLAGS=-g -ggdb -Wall -std=gnu99
+CFLAGS=-g -ggdb -Wall -std=gnu99 -DDEBUG_HS
 
 TARGETS=slitheen-proxy
 

+ 43 - 0
relay_station/crypto.c

@@ -501,6 +501,49 @@ int fake_encrypt(flow *f, int32_t incoming){
 }
 	
 
+/** Mark the hash in a downstream TLS finished message
+ *
+ * Changes the finished hash to
+ * SHA256_HMAC_96(shared_key, "SLITHEEN_FINISHED" || old_finished_hash)
+ *
+ * This feature detects and prevents suspicious behaviour in the event
+ * of a MiTM or RAD attack.
+ *
+ * 	Inputs:
+ * 		f: the tagged flow
+ * 		hs: a pointer to the TLS Finished handshake message
+ *
+ * 	Output:
+ * 		0 on success, 1 on failure
+ *              if success, the message pointed to by hs will have
+ *                      been updated
+ */
+int mark_finished_hash(flow *f, uint8_t *hs){
+	HMAC_CTX ctx;
+	uint8_t hmac_output[EVP_MAX_MD_SIZE];
+	unsigned int hmac_output_len;
+
+	// Ensure this is a Finished message, of length 12 bytes
+	if (memcmp(hs, "\x14\x00\x00\x0c", 4)) {
+		return 1;
+	}
+
+	HMAC_CTX_init(&ctx);
+	HMAC_Init_ex(&ctx, f->key, 16, EVP_sha256(), NULL);
+	HMAC_Update(&ctx, (const unsigned char *)SLITHEEN_FINISHED_INPUT_CONST, SLITHEEN_FINISHED_INPUT_CONST_SIZE);
+	HMAC_Update(&ctx, hs+4, 12);
+	HMAC_Final(&ctx, hmac_output, &hmac_output_len);
+	HMAC_CTX_cleanup(&ctx);
+
+	if (hmac_output_len != 32) {
+		return 1;
+	}
+
+	memmove(hs+4, hmac_output, 12);
+
+	return 0;
+}
+
 /** Verifies the hash in a TLS finished message
  *
  * Adds string derived from the client-relay shared secret to the finished hash.

+ 3 - 3
relay_station/crypto.h

@@ -52,7 +52,7 @@ int PRF(flow *f, uint8_t *secret, int32_t secret_len,
 		uint8_t *output, int32_t output_len);
 
 int update_finish_hash(flow *f, uint8_t *hs);
-int verify_finish_hash(flow *f, uint8_t *p, int32_t incoming);
+int mark_finished_hash(flow *f, uint8_t *hs);
 int init_ciphers(flow *f);
 void generate_client_super_keys(uint8_t *secret, client *c);
 int super_encrypt(client *c, uint8_t *data, uint32_t len);
@@ -66,8 +66,8 @@ int check_tag(byte key[16], const byte privkey[PTWIST_BYTES],
 #define SLITHEEN_KEYGEN_CONST "SLITHEEN_KEYGEN"
 #define SLITHEEN_KEYGEN_CONST_SIZE 15
 
-#define SLITHEEN_FINISHED_INPUT_CONST "SLITHEEN_FINISH"
-#define SLITHEEN_FINISHED_INPUT_CONST_SIZE 15
+#define SLITHEEN_FINISHED_INPUT_CONST "SLITHEEN_FINISHED"
+#define SLITHEEN_FINISHED_INPUT_CONST_SIZE 17
 
 #define SLITHEEN_SUPER_SECRET_SIZE 16 //extracted from slitheen ID tag
 #define SLITHEEN_SUPER_CONST "SLITHEEN_SUPER_ENCRYPT"

+ 7 - 4
relay_station/flow.c

@@ -42,8 +42,6 @@
 #include "relay.h"
 #include "util.h"
 
-#define DEBUG_HS
-
 static flow_table *table;
 static session_cache *sessions;
 client_table *clients;
@@ -376,8 +374,13 @@ int update_flow(flow *f, uint8_t *record, uint8_t incoming) {
 #ifdef DEBUG_HS
 					printf("Received finished (%d) (%x:%d -> %x:%d)\n", incoming, f->src_ip.s_addr, ntohs(f->src_port), f->dst_ip.s_addr, ntohs(f->dst_port));
 #endif
-					if(verify_finish_hash(f,p, incoming)){
-						fprintf(stderr, "Error verifying finished hash\n");
+					if(!incoming) {
+					    // We only care about incoming
+					    // Finished messages
+					    break;
+					}
+					if(mark_finished_hash(f, p)){
+						fprintf(stderr, "Error marking finished hash\n");
 						remove_flow(f);
 						goto err;
 					}