diff --git a/Makefile.PL b/Makefile.PL index 3b72fdd..79b3e7d 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -1,13 +1,35 @@ use strict; use warnings; +use Config; +use List::Util 1.45 qw(uniq); 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. +my $libs = ' -lssl -lcrypto'; +if ( $Config{osname} eq 'aix' ) { + $libs = $libs . ' -lz'; +} + +my $ssllibpth = openssl_lib_paths(); +my $lddlflags = $Config{lddlflags}; +$lddlflags =~ s/(?=-L)/$ssllibpth /; + +my $ldflags = $Config{ldflags}; +$ldflags =~ s/(?=-L)/$ssllibpth /; + +if ($^O eq "hpux" && $Config{ld} eq "/usr/bin/ld") { + my $bpth = join ":" => uniq (+("$ssllibpth $lddlflags $ldflags") =~ m/-L(\S+)/g); + $lddlflags .= " +b $bpth"; + $ldflags .= " +Wl,+b,$bpth"; +} + WriteMakefile( 'NAME' => 'Crypt::OpenSSL::RSA', 'AUTHOR' => 'Ian Robertson ', @@ -22,7 +44,9 @@ WriteMakefile( 'Test::More' => 0, }, 'OBJECT' => 'RSA.o', - 'LIBS' => [openssl_lib_paths() . ' -lssl -lcrypto'], + 'LIBS' => [ openssl_lib_paths() . $libs ], + 'LDDLFLAGS' => $lddlflags, + 'LDFLAGS' => $ldflags, 'DEFINE' => '-DPERL5 -DOPENSSL_NO_KRB5', # perl-5.8/gcc-3.2 needs -DPERL5, and redhat9 likes -DOPENSSL_NO_KRB5 diff --git a/RSA.xs b/RSA.xs index 5f5cfae..1b52037 100644 --- a/RSA.xs +++ b/RSA.xs @@ -1,3 +1,4 @@ +#define PERL_NO_GET_CONTEXT #include "EXTERN.h" #include "perl.h" #include "XSUB.h" @@ -10,14 +11,31 @@ #include #include #include +#if OPENSSL_VERSION_NUMBER < 0x30000000 +#include +#endif #include #include #include #include +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +#include +#include +#include +#endif +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +#define UNSIGNED_CHAR unsigned char +#else +#define UNSIGNED_CHAR char +#endif typedef struct { +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_PKEY* rsa; +#else RSA* rsa; +#endif int padding; int hashMode; } rsaData; @@ -52,16 +70,27 @@ void croakSsl(char* p_file, int p_line) char _is_private(rsaData* p_rsa) { - const BIGNUM *d; #if OLD_CRUFTY_SSL_VERSION + const BIGNUM* d; d = p_rsa->rsa->d; #else +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + BIGNUM* d = NULL; + EVP_PKEY_get_bn_param(p_rsa->rsa, OSSL_PKEY_PARAM_RSA_D, &d); +#else + const BIGNUM* d; RSA_get0_key(p_rsa->rsa, NULL, NULL, &d); +#endif #endif return(d != NULL); } +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + +SV* make_rsa_obj(pTHX_ SV* p_proto, EVP_PKEY* p_rsa) +#else -SV* make_rsa_obj(SV* p_proto, RSA* p_rsa) +SV* make_rsa_obj(pTHX_ SV* p_proto, RSA* p_rsa) +#endif { rsaData* rsa; @@ -111,18 +140,63 @@ int get_digest_length(int hash_method) break; } } +#if OPENSSL_VERSION_NUMBER >= 0x30000000L -unsigned char* get_message_digest(SV* text_SV, int hash_method) +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(pTHX_ 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); @@ -142,7 +216,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: @@ -155,36 +233,59 @@ unsigned char* get_message_digest(SV* text_SV, int hash_method) } } -SV* cor_bn2sv(const BIGNUM* p_bn) +SV* cor_bn2sv(pTHX_ const BIGNUM* p_bn) { return p_bn != NULL ? sv_2mortal(newSViv((IV) BN_dup(p_bn))) : &PL_sv_undef; } -SV* extractBioString(BIO* p_stringBio) +SV* extractBioString(pTHX_ BIO* p_stringBio) { SV* sv; - BUF_MEM* bptr; + char *datap; + long datasize = 0; CHECK_OPEN_SSL(BIO_flush(p_stringBio) == 1); - BIO_get_mem_ptr(p_stringBio, &bptr); - sv = newSVpv(bptr->data, bptr->length); + + datasize = BIO_get_mem_data(p_stringBio, &datap); + sv = newSVpv(datap, datasize); CHECK_OPEN_SSL(BIO_set_close(p_stringBio, BIO_CLOSE) == 1); BIO_free(p_stringBio); return sv; } -RSA* _load_rsa_key(SV* p_keyStringSv, +int get_key_size(rsaData* p_rsa) { + int size = 0; +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + size = EVP_PKEY_get_size(p_rsa->rsa); +#else + size = RSA_size(p_rsa->rsa); +#endif + return size; +} +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + +EVP_PKEY* _load_rsa_key(pTHX_ SV* p_keyStringSv, + EVP_PKEY*(*p_loader)(BIO *, EVP_PKEY**, pem_password_cb*, void*), + SV* p_passphaseSv) + +#else + +RSA* _load_rsa_key(pTHX_ SV* p_keyStringSv, RSA*(*p_loader)(BIO*, RSA**, pem_password_cb*, void*), SV* p_passphaseSv) +#endif { STRLEN keyStringLength; char* keyString; - char* passphase = NULL; - + UNSIGNED_CHAR *passphase = NULL; +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_PKEY* rsa; +#else RSA* rsa; +#endif BIO* stringBIO; keyString = SvPV(p_keyStringSv, keyStringLength); @@ -203,35 +304,65 @@ 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, +SV* rsa_crypt(pTHX_ 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(pTHX_ rsaData* p_rsa, SV* p_from, int (*p_crypt)(int, const unsigned char*, unsigned char*, RSA*, int)) +#endif { +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + STRLEN from_length; + size_t to_length; +#else STRLEN from_length; int to_length; +#endif + UNSIGNED_CHAR *to; int size; unsigned char* from; - char* to; SV* sv; from = (unsigned char*) SvPV(p_from, from_length); - size = RSA_size(p_rsa->rsa); - CHECK_NEW(to, size, char); + size = get_key_size(p_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 @@ -251,8 +382,13 @@ new_private_key(proto, key_string_SV, passphase_SV=&PL_sv_undef) SV* key_string_SV; SV* passphase_SV; CODE: - RETVAL = make_rsa_obj( - proto, _load_rsa_key(key_string_SV, PEM_read_bio_RSAPrivateKey, passphase_SV)); +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + RETVAL = make_rsa_obj(aTHX_ + proto, _load_rsa_key(aTHX_ key_string_SV, PEM_read_bio_PrivateKey, passphase_SV)); +#else + RETVAL = make_rsa_obj(aTHX_ + proto, _load_rsa_key(aTHX_ key_string_SV, PEM_read_bio_RSAPrivateKey, passphase_SV)); +#endif OUTPUT: RETVAL @@ -261,8 +397,13 @@ _new_public_key_pkcs1(proto, key_string_SV) SV* proto; SV* key_string_SV; CODE: - RETVAL = make_rsa_obj( - proto, _load_rsa_key(key_string_SV, PEM_read_bio_RSAPublicKey, &PL_sv_undef)); +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + RETVAL = make_rsa_obj(aTHX_ + proto, _load_rsa_key(aTHX_ key_string_SV, PEM_read_bio_PUBKEY, &PL_sv_undef)); +#else + RETVAL = make_rsa_obj(aTHX_ + proto, _load_rsa_key(aTHX_ key_string_SV, PEM_read_bio_RSAPublicKey, &PL_sv_undef)); +#endif OUTPUT: RETVAL @@ -271,8 +412,13 @@ _new_public_key_x509(proto, key_string_SV) SV* proto; SV* key_string_SV; CODE: - RETVAL = make_rsa_obj( - proto, _load_rsa_key(key_string_SV, PEM_read_bio_RSA_PUBKEY, &PL_sv_undef)); +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + RETVAL = make_rsa_obj(aTHX_ + proto, _load_rsa_key(aTHX_ key_string_SV, PEM_read_bio_PUBKEY, &PL_sv_undef)); +#else + RETVAL = make_rsa_obj(aTHX_ + proto, _load_rsa_key(aTHX_ key_string_SV, PEM_read_bio_RSA_PUBKEY, &PL_sv_undef)); +#endif OUTPUT: RETVAL @@ -280,7 +426,11 @@ void DESTROY(p_rsa) rsaData* p_rsa; CODE: +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_PKEY_free(p_rsa->rsa); +#else RSA_free(p_rsa->rsa); +#endif Safefree(p_rsa); SV* @@ -290,7 +440,7 @@ get_private_key_string(p_rsa, passphase_SV=&PL_sv_undef, cipher_name_SV=&PL_sv_u SV* cipher_name_SV; PREINIT: BIO* stringBIO; - char* passphase = NULL; + char *passphase = NULL; STRLEN passphaseLength = 0; char* cipher_name; const EVP_CIPHER* enc = NULL; @@ -313,9 +463,15 @@ 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())); +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + PEM_write_bio_PrivateKey_traditional(stringBIO, p_rsa->rsa, enc, + passphase, passphaseLength, + NULL, NULL); +#else PEM_write_bio_RSAPrivateKey( - stringBIO, p_rsa->rsa, enc, passphase, passphaseLength, NULL, NULL); - RETVAL = extractBioString(stringBIO); + stringBIO, p_rsa->rsa, enc, (unsigned char *) passphase, passphaseLength, NULL, NULL); +#endif + RETVAL = extractBioString(aTHX_ stringBIO); OUTPUT: RETVAL @@ -327,8 +483,20 @@ 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); - RETVAL = extractBioString(stringBIO); +#endif + RETVAL = extractBioString(aTHX_ stringBIO); OUTPUT: RETVAL @@ -340,8 +508,12 @@ get_public_key_x509_string(p_rsa) BIO* stringBIO; CODE: CHECK_OPEN_SSL(stringBIO = BIO_new(BIO_s_mem())); +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + PEM_write_bio_PUBKEY(stringBIO, p_rsa->rsa); +#else PEM_write_bio_RSA_PUBKEY(stringBIO, p_rsa->rsa); - RETVAL = extractBioString(stringBIO); +#endif + RETVAL = extractBioString(aTHX_ stringBIO); OUTPUT: RETVAL @@ -352,23 +524,43 @@ generate_key(proto, bitsSV, exponent = 65537) SV* bitsSV; unsigned long exponent; PREINIT: +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_PKEY_CTX *ctx; + EVP_PKEY *rsa = NULL; +#else RSA* rsa; +#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); + RETVAL = make_rsa_obj(aTHX_ proto, rsa); OUTPUT: RETVAL @@ -382,7 +574,11 @@ _new_key_from_parameters(proto, n, e, d, p, q) BIGNUM* p; BIGNUM* q; PREINIT: +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_PKEY *rsa = NULL; +#else RSA* rsa; +#endif BN_CTX* ctx; BIGNUM* p_minus_1 = NULL; BIGNUM* q_minus_1 = NULL; @@ -396,10 +592,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) { @@ -418,8 +627,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())); @@ -433,8 +645,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)); @@ -446,13 +664,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(aTHX_ 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); @@ -460,20 +724,16 @@ _new_key_from_parameters(proto, n, e, d, p, q) if (ctx) BN_CTX_free(ctx); if (error) { +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_PKEY_free(rsa); +#else RSA_free(rsa); +#endif 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 @@ -481,6 +741,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; @@ -489,9 +759,14 @@ PREINIT: const BIGNUM* dmp1; const BIGNUM* dmq1; const BIGNUM* iqmp; +#endif PPCODE: { +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_PKEY* rsa; +#else RSA* rsa; +#endif rsa = p_rsa->rsa; #if OLD_CRUFTY_SSL_VERSION n = rsa->n; @@ -502,19 +777,30 @@ 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 - XPUSHs(cor_bn2sv(n)); - XPUSHs(cor_bn2sv(e)); - XPUSHs(cor_bn2sv(d)); - XPUSHs(cor_bn2sv(p)); - XPUSHs(cor_bn2sv(q)); - XPUSHs(cor_bn2sv(dmp1)); - XPUSHs(cor_bn2sv(dmq1)); - XPUSHs(cor_bn2sv(iqmp)); +#endif + XPUSHs(cor_bn2sv(aTHX_ n)); + XPUSHs(cor_bn2sv(aTHX_ e)); + XPUSHs(cor_bn2sv(aTHX_ d)); + XPUSHs(cor_bn2sv(aTHX_ p)); + XPUSHs(cor_bn2sv(aTHX_ q)); + XPUSHs(cor_bn2sv(aTHX_ dmp1)); + XPUSHs(cor_bn2sv(aTHX_ dmq1)); + XPUSHs(cor_bn2sv(aTHX_ iqmp)); } SV* @@ -522,7 +808,11 @@ encrypt(p_rsa, p_plaintext) rsaData* p_rsa; SV* p_plaintext; CODE: - RETVAL = rsa_crypt(p_rsa, p_plaintext, RSA_public_encrypt); +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + RETVAL = rsa_crypt(aTHX_ p_rsa, p_plaintext, EVP_PKEY_encrypt, EVP_PKEY_encrypt_init, 1 /* public */); +#else + RETVAL = rsa_crypt(aTHX_ p_rsa, p_plaintext, RSA_public_encrypt); +#endif OUTPUT: RETVAL @@ -535,7 +825,11 @@ decrypt(p_rsa, p_ciphertext) { croak("Public keys cannot decrypt"); } - RETVAL = rsa_crypt(p_rsa, p_ciphertext, RSA_private_decrypt); +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + RETVAL = rsa_crypt(aTHX_ p_rsa, p_ciphertext, EVP_PKEY_decrypt, EVP_PKEY_decrypt_init, 0 /* private */); +#else + RETVAL = rsa_crypt(aTHX_ p_rsa, p_ciphertext, RSA_private_decrypt); +#endif OUTPUT: RETVAL @@ -548,7 +842,11 @@ private_encrypt(p_rsa, p_plaintext) { croak("Public keys cannot private_encrypt"); } - RETVAL = rsa_crypt(p_rsa, p_plaintext, RSA_private_encrypt); +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + RETVAL = rsa_crypt(aTHX_ p_rsa, p_plaintext, EVP_PKEY_sign, EVP_PKEY_sign_init, 0 /* private */); +#else + RETVAL = rsa_crypt(aTHX_ p_rsa, p_plaintext, RSA_private_encrypt); +#endif OUTPUT: RETVAL @@ -557,7 +855,11 @@ public_decrypt(p_rsa, p_ciphertext) rsaData* p_rsa; SV* p_ciphertext; CODE: - RETVAL = rsa_crypt(p_rsa, p_ciphertext, RSA_public_decrypt); +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + RETVAL = rsa_crypt(aTHX_ p_rsa, p_ciphertext, EVP_PKEY_verify_recover, EVP_PKEY_verify_recover_init, 1 /*public */); +#else + RETVAL = rsa_crypt(aTHX_ p_rsa, p_ciphertext, RSA_public_decrypt); +#endif OUTPUT: RETVAL @@ -565,7 +867,7 @@ int size(p_rsa) rsaData* p_rsa; CODE: - RETVAL = RSA_size(p_rsa->rsa); + RETVAL = get_key_size(p_rsa); OUTPUT: RETVAL @@ -577,7 +879,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 @@ -697,26 +1004,59 @@ sign(p_rsa, text_SV) rsaData* p_rsa; SV* text_SV; PREINIT: - char* signature; unsigned char* digest; +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + unsigned char* signature; + size_t signature_length; +#else + char* signature; unsigned int signature_length; +#endif CODE: { if (!_is_private(p_rsa)) { croak("Public keys cannot sign messages"); } +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + CHECK_NEW(signature, get_key_size(p_rsa), unsigned char); +#else + CHECK_NEW(signature, get_key_size(p_rsa), char); +#endif + + CHECK_OPEN_SSL(digest = get_message_digest(aTHX_ 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); - CHECK_NEW(signature, RSA_size(p_rsa->rsa), char); + EVP_MD* md = get_md_bynid(p_rsa->hashMode); + CHECK_OPEN_SSL(md != NULL); - CHECK_OPEN_SSL(digest = get_message_digest(text_SV, p_rsa->hashMode)); + 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: @@ -736,18 +1076,35 @@ PPCODE: STRLEN sig_length; sig = (unsigned char*) SvPV(sig_SV, sig_length); - if (RSA_size(p_rsa->rsa) < sig_length) + if (get_key_size(p_rsa) < sig_length) { croak("Signature longer than key"); } - CHECK_OPEN_SSL(digest = get_message_digest(text_SV, p_rsa->hashMode)); + CHECK_OPEN_SSL(digest = get_message_digest(aTHX_ 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 d3e7f0b..4bd1f01 100644 --- a/t/rsa.t +++ b/t/rsa.t @@ -3,8 +3,11 @@ 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 ) } +BEGIN { plan tests => 43 + + ( UNIVERSAL::can( "Crypt::OpenSSL::RSA", "use_sha512_hash" ) ? 4 * 5 : 0 ) + + ( UNIVERSAL::can( "Crypt::OpenSSL::RSA", "use_whirlpool_hash" ) ? 1 * 5 : 0 ) } sub _Test_Encrypt_And_Decrypt { my ( $p_plaintext_length, $p_rsa, $p_check_private_encrypt ) = @_; @@ -145,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();