Skip to content

Commit

Permalink
Add proper check for crypto modes (CBC or OFB/CFB)
Browse files Browse the repository at this point in the history
OpenSSL has added AEAD-CBC mode ciphers like AES-128-CBC-HMAC-SHA1, which
have mode EVP_CIPH_CBC_MODE, but require a different API (the AEAD API).
So, add extra checks to filter out those AEAD-mode ciphers.

Adding these made the crypto library agnostic function cfb_ofb_mode()
superfuous, so removed that on the go.

Also update all cipher mode checks to use the new cipher_kt_mode_*()
functions for consistency.

Signed-off-by: Steffan Karger <[email protected]>
Acked-by: Arne Schwabe <[email protected]>
Message-Id: <[email protected]>
URL: http://article.gmane.org/gmane.network.openvpn.devel/8779
Signed-off-by: Gert Doering <[email protected]>
  • Loading branch information
syzzer authored and cron2 committed Jul 7, 2014
1 parent c353af2 commit a4b27b6
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 27 deletions.
36 changes: 15 additions & 21 deletions src/openvpn/crypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,10 @@ openvpn_encrypt (struct buffer *buf, struct buffer work,
{
uint8_t iv_buf[OPENVPN_MAX_IV_LENGTH];
const int iv_size = cipher_ctx_iv_length (ctx->cipher);
const unsigned int mode = cipher_ctx_mode (ctx->cipher);
const cipher_kt_t *cipher_kt = cipher_ctx_get_cipher_kt (ctx->cipher);
int outlen;

if (mode == OPENVPN_MODE_CBC)
if (cipher_kt_mode_cbc(cipher_kt))
{
CLEAR (iv_buf);

Expand All @@ -119,7 +119,7 @@ openvpn_encrypt (struct buffer *buf, struct buffer work,
ASSERT (packet_id_write (&pin, buf, BOOL_CAST (opt->flags & CO_PACKET_ID_LONG_FORM), true));
}
}
else if (mode == OPENVPN_MODE_CFB || mode == OPENVPN_MODE_OFB)
else if (cipher_kt_mode_ofb_cfb(cipher_kt))
{
struct packet_id_net pin;
struct buffer b;
Expand Down Expand Up @@ -171,7 +171,10 @@ openvpn_encrypt (struct buffer *buf, struct buffer work,
/* Flush the encryption buffer */
ASSERT(cipher_ctx_final(ctx->cipher, BPTR (&work) + outlen, &outlen));
work.len += outlen;
ASSERT (mode != OPENVPN_MODE_CBC || outlen == iv_size);

/* 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)
Expand Down Expand Up @@ -272,8 +275,8 @@ openvpn_decrypt (struct buffer *buf, struct buffer work,

if (ctx->cipher)
{
const unsigned int mode = cipher_ctx_mode (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];
int outlen;

Expand Down Expand Up @@ -320,7 +323,7 @@ openvpn_decrypt (struct buffer *buf, struct buffer work,

/* Get packet ID from plaintext buffer or IV, depending on cipher mode */
{
if (mode == OPENVPN_MODE_CBC)
if (cipher_kt_mode_cbc(cipher_kt))
{
if (opt->packet_id)
{
Expand All @@ -329,7 +332,7 @@ openvpn_decrypt (struct buffer *buf, struct buffer work,
have_pin = true;
}
}
else if (mode == OPENVPN_MODE_CFB || mode == OPENVPN_MODE_OFB)
else if (cipher_kt_mode_ofb_cfb(cipher_kt))
{
struct buffer b;

Expand Down Expand Up @@ -426,10 +429,9 @@ init_key_type (struct key_type *kt, const char *ciphername,

/* check legal cipher mode */
{
const unsigned int mode = cipher_kt_mode (kt->cipher);
if (!(mode == OPENVPN_MODE_CBC
if (!(cipher_kt_mode_cbc(kt->cipher)
#ifdef ENABLE_OFB_CFB_MODE
|| (cfb_ofb_allowed && (mode == OPENVPN_MODE_CFB || mode == OPENVPN_MODE_OFB))
|| (cfb_ofb_allowed && cipher_kt_mode_ofb_cfb(kt->cipher))
#endif
))
#ifdef ENABLE_SMALL
Expand Down Expand Up @@ -606,18 +608,10 @@ fixup_key (struct key *key, const struct key_type *kt)
void
check_replay_iv_consistency (const struct key_type *kt, bool packet_id, bool use_iv)
{
if (cfb_ofb_mode (kt) && !(packet_id && use_iv))
msg (M_FATAL, "--no-replay or --no-iv cannot be used with a CFB or OFB mode cipher");
}
ASSERT(kt);

bool
cfb_ofb_mode (const struct key_type* kt)
{
if (kt && kt->cipher) {
const unsigned int mode = cipher_kt_mode (kt->cipher);
return mode == OPENVPN_MODE_CFB || mode == OPENVPN_MODE_OFB;
}
return false;
if (cipher_kt_mode_ofb_cfb(kt->cipher) && !(packet_id && use_iv))
msg (M_FATAL, "--no-replay or --no-iv cannot be used with a CFB or OFB mode cipher");
}

/*
Expand Down
2 changes: 0 additions & 2 deletions src/openvpn/crypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -187,8 +187,6 @@ bool write_key (const struct key *key, const struct key_type *kt,

int read_key (struct key *key, const struct key_type *kt, struct buffer *buf);

bool cfb_ofb_mode (const struct key_type* kt);

void init_key_type (struct key_type *kt, const char *ciphername,
bool ciphername_defined, const char *authname, bool authname_defined,
int keysize, bool cfb_ofb_allowed, bool warn);
Expand Down
30 changes: 30 additions & 0 deletions src/openvpn/crypto_backend.h
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,26 @@ int cipher_kt_block_size (const cipher_kt_t *cipher_kt);
*/
int cipher_kt_mode (const cipher_kt_t *cipher_kt);

/**
* Check of the supplied cipher is a supported CBC mode cipher.
*
* @param cipher Static cipher parameters. May not be NULL.
*
* @return true iff the cipher is a CBC mode cipher.
*/
bool cipher_kt_mode_cbc(const cipher_kt_t *cipher)
__attribute__((nonnull));

/**
* Check of the supplied cipher is a supported OFB or CFB mode cipher.
*
* @param cipher Static cipher parameters. May not be NULL.
*
* @return true iff the cipher is a OFB or CFB mode cipher.
*/
bool cipher_kt_mode_ofb_cfb(const cipher_kt_t *cipher)
__attribute__((nonnull));


/**
*
Expand Down Expand Up @@ -287,6 +307,16 @@ int cipher_ctx_block_size (const cipher_ctx_t *ctx);
*/
int cipher_ctx_mode (const cipher_ctx_t *ctx);

/**
* Returns the static cipher parameters for this context.
*
* @param ctx Cipher's context. May not be NULL.
*
* @return Static cipher parameters for the supplied context.
*/
const cipher_kt_t *cipher_ctx_get_cipher_kt (const cipher_ctx_t *ctx)
__attribute__((nonnull));

/**
* Resets the given cipher context, setting the IV to the specified value.
* Preserves the associated key information.
Expand Down
35 changes: 32 additions & 3 deletions src/openvpn/crypto_openssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -261,10 +261,9 @@ show_available_ciphers ()
const EVP_CIPHER *cipher = EVP_get_cipherbynid (nid);
if (cipher)
{
const unsigned int mode = EVP_CIPHER_mode (cipher);
if (mode == EVP_CIPH_CBC_MODE
if (cipher_kt_mode_cbc(cipher)
#ifdef ENABLE_OFB_CFB_MODE
|| mode == EVP_CIPH_CFB_MODE || mode == EVP_CIPH_OFB_MODE
|| cipher_kt_mode_ofb_cfb(cipher)
#endif
)
printf ("%s %d bit default key (%s)\n",
Expand Down Expand Up @@ -483,6 +482,29 @@ cipher_kt_mode (const EVP_CIPHER *cipher_kt)
return EVP_CIPHER_mode (cipher_kt);
}

bool
cipher_kt_mode_cbc(const cipher_kt_t *cipher)
{
return cipher_kt_mode(cipher) == OPENVPN_MODE_CBC
#ifdef EVP_CIPH_FLAG_AEAD_CIPHER
/* Exclude AEAD cipher modes, they require a different API */
&& !(EVP_CIPHER_flags(cipher) & EVP_CIPH_FLAG_AEAD_CIPHER)
#endif
;
}

bool
cipher_kt_mode_ofb_cfb(const cipher_kt_t *cipher)
{
return (cipher_kt_mode(cipher) == OPENVPN_MODE_OFB ||
cipher_kt_mode(cipher) == OPENVPN_MODE_CFB)
#ifdef EVP_CIPH_FLAG_AEAD_CIPHER
/* Exclude AEAD cipher modes, they require a different API */
&& !(EVP_CIPHER_flags(cipher) & EVP_CIPH_FLAG_AEAD_CIPHER)
#endif
;
}

/*
*
* Generic cipher context functions
Expand Down Expand Up @@ -536,6 +558,13 @@ cipher_ctx_mode (const EVP_CIPHER_CTX *ctx)
return EVP_CIPHER_CTX_mode (ctx);
}

const cipher_kt_t *
cipher_ctx_get_cipher_kt (const cipher_ctx_t *ctx)
{
return EVP_CIPHER_CTX_cipher(ctx);
}


int
cipher_ctx_reset (EVP_CIPHER_CTX *ctx, uint8_t *iv_buf)
{
Expand Down
21 changes: 21 additions & 0 deletions src/openvpn/crypto_polarssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,19 @@ cipher_kt_mode (const cipher_info_t *cipher_kt)
return cipher_kt->mode;
}

bool
cipher_kt_mode_cbc(const cipher_kt_t *cipher)
{
return cipher_kt_mode(cipher) == OPENVPN_MODE_CBC;
}

bool
cipher_kt_mode_ofb_cfb(const cipher_kt_t *cipher)
{
return (cipher_kt_mode(cipher) == OPENVPN_MODE_OFB ||
cipher_kt_mode(cipher) == OPENVPN_MODE_CFB);
}


/*
*
Expand Down Expand Up @@ -464,6 +477,14 @@ int cipher_ctx_mode (const cipher_context_t *ctx)
return cipher_kt_mode(ctx->cipher_info);
}

const cipher_kt_t *
cipher_ctx_get_cipher_kt (const cipher_ctx_t *ctx)
{
ASSERT(NULL != ctx);

return ctx->cipher_info;
}

int cipher_ctx_reset (cipher_context_t *ctx, uint8_t *iv_buf)
{
int retval = cipher_reset(ctx);
Expand Down
2 changes: 1 addition & 1 deletion src/openvpn/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -2186,7 +2186,7 @@ do_init_crypto_tls (struct context *c, const unsigned int flags)
options->use_iv);

/* In short form, unique datagram identifier is 32 bits, in long form 64 bits */
packet_id_long_form = cfb_ofb_mode (&c->c1.ks.key_type);
packet_id_long_form = cipher_kt_mode_ofb_cfb (c->c1.ks.key_type.cipher);

/* Compute MTU parameters */
crypto_adjust_frame_parameters (&c->c2.frame,
Expand Down

0 comments on commit a4b27b6

Please sign in to comment.