From 21ada3bd7e9bc5cca7c2c8399adcbaa044bf8103 Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Thu, 11 Apr 2019 08:18:34 +0000 Subject: IPSEC-MB: Use random & non-repeating IV (VPP-1642) hard code IV and key lengths based on cipher. Init IV from random data, use AES instruction to rotate. Change-Id: I13a6507d12267b823c528660a903787baeba47a0 Signed-off-by: Neale Ranns --- src/plugins/crypto_ipsecmb/CMakeLists.txt | 6 +++ src/plugins/crypto_ipsecmb/ipsecmb.c | 65 ++++++++++++++++++++++++------- src/vnet/crypto/crypto.c | 7 +++- src/vnet/ipsec/esp_decrypt.c | 4 +- src/vnet/ipsec/esp_encrypt.c | 2 - test/test_ipsec_ah.py | 2 +- test/test_ipsec_esp.py | 2 +- 7 files changed, 65 insertions(+), 23 deletions(-) diff --git a/src/plugins/crypto_ipsecmb/CMakeLists.txt b/src/plugins/crypto_ipsecmb/CMakeLists.txt index a6bb8dc7dcd..0d08032c07e 100644 --- a/src/plugins/crypto_ipsecmb/CMakeLists.txt +++ b/src/plugins/crypto_ipsecmb/CMakeLists.txt @@ -12,6 +12,10 @@ # See the License for the specific language governing permissions and # limitations under the License. +if(NOT CMAKE_SYSTEM_PROCESSOR MATCHES "amd64.*|x86_64.*|AMD64.*") + return() +endif() + find_path(IPSECMB_INCLUDE_DIR NAMES intel-ipsec-mb.h HINTS ${IPSECMB_INCLUDE_DIR_HINT}) find_library(IPSECMB_LIB NAMES libIPSec_MB.a HINTS ${IPSECMB_LIB_DIR_HINT}) @@ -33,3 +37,5 @@ if(IPSECMB_INCLUDE_DIR AND IPSECMB_LIB) else() message(STATUS "Intel IPSecMB not found") endif() + +target_compile_options(crypto_ipsecmb_plugin PRIVATE "-march=silvermont") diff --git a/src/plugins/crypto_ipsecmb/ipsecmb.c b/src/plugins/crypto_ipsecmb/ipsecmb.c index 309623ec5e4..8e40e3ec2e9 100644 --- a/src/plugins/crypto_ipsecmb/ipsecmb.c +++ b/src/plugins/crypto_ipsecmb/ipsecmb.c @@ -15,6 +15,8 @@ * limitations under the License. */ +#include + #include #include @@ -26,6 +28,7 @@ typedef struct { MB_MGR *mgr; + __m128i cbc_iv; } ipsecmb_per_thread_data_t; typedef struct ipsecmb_main_t_ @@ -42,9 +45,9 @@ static ipsecmb_main_t ipsecmb_main; _(SHA512, SHA_512, sha512) #define foreach_ipsecmb_cipher_op \ - _(AES_128_CBC, 128) \ - _(AES_192_CBC, 192) \ - _(AES_256_CBC, 256) + _(AES_128_CBC, 128, 16, 16) \ + _(AES_192_CBC, 192, 24, 16) \ + _(AES_256_CBC, 256, 32, 16) always_inline void hash_expand_keys (const MB_MGR * mgr, @@ -200,9 +203,9 @@ ipsecmb_retire_cipher_job (JOB_AES_HMAC * job, u32 * n_fail) static_always_inline u32 ipsecmb_ops_cipher_inline (vlib_main_t * vm, - const ipsecmb_per_thread_data_t * ptd, + ipsecmb_per_thread_data_t * ptd, vnet_crypto_op_t * ops[], - u32 n_ops, + u32 n_ops, u32 key_len, u32 iv_len, keyexp_t fn, JOB_CIPHER_DIRECTION direction) { JOB_AES_HMAC *job; @@ -216,6 +219,7 @@ ipsecmb_ops_cipher_inline (vlib_main_t * vm, u8 aes_enc_key_expanded[EXPANDED_KEY_N_BYTES]; u8 aes_dec_key_expanded[EXPANDED_KEY_N_BYTES]; vnet_crypto_op_t *op = ops[i]; + __m128i iv; fn (op->key, aes_enc_key_expanded, aes_dec_key_expanded); @@ -231,11 +235,18 @@ ipsecmb_ops_cipher_inline (vlib_main_t * vm, job->cipher_direction = direction; job->chain_order = (direction == ENCRYPT ? CIPHER_HASH : HASH_CIPHER); - job->aes_key_len_in_bytes = op->key_len; + if ((direction == ENCRYPT) && (op->flags & VNET_CRYPTO_OP_FLAG_INIT_IV)) + { + iv = ptd->cbc_iv; + _mm_storeu_si128 ((__m128i *) op->iv, iv); + ptd->cbc_iv = _mm_aesenc_si128 (iv, iv); + } + + job->aes_key_len_in_bytes = key_len; job->aes_enc_key_expanded = aes_enc_key_expanded; job->aes_dec_key_expanded = aes_dec_key_expanded; job->iv = op->iv; - job->iv_len_in_bytes = op->iv_len; + job->iv_len_in_bytes = iv_len; job->user_data = op; @@ -257,7 +268,7 @@ ipsecmb_ops_cipher_inline (vlib_main_t * vm, return n_ops - n_fail; } -#define _(a, b) \ +#define _(a, b, c, d) \ static_always_inline u32 \ ipsecmb_ops_cipher_enc_##a (vlib_main_t * vm, \ vnet_crypto_op_t * ops[], \ @@ -269,14 +280,14 @@ ipsecmb_ops_cipher_enc_##a (vlib_main_t * vm, \ imbm = &ipsecmb_main; \ ptd = vec_elt_at_index (imbm->per_thread_data, vm->thread_index); \ \ - return ipsecmb_ops_cipher_inline (vm, ptd, ops, n_ops, \ + return ipsecmb_ops_cipher_inline (vm, ptd, ops, n_ops, c, d, \ ptd->mgr->keyexp_##b, \ ENCRYPT); \ } foreach_ipsecmb_cipher_op; #undef _ -#define _(a, b) \ +#define _(a, b, c, d) \ static_always_inline u32 \ ipsecmb_ops_cipher_dec_##a (vlib_main_t * vm, \ vnet_crypto_op_t * ops[], \ @@ -288,13 +299,35 @@ ipsecmb_ops_cipher_dec_##a (vlib_main_t * vm, \ imbm = &ipsecmb_main; \ ptd = vec_elt_at_index (imbm->per_thread_data, vm->thread_index); \ \ - return ipsecmb_ops_cipher_inline (vm, ptd, ops, n_ops, \ + return ipsecmb_ops_cipher_inline (vm, ptd, ops, n_ops, c, d, \ ptd->mgr->keyexp_##b, \ DECRYPT); \ } foreach_ipsecmb_cipher_op; #undef _ +clib_error_t * +crypto_ipsecmb_iv_init (ipsecmb_main_t * imbm) +{ + ipsecmb_per_thread_data_t *ptd; + clib_error_t *err = 0; + int fd; + + if ((fd = open ("/dev/urandom", O_RDONLY)) < 0) + return clib_error_return_unix (0, "failed to open '/dev/urandom'"); + + vec_foreach (ptd, imbm->per_thread_data) + { + if (read (fd, &ptd->cbc_iv, sizeof (ptd->cbc_iv)) != sizeof (ptd->cbc_iv)) + { + err = clib_error_return_unix (0, "'/dev/urandom' read failure"); + return (err); + } + } + + return (NULL); +} + static clib_error_t * crypto_ipsecmb_init (vlib_main_t * vm) { @@ -340,26 +373,30 @@ crypto_ipsecmb_init (vlib_main_t * vm) } } + if (clib_cpu_supports_x86_aes () && (error = crypto_ipsecmb_iv_init (imbm))) + return (error); + + #define _(a, b, c) \ vnet_crypto_register_ops_handler (vm, eidx, VNET_CRYPTO_OP_##a##_HMAC, \ ipsecmb_ops_hmac_##a); \ foreach_ipsecmb_hmac_op; #undef _ -#define _(a, b) \ +#define _(a, b, c, d) \ vnet_crypto_register_ops_handler (vm, eidx, VNET_CRYPTO_OP_##a##_ENC, \ ipsecmb_ops_cipher_enc_##a); \ foreach_ipsecmb_cipher_op; #undef _ -#define _(a, b) \ +#define _(a, b, c, d) \ vnet_crypto_register_ops_handler (vm, eidx, VNET_CRYPTO_OP_##a##_DEC, \ ipsecmb_ops_cipher_dec_##a); \ foreach_ipsecmb_cipher_op; #undef _ - return 0; + return (NULL); } VLIB_INIT_FUNCTION (crypto_ipsecmb_init); diff --git a/src/vnet/crypto/crypto.c b/src/vnet/crypto/crypto.c index 58b13638924..dbdb58b16f6 100644 --- a/src/vnet/crypto/crypto.c +++ b/src/vnet/crypto/crypto.c @@ -119,8 +119,11 @@ vnet_crypto_set_handler (char *alg_name, char *engine) if (id == 0) continue; od = vec_elt_at_index (cm->opt_data, id); - od->active_engine_index = p[0]; - cm->ops_handlers[id] = ce->ops_handlers[id]; + if (ce->ops_handlers[id]) + { + od->active_engine_index = p[0]; + cm->ops_handlers[id] = ce->ops_handlers[id]; + } } return 0; diff --git a/src/vnet/ipsec/esp_decrypt.c b/src/vnet/ipsec/esp_decrypt.c index de951d1dc85..fc4a99a873d 100644 --- a/src/vnet/ipsec/esp_decrypt.c +++ b/src/vnet/ipsec/esp_decrypt.c @@ -232,9 +232,7 @@ esp_decrypt_inline (vlib_main_t * vm, vec_add2_aligned (ptd->crypto_ops, op, 1, CLIB_CACHE_LINE_BYTES); vnet_crypto_op_init (op, sa0->crypto_dec_op_id); op->key = sa0->crypto_key.data; - op->key_len = sa0->crypto_key.len; op->iv = payload; - op->iv_len = cpd.iv_sz; op->src = op->dst = payload += cpd.iv_sz; op->len = len; op->user_data = b - bufs; @@ -287,7 +285,7 @@ esp_decrypt_inline (vlib_main_t * vm, bi = op->user_data; if (op->status == VNET_CRYPTO_OP_STATUS_FAIL_BAD_HMAC) - err = ESP_DECRYPT_ERROR_INTEG_ERROR; + err = ESP_DECRYPT_ERROR_DECRYPTION_FAILED; else err = ESP_DECRYPT_ERROR_CRYPTO_ENGINE_ERROR; diff --git a/src/vnet/ipsec/esp_encrypt.c b/src/vnet/ipsec/esp_encrypt.c index c8018594bd1..bb1effda68b 100644 --- a/src/vnet/ipsec/esp_encrypt.c +++ b/src/vnet/ipsec/esp_encrypt.c @@ -431,10 +431,8 @@ esp_encrypt_inline (vlib_main_t * vm, vlib_node_runtime_t * node, vec_add2_aligned (ptd->crypto_ops, op, 1, CLIB_CACHE_LINE_BYTES); vnet_crypto_op_init (op, sa0->crypto_enc_op_id); op->iv = payload - iv_sz; - op->iv_len = iv_sz; op->src = op->dst = payload; op->key = sa0->crypto_key.data; - op->key_len = sa0->crypto_key.len; op->len = payload_len - icv_sz; op->flags = VNET_CRYPTO_OP_FLAG_INIT_IV; op->user_data = b - bufs; diff --git a/test/test_ipsec_ah.py b/test/test_ipsec_ah.py index 38d97d584c5..65df8766aeb 100644 --- a/test/test_ipsec_ah.py +++ b/test/test_ipsec_ah.py @@ -337,7 +337,7 @@ class TestIpsecAhAll(ConfigIpsecAH, # loop through the VPP engines # for engine in engines: - self.vapi.cli("set crypto engine all %s" % engine) + self.vapi.cli("set crypto handler all %s" % engine) # # loop through each of the algorithms # diff --git a/test/test_ipsec_esp.py b/test/test_ipsec_esp.py index e5db0a627a5..15803744167 100644 --- a/test/test_ipsec_esp.py +++ b/test/test_ipsec_esp.py @@ -381,7 +381,7 @@ class TestIpsecEspAll(ConfigIpsecESP, # loop through the VPP engines # for engine in engines: - self.vapi.cli("set crypto engine all %s" % engine) + self.vapi.cli("set crypto handler all %s" % engine) # # loop through each of the algorithms -- cgit 1.2.3-korg