Change the logic and behaviour surrounding '--api' and 'no-deprecated'
authorRichard Levitte <levitte@openssl.org>
Tue, 5 Nov 2019 16:00:33 +0000 (17:00 +0100)
committerRichard Levitte <levitte@openssl.org>
Thu, 7 Nov 2019 10:37:25 +0000 (11:37 +0100)
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 <tjh@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/10364)

CHANGES
Configure
include/openssl/macros.h
util/mkdef.pl
util/perl/OpenSSL/ParseC.pm

diff --git a/CHANGES b/CHANGES
index 91c9bc7..23a86dd 100644 (file)
--- 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.
   *) 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)
index 19b05b1..8087da5 100755 (executable)
--- a/Configure
+++ b/Configure
@@ -45,9 +45,11 @@ my $usage="Usage: Configure [no-<cipher> ...] [enable-<cipher> ...] [-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=();
index 78fbd38..0c45580 100644 (file)
@@ -8,6 +8,7 @@
  */
 
 #include <openssl/opensslconf.h>
+#include <openssl/opensslv.h>
 
 #ifndef OPENSSL_MACROS_H
 # define OPENSSL_MACROS_H
 # define NON_EMPTY_TRANSLATION_UNIT static void *dummy = &dummy;
 
 /*
- * Applications should use -DOPENSSL_API_COMPAT=<version> to suppress the
- * declarations of functions deprecated in or before <version>.  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, <version> is expected to be
- * the calculated version number 0xMNNFFPPSL.  For version numbers 3.0.0 and
- * on, <version> 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;
 # 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=<version> to suppress the
+ * declarations of functions deprecated in or before <version>.  If this is
+ * undefined, the value of the macro OPENSSL_CONFIGURED_API (defined in
+ * <openssl/opensslconf.h>) is the default.
+ *
+ * For any version number up until version 1.1.x, <version> is expected to be
+ * the calculated version number 0xMNNFFPPSL.
+ * For version numbers 3.0 and on, <version> 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
index 1147149..b923cb6 100755 (executable)
@@ -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;
         }
     }
 
index 286fa7e..2db43e2 100644 (file)
@@ -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 <openssl/macros.h>
+    # 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;