diff options
author | Adriaan de Jong <dejong@fox-it.com> | 2011-06-23 17:39:42 +0200 |
---|---|---|
committer | David Sommerseth <davids@redhat.com> | 2011-10-19 22:13:25 +0200 |
commit | 485c5f76a15e7f9950a3ee3126dbf50f66f9ef82 (patch) | |
tree | 23209c35da7ddf067803027582190ecec1b6d8c7 | |
parent | 670f9dd91aed7ac435b79c0e28e49fa7c256642c (diff) | |
download | openvpn-485c5f76a15e7f9950a3ee3126dbf50f66f9ef82.tar.gz openvpn-485c5f76a15e7f9950a3ee3126dbf50f66f9ef82.tar.xz openvpn-485c5f76a15e7f9950a3ee3126dbf50f66f9ef82.zip |
Refactored cipher functions
Signed-off-by: Adriaan de Jong <dejong@fox-it.com>
Acked-by: David Sommerseth <davids@redhat.com>
Signed-off-by: David Sommerseth <davids@redhat.com>
-rw-r--r-- | crypto.c | 68 | ||||
-rw-r--r-- | crypto.h | 26 | ||||
-rw-r--r-- | crypto_backend.h | 100 | ||||
-rw-r--r-- | crypto_openssl.c | 89 |
4 files changed, 218 insertions, 65 deletions
@@ -75,8 +75,8 @@ openvpn_encrypt (struct buffer *buf, struct buffer work, if (ctx->cipher) { uint8_t iv_buf[OPENVPN_MAX_IV_LENGTH]; - const int iv_size = EVP_CIPHER_CTX_iv_length (ctx->cipher); - const unsigned int mode = EVP_CIPHER_CTX_mode (ctx->cipher); + const int iv_size = cipher_ctx_iv_length (ctx->cipher); + const unsigned int mode = cipher_ctx_mode (ctx->cipher); int outlen; if (mode == OPENVPN_MODE_CBC) @@ -124,10 +124,10 @@ openvpn_encrypt (struct buffer *buf, struct buffer work, format_hex (BPTR (buf), BLEN (buf), 80, &gc)); /* cipher_ctx was already initialized with key & keylen */ - ASSERT (EVP_CipherInit_ov (ctx->cipher, NULL, NULL, iv_buf, DO_ENCRYPT)); + ASSERT (cipher_ctx_reset(ctx->cipher, iv_buf)); /* Buffer overflow check */ - if (!buf_safe (&work, buf->len + EVP_CIPHER_CTX_block_size (ctx->cipher))) + 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, @@ -136,16 +136,16 @@ openvpn_encrypt (struct buffer *buf, struct buffer work, work.capacity, work.offset, work.len, - EVP_CIPHER_CTX_block_size (ctx->cipher)); + cipher_ctx_block_size (ctx->cipher)); goto err; } /* Encrypt packet ID, payload */ - ASSERT (EVP_CipherUpdate_ov (ctx->cipher, BPTR (&work), &outlen, BPTR (buf), BLEN (buf))); + ASSERT (cipher_ctx_update (ctx->cipher, BPTR (&work), &outlen, BPTR (buf), BLEN (buf))); work.len += outlen; /* Flush the encryption buffer */ - ASSERT (EVP_CipherFinal (ctx->cipher, BPTR (&work) + outlen, &outlen)); + ASSERT(cipher_ctx_final(ctx->cipher, BPTR (&work) + outlen, &outlen)); work.len += outlen; ASSERT (outlen == iv_size); @@ -248,8 +248,8 @@ openvpn_decrypt (struct buffer *buf, struct buffer work, if (ctx->cipher) { - const unsigned int mode = EVP_CIPHER_CTX_mode (ctx->cipher); - const int iv_size = EVP_CIPHER_CTX_iv_length (ctx->cipher); + const unsigned int mode = cipher_ctx_mode (ctx->cipher); + const int iv_size = cipher_ctx_iv_length (ctx->cipher); uint8_t iv_buf[OPENVPN_MAX_IV_LENGTH]; int outlen; @@ -274,7 +274,7 @@ openvpn_decrypt (struct buffer *buf, struct buffer work, CRYPT_ERROR ("missing payload"); /* ctx->cipher was already initialized with key & keylen */ - if (!EVP_CipherInit_ov (ctx->cipher, NULL, NULL, iv_buf, DO_DECRYPT)) + if (!cipher_ctx_reset (ctx->cipher, iv_buf)) CRYPT_ERROR ("cipher init failed"); /* Buffer overflow check (should never happen) */ @@ -282,12 +282,12 @@ openvpn_decrypt (struct buffer *buf, struct buffer work, CRYPT_ERROR ("buffer overflow"); /* Decrypt packet ID, payload */ - if (!EVP_CipherUpdate_ov (ctx->cipher, BPTR (&work), &outlen, BPTR (buf), BLEN (buf))) + if (!cipher_ctx_update (ctx->cipher, BPTR (&work), &outlen, BPTR (buf), BLEN (buf))) CRYPT_ERROR ("cipher update failed"); work.len += outlen; /* Flush the decryption buffer */ - if (!EVP_CipherFinal (ctx->cipher, BPTR (&work) + outlen, &outlen)) + if (!cipher_ctx_final (ctx->cipher, BPTR (&work) + outlen, &outlen)) CRYPT_ERROR ("cipher final failed"); work.len += outlen; @@ -383,41 +383,6 @@ crypto_adjust_frame_parameters(struct frame *frame, kt->hmac_length); } -static void -init_cipher (EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, - struct key *key, const struct key_type *kt, int enc, - const char *prefix) -{ - struct gc_arena gc = gc_new (); - - EVP_CIPHER_CTX_init (ctx); - if (!EVP_CipherInit_ov (ctx, cipher, NULL, NULL, enc)) - msg (M_SSLERR, "EVP cipher init #1"); -#ifdef HAVE_EVP_CIPHER_CTX_SET_KEY_LENGTH - if (!EVP_CIPHER_CTX_set_key_length (ctx, kt->cipher_length)) - msg (M_SSLERR, "EVP set key size"); -#endif - if (!EVP_CipherInit_ov (ctx, NULL, key->cipher, NULL, enc)) - msg (M_SSLERR, "EVP cipher init #2"); - - msg (D_HANDSHAKE, "%s: Cipher '%s' initialized with %d bit key", - prefix, - OBJ_nid2sn (EVP_CIPHER_CTX_nid (ctx)), - EVP_CIPHER_CTX_key_length (ctx) * 8); - - /* make sure we used a big enough key */ - ASSERT (EVP_CIPHER_CTX_key_length (ctx) <= kt->cipher_length); - - 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, - EVP_CIPHER_CTX_block_size (ctx), - EVP_CIPHER_CTX_iv_length (ctx)); - - gc_free (&gc); -} - /* * Build a struct key_type. */ @@ -476,8 +441,9 @@ init_key_ctx (struct key_ctx *ctx, struct key *key, CLEAR (*ctx); if (kt->cipher && kt->cipher_length > 0) { - ALLOC_OBJ (ctx->cipher, EVP_CIPHER_CTX); - init_cipher (ctx->cipher, kt->cipher, key, kt, enc, prefix); + ALLOC_OBJ(ctx->cipher, cipher_ctx_t); + cipher_ctx_init (ctx->cipher, key->cipher, kt->cipher_length, + kt->cipher, enc, prefix); } if (kt->digest && kt->hmac_length > 0) { @@ -492,8 +458,8 @@ free_key_ctx (struct key_ctx *ctx) { if (ctx->cipher) { - EVP_CIPHER_CTX_cleanup (ctx->cipher); - free (ctx->cipher); + cipher_ctx_cleanup(ctx->cipher); + free(ctx->cipher); ctx->cipher = NULL; } if (ctx->hmac) @@ -182,6 +182,17 @@ struct key /**< %Key material for HMAC operations. */ }; + +/** + * Container for one set of OpenSSL cipher and/or HMAC contexts. + * @ingroup control_processor + */ +struct key_ctx +{ + cipher_ctx_t *cipher; /**< Generic cipher %context. */ + hmac_ctx_t *hmac; /**< Generic HMAC %context. */ +}; + #define KEY_DIRECTION_BIDIRECTIONAL 0 /* same keys for both directions */ #define KEY_DIRECTION_NORMAL 1 /* encrypt with keys[0], decrypt with keys[1] */ #define KEY_DIRECTION_INVERSE 2 /* encrypt with keys[1], decrypt with keys[0] */ @@ -224,16 +235,6 @@ struct key_direction_state }; /** - * Container for one set of OpenSSL cipher and/or HMAC contexts. - * @ingroup control_processor - */ -struct key_ctx -{ - EVP_CIPHER_CTX *cipher; /**< OpenSSL cipher %context. */ - HMAC_CTX *hmac; /**< OpenSSL HMAC %context. */ -}; - -/** * Container for two sets of OpenSSL cipher and/or HMAC contexts for both * sending and receiving directions. * @ingroup control_processor @@ -313,9 +314,6 @@ 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); -/* enc parameter in init_key_ctx */ -#define DO_ENCRYPT 1 -#define DO_DECRYPT 0 /* * Key context functions */ @@ -325,6 +323,7 @@ void init_key_ctx (struct key_ctx *ctx, struct key *key, const char *prefix); void free_key_ctx (struct key_ctx *ctx); + void free_key_ctx_bi (struct key_ctx_bi *ctx); @@ -401,7 +400,6 @@ bool openvpn_decrypt (struct buffer *buf, struct buffer work, /** @} name Functions for performing security operations on data channel packets */ - void crypto_adjust_frame_parameters(struct frame *frame, const struct key_type* kt, bool cipher_defined, diff --git a/crypto_backend.h b/crypto_backend.h index c70b60f..8d1f37e 100644 --- a/crypto_backend.h +++ b/crypto_backend.h @@ -219,6 +219,106 @@ int cipher_kt_block_size (const cipher_kt_t *cipher_kt); bool cipher_kt_mode (const cipher_kt_t *cipher_kt); +/** + * + * Generic cipher functions + * + */ + +/** + * Initialise a cipher context, based on the given key and key type. + * + * @param ctx Cipher context. May not be NULL + * @param key Buffer containing the key to use + * @param key_len Length of the key, in bytes + * @param kt Static cipher parameters to use + * @param enc Whether to encrypt or decrypt (either + * \c POLARSSL_OP_ENCRYPT or \c POLARSSL_OP_DECRYPT). + * @param prefix Prefix to use for output. + */ +void cipher_ctx_init (cipher_ctx_t *ctx, uint8_t *key, int key_len, + const cipher_kt_t *kt, int enc, const char *prefix); + +/** + * Cleanup the specified context. + * + * @param ctx Cipher context to cleanup. + */ +void cipher_ctx_cleanup (cipher_ctx_t *ctx); + +/** + * Returns the size of the IV used by the cipher, in bytes, or 0 if no IV is + * used. + * + * @param ctx The cipher's context + * + * @return Size of the IV, in bytes, or \c 0 if the cipher does not + * use an IV or ctx was NULL. + */ +int cipher_ctx_iv_length (const cipher_ctx_t *ctx); + +/** + * Returns the block size of the cipher, in bytes. + * + * @param ctx The cipher's context + * + * @return Block size, in bytes, or 0 if ctx was NULL. + */ +int cipher_ctx_block_size (const cipher_ctx_t *ctx); + +/** + * Returns the mode that the cipher runs in. + * + * @param ctx Cipher's context. May not be NULL. + * + * @return Cipher mode, either \c OPENVPN_MODE_CBC, \c + * OPENVPN_MODE_OFB or \c OPENVPN_MODE_CFB + */ +int cipher_ctx_mode (const cipher_ctx_t *ctx); + +/** + * Resets the given cipher context, setting the IV to the specified value. + * Preserves the associated key information. + * + * @param ctx Cipher's context. May not be NULL. + * @param iv_buf The IV to use. + * + * @return \c 0 on failure, \c 1 on success. + */ +int cipher_ctx_reset (cipher_ctx_t *ctx, uint8_t *iv_buf); + +/** + * Updates the given cipher context, encrypting data in the source buffer, and + * placing any complete blocks in the destination buffer. + * + * Note that if a complete block cannot be written, data is cached in the + * context, and emitted at a later call to \c cipher_ctx_update, or by a call + * to \c cipher_ctx_final(). This implies that dst should have enough room for + * src_len + \c cipher_ctx_block_size() - 1. + * + * @param ctx Cipher's context. May not be NULL. + * @param dst Destination buffer + * @param dst_len Length of the destination buffer, in bytes + * @param src Source buffer + * @param src_len Length of the source buffer, in bytes + * + * @return \c 0 on failure, \c 1 on success. + */ +int cipher_ctx_update (cipher_ctx_t *ctx, uint8_t *dst, int *dst_len, + uint8_t *src, int src_len); + +/** + * Pads the final cipher block using PKCS padding, and output to the destination + * buffer. + * + * @param ctx Cipher's context. May not be NULL. + * @param dst Destination buffer + * @param dst_len Length of the destination buffer, in bytes + * + * @return \c 0 on failure, \c 1 on success. + */ +int cipher_ctx_final (cipher_ctx_t *ctx, uint8_t *dst, int *dst_len); + /* * * Generic message digest information functions diff --git a/crypto_openssl.c b/crypto_openssl.c index 15e2aa6..57f10ae 100644 --- a/crypto_openssl.c +++ b/crypto_openssl.c @@ -560,6 +560,95 @@ cipher_kt_mode (const EVP_CIPHER *cipher_kt) return EVP_CIPHER_mode (cipher_kt); } +/* + * + * Generic cipher context functions + * + */ + + +void +cipher_ctx_init (EVP_CIPHER_CTX *ctx, uint8_t *key, int key_len, + const EVP_CIPHER *kt, int enc, const char *prefix) +{ + struct gc_arena gc = gc_new (); + + ASSERT(NULL != kt && NULL != ctx); + + CLEAR (*ctx); + + EVP_CIPHER_CTX_init (ctx); + if (!EVP_CipherInit_ov (ctx, kt, NULL, NULL, enc)) + msg (M_SSLERR, "EVP cipher init #1"); +#ifdef HAVE_EVP_CIPHER_CTX_SET_KEY_LENGTH + if (!EVP_CIPHER_CTX_set_key_length (ctx, key_len)) + msg (M_SSLERR, "EVP set key size"); +#endif + if (!EVP_CipherInit_ov (ctx, NULL, key, NULL, enc)) + msg (M_SSLERR, "EVP cipher init #2"); + + msg (D_HANDSHAKE, "%s: Cipher '%s' initialized with %d bit key", + prefix, + OBJ_nid2sn (EVP_CIPHER_CTX_nid (ctx)), + EVP_CIPHER_CTX_key_length (ctx) * 8); + + /* make sure we used a big enough key */ + ASSERT (EVP_CIPHER_CTX_key_length (ctx) <= key_len); + + dmsg (D_SHOW_KEYS, "%s: CIPHER KEY: %s", prefix, + format_hex (key, key_len, 0, &gc)); + dmsg (D_CRYPTO_DEBUG, "%s: CIPHER block_size=%d iv_size=%d", + prefix, + EVP_CIPHER_CTX_block_size (ctx), + EVP_CIPHER_CTX_iv_length (ctx)); + + gc_free (&gc); +} + +void +cipher_ctx_cleanup (EVP_CIPHER_CTX *ctx) +{ + EVP_CIPHER_CTX_cleanup (ctx); +} + +int +cipher_ctx_iv_length (const EVP_CIPHER_CTX *ctx) +{ + return EVP_CIPHER_CTX_iv_length (ctx); +} + +int +cipher_ctx_block_size(const EVP_CIPHER_CTX *ctx) +{ + return EVP_CIPHER_CTX_block_size (ctx); +} + +int +cipher_ctx_mode (const EVP_CIPHER_CTX *ctx) +{ + return EVP_CIPHER_CTX_mode (ctx); +} + +int +cipher_ctx_reset (EVP_CIPHER_CTX *ctx, uint8_t *iv_buf) +{ + return EVP_CipherInit_ov (ctx, NULL, NULL, iv_buf, -1); +} + +int +cipher_ctx_update (EVP_CIPHER_CTX *ctx, uint8_t *dst, int *dst_len, + uint8_t *src, int src_len) +{ + return EVP_CipherUpdate_ov (ctx, dst, dst_len, src, src_len); +} + +int +cipher_ctx_final (EVP_CIPHER_CTX *ctx, uint8_t *dst, int *dst_len) +{ + return EVP_CipherFinal (ctx, dst, dst_len); +} + + void cipher_des_encrypt_ecb (const unsigned char key[8], unsigned char *src, |