From: Weili Qian <qianweili@huawei.com> The ECX key exchange used reverse_bytes() to convert endianness directly on the key buffer. Since ECX_KEY objects are shared via dupctx, in-place reversal corrupts the key for all reference holders if the operation fails between the forward and reverse-back. Switch to the non-destructive reverse_bytes_ex() variant which writes reversed bytes into a separate stack buffer, leaving the original key untouched. Also cleanse the temporary private key buffer after use. Signed-off-by: Weili Qian <qianweili@huawei.com> --- src/uadk_ecx.c | 58 ++++++++++++---------------------- src/uadk_prov_ecx.c | 77 +++++++++------------------------------------ 2 files changed, 35 insertions(+), 100 deletions(-) diff --git a/src/uadk_ecx.c b/src/uadk_ecx.c index fbab680..3a33968 100644 --- a/src/uadk_ecx.c +++ b/src/uadk_ecx.c @@ -217,6 +217,14 @@ static int reverse_bytes(unsigned char *to_buf, __u32 size) return UADK_E_SUCCESS; } +static void reverse_bytes_ex(unsigned char *src_buf, unsigned char *dst_buf, __u32 size) +{ + __u32 i; + + for (i = 0; i < size; i++) + dst_buf[i] = src_buf[size - i - 1]; +} + static int x25519_init(EVP_PKEY_CTX *ctx) { struct wd_ecc_sess_setup setup = {0}; @@ -612,22 +620,18 @@ static int ecx_compkey_init_iot(struct ecx_ctx *ecx_ctx, struct wd_ecc_req *req, struct ecx_key *peer_ecx_key, struct ecx_key *ecx_key) { + unsigned char pubkey_be[ECX_MAX_KEYLEN]; __u32 key_size = ecx_ctx->key_size; char buf_y[ECX_MAX_KEYLEN] = {0}; handle_t sess = ecx_ctx->sess; struct wd_ecc_point in_pubkey; struct wd_ecc_out *ecx_out; struct wd_ecc_in *ecx_in; - int ret; - /* Trans public key from little-endian to big-endian */ - ret = reverse_bytes(peer_ecx_key->pubkey, key_size); - if(!ret) { - fprintf(stderr, "failed to trans public key\n"); - return UADK_E_FAIL; - } + /* Trans public key from little-endian to big-endian into a temp buffer */ + reverse_bytes_ex(peer_ecx_key->pubkey, pubkey_be, key_size); - in_pubkey.x.data = (char *)peer_ecx_key->pubkey; + in_pubkey.x.data = (char *)pubkey_be; in_pubkey.x.dsize = key_size; in_pubkey.y.data = buf_y; in_pubkey.y.dsize = 1; @@ -641,27 +645,14 @@ static int ecx_compkey_init_iot(struct ecx_ctx *ecx_ctx, struct wd_ecc_req *req, ecx_out = wd_ecxdh_new_out(sess); if (!ecx_out) { fprintf(stderr, "failed to new ecxdh out\n"); - ret = UADK_E_FAIL; - goto del_in; + wd_ecc_del_in(sess, ecx_in); + return UADK_E_FAIL; } uadk_ecc_fill_req(req, WD_ECXDH_COMPUTE_KEY, ecx_in, ecx_out); - /* Trans public key from big-endian to little-endian */ - ret = reverse_bytes(peer_ecx_key->pubkey, key_size); - if (!ret) { - fprintf(stderr, "failed to trans public key\n"); - goto del_out; - } - - return ret; - -del_out: - wd_ecc_del_out(sess, ecx_out); -del_in: - wd_ecc_del_in(sess, ecx_in); + return UADK_E_SUCCESS; - return ret; } static void ecx_compkey_uninit_iot(handle_t sess, struct wd_ecc_req *req) @@ -673,35 +664,26 @@ static void ecx_compkey_uninit_iot(handle_t sess, struct wd_ecc_req *req) static int ecx_derive_set_private_key(struct ecx_ctx *ecx_ctx, struct ecx_key *ecx_key) { + unsigned char prikey_be[ECX_MAX_KEYLEN]; int key_size = ecx_ctx->key_size; handle_t sess = ecx_ctx->sess; struct wd_ecc_key *ecc_key; struct wd_dtb prikey; int ret; - /* Trans private key from little-endian to big-endian */ - ret = reverse_bytes(ecx_key->privkey, key_size); - if (!ret) { - fprintf(stderr, "failed to trans private key\n"); - return UADK_E_FAIL; - } + /* Trans private key from little-endian to big-endian into a temp buffer */ + reverse_bytes_ex(ecx_key->privkey, prikey_be, key_size); - prikey.data = (char *)ecx_key->privkey; + prikey.data = (char *)prikey_be; prikey.dsize = ecx_ctx->key_size; ecc_key = wd_ecc_get_key(sess); ret = wd_ecc_set_prikey(ecc_key, &prikey); + OPENSSL_cleanse(prikey_be, sizeof(prikey_be)); if (ret) { fprintf(stderr, "failed to set ecc prikey, ret = %d\n", ret); return UADK_E_FAIL; } - /* Trans private key from big-endian to little-endian */ - ret = reverse_bytes(ecx_key->privkey, key_size); - if (!ret) { - fprintf(stderr, "failed to trans private key\n"); - return UADK_E_FAIL; - } - return UADK_E_SUCCESS; } diff --git a/src/uadk_prov_ecx.c b/src/uadk_prov_ecx.c index 3515573..27e9b86 100644 --- a/src/uadk_prov_ecx.c +++ b/src/uadk_prov_ecx.c @@ -676,29 +676,12 @@ static int uadk_prov_reverse_bytes(unsigned char *to_buf, __u32 size) return UADK_P_SUCCESS; } -static int uadk_prov_reverse_bytes_ex(unsigned char *src_buf, unsigned char *dst_buf, __u32 size) +static void uadk_prov_reverse_bytes_ex(unsigned char *src_buf, unsigned char *dst_buf, __u32 size) { __u32 i; - if (size == 0) { - UADK_ERR("invalid size, size = %u\n", size); - return UADK_P_FAIL; - } - - if (src_buf == NULL) { - UADK_ERR("src_buf is NULL\n"); - return UADK_P_FAIL; - } - - if (dst_buf == NULL) { - UADK_ERR("dst_buf is NULL\n"); - return UADK_P_FAIL; - } - for (i = 0; i < size; i++) dst_buf[i] = src_buf[size - i - 1]; - - return UADK_P_SUCCESS; } static int uadk_prov_ecx_set_pkey(PROV_ECX_KEYMGMT_CTX *gctx, struct wd_ecc_req *req, @@ -719,12 +702,8 @@ static int uadk_prov_ecx_set_pkey(PROV_ECX_KEYMGMT_CTX *gctx, struct wd_ecc_req } /* Trans public key from big-endian to little-endian */ - ret = uadk_prov_reverse_bytes_ex((unsigned char *)pubkey->x.data, - ecx_key->pubkey, pubkey->x.dsize); - if (ret == UADK_P_FAIL) { - UADK_ERR("failed to transform pubkey\n"); - return ret; - } + uadk_prov_reverse_bytes_ex((unsigned char *)pubkey->x.data, + ecx_key->pubkey, pubkey->x.dsize); /* Trans private key from big-endian to little-endian */ ret = uadk_prov_reverse_bytes(ecx_key->privkey, gctx->keylen); if (ret == UADK_P_FAIL) { @@ -1060,21 +1039,17 @@ static int uadk_keyexch_x448_set_peer(void *vecxctx, void *vkey) static int uadk_prov_ecx_compkey_init_iot(PROV_ECX_KEYEXCH_CTX *ecxctx, struct wd_ecc_req *req) { + unsigned char pubkey_be[ECX_MAX_KEYLEN]; char buffer_y[ECX_MAX_KEYLEN] = {0}; handle_t sess = ecxctx->sess; struct wd_ecc_point in_pubkey; struct wd_ecc_out *ecx_out; struct wd_ecc_in *ecx_in; - int ret; - /* Trans public key from little-endian to big-endian */ - ret = uadk_prov_reverse_bytes(ecxctx->peerkey->pubkey, ecxctx->keylen); - if (ret == UADK_P_FAIL) { - UADK_ERR("failed to trans public key\n"); - return UADK_P_FAIL; - } + /* Trans public key from little-endian to big-endian into a temp buffer */ + uadk_prov_reverse_bytes_ex(ecxctx->peerkey->pubkey, pubkey_be, ecxctx->keylen); - in_pubkey.x.data = (char *)ecxctx->peerkey->pubkey; + in_pubkey.x.data = (char *)pubkey_be; in_pubkey.x.dsize = ecxctx->keylen; in_pubkey.y.data = buffer_y; in_pubkey.y.dsize = 1; @@ -1088,27 +1063,14 @@ static int uadk_prov_ecx_compkey_init_iot(PROV_ECX_KEYEXCH_CTX *ecxctx, struct w ecx_out = wd_ecxdh_new_out(sess); if (ecx_out == NULL) { UADK_ERR("failed to new ecxdh out\n"); - ret = UADK_P_FAIL; - goto del_ecx_in; + wd_ecc_del_in(sess, ecx_in); + return UADK_P_FAIL; } uadk_prov_ecc_fill_req(req, WD_ECXDH_COMPUTE_KEY, ecx_in, ecx_out); - /* Trans public key from big-endian to little-endian */ - ret = uadk_prov_reverse_bytes(ecxctx->peerkey->pubkey, ecxctx->keylen); - if (ret == UADK_P_FAIL) { - UADK_ERR("failed to trans peer public key\n"); - goto del_ecx_out; - } - - return ret; - -del_ecx_out: - wd_ecc_del_out(sess, ecx_out); -del_ecx_in: - wd_ecc_del_in(sess, ecx_in); + return UADK_P_SUCCESS; - return ret; } static void uadk_prov_ecx_compkey_uninit_iot(PROV_ECX_KEYEXCH_CTX *ecxctx, struct wd_ecc_req *req) @@ -1119,34 +1081,25 @@ static void uadk_prov_ecx_compkey_uninit_iot(PROV_ECX_KEYEXCH_CTX *ecxctx, struc static int uadk_prov_ecx_derive_set_prikey(PROV_ECX_KEYEXCH_CTX *ecxctx) { + unsigned char prikey_be[ECX_MAX_KEYLEN]; handle_t sess = ecxctx->sess; struct wd_ecc_key *ecc_key; struct wd_dtb prikey; int ret; - /* Trans private key from little-endian to big-endian */ - ret = uadk_prov_reverse_bytes(ecxctx->key->privkey, ecxctx->keylen); - if (!ret) { - UADK_ERR("failed to trans private key\n"); - return UADK_P_FAIL; - } + /* Trans private key from little-endian to big-endian into a temp buffer */ + uadk_prov_reverse_bytes_ex(ecxctx->key->privkey, prikey_be, ecxctx->keylen); - prikey.data = (char *)ecxctx->key->privkey; + prikey.data = (char *)prikey_be; prikey.dsize = ecxctx->keylen; ecc_key = wd_ecc_get_key(sess); ret = wd_ecc_set_prikey(ecc_key, &prikey); + OPENSSL_cleanse(prikey_be, sizeof(prikey_be)); if (ret) { UADK_ERR("failed to set ecc prikey, ret = %d\n", ret); return UADK_P_FAIL; } - /* Trans private key from big-endian to little-endian */ - ret = uadk_prov_reverse_bytes(ecxctx->key->privkey, ecxctx->keylen); - if (ret == UADK_P_FAIL) { - UADK_ERR("failed to trans private key\n"); - return UADK_P_FAIL; - } - return UADK_P_SUCCESS; } -- 2.43.0