diff --git a/crypto/rsa/internal.h b/crypto/rsa/internal.h index 410e72ffc..aa3a982b6 100644 --- a/crypto/rsa/internal.h +++ b/crypto/rsa/internal.h @@ -122,6 +122,12 @@ int RSA_padding_add_PKCS1_PSS_mgf1(RSA *rsa, uint8_t *EM, const uint8_t *mHash, const EVP_MD *Hash, const EVP_MD *mgf1Hash, int sLen); +/* RSA_private_transform calls either the method-specific |private_transform| + * function (if given) or the generic one. See the comment for + * |private_transform| in |rsa_meth_st|. */ +int RSA_private_transform(RSA *rsa, uint8_t *out, const uint8_t *in, + size_t len); + typedef struct rsa_pss_params_st { X509_ALGOR *hashAlgorithm; X509_ALGOR *maskGenAlgorithm; diff --git a/crypto/rsa/rsa.c b/crypto/rsa/rsa.c index 54187bb6c..147de1954 100644 --- a/crypto/rsa/rsa.c +++ b/crypto/rsa/rsa.c @@ -741,3 +741,12 @@ err: } return ok; } + +int RSA_private_transform(RSA *rsa, uint8_t *out, const uint8_t *in, + size_t len) { + if (rsa->meth->private_transform) { + return rsa->meth->private_transform(rsa, out, in, len); + } + + return RSA_default_method.private_transform(rsa, out, in, len); +} diff --git a/crypto/rsa/rsa_error.c b/crypto/rsa/rsa_error.c index e76f32ac6..3c8ebe4bb 100644 --- a/crypto/rsa/rsa_error.c +++ b/crypto/rsa/rsa_error.c @@ -43,6 +43,7 @@ const ERR_STRING_DATA RSA_error_string_data[] = { {ERR_PACK(ERR_LIB_RSA, RSA_F_encrypt, 0), "encrypt"}, {ERR_PACK(ERR_LIB_RSA, RSA_F_keygen, 0), "keygen"}, {ERR_PACK(ERR_LIB_RSA, RSA_F_pkcs1_prefixed_msg, 0), "pkcs1_prefixed_msg"}, + {ERR_PACK(ERR_LIB_RSA, RSA_F_private_transform, 0), "private_transform"}, {ERR_PACK(ERR_LIB_RSA, RSA_F_rsa_setup_blinding, 0), "rsa_setup_blinding"}, {ERR_PACK(ERR_LIB_RSA, RSA_F_sign_raw, 0), "sign_raw"}, {ERR_PACK(ERR_LIB_RSA, RSA_F_verify_raw, 0), "verify_raw"}, @@ -56,7 +57,7 @@ const ERR_STRING_DATA RSA_error_string_data[] = { {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_BN_NOT_INITIALIZED), "BN_NOT_INITIALIZED"}, {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_CRT_PARAMS_ALREADY_GIVEN), "CRT_PARAMS_ALREADY_GIVEN"}, {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_CRT_VALUES_INCORRECT), "CRT_VALUES_INCORRECT"}, - {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_DATA_GREATER_THAN_MOD_LEN), "DATA_GREATER_THAN_MOD_LEN"}, + {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_DATA_LEN_NOT_EQUAL_TO_MOD_LEN), "DATA_LEN_NOT_EQUAL_TO_MOD_LEN"}, {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_DATA_TOO_LARGE), "DATA_TOO_LARGE"}, {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE), "DATA_TOO_LARGE_FOR_KEY_SIZE"}, {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_DATA_TOO_LARGE_FOR_MODULUS), "DATA_TOO_LARGE_FOR_MODULUS"}, diff --git a/crypto/rsa/rsa_impl.c b/crypto/rsa/rsa_impl.c index 926f48fb4..7eb1bc545 100644 --- a/crypto/rsa/rsa_impl.c +++ b/crypto/rsa/rsa_impl.c @@ -327,11 +327,7 @@ static void rsa_blinding_release(RSA *rsa, BN_BLINDING *blinding, static int sign_raw(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out, const uint8_t *in, size_t in_len, int padding) { const unsigned rsa_size = RSA_size(rsa); - BIGNUM *f, *result; uint8_t *buf = NULL; - BN_CTX *ctx = NULL; - unsigned blinding_index = 0; - BN_BLINDING *blinding = NULL; int i, ret = 0; if (max_out < rsa_size) { @@ -339,15 +335,8 @@ static int sign_raw(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out, return 0; } - ctx = BN_CTX_new(); - if (ctx == NULL) { - goto err; - } - BN_CTX_start(ctx); - f = BN_CTX_get(ctx); - result = BN_CTX_get(ctx); buf = OPENSSL_malloc(rsa_size); - if (!f || !result || !buf) { + if (buf == NULL) { OPENSSL_PUT_ERROR(RSA, sign_raw, ERR_R_MALLOC_FAILURE); goto err; } @@ -363,83 +352,24 @@ static int sign_raw(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out, OPENSSL_PUT_ERROR(RSA, sign_raw, RSA_R_UNKNOWN_PADDING_TYPE); goto err; } + if (i <= 0) { goto err; } - if (BN_bin2bn(buf, rsa_size, f) == NULL) { - goto err; - } - - if (BN_ucmp(f, rsa->n) >= 0) { - /* usually the padding functions would catch this */ - OPENSSL_PUT_ERROR(RSA, sign_raw, RSA_R_DATA_TOO_LARGE_FOR_MODULUS); - goto err; - } - - if (!(rsa->flags & RSA_FLAG_NO_BLINDING)) { - blinding = rsa_blinding_get(rsa, &blinding_index, ctx); - if (blinding == NULL) { + if (!RSA_private_transform(rsa, out, buf, rsa_size)) { OPENSSL_PUT_ERROR(RSA, sign_raw, ERR_R_INTERNAL_ERROR); goto err; - } - if (!BN_BLINDING_convert_ex(f, NULL, blinding, ctx)) { - goto err; - } - } - - if ((rsa->flags & RSA_FLAG_EXT_PKEY) || - ((rsa->p != NULL) && (rsa->q != NULL) && (rsa->dmp1 != NULL) && - (rsa->dmq1 != NULL) && (rsa->iqmp != NULL))) { - if (!rsa->meth->mod_exp(result, f, rsa, ctx)) { - goto err; - } - } else { - BIGNUM local_d; - BIGNUM *d = NULL; - - BN_init(&local_d); - d = &local_d; - BN_with_flags(d, rsa->d, BN_FLG_CONSTTIME); - - if (rsa->flags & RSA_FLAG_CACHE_PUBLIC) { - if (!BN_MONT_CTX_set_locked(&rsa->_method_mod_n, CRYPTO_LOCK_RSA, rsa->n, - ctx)) { - goto err; - } - } - - if (!rsa->meth->bn_mod_exp(result, f, d, rsa->n, ctx, rsa->_method_mod_n)) { - goto err; - } - } - - if (blinding) { - if (!BN_BLINDING_invert_ex(result, NULL, blinding, ctx)) { - goto err; - } - } - - if (!BN_bn2bin_padded(out, rsa_size, result)) { - OPENSSL_PUT_ERROR(RSA, sign_raw, ERR_R_INTERNAL_ERROR); - goto err; } *out_len = rsa_size; ret = 1; err: - if (ctx != NULL) { - BN_CTX_end(ctx); - BN_CTX_free(ctx); - } if (buf != NULL) { OPENSSL_cleanse(buf, rsa_size); OPENSSL_free(buf); } - if (blinding != NULL) { - rsa_blinding_release(rsa, blinding, blinding_index); - } return ret; } @@ -447,12 +377,8 @@ err: static int decrypt(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out, const uint8_t *in, size_t in_len, int padding) { const unsigned rsa_size = RSA_size(rsa); - BIGNUM *f, *result; int r = -1; uint8_t *buf = NULL; - BN_CTX *ctx = NULL; - unsigned blinding_index; - BN_BLINDING *blinding = NULL; int ret = 0; if (max_out < rsa_size) { @@ -460,80 +386,18 @@ static int decrypt(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out, return 0; } - ctx = BN_CTX_new(); - if (ctx == NULL) { - goto err; - } - BN_CTX_start(ctx); - f = BN_CTX_get(ctx); - result = BN_CTX_get(ctx); buf = OPENSSL_malloc(rsa_size); - if (!f || !result || !buf) { + if (buf == NULL) { OPENSSL_PUT_ERROR(RSA, decrypt, ERR_R_MALLOC_FAILURE); goto err; } - /* This check was for equality but PGP does evil things - * and chops off the top '0' bytes. - * TODO(fork): investigate this. */ - if (in_len > rsa_size) { - OPENSSL_PUT_ERROR(RSA, decrypt, RSA_R_DATA_GREATER_THAN_MOD_LEN); + if (in_len != rsa_size) { + OPENSSL_PUT_ERROR(RSA, decrypt, RSA_R_DATA_LEN_NOT_EQUAL_TO_MOD_LEN); goto err; } - /* make data into a big number */ - if (BN_bin2bn(in, (int)in_len, f) == NULL) { - goto err; - } - - if (BN_ucmp(f, rsa->n) >= 0) { - OPENSSL_PUT_ERROR(RSA, decrypt, RSA_R_DATA_TOO_LARGE_FOR_MODULUS); - goto err; - } - - if (!(rsa->flags & RSA_FLAG_NO_BLINDING)) { - blinding = rsa_blinding_get(rsa, &blinding_index, ctx); - if (blinding == NULL) { - OPENSSL_PUT_ERROR(RSA, decrypt, ERR_R_INTERNAL_ERROR); - goto err; - } - if (!BN_BLINDING_convert_ex(f, NULL, blinding, ctx)) { - goto err; - } - } - - /* do the decrypt */ - if ((rsa->flags & RSA_FLAG_EXT_PKEY) || - ((rsa->p != NULL) && (rsa->q != NULL) && (rsa->dmp1 != NULL) && - (rsa->dmq1 != NULL) && (rsa->iqmp != NULL))) { - if (!rsa->meth->mod_exp(result, f, rsa, ctx)) { - goto err; - } - } else { - BIGNUM local_d; - BIGNUM *d = NULL; - - d = &local_d; - BN_with_flags(d, rsa->d, BN_FLG_CONSTTIME); - - if (rsa->flags & RSA_FLAG_CACHE_PUBLIC) { - if (!BN_MONT_CTX_set_locked(&rsa->_method_mod_n, CRYPTO_LOCK_RSA, rsa->n, - ctx)) { - goto err; - } - } - if (!rsa->meth->bn_mod_exp(result, f, d, rsa->n, ctx, rsa->_method_mod_n)) { - goto err; - } - } - - if (blinding) { - if (!BN_BLINDING_invert_ex(result, NULL, blinding, ctx)) { - goto err; - } - } - - if (!BN_bn2bin_padded(buf, rsa_size, result)) { + if (!RSA_private_transform(rsa, buf, in, rsa_size)) { OPENSSL_PUT_ERROR(RSA, decrypt, ERR_R_INTERNAL_ERROR); goto err; } @@ -563,17 +427,10 @@ static int decrypt(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out, } err: - if (ctx != NULL) { - BN_CTX_end(ctx); - BN_CTX_free(ctx); - } if (buf != NULL) { OPENSSL_cleanse(buf, rsa_size); OPENSSL_free(buf); } - if (blinding != NULL) { - rsa_blinding_release(rsa, blinding, blinding_index); - } return ret; } @@ -623,11 +480,8 @@ static int verify_raw(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out, goto err; } - /* This check was for equality but PGP does evil things - * and chops off the top '0' bytes. - * TODO(fork): investigate */ - if (in_len > rsa_size) { - OPENSSL_PUT_ERROR(RSA, verify_raw, RSA_R_DATA_GREATER_THAN_MOD_LEN); + if (in_len != rsa_size) { + OPENSSL_PUT_ERROR(RSA, verify_raw, RSA_R_DATA_LEN_NOT_EQUAL_TO_MOD_LEN); goto err; } @@ -688,6 +542,99 @@ err: return ret; } +static int private_transform(RSA *rsa, uint8_t *out, const uint8_t *in, + size_t len) { + BIGNUM *f, *result; + BN_CTX *ctx = NULL; + unsigned blinding_index = 0; + BN_BLINDING *blinding = NULL; + int ret = 0; + + ctx = BN_CTX_new(); + if (ctx == NULL) { + goto err; + } + BN_CTX_start(ctx); + f = BN_CTX_get(ctx); + result = BN_CTX_get(ctx); + + if (f == NULL || result == NULL) { + OPENSSL_PUT_ERROR(RSA, private_transform, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (BN_bin2bn(in, len, f) == NULL) { + goto err; + } + + if (BN_ucmp(f, rsa->n) >= 0) { + /* Usually the padding functions would catch this. */ + OPENSSL_PUT_ERROR(RSA, private_transform, RSA_R_DATA_TOO_LARGE_FOR_MODULUS); + goto err; + } + + if (!(rsa->flags & RSA_FLAG_NO_BLINDING)) { + blinding = rsa_blinding_get(rsa, &blinding_index, ctx); + if (blinding == NULL) { + OPENSSL_PUT_ERROR(RSA, private_transform, ERR_R_INTERNAL_ERROR); + goto err; + } + if (!BN_BLINDING_convert_ex(f, NULL, blinding, ctx)) { + goto err; + } + } + + if ((rsa->flags & RSA_FLAG_EXT_PKEY) || + ((rsa->p != NULL) && (rsa->q != NULL) && (rsa->dmp1 != NULL) && + (rsa->dmq1 != NULL) && (rsa->iqmp != NULL))) { + if (!rsa->meth->mod_exp(result, f, rsa, ctx)) { + goto err; + } + } else { + BIGNUM local_d; + BIGNUM *d = NULL; + + BN_init(&local_d); + d = &local_d; + BN_with_flags(d, rsa->d, BN_FLG_CONSTTIME); + + if (rsa->flags & RSA_FLAG_CACHE_PUBLIC) { + if (!BN_MONT_CTX_set_locked(&rsa->_method_mod_n, CRYPTO_LOCK_RSA, rsa->n, + ctx)) { + goto err; + } + } + + if (!rsa->meth->bn_mod_exp(result, f, d, rsa->n, ctx, rsa->_method_mod_n)) { + goto err; + } + } + + if (blinding) { + if (!BN_BLINDING_invert_ex(result, NULL, blinding, ctx)) { + goto err; + } + } + + if (!BN_bn2bin_padded(out, len, result)) { + OPENSSL_PUT_ERROR(RSA, private_transform, ERR_R_INTERNAL_ERROR); + goto err; + } + + ret = 1; + +err: + if (ctx != NULL) { + BN_CTX_end(ctx); + BN_CTX_free(ctx); + } + if (blinding != NULL) { + rsa_blinding_release(rsa, blinding, blinding_index); + } + + return ret; +} + static int mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa, BN_CTX *ctx) { BIGNUM *r1, *m1, *vrfy; BIGNUM local_dmp1, local_dmq1, local_c, local_r1; @@ -1000,6 +947,8 @@ const struct rsa_meth_st RSA_default_method = { decrypt, verify_raw, + private_transform, + mod_exp /* mod_exp */, BN_mod_exp_mont /* bn_mod_exp */, diff --git a/include/openssl/rsa.h b/include/openssl/rsa.h index 9827e697d..bd0b0d17b 100644 --- a/include/openssl/rsa.h +++ b/include/openssl/rsa.h @@ -386,6 +386,21 @@ struct rsa_meth_st { int (*verify_raw)(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out, const uint8_t *in, size_t in_len, int padding); + /* private_transform takes a big-endian integer from |in|, calculates the + * d'th power of it, modulo the RSA modulus and writes the result as a + * big-endian integer to |out|. Both |in| and |out| are |len| bytes long and + * |len| is always equal to |RSA_size(rsa)|. If the result of the transform + * can be represented in fewer than |len| bytes, then |out| must be zero + * padded on the left. + * + * It returns one on success and zero otherwise. + * + * RSA decrypt and sign operations will call this, thus an ENGINE might wish + * to override it in order to avoid having to implement the padding + * functionality demanded by those, higher level, operations. */ + int (*private_transform)(RSA *rsa, uint8_t *out, const uint8_t *in, + size_t len); + int (*mod_exp)(BIGNUM *r0, const BIGNUM *I, RSA *rsa, BN_CTX *ctx); /* Can be null */ int (*bn_mod_exp)(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, @@ -470,8 +485,8 @@ struct rsa_st { #define RSA_F_RSA_padding_check_PKCS1_type_2 126 #define RSA_F_RSA_recover_crt_params 127 #define RSA_F_RSA_check_key 128 +#define RSA_F_private_transform 129 #define RSA_R_INVALID_MESSAGE_LENGTH 100 -#define RSA_R_DATA_GREATER_THAN_MOD_LEN 101 #define RSA_R_NO_PUBLIC_EXPONENT 102 #define RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE 103 #define RSA_R_BLOCK_TYPE_IS_NOT_01 104 @@ -514,5 +529,6 @@ struct rsa_st { #define RSA_R_CRT_VALUES_INCORRECT 141 #define RSA_R_INCONSISTENT_SET_OF_CRT_VALUES 142 #define RSA_R_ONLY_ONE_OF_P_Q_GIVEN 143 +#define RSA_R_DATA_LEN_NOT_EQUAL_TO_MOD_LEN 144 #endif /* OPENSSL_HEADER_RSA_H */