Repository: pyca/cryptography

Issue:
OpenSSL with -DOPENSSL_NO_SRTP errors when initializing backend
When building OpenSSL with the -DOPENSSL_NO_SRTP flag, pyca/cryptography fails to initialize the default backend.

I built OpenSSL against OpenSSL_1_1_1-stable commit (a9a8863b7), with the following config:

```
./config --prefix=/home/ubuntu/openssl/build --openssldir=/home/ubuntu/openssl/build -DOPENSSL_NO_SRTP
make clean; make
make install
```

Then I get the following error:

```
(venv) ubuntu@ip-172-31-21-1:~/openssl/openssl$ python
Python 3.6.9 (default, Nov  7 2019, 10:44:02) 
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from cryptography.hazmat.backends import default_backend
>>> default_backend()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/ubuntu/openssl/cryptography/src/cryptography/hazmat/backends/__init__.py", line 15, in default_backend
    from cryptography.hazmat.backends.openssl.backend import backend
  File "/home/ubuntu/openssl/cryptography/src/cryptography/hazmat/backends/openssl/__init__.py", line 7, in <module>
    from cryptography.hazmat.backends.openssl.backend import backend
  File "/home/ubuntu/openssl/cryptography/src/cryptography/hazmat/backends/openssl/backend.py", line 75, in <module>
    from cryptography.hazmat.bindings.openssl import binding
  File "/home/ubuntu/openssl/cryptography/src/cryptography/hazmat/bindings/openssl/binding.py", line 16, in <module>
    from cryptography.hazmat.bindings._openssl import ffi, lib
ImportError: /home/ubuntu/openssl/cryptography/src/cryptography/hazmat/bindings/_openssl.abi3.so: symbol SSL_CTX_set_tlsext_use_srtp version OPENSSL_1_1_0 not defined in file libssl.so.1.1 with link time reference
```
I'm running against head of cryptography (commit c0dbbb52). 

Using the same setup, and removing the `-DOPENSSL_NO_SRTP` flag to `config` I'm able to initialize the backend as expected.

Os
```
$ uname -a
Linux ip-172-31-21-1 4.15.0-1058-aws #60-Ubuntu SMP Wed Jan 15 22:35:20 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
```

Python version:
```
$ python --version
Python 3.6.9
```

According this link [1], there are a few things that can be disabled in OpenSSL, and if you'll accept this as a bug, I'd be happy to create some script that goes through all the permutations of flags to find out what breaks when this project tries to use it.

[1] https://stackoverflow.com/questions/7827836/build-openssl-with-just-rsa-and-aes#7828924
OpenSSL with -DOPENSSL_NO_SRTP errors when initializing backend
When building OpenSSL with the -DOPENSSL_NO_SRTP flag, pyca/cryptography fails to initialize the default backend.

I built OpenSSL against OpenSSL_1_1_1-stable commit (a9a8863b7), with the following config:

```
./config --prefix=/home/ubuntu/openssl/build --openssldir=/home/ubuntu/openssl/build -DOPENSSL_NO_SRTP
make clean; make
make install
```

Then I get the following error:

```
(venv) ubuntu@ip-172-31-21-1:~/openssl/openssl$ python
Python 3.6.9 (default, Nov  7 2019, 10:44:02) 
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from cryptography.hazmat.backends import default_backend
>>> default_backend()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/ubuntu/openssl/cryptography/src/cryptography/hazmat/backends/__init__.py", line 15, in default_backend
    from cryptography.hazmat.backends.openssl.backend import backend
  File "/home/ubuntu/openssl/cryptography/src/cryptography/hazmat/backends/openssl/__init__.py", line 7, in <module>
    from cryptography.hazmat.backends.openssl.backend import backend
  File "/home/ubuntu/openssl/cryptography/src/cryptography/hazmat/backends/openssl/backend.py", line 75, in <module>
    from cryptography.hazmat.bindings.openssl import binding
  File "/home/ubuntu/openssl/cryptography/src/cryptography/hazmat/bindings/openssl/binding.py", line 16, in <module>
    from cryptography.hazmat.bindings._openssl import ffi, lib
ImportError: /home/ubuntu/openssl/cryptography/src/cryptography/hazmat/bindings/_openssl.abi3.so: symbol SSL_CTX_set_tlsext_use_srtp version OPENSSL_1_1_0 not defined in file libssl.so.1.1 with link time reference
```
I'm running against head of cryptography (commit c0dbbb52). 

Using the same setup, and removing the `-DOPENSSL_NO_SRTP` flag to `config` I'm able to initialize the backend as expected.

Os
```
$ uname -a
Linux ip-172-31-21-1 4.15.0-1058-aws #60-Ubuntu SMP Wed Jan 15 22:35:20 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
```

Python version:
```
$ python --version
Python 3.6.9
```

According this link [1], there are a few things that can be disabled in OpenSSL, and if you'll accept this as a bug, I'd be happy to create some script that goes through all the permutations of flags to find out what breaks when this project tries to use it.

[1] https://stackoverflow.com/questions/7827836/build-openssl-with-just-rsa-and-aes#7828924


Discussion:
You’re welcome to figure out what flags are required, but in general we’re not likely to want to gate features. SRTP might be an exception, but we’d have to modify pyopenssl (I’m assuming that’s what uses it) to handle its absence. 
Hi Paul,

