Skip to content

Commit e26560b

Browse files
lealem47danielinux
authored andcommitted
Adding DTLS support
1 parent 8117569 commit e26560b

5 files changed

Lines changed: 124 additions & 30 deletions

File tree

examples/client.py

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,11 @@ def build_arg_parser():
5959
"(SSLv3, TLSv1, TLSv1.1, TLSv1.2, TLSv1.3, SSLv23)"
6060
)
6161

62+
parser.add_argument(
63+
"-u", action="store_true",
64+
help="Use UDP DTLS, add -v 0 for DTLSv1, -v 1 for DTLSv1.2 (default)"
65+
)
66+
6267
parser.add_argument(
6368
"-l", metavar="ciphers", type=str, default="",
6469
help="Cipher suite list (: delimited)"
@@ -103,7 +108,7 @@ def build_arg_parser():
103108
return parser
104109

105110

106-
def get_method(index):
111+
def get_SSLmethod(index):
107112
return (
108113
wolfssl.PROTOCOL_SSLv3,
109114
wolfssl.PROTOCOL_TLSv1,
@@ -113,17 +118,27 @@ def get_method(index):
113118
wolfssl.PROTOCOL_SSLv23
114119
)[index]
115120

121+
def get_DTLSmethod(index):
122+
return (
123+
wolfssl.PROTOCOL_DTLSv1,
124+
wolfssl.PROTOCOL_DTLSv1_2
125+
)[index]
116126

117127
def main():
118128
args = build_arg_parser().parse_args()
119129

120-
bind_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
130+
# DTLS connection over UDP
131+
if args.u:
132+
bind_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0)
133+
context = wolfssl.SSLContext(get_DTLSmethod(args.v))
134+
# SSL/TLS connection over TCP
135+
else:
136+
bind_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
137+
context = wolfssl.SSLContext(get_SSLmethod(args.v))
121138

122139
# enable debug, if native wolfSSL has been compiled with '--enable-debug'
123140
wolfssl.WolfSSL.enable_debug()
124141

125-
context = wolfssl.SSLContext(get_method(args.v))
126-
127142
context.load_cert_chain(args.c, args.k)
128143

129144
if args.d:

examples/server.py

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@ def build_arg_parser():
5454
"(SSLv3, TLSv1, TLSv1.1, TLSv1.2, TLSv1_3, SSLv23)"
5555
)
5656

57+
parser.add_argument(
58+
"-u", action="store_true",
59+
help="Use UDP DTLS, add -v 0 for DTLSv1, -v 1 for DTLSv1.2"
60+
)
61+
5762
parser.add_argument(
5863
"-l", metavar="ciphers", type=str, default="",
5964
help="Cipher suite list (: delimited)"
@@ -92,7 +97,7 @@ def build_arg_parser():
9297
return parser
9398

9499

95-
def get_method(index):
100+
def get_SSLmethod(index):
96101
return (
97102
wolfssl.PROTOCOL_SSLv3,
98103
wolfssl.PROTOCOL_TLSv1,
@@ -102,21 +107,36 @@ def get_method(index):
102107
wolfssl.PROTOCOL_SSLv23
103108
)[index]
104109

110+
def get_DTLSmethod(index):
111+
return (
112+
wolfssl.PROTOCOL_DTLSv1,
113+
wolfssl.PROTOCOL_DTLSv1_2
114+
)[index]
115+
105116

106117
def main():
107118
args = build_arg_parser().parse_args()
108-
109-
bind_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
110-
bind_socket.bind(("" if args.b else "localhost", args.p))
111-
bind_socket.listen(5)
119+
# DTLS connection over UDP
120+
if args.u:
121+
# Set DTLSv1.2 as default if unspecified
122+
if args.v == 5:
123+
args.v = 1
124+
bind_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0)
125+
bind_socket.bind(("" if args.b else "localhost", args.p))
126+
data, from_addr = bind_socket.recvfrom(1)
127+
context = wolfssl.SSLContext(get_DTLSmethod(args.v), server_side=True)
128+
# SSL/TLS connection over TCP
129+
else:
130+
bind_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
131+
bind_socket.bind(("" if args.b else "localhost", args.p))
132+
bind_socket.listen(5)
133+
context = wolfssl.SSLContext(get_SSLmethod(args.v), server_side=True)
112134

113135
print("Server listening on port", bind_socket.getsockname()[1])
114136

115137
# enable debug, if native wolfSSL has been compiled with '--enable-debug'
116138
wolfssl.WolfSSL.enable_debug()
117139

118-
context = wolfssl.SSLContext(get_method(args.v), server_side=True)
119-
120140
context.load_cert_chain(args.c, args.k)
121141

