From 819c9658ed5d1eb80b8d48e6a033268340aa4445 Mon Sep 17 00:00:00 2001
From: Benjamin Drung <benjamin.drung@profitbricks.com>
Date: Fri, 18 Nov 2016 14:41:19 +0100
Subject: [PATCH] Support initializing OpenSSL 1.1

salt-call fails to run with OpenSSL 1.1:

Traceback (most recent call last):
  File "/usr/bin/salt-call", line 11, in <module>
    salt_call()
  File "/usr/lib/python2.7/dist-packages/salt/scripts.py", line 346, in salt_call
    import salt.cli.call
  File "/usr/lib/python2.7/dist-packages/salt/cli/call.py", line 6, in <module>
    from salt.utils import parsers
  File "/usr/lib/python2.7/dist-packages/salt/utils/parsers.py", line 28, in <module>
    import salt.config as config
  File "/usr/lib/python2.7/dist-packages/salt/config/__init__.py", line 41, in <module>
    import salt.utils.sdb
  File "/usr/lib/python2.7/dist-packages/salt/utils/sdb.py", line 9, in <module>
    import salt.loader
  File "/usr/lib/python2.7/dist-packages/salt/loader.py", line 30, in <module>
    import salt.utils.event
  File "/usr/lib/python2.7/dist-packages/salt/utils/event.py", line 72, in <module>
    import salt.payload
  File "/usr/lib/python2.7/dist-packages/salt/payload.py", line 17, in <module>
    import salt.crypt
  File "/usr/lib/python2.7/dist-packages/salt/crypt.py", line 42, in <module>
    import salt.utils.rsax931
  File "/usr/lib/python2.7/dist-packages/salt/utils/rsax931.py", line 69, in <module>
    libcrypto = _init_libcrypto()
  File "/usr/lib/python2.7/dist-packages/salt/utils/rsax931.py", line 63, in _init_libcrypto
    libcrypto.OPENSSL_no_config()
  File "/usr/lib/python2.7/ctypes/__init__.py", line 375, in __getattr__
    func = self.__getitem__(name)
  File "/usr/lib/python2.7/ctypes/__init__.py", line 380, in __getitem__
    func = self._FuncPtr((name_or_ordinal, self))
AttributeError: /lib/x86_64-linux-gnu/libcrypto.so.1.1: undefined symbol: OPENSSL_no_config

OpenSSL 1.1 replaced the symbols OPENSSL_no_config and
OPENSSL_add_all_algorithms_noconf by OPENSSL_init_crypto and added these
definitions:

    OPENSSL_init_crypto(OPENSSL_INIT_NO_LOAD_CONFIG, NULL)
    OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS \
                        | OPENSSL_INIT_ADD_ALL_DIGESTS, NULL)

These definitions can only be used when compiling the source code, but
not when loading the symbols dynamically. Thus salt needs to adapt the
initialization for OpenSSL 1.1. Try to use OPENSSL_init_crypto (which
was introduced in OpenSSL 1.1) and fall back to the previous behavior
for OpenSSL 1.0 and older (when OPENSSL_init_crypto is not found).

You can easily reproduce the issue on Debian unstable by running

    apt install salt-master
    salt-call

Bug-Debian: https://bugs.debian.org/844503
---
 salt/utils/rsax931.py | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/salt/utils/rsax931.py b/salt/utils/rsax931.py
index 9eb1f4a..bccdad6 100644
--- a/salt/utils/rsax931.py
+++ b/salt/utils/rsax931.py
@@ -16,6 +16,11 @@ import salt.utils
 from ctypes import cdll, c_char_p, c_int, c_void_p, pointer, create_string_buffer
 from ctypes.util import find_library
 
+# Constants taken from openssl-1.1.0c/include/openssl/crypto.h
+OPENSSL_INIT_ADD_ALL_CIPHERS = 0x00000004
+OPENSSL_INIT_ADD_ALL_DIGESTS = 0x00000008
+OPENSSL_INIT_NO_LOAD_CONFIG = 0x00000080
+
 
 def _load_libcrypto():
     '''
@@ -60,8 +65,15 @@ def _init_libcrypto():
     libcrypto.RSA_private_encrypt.argtypes = (c_int, c_char_p, c_char_p, c_void_p, c_int)
     libcrypto.RSA_public_decrypt.argtypes = (c_int, c_char_p, c_char_p, c_void_p, c_int)
 
-    libcrypto.OPENSSL_no_config()
-    libcrypto.OPENSSL_add_all_algorithms_noconf()
+    try:
+        if libcrypto.OPENSSL_init_crypto(OPENSSL_INIT_NO_LOAD_CONFIG |
+                                         OPENSSL_INIT_ADD_ALL_CIPHERS |
+                                         OPENSSL_INIT_ADD_ALL_DIGESTS, None) != 1:
+            raise OSError("Failed to initialize OpenSSL library (OPENSSL_init_crypto failed)")
+    except AttributeError:
+        # Support for OpenSSL < 1.1 (OPENSSL_API_COMPAT < 0x10100000L)
+        libcrypto.OPENSSL_no_config()
+        libcrypto.OPENSSL_add_all_algorithms_noconf()
 
     return libcrypto
 
-- 
2.9.3

