Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use EVP API in more places #436

Merged
merged 3 commits into from
Apr 17, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions ext/openssl/extconf.rb
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,9 @@ def find_openssl_library
have_func("EVP_PBE_scrypt")
have_func("SSL_CTX_set_post_handshake_auth")

# added in 1.1.1
have_func("EVP_PKEY_check")

Logging::message "=== Checking done. ===\n"

create_header
Expand Down
38 changes: 38 additions & 0 deletions ext/openssl/ossl_pkey.c
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,43 @@ ossl_pkey_inspect(VALUE self)
OBJ_nid2sn(nid));
}

/*
* call-seq:
* pkey.to_text -> string
*
* Dumps key parameters, public key, and private key components contained in
* the key into a human-readable text.
*
* This is intended for debugging purpose.
*
* See also the man page EVP_PKEY_print_private(3).
*/
static VALUE
ossl_pkey_to_text(VALUE self)
{
EVP_PKEY *pkey;
BIO *bio;

GetPKey(self, pkey);
if (!(bio = BIO_new(BIO_s_mem())))
ossl_raise(ePKeyError, "BIO_new");

if (EVP_PKEY_print_private(bio, pkey, 0, NULL) == 1)
goto out;
OSSL_BIO_reset(bio);
if (EVP_PKEY_print_public(bio, pkey, 0, NULL) == 1)
goto out;
OSSL_BIO_reset(bio);
if (EVP_PKEY_print_params(bio, pkey, 0, NULL) == 1)
goto out;

BIO_free(bio);
ossl_raise(ePKeyError, "EVP_PKEY_print_params");

out:
return ossl_membio2str(bio);
}

VALUE
ossl_pkey_export_traditional(int argc, VALUE *argv, VALUE self, int to_der)
{
Expand Down Expand Up @@ -1077,6 +1114,7 @@ Init_ossl_pkey(void)
rb_define_method(cPKey, "initialize", ossl_pkey_initialize, 0);
rb_define_method(cPKey, "oid", ossl_pkey_oid, 0);
rb_define_method(cPKey, "inspect", ossl_pkey_inspect, 0);
rb_define_method(cPKey, "to_text", ossl_pkey_to_text, 0);
rb_define_method(cPKey, "private_to_der", ossl_pkey_private_to_der, -1);
rb_define_method(cPKey, "private_to_pem", ossl_pkey_private_to_pem, -1);
rb_define_method(cPKey, "public_to_der", ossl_pkey_public_to_der, 0);
Expand Down
119 changes: 36 additions & 83 deletions ext/openssl/ossl_pkey_dh.c
Original file line number Diff line number Diff line change
Expand Up @@ -266,96 +266,45 @@ ossl_dh_get_params(VALUE self)
return hash;
}

/*
* call-seq:
* dh.to_text -> aString
*
* Prints all parameters of key to buffer
* INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!!
* Don't use :-)) (I's up to you)
*/
static VALUE
ossl_dh_to_text(VALUE self)
{
DH *dh;
BIO *out;
VALUE str;

GetDH(self, dh);
if (!(out = BIO_new(BIO_s_mem()))) {
ossl_raise(eDHError, NULL);
}
if (!DHparams_print(out, dh)) {
BIO_free(out);
ossl_raise(eDHError, NULL);
}
str = ossl_membio2str(out);

return str;
}

/*
* call-seq:
* dh.public_key -> aDH
*
* Returns a new DH instance that carries just the public information, i.e.
* the prime _p_ and the generator _g_, but no public/private key yet. Such
* a pair may be generated using DH#generate_key!. The "public key" needed
* for a key exchange with DH#compute_key is considered as per-session
* information and may be retrieved with DH#pub_key once a key pair has
* been generated.
* If the current instance already contains private information (and thus a
* valid public/private key pair), this information will no longer be present
* in the new instance generated by DH#public_key. This feature is helpful for
* publishing the Diffie-Hellman parameters without leaking any of the private
* per-session information.
*
* === Example
* dh = OpenSSL::PKey::DH.new(2048) # has public and private key set
* public_key = dh.public_key # contains only prime and generator
* parameters = public_key.to_der # it's safe to publish this
*/
static VALUE
ossl_dh_to_public_key(VALUE self)
{
EVP_PKEY *pkey;
DH *orig_dh, *dh;
VALUE obj;

obj = rb_obj_alloc(rb_obj_class(self));
GetPKey(obj, pkey);

GetDH(self, orig_dh);
dh = DHparams_dup(orig_dh);
if (!dh)
ossl_raise(eDHError, "DHparams_dup");
if (!EVP_PKEY_assign_DH(pkey, dh)) {
DH_free(dh);
ossl_raise(eDHError, "EVP_PKEY_assign_DH");
}
return obj;
}

