Skip to content

Commit c310840

Browse files
authored
Merge pull request #436 from rhenium/ky/pkey-generic-evp-more
Use EVP API in more places
2 parents 03cb3d5 + 797e9f8 commit c310840

File tree

10 files changed

+191
-292
lines changed

10 files changed

+191
-292
lines changed

ext/openssl/extconf.rb

+3
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,9 @@ def find_openssl_library
165165
have_func("EVP_PBE_scrypt")
166166
have_func("SSL_CTX_set_post_handshake_auth")
167167

168+
# added in 1.1.1
169+
have_func("EVP_PKEY_check")
170+
168171
Logging::message "=== Checking done. ===\n"
169172

170173
create_header

ext/openssl/ossl_pkey.c

+38
Original file line numberDiff line numberDiff line change
@@ -539,6 +539,43 @@ ossl_pkey_inspect(VALUE self)
539539
OBJ_nid2sn(nid));
540540
}
541541

542+
/*
543+
* call-seq:
544+
* pkey.to_text -> string
545+
*
546+
* Dumps key parameters, public key, and private key components contained in
547+
* the key into a human-readable text.
548+
*
549+
* This is intended for debugging purpose.
550+
*
551+
* See also the man page EVP_PKEY_print_private(3).
552+
*/
553+
static VALUE
554+
ossl_pkey_to_text(VALUE self)
555+
{
556+
EVP_PKEY *pkey;
557+
BIO *bio;
558+
559+
GetPKey(self, pkey);
560+
if (!(bio = BIO_new(BIO_s_mem())))
561+
ossl_raise(ePKeyError, "BIO_new");
562+
563+
if (EVP_PKEY_print_private(bio, pkey, 0, NULL) == 1)
564+
goto out;
565+
OSSL_BIO_reset(bio);
566+
if (EVP_PKEY_print_public(bio, pkey, 0, NULL) == 1)
567+
goto out;
568+
OSSL_BIO_reset(bio);
569+
if (EVP_PKEY_print_params(bio, pkey, 0, NULL) == 1)
570+
goto out;
571+
572+
BIO_free(bio);
573+
ossl_raise(ePKeyError, "EVP_PKEY_print_params");
574+
575+
out:
576+
return ossl_membio2str(bio);
577+
}
578+
542579
VALUE
543580
ossl_pkey_export_traditional(int argc, VALUE *argv, VALUE self, int to_der)
544581
{
@@ -1077,6 +1114,7 @@ Init_ossl_pkey(void)
10771114
rb_define_method(cPKey, "initialize", ossl_pkey_initialize, 0);
10781115
rb_define_method(cPKey, "oid", ossl_pkey_oid, 0);
10791116
rb_define_method(cPKey, "inspect", ossl_pkey_inspect, 0);
1117+
rb_define_method(cPKey, "to_text", ossl_pkey_to_text, 0);
10801118
rb_define_method(cPKey, "private_to_der", ossl_pkey_private_to_der, -1);
10811119
rb_define_method(cPKey, "private_to_pem", ossl_pkey_private_to_pem, -1);
10821120
rb_define_method(cPKey, "public_to_der", ossl_pkey_public_to_der, 0);

ext/openssl/ossl_pkey_dh.c

+36-83
Original file line numberDiff line numberDiff line change
@@ -266,96 +266,45 @@ ossl_dh_get_params(VALUE self)
266266
return hash;
267267
}
268268

