summaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
authorKazuki Yamaguchi <k@rhe.jp>2017-03-18 21:58:46 +0900
committerKazuki Yamaguchi <k@rhe.jp>2021-03-16 19:16:11 +0900
commitfbadb01d6e0881ef6c6e5e105b8ac20fe663c817 (patch)
tree59b9014cf8bf92e142cf9a29053e2ec10e433958 /ext
parentb2dc4880f5d000c3e0117ecf9c57a273cbd713f9 (diff)
[ruby/openssl] 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. https://github.com/ruby/openssl/commit/28f0059bea
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/4275
Diffstat (limited to 'ext')
-rw-r--r--ext/openssl/ossl_pkey.c52
1 files changed, 52 insertions, 0 deletions
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
@@ -887,6 +887,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
*/
void
@@ -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?");