Supports some new auth algs: AES-CMAC,AES-GMAC,AES_XCBC_MAC_96,AES-CBC_PRF_128.
Signed-off-by: Weili Qian qianweili@huawei.com --- v1/drv/hisi_sec_udrv.c | 135 ++++++++++++++++++++++++++++++----------- v1/wd_digest.c | 69 +++++++++++++++++++-- v1/wd_digest.h | 24 ++++++-- 3 files changed, 182 insertions(+), 46 deletions(-)
diff --git a/v1/drv/hisi_sec_udrv.c b/v1/drv/hisi_sec_udrv.c index 9866c10..02a63c2 100644 --- a/v1/drv/hisi_sec_udrv.c +++ b/v1/drv/hisi_sec_udrv.c @@ -54,6 +54,7 @@ #define CBC_AES_BLOCK_SIZE 16 #define AEAD_IV_MAX_BYTES 64 #define MAX_CCM_AAD_LEN 65279 +#define SEC_GMAC_IV_LEN 16
static int g_digest_a_alg[WCRYPTO_MAX_DIGEST_TYPE] = { A_ALG_SM3, A_ALG_MD5, A_ALG_SHA1, A_ALG_SHA256, A_ALG_SHA224, @@ -62,7 +63,9 @@ static int g_digest_a_alg[WCRYPTO_MAX_DIGEST_TYPE] = { static int g_hmac_a_alg[WCRYPTO_MAX_DIGEST_TYPE] = { A_ALG_HMAC_SM3, A_ALG_HMAC_MD5, A_ALG_HMAC_SHA1, A_ALG_HMAC_SHA256, A_ALG_HMAC_SHA224, A_ALG_HMAC_SHA384, - A_ALG_HMAC_SHA512, A_ALG_HMAC_SHA512_224, A_ALG_HMAC_SHA512_256 + A_ALG_HMAC_SHA512, A_ALG_HMAC_SHA512_224, A_ALG_HMAC_SHA512_256, + A_ALG_AES_XCBC_MAC_96, A_ALG_AES_XCBC_PRF_128, A_ALG_AES_CMAC, + A_ALG_AES_GMAC };
static void parse_aead_bd2(struct wd_queue *q, struct hisi_sec_sqe *sqe, @@ -1128,13 +1131,19 @@ int qm_fill_cipher_bd3_sqe(void *message, struct qm_queue_info *info, __u16 i) return ret; }
-static int digest_param_check(struct wcrypto_digest_msg *msg) +static int digest_param_check(struct wcrypto_digest_msg *msg, __u8 bd_type) { if (unlikely(msg->alg >= WCRYPTO_MAX_DIGEST_TYPE)) { WD_ERR("invalid digest type!\n"); return -WD_EINVAL; }
+ if (msg->alg >= WCRYPTO_AES_XCBC_MAC_96 && + (bd_type == BD_TYPE1 || bd_type == BD_TYPE2)) { + WD_ERR("invalid: BD tpye does not support the alg %d!\n", msg->alg); + return -WD_EINVAL; + } + if (unlikely(msg->in_bytes > MAX_CIPHER_LENGTH)) { WD_ERR("invalid digest in_bytes!\n"); return -WD_EINVAL; @@ -1153,12 +1162,12 @@ static int fill_digest_bd2_alg(struct wcrypto_digest_msg *msg, { int ret;
- ret = digest_param_check(msg); + ret = digest_param_check(msg, BD_TYPE2); if (unlikely(ret)) return ret;
if(unlikely(msg->in_bytes == 0)) { - if ((msg->has_next && !msg->iv_bytes) || (msg->has_next && msg->iv_bytes)) { + if (msg->has_next) { /* Long hash first and middle BD */ WD_ERR("invalid: digest bd2 not supports 0 packet in first bd and middle bd!\n"); return -WD_EINVAL; @@ -1223,7 +1232,7 @@ static int fill_digest_bd1_alg(struct wcrypto_digest_msg *msg, { int ret;
- ret = digest_param_check(msg); + ret = digest_param_check(msg, BD_TYPE1); if (unlikely(ret)) return ret;
@@ -1513,12 +1522,29 @@ int qm_fill_digest_sqe(void *message, struct qm_queue_info *info, __u16 i) return WD_SUCCESS; }
-static void qm_fill_digest_long_bd3(struct wcrypto_digest_msg *msg, +static int qm_fill_digest_long_bd3(struct wcrypto_digest_msg *msg, struct hisi_sec_bd3_sqe *sqe) { struct wcrypto_digest_tag *digest_tag = (void *)(uintptr_t)msg->usr_data; __u64 total_bits = 0;
+ if (msg->alg == WCRYPTO_AES_XCBC_MAC_96 || + msg->alg == WCRYPTO_AES_XCBC_PRF_128 || + msg->alg == WCRYPTO_AES_CMAC || + msg->alg == WCRYPTO_AES_GMAC) { + if (msg->has_next) { + WD_ERR("aes alg %d not supports long hash mode!\n", msg->alg); + return -WD_EINVAL; + } + return WD_SUCCESS; + } + + if (unlikely(msg->has_next && !msg->in_bytes)) { + /* Long hash first and middle BD */ + WD_ERR("invalid: digest bd3 not supports 0 packet in first bd and middle bd!\n"); + return -WD_EINVAL; + } + /* iv_bytes is multiplexed as a flag bit to determine whether it is LOGN BD FIRST */ if (msg->has_next && msg->iv_bytes == 0) { /* LONG BD FIRST */ @@ -1548,26 +1574,13 @@ static void qm_fill_digest_long_bd3(struct wcrypto_digest_msg *msg, /* SHORT BD */ msg->iv_bytes = 0; } + + return WD_SUCCESS; }
static int fill_digest_bd3_alg(struct wcrypto_digest_msg *msg, struct hisi_sec_bd3_sqe *sqe) { - int ret; - - ret = digest_param_check(msg); - if (unlikely(ret)) - return ret; - - if (unlikely(msg->in_bytes == 0)) { - if ((msg->has_next && !msg->iv_bytes) || (msg->has_next && msg->iv_bytes)) { - /* Long hash first and middle BD */ - WD_ERR("invalid: digest bd3 not supports 0 packet in first bd and middle bd!\n"); - return -WD_EINVAL; - } - } - - sqe->mac_len = msg->out_bytes / WORD_BYTES; if (msg->mode == WCRYPTO_DIGEST_NORMAL) sqe->a_alg = g_digest_a_alg[msg->alg]; else if (msg->mode == WCRYPTO_DIGEST_HMAC) @@ -1591,8 +1604,7 @@ static int set_hmac_mode_v3(struct wcrypto_digest_msg *msg,
if (unlikely(msg->key_bytes & WORD_ALIGNMENT_MASK)) { WD_ERR("Invalid digest key_bytes!\n"); - ret = -WD_EINVAL; - return ret; + return -WD_EINVAL; } sqe->a_key_len = msg->key_bytes / WORD_BYTES; ret = map_addr(q, msg->key, msg->key_bytes, @@ -1604,21 +1616,68 @@ static int set_hmac_mode_v3(struct wcrypto_digest_msg *msg, return ret; }
- return 0; + if (msg->alg != WCRYPTO_AES_GMAC) + return WD_SUCCESS; + + sqe->ai_gen = AI_GEN_IVIN_ADDR; + ret = map_addr(q, msg->iv, SEC_GMAC_IV_LEN, &sqe->auth_key_iv.a_ivin_addr_l, + &sqe->auth_key_iv.a_ivin_addr_h, msg->data_fmt); + if (unlikely(ret)) { + WD_ERR("Get digest bd3 hmac iv dma address fail!\n"); + unmap_addr(q, msg->key, msg->key_bytes, sqe->auth_key_iv.a_key_addr_l, + sqe->auth_key_iv.a_key_addr_h, msg->data_fmt); + return ret; + } + + return WD_SUCCESS; +} + +static int digest_param_check_v3(struct wcrypto_digest_msg *msg) +{ + int ret; + + ret = digest_param_check(msg, BD_TYPE3); + if (unlikely(ret)) + return ret; + + if (unlikely(!msg->in_bytes && + (msg->alg == WCRYPTO_AES_XCBC_MAC_96 || + msg->alg == WCRYPTO_AES_XCBC_PRF_128 || + msg->alg == WCRYPTO_AES_CMAC))) { + WD_ERR("invalid: digest mode %d not supports 0 packet!\n", msg->alg); + return -WD_EINVAL; + } + + if (unlikely((msg->alg == WCRYPTO_AES_XCBC_MAC_96 && + msg->out_bytes != WCRYPTO_AES_XCBC_MAC_96_LEN) || + (msg->alg == WCRYPTO_AES_XCBC_PRF_128 && + msg->out_bytes != WCRYPTO_AES_XCBC_PRF_128_LEN))) { + WD_ERR("invalid digest out_bytes %u, msg->alg = %d!\n", + msg->out_bytes, msg->alg); + return -WD_EINVAL; + } + + return WD_SUCCESS; }
static int fill_digest_bd3(struct wd_queue *q, struct hisi_sec_bd3_sqe *sqe, struct wcrypto_digest_msg *msg, struct wcrypto_digest_tag *tag) { - int ret = -WD_ENOMEM; uintptr_t phy; + int ret; + + ret = digest_param_check_v3(msg); + if (unlikely(ret)) + return ret;
sqe->type = BD_TYPE3; - sqe->scene = SCENE_STREAM; + if (msg->alg == WCRYPTO_AES_GMAC) + sqe->scene = SCENE_IPSEC; + else + sqe->scene = SCENE_STREAM;
sqe->auth = AUTH_MAC_CALCULATE; sqe->a_len = msg->in_bytes; - phy = (uintptr_t)drv_iova_map(q, msg->in, msg->in_bytes); if (unlikely(!phy)) { WD_ERR("Get message in dma address fail!\n"); @@ -1634,17 +1693,21 @@ static int fill_digest_bd3(struct wd_queue *q, struct hisi_sec_bd3_sqe *sqe, WD_ERR("Get digest bd3 message out dma address fail!\n"); goto map_out_error; } - - ret = set_hmac_mode_v3(msg, sqe, q); - if (ret) - goto map_key_error; + sqe->mac_len = msg->out_bytes / WORD_BYTES;
ret = fill_digest_bd3_alg(msg, sqe); if (ret != WD_SUCCESS) { WD_ERR("fill_digest_bd3_alg fail!\n"); goto map_alg_error; } - qm_fill_digest_long_bd3(msg, sqe); + + ret = qm_fill_digest_long_bd3(msg, sqe); + if (ret) + goto map_alg_error; + + ret = set_hmac_mode_v3(msg, sqe, q); + if (ret) + goto map_alg_error;
if (tag) sqe->tag_l = tag->wcrypto_tag.ctx_id; @@ -1652,9 +1715,6 @@ static int fill_digest_bd3(struct wd_queue *q, struct hisi_sec_bd3_sqe *sqe, return ret;
map_alg_error: - unmap_addr(q, msg->key, msg->key_bytes, sqe->auth_key_iv.a_key_addr_l, - sqe->auth_key_iv.a_key_addr_h, msg->data_fmt); -map_key_error: unmap_addr(q, msg->out, msg->out_bytes, sqe->mac_addr_l, sqe->mac_addr_h, msg->data_fmt); map_out_error: @@ -2585,6 +2645,11 @@ static void parse_digest_bd3(struct wd_queue *q, struct hisi_sec_bd3_sqe *sqe, unmap_addr(q, digest_msg->key, digest_msg->key_bytes, sqe->auth_key_iv.a_key_addr_l, sqe->auth_key_iv.a_key_addr_h, digest_msg->data_fmt); + + if (digest_msg->alg == WCRYPTO_AES_GMAC) + unmap_addr(q, digest_msg->iv, SEC_GMAC_IV_LEN, + sqe->auth_key_iv.a_ivin_addr_l, + sqe->auth_key_iv.a_ivin_addr_h, digest_msg->data_fmt); }
int qm_parse_digest_bd3_sqe(void *msg, const struct qm_queue_info *info, diff --git a/v1/wd_digest.c b/v1/wd_digest.c index be43c73..f6c8b84 100644 --- a/v1/wd_digest.c +++ b/v1/wd_digest.c @@ -30,6 +30,7 @@ #define MAX_DIGEST_RETRY_CNT 20000000 #define SEC_SHA1_ALIGN_SZ 64 #define SEC_SHA512_ALIGN_SZ 128 +#define SEC_GMAC_IV_LEN 16
struct wcrypto_digest_cookie { struct wcrypto_digest_tag tag; @@ -51,7 +52,9 @@ static __u32 g_digest_mac_len[WCRYPTO_MAX_DIGEST_TYPE] = { WCRYPTO_DIGEST_SM3_LEN, WCRYPTO_DIGEST_MD5_LEN, WCRYPTO_DIGEST_SHA1_LEN, WCRYPTO_DIGEST_SHA256_LEN, WCRYPTO_DIGEST_SHA224_LEN, WCRYPTO_DIGEST_SHA384_LEN, WCRYPTO_DIGEST_SHA512_LEN, - WCRYPTO_DIGEST_SHA512_224_LEN, WCRYPTO_DIGEST_SHA512_256_LEN + WCRYPTO_DIGEST_SHA512_224_LEN, WCRYPTO_DIGEST_SHA512_256_LEN, + WCRYPTO_AES_XCBC_MAC_96_LEN, WCRYPTO_AES_XCBC_PRF_128_LEN, + WCRYPTO_AES_CMAC_LEN, WCRYPTO_AES_GMAC_LEN };
static __u32 g_digest_mac_full_len[WCRYPTO_MAX_DIGEST_TYPE] = { @@ -103,6 +106,17 @@ static int create_ctx_para_check(struct wd_queue *q, return -WD_EINVAL; }
+ if (setup->alg >= WCRYPTO_MAX_DIGEST_TYPE) { + WD_ERR("invalid: the alg %d does not support!\n", setup->alg); + return -WD_EINVAL; + } + + if (setup->mode == WCRYPTO_DIGEST_NORMAL && + setup->alg >= WCRYPTO_AES_XCBC_MAC_96) { + WD_ERR("invalid: the alg %d does not support normal mode!\n", setup->alg); + return -WD_EINVAL; + } + return WD_SUCCESS; }
@@ -246,26 +260,65 @@ static void digest_requests_init(struct wcrypto_digest_msg **req, req[i]->in_bytes = op[i]->in_bytes; req[i]->out = op[i]->out; req[i]->out_bytes = op[i]->out_bytes; + req[i]->iv = op[i]->iv; c->io_bytes += op[i]->in_bytes; } }
+static int digest_hmac_key_check(enum wcrypto_digest_alg alg, __u16 key_len) +{ + switch (alg) { + case WCRYPTO_SM3 ... WCRYPTO_SHA224: + if (key_len > (MAX_HMAC_KEY_SIZE >> 1)) { + WD_ERR("failed to check alg %u key bytes, key_len = %u\n", alg, key_len); + return -WD_EINVAL; + } + break; + case WCRYPTO_SHA384 ... WCRYPTO_SHA512_256: + break; + case WCRYPTO_AES_XCBC_MAC_96: + case WCRYPTO_AES_XCBC_PRF_128: + case WCRYPTO_AES_CMAC: + if (key_len != AES_KEYSIZE_128) { + WD_ERR("failed to check alg %u key bytes, key_len = %u\n", alg, key_len); + return -WD_EINVAL; + } + break; + case WCRYPTO_AES_GMAC: + if (key_len != AES_KEYSIZE_128 && + key_len != AES_KEYSIZE_192 && + key_len != AES_KEYSIZE_256) { + WD_ERR("failed to check alg %u key bytes, key_len = %u\n", alg, key_len); + return -WD_EINVAL; + } + break; + default: + WD_ERR("failed to check digest key bytes, invalid alg type = %d\n", alg); + return -WD_EINVAL; + } + + return WD_SUCCESS; +} + int wcrypto_set_digest_key(void *ctx, __u8 *key, __u16 key_len) { struct wcrypto_digest_ctx *ctxt = ctx; + int ret;
if (!ctx || !key) { WD_ERR("%s(): input param err!\n", __func__); return -WD_EINVAL; }
- if ((ctxt->setup.alg <= WCRYPTO_SHA224 && key_len > - MAX_HMAC_KEY_SIZE >> 1) || key_len == 0 || - key_len > MAX_HMAC_KEY_SIZE) { - WD_ERR("%s: input key length err!\n", __func__); + if (key_len == 0 || key_len > MAX_HMAC_KEY_SIZE) { + WD_ERR("%s: input key length err, key_len = %u!\n", __func__, key_len); return -WD_EINVAL; }
+ ret = digest_hmac_key_check(ctxt->setup.alg, key_len); + if (ret) + return ret; + ctxt->key_bytes = key_len;
if (ctxt->setup.data_fmt == WD_SGL_BUF) @@ -361,6 +414,12 @@ static int param_check(struct wcrypto_digest_ctx *d_ctx, WD_ERR("failed to check digest mac length!\n"); return -WD_EINVAL; } + if (d_ctx->setup.alg == WCRYPTO_AES_GMAC && + d_opdata[i]->iv_bytes != SEC_GMAC_IV_LEN) { + WD_ERR("failed to check digest aes_gmac iv length, iv_bytes = %u\n", + d_opdata[i]->iv_bytes); + return -WD_EINVAL; + } }
if (unlikely(tag && !tag[i])) { diff --git a/v1/wd_digest.h b/v1/wd_digest.h index 8f7ac2e..9667a66 100644 --- a/v1/wd_digest.h +++ b/v1/wd_digest.h @@ -36,6 +36,10 @@ enum wcrypto_digest_alg { WCRYPTO_SHA512, WCRYPTO_SHA512_224, WCRYPTO_SHA512_256, + WCRYPTO_AES_XCBC_MAC_96, + WCRYPTO_AES_XCBC_PRF_128, + WCRYPTO_AES_CMAC, + WCRYPTO_AES_GMAC, WCRYPTO_MAX_DIGEST_TYPE, };
@@ -43,12 +47,16 @@ enum wd_digest_mac_len { WCRYPTO_DIGEST_SM3_LEN = 32, WCRYPTO_DIGEST_MD5_LEN = 16, WCRYPTO_DIGEST_SHA1_LEN = 20, - WCRYPTO_DIGEST_SHA256_LEN = 32, - WCRYPTO_DIGEST_SHA224_LEN = 28, - WCRYPTO_DIGEST_SHA384_LEN = 48, - WCRYPTO_DIGEST_SHA512_LEN = 64, - WCRYPTO_DIGEST_SHA512_224_LEN = 28, - WCRYPTO_DIGEST_SHA512_256_LEN = 32 + WCRYPTO_DIGEST_SHA256_LEN = 32, + WCRYPTO_DIGEST_SHA224_LEN = 28, + WCRYPTO_DIGEST_SHA384_LEN = 48, + WCRYPTO_DIGEST_SHA512_LEN = 64, + WCRYPTO_DIGEST_SHA512_224_LEN = 28, + WCRYPTO_DIGEST_SHA512_256_LEN = 32, + WCRYPTO_AES_XCBC_MAC_96_LEN = 12, + WCRYPTO_AES_XCBC_PRF_128_LEN = 16, + WCRYPTO_AES_CMAC_LEN = 16, + WCRYPTO_AES_GMAC_LEN = 16, };
enum wcrypto_digest_mac_full_len { @@ -93,6 +101,8 @@ struct wcrypto_digest_ctx_setup { * @priv:reserved data field segment * @status:I/O operation return status * @has_next: is there next data block + * @iv: initialization verctor data address + * @iv_bytes:initialization verctor data size */ struct wcrypto_digest_op_data { void *in; @@ -102,6 +112,8 @@ struct wcrypto_digest_op_data { void *priv; int status; bool has_next; + void *iv; + __u32 iv_bytes; };
/* Digest message format of Warpdrive */