Modified do_handshake() to send a heartbleed payload and return the result.

def do_handshake_with_heartbleed(self):  # type: ignore
    """Modified do_handshake() to send a heartbleed payload and return the result.
    """
    try:
        # Start the handshake using nassl - will throw WantReadError right away
        self._ssl.do_handshake()
    except WantReadError:
        # Send the Client Hello
        len_to_read = self._network_bio.pending()
        while len_to_read:
            # Get the data from the SSL engine
            handshake_data_out = self._network_bio.read(len_to_read)
            # Send it to the peer
            self._sock.send(handshake_data_out)
            len_to_read = self._network_bio.pending()

    # Build the heartbleed payload - based on
    # https://blog.mozilla.org/security/2014/04/12/testing-for-heartbleed-vulnerability-without-exploiting-the-server/
    payload = TlsHeartbeatRequestRecord.from_parameters(
        tls_version=TlsVersionEnum[self._ssl_version.name],
        heartbeat_data=b'\x01' * 16381
    ).to_bytes()

    payload += TlsHeartbeatRequestRecord.from_parameters(
        TlsVersionEnum[self._ssl_version.name],
        heartbeat_data=b'\x01\x00\x00'
    ).to_bytes()

    # Send the payload
    self._sock.send(payload)

    # Retrieve the server's response - directly read the underlying network socket
    # Retrieve data until we get to the ServerHelloDone
    # The server may send back a ServerHello, an Alert, a CertificateRequest or may just close the connection
    did_receive_hello_done = False
    remaining_bytes = b''
    while not did_receive_hello_done:
        try:
            tls_record, len_consumed = TlsRecordParser.parse_bytes(remaining_bytes)
            remaining_bytes = remaining_bytes[len_consumed::]
        except NotEnoughData:
            # Try to get more data
            try:
                raw_ssl_bytes = self._sock.recv(16381)
            except socket.error:
                # Server closed the connection as soon as it received the Heartbleed payload
                raise NotVulnerableToHeartbleed()

            if not raw_ssl_bytes:
                # No data?
                raise NotVulnerableToHeartbleed()

            remaining_bytes = remaining_bytes + raw_ssl_bytes
            continue

        if isinstance(tls_record, TlsHandshakeRecord):
            # Does the record contain a ServerDone message?
            for handshake_message in tls_record.subprotocol_messages:
                if handshake_message.handshake_type == TlsHandshakeTypeByte.SERVER_DONE:
                    did_receive_hello_done = True
                    break
            # If not, it could be a ServerHello, Certificate or a CertificateRequest if the server requires client auth
        elif isinstance(tls_record, TlsAlertRecord):
            # Server returned a TLS alert
            break
        else:
            raise ValueError('Unknown record? Type {}'.format(tls_record.header.type))

    is_vulnerable_to_heartbleed = False
    if did_receive_hello_done:
        expected_heartbleed_payload = b'\x01' * 10
        if expected_heartbleed_payload in remaining_bytes:
            # Server replied with our hearbeat payload
            is_vulnerable_to_heartbleed = True
        else:
            try:
                raw_ssl_bytes = self._sock.recv(16381)
            except socket.error:
                # Server closed the connection after receiving the heartbleed payload
                raise NotVulnerableToHeartbleed()

            if expected_heartbleed_payload in raw_ssl_bytes:
                # Server replied with our hearbeat payload
                is_vulnerable_to_heartbleed = True

    if is_vulnerable_to_heartbleed:
        raise VulnerableToHeartbleed()
    else:
        raise NotVulnerableToHeartbleed()