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 <steffan@karger.me>
Acked-by: Arne Schwabe <arne@rfc2549.org>
Message-Id: <
1402244175-31462-3-git-send-email-steffan@karger.me>
URL: http://article.gmane.org/gmane.network.openvpn.devel/8779
Signed-off-by: Gert Doering <gert@greenie.muc.de>
{
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);
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;
/* 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)
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;
/* 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)
{
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;
/* 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
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");
}
/*
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);
*/
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));
+
/**
*
*/
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.
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",
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
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)
{
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);
+}
+
/*
*
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);
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,