Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/modules/mbedtls/packet_peer_mbed_dtls.cpp
10277 views
1
/**************************************************************************/
2
/* packet_peer_mbed_dtls.cpp */
3
/**************************************************************************/
4
/* This file is part of: */
5
/* GODOT ENGINE */
6
/* https://godotengine.org */
7
/**************************************************************************/
8
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10
/* */
11
/* Permission is hereby granted, free of charge, to any person obtaining */
12
/* a copy of this software and associated documentation files (the */
13
/* "Software"), to deal in the Software without restriction, including */
14
/* without limitation the rights to use, copy, modify, merge, publish, */
15
/* distribute, sublicense, and/or sell copies of the Software, and to */
16
/* permit persons to whom the Software is furnished to do so, subject to */
17
/* the following conditions: */
18
/* */
19
/* The above copyright notice and this permission notice shall be */
20
/* included in all copies or substantial portions of the Software. */
21
/* */
22
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29
/**************************************************************************/
30
31
#include "packet_peer_mbed_dtls.h"
32
33
int PacketPeerMbedDTLS::bio_send(void *ctx, const unsigned char *buf, size_t len) {
34
if (buf == nullptr || len == 0) {
35
return 0;
36
}
37
38
PacketPeerMbedDTLS *sp = static_cast<PacketPeerMbedDTLS *>(ctx);
39
40
ERR_FAIL_NULL_V(sp, 0);
41
42
Error err = sp->base->put_packet((const uint8_t *)buf, len);
43
if (err == ERR_BUSY) {
44
return MBEDTLS_ERR_SSL_WANT_WRITE;
45
} else if (err != OK) {
46
ERR_FAIL_V(MBEDTLS_ERR_SSL_INTERNAL_ERROR);
47
}
48
return len;
49
}
50
51
int PacketPeerMbedDTLS::bio_recv(void *ctx, unsigned char *buf, size_t len) {
52
if (buf == nullptr || len == 0) {
53
return 0;
54
}
55
56
PacketPeerMbedDTLS *sp = static_cast<PacketPeerMbedDTLS *>(ctx);
57
58
ERR_FAIL_NULL_V(sp, 0);
59
60
int pc = sp->base->get_available_packet_count();
61
if (pc == 0) {
62
return MBEDTLS_ERR_SSL_WANT_READ;
63
} else if (pc < 0) {
64
ERR_FAIL_V(MBEDTLS_ERR_SSL_INTERNAL_ERROR);
65
}
66
67
const uint8_t *buffer;
68
int buffer_size = 0;
69
Error err = sp->base->get_packet(&buffer, buffer_size);
70
if (err != OK) {
71
return MBEDTLS_ERR_SSL_INTERNAL_ERROR;
72
}
73
memcpy(buf, buffer, buffer_size);
74
return buffer_size;
75
}
76
77
void PacketPeerMbedDTLS::_cleanup() {
78
tls_ctx->clear();
79
base = Ref<PacketPeer>();
80
status = STATUS_DISCONNECTED;
81
}
82
83
int PacketPeerMbedDTLS::_set_cookie() {
84
// Setup DTLS session cookie for this client
85
uint8_t client_id[18];
86
IPAddress addr = base->get_packet_address();
87
uint16_t port = base->get_packet_port();
88
memcpy(client_id, addr.get_ipv6(), 16);
89
memcpy(&client_id[16], (uint8_t *)&port, 2);
90
return mbedtls_ssl_set_client_transport_id(tls_ctx->get_context(), client_id, 18);
91
}
92
93
Error PacketPeerMbedDTLS::_do_handshake() {
94
int ret = 0;
95
while ((ret = mbedtls_ssl_handshake(tls_ctx->get_context())) != 0) {
96
if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
97
if (ret != MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED) {
98
ERR_PRINT("TLS handshake error: " + itos(ret));
99
TLSContextMbedTLS::print_mbedtls_error(ret);
100
}
101
_cleanup();
102
status = STATUS_ERROR;
103
return FAILED;
104
}
105
// Will retry via poll later
106
return OK;
107
}
108
109
status = STATUS_CONNECTED;
110
return OK;
111
}
112
113
Error PacketPeerMbedDTLS::connect_to_peer(Ref<PacketPeerUDP> p_base, const String &p_hostname, Ref<TLSOptions> p_options) {
114
ERR_FAIL_COND_V(p_base.is_null() || !p_base->is_socket_connected(), ERR_INVALID_PARAMETER);
115
116
Error err = tls_ctx->init_client(MBEDTLS_SSL_TRANSPORT_DATAGRAM, p_hostname, p_options.is_valid() ? p_options : TLSOptions::client());
117
ERR_FAIL_COND_V(err != OK, err);
118
119
base = p_base;
120
121
mbedtls_ssl_set_bio(tls_ctx->get_context(), this, bio_send, bio_recv, nullptr);
122
mbedtls_ssl_set_timer_cb(tls_ctx->get_context(), &timer, mbedtls_timing_set_delay, mbedtls_timing_get_delay);
123
124
status = STATUS_HANDSHAKING;
125
126
if (_do_handshake() != OK) {
127
status = STATUS_ERROR_HOSTNAME_MISMATCH;
128
return FAILED;
129
}
130
131
return OK;
132
}
133
134
Error PacketPeerMbedDTLS::accept_peer(Ref<PacketPeerUDP> p_base, Ref<TLSOptions> p_options, Ref<CookieContextMbedTLS> p_cookies) {
135
ERR_FAIL_COND_V(p_base.is_null() || !p_base->is_socket_connected(), ERR_INVALID_PARAMETER);
136
137
Error err = tls_ctx->init_server(MBEDTLS_SSL_TRANSPORT_DATAGRAM, p_options, p_cookies);
138
ERR_FAIL_COND_V(err != OK, err);
139
140
base = p_base;
141
base->set_blocking_mode(false);
142
143
mbedtls_ssl_session_reset(tls_ctx->get_context());
144
145
int ret = _set_cookie();
146
if (ret != 0) {
147
_cleanup();
148
ERR_FAIL_V_MSG(FAILED, "Error setting DTLS client cookie");
149
}
150
151
mbedtls_ssl_set_bio(tls_ctx->get_context(), this, bio_send, bio_recv, nullptr);
152
mbedtls_ssl_set_timer_cb(tls_ctx->get_context(), &timer, mbedtls_timing_set_delay, mbedtls_timing_get_delay);
153
154
status = STATUS_HANDSHAKING;
155
156
if (_do_handshake() != OK) {
157
status = STATUS_ERROR;
158
return FAILED;
159
}
160
161
return OK;
162
}
163
164
Error PacketPeerMbedDTLS::put_packet(const uint8_t *p_buffer, int p_bytes) {
165
ERR_FAIL_COND_V(status != STATUS_CONNECTED, ERR_UNCONFIGURED);
166
167
if (p_bytes == 0) {
168
return OK;
169
}
170
171
int ret = mbedtls_ssl_write(tls_ctx->get_context(), p_buffer, p_bytes);
172
if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
173
// Non blocking io.
174
} else if (ret <= 0) {
175
TLSContextMbedTLS::print_mbedtls_error(ret);
176
_cleanup();
177
return ERR_CONNECTION_ERROR;
178
}
179
180
return OK;
181
}
182
183
Error PacketPeerMbedDTLS::get_packet(const uint8_t **r_buffer, int &r_bytes) {
184
ERR_FAIL_COND_V(status != STATUS_CONNECTED, ERR_UNCONFIGURED);
185
186
r_bytes = 0;
187
188
int ret = mbedtls_ssl_read(tls_ctx->get_context(), packet_buffer, PACKET_BUFFER_SIZE);
189
if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
190
ret = 0; // non blocking io
191
} else if (ret <= 0) {
192
if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) {
193
// Also send close notify back
194
disconnect_from_peer();
195
} else {
196
_cleanup();
197
status = STATUS_ERROR;
198
TLSContextMbedTLS::print_mbedtls_error(ret);
199
}
200
return ERR_CONNECTION_ERROR;
201
}
202
*r_buffer = packet_buffer;
203
r_bytes = ret;
204
205
return OK;
206
}
207
208
void PacketPeerMbedDTLS::poll() {
209
if (status == STATUS_HANDSHAKING) {
210
_do_handshake();
211
return;
212
} else if (status != STATUS_CONNECTED) {
213
return;
214
}
215
216
ERR_FAIL_COND(base.is_null());
217
218
int ret = mbedtls_ssl_read(tls_ctx->get_context(), nullptr, 0);
219
220
if (ret < 0 && ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
221
if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) {
222
// Also send close notify back
223
disconnect_from_peer();
224
} else {
225
_cleanup();
226
status = STATUS_ERROR;
227
TLSContextMbedTLS::print_mbedtls_error(ret);
228
}
229
}
230
}
231
232
int PacketPeerMbedDTLS::get_available_packet_count() const {
233
ERR_FAIL_COND_V(status != STATUS_CONNECTED, 0);
234
235
return mbedtls_ssl_get_bytes_avail(&(tls_ctx->tls)) > 0 ? 1 : 0;
236
}
237
238
int PacketPeerMbedDTLS::get_max_packet_size() const {
239
return 488; // 512 (UDP in Godot) - 24 (DTLS header)
240
}
241
242
PacketPeerMbedDTLS::PacketPeerMbedDTLS() {
243
tls_ctx.instantiate();
244
}
245
246
PacketPeerMbedDTLS::~PacketPeerMbedDTLS() {
247
disconnect_from_peer();
248
}
249
250
void PacketPeerMbedDTLS::disconnect_from_peer() {
251
if (status != STATUS_CONNECTED && status != STATUS_HANDSHAKING) {
252
return;
253
}
254
255
if (status == STATUS_CONNECTED) {
256
int ret = 0;
257
// Send SSL close notification, blocking, but ignore other errors.
258
do {
259
ret = mbedtls_ssl_close_notify(tls_ctx->get_context());
260
} while (ret == MBEDTLS_ERR_SSL_WANT_WRITE);
261
}
262
263
_cleanup();
264
}
265
266
PacketPeerMbedDTLS::Status PacketPeerMbedDTLS::get_status() const {
267
return status;
268
}
269
270
PacketPeerDTLS *PacketPeerMbedDTLS::_create_func(bool p_notify_postinitialize) {
271
return static_cast<PacketPeerDTLS *>(ClassDB::creator<PacketPeerMbedDTLS>(p_notify_postinitialize));
272
}
273
274
void PacketPeerMbedDTLS::initialize_dtls() {
275
_create = _create_func;
276
available = true;
277
}
278
279
void PacketPeerMbedDTLS::finalize_dtls() {
280
_create = nullptr;
281
available = false;
282
}
283
284