269-
/*
270-
* call-seq:
271-
* dh.to_text -> aString
272-
*
273-
* Prints all parameters of key to buffer
274-
* INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!!
275-
* Don't use :-)) (I's up to you)
276-
*/
277-
static VALUE
278-
ossl_dh_to_text(VALUE self)
279-
{
280-
DH *dh;
281-
BIO *out;
282-
VALUE str;
283-
284-
GetDH(self, dh);
285-
if (!(out = BIO_new(BIO_s_mem()))) {
286-
ossl_raise(eDHError, NULL);
287-
}
288-
if (!DHparams_print(out, dh)) {
289-
BIO_free(out);
290-
ossl_raise(eDHError, NULL);
291-
}
292-
str = ossl_membio2str(out);
293-
294-
return str;
295-
}
296-
297-
/*
298-
* call-seq:
299-
* dh.public_key -> aDH
300-
*
301-
* Returns a new DH instance that carries just the public information, i.e.
302-
* the prime _p_ and the generator _g_, but no public/private key yet. Such
303-
* a pair may be generated using DH#generate_key!. The "public key" needed
304-
* for a key exchange with DH#compute_key is considered as per-session
305-
* information and may be retrieved with DH#pub_key once a key pair has
306-
* been generated.
307-
* If the current instance already contains private information (and thus a
308-
* valid public/private key pair), this information will no longer be present
309-
* in the new instance generated by DH#public_key. This feature is helpful for
310-
* publishing the Diffie-Hellman parameters without leaking any of the private
311-
* per-session information.
312-
*
313-
* === Example
314-
* dh = OpenSSL::PKey::DH.new(2048) # has public and private key set
315-
* public_key = dh.public_key # contains only prime and generator
316-
* parameters = public_key.to_der # it's safe to publish this
317-
*/
318-
static VALUE
319-
ossl_dh_to_public_key(VALUE self)
320-
{
321-
EVP_PKEY *pkey;
322-
DH *orig_dh, *dh;
323-
VALUE obj;
324-
325-
obj = rb_obj_alloc(rb_obj_class(self));
326-
GetPKey(obj, pkey);
327-
328-
GetDH(self, orig_dh);
329-
dh = DHparams_dup(orig_dh);
330-
if (!dh)
331-
ossl_raise(eDHError, "DHparams_dup");
332-
if (!EVP_PKEY_assign_DH(pkey, dh)) {
333-
DH_free(dh);
334-
ossl_raise(eDHError, "EVP_PKEY_assign_DH");
335-
}
336-
return obj;
337-
}
338-
339269
/*
340270
* call-seq:
341271
* dh.params_ok? -> true | false
342272
*
343273
* Validates the Diffie-Hellman parameters associated with this instance.
344274
* It checks whether a safe prime and a suitable generator are used. If this
345275
* is not the case, +false+ is returned.
276+
*
277+
* See also the man page EVP_PKEY_param_check(3).
346278
*/
347279
static VALUE
348280
ossl_dh_check_params(VALUE self)
349281
{
282+
int ret;
283+
#ifdef HAVE_EVP_PKEY_CHECK
284+
EVP_PKEY *pkey;
285+
EVP_PKEY_CTX *pctx;
286+
287+
GetPKey(self, pkey);
288+
pctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);
289+
if (!pctx)
290+
ossl_raise(eDHError, "EVP_PKEY_CTX_new");
291+
ret = EVP_PKEY_param_check(pctx);
292+
EVP_PKEY_CTX_free(pctx);
293+
#else
350294
DH *dh;
351295
int codes;
352296

353297
GetDH(self, dh);
354-
if (!DH_check(dh, &codes)) {
355-
return Qfalse;
356-
}
298+
ret = DH_check(dh, &codes) == 1 && codes == 0;
299+
#endif
357300

358-
return codes == 0 ? Qtrue : Qfalse;
301+
if (ret == 1)
302+
return Qtrue;
303+
else {
304+
/* DH_check_ex() will put error entry on failure */
305+
ossl_clear_error();
306+
return Qfalse;
307+
}
359308
}
360309