122142
if args.d:
@@ -131,10 +151,11 @@ def main():
131151
while True:
132152
try:
133153
secure_socket = None
134-
135-
new_socket, from_addr = bind_socket.accept()
136-
137-
secure_socket = context.wrap_socket(new_socket)
154+
if args.u:
155+
secure_socket = context.wrap_socket(bind_socket)
156+
else:
157+
new_socket, from_addr = bind_socket.accept()
158+
secure_socket = context.wrap_socket(new_socket)
138159

139160
print("Connection received from", from_addr)
140161

wolfssl/__init__.py

Lines changed: 43 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,8 @@
5151
from wolfssl._methods import ( # noqa: F401
5252
PROTOCOL_SSLv23, PROTOCOL_SSLv3, PROTOCOL_TLSv1,
5353
PROTOCOL_TLSv1_1, PROTOCOL_TLSv1_2, PROTOCOL_TLSv1_3,
54-
PROTOCOL_TLS, WolfSSLMethod as _WolfSSLMethod
54+
PROTOCOL_TLS, PROTOCOL_DTLSv1, PROTOCOL_DTLSv1_2,
55+
WolfSSLMethod as _WolfSSLMethod
5556
)
5657

5758
CERT_NONE = 0
@@ -64,6 +65,8 @@
6465
_SSL_ERROR_WANT_READ = 2
6566
_SSL_ERROR_WANT_WRITE = 3
6667

68+
_SOCKADDR_SZ = 16
69+
6770
_PY3 = sys.version_info[0] == 3
6871

6972

@@ -519,7 +522,6 @@ def enable_crl(self, options):
519522
"""
520523
Enables CRL certificate revocation
521524
"""
522-
523525
ret = _lib.wolfSSL_EnableCRL(self.native_object, options)
524526

525527
if ret != _SSL_SUCCESS:
@@ -529,7 +531,6 @@ def load_crl_file(self, path, filetype):
529531
"""
530532
Load CRL certificate revocation
531533
"""
532-
533534
ret = _lib.wolfSSL_LoadCRLFile(self.native_object,
534535
t2b(path) if path else _ffi.NULL,
535536
filetype)
@@ -543,7 +544,12 @@ def write(self, data):
543544
Returns number of bytes of DATA actually transmitted.
544545
"""
545546
self._check_closed("write")
546-
self._check_connected()
547+
# Check connected if not DTLS
548+
if self._context.protocol < PROTOCOL_DTLSv1:
549+
self._check_connected()
550+
# Complete handshake if DTLS connection
551+
else:
552+
self.do_handshake()
547553

548554
data = t2b(data)
549555

@@ -599,7 +605,12 @@ def read(self, length=1024, buffer=None):
599605
Return zero-length string on EOF.
600606
"""
601607
self._check_closed("read")
602-
self._check_connected()
608+
# Check connected if not DTLS
609+
if self._context.protocol < PROTOCOL_DTLSv1:
610+
self._check_connected()
611+
# Complete handshake if DTLS connection
612+
else:
613+
self.do_handshake()
603614

