1. User need to input full mac buffer in first and middile hash. 2. sha384 alignment mask is 128Byte, here is fix it.
Signed-off-by: Kai Ye yekai13@huawei.com --- drv/hisi_sec.c | 56 ++++++++++++++++++++++++++++++++++++++++++--- include/wd_digest.h | 13 +++++++++++ wd_digest.c | 47 ++++++++++++++++++++++++++++++++----- 3 files changed, 107 insertions(+), 9 deletions(-)
diff --git a/drv/hisi_sec.c b/drv/hisi_sec.c index 1728529..5b676e9 100644 --- a/drv/hisi_sec.c +++ b/drv/hisi_sec.c @@ -116,6 +116,19 @@ enum A_ALG { A_ALG_HMAC_SM3 = 0x26 };
+/* The long hash mode requires full-length mac output */ +enum SEC_MAX_MAC_LEN { + SEC_HMAC_SM3_MAC_LEN = 0x8, + SEC_HMAC_MD5_MAC_LEN = 0x4, + SEC_HMAC_SHA1_MAC_LEN = 0x5, + SEC_HMAC_SHA256_MAC_LEN = 0x8, + SEC_HMAC_SHA224_MAC_LEN = 0x7, + SEC_HMAC_SHA384_MAC_LEN = 0xc, + SEC_HMAC_SHA512_MAC_LEN = 0x10, + SEC_HMAC_SHA512_224_MAC_LEN = 0x7, + SEC_HMAC_SHA512_256_MAC_LEN = 0x8 +}; + enum C_MODE { C_MODE_ECB = 0x0, C_MODE_CBC = 0x1, @@ -484,6 +497,7 @@ static int g_digest_a_alg[WD_DIGEST_TYPE_MAX] = { A_ALG_SM3, A_ALG_MD5, A_ALG_SHA1, A_ALG_SHA256, A_ALG_SHA224, A_ALG_SHA384, A_ALG_SHA512, A_ALG_SHA512_224, A_ALG_SHA512_256 }; + static int g_hmac_a_alg[WD_DIGEST_TYPE_MAX] = { A_ALG_HMAC_SM3, A_ALG_HMAC_MD5, A_ALG_HMAC_SHA1, A_ALG_HMAC_SHA256, A_ALG_HMAC_SHA224, A_ALG_HMAC_SHA384, @@ -492,6 +506,12 @@ static int g_hmac_a_alg[WD_DIGEST_TYPE_MAX] = { A_ALG_AES_GMAC };
+static __u32 g_sec_hmac_full_len[WD_DIGEST_TYPE_MAX] = { + SEC_HMAC_SM3_MAC_LEN, SEC_HMAC_MD5_MAC_LEN, SEC_HMAC_SHA1_MAC_LEN, + SEC_HMAC_SHA256_MAC_LEN, SEC_HMAC_SHA224_MAC_LEN, SEC_HMAC_SHA384_MAC_LEN, + SEC_HMAC_SHA512_MAC_LEN, SEC_HMAC_SHA512_224_MAC_LEN, SEC_HMAC_SHA512_256_MAC_LEN +}; + int hisi_sec_init(struct wd_ctx_config_internal *config, void *priv); void hisi_sec_exit(void *priv);
@@ -1308,7 +1328,21 @@ static int fill_digest_bd2_alg(struct wd_digest_msg *msg, return -WD_EINVAL; }
- sqe->type2.mac_key_alg = msg->out_bytes / WORD_BYTES; + /* + * Long hash mode must config full output length, 0 mac len indicates + * the output full length. + */ + if (!msg->has_next) + sqe->type2.mac_key_alg = msg->out_bytes / WORD_BYTES; + + /* SM3 can't config 0 in normal mode */ + if (msg->has_next && msg->mode == WD_DIGEST_NORMAL && + msg->alg == WD_DIGEST_SM3) + sqe->type2.mac_key_alg = g_sec_hmac_full_len[msg->alg]; + + if (msg->has_next && msg->mode == WD_DIGEST_HMAC) + sqe->type2.mac_key_alg = g_sec_hmac_full_len[msg->alg]; + if (msg->mode == WD_DIGEST_NORMAL) sqe->type2.mac_key_alg |= (__u32)g_digest_a_alg[msg->alg] << AUTH_ALG_OFFSET; @@ -1427,7 +1461,7 @@ static int digest_long_bd_align_check(struct wd_digest_msg *msg) { __u32 alg_align_sz;
- alg_align_sz = msg->alg >= WD_DIGEST_SHA512 ? + alg_align_sz = msg->alg >= WD_DIGEST_SHA384 ? SHA512_ALIGN_SZ - 1 : SHA1_ALIGN_SZ - 1;
if (msg->in_bytes & alg_align_sz) @@ -1624,8 +1658,24 @@ static int fill_digest_bd3_alg(struct wd_digest_msg *msg, return -WD_EINVAL; }
- sqe->auth_mac_key |= (msg->out_bytes / WORD_BYTES) << + /* + * Long hash mode must config full output length, 0 mac len indicates + * the output full length. + */ + if (!msg->has_next) + sqe->auth_mac_key |= (msg->out_bytes / WORD_BYTES) << + SEC_MAC_OFFSET_V3; + + /* SM3 can't config 0 in normal mode */ + if (msg->has_next && msg->mode == WD_DIGEST_NORMAL && + msg->alg == WD_DIGEST_SM3) + sqe->auth_mac_key |= g_sec_hmac_full_len[msg->alg] << + SEC_MAC_OFFSET_V3; + + if (msg->has_next && msg->mode == WD_DIGEST_HMAC) + sqe->auth_mac_key |= g_sec_hmac_full_len[msg->alg] << SEC_MAC_OFFSET_V3; + if (msg->mode == WD_DIGEST_NORMAL) { sqe->auth_mac_key |= (__u32)g_digest_a_alg[msg->alg] << SEC_AUTH_ALG_OFFSET_V3; diff --git a/include/wd_digest.h b/include/wd_digest.h index bf085ea..6a7a913 100644 --- a/include/wd_digest.h +++ b/include/wd_digest.h @@ -54,6 +54,19 @@ enum wd_digest_mac_len { WD_DIGEST_AES_GMAC_LEN = 16, };
+/* User need to input full mac len in first and middle hash */ +enum wd_digest_mac_full_len { + WD_DIGEST_SM3_FULL_LEN = 32, + WD_DIGEST_MD5_FULL_LEN = 16, + WD_DIGEST_SHA1_FULL_LEN = 20, + WD_DIGEST_SHA256_FULL_LEN = 32, + WD_DIGEST_SHA224_FULL_LEN = 32, + WD_DIGEST_SHA384_FULL_LEN = 64, + WD_DIGEST_SHA512_FULL_LEN = 64, + WD_DIGEST_SHA512_224_FULL_LEN = 64, + WD_DIGEST_SHA512_256_FULL_LEN = 64, +}; + /** * wd_digest_mode - Mode of digest * Mode should be offered by struct wd_digest_arg diff --git a/wd_digest.c b/wd_digest.c index a55b1ed..f56be0c 100644 --- a/wd_digest.c +++ b/wd_digest.c @@ -31,6 +31,13 @@ static int g_digest_mac_len[WD_DIGEST_TYPE_MAX] = { WD_DIGEST_AES_CMAC_LEN, WD_DIGEST_AES_GMAC_LEN };
+static int g_digest_mac_full_len[WD_DIGEST_TYPE_MAX] = { + WD_DIGEST_SM3_FULL_LEN, WD_DIGEST_MD5_LEN, WD_DIGEST_SHA1_FULL_LEN, + WD_DIGEST_SHA256_FULL_LEN, WD_DIGEST_SHA224_FULL_LEN, + WD_DIGEST_SHA384_FULL_LEN, WD_DIGEST_SHA512_FULL_LEN, + WD_DIGEST_SHA512_224_FULL_LEN, WD_DIGEST_SHA512_256_FULL_LEN +}; + struct wd_digest_setting { struct wd_ctx_config_internal config; struct wd_sched sched; @@ -255,7 +262,7 @@ void wd_digest_uninit(void) wd_clear_ctx_config(&wd_digest_setting.config); }
-static int wd_hmac_length_check(struct wd_digest_sess *sess, +static int wd_aes_hmac_length_check(struct wd_digest_sess *sess, struct wd_digest_req *req) { switch (sess->alg) { @@ -275,6 +282,32 @@ static int wd_hmac_length_check(struct wd_digest_sess *sess, return 0; }
+static int wd_mac_length_check(struct wd_digest_sess *sess, + struct wd_digest_req *req) +{ + if (unlikely(req->out_bytes == 0)) { + WD_ERR("invalid: digest alg:%d mac length is 0.\n", sess->alg); + return -WD_EINVAL; + } + + if (unlikely(!req->has_next && + req->out_bytes > g_digest_mac_len[sess->alg])) { + WD_ERR("invalid: digest mac length, alg = %d, out_bytes = %u\n", + sess->alg, req->out_bytes); + return -WD_EINVAL; + } + + /* User need to input full mac buffer in first and middle hash */ + if (unlikely(req->has_next && + req->out_bytes != g_digest_mac_full_len[sess->alg])) { + WD_ERR("invalid: digest mac full length is error, alg = %d, out_bytes = %u\n", + sess->alg, req->out_bytes); + return -WD_EINVAL; + } + + return 0; +} + static int wd_digest_param_check(struct wd_digest_sess *sess, struct wd_digest_req *req) { @@ -291,13 +324,15 @@ static int wd_digest_param_check(struct wd_digest_sess *sess, return -WD_EINVAL; }
- if (unlikely(sess->alg >= WD_DIGEST_TYPE_MAX || req->out_bytes == 0 || - req->out_bytes > g_digest_mac_len[sess->alg])) { - WD_ERR("failed to check digest type or mac length, alg = %d, out_bytes = %u\n", - sess->alg, req->out_bytes); + if (unlikely(sess->alg >= WD_DIGEST_TYPE_MAX)) { + WD_ERR("invalid: check digest type, alg = %d\n", sess->alg); return -WD_EINVAL; }
+ ret = wd_mac_length_check(sess, req); + if (ret) + return ret; + if (unlikely(sess->alg == WD_DIGEST_AES_GMAC && req->iv_bytes != GMAC_IV_LEN)) { WD_ERR("failed to check digest aes_gmac iv length, iv_bytes = %u\n", @@ -314,7 +349,7 @@ static int wd_digest_param_check(struct wd_digest_sess *sess, } }
- return wd_hmac_length_check(sess, req); + return wd_aes_hmac_length_check(sess, req); }
static void fill_request_msg(struct wd_digest_msg *msg,