361310
/*
@@ -412,26 +361,30 @@ Init_ossl_dh(void)
412361
* The per-session private key, an OpenSSL::BN.
413362
*
414363
* === Example of a key exchange
415-
* dh1 = OpenSSL::PKey::DH.new(2048)
416-
* der = dh1.public_key.to_der #you may send this publicly to the participating party
417-
* dh2 = OpenSSL::PKey::DH.new(der)
418-
* dh2.generate_key! #generate the per-session key pair
419-
* symm_key1 = dh1.compute_key(dh2.pub_key)
420-
* symm_key2 = dh2.compute_key(dh1.pub_key)
364+
* # you may send the parameters (der) and own public key (pub1) publicly
365+
* # to the participating party
366+
* dh1 = OpenSSL::PKey::DH.new(2048)
367+
* der = dh1.to_der
368+
* pub1 = dh1.pub_key
369+
*
370+
* # the other party generates its per-session key pair
371+
* dhparams = OpenSSL::PKey::DH.new(der)
372+
* dh2 = OpenSSL::PKey.generate_key(dhparams)
373+
* pub2 = dh2.pub_key
421374
*
422-
* puts symm_key1 == symm_key2 # => true
375+
* symm_key1 = dh1.compute_key(pub2)
376+
* symm_key2 = dh2.compute_key(pub1)
377+
* puts symm_key1 == symm_key2 # => true
423378
*/
424379
cDH = rb_define_class_under(mPKey, "DH", cPKey);
425380
rb_define_method(cDH, "initialize", ossl_dh_initialize, -1);
426381
rb_define_method(cDH, "initialize_copy", ossl_dh_initialize_copy, 1);
427382
rb_define_method(cDH, "public?", ossl_dh_is_public, 0);
428383
rb_define_method(cDH, "private?", ossl_dh_is_private, 0);
429-
rb_define_method(cDH, "to_text", ossl_dh_to_text, 0);
430384
rb_define_method(cDH, "export", ossl_dh_export, 0);
431385
rb_define_alias(cDH, "to_pem", "export");
432386
rb_define_alias(cDH, "to_s", "export");
433387
rb_define_method(cDH, "to_der", ossl_dh_to_der, 0);
434-
rb_define_method(cDH, "public_key", ossl_dh_to_public_key, 0);
435388
rb_define_method(cDH, "params_ok?", ossl_dh_check_params, 0);
436389

437390
DEF_OSSL_PKEY_BN(cDH, dh, p);

ext/openssl/ossl_pkey_dsa.c

-71
Original file line numberDiff line numberDiff line change
@@ -264,75 +264,6 @@ ossl_dsa_get_params(VALUE self)
264264
return hash;
265265
}
266266