To provide a bit of context and clarification:

This is a specific case of the issue we talked about last year at PyCon, where the backend fails to load if certain bindings are missing from the OpenSSL ABI. In contrast, there are some bindings, such as RSA-OAEP with SHA2 hashes, that [in the absence of bindings] only fail when you try to use them rather than when you try to load the backend. Our end-goal here is for pyca/cryptography to exhibit this later behavior for any features that can be disabled in the standard OpenSSL build.

We realize that this is probably a bit of a niche use case, as I assume that the majority of pyca/cryptography users just use the wheels and their included binaries, but this is a use case that we need to support and we would like to work with you all to get pyca/cryptography to a point where it does.

We don't have a timeline on when we'll be able to start digging into this, but we wanted to get the conversation started to begin scoping the level of effort needed to address this as well as to start enumerating what changes will need to be made where.
Ah, gotcha. I'm in favor of making us more robust where possible (and with the caveat that we need to make it testable to prevent regressions...without blowing up our test matrix). I look forward to seeing what your team makes of it :)
`OPENSSL_NO_CT` is another flag we may want to consider. (ported that from #5067)
You’re welcome to figure out what flags are required, but in general we’re not likely to want to gate features. SRTP might be an exception, but we’d have to modify pyopenssl (I’m assuming that’s what uses it) to handle its absence. 
Hi Paul,

To provide a bit of context and clarification:

This is a specific case of the issue we talked about last year at PyCon, where the backend fails to load if certain bindings are missing from the OpenSSL ABI. In contrast, there are some bindings, such as RSA-OAEP with SHA2 hashes, that [in the absence of bindings] only fail when you try to use them rather than when you try to load the backend. Our end-goal here is for pyca/cryptography to exhibit this later behavior for any features that can be disabled in the standard OpenSSL build.

We realize that this is probably a bit of a niche use case, as I assume that the majority of pyca/cryptography users just use the wheels and their included binaries, but this is a use case that we need to support and we would like to work with you all to get pyca/cryptography to a point where it does.

We don't have a timeline on when we'll be able to start digging into this, but we wanted to get the conversation started to begin scoping the level of effort needed to address this as well as to start enumerating what changes will need to be made where.
Ah, gotcha. I'm in favor of making us more robust where possible (and with the caveat that we need to make it testable to prevent regressions...without blowing up our test matrix). I look forward to seeing what your team makes of it :)
`OPENSSL_NO_CT` is another flag we may want to consider. (ported that from #5067)

Resolving patch:
diff --git a/src/_cffi_src/openssl/ssl.py b/src/_cffi_src/openssl/ssl.py
--- a/src/_cffi_src/openssl/ssl.py
+++ b/src/_cffi_src/openssl/ssl.py
@@ -50,6 +50,7 @@
 static const long Cryptography_HAS_NEXTPROTONEG;
 static const long Cryptography_HAS_SET_CERT_CB;
 static const long Cryptography_HAS_CUSTOM_EXT;
+static const long Cryptography_HAS_SRTP;
 
 static const long SSL_FILETYPE_PEM;
 static const long SSL_FILETYPE_ASN1;
@@ -762,6 +763,15 @@
 int (*SSL_extension_supported)(unsigned int) = NULL;
 #endif
 
+#ifndef OPENSSL_NO_SRTP
+static const long Cryptography_HAS_SRTP = 1;
+#else
+static const long Cryptography_HAS_SRTP = 0;
+int (*SSL_CTX_set_tlsext_use_srtp)(SSL_CTX *, const char *) = NULL;
+int (*SSL_set_tlsext_use_srtp)(SSL *, const char *) = NULL;
+SRTP_PROTECTION_PROFILE * (*SSL_get_selected_srtp_profile)(SSL *) = NULL;
+#endif
+
 #if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110 && !CRYPTOGRAPHY_IS_LIBRESSL
 int (*SSL_CIPHER_is_aead)(const SSL_CIPHER *) = NULL;
 int (*SSL_CIPHER_get_cipher_nid)(const SSL_CIPHER *) = NULL;
diff --git a/src/cryptography/hazmat/bindings/openssl/_conditional.py b/src/cryptography/hazmat/bindings/openssl/_conditional.py
--- a/src/cryptography/hazmat/bindings/openssl/_conditional.py
+++ b/src/cryptography/hazmat/bindings/openssl/_conditional.py
@@ -297,6 +297,14 @@ def cryptography_has_verified_chain():
     ]
 
 
+def cryptography_has_srtp():
+    return [
+        "SSL_CTX_set_tlsext_use_srtp",
+        "SSL_set_tlsext_use_srtp",
+        "SSL_get_selected_srtp_profile",
+    ]
+
+
 # This is a mapping of
 # {condition: function-returning-names-dependent-on-that-condition} so we can
 # loop over them and delete unsupported names at runtime. It will be removed
@@ -354,4 +362,5 @@ def cryptography_has_verified_chain():
     ),
     "Cryptography_HAS_ENGINE": cryptography_has_engine,
     "Cryptography_HAS_VERIFIED_CHAIN": cryptography_has_verified_chain,
+    "Cryptography_HAS_SRTP": cryptography_has_srtp,
 }


Test patch: