From 1f1e1fc27d2c503481cc04cab9766cf4230a1fd7 Mon Sep 17 00:00:00 2001 From: Kazuki Yamaguchi Date: Tue, 17 Feb 2026 00:44:12 +0900 Subject: [PATCH 1/5] Add const qualifiers for OpenSSL 4.0 compatibility There is an ongoing effort in OpenSSL's master branch to change a number of functions to return const pointers. --- ext/openssl/ossl_ocsp.c | 5 ++--- ext/openssl/ossl_ts.c | 2 +- ext/openssl/ossl_x509.h | 12 ++++++------ ext/openssl/ossl_x509attr.c | 6 +++--- ext/openssl/ossl_x509cert.c | 9 ++++----- ext/openssl/ossl_x509crl.c | 7 +++---- ext/openssl/ossl_x509ext.c | 16 ++++++++++++---- ext/openssl/ossl_x509name.c | 2 +- ext/openssl/ossl_x509req.c | 4 ++-- ext/openssl/ossl_x509revoked.c | 4 ++-- ext/openssl/ossl_x509store.c | 10 ++++------ 11 files changed, 40 insertions(+), 37 deletions(-) diff --git a/ext/openssl/ossl_ocsp.c b/ext/openssl/ossl_ocsp.c index ddb67fcf0..9dd4b466d 100644 --- a/ext/openssl/ossl_ocsp.c +++ b/ext/openssl/ossl_ocsp.c @@ -922,7 +922,7 @@ ossl_ocspbres_get_status(VALUE self) VALUE ext = rb_ary_new(); int ext_count = OCSP_SINGLERESP_get_ext_count(single); for (int j = 0; j < ext_count; j++) { - X509_EXTENSION *x509ext = OCSP_SINGLERESP_get_ext(single, j); + const X509_EXTENSION *x509ext = OCSP_SINGLERESP_get_ext(single, j); rb_ary_push(ext, ossl_x509ext_new(x509ext)); } rb_ary_push(ary, ext); @@ -1341,7 +1341,6 @@ static VALUE ossl_ocspsres_get_extensions(VALUE self) { OCSP_SINGLERESP *sres; - X509_EXTENSION *ext; int count, i; VALUE ary; @@ -1350,7 +1349,7 @@ ossl_ocspsres_get_extensions(VALUE self) count = OCSP_SINGLERESP_get_ext_count(sres); ary = rb_ary_new2(count); for (i = 0; i < count; i++) { - ext = OCSP_SINGLERESP_get_ext(sres, i); + const X509_EXTENSION *ext = OCSP_SINGLERESP_get_ext(sres, i); rb_ary_push(ary, ossl_x509ext_new(ext)); /* will dup */ } diff --git a/ext/openssl/ossl_ts.c b/ext/openssl/ossl_ts.c index b31a854a6..393e08acf 100644 --- a/ext/openssl/ossl_ts.c +++ b/ext/openssl/ossl_ts.c @@ -706,7 +706,7 @@ ossl_ts_resp_get_tsa_certificate(VALUE self) TS_RESP *resp; PKCS7 *p7; PKCS7_SIGNER_INFO *ts_info; - X509 *cert; + const X509 *cert; GetTSResponse(self, resp); if (!(p7 = TS_RESP_get_token(resp))) diff --git a/ext/openssl/ossl_x509.h b/ext/openssl/ossl_x509.h index d25167ee7..71932ef1a 100644 --- a/ext/openssl/ossl_x509.h +++ b/ext/openssl/ossl_x509.h @@ -29,7 +29,7 @@ void Init_ossl_x509(void); */ extern VALUE cX509Attr; -VALUE ossl_x509attr_new(X509_ATTRIBUTE *); +VALUE ossl_x509attr_new(const X509_ATTRIBUTE *); X509_ATTRIBUTE *GetX509AttrPtr(VALUE); void Init_ossl_x509attr(void); @@ -38,7 +38,7 @@ void Init_ossl_x509attr(void); */ extern VALUE cX509Cert; -VALUE ossl_x509_new(X509 *); +VALUE ossl_x509_new(const X509 *); X509 *GetX509CertPtr(VALUE); X509 *DupX509CertPtr(VALUE); void Init_ossl_x509cert(void); @@ -46,7 +46,7 @@ void Init_ossl_x509cert(void); /* * X509CRL */ -VALUE ossl_x509crl_new(X509_CRL *); +VALUE ossl_x509crl_new(const X509_CRL *); X509_CRL *GetX509CRLPtr(VALUE); void Init_ossl_x509crl(void); @@ -55,14 +55,14 @@ void Init_ossl_x509crl(void); */ extern VALUE cX509Ext; -VALUE ossl_x509ext_new(X509_EXTENSION *); +VALUE ossl_x509ext_new(const X509_EXTENSION *); X509_EXTENSION *GetX509ExtPtr(VALUE); void Init_ossl_x509ext(void); /* * X509Name */ -VALUE ossl_x509name_new(X509_NAME *); +VALUE ossl_x509name_new(const X509_NAME *); X509_NAME *GetX509NamePtr(VALUE); void Init_ossl_x509name(void); @@ -77,7 +77,7 @@ void Init_ossl_x509req(void); */ extern VALUE cX509Rev; -VALUE ossl_x509revoked_new(X509_REVOKED *); +VALUE ossl_x509revoked_new(const X509_REVOKED *); X509_REVOKED *DupX509RevokedPtr(VALUE); void Init_ossl_x509revoked(void); diff --git a/ext/openssl/ossl_x509attr.c b/ext/openssl/ossl_x509attr.c index 4769e56e1..4368e2edd 100644 --- a/ext/openssl/ossl_x509attr.c +++ b/ext/openssl/ossl_x509attr.c @@ -48,7 +48,7 @@ static const rb_data_type_t ossl_x509attr_type = { * Public */ VALUE -ossl_x509attr_new(X509_ATTRIBUTE *attr) +ossl_x509attr_new(const X509_ATTRIBUTE *attr) { X509_ATTRIBUTE *new; VALUE obj; @@ -196,7 +196,7 @@ ossl_x509attr_set_value(VALUE self, VALUE value) ossl_raise(eX509AttrError, "attribute value must be ASN1::Set"); if (X509_ATTRIBUTE_count(attr)) { /* populated, reset first */ - ASN1_OBJECT *obj = X509_ATTRIBUTE_get0_object(attr); + const ASN1_OBJECT *obj = X509_ATTRIBUTE_get0_object(attr); X509_ATTRIBUTE *new_attr = X509_ATTRIBUTE_create_by_OBJ(NULL, obj, 0, NULL, -1); if (!new_attr) { sk_ASN1_TYPE_pop_free(sk, ASN1_TYPE_free); @@ -240,7 +240,7 @@ ossl_x509attr_get_value(VALUE self) count = X509_ATTRIBUTE_count(attr); for (i = 0; i < count; i++) - sk_ASN1_TYPE_push(sk, X509_ATTRIBUTE_get0_type(attr, i)); + sk_ASN1_TYPE_push(sk, (ASN1_TYPE *)X509_ATTRIBUTE_get0_type(attr, i)); if ((len = i2d_ASN1_SET_ANY(sk, NULL)) <= 0) { sk_ASN1_TYPE_free(sk); diff --git a/ext/openssl/ossl_x509cert.c b/ext/openssl/ossl_x509cert.c index 95679c7d2..8902a0a22 100644 --- a/ext/openssl/ossl_x509cert.c +++ b/ext/openssl/ossl_x509cert.c @@ -48,7 +48,7 @@ static const rb_data_type_t ossl_x509_type = { * Public */ VALUE -ossl_x509_new(X509 *x509) +ossl_x509_new(const X509 *x509) { X509 *new; VALUE obj; @@ -345,7 +345,7 @@ static VALUE ossl_x509_get_subject(VALUE self) { X509 *x509; - X509_NAME *name; + const X509_NAME *name; GetX509(self, x509); if (!(name = X509_get_subject_name(x509))) { /* NO DUP - don't free! */ @@ -380,7 +380,7 @@ static VALUE ossl_x509_get_issuer(VALUE self) { X509 *x509; - X509_NAME *name; + const X509_NAME *name; GetX509(self, x509); if(!(name = X509_get_issuer_name(x509))) { /* NO DUP - don't free! */ @@ -603,14 +603,13 @@ ossl_x509_get_extensions(VALUE self) { X509 *x509; int count, i; - X509_EXTENSION *ext; VALUE ary; GetX509(self, x509); count = X509_get_ext_count(x509); ary = rb_ary_new_capa(count); for (i=0; i Date: Tue, 17 Feb 2026 16:16:54 +0900 Subject: [PATCH 2/5] ssl: fix test_tmp_dh and test_tmp_dh_callback with OpenSSL master OpenSSL master added support for RFC 7919 groups in TLS 1.2. They are preferred over SSLContext#tmp_dh= or #tmp_dh_callback= values if the client advertises them in the supported_groups extension. --- test/openssl/test_ssl.rb | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/test/openssl/test_ssl.rb b/test/openssl/test_ssl.rb index ce1b2c1e9..3a3e8a958 100644 --- a/test/openssl/test_ssl.rb +++ b/test/openssl/test_ssl.rb @@ -1909,7 +1909,9 @@ def test_tmp_dh_callback } } start_server(ctx_proc: ctx_proc) do |port| - server_connect(port) { |ssl| + ctx = OpenSSL::SSL::SSLContext.new + ctx.groups = "P-256" # Exclude RFC7919 groups + server_connect(port, ctx) { |ssl| assert called, "dh callback should be called" assert_equal dh.to_der, ssl.tmp_key.to_der } @@ -2172,7 +2174,9 @@ def test_tmp_dh ctx.tmp_dh = dh } start_server(ctx_proc: ctx_proc) do |port| - server_connect(port) { |ssl| + ctx = OpenSSL::SSL::SSLContext.new + ctx.groups = "P-256" # Exclude RFC7919 groups + server_connect(port, ctx) { |ssl| assert_equal dh.to_der, ssl.tmp_key.to_der } end From 727c4a7f52e59f51fe26e3babd4ae0cfbbc683a5 Mon Sep 17 00:00:00 2001 From: Kazuki Yamaguchi Date: Thu, 26 Feb 2026 21:33:19 +0900 Subject: [PATCH 3/5] asn1: support opaque ASN1_STRING in OpenSSL 4.0 ASN1_STRING has been made opaque in OpenSSL's master branch. Use the new accessor functions instead of accessing fields directly. --- ext/openssl/extconf.rb | 3 +++ ext/openssl/openssl_missing.h | 23 ++++++++++++++++++++++ ext/openssl/ossl_asn1.c | 37 +++++++++++++++++++---------------- 3 files changed, 46 insertions(+), 17 deletions(-) diff --git a/ext/openssl/extconf.rb b/ext/openssl/extconf.rb index a897c86b6..06ed4f6ac 100644 --- a/ext/openssl/extconf.rb +++ b/ext/openssl/extconf.rb @@ -169,6 +169,9 @@ def find_openssl_library # added in 3.5.0 have_func("SSL_get0_peer_signature_name(NULL, NULL)", ssl_h) +# added in 4.0.0 +have_func("ASN1_BIT_STRING_set1(NULL, NULL, 0, 0)", "openssl/asn1.h") + Logging::message "=== Checking done. ===\n" # Append flags from environment variables. diff --git a/ext/openssl/openssl_missing.h b/ext/openssl/openssl_missing.h index 6592f9cce..ed3b5b7c0 100644 --- a/ext/openssl/openssl_missing.h +++ b/ext/openssl/openssl_missing.h @@ -29,4 +29,27 @@ # define EVP_PKEY_eq(a, b) EVP_PKEY_cmp(a, b) #endif +/* added in 4.0.0 */ +#ifndef HAVE_ASN1_BIT_STRING_SET1 +static inline int +ASN1_BIT_STRING_set1(ASN1_BIT_STRING *bitstr, const uint8_t *data, + size_t length, int unused_bits) +{ + if (length > INT_MAX || !ASN1_STRING_set(bitstr, data, (int)length)) + return 0; + bitstr->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07); + bitstr->flags |= ASN1_STRING_FLAG_BITS_LEFT | unused_bits; + return 1; +} + +static inline int +ASN1_BIT_STRING_get_length(const ASN1_BIT_STRING *bitstr, size_t *length, + int *unused_bits) +{ + *length = bitstr->length; + *unused_bits = bitstr->flags & 0x07; + return 1; +} +#endif + #endif /* _OSSL_OPENSSL_MISSING_H_ */ diff --git a/ext/openssl/ossl_asn1.c b/ext/openssl/ossl_asn1.c index 71a87f046..9e9e713f4 100644 --- a/ext/openssl/ossl_asn1.c +++ b/ext/openssl/ossl_asn1.c @@ -226,7 +226,7 @@ obj_to_asn1int(VALUE obj) } static ASN1_BIT_STRING* -obj_to_asn1bstr(VALUE obj, long unused_bits) +obj_to_asn1bstr(VALUE obj, int unused_bits) { ASN1_BIT_STRING *bstr; @@ -234,11 +234,11 @@ obj_to_asn1bstr(VALUE obj, long unused_bits) ossl_raise(eASN1Error, "unused_bits for a bitstring value must be in "\ "the range 0 to 7"); StringValue(obj); - if(!(bstr = ASN1_BIT_STRING_new())) - ossl_raise(eASN1Error, NULL); - ASN1_BIT_STRING_set(bstr, (unsigned char *)RSTRING_PTR(obj), RSTRING_LENINT(obj)); - bstr->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT|0x07); /* clear */ - bstr->flags |= ASN1_STRING_FLAG_BITS_LEFT | unused_bits; + if (!(bstr = ASN1_BIT_STRING_new())) + ossl_raise(eASN1Error, "ASN1_BIT_STRING_new"); + if (!ASN1_BIT_STRING_set1(bstr, (uint8_t *)RSTRING_PTR(obj), + RSTRING_LEN(obj), unused_bits)) + ossl_raise(eASN1Error, "ASN1_BIT_STRING_set1"); return bstr; } @@ -362,22 +362,25 @@ decode_int(unsigned char* der, long length) } static VALUE -decode_bstr(unsigned char* der, long length, long *unused_bits) +decode_bstr(unsigned char* der, long length, int *unused_bits) { ASN1_BIT_STRING *bstr; const unsigned char *p; - long len; + size_t len; VALUE ret; + int state; p = der; - if(!(bstr = d2i_ASN1_BIT_STRING(NULL, &p, length))) - ossl_raise(eASN1Error, NULL); - len = bstr->length; - *unused_bits = 0; - if(bstr->flags & ASN1_STRING_FLAG_BITS_LEFT) - *unused_bits = bstr->flags & 0x07; - ret = rb_str_new((const char *)bstr->data, len); + if (!(bstr = d2i_ASN1_BIT_STRING(NULL, &p, length))) + ossl_raise(eASN1Error, "d2i_ASN1_BIT_STRING"); + if (!ASN1_BIT_STRING_get_length(bstr, &len, unused_bits)) { + ASN1_BIT_STRING_free(bstr); + ossl_raise(eASN1Error, "ASN1_BIT_STRING_get_length"); + } + ret = ossl_str_new((const char *)ASN1_STRING_get0_data(bstr), len, &state); ASN1_BIT_STRING_free(bstr); + if (state) + rb_jump_tag(state); return ret; } @@ -761,7 +764,7 @@ int_ossl_asn1_decode0_prim(unsigned char **pp, long length, long hlen, int tag, { VALUE value, asn1data; unsigned char *p; - long flag = 0; + int flag = 0; p = *pp; @@ -818,7 +821,7 @@ int_ossl_asn1_decode0_prim(unsigned char **pp, long length, long hlen, int tag, asn1data = rb_obj_alloc(klass); ossl_asn1_initialize(4, args, asn1data); if(tag == V_ASN1_BIT_STRING){ - rb_ivar_set(asn1data, sivUNUSED_BITS, LONG2NUM(flag)); + rb_ivar_set(asn1data, sivUNUSED_BITS, INT2NUM(flag)); } } else { From 8101b7bd012eb4e341827c52bc7df0bc667e7d55 Mon Sep 17 00:00:00 2001 From: Kazuki Yamaguchi Date: Thu, 26 Feb 2026 22:17:47 +0900 Subject: [PATCH 4/5] fixup! Add const qualifiers for OpenSSL 4.0 compatibility --- ext/openssl/ossl_x509attr.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ext/openssl/ossl_x509attr.c b/ext/openssl/ossl_x509attr.c index 4368e2edd..b0773e7a7 100644 --- a/ext/openssl/ossl_x509attr.c +++ b/ext/openssl/ossl_x509attr.c @@ -54,7 +54,8 @@ ossl_x509attr_new(const X509_ATTRIBUTE *attr) VALUE obj; obj = NewX509Attr(cX509Attr); - new = X509_ATTRIBUTE_dup(attr); + /* OpenSSL 1.1.1 takes a non-const pointer */ + new = X509_ATTRIBUTE_dup((X509_ATTRIBUTE *)attr); if (!new) ossl_raise(eX509AttrError, "X509_ATTRIBUTE_dup"); SetX509Attr(obj, new); From 67f20c0e2143349e836b4b3effbe211201c40611 Mon Sep 17 00:00:00 2001 From: Kazuki Yamaguchi Date: Thu, 26 Feb 2026 22:22:58 +0900 Subject: [PATCH 5/5] fixup! Add const qualifiers for OpenSSL 4.0 compatibility --- ext/openssl/ossl_x509cert.c | 3 ++- ext/openssl/ossl_x509crl.c | 3 ++- ext/openssl/ossl_x509ext.c | 3 ++- ext/openssl/ossl_x509name.c | 3 ++- ext/openssl/ossl_x509revoked.c | 3 ++- 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/ext/openssl/ossl_x509cert.c b/ext/openssl/ossl_x509cert.c index 8902a0a22..de246759a 100644 --- a/ext/openssl/ossl_x509cert.c +++ b/ext/openssl/ossl_x509cert.c @@ -54,7 +54,8 @@ ossl_x509_new(const X509 *x509) VALUE obj; obj = NewX509(cX509Cert); - new = X509_dup(x509); + /* OpenSSL 1.1.1 takes a non-const pointer */ + new = X509_dup((X509 *)x509); if (!new) ossl_raise(eX509CertError, "X509_dup"); SetX509(obj, new); diff --git a/ext/openssl/ossl_x509crl.c b/ext/openssl/ossl_x509crl.c index 3e9ad55e6..9b59bda9e 100644 --- a/ext/openssl/ossl_x509crl.c +++ b/ext/openssl/ossl_x509crl.c @@ -64,7 +64,8 @@ ossl_x509crl_new(const X509_CRL *crl) VALUE obj; obj = NewX509CRL(cX509CRL); - tmp = X509_CRL_dup(crl); + /* OpenSSL 1.1.1 takes a non-const pointer */ + tmp = X509_CRL_dup((X509_CRL *)crl); if (!tmp) ossl_raise(eX509CRLError, "X509_CRL_dup"); SetX509CRL(obj, tmp); diff --git a/ext/openssl/ossl_x509ext.c b/ext/openssl/ossl_x509ext.c index ad14b15c3..1fe727d3f 100644 --- a/ext/openssl/ossl_x509ext.c +++ b/ext/openssl/ossl_x509ext.c @@ -68,7 +68,8 @@ ossl_x509ext_new(const X509_EXTENSION *ext) VALUE obj; obj = NewX509Ext(cX509Ext); - new = X509_EXTENSION_dup(ext); + /* OpenSSL 1.1.1 takes a non-const pointer */ + new = X509_EXTENSION_dup((X509_EXTENSION *)ext); if (!new) ossl_raise(eX509ExtError, "X509_EXTENSION_dup"); SetX509Ext(obj, new); diff --git a/ext/openssl/ossl_x509name.c b/ext/openssl/ossl_x509name.c index 86f413002..2b66a4a09 100644 --- a/ext/openssl/ossl_x509name.c +++ b/ext/openssl/ossl_x509name.c @@ -59,7 +59,8 @@ ossl_x509name_new(const X509_NAME *name) VALUE obj; obj = NewX509Name(cX509Name); - new = X509_NAME_dup(name); + /* OpenSSL 1.1.1 takes a non-const pointer */ + new = X509_NAME_dup((X509_NAME *)name); if (!new) ossl_raise(eX509NameError, "X509_NAME_dup"); SetX509Name(obj, new); diff --git a/ext/openssl/ossl_x509revoked.c b/ext/openssl/ossl_x509revoked.c index 8fa4008fc..0151961e9 100644 --- a/ext/openssl/ossl_x509revoked.c +++ b/ext/openssl/ossl_x509revoked.c @@ -54,7 +54,8 @@ ossl_x509revoked_new(const X509_REVOKED *rev) VALUE obj; obj = NewX509Rev(cX509Rev); - new = X509_REVOKED_dup(rev); + /* OpenSSL 1.1.1 takes a non-const pointer */ + new = X509_REVOKED_dup((X509_REVOKED *)rev); if (!new) ossl_raise(eX509RevError, "X509_REVOKED_dup"); SetX509Rev(obj, new);