267-
/*
268-
* call-seq:
269-
* dsa.to_text -> aString
270-
*
271-
* Prints all parameters of key to buffer
272-
* INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!!
273-
* Don't use :-)) (I's up to you)
274-
*/
275-
static VALUE
276-
ossl_dsa_to_text(VALUE self)
277-
{
278-
DSA *dsa;
279-
BIO *out;
280-
VALUE str;
281-
282-
GetDSA(self, dsa);
283-
if (!(out = BIO_new(BIO_s_mem()))) {
284-
ossl_raise(eDSAError, NULL);
285-
}
286-
if (!DSA_print(out, dsa, 0)) { /* offset = 0 */
287-
BIO_free(out);
288-
ossl_raise(eDSAError, NULL);
289-
}
290-
str = ossl_membio2str(out);
291-
292-
return str;
293-
}
294-
295-
/*
296-
* call-seq:
297-
* dsa.public_key -> aDSA
298-
*
299-
* Returns a new DSA instance that carries just the public key information.
300-
* If the current instance has also private key information, this will no
301-
* longer be present in the new instance. This feature is helpful for
302-
* publishing the public key information without leaking any of the private
303-
* information.
304-
*
305-
* === Example
306-
* dsa = OpenSSL::PKey::DSA.new(2048) # has public and private information
307-
* pub_key = dsa.public_key # has only the public part available
308-
* pub_key_der = pub_key.to_der # it's safe to publish this
309-
*
310-
*
311-
*/
312-
static VALUE
313-
ossl_dsa_to_public_key(VALUE self)
314-
{
315-
EVP_PKEY *pkey, *pkey_new;
316-
DSA *dsa;
317-
VALUE obj;
318-
319-
GetPKeyDSA(self, pkey);
320-
obj = rb_obj_alloc(rb_obj_class(self));
321-
GetPKey(obj, pkey_new);
322-
323-
#define DSAPublicKey_dup(dsa) (DSA *)ASN1_dup( \
324-
(i2d_of_void *)i2d_DSAPublicKey, (d2i_of_void *)d2i_DSAPublicKey, (char *)(dsa))
325-
dsa = DSAPublicKey_dup(EVP_PKEY_get0_DSA(pkey));
326-
#undef DSAPublicKey_dup
327-
if (!dsa)
328-
ossl_raise(eDSAError, "DSAPublicKey_dup");
329-
if (!EVP_PKEY_assign_DSA(pkey_new, dsa)) {
330-
DSA_free(dsa);
331-
ossl_raise(eDSAError, "EVP_PKEY_assign_DSA");
332-
}
333-
return obj;
334-
}
335-
336267
/*
337268
* call-seq:
338269
* dsa.syssign(string) -> aString
@@ -469,12 +400,10 @@ Init_ossl_dsa(void)
469400

470401
rb_define_method(cDSA, "public?", ossl_dsa_is_public, 0);
471402
rb_define_method(cDSA, "private?", ossl_dsa_is_private, 0);
472-
rb_define_method(cDSA, "to_text", ossl_dsa_to_text, 0);
473403
rb_define_method(cDSA, "export", ossl_dsa_export, -1);
474404
rb_define_alias(cDSA, "to_pem", "export");
475405
rb_define_alias(cDSA, "to_s", "export");
476406
rb_define_method(cDSA, "to_der", ossl_dsa_to_der, 0);
477-
rb_define_method(cDSA, "public_key", ossl_dsa_to_public_key, 0);
478407
rb_define_method(cDSA, "syssign", ossl_dsa_sign, 1);
479408
rb_define_method(cDSA, "sysverify", ossl_dsa_verify, 2);
480409

ext/openssl/ossl_pkey_ec.c

+19-31
Original file line numberDiff line numberDiff line change
@@ -412,32 +412,6 @@ ossl_ec_key_to_der(VALUE self)
412412
else
413413
return ossl_pkey_export_spki(self, 1);
414414
}
415-
416-
/*
417-
* call-seq:
418-
* key.to_text => String
419-
*
420-
* See the OpenSSL documentation for EC_KEY_print()
421-
*/
422-
static VALUE ossl_ec_key_to_text(VALUE self)
423-
{
424-
EC_KEY *ec;
425-
BIO *out;
426-
VALUE str;
427-
428-
GetEC(self, ec);
429-
if (!(out = BIO_new(BIO_s_mem()))) {
430-
ossl_raise(eECError, "BIO_new(BIO_s_mem())");
431-
}
432-
if (!EC_KEY_print(out, ec, 0)) {
433-
BIO_free(out);
434-
ossl_raise(eECError, "EC_KEY_print");
435-
}
436-
str = ossl_membio2str(out);
437-
438-
return str;
439-
}
440-
441415
/*
442416
* call-seq:
443417
* key.generate_key! => self
@@ -464,20 +438,35 @@ static VALUE ossl_ec_key_generate_key(VALUE self)
464438
}
465439

466440
/*
467-
* call-seq:
468-
* key.check_key => true
441+
* call-seq:
442+
* key.check_key => true
469443
*
470-
* Raises an exception if the key is invalid.
444+
* Raises an exception if the key is invalid.
471445
*
472-
* See the OpenSSL documentation for EC_KEY_check_key()
446+
* See also the man page EVP_PKEY_public_check(3).
473447
*/
474448
static VALUE ossl_ec_key_check_key(VALUE self)
475449
{
450+
#ifdef HAVE_EVP_PKEY_CHECK
451+
EVP_PKEY *pkey;
452+
EVP_PKEY_CTX *pctx;
453+
int ret;
454+
455+
GetPKey(self, pkey);
456+
pctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);
457+
if (!pctx)
458+
ossl_raise(eDHError, "EVP_PKEY_CTX_new");
459+
ret = EVP_PKEY_public_check(pctx);
460+
EVP_PKEY_CTX_free(pctx);
461+
if (ret != 1)
462+
ossl_raise(eECError, "EVP_PKEY_public_check");
463+
#else
476464
EC_KEY *ec;
477465

478466
GetEC(self, ec);
479467
if (EC_KEY_check_key(ec) != 1)
480468
ossl_raise(eECError, "EC_KEY_check_key");
469+
#endif
481470

482471
return Qtrue;
483472
}
@@ -1601,7 +1590,6 @@ void Init_ossl_ec(void)
16011590
rb_define_method(cEC, "export", ossl_ec_key_export, -1);
16021591
rb_define_alias(cEC, "to_pem", "export");
16031592
rb_define_method(cEC, "to_der", ossl_ec_key_to_der, 0);
1604-
rb_define_method(cEC, "to_text", ossl_ec_key_to_text, 0);
16051593

16061594

16071595
rb_define_alloc_func(cEC_GROUP, ossl_ec_group_alloc);

0 commit comments

Comments
 (0)