Repository: pyca/cryptography

Issue:
Add bindings for TLS 1.3 post-handshake auth
https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_post_handshake_auth.html

Methods / constants:

* ``int SSL_verify_client_post_handshake(SSL *ssl)``
* ``void SSL_CTX_set_post_handshake_auth(SSL_CTX *ctx, int val)``
* ``void SSL_set_post_handshake_auth(SSL *ssl, int val)``
* ``SSL_VERIFY_POST_HANDSHAKE``

Blocks https://github.com/pyca/pyopenssl/issues/793


Discussion:

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
@@ -17,6 +17,7 @@
 static const long Cryptography_HAS_SSL3_METHOD;
 static const long Cryptography_HAS_TLSv1_1;
 static const long Cryptography_HAS_TLSv1_2;
+static const long Cryptography_HAS_TLSv1_3;
 static const long Cryptography_HAS_SECURE_RENEGOTIATION;
 static const long Cryptography_HAS_COMPRESSION;
 static const long Cryptography_HAS_TLSEXT_STATUS_REQ_CB;
@@ -68,6 +69,7 @@
 static const long SSL_OP_NO_TLSv1;
 static const long SSL_OP_NO_TLSv1_1;
 static const long SSL_OP_NO_TLSv1_2;
+static const long SSL_OP_NO_TLSv1_3;
 static const long SSL_OP_NO_DTLSv1;
 static const long SSL_OP_NO_DTLSv1_2;
 static const long SSL_OP_NO_COMPRESSION;
@@ -100,6 +102,7 @@
 static const long SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
 static const long SSL_VERIFY_CLIENT_ONCE;
 static const long SSL_VERIFY_NONE;
+static const long SSL_VERIFY_POST_HANDSHAKE;
 static const long SSL_SESS_CACHE_OFF;
 static const long SSL_SESS_CACHE_CLIENT;
 static const long SSL_SESS_CACHE_SERVER;
@@ -529,6 +532,11 @@
                                   void *);
 
 int SSL_extension_supported(unsigned int);
+
+int SSL_CTX_set_ciphersuites(SSL_CTX *, const char *);
+int SSL_verify_client_post_handshake(SSL *);
+void SSL_CTX_set_post_handshake_auth(SSL_CTX *, int);
+void SSL_set_post_handshake_auth(SSL *, int);
 """
 
 CUSTOMIZATIONS = """
@@ -815,4 +823,15 @@
 static const long Cryptography_HAS_CIPHER_DETAILS = 1;
 #endif
 
+#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_111
+static const long Cryptography_HAS_TLSv1_3 = 0;
+static const long SSL_OP_NO_TLSv1_3 = 0;
+static const long SSL_VERIFY_POST_HANDSHAKE = 0;
+int (*SSL_CTX_set_ciphersuites)(SSL_CTX *, const char *) = NULL;
+int (*SSL_verify_client_post_handshake)(SSL *) = NULL;
+void (*SSL_CTX_set_post_handshake_auth)(SSL_CTX *, int) = NULL;
+void (*SSL_set_post_handshake_auth)(SSL *, int) = NULL;
+#else
+static const long Cryptography_HAS_TLSv1_3 = 1;
+#endif
 """
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
@@ -290,6 +290,17 @@ def cryptography_has_cipher_details():
     ]
 
 
+def cryptography_has_tlsv13():
+    return [
+        "SSL_OP_NO_TLSv1_3",
+        "SSL_VERIFY_POST_HANDSHAKE",
+        "SSL_CTX_set_ciphersuites",
+        "SSL_verify_client_post_handshake",
+        "SSL_CTX_set_post_handshake_auth",
+        "SSL_set_post_handshake_auth",
+    ]
+
+
 # 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
@@ -351,4 +362,5 @@ def cryptography_has_cipher_details():
     "Cryptography_HAS_CUSTOM_EXT": cryptography_has_custom_ext,
     "Cryptography_HAS_OPENSSL_CLEANUP": cryptography_has_openssl_cleanup,
     "Cryptography_HAS_CIPHER_DETAILS": cryptography_has_cipher_details,
+    "Cryptography_HAS_TLSv1_3": cryptography_has_tlsv13,
 }


Test patch: