Coder Social home page Coder Social logo

Comments (16)

Synss avatar Synss commented on June 12, 2024

Hi @P2Uming, I will look into this shortly.

from python-mbedtls.

Synss avatar Synss commented on June 12, 2024

While trying some more, I got some reproducible segmentation faults. There is definitely something wrong here.

from python-mbedtls.

mingssun avatar mingssun commented on June 12, 2024

Hi @Synss, Thanks for your effort, Looking forward to the fix!

from python-mbedtls.

Krolken avatar Krolken commented on June 12, 2024

I am not sure the solution with a wrapped socket is the best one of a server implementation.

A server need to accept multiple "connection" from many clients. It seems like the solution with a wrapped socket only will support 1 client as it says in the documentation that you need to make a new bind() for new clients. But you can only bind on one port at a time.

A better and maybe simpler solution would maybe be to have a DTLSSessionManager that sits between the socket and application.
The manager would store DTLS handshake state for each client that is connecting to it and return the correct responses.
As it keeps a record of clients it could also support sleeping clients and clients behind NATs if you would use the CID identifier but resuming the DTLS session. In an IoT environment it is important to keep the number of handshakes to a minimum.

So my proposed solution would be to not wrap the socket. Keep the socket as standard and handle the DTLS state in another class. Since you would use a standard socket it should be simple to integrate into different I/O paradigms. Just use a simple socketserver or use asyncio.

some psuedo-code

sock = make_socket()
appliation_reader, application_writer = get_app_reader_writer()

def on_datagram(data, addr):
   """Our server socket receives a datagram"""
   # If there is a DTLS connection the decrypted datagram will be passed to application_reader.
   # If not the next handshake package will be sent back
   sock.send(DTLSSessionManager.recv(data, addr))

I am just not sure on what parts of the mbedtls I need to interact with to support this setup.

from python-mbedtls.

Krolken avatar Krolken commented on June 12, 2024

I tired setting up a small sample using "socketserver"

from socketserver import ThreadingUDPServer, BaseRequestHandler
import logging

from mbedtls import tls

logger = logging.getLogger(__name__)


class SimpleUdpHandler(BaseRequestHandler):
    """
    Simple request handler for UDP that will log incoming data.
    """

    def handle(self):
        srv_conf = tls.DTLSConfiguration(
            ciphers=(  # PSK Requires the selection PSK ciphers.
                "TLS-ECDHE-PSK-WITH-CHACHA20-POLY1305-SHA256",
                "TLS-RSA-PSK-WITH-CHACHA20-POLY1305-SHA256",
                "TLS-PSK-WITH-CHACHA20-POLY1305-SHA256",
            ),
            pre_shared_key_store={
                "client0": b"a secret",
                "client1": b"other secret",
                "client42": b"the secret",
                "client100": b"yet another one",
            },
        )
        dtls_context = tls.ServerContext(srv_conf)
        dtls_buffer = tls.TLSWrappedBuffer(dtls_context)

        data = self.request[0]
        socket = self.request[1]
        # dtls_socket = dtls_context.wrap_socket(socket)
        print(dtls_context._state)
        dtls_buffer._setcookieparam(str((self.client_address[0])).encode())
        dtls_buffer.receive_from_network(data)

        # dtls_socket.do_handshake()
        dtls_buffer._as_bio()
        dtls_buffer.do_handshake()

        print(dtls_context._state)

        print(data)
        print(socket)
        logger.debug(
            f"Received UDP Message",
            extra={
                "data": f"{data!r}",
                "host": self.client_address[0],
                "port": self.client_address[1],
            },
        )


if __name__ == "__main__":
    request_handler = SimpleUdpHandler

    with ThreadingUDPServer(("localhost", 2883), request_handler) as server:
        click.secho(
            f"Staring {server.__class__.__name__} ",
            fg="bright_yellow",
            blink=True,
        )
        server.serve_forever()

If I try to use a wrapped socket I get the error mbedtls.exceptions.TLSError: TLSError([0x004E] 'NET - Sending information through the socket failed')

But I wanted to try and only use the buffer to be able to handle the sockets and threads myself. But the _as_bio() is not availabe on the python object. If I just call dtls_buffer.do_handshake() i get mbedtls.exceptions.TLSError: TLSError([0x7100] 'SSL - Bad input parameters to function')

from python-mbedtls.

Synss avatar Synss commented on June 12, 2024

Indeed,

It seems like the solution with a wrapped socket only will support 1 client as it says in the documentation that you need to make a new bind() for new clients. But you can only bind on one port at a time.

