crypto/openssl: support AES-CCM
authorPablo de Lara <pablo.de.lara.guarch@intel.com>
Thu, 21 Sep 2017 13:11:19 +0000 (14:11 +0100)
committerPablo de Lara <pablo.de.lara.guarch@intel.com>
Thu, 12 Oct 2017 14:22:07 +0000 (15:22 +0100)
Add support to AES-CCM, for 128, 192 and 256-bit keys.

Signed-off-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
Acked-by: Fan Zhang <roy.fan.zhang@intel.com>
doc/guides/cryptodevs/features/default.ini
doc/guides/cryptodevs/features/openssl.ini
doc/guides/cryptodevs/openssl.rst
doc/guides/rel_notes/release_17_11.rst
drivers/crypto/openssl/rte_openssl_pmd.c
drivers/crypto/openssl/rte_openssl_pmd_ops.c
lib/librte_cryptodev/rte_crypto_sym.h

index 0926887..c98717a 100644 (file)
@@ -68,3 +68,6 @@ ZUC EIA3     =
 AES GCM (128) =
 AES GCM (192) =
 AES GCM (256) =
+AES CCM (128) =
+AES CCM (192) =
+AES CCM (256) =
index aeb2a50..385ec4e 100644 (file)
@@ -45,3 +45,6 @@ AES GMAC     = Y
 AES GCM (128) = Y
 AES GCM (192) = Y
 AES GCM (256) = Y
+AES CCM (128) = Y
+AES CCM (192) = Y
+AES CCM (256) = Y
index f18a456..243ea36 100644 (file)
@@ -67,6 +67,7 @@ Supported authentication algorithms:
 
 Supported AEAD algorithms:
 * ``RTE_CRYPTO_AEAD_AES_GCM``
+* ``RTE_CRYPTO_AEAD_AES_CCM``
 
 
 Installation
index d0b2ff6..847fdd8 100644 (file)
@@ -104,6 +104,7 @@ New Features
   The OpenSSL PMD has been updated with additional support for:
 
   * DES CBC algorithm.
+  * AES CCM algorithm.
 
 * **Add new benchmarking mode to dpdk-test-crypto-perf application.**
 
index cd80b99..95c0236 100644 (file)
@@ -287,6 +287,21 @@ get_aead_algo(enum rte_crypto_aead_algorithm sess_algo, size_t keylen,
                                res = -EINVAL;
                        }
                        break;
+               case RTE_CRYPTO_AEAD_AES_CCM:
+                       switch (keylen) {
+                       case 16:
+                               *algo = EVP_aes_128_ccm();
+                               break;
+                       case 24:
+                               *algo = EVP_aes_192_ccm();
+                               break;
+                       case 32:
+                               *algo = EVP_aes_256_ccm();
+                               break;
+                       default:
+                               res = -EINVAL;
+                       }
+                       break;
                default:
                        res = -EINVAL;
                        break;
