From 237d723374ac05b7ec67fd2ec2021c9d43d83a44 Mon Sep 17 00:00:00 2001 From: Ludovic Chenut Date: Fri, 18 Aug 2023 11:47:20 +0200 Subject: [PATCH 01/11] Multiple fixes --- webrtc/dtls.nim | 34 +++++++++++-------- webrtc/sctp.nim | 21 ++++++++---- webrtc/{ => stun}/stun.nim | 2 +- .../stun_attributes.nim} | 2 +- webrtc/{ => stun}/stun_connection.nim | 6 ++-- webrtc/udp_connection.nim | 7 ++-- webrtc/webrtc.nim | 2 +- webrtc/webrtc_connection.nim | 4 +-- 8 files changed, 46 insertions(+), 32 deletions(-) rename webrtc/{ => stun}/stun.nim (99%) rename webrtc/{stunattributes.nim => stun/stun_attributes.nim} (99%) rename webrtc/{ => stun}/stun_connection.nim (93%) diff --git a/webrtc/dtls.nim b/webrtc/dtls.nim index a904011..0e38b89 100644 --- a/webrtc/dtls.nim +++ b/webrtc/dtls.nim @@ -8,7 +8,7 @@ # those terms. import std/times -import chronos +import chronos, chronicles import webrtc_connection import mbedtls/ssl @@ -22,6 +22,10 @@ import mbedtls/x509_crt import mbedtls/bignum import mbedtls/error import mbedtls/net_sockets +import mbedtls/timing + +logScope: + topics = "webrtc dtls" type DtlsConn* = ref object of WebRTCConn @@ -31,6 +35,7 @@ type entropy: mbedtls_entropy_context ctr_drbg: mbedtls_ctr_drbg_context + timer: mbedtls_timing_delay_context config: mbedtls_ssl_config ssl: mbedtls_ssl_context @@ -57,7 +62,6 @@ proc generateCertificate(self: DtlsConn): mbedtls_x509_crt = time_from = times.now().format(time_format) time_to = (times.now() + times.years(1)).format(time_format) - var issuer_key = self.generateKey() var write_cert: mbedtls_x509write_cert var serial_mpi: mbedtls_mpi @@ -78,14 +82,15 @@ proc generateCertificate(self: DtlsConn): mbedtls_x509_crt = mb_x509_crt_parse(result, buf) proc dtlsSend*(ctx: pointer, buf: ptr byte, len: uint): cint {.cdecl.} = - echo "dtlsSend: " + echo "Send: ", len let self = cast[ptr DtlsConn](ctx) self.sendEvent.fire() proc dtlsRecv*(ctx: pointer, buf: ptr byte, len: uint): cint {.cdecl.} = - echo "dtlsRecv: " + echo "Recv: ", len let self = cast[ptr DtlsConn](ctx)[] - self.recvEvent.fire() + + let x = self.read() method init*(self: DtlsConn, conn: WebRTCConn, address: TransportAddress) {.async.} = await procCall(WebRTCConn(self).init(conn, address)) @@ -110,7 +115,10 @@ method init*(self: DtlsConn, conn: WebRTCConn, address: TransportAddress) {.asyn mb_ssl_conf_read_timeout(self.config, 10000) # in milliseconds mb_ssl_conf_ca_chain(self.config, srvcert.next, nil) mb_ssl_conf_own_cert(self.config, srvcert, pkey) - # cookies ? + mbedtls_ssl_set_timer_cb(addr self.ssl, cast[pointer](addr self.timer), + mbedtls_timing_set_delay, + mbedtls_timing_get_delay) + # cookie ? mb_ssl_setup(self.ssl, self.config) mb_ssl_session_reset(self.ssl) mb_ssl_set_bio(self.ssl, cast[pointer](addr selfvar), @@ -118,25 +126,21 @@ method init*(self: DtlsConn, conn: WebRTCConn, address: TransportAddress) {.asyn while true: mb_ssl_handshake(self.ssl) -method close*(self: DtlsConn) {.async.} = - discard - method write*(self: DtlsConn, msg: seq[byte]) {.async.} = var buf = msg self.sendEvent.clear() - discard mbedtls_ssl_write(addr self.ssl, cast[ptr byte](buf.cstring), buf.len()) + discard mbedtls_ssl_write(addr self.ssl, cast[ptr byte](addr buf[0]), buf.len().uint) await self.sendEvent.wait() method read*(self: DtlsConn): Future[seq[byte]] {.async.} = - var res = newString(4096) - self.recvEvent.clear() - discard mbedtls_ssl_read(addr self.ssl, cast[ptr byte](res.cstring), 4096) - await self.recvEvent.wait() + return await self.conn.read() + +method close*(self: DtlsConn) {.async.} = + discard proc main {.async.} = let laddr = initTAddress("127.0.0.1:" & "4242") var dtls = DtlsConn() await dtls.init(nil, laddr) - let cert = dtls.generateCertificate() waitFor(main()) diff --git a/webrtc/sctp.nim b/webrtc/sctp.nim index d86833d..78e6004 100644 --- a/webrtc/sctp.nim +++ b/webrtc/sctp.nim @@ -8,7 +8,7 @@ # those terms. import tables, bitops, posix, strutils, sequtils -import chronos, chronicles, stew/ranges/ptr_arith +import chronos, chronicles, stew/[ranges/ptr_arith, byteutils] import usrsctp export chronicles @@ -101,10 +101,13 @@ proc write*(self: SctpConnection, buf: seq[byte]) {.async.} = self.sctp.sentConnection = self self.sctp.sentAddress = self.address let sendvErr = self.sctp.usrsctpAwait: - self.sctpSocket.usrsctp_sendv(addr buf[0], buf.len.uint, + self.sctpSocket.usrsctp_sendv(unsafeAddr buf[0], buf.len.uint, nil, 0, nil, 0, SCTP_SENDV_NOINFO, 0) +proc write*(self: SctpConnection, s: string) {.async.} = + await self.write(s.toBytes()) + proc close*(self: SctpConnection) {.async.} = self.sctp.usrsctpAwait: self.sctpSocket.usrsctp_close() @@ -143,7 +146,7 @@ proc handleUpcall(sock: ptr socket, data: pointer, flags: cint) {.cdecl.} = if bitand(flags, MSG_NOTIFICATION) != 0: trace "Notification received", length = n else: - conn.dataRecv = conn.dataRecv.concat(buffer[0..n]) + conn.dataRecv = conn.dataRecv.concat(buffer[0.. Date: Fri, 18 Aug 2023 13:37:08 +0200 Subject: [PATCH 02/11] Fix in case of double connections with sctp --- webrtc/sctp.nim | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/webrtc/sctp.nim b/webrtc/sctp.nim index 78e6004..7206c37 100644 --- a/webrtc/sctp.nim +++ b/webrtc/sctp.nim @@ -191,7 +191,7 @@ proc getOrCreateConnection(self: Sctp, self.sentAddress = address let connErr = self.usrsctpAwait: conn.sctpSocket.usrsctp_connect(cast[ptr SockAddr](addr sconn), SockLen(sizeof(sconn))) - doAssert 0 == connErr or errno == EINPROGRESS, ($errno) # TODO raise + doAssert 0 == connErr or errno == posix.EINPROGRESS, ($errno) # TODO raise self.connections[address] = conn return conn @@ -308,6 +308,8 @@ proc connect*(self: Sctp, sctpPort: uint16 = 5000): Future[SctpConnection] {.async.} = trace "Connect", address let conn = await self.getOrCreateConnection(self.udp, address, sctpPort) + if conn.state == Connected: + return conn try: await conn.connectEvent.wait() except CancelledError as exc: From 8a33c17c3842d8c23c899f691863503ed23cba0b Mon Sep 17 00:00:00 2001 From: Ludovic Chenut Date: Fri, 18 Aug 2023 14:45:25 +0200 Subject: [PATCH 03/11] Some fixes in dtls --- webrtc/{ => dtls}/dtls.nim | 43 +--------------------------- webrtc/dtls/utils.nim | 58 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 42 deletions(-) rename webrtc/{ => dtls}/dtls.nim (64%) create mode 100644 webrtc/dtls/utils.nim diff --git a/webrtc/dtls.nim b/webrtc/dtls/dtls.nim similarity index 64% rename from webrtc/dtls.nim rename to webrtc/dtls/dtls.nim index 0e38b89..01041df 100644 --- a/webrtc/dtls.nim +++ b/webrtc/dtls/dtls.nim @@ -9,7 +9,7 @@ import std/times import chronos, chronicles -import webrtc_connection +import ./utils, ../webrtc_connection import mbedtls/ssl import mbedtls/pk @@ -40,47 +40,6 @@ type config: mbedtls_ssl_config ssl: mbedtls_ssl_context -proc mbedtls_pk_rsa(pk: mbedtls_pk_context): ptr mbedtls_rsa_context = - var key = pk - case mbedtls_pk_get_type(addr key): - of MBEDTLS_PK_RSA: - return cast[ptr mbedtls_rsa_context](pk.private_pk_ctx) - else: - return nil - -proc generateKey(self: DtlsConn): mbedtls_pk_context = - var res: mbedtls_pk_context - mb_pk_init(res) - discard mbedtls_pk_setup(addr res, mbedtls_pk_info_from_type(MBEDTLS_PK_RSA)) - mb_rsa_gen_key(mb_pk_rsa(res), mbedtls_ctr_drbg_random, self.ctr_drbg, 4096, 65537) - return res - -proc generateCertificate(self: DtlsConn): mbedtls_x509_crt = - let - name = "C=FR,O=webrtc,CN=wbrtc" - time_format = initTimeFormat("YYYYMMddHHmmss") - time_from = times.now().format(time_format) - time_to = (times.now() + times.years(1)).format(time_format) - - var issuer_key = self.generateKey() - var write_cert: mbedtls_x509write_cert - var serial_mpi: mbedtls_mpi - mb_x509write_crt_init(write_cert) - mb_x509write_crt_set_md_alg(write_cert, MBEDTLS_MD_SHA256); - mb_x509write_crt_set_subject_key(write_cert, issuer_key) - mb_x509write_crt_set_issuer_key(write_cert, issuer_key) - mb_x509write_crt_set_subject_name(write_cert, name) - mb_x509write_crt_set_issuer_name(write_cert, name) - mb_x509write_crt_set_validity(write_cert, time_from, time_to) - mb_x509write_crt_set_basic_constraints(write_cert, 0, -1) - mb_x509write_crt_set_subject_key_identifier(write_cert) - mb_x509write_crt_set_authority_key_identifier(write_cert) - mb_mpi_init(serial_mpi) - let serial_hex = mb_mpi_read_string(serial_mpi, 16) - mb_x509write_crt_set_serial(write_cert, serial_mpi) - let buf = mb_x509write_crt_pem(write_cert, 4096, mbedtls_ctr_drbg_random, self.ctr_drbg) - mb_x509_crt_parse(result, buf) - proc dtlsSend*(ctx: pointer, buf: ptr byte, len: uint): cint {.cdecl.} = echo "Send: ", len let self = cast[ptr DtlsConn](ctx) diff --git a/webrtc/dtls/utils.nim b/webrtc/dtls/utils.nim new file mode 100644 index 0000000..eb71d3f --- /dev/null +++ b/webrtc/dtls/utils.nim @@ -0,0 +1,58 @@ +# Nim-WebRTC +# Copyright (c) 2023 Status Research & Development GmbH +# Licensed under either of +# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE)) +# * MIT license ([LICENSE-MIT](LICENSE-MIT)) +# at your option. +# This file may not be copied, modified, or distributed except according to +# those terms. + +import std/times + +import mbedtls/pk +import mbedtls/rsa +import mbedtls/ctr_drbg +import mbedtls/x509_crt +import mbedtls/bignum +import mbedtls/md + +proc mbedtls_pk_rsa*(pk: mbedtls_pk_context): ptr mbedtls_rsa_context = + var key = pk + case mbedtls_pk_get_type(addr key): + of MBEDTLS_PK_RSA: + return cast[ptr mbedtls_rsa_context](pk.private_pk_ctx) + else: + return nil + +proc generateKey*(random: mbedtls_ctr_drbg_context): mbedtls_pk_context = + var res: mbedtls_pk_context + mb_pk_init(res) + discard mbedtls_pk_setup(addr res, mbedtls_pk_info_from_type(MBEDTLS_PK_RSA)) + mb_rsa_gen_key(mb_pk_rsa(res), mbedtls_ctr_drbg_random, random, 4096, 65537) + return res + +proc generateCertificate*(random: mbedtls_ctr_drbg_context): mbedtls_x509_crt = + let + name = "C=FR,O=webrtc,CN=webrtc" + time_format = initTimeFormat("YYYYMMddHHmmss") + time_from = times.now().format(time_format) + time_to = (times.now() + times.years(1)).format(time_format) + + var issuer_key = random.generateKey() + var write_cert: mbedtls_x509write_cert + var serial_mpi: mbedtls_mpi + mb_x509write_crt_init(write_cert) + mb_x509write_crt_set_md_alg(write_cert, MBEDTLS_MD_SHA256); + mb_x509write_crt_set_subject_key(write_cert, issuer_key) + mb_x509write_crt_set_issuer_key(write_cert, issuer_key) + mb_x509write_crt_set_subject_name(write_cert, name) + mb_x509write_crt_set_issuer_name(write_cert, name) + mb_x509write_crt_set_validity(write_cert, time_from, time_to) + mb_x509write_crt_set_basic_constraints(write_cert, 0, -1) + mb_x509write_crt_set_subject_key_identifier(write_cert) + mb_x509write_crt_set_authority_key_identifier(write_cert) + mb_mpi_init(serial_mpi) + let serial_hex = mb_mpi_read_string(serial_mpi, 16) + mb_x509write_crt_set_serial(write_cert, serial_mpi) + let buf = mb_x509write_crt_pem(write_cert, 4096, mbedtls_ctr_drbg_random, random) + mb_x509_crt_parse(result, buf) From c28ae5ca31430f3c94a49f29893964f34f1eee29 Mon Sep 17 00:00:00 2001 From: Ludovic Chenut Date: Fri, 18 Aug 2023 17:13:34 +0200 Subject: [PATCH 04/11] dtls fixes 1 --- webrtc/dtls/dtls.nim | 100 +++++++++++++++++++++++++++++-------------- 1 file changed, 67 insertions(+), 33 deletions(-) diff --git a/webrtc/dtls/dtls.nim b/webrtc/dtls/dtls.nim index 01041df..c9debdf 100644 --- a/webrtc/dtls/dtls.nim +++ b/webrtc/dtls/dtls.nim @@ -33,8 +33,6 @@ type recvEvent: AsyncEvent sendEvent: AsyncEvent - entropy: mbedtls_entropy_context - ctr_drbg: mbedtls_ctr_drbg_context timer: mbedtls_timing_delay_context config: mbedtls_ssl_config @@ -53,37 +51,9 @@ proc dtlsRecv*(ctx: pointer, buf: ptr byte, len: uint): cint {.cdecl.} = method init*(self: DtlsConn, conn: WebRTCConn, address: TransportAddress) {.async.} = await procCall(WebRTCConn(self).init(conn, address)) - self.recvEvent = AsyncEvent() - self.sendEvent = AsyncEvent() - - mb_ctr_drbg_init(self.ctr_drbg) - mb_entropy_init(self.entropy) - mb_ctr_drbg_seed(self.ctr_drbg, mbedtls_entropy_func, - self.entropy, nil, 0) - var - srvcert = self.generateCertificate() - pkey = self.generateKey() - selfvar = self - - mb_ssl_init(self.ssl) - mb_ssl_config_init(self.config) - mb_ssl_config_defaults(self.config, MBEDTLS_SSL_IS_SERVER, - MBEDTLS_SSL_TRANSPORT_DATAGRAM, - MBEDTLS_SSL_PRESET_DEFAULT) - mb_ssl_conf_rng(self.config, mbedtls_ctr_drbg_random, self.ctr_drbg) - mb_ssl_conf_read_timeout(self.config, 10000) # in milliseconds - mb_ssl_conf_ca_chain(self.config, srvcert.next, nil) - mb_ssl_conf_own_cert(self.config, srvcert, pkey) - mbedtls_ssl_set_timer_cb(addr self.ssl, cast[pointer](addr self.timer), - mbedtls_timing_set_delay, - mbedtls_timing_get_delay) - # cookie ? - mb_ssl_setup(self.ssl, self.config) - mb_ssl_session_reset(self.ssl) - mb_ssl_set_bio(self.ssl, cast[pointer](addr selfvar), - dtlsSend, dtlsRecv, nil) - while true: - mb_ssl_handshake(self.ssl) +# self.recvEvent = AsyncEvent() +# self.sendEvent = AsyncEvent() +# method write*(self: DtlsConn, msg: seq[byte]) {.async.} = var buf = msg @@ -103,3 +73,67 @@ proc main {.async.} = await dtls.init(nil, laddr) waitFor(main()) + +type + Dtls* = ref object of RootObj + ctr_drbg: mbedtls_ctr_drbg_context + entropy: mbedtls_entropy_context + + address: TransportAddress + started: bool + +proc start*(self: Dtls, address: TransportAddress) = + if self.started: + warn "Already started" + return + + self.address = address + self.started = true + mb_ctr_drbg_init(self.ctr_drbg) + mb_entropy_init(self.entropy) + mb_ctr_drbg_seed(self.ctr_drbg, mbedtls_entropy_func, + self.entropy, nil, 0) + +proc stop*(self: Dtls) = + if not self.started: + warn "Already stopped" + return + + self.stopped = false + +proc handshake(self: DtlsConn) {.async.} = + while self.ssl.private_state != MBEDTLS_SSL_HANDSHAKE_OVER: + let res = mbedtls_ssl_handshake_step(addr self.ssl) + if res == MBEDTLS_ERR_SSL_WANT_READ or res == MBEDTLS_ERR_SSL_WANT_READ: + continue + +proc accept*(self: Dtls, conn: WebRTCConn): DtlsConn {.async.} = + var + srvcert = self.generateCertificate() + pkey = self.generateKey() + selfvar = self + + result = Dtls() + result.init(conn, self.address) + mb_ssl_init(result.ssl) + mb_ssl_config_init(result.config) + mb_ssl_config_defaults(result.config, + MBEDTLS_SSL_IS_SERVER, + MBEDTLS_SSL_TRANSPORT_DATAGRAM, + MBEDTLS_SSL_PRESET_DEFAULT) + mb_ssl_conf_rng(result.config, mbedtls_ctr_drbg_random, self.ctr_drbg) + mb_ssl_conf_read_timeout(result.config, 10000) # in milliseconds + mb_ssl_conf_ca_chain(result.config, srvcert.next, nil) + mb_ssl_conf_own_cert(result.config, srvcert, pkey) + mbedtls_ssl_set_timer_cb(addr result.ssl, cast[pointer](addr result.timer), + mbedtls_timing_set_delay, + mbedtls_timing_get_delay) + # Add the cookie management (it works without, but it's more secure) + mb_ssl_setup(result.ssl, result.config) + mb_ssl_session_reset(result.ssl) + mb_ssl_set_bio(result.ssl, cast[pointer](result), + dtlsSend, dtlsRecv, nil) + await result.handshake() + +proc dial*(self: Dtls, address: TransportAddress): DtlsConn = + discard From 8e826f7eb241f32218942404cc5e3e9bd07431c6 Mon Sep 17 00:00:00 2001 From: Ludovic Chenut Date: Fri, 18 Aug 2023 17:14:03 +0200 Subject: [PATCH 05/11] add sctp examples --- examples/sctp_client.nim | 14 ++++++++++++++ examples/sctp_server.nim | 13 +++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 examples/sctp_client.nim create mode 100644 examples/sctp_server.nim diff --git a/examples/sctp_client.nim b/examples/sctp_client.nim new file mode 100644 index 0000000..b49b1d8 --- /dev/null +++ b/examples/sctp_client.nim @@ -0,0 +1,14 @@ +import chronos, stew/byteutils +import ../webrtc/sctp + +proc main() {.async.} = + let + sctp = Sctp.new(port = 4244) + address = TransportAddress(initTAddress("127.0.0.1:4242")) + conn = await sctp.connect(address, sctpPort = 13) + await conn.write("test".toBytes) + let msg = await conn.read() + echo "Client read() finished ; receive: ", string.fromBytes(msg) + await conn.close() + +waitFor(main()) diff --git a/examples/sctp_server.nim b/examples/sctp_server.nim new file mode 100644 index 0000000..429e247 --- /dev/null +++ b/examples/sctp_server.nim @@ -0,0 +1,13 @@ +import chronos, stew/byteutils +import ../webrtc/sctp + +proc main() {.async.} = + let sctp = Sctp.new(port = 4242) + sctp.startServer(13) + let conn = await sctp.listen() + let msg = await conn.read() + echo "Receive: ", string.fromBytes(msg) + await conn.close() + sctp.stopServer() + +waitFor(main()) From d6c2877fc2eb544d74fac392b2a5763610b6d4ab Mon Sep 17 00:00:00 2001 From: Ludovic Chenut Date: Fri, 18 Aug 2023 17:19:06 +0200 Subject: [PATCH 06/11] add example sctp_both.nim --- examples/sctp_both.nim | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 examples/sctp_both.nim diff --git a/examples/sctp_both.nim b/examples/sctp_both.nim new file mode 100644 index 0000000..d801f6b --- /dev/null +++ b/examples/sctp_both.nim @@ -0,0 +1,27 @@ +import chronos, stew/byteutils +import ../webrtc/sctp as sc + +let sctp = Sctp.new(port = 4242) +proc serv(fut: Future[void]) {.async.} = + #let sctp = Sctp.new(port = 4242) + sctp.startServer(13) + fut.complete() + let conn = await sctp.listen() + echo "await read()" + let msg = await conn.read() + echo "read() finished" + echo "Receive: ", string.fromBytes(msg) + await conn.close() + sctp.stopServer() + +proc main() {.async.} = + let fut = Future[void]() + asyncSpawn serv(fut) + await fut + #let sctp = Sctp.new(port = 4244) + let address = TransportAddress(initTAddress("127.0.0.1:4242")) + let conn = await sctp.connect(address, sctpPort = 13) + await conn.write("test".toBytes) + await conn.close() + +waitFor(main()) From a65d905fb8eeca74a120c191dee12d36488051cb Mon Sep 17 00:00:00 2001 From: Ludovic Chenut Date: Fri, 18 Aug 2023 17:20:18 +0200 Subject: [PATCH 07/11] remove useless comments --- examples/sctp_both.nim | 2 -- 1 file changed, 2 deletions(-) diff --git a/examples/sctp_both.nim b/examples/sctp_both.nim index d801f6b..bb861fa 100644 --- a/examples/sctp_both.nim +++ b/examples/sctp_both.nim @@ -3,7 +3,6 @@ import ../webrtc/sctp as sc let sctp = Sctp.new(port = 4242) proc serv(fut: Future[void]) {.async.} = - #let sctp = Sctp.new(port = 4242) sctp.startServer(13) fut.complete() let conn = await sctp.listen() @@ -18,7 +17,6 @@ proc main() {.async.} = let fut = Future[void]() asyncSpawn serv(fut) await fut - #let sctp = Sctp.new(port = 4244) let address = TransportAddress(initTAddress("127.0.0.1:4242")) let conn = await sctp.connect(address, sctpPort = 13) await conn.write("test".toBytes) From 11031a47060fd2905eab5d443d4ce2a04db42a7a Mon Sep 17 00:00:00 2001 From: Ludovic Chenut Date: Tue, 22 Aug 2023 17:03:14 +0200 Subject: [PATCH 08/11] few fixes on udp & try to fix dtls read and write --- webrtc/dtls/dtls.nim | 94 ++++++++++++++++++++++++++------------- webrtc/dtls/utils.nim | 10 +++-- webrtc/udp_connection.nim | 7 +-- 3 files changed, 72 insertions(+), 39 deletions(-) diff --git a/webrtc/dtls/dtls.nim b/webrtc/dtls/dtls.nim index c9debdf..e5c2e57 100644 --- a/webrtc/dtls/dtls.nim +++ b/webrtc/dtls/dtls.nim @@ -7,7 +7,8 @@ # This file may not be copied, modified, or distributed except according to # those terms. -import std/times +import times, sequtils +import strutils # to remove import chronos, chronicles import ./utils, ../webrtc_connection @@ -40,14 +41,16 @@ type proc dtlsSend*(ctx: pointer, buf: ptr byte, len: uint): cint {.cdecl.} = echo "Send: ", len - let self = cast[ptr DtlsConn](ctx) + let self = cast[DtlsConn](ctx) self.sendEvent.fire() proc dtlsRecv*(ctx: pointer, buf: ptr byte, len: uint): cint {.cdecl.} = - echo "Recv: ", len - let self = cast[ptr DtlsConn](ctx)[] - - let x = self.read() + var self = cast[DtlsConn](ctx)[] + echo "Recv: ", self.recvData[0].len(), " ", len + echo ctx.repr + result = self.recvData[0].len().cint + copyMem(buf, addr self.recvData[0][0], self.recvData[0].len()) + self.recvData.delete(0..0) method init*(self: DtlsConn, conn: WebRTCConn, address: TransportAddress) {.async.} = await procCall(WebRTCConn(self).init(conn, address)) @@ -67,13 +70,6 @@ method read*(self: DtlsConn): Future[seq[byte]] {.async.} = method close*(self: DtlsConn) {.async.} = discard -proc main {.async.} = - let laddr = initTAddress("127.0.0.1:" & "4242") - var dtls = DtlsConn() - await dtls.init(nil, laddr) - -waitFor(main()) - type Dtls* = ref object of RootObj ctr_drbg: mbedtls_ctr_drbg_context @@ -99,41 +95,75 @@ proc stop*(self: Dtls) = warn "Already stopped" return - self.stopped = false + self.started = false proc handshake(self: DtlsConn) {.async.} = + var endpoint = + if self.ssl.private_conf.private_endpoint == MBEDTLS_SSL_IS_SERVER: + MBEDTLS_ERR_SSL_WANT_READ + else: + MBEDTLS_ERR_SSL_WANT_WRITE + while self.ssl.private_state != MBEDTLS_SSL_HANDSHAKE_OVER: + echo "State: ", toHex(self.ssl.private_state.int) + if endpoint == MBEDTLS_ERR_SSL_WANT_READ: + self.recvData.add(await self.conn.read()) + echo "=====> ", self.recvData.len() let res = mbedtls_ssl_handshake_step(addr self.ssl) - if res == MBEDTLS_ERR_SSL_WANT_READ or res == MBEDTLS_ERR_SSL_WANT_READ: + echo "Result handshake step: ", (-res).toHex, " ", + (-MBEDTLS_ERR_SSL_WANT_READ).toHex, " ", + (-MBEDTLS_ERR_SSL_WANT_WRITE).toHex + if res == MBEDTLS_ERR_SSL_WANT_READ or res == MBEDTLS_ERR_SSL_WANT_WRITE: + echo if res == MBEDTLS_ERR_SSL_WANT_READ: "WANT_READ" else: "WANT_WRITE" continue + elif res != 0: + break # raise whatever + endpoint = res -proc accept*(self: Dtls, conn: WebRTCConn): DtlsConn {.async.} = +proc accept*(self: Dtls, conn: WebRTCConn): Future[DtlsConn] {.async.} = + echo "1" var - srvcert = self.generateCertificate() - pkey = self.generateKey() + srvcert = self.ctr_drbg.generateCertificate() + pkey = self.ctr_drbg.generateKey() selfvar = self + res = DtlsConn() + let v = cast[pointer](res) + echo v.repr - result = Dtls() - result.init(conn, self.address) - mb_ssl_init(result.ssl) - mb_ssl_config_init(result.config) - mb_ssl_config_defaults(result.config, + await res.init(conn, self.address) + mb_ssl_init(res.ssl) + mb_ssl_config_init(res.config) + mb_ssl_config_defaults(res.config, MBEDTLS_SSL_IS_SERVER, MBEDTLS_SSL_TRANSPORT_DATAGRAM, MBEDTLS_SSL_PRESET_DEFAULT) - mb_ssl_conf_rng(result.config, mbedtls_ctr_drbg_random, self.ctr_drbg) - mb_ssl_conf_read_timeout(result.config, 10000) # in milliseconds - mb_ssl_conf_ca_chain(result.config, srvcert.next, nil) - mb_ssl_conf_own_cert(result.config, srvcert, pkey) - mbedtls_ssl_set_timer_cb(addr result.ssl, cast[pointer](addr result.timer), + mb_ssl_conf_rng(res.config, mbedtls_ctr_drbg_random, self.ctr_drbg) + mb_ssl_conf_read_timeout(res.config, 10000) # in milliseconds + mb_ssl_conf_ca_chain(res.config, srvcert.next, nil) + mb_ssl_conf_own_cert(res.config, srvcert, pkey) + mbedtls_ssl_set_timer_cb(addr res.ssl, cast[pointer](addr res.timer), mbedtls_timing_set_delay, mbedtls_timing_get_delay) # Add the cookie management (it works without, but it's more secure) - mb_ssl_setup(result.ssl, result.config) - mb_ssl_session_reset(result.ssl) - mb_ssl_set_bio(result.ssl, cast[pointer](result), + mb_ssl_setup(res.ssl, res.config) + mb_ssl_session_reset(res.ssl) + mb_ssl_set_bio(res.ssl, cast[pointer](res), dtlsSend, dtlsRecv, nil) - await result.handshake() + await res.handshake() + return res proc dial*(self: Dtls, address: TransportAddress): DtlsConn = discard + +import ../udp_connection +proc main() {.async.} = + let laddr = initTAddress("127.0.0.1:4433") + let udp = UdpConn() + await udp.init(nil, laddr) + let dtls = Dtls() + dtls.start(laddr) + echo "Before accept" + let x = await dtls.accept(udp) + echo "After accept" + +waitFor(main()) diff --git a/webrtc/dtls/utils.nim b/webrtc/dtls/utils.nim index eb71d3f..63ed41e 100644 --- a/webrtc/dtls/utils.nim +++ b/webrtc/dtls/utils.nim @@ -24,14 +24,14 @@ proc mbedtls_pk_rsa*(pk: mbedtls_pk_context): ptr mbedtls_rsa_context = else: return nil -proc generateKey*(random: mbedtls_ctr_drbg_context): mbedtls_pk_context = +template generateKey*(random: mbedtls_ctr_drbg_context): mbedtls_pk_context = var res: mbedtls_pk_context mb_pk_init(res) discard mbedtls_pk_setup(addr res, mbedtls_pk_info_from_type(MBEDTLS_PK_RSA)) mb_rsa_gen_key(mb_pk_rsa(res), mbedtls_ctr_drbg_random, random, 4096, 65537) - return res + res -proc generateCertificate*(random: mbedtls_ctr_drbg_context): mbedtls_x509_crt = +template generateCertificate*(random: mbedtls_ctr_drbg_context): mbedtls_x509_crt = let name = "C=FR,O=webrtc,CN=webrtc" time_format = initTimeFormat("YYYYMMddHHmmss") @@ -55,4 +55,6 @@ proc generateCertificate*(random: mbedtls_ctr_drbg_context): mbedtls_x509_crt = let serial_hex = mb_mpi_read_string(serial_mpi, 16) mb_x509write_crt_set_serial(write_cert, serial_mpi) let buf = mb_x509write_crt_pem(write_cert, 4096, mbedtls_ctr_drbg_random, random) - mb_x509_crt_parse(result, buf) + var res: mbedtls_x509_crt + mb_x509_crt_parse(res, buf) + res diff --git a/webrtc/udp_connection.nim b/webrtc/udp_connection.nim index 49d20b6..20a7173 100644 --- a/webrtc/udp_connection.nim +++ b/webrtc/udp_connection.nim @@ -7,6 +7,7 @@ # This file may not be copied, modified, or distributed except according to # those terms. +import sequtils import chronos, chronicles import webrtc_connection @@ -20,7 +21,7 @@ type recvEvent: AsyncEvent method init(self: UdpConn, conn: WebRTCConn, address: TransportAddress) {.async.} = - procCall(WebRTCConn(self).init(conn, address)) + await procCall(WebRTCConn(self).init(conn, address)) proc onReceive(udp: DatagramTransport, address: TransportAddress) {.async, gcsafe.} = let msg = udp.getMessage() @@ -33,12 +34,12 @@ method init(self: UdpConn, conn: WebRTCConn, address: TransportAddress) {.async. method close(self: UdpConn) {.async.} = self.udp.close() if not self.conn.isNil(): - self.conn.close() + await self.conn.close() method write(self: UdpConn, msg: seq[byte]) {.async.} = await self.udp.sendTo(self.address, msg) -method read(self: UdpConn): seq[byte] {.async.} = +method read(self: UdpConn): Future[seq[byte]] {.async.} = while self.recvData.len() <= 0: self.recvEvent.clear() await self.recvEvent.wait() From 12debd98a9bd511301a3c593071be1f67aa8cf2a Mon Sep 17 00:00:00 2001 From: Ludovic Chenut Date: Tue, 29 Aug 2023 17:27:44 +0200 Subject: [PATCH 09/11] Fix a lot of bugs in mbedtls, udp_connection and dtls --- webrtc/dtls/dtls.nim | 89 ++++++++++++++++++++++----------- webrtc/dtls/utils.nim | 45 +++++++++++++++-- webrtc/stun/stun_connection.nim | 3 ++ webrtc/udp_connection.nim | 16 ++++-- webrtc/webrtc_connection.nim | 3 ++ 5 files changed, 119 insertions(+), 37 deletions(-) diff --git a/webrtc/dtls/dtls.nim b/webrtc/dtls/dtls.nim index e5c2e57..b9441db 100644 --- a/webrtc/dtls/dtls.nim +++ b/webrtc/dtls/dtls.nim @@ -13,6 +13,8 @@ import chronos, chronicles import ./utils, ../webrtc_connection import mbedtls/ssl +import mbedtls/ssl_cookie +import mbedtls/ssl_cache import mbedtls/pk import mbedtls/md import mbedtls/entropy @@ -32,22 +34,30 @@ type DtlsConn* = ref object of WebRTCConn recvData: seq[seq[byte]] recvEvent: AsyncEvent - sendEvent: AsyncEvent + sendFuture: Future[void] timer: mbedtls_timing_delay_context - config: mbedtls_ssl_config ssl: mbedtls_ssl_context + config: mbedtls_ssl_config + cookie: mbedtls_ssl_cookie_ctx + cache: mbedtls_ssl_cache_context + + ctr_drbg: mbedtls_ctr_drbg_context + entropy: mbedtls_entropy_context proc dtlsSend*(ctx: pointer, buf: ptr byte, len: uint): cint {.cdecl.} = - echo "Send: ", len - let self = cast[DtlsConn](ctx) - self.sendEvent.fire() + echo "\e[36m\e[0;1m Send\e[0m: ", len + var self = cast[DtlsConn](ctx) + var toWrite = newSeq[byte](len) + if len > 0: + copyMem(addr toWrite[0], buf, len) + self.sendFuture = self.conn.write(toWrite) + result = len.cint proc dtlsRecv*(ctx: pointer, buf: ptr byte, len: uint): cint {.cdecl.} = - var self = cast[DtlsConn](ctx)[] - echo "Recv: ", self.recvData[0].len(), " ", len - echo ctx.repr + var self = cast[DtlsConn](ctx) + echo "\e[36m\e[0;1m Recv\e[0m: ", self.recvData[0].len() result = self.recvData[0].len().cint copyMem(buf, addr self.recvData[0][0], self.recvData[0].len()) self.recvData.delete(0..0) @@ -60,9 +70,7 @@ method init*(self: DtlsConn, conn: WebRTCConn, address: TransportAddress) {.asyn method write*(self: DtlsConn, msg: seq[byte]) {.async.} = var buf = msg - self.sendEvent.clear() discard mbedtls_ssl_write(addr self.ssl, cast[ptr byte](addr buf[0]), buf.len().uint) - await self.sendEvent.wait() method read*(self: DtlsConn): Future[seq[byte]] {.async.} = return await self.conn.read() @@ -70,11 +78,11 @@ method read*(self: DtlsConn): Future[seq[byte]] {.async.} = method close*(self: DtlsConn) {.async.} = discard +method getRemoteAddress*(self: DtlsConn): TransportAddress = + self.conn.getRemoteAddress() + type Dtls* = ref object of RootObj - ctr_drbg: mbedtls_ctr_drbg_context - entropy: mbedtls_entropy_context - address: TransportAddress started: bool @@ -85,10 +93,6 @@ proc start*(self: Dtls, address: TransportAddress) = self.address = address self.started = true - mb_ctr_drbg_init(self.ctr_drbg) - mb_entropy_init(self.entropy) - mb_ctr_drbg_seed(self.ctr_drbg, mbedtls_entropy_func, - self.entropy, nil, 0) proc stop*(self: Dtls) = if not self.started: @@ -105,42 +109,72 @@ proc handshake(self: DtlsConn) {.async.} = MBEDTLS_ERR_SSL_WANT_WRITE while self.ssl.private_state != MBEDTLS_SSL_HANDSHAKE_OVER: - echo "State: ", toHex(self.ssl.private_state.int) + echo "State: ", mb_ssl_states[self.ssl.private_state.int], "(", self.ssl.private_state, ")" if endpoint == MBEDTLS_ERR_SSL_WANT_READ: self.recvData.add(await self.conn.read()) echo "=====> ", self.recvData.len() - let res = mbedtls_ssl_handshake_step(addr self.ssl) - echo "Result handshake step: ", (-res).toHex, " ", - (-MBEDTLS_ERR_SSL_WANT_READ).toHex, " ", - (-MBEDTLS_ERR_SSL_WANT_WRITE).toHex + # TODO: Change set_client_transport_id in mbedtls.nim directly + var ta = self.getRemoteAddress() + case ta.family + of AddressFamily.IPv4: + discard mbedtls_ssl_set_client_transport_id(addr self.ssl, + addr ta.address_v4[0], + ta.address_v4.len().uint) + of AddressFamily.IPv6: + discard mbedtls_ssl_set_client_transport_id(addr self.ssl, + addr ta.address_v6[0], + ta.address_v6.len().uint) + else: discard # TODO: raise ? + + self.sendFuture = nil + let res = mbedtls_ssl_handshake_step(addr self.ssl) # TODO: Change in mbedtls.nim + echo "\e[34m\e[0m: ", res + if not self.sendFuture.isNil(): await self.sendFuture + echo "Result handshake step: ", res.mbedtls_high_level_strerr(), "(", res, ")" if res == MBEDTLS_ERR_SSL_WANT_READ or res == MBEDTLS_ERR_SSL_WANT_WRITE: echo if res == MBEDTLS_ERR_SSL_WANT_READ: "WANT_READ" else: "WANT_WRITE" continue + elif res == MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED: + echo "hello verification requested" + mb_ssl_session_reset(self.ssl) + endpoint = MBEDTLS_ERR_SSL_WANT_READ + continue elif res != 0: + echo "\e[31mRaise Whatever\e[0m" break # raise whatever endpoint = res proc accept*(self: Dtls, conn: WebRTCConn): Future[DtlsConn] {.async.} = - echo "1" var - srvcert = self.ctr_drbg.generateCertificate() - pkey = self.ctr_drbg.generateKey() selfvar = self res = DtlsConn() let v = cast[pointer](res) - echo v.repr await res.init(conn, self.address) mb_ssl_init(res.ssl) mb_ssl_config_init(res.config) + mbedtls_ssl_cookie_init(addr res.cookie) # TODO: Change in mbedtls.nim + mbedtls_ssl_cache_init(addr res.cache) # TODO: Change in mbedtls.nim + + mb_ctr_drbg_init(res.ctr_drbg) + mb_entropy_init(res.entropy) + mb_ctr_drbg_seed(res.ctr_drbg, mbedtls_entropy_func, res.entropy, nil, 0) + + var srvcert = res.ctr_drbg.generateCertificate() + echo "========> ", srvcert.version, " ", srvcert.raw.len + var pkey = res.ctr_drbg.generateKey() + mb_ssl_config_defaults(res.config, MBEDTLS_SSL_IS_SERVER, MBEDTLS_SSL_TRANSPORT_DATAGRAM, MBEDTLS_SSL_PRESET_DEFAULT) - mb_ssl_conf_rng(res.config, mbedtls_ctr_drbg_random, self.ctr_drbg) + mb_ssl_conf_rng(res.config, mbedtls_ctr_drbg_random, res.ctr_drbg) mb_ssl_conf_read_timeout(res.config, 10000) # in milliseconds mb_ssl_conf_ca_chain(res.config, srvcert.next, nil) mb_ssl_conf_own_cert(res.config, srvcert, pkey) + discard mbedtls_ssl_cookie_setup(addr res.cookie, mbedtls_ctr_drbg_random, addr res.ctr_drbg) # TODO: Change in mbedtls.nim + mbedtls_ssl_conf_dtls_cookies(addr res.config, mbedtls_ssl_cookie_write, + mbedtls_ssl_cookie_check, addr res.cookie) # TODO: Change in mbedtls.nim mbedtls_ssl_set_timer_cb(addr res.ssl, cast[pointer](addr res.timer), mbedtls_timing_set_delay, mbedtls_timing_get_delay) @@ -162,7 +196,6 @@ proc main() {.async.} = await udp.init(nil, laddr) let dtls = Dtls() dtls.start(laddr) - echo "Before accept" let x = await dtls.accept(udp) echo "After accept" diff --git a/webrtc/dtls/utils.nim b/webrtc/dtls/utils.nim index 63ed41e..78c4c92 100644 --- a/webrtc/dtls/utils.nim +++ b/webrtc/dtls/utils.nim @@ -18,11 +18,11 @@ import mbedtls/md proc mbedtls_pk_rsa*(pk: mbedtls_pk_context): ptr mbedtls_rsa_context = var key = pk - case mbedtls_pk_get_type(addr key): - of MBEDTLS_PK_RSA: - return cast[ptr mbedtls_rsa_context](pk.private_pk_ctx) - else: - return nil + case mbedtls_pk_get_type(addr key) + of MBEDTLS_PK_RSA: + return cast[ptr mbedtls_rsa_context](pk.private_pk_ctx) + else: + return nil template generateKey*(random: mbedtls_ctr_drbg_context): mbedtls_pk_context = var res: mbedtls_pk_context @@ -58,3 +58,38 @@ template generateCertificate*(random: mbedtls_ctr_drbg_context): mbedtls_x509_cr var res: mbedtls_x509_crt mb_x509_crt_parse(res, buf) res + + + +const mb_ssl_states* = @[ + "MBEDTLS_SSL_HELLO_REQUEST", + "MBEDTLS_SSL_CLIENT_HELLO", + "MBEDTLS_SSL_SERVER_HELLO", + "MBEDTLS_SSL_SERVER_CERTIFICATE", + "MBEDTLS_SSL_SERVER_KEY_EXCHANGE", + "MBEDTLS_SSL_CERTIFICATE_REQUEST", + "MBEDTLS_SSL_SERVER_HELLO_DONE", + "MBEDTLS_SSL_CLIENT_CERTIFICATE", + "MBEDTLS_SSL_CLIENT_KEY_EXCHANGE", + "MBEDTLS_SSL_CERTIFICATE_VERIFY", + "MBEDTLS_SSL_CLIENT_CHANGE_CIPHER_SPEC", + "MBEDTLS_SSL_CLIENT_FINISHED", + "MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC", + "MBEDTLS_SSL_SERVER_FINISHED", + "MBEDTLS_SSL_FLUSH_BUFFERS", + "MBEDTLS_SSL_HANDSHAKE_WRAPUP", + "MBEDTLS_SSL_NEW_SESSION_TICKET", + "MBEDTLS_SSL_SERVER_HELLO_VERIFY_REQUEST_SENT", + "MBEDTLS_SSL_HELLO_RETRY_REQUEST", + "MBEDTLS_SSL_ENCRYPTED_EXTENSIONS", + "MBEDTLS_SSL_END_OF_EARLY_DATA", + "MBEDTLS_SSL_CLIENT_CERTIFICATE_VERIFY", + "MBEDTLS_SSL_CLIENT_CCS_AFTER_SERVER_FINISHED", + "MBEDTLS_SSL_CLIENT_CCS_BEFORE_2ND_CLIENT_HELLO", + "MBEDTLS_SSL_SERVER_CCS_AFTER_SERVER_HELLO", + "MBEDTLS_SSL_CLIENT_CCS_AFTER_CLIENT_HELLO", + "MBEDTLS_SSL_SERVER_CCS_AFTER_HELLO_RETRY_REQUEST", + "MBEDTLS_SSL_HANDSHAKE_OVER", + "MBEDTLS_SSL_TLS1_3_NEW_SESSION_TICKET", + "MBEDTLS_SSL_TLS1_3_NEW_SESSION_TICKET_FLUSH" +] diff --git a/webrtc/stun/stun_connection.nim b/webrtc/stun/stun_connection.nim index e0d3a04..5edd9d4 100644 --- a/webrtc/stun/stun_connection.nim +++ b/webrtc/stun/stun_connection.nim @@ -46,3 +46,6 @@ method read(self: StunConn): Future[seq[byte]] {.async.} = await self.recvEvent.wait() result = self.recvData[0] self.recvData.delete(0..0) + +method getRemoteAddress*(self: StunConn): TransportAddress = + self.conn.getRemoteAddress() diff --git a/webrtc/udp_connection.nim b/webrtc/udp_connection.nim index 20a7173..6bd4952 100644 --- a/webrtc/udp_connection.nim +++ b/webrtc/udp_connection.nim @@ -17,19 +17,22 @@ logScope: type UdpConn* = ref object of WebRTCConn udp: DatagramTransport + remote: TransportAddress recvData: seq[seq[byte]] recvEvent: AsyncEvent -method init(self: UdpConn, conn: WebRTCConn, address: TransportAddress) {.async.} = - await procCall(WebRTCConn(self).init(conn, address)) +method init(self: UdpConn, conn: WebRTCConn, addrss: TransportAddress) {.async.} = + await procCall(WebRTCConn(self).init(conn, addrss)) proc onReceive(udp: DatagramTransport, address: TransportAddress) {.async, gcsafe.} = let msg = udp.getMessage() + echo "\e[33m\e[0;1m onReceive\e[0m: ", udp.getMessage().len() + self.remote = address self.recvData.add(msg) self.recvEvent.fire() self.recvEvent = newAsyncEvent() - self.udp = newDatagramTransport(onReceive, local = address) + self.udp = newDatagramTransport(onReceive, local = addrss) method close(self: UdpConn) {.async.} = self.udp.close() @@ -37,11 +40,16 @@ method close(self: UdpConn) {.async.} = await self.conn.close() method write(self: UdpConn, msg: seq[byte]) {.async.} = - await self.udp.sendTo(self.address, msg) + echo "\e[33m\e[0;1m write\e[0m" + await self.udp.sendTo(self.remote, msg) method read(self: UdpConn): Future[seq[byte]] {.async.} = + echo "\e[33m\e[0;1m read\e[0m" while self.recvData.len() <= 0: self.recvEvent.clear() await self.recvEvent.wait() result = self.recvData[0] self.recvData.delete(0..0) + +method getRemoteAddress*(self: UdpConn): TransportAddress = + self.remote diff --git a/webrtc/webrtc_connection.nim b/webrtc/webrtc_connection.nim index 5cdf63c..103d48c 100644 --- a/webrtc/webrtc_connection.nim +++ b/webrtc/webrtc_connection.nim @@ -28,3 +28,6 @@ method write*(self: WebRTCConn, msg: seq[byte]) {.async, base.} = method read*(self: WebRTCConn): Future[seq[byte]] {.async, base.} = doAssert(false, "not implemented!") + +method getRemoteAddress*(self: WebRTCConn): TransportAddress {.base.} = + doAssert(false, "not implemented") From bf8ea1bbaa8169eb2f1e7f80c1ac84ddb6d125d4 Mon Sep 17 00:00:00 2001 From: Ludovic Chenut Date: Tue, 3 Oct 2023 16:36:38 +0200 Subject: [PATCH 10/11] Clear DTLS Server --- webrtc/dtls/dtls.nim | 47 +++++++-------------- webrtc/dtls/utils.nim | 97 +++++++++++++++++++++++-------------------- 2 files changed, 66 insertions(+), 78 deletions(-) diff --git a/webrtc/dtls/dtls.nim b/webrtc/dtls/dtls.nim index b9441db..39a10d4 100644 --- a/webrtc/dtls/dtls.nim +++ b/webrtc/dtls/dtls.nim @@ -47,7 +47,6 @@ type entropy: mbedtls_entropy_context proc dtlsSend*(ctx: pointer, buf: ptr byte, len: uint): cint {.cdecl.} = - echo "\e[36m\e[0;1m Send\e[0m: ", len var self = cast[DtlsConn](ctx) var toWrite = newSeq[byte](len) if len > 0: @@ -57,16 +56,12 @@ proc dtlsSend*(ctx: pointer, buf: ptr byte, len: uint): cint {.cdecl.} = proc dtlsRecv*(ctx: pointer, buf: ptr byte, len: uint): cint {.cdecl.} = var self = cast[DtlsConn](ctx) - echo "\e[36m\e[0;1m Recv\e[0m: ", self.recvData[0].len() result = self.recvData[0].len().cint copyMem(buf, addr self.recvData[0][0], self.recvData[0].len()) self.recvData.delete(0..0) method init*(self: DtlsConn, conn: WebRTCConn, address: TransportAddress) {.async.} = await procCall(WebRTCConn(self).init(conn, address)) -# self.recvEvent = AsyncEvent() -# self.sendEvent = AsyncEvent() -# method write*(self: DtlsConn, msg: seq[byte]) {.async.} = var buf = msg @@ -109,38 +104,28 @@ proc handshake(self: DtlsConn) {.async.} = MBEDTLS_ERR_SSL_WANT_WRITE while self.ssl.private_state != MBEDTLS_SSL_HANDSHAKE_OVER: - echo "State: ", mb_ssl_states[self.ssl.private_state.int], "(", self.ssl.private_state, ")" - if endpoint == MBEDTLS_ERR_SSL_WANT_READ: + if endpoint == MBEDTLS_ERR_SSL_WANT_READ or + self.ssl.private_state == MBEDTLS_SSL_CLIENT_KEY_EXCHANGE: self.recvData.add(await self.conn.read()) - echo "=====> ", self.recvData.len() - # TODO: Change set_client_transport_id in mbedtls.nim directly var ta = self.getRemoteAddress() case ta.family of AddressFamily.IPv4: - discard mbedtls_ssl_set_client_transport_id(addr self.ssl, - addr ta.address_v4[0], - ta.address_v4.len().uint) - of AddressFamily.IPv6: - discard mbedtls_ssl_set_client_transport_id(addr self.ssl, - addr ta.address_v6[0], - ta.address_v6.len().uint) - else: discard # TODO: raise ? + mb_ssl_set_client_transport_id(self.ssl, ta.address_v4) + of AddressFamily.IPv6: + mb_ssl_set_client_transport_id(self.ssl, ta.address_v6) + else: + discard # TODO: raise ? self.sendFuture = nil - let res = mbedtls_ssl_handshake_step(addr self.ssl) # TODO: Change in mbedtls.nim - echo "\e[34m\e[0m: ", res + let res = mb_ssl_handshake_step(self.ssl) if not self.sendFuture.isNil(): await self.sendFuture - echo "Result handshake step: ", res.mbedtls_high_level_strerr(), "(", res, ")" if res == MBEDTLS_ERR_SSL_WANT_READ or res == MBEDTLS_ERR_SSL_WANT_WRITE: - echo if res == MBEDTLS_ERR_SSL_WANT_READ: "WANT_READ" else: "WANT_WRITE" continue elif res == MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED: - echo "hello verification requested" mb_ssl_session_reset(self.ssl) endpoint = MBEDTLS_ERR_SSL_WANT_READ continue elif res != 0: - echo "\e[31mRaise Whatever\e[0m" break # raise whatever endpoint = res @@ -153,16 +138,15 @@ proc accept*(self: Dtls, conn: WebRTCConn): Future[DtlsConn] {.async.} = await res.init(conn, self.address) mb_ssl_init(res.ssl) mb_ssl_config_init(res.config) - mbedtls_ssl_cookie_init(addr res.cookie) # TODO: Change in mbedtls.nim - mbedtls_ssl_cache_init(addr res.cache) # TODO: Change in mbedtls.nim + mb_ssl_cookie_init(res.cookie) + mb_ssl_cache_init(res.cache) mb_ctr_drbg_init(res.ctr_drbg) mb_entropy_init(res.entropy) mb_ctr_drbg_seed(res.ctr_drbg, mbedtls_entropy_func, res.entropy, nil, 0) - var srvcert = res.ctr_drbg.generateCertificate() - echo "========> ", srvcert.version, " ", srvcert.raw.len var pkey = res.ctr_drbg.generateKey() + var srvcert = res.ctr_drbg.generateCertificate(pkey) mb_ssl_config_defaults(res.config, MBEDTLS_SSL_IS_SERVER, @@ -172,12 +156,9 @@ proc accept*(self: Dtls, conn: WebRTCConn): Future[DtlsConn] {.async.} = mb_ssl_conf_read_timeout(res.config, 10000) # in milliseconds mb_ssl_conf_ca_chain(res.config, srvcert.next, nil) mb_ssl_conf_own_cert(res.config, srvcert, pkey) - discard mbedtls_ssl_cookie_setup(addr res.cookie, mbedtls_ctr_drbg_random, addr res.ctr_drbg) # TODO: Change in mbedtls.nim - mbedtls_ssl_conf_dtls_cookies(addr res.config, mbedtls_ssl_cookie_write, - mbedtls_ssl_cookie_check, addr res.cookie) # TODO: Change in mbedtls.nim - mbedtls_ssl_set_timer_cb(addr res.ssl, cast[pointer](addr res.timer), - mbedtls_timing_set_delay, - mbedtls_timing_get_delay) + mb_ssl_cookie_setup(res.cookie, mbedtls_ctr_drbg_random, res.ctr_drbg) + mb_ssl_conf_dtls_cookies(res.config, res.cookie) + mb_ssl_set_timer_cb(res.ssl, res.timer) # Add the cookie management (it works without, but it's more secure) mb_ssl_setup(res.ssl, res.config) mb_ssl_session_reset(res.ssl) diff --git a/webrtc/dtls/utils.nim b/webrtc/dtls/utils.nim index 78c4c92..6f9ad5b 100644 --- a/webrtc/dtls/utils.nim +++ b/webrtc/dtls/utils.nim @@ -9,6 +9,8 @@ import std/times +import stew/byteutils + import mbedtls/pk import mbedtls/rsa import mbedtls/ctr_drbg @@ -16,52 +18,9 @@ import mbedtls/x509_crt import mbedtls/bignum import mbedtls/md -proc mbedtls_pk_rsa*(pk: mbedtls_pk_context): ptr mbedtls_rsa_context = - var key = pk - case mbedtls_pk_get_type(addr key) - of MBEDTLS_PK_RSA: - return cast[ptr mbedtls_rsa_context](pk.private_pk_ctx) - else: - return nil +import chronicles -template generateKey*(random: mbedtls_ctr_drbg_context): mbedtls_pk_context = - var res: mbedtls_pk_context - mb_pk_init(res) - discard mbedtls_pk_setup(addr res, mbedtls_pk_info_from_type(MBEDTLS_PK_RSA)) - mb_rsa_gen_key(mb_pk_rsa(res), mbedtls_ctr_drbg_random, random, 4096, 65537) - res - -template generateCertificate*(random: mbedtls_ctr_drbg_context): mbedtls_x509_crt = - let - name = "C=FR,O=webrtc,CN=webrtc" - time_format = initTimeFormat("YYYYMMddHHmmss") - time_from = times.now().format(time_format) - time_to = (times.now() + times.years(1)).format(time_format) - - var issuer_key = random.generateKey() - var write_cert: mbedtls_x509write_cert - var serial_mpi: mbedtls_mpi - mb_x509write_crt_init(write_cert) - mb_x509write_crt_set_md_alg(write_cert, MBEDTLS_MD_SHA256); - mb_x509write_crt_set_subject_key(write_cert, issuer_key) - mb_x509write_crt_set_issuer_key(write_cert, issuer_key) - mb_x509write_crt_set_subject_name(write_cert, name) - mb_x509write_crt_set_issuer_name(write_cert, name) - mb_x509write_crt_set_validity(write_cert, time_from, time_to) - mb_x509write_crt_set_basic_constraints(write_cert, 0, -1) - mb_x509write_crt_set_subject_key_identifier(write_cert) - mb_x509write_crt_set_authority_key_identifier(write_cert) - mb_mpi_init(serial_mpi) - let serial_hex = mb_mpi_read_string(serial_mpi, 16) - mb_x509write_crt_set_serial(write_cert, serial_mpi) - let buf = mb_x509write_crt_pem(write_cert, 4096, mbedtls_ctr_drbg_random, random) - var res: mbedtls_x509_crt - mb_x509_crt_parse(res, buf) - res - - - -const mb_ssl_states* = @[ +const mb_ssl_states* = @[ "MBEDTLS_SSL_HELLO_REQUEST", "MBEDTLS_SSL_CLIENT_HELLO", "MBEDTLS_SSL_SERVER_HELLO", @@ -93,3 +52,51 @@ const mb_ssl_states* = @[ "MBEDTLS_SSL_TLS1_3_NEW_SESSION_TICKET", "MBEDTLS_SSL_TLS1_3_NEW_SESSION_TICKET_FLUSH" ] + +proc mbedtls_pk_rsa*(pk: mbedtls_pk_context): ptr mbedtls_rsa_context = + var key = pk + case mbedtls_pk_get_type(addr key) + of MBEDTLS_PK_RSA: + return cast[ptr mbedtls_rsa_context](pk.private_pk_ctx) + else: + return nil + +template generateKey*(random: mbedtls_ctr_drbg_context): mbedtls_pk_context = + var res: mbedtls_pk_context + mb_pk_init(res) + discard mbedtls_pk_setup(addr res, mbedtls_pk_info_from_type(MBEDTLS_PK_RSA)) + mb_rsa_gen_key(mb_pk_rsa(res), mbedtls_ctr_drbg_random, random, 2048, 65537) + let x = mb_pk_rsa(res) + res + +template generateCertificate*(random: mbedtls_ctr_drbg_context, + issuer_key: mbedtls_pk_context): mbedtls_x509_crt = + let + name = "C=FR,O=Status,CN=webrtc" + time_format = initTimeFormat("YYYYMMddHHmmss") + time_from = times.now().format(time_format) + time_to = (times.now() + times.years(1)).format(time_format) + + var write_cert: mbedtls_x509write_cert + var serial_mpi: mbedtls_mpi + mb_x509write_crt_init(write_cert) + mb_x509write_crt_set_md_alg(write_cert, MBEDTLS_MD_SHA256); + mb_x509write_crt_set_subject_key(write_cert, issuer_key) + mb_x509write_crt_set_issuer_key(write_cert, issuer_key) + mb_x509write_crt_set_subject_name(write_cert, name) + mb_x509write_crt_set_issuer_name(write_cert, name) + mb_x509write_crt_set_validity(write_cert, time_from, time_to) + mb_x509write_crt_set_basic_constraints(write_cert, 0, -1) + mb_x509write_crt_set_subject_key_identifier(write_cert) + mb_x509write_crt_set_authority_key_identifier(write_cert) + mb_mpi_init(serial_mpi) + let serial_hex = mb_mpi_read_string(serial_mpi, 16) + mb_x509write_crt_set_serial(write_cert, serial_mpi) + let buf = + try: + mb_x509write_crt_pem(write_cert, 2048, mbedtls_ctr_drbg_random, random) + except MbedTLSError as e: + raise e + var res: mbedtls_x509_crt + mb_x509_crt_parse(res, buf) + res From ca2b411f97023260f0a3f03e0fd38262e89283b4 Mon Sep 17 00:00:00 2001 From: Ludovic Chenut Date: Thu, 5 Oct 2023 13:14:42 +0200 Subject: [PATCH 11/11] Finalize dtls server --- webrtc/dtls/dtls.nim | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/webrtc/dtls/dtls.nim b/webrtc/dtls/dtls.nim index 39a10d4..e78b75b 100644 --- a/webrtc/dtls/dtls.nim +++ b/webrtc/dtls/dtls.nim @@ -8,7 +8,6 @@ # those terms. import times, sequtils -import strutils # to remove import chronos, chronicles import ./utils, ../webrtc_connection @@ -31,6 +30,7 @@ logScope: topics = "webrtc dtls" type + DtlsError* = object of CatchableError DtlsConn* = ref object of WebRTCConn recvData: seq[seq[byte]] recvEvent: AsyncEvent @@ -96,16 +96,11 @@ proc stop*(self: Dtls) = self.started = false -proc handshake(self: DtlsConn) {.async.} = - var endpoint = - if self.ssl.private_conf.private_endpoint == MBEDTLS_SSL_IS_SERVER: - MBEDTLS_ERR_SSL_WANT_READ - else: - MBEDTLS_ERR_SSL_WANT_WRITE +proc serverHandshake(self: DtlsConn) {.async.} = + var shouldRead = true while self.ssl.private_state != MBEDTLS_SSL_HANDSHAKE_OVER: - if endpoint == MBEDTLS_ERR_SSL_WANT_READ or - self.ssl.private_state == MBEDTLS_SSL_CLIENT_KEY_EXCHANGE: + if shouldRead: self.recvData.add(await self.conn.read()) var ta = self.getRemoteAddress() case ta.family @@ -114,20 +109,24 @@ proc handshake(self: DtlsConn) {.async.} = of AddressFamily.IPv6: mb_ssl_set_client_transport_id(self.ssl, ta.address_v6) else: - discard # TODO: raise ? + raise newException(DtlsError, "Remote address isn't an IP address") self.sendFuture = nil let res = mb_ssl_handshake_step(self.ssl) + shouldRead = false if not self.sendFuture.isNil(): await self.sendFuture - if res == MBEDTLS_ERR_SSL_WANT_READ or res == MBEDTLS_ERR_SSL_WANT_WRITE: + if res == MBEDTLS_ERR_SSL_WANT_WRITE: + continue + elif res == MBEDTLS_ERR_SSL_WANT_READ or + self.ssl.private_state == MBEDTLS_SSL_CLIENT_KEY_EXCHANGE: + shouldRead = true continue elif res == MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED: mb_ssl_session_reset(self.ssl) - endpoint = MBEDTLS_ERR_SSL_WANT_READ + shouldRead = true continue elif res != 0: - break # raise whatever - endpoint = res + raise newException(DtlsError, $(res.mbedtls_high_level_strerr())) proc accept*(self: Dtls, conn: WebRTCConn): Future[DtlsConn] {.async.} = var @@ -159,12 +158,11 @@ proc accept*(self: Dtls, conn: WebRTCConn): Future[DtlsConn] {.async.} = mb_ssl_cookie_setup(res.cookie, mbedtls_ctr_drbg_random, res.ctr_drbg) mb_ssl_conf_dtls_cookies(res.config, res.cookie) mb_ssl_set_timer_cb(res.ssl, res.timer) - # Add the cookie management (it works without, but it's more secure) mb_ssl_setup(res.ssl, res.config) mb_ssl_session_reset(res.ssl) mb_ssl_set_bio(res.ssl, cast[pointer](res), dtlsSend, dtlsRecv, nil) - await res.handshake() + await res.serverHandshake() return res proc dial*(self: Dtls, address: TransportAddress): DtlsConn =