/*
* call-seq:
* dh.params_ok? -> true | false
*
* Validates the Diffie-Hellman parameters associated with this instance.
* It checks whether a safe prime and a suitable generator are used. If this
* is not the case, +false+ is returned.
*
* See also the man page EVP_PKEY_param_check(3).
*/
static VALUE
ossl_dh_check_params(VALUE self)
{
int ret;
#ifdef HAVE_EVP_PKEY_CHECK
EVP_PKEY *pkey;
EVP_PKEY_CTX *pctx;

GetPKey(self, pkey);
pctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);
if (!pctx)
ossl_raise(eDHError, "EVP_PKEY_CTX_new");
ret = EVP_PKEY_param_check(pctx);
EVP_PKEY_CTX_free(pctx);
#else
DH *dh;
int codes;

GetDH(self, dh);
if (!DH_check(dh, &codes)) {
return Qfalse;
}
ret = DH_check(dh, &codes) == 1 && codes == 0;
#endif

return codes == 0 ? Qtrue : Qfalse;
if (ret == 1)
return Qtrue;
else {
/* DH_check_ex() will put error entry on failure */
ossl_clear_error();
return Qfalse;
}
}

/*
Expand Down Expand Up @@ -412,26 +361,30 @@ Init_ossl_dh(void)
* The per-session private key, an OpenSSL::BN.
*
* === Example of a key exchange
* dh1 = OpenSSL::PKey::DH.new(2048)
* der = dh1.public_key.to_der #you may send this publicly to the participating party
* dh2 = OpenSSL::PKey::DH.new(der)
* dh2.generate_key! #generate the per-session key pair
* symm_key1 = dh1.compute_key(dh2.pub_key)
* symm_key2 = dh2.compute_key(dh1.pub_key)
* # you may send the parameters (der) and own public key (pub1) publicly
* # to the participating party
* dh1 = OpenSSL::PKey::DH.new(2048)
* der = dh1.to_der
* pub1 = dh1.pub_key
*
* # the other party generates its per-session key pair
* dhparams = OpenSSL::PKey::DH.new(der)
* dh2 = OpenSSL::PKey.generate_key(dhparams)
* pub2 = dh2.pub_key
*
* puts symm_key1 == symm_key2 # => true
* symm_key1 = dh1.compute_key(pub2)
* symm_key2 = dh2.compute_key(pub1)
* puts symm_key1 == symm_key2 # => true
*/
cDH = rb_define_class_under(mPKey, "DH", cPKey);
rb_define_method(cDH, "initialize", ossl_dh_initialize, -1);
rb_define_method(cDH, "initialize_copy", ossl_dh_initialize_copy, 1);
rb_define_method(cDH, "public?", ossl_dh_is_public, 0);
rb_define_method(cDH, "private?", ossl_dh_is_private, 0);
rb_define_method(cDH, "to_text", ossl_dh_to_text, 0);
rb_define_method(cDH, "export", ossl_dh_export, 0);
rb_define_alias(cDH, "to_pem", "export");
rb_define_alias(cDH, "to_s", "export");
rb_define_method(cDH, "to_der", ossl_dh_to_der, 0);
rb_define_method(cDH, "public_key", ossl_dh_to_public_key, 0);
rb_define_method(cDH, "params_ok?", ossl_dh_check_params, 0);

DEF_OSSL_PKEY_BN(cDH, dh, p);
Expand Down
71 changes: 0 additions & 71 deletions ext/openssl/ossl_pkey_dsa.c
Original file line number Diff line number Diff line change
Expand Up @@ -264,75 +264,6 @@ ossl_dsa_get_params(VALUE self)
return hash;
}

/*
* call-seq:
* dsa.to_text -> aString
*
* Prints all parameters of key to buffer
* INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!!
* Don't use :-)) (I's up to you)
*/
static VALUE
ossl_dsa_to_text(VALUE self)
{
DSA *dsa;
BIO *out;
VALUE str;

GetDSA(self, dsa);
if (!(out = BIO_new(BIO_s_mem()))) {
ossl_raise(eDSAError, NULL);
}
if (!DSA_print(out, dsa, 0)) { /* offset = 0 */
BIO_free(out);
ossl_raise(eDSAError, NULL);
}
str = ossl_membio2str(out);

return str;
}