is entirely correct. The wrapped socket comes from https://www.python.org/dev/peps/pep-0543/#toc-entry-10 so it is not something I will change. However,

the _as_bio() is not availabe on the python object.

the _as_bio() functions should not be necessary, at all. It was a useful shortcut I took in the beginning but it is on my to-do list to remove it and perform the handshake explicitly. That would result in further simplification such as making TLSWrappedSocket pure Python.

If that helps here I might as well do it sooner than later. It should be possible to perform the handshake using the buffer and a regular socket.socket(). However, it is not easy to explain and removing _as_bio() would be the perfect example for this.

from python-mbedtls.

Krolken avatar Krolken commented on June 12, 2024

I made a public method calling _as_bio() in my fork and then I could get futher.
What I can't find in the mbedtls code is what generates the payloads.
I assume I should add the ClientHello in the buffer, then try to move the state. Since there is no cookie we get the HelloVerifyRequeset exception.
But where do I get the payload for the HelloVerify? If i use buffer.consume_output I get None.

from python-mbedtls.

Synss avatar Synss commented on June 12, 2024

The handshake does not use the buffer. Be sure to call _as_bio() on TLSWrappedBuffer. Then, you will probably need to jungle between the two buffers. You should probably publicise them as well, or at least some part of them (like their current size) if you want to keep on debugging. I am working on it as well.

from python-mbedtls.

Synss avatar Synss commented on June 12, 2024

Sorry, I realise I misunderstood your question and you are that far already.

But where do I get the payload for the HelloVerify? If i use buffer.consume_output I get None.

The best for the details of the handshake with a raw socket is probably to check upstream:

from python-mbedtls.

Synss avatar Synss commented on June 12, 2024

@Krolken : As it seems you wanted to have a go at it as well I just pushed my dev branch

https://github.com/Synss/python-mbedtls/tree/dev

where the last commit performs a TLS handshake in the TLSWrappedBuffer instead of bypassing it. That means, handshake does not require the TLSWrappedSocket anymore (and actually does not use it).

I only tested it on TLS, DTLS will not work. But the idea is here. I will keep working on it and rebase/rewrite the history of the dev branch, too, so do not build on it: it will keep moving! 😉

from python-mbedtls.

Krolken avatar Krolken commented on June 12, 2024

Thanks. Pulled it last night and tried some things. I am not able to get it to raise a HelloVerifyRequest Exception.
Also tried rewriting the handshake with sendto(), which did work on returning the response but since it did not raise a HelloVerifyRequest it just sent b'' and the client interpreted it as EOF.
Then of course it wouldn't work on the second try with my current setup as it is a threaded server and it would create a new thread for the response.

My current plan is to keep a dict of source_address and port mapping to the context as shared state. Just need to figure out how to initialize the handshake properly.

Now I am doing something like this.

dtls_context = tls.ServerContext(srv_conf)
dtls_buffer = tls.TLSWrappedBuffer(dtls_context)
data = get_udp_data()
dtls_buffer.receive_from_network(data)
dtls_buffer._setcookieparam(self.client_address[0].encode('ascii'))
# Assumed this would raise HelloVerify
dtls_buffer.context._do_handshake_step()
# and assumed that the data to send back would be in the buffer.
print(dtls_buffer.peek_outgoing(1024))

from python-mbedtls.

Synss avatar Synss commented on June 12, 2024

I have not forgotten about this issue but my personal computer is broken.

from python-mbedtls.

Krolken avatar Krolken commented on June 12, 2024

No problem. I have been bogged down with other stuff.

from python-mbedtls.

Synss avatar Synss commented on June 12, 2024

Current master should have most of the necessary changes we discussed here.

  • TLSWrappedSocket and TLSWrappedBuffer are pure Python: less magic happens here and they may be swapped for other implementations.
  • The handshake now happens entirely in the TLS context instead of the wrapped socket and buffer.

I also have example client/server under programs.

from python-mbedtls.

Synss avatar Synss commented on June 12, 2024

On master, ClientContext and ServerContext are picklable (and therefore threadable or multiprocessing-friendly) and the contexts can wrap several sockets or buffers.

Now, some changes are still in progress for the handshake but, unless I am overlooking something important, the points above should fix this issue.

from python-mbedtls.

Synss avatar Synss commented on June 12, 2024

Now, I/O and crypto are independent and you can select any strategy you want on the I/O layer. The latest patches exemplify the crypto part without any actual I/O (test_tls).

Note that session tickets are currently not available on master. This is known and I am working on it. I may still release the current code without session handling shortly and add the session handling back later.

There have been small API changes since 1.6-1.7.

from python-mbedtls.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.