[pypy-commit] pypy default: handle OpenSSL v1.1, in _ssl, add post_handshake_auth for TLSv1_3

mattip pypy.commits at gmail.com
Sat Dec 14 16:46:08 EST 2019


Author: Matti Picus <matti.picus at gmail.com>
Branch: 
Changeset: r98287:826708d0c629
Date: 2019-12-14 23:33 +0200
http://bitbucket.org/pypy/pypy/changeset/826708d0c629/

Log:	handle OpenSSL v1.1, in _ssl, add post_handshake_auth for TLSv1_3
	(grafted from a56889d5df88dc57c7385151b1f54f644c34c2da)

diff --git a/lib_pypy/_cffi_ssl/_cffi_src/openssl/ssl.py b/lib_pypy/_cffi_ssl/_cffi_src/openssl/ssl.py
--- a/lib_pypy/_cffi_ssl/_cffi_src/openssl/ssl.py
+++ b/lib_pypy/_cffi_ssl/_cffi_src/openssl/ssl.py
@@ -76,6 +76,7 @@
 static const long SSL_OP_SINGLE_DH_USE;
 static const long SSL_OP_EPHEMERAL_RSA;
 static const long SSL_OP_MICROSOFT_SESS_ID_BUG;
+static const long SSL_OP_ENABLE_MIDDLEBOX_COMPAT;
 static const long SSL_OP_NETSCAPE_CHALLENGE_BUG;
 static const long SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG;
 static const long SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG;
diff --git a/lib_pypy/_cffi_ssl/_stdssl/__init__.py b/lib_pypy/_cffi_ssl/_stdssl/__init__.py
--- a/lib_pypy/_cffi_ssl/_stdssl/__init__.py
+++ b/lib_pypy/_cffi_ssl/_stdssl/__init__.py
@@ -83,6 +83,9 @@
 OP_NO_SSLv2 = lib.SSL_OP_NO_SSLv2
 OP_NO_SSLv3 = lib.SSL_OP_NO_SSLv3
 OP_NO_TLSv1_3 = lib.SSL_OP_NO_TLSv1_3
+if OPENSSL_VERSION_INFO > (1, 1, 0, 0, 0):
+    OP_ENABLE_MIDDLEBOX_COMPAT = lib.SSL_OP_ENABLE_MIDDLEBOX_COMPAT
+
  
 
 SSL_CLIENT = 0
@@ -265,6 +268,20 @@
             mode |= lib.SSL_MODE_AUTO_RETRY
         lib.SSL_set_mode(ssl, mode)
 
+        if HAS_TLSv1_3:
+            if sslctx._post_handshake_auth:
+                if socket_type == SSL_SERVER:
+                    # bpo-37428: OpenSSL does not ignore SSL_VERIFY_POST_HANDSHAKE.
+                    # Set SSL_VERIFY_POST_HANDSHAKE flag only for server sockets and
+                    # only in combination with SSL_VERIFY_PEER flag.
+                    mode = lib.SSL_CTX_get_verify_mode(lib.SSL_get_SSL_CTX(self.ssl))
+                    if (mode & lib.SSL_VERIFY_PEER):
+                        verify_cb = lib.SSL_get_verify_callback(self.ssl)
+                        mode |= lib.SSL_VERIFY_POST_HANDSHAKE
+                        lib.SSL_set_verify(ssl, mode, verify_cb)
+                else:
+                    lib.SSL_set_post_handshake_auth(ssl, 1)
+
         if HAS_SNI and self.server_hostname:
             name = _str_to_ffi_buffer(self.server_hostname)
             lib.SSL_set_tlsext_host_name(ssl, name)
@@ -652,6 +669,15 @@
         else:
             return None
 
+    def verify_client_post_handshake(self):
+
+        if not HAS_TLSv1_3:
+            raise NotImplementedError("Post-handshake auth is not supported by "
+                                      "your OpenSSL version.")
+        err = lib.SSL_verify_client_post_handshake(self.ssl);
+        if err == 0:
+            raise pyssl_error(self, err)
+
     def pending(self):
         count = lib.SSL_pending(self.ssl)
         if count < 0:
