From 703c271233a552975bd457c0418a6eb95ca66795 Mon Sep 17 00:00:00 2001 From: Michael Richardson Date: Fri, 1 Aug 2025 22:40:59 -0400 Subject: [PATCH 1/4] feat: added PKey.load_from_handle to use provider load routine to get handle on keys (was going to be load, but confused with Kernel.load , complicating testing) --- ext/openssl/ossl_pkey.c | 45 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c index e88074ddf..d70bc2b75 100644 --- a/ext/openssl/ossl_pkey.c +++ b/ext/openssl/ossl_pkey.c @@ -13,6 +13,8 @@ # include #endif +#include + /* * Classes */ @@ -242,6 +244,47 @@ ossl_pkey_new_from_data(int argc, VALUE *argv, VALUE self) return ossl_pkey_wrap(pkey); } +/* + * call-seq: + * OpenSSL::PKey.load(uri [, pwd ]) -> PKey + * + * Loads a private or public key from a URI. + * It can be a file://, or a provider specific handle. + * + * === Parameters + * * _uri_ is a file:// or provider specific thing, like a TPM2 handle: + * * _pwd_ is an optional password in case the thing is an encrypted + * PEM resource. + */ +static VALUE +ossl_pkey_load_from_handle(int argc, VALUE *argv, VALUE self) +{ + EVP_PKEY *pkey; + VALUE handle, pass; + OSSL_STORE_CTX *sctx; + + rb_scan_args(argc, argv, "11", &handle, &pass); + StringValue(handle); + + const char *uri = RSTRING_PTR(handle); + sctx = OSSL_STORE_open(uri, NULL /* ui_method */, NULL /* ui_data */, + NULL /* post_process */, + NULL /* post_process_data */); + + if(sctx == NULL) + ossl_raise(ePKeyError, "Could not initialize load ctx"); + + OSSL_STORE_INFO *store1 = OSSL_STORE_load(sctx); + if(store1 == NULL) + ossl_raise(ePKeyError, "Could not load key"); + + pkey = OSSL_STORE_INFO_get1_PKEY(store1); + if(pkey == NULL) + ossl_raise(ePKeyError, "Could not decode as keyh"); + + return ossl_pkey_new(pkey); +} + static VALUE pkey_ctx_apply_options_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, ctx_v)) { @@ -1733,6 +1776,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, "load_from_handle", ossl_pkey_load_from_handle, -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_module_function(mPKey, "new_raw_private_key", ossl_pkey_new_raw_private_key, 2); From c31caac2a64a813daf6611cfcafaa82ff562e1d9 Mon Sep 17 00:00:00 2001 From: Michael Richardson Date: Tue, 12 Aug 2025 18:01:40 -0400 Subject: [PATCH 2/4] test: example of loading a key from a tpm2 provider --- sample/provider.rb | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 sample/provider.rb diff --git a/sample/provider.rb b/sample/provider.rb new file mode 100644 index 000000000..feb517b1c --- /dev/null +++ b/sample/provider.rb @@ -0,0 +1,34 @@ +require 'openssl' +require 'pathname' +require 'fileutils' + +# note that this assumes that commands like: +# tpm2_createak --tcti=swtpm:port=4523 -C 0x81010001 -G rsa -g sha256 -s rsassa -c ak_rsa.ctxi -u ak_rsa.pub -n ak_rsa.name +# tpm2_evictcontrol --tcti=swtpm:port=4523 -C o -c ak_rsa.ctx 0x81010003 +# have been run + +cwd=Pathname.new(FileUtils.pwd()) + +tpmstatedir = cwd + "tpmstate" +FileUtils.mkdir_p(tpmstatedir) +ENV['TPM2OPENSSL_TCTI']="swtpm:port=4523" +if !File.exist?(tpmstatedir + "tpm2-00.permall") + system("swtpm_setup --tpm-state #{tpmstatedir} --tpm2 --createek") +end + +# startup-clear implies not-need-init, and otherwise swtpm returns error 0x101. +# and the provider won't even load. +#system("swtpm socket --daemon --server type=tcp,port=4523 --ctrl type=tcp,port=4524 --tpmstate dir=#{tpmstatedir} --tpm2 --log file=/var/tmp/tpm2.log --flags startup-clear") +sleep(1) +prov01=OpenSSL::Provider.load("tpm2") +print "Loaded #{OpenSSL::VERSION}\n" +#print OpenSSL::PKey.methods.sort; print "\n" +#ENV['TSS2_LOG']="all+ERROR,marshal+TRACE,tcti+DEBUG" +pkey = OpenSSL::PKey.load_from_handle("handle:0x81010003") +#pkey=prov01.pkey +print pkey +print pkey.inspect +print "Done\n" + + + From 81fa1db0ca00ed87ed3e46ccea1192d93bd38343 Mon Sep 17 00:00:00 2001 From: Michael Richardson Date: Wed, 13 Aug 2025 17:11:54 -0400 Subject: [PATCH 3/4] protect against compiling without openssl 3.x --- ext/openssl/ossl_pkey.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c index d70bc2b75..81265a5c7 100644 --- a/ext/openssl/ossl_pkey.c +++ b/ext/openssl/ossl_pkey.c @@ -244,6 +244,7 @@ ossl_pkey_new_from_data(int argc, VALUE *argv, VALUE self) return ossl_pkey_wrap(pkey); } +#if OSSL_OPENSSL_PREREQ(3, 0, 0) /* * call-seq: * OpenSSL::PKey.load(uri [, pwd ]) -> PKey @@ -284,6 +285,7 @@ ossl_pkey_load_from_handle(int argc, VALUE *argv, VALUE self) return ossl_pkey_new(pkey); } +#endif static VALUE pkey_ctx_apply_options_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, ctx_v)) @@ -1776,7 +1778,9 @@ 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); +#if OSSL_OPENSSL_PREREQ(3, 0, 0) rb_define_module_function(mPKey, "load_from_handle", ossl_pkey_load_from_handle, -1); +#endif 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); From 922c4810cd2f24b758d0ba8bf8ffd5af967d7721 Mon Sep 17 00:00:00 2001 From: Michael Richardson Date: Wed, 13 Aug 2025 17:16:00 -0400 Subject: [PATCH 4/4] fix: pkey_new becomes pkey_wrap --- ext/openssl/ossl_pkey.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c index 81265a5c7..99deab747 100644 --- a/ext/openssl/ossl_pkey.c +++ b/ext/openssl/ossl_pkey.c @@ -283,7 +283,7 @@ ossl_pkey_load_from_handle(int argc, VALUE *argv, VALUE self) if(pkey == NULL) ossl_raise(ePKeyError, "Could not decode as keyh"); - return ossl_pkey_new(pkey); + return ossl_pkey_wrap(pkey); } #endif