3333static VALUE cCipher ;
3434static VALUE eCipherError ;
3535static VALUE eAuthTagError ;
36- static ID id_auth_tag_len , id_key_set ;
36+ static ID id_auth_tag_len , id_key_set , id_cipher_holder ;
3737
3838static VALUE ossl_cipher_alloc (VALUE klass );
3939static void ossl_cipher_free (void * ptr );
@@ -46,30 +46,58 @@ static const rb_data_type_t ossl_cipher_type = {
4646 0 , 0 , RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED ,
4747};
4848
49+ #ifdef OSSL_USE_PROVIDER
50+ static void
51+ ossl_evp_cipher_free (void * ptr )
52+ {
53+ // This is safe to call against const EVP_CIPHER * returned by
54+ // EVP_get_cipherbyname()
55+ EVP_CIPHER_free (ptr );
56+ }
57+
58+ static const rb_data_type_t ossl_evp_cipher_holder_type = {
59+ "OpenSSL/EVP_CIPHER" ,
60+ {
61+ .dfree = ossl_evp_cipher_free ,
62+ },
63+ 0 , 0 , RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED ,
64+ };
65+ #endif
66+
4967/*
5068 * PUBLIC
5169 */
5270const EVP_CIPHER *
53- ossl_evp_get_cipherbyname (VALUE obj )
71+ ossl_evp_cipher_fetch (VALUE obj , volatile VALUE * holder )
5472{
73+ * holder = Qnil ;
5574 if (rb_obj_is_kind_of (obj , cCipher )) {
56- EVP_CIPHER_CTX * ctx ;
57-
58- GetCipher (obj , ctx );
59-
60- return EVP_CIPHER_CTX_cipher (ctx );
75+ EVP_CIPHER_CTX * ctx ;
76+ GetCipher (obj , ctx );
77+ EVP_CIPHER * cipher = (EVP_CIPHER * )EVP_CIPHER_CTX_cipher (ctx );
78+ #ifdef OSSL_USE_PROVIDER
79+ * holder = TypedData_Wrap_Struct (0 , & ossl_evp_cipher_holder_type , NULL );
80+ if (!EVP_CIPHER_up_ref (cipher ))
81+ ossl_raise (eCipherError , "EVP_CIPHER_up_ref" );
82+ RTYPEDDATA_DATA (* holder ) = cipher ;
83+ #endif
84+ return cipher ;
6185 }
62- else {
63- const EVP_CIPHER * cipher ;
6486
65- StringValueCStr (obj );
66- cipher = EVP_get_cipherbyname (RSTRING_PTR (obj ));
67- if (!cipher )
68- ossl_raise (eCipherError , "unsupported cipher algorithm: %" PRIsVALUE ,
69- obj );
70-
71- return cipher ;
87+ const char * name = StringValueCStr (obj );
88+ EVP_CIPHER * cipher = (EVP_CIPHER * )EVP_get_cipherbyname (name );
89+ #ifdef OSSL_USE_PROVIDER
90+ if (!cipher ) {
91+ ossl_clear_error ();
92+ * holder = TypedData_Wrap_Struct (0 , & ossl_evp_cipher_holder_type , NULL );
93+ cipher = EVP_CIPHER_fetch (NULL , name , NULL );
94+ RTYPEDDATA_DATA (* holder ) = cipher ;
7295 }
96+ #endif
97+ if (!cipher )
98+ ossl_raise (eCipherError , "unsupported cipher algorithm: %" PRIsVALUE ,
99+ obj );
100+ return cipher ;
73101}
74102
75103VALUE
@@ -78,6 +106,9 @@ ossl_cipher_new(const EVP_CIPHER *cipher)
78106 VALUE ret ;
79107 EVP_CIPHER_CTX * ctx ;
80108
109+ // NOTE: This does not set id_cipher_holder because this function should
110+ // only be called from ossl_engine.c, which will not use any
111+ // reference-counted ciphers.
81112 ret = ossl_cipher_alloc (cCipher );
82113 AllocCipher (ret , ctx );
83114 if (EVP_CipherInit_ex (ctx , cipher , NULL , NULL , NULL , -1 ) != 1 )
@@ -114,15 +145,17 @@ ossl_cipher_initialize(VALUE self, VALUE str)
114145{
115146 EVP_CIPHER_CTX * ctx ;
116147 const EVP_CIPHER * cipher ;
148+ VALUE cipher_holder ;
117149
118150 GetCipherInit (self , ctx );
119151 if (ctx ) {
120152 ossl_raise (rb_eRuntimeError , "Cipher already initialized!" );
121153 }
122- cipher = ossl_evp_get_cipherbyname (str );
154+ cipher = ossl_evp_cipher_fetch (str , & cipher_holder );
123155 AllocCipher (self , ctx );
124156 if (EVP_CipherInit_ex (ctx , cipher , NULL , NULL , NULL , -1 ) != 1 )
125- ossl_raise (eCipherError , NULL );
157+ ossl_raise (eCipherError , "EVP_CipherInit_ex" );
158+ rb_ivar_set (self , id_cipher_holder , cipher_holder );
126159
127160 return self ;
128161}
@@ -1106,4 +1139,5 @@ Init_ossl_cipher(void)
11061139
11071140 id_auth_tag_len = rb_intern_const ("auth_tag_len" );
11081141 id_key_set = rb_intern_const ("key_set" );
1142+ id_cipher_holder = rb_intern_const ("EVP_CIPHER_holder" );
11091143}
0 commit comments