@@ -708,6 +734,7 @@
         return bool(lib.SSL_session_reused(self.ssl))
 
 
+
 def _fs_decode(name):
     return name.decode(sys.getfilesystemencoding())
 def _fs_converter(name):
@@ -763,13 +790,13 @@
     if OPENSSL_VERSION_INFO > (1, 1, 0, 0, 0):
         aead = lib.SSL_CIPHER_is_aead(cipher)
         nid = lib.SSL_CIPHER_get_cipher_nid(cipher)
-        skcipher = OBJ_nid2ln(nid) if nid != NID_undef else None
+        skcipher = lib.OBJ_nid2ln(nid) if nid != lib.NID_undef else None
         nid = lib.SSL_CIPHER_get_digest_nid(cipher);
-        digest = OBJ_nid2ln(nid) if nid != NID_undef else None
+        digest = lib.OBJ_nid2ln(nid) if nid != lib.NID_undef else None
         nid = lib.SSL_CIPHER_get_kx_nid(cipher);
-        kx = OBJ_nid2ln(nid) if nid != NID_undef else None
-        nid = SSL_CIPHER_get_auth_nid(cipher);
-        auth = OBJ_nid2ln(nid) if nid != NID_undef else None
+        kx = lib.OBJ_nid2ln(nid) if nid != lib.NID_undef else None
+        nid = lib.SSL_CIPHER_get_auth_nid(cipher);
+        auth = lib.OBJ_nid2ln(nid) if nid != lib.NID_undef else None
         ret.update({'aead' : bool(aead),
             'symmmetric'   : skcipher,
             'digest'       : digest,
@@ -829,9 +856,8 @@
 class _SSLContext(object):
     __slots__ = ('ctx', '_check_hostname', 'servername_callback',
                  'alpn_protocols', '_alpn_protocols_handle',
-                 'npn_protocols', 'set_hostname',
+                 'npn_protocols', 'set_hostname', '_post_handshake_auth',
                  '_set_hostname_handle', '_npn_protocols_handle')
-
     def __new__(cls, protocol):
         self = object.__new__(cls)
         self.ctx = ffi.NULL
@@ -908,6 +934,9 @@
         if lib.Cryptography_HAS_X509_V_FLAG_TRUSTED_FIRST:
             store = lib.SSL_CTX_get_cert_store(self.ctx)
             lib.X509_STORE_set_flags(store, lib.X509_V_FLAG_TRUSTED_FIRST)
+        if HAS_TLSv1_3:
+            self.post_handshake_auth = 0;
+            lib.SSL_CTX_set_post_handshake_auth(self.ctx, self.post_handshake_auth)
         return self
 
     @property
@@ -993,6 +1022,7 @@
                              "CERT_OPTIONAL or CERT_REQUIRED")
         self._check_hostname = check_hostname
 
+
     def set_ciphers(self, cipherlist):
         cipherlistbuf = _str_to_ffi_buffer(cipherlist)
         ret = lib.SSL_CTX_set_cipher_list(self.ctx, cipherlistbuf)
@@ -1329,6 +1359,25 @@
         sock = _SSLSocket._new__ssl_socket(self, None, server_side, hostname, incoming, outgoing)
         return sock
 
+    @property
+    def post_handshake_auth(self):
+        if HAS_TLSv1_3:
+            return bool(self._post_handshake_auth)
+        return None
+
+    @post_handshake_auth.setter
+    def post_handshake_auth(self, arg):
+        if arg is None:
+            raise AttributeError("cannot delete attribute")
+
+        pha = bool(arg)
+        self._post_handshake_auth = pha;
+
+        # bpo-37428: newPySSLSocket() sets SSL_VERIFY_POST_HANDSHAKE flag for
+        # server sockets and SSL_set_post_handshake_auth() for client
+
+        return 0;
+
 
 
 # cryptography constraint: OPENSSL_NO_TLSEXT will never be set!


More information about the pypy-commit mailing list