Author: Richard Plangger <[email protected]>
Branch: py3.5-ssl
Changeset: r88141:d873256da8f4
Date: 2016-11-04 20:33 +0100
http://bitbucket.org/pypy/pypy/changeset/d873256da8f4/

Log:    checkin changes made on the pypy stdlib ssl repo

diff --git a/lib_pypy/openssl/_cffi_src/openssl/x509_vfy.py 
b/lib_pypy/openssl/_cffi_src/openssl/x509_vfy.py
--- a/lib_pypy/openssl/_cffi_src/openssl/x509_vfy.py
+++ b/lib_pypy/openssl/_cffi_src/openssl/x509_vfy.py
@@ -133,7 +133,7 @@
 int X509_STORE_set_default_paths(X509_STORE *);
 int X509_STORE_set_flags(X509_STORE *, unsigned long);
 void X509_STORE_free(X509_STORE *);
-
+X509_VERIFY_PARAM *_X509_STORE_get0_param(X509_STORE *);
 
 /* X509_STORE_CTX */
 X509_STORE_CTX *X509_STORE_CTX_new(void);
@@ -250,4 +250,8 @@
 static const long Cryptography_HAS_X509_V_FLAG_TRUSTED_FIRST = 0;
 static const long X509_V_FLAG_TRUSTED_FIRST = 0;
 #endif
