Browse Source

fixed GCM tag counter bug and session ticket bugs

cecylia 7 years ago
parent
commit
bdb9a83c4e
5 changed files with 107 additions and 32 deletions
  1. 32 1
      relay_station/crypto.c
  2. 1 0
      relay_station/crypto.h
  3. 58 27
      relay_station/flow.c
  4. 1 0
      relay_station/flow.h
  5. 15 4
      relay_station/relay.c

+ 32 - 1
relay_station/crypto.c

@@ -477,6 +477,32 @@ int encrypt(flow *f, uint8_t *input, uint8_t *output, int32_t len, int32_t incom
 	return n;
 }
 
+
+/** Increases the GCM counter when we don't decrypt a record to produce the correct tag in the next
+ *  re-encrypted record
+ *
+ * 	Inputs:
+ * 		f: the tagged flow
+ * 		incoming: the direction of the flow
+ *
+ * 	Output:
+ * 		0 on success, 1 on failure
+ */
+int fake_encrypt(flow *f, int32_t incoming){
+
+	uint8_t *seq = (incoming) ? f->read_seq : f->write_seq;
+
+	for(int i=7; i>=0; i--){
+		++seq[i];
+		if(seq[i] != 0)
+			break;
+	}
+
+	return 0;
+
+}
+	
+
 /** Verifies the hash in a TLS finished message
  *
  * Adds string derived from the client-relay shared secret to the finished hash.
@@ -1299,6 +1325,11 @@ int super_encrypt(client *c, uint8_t *data, uint32_t len){
 
 	hdr_ctx = EVP_CIPHER_CTX_new();
 
+	if(c->header_key == NULL){
+		retval = 0;
+		goto end;
+	}
+
 	EVP_CipherInit_ex(hdr_ctx, EVP_aes_256_cbc(), NULL, c->header_key, NULL, 1);
 	
 	if(!EVP_CipherUpdate(hdr_ctx, p, &out_len, p, SLITHEEN_HEADER_LEN)){
@@ -1343,8 +1374,8 @@ int super_encrypt(client *c, uint8_t *data, uint32_t len){
 
 	if(!EVP_CipherUpdate(bdy_ctx, p, &out_len, p, len)){
 		printf("Failed!\n");
-		goto end;
 		retval = 0;
+		goto end;
 	}
 
 #ifdef DEBUG

+ 1 - 0
relay_station/crypto.h

@@ -13,6 +13,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, uint8_t re);
+int fake_encrypt(flow *f, int32_t incoming);
 int extract_server_random(flow *f, uint8_t *hs);
 int compute_master_secret(flow *f);
 

+ 58 - 27
relay_station/flow.c

@@ -81,12 +81,14 @@ flow *add_flow(struct packet_info *info) {
 
 	new_flow->streams=NULL;
 	new_flow->downstream_queue=NULL;
+	new_flow->client_ptr=NULL;
 
 	sem_init(&(new_flow->flow_lock), 0, 1);
 	new_flow->state = TLS_CLNT_HELLO;
 	new_flow->in_encrypted = 0;
 	new_flow->out_encrypted = 0;
 	new_flow->application = 0;
+	new_flow->stall = 0;
 	new_flow->resume_session = 0;
 	new_flow->current_session = NULL;
 
@@ -376,8 +378,6 @@ int update_flow(flow *f, uint8_t *record, uint8_t incoming) {
 					}
 
 					if((f->in_encrypted == 2) && (f->out_encrypted == 2)){
-						printf("Handshake complete!\n");
-						fflush(stdout);
 						f->application = 1;
 					}
 
@@ -398,7 +398,6 @@ int update_flow(flow *f, uint8_t *record, uint8_t incoming) {
 			/*Initialize ciphers */
 			if ((!f->in_encrypted) && (!f->out_encrypted)){
 				if(init_ciphers(f)){
-					fprintf(stderr, "Failed to initialize ciphers\n");
 					remove_flow(f);
 					goto err;
 				}
@@ -515,8 +514,8 @@ int remove_flow(flow *f) {
 		EC_KEY_free(f->ecdh);
 	}
 
-	if(f->resume_session == 1){
-		if(f->current_session->session_ticket != NULL){
+	if(f->current_session != NULL && f->resume_session == 1){
+		if( f->current_session->session_ticket != NULL){
 			free(f->current_session->session_ticket);
 		}
 		free(f->current_session);
@@ -565,8 +564,6 @@ int remove_flow(flow *f) {
 		table->first_entry = entry->next;
 		free(entry->f);
 		free(entry);
-		printf("flow removed!\n");
-		fflush(stdout);
 		table->len --;
 	} else {
 
@@ -583,7 +580,6 @@ int remove_flow(flow *f) {
 				entry->next = next->next;
 				free(next->f);
 				free(next);
-				printf("flow removed!\n");
 				table->len --;
 				break;
 			}
@@ -690,6 +686,9 @@ int init_session_cache(void){
  */
 int verify_session_id(flow *f, uint8_t *hs){
 	
+	if (f->current_session == NULL)
+		return 1;
+
 	//increment pointer to point to sessionid
 	uint8_t *p = hs + HANDSHAKE_HEADER_LEN;
 	p += 2; //skip version
@@ -699,7 +698,7 @@ int verify_session_id(flow *f, uint8_t *hs){
 	p ++;
 	
 	//check to see if it matches flow's session id set by ClientHello
-	if(f->current_session != NULL && f->current_session->session_id_len > 0 && !memcmp(f->current_session->session_id, p, id_len)){
+	if(f->current_session->session_id_len > 0 && !memcmp(f->current_session->session_id, p, id_len)){
 		//if it matched, update flow with master secret :D
 #ifdef DEBUG_HS
 		printf("Session id matched!\n");
@@ -724,25 +723,50 @@ int verify_session_id(flow *f, uint8_t *hs){
 		if((!found) && (f->current_session->session_ticket_len > 0)){
 			last = sessions->first_session;
 			for(int i=0; ((i<sessions->length) && (!found)); i++){
-				if(last->session_ticket_len == f->current_session->session_ticket_len){
-				if(!memcmp(last->session_ticket, f->current_session->session_ticket, f->current_session->session_ticket_len)){
-					memcpy(f->master_secret, last->master_secret, SSL3_MASTER_SECRET_SIZE);
-					found = 1;
-#ifdef DEBUG_HS
-					printf("Found new session ticket (%x:%d -> %x:%d)\n", f->src_ip.s_addr, f->src_port, f->dst_ip.s_addr, f->dst_port);
-					for(int i=0; i< last->session_ticket_len; i++){
-						printf("%02x ", last->session_ticket[i]);
+				if( (last->session_ticket != NULL) && (last->session_ticket_len == f->current_session->session_ticket_len)){
+					if(!memcmp(last->session_ticket, f->current_session->session_ticket, f->current_session->session_ticket_len)){
+						memcpy(f->master_secret, last->master_secret, SSL3_MASTER_SECRET_SIZE);
+						found = 1;
+	#ifdef DEBUG_HS
+						printf("Found new session ticket (%x:%d -> %x:%d)\n", f->src_ip.s_addr, f->src_port, f->dst_ip.s_addr, f->dst_port);
+						for(int i=0; i< last->session_ticket_len; i++){
+							printf("%02x ", last->session_ticket[i]);
+						}
+						printf("\n");
+	#endif
 					}
-					printf("\n");
-#endif
 				}
+				last = last->next;
+			}
+		}
+
+	} else if (f->current_session->session_id_len == 0){
+		//search for session ticket in session cache
+        printf("clnt session id was empty, looking for ticket\n");
+		session *last = sessions->first_session;
+		if(f->current_session->session_ticket_len > 0){
+			last = sessions->first_session;
+			for(int i=0; i<sessions->length; i++){
+				if(last->session_ticket_len == f->current_session->session_ticket_len){
+					if(!memcmp(last->session_ticket, f->current_session->session_ticket, f->current_session->session_ticket_len)){
+						memcpy(f->master_secret, last->master_secret, SSL3_MASTER_SECRET_SIZE);
+	#ifdef DEBUG_HS
+						printf("Found new session ticket (%x:%d -> %x:%d)\n", f->src_ip.s_addr, f->src_port, f->dst_ip.s_addr, f->dst_port);
+						for(int i=0; i< last->session_ticket_len; i++){
+							printf("%02x ", last->session_ticket[i]);
+						}
+						printf("\n");
+						break;
+	#endif
+					}
 				}
 				last = last->next;
 			}
 		}
 
-	} else if (f->current_session != NULL &&  f->current_session->session_id_len > 0){
-		//check to see if server's hello extension matches the ticket
+	} else if (f->current_session->session_id_len > 0){
+		//server refused resumption, save new session id
+        printf("session ids did not match, saving new id\n");
 		save_session_id(f, p);
 	}
 
@@ -770,6 +794,7 @@ int check_session(flow *f, uint8_t *hs, uint32_t len){
 	session *new_session = emalloc(sizeof(session));
 	new_session->session_id_len = (uint8_t) p[0];
 	new_session->session_ticket_len = 0;
+	new_session->session_ticket = NULL;
 	p  ++;
 
 	if(new_session->session_id_len > 0){
@@ -816,7 +841,7 @@ int check_session(flow *f, uint8_t *hs, uint32_t len){
 			if(ext_len > 0){
 				f->resume_session = 1;
 				new_session->session_ticket_len = ext_len;
-				new_session->session_ticket = emalloc(ext_len);
+				new_session->session_ticket = ecalloc(1, ext_len);
 				memcpy(new_session->session_ticket, p, ext_len);
 				f->current_session = new_session;
 			}
@@ -826,8 +851,8 @@ int check_session(flow *f, uint8_t *hs, uint32_t len){
 	}
 
 	if(!f->resume_session){
-		//see if a ticket is incuded
 		free(new_session);
+		f->stall = 0; //unstall the next packet
 	}
 
 	return 0;
@@ -854,7 +879,7 @@ int save_session_id(flow *f, uint8_t *hs){
 	session *new_session = emalloc(sizeof(session));
 
 	new_session->session_id_len = (uint8_t) p[0];
-	if(new_session->session_id_len <= 0){
+	if((new_session->session_id_len <= 0) || (new_session->session_id_len > SSL_MAX_SSL_SESSION_ID_LENGTH)){
 		//if this value is zero, the session is non-resumable or the
 		//server will issue a NewSessionTicket handshake message
 		free(new_session);
@@ -862,6 +887,8 @@ int save_session_id(flow *f, uint8_t *hs){
 	}
 	p++;
 	memcpy(new_session->session_id, p, new_session->session_id_len);
+    new_session->session_ticket_len = 0;
+	new_session->session_ticket = NULL;
 	new_session->next = NULL;
 
 	if(f->current_session != NULL){
@@ -892,6 +919,7 @@ int save_session_id(flow *f, uint8_t *hs){
 
 	sessions->length ++;
 
+#ifdef DEBUG_HS
 	printf("Saved session id:");
 	for(int i=0; i< new_session->session_id_len; i++){
 		printf(" %02x", new_session->session_id[i]);
@@ -900,6 +928,8 @@ int save_session_id(flow *f, uint8_t *hs){
 
 	printf("THERE ARE NOW %d saved sessions\n", sessions->length);
 
+#endif
+
 	return 0;
 
 }
@@ -929,6 +959,7 @@ int save_session_ticket(flow *f, uint8_t *hs, uint32_t len){
 	new_session->session_id_len = 0;
 	
 	new_session->session_ticket_len = (p[0] << 8) + p[1];
+    new_session->next = NULL;
 	p += 2;
 
 	uint8_t *ticket = emalloc(new_session->session_ticket_len);
@@ -969,10 +1000,10 @@ int save_session_ticket(flow *f, uint8_t *hs, uint32_t len){
 	printf("\n");
 	fflush(stdout);
 
-	printf("THERE ARE NOW %d saved sessions\n", sessions->length);
+	printf("THERE ARE NOW %d saved sessions (2)\n", sessions->length);
 	fflush(stdout);
-#endif
 
+#endif
 	return 0;
 }
 
@@ -1161,7 +1192,7 @@ int add_packet(flow *f, struct packet_info *info){
 		
 		} else {//
 			//add to end of packet_chain
-			printf("Missing packet (expected %d, received %d)\n", chain->expected_seq_num, new_packet->seq_num);
+			//printf("Missing packet (expected %d, received %d)\n", chain->expected_seq_num, new_packet->seq_num);
 		}
 	}
 	return 0;

+ 1 - 0
relay_station/flow.h

@@ -103,6 +103,7 @@ typedef struct flow_st {
 	int in_encrypted;		/* indicates whether incoming flow is encrypted */
 	int out_encrypted;		/* indicates whether outgoing flow is encrypted */
 	int application; /* indicates handshake is complete */
+	int stall; /* indicates the Finished message is expected and relay station should stall */
 	int resume_session;
 	stream_table *streams;
 	data_queue *downstream_queue;

+ 15 - 4
relay_station/relay.c

@@ -121,9 +121,7 @@ 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));
 
@@ -237,8 +235,6 @@ int read_header(flow *f, struct packet_info *info){
 
 	uint8_t *upstream_data;
 	if(header_ptr == NULL){
-		printf("Slitheen header not found(%x:%d > %x:%d) \n",info->ip_hdr->src.s_addr,info->tcp_hdr->src_port, info->ip_hdr->dst.s_addr, info->tcp_hdr->dst_port);
-		fflush(stdout);
 		if(record_ptr != NULL)
 			free(record_ptr);
 		free(decrypted_data);
@@ -352,6 +348,8 @@ int read_header(flow *f, struct packet_info *info){
 
 			if(f->streams == NULL){
 				//create new client
+
+				printf("Creating a new client\n");
 				client *new_client = emalloc(sizeof(client));
 
 				memcpy(new_client->slitheen_id, p, output_len);
@@ -900,9 +898,12 @@ int process_downstream(flow *f, int32_t offset, struct packet_info *info){
 		uint8_t *record_ptr = p; //points to the beginning of record data
 		uint32_t remaining_record_len = record_len;
 
+
 		if(record_len > remaining_packet_len){
+			int8_t increment_ctr = 1;
 			f->remaining_record_len = record_len - remaining_packet_len;
 
+
 			if(f->httpstate == PARSE_HEADER || f->httpstate == BEGIN_CHUNK || f->httpstate == END_CHUNK){
 				f->httpstate = FORFEIT_REST;
 			} else if( f->httpstate == MID_CONTENT || f->httpstate == MID_CHUNK){
@@ -925,6 +926,7 @@ int process_downstream(flow *f, int32_t offset, struct packet_info *info){
 						
 						memcpy(p, f->outbox, remaining_packet_len);
 						changed = 1;
+						increment_ctr = 0;
 						f->outbox_len -= remaining_packet_len;
 						f->outbox_offset += remaining_packet_len;
 					}
@@ -943,11 +945,17 @@ int process_downstream(flow *f, int32_t offset, struct packet_info *info){
 					f->httpstate = FORFEIT_REST;
 				}
 			}
+
+			if(increment_ctr){//not decrypting record, must increment GCM ctr
+				fake_encrypt(f, 1);
+			}
+
 			remaining_packet_len -= remaining_packet_len;
 			if(f->partial_record_header_len > 0){
 				f->partial_record_header_len = 0;
 				free(f->partial_record_header);
 			}
+
 			break;
 		}
 
@@ -1245,6 +1253,9 @@ 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;
 
+	if(client_ptr == NULL) return 1;
+
+
 	//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.