diff --git a/src/wolfssl/__init__.py b/src/wolfssl/__init__.py index 3314449..4a85e6a 100644 --- a/src/wolfssl/__init__.py +++ b/src/wolfssl/__init__.py @@ -94,14 +94,7 @@ class WolfSSLX509(object): if cnPtr == _ffi.NULL: return '' - cn = _ffi.string(cnPtr) - - if _PY3: - if isinstance(cn, bytes): - cn = cn.decode("utf-8") - else: - if isinstance(cn, unicode): - cn = cn.encode("utf-8") + cn = _ffi.string(cnPtr).decode("ascii") return cn @@ -110,7 +103,7 @@ class WolfSSLX509(object): if (sanPtr == _ffi.NULL): return None - san = _ffi.string(sanPtr) + san = _ffi.string(sanPtr).decode("ascii") return san @@ -284,6 +277,11 @@ class SSLContext(object): private key in. The password parameter is not supported yet. + + wolfSSL does not support loading a certificate file that contains + both the certificate AND private key. In this case, users should + split them into two separate files and load using the certfile + and keyfile parameters, respectively. """ if password is not None: @@ -397,35 +395,6 @@ class SSLSocket(object): if server_hostname is not None: self._context.use_sni(server_hostname) - # preparing socket - if sock is not None: - # Can't use sock.type as other flags (such as SOCK_NONBLOCK) get - # mixed in. - if sock.getsockopt(SOL_SOCKET, SO_TYPE) != SOCK_STREAM: - raise NotImplementedError("only stream sockets are supported") - - if _PY3: - socket.__init__(self._sock, - family=sock.family, - type=sock.type, - proto=sock.proto, - fileno=sock.fileno()) - else: - socket.__init__( - self._sock, _sock=sock._sock) # pylint: disable=protected-access - - self._sock.settimeout(sock.gettimeout()) - - if _PY3: - sock.detach() - - elif fileno is not None: - socket.__init__(self._sock, fileno=fileno) - - else: - socket.__init__(self._sock, family=family, type=sock_type, - proto=proto) - # see if we are connected try: self._sock.getpeername() @@ -584,8 +553,36 @@ class SSLSocket(object): return self.read(length=length) def recv_into(self, buffer, nbytes=None, flags=0): - raise NotImplementedError("recv_into not allowed on instances " - "of %s" % self.__class__) + """ + Read nbytes bytes and place into buffer. If nbytes is 0, read up + to full size of buffer. + """ + self._check_closed("read") + self._check_connected() + + if buffer is None: + raise ValueError("buffer cannot be None") + + if nbytes is None: + nbytes = len(buffer) + else: + nbytes = min(len(buffer), nbytes) + + if nbytes == 0: + return 0 + + data = _ffi.from_buffer(buffer) + length = _lib.wolfSSL_read(self.native_object, data, nbytes) + + if length < 0: + err = _lib.wolfSSL_get_error(self.native_object, 0) + if err == _SSL_ERROR_WANT_READ: + raise SSLWantReadError() + else: + raise SSLError("wolfSSL_read error (%d)" % err) + + return length + def recvfrom(self, length=1024, flags=0): # Ensures not to receive encrypted data trying to use this method @@ -651,7 +648,8 @@ class SSLSocket(object): raise SSLWantWriteError() else: eBuf = _ffi.new("char[80]") - eStr = _ffi.string(_lib.wolfSSL_ERR_error_string(err, eBuf)) + eStr = _ffi.string(_lib.wolfSSL_ERR_error_string(err, + eBuf)).decode("ascii") if 'ASN no signer error to confirm' in eStr or err is -188: # Some Python ssl consumers explicitly check error message @@ -659,8 +657,25 @@ class SSLSocket(object): raise SSLError("do_handshake failed with error %d, " "certificate verify failed" % err) - raise SSLError("do_handshake failed with error %d: %s" % - (err, eStr)) + # get alert code and string to put in exception msg + alertHistoryPtr = _ffi.new("WOLFSSL_ALERT_HISTORY*") + alertRet = _lib.wolfSSL_get_alert_history(self.native_object, + alertHistoryPtr) + if alertRet == _SSL_SUCCESS: + alertHistory = alertHistoryPtr[0] + code = alertHistory.last_rx.code + alertDesc = _lib.wolfSSL_alert_type_string_long(code) + if alertDesc != _ffi.NULL: + alertStr = _ffi.string(alertDesc).decode("ascii") + else: + alertStr = '' + + raise SSLError("do_handshake failed with error %d: %s. " + "alert (%d): %s" % + (err, eStr, code, alertStr)) + else: + raise SSLError("do_handshake failed with error %d: %s" % + (err, eStr)) def _real_connect(self, addr, connect_ex): if self.server_side: diff --git a/src/wolfssl/_build_ffi.py b/src/wolfssl/_build_ffi.py index 82e77b4..a1c1aa6 100644 --- a/src/wolfssl/_build_ffi.py +++ b/src/wolfssl/_build_ffi.py @@ -41,6 +41,20 @@ ffi.set_source( ffi.cdef( """ + + /** + * Structs + */ + typedef struct WOLFSSL_ALERT { + int code; + int level; + } WOLFSSL_ALERT; + + typedef struct WOLFSSL_ALERT_HISTORY { + WOLFSSL_ALERT last_rx; + WOLFSSL_ALERT last_tx; + } WOLFSSL_ALERT_HISTORY; + /** * Types */ @@ -104,6 +118,9 @@ ffi.cdef( void* wolfSSL_get_peer_certificate(void*); int wolfSSL_UseSNI(void*, unsigned char, const void*, unsigned short); int wolfSSL_check_domain_name(void*, const char*); + int wolfSSL_get_alert_history(void*, WOLFSSL_ALERT_HISTORY*); + char* wolfSSL_alert_type_string_long(int); + char* wolfSSL_alert_desc_string_long(int); /** * WOLFSSL_X509 functions