From 4d564e837a69e041081cda689b18ed92302d979a Mon Sep 17 00:00:00 2001 From: Heikki Vatiainen Date: Thu, 23 Dec 2021 22:42:17 +0200 Subject: [PATCH] GH-315 Use 64 bit constants with OpenSSL 3.0.0 and later. This is a partial solution to GH-315. 64 bit constants are used with OpenSSL 3.0.0 and later when perl supports 64 bit integers. Otherwise constants, SSL_CTX_get_options() and its related functions continue to use double as the flag type. OpenSSL 3.0.0-alpha17 switched from long to uint64_t with SSL_CTX_get_options() family of functions. --- Makefile.PL | 12 ++++++ SSLeay.xs | 49 +++++++++++++++++++++++++ constants.c | 4 ++ helper_script/update-exported-constants | 11 +++++- typemap | 8 ++++ 5 files changed, 83 insertions(+), 1 deletion(-) diff --git a/Makefile.PL b/Makefile.PL index fcb1d007..66a16983 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -111,6 +111,18 @@ my %eumm_args = ( ssleay(), ); +# See if integers are only 32 bits long. If they are, add a flag to +# CCFLAGS. Since OpenSSL 1.1.0, a growing number of APIs are using 64 +# bit integers. This causes a problem if Perl is compiled without 64 +# bit integers. DEFINE is not used because Makefile.PL command line +# DEFINE argument is used for enabling compile time PR1 +# etc. debugging. +# +# Note: 32bit integers are treated as the non-default case. When you +# use this define, do it so that 64bit case is the default whenever +# possible. This is safer for future library and Net::SSLeay releases. +$eumm_args{CCFLAGS} = "-DNET_SSLEAY_32BIT_INT_PERL $Config{ccflags}" if !defined $Config{use64bitint} || $Config{use64bitint} ne 'define'; + # This can go when EU::MM older than 6.58 are gone $eumm_args{AUTHOR} = join(', ', @{$eumm_args{AUTHOR}}) unless eval { ExtUtils::MakeMaker->VERSION(6.58); }; diff --git a/SSLeay.xs b/SSLeay.xs index 348f5e9e..13159b1b 100644 --- a/SSLeay.xs +++ b/SSLeay.xs @@ -200,6 +200,17 @@ which conflicts with perls #endif #undef BLOCK +/* Beginning with OpenSSL 3.0.0-alpha17, SSL_CTX_get_options() and + * related functions return uint64_t instead of long. For this reason + * constant() in constant.c and Net::SSleay must also be able to + * return 64bit constants. However, this creates a problem with Perls + * that have only 32 bit integers. The define below helps with + * handling this API change. + */ +#if (OPENSSL_VERSION_NUMBER < 0x30000000L) || defined(NET_SSLEAY_32BIT_INT_PERL) +#define NET_SSLEAY_32BIT_CONSTANTS +#endif + /* Debugging output - to enable use: * * perl Makefile.PL DEFINE=-DSHOW_XS_DEBUG @@ -1958,6 +1969,7 @@ CODE: PR1("CLONE: but USE_ITHREADS not defined\n"); #endif +#ifdef NET_SSLEAY_32BIT_CONSTANTS double constant(name) char * name @@ -1967,6 +1979,19 @@ constant(name) OUTPUT: RETVAL +#else + +uint64_t +constant(name) + char * name + CODE: + errno = 0; + RETVAL = constant(name, strlen(name)); + OUTPUT: + RETVAL + +#endif + int hello() CODE: @@ -2808,6 +2833,8 @@ SSL_CTX_ctrl(ctx,cmd,larg,parg) long larg char * parg +#ifdef NET_SSLEAY_32BIT_CONSTANTS + long SSL_get_options(ssl) SSL * ssl @@ -2826,6 +2853,28 @@ SSL_CTX_set_options(ctx,op) SSL_CTX * ctx long op +#else + +uint64_t +SSL_get_options(ssl) + SSL * ssl + +uint64_t +SSL_set_options(ssl,op) + SSL * ssl + uint64_t op + +uint64_t +SSL_CTX_get_options(ctx) + SSL_CTX * ctx + +uint64_t +SSL_CTX_set_options(ctx,op) + SSL_CTX * ctx + uint64_t op + +#endif + #if OPENSSL_VERSION_NUMBER >= 0x10000000L struct lhash_st_SSL_SESSION * diff --git a/constants.c b/constants.c index 099c338f..abe44c32 100644 --- a/constants.c +++ b/constants.c @@ -5,7 +5,11 @@ * helper_script/update-exported-constants. */ +#ifdef NET_SSLEAY_32BIT_CONSTANTS static double +#else +static uint64_t +#endif constant (const char *name, size_t len) { /* Initially switch on the length of the name. */ switch (len) { diff --git a/helper_script/update-exported-constants b/helper_script/update-exported-constants index 4d179ee2..34c1cad7 100755 --- a/helper_script/update-exported-constants +++ b/helper_script/update-exported-constants @@ -377,7 +377,16 @@ sub assignment_clause_for_type { } sub C_constant_return_type { - return 'static double'; + my $ret = <<'END'; +#ifdef NET_SSLEAY_32BIT_CONSTANTS +static double +#else +static uint64_t +#endif +END + # Newline is automatically added, remove ours. + chomp($ret); + return $ret; } sub return_statement_for_notfound { diff --git a/typemap b/typemap index 0eae0d38..99fbada7 100644 --- a/typemap +++ b/typemap @@ -86,7 +86,15 @@ OSSL_LIB_CTX * T_PTR OSSL_PROVIDER * T_PTR const OSSL_PROVIDER * T_PTR +uint64_t T_UINT64 + +OUTPUT +T_UINT64 + sv_setuv($arg, (UV)$var); + INPUT +T_UINT64 + $var = (uint64_t)SvUV($arg) T_PERL_IO_HANDLE if ($arg && SvOK($arg) && SvROK($arg)) {