void handle_packet(const u_char *packet, int length) { static int n = 0; static unsigned char initial_hello[] = { 0x16, 0xfe, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; uint8 *data; size_t data_length, rlen; int i, res; #if DTLS_VERSION == 0xfeff #ifndef SHA1_DIGEST_LENGTH #define SHA1_DIGEST_LENGTH 20 #endif uint8 hash_buf[16 + SHA1_DIGEST_LENGTH]; #elif DTLS_VERSION == 0xfefd uint8 hash_buf[DTLS_SHA256_DIGEST_LENGTH]; #endif #define verify_data_length 12 int is_client; n++; SKIP_ETH_HEADER(packet, length); SKIP_IP_HEADER(packet, length); /* determine from port if this is a client */ is_client = dtls_uint16_to_int(packet) != 20220; SKIP_UDP_HEADER(packet, length); while (length) { rlen = dtls_uint16_to_int(packet + 11) + sizeof(dtls_record_header_t); if (!rlen) { fprintf(stderr, "invalid length!\n"); return; } /* skip packet if it is from a different epoch */ if (dtls_uint16_to_int(packet + 3) != epoch[is_client]) goto next; res = decrypt_verify(is_client, packet, rlen, &data, &data_length); if (res <= 0) goto next; printf("packet %d (from %s):\n", n, is_client ? "client" : "server"); hexdump(packet, sizeof(dtls_record_header_t)); printf("\n"); hexdump(data, data_length); printf("\n"); if (packet[0] == 22 && data[0] == 1) { /* ClientHello */ if (memcmp(packet, initial_hello, sizeof(initial_hello)) == 0) goto next; memcpy(dtls_kb_client_iv(OTHER_CONFIG), data + 14, 32); clear_hash(); #if DTLS_VERSION == 0xfeff hs_hash[0] = dtls_new_hash(HASH_MD5); hs_hash[1] = dtls_new_hash(HASH_SHA1); hs_hash[0]->init(hs_hash[0]->data); hs_hash[1]->init(hs_hash[1]->data); #elif DTLS_VERSION == 0xfefd dtls_hash_init(hs_hash[0]); #endif } if (packet[0] == 22 && data[0] == 2) { /* ServerHello */ memcpy(dtls_kb_server_iv(OTHER_CONFIG), data + 14, 32); /* FIXME: search in ciphers */ OTHER_CONFIG->cipher = TLS_PSK_WITH_AES_128_CCM_8; } if (packet[0] == 20 && data[0] == 1) { /* ChangeCipherSpec */ printf("client random: "); dump(dtls_kb_client_iv(OTHER_CONFIG), 32); printf("\nserver random: "); dump(dtls_kb_server_iv(OTHER_CONFIG), 32); printf("\n"); master_secret_len = dtls_prf(pre_master_secret, pre_master_len, (unsigned char *)"master secret", 13, dtls_kb_client_iv(OTHER_CONFIG), 32, dtls_kb_server_iv(OTHER_CONFIG), 32, master_secret, DTLS_MASTER_SECRET_LENGTH); printf("master_secret:\n "); for(i = 0; i < master_secret_len; i++) printf("%02x", master_secret[i]); printf("\n"); /* create key_block from master_secret * key_block = PRF(master_secret, "key expansion" + server_random + client_random) */ dtls_prf(master_secret, master_secret_len, (unsigned char *)"key expansion", 13, dtls_kb_server_iv(OTHER_CONFIG), 32, dtls_kb_client_iv(OTHER_CONFIG), 32, OTHER_CONFIG->key_block, dtls_kb_size(OTHER_CONFIG)); OTHER_CONFIG->read_cipher = dtls_cipher_new(OTHER_CONFIG->cipher, dtls_kb_client_write_key(OTHER_CONFIG), dtls_kb_key_size(OTHER_CONFIG)); if (!OTHER_CONFIG->read_cipher) { warn("cannot create read cipher\n"); } else { dtls_cipher_set_iv(OTHER_CONFIG->read_cipher, dtls_kb_client_iv(OTHER_CONFIG), dtls_kb_iv_size(OTHER_CONFIG)); } OTHER_CONFIG->write_cipher = dtls_cipher_new(OTHER_CONFIG->cipher, dtls_kb_server_write_key(OTHER_CONFIG), dtls_kb_key_size(OTHER_CONFIG)); if (!OTHER_CONFIG->write_cipher) { warn("cannot create write cipher\n"); } else { dtls_cipher_set_iv(OTHER_CONFIG->write_cipher, dtls_kb_server_iv(OTHER_CONFIG), dtls_kb_iv_size(OTHER_CONFIG)); } /* if (is_client) */ SWITCH_CONFIG; epoch[is_client]++; printf("key_block:\n"); printf(" client_MAC_secret:\t"); dump(dtls_kb_client_mac_secret(CURRENT_CONFIG), dtls_kb_mac_secret_size(CURRENT_CONFIG)); printf("\n"); printf(" server_MAC_secret:\t"); dump(dtls_kb_server_mac_secret(CURRENT_CONFIG), dtls_kb_mac_secret_size(CURRENT_CONFIG)); printf("\n"); printf(" client_write_key:\t"); dump(dtls_kb_client_write_key(CURRENT_CONFIG), dtls_kb_key_size(CURRENT_CONFIG)); printf("\n"); printf(" server_write_key:\t"); dump(dtls_kb_server_write_key(CURRENT_CONFIG), dtls_kb_key_size(CURRENT_CONFIG)); printf("\n"); printf(" client_IV:\t\t"); dump(dtls_kb_client_iv(CURRENT_CONFIG), dtls_kb_iv_size(CURRENT_CONFIG)); printf("\n"); printf(" server_IV:\t\t"); dump(dtls_kb_server_iv(CURRENT_CONFIG), dtls_kb_iv_size(CURRENT_CONFIG)); printf("\n"); } if (packet[0] == 22) { if (data[0] == 20) { /* Finished */ finalize_hash(hash_buf); /* clear_hash(); */ update_hash((unsigned char *)packet, sizeof(dtls_record_header_t), data, data_length); dtls_prf(master_secret, master_secret_len, is_client ? (unsigned char *)"client finished" : (unsigned char *)"server finished" , 15, hash_buf, sizeof(hash_buf), NULL, 0, data + sizeof(dtls_handshake_header_t), verify_data_length); printf("verify_data:\n"); dump(data, data_length); printf("\n"); } else { update_hash((unsigned char *)packet, sizeof(dtls_record_header_t), data, data_length); } } if (packet[0] == 23) { /* Application Data */ printf("Application Data:\n"); dump(data, data_length); printf("\n"); } next: length -= rlen; packet += rlen; } }
static int handle_data (int sock, struct allnet_header * hp, char * data, int dsize, char ** contact, keyset * kset, char ** message, char ** desc, int * verified, time_t * sent, int * duplicate, int * broadcast) { int verif = 0; char * text = NULL; int tsize = decrypt_verify (hp->sig_algo, data, dsize, contact, kset, &text, (char *) (hp->source), hp->src_nbits, (char *) (hp->destination), hp->dst_nbits, 0); if (tsize < 0) { printf ("no signature to verify, but decrypted from %s\n", *contact); tsize = -tsize; } else if (tsize > 0) { verif = 1; } if (tsize < CHAT_DESCRIPTOR_SIZE) { #ifdef DEBUG_PRINT printf ("decrypted packet has size %d, min is %zd, dropping\n", tsize, CHAT_DESCRIPTOR_SIZE); #endif /* DEBUG_PRINT */ return 0; } if (*contact == NULL) { #ifdef DEBUG_PRINT printf ("contact not known\n"); #endif /* DEBUG_PRINT */ if (text != NULL) free (text); return 0; } #ifdef DEBUG_PRINT printf ("got packet from contact %s\n", *contact); #endif /* DEBUG_PRINT */ struct chat_descriptor * cdp = (struct chat_descriptor *) text; int app = readb32u (cdp->app_media.app); if (app != XCHAT_ALLNET_APP_ID) { #ifdef DEBUG_PRINT printf ("handle_data ignoring unknown app %08x\n", app); print_buffer (text, CHAT_DESCRIPTOR_SIZE, "chat descriptor", 100, 1); #endif /* DEBUG_PRINT */ return 0; } int media = readb32u (cdp->app_media.media); if ((media != ALLNET_MEDIA_TEXT_PLAIN) && (media != ALLNET_MEDIA_PUBLIC_KEY)) { #ifdef DEBUG_PRINT printf ("handle_data ignoring media type %08x\n", media); print_buffer (text, CHAT_DESCRIPTOR_SIZE, "chat descriptor", 100, 1); #endif /* DEBUG_PRINT */ return 0; } char * cleartext = text + CHAT_DESCRIPTOR_SIZE; int msize = tsize - CHAT_DESCRIPTOR_SIZE; long long int seq = readb64u (cdp->counter); if (seq == COUNTER_FLAG) { do_chat_control (*contact, *kset, text, tsize, sock, hp->hops + 4); send_ack (sock, hp, cdp->message_ack, verif, *contact, *kset); if (*contact != NULL) { free (*contact); *contact = NULL; } if (text != NULL) free (text); return 0; } *broadcast = 0; *duplicate = 0; if (was_received (*contact, *kset, seq)) *duplicate = 1; save_incoming (*contact, *kset, cdp, cleartext, msize); if (media == ALLNET_MEDIA_PUBLIC_KEY) { cleartext = "received a key for an additional device"; msize = strlen (cleartext); } *desc = chat_descriptor_to_string (cdp, 0, 0); *verified = verif; if (sent != NULL) *sent = (readb64u (cdp->timestamp) >> 16) & 0xffffffff; *message = malloc_or_fail (msize + 1, "handle_data message"); memcpy (*message, cleartext, msize); (*message) [msize] = '\0'; /* null-terminate the message */ /* printf ("hp->hops = %d\n", hp->hops); */ send_ack (sock, hp, cdp->message_ack, verif, *contact, *kset); free (text); return msize; }