+
+X509_VERIFY_PARAM *_X509_STORE_get0_param(X509_STORE *store) {
+    return store->param;
+}
 """
diff --git a/lib_pypy/openssl/_stdssl/__init__.py 
b/lib_pypy/openssl/_stdssl/__init__.py
--- a/lib_pypy/openssl/_stdssl/__init__.py
+++ b/lib_pypy/openssl/_stdssl/__init__.py
@@ -1,3 +1,5 @@
+import sys
+import errno
 import time
 import _thread
 import weakref
@@ -5,7 +7,7 @@
 from _openssl import lib
 from openssl._stdssl.certificate import _test_decode_cert
 from openssl._stdssl.utility import _str_with_len
-from openssl._stdssl.error import (ssl_error,
+from openssl._stdssl.error import (ssl_error, ssl_lib_error,
         SSLError, SSLZeroReturnError, SSLWantReadError,
         SSLWantWriteError, SSLSyscallError,
         SSLEOFError)
@@ -33,6 +35,13 @@
 CLIENT = 0
 SERVER = 1
 
+VERIFY_DEFAULT = 0
+VERIFY_CRL_CHECK_LEAF = lib.X509_V_FLAG_CRL_CHECK 
+VERIFY_CRL_CHECK_CHAIN = lib.X509_V_FLAG_CRL_CHECK | 
lib.X509_V_FLAG_CRL_CHECK_ALL
+VERIFY_X509_STRICT = lib.X509_V_FLAG_X509_STRICT
+if lib.Cryptography_HAS_X509_V_FLAG_TRUSTED_FIRST:
+    VERIFY_X509_TRUSTED_FIRST = lib.X509_V_FLAG_TRUSTED_FIRST
+
 CERT_NONE = 0
 CERT_OPTIONAL = 1
 CERT_REQUIRED = 2
@@ -41,10 +50,13 @@
     if name.startswith('SSL_OP'):
         globals()[name[4:]] = getattr(lib, name)
 
+OP_ALL = lib.SSL_OP_ALL & ~lib.SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
+
 SSL_CLIENT = 0
 SSL_SERVER = 1
 
-PROTOCOL_SSLv2  = 0
+if lib.Cryptography_HAS_SSL2:
+    PROTOCOL_SSLv2  = 0
 PROTOCOL_SSLv3  = 1
 PROTOCOL_SSLv23 = 2
 PROTOCOL_TLSv1    = 3
@@ -71,14 +83,43 @@
 lib.OpenSSL_add_all_algorithms()
 
 class PasswordInfo(object):
-    w_callable = None
+    callable = None
     password = None
     operationerror = None
 PWINFO_STORAGE = {}
 
[email protected]_extern
-def _password_callback(buf, size, rwflag, userdata):
-    pass
+def _Cryptography_pem_password_cb(buf, size, rwflag, userdata):
+    pw_info = ffi.from_handle(userdata)
+
+    # TODO PySSL_END_ALLOW_THREADS_S(pw_info->thread_state);
+    password = pw_info.password
+
+    if pw_info.callable:
+        try:
+            password = pw_info.callable()
+        except Exception as e:
+            pw_info.operationerror = e
+            return 0
+
+        if not isinstance(password, (str, bytes, bytearray)):
+            pw_info.operationerror = TypeError("password callback must return 
a string")
+            return 0
+
+    password = _str_to_ffi_buffer(password)
+
+    if (len(password) > size):
+        pw_info.operationerror = ValueError("password cannot be longer than %d 
bytes" % size)
+        return 0
+
+    #PySSL_BEGIN_ALLOW_THREADS_S(pw_info->thread_state);
+    ffi.memmove(buf, password, len(password))
+    return len(password)
+
+if lib.Cryptography_STATIC_CALLBACKS:
+    ffi.def_extern(_Cryptography_pem_password_cb)
+    Cryptography_pem_password_cb = lib.Cryptography_pem_password_cb
+else:
+    Cryptography_pem_password_cb = 
ffi.callback("int(char*,int,int,void*)")(_Cryptography_pem_password_cb)
 
 def _ssl_select(sock, write, timeout):
     pass
@@ -216,7 +257,7 @@
 
 
 class _SSLContext(object):
-    __slots__ = ('ctx', 'check_hostname', 'verify_mode')
+    __slots__ = ('ctx', 'check_hostname')
 
     def __new__(cls, protocol):
         self = object.__new__(cls)
@@ -229,7 +270,7 @@
             method = lib.TLSv1_2_method()
         elif protocol == PROTOCOL_SSLv3 and lib.Cryptography_HAS_SSL3_METHOD:
             method = lib.SSLv3_method()
-        elif protocol == PROTOCOL_SSLv2 and lib.Cryptography_HAS_SSL2_METHOD:
+        elif lib.Cryptography_HAS_SSL2 and protocol == PROTOCOL_SSLv2:
             method = lib.SSLv2_method()
         elif protocol == PROTOCOL_SSLv23:
             method = lib.SSLv23_method()
@@ -246,7 +287,7 @@
         # Defaults
         lib.SSL_CTX_set_verify(self.ctx, lib.SSL_VERIFY_NONE, ffi.NULL)
         options = lib.SSL_OP_ALL & ~lib.SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
-        if protocol != PROTOCOL_SSLv2:
+        if not lib.Cryptography_HAS_SSL2 or protocol != PROTOCOL_SSLv2:
             options |= lib.SSL_OP_NO_SSLv2
         if protocol != PROTOCOL_SSLv3:
             options |= lib.SSL_OP_NO_SSLv3
@@ -269,8 +310,80 @@
                     lib.SSL_CTX_set_tmp_ecdh(self.ctx, key)
                 finally:
                     lib.EC_KEY_free(key)
+        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)
         return self
 
+    @property
+    def options(self):
+        return lib.SSL_CTX_get_options(self.ctx)
+
+    @options.setter
+    def options(self, value):
+        new_opts = int(value)
+        opts = lib.SSL_CTX_get_options(self.ctx)
+        clear = opts & ~new_opts
+        set = ~opts & new_opts
+        if clear:
+            if lib.Cryptography_HAS_SSL_CTX_CLEAR_OPTIONS:
+                lib.SSL_CTX_clear_options(self.ctx, clear)
+            else:
+                raise ValueError("can't clear options before OpenSSL 0.9.8m")
+        if set:
+            lib.SSL_CTX_set_options(self.ctx, set)
+
+    @property
+    def verify_mode(self):
+        mode = lib.SSL_CTX_get_verify_mode(self.ctx)
+        if mode == lib.SSL_VERIFY_NONE:
+            return CERT_NONE
+        elif mode == lib.SSL_VERIFY_PEER:
+            return CERT_OPTIONAL
+        elif mode == lib.SSL_VERIFY_PEER | lib.SSL_VERIFY_FAIL_IF_NO_PEER_CERT:
+            return CERT_REQUIRED
+        raise ssl_error("invalid return value from SSL_CTX_get_verify_mode")
+
+    @verify_mode.setter
+    def verify_mode(self, value):
+        n = int(value)
+        if n == CERT_NONE:
+            mode = lib.SSL_VERIFY_NONE
+        elif n == CERT_OPTIONAL:
+            mode = lib.SSL_VERIFY_PEER
+        elif n == CERT_REQUIRED:
+            mode = lib.SSL_VERIFY_PEER | lib.SSL_VERIFY_FAIL_IF_NO_PEER_CERT
+        else:
+            raise ValueError("invalid value for verify_mode")
+        if mode == lib.SSL_VERIFY_NONE and self.check_hostname:
+            raise ValueError("Cannot set verify_mode to CERT_NONE when " \
+                             "check_hostname is enabled.")
+        lib.SSL_CTX_set_verify(self.ctx, mode, ffi.NULL);
+
+    @property
+    def verify_flags(self):
+        store = lib.SSL_CTX_get_cert_store(self.ctx)
+        param = lib._X509_STORE_get0_param(store)
+        flags = lib.X509_VERIFY_PARAM_get_flags(param)
+        return int(flags)
+
+    @verify_flags.setter
+    def verify_flags(self, value):
+        new_flags = int(value)
+        store = lib.SSL_CTX_get_cert_store(self.ctx);
+        param = lib._X509_STORE_get0_param(store)
+        flags = lib.X509_VERIFY_PARAM_get_flags(param);
+        clear = flags & ~new_flags;
+        set = ~flags & new_flags;
+        if clear:
+            param = lib._X509_STORE_get0_param(store)
+            if not lib.X509_VERIFY_PARAM_clear_flags(param, clear):
+                raise ssl_error(None, 0)
+        if set:
+            param = lib._X509_STORE_get0_param(store)
+            if not lib.X509_VERIFY_PARAM_set_flags(param, set):
+                raise ssl_error(None, 0)
+
     def set_ciphers(self, cipherlist):
         cipherlistbuf = _str_to_ffi_buffer(cipherlist)
         ret = lib.SSL_CTX_set_cipher_list(self.ctx, cipherlistbuf)
@@ -294,13 +407,13 @@
             if callable(password):
                 pw_info.callable = password
             else:
-                if isinstance(password, str):
+                if isinstance(password, (str, bytes, bytearray)):
                     pw_info.password = password
+                else:
+                    raise TypeError("password should be a string or callable")
 
-                raise TypeError("password should be a string or callable")
-
-            lib.SSL_CTX_set_default_passwd_cb(self.ctx, _password_callback)
-            lib.SSL_CTX_set_default_passwd_cb_userdata(self.ctx, 
ffi.cast("void*", index))
+            lib.SSL_CTX_set_default_passwd_cb(self.ctx, 
Cryptography_pem_password_cb)
+            lib.SSL_CTX_set_default_passwd_cb_userdata(self.ctx, 
ffi.new_handle(pw_info))
 
         try:
             certfilebuf = _str_to_ffi_buffer(certfile)
@@ -309,12 +422,12 @@
                 if pw_info.operationerror:
                     lib.ERR_clear_error()
                     raise pw_info.operationerror
-                errno = ffi.errno
-                if errno:
+                _errno = ffi.errno
+                if _errno:
                     lib.ERR_clear_error()
-                    raise OSError(errno, '')
+                    raise OSError(_errno, "Error")
                 else:
-                    raise _ssl_seterror(None, -1)
+                    raise ssl_lib_error()
 
             keyfilebuf = _str_to_ffi_buffer(keyfile)
             ret = lib.SSL_CTX_use_PrivateKey_file(self.ctx, keyfilebuf,
@@ -323,12 +436,12 @@
                 if pw_info.operationerror:
                     lib.ERR_clear_error()
                     raise pw_info.operationerror
-                errno = ffi.errno
-                if errno:
+                _errno = ffi.errno
+                if _errno:
                     lib.ERR_clear_error()
-                    raise OSError(errno, '')
+                    raise OSError(_errno, None)
                 else:
-                    raise _ssl_seterror(None, -1)
+                    raise ssl_lib_error()
 
             ret = lib.SSL_CTX_check_private_key(self.ctx)
             if ret != 1:
@@ -665,12 +778,15 @@
 #
 #
 
+def _str_from_buf(buf):
+    return ffi.string(buf).decode('utf-8')
+
 def _asn1obj2py(obj):
     nid = lib.OBJ_obj2nid(obj)
     if nid == lib.NID_undef:
         raise ValueError("Unknown object")
-    sn = lib.OBJ_nid2sn(nid)
-    ln = lib.OBJ_nid2ln(nid)
+    sn = _str_from_buf(lib.OBJ_nid2sn(nid))
+    ln = _str_from_buf(lib.OBJ_nid2ln(nid))
     buf = ffi.new("char[255]")
     length = lib.OBJ_obj2txt(buf, len(buf), obj, 1)
     if length < 0:
@@ -682,15 +798,23 @@
 
 def txt2obj(txt, name):
     _bytes = _str_to_ffi_buffer(txt)
-    obj = lib.OBJ_txt2obj(_bytes, int(name))
-    if obj is ffi.NULL:
-        raise ValueError("unkown object '%s'", txt)
+    is_name = 0 if name else 1
+    obj = lib.OBJ_txt2obj(_bytes, is_name)
+    if obj == ffi.NULL:
+        raise ValueError("unknown object '%s'" % txt)
     result = _asn1obj2py(obj)
     lib.ASN1_OBJECT_free(obj)
     return result
 
 def nid2obj(nid):
-    raise NotImplementedError
+    if nid < lib.NID_undef:
+        raise ValueError("NID must be positive.")
+    obj = lib.OBJ_nid2obj(nid);
+    if obj == ffi.NULL:
+        raise ValueError("unknown NID %i" % nid)
+    result = _asn1obj2py(obj);
+    lib.ASN1_OBJECT_free(obj);
+    return result;
                                                                
 
 class MemoryBIO(object):
@@ -744,7 +868,7 @@
 #        if (!target) goto error; \
 #    }
     # XXX
-    return ffi.string(buf).decode('utf-8')
+    return ffi.string(buf).decode(sys.getfilesystemencoding())
 
 def get_default_verify_paths():
 
diff --git a/lib_pypy/openssl/_stdssl/error.py 
b/lib_pypy/openssl/_stdssl/error.py
--- a/lib_pypy/openssl/_stdssl/error.py
+++ b/lib_pypy/openssl/_stdssl/error.py
@@ -23,6 +23,9 @@
 class SSLEOFError(SSLError):
     """ SSL/TLS connection terminated abruptly. """
 
+def ssl_lib_error():
+    errcode = lib.ERR_peek_last_error()
+    return ssl_error(None, 0, None, errcode)
 
 def ssl_error(msg, errno=0, errtype=None, errcode=0):
     reason_str = None
@@ -30,8 +33,8 @@
     if errcode:
         err_lib = lib.ERR_GET_LIB(errcode)
         err_reason = lib.ERR_GET_REASON(errcode)
-        reason_str = ERROR_CODES_TO_NAMES.get((err_lib, err_reason), None)
-        lib_str = LIBRARY_CODES_TO_NAMES.get(err_lib, None)
+        reason_str = ERR_CODES_TO_NAMES.get((err_lib, err_reason), None)
+        lib_str = LIB_CODES_TO_NAMES.get(err_lib, None)
         msg = ffi.string(lib.ERR_reason_error_string(errcode)).decode('utf-8')
     if not msg:
         msg = "unknown error"
@@ -54,22 +57,16 @@
     #return OperationError(w_exception_class, w_exception)
 
 ERR_CODES_TO_NAMES = {}
+ERR_NAMES_TO_CODES = {}
 LIB_CODES_TO_NAMES = {}
 
-# TODO errcode = error_codes;
-# TODO while (errcode->mnemonic != NULL) {
-# TODO     mnemo = PyUnicode_FromString(errcode->mnemonic);
-# TODO     key = Py_BuildValue("ii", errcode->library, errcode->reason);
-# TODO     if (mnemo == NULL || key == NULL)
-# TODO         return NULL;
-# TODO     if (PyDict_SetItem(err_codes_to_names, key, mnemo))
-# TODO         return NULL;
-# TODO     if (PyDict_SetItem(err_names_to_codes, mnemo, key))
-# TODO         return NULL;
-# TODO     Py_DECREF(key);
-# TODO     Py_DECREF(mnemo);
-# TODO     errcode++;
-# TODO }
+from openssl._stdssl.errorcodes import _error_codes
+
+for mnemo, library, reason in _error_codes:
+    key = (library, reason)
+    assert mnemo is not None and key is not None
+    ERR_CODES_TO_NAMES[key] = mnemo
+    ERR_NAMES_TO_CODES[mnemo] = key
 
 def _fill_and_raise_ssl_error(error, errcode):
     pass
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to