You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1319 lines
43 KiB
1319 lines
43 KiB
From 3e6cd88c621d8834712d2279f925b9af83c2bb34 Mon Sep 17 00:00:00 2001 |
|
From: Kazuki Yamaguchi <k@rhe.jp> |
|
Date: Mon, 18 May 2020 20:06:16 +0900 |
|
Subject: [PATCH 1/6] pkey: implement PKey#encrypt and #decrypt |
|
|
|
Support public key encryption and decryption operations using the EVP |
|
API. |
|
--- |
|
ext/openssl/ossl_pkey.c | 141 ++++++++++++++++++++++++++++++++++ |
|
test/openssl/test_pkey_rsa.rb | 34 ++++++++ |
|
2 files changed, 175 insertions(+) |
|
|
|
diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c |
|
index 21cd4b2cda..baf8ce9f20 100644 |
|
--- a/ext/openssl/ossl_pkey.c |
|
+++ b/ext/openssl/ossl_pkey.c |
|
@@ -986,6 +986,145 @@ ossl_pkey_derive(int argc, VALUE *argv, VALUE self) |
|
return str; |
|
} |
|
|
|
+/* |
|
+ * call-seq: |
|
+ * pkey.encrypt(data [, options]) -> string |
|
+ * |
|
+ * Performs a public key encryption operation using +pkey+. |
|
+ * |
|
+ * See #decrypt for the reverse operation. |
|
+ * |
|
+ * Added in version 3.0. See also the man page EVP_PKEY_encrypt(3). |
|
+ * |
|
+ * +data+:: |
|
+ * A String to be encrypted. |
|
+ * +options+:: |
|
+ * A Hash that contains algorithm specific control operations to \OpenSSL. |
|
+ * See OpenSSL's man page EVP_PKEY_CTX_ctrl_str(3) for details. |
|
+ * |
|
+ * Example: |
|
+ * pkey = OpenSSL::PKey.generate_key("RSA", rsa_keygen_bits: 2048) |
|
+ * data = "secret data" |
|
+ * encrypted = pkey.encrypt(data, rsa_padding_mode: "oaep") |
|
+ * decrypted = pkey.decrypt(data, rsa_padding_mode: "oaep") |
|
+ * p decrypted #=> "secret data" |
|
+ */ |
|
+static VALUE |
|
+ossl_pkey_encrypt(int argc, VALUE *argv, VALUE self) |
|
+{ |
|
+ EVP_PKEY *pkey; |
|
+ EVP_PKEY_CTX *ctx; |
|
+ VALUE data, options, str; |
|
+ size_t outlen; |
|
+ int state; |
|
+ |
|
+ GetPKey(self, pkey); |
|
+ rb_scan_args(argc, argv, "11", &data, &options); |
|
+ StringValue(data); |
|
+ |
|
+ ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL); |
|
+ if (!ctx) |
|
+ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new"); |
|
+ if (EVP_PKEY_encrypt_init(ctx) <= 0) { |
|
+ EVP_PKEY_CTX_free(ctx); |
|
+ ossl_raise(ePKeyError, "EVP_PKEY_encrypt_init"); |
|
+ } |
|
+ if (!NIL_P(options)) { |
|
+ pkey_ctx_apply_options(ctx, options, &state); |
|
+ if (state) { |
|
+ EVP_PKEY_CTX_free(ctx); |
|
+ rb_jump_tag(state); |
|
+ } |
|
+ } |
|
+ if (EVP_PKEY_encrypt(ctx, NULL, &outlen, |
|
+ (unsigned char *)RSTRING_PTR(data), |
|
+ RSTRING_LEN(data)) <= 0) { |
|
+ EVP_PKEY_CTX_free(ctx); |
|
+ ossl_raise(ePKeyError, "EVP_PKEY_encrypt"); |
|
+ } |
|
+ if (outlen > LONG_MAX) { |
|
+ EVP_PKEY_CTX_free(ctx); |
|
+ rb_raise(ePKeyError, "encrypted data would be too large"); |
|
+ } |
|
+ str = ossl_str_new(NULL, (long)outlen, &state); |
|
+ if (state) { |
|
+ EVP_PKEY_CTX_free(ctx); |
|
+ rb_jump_tag(state); |
|
+ } |
|
+ if (EVP_PKEY_encrypt(ctx, (unsigned char *)RSTRING_PTR(str), &outlen, |
|
+ (unsigned char *)RSTRING_PTR(data), |
|
+ RSTRING_LEN(data)) <= 0) { |
|
+ EVP_PKEY_CTX_free(ctx); |
|
+ ossl_raise(ePKeyError, "EVP_PKEY_encrypt"); |
|
+ } |
|
+ EVP_PKEY_CTX_free(ctx); |
|
+ rb_str_set_len(str, outlen); |
|
+ return str; |
|
+} |
|
+ |
|
+/* |
|
+ * call-seq: |
|
+ * pkey.decrypt(data [, options]) -> string |
|
+ * |
|
+ * Performs a public key decryption operation using +pkey+. |
|
+ * |
|
+ * See #encrypt for a description of the parameters and an example. |
|
+ * |
|
+ * Added in version 3.0. See also the man page EVP_PKEY_decrypt(3). |
|
+ */ |
|
+static VALUE |
|
+ossl_pkey_decrypt(int argc, VALUE *argv, VALUE self) |
|
+{ |
|
+ EVP_PKEY *pkey; |
|
+ EVP_PKEY_CTX *ctx; |
|
+ VALUE data, options, str; |
|
+ size_t outlen; |
|
+ int state; |
|
+ |
|
+ GetPKey(self, pkey); |
|
+ rb_scan_args(argc, argv, "11", &data, &options); |
|
+ StringValue(data); |
|
+ |
|
+ ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL); |
|
+ if (!ctx) |
|
+ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new"); |
|
+ if (EVP_PKEY_decrypt_init(ctx) <= 0) { |
|
+ EVP_PKEY_CTX_free(ctx); |
|
+ ossl_raise(ePKeyError, "EVP_PKEY_decrypt_init"); |
|
+ } |
|
+ if (!NIL_P(options)) { |
|
+ pkey_ctx_apply_options(ctx, options, &state); |
|
+ if (state) { |
|
+ EVP_PKEY_CTX_free(ctx); |
|
+ rb_jump_tag(state); |
|
+ } |
|
+ } |
|
+ if (EVP_PKEY_decrypt(ctx, NULL, &outlen, |
|
+ (unsigned char *)RSTRING_PTR(data), |
|
+ RSTRING_LEN(data)) <= 0) { |
|
+ EVP_PKEY_CTX_free(ctx); |
|
+ ossl_raise(ePKeyError, "EVP_PKEY_decrypt"); |
|
+ } |
|
+ if (outlen > LONG_MAX) { |
|
+ EVP_PKEY_CTX_free(ctx); |
|
+ rb_raise(ePKeyError, "decrypted data would be too large"); |
|
+ } |
|
+ str = ossl_str_new(NULL, (long)outlen, &state); |
|
+ if (state) { |
|
+ EVP_PKEY_CTX_free(ctx); |
|
+ rb_jump_tag(state); |
|
+ } |
|
+ if (EVP_PKEY_decrypt(ctx, (unsigned char *)RSTRING_PTR(str), &outlen, |
|
+ (unsigned char *)RSTRING_PTR(data), |
|
+ RSTRING_LEN(data)) <= 0) { |
|
+ EVP_PKEY_CTX_free(ctx); |
|
+ ossl_raise(ePKeyError, "EVP_PKEY_decrypt"); |
|
+ } |
|
+ EVP_PKEY_CTX_free(ctx); |
|
+ rb_str_set_len(str, outlen); |
|
+ return str; |
|
+} |
|
+ |
|
/* |
|
* INIT |
|
*/ |
|
@@ -1085,6 +1224,8 @@ Init_ossl_pkey(void) |
|
rb_define_method(cPKey, "sign", ossl_pkey_sign, -1); |
|
rb_define_method(cPKey, "verify", ossl_pkey_verify, -1); |
|
rb_define_method(cPKey, "derive", ossl_pkey_derive, -1); |
|
+ rb_define_method(cPKey, "encrypt", ossl_pkey_encrypt, -1); |
|
+ rb_define_method(cPKey, "decrypt", ossl_pkey_decrypt, -1); |
|
|
|
id_private_q = rb_intern("private?"); |
|
|
|
diff --git a/test/openssl/test_pkey_rsa.rb b/test/openssl/test_pkey_rsa.rb |
|
index 5f8d04e754..d6bfca3ac5 100644 |
|
--- a/test/openssl/test_pkey_rsa.rb |
|
+++ b/test/openssl/test_pkey_rsa.rb |
|
@@ -173,6 +173,40 @@ def test_sign_verify_pss |
|
} |
|
end |
|
|
|
+ def test_encrypt_decrypt |
|
+ rsapriv = Fixtures.pkey("rsa-1") |
|
+ rsapub = dup_public(rsapriv) |
|
+ |
|
+ # Defaults to PKCS #1 v1.5 |
|
+ raw = "data" |
|
+ enc = rsapub.encrypt(raw) |
|
+ assert_equal raw, rsapriv.decrypt(enc) |
|
+ |
|
+ # Invalid options |
|
+ assert_raise(OpenSSL::PKey::PKeyError) { |
|
+ rsapub.encrypt(raw, { "nonexistent" => "option" }) |
|
+ } |
|
+ end |
|
+ |
|
+ def test_encrypt_decrypt_legacy |
|
+ rsapriv = Fixtures.pkey("rsa-1") |
|
+ rsapub = dup_public(rsapriv) |
|
+ |
|
+ # Defaults to PKCS #1 v1.5 |
|
+ raw = "data" |
|
+ enc_legacy = rsapub.public_encrypt(raw) |
|
+ assert_equal raw, rsapriv.decrypt(enc_legacy) |
|
+ enc_new = rsapub.encrypt(raw) |
|
+ assert_equal raw, rsapriv.private_decrypt(enc_new) |
|
+ |
|
+ # OAEP with default parameters |
|
+ raw = "data" |
|
+ enc_legacy = rsapub.public_encrypt(raw, OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING) |
|
+ assert_equal raw, rsapriv.decrypt(enc_legacy, { "rsa_padding_mode" => "oaep" }) |
|
+ enc_new = rsapub.encrypt(raw, { "rsa_padding_mode" => "oaep" }) |
|
+ assert_equal raw, rsapriv.private_decrypt(enc_legacy, OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING) |
|
+ end |
|
+ |
|
def test_export |
|
rsa1024 = Fixtures.pkey("rsa1024") |
|
key = OpenSSL::PKey::RSA.new |
|
-- |
|
2.32.0 |
|
|
|
|
|
From 6f5c75b06967b5b2db1d13646d74310e1cdc563e Mon Sep 17 00:00:00 2001 |
|
From: Kazuki Yamaguchi <k@rhe.jp> |
|
Date: Tue, 25 May 2021 18:43:29 +0900 |
|
Subject: [PATCH 2/6] pkey: update version reference in #sign and #verify |
|
documentation |
|
|
|
The next release is decided to be 3.0 rather than 2.3. |
|
--- |
|
ext/openssl/ossl_pkey.c | 4 ++-- |
|
1 file changed, 2 insertions(+), 2 deletions(-) |
|
|
|
diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c |
|
index baf8ce9f20..d08f6f7e60 100644 |
|
--- a/ext/openssl/ossl_pkey.c |
|
+++ b/ext/openssl/ossl_pkey.c |
|
@@ -761,7 +761,7 @@ ossl_pkey_public_to_pem(VALUE self) |
|
* +options+:: |
|
* A Hash that contains algorithm specific control operations to \OpenSSL. |
|
* See OpenSSL's man page EVP_PKEY_CTX_ctrl_str(3) for details. |
|
- * +options+ parameter was added in version 2.3. |
|
+ * +options+ parameter was added in version 3.0. |
|
* |
|
* Example: |
|
* data = "Sign me!" |
|
@@ -875,7 +875,7 @@ ossl_pkey_sign(int argc, VALUE *argv, VALUE self) |
|
* +data+:: |
|
* See #sign. |
|
* +options+:: |
|
- * See #sign. +options+ parameter was added in version 2.3. |
|
+ * See #sign. +options+ parameter was added in version 3.0. |
|
*/ |
|
static VALUE |
|
ossl_pkey_verify(int argc, VALUE *argv, VALUE self) |
|
-- |
|
2.32.0 |
|
|
|
|
|
From 99fc31a9b4843b7f8923b5ce8b36115b2c66f4db Mon Sep 17 00:00:00 2001 |
|
From: Kazuki Yamaguchi <k@rhe.jp> |
|
Date: Fri, 22 May 2020 16:10:35 +0900 |
|
Subject: [PATCH 3/6] pkey: implement PKey#sign_raw, #verify_raw, and |
|
#verify_recover |
|
|
|
Add a variant of PKey#sign and #verify that do not hash the data |
|
automatically. |
|
|
|
Sometimes the caller has the hashed data only, but not the plaintext |
|
to be signed. In that case, users would have to use the low-level API |
|
such as RSA#private_encrypt or #public_decrypt directly. |
|
|
|
OpenSSL 1.0.0 and later supports EVP_PKEY_sign() and EVP_PKEY_verify() |
|
which provide the same functionality as part of the EVP API. This patch |
|
adds wrappers for them. |
|
--- |
|
ext/openssl/ossl_pkey.c | 232 ++++++++++++++++++++++++++++++++++ |
|
test/openssl/test_pkey_dsa.rb | 25 +++- |
|
test/openssl/test_pkey_ec.rb | 21 ++- |
|
test/openssl/test_pkey_rsa.rb | 78 ++++++++---- |
|
4 files changed, 325 insertions(+), 31 deletions(-) |
|
|
|
diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c |
|
index d08f6f7e60..ba909c7632 100644 |
|
--- a/ext/openssl/ossl_pkey.c |
|
+++ b/ext/openssl/ossl_pkey.c |
|
@@ -935,6 +935,235 @@ ossl_pkey_verify(int argc, VALUE *argv, VALUE self) |
|
} |
|
} |
|
|
|
+/* |
|
+ * call-seq: |
|
+ * pkey.sign_raw(digest, data [, options]) -> string |
|
+ * |
|
+ * Signs +data+ using a private key +pkey+. Unlike #sign, +data+ will not be |
|
+ * hashed by +digest+ automatically. |
|
+ * |
|
+ * See #verify_raw for the verification operation. |
|
+ * |
|
+ * Added in version 3.0. See also the man page EVP_PKEY_sign(3). |
|
+ * |
|
+ * +digest+:: |
|
+ * A String that represents the message digest algorithm name, or +nil+ |
|
+ * if the PKey type requires no digest algorithm. |
|
+ * Although this method will not hash +data+ with it, this parameter may still |
|
+ * be required depending on the signature algorithm. |
|
+ * +data+:: |
|
+ * A String. The data to be signed. |
|
+ * +options+:: |
|
+ * A Hash that contains algorithm specific control operations to \OpenSSL. |
|
+ * See OpenSSL's man page EVP_PKEY_CTX_ctrl_str(3) for details. |
|
+ * |
|
+ * Example: |
|
+ * data = "Sign me!" |
|
+ * hash = OpenSSL::Digest.digest("SHA256", data) |
|
+ * pkey = OpenSSL::PKey.generate_key("RSA", rsa_keygen_bits: 2048) |
|
+ * signopts = { rsa_padding_mode: "pss" } |
|
+ * signature = pkey.sign_raw("SHA256", hash, signopts) |
|
+ * |
|
+ * # Creates a copy of the RSA key pkey, but without the private components |
|
+ * pub_key = pkey.public_key |
|
+ * puts pub_key.verify_raw("SHA256", signature, hash, signopts) # => true |
|
+ */ |
|
+static VALUE |
|
+ossl_pkey_sign_raw(int argc, VALUE *argv, VALUE self) |
|
+{ |
|
+ EVP_PKEY *pkey; |
|
+ VALUE digest, data, options, sig; |
|
+ const EVP_MD *md = NULL; |
|
+ EVP_PKEY_CTX *ctx; |
|
+ size_t outlen; |
|
+ int state; |
|
+ |
|
+ GetPKey(self, pkey); |
|
+ rb_scan_args(argc, argv, "21", &digest, &data, &options); |
|
+ if (!NIL_P(digest)) |
|
+ md = ossl_evp_get_digestbyname(digest); |
|
+ StringValue(data); |
|
+ |
|
+ ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL); |
|
+ if (!ctx) |
|
+ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new"); |
|
+ if (EVP_PKEY_sign_init(ctx) <= 0) { |
|
+ EVP_PKEY_CTX_free(ctx); |
|
+ ossl_raise(ePKeyError, "EVP_PKEY_sign_init"); |
|
+ } |
|
+ if (md && EVP_PKEY_CTX_set_signature_md(ctx, md) <= 0) { |
|
+ EVP_PKEY_CTX_free(ctx); |
|
+ ossl_raise(ePKeyError, "EVP_PKEY_CTX_set_signature_md"); |
|
+ } |
|
+ if (!NIL_P(options)) { |
|
+ pkey_ctx_apply_options(ctx, options, &state); |
|
+ if (state) { |
|
+ EVP_PKEY_CTX_free(ctx); |
|
+ rb_jump_tag(state); |
|
+ } |
|
+ } |
|
+ if (EVP_PKEY_sign(ctx, NULL, &outlen, (unsigned char *)RSTRING_PTR(data), |
|
+ RSTRING_LEN(data)) <= 0) { |
|
+ EVP_PKEY_CTX_free(ctx); |
|
+ ossl_raise(ePKeyError, "EVP_PKEY_sign"); |
|
+ } |
|
+ if (outlen > LONG_MAX) { |
|
+ EVP_PKEY_CTX_free(ctx); |
|
+ rb_raise(ePKeyError, "signature would be too large"); |
|
+ } |
|
+ sig = ossl_str_new(NULL, (long)outlen, &state); |
|
+ if (state) { |
|
+ EVP_PKEY_CTX_free(ctx); |
|
+ rb_jump_tag(state); |
|
+ } |
|
+ if (EVP_PKEY_sign(ctx, (unsigned char *)RSTRING_PTR(sig), &outlen, |
|
+ (unsigned char *)RSTRING_PTR(data), |
|
+ RSTRING_LEN(data)) <= 0) { |
|
+ EVP_PKEY_CTX_free(ctx); |
|
+ ossl_raise(ePKeyError, "EVP_PKEY_sign"); |
|
+ } |
|
+ EVP_PKEY_CTX_free(ctx); |
|
+ rb_str_set_len(sig, outlen); |
|
+ return sig; |
|
+} |
|
+ |
|
+/* |
|
+ * call-seq: |
|
+ * pkey.verify_raw(digest, signature, data [, options]) -> true or false |
|
+ * |
|
+ * Verifies the +signature+ for the +data+ using a public key +pkey+. Unlike |
|
+ * #verify, this method will not hash +data+ with +digest+ automatically. |
|
+ * |
|
+ * Returns +true+ if the signature is successfully verified, +false+ otherwise. |
|
+ * The caller must check the return value. |
|
+ * |
|
+ * See #sign_raw for the signing operation and an example code. |
|
+ * |
|
+ * Added in version 3.0. See also the man page EVP_PKEY_verify(3). |
|
+ * |
|
+ * +signature+:: |
|
+ * A String containing the signature to be verified. |
|
+ */ |
|
+static VALUE |
|
+ossl_pkey_verify_raw(int argc, VALUE *argv, VALUE self) |
|
+{ |
|
+ EVP_PKEY *pkey; |
|
+ VALUE digest, sig, data, options; |
|
+ const EVP_MD *md = NULL; |
|
+ EVP_PKEY_CTX *ctx; |
|
+ int state, ret; |
|
+ |
|
+ GetPKey(self, pkey); |
|
+ rb_scan_args(argc, argv, "31", &digest, &sig, &data, &options); |
|
+ ossl_pkey_check_public_key(pkey); |
|
+ if (!NIL_P(digest)) |
|
+ md = ossl_evp_get_digestbyname(digest); |
|
+ StringValue(sig); |
|
+ StringValue(data); |
|
+ |
|
+ ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL); |
|
+ if (!ctx) |
|
+ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new"); |
|
+ if (EVP_PKEY_verify_init(ctx) <= 0) { |
|
+ EVP_PKEY_CTX_free(ctx); |
|
+ ossl_raise(ePKeyError, "EVP_PKEY_verify_init"); |
|
+ } |
|
+ if (md && EVP_PKEY_CTX_set_signature_md(ctx, md) <= 0) { |
|
+ EVP_PKEY_CTX_free(ctx); |
|
+ ossl_raise(ePKeyError, "EVP_PKEY_CTX_set_signature_md"); |
|
+ } |
|
+ if (!NIL_P(options)) { |
|
+ pkey_ctx_apply_options(ctx, options, &state); |
|
+ if (state) { |
|
+ EVP_PKEY_CTX_free(ctx); |
|
+ rb_jump_tag(state); |
|
+ } |
|
+ } |
|
+ ret = EVP_PKEY_verify(ctx, (unsigned char *)RSTRING_PTR(sig), |
|
+ RSTRING_LEN(sig), |
|
+ (unsigned char *)RSTRING_PTR(data), |
|
+ RSTRING_LEN(data)); |
|
+ EVP_PKEY_CTX_free(ctx); |
|
+ if (ret < 0) |
|
+ ossl_raise(ePKeyError, "EVP_PKEY_verify"); |
|
+ |
|
+ if (ret) |
|
+ return Qtrue; |
|
+ else { |
|
+ ossl_clear_error(); |
|
+ return Qfalse; |
|
+ } |
|
+} |
|
+ |
|
+/* |
|
+ * call-seq: |
|
+ * pkey.verify_recover(digest, signature [, options]) -> string |
|
+ * |
|
+ * Recovers the signed data from +signature+ using a public key +pkey+. Not all |
|
+ * signature algorithms support this operation. |
|
+ * |
|
+ * Added in version 3.0. See also the man page EVP_PKEY_verify_recover(3). |
|
+ * |
|
+ * +signature+:: |
|
+ * A String containing the signature to be verified. |
|
+ */ |
|
+static VALUE |
|
+ossl_pkey_verify_recover(int argc, VALUE *argv, VALUE self) |
|
+{ |
|
+ EVP_PKEY *pkey; |
|
+ VALUE digest, sig, options, out; |
|
+ const EVP_MD *md = NULL; |
|
+ EVP_PKEY_CTX *ctx; |
|
+ int state; |
|
+ size_t outlen; |
|
+ |
|
+ GetPKey(self, pkey); |
|
+ rb_scan_args(argc, argv, "21", &digest, &sig, &options); |
|
+ ossl_pkey_check_public_key(pkey); |
|
+ if (!NIL_P(digest)) |
|
+ md = ossl_evp_get_digestbyname(digest); |
|
+ StringValue(sig); |
|
+ |
|
+ ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL); |
|
+ if (!ctx) |
|
+ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new"); |
|
+ if (EVP_PKEY_verify_recover_init(ctx) <= 0) { |
|
+ EVP_PKEY_CTX_free(ctx); |
|
+ ossl_raise(ePKeyError, "EVP_PKEY_verify_recover_init"); |
|
+ } |
|
+ if (md && EVP_PKEY_CTX_set_signature_md(ctx, md) <= 0) { |
|
+ EVP_PKEY_CTX_free(ctx); |
|
+ ossl_raise(ePKeyError, "EVP_PKEY_CTX_set_signature_md"); |
|
+ } |
|
+ if (!NIL_P(options)) { |
|
+ pkey_ctx_apply_options(ctx, options, &state); |
|
+ if (state) { |
|
+ EVP_PKEY_CTX_free(ctx); |
|
+ rb_jump_tag(state); |
|
+ } |
|
+ } |
|
+ if (EVP_PKEY_verify_recover(ctx, NULL, &outlen, |
|
+ (unsigned char *)RSTRING_PTR(sig), |
|
+ RSTRING_LEN(sig)) <= 0) { |
|
+ EVP_PKEY_CTX_free(ctx); |
|
+ ossl_raise(ePKeyError, "EVP_PKEY_verify_recover"); |
|
+ } |
|
+ out = ossl_str_new(NULL, (long)outlen, &state); |
|
+ if (state) { |
|
+ EVP_PKEY_CTX_free(ctx); |
|
+ rb_jump_tag(state); |
|
+ } |
|
+ if (EVP_PKEY_verify_recover(ctx, (unsigned char *)RSTRING_PTR(out), &outlen, |
|
+ (unsigned char *)RSTRING_PTR(sig), |
|
+ RSTRING_LEN(sig)) <= 0) { |
|
+ EVP_PKEY_CTX_free(ctx); |
|
+ ossl_raise(ePKeyError, "EVP_PKEY_verify_recover"); |
|
+ } |
|
+ EVP_PKEY_CTX_free(ctx); |
|
+ rb_str_set_len(out, outlen); |
|
+ return out; |
|
+} |
|
+ |
|
/* |
|
* call-seq: |
|
* pkey.derive(peer_pkey) -> string |
|
@@ -1223,6 +1452,9 @@ Init_ossl_pkey(void) |
|
|
|
rb_define_method(cPKey, "sign", ossl_pkey_sign, -1); |
|
rb_define_method(cPKey, "verify", ossl_pkey_verify, -1); |
|
+ rb_define_method(cPKey, "sign_raw", ossl_pkey_sign_raw, -1); |
|
+ rb_define_method(cPKey, "verify_raw", ossl_pkey_verify_raw, -1); |
|
+ rb_define_method(cPKey, "verify_recover", ossl_pkey_verify_recover, -1); |
|
rb_define_method(cPKey, "derive", ossl_pkey_derive, -1); |
|
rb_define_method(cPKey, "encrypt", ossl_pkey_encrypt, -1); |
|
rb_define_method(cPKey, "decrypt", ossl_pkey_decrypt, -1); |
|
diff --git a/test/openssl/test_pkey_dsa.rb b/test/openssl/test_pkey_dsa.rb |
|
index 85bb6ec0ae..147e50176b 100644 |
|
--- a/test/openssl/test_pkey_dsa.rb |
|
+++ b/test/openssl/test_pkey_dsa.rb |
|
@@ -48,12 +48,31 @@ def test_sign_verify |
|
assert_equal false, dsa512.verify("SHA256", signature1, data) |
|
end |
|
|
|
- def test_sys_sign_verify |
|
- key = Fixtures.pkey("dsa256") |
|
+ def test_sign_verify_raw |
|
+ key = Fixtures.pkey("dsa512") |
|
data = 'Sign me!' |
|
digest = OpenSSL::Digest.digest('SHA1', data) |
|
+ |
|
+ invalid_sig = key.sign_raw(nil, digest.succ) |
|
+ malformed_sig = "*" * invalid_sig.bytesize |
|
+ |
|
+ # Sign by #syssign |
|
sig = key.syssign(digest) |
|
- assert(key.sysverify(digest, sig)) |
|
+ assert_equal true, key.sysverify(digest, sig) |
|
+ assert_equal false, key.sysverify(digest, invalid_sig) |
|
+ assert_raise(OpenSSL::PKey::DSAError) { key.sysverify(digest, malformed_sig) } |
|
+ assert_equal true, key.verify_raw(nil, sig, digest) |
|
+ assert_equal false, key.verify_raw(nil, invalid_sig, digest) |
|
+ assert_raise(OpenSSL::PKey::PKeyError) { key.verify_raw(nil, malformed_sig, digest) } |
|
+ |
|
+ # Sign by #sign_raw |
|
+ sig = key.sign_raw(nil, digest) |
|
+ assert_equal true, key.sysverify(digest, sig) |
|
+ assert_equal false, key.sysverify(digest, invalid_sig) |
|
+ assert_raise(OpenSSL::PKey::DSAError) { key.sysverify(digest, malformed_sig) } |
|
+ assert_equal true, key.verify_raw(nil, sig, digest) |
|
+ assert_equal false, key.verify_raw(nil, invalid_sig, digest) |
|
+ assert_raise(OpenSSL::PKey::PKeyError) { key.verify_raw(nil, malformed_sig, digest) } |
|
end |
|
|
|
def test_DSAPrivateKey |
|
diff --git a/test/openssl/test_pkey_ec.rb b/test/openssl/test_pkey_ec.rb |
|
index 95d4338a51..4b6df0290f 100644 |
|
--- a/test/openssl/test_pkey_ec.rb |
|
+++ b/test/openssl/test_pkey_ec.rb |
|
@@ -109,13 +109,30 @@ def test_derive_key |
|
assert_equal a.derive(b), a.dh_compute_key(b.public_key) |
|
end |
|
|
|
- def test_dsa_sign_verify |
|
+ def test_sign_verify_raw |
|
+ key = Fixtures.pkey("p256") |
|
data1 = "foo" |
|
data2 = "bar" |
|
- key = OpenSSL::PKey::EC.new("prime256v1").generate_key! |
|
+ |
|
+ malformed_sig = "*" * 30 |
|
+ |
|
+ # Sign by #dsa_sign_asn1 |
|
sig = key.dsa_sign_asn1(data1) |
|
assert_equal true, key.dsa_verify_asn1(data1, sig) |
|
assert_equal false, key.dsa_verify_asn1(data2, sig) |
|
+ assert_raise(OpenSSL::PKey::ECError) { key.dsa_verify_asn1(data1, malformed_sig) } |
|
+ assert_equal true, key.verify_raw(nil, sig, data1) |
|
+ assert_equal false, key.verify_raw(nil, sig, data2) |
|
+ assert_raise(OpenSSL::PKey::PKeyError) { key.verify_raw(nil, malformed_sig, data1) } |
|
+ |
|
+ # Sign by #sign_raw |
|
+ sig = key.sign_raw(nil, data1) |
|
+ assert_equal true, key.dsa_verify_asn1(data1, sig) |
|
+ assert_equal false, key.dsa_verify_asn1(data2, sig) |
|
+ assert_raise(OpenSSL::PKey::ECError) { key.dsa_verify_asn1(data1, malformed_sig) } |
|
+ assert_equal true, key.verify_raw(nil, sig, data1) |
|
+ assert_equal false, key.verify_raw(nil, sig, data2) |
|
+ assert_raise(OpenSSL::PKey::PKeyError) { key.verify_raw(nil, malformed_sig, data1) } |
|
end |
|
|
|
def test_dsa_sign_asn1_FIPS186_3 |
|
diff --git a/test/openssl/test_pkey_rsa.rb b/test/openssl/test_pkey_rsa.rb |
|
index d6bfca3ac5..5e127f5407 100644 |
|
--- a/test/openssl/test_pkey_rsa.rb |
|
+++ b/test/openssl/test_pkey_rsa.rb |
|
@@ -13,32 +13,6 @@ def test_no_private_exp |
|
assert_raise(OpenSSL::PKey::RSAError){ key.private_decrypt("foo") } |
|
end |
|
|
|
- def test_padding |
|
- key = OpenSSL::PKey::RSA.new(512, 3) |
|
- |
|
- # Need right size for raw mode |
|
- plain0 = "x" * (512/8) |
|
- cipher = key.private_encrypt(plain0, OpenSSL::PKey::RSA::NO_PADDING) |
|
- plain1 = key.public_decrypt(cipher, OpenSSL::PKey::RSA::NO_PADDING) |
|
- assert_equal(plain0, plain1) |
|
- |
|
- # Need smaller size for pkcs1 mode |
|
- plain0 = "x" * (512/8 - 11) |
|
- cipher1 = key.private_encrypt(plain0, OpenSSL::PKey::RSA::PKCS1_PADDING) |
|
- plain1 = key.public_decrypt(cipher1, OpenSSL::PKey::RSA::PKCS1_PADDING) |
|
- assert_equal(plain0, plain1) |
|
- |
|
- cipherdef = key.private_encrypt(plain0) # PKCS1_PADDING is default |
|
- plain1 = key.public_decrypt(cipherdef) |
|
- assert_equal(plain0, plain1) |
|
- assert_equal(cipher1, cipherdef) |
|
- |
|
- # Failure cases |
|
- assert_raise(ArgumentError){ key.private_encrypt() } |
|
- assert_raise(ArgumentError){ key.private_encrypt("hi", 1, nil) } |
|
- assert_raise(OpenSSL::PKey::RSAError){ key.private_encrypt(plain0, 666) } |
|
- end |
|
- |
|
def test_private |
|
# Generated by key size and public exponent |
|
key = OpenSSL::PKey::RSA.new(512, 3) |
|
@@ -133,6 +107,58 @@ def test_sign_verify_options |
|
assert_equal false, key.verify("SHA256", sig_pss, data) |
|
end |
|
|
|
+ def test_sign_verify_raw |
|
+ key = Fixtures.pkey("rsa-1") |
|
+ data = "Sign me!" |
|
+ hash = OpenSSL::Digest.digest("SHA1", data) |
|
+ signature = key.sign_raw("SHA1", hash) |
|
+ assert_equal true, key.verify_raw("SHA1", signature, hash) |
|
+ assert_equal true, key.verify("SHA1", signature, data) |
|
+ |
|
+ # Too long data |
|
+ assert_raise(OpenSSL::PKey::PKeyError) { |
|
+ key.sign_raw("SHA1", "x" * (key.n.num_bytes + 1)) |
|
+ } |
|
+ |
|
+ # With options |
|
+ pssopts = { |
|
+ "rsa_padding_mode" => "pss", |
|
+ "rsa_pss_saltlen" => 20, |
|
+ "rsa_mgf1_md" => "SHA256" |
|
+ } |
|
+ sig_pss = key.sign_raw("SHA1", hash, pssopts) |
|
+ assert_equal true, key.verify("SHA1", sig_pss, data, pssopts) |
|
+ assert_equal true, key.verify_raw("SHA1", sig_pss, hash, pssopts) |
|
+ end |
|
+ |
|
+ def test_sign_verify_raw_legacy |
|
+ key = Fixtures.pkey("rsa-1") |
|
+ bits = key.n.num_bits |
|
+ |
|
+ # Need right size for raw mode |
|
+ plain0 = "x" * (bits/8) |
|
+ cipher = key.private_encrypt(plain0, OpenSSL::PKey::RSA::NO_PADDING) |
|
+ plain1 = key.public_decrypt(cipher, OpenSSL::PKey::RSA::NO_PADDING) |
|
+ assert_equal(plain0, plain1) |
|
+ |
|
+ # Need smaller size for pkcs1 mode |
|
+ plain0 = "x" * (bits/8 - 11) |
|
+ cipher1 = key.private_encrypt(plain0, OpenSSL::PKey::RSA::PKCS1_PADDING) |
|
+ plain1 = key.public_decrypt(cipher1, OpenSSL::PKey::RSA::PKCS1_PADDING) |
|
+ assert_equal(plain0, plain1) |
|
+ |
|
+ cipherdef = key.private_encrypt(plain0) # PKCS1_PADDING is default |
|
+ plain1 = key.public_decrypt(cipherdef) |
|
+ assert_equal(plain0, plain1) |
|
+ assert_equal(cipher1, cipherdef) |
|
+ |
|
+ # Failure cases |
|
+ assert_raise(ArgumentError){ key.private_encrypt() } |
|
+ assert_raise(ArgumentError){ key.private_encrypt("hi", 1, nil) } |
|
+ assert_raise(OpenSSL::PKey::RSAError){ key.private_encrypt(plain0, 666) } |
|
+ end |
|
+ |
|
+ |
|
def test_verify_empty_rsa |
|
rsa = OpenSSL::PKey::RSA.new |
|
assert_raise(OpenSSL::PKey::PKeyError, "[Bug #12783]") { |
|
-- |
|
2.32.0 |
|
|
|
|
|
From 4330b1b9661fcab1172473f4fdd9986602c1e78c Mon Sep 17 00:00:00 2001 |
|
From: Kazuki Yamaguchi <k@rhe.jp> |
|
Date: Mon, 18 May 2020 20:24:08 +0900 |
|
Subject: [PATCH 4/6] pkey/rsa: port RSA#{private,public}_{encrypt,decrypt} to |
|
the EVP API |
|
|
|
Implement these methods using the new OpenSSL::PKey::PKey#{encrypt,sign} |
|
family. The definitions are now in lib/openssl/pkey.rb. |
|
|
|
Also, recommend using those generic methods in the documentation. |
|
--- |
|
ext/openssl/lib/openssl/pkey.rb | 106 ++++++++++++++++++++++++ |
|
ext/openssl/ossl_pkey_rsa.c | 141 -------------------------------- |
|
2 files changed, 106 insertions(+), 141 deletions(-) |
|
|
|
diff --git a/ext/openssl/lib/openssl/pkey.rb b/ext/openssl/lib/openssl/pkey.rb |
|
index 569559e1ce..dd8c7c0b09 100644 |
|
--- a/ext/openssl/lib/openssl/pkey.rb |
|
+++ b/ext/openssl/lib/openssl/pkey.rb |
|
@@ -243,5 +243,111 @@ def new(*args, &blk) # :nodoc: |
|
end |
|
end |
|
end |
|
+ |
|
+ # :call-seq: |
|
+ # rsa.private_encrypt(string) -> String |
|
+ # rsa.private_encrypt(string, padding) -> String |
|
+ # |
|
+ # Encrypt +string+ with the private key. +padding+ defaults to |
|
+ # PKCS1_PADDING. The encrypted string output can be decrypted using |
|
+ # #public_decrypt. |
|
+ # |
|
+ # <b>Deprecated in version 3.0</b>. |
|
+ # Consider using PKey::PKey#sign_raw and PKey::PKey#verify_raw, and |
|
+ # PKey::PKey#verify_recover instead. |
|
+ def private_encrypt(string, padding = PKCS1_PADDING) |
|
+ n or raise OpenSSL::PKey::RSAError, "incomplete RSA" |
|
+ private? or raise OpenSSL::PKey::RSAError, "private key needed." |
|
+ begin |
|
+ sign_raw(nil, string, { |
|
+ "rsa_padding_mode" => translate_padding_mode(padding), |
|
+ }) |
|
+ rescue OpenSSL::PKey::PKeyError |
|
+ raise OpenSSL::PKey::RSAError, $!.message |
|
+ end |
|
+ end |
|
+ |
|
+ # :call-seq: |
|
+ # rsa.public_decrypt(string) -> String |
|
+ # rsa.public_decrypt(string, padding) -> String |
|
+ # |
|
+ # Decrypt +string+, which has been encrypted with the private key, with the |
|
+ # public key. +padding+ defaults to PKCS1_PADDING. |
|
+ # |
|
+ # <b>Deprecated in version 3.0</b>. |
|
+ # Consider using PKey::PKey#sign_raw and PKey::PKey#verify_raw, and |
|
+ # PKey::PKey#verify_recover instead. |
|
+ def public_decrypt(string, padding = PKCS1_PADDING) |
|
+ n or raise OpenSSL::PKey::RSAError, "incomplete RSA" |
|
+ begin |
|
+ verify_recover(nil, string, { |
|
+ "rsa_padding_mode" => translate_padding_mode(padding), |
|
+ }) |
|
+ rescue OpenSSL::PKey::PKeyError |
|
+ raise OpenSSL::PKey::RSAError, $!.message |
|
+ end |
|
+ end |
|
+ |
|
+ # :call-seq: |
|
+ # rsa.public_encrypt(string) -> String |
|
+ # rsa.public_encrypt(string, padding) -> String |
|
+ # |
|
+ # Encrypt +string+ with the public key. +padding+ defaults to |
|
+ # PKCS1_PADDING. The encrypted string output can be decrypted using |
|
+ # #private_decrypt. |
|
+ # |
|
+ # <b>Deprecated in version 3.0</b>. |
|
+ # Consider using PKey::PKey#encrypt and PKey::PKey#decrypt instead. |
|
+ def public_encrypt(data, padding = PKCS1_PADDING) |
|
+ n or raise OpenSSL::PKey::RSAError, "incomplete RSA" |
|
+ begin |
|
+ encrypt(data, { |
|
+ "rsa_padding_mode" => translate_padding_mode(padding), |
|
+ }) |
|
+ rescue OpenSSL::PKey::PKeyError |
|
+ raise OpenSSL::PKey::RSAError, $!.message |
|
+ end |
|
+ end |
|
+ |
|
+ # :call-seq: |
|
+ # rsa.private_decrypt(string) -> String |
|
+ # rsa.private_decrypt(string, padding) -> String |
|
+ # |
|
+ # Decrypt +string+, which has been encrypted with the public key, with the |
|
+ # private key. +padding+ defaults to PKCS1_PADDING. |
|
+ # |
|
+ # <b>Deprecated in version 3.0</b>. |
|
+ # Consider using PKey::PKey#encrypt and PKey::PKey#decrypt instead. |
|
+ def private_decrypt(data, padding = PKCS1_PADDING) |
|
+ n or raise OpenSSL::PKey::RSAError, "incomplete RSA" |
|
+ private? or raise OpenSSL::PKey::RSAError, "private key needed." |
|
+ begin |
|
+ decrypt(data, { |
|
+ "rsa_padding_mode" => translate_padding_mode(padding), |
|
+ }) |
|
+ rescue OpenSSL::PKey::PKeyError |
|
+ raise OpenSSL::PKey::RSAError, $!.message |
|
+ end |
|
+ end |
|
+ |
|
+ PKCS1_PADDING = 1 |
|
+ SSLV23_PADDING = 2 |
|
+ NO_PADDING = 3 |
|
+ PKCS1_OAEP_PADDING = 4 |
|
+ |
|
+ private def translate_padding_mode(num) |
|
+ case num |
|
+ when PKCS1_PADDING |
|
+ "pkcs1" |
|
+ when SSLV23_PADDING |
|
+ "sslv23" |
|
+ when NO_PADDING |
|
+ "none" |
|
+ when PKCS1_OAEP_PADDING |
|
+ "oaep" |
|
+ else |
|
+ raise OpenSSL::PKey::PKeyError, "unsupported padding mode" |
|
+ end |
|
+ end |
|
end |
|
end |
|
diff --git a/ext/openssl/ossl_pkey_rsa.c b/ext/openssl/ossl_pkey_rsa.c |
|
index 1c5476cdcd..8ebd3ec559 100644 |
|
--- a/ext/openssl/ossl_pkey_rsa.c |
|
+++ b/ext/openssl/ossl_pkey_rsa.c |
|
@@ -229,138 +229,6 @@ ossl_rsa_to_der(VALUE self) |
|
return ossl_pkey_export_spki(self, 1); |
|
} |
|
|
|
-/* |
|
- * call-seq: |
|
- * rsa.public_encrypt(string) => String |
|
- * rsa.public_encrypt(string, padding) => String |
|
- * |
|
- * Encrypt _string_ with the public key. _padding_ defaults to PKCS1_PADDING. |
|
- * The encrypted string output can be decrypted using #private_decrypt. |
|
- */ |
|
-static VALUE |
|
-ossl_rsa_public_encrypt(int argc, VALUE *argv, VALUE self) |
|
-{ |
|
- RSA *rsa; |
|
- const BIGNUM *rsa_n; |
|
- int buf_len, pad; |
|
- VALUE str, buffer, padding; |
|
- |
|
- GetRSA(self, rsa); |
|
- RSA_get0_key(rsa, &rsa_n, NULL, NULL); |
|
- if (!rsa_n) |
|
- ossl_raise(eRSAError, "incomplete RSA"); |
|
- rb_scan_args(argc, argv, "11", &buffer, &padding); |
|
- pad = (argc == 1) ? RSA_PKCS1_PADDING : NUM2INT(padding); |
|
- StringValue(buffer); |
|
- str = rb_str_new(0, RSA_size(rsa)); |
|
- buf_len = RSA_public_encrypt(RSTRING_LENINT(buffer), (unsigned char *)RSTRING_PTR(buffer), |
|
- (unsigned char *)RSTRING_PTR(str), rsa, pad); |
|
- if (buf_len < 0) ossl_raise(eRSAError, NULL); |
|
- rb_str_set_len(str, buf_len); |
|
- |
|
- return str; |
|
-} |
|
- |
|
-/* |
|
- * call-seq: |
|
- * rsa.public_decrypt(string) => String |
|
- * rsa.public_decrypt(string, padding) => String |
|
- * |
|
- * Decrypt _string_, which has been encrypted with the private key, with the |
|
- * public key. _padding_ defaults to PKCS1_PADDING. |
|
- */ |
|
-static VALUE |
|
-ossl_rsa_public_decrypt(int argc, VALUE *argv, VALUE self) |
|
-{ |
|
- RSA *rsa; |
|
- const BIGNUM *rsa_n; |
|
- int buf_len, pad; |
|
- VALUE str, buffer, padding; |
|
- |
|
- GetRSA(self, rsa); |
|
- RSA_get0_key(rsa, &rsa_n, NULL, NULL); |
|
- if (!rsa_n) |
|
- ossl_raise(eRSAError, "incomplete RSA"); |
|
- rb_scan_args(argc, argv, "11", &buffer, &padding); |
|
- pad = (argc == 1) ? RSA_PKCS1_PADDING : NUM2INT(padding); |
|
- StringValue(buffer); |
|
- str = rb_str_new(0, RSA_size(rsa)); |
|
- buf_len = RSA_public_decrypt(RSTRING_LENINT(buffer), (unsigned char *)RSTRING_PTR(buffer), |
|
- (unsigned char *)RSTRING_PTR(str), rsa, pad); |
|
- if (buf_len < 0) ossl_raise(eRSAError, NULL); |
|
- rb_str_set_len(str, buf_len); |
|
- |
|
- return str; |
|
-} |
|
- |
|
-/* |
|
- * call-seq: |
|
- * rsa.private_encrypt(string) => String |
|
- * rsa.private_encrypt(string, padding) => String |
|
- * |
|
- * Encrypt _string_ with the private key. _padding_ defaults to PKCS1_PADDING. |
|
- * The encrypted string output can be decrypted using #public_decrypt. |
|
- */ |
|
-static VALUE |
|
-ossl_rsa_private_encrypt(int argc, VALUE *argv, VALUE self) |
|
-{ |
|
- RSA *rsa; |
|
- const BIGNUM *rsa_n; |
|
- int buf_len, pad; |
|
- VALUE str, buffer, padding; |
|
- |
|
- GetRSA(self, rsa); |
|
- RSA_get0_key(rsa, &rsa_n, NULL, NULL); |
|
- if (!rsa_n) |
|
- ossl_raise(eRSAError, "incomplete RSA"); |
|
- if (!RSA_PRIVATE(self, rsa)) |
|
- ossl_raise(eRSAError, "private key needed."); |
|
- rb_scan_args(argc, argv, "11", &buffer, &padding); |
|
- pad = (argc == 1) ? RSA_PKCS1_PADDING : NUM2INT(padding); |
|
- StringValue(buffer); |
|
- str = rb_str_new(0, RSA_size(rsa)); |
|
- buf_len = RSA_private_encrypt(RSTRING_LENINT(buffer), (unsigned char *)RSTRING_PTR(buffer), |
|
- (unsigned char *)RSTRING_PTR(str), rsa, pad); |
|
- if (buf_len < 0) ossl_raise(eRSAError, NULL); |
|
- rb_str_set_len(str, buf_len); |
|
- |
|
- return str; |
|
-} |
|
- |
|
-/* |
|
- * call-seq: |
|
- * rsa.private_decrypt(string) => String |
|
- * rsa.private_decrypt(string, padding) => String |
|
- * |
|
- * Decrypt _string_, which has been encrypted with the public key, with the |
|
- * private key. _padding_ defaults to PKCS1_PADDING. |
|
- */ |
|
-static VALUE |
|
-ossl_rsa_private_decrypt(int argc, VALUE *argv, VALUE self) |
|
-{ |
|
- RSA *rsa; |
|
- const BIGNUM *rsa_n; |
|
- int buf_len, pad; |
|
- VALUE str, buffer, padding; |
|
- |
|
- GetRSA(self, rsa); |
|
- RSA_get0_key(rsa, &rsa_n, NULL, NULL); |
|
- if (!rsa_n) |
|
- ossl_raise(eRSAError, "incomplete RSA"); |
|
- if (!RSA_PRIVATE(self, rsa)) |
|
- ossl_raise(eRSAError, "private key needed."); |
|
- rb_scan_args(argc, argv, "11", &buffer, &padding); |
|
- pad = (argc == 1) ? RSA_PKCS1_PADDING : NUM2INT(padding); |
|
- StringValue(buffer); |
|
- str = rb_str_new(0, RSA_size(rsa)); |
|
- buf_len = RSA_private_decrypt(RSTRING_LENINT(buffer), (unsigned char *)RSTRING_PTR(buffer), |
|
- (unsigned char *)RSTRING_PTR(str), rsa, pad); |
|
- if (buf_len < 0) ossl_raise(eRSAError, NULL); |
|
- rb_str_set_len(str, buf_len); |
|
- |
|
- return str; |
|
-} |
|
- |
|
/* |
|
* call-seq: |
|
* rsa.sign_pss(digest, data, salt_length:, mgf1_hash:) -> String |
|
@@ -657,10 +525,6 @@ Init_ossl_rsa(void) |
|
rb_define_alias(cRSA, "to_pem", "export"); |
|
rb_define_alias(cRSA, "to_s", "export"); |
|
rb_define_method(cRSA, "to_der", ossl_rsa_to_der, 0); |
|
- rb_define_method(cRSA, "public_encrypt", ossl_rsa_public_encrypt, -1); |
|
- rb_define_method(cRSA, "public_decrypt", ossl_rsa_public_decrypt, -1); |
|
- rb_define_method(cRSA, "private_encrypt", ossl_rsa_private_encrypt, -1); |
|
- rb_define_method(cRSA, "private_decrypt", ossl_rsa_private_decrypt, -1); |
|
rb_define_method(cRSA, "sign_pss", ossl_rsa_sign_pss, -1); |
|
rb_define_method(cRSA, "verify_pss", ossl_rsa_verify_pss, -1); |
|
|
|
@@ -678,11 +542,6 @@ Init_ossl_rsa(void) |
|
|
|
rb_define_method(cRSA, "params", ossl_rsa_get_params, 0); |
|
|
|
- DefRSAConst(PKCS1_PADDING); |
|
- DefRSAConst(SSLV23_PADDING); |
|
- DefRSAConst(NO_PADDING); |
|
- DefRSAConst(PKCS1_OAEP_PADDING); |
|
- |
|
/* |
|
* TODO: Test it |
|
rb_define_method(cRSA, "blinding_on!", ossl_rsa_blinding_on, 0); |
|
-- |
|
2.32.0 |
|
|
|
|
|
From d45a31cf70f5a55d7f6cf5082efc4dbb68d1169d Mon Sep 17 00:00:00 2001 |
|
From: Kazuki Yamaguchi <k@rhe.jp> |
|
Date: Fri, 10 Jul 2020 13:43:20 +0900 |
|
Subject: [PATCH 5/6] pkey/ec: refactor EC#dsa_{sign,verify}_asn1 with |
|
PKey#{sign,verify}_raw |
|
|
|
With the newly added OpenSSL::PKey::PKey#{sign,verify}_raw, |
|
OpenSSL::PKey::EC's low level signing operation methods can be |
|
implemented in Ruby. The definitions are now in lib/openssl/pkey.rb. |
|
--- |
|
ext/openssl/lib/openssl/pkey.rb | 22 +++++++++++++ |
|
ext/openssl/ossl_pkey_ec.c | 55 --------------------------------- |
|
2 files changed, 22 insertions(+), 55 deletions(-) |
|
|
|
diff --git a/ext/openssl/lib/openssl/pkey.rb b/ext/openssl/lib/openssl/pkey.rb |
|
index dd8c7c0b09..e587109694 100644 |
|
--- a/ext/openssl/lib/openssl/pkey.rb |
|
+++ b/ext/openssl/lib/openssl/pkey.rb |
|
@@ -164,6 +164,28 @@ def new(*args, &blk) # :nodoc: |
|
class EC |
|
include OpenSSL::Marshal |
|
|
|
+ # :call-seq: |
|
+ # key.dsa_sign_asn1(data) -> String |
|
+ # |
|
+ # <b>Deprecated in version 3.0</b>. |
|
+ # Consider using PKey::PKey#sign_raw and PKey::PKey#verify_raw instead. |
|
+ def dsa_sign_asn1(data) |
|
+ sign_raw(nil, data) |
|
+ rescue OpenSSL::PKey::PKeyError |
|
+ raise OpenSSL::PKey::ECError, $!.message |
|
+ end |
|
+ |
|
+ # :call-seq: |
|
+ # key.dsa_verify_asn1(data, sig) -> true | false |
|
+ # |
|
+ # <b>Deprecated in version 3.0</b>. |
|
+ # Consider using PKey::PKey#sign_raw and PKey::PKey#verify_raw instead. |
|
+ def dsa_verify_asn1(data, sig) |
|
+ verify_raw(nil, sig, data) |
|
+ rescue OpenSSL::PKey::PKeyError |
|
+ raise OpenSSL::PKey::ECError, $!.message |
|
+ end |
|
+ |
|
# :call-seq: |
|
# ec.dh_compute_key(pubkey) -> string |
|
# |
|
diff --git a/ext/openssl/ossl_pkey_ec.c b/ext/openssl/ossl_pkey_ec.c |
|
index 829529d4b9..f52e67079d 100644 |
|
--- a/ext/openssl/ossl_pkey_ec.c |
|
+++ b/ext/openssl/ossl_pkey_ec.c |
|
@@ -476,57 +476,6 @@ static VALUE ossl_ec_key_check_key(VALUE self) |
|
return Qtrue; |
|
} |
|
|
|
-/* |
|
- * call-seq: |
|
- * key.dsa_sign_asn1(data) => String |
|
- * |
|
- * See the OpenSSL documentation for ECDSA_sign() |
|
- */ |
|
-static VALUE ossl_ec_key_dsa_sign_asn1(VALUE self, VALUE data) |
|
-{ |
|
- EC_KEY *ec; |
|
- unsigned int buf_len; |
|
- VALUE str; |
|
- |
|
- GetEC(self, ec); |
|
- StringValue(data); |
|
- |
|
- if (EC_KEY_get0_private_key(ec) == NULL) |
|
- ossl_raise(eECError, "Private EC key needed!"); |
|
- |
|
- str = rb_str_new(0, ECDSA_size(ec)); |
|
- if (ECDSA_sign(0, (unsigned char *) RSTRING_PTR(data), RSTRING_LENINT(data), (unsigned char *) RSTRING_PTR(str), &buf_len, ec) != 1) |
|
- ossl_raise(eECError, "ECDSA_sign"); |
|
- rb_str_set_len(str, buf_len); |
|
- |
|
- return str; |
|
-} |
|
- |
|
-/* |
|
- * call-seq: |
|
- * key.dsa_verify_asn1(data, sig) => true or false |
|
- * |
|
- * See the OpenSSL documentation for ECDSA_verify() |
|
- */ |
|
-static VALUE ossl_ec_key_dsa_verify_asn1(VALUE self, VALUE data, VALUE sig) |
|
-{ |
|
- EC_KEY *ec; |
|
- |
|
- GetEC(self, ec); |
|
- StringValue(data); |
|
- StringValue(sig); |
|
- |
|
- switch (ECDSA_verify(0, (unsigned char *)RSTRING_PTR(data), RSTRING_LENINT(data), |
|
- (unsigned char *)RSTRING_PTR(sig), RSTRING_LENINT(sig), ec)) { |
|
- case 1: |
|
- return Qtrue; |
|
- case 0: |
|
- return Qfalse; |
|
- default: |
|
- ossl_raise(eECError, "ECDSA_verify"); |
|
- } |
|
-} |
|
- |
|
/* |
|
* OpenSSL::PKey::EC::Group |
|
*/ |
|
@@ -1615,10 +1564,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, "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 */ |
|
- |
|
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); |
|
-- |
|
2.32.0 |
|
|
|
|
|
From 2494043e302c920e90e06cce443c5cd428e183f7 Mon Sep 17 00:00:00 2001 |
|
From: Kazuki Yamaguchi <k@rhe.jp> |
|
Date: Fri, 10 Jul 2020 13:51:18 +0900 |
|
Subject: [PATCH 6/6] pkey/dsa: refactor DSA#sys{sign,verify} with |
|
PKey#{sign,verify}_raw |
|
|
|
With the newly added OpenSSL::PKey::PKey#{sign,verify}_raw, |
|
OpenSSL::PKey::DSA's low level signing operation methods can be |
|
implemented in Ruby. The definitions are now in lib/openssl/pkey.rb. |
|
--- |
|
ext/openssl/lib/openssl/pkey.rb | 54 ++++++++++++++++++++ |
|
ext/openssl/ossl_pkey_dsa.c | 88 --------------------------------- |
|
2 files changed, 54 insertions(+), 88 deletions(-) |
|
|
|
diff --git a/ext/openssl/lib/openssl/pkey.rb b/ext/openssl/lib/openssl/pkey.rb |
|
index e587109694..f6bf5892b0 100644 |
|
--- a/ext/openssl/lib/openssl/pkey.rb |
|
+++ b/ext/openssl/lib/openssl/pkey.rb |
|
@@ -158,6 +158,60 @@ def new(*args, &blk) # :nodoc: |
|
end |
|
end |
|
end |
|
+ |
|
+ # :call-seq: |
|
+ # dsa.syssign(string) -> string |
|
+ # |
|
+ # Computes and returns the \DSA signature of +string+, where +string+ is |
|
+ # expected to be an already-computed message digest of the original input |
|
+ # data. The signature is issued using the private key of this DSA instance. |
|
+ # |
|
+ # <b>Deprecated in version 3.0</b>. |
|
+ # Consider using PKey::PKey#sign_raw and PKey::PKey#verify_raw instead. |
|
+ # |
|
+ # +string+:: |
|
+ # A message digest of the original input data to be signed. |
|
+ # |
|
+ # Example: |
|
+ # dsa = OpenSSL::PKey::DSA.new(2048) |
|
+ # doc = "Sign me" |
|
+ # digest = OpenSSL::Digest.digest('SHA1', doc) |
|
+ # |
|
+ # # With legacy #syssign and #sysverify: |
|
+ # sig = dsa.syssign(digest) |
|
+ # p dsa.sysverify(digest, sig) #=> true |
|
+ # |
|
+ # # With #sign_raw and #verify_raw: |
|
+ # sig = dsa.sign_raw(nil, digest) |
|
+ # p dsa.verify_raw(nil, sig, digest) #=> true |
|
+ def syssign(string) |
|
+ q or raise OpenSSL::PKey::DSAError, "incomplete DSA" |
|
+ private? or raise OpenSSL::PKey::DSAError, "Private DSA key needed!" |
|
+ begin |
|
+ sign_raw(nil, string) |
|
+ rescue OpenSSL::PKey::PKeyError |
|
+ raise OpenSSL::PKey::DSAError, $!.message |
|
+ end |
|
+ end |
|
+ |
|
+ # :call-seq: |
|
+ # dsa.sysverify(digest, sig) -> true | false |
|
+ # |
|
+ # Verifies whether the signature is valid given the message digest input. |
|
+ # It does so by validating +sig+ using the public key of this DSA instance. |
|
+ # |
|
+ # <b>Deprecated in version 3.0</b>. |
|
+ # Consider using PKey::PKey#sign_raw and PKey::PKey#verify_raw instead. |
|
+ # |
|
+ # +digest+:: |
|
+ # A message digest of the original input data to be signed. |
|
+ # +sig+:: |
|
+ # A \DSA signature value. |
|
+ def sysverify(digest, sig) |
|
+ verify_raw(nil, sig, digest) |
|
+ rescue OpenSSL::PKey::PKeyError |
|
+ raise OpenSSL::PKey::DSAError, $!.message |
|
+ end |
|
end |
|
|
|
if defined?(EC) |
|
diff --git a/ext/openssl/ossl_pkey_dsa.c b/ext/openssl/ossl_pkey_dsa.c |
|
index ab9ac781e8..7af00eebec 100644 |
|
--- a/ext/openssl/ossl_pkey_dsa.c |
|
+++ b/ext/openssl/ossl_pkey_dsa.c |
|
@@ -264,92 +264,6 @@ ossl_dsa_get_params(VALUE self) |
|
return hash; |
|
} |
|
|
|
-/* |
|
- * call-seq: |
|
- * dsa.syssign(string) -> aString |
|
- * |
|
- * Computes and returns the DSA signature of _string_, where _string_ is |
|
- * expected to be an already-computed message digest of the original input |
|
- * data. The signature is issued using the private key of this DSA instance. |
|
- * |
|
- * === Parameters |
|
- * * _string_ is a message digest of the original input data to be signed. |
|
- * |
|
- * === Example |
|
- * dsa = OpenSSL::PKey::DSA.new(2048) |
|
- * doc = "Sign me" |
|
- * digest = OpenSSL::Digest.digest('SHA1', doc) |
|
- * sig = dsa.syssign(digest) |
|
- * |
|
- * |
|
- */ |
|
-static VALUE |
|
-ossl_dsa_sign(VALUE self, VALUE data) |
|
-{ |
|
- DSA *dsa; |
|
- const BIGNUM *dsa_q; |
|
- unsigned int buf_len; |
|
- VALUE str; |
|
- |
|
- GetDSA(self, dsa); |
|
- DSA_get0_pqg(dsa, NULL, &dsa_q, NULL); |
|
- if (!dsa_q) |
|
- ossl_raise(eDSAError, "incomplete DSA"); |
|
- if (!DSA_PRIVATE(self, dsa)) |
|
- ossl_raise(eDSAError, "Private DSA key needed!"); |
|
- StringValue(data); |
|
- str = rb_str_new(0, DSA_size(dsa)); |
|
- if (!DSA_sign(0, (unsigned char *)RSTRING_PTR(data), RSTRING_LENINT(data), |
|
- (unsigned char *)RSTRING_PTR(str), |
|
- &buf_len, dsa)) { /* type is ignored (0) */ |
|
- ossl_raise(eDSAError, NULL); |
|
- } |
|
- rb_str_set_len(str, buf_len); |
|
- |
|
- return str; |
|
-} |
|
- |
|
-/* |
|
- * call-seq: |
|
- * dsa.sysverify(digest, sig) -> true | false |
|
- * |
|
- * Verifies whether the signature is valid given the message digest input. It |
|
- * does so by validating _sig_ using the public key of this DSA instance. |
|
- * |
|
- * === Parameters |
|
- * * _digest_ is a message digest of the original input data to be signed |
|
- * * _sig_ is a DSA signature value |
|
- * |
|
- * === Example |
|
- * dsa = OpenSSL::PKey::DSA.new(2048) |
|
- * doc = "Sign me" |
|
- * digest = OpenSSL::Digest.digest('SHA1', doc) |
|
- * sig = dsa.syssign(digest) |
|
- * puts dsa.sysverify(digest, sig) # => true |
|
- * |
|
- */ |
|
-static VALUE |
|
-ossl_dsa_verify(VALUE self, VALUE digest, VALUE sig) |
|
-{ |
|
- DSA *dsa; |
|
- int ret; |
|
- |
|
- GetDSA(self, dsa); |
|
- StringValue(digest); |
|
- StringValue(sig); |
|
- /* type is ignored (0) */ |
|
- ret = DSA_verify(0, (unsigned char *)RSTRING_PTR(digest), RSTRING_LENINT(digest), |
|
- (unsigned char *)RSTRING_PTR(sig), RSTRING_LENINT(sig), dsa); |
|
- if (ret < 0) { |
|
- ossl_raise(eDSAError, NULL); |
|
- } |
|
- else if (ret == 1) { |
|
- return Qtrue; |
|
- } |
|
- |
|
- return Qfalse; |
|
-} |
|
- |
|
/* |
|
* Document-method: OpenSSL::PKey::DSA#set_pqg |
|
* call-seq: |
|
@@ -404,8 +318,6 @@ Init_ossl_dsa(void) |
|
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, "syssign", ossl_dsa_sign, 1); |
|
- rb_define_method(cDSA, "sysverify", ossl_dsa_verify, 2); |
|
|
|
DEF_OSSL_PKEY_BN(cDSA, dsa, p); |
|
DEF_OSSL_PKEY_BN(cDSA, dsa, q); |
|
-- |
|
2.32.0 |
|
|
|
|