From: lizhi <lizhi206@huawei.com> Add support for RSA encryption padding modes with OpenSSL provider mechanism, including RSA_PKCS1_OAEP_PADDING and RSA_PKCS1_WITH_TLS_PADDING. Test with: openssl pkeyutl -encrypt -in test.txt -out encrypted.bin -pubin -inkey public.pem -pkeyopt rsa_padding_mode:oaep openssl pkeyutl -decrypt -in encrypted.bin -out decrypted.txt -inkey private.pem -pkeyopt rsa_padding_mode:oaep openssl s_server -provider uadk_provider -accept 4333 -cert server.pem -www -cipher AES256-SHA openssl s_client -provider uadk_provider -connect localhost:4333 Signed-off-by: lizhi <lizhi206@huawei.com> --- src/uadk_prov_rsa_enc.c | 287 ++++++++++++++++++++++++++++++++++---- src/uadk_prov_rsa_kmgmt.c | 20 +-- 2 files changed, 268 insertions(+), 39 deletions(-) diff --git a/src/uadk_prov_rsa_enc.c b/src/uadk_prov_rsa_enc.c index 3c4fe0e..d4f8106 100644 --- a/src/uadk_prov_rsa_enc.c +++ b/src/uadk_prov_rsa_enc.c @@ -17,6 +17,15 @@ * */ #include "uadk_prov_rsa.h" +#include <openssl/prov_ssl.h> +#include <openssl/rand.h> + +#define RSA_PKCS1_PADDING_SIZE 11 +#define PKCS1_TLS_ZERO_PADD 0x00 +#define PKCS1_TLS_NONE_ZERO_PADD 0x02 +#define CLIENT_VERSION_SHIFT 8 +#define PKCS1_TLS_PADDING_POS 2 +#define CLIENT_VERSION_MASK 0xFF UADK_PKEY_ASYM_CIPHER_DESCR(rsa, RSA); @@ -64,6 +73,66 @@ static UADK_PKEY_ASYM_CIPHER get_default_rsa_asym_cipher(void) return s_asym_cipher; } +/** + * Checks and removes PKCS#1 v1.5 padding for TLS RSA decryption. + * This function validates and strips PKCS#1 type 2 (v1.5) padding from an RSA-encrypted + * pre-master secret as used in TLS. It ensures the decrypted data conforms to the expected + * format, checks the client version, and provides constant-time fallback to random data + * if the padding or version is invalid, as required by the TLS protocol to prevent + * side-channel attacks. + */ +static int RSA_padding_check_PKCS1_type_2_TLS(OSSL_LIB_CTX *libctx, + unsigned char *to, size_t tlen, + const unsigned char *from, size_t flen, + int client_version, int alt_version) +{ + unsigned char rand_premaster[SSL_MAX_MASTER_KEY_LENGTH]; + int premaster_len = SSL_MAX_MASTER_KEY_LENGTH; + int plen, good; + unsigned char *p; + int i; + + if (flen < RSA_PKCS1_PADDING_SIZE || tlen < premaster_len) + goto err; + + p = (unsigned char *)from; + if (p[0] != PKCS1_TLS_ZERO_PADD || p[1] != PKCS1_TLS_NONE_ZERO_PADD) + goto err; + + for (i = PKCS1_TLS_PADDING_POS; i < flen; i++) { + if (p[i] == PKCS1_TLS_ZERO_PADD) + break; + } + + if (i == flen || i < (RSA_PKCS1_PADDING_SIZE - 1)) + goto err; + plen = flen - (i + 1); + if (plen != premaster_len) + goto err; + memcpy(to, p + i + 1, premaster_len); + + good = (to[0] == (client_version >> CLIENT_VERSION_SHIFT) && + to[1] == (client_version & CLIENT_VERSION_MASK)); + if (!good && alt_version > 0) + good = (to[0] == (alt_version >> CLIENT_VERSION_SHIFT) + && to[1] == + (alt_version & CLIENT_VERSION_MASK)); + if (!good) { + if (RAND_bytes_ex(libctx, rand_premaster, premaster_len, 0) <= 0) + goto err; + memcpy(to, rand_premaster, premaster_len); + } + + OPENSSL_cleanse(rand_premaster, premaster_len); + return premaster_len; +err: + if (RAND_bytes_ex(libctx, rand_premaster, premaster_len, 0) > 0) + memcpy(to, rand_premaster, premaster_len); + OPENSSL_cleanse(rand_premaster, premaster_len); + + return CHECK_PADDING_FAIL; +} + static int add_rsa_pubenc_padding(int flen, const unsigned char *from, unsigned char *buf, int num, int padding) { @@ -72,18 +141,22 @@ static int add_rsa_pubenc_padding(int flen, const unsigned char *from, switch (padding) { case RSA_PKCS1_PADDING: ret = RSA_padding_add_PKCS1_type_2(buf, num, from, flen); - if (!ret) - UADK_ERR("RSA_PKCS1_PADDING err.\n"); break; case RSA_PKCS1_OAEP_PADDING: ret = RSA_padding_add_PKCS1_OAEP(buf, num, from, flen, NULL, 0); - if (!ret) - UADK_ERR("RSA_PKCS1_OAEP_PADDING err.\n"); + break; + case RSA_NO_PADDING: + ret = RSA_padding_add_none(buf, num, from, flen); break; default: ret = UADK_P_FAIL; } + if (ret <= UADK_P_FAIL) { + ret = UADK_P_FAIL; + UADK_ERR("failed to add rsa encrypt padding %d\n", padding); + } + return ret; } @@ -96,21 +169,23 @@ static int check_rsa_pridec_padding(unsigned char *to, int num, switch (padding) { case RSA_PKCS1_PADDING: ret = RSA_padding_check_PKCS1_type_2(to, num, buf, flen, num); - if (ret == CHECK_PADDING_FAIL) - UADK_ERR("RSA_PKCS1_PADDING err.\n"); break; case RSA_PKCS1_OAEP_PADDING: ret = RSA_padding_check_PKCS1_OAEP(to, num, buf, flen, num, NULL, 0); - if (ret == CHECK_PADDING_FAIL) - UADK_ERR("RSA_PKCS1_OAEP_PADDING err.\n"); + break; + case RSA_NO_PADDING: + memcpy(to, buf, flen); + ret = flen; break; default: - ret = UADK_P_FAIL; + ret = CHECK_PADDING_FAIL; } - if (ret == CHECK_PADDING_FAIL) + if (ret == CHECK_PADDING_FAIL) { + UADK_ERR("failed to check rsa decrypt %d\n", padding); ret = UADK_P_FAIL; + } return ret; } @@ -247,8 +322,6 @@ static int uadk_prov_rsa_private_decrypt(int flen, const unsigned char *from, goto free_buf; ret = check_rsa_pridec_padding(to, num_bytes, from_buf, flen, padding); - if (!ret) - ret = UADK_P_FAIL; free_buf: rsa_free_pri_bn_ctx(from_buf); @@ -264,9 +337,13 @@ static int uadk_rsa_asym_init(void *vprsactx, void *vrsa, { struct PROV_RSA_ASYM_CTX *priv = (struct PROV_RSA_ASYM_CTX *)vprsactx; - if (priv == NULL || vrsa == NULL) + if (!priv || !vrsa) + return UADK_P_FAIL; + + if (!RSA_up_ref(vrsa)) return UADK_P_FAIL; + RSA_free(priv->rsa); priv->rsa = vrsa; priv->operation = operation; @@ -293,7 +370,7 @@ static void *uadk_asym_cipher_rsa_newctx(void *provctx) struct PROV_RSA_ASYM_CTX *priv = NULL; priv = OPENSSL_zalloc(sizeof(*priv)); - if (priv == NULL) + if (!priv) return NULL; priv->libctx = prov_libctx_of(provctx); @@ -304,9 +381,14 @@ static void uadk_asym_cipher_rsa_freectx(void *vprsactx) { struct PROV_RSA_ASYM_CTX *priv = (struct PROV_RSA_ASYM_CTX *)vprsactx; - if (priv == NULL) + if (!priv) return; + RSA_free(priv->rsa); + EVP_MD_free(priv->oaep_md); + EVP_MD_free(priv->mgf1_md); + OPENSSL_free(priv->oaep_label); + OPENSSL_free(priv); } @@ -341,6 +423,46 @@ static int uadk_rsa_sw_encrypt(void *vprsactx, unsigned char *out, return get_default_rsa_asym_cipher().encrypt(vprsactx, out, outlen, outsize, in, inlen); } +static int uadk_asym_cipher_rsa_oaep_encrypt(void *vprsactx, unsigned char *out, + const unsigned char *in, size_t inlen) +{ + struct PROV_RSA_ASYM_CTX *priv = (struct PROV_RSA_ASYM_CTX *)vprsactx; + unsigned char *tbuf; + int rsasize, ret; + + rsasize = RSA_size(priv->rsa); + tbuf = OPENSSL_malloc(rsasize); + if (!tbuf) { + UADK_ERR("failed to malloc buffer in rsa oaep encrypt\n"); + return UADK_P_FAIL; + } + + if (!priv->oaep_md) { + priv->oaep_md = EVP_MD_fetch(priv->libctx, "SHA-1", NULL); + if (!priv->oaep_md) { + OPENSSL_free(tbuf); + UADK_ERR("failed to fetch SHA-1 digest method in rsa oaep encrypt\n"); + return UADK_P_FAIL; + } + } + + ret = RSA_padding_add_PKCS1_OAEP_mgf1(tbuf, rsasize, + in, inlen, + priv->oaep_label, + priv->oaep_labellen, + priv->oaep_md, + priv->mgf1_md); + if (!ret) { + OPENSSL_free(tbuf); + return UADK_P_FAIL; + } + + ret = uadk_prov_rsa_public_encrypt(rsasize, tbuf, out, priv->rsa, RSA_NO_PADDING); + OPENSSL_free(tbuf); + + return ret; +} + static int uadk_asym_cipher_rsa_encrypt(void *vprsactx, unsigned char *out, size_t *outlen, size_t outsize, const unsigned char *in, size_t inlen) @@ -354,7 +476,7 @@ static int uadk_asym_cipher_rsa_encrypt(void *vprsactx, unsigned char *out, goto exe_soft; } - if (out == NULL) { + if (!out) { len = uadk_rsa_size(priv->rsa); if (len == 0) { UADK_ERR("invalid: rsa encrypt size.\n"); @@ -364,12 +486,15 @@ static int uadk_asym_cipher_rsa_encrypt(void *vprsactx, unsigned char *out, return UADK_P_SUCCESS; } - ret = uadk_prov_rsa_public_encrypt(inlen, in, out, priv->rsa, priv->pad_mode); + if (priv->pad_mode == RSA_PKCS1_OAEP_PADDING) + ret = uadk_asym_cipher_rsa_oaep_encrypt(priv, out, in, inlen); + else + ret = uadk_prov_rsa_public_encrypt(inlen, in, out, priv->rsa, priv->pad_mode); + if (ret == UADK_DO_SOFT || ret == UADK_P_FAIL) goto exe_soft; *outlen = ret; - return UADK_P_SUCCESS; exe_soft: if (ret == UADK_DO_SOFT) @@ -388,34 +513,138 @@ static int uadk_rsa_sw_decrypt(void *vprsactx, unsigned char *out, return get_default_rsa_asym_cipher().decrypt(vprsactx, out, outlen, outsize, in, inlen); } +static int uadk_asym_cipher_rsa_oaep_decrypt(struct PROV_RSA_ASYM_CTX *priv, + unsigned char *out, size_t *outlen, size_t outsize, + const unsigned char *in, size_t inlen) +{ + size_t len = uadk_rsa_size(priv->rsa); + unsigned char *tbuf; + int ret; + + tbuf = OPENSSL_malloc(len); + if (!tbuf) { + UADK_ERR("failed to malloc buf in rsa oaep decrypt\n"); + return UADK_P_FAIL; + } + + ret = uadk_prov_rsa_private_decrypt(inlen, in, tbuf, priv->rsa, RSA_NO_PADDING); + if (ret != (int)len) { + OPENSSL_free(tbuf); + UADK_ERR("failed to do rsa oaep decrypt\n"); + return ret; + } + + if (!priv->oaep_md) { + priv->oaep_md = EVP_MD_fetch(priv->libctx, "SHA-1", NULL); + if (!priv->oaep_md) { + OPENSSL_free(tbuf); + UADK_ERR("faile to fetch SHA-1 digest method in rsa oaep decrypt\n"); + return UADK_P_FAIL; + } + } + ret = RSA_padding_check_PKCS1_OAEP_mgf1(out, outsize, tbuf, + len, len, + priv->oaep_label, + priv->oaep_labellen, + priv->oaep_md, + priv->mgf1_md); + if (ret == CHECK_PADDING_FAIL) + ret = UADK_P_FAIL; + + OPENSSL_free(tbuf); + return ret; +} + +static int uadk_asym_cipher_rsa_tls_decrypt(struct PROV_RSA_ASYM_CTX *priv, + unsigned char *out, size_t *outlen, size_t outsize, + const unsigned char *in, size_t inlen) +{ + size_t len = uadk_rsa_size(priv->rsa); + unsigned char *tbuf; + int ret; + + /* RSA_PKCS1_WITH_TLS_PADDING */ + if (priv->client_version == 0) { + UADK_ERR("invalid: tls client version is %u\n", priv->client_version); + return UADK_P_FAIL; + } + + tbuf = OPENSSL_malloc(len); + if (!tbuf) { + UADK_ERR("failed to malloc buf in rsa tls decrypt\n"); + return UADK_P_FAIL; + } + + ret = uadk_prov_rsa_private_decrypt(inlen, in, tbuf, priv->rsa, RSA_NO_PADDING); + if (ret != (int)len) { + OPENSSL_free(tbuf); + UADK_ERR("failed to do rsa tls decrypt\n"); + return ret; + } + + ret = RSA_padding_check_PKCS1_type_2_TLS(priv->libctx, out, outsize, + tbuf, len, priv->client_version, + priv->alt_version); + if (ret == CHECK_PADDING_FAIL) + ret = UADK_P_FAIL; + + OPENSSL_free(tbuf); + return ret; +} + static int uadk_asym_cipher_rsa_decrypt(void *vprsactx, unsigned char *out, size_t *outlen, size_t outsize, const unsigned char *in, size_t inlen) { struct PROV_RSA_ASYM_CTX *priv = (struct PROV_RSA_ASYM_CTX *)vprsactx; - size_t len = uadk_rsa_size(priv->rsa); + size_t len; int ret; - if (priv->soft) { + if (!priv || priv->soft) { ret = UADK_DO_SOFT; goto exe_soft; } - if (out == NULL) { - if (len == 0) { - UADK_ERR("invalid: rsa decrypt size.\n"); + len = uadk_rsa_size(priv->rsa); + if (priv->pad_mode == RSA_PKCS1_WITH_TLS_PADDING) { + if (!out) { + *outlen = SSL_MAX_MASTER_KEY_LENGTH; + return UADK_P_SUCCESS; + } + if (outsize < SSL_MAX_MASTER_KEY_LENGTH) { + UADK_ERR("invalid: incorrect rsa decrypt outsize in padding %d\n", + priv->pad_mode); + return UADK_P_FAIL; + } + } else { + if (!out) { + if (len == 0) { + UADK_ERR("invalid: incorrect rsa decrypt size in padding %d\n", + priv->pad_mode); + return UADK_P_FAIL; + } + *outlen = len; + return UADK_P_SUCCESS; + } + + if (outsize < len) { + UADK_ERR("invalid: incorrect rsa decrypt outsize in padding %d\n", + priv->pad_mode); return UADK_P_FAIL; } - *outlen = len; - return UADK_P_SUCCESS; } - if (outsize < len) { - UADK_ERR("invalid: rsa decrypt outsize is too small.\n"); - return UADK_P_FAIL; + switch (priv->pad_mode) { + case RSA_PKCS1_OAEP_PADDING: + ret = uadk_asym_cipher_rsa_oaep_decrypt(priv, out, outlen, outsize, in, inlen); + break; + case RSA_PKCS1_WITH_TLS_PADDING: + ret = uadk_asym_cipher_rsa_tls_decrypt(priv, out, outlen, outsize, in, inlen); + break; + default: + ret = uadk_prov_rsa_private_decrypt(inlen, in, out, priv->rsa, priv->pad_mode); } - ret = uadk_prov_rsa_private_decrypt(inlen, in, out, priv->rsa, priv->pad_mode); if (ret == UADK_DO_SOFT || ret == UADK_P_FAIL) goto exe_soft; diff --git a/src/uadk_prov_rsa_kmgmt.c b/src/uadk_prov_rsa_kmgmt.c index fc03276..f71eed3 100644 --- a/src/uadk_prov_rsa_kmgmt.c +++ b/src/uadk_prov_rsa_kmgmt.c @@ -91,8 +91,8 @@ static int uadk_rsa_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d) * parameters MUST be non-NULL for n and e. d may be * left NULL (in case only the public key is used). */ - if ((r->n == NULL && n == NULL) - || (r->e == NULL && e == NULL)) + if ((!r->n && !n) + || (!r->e && !e)) return UADK_P_FAIL; if (n != NULL) { @@ -119,7 +119,7 @@ static int uadk_rsa_set0_factors(RSA *r, BIGNUM *p, BIGNUM *q) * If the fields p and q in r are NULL, the corresponding input * parameters MUST be non-NULL. */ - if ((r->p == NULL && p == NULL) || (r->q == NULL && q == NULL)) + if ((!r->p && !p) || (!r->q && !q)) return UADK_P_FAIL; if (p != NULL) { @@ -145,9 +145,9 @@ static int uadk_rsa_set0_crt_params(RSA *r, BIGNUM *dmp1, BIGNUM *dmq1, BIGNUM * * If the fields dmp1, dmq1 and iqmp in r are NULL, the corresponding input * parameters MUST be non-NULL. */ - if ((r->dmp1 == NULL && dmp1 == NULL) - || (r->dmq1 == NULL && dmq1 == NULL) - || (r->iqmp == NULL && iqmp == NULL)) + if ((!r->dmp1 && !dmp1) + || (!r->dmq1 && !dmq1) + || (!r->iqmp && !iqmp)) return UADK_P_FAIL; if (dmp1 != NULL) { @@ -516,14 +516,14 @@ static RSA *ossl_rsa_new_with_ctx(OSSL_LIB_CTX *libctx) { RSA *rsa = OPENSSL_zalloc(sizeof(*rsa)); - if (rsa == NULL) { + if (!rsa) { UADK_ERR("failed to zalloc rsa ret\n"); return NULL; } rsa->references = 1; rsa->lock = CRYPTO_THREAD_lock_new(); - if (rsa->lock == NULL) { + if (!rsa->lock) { UADK_ERR("failed to malloc thread lock\n"); OPENSSL_free(rsa); return NULL; @@ -843,7 +843,7 @@ static void *uadk_keymgmt_rsa_gen(void *genctx, OSSL_CALLBACK *osslcb, void *cba RSA *rsa; int ret; - if (gctx == NULL) + if (!gctx) return NULL; ret = uadk_prov_rsa_init(); @@ -853,7 +853,7 @@ static void *uadk_keymgmt_rsa_gen(void *genctx, OSSL_CALLBACK *osslcb, void *cba } rsa = ossl_rsa_new_with_ctx(gctx->libctx); - if (rsa == NULL) + if (!rsa) return NULL; gctx->cb = osslcb; -- 2.43.0