@@ -305,6 +320,7 @@ openssl_set_sess_aead_enc_param(struct openssl_session *sess,
                uint8_t tag_len, uint8_t *key)
 {
        int iv_type = 0;
+       unsigned int do_ccm;
 
        sess->cipher.direction = RTE_CRYPTO_CIPHER_OP_ENCRYPT;
        sess->auth.operation = RTE_CRYPTO_AUTH_OP_GENERATE;
@@ -315,6 +331,14 @@ openssl_set_sess_aead_enc_param(struct openssl_session *sess,
                iv_type = EVP_CTRL_GCM_SET_IVLEN;
                if (tag_len != 16)
                        return -EINVAL;
+               do_ccm = 0;
+               break;
+       case RTE_CRYPTO_AEAD_AES_CCM:
+               iv_type = EVP_CTRL_CCM_SET_IVLEN;
+               /* Digest size can be 4, 6, 8, 10, 12, 14 or 16 bytes */
+               if (tag_len < 4 || tag_len > 16 || (tag_len & 1) == 1)
+                       return -EINVAL;
+               do_ccm = 1;
                break;
        default:
                return -ENOTSUP;
@@ -339,6 +363,10 @@ openssl_set_sess_aead_enc_param(struct openssl_session *sess,
                        NULL) <= 0)
                return -EINVAL;
 
+       if (do_ccm)
+               EVP_CIPHER_CTX_ctrl(sess->cipher.ctx, EVP_CTRL_CCM_SET_TAG,
+                               tag_len, NULL);
+
        if (EVP_EncryptInit_ex(sess->cipher.ctx, NULL, NULL, key, NULL) <= 0)
                return -EINVAL;
 
@@ -352,6 +380,7 @@ openssl_set_sess_aead_dec_param(struct openssl_session *sess,
                uint8_t tag_len, uint8_t *key)
 {
        int iv_type = 0;
+       unsigned int do_ccm = 0;
 
        sess->cipher.direction = RTE_CRYPTO_CIPHER_OP_DECRYPT;
        sess->auth.operation = RTE_CRYPTO_AUTH_OP_VERIFY;
@@ -363,6 +392,13 @@ openssl_set_sess_aead_dec_param(struct openssl_session *sess,
                if (tag_len != 16)
                        return -EINVAL;
                break;
+       case RTE_CRYPTO_AEAD_AES_CCM:
+               iv_type = EVP_CTRL_CCM_SET_IVLEN;
+               /* Digest size can be 4, 6, 8, 10, 12, 14 or 16 bytes */
+               if (tag_len < 4 || tag_len > 16 || (tag_len & 1) == 1)
+                       return -EINVAL;
+               do_ccm = 1;
+               break;
        default:
                return -ENOTSUP;
        }
@@ -386,6 +422,10 @@ openssl_set_sess_aead_dec_param(struct openssl_session *sess,
                        sess->iv.length, NULL) <= 0)
                return -EINVAL;
 
+       if (do_ccm)
+               EVP_CIPHER_CTX_ctrl(sess->cipher.ctx, EVP_CTRL_CCM_SET_TAG,
+                               tag_len, NULL);
+
        if (EVP_DecryptInit_ex(sess->cipher.ctx, NULL, NULL, key, NULL) <= 0)
                return -EINVAL;
 
@@ -600,7 +640,16 @@ openssl_set_session_aead_parameters(struct openssl_session *sess,
        sess->cipher.key.length = xform->aead.key.length;
 
        /* Set IV parameters */
-       sess->iv.offset = xform->aead.iv.offset;
+       if (xform->aead.algo == RTE_CRYPTO_AEAD_AES_CCM)
+               /*
+                * For AES-CCM, the actual IV is placed
+                * one byte after the start of the IV field,
+                * according to the API.
+                */
+               sess->iv.offset = xform->aead.iv.offset + 1;
+       else
+               sess->iv.offset = xform->aead.iv.offset;
+
        sess->iv.length = xform->aead.iv.length;
 
        sess->auth.aad_length = xform->aead.aad_length;
@@ -973,7 +1022,7 @@ process_cipher_des3ctr_err:
        return -EINVAL;
 }
 
-/** Process auth/encription aes-gcm algorithm */
+/** Process AES-GCM encrypt algorithm */
 static int
 process_openssl_auth_encryption_gcm(struct rte_mbuf *mbuf_src, int offset,
                int srclen, uint8_t *aad, int aadlen, uint8_t *iv,
@@ -1011,6 +1060,48 @@ process_auth_encryption_gcm_err:
        return -EINVAL;
 }
 
+/** Process AES-CCM encrypt algorithm */
+static int
+process_openssl_auth_encryption_ccm(struct rte_mbuf *mbuf_src, int offset,
+               int srclen, uint8_t *aad, int aadlen, uint8_t *iv,
+               uint8_t *dst, uint8_t *tag, uint8_t taglen, EVP_CIPHER_CTX *ctx)
+{
+       int len = 0;
+
+       if (EVP_EncryptInit_ex(ctx, NULL, NULL, NULL, iv) <= 0)
+               goto process_auth_encryption_ccm_err;
+
+       if (EVP_EncryptUpdate(ctx, NULL, &len, NULL, srclen) <= 0)
+               goto process_auth_encryption_ccm_err;
+
+       if (aadlen > 0)
+               /*
+                * For AES-CCM, the actual AAD is placed
+                * 18 bytes after the start of the AAD field,
+                * according to the API.
+                */
+               if (EVP_EncryptUpdate(ctx, NULL, &len, aad + 18, aadlen) <= 0)
+                       goto process_auth_encryption_ccm_err;
+
+       if (srclen > 0)
+               if (process_openssl_encryption_update(mbuf_src, offset, &dst,
+                               srclen, ctx))
+                       goto process_auth_encryption_ccm_err;
+
+       if (EVP_EncryptFinal_ex(ctx, dst, &len) <= 0)
+               goto process_auth_encryption_ccm_err;
+
+       if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_GET_TAG, taglen, tag) <= 0)
+               goto process_auth_encryption_ccm_err;
+
+       return 0;
+
+process_auth_encryption_ccm_err:
+       OPENSSL_LOG_ERR("Process openssl auth encryption ccm failed");
+       return -EINVAL;
+}
+
+/** Process AES-GCM decrypt algorithm */
 static int
 process_openssl_auth_decryption_gcm(struct rte_mbuf *mbuf_src, int offset,
                int srclen, uint8_t *aad, int aadlen, uint8_t *iv,
@@ -1039,16 +1130,52 @@ process_openssl_auth_decryption_gcm(struct rte_mbuf *mbuf_src, int offset,
                goto process_auth_decryption_gcm_err;
 
        if (EVP_DecryptFinal_ex(ctx, dst, &len) <= 0)
-               goto process_auth_decryption_gcm_final_err;
+               return -EFAULT;
 
        return 0;
 
 process_auth_decryption_gcm_err:
-       OPENSSL_LOG_ERR("Process openssl auth description gcm failed");
+       OPENSSL_LOG_ERR("Process openssl auth decryption gcm failed");
        return -EINVAL;
+}
 
-process_auth_decryption_gcm_final_err:
-       return -EFAULT;
+/** Process AES-CCM decrypt algorithm */
+static int
+process_openssl_auth_decryption_ccm(struct rte_mbuf *mbuf_src, int offset,
+               int srclen, uint8_t *aad, int aadlen, uint8_t *iv,
+               uint8_t *dst, uint8_t *tag, uint8_t tag_len,
+               EVP_CIPHER_CTX *ctx)
+{
+       int len = 0;
+
+       if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG, tag_len, tag) <= 0)
+               goto process_auth_decryption_ccm_err;
+
+       if (EVP_DecryptInit_ex(ctx, NULL, NULL, NULL, iv) <= 0)
+               goto process_auth_decryption_ccm_err;
+
+       if (EVP_DecryptUpdate(ctx, NULL, &len, NULL, srclen) <= 0)
+               goto process_auth_decryption_ccm_err;
+
+       if (aadlen > 0)
+               /*
+                * For AES-CCM, the actual AAD is placed
+                * 18 bytes after the start of the AAD field,
+                * according to the API.
+                */
+               if (EVP_DecryptUpdate(ctx, NULL, &len, aad + 18, aadlen) <= 0)
+                       goto process_auth_decryption_ccm_err;
+
+       if (srclen > 0)
+               if (process_openssl_decryption_update(mbuf_src, offset, &dst,
+                               srclen, ctx))
+                       return -EFAULT;
+
+       return 0;
+
+process_auth_decryption_ccm_err:
+       OPENSSL_LOG_ERR("Process openssl auth decryption ccm failed");
+       return -EINVAL;
 }
 
 /** Process standard openssl auth algorithms */
