Browse Source

fixed a bug with AES-GCM tags

cecylia 7 years ago
parent
commit
1a78f1de1c
4 changed files with 40 additions and 47 deletions
  1. 12 27
      relay_station/crypto.c
  2. 1 2
      relay_station/crypto.h
  3. 13 11
      relay_station/flow.c
  4. 14 7
      relay_station/relay.c

+ 12 - 27
relay_station/crypto.c

@@ -399,14 +399,16 @@ err:
  * 		incoming: the direction of the record
  * 		type: the type of the TLS record
  * 		enc: 1 for encryption, 0 for decryption
+ * 		re:	 1 if this is a re-encryption (counters are reset), 0 otherwise
+ * 			 Note: is only checked during encryption
  *
  * 	Output:
  * 		length of the output data
  */
-int encrypt(flow *f, uint8_t *input, uint8_t *output, int32_t len, int32_t incoming, int32_t type, int32_t enc){
+int encrypt(flow *f, uint8_t *input, uint8_t *output, int32_t len, int32_t incoming, int32_t type, int32_t enc, uint8_t re){
 	uint8_t *p = input;
 	
-	EVP_CIPHER_CTX *ds = (incoming) ? ((enc) ? f->srvr_write_ctx : f->clnt_read_ctx) : ((enc) ? f->clnt_write_ctx : f->srvr_read_ctx) ;
+	EVP_CIPHER_CTX *ds = (incoming) ? ((enc) ? f->srvr_write_ctx : f->clnt_read_ctx) : ((enc) ? f->clnt_write_ctx : f->srvr_read_ctx);
 	if(ds == NULL){
 		printf("FAIL\n");
 		return 1;
@@ -415,8 +417,15 @@ int encrypt(flow *f, uint8_t *input, uint8_t *output, int32_t len, int32_t incom
 	uint8_t *seq;
 	seq = (incoming) ? f->read_seq : f->write_seq;
 
+	if(enc && re){
+		for(int i=7; i>=0; i--){
+			--seq[i];
+			if(seq[i] != 0xff)
+				break;
+		}
+	}
+
 	if(f->application && (ds->iv[EVP_GCM_TLS_FIXED_IV_LEN] == 0)){
-		//printf("MERP\n");
 		//fill in rest of iv
 		for(int i = EVP_GCM_TLS_FIXED_IV_LEN; i< ds->cipher->iv_len; i++){
 			ds->iv[i] = p[i- EVP_GCM_TLS_FIXED_IV_LEN];
@@ -1161,30 +1170,6 @@ int init_ciphers(flow *f){
 	return 0;
 }
 
-// To avoid warnings about MAC paddings, use this to update contexts
-void update_context(flow *f, uint8_t *input, int32_t len, int32_t incoming, int32_t type, int32_t enc){
-
-	uint8_t *output = ecalloc(1, len+16+8);
-
-	memcpy(output + EVP_GCM_TLS_EXPLICIT_IV_LEN, input, len);
-
-	//If the original message was a decryption, this will be an necryption.
-	//Incoming field stays the same
-	encrypt(f, output, output, len+8, incoming, type, !enc);
-
-	//revert the sequence number
-	uint8_t *seq = incoming ? f->read_seq : f->write_seq;
-	for(int i=7; i>=0; i--){
-		--seq[i];
-		if(seq[i] >= 0)
-			break;
-		else
-			seq[i] = 0;
-	}
-
-	free(output);
-}
-
 /* Generate the keys for a client's super encryption layer
  * 
  * The header of each downstream slitheen data chunk is 16 bytes and encrypted with

+ 1 - 2
relay_station/crypto.h

@@ -12,7 +12,7 @@
 
 
 int extract_parameters(flow *f, uint8_t *hs);
-int encrypt(flow *f, uint8_t *input, uint8_t *output, int32_t len, int32_t incoming, int32_t type, int32_t enc);
+int encrypt(flow *f, uint8_t *input, uint8_t *output, int32_t len, int32_t incoming, int32_t type, int32_t enc, uint8_t re);
 int extract_server_random(flow *f, uint8_t *hs);
 int compute_master_secret(flow *f);
 
@@ -26,7 +26,6 @@ int PRF(flow *f, uint8_t *secret, int32_t secret_len,
 int update_finish_hash(flow *f, uint8_t *hs);
 int verify_finish_hash(flow *f, uint8_t *p, int32_t incoming);
 int init_ciphers(flow *f);
-void update_context(flow *f, uint8_t *input, int32_t len, int32_t incoming, int32_t type, int32_t enc);
 void generate_client_super_keys(uint8_t *secret, client *c);
 int super_encrypt(client *c, uint8_t *data, uint32_t len);
 void check_handshake(struct packet_info *info);

+ 13 - 11
relay_station/flow.c

@@ -182,7 +182,7 @@ int update_flow(flow *f, uint8_t *record, uint8_t incoming) {
 				}
 				printf("\n");
 #endif
-				int32_t n = encrypt(f, p, p, record_len - RECORD_HEADER_LEN, incoming, 0x16, 0);
+				int32_t n = encrypt(f, p, p, record_len - RECORD_HEADER_LEN, incoming, 0x16, 0, 0);
 				if(n<=0){
 					printf("Error decrypting finished  (%x:%d -> %x:%d)\n", f->src_ip.s_addr, ntohs(f->src_port), f->dst_ip.s_addr, ntohs(f->dst_port));
 				}
@@ -206,7 +206,6 @@ int update_flow(flow *f, uint8_t *record, uint8_t incoming) {
 					f->in_encrypted = 2;
 				} else {
 					f->out_encrypted = 2;
-					update_context(f, p, n, incoming, 0x16, 0);
 				}
 
 			}
@@ -354,14 +353,7 @@ int update_flow(flow *f, uint8_t *record, uint8_t incoming) {
 					verify_finish_hash(f,p, incoming);
 					
 					//re-encrypt finished message
-
-					//revert the sequence number
-					if(incoming)
-						memset(f->read_seq, 0, 8);
-					else 
-						memset(f->write_seq, 0, 8);
-
-					int32_t n =  encrypt(f, record+RECORD_HEADER_LEN, record+RECORD_HEADER_LEN, record_len - (RECORD_HEADER_LEN+16), incoming, 0x16, 1);
+					int32_t n =  encrypt(f, record+RECORD_HEADER_LEN, record+RECORD_HEADER_LEN, record_len - (RECORD_HEADER_LEN+16), incoming, 0x16, 1, 1);
 
 #ifdef HS_DEBUG
 					printf("New finished ciphertext:\n");
@@ -416,11 +408,21 @@ int update_flow(flow *f, uint8_t *record, uint8_t incoming) {
 			p = record;
 			p += RECORD_HEADER_LEN;
 			if(((incoming) && (f->in_encrypted > 0)) || ((!incoming) && (f->out_encrypted > 0))){
-				encrypt(f, p, p, record_len - RECORD_HEADER_LEN, incoming, 0x16, 0);
+				//decrypt alert
+				encrypt(f, p, p, record_len - RECORD_HEADER_LEN, incoming, 0x16, 0, 0);
 				p += EVP_GCM_TLS_EXPLICIT_IV_LEN;
 			}
 			printf("Alert (%x:%d -> %x:%d) %02x %02x \n", f->src_ip.s_addr, ntohs(f->src_port), f->dst_ip.s_addr, ntohs(f->dst_port), p[0], p[1]);
 			fflush(stdout);
+			
+			//re-encrypt alert
+			if(((incoming) && (f->in_encrypted > 0)) || ((!incoming) && (f->out_encrypted > 0))){
+				int32_t n =  encrypt(f, record+RECORD_HEADER_LEN, record+RECORD_HEADER_LEN, record_len - (RECORD_HEADER_LEN+16), incoming, 0x16, 1, 1);
+				if(n <= 0){
+					printf("Error re-encrypting alert\n");
+				}
+			}
+
 			break;
 		case HB:
 			printf("Heartbeat\n");

+ 14 - 7
relay_station/relay.c

@@ -121,7 +121,9 @@ int read_header(flow *f, struct packet_info *info){
 	uint32_t record_length;
 	if(f->upstream_remaining > 0){
 	//check to see whether the previous record has finished
+		printf("US: finishing previous record\n");
 		if(f->upstream_remaining > info->app_data_len){
+			printf("US: still need more\n");
 			//ignore entire packet for now
 			queue_block *new_block = emalloc(sizeof(queue_block));
 
@@ -206,8 +208,9 @@ int read_header(flow *f, struct packet_info *info){
 
 	memcpy(decrypted_data, p, record_length);
 
-	int32_t decrypted_len = encrypt(f, decrypted_data, decrypted_data, record_length, 0, record_hdr->type, 0);
+	int32_t decrypted_len = encrypt(f, decrypted_data, decrypted_data, record_length, 0, record_hdr->type, 0, 0);
 	if(decrypted_len<0){
+		printf("US: decryption failed!\n");
 		if(record_ptr != NULL)
 			free(record_ptr);
 		free(decrypted_data);
@@ -220,6 +223,8 @@ int read_header(flow *f, struct packet_info *info){
 			printf("%02x ", decrypted_data[i]);
 		}
 		fflush(stdout);
+
+		//TODO: re-encrypt and return
 	}
 
 #ifdef DEBUG
@@ -886,6 +891,7 @@ int process_downstream(flow *f, int32_t offset, struct packet_info *info){
 			printf("%02x ", ((uint8_t *) record_hdr)[i]);
 		}
 		printf("\n");
+		fflush(stdout);
 #endif
 
 		p += (RECORD_HEADER_LEN - f->partial_record_header_len);
@@ -907,12 +913,12 @@ int process_downstream(flow *f, int32_t offset, struct packet_info *info){
 					f->outbox = emalloc(record_len+1);
 					f->outbox_len = record_len;
 					f->outbox_offset = 0;
-					printf("FILLED: mid content or mid chunk and could not decrypt\n");
 					fill_with_downstream(f, f->outbox + EVP_GCM_TLS_EXPLICIT_IV_LEN , record_len - (EVP_GCM_TLS_EXPLICIT_IV_LEN+ 16));
-					//encrypt
+
+					//encrypt (not a re-encryption)
 					int32_t n = encrypt(f, f->outbox, f->outbox,
 									record_len - 16, 1,
-									record_hdr->type, 1);
+									record_hdr->type, 1, 0);
 					if(n < 0){
 						fprintf(stdout,"outbox encryption failed\n");
 					} else {
@@ -948,9 +954,10 @@ int process_downstream(flow *f, int32_t offset, struct packet_info *info){
 
 		//now decrypt the record
 		int32_t n = encrypt(f, record_ptr, record_ptr, record_len, 1,
-						record_hdr->type, 0);
+						record_hdr->type, 0, 0);
 		if(n < 0){
 			//do something smarter here
+			printf("Decryption failed\n");
 			if(f->partial_record_header_len > 0){
 				f->partial_record_header_len = 0;
 				free(f->partial_record_header);
@@ -1190,11 +1197,12 @@ int process_downstream(flow *f, int32_t offset, struct packet_info *info){
 			printf("Text:\n");
 			printf("%s\n", record_ptr+EVP_GCM_TLS_EXPLICIT_IV_LEN);
 			fflush(stdout);
+		}
 #endif
 
 		if((n = encrypt(f, record_ptr, record_ptr,
 						n + EVP_GCM_TLS_EXPLICIT_IV_LEN, 1, record_hdr->type,
-						1)) < 0){
+						1, 1)) < 0){
 			printf("UH OH, failed to re-encrypt record\n");
 			if(f->partial_record_header_len > 0){
 				f->partial_record_header_len = 0;
@@ -1237,7 +1245,6 @@ int fill_with_downstream(flow *f, uint8_t *data, int32_t length){
 	data_queue *downstream_queue = f->downstream_queue;
 	client *client_ptr = f->client_ptr;
 
-
 	//Fill as much as we can from the censored_queue
 	//Note: need enough for the header and one block of data (16 byte IV, 16 byte
 	//		block, 16 byte MAC) = header_len + 48.