diff --git a/Makefile.PL b/Makefile.PL index 76c9b76..588bd5b 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -4,8 +4,10 @@ use Config; use 5.006; use ExtUtils::MakeMaker 6.48; -use Crypt::OpenSSL::Guess qw(openssl_inc_paths openssl_lib_paths); +use Crypt::OpenSSL::Guess qw(openssl_inc_paths openssl_lib_paths openssl_version); +my ($major, $minor, $patch) = openssl_version(); +print "OpenSSL version: $major.$minor $patch", "\n"; # See lib/ExtUtils/MakeMaker.pm for details of how to influence # the contents of the Makefile that is written. diff --git a/RSA.xs b/RSA.xs index 9554126..a3f2ea9 100644 --- a/RSA.xs +++ b/RSA.xs @@ -17,10 +17,41 @@ #include #include #include +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +#include +#include +#include +#endif + +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +#define UNSIGNED_CHAR unsigned char +#define SIZE_T_INT size_t +#define SIZE_T_UNSIGNED_INT size_t +#define EVP_PKEY EVP_PKEY +#define EVP_PKEY_free(p) EVP_PKEY_free(p) +#define EVP_PKEY_get_size(p) EVP_PKEY_get_size(p) +#define PEM_read_bio_PrivateKey PEM_read_bio_PrivateKey +#define PEM_read_bio_RSAPublicKey PEM_read_bio_PUBKEY +#define PEM_read_bio_RSA_PUBKEY PEM_read_bio_PUBKEY +#define PEM_write_bio_PUBKEY(o,p) PEM_write_bio_PUBKEY(o,p); +#define PEM_write_bio_PrivateKey_traditional(m, n, o, p, q, r, s) PEM_write_bio_PrivateKey_traditional(m, n, o, p, q, r, s) +#else +#define UNSIGNED_CHAR char +#define SIZE_T_INT int +#define SIZE_T_UNSIGNED_INT unsigned int +#define EVP_PKEY RSA +#define EVP_PKEY_free(p) RSA_free(p) +#define EVP_PKEY_get_size(p) RSA_size(p) +#define PEM_read_bio_PrivateKey PEM_read_bio_RSAPrivateKey +#define PEM_read_bio_RSAPublicKey PEM_read_bio_RSAPublicKey +#define PEM_read_bio_RSA_PUBKEY PEM_read_bio_RSA_PUBKEY +#define PEM_write_bio_PUBKEY(o,p) PEM_write_bio_RSA_PUBKEY(o,p) +#define PEM_write_bio_PrivateKey_traditional(m, n, o, p, q, r, s) PEM_write_bio_RSAPrivateKey(m, n , o, p, q, r, s) +#endif typedef struct { - RSA* rsa; + EVP_PKEY* rsa; int padding; int hashMode; } rsaData; @@ -55,16 +86,27 @@ void croakSsl(char* p_file, int p_line) char _is_private(rsaData* p_rsa) { - const BIGNUM *d; + char ret = 0; #if OLD_CRUFTY_SSL_VERSION + const BIGNUM* d; d = p_rsa->rsa->d; + ret = (d != NULL); #else +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + BIGNUM* d = NULL; + EVP_PKEY_get_bn_param(p_rsa->rsa, OSSL_PKEY_PARAM_RSA_D, &d); + ret = (d != NULL); + BN_clear_free(d); +#else + const BIGNUM* d = NULL; RSA_get0_key(p_rsa->rsa, NULL, NULL, &d); + ret = (d != NULL); +#endif #endif - return(d != NULL); + return ret; } -SV* make_rsa_obj(SV* p_proto, RSA* p_rsa) +SV* make_rsa_obj(SV* p_proto, EVP_PKEY* p_rsa) { rsaData* rsa; @@ -114,18 +156,63 @@ int get_digest_length(int hash_method) break; } } +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +EVP_MD *get_md_bynid(int hash_method) +{ + switch(hash_method) + { + case NID_md5: + return EVP_MD_fetch(NULL, "md5", NULL); + break; + case NID_sha1: + return EVP_MD_fetch(NULL, "sha1", NULL); + break; +#ifdef SHA512_DIGEST_LENGTH + case NID_sha224: + return EVP_MD_fetch(NULL, "sha224", NULL); + break; + case NID_sha256: + return EVP_MD_fetch(NULL, "sha256", NULL); + break; + case NID_sha384: + return EVP_MD_fetch(NULL, "sha384", NULL); + break; + case NID_sha512: + return EVP_MD_fetch(NULL, "sha512", NULL); + break; +#endif + case NID_ripemd160: + return EVP_MD_fetch(NULL, "ripemd160", NULL); + break; +#ifdef WHIRLPOOL_DIGEST_LENGTH + case NID_whirlpool: + return EVP_MD_fetch(NULL, "whirlpool", NULL); + break; +#endif + default: + croak("Unknown digest hash mode %u", hash_method); + break; + } +} +#endif unsigned char* get_message_digest(SV* text_SV, int hash_method) { STRLEN text_length; unsigned char* text; - +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + static unsigned char md[EVP_MAX_MD_SIZE]; +#endif text = (unsigned char*) SvPV(text_SV, text_length); switch(hash_method) { case NID_md5: +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + return EVP_Q_digest(NULL, "MD5", NULL, text, text_length, md, NULL) ? md : NULL; +#else return MD5(text, text_length, NULL); +#endif break; case NID_sha1: return SHA1(text, text_length, NULL); @@ -145,7 +232,11 @@ unsigned char* get_message_digest(SV* text_SV, int hash_method) break; #endif case NID_ripemd160: +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + return EVP_Q_digest(NULL, "RIPEMD160", NULL, text, text_length, md, NULL) ? md : NULL; +#else return RIPEMD160(text, text_length, NULL); +#endif break; #ifdef WHIRLPOOL_DIGEST_LENGTH case NID_whirlpool: @@ -168,7 +259,7 @@ SV* cor_bn2sv(const BIGNUM* p_bn) SV* extractBioString(BIO* p_stringBio) { SV* sv; - char *datap; + char* datap; long datasize = 0; CHECK_OPEN_SSL(BIO_flush(p_stringBio) == 1); @@ -181,15 +272,15 @@ SV* extractBioString(BIO* p_stringBio) return sv; } -RSA* _load_rsa_key(SV* p_keyStringSv, - RSA*(*p_loader)(BIO*, RSA**, pem_password_cb*, void*), +EVP_PKEY* _load_rsa_key(SV* p_keyStringSv, + EVP_PKEY*(*p_loader)(BIO *, EVP_PKEY**, pem_password_cb*, void*), SV* p_passphaseSv) { STRLEN keyStringLength; char* keyString; - char* passphase = NULL; + UNSIGNED_CHAR *passphase = NULL; - RSA* rsa; + EVP_PKEY* rsa; BIO* stringBIO; keyString = SvPV(p_keyStringSv, keyStringLength); @@ -208,35 +299,60 @@ RSA* _load_rsa_key(SV* p_keyStringSv, CHECK_OPEN_SSL(rsa); return rsa; } +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + +SV* rsa_crypt(rsaData* p_rsa, SV* p_from, + int (*p_crypt)(EVP_PKEY_CTX*, unsigned char*, size_t*, const unsigned char*, size_t), + int (*init_crypt)(EVP_PKEY_CTX*), int public) +#else SV* rsa_crypt(rsaData* p_rsa, SV* p_from, int (*p_crypt)(int, const unsigned char*, unsigned char*, RSA*, int)) +#endif { STRLEN from_length; - int to_length; + SIZE_T_INT to_length; int size; unsigned char* from; - char* to; + UNSIGNED_CHAR *to; SV* sv; from = (unsigned char*) SvPV(p_from, from_length); - size = RSA_size(p_rsa->rsa); - CHECK_NEW(to, size, char); + size = EVP_PKEY_get_size(p_rsa->rsa); + CHECK_NEW(to, size, UNSIGNED_CHAR); +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_PKEY_CTX *ctx; + + OSSL_LIB_CTX *ossllibctx = OSSL_LIB_CTX_new(); + const char* propquery; + if (public) { + ctx = EVP_PKEY_CTX_new_from_pkey(ossllibctx, (EVP_PKEY* )p_rsa->rsa, propquery); + } else { + ctx = EVP_PKEY_CTX_new((EVP_PKEY* )p_rsa->rsa, NULL); + } + + CHECK_OPEN_SSL(ctx); + CHECK_OPEN_SSL(init_crypt(ctx) == 1); + CHECK_OPEN_SSL(EVP_PKEY_CTX_set_rsa_padding(ctx, p_rsa->padding) > 0); + CHECK_OPEN_SSL(p_crypt(ctx, NULL, &to_length, from, from_length) == 1); + CHECK_OPEN_SSL(p_crypt(ctx, to, &to_length, from, from_length) == 1); + + EVP_PKEY_CTX_free(ctx); +#else to_length = p_crypt( from_length, from, (unsigned char*) to, p_rsa->rsa, p_rsa->padding); - +#endif if (to_length < 0) { Safefree(to); CHECK_OPEN_SSL(0); } - sv = newSVpv(to, to_length); + sv = newSVpv((char* ) to, to_length); Safefree(to); return sv; } - MODULE = Crypt::OpenSSL::RSA PACKAGE = Crypt::OpenSSL::RSA PROTOTYPES: DISABLE @@ -257,7 +373,7 @@ new_private_key(proto, key_string_SV, passphase_SV=&PL_sv_undef) SV* passphase_SV; CODE: RETVAL = make_rsa_obj( - proto, _load_rsa_key(key_string_SV, PEM_read_bio_RSAPrivateKey, passphase_SV)); + proto, _load_rsa_key(key_string_SV, PEM_read_bio_PrivateKey, passphase_SV)); OUTPUT: RETVAL @@ -285,7 +401,7 @@ void DESTROY(p_rsa) rsaData* p_rsa; CODE: - RSA_free(p_rsa->rsa); + EVP_PKEY_free(p_rsa->rsa); Safefree(p_rsa); SV* @@ -318,8 +434,8 @@ get_private_key_string(p_rsa, passphase_SV=&PL_sv_undef, cipher_name_SV=&PL_sv_u } CHECK_OPEN_SSL(stringBIO = BIO_new(BIO_s_mem())); - PEM_write_bio_RSAPrivateKey( - stringBIO, p_rsa->rsa, enc, passphase, passphaseLength, NULL, NULL); + PEM_write_bio_PrivateKey_traditional( + stringBIO, p_rsa->rsa, enc, (unsigned char* ) passphase, passphaseLength, NULL, NULL); RETVAL = extractBioString(stringBIO); OUTPUT: @@ -332,7 +448,19 @@ get_public_key_string(p_rsa) BIO* stringBIO; CODE: CHECK_OPEN_SSL(stringBIO = BIO_new(BIO_s_mem())); +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + OSSL_ENCODER_CTX *ctx = NULL; + + ctx = OSSL_ENCODER_CTX_new_for_pkey(p_rsa->rsa, OSSL_KEYMGMT_SELECT_PUBLIC_KEY, + "PEM", "PKCS1", NULL); + CHECK_OPEN_SSL(ctx != NULL && OSSL_ENCODER_CTX_get_num_encoders(ctx)); + + CHECK_OPEN_SSL(OSSL_ENCODER_to_bio(ctx, stringBIO) == 1); + + OSSL_ENCODER_CTX_free(ctx); +#else PEM_write_bio_RSAPublicKey(stringBIO, p_rsa->rsa); +#endif RETVAL = extractBioString(stringBIO); OUTPUT: @@ -345,7 +473,7 @@ get_public_key_x509_string(p_rsa) BIO* stringBIO; CODE: CHECK_OPEN_SSL(stringBIO = BIO_new(BIO_s_mem())); - PEM_write_bio_RSA_PUBKEY(stringBIO, p_rsa->rsa); + PEM_write_bio_PUBKEY(stringBIO, p_rsa->rsa); RETVAL = extractBioString(stringBIO); OUTPUT: @@ -357,20 +485,38 @@ generate_key(proto, bitsSV, exponent = 65537) SV* bitsSV; unsigned long exponent; PREINIT: - RSA* rsa; + EVP_PKEY* rsa = NULL; +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_PKEY_CTX *ctx; +#endif CODE: -#if OPENSSL_VERSION_NUMBER >= 0x00908000L BIGNUM *e; - int rc; e = BN_new(); BN_set_word(e, exponent); +#if OPENSSL_VERSION_NUMBER < 0x00908000L + rsa = RSA_generate_key(SvIV(bitsSV), exponent, NULL, NULL); + CHECK_OPEN_SSL(rsa != NULL); +#endif +#if OPENSSL_VERSION_NUMBER >= 0x00908000L && OPENSSL_VERSION_NUMBER < 0x30000000L rsa = RSA_new(); - rc = RSA_generate_key_ex(rsa, SvIV(bitsSV), e, NULL); + if (!RSA_generate_key_ex(rsa, SvIV(bitsSV), e, NULL)) + croak("Unable to generate a key"); BN_free(e); + CHECK_OPEN_SSL(rsa != NULL); +#endif +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL); + + CHECK_OPEN_SSL(ctx); + CHECK_OPEN_SSL(EVP_PKEY_keygen_init(ctx) == 1); + CHECK_OPEN_SSL(EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, SvIV(bitsSV)) > 0); + CHECK_OPEN_SSL(EVP_PKEY_CTX_set1_rsa_keygen_pubexp(ctx, e) >0); + CHECK_OPEN_SSL(EVP_PKEY_generate(ctx, &rsa) == 1); + CHECK_OPEN_SSL(rsa != NULL); + e = NULL; - CHECK_OPEN_SSL(rc != -1); -#else - rsa = RSA_generate_key(SvIV(bitsSV), exponent, NULL, NULL); + BN_free(e); + EVP_PKEY_CTX_free(ctx); #endif CHECK_OPEN_SSL(rsa); RETVAL = make_rsa_obj(proto, rsa); @@ -387,8 +533,8 @@ _new_key_from_parameters(proto, n, e, d, p, q) BIGNUM* p; BIGNUM* q; PREINIT: - RSA* rsa; - BN_CTX* ctx; + EVP_PKEY* rsa = NULL; + BN_CTX* ctx = NULL; BIGNUM* p_minus_1 = NULL; BIGNUM* q_minus_1 = NULL; BIGNUM* dmp1 = NULL; @@ -401,10 +547,23 @@ _new_key_from_parameters(proto, n, e, d, p, q) { croak("At least a modulus and public key must be provided"); } +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + OSSL_PARAM *params = NULL; + EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL); + CHECK_OPEN_SSL(pctx != NULL); + CHECK_OPEN_SSL(EVP_PKEY_fromdata_init(pctx) > 0); + OSSL_PARAM_BLD *params_build = OSSL_PARAM_BLD_new(); + CHECK_OPEN_SSL(params_build) +#else CHECK_OPEN_SSL(rsa = RSA_new()); +#endif #if OLD_CRUFTY_SSL_VERSION rsa->n = n; rsa->e = e; +#endif +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + CHECK_OPEN_SSL(OSSL_PARAM_BLD_push_BN(params_build, OSSL_PKEY_PARAM_RSA_N, n)); + CHECK_OPEN_SSL(OSSL_PARAM_BLD_push_BN(params_build, OSSL_PKEY_PARAM_RSA_E, e)); #endif if (p || q) { @@ -423,8 +582,11 @@ _new_key_from_parameters(proto, n, e, d, p, q) #if OLD_CRUFTY_SSL_VERSION rsa->p = p; rsa->q = q; +#else +#if OPENSSL_VERSION_NUMBER >= 0x30000000L #else THROW(RSA_set0_factors(rsa, p, q)); +#endif #endif THROW(p_minus_1 = BN_new()); THROW(BN_sub(p_minus_1, p, BN_value_one())); @@ -438,8 +600,14 @@ _new_key_from_parameters(proto, n, e, d, p, q) } #if OLD_CRUFTY_SSL_VERSION rsa->d = d; +#else +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + THROW(OSSL_PARAM_BLD_push_BN(params_build, OSSL_PKEY_PARAM_RSA_D, d)); + THROW(OSSL_PARAM_BLD_push_BN(params_build, OSSL_PKEY_PARAM_RSA_FACTOR1, p)); + THROW(OSSL_PARAM_BLD_push_BN(params_build, OSSL_PKEY_PARAM_RSA_FACTOR2, q)); #else THROW(RSA_set0_key(rsa, n, e, d)); +#endif #endif THROW(dmp1 = BN_new()); THROW(BN_mod(dmp1, d, p_minus_1, ctx)); @@ -451,13 +619,59 @@ _new_key_from_parameters(proto, n, e, d, p, q) rsa->dmp1 = dmp1; rsa->dmq1 = dmq1; rsa->iqmp = iqmp; +#else +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + THROW(OSSL_PARAM_BLD_push_BN(params_build, OSSL_PKEY_PARAM_RSA_EXPONENT1, dmp1)); + THROW(OSSL_PARAM_BLD_push_BN(params_build, OSSL_PKEY_PARAM_RSA_EXPONENT2, dmq1)); + THROW(OSSL_PARAM_BLD_push_BN(params_build, OSSL_PKEY_PARAM_RSA_COEFFICIENT1, iqmp)); + + params = OSSL_PARAM_BLD_to_param(params_build); + THROW(params != NULL); + + int status = EVP_PKEY_fromdata(pctx, &rsa, EVP_PKEY_KEYPAIR, params); + THROW( status > 0 && rsa != NULL ); + EVP_PKEY_CTX* test_ctx = EVP_PKEY_CTX_new_from_pkey(NULL, rsa, NULL); + THROW(EVP_PKEY_check(test_ctx) == 1); #else THROW(RSA_set0_crt_params(rsa, dmp1, dmq1, iqmp)); +#endif #endif dmp1 = dmq1 = iqmp = NULL; +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + OSSL_PARAM_BLD_free(params_build); + OSSL_PARAM_free(params); +#else THROW(RSA_check_key(rsa) == 1); - err: +#endif + } + else + { +#if OLD_CRUFTY_SSL_VERSION + rsa->d = d; +#else +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + if(d != NULL) + THROW(OSSL_PARAM_BLD_push_BN(params_build, OSSL_PKEY_PARAM_RSA_D, d)); + params = OSSL_PARAM_BLD_to_param(params_build); + THROW(params != NULL); + + int status = EVP_PKEY_fromdata(pctx, &rsa, EVP_PKEY_KEYPAIR, params); + THROW( status > 0 && rsa != NULL ); +#else + CHECK_OPEN_SSL(RSA_set0_key(rsa, n, e, d)); +#endif +#endif + } + + RETVAL = make_rsa_obj(proto, rsa); + if(RETVAL) + goto end; + + err: + //if (p) BN_clear_free(p); if (p_minus_1) BN_clear_free(p_minus_1); + //if (q) BN_clear_free(q); + //if (d) BN_clear_free(d); if (q_minus_1) BN_clear_free(q_minus_1); if (dmp1) BN_clear_free(dmp1); if (dmq1) BN_clear_free(dmq1); @@ -465,20 +679,12 @@ _new_key_from_parameters(proto, n, e, d, p, q) if (ctx) BN_CTX_free(ctx); if (error) { - RSA_free(rsa); + EVP_PKEY_free(rsa); CHECK_OPEN_SSL(0); } } - else - { -#if OLD_CRUFTY_SSL_VERSION - rsa->d = d; -#else - CHECK_OPEN_SSL(RSA_set0_key(rsa, n, e, d)); -#endif - } - RETVAL = make_rsa_obj(proto, rsa); -} + end: + OUTPUT: RETVAL @@ -486,6 +692,16 @@ void _get_key_parameters(p_rsa) rsaData* p_rsa; PREINIT: +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + BIGNUM* n = NULL; + BIGNUM* e = NULL; + BIGNUM* d = NULL; + BIGNUM* p = NULL; + BIGNUM* q = NULL; + BIGNUM* dmp1 = NULL; + BIGNUM* dmq1 = NULL; + BIGNUM* iqmp = NULL; +#else const BIGNUM* n; const BIGNUM* e; const BIGNUM* d; @@ -494,9 +710,10 @@ PREINIT: const BIGNUM* dmp1; const BIGNUM* dmq1; const BIGNUM* iqmp; +#endif PPCODE: { - RSA* rsa; + EVP_PKEY* rsa; rsa = p_rsa->rsa; #if OLD_CRUFTY_SSL_VERSION n = rsa->n; @@ -507,10 +724,21 @@ PPCODE: dmp1 = rsa->dmp1; dmq1 = rsa->dmq1; iqmp = rsa->iqmp; +#else +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_PKEY_get_bn_param(rsa, OSSL_PKEY_PARAM_RSA_N, &n); + EVP_PKEY_get_bn_param(rsa, OSSL_PKEY_PARAM_RSA_E, &e); + EVP_PKEY_get_bn_param(rsa, OSSL_PKEY_PARAM_RSA_D, &d); + EVP_PKEY_get_bn_param(rsa, OSSL_PKEY_PARAM_RSA_FACTOR1, &p); + EVP_PKEY_get_bn_param(rsa, OSSL_PKEY_PARAM_RSA_FACTOR2, &q); + EVP_PKEY_get_bn_param(rsa, OSSL_PKEY_PARAM_RSA_EXPONENT1, &dmp1); + EVP_PKEY_get_bn_param(rsa, OSSL_PKEY_PARAM_RSA_EXPONENT2, &dmq1); + EVP_PKEY_get_bn_param(rsa, OSSL_PKEY_PARAM_RSA_COEFFICIENT1, &iqmp); #else RSA_get0_key(rsa, &n, &e, &d); RSA_get0_factors(rsa, &p, &q); RSA_get0_crt_params(rsa, &dmp1, &dmq1, &iqmp); +#endif #endif XPUSHs(cor_bn2sv(n)); XPUSHs(cor_bn2sv(e)); @@ -527,7 +755,11 @@ encrypt(p_rsa, p_plaintext) rsaData* p_rsa; SV* p_plaintext; CODE: +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + RETVAL = rsa_crypt(p_rsa, p_plaintext, EVP_PKEY_encrypt, EVP_PKEY_encrypt_init, 1 /* public */); +#else RETVAL = rsa_crypt(p_rsa, p_plaintext, RSA_public_encrypt); +#endif OUTPUT: RETVAL @@ -540,7 +772,11 @@ decrypt(p_rsa, p_ciphertext) { croak("Public keys cannot decrypt"); } +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + RETVAL = rsa_crypt(p_rsa, p_ciphertext, EVP_PKEY_decrypt, EVP_PKEY_decrypt_init, 0 /* private */); +#else RETVAL = rsa_crypt(p_rsa, p_ciphertext, RSA_private_decrypt); +#endif OUTPUT: RETVAL @@ -553,7 +789,11 @@ private_encrypt(p_rsa, p_plaintext) { croak("Public keys cannot private_encrypt"); } +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + RETVAL = rsa_crypt(p_rsa, p_plaintext, EVP_PKEY_sign, EVP_PKEY_sign_init, 0 /* private */); +#else RETVAL = rsa_crypt(p_rsa, p_plaintext, RSA_private_encrypt); +#endif OUTPUT: RETVAL @@ -562,7 +802,11 @@ public_decrypt(p_rsa, p_ciphertext) rsaData* p_rsa; SV* p_ciphertext; CODE: +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + RETVAL = rsa_crypt(p_rsa, p_ciphertext, EVP_PKEY_verify_recover, EVP_PKEY_verify_recover_init, 1 /*public */); +#else RETVAL = rsa_crypt(p_rsa, p_ciphertext, RSA_public_decrypt); +#endif OUTPUT: RETVAL @@ -570,7 +814,7 @@ int size(p_rsa) rsaData* p_rsa; CODE: - RETVAL = RSA_size(p_rsa->rsa); + RETVAL = EVP_PKEY_get_size(p_rsa->rsa); OUTPUT: RETVAL @@ -582,7 +826,12 @@ check_key(p_rsa) { croak("Public keys cannot be checked"); } +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_from_pkey(NULL, p_rsa->rsa, NULL); + RETVAL = EVP_PKEY_private_check(pctx); +#else RETVAL = RSA_check_key(p_rsa->rsa); +#endif OUTPUT: RETVAL @@ -702,26 +951,50 @@ sign(p_rsa, text_SV) rsaData* p_rsa; SV* text_SV; PREINIT: - char* signature; + UNSIGNED_CHAR *signature; unsigned char* digest; - unsigned int signature_length; + SIZE_T_UNSIGNED_INT signature_length; CODE: { if (!_is_private(p_rsa)) { croak("Public keys cannot sign messages"); } - - CHECK_NEW(signature, RSA_size(p_rsa->rsa), char); + CHECK_NEW(signature, EVP_PKEY_get_size(p_rsa->rsa), UNSIGNED_CHAR); CHECK_OPEN_SSL(digest = get_message_digest(text_SV, p_rsa->hashMode)); +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_PKEY_CTX *ctx; + ctx = EVP_PKEY_CTX_new(p_rsa->rsa, NULL /* no engine */); + CHECK_OPEN_SSL(ctx); + CHECK_OPEN_SSL(EVP_PKEY_sign_init(ctx)); + /* FIXME: Issue setting padding in some cases */ + EVP_PKEY_CTX_set_rsa_padding(ctx, p_rsa->padding); + + EVP_MD* md = get_md_bynid(p_rsa->hashMode); + CHECK_OPEN_SSL(md != NULL); + + int md_status; + CHECK_OPEN_SSL((md_status = EVP_PKEY_CTX_set_signature_md(ctx, md)) > 0); + + CHECK_OPEN_SSL(EVP_PKEY_sign(ctx, NULL, &signature_length, digest, get_digest_length(p_rsa->hashMode)) == 1); + + //signature = OPENSSL_malloc(signature_length); + Newx(signature, signature_length, char); + + CHECK_OPEN_SSL(signature); + + CHECK_OPEN_SSL(EVP_PKEY_sign(ctx, signature, &signature_length, digest, get_digest_length(p_rsa->hashMode)) == 1); + CHECK_OPEN_SSL(signature); +#else CHECK_OPEN_SSL(RSA_sign(p_rsa->hashMode, digest, get_digest_length(p_rsa->hashMode), (unsigned char*) signature, &signature_length, p_rsa->rsa)); - RETVAL = newSVpvn(signature, signature_length); +#endif + RETVAL = newSVpvn((const char* )signature, signature_length); Safefree(signature); } OUTPUT: @@ -741,18 +1014,35 @@ PPCODE: STRLEN sig_length; sig = (unsigned char*) SvPV(sig_SV, sig_length); - if (RSA_size(p_rsa->rsa) < sig_length) + if (EVP_PKEY_get_size(p_rsa->rsa) < sig_length) { croak("Signature longer than key"); } CHECK_OPEN_SSL(digest = get_message_digest(text_SV, p_rsa->hashMode)); +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_PKEY_CTX *ctx; + ctx = EVP_PKEY_CTX_new(p_rsa->rsa, NULL /* no engine */); + CHECK_OPEN_SSL(ctx); + CHECK_OPEN_SSL(EVP_PKEY_verify_init(ctx) == 1); + /* FIXME: Issue setting padding in some cases */ + EVP_PKEY_CTX_set_rsa_padding(ctx, p_rsa->padding); + + EVP_MD* md = get_md_bynid(p_rsa->hashMode); + CHECK_OPEN_SSL(md != NULL); + + int md_status; + CHECK_OPEN_SSL((md_status = EVP_PKEY_CTX_set_signature_md(ctx, md)) > 0); + + switch (EVP_PKEY_verify(ctx, sig, sig_length, digest, get_digest_length(p_rsa->hashMode))) +#else switch(RSA_verify(p_rsa->hashMode, digest, get_digest_length(p_rsa->hashMode), sig, sig_length, p_rsa->rsa)) +#endif { case 0: ERR_clear_error(); diff --git a/t/rsa.t b/t/rsa.t index e97c15d..4bd1f01 100644 --- a/t/rsa.t +++ b/t/rsa.t @@ -3,6 +3,7 @@ use Test::More; use Crypt::OpenSSL::Random; use Crypt::OpenSSL::RSA; +use Crypt::OpenSSL::Guess qw(openssl_version); BEGIN { plan tests => 43 + ( UNIVERSAL::can( "Crypt::OpenSSL::RSA", "use_sha512_hash" ) ? 4 * 5 : 0 ) + @@ -147,9 +148,16 @@ if ( UNIVERSAL::can( "Crypt::OpenSSL::RSA", "use_sha512_hash" ) ) { _Test_Sign_And_Verify( $plaintext, $rsa, $rsa_pub ); } -$rsa->use_ripemd160_hash(); -$rsa_pub->use_ripemd160_hash(); -_Test_Sign_And_Verify( $plaintext, $rsa, $rsa_pub ); +my ($major, $minor, $patch) = openssl_version(); + +SKIP: { + skip "ripemd160 in legacy provider between 3.02 and 3.07", 5 if $major eq '3.0' && + ($minor ge '2' && $minor le '6'); + + $rsa->use_ripemd160_hash(); + $rsa_pub->use_ripemd160_hash(); + _Test_Sign_And_Verify( $plaintext, $rsa, $rsa_pub ); +} if (UNIVERSAL::can("Crypt::OpenSSL::RSA", "use_whirlpool_hash")) { $rsa->use_whirlpool_hash();