From a6a4d0acd23b3fc85041d9096b67bcf18ccb635c Mon Sep 17 00:00:00 2001 From: Richard Levitte Date: Tue, 5 Nov 2019 17:00:33 +0100 Subject: [PATCH] Change the logic and behaviour surrounding '--api' and 'no-deprecated' At some point in time, there was a 'no-deprecated' configuration option, which had the effect of hiding all declarations of deprecated stuff, i.e. make the public API look like they were all removed. At some point in time, there was a '--api' configuration option, which had the effect of having the public API look like it did in the version given as value, on a best effort basis. In practice, this was used to get different implementations of BN_zero(), depending on the desired API compatibility level. At some later point in time, '--api' was changed to mean the same as 'no-deprecated', but only for the deprecations up to and including the desired API compatibility level. BN_zero() has been set to the pre-1.0.0 implementation ever since, unless 'no-deprecation' has been given. This change turns these options back to their original meaning, but with the slight twist that when combined, i.e. both '--api' and 'no-deprecated' is given, the declarations that are marked deprecated up to an including the desired API compatibility level are hidden, simulating that they have been removed. If no desired API compatibility level has been given, then configuration sets the current OpenSSL version by default. Furthermore, the macro OPENSSL_API_LEVEL is now used exclusively to check what API compatibility level is desired. For checking in code if `no-deprecated` has been configured for the desired API compatibility level, macros for each supported level is generated, such as OPENSSL_NO_DEPRECATED_1_1_1, corresponding to the use of DEPRECATEDIN_ macros, such as DEPRECATEDIN_1_1_1(). Just like before, to set an API compatibility level when building an application, define OPENSSL_API_COMPAT with an appropriate value. If it's desirable to hide deprecated functions up to and including that level, additionally define OPENSSL_NO_DEPRECATED (the value is ignored). Reviewed-by: Tim Hudson (Merged from https://github.com/openssl/openssl/pull/10364) --- CHANGES | 35 ++++-- Configure | 51 +++++---- include/openssl/macros.h | 205 +++++++++++++++++++++++++----------- util/mkdef.pl | 14 ++- util/perl/OpenSSL/ParseC.pm | 11 +- 5 files changed, 211 insertions(+), 105 deletions(-) diff --git a/CHANGES b/CHANGES index 91c9bc7f06..23a86ddcd1 100644 --- a/CHANGES +++ b/CHANGES @@ -9,6 +9,32 @@ Changes between 1.1.1 and 3.0.0 [xx XXX xxxx] + *) Change the interpretation of the '--api' configuration option to + mean that this is a desired API compatibility level with no + further meaning. The previous interpretation, that this would + also mean to remove all deprecated symbols up to and including + the given version, no requires that 'no-deprecated' is also used + in the configuration. + + When building applications, the desired API compatibility level + can be set with the OPENSSL_API_COMPAT macro like before. For + API compatibility version below 3.0, the old style numerical + value is valid as before, such as -DOPENSSL_API_COMPAT=0x10100000L. + For version 3.0 and on, the value is expected to be the decimal + value calculated from the major and minor version like this: + + MAJOR * 10000 + MINOR * 100 + + Examples: + + -DOPENSSL_API_COMPAT=30000 For 3.0 + -DOPENSSL_API_COMPAT=30200 For 3.2 + + To hide declarations that are deprecated up to and including the + given API compatibility level, -DOPENSSL_NO_DEPRECATED must be + given when building the application as well. + [Richard Levitte] + *) Added the X509_LOOKUP_METHOD called X509_LOOKUP_store, to allow access to certificate and CRL stores via URIs and OSSL_STORE loaders. @@ -360,15 +386,6 @@ *) Change the license to the Apache License v2.0. [Richard Levitte] - *) Change the possible version information given with OPENSSL_API_COMPAT. - It may be a pre-3.0.0 style numerical version number as it was defined - in 1.1.0, and it may also simply take the major version number. - - Because of the version numbering of pre-3.0.0 releases, the values 0, - 1 and 2 are equivalent to 0x00908000L (0.9.8), 0x10000000L (1.0.0) and - 0x10100000L (1.1.0), respectively. - [Richard Levitte] - *) Switch to a new version scheme using three numbers MAJOR.MINOR.PATCH. o Major releases (indicated by incrementing the MAJOR release number) diff --git a/Configure b/Configure index 19b05b12ad..8087da52e6 100755 --- a/Configure +++ b/Configure @@ -45,9 +45,11 @@ my $usage="Usage: Configure [no- ...] [enable- ...] [-Dxxx] [-lx # # --cross-compile-prefix Add specified prefix to binutils components. # -# --api One of 0.9.8, 1.0.0, 1.0.1, 1.0.2, 1.1.0, 1.1.1, or 3.0.0 / 3. -# Do not compile support for interfaces deprecated as of the -# specified OpenSSL version. +# --api One of 0.9.8, 1.0.0, 1.0.1, 1.0.2, 1.1.0, 1.1.1, or 3.0 +# Define the public APIs as they were for that version +# including patch releases. If 'no-deprecated' is also +# given, do not compile support for interfaces deprecated +# up to and including the specified OpenSSL version. # # no-hw-xxx do not compile support for specific crypto hardware. # Generic OpenSSL-style methods relating to this support @@ -186,15 +188,24 @@ our $BSDthreads="-pthread -D_THREAD_SAFE -D_REENTRANT"; # # API compatibility name to version number mapping. # -my $maxapi = "3.0.0"; # API for "no-deprecated" builds my $apitable = { - "3.0.0" => 3, - "1.1.1" => 2, - "1.1.0" => 2, - "1.0.2" => 1, - "1.0.1" => 1, - "1.0.0" => 1, - "0.9.8" => 0, + # This table expresses when API additions or changes can occur. + # The numbering used changes from 3.0 and on because we updated + # (solidified) our version numbering scheme at that point. + + # From 3.0 and on, we internalise the given version number in dedcimal + # as MAJOR * 10000 + MINOR * 100 + 0 + "3.0.0" => 30000, + "3.0" => 30000, + + # Note that before 3.0, we didn't have the same version number scheme. + # Still, the numbering we use here covers what we need. + "1.1.1" => 10101, + "1.1.0" => 10100, + "1.0.2" => 10002, + "1.0.1" => 10001, + "1.0.0" => 10000, + "0.9.8" => 908, }; our %table = (); @@ -844,7 +855,10 @@ while (@argvcopy) } elsif (/^--api=(.*)$/) { - $config{api}=$1; + my $api = $1; + die "Unknown API compatibility level $api" + unless defined $apitable->{$api}; + $config{api}=$apitable->{$api}; } elsif (/^--libdir=(.*)$/) { @@ -961,10 +975,6 @@ while (@argvcopy) } } -if (defined($config{api}) && !exists $apitable->{$config{api}}) { - die "***** Unsupported api compatibility level: $config{api}\n", -} - if (keys %deprecated_options) { warn "***** Deprecated options: ", @@ -1365,11 +1375,6 @@ unless($disabled{threads}) { push @{$config{openssl_feature_defines}}, "OPENSSL_THREADS"; } -# With "deprecated" disable all deprecated features. -if (defined($disabled{"deprecated"})) { - $config{api} = $maxapi; -} - my $no_shared_warn=0; if ($target{shared_target} eq "") { @@ -1503,6 +1508,8 @@ foreach (sort split(/\s+/,$target{bn_ops})) { die "Exactly one of SIXTY_FOUR_BIT|SIXTY_FOUR_BIT_LONG|THIRTY_TWO_BIT can be set in bn_ops\n" if $count > 1; +$config{api} = $config{major} * 10000 + $config{minor} * 100 + unless $config{api}; # Hack cflags for better warnings (dev option) ####################### @@ -1514,7 +1521,7 @@ $config{cxxflags} = [ map { (my $x = $_) =~ s/([\\\"])/\\$1/g; $x } @{$config{cxxflags}} ] if $config{CXX}; $config{openssl_api_defines} = [ - "OPENSSL_MIN_API=".($apitable->{$config{api} // ""} // -1) + "OPENSSL_CONFIGURED_API=".$config{api} ]; my @strict_warnings_collection=(); diff --git a/include/openssl/macros.h b/include/openssl/macros.h index 78fbd38698..0c45580405 100644 --- a/include/openssl/macros.h +++ b/include/openssl/macros.h @@ -8,6 +8,7 @@ */ #include +#include #ifndef OPENSSL_MACROS_H # define OPENSSL_MACROS_H @@ -19,14 +20,7 @@ # define NON_EMPTY_TRANSLATION_UNIT static void *dummy = &dummy; /* - * Applications should use -DOPENSSL_API_COMPAT= to suppress the - * declarations of functions deprecated in or before . If this is - * undefined, the value of the macro OPENSSL_API_MIN above is the default. - * - * For any version number up until version 1.1.x, is expected to be - * the calculated version number 0xMNNFFPPSL. For version numbers 3.0.0 and - * on, is expected to be only the major version number (i.e. 3 for - * version 3.0.0). + * Generic deprecation macro */ # ifndef DECLARE_DEPRECATED # define DECLARE_DEPRECATED(f) f; @@ -44,82 +38,169 @@ # endif /* - * We convert the OPENSSL_API_COMPAT value to an API level. The API level - * is the major version number for 3.0.0 and on. For earlier versions, it - * uses this scheme, which is close enough for our purposes: + * Applications should use -DOPENSSL_API_COMPAT= to suppress the + * declarations of functions deprecated in or before . If this is + * undefined, the value of the macro OPENSSL_CONFIGURED_API (defined in + * ) is the default. + * + * For any version number up until version 1.1.x, is expected to be + * the calculated version number 0xMNNFFPPSL. + * For version numbers 3.0 and on, is expected to be a computation + * of the major and minor numbers in decimal using this formula: + * + * MAJOR * 10000 + MINOR * 100 * - * 0.x.y 0 (0.9.8 was the last release in this series) - * 1.0.x 1 (1.0.2 was the last release in this series) - * 1.1.x 2 (1.1.1 was the last release in this series) + * So version 3.0 becomes 30000, version 3.2 becomes 30200, etc. */ -/* In case someone defined both */ -# if defined(OPENSSL_API_COMPAT) && defined(OPENSSL_API_LEVEL) -# error "Disallowed to define both OPENSSL_API_COMPAT and OPENSSL_API_LEVEL" +/* + * We use the OPENSSL_API_COMPAT value to define API level macros. These + * macros are used to enable or disable features at that API version boundary. + */ + +# ifdef OPENSSL_API_LEVEL +# error "OPENSSL_API_LEVEL must not be defined by application" # endif -# ifndef OPENSSL_API_COMPAT -# define OPENSSL_API_LEVEL OPENSSL_MIN_API -# else -# if (OPENSSL_API_COMPAT < 0x1000L) /* Major version numbers up to 16777215 */ -# define OPENSSL_API_LEVEL OPENSSL_API_COMPAT -# elif (OPENSSL_API_COMPAT & 0xF0000000L) == 0x00000000L -# define OPENSSL_API_LEVEL 0 -# elif (OPENSSL_API_COMPAT & 0xFFF00000L) == 0x10000000L -# define OPENSSL_API_LEVEL 1 -# elif (OPENSSL_API_COMPAT & 0xFFF00000L) == 0x10100000L -# define OPENSSL_API_LEVEL 2 +/* + * We figure out what API level was intended by simple numeric comparison. + * The lowest old style number we recognise is 0x00908000L, so we take some + * safety margin and assume that anything below 0x00900000L is a new style + * number. This allows new versions up to and including v943.71.83. + */ +# ifdef OPENSSL_API_COMPAT +# if OPENSSL_API_COMPAT < 0x900000L +# define OPENSSL_API_LEVEL (OPENSSL_API_COMPAT) # else - /* Major number 3 to 15 */ -# define OPENSSL_API_LEVEL ((OPENSSL_API_COMPAT >> 28) & 0xF) +# define OPENSSL_API_LEVEL \ + (((OPENSSL_API_COMPAT >> 28) & 0xF) * 10000 \ + + ((OPENSSL_API_COMPAT >> 20) & 0xFF) * 100 \ + + ((OPENSSL_API_COMPAT >> 12) & 0xFF)) # endif # endif /* - * Define API level check macros up to what makes sense. Since we - * do future deprecations, we define one API level beyond the current - * major version number. + * If OPENSSL_API_COMPAT wasn't given, we use default numbers to set + * the API compatibility level. */ +# ifndef OPENSSL_API_LEVEL +# if OPENSSL_CONFIGURED_API > 0 +# define OPENSSL_API_LEVEL (OPENSSL_CONFIGURED_API) +# else +# define OPENSSL_API_LEVEL \ + (OPENSSL_VERSION_MAJOR * 10000 + OPENSSL_VERSION_MINOR * 100) +# endif +# endif -# if OPENSSL_API_LEVEL < 4 -# define DEPRECATEDIN_4(f) DECLARE_DEPRECATED(f) -# define OPENSSL_API_4 0 -# else -# define DEPRECATEDIN_4(f) -# define OPENSSL_API_4 1 +# if OPENSSL_API_LEVEL > OPENSSL_CONFIGURED_API +# error "The requested API level higher than the configured API compatibility level" # endif -# if OPENSSL_API_LEVEL < 3 -# define DEPRECATEDIN_3(f) DECLARE_DEPRECATED(f) -# define OPENSSL_API_3 0 -# else -# define DEPRECATEDIN_3(f) -# define OPENSSL_API_3 1 +/* + * Check of sane values. + */ +/* Can't go higher than the current version. */ +# if OPENSSL_API_LEVEL > (OPENSSL_VERSION_MAJOR * 10000 + OPENSSL_VERSION_MINOR * 100) +# error "OPENSSL_API_COMPAT expresses an impossible API compatibility level" +# endif +/* OpenSSL will have no version 2.y.z */ +# if OPENSSL_API_LEVEL < 30000 && OPENSSL_API_LEVEL >= 20000 +# error "OPENSSL_API_COMPAT expresses an impossible API compatibility level" +# endif +/* Below 0.9.8 is unacceptably low */ +# if OPENSSL_API_LEVEL < 908 +# error "OPENSSL_API_COMPAT expresses an impossible API compatibility level" # endif -# if OPENSSL_API_LEVEL < 2 -# define DEPRECATEDIN_1_1_0(f) DECLARE_DEPRECATED(f) -# define OPENSSL_API_1_1_0 0 +/* + * Define macros for deprecation purposes. We always define the macros + * DEPERECATEDIN_{major}_{minor}() for all OpenSSL versions we care for, + * and OPENSSL_NO_DEPRECATED_{major}_{minor} to be used to check if + * removal of deprecated functions applies on that particular version. + */ + +# undef OPENSSL_NO_DEPRECATED_3_0 +# undef OPENSSL_NO_DEPRECATED_1_1_1 +# undef OPENSSL_NO_DEPRECATED_1_1_0 +# undef OPENSSL_NO_DEPRECATED_1_0_2 +# undef OPENSSL_NO_DEPRECATED_1_0_1 +# undef OPENSSL_NO_DEPRECATED_1_0_0 +# undef OPENSSL_NO_DEPRECATED_0_9_8 + +# if OPENSSL_API_LEVEL >= 30000 +# ifndef OPENSSL_NO_DEPRECATED +# define DEPRECATEDIN_3_0(f) DECLARE_DEPRECATED(f) +# else +# define DEPRECATEDIN_3_0(f) +# define OPENSSL_NO_DEPRECATED_3_0 +# endif # else -# define DEPRECATEDIN_1_1_0(f) -# define OPENSSL_API_1_1_0 1 +# define DEPRECATEDIN_3_0(f) f; # endif - -# if OPENSSL_API_LEVEL < 1 -# define DEPRECATEDIN_1_0_0(f) DECLARE_DEPRECATED(f) -# define OPENSSL_API_1_0_0 0 +# if OPENSSL_API_LEVEL >= 10101 +# ifndef OPENSSL_NO_DEPRECATED +# define DEPRECATEDIN_1_1_1(f) DECLARE_DEPRECATED(f) +# else +# define DEPRECATEDIN_1_1_1(f) +# define OPENSSL_NO_DEPRECATED_1_1_1 +# endif # else -# define DEPRECATEDIN_1_0_0(f) -# define OPENSSL_API_1_0_0 1 +# define DEPRECATEDIN_1_1_1(f) f; # endif - -# if OPENSSL_API_LEVEL < 0 -# define DEPRECATEDIN_0_9_8(f) DECLARE_DEPRECATED(f) -# define OPENSSL_API_0_9_8 0 +# if OPENSSL_API_LEVEL >= 10100 +# ifndef OPENSSL_NO_DEPRECATED +# define DEPRECATEDIN_1_1_0(f) DECLARE_DEPRECATED(f) +# else +# define DEPRECATEDIN_1_1_0(f) +# define OPENSSL_NO_DEPRECATED_1_1_0 +# endif # else -# define DEPRECATEDIN_0_9_8(f) -# define OPENSSL_API_0_9_8 1 +# define DEPRECATEDIN_1_1_0(f) f; # endif +# if OPENSSL_API_LEVEL >= 10002 +# ifndef OPENSSL_NO_DEPRECATED +# define DEPRECATEDIN_1_0_2(f) DECLARE_DEPRECATED(f) +# else +# define DEPRECATEDIN_1_0_2(f) +# define OPENSSL_NO_DEPRECATED_1_0_2 +# endif +# else +# define DEPRECATEDIN_1_0_2(f) f; +# endif +# if OPENSSL_API_LEVEL >= 10001 +# ifndef OPENSSL_NO_DEPRECATED +# define DEPRECATEDIN_1_0_1(f) DECLARE_DEPRECATED(f) +# else +# define DEPRECATEDIN_1_0_1(f) +# define OPENSSL_NO_DEPRECATED_1_0_1 +# endif +# else +# define DEPRECATEDIN_1_0_1(f) f; +# endif +# if OPENSSL_API_LEVEL >= 10000 +# ifndef OPENSSL_NO_DEPRECATED +# define DEPRECATEDIN_1_0_0(f) DECLARE_DEPRECATED(f) +# else +# define DEPRECATEDIN_1_0_0(f) +# define OPENSSL_NO_DEPRECATED_1_0_0 +# endif +# else +# define DEPRECATEDIN_1_0_0(f) f; +# endif +# if OPENSSL_API_LEVEL >= 908 +# ifndef OPENSSL_NO_DEPRECATED +# define DEPRECATEDIN_0_9_8(f) DECLARE_DEPRECATED(f) +# else +# define DEPRECATEDIN_0_9_8(f) +# define OPENSSL_NO_DEPRECATED_0_9_8 +# endif +# else +# define DEPRECATEDIN_0_9_8(f) f; +# endif + +/* + * Make our own variants of __FILE__ and __LINE__, depending on configuration + */ # ifndef OPENSSL_FILE # ifdef OPENSSL_NO_FILENAMES diff --git a/util/mkdef.pl b/util/mkdef.pl index 11471499df..b923cb62c3 100755 --- a/util/mkdef.pl +++ b/util/mkdef.pl @@ -100,10 +100,6 @@ die "Please supply arguments\n" # (my $SO_VARIANT = uc($target{"shlib_variant"} // '')) =~ s/\W/_/g; -my $apiv = undef; -$apiv = sprintf "%x%02x%02x", split(/\./, $config{api}) - if $config{api}; - my $libname = platform->sharedname($name); my %OS_data = ( @@ -191,11 +187,13 @@ sub feature_filter { my $verdict = ! grep { $disabled_uc{$_} } @features; - if ($apiv) { + if ($disabled{deprecated}) { foreach (@features) { - next unless /^DEPRECATEDIN_(\d+)(?:_(\d+)_(\d+))?$/; - my $symdep = sprintf "%x%02x%02x", $1, ($2 // 0), ($3 // 0); - $verdict = 0 if $apiv ge $symdep; + next unless /^DEPRECATEDIN_(\d+)_(\d+)(?:_(\d+))?$/; + my $symdep = $1 * 10000 + $2 * 100 + ($3 // 0); + $verdict = 0 if $config{api} >= $symdep; + print STDERR "DEBUG: \$symdep = $symdep, \$verdict = $verdict\n" + if $1 == 0; } } diff --git a/util/perl/OpenSSL/ParseC.pm b/util/perl/OpenSSL/ParseC.pm index 286fa7e0ef..2db43e2a61 100644 --- a/util/perl/OpenSSL/ParseC.pm +++ b/util/perl/OpenSSL/ParseC.pm @@ -65,11 +65,14 @@ my @opensslcpphandlers = ( # These are used to convert certain pre-precessor expressions into # others that @cpphandlers have a better chance to understand. - { regexp => qr/#if (!?)OPENSSL_API_([0-9_]+)$/, + # This changes any OPENSSL_NO_DEPRECATED_x_y[_z] check to a check of + # OPENSSL_NO_DEPRECATEDIN_x_y[_z]. That's due to + # creating OPENSSL_NO_DEPRECATED_x_y[_z], but the ordinals files using + # DEPRECATEDIN_x_y[_z]. + { regexp => qr/#if(def|ndef) OPENSSL_NO_DEPRECATED_(\d+_\d+(?:_\d+)?)$/, massager => sub { - my $cnd = $1 eq '!' ? 'ndef' : 'def'; return (<<"EOF"); -#if$cnd DEPRECATEDIN_$2 +#if$1 OPENSSL_NO_DEPRECATEDIN_$2 EOF } } @@ -261,7 +264,7 @@ my @opensslchandlers = ( # We trick the parser by pretending that the declaration is wrapped in a # check if the DEPRECATEDIN macro is defined or not. Callers of parse() # will have to decide what to do with it. - { regexp => qr/(DEPRECATEDIN_\d+(?:_\d+_\d+)?)<<<\((.*)\)>>>/, + { regexp => qr/(DEPRECATEDIN_\d+_\d+(?:_\d+)?)<<<\((.*)\)>>>/, massager => sub { return (<<"EOF"); #ifndef $1 $2; -- 2.25.1