X-Git-Url: https://pd.if.org/git/?a=blobdiff_plain;f=crypto%2Fpacket_update.c;fp=crypto%2Fpacket_update.c;h=d3ec520eb8ea6e9df451c773dc01909f78379bff;hb=66bc25938679f1d6a1d1200f329093d82a5e99b4;hp=0000000000000000000000000000000000000000;hpb=a52ee0733f420ca20224049260d6fc5cf7d8f621;p=zpackage diff --git a/crypto/packet_update.c b/crypto/packet_update.c new file mode 100644 index 0000000..d3ec520 --- /dev/null +++ b/crypto/packet_update.c @@ -0,0 +1,276 @@ +#define _POSIX_C_SOURCE 200809L + +#include + +#include "tlse.h" + +#ifndef htonll +#define htonll(x) ((1==htonl(1)) ? (x) : ((uint64_t)htonl((x) & 0xFFFFFFFF) << 32) | htonl((x) >> 32)) +#endif + +#ifndef ntohll +#define ntohll(x) ((1==ntohl(1)) ? (x) : ((uint64_t)ntohl((x) & 0xFFFFFFFF) << 32) | ntohl((x) >> 32)) +#endif + +static int crypto_encrypt(struct TLSContext *context, unsigned char *buf, + unsigned char *ct, unsigned int len) { + if (context->crypto.created == 1) { + return cbc_encrypt(buf, ct, len, + &context->crypto.ctx_local.aes_local); + } + + memset(ct, 0, len); + return TLS_GENERIC_ERROR; +} + +static int packet_encrypt(struct TLSPacket *packet) { + int header_size = 5; + int block_size = TLS_AES_BLOCK_SIZE; + int mac_size = 0; + unsigned int length = 0; + unsigned char padding = 0; + //unsigned int pt_length = packet->len - header_size; + struct TLSContext *context = packet->context; + + mac_size = tls_mac_length(packet->context); + length = packet->len - header_size + TLS_AES_IV_LENGTH + mac_size; + + padding = block_size - length % block_size; + length += padding; + unsigned char *buf = malloc(length); + if (buf) { + unsigned char *ct = malloc(length + header_size); + if (ct) { + unsigned int buf_pos = 0; + memcpy(ct, packet->buf, header_size - 2); + *(unsigned short *)&ct[header_size - 2] = htons(length); + tls_random(buf, TLS_AES_IV_LENGTH); + buf_pos += TLS_AES_IV_LENGTH; + /* copy payload */ + memcpy(buf + buf_pos, packet-> buf + header_size, packet->len - header_size); + buf_pos += packet->len - header_size; + + tls_hmac_message(1, context, + packet->buf, + packet->len, NULL, 0, + buf + buf_pos, + mac_size); + buf_pos += mac_size; + + memset(buf + buf_pos, padding - 1, padding); + buf_pos += padding; + + crypto_encrypt(context, buf, ct + header_size, length); + free(packet->buf); + packet->buf = ct; + packet->len = length + header_size; + packet->size = packet->len; + } else { + /* invalidate packet */ + memset (packet->buf, 0, packet-> len); + } + free(buf); + } else { + /* invalidate packet */ + memset(packet->buf, 0, packet->len); + } + + return 1; +} + +static void put16(unsigned char *at, uint16_t val) { + at[0] = val >> 8; + at[1] = val & 0xff; +} + +void tls_packet_update(struct TLSPacket *packet) { + struct TLSContext *context; + unsigned int header_size = 5; + int footer_size = 0; + uint16_t real_packet_len; + uint64_t lsn; + int mac_size = 0; + unsigned int length = 0; + int context_is_v13 = 0; + struct tls_buffer ciphertext; + + if (!packet || packet->broken) { + return; + } + + if (packet->context && packet->context->tlsver == TLS_VERSION13 + && packet->context->cipher_spec_set + && packet->context->crypto.created) { + /* type */ + tls_packet_uint8(packet, packet->buf[0]); + /* no padding + * tls_packet_uint8(packet, 0); + */ + footer_size = 1; + } + + real_packet_len = packet->len - header_size; + + put16(packet->buf + 3, real_packet_len); + + if (!packet->context) { + return; + } + + context = packet->context; + lsn = context->local_sequence_number; + + if (context->tlsver == TLS_VERSION13) { + context_is_v13 = 1; + } + + if (packet->buf[0] == TLS_CHANGE_CIPHER) { + context->local_sequence_number++; + return; + } + + /* If this is a handshake message, update the handshake hash */ + if (packet->buf[0] == TLS_HANDSHAKE && packet->len > header_size) { + unsigned char handshake_type = packet->buf[header_size]; + if (handshake_type != 0x00 && handshake_type != 0x03) { + tls_update_hash(context, packet->buf + header_size, + real_packet_len - + footer_size); + } + } + + if (!context->cipher_spec_set || !context->crypto.created) { + context->local_sequence_number++; + return; + } + + unsigned int pt_length = real_packet_len; + + if (context->crypto.created == 1) { + } else if (context->crypto.created == 3) { + mac_size = POLY1305_TAGLEN; + length = real_packet_len + mac_size; + } else { + mac_size = TLS_GCM_TAG_LEN; + length = real_packet_len + 8 + mac_size; + } + + if (context->crypto.created == 1) { + packet_encrypt(packet); + context->local_sequence_number++; + return; + } + + if (context->crypto.created < 1) { + /* invalidate packet */ + memset(packet->buf, 0, packet->len); + context->local_sequence_number++; + return; + } + + /* + 1 = type */ + int ct_size = length + header_size + 12 + TLS_MAX_TAG_LEN + 1; + tls_buffer_init(&ciphertext, ct_size); + + if (ciphertext.error) { + /* invalidate packet */ + memset(packet->buf, 0, packet->len); + context->local_sequence_number++; + return; + } + + /* AEAD */ + /* sequence number (8 bytes) */ + /* content type (1 byte) */ + /* version (2 bytes) */ + /* length (2 bytes) */ + unsigned char aad[13]; + int aad_size = sizeof(aad); + unsigned char *sequence = aad; + if (context_is_v13) { + aad[0] = TLS_APPLICATION_DATA; + aad[1] = packet->buf[1]; + aad[2] = packet->buf[2]; + if (packet->context->crypto.created == 3) { + put16(aad+3, real_packet_len + POLY1305_TAGLEN); + } else { + put16(aad+3, real_packet_len + TLS_GCM_TAG_LEN); + } + aad_size = 5; + sequence = aad + 5; + + *((uint64_t *) (aad+5)) = htonll(lsn); + + } else { + *((uint64_t *) aad) = htonll(lsn); + aad[8] = packet->buf[0]; + aad[9] = packet->buf[1]; + aad[10] = packet->buf[2]; + put16(aad+11, packet->len - header_size); + } + + ciphertext.len = header_size; + + if (context->crypto.created == 3) { + int size; + unsigned int counter = 1; + unsigned char poly1305_key[POLY1305_KEYLEN]; + chacha_ivupdate(&context->crypto.ctx_local.chacha_local, + context->crypto.ctx_local_mac.local_aead_iv, + sequence, (uint8_t *) &counter); + chacha20_poly1305_key(&context->crypto.ctx_local.chacha_local, + poly1305_key); + size = + chacha20_poly1305_aead(&context->crypto.ctx_local.chacha_local, + packet->buf + header_size, pt_length, + aad, aad_size, poly1305_key, + ciphertext.buffer + ciphertext.len); + ciphertext.len += size; + } else { + unsigned char iv [TLS_13_AES_GCM_IV_LENGTH]; + if (context_is_v13) { + memcpy(iv, context->crypto.ctx_local_mac.local_iv, + TLS_13_AES_GCM_IV_LENGTH); + int i; + int offset = TLS_13_AES_GCM_IV_LENGTH - 8; + for (i = 0; i < 8; i++) + iv[offset + i] = context->crypto.ctx_local_mac.local_iv[offset + i] ^ sequence[i]; + } else { + memcpy(iv, context->crypto.ctx_local_mac.local_aead_iv, + TLS_AES_GCM_IV_LENGTH); + tls_random(iv + TLS_AES_GCM_IV_LENGTH, 8); + tls_buffer_append(&ciphertext, + iv+TLS_AES_GCM_IV_LENGTH, 8); + } + + gcm_state *localgcm; + localgcm = &context->crypto.ctx_local.aes_gcm_local; + + gcm_reset(localgcm); + gcm_add_iv(localgcm, iv, 12); + gcm_add_aad(localgcm, aad, aad_size); + gcm_process(localgcm, packet->buf + header_size, pt_length, + ciphertext.buffer+ciphertext.len, GCM_ENCRYPT); + ciphertext.len += pt_length; + + unsigned long taglen = TLS_GCM_TAG_LEN; + gcm_done(localgcm, ciphertext.buffer+ciphertext.len, &taglen); + ciphertext.len += taglen; + } + + if (context_is_v13) { + ciphertext.buffer[0] = TLS_APPLICATION_DATA; + tls_buffer_write16(&ciphertext, TLS_V12, 1); + } else { + memcpy(ciphertext.buffer, packet->buf, header_size - 2); + } + + tls_buffer_write16(&ciphertext, ciphertext.len - header_size, header_size - 2); + + free(packet->buf); + packet->buf = ciphertext.buffer; + packet->len = ciphertext.len; + packet->size = ciphertext.size; + + context->local_sequence_number++; +}