static void test_packet_id_write_short_wrap(void **state) { struct test_packet_id_write_data *data = *state; data->pis.id = ~0; assert_false(packet_id_write(&data->pis, &data->test_buf, false, false)); }
static void test_packet_id_write_short(void **state) { struct test_packet_id_write_data *data = *state; now = 5010; assert_true(packet_id_write(&data->pis, &data->test_buf, false, false)); assert_true(data->pis.id == 1); assert_true(data->test_buf_data.buf_id == htonl(1)); assert_true(data->test_buf_data.buf_time == 0); }
static void test_packet_id_write_short_prepend(void **state) { struct test_packet_id_write_data *data = *state; data->test_buf.offset = sizeof(packet_id_type); now = 5010; assert_true(packet_id_write(&data->pis, &data->test_buf, false, true)); assert_true(data->pis.id == 1); assert_true(data->test_buf_data.buf_id == htonl(1)); assert_true(data->test_buf_data.buf_time == 0); }
static void test_packet_id_write_long_wrap(void **state) { struct test_packet_id_write_data *data = *state; data->pis.id = ~0; data->pis.time = 5006; /* Write fails if time did not change */ now = 5006; assert_false(packet_id_write(&data->pis, &data->test_buf, true, false)); /* Write succeeds if time moved forward */ now = 5010; assert_true(packet_id_write(&data->pis, &data->test_buf, true, false)); assert(data->pis.id == 1); assert(data->pis.time == now); assert_true(data->test_buf_data.buf_id == htonl(1)); assert_true(data->test_buf_data.buf_time == htonl(now)); }
static void test_packet_id_write_long_prepend(void **state) { struct test_packet_id_write_data *data = *state; data->test_buf.offset = sizeof(data->test_buf_data); now = 5010; assert_true(packet_id_write(&data->pis, &data->test_buf, true, true)); assert(data->pis.id == 1); assert(data->pis.time == now); assert_true(data->test_buf_data.buf_id == htonl(1)); assert_true(data->test_buf_data.buf_time == htonl(now)); }
bool tls_crypt_wrap(const struct buffer *src, struct buffer *dst, struct crypto_options *opt) { const struct key_ctx *ctx = &opt->key_ctx_bi.encrypt; struct gc_arena gc; /* IV, packet-ID and implicit IV required for this mode. */ ASSERT(ctx->cipher); ASSERT(ctx->hmac); ASSERT(packet_id_initialized(&opt->packet_id)); ASSERT(hmac_ctx_size(ctx->hmac) == 256/8); gc_init(&gc); dmsg(D_PACKET_CONTENT, "TLS-CRYPT WRAP FROM: %s", format_hex(BPTR(src), BLEN(src), 80, &gc)); /* Get packet ID */ if (!packet_id_write(&opt->packet_id.send, dst, true, false)) { msg(D_CRYPT_ERRORS, "TLS-CRYPT ERROR: packet ID roll over."); goto err; } dmsg(D_PACKET_CONTENT, "TLS-CRYPT WRAP AD: %s", format_hex(BPTR(dst), BLEN(dst), 0, &gc)); /* Buffer overflow check */ if (!buf_safe(dst, BLEN(src) + TLS_CRYPT_BLOCK_SIZE + TLS_CRYPT_TAG_SIZE)) { msg(D_CRYPT_ERRORS, "TLS-CRYPT WRAP: buffer size error, " "sc=%d so=%d sl=%d dc=%d do=%d dl=%d", src->capacity, src->offset, src->len, dst->capacity, dst->offset, dst->len); goto err; } /* Calculate auth tag and synthetic IV */ { uint8_t *tag = NULL; hmac_ctx_reset(ctx->hmac); hmac_ctx_update(ctx->hmac, BPTR(dst), BLEN(dst)); hmac_ctx_update(ctx->hmac, BPTR(src), BLEN(src)); ASSERT(tag = buf_write_alloc(dst, TLS_CRYPT_TAG_SIZE)); hmac_ctx_final(ctx->hmac, tag); dmsg(D_PACKET_CONTENT, "TLS-CRYPT WRAP TAG: %s", format_hex(tag, TLS_CRYPT_TAG_SIZE, 0, &gc)); /* Use the 128 most significant bits of the tag as IV */ ASSERT(cipher_ctx_reset(ctx->cipher, tag)); } /* Encrypt src */ { int outlen = 0; ASSERT(cipher_ctx_update(ctx->cipher, BEND(dst), &outlen, BPTR(src), BLEN(src))); ASSERT(buf_inc_len(dst, outlen)); ASSERT(cipher_ctx_final(ctx->cipher, BPTR(dst), &outlen)); ASSERT(buf_inc_len(dst, outlen)); } dmsg(D_PACKET_CONTENT, "TLS-CRYPT WRAP TO: %s", format_hex(BPTR(dst), BLEN(dst), 80, &gc)); gc_free(&gc); return true; err: crypto_clear_error(); dst->len = 0; gc_free(&gc); return false; }
void openvpn_encrypt (struct buffer *buf, struct buffer work, const struct crypto_options *opt, const struct frame* frame) { struct gc_arena gc; gc_init (&gc); if (buf->len > 0 && opt->key_ctx_bi) { struct key_ctx *ctx = &opt->key_ctx_bi->encrypt; /* Do Encrypt from buf -> work */ if (ctx->cipher) { uint8_t iv_buf[OPENVPN_MAX_IV_LENGTH]; const int iv_size = cipher_ctx_iv_length (ctx->cipher); const cipher_kt_t *cipher_kt = cipher_ctx_get_cipher_kt (ctx->cipher); int outlen; if (cipher_kt_mode_cbc(cipher_kt)) { CLEAR (iv_buf); /* generate pseudo-random IV */ if (opt->flags & CO_USE_IV) prng_bytes (iv_buf, iv_size); /* Put packet ID in plaintext buffer or IV, depending on cipher mode */ if (opt->packet_id) { struct packet_id_net pin; packet_id_alloc_outgoing (&opt->packet_id->send, &pin, BOOL_CAST (opt->flags & CO_PACKET_ID_LONG_FORM)); ASSERT (packet_id_write (&pin, buf, BOOL_CAST (opt->flags & CO_PACKET_ID_LONG_FORM), true)); } } else if (cipher_kt_mode_ofb_cfb(cipher_kt)) { struct packet_id_net pin; struct buffer b; ASSERT (opt->flags & CO_USE_IV); /* IV and packet-ID required */ ASSERT (opt->packet_id); /* for this mode. */ packet_id_alloc_outgoing (&opt->packet_id->send, &pin, true); memset (iv_buf, 0, iv_size); buf_set_write (&b, iv_buf, iv_size); ASSERT (packet_id_write (&pin, &b, true, false)); } else /* We only support CBC, CFB, or OFB modes right now */ { ASSERT (0); } /* initialize work buffer with FRAME_HEADROOM bytes of prepend capacity */ ASSERT (buf_init (&work, FRAME_HEADROOM (frame))); /* set the IV pseudo-randomly */ if (opt->flags & CO_USE_IV) dmsg (D_PACKET_CONTENT, "ENCRYPT IV: %s", format_hex (iv_buf, iv_size, 0, &gc)); dmsg (D_PACKET_CONTENT, "ENCRYPT FROM: %s", format_hex (BPTR (buf), BLEN (buf), 80, &gc)); /* cipher_ctx was already initialized with key & keylen */ ASSERT (cipher_ctx_reset(ctx->cipher, iv_buf)); /* Buffer overflow check */ if (!buf_safe (&work, buf->len + cipher_ctx_block_size(ctx->cipher))) { msg (D_CRYPT_ERRORS, "ENCRYPT: buffer size error, bc=%d bo=%d bl=%d wc=%d wo=%d wl=%d cbs=%d", buf->capacity, buf->offset, buf->len, work.capacity, work.offset, work.len, cipher_ctx_block_size (ctx->cipher)); goto err; } /* Encrypt packet ID, payload */ ASSERT (cipher_ctx_update (ctx->cipher, BPTR (&work), &outlen, BPTR (buf), BLEN (buf))); ASSERT (buf_inc_len(&work, outlen)); /* Flush the encryption buffer */ ASSERT (cipher_ctx_final(ctx->cipher, BPTR (&work) + outlen, &outlen)); ASSERT (buf_inc_len(&work, outlen)); /* For all CBC mode ciphers, check the last block is complete */ ASSERT (cipher_kt_mode (cipher_kt) != OPENVPN_MODE_CBC || outlen == iv_size); /* prepend the IV to the ciphertext */ if (opt->flags & CO_USE_IV) { uint8_t *output = buf_prepend (&work, iv_size); ASSERT (output); memcpy (output, iv_buf, iv_size); } dmsg (D_PACKET_CONTENT, "ENCRYPT TO: %s", format_hex (BPTR (&work), BLEN (&work), 80, &gc)); } else /* No Encryption */ { if (opt->packet_id) { struct packet_id_net pin; packet_id_alloc_outgoing (&opt->packet_id->send, &pin, BOOL_CAST (opt->flags & CO_PACKET_ID_LONG_FORM)); ASSERT (packet_id_write (&pin, buf, BOOL_CAST (opt->flags & CO_PACKET_ID_LONG_FORM), true)); } work = *buf; } /* HMAC the ciphertext (or plaintext if !cipher) */ if (ctx->hmac) { uint8_t *output = NULL; hmac_ctx_reset (ctx->hmac); hmac_ctx_update (ctx->hmac, BPTR(&work), BLEN(&work)); output = buf_prepend (&work, hmac_ctx_size(ctx->hmac)); ASSERT (output); hmac_ctx_final (ctx->hmac, output); } *buf = work; } gc_free (&gc); return; err: crypto_clear_error(); buf->len = 0; gc_free (&gc); return; }