OSDN Git Service

net/tls: Add support of AES128-CCM based ciphers
authorVakul Garg <vakul.garg@nxp.com>
Wed, 20 Mar 2019 02:03:36 +0000 (02:03 +0000)
committerDavid S. Miller <davem@davemloft.net>
Wed, 20 Mar 2019 18:02:05 +0000 (11:02 -0700)
Added support for AES128-CCM based record encryption. AES128-CCM is
similar to AES128-GCM. Both of them have same salt/iv/mac size. The
notable difference between the two is that while invoking AES128-CCM
operation, the salt||nonce (which is passed as IV) has to be prefixed
with a hardcoded value '2'. Further, CCM implementation in kernel
requires IV passed in crypto_aead_request() to be full '16' bytes.
Therefore, the record structure 'struct tls_rec' has been modified to
reserve '16' bytes for IV. This works for both GCM and CCM based cipher.

Signed-off-by: Vakul Garg <vakul.garg@nxp.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/tls.h
include/uapi/linux/tls.h
net/tls/tls_main.c
net/tls/tls_sw.c

index a5a9385..3ce71d7 100644 (file)
 #define TLS_AAD_SPACE_SIZE             13
 #define TLS_DEVICE_NAME_MAX            32
 
+#define MAX_IV_SIZE                    16
+
+/* For AES-CCM, the full 16-bytes of IV is made of '4' fields of given sizes.
+ *
+ * IV[16] = b0[1] || implicit nonce[4] || explicit nonce[8] || length[3]
+ *
+ * The field 'length' is encoded in field 'b0' as '(length width - 1)'.
+ * Hence b0 contains (3 - 1) = 2.
+ */
+#define TLS_AES_CCM_IV_B0_BYTE         2
+
 /*
  * This structure defines the routines for Inline TLS driver.
  * The following routines are optional and filled with a
@@ -123,8 +134,7 @@ struct tls_rec {
        struct scatterlist sg_content_type;
 
        char aad_space[TLS_AAD_SPACE_SIZE];
-       u8 iv_data[TLS_CIPHER_AES_GCM_128_IV_SIZE +
-                  TLS_CIPHER_AES_GCM_128_SALT_SIZE];
+       u8 iv_data[MAX_IV_SIZE];
        struct aead_request aead_req;
        u8 aead_req_ctx[];
 };
@@ -219,6 +229,7 @@ struct tls_prot_info {
        u16 tag_size;
        u16 overhead_size;
        u16 iv_size;
+       u16 salt_size;
        u16 rec_seq_size;
        u16 aad_size;
        u16 tail_size;
index 401d6f0..5b9c267 100644 (file)
 #define TLS_CIPHER_AES_GCM_256_TAG_SIZE                16
 #define TLS_CIPHER_AES_GCM_256_REC_SEQ_SIZE            8
 
+#define TLS_CIPHER_AES_CCM_128                         53
+#define TLS_CIPHER_AES_CCM_128_IV_SIZE                 8
+#define TLS_CIPHER_AES_CCM_128_KEY_SIZE                16
+#define TLS_CIPHER_AES_CCM_128_SALT_SIZE               4
+#define TLS_CIPHER_AES_CCM_128_TAG_SIZE                16
+#define TLS_CIPHER_AES_CCM_128_REC_SEQ_SIZE            8
+
 #define TLS_SET_RECORD_TYPE    1
 #define TLS_GET_RECORD_TYPE    2
 
@@ -94,4 +101,12 @@ struct tls12_crypto_info_aes_gcm_256 {
        unsigned char rec_seq[TLS_CIPHER_AES_GCM_256_REC_SEQ_SIZE];
 };
 
+struct tls12_crypto_info_aes_ccm_128 {
+       struct tls_crypto_info info;
+       unsigned char iv[TLS_CIPHER_AES_CCM_128_IV_SIZE];
+       unsigned char key[TLS_CIPHER_AES_CCM_128_KEY_SIZE];
+       unsigned char salt[TLS_CIPHER_AES_CCM_128_SALT_SIZE];
+       unsigned char rec_seq[TLS_CIPHER_AES_CCM_128_REC_SEQ_SIZE];
+};
+
 #endif /* _UAPI_LINUX_TLS_H */
