def do_handshake(self, block=False): # pylint: disable=unused-argument """ Perform a TLS/SSL handshake. """ self._check_closed("do_handshake") self._check_connected() if self._server_side: ret = _lib.wolfSSL_accept(self.native_object) else: ret = _lib.wolfSSL_connect(self.native_object) if ret != _SSL_SUCCESS: err = _lib.wolfSSL_get_error(self.native_object, 0) if err == _SSL_ERROR_WANT_READ: raise SSLWantReadError() elif err == _SSL_ERROR_WANT_WRITE: raise SSLWantWriteError() else: eBuf = _ffi.new("char[80]") 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 # for 'certificate verify failed' raise SSLError("do_handshake failed with error %d, " "certificate verify failed" % err) # 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 get_der(self): outSz = _ffi.new("int *") derPtr = _lib.wolfSSL_X509_get_der(self.native_object, outSz) if derPtr == _ffi.NULL: return None derBytes = _ffi.buffer(derPtr, outSz[0]) return derBytes
def set_ciphers(self, ciphers): """ Set the available ciphers for sockets created with this context. It should be a string in the wolfSSL cipher list format. If no cipher can be selected (because compile-time options or other configuration forbids use of all the specified ciphers), an SSLError will be raised. """ cipherBytes = t2b(ciphers) ret = _lib.wolfSSL_CTX_set_cipher_list(self.native_object, _ffi.new("char[]", cipherBytes)) if ret != _SSL_SUCCESS: raise SSLError("Unable to set cipher list")
def read(self, length=1024, buffer=None): """ Read up to LENGTH bytes and return them. Return zero-length string on EOF. """ self._check_closed("read") self._check_connected() if buffer is not None: raise ValueError("buffer not allowed in calls to " "read() on %s" % self.__class__) data = _ffi.new('byte[%d]' % length) length = _lib.wolfSSL_read(self.native_object, data, length) 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 _ffi.buffer(data, length)[:] if length > 0 else b''
def __init__(self, sock=None, keyfile=None, certfile=None, server_side=False, cert_reqs=CERT_NONE, ssl_version=PROTOCOL_TLS, ca_certs=None, do_handshake_on_connect=True, family=AF_INET, sock_type=SOCK_STREAM, proto=0, fileno=None, suppress_ragged_eofs=True, ciphers=None, _context=None, server_hostname=None): # set options self.do_handshake_on_connect = do_handshake_on_connect self.suppress_ragged_eofs = suppress_ragged_eofs self._server_side = server_side # save socket self._sock = sock # set context if _context: self._context = _context else: if server_side and not certfile: raise ValueError("certfile must be specified for server-side " "operations") if keyfile and not certfile: raise ValueError("certfile must be specified") if certfile and not keyfile: keyfile = certfile self._context = SSLContext(ssl_version, server_side) self._context.verify_mode = cert_reqs if ca_certs: self._context.load_verify_locations(ca_certs) if certfile: self._context.load_cert_chain(certfile, keyfile) if ciphers: self._context.set_ciphers(ciphers) self.keyfile = keyfile self.certfile = certfile self.cert_reqs = cert_reqs self.ssl_version = ssl_version self.ca_certs = ca_certs self.ciphers = ciphers self.server_hostname = server_hostname # set SNI if passed in if server_hostname is not None: self._context.use_sni(server_hostname) # see if we are connected try: self._sock.getpeername() except socket_error as exception: if exception.errno != errno.ENOTCONN: raise connected = False else: connected = True self._closed = False self._connected = connected # create the SSL object self.native_object = _lib.wolfSSL_new(self.context.native_object) if self.native_object == _ffi.NULL: raise MemoryError("Unnable to allocate ssl object") ret = _lib.wolfSSL_set_fd(self.native_object, self._sock.fileno()) if ret != _SSL_SUCCESS: self._release_native_object() raise ValueError("Unnable to set fd to ssl object") # match domain name / host name if set in context if server_hostname is not None: if self._context.check_hostname: sni = _ffi.new("char[]", server_hostname.encode("utf-8")) _lib.wolfSSL_check_domain_name(self.native_object, sni) if connected: try: if do_handshake_on_connect: self.do_handshake() except SSLError: self._release_native_object() self._sock.close() raise