Crypt-OpenSSL-RSA
view release on metacpan or search on metacpan
THROW(RETVAL = make_rsa_obj(proto, rsa));
goto end;
err:
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
/* On 3.x, push_BN copies, so originals are always ours to free.
On pre-3.x, RSA_set0_key/set0_factors may have taken ownership,
so these are intentionally skipped (risk of double-free). */
BN_clear_free(n);
BN_clear_free(e);
BN_clear_free(d);
BN_clear_free(p);
BN_clear_free(q);
#endif
if (p_minus_1) BN_clear_free(p_minus_1);
if (q_minus_1) BN_clear_free(q_minus_1);
if (dmp1) BN_clear_free(dmp1);
if (dmq1) BN_clear_free(dmq1);
if (iqmp) BN_clear_free(iqmp);
if (ctx) BN_CTX_free(ctx);
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
if (pctx) { EVP_PKEY_CTX_free(pctx); pctx = NULL; }
if (params_build) { OSSL_PARAM_BLD_free(params_build); params_build = NULL; }
if (params) { OSSL_PARAM_free(params); params = NULL; }
#endif
if (error)
{
EVP_PKEY_free(rsa);
CHECK_OPEN_SSL(0);
}
}
end:
OUTPUT:
RETVAL
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;
const BIGNUM* p;
const BIGNUM* q;
const BIGNUM* dmp1;
const BIGNUM* dmq1;
const BIGNUM* iqmp;
#endif
PPCODE:
{
EVP_PKEY* rsa;
rsa = p_rsa->rsa;
#if OLD_CRUFTY_SSL_VERSION
n = rsa->n;
e = rsa->e;
d = rsa->d;
p = rsa->p;
q = rsa->q;
dmp1 = rsa->dmp1;
dmq1 = rsa->dmq1;
iqmp = rsa->iqmp;
#else
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
/* n and e are mandatory for every RSA key â croak on failure. */
if (!EVP_PKEY_get_bn_param(rsa, OSSL_PKEY_PARAM_RSA_N, &n))
croakSsl(__FILE__, __LINE__);
if (!EVP_PKEY_get_bn_param(rsa, OSSL_PKEY_PARAM_RSA_E, &e)) {
BN_free(n);
croakSsl(__FILE__, __LINE__);
}
/* Private components are absent for public keys â EVP_PKEY_get_bn_param()
returns 0 and may push errors onto the queue, but the pointer stays NULL
so cor_bn2sv() will return undef. This matches the pre-3.x behaviour
where RSA_get0_key/factors/crt_params simply set NULL for missing fields. */
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);
/* Failed calls (e.g. private params on a public key) push errors
onto the OpenSSL error queue. Drain them so they don't leak
into the next croakSsl() call from an unrelated operation. */
ERR_clear_error();
#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));
XPUSHs(cor_bn2sv(d));
XPUSHs(cor_bn2sv(p));
XPUSHs(cor_bn2sv(q));
XPUSHs(cor_bn2sv(dmp1));
XPUSHs(cor_bn2sv(dmq1));
XPUSHs(cor_bn2sv(iqmp));
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
/* EVP_PKEY_get_bn_param() allocates new BIGNUMs (unlike the pre-3.x
getters which return internal pointers). cor_bn2sv() duplicates
them via BN_dup(), so we must free the originals here. */
BN_free(n);
BN_free(e);
BN_clear_free(d);
BN_clear_free(p);
BN_clear_free(q);
BN_clear_free(dmp1);
BN_clear_free(dmq1);
croak("Public keys cannot sign messages");
}
unsigned char digest_buf[EVP_MAX_MD_SIZE];
CHECK_OPEN_SSL(digest = get_message_digest(text_SV, p_rsa->hashMode, digest_buf));
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
ctx = EVP_PKEY_CTX_new(p_rsa->rsa, NULL /* no engine */);
THROW(ctx);
THROW(EVP_PKEY_sign_init(ctx));
THROW(setup_pss_sign_ctx(ctx, p_rsa->padding, p_rsa->hashMode, &md));
THROW(EVP_PKEY_sign(ctx, NULL, &signature_length, digest, get_digest_length(p_rsa->hashMode)) == 1);
Newx(signature, signature_length, UNSIGNED_CHAR);
THROW(signature);
THROW(EVP_PKEY_sign(ctx, signature, &signature_length, digest, get_digest_length(p_rsa->hashMode)) == 1);
EVP_MD_free(md);
EVP_PKEY_CTX_free(ctx);
goto sign_done;
err:
Safefree(signature);
if (md) EVP_MD_free(md);
if (ctx) EVP_PKEY_CTX_free(ctx);
CHECK_OPEN_SSL(0);
sign_done:
#else
CHECK_NEW(signature, EVP_PKEY_get_size(p_rsa->rsa), UNSIGNED_CHAR);
if (!RSA_sign(p_rsa->hashMode,
digest,
get_digest_length(p_rsa->hashMode),
(unsigned char*) signature,
&signature_length,
p_rsa->rsa))
{
Safefree(signature);
croakSsl(__FILE__, __LINE__);
}
#endif
RETVAL = newSVpvn((const char* )signature, signature_length);
Safefree(signature);
}
OUTPUT:
RETVAL
# Verify signature. Returns true if correct, false otherwise.
void
verify(p_rsa, text_SV, sig_SV)
rsaData* p_rsa;
SV* text_SV;
SV* sig_SV;
PREINIT:
int verify_result;
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
int error = 0;
EVP_PKEY_CTX *ctx = NULL;
EVP_MD *md = NULL;
#endif
PPCODE:
{
unsigned char* sig;
unsigned char* digest;
STRLEN sig_length;
sig = (unsigned char*) SvPV(sig_SV, sig_length);
if (EVP_PKEY_get_size(p_rsa->rsa) < sig_length)
{
croak("Signature longer than key");
}
unsigned char digest_buf[EVP_MAX_MD_SIZE];
CHECK_OPEN_SSL(digest = get_message_digest(text_SV, p_rsa->hashMode, digest_buf));
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
ctx = EVP_PKEY_CTX_new(p_rsa->rsa, NULL /* no engine */);
THROW(ctx);
THROW(EVP_PKEY_verify_init(ctx) == 1);
THROW(setup_pss_sign_ctx(ctx, p_rsa->padding, p_rsa->hashMode, &md));
verify_result = EVP_PKEY_verify(ctx, sig, sig_length, digest, get_digest_length(p_rsa->hashMode));
EVP_MD_free(md);
EVP_PKEY_CTX_free(ctx);
goto verify_switch;
err:
if (md) EVP_MD_free(md);
if (ctx) EVP_PKEY_CTX_free(ctx);
CHECK_OPEN_SSL(0);
verify_switch: ;
#else
verify_result = RSA_verify(p_rsa->hashMode,
digest,
get_digest_length(p_rsa->hashMode),
sig,
sig_length,
p_rsa->rsa);
#endif
switch(verify_result)
{
case 0:
ERR_clear_error();
XSRETURN_NO;
break;
case 1:
XSRETURN_YES;
break;
default:
CHECK_OPEN_SSL(0);
break;
}
}
int
is_private(p_rsa)
rsaData* p_rsa;
CODE:
RETVAL = _is_private(p_rsa);
OUTPUT:
RETVAL
( run in 1.246 second using v1.01-cache-2.11-cpan-71847e10f99 )