index df921a2..0e24eda 100644 (file)
@@ -469,27 +469,32 @@ static int do_tls_setsockopt_conf(struct sock *sk, char __user *optval,
 
        switch (crypto_info->cipher_type) {
        case TLS_CIPHER_AES_GCM_128:
+               optsize = sizeof(struct tls12_crypto_info_aes_gcm_128);
+               break;
        case TLS_CIPHER_AES_GCM_256: {
-               optsize = crypto_info->cipher_type == TLS_CIPHER_AES_GCM_128 ?
-                       sizeof(struct tls12_crypto_info_aes_gcm_128) :
-                       sizeof(struct tls12_crypto_info_aes_gcm_256);
-               if (optlen != optsize) {
-                       rc = -EINVAL;
-                       goto err_crypto_info;
-               }
-               rc = copy_from_user(crypto_info + 1, optval + sizeof(*crypto_info),
-                                   optlen - sizeof(*crypto_info));
-               if (rc) {
-                       rc = -EFAULT;
-                       goto err_crypto_info;
-               }
+               optsize = sizeof(struct tls12_crypto_info_aes_gcm_256);
                break;
        }
+       case TLS_CIPHER_AES_CCM_128:
+               optsize = sizeof(struct tls12_crypto_info_aes_ccm_128);
+               break;
        default:
                rc = -EINVAL;
                goto err_crypto_info;
        }
 
+       if (optlen != optsize) {
+               rc = -EINVAL;
+               goto err_crypto_info;
+       }
+
+       rc = copy_from_user(crypto_info + 1, optval + sizeof(*crypto_info),
+                           optlen - sizeof(*crypto_info));
+       if (rc) {
+               rc = -EFAULT;
+               goto err_crypto_info;
+       }
+
        if (tx) {
 #ifdef CONFIG_TLS_DEVICE
                rc = tls_set_device_offload(sk, ctx);
index 425351a..f635c10 100644 (file)
@@ -42,8 +42,6 @@
 #include <net/strparser.h>
 #include <net/tls.h>
 
-#define MAX_IV_SIZE    TLS_CIPHER_AES_GCM_128_IV_SIZE
-
 static int __skb_nsg(struct sk_buff *skb, int offset, int len,
                      unsigned int recursion_level)
 {
@@ -479,11 +477,18 @@ static int tls_do_encryption(struct sock *sk,
        struct tls_rec *rec = ctx->open_rec;
        struct sk_msg *msg_en = &rec->msg_encrypted;
        struct scatterlist *sge = sk_msg_elem(msg_en, start);
-       int rc;
+       int rc, iv_offset = 0;
+
+       /* For CCM based ciphers, first byte of IV is a constant */
+       if (prot->cipher_type == TLS_CIPHER_AES_CCM_128) {
+               rec->iv_data[0] = TLS_AES_CCM_IV_B0_BYTE;
+               iv_offset = 1;
+       }
+
+       memcpy(&rec->iv_data[iv_offset], tls_ctx->tx.iv,
+              prot->iv_size + prot->salt_size);
 
-       memcpy(rec->iv_data, tls_ctx->tx.iv, sizeof(rec->iv_data));
-       xor_iv_with_seq(prot->version, rec->iv_data,
-                       tls_ctx->tx.rec_seq);
+       xor_iv_with_seq(prot->version, rec->iv_data, tls_ctx->tx.rec_seq);
 
        sge->offset += prot->prepend_size;
        sge->length -= prot->prepend_size;
@@ -1344,6 +1349,7 @@ static int decrypt_internal(struct sock *sk, struct sk_buff *skb,
        struct scatterlist *sgout = NULL;
        const int data_len = rxm->full_len - prot->overhead_size +
                             prot->tail_size;
+       int iv_offset = 0;
 
        if (*zc && (out_iov || out_sg)) {
                if (out_iov)
@@ -1386,18 +1392,25 @@ static int decrypt_internal(struct sock *sk, struct sk_buff *skb,
        aad = (u8 *)(sgout + n_sgout);
        iv = aad + prot->aad_size;
 
+       /* For CCM based ciphers, first byte of nonce+iv is always '2' */
+       if (prot->cipher_type == TLS_CIPHER_AES_CCM_128) {
+               iv[0] = 2;
+               iv_offset = 1;
+       }
+
        /* Prepare IV */
        err = skb_copy_bits(skb, rxm->offset + TLS_HEADER_SIZE,
-                           iv + TLS_CIPHER_AES_GCM_128_SALT_SIZE,
+                           iv + iv_offset + prot->salt_size,
                            prot->iv_size);
        if (err < 0) {
                kfree(mem);
                return err;
        }
        if (prot->version == TLS_1_3_VERSION)
-               memcpy(iv, tls_ctx->rx.iv, crypto_aead_ivsize(ctx->aead_recv));
+               memcpy(iv + iv_offset, tls_ctx->rx.iv,
+                      crypto_aead_ivsize(ctx->aead_recv));
        else
-               memcpy(iv, tls_ctx->rx.iv, TLS_CIPHER_AES_GCM_128_SALT_SIZE);
+               memcpy(iv + iv_offset, tls_ctx->rx.iv, prot->salt_size);
 
        xor_iv_with_seq(prot->version, iv, tls_ctx->rx.rec_seq);
 
@@ -2152,14 +2165,15 @@ int tls_set_sw_offload(struct sock *sk, struct tls_context *ctx, int tx)
        struct tls_crypto_info *crypto_info;
        struct tls12_crypto_info_aes_gcm_128 *gcm_128_info;
        struct tls12_crypto_info_aes_gcm_256 *gcm_256_info;
+       struct tls12_crypto_info_aes_ccm_128 *ccm_128_info;
        struct tls_sw_context_tx *sw_ctx_tx = NULL;
        struct tls_sw_context_rx *sw_ctx_rx = NULL;
        struct cipher_context *cctx;
        struct crypto_aead **aead;
        struct strp_callbacks cb;
-       u16 nonce_size, tag_size, iv_size, rec_seq_size;
+       u16 nonce_size, tag_size, iv_size, rec_seq_size, salt_size;
        struct crypto_tfm *tfm;
-       char *iv, *rec_seq, *key, *salt;
+       char *iv, *rec_seq, *key, *salt, *cipher_name;
        size_t keysize;
        int rc = 0;
 
@@ -2224,6 +2238,8 @@ int tls_set_sw_offload(struct sock *sk, struct tls_context *ctx, int tx)
                keysize = TLS_CIPHER_AES_GCM_128_KEY_SIZE;
                key = gcm_128_info->key;
                salt = gcm_128_info->salt;
+               salt_size = TLS_CIPHER_AES_GCM_128_SALT_SIZE;
+               cipher_name = "gcm(aes)";
                break;
        }
        case TLS_CIPHER_AES_GCM_256: {
@@ -2239,6 +2255,25 @@ int tls_set_sw_offload(struct sock *sk, struct tls_context *ctx, int tx)
                keysize = TLS_CIPHER_AES_GCM_256_KEY_SIZE;
                key = gcm_256_info->key;
                salt = gcm_256_info->salt;
+               salt_size = TLS_CIPHER_AES_GCM_256_SALT_SIZE;
+               cipher_name = "gcm(aes)";
+               break;
+       }
+       case TLS_CIPHER_AES_CCM_128: {
+               nonce_size = TLS_CIPHER_AES_CCM_128_IV_SIZE;
+               tag_size = TLS_CIPHER_AES_CCM_128_TAG_SIZE;
+               iv_size = TLS_CIPHER_AES_CCM_128_IV_SIZE;
+               iv = ((struct tls12_crypto_info_aes_ccm_128 *)crypto_info)->iv;
+               rec_seq_size = TLS_CIPHER_AES_CCM_128_REC_SEQ_SIZE;
+               rec_seq =
+               ((struct tls12_crypto_info_aes_ccm_128 *)crypto_info)->rec_seq;
+               ccm_128_info =
+               (struct tls12_crypto_info_aes_ccm_128 *)crypto_info;
+               keysize = TLS_CIPHER_AES_CCM_128_KEY_SIZE;
+               key = ccm_128_info->key;
+               salt = ccm_128_info->salt;
+               salt_size = TLS_CIPHER_AES_CCM_128_SALT_SIZE;
+               cipher_name = "ccm(aes)";
                break;
        }
        default:
@@ -2268,16 +2303,16 @@ int tls_set_sw_offload(struct sock *sk, struct tls_context *ctx, int tx)
        prot->overhead_size = prot->prepend_size +
                              prot->tag_size + prot->tail_size;
        prot->iv_size = iv_size;
-       cctx->iv = kmalloc(iv_size + TLS_CIPHER_AES_GCM_128_SALT_SIZE,
-                          GFP_KERNEL);
+       prot->salt_size = salt_size;
+       cctx->iv = kmalloc(iv_size + salt_size, GFP_KERNEL);
        if (!cctx->iv) {
                rc = -ENOMEM;
                goto free_priv;
        }
        /* Note: 128 & 256 bit salt are the same size */
-       memcpy(cctx->iv, salt, TLS_CIPHER_AES_GCM_128_SALT_SIZE);
-       memcpy(cctx->iv + TLS_CIPHER_AES_GCM_128_SALT_SIZE, iv, iv_size);
        prot->rec_seq_size = rec_seq_size;
+       memcpy(cctx->iv, salt, salt_size);
+       memcpy(cctx->iv + salt_size, iv, iv_size);
        cctx->rec_seq = kmemdup(rec_seq, rec_seq_size, GFP_KERNEL);
        if (!cctx->rec_seq) {
                rc = -ENOMEM;
@@ -2285,7 +2320,7 @@ int tls_set_sw_offload(struct sock *sk, struct tls_context *ctx, int tx)
        }
 
        if (!*aead) {
-               *aead = crypto_alloc_aead("gcm(aes)", 0, 0);
+               *aead = crypto_alloc_aead(cipher_name, 0, 0);
                if (IS_ERR(*aead)) {
                        rc = PTR_ERR(*aead);
                        *aead = NULL;