Skip to content

Commit 9ea2882

Browse files
committed
extmod/modussl_mbedtls: Initial implementation of mbedTLS ussl module.
1 parent 93c4a6a commit 9ea2882

1 file changed

Lines changed: 259 additions & 0 deletions

File tree

extmod/modussl_mbedtls.c

Lines changed: 259 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,259 @@
1+
/*
2+
* This file is part of the MicroPython project, http://micropython.org/
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* Copyright (c) 2016 Linaro Ltd.
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy
9+
* of this software and associated documentation files (the "Software"), to deal
10+
* in the Software without restriction, including without limitation the rights
11+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
* copies of the Software, and to permit persons to whom the Software is
13+
* furnished to do so, subject to the following conditions:
14+
*
15+
* The above copyright notice and this permission notice shall be included in
16+
* all copies or substantial portions of the Software.
17+
*
18+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24+
* THE SOFTWARE.
25+
*/
26+
27+
#include "py/mpconfig.h"
28+
#if MICROPY_PY_USSL && MICROPY_SSL_MBEDTLS
29+
30+
#include <stdio.h>
31+
#include <string.h>
32+
#include <errno.h>
33+
34+
#include "py/nlr.h"
35+
#include "py/runtime.h"
36+
#include "py/stream.h"
37+
38+
// mbedtls_time_t
39+
#include "mbedtls/include/mbedtls/platform.h"
40+
#include "mbedtls/include/mbedtls/net.h"
41+
#include "mbedtls/include/mbedtls/ssl.h"
42+
#include "mbedtls/include/mbedtls/entropy.h"
43+
#include "mbedtls/include/mbedtls/ctr_drbg.h"
44+
#include "mbedtls/include/mbedtls/debug.h"
45+
46+
typedef struct _mp_obj_ssl_socket_t {
47+
mp_obj_base_t base;
48+
mp_obj_t sock;
49+
mbedtls_entropy_context entropy;
50+
mbedtls_ctr_drbg_context ctr_drbg;
51+
mbedtls_ssl_context ssl;
52+
mbedtls_ssl_config conf;
53+
mbedtls_x509_crt cacert;
54+
} mp_obj_ssl_socket_t;
55+
56+
STATIC const mp_obj_type_t ussl_socket_type;
57+
58+
static void mbedtls_debug(void *ctx, int level, const char *file, int line, const char *str) {
59+
printf("DBG:%s:%04d: %s\n", file, line, str);
60+
}
61+
62+
// TODO: FIXME!
63+
int null_entropy_func(void *data, unsigned char *output, size_t len) {
64+
// enjoy random bytes
65+
return 0;
66+
}
67+
68+
int _mbedtls_ssl_send(void *ctx, const byte *buf, size_t len) {
69+
mp_obj_t sock = *(mp_obj_t*)ctx;
70+
71+
const mp_stream_p_t *sock_stream = mp_get_stream_raise(sock, MP_STREAM_OP_WRITE);
72+
int err;
73+
74+
int out_sz = sock_stream->write(sock, buf, len, &err);
75+
if (out_sz == MP_STREAM_ERROR) {
76+
return -err;
77+
} else {
78+
return out_sz;
79+
}
80+
}
81+
82+
int _mbedtls_ssl_recv(void *ctx, byte *buf, size_t len) {
83+
mp_obj_t sock = *(mp_obj_t*)ctx;
84+
85+
const mp_stream_p_t *sock_stream = mp_get_stream_raise(sock, MP_STREAM_OP_READ);
86+
int err;
87+
88+
int out_sz = sock_stream->read(sock, buf, len, &err);
89+
if (out_sz == MP_STREAM_ERROR) {
90+
return -err;
91+
} else {
92+
return out_sz;
93+
}
94+
}
95+
96+
97+
STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, bool server_side) {
98+
mp_obj_ssl_socket_t *o = m_new_obj(mp_obj_ssl_socket_t);
99+
o->base.type = &ussl_socket_type;
100+
101+
int ret;
102+
mbedtls_ssl_init(&o->ssl);
103+
mbedtls_ssl_config_init(&o->conf);
104+
mbedtls_x509_crt_init(&o->cacert);
105+
mbedtls_ctr_drbg_init(&o->ctr_drbg);
106+
// Debug level (0-4)
107+
mbedtls_debug_set_threshold(0);
108+
109+
mbedtls_entropy_init(&o->entropy);
110+
const byte seed[] = "upy";
111+
ret = mbedtls_ctr_drbg_seed(&o->ctr_drbg, null_entropy_func/*mbedtls_entropy_func*/, &o->entropy, seed, sizeof(seed));
112+
if (ret != 0) {
113+
printf("ret=%d\n", ret);
114+
assert(0);
115+
}
116+
117+
ret = mbedtls_ssl_config_defaults(&o->conf,
118+
MBEDTLS_SSL_IS_CLIENT,
119+
MBEDTLS_SSL_TRANSPORT_STREAM,
120+
MBEDTLS_SSL_PRESET_DEFAULT);
121+
if (ret != 0) {
122+
assert(0);
123+
}
124+
125+
mbedtls_ssl_conf_authmode(&o->conf, MBEDTLS_SSL_VERIFY_NONE);
126+
mbedtls_ssl_conf_rng(&o->conf, mbedtls_ctr_drbg_random, &o->ctr_drbg);
127+
mbedtls_ssl_conf_dbg(&o->conf, mbedtls_debug, NULL);
128+
129+
ret = mbedtls_ssl_setup(&o->ssl, &o->conf);
130+
if (ret != 0) {
131+
assert(0);
132+
}
133+
134+
// delme
135+
ret = mbedtls_ssl_set_hostname(&o->ssl, "mbed TLS Server 1");
136+
if (ret != 0) {
137+
assert(0);
138+
}
139+
140+
o->sock = sock;
141+
mbedtls_ssl_set_bio(&o->ssl, &o->sock, _mbedtls_ssl_send, _mbedtls_ssl_recv, NULL);
142+
143+
if (server_side) {
144+
assert(0);
145+
} else {
146+
while ((ret = mbedtls_ssl_handshake(&o->ssl)) != 0) {
147+
if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
148+
//assert(0);
149+
printf("mbedtls_ssl_handshake error: -%x\n", -ret);
150+
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(EIO)));
151+
}
152+
}
153+
}
154+
155+
return o;
156+
}
157+
158+
STATIC void socket_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
159+
(void)kind;
160+
mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(self_in);
161+
mp_printf(print, "<_SSLSocket %p>", self);
162+
}
163+
164+
STATIC mp_uint_t socket_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) {
165+
mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(o_in);
166+
167+
int ret = mbedtls_ssl_read(&o->ssl, buf, size);
168+
if (ret >= 0) {
169+
return ret;
170+
}
171+
*errcode = ret;
172+
return MP_STREAM_ERROR;
173+
}
174+
175+
STATIC mp_uint_t socket_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) {
176+
mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(o_in);
177+
178+
int ret = mbedtls_ssl_write(&o->ssl, buf, size);
179+
if (ret >= 0) {
180+
return ret;
181+
}
182+
*errcode = ret;
183+
return MP_STREAM_ERROR;
184+
}
185+
186+
STATIC mp_obj_t socket_close(mp_obj_t self_in) {
187+
mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(self_in);
188+
189+
mbedtls_x509_crt_free(&self->cacert);
190+
mbedtls_ssl_free(&self->ssl);
191+
mbedtls_ssl_config_free(&self->conf);
192+
mbedtls_ctr_drbg_free(&self->ctr_drbg);
193+
mbedtls_entropy_free(&self->entropy);
194+
195+
mp_obj_t dest[2];
196+
mp_load_method(self->sock, MP_QSTR_close, dest);
197+
return mp_call_method_n_kw(0, 0, dest);
198+
}
199+
STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_close_obj, socket_close);
200+
201+
STATIC const mp_rom_map_elem_t ussl_socket_locals_dict_table[] = {
202+
{ MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
203+
{ MP_ROM_QSTR(MP_QSTR_readall), MP_ROM_PTR(&mp_stream_readall_obj) },
204+
{ MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
205+
{ MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) },
206+
{ MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
207+
{ MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&socket_close_obj) },
208+
};
209+
210+
STATIC MP_DEFINE_CONST_DICT(ussl_socket_locals_dict, ussl_socket_locals_dict_table);
211+
212+
STATIC const mp_stream_p_t ussl_socket_stream_p = {
213+
.read = socket_read,
214+
.write = socket_write,
215+
};
216+
217+
STATIC const mp_obj_type_t ussl_socket_type = {
218+
{ &mp_type_type },
219+
// Save on qstr's, reuse same as for module
220+
.name = MP_QSTR_ussl,
221+
.print = socket_print,
222+
.getiter = NULL,
223+
.iternext = NULL,
224+
.protocol = &ussl_socket_stream_p,
225+
.locals_dict = (void*)&ussl_socket_locals_dict,
226+
};
227+
228+
STATIC mp_obj_t mod_ssl_wrap_socket(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
229+
// TODO: Implement more args
230+
static const mp_arg_t allowed_args[] = {
231+
{ MP_QSTR_server_side, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
232+
};
233+
234+
// TODO: Check that sock implements stream protocol
235+
mp_obj_t sock = pos_args[0];
236+
237+
struct {
238+
mp_arg_val_t server_side;
239+
} args;
240+
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args,
241+
MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t*)&args);
242+
243+
return MP_OBJ_FROM_PTR(socket_new(sock, args.server_side.u_bool));
244+
}
245+
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_ssl_wrap_socket_obj, 1, mod_ssl_wrap_socket);
246+
247+
STATIC const mp_rom_map_elem_t mp_module_ssl_globals_table[] = {
248+
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ussl) },
249+
{ MP_ROM_QSTR(MP_QSTR_wrap_socket), MP_ROM_PTR(&mod_ssl_wrap_socket_obj) },
250+
};
251+
252+
STATIC MP_DEFINE_CONST_DICT(mp_module_ssl_globals, mp_module_ssl_globals_table);
253+
254+
const mp_obj_module_t mp_module_ussl = {
255+
.base = { &mp_type_module },
256+
.globals = (mp_obj_dict_t*)&mp_module_ssl_globals,
257+
};
258+
259+
#endif // MICROPY_PY_USSL

0 commit comments

Comments
 (0)