604615
if buffer is not None:
605616
raise ValueError("buffer not allowed in calls to "
@@ -630,7 +641,8 @@ def recv_into(self, buffer, nbytes=None, flags=0):
630641
to full size of buffer.
631642
"""
632643
self._check_closed("read")
633-
self._check_connected()
644+
if self._context.protocol < PROTOCOL_DTLSv1:
645+
self._check_connected()
634646

635647
if buffer is None:
636648
raise ValueError("buffer cannot be None")
@@ -678,7 +690,8 @@ def shutdown(self, how):
678690
if self.native_object != _ffi.NULL:
679691
_lib.wolfSSL_shutdown(self.native_object)
680692
self._release_native_object()
681-
self._sock.shutdown(how)
693+
if self._context.protocol < PROTOCOL_DTLSv1:
694+
self._sock.shutdown(how)
682695

683696
def unwrap(self):
684697
"""
@@ -698,12 +711,23 @@ def unwrap(self):
698711

699712
return sock
700713

714+
def add_peer(self, addr):
715+
peerAddr = _lib.wolfSSL_dtls_create_peer(addr[1],t2b(addr[0]))
716+
if peerAddr == _ffi.NULL:
717+
raise SSLError("Failed to create peer")
718+
ret = _lib.wolfSSL_dtls_set_peer(self.native_object, peerAddr,
719+
_SOCKADDR_SZ)
720+
if ret != _SSL_SUCCESS:
721+
raise SSLError("Unable to set dtls peer. E(%d)" % ret)
722+
_lib.wolfSSL_dtls_free_peer(peerAddr)
723+
701724
def do_handshake(self, block=False): # pylint: disable=unused-argument
702725
"""
703726
Perform a TLS/SSL handshake.
704727
"""
705728
self._check_closed("do_handshake")
706-
self._check_connected()
729+
if self._context.protocol < PROTOCOL_DTLSv1:
730+
self._check_connected()
707731

708732
if self._server_side:
709733
ret = _lib.wolfSSL_accept(self.native_object)
@@ -756,13 +780,19 @@ def _real_connect(self, addr, connect_ex):
756780
if self._connected:
757781
raise ValueError("attempt to connect already-connected SSLSocket!")
758782

759-
if connect_ex:
760-
err = self._sock.connect_ex(addr)
783+
err = 0
784+
ret = _SSL_SUCCESS
785+
786+
if self._context.protocol >= PROTOCOL_DTLSv1:
787+
self.add_peer(addr)
761788
else:
762-
err = 0
763-
self._sock.connect(addr)
789+
if connect_ex:
790+
err = self._sock.connect_ex(addr)
791+
else:
792+
err = 0
793+
self._sock.connect(addr)
764794

765-
if err == 0:
795+
if err == 0 and ret == _SSL_SUCCESS:
766796
self._connected = True
767797
if self.do_handshake_on_connect:
768798
self.do_handshake()

wolfssl/_build_ffi.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,9 +156,15 @@ def make_flags(prefix, debug):
156156
# tls 1.3
157157
flags.append("--enable-tls13")
158158

159+
# dtls
160+
flags.append("--enable-dtls")
161+
159162
# crl
160163
flags.append("--enable-crl")
161164

165+
# wrapper allocators
166+
cflags.append("-DWOLFSSL_WRAPPER_ALLOCATORS")
167+
162168
# for urllib3 - requires SNI (tlsx), options (openssl compat), peer cert
163169
flags.append("--enable-tlsx")
164170
flags.append("--enable-opensslextra")
@@ -202,7 +208,7 @@ def make(configure_flags):
202208
call("make install")
203209

204210

205-
def build_wolfssl(ref, debug=False):
211+
def build_wolfssl(ref, debug=True):
206212
prefix = local_path("lib/wolfssl/{}/{}".format(
207213
get_platform(), ref))
208214
libfile = os.path.join(prefix, 'lib/libwolfssl.la')
@@ -394,6 +400,12 @@ def generate_libwolfssl():
394400
WOLFSSL_METHOD* wolfSSLv23_client_method(void);
395401
396402
WOLFSSL_METHOD* wolfSSLv23_method(void);
403+
404+
WOLFSSL_METHOD* wolfDTLSv1_server_method(void);
405+
WOLFSSL_METHOD* wolfDTLSv1_client_method(void);
406+
407+
WOLFSSL_METHOD* wolfDTLSv1_2_server_method(void);
408+
WOLFSSL_METHOD* wolfDTLSv1_2_client_method(void);
397409
"""
398410
if OLDTLS_ENABLED:
399411
cdef += """
@@ -453,6 +465,9 @@ def generate_libwolfssl():
453465
void wolfSSL_set_connect_state(WOLFSSL*);
454466
int wolfSSL_EnableCRL(WOLFSSL*, int);
455467
int wolfSSL_LoadCRLFile(WOLFSSL*, const char*, int);
468+
void* wolfSSL_dtls_create_peer(int, char*);
469+
int wolfSSL_dtls_free_peer(void*);
470+
int wolfSSL_dtls_set_peer(WOLFSSL*, void*, unsigned int);
456471
457472
/**
458473
* WOLFSSL_X509 functions

wolfssl/_methods.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,12 @@
3636
PROTOCOL_TLSv1_1 = 4
3737
PROTOCOL_TLSv1_2 = 5
3838
PROTOCOL_TLSv1_3 = 6
39+
PROTOCOL_DTLSv1 = 7
40+
PROTOCOL_DTLSv1_2 = 8
3941

4042
_PROTOCOL_LIST = [PROTOCOL_SSLv23, PROTOCOL_SSLv3, PROTOCOL_TLS,
4143
PROTOCOL_TLSv1, PROTOCOL_TLSv1_1, PROTOCOL_TLSv1_2,
42-
PROTOCOL_TLSv1_3]
44+
PROTOCOL_TLSv1_3, PROTOCOL_DTLSv1, PROTOCOL_DTLSv1_2]
4345

4446
_DYNAMIC_TYPE_METHOD = 11
4547

@@ -86,6 +88,17 @@ def __init__(self, protocol, server_side):
8688
_lib.wolfSSLv23_server_method() if server_side else \
8789
_lib.wolfSSLv23_client_method()
8890

91+
elif protocol == PROTOCOL_DTLSv1:
92+
self.native_object = \
93+
_lib.wolfDTLSv1_server_method() if server_side else \
94+
_lib.wolfDTLSv1_client_method()
95+
96+
elif protocol == PROTOCOL_DTLSv1_2:
97+
self.native_object = \
98+
_lib.wolfDTLSv1_2_server_method() if server_side else \
99+
_lib.wolfDTLSv1_2_client_method()
100+
101+
89102
if self.native_object == _ffi.NULL:
90103
raise MemoryError("Unnable to allocate method object")
91104

0 commit comments

Comments
 (0)