/*
* call-seq:
* dsa.public_key -> aDSA
*
* Returns a new DSA instance that carries just the public key information.
* If the current instance has also private key information, this will no
* longer be present in the new instance. This feature is helpful for
* publishing the public key information without leaking any of the private
* information.
*
* === Example
* dsa = OpenSSL::PKey::DSA.new(2048) # has public and private information
* pub_key = dsa.public_key # has only the public part available
* pub_key_der = pub_key.to_der # it's safe to publish this
*
*
*/
static VALUE
ossl_dsa_to_public_key(VALUE self)
{
EVP_PKEY *pkey, *pkey_new;
DSA *dsa;
VALUE obj;

GetPKeyDSA(self, pkey);
obj = rb_obj_alloc(rb_obj_class(self));
GetPKey(obj, pkey_new);

#define DSAPublicKey_dup(dsa) (DSA *)ASN1_dup( \
(i2d_of_void *)i2d_DSAPublicKey, (d2i_of_void *)d2i_DSAPublicKey, (char *)(dsa))
dsa = DSAPublicKey_dup(EVP_PKEY_get0_DSA(pkey));
#undef DSAPublicKey_dup
if (!dsa)
ossl_raise(eDSAError, "DSAPublicKey_dup");
if (!EVP_PKEY_assign_DSA(pkey_new, dsa)) {
DSA_free(dsa);
ossl_raise(eDSAError, "EVP_PKEY_assign_DSA");
}
return obj;
}

/*
* call-seq:
* dsa.syssign(string) -> aString
Expand Down Expand Up @@ -469,12 +400,10 @@ Init_ossl_dsa(void)

rb_define_method(cDSA, "public?", ossl_dsa_is_public, 0);
rb_define_method(cDSA, "private?", ossl_dsa_is_private, 0);
rb_define_method(cDSA, "to_text", ossl_dsa_to_text, 0);
rb_define_method(cDSA, "export", ossl_dsa_export, -1);
rb_define_alias(cDSA, "to_pem", "export");
rb_define_alias(cDSA, "to_s", "export");
rb_define_method(cDSA, "to_der", ossl_dsa_to_der, 0);
rb_define_method(cDSA, "public_key", ossl_dsa_to_public_key, 0);
rb_define_method(cDSA, "syssign", ossl_dsa_sign, 1);
rb_define_method(cDSA, "sysverify", ossl_dsa_verify, 2);

Expand Down
50 changes: 19 additions & 31 deletions ext/openssl/ossl_pkey_ec.c
Original file line number Diff line number Diff line change
Expand Up @@ -412,32 +412,6 @@ ossl_ec_key_to_der(VALUE self)
else
return ossl_pkey_export_spki(self, 1);
}

/*
* call-seq:
* key.to_text => String
*
* See the OpenSSL documentation for EC_KEY_print()
*/
static VALUE ossl_ec_key_to_text(VALUE self)
{
EC_KEY *ec;
BIO *out;
VALUE str;

GetEC(self, ec);
if (!(out = BIO_new(BIO_s_mem()))) {
ossl_raise(eECError, "BIO_new(BIO_s_mem())");
}
if (!EC_KEY_print(out, ec, 0)) {
BIO_free(out);
ossl_raise(eECError, "EC_KEY_print");
}
str = ossl_membio2str(out);

return str;
}

/*
* call-seq:
* key.generate_key! => self
Expand All @@ -464,20 +438,35 @@ static VALUE ossl_ec_key_generate_key(VALUE self)
}

/*
* call-seq:
* key.check_key => true
* call-seq:
* key.check_key => true
*
* Raises an exception if the key is invalid.
* Raises an exception if the key is invalid.
*
* See the OpenSSL documentation for EC_KEY_check_key()
* See also the man page EVP_PKEY_public_check(3).
*/
static VALUE ossl_ec_key_check_key(VALUE self)
{
#ifdef HAVE_EVP_PKEY_CHECK
EVP_PKEY *pkey;
EVP_PKEY_CTX *pctx;
int ret;

GetPKey(self, pkey);
pctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);
if (!pctx)
ossl_raise(eDHError, "EVP_PKEY_CTX_new");
ret = EVP_PKEY_public_check(pctx);
EVP_PKEY_CTX_free(pctx);
if (ret != 1)
ossl_raise(eECError, "EVP_PKEY_public_check");
#else
EC_KEY *ec;

GetEC(self, ec);
if (EC_KEY_check_key(ec) != 1)
ossl_raise(eECError, "EC_KEY_check_key");
#endif

return Qtrue;
}
Expand Down Expand Up @@ -1601,7 +1590,6 @@ void Init_ossl_ec(void)
rb_define_method(cEC, "export", ossl_ec_key_export, -1);
rb_define_alias(cEC, "to_pem", "export");
rb_define_method(cEC, "to_der", ossl_ec_key_to_der, 0);
rb_define_method(cEC, "to_text", ossl_ec_key_to_text, 0);


rb_define_alloc_func(cEC_GROUP, ossl_ec_group_alloc);
Expand Down
Loading