Skip to content

Commit 43bd8d9

Browse files
committed
pkey/rsa: use high level EVP interface to generate parameters and keys
Implement PKey::RSA.new(size, exponent) and PKey::RSA.generate using OpenSSL::PKey.generate_key instead of the low level RSA functions.
1 parent f774e74 commit 43bd8d9

File tree

2 files changed

+48
-116
lines changed

2 files changed

+48
-116
lines changed

ext/openssl/ossl_pkey_rsa.c

+16-116
Original file line numberDiff line numberDiff line change
@@ -47,125 +47,28 @@ VALUE eRSAError;
4747
/*
4848
* Private
4949
*/
50-
struct rsa_blocking_gen_arg {
51-
RSA *rsa;
52-
BIGNUM *e;
53-
int size;
54-
BN_GENCB *cb;
55-
int result;
56-
};
57-
58-
static void *
59-
rsa_blocking_gen(void *arg)
60-
{
61-
struct rsa_blocking_gen_arg *gen = (struct rsa_blocking_gen_arg *)arg;
62-
gen->result = RSA_generate_key_ex(gen->rsa, gen->size, gen->e, gen->cb);
63-
return 0;
64-
}
65-
66-
static RSA *
67-
rsa_generate(int size, unsigned long exp)
68-
{
69-
int i;
70-
struct ossl_generate_cb_arg cb_arg = { 0 };
71-
struct rsa_blocking_gen_arg gen_arg;
72-
RSA *rsa = RSA_new();
73-
BIGNUM *e = BN_new();
74-
BN_GENCB *cb = BN_GENCB_new();
75-
76-
if (!rsa || !e || !cb) {
77-
RSA_free(rsa);
78-
BN_free(e);
79-
BN_GENCB_free(cb);
80-
ossl_raise(eRSAError, "malloc failure");
81-
}
82-
for (i = 0; i < (int)sizeof(exp) * 8; ++i) {
83-
if (exp & (1UL << i)) {
84-
if (BN_set_bit(e, i) == 0) {
85-
BN_free(e);
86-
RSA_free(rsa);
87-
BN_GENCB_free(cb);
88-
ossl_raise(eRSAError, "BN_set_bit");
89-
}
90-
}
91-
}
92-
93-
if (rb_block_given_p())
94-
cb_arg.yield = 1;
95-
BN_GENCB_set(cb, ossl_generate_cb_2, &cb_arg);
96-
gen_arg.rsa = rsa;
97-
gen_arg.e = e;
98-
gen_arg.size = size;
99-
gen_arg.cb = cb;
100-
if (cb_arg.yield == 1) {
101-
/* we cannot release GVL when callback proc is supplied */
102-
rsa_blocking_gen(&gen_arg);
103-
} else {
104-
/* there's a chance to unblock */
105-
rb_thread_call_without_gvl(rsa_blocking_gen, &gen_arg, ossl_generate_cb_stop, &cb_arg);
106-
}
107-
108-
BN_GENCB_free(cb);
109-
BN_free(e);
110-
if (!gen_arg.result) {
111-
RSA_free(rsa);
112-
if (cb_arg.state) {
113-
/* must clear OpenSSL error stack */
114-
ossl_clear_error();
115-
rb_jump_tag(cb_arg.state);
116-
}
117-
ossl_raise(eRSAError, "RSA_generate_key_ex");
118-
}
119-
120-
return rsa;
121-
}
122-
12350
/*
12451
* call-seq:
125-
* RSA.generate(size) => RSA instance
126-
* RSA.generate(size, exponent) => RSA instance
52+
* RSA.new -> rsa
53+
* RSA.new(encoded_key [, passphrase]) -> rsa
54+
* RSA.new(encoded_key) { passphrase } -> rsa
55+
* RSA.new(size [, exponent]) -> rsa
12756
*
128-
* Generates an RSA keypair. _size_ is an integer representing the desired key
129-
* size. Keys smaller than 1024 should be considered insecure. _exponent_ is
130-
* an odd number normally 3, 17, or 65537.
131-
*/
132-
static VALUE
133-
ossl_rsa_s_generate(int argc, VALUE *argv, VALUE klass)
134-
{
135-
/* why does this method exist? why can't initialize take an optional exponent? */
136-
EVP_PKEY *pkey;
137-
RSA *rsa;
138-
VALUE size, exp;
139-
VALUE obj;
140-
141-
rb_scan_args(argc, argv, "11", &size, &exp);
142-
obj = rb_obj_alloc(klass);
143-
GetPKey(obj, pkey);
144-
145-
rsa = rsa_generate(NUM2INT(size), NIL_P(exp) ? RSA_F4 : NUM2ULONG(exp));
146-
if (!EVP_PKEY_assign_RSA(pkey, rsa)) {
147-
RSA_free(rsa);
148-
ossl_raise(eRSAError, "EVP_PKEY_assign_RSA");
149-
}
150-
return obj;
151-
}
152-
153-
/*
154-
* call-seq:
155-
* RSA.new(size [, exponent]) => RSA instance
156-
* RSA.new(encoded_key) => RSA instance
157-
* RSA.new(encoded_key, pass_phrase) => RSA instance
57+
* Generates or loads an \RSA keypair.
15858
*
159-
* Generates or loads an RSA keypair. If an integer _key_size_ is given it
160-
* represents the desired key size. Keys less than 1024 bits should be
161-
* considered insecure.
59+
* If called without arguments, creates a new instance with no key components
60+
* set. They can be set individually by #set_key, #set_factors, and
61+
* #set_crt_params.
16262
*
163-
* A key can instead be loaded from an _encoded_key_ which must be PEM or DER
164-
* encoded. A _pass_phrase_ can be used to decrypt the key. If none is given
165-
* OpenSSL will prompt for the pass phrase.
63+
* If called with a String, tries to parse as DER or PEM encoding of an \RSA key.
64+
* Note that, if _passphrase_ is not specified but the key is encrypted with a
65+
* passphrase, \OpenSSL will prompt for it.
66+
* See also OpenSSL::PKey.read which can parse keys of any kinds.
16667
*
167-
* = Examples
68+
* If called with a number, generates a new key pair. This form works as an
69+
* alias of RSA.generate.
16870
*
71+
* Examples:
16972
* OpenSSL::PKey::RSA.new 2048
17073
* OpenSSL::PKey::RSA.new File.read 'rsa.pem'
17174
* OpenSSL::PKey::RSA.new File.read('rsa.pem'), 'my pass phrase'
@@ -179,15 +82,13 @@ ossl_rsa_initialize(int argc, VALUE *argv, VALUE self)
17982
VALUE arg, pass;
18083

18184
GetPKey(self, pkey);
85+
/* The RSA.new(size, generator) form is handled by lib/openssl/pkey.rb */
18286
rb_scan_args(argc, argv, "02", &arg, &pass);
18387
if (argc == 0) {
18488
rsa = RSA_new();
18589
if (!rsa)
18690
ossl_raise(eRSAError, "RSA_new");
18791
}
188-
else if (RB_INTEGER_TYPE_P(arg)) {
189-
rsa = rsa_generate(NUM2INT(arg), NIL_P(pass) ? RSA_F4 : NUM2ULONG(pass));
190-
}
19192
else {
19293
pass = ossl_pem_passwd_value(pass);
19394
arg = ossl_to_der_if_possible(arg);
@@ -832,7 +733,6 @@ Init_ossl_rsa(void)
832733
*/
833734
cRSA = rb_define_class_under(mPKey, "RSA", cPKey);
834735

835-
rb_define_singleton_method(cRSA, "generate", ossl_rsa_s_generate, -1);
836736
rb_define_method(cRSA, "initialize", ossl_rsa_initialize, -1);
837737
rb_define_method(cRSA, "initialize_copy", ossl_rsa_initialize_copy, 1);
838738

lib/openssl/pkey.rb

+32
Original file line numberDiff line numberDiff line change
@@ -128,5 +128,37 @@ def to_bn(conversion_form = group.point_conversion_form)
128128

129129
class RSA
130130
include OpenSSL::Marshal
131+
132+
class << self
133+
# :call-seq:
134+
# RSA.generate(size) => RSA instance
135+
# RSA.generate(size, exponent) => RSA instance
136+
#
137+
# Generates an \RSA keypair.
138+
#
139+
# See also OpenSSL::PKey.generate_key.
140+
#
141+
# size::
142+
# An Integer representing the desired key size. Keys smaller than 1024
143+
# should be considered insecure.
144+
# exponent::
145+
# An odd Integer, normally 3, 17, or 65537.
146+
def generate(size, exp = 0x10001, &blk)
147+
OpenSSL::PKey.generate_key("RSA", {
148+
"rsa_keygen_bits" => size,
149+
"rsa_keygen_pubexp" => exp,
150+
}, &blk)
151+
end
152+
153+
# Handle RSA.new(size, exponent) form here; new(str) and new() forms
154+
# are handled by #initialize
155+
def new(*args, &blk) # :nodoc:
156+
if args[0].is_a?(Integer)
157+
generate(*args, &blk)
158+
else
159+
super
160+
end
161+
end
162+
end
131163
end
132164
end

0 commit comments

Comments
 (0)