summaryrefslogtreecommitdiff
path: root/src/openvpn/crypto.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/openvpn/crypto.c')
-rw-r--r--src/openvpn/crypto.c2560
1 files changed, 1358 insertions, 1202 deletions
diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c
index 708cc92..7119abc 100644
--- a/src/openvpn/crypto.c
+++ b/src/openvpn/crypto.c
@@ -5,8 +5,8 @@
* packet encryption, packet authentication, and
* packet compression.
*
- * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
- * Copyright (C) 2010-2016 Fox Crypto B.V. <openvpn@fox-it.com>
+ * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net>
+ * Copyright (C) 2010-2017 Fox Crypto B.V. <openvpn@fox-it.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
@@ -64,284 +64,294 @@
*/
static void
-openvpn_encrypt_aead (struct buffer *buf, struct buffer work,
- struct crypto_options *opt) {
+openvpn_encrypt_aead(struct buffer *buf, struct buffer work,
+ struct crypto_options *opt) {
#ifdef HAVE_AEAD_CIPHER_MODES
- struct gc_arena gc;
- int outlen = 0;
- const struct key_ctx *ctx = &opt->key_ctx_bi.encrypt;
- uint8_t *mac_out = NULL;
- const cipher_kt_t *cipher_kt = cipher_ctx_get_cipher_kt (ctx->cipher);
- const int mac_len = cipher_kt_tag_size (cipher_kt);
-
- /* IV, packet-ID and implicit IV required for this mode. */
- ASSERT (ctx->cipher);
- ASSERT (cipher_kt_mode_aead (cipher_kt));
- ASSERT (opt->flags & CO_USE_IV);
- ASSERT (packet_id_initialized(&opt->packet_id));
-
- gc_init (&gc);
-
- /* Prepare IV */
- {
- struct buffer iv_buffer;
- struct packet_id_net pin;
- uint8_t iv[OPENVPN_MAX_IV_LENGTH] = {0};
- const int iv_len = cipher_ctx_iv_length (ctx->cipher);
+ struct gc_arena gc;
+ int outlen = 0;
+ const struct key_ctx *ctx = &opt->key_ctx_bi.encrypt;
+ uint8_t *mac_out = NULL;
+ const cipher_kt_t *cipher_kt = cipher_ctx_get_cipher_kt(ctx->cipher);
+ const int mac_len = cipher_kt_tag_size(cipher_kt);
+
+ /* IV, packet-ID and implicit IV required for this mode. */
+ ASSERT(ctx->cipher);
+ ASSERT(cipher_kt_mode_aead(cipher_kt));
+ ASSERT(opt->flags & CO_USE_IV);
+ ASSERT(packet_id_initialized(&opt->packet_id));
+
+ gc_init(&gc);
+
+ /* Prepare IV */
+ {
+ struct buffer iv_buffer;
+ struct packet_id_net pin;
+ uint8_t iv[OPENVPN_MAX_IV_LENGTH] = {0};
+ const int iv_len = cipher_ctx_iv_length(ctx->cipher);
- ASSERT (iv_len >= OPENVPN_AEAD_MIN_IV_LEN && iv_len <= OPENVPN_MAX_IV_LENGTH);
+ ASSERT(iv_len >= OPENVPN_AEAD_MIN_IV_LEN && iv_len <= OPENVPN_MAX_IV_LENGTH);
- buf_set_write (&iv_buffer, iv, iv_len);
+ buf_set_write(&iv_buffer, iv, iv_len);
- /* IV starts with packet id to make the IV unique for packet */
- packet_id_alloc_outgoing (&opt->packet_id.send, &pin, false);
- ASSERT (packet_id_write (&pin, &iv_buffer, false, false));
+ /* IV starts with packet id to make the IV unique for packet */
+ packet_id_alloc_outgoing(&opt->packet_id.send, &pin, false);
+ ASSERT(packet_id_write(&pin, &iv_buffer, false, false));
- /* Remainder of IV consists of implicit part (unique per session) */
- ASSERT (buf_write (&iv_buffer, ctx->implicit_iv, ctx->implicit_iv_len));
- ASSERT (iv_buffer.len == iv_len);
+ /* Remainder of IV consists of implicit part (unique per session) */
+ ASSERT(buf_write(&iv_buffer, ctx->implicit_iv, ctx->implicit_iv_len));
+ ASSERT(iv_buffer.len == iv_len);
- /* Write explicit part of IV to work buffer */
- ASSERT (buf_write(&work, iv, iv_len - ctx->implicit_iv_len));
- dmsg (D_PACKET_CONTENT, "ENCRYPT IV: %s", format_hex (iv, iv_len, 0, &gc));
+ /* Write explicit part of IV to work buffer */
+ ASSERT(buf_write(&work, iv, iv_len - ctx->implicit_iv_len));
+ dmsg(D_PACKET_CONTENT, "ENCRYPT IV: %s", format_hex(iv, iv_len, 0, &gc));
- /* Init cipher_ctx with IV. key & keylen are already initialized */
- ASSERT (cipher_ctx_reset(ctx->cipher, iv));
- }
+ /* Init cipher_ctx with IV. key & keylen are already initialized */
+ ASSERT(cipher_ctx_reset(ctx->cipher, iv));
+ }
- /* Reserve space for authentication tag */
- mac_out = buf_write_alloc (&work, mac_len);
- ASSERT (mac_out);
+ /* Reserve space for authentication tag */
+ mac_out = buf_write_alloc(&work, mac_len);
+ ASSERT(mac_out);
- dmsg (D_PACKET_CONTENT, "ENCRYPT FROM: %s", format_hex (BPTR (buf), BLEN (buf), 80, &gc));
+ dmsg(D_PACKET_CONTENT, "ENCRYPT FROM: %s", format_hex(BPTR(buf), BLEN(buf), 80, &gc));
- /* Buffer overflow check */
- if (!buf_safe (&work, buf->len + cipher_ctx_block_size(ctx->cipher)))
+ /* 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",
- buf->capacity, buf->offset, buf->len, work.capacity, work.offset,
- work.len);
- goto err;
+ msg(D_CRYPT_ERRORS,
+ "ENCRYPT: buffer size error, bc=%d bo=%d bl=%d wc=%d wo=%d wl=%d",
+ buf->capacity, buf->offset, buf->len, work.capacity, work.offset,
+ work.len);
+ goto err;
}
- /* For AEAD ciphers, authenticate Additional Data, including opcode */
- ASSERT (cipher_ctx_update_ad (ctx->cipher, BPTR (&work), BLEN (&work) - mac_len));
- dmsg (D_PACKET_CONTENT, "ENCRYPT AD: %s",
- format_hex (BPTR (&work), BLEN (&work) - mac_len, 0, &gc));
+ /* For AEAD ciphers, authenticate Additional Data, including opcode */
+ ASSERT(cipher_ctx_update_ad(ctx->cipher, BPTR(&work), BLEN(&work) - mac_len));
+ dmsg(D_PACKET_CONTENT, "ENCRYPT AD: %s",
+ format_hex(BPTR(&work), BLEN(&work) - mac_len, 0, &gc));
- /* Encrypt packet ID, payload */
- ASSERT (cipher_ctx_update (ctx->cipher, BEND (&work), &outlen, BPTR (buf), BLEN (buf)));
- ASSERT (buf_inc_len (&work, outlen));
+ /* Encrypt packet ID, payload */
+ ASSERT(cipher_ctx_update(ctx->cipher, BEND(&work), &outlen, BPTR(buf), BLEN(buf)));
+ ASSERT(buf_inc_len(&work, outlen));
- /* Flush the encryption buffer */
- ASSERT (cipher_ctx_final (ctx->cipher, BEND (&work), &outlen));
- ASSERT (buf_inc_len (&work, outlen));
+ /* Flush the encryption buffer */
+ ASSERT(cipher_ctx_final(ctx->cipher, BEND(&work), &outlen));
+ ASSERT(buf_inc_len(&work, outlen));
- /* Write authentication tag */
- ASSERT (cipher_ctx_get_tag (ctx->cipher, mac_out, mac_len));
+ /* Write authentication tag */
+ ASSERT(cipher_ctx_get_tag(ctx->cipher, mac_out, mac_len));
- *buf = work;
+ *buf = work;
- dmsg (D_PACKET_CONTENT, "ENCRYPT TO: %s", format_hex (BPTR (buf), BLEN (buf), 80, &gc));
+ dmsg(D_PACKET_CONTENT, "ENCRYPT TO: %s", format_hex(BPTR(buf), BLEN(buf), 80, &gc));
- gc_free (&gc);
- return;
+ gc_free(&gc);
+ return;
err:
- crypto_clear_error();
- buf->len = 0;
- gc_free (&gc);
- return;
+ crypto_clear_error();
+ buf->len = 0;
+ gc_free(&gc);
+ return;
#else /* HAVE_AEAD_CIPHER_MODES */
- ASSERT (0);
-#endif
+ ASSERT(0);
+#endif /* ifdef HAVE_AEAD_CIPHER_MODES */
}
static void
-openvpn_encrypt_v1 (struct buffer *buf, struct buffer work,
- struct crypto_options *opt)
+openvpn_encrypt_v1(struct buffer *buf, struct buffer work,
+ struct crypto_options *opt)
{
- struct gc_arena gc;
- gc_init (&gc);
-
- if (buf->len > 0 && opt)
- {
- const struct key_ctx *ctx = &opt->key_ctx_bi.encrypt;
- uint8_t *mac_out = NULL;
- const uint8_t *hmac_start = NULL;
-
- /* Do Encrypt from buf -> work */
- if (ctx->cipher)
- {
- uint8_t iv_buf[OPENVPN_MAX_IV_LENGTH] = {0};
- 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;
-
- /* Reserve space for HMAC */
- if (ctx->hmac)
- {
- mac_out = buf_write_alloc (&work, hmac_ctx_size(ctx->hmac));
- ASSERT (mac_out);
- hmac_start = BEND(&work);
- }
-
- if (cipher_kt_mode_cbc(cipher_kt))
- {
- /* generate pseudo-random IV */
- if (opt->flags & CO_USE_IV)
- prng_bytes (iv_buf, iv_size);
-
- /* Put packet ID in plaintext buffer */
- if (packet_id_initialized(&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;
-
- /* IV and packet-ID required for this mode. */
- ASSERT (opt->flags & CO_USE_IV);
- ASSERT (packet_id_initialized(&opt->packet_id));
-
- packet_id_alloc_outgoing (&opt->packet_id.send, &pin, true);
- 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);
- }
-
- /* set the IV pseudo-randomly */
- if (opt->flags & CO_USE_IV)
+ struct gc_arena gc;
+ gc_init(&gc);
+
+ if (buf->len > 0 && opt)
+ {
+ const struct key_ctx *ctx = &opt->key_ctx_bi.encrypt;
+ uint8_t *mac_out = NULL;
+ const uint8_t *hmac_start = NULL;
+
+ /* Do Encrypt from buf -> work */
+ if (ctx->cipher)
+ {
+ uint8_t iv_buf[OPENVPN_MAX_IV_LENGTH] = {0};
+ 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;
+
+ /* Reserve space for HMAC */
+ if (ctx->hmac)
{
- ASSERT (buf_write(&work, iv_buf, iv_size));
- dmsg (D_PACKET_CONTENT, "ENCRYPT IV: %s", format_hex (iv_buf, iv_size, 0, &gc));
+ mac_out = buf_write_alloc(&work, hmac_ctx_size(ctx->hmac));
+ ASSERT(mac_out);
+ hmac_start = BEND(&work);
}
- 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, BEND (&work), &outlen, BPTR (buf), BLEN (buf)));
- ASSERT (buf_inc_len(&work, outlen));
-
- /* Flush the encryption buffer */
- ASSERT (cipher_ctx_final(ctx->cipher, BEND (&work), &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);
- }
- else /* No Encryption */
- {
- if (packet_id_initialized(&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));
- }
- if (ctx->hmac)
- {
- hmac_start = BPTR(buf);
- ASSERT (mac_out = buf_prepend (buf, hmac_ctx_size(ctx->hmac)));
- }
- if (BLEN(&work)) {
- buf_write_prepend(buf, BPTR(&work), BLEN(&work));
- }
- work = *buf;
- }
-
- /* HMAC the ciphertext (or plaintext if !cipher) */
- if (ctx->hmac)
- {
- hmac_ctx_reset (ctx->hmac);
- hmac_ctx_update (ctx->hmac, hmac_start, BEND(&work) - hmac_start);
- hmac_ctx_final (ctx->hmac, mac_out);
- dmsg (D_PACKET_CONTENT, "ENCRYPT HMAC: %s",
- format_hex (mac_out, hmac_ctx_size(ctx->hmac), 80, &gc));
- }
-
- *buf = work;
-
- dmsg (D_PACKET_CONTENT, "ENCRYPT TO: %s",
- format_hex (BPTR (&work), BLEN (&work), 80, &gc));
- }
-
- gc_free (&gc);
- return;
+ if (cipher_kt_mode_cbc(cipher_kt))
+ {
+ /* generate pseudo-random IV */
+ if (opt->flags & CO_USE_IV)
+ {
+ prng_bytes(iv_buf, iv_size);
+ }
+
+ /* Put packet ID in plaintext buffer */
+ if (packet_id_initialized(&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;
+
+ /* IV and packet-ID required for this mode. */
+ ASSERT(opt->flags & CO_USE_IV);
+ ASSERT(packet_id_initialized(&opt->packet_id));
+
+ packet_id_alloc_outgoing(&opt->packet_id.send, &pin, true);
+ 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);
+ }
+
+ /* set the IV pseudo-randomly */
+ if (opt->flags & CO_USE_IV)
+ {
+ ASSERT(buf_write(&work, iv_buf, iv_size));
+ 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, BEND(&work), &outlen, BPTR(buf), BLEN(buf)));
+ ASSERT(buf_inc_len(&work, outlen));
+
+ /* Flush the encryption buffer */
+ ASSERT(cipher_ctx_final(ctx->cipher, BEND(&work), &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);
+ }
+ else /* No Encryption */
+ {
+ if (packet_id_initialized(&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));
+ }
+ if (ctx->hmac)
+ {
+ hmac_start = BPTR(buf);
+ ASSERT(mac_out = buf_prepend(buf, hmac_ctx_size(ctx->hmac)));
+ }
+ if (BLEN(&work))
+ {
+ buf_write_prepend(buf, BPTR(&work), BLEN(&work));
+ }
+ work = *buf;
+ }
+
+ /* HMAC the ciphertext (or plaintext if !cipher) */
+ if (ctx->hmac)
+ {
+ hmac_ctx_reset(ctx->hmac);
+ hmac_ctx_update(ctx->hmac, hmac_start, BEND(&work) - hmac_start);
+ hmac_ctx_final(ctx->hmac, mac_out);
+ dmsg(D_PACKET_CONTENT, "ENCRYPT HMAC: %s",
+ format_hex(mac_out, hmac_ctx_size(ctx->hmac), 80, &gc));
+ }
+
+ *buf = work;
+
+ dmsg(D_PACKET_CONTENT, "ENCRYPT TO: %s",
+ format_hex(BPTR(&work), BLEN(&work), 80, &gc));
+ }
+
+ gc_free(&gc);
+ return;
err:
- crypto_clear_error();
- buf->len = 0;
- gc_free (&gc);
- return;
+ crypto_clear_error();
+ buf->len = 0;
+ gc_free(&gc);
+ return;
}
void
-openvpn_encrypt (struct buffer *buf, struct buffer work,
- struct crypto_options *opt)
+openvpn_encrypt(struct buffer *buf, struct buffer work,
+ struct crypto_options *opt)
{
- if (buf->len > 0 && opt)
+ if (buf->len > 0 && opt)
{
- const cipher_kt_t *cipher_kt =
- cipher_ctx_get_cipher_kt(opt->key_ctx_bi.encrypt.cipher);
-
- if (cipher_kt_mode_aead (cipher_kt))
- openvpn_encrypt_aead(buf, work, opt);
- else
- openvpn_encrypt_v1(buf, work, opt);
+ const cipher_kt_t *cipher_kt =
+ cipher_ctx_get_cipher_kt(opt->key_ctx_bi.encrypt.cipher);
+
+ if (cipher_kt_mode_aead(cipher_kt))
+ {
+ openvpn_encrypt_aead(buf, work, opt);
+ }
+ else
+ {
+ openvpn_encrypt_v1(buf, work, opt);
+ }
}
}
-bool crypto_check_replay(struct crypto_options *opt,
- const struct packet_id_net *pin, const char *error_prefix,
- struct gc_arena *gc) {
- bool ret = false;
- packet_id_reap_test (&opt->packet_id.rec);
- if (packet_id_test (&opt->packet_id.rec, pin))
- {
- packet_id_add (&opt->packet_id.rec, pin);
- if (opt->pid_persist && (opt->flags & CO_PACKET_ID_LONG_FORM))
- packet_id_persist_save_obj (opt->pid_persist, &opt->packet_id);
- ret = true;
- }
- else
- {
- if (!(opt->flags & CO_MUTE_REPLAY_WARNINGS))
- {
- msg (D_REPLAY_ERRORS, "%s: bad packet ID (may be a replay): %s -- "
- "see the man page entry for --no-replay and --replay-window for "
- "more info or silence this warning with --mute-replay-warnings",
- error_prefix, packet_id_net_print (pin, true, gc));
- }
- }
- return ret;
+bool
+crypto_check_replay(struct crypto_options *opt,
+ const struct packet_id_net *pin, const char *error_prefix,
+ struct gc_arena *gc) {
+ bool ret = false;
+ packet_id_reap_test(&opt->packet_id.rec);
+ if (packet_id_test(&opt->packet_id.rec, pin))
+ {
+ packet_id_add(&opt->packet_id.rec, pin);
+ if (opt->pid_persist && (opt->flags & CO_PACKET_ID_LONG_FORM))
+ {
+ packet_id_persist_save_obj(opt->pid_persist, &opt->packet_id);
+ }
+ ret = true;
+ }
+ else
+ {
+ if (!(opt->flags & CO_MUTE_REPLAY_WARNINGS))
+ {
+ msg(D_REPLAY_ERRORS, "%s: bad packet ID (may be a replay): %s -- "
+ "see the man page entry for --no-replay and --replay-window for "
+ "more info or silence this warning with --mute-replay-warnings",
+ error_prefix, packet_id_net_print(pin, true, gc));
+ }
+ }
+ return ret;
}
/*
@@ -353,141 +363,143 @@ bool crypto_check_replay(struct crypto_options *opt,
* is returned.
*/
static bool
-openvpn_decrypt_aead (struct buffer *buf, struct buffer work,
- struct crypto_options *opt, const struct frame* frame,
- const uint8_t *ad_start)
+openvpn_decrypt_aead(struct buffer *buf, struct buffer work,
+ struct crypto_options *opt, const struct frame *frame,
+ const uint8_t *ad_start)
{
#ifdef HAVE_AEAD_CIPHER_MODES
- static const char error_prefix[] = "AEAD Decrypt error";
- struct packet_id_net pin = { 0 };
- const struct key_ctx *ctx = &opt->key_ctx_bi.decrypt;
- const cipher_kt_t *cipher_kt = cipher_ctx_get_cipher_kt (ctx->cipher);
- uint8_t *tag_ptr = NULL;
- int tag_size = 0;
- int outlen;
- struct gc_arena gc;
-
- gc_init (&gc);
-
- ASSERT (opt);
- ASSERT (frame);
- ASSERT (buf->len > 0);
- ASSERT (ctx->cipher);
- ASSERT (cipher_kt_mode_aead (cipher_kt));
-
- dmsg (D_PACKET_CONTENT, "DECRYPT FROM: %s",
- format_hex (BPTR (buf), BLEN (buf), 80, &gc));
-
- ASSERT (ad_start >= buf->data && ad_start <= BPTR (buf));
+ static const char error_prefix[] = "AEAD Decrypt error";
+ struct packet_id_net pin = { 0 };
+ const struct key_ctx *ctx = &opt->key_ctx_bi.decrypt;
+ const cipher_kt_t *cipher_kt = cipher_ctx_get_cipher_kt(ctx->cipher);
+ uint8_t *tag_ptr = NULL;
+ int tag_size = 0;
+ int outlen;
+ struct gc_arena gc;
- ASSERT (buf_init (&work, FRAME_HEADROOM_ADJ (frame, FRAME_HEADROOM_MARKER_DECRYPT)));
+ gc_init(&gc);
- /* IV and Packet ID required for this mode */
- ASSERT (packet_id_initialized (&opt->packet_id));
- ASSERT (opt->flags & CO_USE_IV);
+ ASSERT(opt);
+ ASSERT(frame);
+ ASSERT(buf->len > 0);
+ ASSERT(ctx->cipher);
+ ASSERT(cipher_kt_mode_aead(cipher_kt));
- /* Combine IV from explicit part from packet and implicit part from context */
- {
- uint8_t iv[OPENVPN_MAX_IV_LENGTH] = { 0 };
- const int iv_len = cipher_ctx_iv_length (ctx->cipher);
- const size_t packet_iv_len = iv_len - ctx->implicit_iv_len;
+ dmsg(D_PACKET_CONTENT, "DECRYPT FROM: %s",
+ format_hex(BPTR(buf), BLEN(buf), 80, &gc));
- ASSERT (ctx->implicit_iv_len <= iv_len);
- if (buf->len + ctx->implicit_iv_len < iv_len)
- CRYPT_ERROR ("missing IV info");
+ ASSERT(ad_start >= buf->data && ad_start <= BPTR(buf));
- memcpy (iv, BPTR(buf), packet_iv_len);
- memcpy (iv + packet_iv_len, ctx->implicit_iv, ctx->implicit_iv_len);
+ ASSERT(buf_init(&work, FRAME_HEADROOM_ADJ(frame, FRAME_HEADROOM_MARKER_DECRYPT)));
- dmsg (D_PACKET_CONTENT, "DECRYPT IV: %s", format_hex (iv, iv_len, 0, &gc));
+ /* IV and Packet ID required for this mode */
+ ASSERT(packet_id_initialized(&opt->packet_id));
+ ASSERT(opt->flags & CO_USE_IV);
- /* Load IV, ctx->cipher was already initialized with key & keylen */
- if (!cipher_ctx_reset (ctx->cipher, iv))
- {
- CRYPT_ERROR ("cipher init failed");
- }
- }
+ /* Combine IV from explicit part from packet and implicit part from context */
+ {
+ uint8_t iv[OPENVPN_MAX_IV_LENGTH] = { 0 };
+ const int iv_len = cipher_ctx_iv_length(ctx->cipher);
+ const size_t packet_iv_len = iv_len - ctx->implicit_iv_len;
+
+ ASSERT(ctx->implicit_iv_len <= iv_len);
+ if (buf->len + ctx->implicit_iv_len < iv_len)
+ {
+ CRYPT_ERROR("missing IV info");
+ }
+
+ memcpy(iv, BPTR(buf), packet_iv_len);
+ memcpy(iv + packet_iv_len, ctx->implicit_iv, ctx->implicit_iv_len);
+
+ dmsg(D_PACKET_CONTENT, "DECRYPT IV: %s", format_hex(iv, iv_len, 0, &gc));
+
+ /* Load IV, ctx->cipher was already initialized with key & keylen */
+ if (!cipher_ctx_reset(ctx->cipher, iv))
+ {
+ CRYPT_ERROR("cipher init failed");
+ }
+ }
- /* Read packet ID from packet */
- if (!packet_id_read (&pin, buf, false))
+ /* Read packet ID from packet */
+ if (!packet_id_read(&pin, buf, false))
{
- CRYPT_ERROR ("error reading packet-id");
+ CRYPT_ERROR("error reading packet-id");
}
- /* keep the tag value to feed in later */
- tag_size = cipher_kt_tag_size(cipher_kt);
- if (buf->len < tag_size)
+ /* keep the tag value to feed in later */
+ tag_size = cipher_kt_tag_size(cipher_kt);
+ if (buf->len < tag_size)
{
- CRYPT_ERROR ("missing tag");
+ CRYPT_ERROR("missing tag");
}
- tag_ptr = BPTR(buf);
- ASSERT (buf_advance (buf, tag_size));
- dmsg (D_PACKET_CONTENT, "DECRYPT MAC: %s", format_hex (tag_ptr, tag_size, 0, &gc));
+ tag_ptr = BPTR(buf);
+ ASSERT(buf_advance(buf, tag_size));
+ dmsg(D_PACKET_CONTENT, "DECRYPT MAC: %s", format_hex(tag_ptr, tag_size, 0, &gc));
#if defined(ENABLE_CRYPTO_OPENSSL) && OPENSSL_VERSION_NUMBER < 0x10001040L
- /* OpenSSL <= 1.0.1c bug requires set tag before processing ciphertext */
- if (!EVP_CIPHER_CTX_ctrl (ctx->cipher, EVP_CTRL_GCM_SET_TAG, tag_size, tag_ptr))
+ /* OpenSSL <= 1.0.1c bug requires set tag before processing ciphertext */
+ if (!EVP_CIPHER_CTX_ctrl(ctx->cipher, EVP_CTRL_GCM_SET_TAG, tag_size, tag_ptr))
{
- CRYPT_ERROR ("setting tag failed");
+ CRYPT_ERROR("setting tag failed");
}
#endif
- if (buf->len < 1)
+ if (buf->len < 1)
{
- CRYPT_ERROR ("missing payload");
+ CRYPT_ERROR("missing payload");
}
- dmsg (D_PACKET_CONTENT, "DECRYPT FROM: %s", format_hex (BPTR(buf), BLEN(buf), 0, &gc));
+ dmsg(D_PACKET_CONTENT, "DECRYPT FROM: %s", format_hex(BPTR(buf), BLEN(buf), 0, &gc));
- /* Buffer overflow check (should never fail) */
- if (!buf_safe (&work, buf->len + cipher_ctx_block_size(ctx->cipher)))
+ /* Buffer overflow check (should never fail) */
+ if (!buf_safe(&work, buf->len + cipher_ctx_block_size(ctx->cipher)))
{
- CRYPT_ERROR ("potential buffer overflow");
+ CRYPT_ERROR("potential buffer overflow");
}
- {
- /* feed in tag and the authenticated data */
- const int ad_size = BPTR (buf) - ad_start - tag_size;
- ASSERT (cipher_ctx_update_ad (ctx->cipher, ad_start, ad_size));
- dmsg (D_PACKET_CONTENT, "DECRYPT AD: %s",
- format_hex (BPTR (buf) - ad_size - tag_size, ad_size, 0, &gc));
- }
+ {
+ /* feed in tag and the authenticated data */
+ const int ad_size = BPTR(buf) - ad_start - tag_size;
+ ASSERT(cipher_ctx_update_ad(ctx->cipher, ad_start, ad_size));
+ dmsg(D_PACKET_CONTENT, "DECRYPT AD: %s",
+ format_hex(BPTR(buf) - ad_size - tag_size, ad_size, 0, &gc));
+ }
- /* Decrypt and authenticate packet */
- if (!cipher_ctx_update (ctx->cipher, BPTR (&work), &outlen, BPTR (buf),
- BLEN (buf)))
+ /* Decrypt and authenticate packet */
+ if (!cipher_ctx_update(ctx->cipher, BPTR(&work), &outlen, BPTR(buf),
+ BLEN(buf)))
{
- CRYPT_ERROR ("cipher update failed");
+ CRYPT_ERROR("cipher update failed");
}
- ASSERT (buf_inc_len (&work, outlen));
- if (!cipher_ctx_final_check_tag (ctx->cipher, BPTR (&work) + outlen,
- &outlen, tag_ptr, tag_size))
+ ASSERT(buf_inc_len(&work, outlen));
+ if (!cipher_ctx_final_check_tag(ctx->cipher, BPTR(&work) + outlen,
+ &outlen, tag_ptr, tag_size))
{
- CRYPT_ERROR ("cipher final failed");
+ CRYPT_ERROR("cipher final failed");
}
- ASSERT (buf_inc_len (&work, outlen));
+ ASSERT(buf_inc_len(&work, outlen));
- dmsg (D_PACKET_CONTENT, "DECRYPT TO: %s",
- format_hex (BPTR (&work), BLEN (&work), 80, &gc));
+ dmsg(D_PACKET_CONTENT, "DECRYPT TO: %s",
+ format_hex(BPTR(&work), BLEN(&work), 80, &gc));
- if (!crypto_check_replay (opt, &pin, error_prefix, &gc))
+ if (!crypto_check_replay(opt, &pin, error_prefix, &gc))
{
- goto error_exit;
+ goto error_exit;
}
- *buf = work;
+ *buf = work;
- gc_free (&gc);
- return true;
+ gc_free(&gc);
+ return true;
- error_exit:
- crypto_clear_error();
- buf->len = 0;
- gc_free (&gc);
- return false;
+error_exit:
+ crypto_clear_error();
+ buf->len = 0;
+ gc_free(&gc);
+ return false;
#else /* HAVE_AEAD_CIPHER_MODES */
- ASSERT (0);
- return false;
-#endif
+ ASSERT(0);
+ return false;
+#endif /* ifdef HAVE_AEAD_CIPHER_MODES */
}
/*
@@ -499,397 +511,448 @@ openvpn_decrypt_aead (struct buffer *buf, struct buffer work,
* is returned.
*/
static bool
-openvpn_decrypt_v1 (struct buffer *buf, struct buffer work,
- struct crypto_options *opt, const struct frame* frame)
+openvpn_decrypt_v1(struct buffer *buf, struct buffer work,
+ struct crypto_options *opt, const struct frame *frame)
{
- static const char error_prefix[] = "Authenticate/Decrypt packet error";
- struct gc_arena gc;
- gc_init (&gc);
-
- if (buf->len > 0 && opt)
- {
- const struct key_ctx *ctx = &opt->key_ctx_bi.decrypt;
- struct packet_id_net pin;
- bool have_pin = false;
-
- dmsg (D_PACKET_CONTENT, "DECRYPT FROM: %s",
- format_hex (BPTR (buf), BLEN (buf), 80, &gc));
-
- /* Verify the HMAC */
- if (ctx->hmac)
- {
- int hmac_len;
- uint8_t local_hmac[MAX_HMAC_KEY_LENGTH]; /* HMAC of ciphertext computed locally */
-
- hmac_ctx_reset(ctx->hmac);
-
- /* Assume the length of the input HMAC */
- hmac_len = hmac_ctx_size (ctx->hmac);
-
- /* Authentication fails if insufficient data in packet for HMAC */
- if (buf->len < hmac_len)
- CRYPT_ERROR ("missing authentication info");
-
- hmac_ctx_update (ctx->hmac, BPTR (buf) + hmac_len, BLEN (buf) - hmac_len);
- hmac_ctx_final (ctx->hmac, local_hmac);
-
- /* Compare locally computed HMAC with packet HMAC */
- if (memcmp_constant_time (local_hmac, BPTR (buf), hmac_len))
- CRYPT_ERROR ("packet HMAC authentication failed");
-
- ASSERT (buf_advance (buf, hmac_len));
- }
-
- /* Decrypt packet ID + payload */
-
- if (ctx->cipher)
- {
- const int iv_size = cipher_ctx_iv_length (ctx->cipher);
- const cipher_kt_t *cipher_kt = cipher_ctx_get_cipher_kt (ctx->cipher);
- uint8_t iv_buf[OPENVPN_MAX_IV_LENGTH] = { 0 };
- int outlen;
-
- /* initialize work buffer with FRAME_HEADROOM bytes of prepend capacity */
- ASSERT (buf_init (&work, FRAME_HEADROOM_ADJ (frame, FRAME_HEADROOM_MARKER_DECRYPT)));
-
- /* use IV if user requested it */
- if (opt->flags & CO_USE_IV)
- {
- if (buf->len < iv_size)
- CRYPT_ERROR ("missing IV info");
- memcpy (iv_buf, BPTR (buf), iv_size);
- ASSERT (buf_advance (buf, iv_size));
- }
-
- /* show the IV's initial state */
- if (opt->flags & CO_USE_IV)
- dmsg (D_PACKET_CONTENT, "DECRYPT IV: %s", format_hex (iv_buf, iv_size, 0, &gc));
-
- if (buf->len < 1)
- CRYPT_ERROR ("missing payload");
-
- /* ctx->cipher was already initialized with key & keylen */
- if (!cipher_ctx_reset (ctx->cipher, iv_buf))
- CRYPT_ERROR ("cipher init failed");
-
- /* Buffer overflow check (should never happen) */
- if (!buf_safe (&work, buf->len + cipher_ctx_block_size(ctx->cipher)))
- CRYPT_ERROR ("potential buffer overflow");
-
- /* Decrypt packet ID, payload */
- if (!cipher_ctx_update (ctx->cipher, BPTR (&work), &outlen, BPTR (buf), BLEN (buf)))
- CRYPT_ERROR ("cipher update failed");
- ASSERT (buf_inc_len(&work, outlen));
-
- /* Flush the decryption buffer */
- if (!cipher_ctx_final (ctx->cipher, BPTR (&work) + outlen, &outlen))
- CRYPT_ERROR ("cipher final failed");
- ASSERT (buf_inc_len(&work, outlen));
-
- dmsg (D_PACKET_CONTENT, "DECRYPT TO: %s",
- format_hex (BPTR (&work), BLEN (&work), 80, &gc));
-
- /* Get packet ID from plaintext buffer or IV, depending on cipher mode */
- {
- if (cipher_kt_mode_cbc(cipher_kt))
- {
- if (packet_id_initialized(&opt->packet_id))
- {
- if (!packet_id_read (&pin, &work, BOOL_CAST (opt->flags & CO_PACKET_ID_LONG_FORM)))
- CRYPT_ERROR ("error reading CBC packet-id");
- have_pin = true;
- }
- }
- else if (cipher_kt_mode_ofb_cfb(cipher_kt))
- {
- struct buffer b;
-
- /* IV and packet-ID required for this mode. */
- ASSERT (opt->flags & CO_USE_IV);
- ASSERT (packet_id_initialized(&opt->packet_id));
-
- buf_set_read (&b, iv_buf, iv_size);
- if (!packet_id_read (&pin, &b, true))
- CRYPT_ERROR ("error reading CFB/OFB packet-id");
- have_pin = true;
- }
- else /* We only support CBC, CFB, or OFB modes right now */
- {
- ASSERT (0);
- }
- }
- }
- else
- {
- work = *buf;
- if (packet_id_initialized(&opt->packet_id))
- {
- if (!packet_id_read (&pin, &work, BOOL_CAST (opt->flags & CO_PACKET_ID_LONG_FORM)))
- CRYPT_ERROR ("error reading packet-id");
- have_pin = !BOOL_CAST (opt->flags & CO_IGNORE_PACKET_ID);
- }
- }
-
- if (have_pin && !crypto_check_replay(opt, &pin, error_prefix, &gc))
- {
- goto error_exit;
- }
- *buf = work;
- }
-
- gc_free (&gc);
- return true;
-
- error_exit:
- crypto_clear_error();
- buf->len = 0;
- gc_free (&gc);
- return false;
+ static const char error_prefix[] = "Authenticate/Decrypt packet error";
+ struct gc_arena gc;
+ gc_init(&gc);
+
+ if (buf->len > 0 && opt)
+ {
+ const struct key_ctx *ctx = &opt->key_ctx_bi.decrypt;
+ struct packet_id_net pin;
+ bool have_pin = false;
+
+ dmsg(D_PACKET_CONTENT, "DECRYPT FROM: %s",
+ format_hex(BPTR(buf), BLEN(buf), 80, &gc));
+
+ /* Verify the HMAC */
+ if (ctx->hmac)
+ {
+ int hmac_len;
+ uint8_t local_hmac[MAX_HMAC_KEY_LENGTH]; /* HMAC of ciphertext computed locally */
+
+ hmac_ctx_reset(ctx->hmac);
+
+ /* Assume the length of the input HMAC */
+ hmac_len = hmac_ctx_size(ctx->hmac);
+
+ /* Authentication fails if insufficient data in packet for HMAC */
+ if (buf->len < hmac_len)
+ {
+ CRYPT_ERROR("missing authentication info");
+ }
+
+ hmac_ctx_update(ctx->hmac, BPTR(buf) + hmac_len, BLEN(buf) - hmac_len);
+ hmac_ctx_final(ctx->hmac, local_hmac);
+
+ /* Compare locally computed HMAC with packet HMAC */
+ if (memcmp_constant_time(local_hmac, BPTR(buf), hmac_len))
+ {
+ CRYPT_ERROR("packet HMAC authentication failed");
+ }
+
+ ASSERT(buf_advance(buf, hmac_len));
+ }
+
+ /* Decrypt packet ID + payload */
+
+ if (ctx->cipher)
+ {
+ const int iv_size = cipher_ctx_iv_length(ctx->cipher);
+ const cipher_kt_t *cipher_kt = cipher_ctx_get_cipher_kt(ctx->cipher);
+ uint8_t iv_buf[OPENVPN_MAX_IV_LENGTH] = { 0 };
+ int outlen;
+
+ /* initialize work buffer with FRAME_HEADROOM bytes of prepend capacity */
+ ASSERT(buf_init(&work, FRAME_HEADROOM_ADJ(frame, FRAME_HEADROOM_MARKER_DECRYPT)));
+
+ /* use IV if user requested it */
+ if (opt->flags & CO_USE_IV)
+ {
+ if (buf->len < iv_size)
+ {
+ CRYPT_ERROR("missing IV info");
+ }
+ memcpy(iv_buf, BPTR(buf), iv_size);
+ ASSERT(buf_advance(buf, iv_size));
+ }
+
+ /* show the IV's initial state */
+ if (opt->flags & CO_USE_IV)
+ {
+ dmsg(D_PACKET_CONTENT, "DECRYPT IV: %s", format_hex(iv_buf, iv_size, 0, &gc));
+ }
+
+ if (buf->len < 1)
+ {
+ CRYPT_ERROR("missing payload");
+ }
+
+ /* ctx->cipher was already initialized with key & keylen */
+ if (!cipher_ctx_reset(ctx->cipher, iv_buf))
+ {
+ CRYPT_ERROR("cipher init failed");
+ }
+
+ /* Buffer overflow check (should never happen) */
+ if (!buf_safe(&work, buf->len + cipher_ctx_block_size(ctx->cipher)))
+ {
+ CRYPT_ERROR("potential buffer overflow");
+ }
+
+ /* Decrypt packet ID, payload */
+ if (!cipher_ctx_update(ctx->cipher, BPTR(&work), &outlen, BPTR(buf), BLEN(buf)))
+ {
+ CRYPT_ERROR("cipher update failed");
+ }
+ ASSERT(buf_inc_len(&work, outlen));
+
+ /* Flush the decryption buffer */
+ if (!cipher_ctx_final(ctx->cipher, BPTR(&work) + outlen, &outlen))
+ {
+ CRYPT_ERROR("cipher final failed");
+ }
+ ASSERT(buf_inc_len(&work, outlen));
+
+ dmsg(D_PACKET_CONTENT, "DECRYPT TO: %s",
+ format_hex(BPTR(&work), BLEN(&work), 80, &gc));
+
+ /* Get packet ID from plaintext buffer or IV, depending on cipher mode */
+ {
+ if (cipher_kt_mode_cbc(cipher_kt))
+ {
+ if (packet_id_initialized(&opt->packet_id))
+ {
+ if (!packet_id_read(&pin, &work, BOOL_CAST(opt->flags & CO_PACKET_ID_LONG_FORM)))
+ {
+ CRYPT_ERROR("error reading CBC packet-id");
+ }
+ have_pin = true;
+ }
+ }
+ else if (cipher_kt_mode_ofb_cfb(cipher_kt))
+ {
+ struct buffer b;
+
+ /* IV and packet-ID required for this mode. */
+ ASSERT(opt->flags & CO_USE_IV);
+ ASSERT(packet_id_initialized(&opt->packet_id));
+
+ buf_set_read(&b, iv_buf, iv_size);
+ if (!packet_id_read(&pin, &b, true))
+ {
+ CRYPT_ERROR("error reading CFB/OFB packet-id");
+ }
+ have_pin = true;
+ }
+ else /* We only support CBC, CFB, or OFB modes right now */
+ {
+ ASSERT(0);
+ }
+ }
+ }
+ else
+ {
+ work = *buf;
+ if (packet_id_initialized(&opt->packet_id))
+ {
+ if (!packet_id_read(&pin, &work, BOOL_CAST(opt->flags & CO_PACKET_ID_LONG_FORM)))
+ {
+ CRYPT_ERROR("error reading packet-id");
+ }
+ have_pin = !BOOL_CAST(opt->flags & CO_IGNORE_PACKET_ID);
+ }
+ }
+
+ if (have_pin && !crypto_check_replay(opt, &pin, error_prefix, &gc))
+ {
+ goto error_exit;
+ }
+ *buf = work;
+ }
+
+ gc_free(&gc);
+ return true;
+
+error_exit:
+ crypto_clear_error();
+ buf->len = 0;
+ gc_free(&gc);
+ return false;
}
bool
-openvpn_decrypt (struct buffer *buf, struct buffer work,
- struct crypto_options *opt, const struct frame* frame,
- const uint8_t *ad_start)
+openvpn_decrypt(struct buffer *buf, struct buffer work,
+ struct crypto_options *opt, const struct frame *frame,
+ const uint8_t *ad_start)
{
- bool ret = false;
+ bool ret = false;
- if (buf->len > 0 && opt)
+ if (buf->len > 0 && opt)
{
- const struct key_ctx *ctx = &opt->key_ctx_bi.decrypt;
- if (cipher_kt_mode_aead (cipher_ctx_get_cipher_kt (ctx->cipher)))
- {
- ret = openvpn_decrypt_aead (buf, work, opt, frame, ad_start);
- }
- else
- {
- ret = openvpn_decrypt_v1 (buf, work, opt, frame);
- }
+ const struct key_ctx *ctx = &opt->key_ctx_bi.decrypt;
+ if (cipher_kt_mode_aead(cipher_ctx_get_cipher_kt(ctx->cipher)))
+ {
+ ret = openvpn_decrypt_aead(buf, work, opt, frame, ad_start);
+ }
+ else
+ {
+ ret = openvpn_decrypt_v1(buf, work, opt, frame);
+ }
}
- else
+ else
{
- ret = true;
+ ret = true;
}
- return ret;
+ return ret;
}
void
crypto_adjust_frame_parameters(struct frame *frame,
- const struct key_type* kt,
- bool use_iv,
- bool packet_id,
- bool packet_id_long_form)
+ const struct key_type *kt,
+ bool use_iv,
+ bool packet_id,
+ bool packet_id_long_form)
{
- size_t crypto_overhead = 0;
+ size_t crypto_overhead = 0;
- if (packet_id)
- crypto_overhead += packet_id_size (packet_id_long_form);
-
- if (kt->cipher)
+ if (packet_id)
{
- if (use_iv)
- crypto_overhead += cipher_kt_iv_size (kt->cipher);
-
- if (cipher_kt_mode_aead (kt->cipher))
- crypto_overhead += cipher_kt_tag_size (kt->cipher);
+ crypto_overhead += packet_id_size(packet_id_long_form);
+ }
- /* extra block required by cipher_ctx_update() */
- crypto_overhead += cipher_kt_block_size (kt->cipher);
+ if (kt->cipher)
+ {
+ if (use_iv)
+ {
+ crypto_overhead += cipher_kt_iv_size(kt->cipher);
+ }
+
+ if (cipher_kt_mode_aead(kt->cipher))
+ {
+ crypto_overhead += cipher_kt_tag_size(kt->cipher);
+ }
+
+ /* extra block required by cipher_ctx_update() */
+ crypto_overhead += cipher_kt_block_size(kt->cipher);
}
- crypto_overhead += kt->hmac_length;
+ crypto_overhead += kt->hmac_length;
- frame_add_to_extra_frame (frame, crypto_overhead);
+ frame_add_to_extra_frame(frame, crypto_overhead);
- msg(D_MTU_DEBUG, "%s: Adjusting frame parameters for crypto by %u bytes",
- __func__, (unsigned int) crypto_overhead);
+ msg(D_MTU_DEBUG, "%s: Adjusting frame parameters for crypto by %u bytes",
+ __func__, (unsigned int) crypto_overhead);
}
size_t
crypto_max_overhead(void)
{
- return packet_id_size(true) + OPENVPN_MAX_IV_LENGTH +
- OPENVPN_MAX_CIPHER_BLOCK_SIZE +
- max_int (OPENVPN_MAX_HMAC_SIZE, OPENVPN_AEAD_TAG_LENGTH);
+ return packet_id_size(true) + OPENVPN_MAX_IV_LENGTH
+ +OPENVPN_MAX_CIPHER_BLOCK_SIZE
+ +max_int(OPENVPN_MAX_HMAC_SIZE, OPENVPN_AEAD_TAG_LENGTH);
}
/*
* Build a struct key_type.
*/
void
-init_key_type (struct key_type *kt, const char *ciphername,
- const char *authname, int keysize, bool tls_mode, bool warn)
+init_key_type(struct key_type *kt, const char *ciphername,
+ const char *authname, int keysize, bool tls_mode, bool warn)
{
- bool aead_cipher = false;
+ bool aead_cipher = false;
- ASSERT(ciphername);
- ASSERT(authname);
+ ASSERT(ciphername);
+ ASSERT(authname);
- CLEAR (*kt);
- if (strcmp (ciphername, "none") != 0)
+ CLEAR(*kt);
+ if (strcmp(ciphername, "none") != 0)
{
- kt->cipher = cipher_kt_get (translate_cipher_name_from_openvpn(ciphername));
- if (!kt->cipher)
- {
- msg (M_FATAL, "Cipher %s not supported", ciphername);
- }
-
- kt->cipher_length = cipher_kt_key_size (kt->cipher);
- if (keysize > 0 && keysize <= MAX_CIPHER_KEY_LENGTH)
- kt->cipher_length = keysize;
-
- /* check legal cipher mode */
- aead_cipher = cipher_kt_mode_aead(kt->cipher);
- if (!(cipher_kt_mode_cbc(kt->cipher)
- || (tls_mode && aead_cipher)
+ kt->cipher = cipher_kt_get(translate_cipher_name_from_openvpn(ciphername));
+ if (!kt->cipher)
+ {
+ msg(M_FATAL, "Cipher %s not supported", ciphername);
+ }
+
+ kt->cipher_length = cipher_kt_key_size(kt->cipher);
+ if (keysize > 0 && keysize <= MAX_CIPHER_KEY_LENGTH)
+ {
+ kt->cipher_length = keysize;
+ }
+
+ /* check legal cipher mode */
+ aead_cipher = cipher_kt_mode_aead(kt->cipher);
+ if (!(cipher_kt_mode_cbc(kt->cipher)
+ || (tls_mode && aead_cipher)
#ifdef ENABLE_OFB_CFB_MODE
- || (tls_mode && cipher_kt_mode_ofb_cfb(kt->cipher))
+ || (tls_mode && cipher_kt_mode_ofb_cfb(kt->cipher))
#endif
- ))
- msg (M_FATAL, "Cipher '%s' mode not supported", ciphername);
-
- if (OPENVPN_MAX_CIPHER_BLOCK_SIZE < cipher_kt_block_size(kt->cipher))
- msg (M_FATAL, "Cipher '%s' not allowed: block size too big.", ciphername);
+ ))
+ {
+ msg(M_FATAL, "Cipher '%s' mode not supported", ciphername);
+ }
+
+ if (OPENVPN_MAX_CIPHER_BLOCK_SIZE < cipher_kt_block_size(kt->cipher))
+ {
+ msg(M_FATAL, "Cipher '%s' not allowed: block size too big.", ciphername);
+ }
}
- else
+ else
{
- if (warn)
- msg (M_WARN, "******* WARNING *******: null cipher specified, no encryption will be used");
+ if (warn)
+ {
+ msg(M_WARN, "******* WARNING *******: null cipher specified, no encryption will be used");
+ }
}
- if (strcmp (authname, "none") != 0)
+ if (strcmp(authname, "none") != 0)
{
- if (!aead_cipher) { /* Ignore auth for AEAD ciphers */
- kt->digest = md_kt_get (authname);
- kt->hmac_length = md_kt_size (kt->digest);
+ if (!aead_cipher) /* Ignore auth for AEAD ciphers */
+ {
+ kt->digest = md_kt_get(authname);
+ kt->hmac_length = md_kt_size(kt->digest);
- if (OPENVPN_MAX_HMAC_SIZE < kt->hmac_length)
- msg (M_FATAL, "HMAC '%s' not allowed: digest size too big.", authname);
- }
+ if (OPENVPN_MAX_HMAC_SIZE < kt->hmac_length)
+ {
+ msg(M_FATAL, "HMAC '%s' not allowed: digest size too big.", authname);
+ }
+ }
}
- else if (!aead_cipher)
+ else if (!aead_cipher)
{
- if (warn)
- msg (M_WARN, "******* WARNING *******: null MAC specified, no authentication will be used");
+ if (warn)
+ {
+ msg(M_WARN, "******* WARNING *******: null MAC specified, no authentication will be used");
+ }
}
}
/* given a key and key_type, build a key_ctx */
void
-init_key_ctx (struct key_ctx *ctx, struct key *key,
- const struct key_type *kt, int enc,
- const char *prefix)
+init_key_ctx(struct key_ctx *ctx, struct key *key,
+ const struct key_type *kt, int enc,
+ const char *prefix)
{
- struct gc_arena gc = gc_new ();
- CLEAR (*ctx);
- if (kt->cipher && kt->cipher_length > 0)
+ struct gc_arena gc = gc_new();
+ CLEAR(*ctx);
+ if (kt->cipher && kt->cipher_length > 0)
{
- ALLOC_OBJ(ctx->cipher, cipher_ctx_t);
- cipher_ctx_init (ctx->cipher, key->cipher, kt->cipher_length,
- kt->cipher, enc);
-
- msg (D_HANDSHAKE, "%s: Cipher '%s' initialized with %d bit key",
- prefix,
- translate_cipher_name_to_openvpn(cipher_kt_name(kt->cipher)),
- kt->cipher_length *8);
-
- dmsg (D_SHOW_KEYS, "%s: CIPHER KEY: %s", prefix,
- format_hex (key->cipher, kt->cipher_length, 0, &gc));
- dmsg (D_CRYPTO_DEBUG, "%s: CIPHER block_size=%d iv_size=%d",
- prefix, cipher_kt_block_size(kt->cipher),
- cipher_kt_iv_size(kt->cipher));
- if (cipher_kt_block_size(kt->cipher) < 128/8)
- {
- msg (M_WARN, "WARNING: INSECURE cipher with block size less than 128"
- " bit (%d bit). This allows attacks like SWEET32. Mitigate by "
- "using a --cipher with a larger block size (e.g. AES-256-CBC).",
- cipher_kt_block_size(kt->cipher)*8);
- }
+ ALLOC_OBJ(ctx->cipher, cipher_ctx_t);
+ cipher_ctx_init(ctx->cipher, key->cipher, kt->cipher_length,
+ kt->cipher, enc);
+
+ msg(D_HANDSHAKE, "%s: Cipher '%s' initialized with %d bit key",
+ prefix,
+ translate_cipher_name_to_openvpn(cipher_kt_name(kt->cipher)),
+ kt->cipher_length *8);
+
+ dmsg(D_SHOW_KEYS, "%s: CIPHER KEY: %s", prefix,
+ format_hex(key->cipher, kt->cipher_length, 0, &gc));
+ dmsg(D_CRYPTO_DEBUG, "%s: CIPHER block_size=%d iv_size=%d",
+ prefix, cipher_kt_block_size(kt->cipher),
+ cipher_kt_iv_size(kt->cipher));
+ if (cipher_kt_block_size(kt->cipher) < 128/8)
+ {
+ msg(M_WARN, "WARNING: INSECURE cipher with block size less than 128"
+ " bit (%d bit). This allows attacks like SWEET32. Mitigate by "
+ "using a --cipher with a larger block size (e.g. AES-256-CBC).",
+ cipher_kt_block_size(kt->cipher)*8);
+ }
}
- if (kt->digest && kt->hmac_length > 0)
+ if (kt->digest && kt->hmac_length > 0)
{
- ALLOC_OBJ(ctx->hmac, hmac_ctx_t);
- hmac_ctx_init (ctx->hmac, key->hmac, kt->hmac_length, kt->digest);
+ ALLOC_OBJ(ctx->hmac, hmac_ctx_t);
+ hmac_ctx_init(ctx->hmac, key->hmac, kt->hmac_length, kt->digest);
- msg (D_HANDSHAKE,
- "%s: Using %d bit message hash '%s' for HMAC authentication",
- prefix, md_kt_size(kt->digest) * 8, md_kt_name(kt->digest));
+ msg(D_HANDSHAKE,
+ "%s: Using %d bit message hash '%s' for HMAC authentication",
+ prefix, md_kt_size(kt->digest) * 8, md_kt_name(kt->digest));
- dmsg (D_SHOW_KEYS, "%s: HMAC KEY: %s", prefix,
- format_hex (key->hmac, kt->hmac_length, 0, &gc));
+ dmsg(D_SHOW_KEYS, "%s: HMAC KEY: %s", prefix,
+ format_hex(key->hmac, kt->hmac_length, 0, &gc));
- dmsg (D_CRYPTO_DEBUG, "%s: HMAC size=%d block_size=%d",
- prefix,
- md_kt_size(kt->digest),
- hmac_ctx_size(ctx->hmac));
+ dmsg(D_CRYPTO_DEBUG, "%s: HMAC size=%d block_size=%d",
+ prefix,
+ md_kt_size(kt->digest),
+ hmac_ctx_size(ctx->hmac));
}
- gc_free (&gc);
+ gc_free(&gc);
}
void
-free_key_ctx (struct key_ctx *ctx)
+free_key_ctx(struct key_ctx *ctx)
{
- if (ctx->cipher)
+ if (ctx->cipher)
{
- cipher_ctx_cleanup(ctx->cipher);
- free(ctx->cipher);
- ctx->cipher = NULL;
+ cipher_ctx_cleanup(ctx->cipher);
+ free(ctx->cipher);
+ ctx->cipher = NULL;
}
- if (ctx->hmac)
+ if (ctx->hmac)
{
- hmac_ctx_cleanup(ctx->hmac);
- free(ctx->hmac);
- ctx->hmac = NULL;
+ hmac_ctx_cleanup(ctx->hmac);
+ free(ctx->hmac);
+ ctx->hmac = NULL;
}
- ctx->implicit_iv_len = 0;
+ ctx->implicit_iv_len = 0;
}
void
-free_key_ctx_bi (struct key_ctx_bi *ctx)
+free_key_ctx_bi(struct key_ctx_bi *ctx)
{
- free_key_ctx(&ctx->encrypt);
- free_key_ctx(&ctx->decrypt);
+ free_key_ctx(&ctx->encrypt);
+ free_key_ctx(&ctx->decrypt);
}
static bool
-key_is_zero (struct key *key, const struct key_type *kt)
+key_is_zero(struct key *key, const struct key_type *kt)
{
- int i;
- for (i = 0; i < kt->cipher_length; ++i)
- if (key->cipher[i])
- return false;
- msg (D_CRYPT_ERRORS, "CRYPTO INFO: WARNING: zero key detected");
- return true;
+ int i;
+ for (i = 0; i < kt->cipher_length; ++i)
+ if (key->cipher[i])
+ {
+ return false;
+ }
+ msg(D_CRYPT_ERRORS, "CRYPTO INFO: WARNING: zero key detected");
+ return true;
}
/*
* Make sure that cipher key is a valid key for current key_type.
*/
bool
-check_key (struct key *key, const struct key_type *kt)
+check_key(struct key *key, const struct key_type *kt)
{
- if (kt->cipher)
- {
- /*
- * Check for zero key
- */
- if (key_is_zero(key, kt))
- return false;
-
- /*
- * Check for weak or semi-weak DES keys.
- */
- {
- const int ndc = key_des_num_cblocks (kt->cipher);
- if (ndc)
- return key_des_check (key->cipher, kt->cipher_length, ndc);
- else
- return true;
- }
- }
- return true;
+ if (kt->cipher)
+ {
+ /*
+ * Check for zero key
+ */
+ if (key_is_zero(key, kt))
+ {
+ return false;
+ }
+
+ /*
+ * Check for weak or semi-weak DES keys.
+ */
+ {
+ const int ndc = key_des_num_cblocks(kt->cipher);
+ if (ndc)
+ {
+ return key_des_check(key->cipher, kt->cipher_length, ndc);
+ }
+ else
+ {
+ return true;
+ }
+ }
+ }
+ return true;
}
/*
@@ -899,43 +962,49 @@ check_key (struct key *key, const struct key_type *kt)
* This routine cannot guarantee it will generate a good
* key. You must always call check_key after this routine
* to make sure.
- */
+ */
void
-fixup_key (struct key *key, const struct key_type *kt)
+fixup_key(struct key *key, const struct key_type *kt)
{
- struct gc_arena gc = gc_new ();
- if (kt->cipher)
+ struct gc_arena gc = gc_new();
+ if (kt->cipher)
{
#ifdef ENABLE_DEBUG
- const struct key orig = *key;
+ const struct key orig = *key;
#endif
- const int ndc = key_des_num_cblocks (kt->cipher);
+ const int ndc = key_des_num_cblocks(kt->cipher);
- if (ndc)
- key_des_fixup (key->cipher, kt->cipher_length, ndc);
+ if (ndc)
+ {
+ key_des_fixup(key->cipher, kt->cipher_length, ndc);
+ }
#ifdef ENABLE_DEBUG
- if (check_debug_level (D_CRYPTO_DEBUG))
- {
- if (memcmp (orig.cipher, key->cipher, kt->cipher_length))
- dmsg (D_CRYPTO_DEBUG, "CRYPTO INFO: fixup_key: before=%s after=%s",
- format_hex (orig.cipher, kt->cipher_length, 0, &gc),
- format_hex (key->cipher, kt->cipher_length, 0, &gc));
- }
+ if (check_debug_level(D_CRYPTO_DEBUG))
+ {
+ if (memcmp(orig.cipher, key->cipher, kt->cipher_length))
+ {
+ dmsg(D_CRYPTO_DEBUG, "CRYPTO INFO: fixup_key: before=%s after=%s",
+ format_hex(orig.cipher, kt->cipher_length, 0, &gc),
+ format_hex(key->cipher, kt->cipher_length, 0, &gc));
+ }
+ }
#endif
}
- gc_free (&gc);
+ gc_free(&gc);
}
void
-check_replay_iv_consistency (const struct key_type *kt, bool packet_id, bool use_iv)
+check_replay_iv_consistency(const struct key_type *kt, bool packet_id, bool use_iv)
{
- ASSERT(kt);
+ ASSERT(kt);
- if (!(packet_id && use_iv) && (cipher_kt_mode_ofb_cfb(kt->cipher) ||
- cipher_kt_mode_aead(kt->cipher)))
- msg (M_FATAL, "--no-replay or --no-iv cannot be used with a CFB, OFB or "
- "AEAD mode cipher");
+ if (!(packet_id && use_iv) && (cipher_kt_mode_ofb_cfb(kt->cipher)
+ || cipher_kt_mode_aead(kt->cipher)))
+ {
+ msg(M_FATAL, "--no-replay or --no-iv cannot be used with a CFB, OFB or "
+ "AEAD mode cipher");
+ }
}
/*
@@ -943,187 +1012,199 @@ check_replay_iv_consistency (const struct key_type *kt, bool packet_id, bool use
* sure generated key is valid for key_type.
*/
void
-generate_key_random (struct key *key, const struct key_type *kt)
+generate_key_random(struct key *key, const struct key_type *kt)
{
- int cipher_len = MAX_CIPHER_KEY_LENGTH;
- int hmac_len = MAX_HMAC_KEY_LENGTH;
-
- struct gc_arena gc = gc_new ();
-
- do {
- CLEAR (*key);
- if (kt)
- {
- if (kt->cipher && kt->cipher_length > 0 && kt->cipher_length <= cipher_len)
- cipher_len = kt->cipher_length;
-
- if (kt->digest && kt->hmac_length > 0 && kt->hmac_length <= hmac_len)
- hmac_len = kt->hmac_length;
- }
- if (!rand_bytes (key->cipher, cipher_len)
- || !rand_bytes (key->hmac, hmac_len))
- msg (M_FATAL, "ERROR: Random number generator cannot obtain entropy for key generation");
+ int cipher_len = MAX_CIPHER_KEY_LENGTH;
+ int hmac_len = MAX_HMAC_KEY_LENGTH;
- dmsg (D_SHOW_KEY_SOURCE, "Cipher source entropy: %s", format_hex (key->cipher, cipher_len, 0, &gc));
- dmsg (D_SHOW_KEY_SOURCE, "HMAC source entropy: %s", format_hex (key->hmac, hmac_len, 0, &gc));
+ struct gc_arena gc = gc_new();
- if (kt)
- fixup_key (key, kt);
- } while (kt && !check_key (key, kt));
+ do {
+ CLEAR(*key);
+ if (kt)
+ {
+ if (kt->cipher && kt->cipher_length > 0 && kt->cipher_length <= cipher_len)
+ {
+ cipher_len = kt->cipher_length;
+ }
- gc_free (&gc);
+ if (kt->digest && kt->hmac_length > 0 && kt->hmac_length <= hmac_len)
+ {
+ hmac_len = kt->hmac_length;
+ }
+ }
+ if (!rand_bytes(key->cipher, cipher_len)
+ || !rand_bytes(key->hmac, hmac_len))
+ {
+ msg(M_FATAL, "ERROR: Random number generator cannot obtain entropy for key generation");
+ }
+
+ dmsg(D_SHOW_KEY_SOURCE, "Cipher source entropy: %s", format_hex(key->cipher, cipher_len, 0, &gc));
+ dmsg(D_SHOW_KEY_SOURCE, "HMAC source entropy: %s", format_hex(key->hmac, hmac_len, 0, &gc));
+
+ if (kt)
+ {
+ fixup_key(key, kt);
+ }
+ } while (kt && !check_key(key, kt));
+
+ gc_free(&gc);
}
/*
* Print key material
*/
void
-key2_print (const struct key2* k,
- const struct key_type *kt,
- const char* prefix0,
- const char* prefix1)
+key2_print(const struct key2 *k,
+ const struct key_type *kt,
+ const char *prefix0,
+ const char *prefix1)
{
- struct gc_arena gc = gc_new ();
- ASSERT (k->n == 2);
- dmsg (D_SHOW_KEY_SOURCE, "%s (cipher): %s",
- prefix0,
- format_hex (k->keys[0].cipher, kt->cipher_length, 0, &gc));
- dmsg (D_SHOW_KEY_SOURCE, "%s (hmac): %s",
- prefix0,
- format_hex (k->keys[0].hmac, kt->hmac_length, 0, &gc));
- dmsg (D_SHOW_KEY_SOURCE, "%s (cipher): %s",
- prefix1,
- format_hex (k->keys[1].cipher, kt->cipher_length, 0, &gc));
- dmsg (D_SHOW_KEY_SOURCE, "%s (hmac): %s",
- prefix1,
- format_hex (k->keys[1].hmac, kt->hmac_length, 0, &gc));
- gc_free (&gc);
+ struct gc_arena gc = gc_new();
+ ASSERT(k->n == 2);
+ dmsg(D_SHOW_KEY_SOURCE, "%s (cipher): %s",
+ prefix0,
+ format_hex(k->keys[0].cipher, kt->cipher_length, 0, &gc));
+ dmsg(D_SHOW_KEY_SOURCE, "%s (hmac): %s",
+ prefix0,
+ format_hex(k->keys[0].hmac, kt->hmac_length, 0, &gc));
+ dmsg(D_SHOW_KEY_SOURCE, "%s (cipher): %s",
+ prefix1,
+ format_hex(k->keys[1].cipher, kt->cipher_length, 0, &gc));
+ dmsg(D_SHOW_KEY_SOURCE, "%s (hmac): %s",
+ prefix1,
+ format_hex(k->keys[1].hmac, kt->hmac_length, 0, &gc));
+ gc_free(&gc);
}
void
-test_crypto (struct crypto_options *co, struct frame* frame)
+test_crypto(struct crypto_options *co, struct frame *frame)
{
- int i, j;
- struct gc_arena gc = gc_new ();
- struct buffer src = alloc_buf_gc (TUN_MTU_SIZE (frame), &gc);
- struct buffer work = alloc_buf_gc (BUF_SIZE (frame), &gc);
- struct buffer encrypt_workspace = alloc_buf_gc (BUF_SIZE (frame), &gc);
- struct buffer decrypt_workspace = alloc_buf_gc (BUF_SIZE (frame), &gc);
- struct buffer buf = clear_buf();
- void *buf_p;
-
- /* init work */
- ASSERT (buf_init (&work, FRAME_HEADROOM (frame)));
+ int i, j;
+ struct gc_arena gc = gc_new();
+ struct buffer src = alloc_buf_gc(TUN_MTU_SIZE(frame), &gc);
+ struct buffer work = alloc_buf_gc(BUF_SIZE(frame), &gc);
+ struct buffer encrypt_workspace = alloc_buf_gc(BUF_SIZE(frame), &gc);
+ struct buffer decrypt_workspace = alloc_buf_gc(BUF_SIZE(frame), &gc);
+ struct buffer buf = clear_buf();
+ void *buf_p;
+
+ /* init work */
+ ASSERT(buf_init(&work, FRAME_HEADROOM(frame)));
#ifdef HAVE_AEAD_CIPHER_MODES
- /* init implicit IV */
- {
- const cipher_kt_t *cipher =
- cipher_ctx_get_cipher_kt(co->key_ctx_bi.encrypt.cipher);
-
- if (cipher_kt_mode_aead(cipher))
- {
- size_t impl_iv_len = cipher_kt_iv_size(cipher) - sizeof(packet_id_type);
- ASSERT (cipher_kt_iv_size(cipher) <= OPENVPN_MAX_IV_LENGTH);
- ASSERT (cipher_kt_iv_size(cipher) >= OPENVPN_AEAD_MIN_IV_LEN);
-
- /* Generate dummy implicit IV */
- ASSERT (rand_bytes(co->key_ctx_bi.encrypt.implicit_iv,
- OPENVPN_MAX_IV_LENGTH));
- co->key_ctx_bi.encrypt.implicit_iv_len = impl_iv_len;
-
- memcpy(co->key_ctx_bi.decrypt.implicit_iv,
- co->key_ctx_bi.encrypt.implicit_iv, OPENVPN_MAX_IV_LENGTH);
- co->key_ctx_bi.decrypt.implicit_iv_len = impl_iv_len;
- }
- }
-#endif
+ /* init implicit IV */
+ {
+ const cipher_kt_t *cipher =
+ cipher_ctx_get_cipher_kt(co->key_ctx_bi.encrypt.cipher);
+
+ if (cipher_kt_mode_aead(cipher))
+ {
+ size_t impl_iv_len = cipher_kt_iv_size(cipher) - sizeof(packet_id_type);
+ ASSERT(cipher_kt_iv_size(cipher) <= OPENVPN_MAX_IV_LENGTH);
+ ASSERT(cipher_kt_iv_size(cipher) >= OPENVPN_AEAD_MIN_IV_LEN);
+
+ /* Generate dummy implicit IV */
+ ASSERT(rand_bytes(co->key_ctx_bi.encrypt.implicit_iv,
+ OPENVPN_MAX_IV_LENGTH));
+ co->key_ctx_bi.encrypt.implicit_iv_len = impl_iv_len;
+
+ memcpy(co->key_ctx_bi.decrypt.implicit_iv,
+ co->key_ctx_bi.encrypt.implicit_iv, OPENVPN_MAX_IV_LENGTH);
+ co->key_ctx_bi.decrypt.implicit_iv_len = impl_iv_len;
+ }
+ }
+#endif /* ifdef HAVE_AEAD_CIPHER_MODES */
- msg (M_INFO, "Entering " PACKAGE_NAME " crypto self-test mode.");
- for (i = 1; i <= TUN_MTU_SIZE (frame); ++i)
- {
- update_time ();
-
- msg (M_INFO, "TESTING ENCRYPT/DECRYPT of packet length=%d", i);
-
- /*
- * Load src with random data.
- */
- ASSERT (buf_init (&src, 0));
- ASSERT (i <= src.capacity);
- src.len = i;
- ASSERT (rand_bytes (BPTR (&src), BLEN (&src)));
-
- /* copy source to input buf */
- buf = work;
- buf_p = buf_write_alloc (&buf, BLEN (&src));
- ASSERT(buf_p);
- memcpy (buf_p, BPTR (&src), BLEN (&src));
-
- /* initialize work buffer with FRAME_HEADROOM bytes of prepend capacity */
- ASSERT (buf_init (&encrypt_workspace, FRAME_HEADROOM (frame)));
-
- /* encrypt */
- openvpn_encrypt (&buf, encrypt_workspace, co);
-
- /* decrypt */
- openvpn_decrypt (&buf, decrypt_workspace, co, frame, BPTR (&buf));
-
- /* compare */
- if (buf.len != src.len)
- msg (M_FATAL, "SELF TEST FAILED, src.len=%d buf.len=%d", src.len, buf.len);
- for (j = 0; j < i; ++j)
- {
- const uint8_t in = *(BPTR (&src) + j);
- const uint8_t out = *(BPTR (&buf) + j);
- if (in != out)
- msg (M_FATAL, "SELF TEST FAILED, pos=%d in=%d out=%d", j, in, out);
- }
- }
- msg (M_INFO, PACKAGE_NAME " crypto self-test mode SUCCEEDED.");
- gc_free (&gc);
+ msg(M_INFO, "Entering " PACKAGE_NAME " crypto self-test mode.");
+ for (i = 1; i <= TUN_MTU_SIZE(frame); ++i)
+ {
+ update_time();
+
+ msg(M_INFO, "TESTING ENCRYPT/DECRYPT of packet length=%d", i);
+
+ /*
+ * Load src with random data.
+ */
+ ASSERT(buf_init(&src, 0));
+ ASSERT(i <= src.capacity);
+ src.len = i;
+ ASSERT(rand_bytes(BPTR(&src), BLEN(&src)));
+
+ /* copy source to input buf */
+ buf = work;
+ buf_p = buf_write_alloc(&buf, BLEN(&src));
+ ASSERT(buf_p);
+ memcpy(buf_p, BPTR(&src), BLEN(&src));
+
+ /* initialize work buffer with FRAME_HEADROOM bytes of prepend capacity */
+ ASSERT(buf_init(&encrypt_workspace, FRAME_HEADROOM(frame)));
+
+ /* encrypt */
+ openvpn_encrypt(&buf, encrypt_workspace, co);
+
+ /* decrypt */
+ openvpn_decrypt(&buf, decrypt_workspace, co, frame, BPTR(&buf));
+
+ /* compare */
+ if (buf.len != src.len)
+ {
+ msg(M_FATAL, "SELF TEST FAILED, src.len=%d buf.len=%d", src.len, buf.len);
+ }
+ for (j = 0; j < i; ++j)
+ {
+ const uint8_t in = *(BPTR(&src) + j);
+ const uint8_t out = *(BPTR(&buf) + j);
+ if (in != out)
+ {
+ msg(M_FATAL, "SELF TEST FAILED, pos=%d in=%d out=%d", j, in, out);
+ }
+ }
+ }
+ msg(M_INFO, PACKAGE_NAME " crypto self-test mode SUCCEEDED.");
+ gc_free(&gc);
}
void
-crypto_read_openvpn_key (const struct key_type *key_type,
- struct key_ctx_bi *ctx, const char *key_file, const char *key_inline,
- const int key_direction, const char *key_name, const char *opt_name)
+crypto_read_openvpn_key(const struct key_type *key_type,
+ struct key_ctx_bi *ctx, const char *key_file, const char *key_inline,
+ const int key_direction, const char *key_name, const char *opt_name)
{
- struct key2 key2;
- struct key_direction_state kds;
- char log_prefix[128] = { 0 };
+ struct key2 key2;
+ struct key_direction_state kds;
+ char log_prefix[128] = { 0 };
- if (key_inline)
+ if (key_inline)
{
- read_key_file (&key2, key_inline, RKF_MUST_SUCCEED|RKF_INLINE);
+ read_key_file(&key2, key_inline, RKF_MUST_SUCCEED|RKF_INLINE);
}
- else
+ else
{
- read_key_file (&key2, key_file, RKF_MUST_SUCCEED);
+ read_key_file(&key2, key_file, RKF_MUST_SUCCEED);
}
- if (key2.n != 2)
+ if (key2.n != 2)
{
- msg (M_ERR, "File '%s' does not have OpenVPN Static Key format. Using "
- "free-form passphrase file is not supported anymore.", key_file);
+ msg(M_ERR, "File '%s' does not have OpenVPN Static Key format. Using "
+ "free-form passphrase file is not supported anymore.", key_file);
}
- /* check for and fix highly unlikely key problems */
- verify_fix_key2 (&key2, key_type, key_file);
+ /* check for and fix highly unlikely key problems */
+ verify_fix_key2(&key2, key_type, key_file);
- /* handle key direction */
- key_direction_state_init (&kds, key_direction);
- must_have_n_keys (key_file, opt_name, &key2, kds.need_keys);
+ /* handle key direction */
+ key_direction_state_init(&kds, key_direction);
+ must_have_n_keys(key_file, opt_name, &key2, kds.need_keys);
- /* initialize key in both directions */
- openvpn_snprintf (log_prefix, sizeof (log_prefix), "Outgoing %s", key_name);
- init_key_ctx (&ctx->encrypt, &key2.keys[kds.out_key], key_type,
- OPENVPN_OP_ENCRYPT, log_prefix);
- openvpn_snprintf (log_prefix, sizeof (log_prefix), "Incoming %s", key_name);
- init_key_ctx (&ctx->decrypt, &key2.keys[kds.in_key], key_type,
- OPENVPN_OP_DECRYPT, log_prefix);
+ /* initialize key in both directions */
+ openvpn_snprintf(log_prefix, sizeof(log_prefix), "Outgoing %s", key_name);
+ init_key_ctx(&ctx->encrypt, &key2.keys[kds.out_key], key_type,
+ OPENVPN_OP_ENCRYPT, log_prefix);
+ openvpn_snprintf(log_prefix, sizeof(log_prefix), "Incoming %s", key_name);
+ init_key_ctx(&ctx->decrypt, &key2.keys[kds.in_key], key_type,
+ OPENVPN_OP_DECRYPT, log_prefix);
- secure_memzero (&key2, sizeof (key2));
+ secure_memzero(&key2, sizeof(key2));
}
/* header and footer for static key file */
@@ -1131,198 +1212,221 @@ static const char static_key_head[] = "-----BEGIN OpenVPN Static key V1-----";
static const char static_key_foot[] = "-----END OpenVPN Static key V1-----";
static const char printable_char_fmt[] =
- "Non-Hex character ('%c') found at line %d in key file '%s' (%d/%d/%d bytes found/min/max)";
+ "Non-Hex character ('%c') found at line %d in key file '%s' (%d/%d/%d bytes found/min/max)";
static const char unprintable_char_fmt[] =
- "Non-Hex, unprintable character (0x%02x) found at line %d in key file '%s' (%d/%d/%d bytes found/min/max)";
+ "Non-Hex, unprintable character (0x%02x) found at line %d in key file '%s' (%d/%d/%d bytes found/min/max)";
/* read key from file */
void
-read_key_file (struct key2 *key2, const char *file, const unsigned int flags)
+read_key_file(struct key2 *key2, const char *file, const unsigned int flags)
{
- struct gc_arena gc = gc_new ();
- struct buffer in;
- int fd, size;
- uint8_t hex_byte[3] = {0, 0, 0};
- const char *error_filename = file;
-
- /* parse info */
- const unsigned char *cp;
- int hb_index = 0;
- int line_num = 1;
- int line_index = 0;
- int match = 0;
-
- /* output */
- uint8_t* out = (uint8_t*) &key2->keys;
- const int keylen = sizeof (key2->keys);
- int count = 0;
-
- /* parse states */
-# define PARSE_INITIAL 0
-# define PARSE_HEAD 1
-# define PARSE_DATA 2
-# define PARSE_DATA_COMPLETE 3
-# define PARSE_FOOT 4
-# define PARSE_FINISHED 5
- int state = PARSE_INITIAL;
-
- /* constants */
- const int hlen = strlen (static_key_head);
- const int flen = strlen (static_key_foot);
- const int onekeylen = sizeof (key2->keys[0]);
-
- CLEAR (*key2);
-
- /*
- * Key can be provided as a filename in 'file' or if RKF_INLINE
- * is set, the actual key data itself in ascii form.
- */
- if (flags & RKF_INLINE) /* 'file' is a string containing ascii representation of key */
- {
- size = strlen (file) + 1;
- buf_set_read (&in, (const uint8_t *)file, size);
- error_filename = INLINE_FILE_TAG;
- }
- else /* 'file' is a filename which refers to a file containing the ascii key */
- {
- in = alloc_buf_gc (2048, &gc);
- fd = platform_open (file, O_RDONLY, 0);
- if (fd == -1)
- msg (M_ERR, "Cannot open file key file '%s'", file);
- size = read (fd, in.data, in.capacity);
- if (size < 0)
- msg (M_FATAL, "Read error on key file ('%s')", file);
- if (size == in.capacity)
- msg (M_FATAL, "Key file ('%s') can be a maximum of %d bytes", file, (int)in.capacity);
- close (fd);
- }
-
- cp = (unsigned char *)in.data;
- while (size > 0)
- {
- const unsigned char c = *cp;
+ struct gc_arena gc = gc_new();
+ struct buffer in;
+ int fd, size;
+ uint8_t hex_byte[3] = {0, 0, 0};
+ const char *error_filename = file;
+
+ /* parse info */
+ const unsigned char *cp;
+ int hb_index = 0;
+ int line_num = 1;
+ int line_index = 0;
+ int match = 0;
+
+ /* output */
+ uint8_t *out = (uint8_t *) &key2->keys;
+ const int keylen = sizeof(key2->keys);
+ int count = 0;
+
+ /* parse states */
+#define PARSE_INITIAL 0
+#define PARSE_HEAD 1
+#define PARSE_DATA 2
+#define PARSE_DATA_COMPLETE 3
+#define PARSE_FOOT 4
+#define PARSE_FINISHED 5
+ int state = PARSE_INITIAL;
+
+ /* constants */
+ const int hlen = strlen(static_key_head);
+ const int flen = strlen(static_key_foot);
+ const int onekeylen = sizeof(key2->keys[0]);
+
+ CLEAR(*key2);
+
+ /*
+ * Key can be provided as a filename in 'file' or if RKF_INLINE
+ * is set, the actual key data itself in ascii form.
+ */
+ if (flags & RKF_INLINE) /* 'file' is a string containing ascii representation of key */
+ {
+ size = strlen(file) + 1;
+ buf_set_read(&in, (const uint8_t *)file, size);
+ error_filename = INLINE_FILE_TAG;
+ }
+ else /* 'file' is a filename which refers to a file containing the ascii key */
+ {
+ in = alloc_buf_gc(2048, &gc);
+ fd = platform_open(file, O_RDONLY, 0);
+ if (fd == -1)
+ {
+ msg(M_ERR, "Cannot open file key file '%s'", file);
+ }
+ size = read(fd, in.data, in.capacity);
+ if (size < 0)
+ {
+ msg(M_FATAL, "Read error on key file ('%s')", file);
+ }
+ if (size == in.capacity)
+ {
+ msg(M_FATAL, "Key file ('%s') can be a maximum of %d bytes", file, (int)in.capacity);
+ }
+ close(fd);
+ }
+
+ cp = (unsigned char *)in.data;
+ while (size > 0)
+ {
+ const unsigned char c = *cp;
#if 0
- msg (M_INFO, "char='%c'[%d] s=%d ln=%d li=%d m=%d c=%d",
- c, (int)c, state, line_num, line_index, match, count);
+ msg(M_INFO, "char='%c'[%d] s=%d ln=%d li=%d m=%d c=%d",
+ c, (int)c, state, line_num, line_index, match, count);
#endif
- if (c == '\n')
- {
- line_index = match = 0;
- ++line_num;
- }
- else
- {
- /* first char of new line */
- if (!line_index)
- {
- /* first char of line after header line? */
- if (state == PARSE_HEAD)
- state = PARSE_DATA;
-
- /* first char of footer */
- if ((state == PARSE_DATA || state == PARSE_DATA_COMPLETE) && c == '-')
- state = PARSE_FOOT;
- }
-
- /* compare read chars with header line */
- if (state == PARSE_INITIAL)
- {
- if (line_index < hlen && c == static_key_head[line_index])
- {
- if (++match == hlen)
- state = PARSE_HEAD;
- }
- }
-
- /* compare read chars with footer line */
- if (state == PARSE_FOOT)
- {
- if (line_index < flen && c == static_key_foot[line_index])
- {
- if (++match == flen)
- state = PARSE_FINISHED;
- }
- }
-
- /* reading key */
- if (state == PARSE_DATA)
- {
- if (isxdigit(c))
- {
- ASSERT (hb_index >= 0 && hb_index < 2);
- hex_byte[hb_index++] = c;
- if (hb_index == 2)
- {
- unsigned int u;
- ASSERT(sscanf((const char *)hex_byte, "%x", &u) == 1);
- *out++ = u;
- hb_index = 0;
- if (++count == keylen)
- state = PARSE_DATA_COMPLETE;
- }
- }
- else if (isspace(c))
- ;
- else
- {
- msg (M_FATAL,
- (isprint (c) ? printable_char_fmt : unprintable_char_fmt),
- c, line_num, error_filename, count, onekeylen, keylen);
- }
- }
- ++line_index;
- }
- ++cp;
- --size;
- }
-
- /*
- * Normally we will read either 1 or 2 keys from file.
- */
- key2->n = count / onekeylen;
-
- ASSERT (key2->n >= 0 && key2->n <= (int) SIZE (key2->keys));
-
- if (flags & RKF_MUST_SUCCEED)
- {
- if (!key2->n)
- msg (M_FATAL, "Insufficient key material or header text not found in file '%s' (%d/%d/%d bytes found/min/max)",
- error_filename, count, onekeylen, keylen);
-
- if (state != PARSE_FINISHED)
- msg (M_FATAL, "Footer text not found in file '%s' (%d/%d/%d bytes found/min/max)",
- error_filename, count, onekeylen, keylen);
- }
-
- /* zero file read buffer if not an inline file */
- if (!(flags & RKF_INLINE))
- buf_clear (&in);
+ if (c == '\n')
+ {
+ line_index = match = 0;
+ ++line_num;
+ }
+ else
+ {
+ /* first char of new line */
+ if (!line_index)
+ {
+ /* first char of line after header line? */
+ if (state == PARSE_HEAD)
+ {
+ state = PARSE_DATA;
+ }
+
+ /* first char of footer */
+ if ((state == PARSE_DATA || state == PARSE_DATA_COMPLETE) && c == '-')
+ {
+ state = PARSE_FOOT;
+ }
+ }
+
+ /* compare read chars with header line */
+ if (state == PARSE_INITIAL)
+ {
+ if (line_index < hlen && c == static_key_head[line_index])
+ {
+ if (++match == hlen)
+ {
+ state = PARSE_HEAD;
+ }
+ }
+ }
+
+ /* compare read chars with footer line */
+ if (state == PARSE_FOOT)
+ {
+ if (line_index < flen && c == static_key_foot[line_index])
+ {
+ if (++match == flen)
+ {
+ state = PARSE_FINISHED;
+ }
+ }
+ }
+
+ /* reading key */
+ if (state == PARSE_DATA)
+ {
+ if (isxdigit(c))
+ {
+ ASSERT(hb_index >= 0 && hb_index < 2);
+ hex_byte[hb_index++] = c;
+ if (hb_index == 2)
+ {
+ unsigned int u;
+ ASSERT(sscanf((const char *)hex_byte, "%x", &u) == 1);
+ *out++ = u;
+ hb_index = 0;
+ if (++count == keylen)
+ {
+ state = PARSE_DATA_COMPLETE;
+ }
+ }
+ }
+ else if (isspace(c))
+ {
+ }
+ else
+ {
+ msg(M_FATAL,
+ (isprint(c) ? printable_char_fmt : unprintable_char_fmt),
+ c, line_num, error_filename, count, onekeylen, keylen);
+ }
+ }
+ ++line_index;
+ }
+ ++cp;
+ --size;
+ }
+
+ /*
+ * Normally we will read either 1 or 2 keys from file.
+ */
+ key2->n = count / onekeylen;
+
+ ASSERT(key2->n >= 0 && key2->n <= (int) SIZE(key2->keys));
+
+ if (flags & RKF_MUST_SUCCEED)
+ {
+ if (!key2->n)
+ {
+ msg(M_FATAL, "Insufficient key material or header text not found in file '%s' (%d/%d/%d bytes found/min/max)",
+ error_filename, count, onekeylen, keylen);
+ }
+
+ if (state != PARSE_FINISHED)
+ {
+ msg(M_FATAL, "Footer text not found in file '%s' (%d/%d/%d bytes found/min/max)",
+ error_filename, count, onekeylen, keylen);
+ }
+ }
+
+ /* zero file read buffer if not an inline file */
+ if (!(flags & RKF_INLINE))
+ {
+ buf_clear(&in);
+ }
#if 0
- /* DEBUGGING */
- {
- int i;
- printf ("KEY READ, n=%d\n", key2->n);
- for (i = 0; i < (int) SIZE (key2->keys); ++i)
- {
- /* format key as ascii */
- const char *fmt = format_hex_ex ((const uint8_t*)&key2->keys[i],
- sizeof (key2->keys[i]),
- 0,
- 16,
- "\n",
- &gc);
- printf ("[%d]\n%s\n\n", i, fmt);
- }
- }
+ /* DEBUGGING */
+ {
+ int i;
+ printf("KEY READ, n=%d\n", key2->n);
+ for (i = 0; i < (int) SIZE(key2->keys); ++i)
+ {
+ /* format key as ascii */
+ const char *fmt = format_hex_ex((const uint8_t *)&key2->keys[i],
+ sizeof(key2->keys[i]),
+ 0,
+ 16,
+ "\n",
+ &gc);
+ printf("[%d]\n%s\n\n", i, fmt);
+ }
+ }
#endif
- /* pop our garbage collection level */
- gc_free (&gc);
+ /* pop our garbage collection level */
+ gc_free(&gc);
}
/*
@@ -1330,222 +1434,261 @@ read_key_file (struct key2 *key2, const char *file, const unsigned int flags)
* written.
*/
int
-write_key_file (const int nkeys, const char *filename)
+write_key_file(const int nkeys, const char *filename)
{
- struct gc_arena gc = gc_new ();
+ struct gc_arena gc = gc_new();
- int fd, i;
- int nbits = 0;
+ int fd, i;
+ int nbits = 0;
- /* must be large enough to hold full key file */
- struct buffer out = alloc_buf_gc (2048, &gc);
- struct buffer nbits_head_text = alloc_buf_gc (128, &gc);
+ /* must be large enough to hold full key file */
+ struct buffer out = alloc_buf_gc(2048, &gc);
+ struct buffer nbits_head_text = alloc_buf_gc(128, &gc);
- /* how to format the ascii file representation of key */
- const int bytes_per_line = 16;
+ /* how to format the ascii file representation of key */
+ const int bytes_per_line = 16;
- /* open key file */
- fd = platform_open (filename, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR);
+ /* open key file */
+ fd = platform_open(filename, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR);
- if (fd == -1)
- msg (M_ERR, "Cannot open shared secret file '%s' for write", filename);
+ if (fd == -1)
+ {
+ msg(M_ERR, "Cannot open shared secret file '%s' for write", filename);
+ }
- buf_printf (&out, "%s\n", static_key_head);
+ buf_printf(&out, "%s\n", static_key_head);
- for (i = 0; i < nkeys; ++i)
+ for (i = 0; i < nkeys; ++i)
{
- struct key key;
- char* fmt;
+ struct key key;
+ char *fmt;
- /* generate random bits */
- generate_key_random (&key, NULL);
+ /* generate random bits */
+ generate_key_random(&key, NULL);
- /* format key as ascii */
- fmt = format_hex_ex ((const uint8_t*)&key,
- sizeof (key),
- 0,
- bytes_per_line,
- "\n",
- &gc);
+ /* format key as ascii */
+ fmt = format_hex_ex((const uint8_t *)&key,
+ sizeof(key),
+ 0,
+ bytes_per_line,
+ "\n",
+ &gc);
- /* increment random bits counter */
- nbits += sizeof (key) * 8;
+ /* increment random bits counter */
+ nbits += sizeof(key) * 8;
- /* write to holding buffer */
- buf_printf (&out, "%s\n", fmt);
+ /* write to holding buffer */
+ buf_printf(&out, "%s\n", fmt);
- /* zero memory which held key component (will be freed by GC) */
- secure_memzero (fmt, strlen (fmt));
- secure_memzero (&key, sizeof (key));
+ /* zero memory which held key component (will be freed by GC) */
+ secure_memzero(fmt, strlen(fmt));
+ secure_memzero(&key, sizeof(key));
}
- buf_printf (&out, "%s\n", static_key_foot);
+ buf_printf(&out, "%s\n", static_key_foot);
- /* write number of bits */
- buf_printf (&nbits_head_text, "#\n# %d bit OpenVPN static key\n#\n", nbits);
- buf_write_string_file (&nbits_head_text, filename, fd);
+ /* write number of bits */
+ buf_printf(&nbits_head_text, "#\n# %d bit OpenVPN static key\n#\n", nbits);
+ buf_write_string_file(&nbits_head_text, filename, fd);
- /* write key file, now formatted in out, to file */
- buf_write_string_file (&out, filename, fd);
+ /* write key file, now formatted in out, to file */
+ buf_write_string_file(&out, filename, fd);
- if (close (fd))
- msg (M_ERR, "Close error on shared secret file %s", filename);
+ if (close(fd))
+ {
+ msg(M_ERR, "Close error on shared secret file %s", filename);
+ }
- /* zero memory which held file content (memory will be freed by GC) */
- buf_clear (&out);
+ /* zero memory which held file content (memory will be freed by GC) */
+ buf_clear(&out);
- /* pop our garbage collection level */
- gc_free (&gc);
+ /* pop our garbage collection level */
+ gc_free(&gc);
- return nbits;
+ return nbits;
}
void
-must_have_n_keys (const char *filename, const char *option, const struct key2 *key2, int n)
+must_have_n_keys(const char *filename, const char *option, const struct key2 *key2, int n)
{
- if (key2->n < n)
+ if (key2->n < n)
{
#ifdef ENABLE_SMALL
- msg (M_FATAL, "Key file '%s' used in --%s contains insufficient key material [keys found=%d required=%d]", filename, option, key2->n, n);
+ msg(M_FATAL, "Key file '%s' used in --%s contains insufficient key material [keys found=%d required=%d]", filename, option, key2->n, n);
#else
- msg (M_FATAL, "Key file '%s' used in --%s contains insufficient key material [keys found=%d required=%d] -- try generating a new key file with '" PACKAGE " --genkey --secret [file]', or use the existing key file in bidirectional mode by specifying --%s without a key direction parameter", filename, option, key2->n, n, option);
+ msg(M_FATAL, "Key file '%s' used in --%s contains insufficient key material [keys found=%d required=%d] -- try generating a new key file with '" PACKAGE " --genkey --secret [file]', or use the existing key file in bidirectional mode by specifying --%s without a key direction parameter", filename, option, key2->n, n, option);
#endif
}
}
int
-ascii2keydirection (int msglevel, const char *str)
+ascii2keydirection(int msglevel, const char *str)
{
- if (!str)
- return KEY_DIRECTION_BIDIRECTIONAL;
- else if (!strcmp (str, "0"))
- return KEY_DIRECTION_NORMAL;
- else if (!strcmp (str, "1"))
- return KEY_DIRECTION_INVERSE;
- else
- {
- msg (msglevel, "Unknown key direction '%s' -- must be '0' or '1'", str);
- return -1;
- }
- return KEY_DIRECTION_BIDIRECTIONAL; /* NOTREACHED */
+ if (!str)
+ {
+ return KEY_DIRECTION_BIDIRECTIONAL;
+ }
+ else if (!strcmp(str, "0"))
+ {
+ return KEY_DIRECTION_NORMAL;
+ }
+ else if (!strcmp(str, "1"))
+ {
+ return KEY_DIRECTION_INVERSE;
+ }
+ else
+ {
+ msg(msglevel, "Unknown key direction '%s' -- must be '0' or '1'", str);
+ return -1;
+ }
+ return KEY_DIRECTION_BIDIRECTIONAL; /* NOTREACHED */
}
const char *
-keydirection2ascii (int kd, bool remote)
+keydirection2ascii(int kd, bool remote)
{
- if (kd == KEY_DIRECTION_BIDIRECTIONAL)
- return NULL;
- else if (kd == KEY_DIRECTION_NORMAL)
- return remote ? "1" : "0";
- else if (kd == KEY_DIRECTION_INVERSE)
- return remote ? "0" : "1";
- else
+ if (kd == KEY_DIRECTION_BIDIRECTIONAL)
+ {
+ return NULL;
+ }
+ else if (kd == KEY_DIRECTION_NORMAL)
+ {
+ return remote ? "1" : "0";
+ }
+ else if (kd == KEY_DIRECTION_INVERSE)
+ {
+ return remote ? "0" : "1";
+ }
+ else
{
- ASSERT (0);
+ ASSERT(0);
}
- return NULL; /* NOTREACHED */
+ return NULL; /* NOTREACHED */
}
void
-key_direction_state_init (struct key_direction_state *kds, int key_direction)
+key_direction_state_init(struct key_direction_state *kds, int key_direction)
{
- CLEAR (*kds);
- switch (key_direction)
- {
- case KEY_DIRECTION_NORMAL:
- kds->out_key = 0;
- kds->in_key = 1;
- kds->need_keys = 2;
- break;
- case KEY_DIRECTION_INVERSE:
- kds->out_key = 1;
- kds->in_key = 0;
- kds->need_keys = 2;
- break;
- case KEY_DIRECTION_BIDIRECTIONAL:
- kds->out_key = 0;
- kds->in_key = 0;
- kds->need_keys = 1;
- break;
- default:
- ASSERT (0);
+ CLEAR(*kds);
+ switch (key_direction)
+ {
+ case KEY_DIRECTION_NORMAL:
+ kds->out_key = 0;
+ kds->in_key = 1;
+ kds->need_keys = 2;
+ break;
+
+ case KEY_DIRECTION_INVERSE:
+ kds->out_key = 1;
+ kds->in_key = 0;
+ kds->need_keys = 2;
+ break;
+
+ case KEY_DIRECTION_BIDIRECTIONAL:
+ kds->out_key = 0;
+ kds->in_key = 0;
+ kds->need_keys = 1;
+ break;
+
+ default:
+ ASSERT(0);
}
}
void
-verify_fix_key2 (struct key2 *key2, const struct key_type *kt, const char *shared_secret_file)
+verify_fix_key2(struct key2 *key2, const struct key_type *kt, const char *shared_secret_file)
{
- int i;
+ int i;
- for (i = 0; i < key2->n; ++i)
+ for (i = 0; i < key2->n; ++i)
{
- /* Fix parity for DES keys and make sure not a weak key */
- fixup_key (&key2->keys[i], kt);
-
- /* This should be a very improbable failure */
- if (!check_key (&key2->keys[i], kt))
- msg (M_FATAL, "Key #%d in '%s' is bad. Try making a new key with --genkey.",
- i+1, shared_secret_file);
+ /* Fix parity for DES keys and make sure not a weak key */
+ fixup_key(&key2->keys[i], kt);
+
+ /* This should be a very improbable failure */
+ if (!check_key(&key2->keys[i], kt))
+ {
+ msg(M_FATAL, "Key #%d in '%s' is bad. Try making a new key with --genkey.",
+ i+1, shared_secret_file);
+ }
}
}
/* given a key and key_type, write key to buffer */
bool
-write_key (const struct key *key, const struct key_type *kt,
- struct buffer *buf)
+write_key(const struct key *key, const struct key_type *kt,
+ struct buffer *buf)
{
- ASSERT (kt->cipher_length <= MAX_CIPHER_KEY_LENGTH
- && kt->hmac_length <= MAX_HMAC_KEY_LENGTH);
+ ASSERT(kt->cipher_length <= MAX_CIPHER_KEY_LENGTH
+ && kt->hmac_length <= MAX_HMAC_KEY_LENGTH);
- if (!buf_write (buf, &kt->cipher_length, 1))
- return false;
- if (!buf_write (buf, &kt->hmac_length, 1))
- return false;
- if (!buf_write (buf, key->cipher, kt->cipher_length))
- return false;
- if (!buf_write (buf, key->hmac, kt->hmac_length))
- return false;
+ if (!buf_write(buf, &kt->cipher_length, 1))
+ {
+ return false;
+ }
+ if (!buf_write(buf, &kt->hmac_length, 1))
+ {
+ return false;
+ }
+ if (!buf_write(buf, key->cipher, kt->cipher_length))
+ {
+ return false;
+ }
+ if (!buf_write(buf, key->hmac, kt->hmac_length))
+ {
+ return false;
+ }
- return true;
+ return true;
}
/*
* Given a key_type and buffer, read key from buffer.
* Return: 1 on success
* -1 read failure
- * 0 on key length mismatch
+ * 0 on key length mismatch
*/
int
-read_key (struct key *key, const struct key_type *kt, struct buffer *buf)
+read_key(struct key *key, const struct key_type *kt, struct buffer *buf)
{
- uint8_t cipher_length;
- uint8_t hmac_length;
+ uint8_t cipher_length;
+ uint8_t hmac_length;
- CLEAR (*key);
- if (!buf_read (buf, &cipher_length, 1))
- goto read_err;
- if (!buf_read (buf, &hmac_length, 1))
- goto read_err;
+ CLEAR(*key);
+ if (!buf_read(buf, &cipher_length, 1))
+ {
+ goto read_err;
+ }
+ if (!buf_read(buf, &hmac_length, 1))
+ {
+ goto read_err;
+ }
- if (!buf_read (buf, key->cipher, cipher_length))
- goto read_err;
- if (!buf_read (buf, key->hmac, hmac_length))
- goto read_err;
+ if (!buf_read(buf, key->cipher, cipher_length))
+ {
+ goto read_err;
+ }
+ if (!buf_read(buf, key->hmac, hmac_length))
+ {
+ goto read_err;
+ }
- if (cipher_length != kt->cipher_length || hmac_length != kt->hmac_length)
- goto key_len_err;
+ if (cipher_length != kt->cipher_length || hmac_length != kt->hmac_length)
+ {
+ goto key_len_err;
+ }
- return 1;
+ return 1;
read_err:
- msg (D_TLS_ERRORS, "TLS Error: error reading key from remote");
- return -1;
+ msg(D_TLS_ERRORS, "TLS Error: error reading key from remote");
+ return -1;
key_len_err:
- msg (D_TLS_ERRORS,
- "TLS Error: key length mismatch, local cipher/hmac %d/%d, remote cipher/hmac %d/%d",
- kt->cipher_length, kt->hmac_length, cipher_length, hmac_length);
- return 0;
+ msg(D_TLS_ERRORS,
+ "TLS Error: key length mismatch, local cipher/hmac %d/%d, remote cipher/hmac %d/%d",
+ kt->cipher_length, kt->hmac_length, cipher_length, hmac_length);
+ return 0;
}
/*
@@ -1561,125 +1704,138 @@ static int nonce_secret_len = 0; /* GLOBAL */
/* Reset the nonce value, also done periodically to refresh entropy */
static void
-prng_reset_nonce ()
+prng_reset_nonce()
{
- const int size = md_kt_size (nonce_md) + nonce_secret_len;
+ const int size = md_kt_size(nonce_md) + nonce_secret_len;
#if 1 /* Must be 1 for real usage */
- if (!rand_bytes (nonce_data, size))
- msg (M_FATAL, "ERROR: Random number generator cannot obtain entropy for PRNG");
+ if (!rand_bytes(nonce_data, size))
+ {
+ msg(M_FATAL, "ERROR: Random number generator cannot obtain entropy for PRNG");
+ }
#else
/* Only for testing -- will cause a predictable PRNG sequence */
{
- int i;
- for (i = 0; i < size; ++i)
- nonce_data[i] = (uint8_t) i;
+ int i;
+ for (i = 0; i < size; ++i)
+ nonce_data[i] = (uint8_t) i;
}
#endif
}
void
-prng_init (const char *md_name, const int nonce_secret_len_parm)
+prng_init(const char *md_name, const int nonce_secret_len_parm)
{
- prng_uninit ();
- nonce_md = md_name ? md_kt_get (md_name) : NULL;
- if (nonce_md)
- {
- ASSERT (nonce_secret_len_parm >= NONCE_SECRET_LEN_MIN && nonce_secret_len_parm <= NONCE_SECRET_LEN_MAX);
- nonce_secret_len = nonce_secret_len_parm;
- {
- const int size = md_kt_size(nonce_md) + nonce_secret_len;
- dmsg (D_CRYPTO_DEBUG, "PRNG init md=%s size=%d", md_kt_name(nonce_md), size);
- nonce_data = (uint8_t*) malloc (size);
- check_malloc_return (nonce_data);
- prng_reset_nonce();
- }
+ prng_uninit();
+ nonce_md = md_name ? md_kt_get(md_name) : NULL;
+ if (nonce_md)
+ {
+ ASSERT(nonce_secret_len_parm >= NONCE_SECRET_LEN_MIN && nonce_secret_len_parm <= NONCE_SECRET_LEN_MAX);
+ nonce_secret_len = nonce_secret_len_parm;
+ {
+ const int size = md_kt_size(nonce_md) + nonce_secret_len;
+ dmsg(D_CRYPTO_DEBUG, "PRNG init md=%s size=%d", md_kt_name(nonce_md), size);
+ nonce_data = (uint8_t *) malloc(size);
+ check_malloc_return(nonce_data);
+ prng_reset_nonce();
+ }
}
}
void
-prng_uninit (void)
+prng_uninit(void)
{
- free (nonce_data);
- nonce_data = NULL;
- nonce_md = NULL;
- nonce_secret_len = 0;
+ free(nonce_data);
+ nonce_data = NULL;
+ nonce_md = NULL;
+ nonce_secret_len = 0;
}
void
-prng_bytes (uint8_t *output, int len)
+prng_bytes(uint8_t *output, int len)
{
- static size_t processed = 0;
-
- if (nonce_md)
- {
- const int md_size = md_kt_size (nonce_md);
- while (len > 0)
- {
- const int blen = min_int (len, md_size);
- md_full(nonce_md, nonce_data, md_size + nonce_secret_len, nonce_data);
- memcpy (output, nonce_data, blen);
- output += blen;
- len -= blen;
-
- /* Ensure that random data is reset regularly */
- processed += blen;
- if(processed > PRNG_NONCE_RESET_BYTES) {
- prng_reset_nonce();
- processed = 0;
- }
- }
- }
- else
- ASSERT (rand_bytes (output, len));
+ static size_t processed = 0;
+
+ if (nonce_md)
+ {
+ const int md_size = md_kt_size(nonce_md);
+ while (len > 0)
+ {
+ const int blen = min_int(len, md_size);
+ md_full(nonce_md, nonce_data, md_size + nonce_secret_len, nonce_data);
+ memcpy(output, nonce_data, blen);
+ output += blen;
+ len -= blen;
+
+ /* Ensure that random data is reset regularly */
+ processed += blen;
+ if (processed > PRNG_NONCE_RESET_BYTES)
+ {
+ prng_reset_nonce();
+ processed = 0;
+ }
+ }
+ }
+ else
+ {
+ ASSERT(rand_bytes(output, len));
+ }
}
/* an analogue to the random() function, but use prng_bytes */
long int
get_random()
{
- long int l;
- prng_bytes ((unsigned char *)&l, sizeof(l));
- if (l < 0)
- l = -l;
- return l;
+ long int l;
+ prng_bytes((unsigned char *)&l, sizeof(l));
+ if (l < 0)
+ {
+ l = -l;
+ }
+ return l;
}
static const cipher_name_pair *
get_cipher_name_pair(const char *cipher_name) {
- const cipher_name_pair *pair;
- size_t i = 0;
+ const cipher_name_pair *pair;
+ size_t i = 0;
- /* Search for a cipher name translation */
- for (; i < cipher_name_translation_table_count; i++)
+ /* Search for a cipher name translation */
+ for (; i < cipher_name_translation_table_count; i++)
{
- pair = &cipher_name_translation_table[i];
- if (0 == strcmp (cipher_name, pair->openvpn_name) ||
- 0 == strcmp (cipher_name, pair->lib_name))
- return pair;
+ pair = &cipher_name_translation_table[i];
+ if (0 == strcmp(cipher_name, pair->openvpn_name)
+ || 0 == strcmp(cipher_name, pair->lib_name))
+ {
+ return pair;
+ }
}
- /* Nothing found, return null */
- return NULL;
+ /* Nothing found, return null */
+ return NULL;
}
const char *
-translate_cipher_name_from_openvpn (const char *cipher_name) {
- const cipher_name_pair *pair = get_cipher_name_pair(cipher_name);
+translate_cipher_name_from_openvpn(const char *cipher_name) {
+ const cipher_name_pair *pair = get_cipher_name_pair(cipher_name);
- if (NULL == pair)
- return cipher_name;
+ if (NULL == pair)
+ {
+ return cipher_name;
+ }
- return pair->lib_name;
+ return pair->lib_name;
}
const char *
-translate_cipher_name_to_openvpn (const char *cipher_name) {
- const cipher_name_pair *pair = get_cipher_name_pair(cipher_name);
+translate_cipher_name_to_openvpn(const char *cipher_name) {
+ const cipher_name_pair *pair = get_cipher_name_pair(cipher_name);
- if (NULL == pair)
- return cipher_name;
+ if (NULL == pair)
+ {
+ return cipher_name;
+ }
- return pair->openvpn_name;
+ return pair->openvpn_name;
}
#endif /* ENABLE_CRYPTO */