@@ -1169,6 +1296,7 @@ process_openssl_combined_op
        uint8_t *dst = NULL, *iv, *tag, *aad;
        int srclen, aadlen, status = -1;
        uint32_t offset;
+       uint8_t taglen;
 
        /*
         * Segmented destination buffer is not supported for
@@ -1204,16 +1332,34 @@ process_openssl_combined_op
                                offset + srclen);
        }
 
-       if (sess->cipher.direction == RTE_CRYPTO_CIPHER_OP_ENCRYPT)
-               status = process_openssl_auth_encryption_gcm(
-                               mbuf_src, offset, srclen,
-                               aad, aadlen, iv,
-                               dst, tag, sess->cipher.ctx);
-       else
-               status = process_openssl_auth_decryption_gcm(
-                               mbuf_src, offset, srclen,
-                               aad, aadlen, iv,
-                               dst, tag, sess->cipher.ctx);
+       taglen = sess->auth.digest_length;
+
+       if (sess->cipher.direction == RTE_CRYPTO_CIPHER_OP_ENCRYPT) {
+               if (sess->auth.algo == RTE_CRYPTO_AUTH_AES_GMAC ||
+                               sess->aead_algo == RTE_CRYPTO_AEAD_AES_GCM)
+                       status = process_openssl_auth_encryption_gcm(
+                                       mbuf_src, offset, srclen,
+                                       aad, aadlen, iv,
+                                       dst, tag, sess->cipher.ctx);
+               else
+                       status = process_openssl_auth_encryption_ccm(
+                                       mbuf_src, offset, srclen,
+                                       aad, aadlen, iv,
+                                       dst, tag, taglen, sess->cipher.ctx);
+
+       } else {
+               if (sess->auth.algo == RTE_CRYPTO_AUTH_AES_GMAC ||
+                               sess->aead_algo == RTE_CRYPTO_AEAD_AES_GCM)
+                       status = process_openssl_auth_decryption_gcm(
+                                       mbuf_src, offset, srclen,
+                                       aad, aadlen, iv,
+                                       dst, tag, sess->cipher.ctx);
+               else
+                       status = process_openssl_auth_decryption_ccm(
+                                       mbuf_src, offset, srclen,
+                                       aad, aadlen, iv,
+                                       dst, tag, taglen, sess->cipher.ctx);
+       }
 
        if (status != 0) {
                if (status == (-EFAULT) &&
index a197f79..e1c225d 100644 (file)
@@ -362,6 +362,36 @@ static const struct rte_cryptodev_capabilities openssl_pmd_capabilities[] = {
                        }, }
                }, }
        },
+       {       /* AES CCM */
+               .op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+               {.sym = {
+                       .xform_type = RTE_CRYPTO_SYM_XFORM_AEAD,
+                       {.aead = {
+                               .algo = RTE_CRYPTO_AEAD_AES_CCM,
+                               .block_size = 16,
+                               .key_size = {
+                                       .min = 16,
+                                       .max = 32,
+                                       .increment = 8
+                               },
+                               .digest_size = {
+                                       .min = 4,
+                                       .max = 16,
+                                       .increment = 2
+                               },
+                               .aad_size = {
+                                       .min = 0,
+                                       .max = 65535,
+                                       .increment = 1
+                               },
+                               .iv_size = {
+                                       .min = 7,
+                                       .max = 13,
+                                       .increment = 1
+                               },
+                       }, }
+               }, }
+       },
        {       /* AES GMAC (AUTH) */
                .op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
                {.sym = {
index 5f859ec..0a0ea59 100644 (file)
@@ -160,9 +160,6 @@ struct rte_crypto_cipher_xform {
         * Cipher key length is in bytes. For AES it can be 128 bits (16 bytes),
         * 192 bits (24 bytes) or 256 bits (32 bytes).
         *
-        * For the CCM mode of operation, the only supported key length is 128
-        * bits (16 bytes).
-        *
         * For the RTE_CRYPTO_CIPHER_AES_F8 mode of operation, key.length
         * should be set to the combined length of the encryption key and the
         * keymask. Since the keymask and the encryption key are the same size,
@@ -429,7 +426,11 @@ struct rte_crypto_aead_xform {
        uint16_t digest_length;
 
        uint16_t aad_length;
-       /**< The length of the additional authenticated data (AAD) in bytes. */
+       /**< The length of the additional authenticated data (AAD) in bytes.
+        * For CCM mode, this is the length of the actual AAD, even though
+        * it is required to reserve 18 bytes before the AAD and padding
+        * at the end of it, so a multiple of 16 bytes is allocated.
+        */
 };
 
 /** Crypto transformation types */