1005 lines
32 KiB
Diff
1005 lines
32 KiB
Diff
|
From 6bbdaef1a578fdbfc6a5bf82402ba4d3fd733d4a Mon Sep 17 00:00:00 2001
|
||
|
From: Kazuki Yamaguchi <k@rhe.jp>
|
||
|
Date: Tue, 21 Mar 2017 18:23:53 +0900
|
||
|
Subject: [PATCH 1/6] pkey: assume generic PKeys contain private components
|
||
|
|
||
|
The EVP interface cannot tell whether if a pkey contains the private
|
||
|
components or not. Assume it does if it does not respond to #private?.
|
||
|
This fixes the NoMethodError on calling #sign on a generic PKey.
|
||
|
---
|
||
|
ext/openssl/ossl_pkey.c | 15 +++++++++++----
|
||
|
1 file changed, 11 insertions(+), 4 deletions(-)
|
||
|
|
||
|
diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c
|
||
|
index 610a83fd2d..8d41623e80 100644
|
||
|
--- a/ext/openssl/ossl_pkey.c
|
||
|
+++ b/ext/openssl/ossl_pkey.c
|
||
|
@@ -252,12 +252,19 @@ GetPrivPKeyPtr(VALUE obj)
|
||
|
{
|
||
|
EVP_PKEY *pkey;
|
||
|
|
||
|
- if (rb_funcallv(obj, id_private_q, 0, NULL) != Qtrue) {
|
||
|
- ossl_raise(rb_eArgError, "Private key is needed.");
|
||
|
- }
|
||
|
GetPKey(obj, pkey);
|
||
|
+ if (OSSL_PKEY_IS_PRIVATE(obj))
|
||
|
+ return pkey;
|
||
|
+ /*
|
||
|
+ * The EVP API does not provide a way to check if the EVP_PKEY has private
|
||
|
+ * components. Assuming it does...
|
||
|
+ */
|
||
|
+ if (!rb_respond_to(obj, id_private_q))
|
||
|
+ return pkey;
|
||
|
+ if (RTEST(rb_funcallv(obj, id_private_q, 0, NULL)))
|
||
|
+ return pkey;
|
||
|
|
||
|
- return pkey;
|
||
|
+ rb_raise(rb_eArgError, "private key is needed");
|
||
|
}
|
||
|
|
||
|
EVP_PKEY *
|
||
|
--
|
||
|
2.32.0
|
||
|
|
||
|
|
||
|
From 86508f74b3d41166ed6091b7b31f18a26478c347 Mon Sep 17 00:00:00 2001
|
||
|
From: Kazuki Yamaguchi <k@rhe.jp>
|
||
|
Date: Mon, 20 Mar 2017 23:18:26 +0900
|
||
|
Subject: [PATCH 2/6] pkey: add PKey.generate_parameters and .generate_key
|
||
|
|
||
|
Add two methods to create a PKey using the generic EVP interface. This
|
||
|
is useful for the PKey types we don't have a dedicated class.
|
||
|
---
|
||
|
ext/openssl/ossl_pkey.c | 222 ++++++++++++++++++++++++++++++++++++++
|
||
|
test/openssl/test_pkey.rb | 43 ++++++++
|
||
|
2 files changed, 265 insertions(+)
|
||
|
|
||
|
diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c
|
||
|
index 8d41623e80..1f3dd39b9b 100644
|
||
|
--- a/ext/openssl/ossl_pkey.c
|
||
|
+++ b/ext/openssl/ossl_pkey.c
|
||
|
@@ -197,6 +197,226 @@ ossl_pkey_new_from_data(int argc, VALUE *argv, VALUE self)
|
||
|
return ossl_pkey_new(pkey);
|
||
|
}
|
||
|
|
||
|
+static VALUE
|
||
|
+pkey_gen_apply_options_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, ctx_v))
|
||
|
+{
|
||
|
+ VALUE key = rb_ary_entry(i, 0), value = rb_ary_entry(i, 1);
|
||
|
+ EVP_PKEY_CTX *ctx = (EVP_PKEY_CTX *)ctx_v;
|
||
|
+
|
||
|
+ if (SYMBOL_P(key))
|
||
|
+ key = rb_sym2str(key);
|
||
|
+ value = rb_String(value);
|
||
|
+
|
||
|
+ if (EVP_PKEY_CTX_ctrl_str(ctx, StringValueCStr(key), StringValueCStr(value)) <= 0)
|
||
|
+ ossl_raise(ePKeyError, "EVP_PKEY_CTX_ctrl_str(ctx, %+"PRIsVALUE", %+"PRIsVALUE")",
|
||
|
+ key, value);
|
||
|
+ return Qnil;
|
||
|
+}
|
||
|
+
|
||
|
+static VALUE
|
||
|
+pkey_gen_apply_options0(VALUE args_v)
|
||
|
+{
|
||
|
+ VALUE *args = (VALUE *)args_v;
|
||
|
+
|
||
|
+ rb_block_call(args[1], rb_intern("each"), 0, NULL,
|
||
|
+ pkey_gen_apply_options_i, args[0]);
|
||
|
+ return Qnil;
|
||
|
+}
|
||
|
+
|
||
|
+struct pkey_blocking_generate_arg {
|
||
|
+ EVP_PKEY_CTX *ctx;
|
||
|
+ EVP_PKEY *pkey;
|
||
|
+ int state;
|
||
|
+ int yield: 1;
|
||
|
+ int genparam: 1;
|
||
|
+ int stop: 1;
|
||
|
+};
|
||
|
+
|
||
|
+static VALUE
|
||
|
+pkey_gen_cb_yield(VALUE ctx_v)
|
||
|
+{
|
||
|
+ EVP_PKEY_CTX *ctx = (void *)ctx_v;
|
||
|
+ int i, info_num;
|
||
|
+ VALUE *argv;
|
||
|
+
|
||
|
+ info_num = EVP_PKEY_CTX_get_keygen_info(ctx, -1);
|
||
|
+ argv = ALLOCA_N(VALUE, info_num);
|
||
|
+ for (i = 0; i < info_num; i++)
|
||
|
+ argv[i] = INT2NUM(EVP_PKEY_CTX_get_keygen_info(ctx, i));
|
||
|
+
|
||
|
+ return rb_yield_values2(info_num, argv);
|
||
|
+}
|
||
|
+
|
||
|
+static int
|
||
|
+pkey_gen_cb(EVP_PKEY_CTX *ctx)
|
||
|
+{
|
||
|
+ struct pkey_blocking_generate_arg *arg = EVP_PKEY_CTX_get_app_data(ctx);
|
||
|
+
|
||
|
+ if (arg->yield) {
|
||
|
+ int state;
|
||
|
+ rb_protect(pkey_gen_cb_yield, (VALUE)ctx, &state);
|
||
|
+ if (state) {
|
||
|
+ arg->stop = 1;
|
||
|
+ arg->state = state;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ return !arg->stop;
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+pkey_blocking_gen_stop(void *ptr)
|
||
|
+{
|
||
|
+ struct pkey_blocking_generate_arg *arg = ptr;
|
||
|
+ arg->stop = 1;
|
||
|
+}
|
||
|
+
|
||
|
+static void *
|
||
|
+pkey_blocking_gen(void *ptr)
|
||
|
+{
|
||
|
+ struct pkey_blocking_generate_arg *arg = ptr;
|
||
|
+
|
||
|
+ if (arg->genparam && EVP_PKEY_paramgen(arg->ctx, &arg->pkey) <= 0)
|
||
|
+ return NULL;
|
||
|
+ if (!arg->genparam && EVP_PKEY_keygen(arg->ctx, &arg->pkey) <= 0)
|
||
|
+ return NULL;
|
||
|
+ return arg->pkey;
|
||
|
+}
|
||
|
+
|
||
|
+static VALUE
|
||
|
+pkey_generate(int argc, VALUE *argv, VALUE self, int genparam)
|
||
|
+{
|
||
|
+ EVP_PKEY_CTX *ctx;
|
||
|
+ VALUE alg, options;
|
||
|
+ struct pkey_blocking_generate_arg gen_arg = { 0 };
|
||
|
+ int state;
|
||
|
+
|
||
|
+ rb_scan_args(argc, argv, "11", &alg, &options);
|
||
|
+ if (rb_obj_is_kind_of(alg, cPKey)) {
|
||
|
+ EVP_PKEY *base_pkey;
|
||
|
+
|
||
|
+ GetPKey(alg, base_pkey);
|
||
|
+ ctx = EVP_PKEY_CTX_new(base_pkey, NULL/* engine */);
|
||
|
+ if (!ctx)
|
||
|
+ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new");
|
||
|
+ }
|
||
|
+ else {
|
||
|
+ const EVP_PKEY_ASN1_METHOD *ameth;
|
||
|
+ ENGINE *tmpeng;
|
||
|
+ int pkey_id;
|
||
|
+
|
||
|
+ StringValue(alg);
|
||
|
+ ameth = EVP_PKEY_asn1_find_str(&tmpeng, RSTRING_PTR(alg),
|
||
|
+ RSTRING_LENINT(alg));
|
||
|
+ if (!ameth)
|
||
|
+ ossl_raise(ePKeyError, "algorithm %"PRIsVALUE" not found", alg);
|
||
|
+ EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL, ameth);
|
||
|
+#if !defined(OPENSSL_NO_ENGINE)
|
||
|
+ if (tmpeng)
|
||
|
+ ENGINE_finish(tmpeng);
|
||
|
+#endif
|
||
|
+
|
||
|
+ ctx = EVP_PKEY_CTX_new_id(pkey_id, NULL/* engine */);
|
||
|
+ if (!ctx)
|
||
|
+ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new_id");
|
||
|
+ }
|
||
|
+
|
||
|
+ if (genparam && EVP_PKEY_paramgen_init(ctx) <= 0) {
|
||
|
+ EVP_PKEY_CTX_free(ctx);
|
||
|
+ ossl_raise(ePKeyError, "EVP_PKEY_paramgen_init");
|
||
|
+ }
|
||
|
+ if (!genparam && EVP_PKEY_keygen_init(ctx) <= 0) {
|
||
|
+ EVP_PKEY_CTX_free(ctx);
|
||
|
+ ossl_raise(ePKeyError, "EVP_PKEY_keygen_init");
|
||
|
+ }
|
||
|
+
|
||
|
+ if (!NIL_P(options)) {
|
||
|
+ VALUE args[2];
|
||
|
+
|
||
|
+ args[0] = (VALUE)ctx;
|
||
|
+ args[1] = options;
|
||
|
+ rb_protect(pkey_gen_apply_options0, (VALUE)args, &state);
|
||
|
+ if (state) {
|
||
|
+ EVP_PKEY_CTX_free(ctx);
|
||
|
+ rb_jump_tag(state);
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ gen_arg.genparam = genparam;
|
||
|
+ gen_arg.ctx = ctx;
|
||
|
+ gen_arg.yield = rb_block_given_p();
|
||
|
+ EVP_PKEY_CTX_set_app_data(ctx, &gen_arg);
|
||
|
+ EVP_PKEY_CTX_set_cb(ctx, pkey_gen_cb);
|
||
|
+ if (gen_arg.yield)
|
||
|
+ pkey_blocking_gen(&gen_arg);
|
||
|
+ else
|
||
|
+ rb_thread_call_without_gvl(pkey_blocking_gen, &gen_arg,
|
||
|
+ pkey_blocking_gen_stop, &gen_arg);
|
||
|
+ EVP_PKEY_CTX_free(ctx);
|
||
|
+ if (!gen_arg.pkey) {
|
||
|
+ if (gen_arg.state) {
|
||
|
+ ossl_clear_error();
|
||
|
+ rb_jump_tag(gen_arg.state);
|
||
|
+ }
|
||
|
+ else {
|
||
|
+ ossl_raise(ePKeyError, genparam ? "EVP_PKEY_paramgen" : "EVP_PKEY_keygen");
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ return ossl_pkey_new(gen_arg.pkey);
|
||
|
+}
|
||
|
+
|
||
|
+/*
|
||
|
+ * call-seq:
|
||
|
+ * OpenSSL::PKey.generate_parameters(algo_name [, options]) -> pkey
|
||
|
+ *
|
||
|
+ * Generates new parameters for the algorithm. _algo_name_ is a String that
|
||
|
+ * represents the algorithm. The optional argument _options_ is a Hash that
|
||
|
+ * specifies the options specific to the algorithm. The order of the options
|
||
|
+ * can be important.
|
||
|
+ *
|
||
|
+ * A block can be passed optionally. The meaning of the arguments passed to
|
||
|
+ * the block varies depending on the implementation of the algorithm. The block
|
||
|
+ * may be called once or multiple times, or may not even be called.
|
||
|
+ *
|
||
|
+ * For the supported options, see the documentation for the 'openssl genpkey'
|
||
|
+ * utility command.
|
||
|
+ *
|
||
|
+ * == Example
|
||
|
+ * pkey = OpenSSL::PKey.generate_parameters("DSA", "dsa_paramgen_bits" => 2048)
|
||
|
+ * p pkey.p.num_bits #=> 2048
|
||
|
+ */
|
||
|
+static VALUE
|
||
|
+ossl_pkey_s_generate_parameters(int argc, VALUE *argv, VALUE self)
|
||
|
+{
|
||
|
+ return pkey_generate(argc, argv, self, 1);
|
||
|
+}
|
||
|
+
|
||
|
+/*
|
||
|
+ * call-seq:
|
||
|
+ * OpenSSL::PKey.generate_key(algo_name [, options]) -> pkey
|
||
|
+ * OpenSSL::PKey.generate_key(pkey [, options]) -> pkey
|
||
|
+ *
|
||
|
+ * Generates a new key (pair).
|
||
|
+ *
|
||
|
+ * If a String is given as the first argument, it generates a new random key
|
||
|
+ * for the algorithm specified by the name just as ::generate_parameters does.
|
||
|
+ * If an OpenSSL::PKey::PKey is given instead, it generates a new random key
|
||
|
+ * for the same algorithm as the key, using the parameters the key contains.
|
||
|
+ *
|
||
|
+ * See ::generate_parameters for the details of _options_ and the given block.
|
||
|
+ *
|
||
|
+ * == Example
|
||
|
+ * pkey_params = OpenSSL::PKey.generate_parameters("DSA", "dsa_paramgen_bits" => 2048)
|
||
|
+ * pkey_params.priv_key #=> nil
|
||
|
+ * pkey = OpenSSL::PKey.generate_key(pkey_params)
|
||
|
+ * pkey.priv_key #=> #<OpenSSL::BN 6277...
|
||
|
+ */
|
||
|
+static VALUE
|
||
|
+ossl_pkey_s_generate_key(int argc, VALUE *argv, VALUE self)
|
||
|
+{
|
||
|
+ return pkey_generate(argc, argv, self, 0);
|
||
|
+}
|
||
|
+
|
||
|
void
|
||
|
ossl_pkey_check_public_key(const EVP_PKEY *pkey)
|
||
|
{
|
||
|
@@ -707,6 +927,8 @@ Init_ossl_pkey(void)
|
||
|
cPKey = rb_define_class_under(mPKey, "PKey", rb_cObject);
|
||
|
|
||
|
rb_define_module_function(mPKey, "read", ossl_pkey_new_from_data, -1);
|
||
|
+ rb_define_module_function(mPKey, "generate_parameters", ossl_pkey_s_generate_parameters, -1);
|
||
|
+ rb_define_module_function(mPKey, "generate_key", ossl_pkey_s_generate_key, -1);
|
||
|
|
||
|
rb_define_alloc_func(cPKey, ossl_pkey_alloc);
|
||
|
rb_define_method(cPKey, "initialize", ossl_pkey_initialize, 0);
|
||
|
diff --git a/test/openssl/test_pkey.rb b/test/openssl/test_pkey.rb
|
||
|
index 0bdc9795cc..a325a1ea2b 100644
|
||
|
--- a/test/openssl/test_pkey.rb
|
||
|
+++ b/test/openssl/test_pkey.rb
|
||
|
@@ -25,4 +25,47 @@ def test_generic_oid_inspect
|
||
|
assert_equal "X25519", x25519.oid
|
||
|
assert_match %r{oid=X25519}, x25519.inspect
|
||
|
end
|
||
|
+
|
||
|
+ def test_s_generate_parameters
|
||
|
+ # 512 is non-default; 1024 is used if 'dsa_paramgen_bits' is not specified
|
||
|
+ # with OpenSSL 1.1.0.
|
||
|
+ pkey = OpenSSL::PKey.generate_parameters("DSA", {
|
||
|
+ "dsa_paramgen_bits" => 512,
|
||
|
+ "dsa_paramgen_q_bits" => 256,
|
||
|
+ })
|
||
|
+ assert_instance_of OpenSSL::PKey::DSA, pkey
|
||
|
+ assert_equal 512, pkey.p.num_bits
|
||
|
+ assert_equal 256, pkey.q.num_bits
|
||
|
+ assert_equal nil, pkey.priv_key
|
||
|
+
|
||
|
+ # Invalid options are checked
|
||
|
+ assert_raise(OpenSSL::PKey::PKeyError) {
|
||
|
+ OpenSSL::PKey.generate_parameters("DSA", "invalid" => "option")
|
||
|
+ }
|
||
|
+
|
||
|
+ # Parameter generation callback is called
|
||
|
+ cb_called = []
|
||
|
+ assert_raise(RuntimeError) {
|
||
|
+ OpenSSL::PKey.generate_parameters("DSA") { |*args|
|
||
|
+ cb_called << args
|
||
|
+ raise "exit!" if cb_called.size == 3
|
||
|
+ }
|
||
|
+ }
|
||
|
+ assert_not_empty cb_called
|
||
|
+ end
|
||
|
+
|
||
|
+ def test_s_generate_key
|
||
|
+ assert_raise(OpenSSL::PKey::PKeyError) {
|
||
|
+ # DSA key pair cannot be generated without parameters
|
||
|
+ OpenSSL::PKey.generate_key("DSA")
|
||
|
+ }
|
||
|
+ pkey_params = OpenSSL::PKey.generate_parameters("DSA", {
|
||
|
+ "dsa_paramgen_bits" => 512,
|
||
|
+ "dsa_paramgen_q_bits" => 256,
|
||
|
+ })
|
||
|
+ pkey = OpenSSL::PKey.generate_key(pkey_params)
|
||
|
+ assert_instance_of OpenSSL::PKey::DSA, pkey
|
||
|
+ assert_equal 512, pkey.p.num_bits
|
||
|
+ assert_not_equal nil, pkey.priv_key
|
||
|
+ end
|
||
|
end
|
||
|
--
|
||
|
2.32.0
|
||
|
|
||
|
|
||
|
From 5713605e70c96e3215aab0e0341548af29b5088e Mon Sep 17 00:00:00 2001
|
||
|
From: Kazuki Yamaguchi <k@rhe.jp>
|
||
|
Date: Mon, 15 May 2017 23:47:47 +0900
|
||
|
Subject: [PATCH 3/6] pkey: port PKey::PKey#sign and #verify to the EVP_Digest*
|
||
|
interface
|
||
|
|
||
|
Use EVP_DigestSign*() and EVP_DigestVerify*() interface instead of the
|
||
|
old EVP_Sign*() and EVP_Verify*() functions. They were added in OpenSSL
|
||
|
1.0.0.
|
||
|
|
||
|
Also, allow the digest to be specified as nil, as certain EVP_PKEY types
|
||
|
don't expect a digest algorithm.
|
||
|
---
|
||
|
ext/openssl/ossl_pkey.c | 90 ++++++++++++++++++++++-----------------
|
||
|
test/openssl/test_pkey.rb | 12 ++++++
|
||
|
2 files changed, 63 insertions(+), 39 deletions(-)
|
||
|
|
||
|
diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c
|
||
|
index 1f3dd39b9b..a0d73f5821 100644
|
||
|
--- a/ext/openssl/ossl_pkey.c
|
||
|
+++ b/ext/openssl/ossl_pkey.c
|
||
|
@@ -753,35 +753,47 @@ static VALUE
|
||
|
ossl_pkey_sign(VALUE self, VALUE digest, VALUE data)
|
||
|
{
|
||
|
EVP_PKEY *pkey;
|
||
|
- const EVP_MD *md;
|
||
|
+ const EVP_MD *md = NULL;
|
||
|
EVP_MD_CTX *ctx;
|
||
|
- unsigned int buf_len;
|
||
|
- VALUE str;
|
||
|
- int result;
|
||
|
+ size_t siglen;
|
||
|
+ int state;
|
||
|
+ VALUE sig;
|
||
|
|
||
|
pkey = GetPrivPKeyPtr(self);
|
||
|
- md = ossl_evp_get_digestbyname(digest);
|
||
|
+ if (!NIL_P(digest))
|
||
|
+ md = ossl_evp_get_digestbyname(digest);
|
||
|
StringValue(data);
|
||
|
- str = rb_str_new(0, EVP_PKEY_size(pkey));
|
||
|
|
||
|
ctx = EVP_MD_CTX_new();
|
||
|
if (!ctx)
|
||
|
- ossl_raise(ePKeyError, "EVP_MD_CTX_new");
|
||
|
- if (!EVP_SignInit_ex(ctx, md, NULL)) {
|
||
|
- EVP_MD_CTX_free(ctx);
|
||
|
- ossl_raise(ePKeyError, "EVP_SignInit_ex");
|
||
|
+ ossl_raise(ePKeyError, "EVP_MD_CTX_new");
|
||
|
+ if (EVP_DigestSignInit(ctx, NULL, md, /* engine */NULL, pkey) < 1) {
|
||
|
+ EVP_MD_CTX_free(ctx);
|
||
|
+ ossl_raise(ePKeyError, "EVP_DigestSignInit");
|
||
|
+ }
|
||
|
+ if (EVP_DigestSignUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data)) < 1) {
|
||
|
+ EVP_MD_CTX_free(ctx);
|
||
|
+ ossl_raise(ePKeyError, "EVP_DigestSignUpdate");
|
||
|
+ }
|
||
|
+ if (EVP_DigestSignFinal(ctx, NULL, &siglen) < 1) {
|
||
|
+ EVP_MD_CTX_free(ctx);
|
||
|
+ ossl_raise(ePKeyError, "EVP_DigestSignFinal");
|
||
|
}
|
||
|
- if (!EVP_SignUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data))) {
|
||
|
- EVP_MD_CTX_free(ctx);
|
||
|
- ossl_raise(ePKeyError, "EVP_SignUpdate");
|
||
|
+ if (siglen > LONG_MAX)
|
||
|
+ rb_raise(ePKeyError, "signature would be too large");
|
||
|
+ sig = ossl_str_new(NULL, (long)siglen, &state);
|
||
|
+ if (state) {
|
||
|
+ EVP_MD_CTX_free(ctx);
|
||
|
+ rb_jump_tag(state);
|
||
|
+ }
|
||
|
+ if (EVP_DigestSignFinal(ctx, (unsigned char *)RSTRING_PTR(sig),
|
||
|
+ &siglen) < 1) {
|
||
|
+ EVP_MD_CTX_free(ctx);
|
||
|
+ ossl_raise(ePKeyError, "EVP_DigestSignFinal");
|
||
|
}
|
||
|
- result = EVP_SignFinal(ctx, (unsigned char *)RSTRING_PTR(str), &buf_len, pkey);
|
||
|
EVP_MD_CTX_free(ctx);
|
||
|
- if (!result)
|
||
|
- ossl_raise(ePKeyError, "EVP_SignFinal");
|
||
|
- rb_str_set_len(str, buf_len);
|
||
|
-
|
||
|
- return str;
|
||
|
+ rb_str_set_len(sig, siglen);
|
||
|
+ return sig;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
@@ -809,38 +821,38 @@ static VALUE
|
||
|
ossl_pkey_verify(VALUE self, VALUE digest, VALUE sig, VALUE data)
|
||
|
{
|
||
|
EVP_PKEY *pkey;
|
||
|
- const EVP_MD *md;
|
||
|
+ const EVP_MD *md = NULL;
|
||
|
EVP_MD_CTX *ctx;
|
||
|
- int siglen, result;
|
||
|
+ int ret;
|
||
|
|
||
|
GetPKey(self, pkey);
|
||
|
ossl_pkey_check_public_key(pkey);
|
||
|
- md = ossl_evp_get_digestbyname(digest);
|
||
|
+ if (!NIL_P(digest))
|
||
|
+ md = ossl_evp_get_digestbyname(digest);
|
||
|
StringValue(sig);
|
||
|
- siglen = RSTRING_LENINT(sig);
|
||
|
StringValue(data);
|
||
|
|
||
|
ctx = EVP_MD_CTX_new();
|
||
|
if (!ctx)
|
||
|
- ossl_raise(ePKeyError, "EVP_MD_CTX_new");
|
||
|
- if (!EVP_VerifyInit_ex(ctx, md, NULL)) {
|
||
|
- EVP_MD_CTX_free(ctx);
|
||
|
- ossl_raise(ePKeyError, "EVP_VerifyInit_ex");
|
||
|
+ ossl_raise(ePKeyError, "EVP_MD_CTX_new");
|
||
|
+ if (EVP_DigestVerifyInit(ctx, NULL, md, /* engine */NULL, pkey) < 1) {
|
||
|
+ EVP_MD_CTX_free(ctx);
|
||
|
+ ossl_raise(ePKeyError, "EVP_DigestVerifyInit");
|
||
|
}
|
||
|
- if (!EVP_VerifyUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data))) {
|
||
|
- EVP_MD_CTX_free(ctx);
|
||
|
- ossl_raise(ePKeyError, "EVP_VerifyUpdate");
|
||
|
+ if (EVP_DigestVerifyUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data)) < 1) {
|
||
|
+ EVP_MD_CTX_free(ctx);
|
||
|
+ ossl_raise(ePKeyError, "EVP_DigestVerifyUpdate");
|
||
|
}
|
||
|
- result = EVP_VerifyFinal(ctx, (unsigned char *)RSTRING_PTR(sig), siglen, pkey);
|
||
|
+ ret = EVP_DigestVerifyFinal(ctx, (unsigned char *)RSTRING_PTR(sig),
|
||
|
+ RSTRING_LEN(sig));
|
||
|
EVP_MD_CTX_free(ctx);
|
||
|
- switch (result) {
|
||
|
- case 0:
|
||
|
- ossl_clear_error();
|
||
|
- return Qfalse;
|
||
|
- case 1:
|
||
|
- return Qtrue;
|
||
|
- default:
|
||
|
- ossl_raise(ePKeyError, "EVP_VerifyFinal");
|
||
|
+ if (ret < 0)
|
||
|
+ ossl_raise(ePKeyError, "EVP_DigestVerifyFinal");
|
||
|
+ if (ret)
|
||
|
+ return Qtrue;
|
||
|
+ else {
|
||
|
+ ossl_clear_error();
|
||
|
+ return Qfalse;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
diff --git a/test/openssl/test_pkey.rb b/test/openssl/test_pkey.rb
|
||
|
index a325a1ea2b..247ba84f83 100644
|
||
|
--- a/test/openssl/test_pkey.rb
|
||
|
+++ b/test/openssl/test_pkey.rb
|
||
|
@@ -68,4 +68,16 @@ def test_s_generate_key
|
||
|
assert_equal 512, pkey.p.num_bits
|
||
|
assert_not_equal nil, pkey.priv_key
|
||
|
end
|
||
|
+
|
||
|
+ def test_hmac_sign_verify
|
||
|
+ pkey = OpenSSL::PKey.generate_key("HMAC", { "key" => "abcd" })
|
||
|
+
|
||
|
+ hmac = OpenSSL::HMAC.new("abcd", "SHA256").update("data").digest
|
||
|
+ assert_equal hmac, pkey.sign("SHA256", "data")
|
||
|
+
|
||
|
+ # EVP_PKEY_HMAC does not support verify
|
||
|
+ assert_raise(OpenSSL::PKey::PKeyError) {
|
||
|
+ pkey.verify("SHA256", "data", hmac)
|
||
|
+ }
|
||
|
+ end
|
||
|
end
|
||
|
--
|
||
|
2.32.0
|
||
|
|
||
|
|
||
|
From 76566a2e1bab42a2e1587ecbec23779ee00020fc Mon Sep 17 00:00:00 2001
|
||
|
From: Kazuki Yamaguchi <k@rhe.jp>
|
||
|
Date: Mon, 15 May 2017 23:47:47 +0900
|
||
|
Subject: [PATCH 4/6] pkey: support 'one-shot' signing and verification
|
||
|
|
||
|
OpenSSL 1.1.1 added EVP_DigestSign() and EVP_DigestVerify() functions
|
||
|
to the interface. Some EVP_PKEY methods such as PureEdDSA algorithms
|
||
|
do not support the streaming mechanism and require us to use them.
|
||
|
---
|
||
|
ext/openssl/ossl_pkey.c | 30 ++++++++++++++++++++++++++
|
||
|
test/openssl/test_pkey.rb | 45 +++++++++++++++++++++++++++++++++++++++
|
||
|
2 files changed, 75 insertions(+)
|
||
|
|
||
|
diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c
|
||
|
index a0d73f5821..19544ec7f0 100644
|
||
|
--- a/ext/openssl/ossl_pkey.c
|
||
|
+++ b/ext/openssl/ossl_pkey.c
|
||
|
@@ -771,6 +771,26 @@ ossl_pkey_sign(VALUE self, VALUE digest, VALUE data)
|
||
|
EVP_MD_CTX_free(ctx);
|
||
|
ossl_raise(ePKeyError, "EVP_DigestSignInit");
|
||
|
}
|
||
|
+#if OPENSSL_VERSION_NUMBER >= 0x10101000 && !defined(LIBRESSL_VERSION_NUMBER)
|
||
|
+ if (EVP_DigestSign(ctx, NULL, &siglen, (unsigned char *)RSTRING_PTR(data),
|
||
|
+ RSTRING_LEN(data)) < 1) {
|
||
|
+ EVP_MD_CTX_free(ctx);
|
||
|
+ ossl_raise(ePKeyError, "EVP_DigestSign");
|
||
|
+ }
|
||
|
+ if (siglen > LONG_MAX)
|
||
|
+ rb_raise(ePKeyError, "signature would be too large");
|
||
|
+ sig = ossl_str_new(NULL, (long)siglen, &state);
|
||
|
+ if (state) {
|
||
|
+ EVP_MD_CTX_free(ctx);
|
||
|
+ rb_jump_tag(state);
|
||
|
+ }
|
||
|
+ if (EVP_DigestSign(ctx, (unsigned char *)RSTRING_PTR(sig), &siglen,
|
||
|
+ (unsigned char *)RSTRING_PTR(data),
|
||
|
+ RSTRING_LEN(data)) < 1) {
|
||
|
+ EVP_MD_CTX_free(ctx);
|
||
|
+ ossl_raise(ePKeyError, "EVP_DigestSign");
|
||
|
+ }
|
||
|
+#else
|
||
|
if (EVP_DigestSignUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data)) < 1) {
|
||
|
EVP_MD_CTX_free(ctx);
|
||
|
ossl_raise(ePKeyError, "EVP_DigestSignUpdate");
|
||
|
@@ -791,6 +811,7 @@ ossl_pkey_sign(VALUE self, VALUE digest, VALUE data)
|
||
|
EVP_MD_CTX_free(ctx);
|
||
|
ossl_raise(ePKeyError, "EVP_DigestSignFinal");
|
||
|
}
|
||
|
+#endif
|
||
|
EVP_MD_CTX_free(ctx);
|
||
|
rb_str_set_len(sig, siglen);
|
||
|
return sig;
|
||
|
@@ -839,6 +860,14 @@ ossl_pkey_verify(VALUE self, VALUE digest, VALUE sig, VALUE data)
|
||
|
EVP_MD_CTX_free(ctx);
|
||
|
ossl_raise(ePKeyError, "EVP_DigestVerifyInit");
|
||
|
}
|
||
|
+#if OPENSSL_VERSION_NUMBER >= 0x10101000 && !defined(LIBRESSL_VERSION_NUMBER)
|
||
|
+ ret = EVP_DigestVerify(ctx, (unsigned char *)RSTRING_PTR(sig),
|
||
|
+ RSTRING_LEN(sig), (unsigned char *)RSTRING_PTR(data),
|
||
|
+ RSTRING_LEN(data));
|
||
|
+ EVP_MD_CTX_free(ctx);
|
||
|
+ if (ret < 0)
|
||
|
+ ossl_raise(ePKeyError, "EVP_DigestVerify");
|
||
|
+#else
|
||
|
if (EVP_DigestVerifyUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data)) < 1) {
|
||
|
EVP_MD_CTX_free(ctx);
|
||
|
ossl_raise(ePKeyError, "EVP_DigestVerifyUpdate");
|
||
|
@@ -848,6 +877,7 @@ ossl_pkey_verify(VALUE self, VALUE digest, VALUE sig, VALUE data)
|
||
|
EVP_MD_CTX_free(ctx);
|
||
|
if (ret < 0)
|
||
|
ossl_raise(ePKeyError, "EVP_DigestVerifyFinal");
|
||
|
+#endif
|
||
|
if (ret)
|
||
|
return Qtrue;
|
||
|
else {
|
||
|
diff --git a/test/openssl/test_pkey.rb b/test/openssl/test_pkey.rb
|
||
|
index 247ba84f83..d811b9c75f 100644
|
||
|
--- a/test/openssl/test_pkey.rb
|
||
|
+++ b/test/openssl/test_pkey.rb
|
||
|
@@ -80,4 +80,49 @@ def test_hmac_sign_verify
|
||
|
pkey.verify("SHA256", "data", hmac)
|
||
|
}
|
||
|
end
|
||
|
+
|
||
|
+ def test_ed25519
|
||
|
+ # Test vector from RFC 8032 Section 7.1 TEST 2
|
||
|
+ priv_pem = <<~EOF
|
||
|
+ -----BEGIN PRIVATE KEY-----
|
||
|
+ MC4CAQAwBQYDK2VwBCIEIEzNCJso/5banbbDRuwRTg9bijGfNaumJNqM9u1PuKb7
|
||
|
+ -----END PRIVATE KEY-----
|
||
|
+ EOF
|
||
|
+ pub_pem = <<~EOF
|
||
|
+ -----BEGIN PUBLIC KEY-----
|
||
|
+ MCowBQYDK2VwAyEAPUAXw+hDiVqStwqnTRt+vJyYLM8uxJaMwM1V8Sr0Zgw=
|
||
|
+ -----END PUBLIC KEY-----
|
||
|
+ EOF
|
||
|
+ begin
|
||
|
+ priv = OpenSSL::PKey.read(priv_pem)
|
||
|
+ pub = OpenSSL::PKey.read(pub_pem)
|
||
|
+ rescue OpenSSL::PKey::PKeyError
|
||
|
+ # OpenSSL < 1.1.1
|
||
|
+ pend "Ed25519 is not implemented"
|
||
|
+ end
|
||
|
+ assert_instance_of OpenSSL::PKey::PKey, priv
|
||
|
+ assert_instance_of OpenSSL::PKey::PKey, pub
|
||
|
+ assert_equal priv_pem, priv.private_to_pem
|
||
|
+ assert_equal pub_pem, priv.public_to_pem
|
||
|
+ assert_equal pub_pem, pub.public_to_pem
|
||
|
+
|
||
|
+ sig = [<<~EOF.gsub(/[^0-9a-f]/, "")].pack("H*")
|
||
|
+ 92a009a9f0d4cab8720e820b5f642540
|
||
|
+ a2b27b5416503f8fb3762223ebdb69da
|
||
|
+ 085ac1e43e15996e458f3613d0f11d8c
|
||
|
+ 387b2eaeb4302aeeb00d291612bb0c00
|
||
|
+ EOF
|
||
|
+ data = ["72"].pack("H*")
|
||
|
+ assert_equal sig, priv.sign(nil, data)
|
||
|
+ assert_equal true, priv.verify(nil, sig, data)
|
||
|
+ assert_equal true, pub.verify(nil, sig, data)
|
||
|
+ assert_equal false, pub.verify(nil, sig, data.succ)
|
||
|
+
|
||
|
+ # PureEdDSA wants nil as the message digest
|
||
|
+ assert_raise(OpenSSL::PKey::PKeyError) { priv.sign("SHA512", data) }
|
||
|
+ assert_raise(OpenSSL::PKey::PKeyError) { pub.verify("SHA512", sig, data) }
|
||
|
+
|
||
|
+ # Ed25519 pkey type does not support key derivation
|
||
|
+ assert_raise(OpenSSL::PKey::PKeyError) { priv.derive(pub) }
|
||
|
+ end
|
||
|
end
|
||
|
--
|
||
|
2.32.0
|
||
|
|
||
|
|
||
|
From fabdd22bddc572ba3342ec0b09e3fef8ed6245b8 Mon Sep 17 00:00:00 2001
|
||
|
From: Kazuki Yamaguchi <k@rhe.jp>
|
||
|
Date: Sat, 18 Mar 2017 21:58:46 +0900
|
||
|
Subject: [PATCH 5/6] pkey: add PKey::PKey#derive
|
||
|
|
||
|
Add OpenSSL::PKey::PKey#derive as the wrapper for EVP_PKEY_CTX_derive().
|
||
|
This is useful for pkey types that we don't have dedicated classes, such
|
||
|
as X25519.
|
||
|
---
|
||
|
ext/openssl/ossl_pkey.c | 52 ++++++++++++++++++++++++++++++++++++
|
||
|
test/openssl/test_pkey.rb | 26 ++++++++++++++++++
|
||
|
test/openssl/test_pkey_dh.rb | 13 +++++++++
|
||
|
test/openssl/test_pkey_ec.rb | 16 +++++++++++
|
||
|
4 files changed, 107 insertions(+)
|
||
|
|
||
|
diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c
|
||
|
index 19544ec7f0..df8b425a0f 100644
|
||
|
--- a/ext/openssl/ossl_pkey.c
|
||
|
+++ b/ext/openssl/ossl_pkey.c
|
||
|
@@ -886,6 +886,57 @@ ossl_pkey_verify(VALUE self, VALUE digest, VALUE sig, VALUE data)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
+/*
|
||
|
+ * call-seq:
|
||
|
+ * pkey.derive(peer_pkey) -> string
|
||
|
+ *
|
||
|
+ * Derives a shared secret from _pkey_ and _peer_pkey_. _pkey_ must contain
|
||
|
+ * the private components, _peer_pkey_ must contain the public components.
|
||
|
+ */
|
||
|
+static VALUE
|
||
|
+ossl_pkey_derive(int argc, VALUE *argv, VALUE self)
|
||
|
+{
|
||
|
+ EVP_PKEY *pkey, *peer_pkey;
|
||
|
+ EVP_PKEY_CTX *ctx;
|
||
|
+ VALUE peer_pkey_obj, str;
|
||
|
+ size_t keylen;
|
||
|
+ int state;
|
||
|
+
|
||
|
+ GetPKey(self, pkey);
|
||
|
+ rb_scan_args(argc, argv, "1", &peer_pkey_obj);
|
||
|
+ GetPKey(peer_pkey_obj, peer_pkey);
|
||
|
+
|
||
|
+ ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);
|
||
|
+ if (!ctx)
|
||
|
+ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new");
|
||
|
+ if (EVP_PKEY_derive_init(ctx) <= 0) {
|
||
|
+ EVP_PKEY_CTX_free(ctx);
|
||
|
+ ossl_raise(ePKeyError, "EVP_PKEY_derive_init");
|
||
|
+ }
|
||
|
+ if (EVP_PKEY_derive_set_peer(ctx, peer_pkey) <= 0) {
|
||
|
+ EVP_PKEY_CTX_free(ctx);
|
||
|
+ ossl_raise(ePKeyError, "EVP_PKEY_derive_set_peer");
|
||
|
+ }
|
||
|
+ if (EVP_PKEY_derive(ctx, NULL, &keylen) <= 0) {
|
||
|
+ EVP_PKEY_CTX_free(ctx);
|
||
|
+ ossl_raise(ePKeyError, "EVP_PKEY_derive");
|
||
|
+ }
|
||
|
+ if (keylen > LONG_MAX)
|
||
|
+ rb_raise(ePKeyError, "derived key would be too large");
|
||
|
+ str = ossl_str_new(NULL, (long)keylen, &state);
|
||
|
+ if (state) {
|
||
|
+ EVP_PKEY_CTX_free(ctx);
|
||
|
+ rb_jump_tag(state);
|
||
|
+ }
|
||
|
+ if (EVP_PKEY_derive(ctx, (unsigned char *)RSTRING_PTR(str), &keylen) <= 0) {
|
||
|
+ EVP_PKEY_CTX_free(ctx);
|
||
|
+ ossl_raise(ePKeyError, "EVP_PKEY_derive");
|
||
|
+ }
|
||
|
+ EVP_PKEY_CTX_free(ctx);
|
||
|
+ rb_str_set_len(str, keylen);
|
||
|
+ return str;
|
||
|
+}
|
||
|
+
|
||
|
/*
|
||
|
* INIT
|
||
|
*/
|
||
|
@@ -983,6 +1034,7 @@ Init_ossl_pkey(void)
|
||
|
|
||
|
rb_define_method(cPKey, "sign", ossl_pkey_sign, 2);
|
||
|
rb_define_method(cPKey, "verify", ossl_pkey_verify, 3);
|
||
|
+ rb_define_method(cPKey, "derive", ossl_pkey_derive, -1);
|
||
|
|
||
|
id_private_q = rb_intern("private?");
|
||
|
|
||
|
diff --git a/test/openssl/test_pkey.rb b/test/openssl/test_pkey.rb
|
||
|
index d811b9c75f..5307fe5b08 100644
|
||
|
--- a/test/openssl/test_pkey.rb
|
||
|
+++ b/test/openssl/test_pkey.rb
|
||
|
@@ -125,4 +125,30 @@ def test_ed25519
|
||
|
# Ed25519 pkey type does not support key derivation
|
||
|
assert_raise(OpenSSL::PKey::PKeyError) { priv.derive(pub) }
|
||
|
end
|
||
|
+
|
||
|
+ def test_x25519
|
||
|
+ # Test vector from RFC 7748 Section 6.1
|
||
|
+ alice_pem = <<~EOF
|
||
|
+ -----BEGIN PRIVATE KEY-----
|
||
|
+ MC4CAQAwBQYDK2VuBCIEIHcHbQpzGKV9PBbBclGyZkXfTC+H68CZKrF3+6UduSwq
|
||
|
+ -----END PRIVATE KEY-----
|
||
|
+ EOF
|
||
|
+ bob_pem = <<~EOF
|
||
|
+ -----BEGIN PUBLIC KEY-----
|
||
|
+ MCowBQYDK2VuAyEA3p7bfXt9wbTTW2HC7OQ1Nz+DQ8hbeGdNrfx+FG+IK08=
|
||
|
+ -----END PUBLIC KEY-----
|
||
|
+ EOF
|
||
|
+ shared_secret = "4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742"
|
||
|
+ begin
|
||
|
+ alice = OpenSSL::PKey.read(alice_pem)
|
||
|
+ bob = OpenSSL::PKey.read(bob_pem)
|
||
|
+ rescue OpenSSL::PKey::PKeyError
|
||
|
+ # OpenSSL < 1.1.0
|
||
|
+ pend "X25519 is not implemented"
|
||
|
+ end
|
||
|
+ assert_instance_of OpenSSL::PKey::PKey, alice
|
||
|
+ assert_equal alice_pem, alice.private_to_pem
|
||
|
+ assert_equal bob_pem, bob.public_to_pem
|
||
|
+ assert_equal [shared_secret].pack("H*"), alice.derive(bob)
|
||
|
+ end
|
||
|
end
|
||
|
diff --git a/test/openssl/test_pkey_dh.rb b/test/openssl/test_pkey_dh.rb
|
||
|
index 4a05626a12..9efc3ba68d 100644
|
||
|
--- a/test/openssl/test_pkey_dh.rb
|
||
|
+++ b/test/openssl/test_pkey_dh.rb
|
||
|
@@ -18,6 +18,19 @@ def test_new_break
|
||
|
end
|
||
|
end
|
||
|
|
||
|
+ def test_derive_key
|
||
|
+ dh1 = Fixtures.pkey("dh1024").generate_key!
|
||
|
+ dh2 = Fixtures.pkey("dh1024").generate_key!
|
||
|
+ dh1_pub = OpenSSL::PKey.read(dh1.public_to_der)
|
||
|
+ dh2_pub = OpenSSL::PKey.read(dh2.public_to_der)
|
||
|
+ z = dh1.g.mod_exp(dh1.priv_key, dh1.p).mod_exp(dh2.priv_key, dh1.p).to_s(2)
|
||
|
+ assert_equal z, dh1.derive(dh2_pub)
|
||
|
+ assert_equal z, dh2.derive(dh1_pub)
|
||
|
+
|
||
|
+ assert_equal z, dh1.compute_key(dh2.pub_key)
|
||
|
+ assert_equal z, dh2.compute_key(dh1.pub_key)
|
||
|
+ end
|
||
|
+
|
||
|
def test_DHparams
|
||
|
dh1024 = Fixtures.pkey("dh1024")
|
||
|
asn1 = OpenSSL::ASN1::Sequence([
|
||
|
diff --git a/test/openssl/test_pkey_ec.rb b/test/openssl/test_pkey_ec.rb
|
||
|
index a0e6a23ff8..95d4338a51 100644
|
||
|
--- a/test/openssl/test_pkey_ec.rb
|
||
|
+++ b/test/openssl/test_pkey_ec.rb
|
||
|
@@ -93,6 +93,22 @@ def test_sign_verify
|
||
|
assert_equal false, p256.verify("SHA256", signature1, data)
|
||
|
end
|
||
|
|
||
|
+ def test_derive_key
|
||
|
+ # NIST CAVP, KAS_ECC_CDH_PrimitiveTest.txt, P-256 COUNT = 0
|
||
|
+ qCAVSx = "700c48f77f56584c5cc632ca65640db91b6bacce3a4df6b42ce7cc838833d287"
|
||
|
+ qCAVSy = "db71e509e3fd9b060ddb20ba5c51dcc5948d46fbf640dfe0441782cab85fa4ac"
|
||
|
+ dIUT = "7d7dc5f71eb29ddaf80d6214632eeae03d9058af1fb6d22ed80badb62bc1a534"
|
||
|
+ zIUT = "46fc62106420ff012e54a434fbdd2d25ccc5852060561e68040dd7778997bd7b"
|
||
|
+ a = OpenSSL::PKey::EC.new("prime256v1")
|
||
|
+ a.private_key = OpenSSL::BN.new(dIUT, 16)
|
||
|
+ b = OpenSSL::PKey::EC.new("prime256v1")
|
||
|
+ uncompressed = OpenSSL::BN.new("04" + qCAVSx + qCAVSy, 16)
|
||
|
+ b.public_key = OpenSSL::PKey::EC::Point.new(b.group, uncompressed)
|
||
|
+ assert_equal [zIUT].pack("H*"), a.derive(b)
|
||
|
+
|
||
|
+ assert_equal a.derive(b), a.dh_compute_key(b.public_key)
|
||
|
+ end
|
||
|
+
|
||
|
def test_dsa_sign_verify
|
||
|
data1 = "foo"
|
||
|
data2 = "bar"
|
||
|
--
|
||
|
2.32.0
|
||
|
|
||
|
|
||
|
From 97078c7fa8a724c7c71f9850d31fc401239da228 Mon Sep 17 00:00:00 2001
|
||
|
From: Kazuki Yamaguchi <k@rhe.jp>
|
||
|
Date: Sat, 18 Mar 2017 22:34:19 +0900
|
||
|
Subject: [PATCH 6/6] pkey: reimplement PKey::DH#compute_key and
|
||
|
PKey::EC#dh_compute_key
|
||
|
|
||
|
Use the new OpenSSL::PKey::PKey#derive instead of the raw
|
||
|
{EC,}DH_compute_key(), mainly to reduce amount of the C code.
|
||
|
---
|
||
|
ext/openssl/lib/openssl/pkey.rb | 33 +++++++++++++++++++++++++++++++
|
||
|
ext/openssl/ossl_pkey_dh.c | 35 ---------------------------------
|
||
|
ext/openssl/ossl_pkey_ec.c | 32 ------------------------------
|
||
|
3 files changed, 33 insertions(+), 67 deletions(-)
|
||
|
|
||
|
diff --git a/ext/openssl/lib/openssl/pkey.rb b/ext/openssl/lib/openssl/pkey.rb
|
||
|
index 9cc3276356..be60ac2beb 100644
|
||
|
--- a/ext/openssl/lib/openssl/pkey.rb
|
||
|
+++ b/ext/openssl/lib/openssl/pkey.rb
|
||
|
@@ -9,6 +9,24 @@
|
||
|
module OpenSSL::PKey
|
||
|
class DH
|
||
|
include OpenSSL::Marshal
|
||
|
+
|
||
|
+ # :call-seq:
|
||
|
+ # dh.compute_key(pub_bn) -> string
|
||
|
+ #
|
||
|
+ # Returns a String containing a shared secret computed from the other
|
||
|
+ # party's public value.
|
||
|
+ #
|
||
|
+ # This method is provided for backwards compatibility, and calls #derive
|
||
|
+ # internally.
|
||
|
+ #
|
||
|
+ # === Parameters
|
||
|
+ # * _pub_bn_ is a OpenSSL::BN, *not* the DH instance returned by
|
||
|
+ # DH#public_key as that contains the DH parameters only.
|
||
|
+ def compute_key(pub_bn)
|
||
|
+ peer = dup
|
||
|
+ peer.set_key(pub_bn, nil)
|
||
|
+ derive(peer)
|
||
|
+ end
|
||
|
end
|
||
|
|
||
|
class DSA
|
||
|
@@ -18,7 +36,22 @@ class DSA
|
||
|
if defined?(EC)
|
||
|
class EC
|
||
|
include OpenSSL::Marshal
|
||
|
+
|
||
|
+ # :call-seq:
|
||
|
+ # ec.dh_compute_key(pubkey) -> string
|
||
|
+ #
|
||
|
+ # Derives a shared secret by ECDH. _pubkey_ must be an instance of
|
||
|
+ # OpenSSL::PKey::EC::Point and must belong to the same group.
|
||
|
+ #
|
||
|
+ # This method is provided for backwards compatibility, and calls #derive
|
||
|
+ # internally.
|
||
|
+ def dh_compute_key(pubkey)
|
||
|
+ peer = OpenSSL::PKey::EC.new(group)
|
||
|
+ peer.public_key = pubkey
|
||
|
+ derive(peer)
|
||
|
+ end
|
||
|
end
|
||
|
+
|
||
|
class EC::Point
|
||
|
# :call-seq:
|
||
|
# point.to_bn([conversion_form]) -> OpenSSL::BN
|
||
|
diff --git a/ext/openssl/ossl_pkey_dh.c b/ext/openssl/ossl_pkey_dh.c
|
||
|
index bc50e5566b..5bc1c49ca1 100644
|
||
|
--- a/ext/openssl/ossl_pkey_dh.c
|
||
|
+++ b/ext/openssl/ossl_pkey_dh.c
|
||
|
@@ -476,40 +476,6 @@ ossl_dh_generate_key(VALUE self)
|
||
|
return self;
|
||
|
}
|
||
|
|
||
|
-/*
|
||
|
- * call-seq:
|
||
|
- * dh.compute_key(pub_bn) -> aString
|
||
|
- *
|
||
|
- * Returns a String containing a shared secret computed from the other party's public value.
|
||
|
- * See DH_compute_key() for further information.
|
||
|
- *
|
||
|
- * === Parameters
|
||
|
- * * _pub_bn_ is a OpenSSL::BN, *not* the DH instance returned by
|
||
|
- * DH#public_key as that contains the DH parameters only.
|
||
|
- */
|
||
|
-static VALUE
|
||
|
-ossl_dh_compute_key(VALUE self, VALUE pub)
|
||
|
-{
|
||
|
- DH *dh;
|
||
|
- const BIGNUM *pub_key, *dh_p;
|
||
|
- VALUE str;
|
||
|
- int len;
|
||
|
-
|
||
|
- GetDH(self, dh);
|
||
|
- DH_get0_pqg(dh, &dh_p, NULL, NULL);
|
||
|
- if (!dh_p)
|
||
|
- ossl_raise(eDHError, "incomplete DH");
|
||
|
- pub_key = GetBNPtr(pub);
|
||
|
- len = DH_size(dh);
|
||
|
- str = rb_str_new(0, len);
|
||
|
- if ((len = DH_compute_key((unsigned char *)RSTRING_PTR(str), pub_key, dh)) < 0) {
|
||
|
- ossl_raise(eDHError, NULL);
|
||
|
- }
|
||
|
- rb_str_set_len(str, len);
|
||
|
-
|
||
|
- return str;
|
||
|
-}
|
||
|
-
|
||
|
/*
|
||
|
* Document-method: OpenSSL::PKey::DH#set_pqg
|
||
|
* call-seq:
|
||
|
@@ -587,7 +553,6 @@ Init_ossl_dh(void)
|
||
|
rb_define_method(cDH, "public_key", ossl_dh_to_public_key, 0);
|
||
|
rb_define_method(cDH, "params_ok?", ossl_dh_check_params, 0);
|
||
|
rb_define_method(cDH, "generate_key!", ossl_dh_generate_key, 0);
|
||
|
- rb_define_method(cDH, "compute_key", ossl_dh_compute_key, 1);
|
||
|
|
||
|
DEF_OSSL_PKEY_BN(cDH, dh, p);
|
||
|
DEF_OSSL_PKEY_BN(cDH, dh, q);
|
||
|
diff --git a/ext/openssl/ossl_pkey_ec.c b/ext/openssl/ossl_pkey_ec.c
|
||
|
index 6fe2533e2a..c2534251c3 100644
|
||
|
--- a/ext/openssl/ossl_pkey_ec.c
|
||
|
+++ b/ext/openssl/ossl_pkey_ec.c
|
||
|
@@ -487,37 +487,6 @@ static VALUE ossl_ec_key_check_key(VALUE self)
|
||
|
return Qtrue;
|
||
|
}
|
||
|
|
||
|
-/*
|
||
|
- * call-seq:
|
||
|
- * key.dh_compute_key(pubkey) => String
|
||
|
- *
|
||
|
- * See the OpenSSL documentation for ECDH_compute_key()
|
||
|
- */
|
||
|
-static VALUE ossl_ec_key_dh_compute_key(VALUE self, VALUE pubkey)
|
||
|
-{
|
||
|
- EC_KEY *ec;
|
||
|
- EC_POINT *point;
|
||
|
- int buf_len;
|
||
|
- VALUE str;
|
||
|
-
|
||
|
- GetEC(self, ec);
|
||
|
- GetECPoint(pubkey, point);
|
||
|
-
|
||
|
-/* BUG: need a way to figure out the maximum string size */
|
||
|
- buf_len = 1024;
|
||
|
- str = rb_str_new(0, buf_len);
|
||
|
-/* BUG: take KDF as a block */
|
||
|
- buf_len = ECDH_compute_key(RSTRING_PTR(str), buf_len, point, ec, NULL);
|
||
|
- if (buf_len < 0)
|
||
|
- ossl_raise(eECError, "ECDH_compute_key");
|
||
|
-
|
||
|
- rb_str_resize(str, buf_len);
|
||
|
-
|
||
|
- return str;
|
||
|
-}
|
||
|
-
|
||
|
-/* sign_setup */
|
||
|
-
|
||
|
/*
|
||
|
* call-seq:
|
||
|
* key.dsa_sign_asn1(data) => String
|
||
|
@@ -1657,7 +1626,6 @@ void Init_ossl_ec(void)
|
||
|
rb_define_alias(cEC, "generate_key", "generate_key!");
|
||
|
rb_define_method(cEC, "check_key", ossl_ec_key_check_key, 0);
|
||
|
|
||
|
- rb_define_method(cEC, "dh_compute_key", ossl_ec_key_dh_compute_key, 1);
|
||
|
rb_define_method(cEC, "dsa_sign_asn1", ossl_ec_key_dsa_sign_asn1, 1);
|
||
|
rb_define_method(cEC, "dsa_verify_asn1", ossl_ec_key_dsa_verify_asn1, 2);
|
||
|
/* do_sign/do_verify */
|
||
|
--
|
||
|
2.32.0
|
||
|
|