tls_socket_mbedtls.c
Go to the documentation of this file.
1 
9 #include "../mcl_tls_socket.h"
10 #include "mcl_core/mcl_memory.h"
12 #include "mcl_core/mcl_log_util.h"
13 #include "mbedtls/ssl.h"
14 #include "mbedtls/entropy.h"
15 #include "mbedtls/net_sockets.h"
16 #include "mbedtls/ctr_drbg.h"
17 #include "mbedtls/debug.h"
18 
19 #define PORT_STRING_BUFFER_SIZE 6
20 
21 static const unsigned char entropy_string[] = "MCL TLS socket wrapper using mbedTLS.";
22 
23 typedef struct mcl_tls_socket_t
24 {
25  mbedtls_net_context net_context;
26  mbedtls_ssl_context ssl_context;
27  mbedtls_ssl_config ssl_config;
28  mbedtls_ctr_drbg_context drbg_context;
29  mbedtls_entropy_context entropy_context;
32 
33 typedef struct mcl_tls_ca_chain_t
34 {
35  mbedtls_x509_crt certificate_chain;
37 
38 #if defined MCL_MOCKSERVER_INTEGRATION
39 #if defined(WIN32) || defined(WIN64)
40 #pragma message("This callback function should not be enabled except for integration test with mock server!")
41 #else
42 #warning This callback function should not be enabled except for integration test with mock server!
43 #endif
44 
45 static int verify_callback(void *context, mbedtls_x509_crt *certificate, int remaining, uint32_t *flags)
46 {
47  const char issuer[] = "www.mockserver.com";
48  if (((sizeof(issuer) - MCL_NULL_CHAR_SIZE) == certificate->issuer.val.len) &&
49  (MCL_TRUE == mcl_string_util_memcmp(issuer, certificate->issuer.val.p, certificate->issuer.val.len)))
50  {
51  (*flags) &= (~(MBEDTLS_X509_BADCERT_BAD_KEY | MBEDTLS_X509_BADCERT_CN_MISMATCH));
52  }
53 
54  return 0;
55 }
56 #endif
57 
58 static void mbedtls_debug_function(void *ctx, int level, const char *file, int line, const char *str)
59 {
60  // Unused parameter ctx.
61  (void) ctx;
62 
63 #if MCL_LOG_DISABLED
64  (void) level;
65  (void) file;
66  (void) line;
67  (void) str;
68 #else
69  switch (level)
70  {
71 #if MCL_LOG_ENABLED_COMPILE_TIME(MCL_LOG_LEVEL_ERROR)
72  case 1:
74  {
75  mcl_log_util_function(mcl_log_util_user_context, MCL_LOG_LEVEL_ERROR, file, line, "mbedTLS", "%s", str);
76  }
77  break;
78 #endif
79 #if MCL_LOG_ENABLED_COMPILE_TIME(MCL_LOG_LEVEL_DEBUG)
80  case 2:
81  case 3:
83  {
84  mcl_log_util_function(mcl_log_util_user_context, MCL_LOG_LEVEL_DEBUG, file, line, "mbedTLS", "%s", str);
85  }
86  break;
87 #endif
88 #if MCL_LOG_ENABLED_COMPILE_TIME(MCL_LOG_LEVEL_VERBOSE)
89  case 4:
91  {
92  mcl_log_util_function(mcl_log_util_user_context, MCL_LOG_LEVEL_VERBOSE, file, line, "mbedTLS", "%s", str);
93  }
94  break;
95 #endif
96  default:
97  break;
98  }
99 #endif
100 }
101 
102 mcl_error_t mcl_tls_ca_chain_init(mcl_tls_ca_chain_handle *tls_ca_chain_handle)
103 {
104  mcl_error_t code = MCL_OK;
105 
106  MCL_DEBUG_ENTRY("mcl_tls_ca_chain_handle *tls_ca_chain_handle = <%p>", tls_ca_chain_handle);
107 
108  MCL_ASSERT_NOT_NULL(tls_ca_chain_handle, code);
109 
110  *tls_ca_chain_handle = (mcl_tls_ca_chain_handle) MCL_MALLOC(sizeof(mcl_tls_ca_chain_t));
111 
112  if (NULL == *tls_ca_chain_handle)
113  {
114  code = MCL_OUT_OF_MEMORY;
115  }
116  else
117  {
118  mbedtls_x509_crt_init(&(*tls_ca_chain_handle)->certificate_chain);
119  }
120 
122  MCL_DEBUG_LEAVE("retVal = <%d>", code);
123  return code;
124 }
125 
126 mcl_error_t mcl_tls_ca_chain_add_certificate(mcl_tls_ca_chain_handle tls_ca_chain_handle, const char *certificate, mcl_bool_t is_file)
127 {
128  mcl_error_t code;
129  int mbedtls_code;
130 
131  MCL_DEBUG_ENTRY("mcl_tls_ca_chain_handle tls_ca_chain_handle = <%p>, const char *certificate = <%p>, mcl_bool_t is_file = <%u>", tls_ca_chain_handle, certificate, is_file);
132 
133  if (MCL_TRUE == is_file)
134  {
135 #ifdef MBEDTLS_FS_IO
136  mbedtls_code = mbedtls_x509_crt_parse_file(&tls_ca_chain_handle->certificate_chain, certificate);
137 #else
138  MCL_ERROR_RETURN(MCL_OPERATION_NOT_SUPPORTED, "Certificate cannot be given as file for this specific configuration.")
139 #endif
140  }
141  else
142  {
143  size_t buffer_length = mcl_string_util_strlen(certificate) + MCL_NULL_CHAR_SIZE;
144  mbedtls_code = mbedtls_x509_crt_parse(&tls_ca_chain_handle->certificate_chain, (const unsigned char *)certificate, buffer_length);
145  }
146 
147  switch (mbedtls_code)
148  {
149  case 0:
150  code = MCL_OK;
151  break;
152 
153  case MBEDTLS_ERR_X509_ALLOC_FAILED:
154  code = MCL_OUT_OF_MEMORY;
155  break;
156 
157  default:
159  break;
160  }
161 
162  MCL_DEBUG_LEAVE("retVal = <%d>", code);
163  return code;
164 }
165 
166 void mcl_tls_ca_chain_destroy(mcl_tls_ca_chain_handle *tls_ca_chain_handle)
167 {
168  MCL_DEBUG_ENTRY("mcl_tls_ca_chain_handle *tls_ca_chain_handle = <%p>", tls_ca_chain_handle);
169 
170  if ((NULL != tls_ca_chain_handle) && (NULL != *tls_ca_chain_handle))
171  {
172  mbedtls_x509_crt_free(&(*tls_ca_chain_handle)->certificate_chain);
173  MCL_FREE(*tls_ca_chain_handle);
174  }
175 
176  MCL_DEBUG_LEAVE("retVal = void");
177 }
178 
179 mcl_error_t mcl_tls_socket_init(mcl_tls_socket_handle *tls_socket_handle)
180 {
181  mcl_error_t code = MCL_OK;
182 
183  MCL_DEBUG_ENTRY("mcl_tls_socket_handle *tls_socket_handle = <%p>", tls_socket_handle);
184 
185  MCL_ASSERT_NOT_NULL(tls_socket_handle, code);
186 
187  *tls_socket_handle = MCL_MALLOC(sizeof(mcl_tls_socket_t));
188 
189  if (MCL_NULL == *tls_socket_handle)
190  {
191  code = MCL_OUT_OF_MEMORY;
192  }
193  else
194  {
195  int mbedtls_debug;
196 
197  (*tls_socket_handle)->timeout = 0;
198  mbedtls_net_init(&((*tls_socket_handle)->net_context));
199  mbedtls_ssl_init(&((*tls_socket_handle)->ssl_context));
200  mbedtls_ctr_drbg_init(&((*tls_socket_handle)->drbg_context));
201  mbedtls_entropy_init(&((*tls_socket_handle)->entropy_context));
202  mbedtls_ssl_config_init(&((*tls_socket_handle)->ssl_config));
203  mbedtls_ssl_conf_rng(&((*tls_socket_handle)->ssl_config), mbedtls_ctr_drbg_random, &((*tls_socket_handle)->drbg_context));
204  mbedtls_ssl_conf_dbg(&((*tls_socket_handle)->ssl_config), mbedtls_debug_function, MCL_NULL);
205  mbedtls_ssl_conf_authmode(&((*tls_socket_handle)->ssl_config), MBEDTLS_SSL_VERIFY_REQUIRED);
206 
208  {
209  mbedtls_debug = 4;
210  }
212  {
213  mbedtls_debug = 3;
214  }
216  {
217  mbedtls_debug = 1;
218  }
219  else
220  {
221  mbedtls_debug = 0;
222  }
223 
224  mbedtls_debug_set_threshold(mbedtls_debug);
225 
226 #if defined MCL_MOCKSERVER_INTEGRATION
227  mbedtls_ssl_conf_verify(&((*tls_socket_handle)->ssl_config), verify_callback, MCL_NULL);
228 #endif
229  }
230 
231  if ((MCL_OK == code) && (0 != mbedtls_ssl_config_defaults(&((*tls_socket_handle)->ssl_config), MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT)))
232  {
233  code = MCL_FAIL;
234  }
235 
236  if ((MCL_OK == code) && (0 != mbedtls_ctr_drbg_seed(&((*tls_socket_handle)->drbg_context), mbedtls_entropy_func, &((*tls_socket_handle)->entropy_context), entropy_string, sizeof(entropy_string) - MCL_NULL_CHAR_SIZE)))
237  {
238  code = MCL_FAIL;
239  }
240 
241  if (MCL_OK != code)
242  {
243  mcl_tls_socket_destroy(tls_socket_handle);
244  }
245 
247  MCL_DEBUG_LEAVE("retVal = <%d>", code);
248  return code;
249 }
250 
251 mcl_error_t mcl_tls_socket_set_parameter(mcl_tls_socket_handle tls_socket_handle, E_MCL_TLS_SOCKET_PARAMETER parameter, const void *value)
252 {
253  mcl_error_t code = MCL_OK;
254 
255  MCL_DEBUG_ENTRY("mcl_tls_socket_handle tls_socket_handle = <%p>", tls_socket_handle);
256 
257  MCL_ASSERT_NOT_NULL(tls_socket_handle, code);
258 
259  switch(parameter)
260  {
262  mbedtls_ssl_conf_ca_chain(&(tls_socket_handle->ssl_config), &((mcl_tls_ca_chain_handle) value)->certificate_chain, MCL_NULL);
263  break;
264 
266  tls_socket_handle->timeout = *((const int *) value);
267  break;
268 
269  default:
270  code = MCL_INVALID_PARAMETER;
271  break;
272  }
273 
275  MCL_DEBUG_LEAVE("retVal = <%d>", code);
276  return code;
277 }
278 
279 mcl_error_t mcl_tls_socket_open(mcl_tls_socket_handle tls_socket_handle)
280 {
281  mcl_error_t code = MCL_OK;
282 
283  MCL_DEBUG_ENTRY("mcl_tls_socket_handle tls_socket_handle = <%p>", tls_socket_handle);
284 
285  MCL_ASSERT_NOT_NULL(tls_socket_handle, code);
286 
287  // mbedtls does not wrap socket function, mbedtls_net_connect does both socket and connect.
288 
290  MCL_DEBUG_LEAVE("retVal = <%d>", code);
291  return code;
292 }
293 
294 mcl_error_t mcl_tls_socket_connect(mcl_tls_socket_handle tls_socket_handle, const char *host, mcl_uint16_t port)
295 {
296  mcl_error_t code;
297  char port_string[PORT_STRING_BUFFER_SIZE];
298  int mbedtls_code;
299 
300  MCL_DEBUG_ENTRY("mcl_tls_socket_handle tls_socket_handle = <%p>, const char *host = <%s>, mcl_uint16_t port = <%u>", tls_socket_handle, host, (unsigned int) port);
301 
302  if (NULL == tls_socket_handle)
303  {
305  }
306  else
307  {
308  code = mcl_string_util_snprintf(port_string, PORT_STRING_BUFFER_SIZE, "%u", port);
309  }
310 
311  if (MCL_OK == code)
312  {
313  mbedtls_code = mbedtls_net_connect(&tls_socket_handle->net_context, host, port_string, MBEDTLS_NET_PROTO_TCP);
314 
315  if (0 != mbedtls_code)
316  {
317  MCL_ERROR("mbedtls_net_connect returned: -0x%x", (0 - mbedtls_code));
318 
319  switch (mbedtls_code)
320  {
321  case MBEDTLS_ERR_NET_UNKNOWN_HOST:
323  break;
324 
325  case MBEDTLS_ERR_NET_CONNECT_FAILED:
326  code = MCL_COULD_NOT_CONNECT;
327  break;
328 
329  default:
330  code = MCL_FAIL;
331  break;
332  }
333  }
334  }
335 
336  if (MCL_OK == code)
337  {
338  mbedtls_code = mbedtls_ssl_setup(&tls_socket_handle->ssl_context, &tls_socket_handle->ssl_config);
339 
340  if (0 != mbedtls_code)
341  {
342  MCL_ERROR("mbedtls_ssl_setup returned: -0x%x", (0 - mbedtls_code));
343  code = MCL_OUT_OF_MEMORY;
344  }
345  }
346 
347  if (MCL_OK == code)
348  {
349  mbedtls_code = mbedtls_ssl_set_hostname(&tls_socket_handle->ssl_context, host);
350  if (0 != mbedtls_code)
351  {
352  MCL_ERROR("mbedtls_ssl_set_hostname returned: -0x%x", (0 - mbedtls_code));
353 
354  switch (mbedtls_code)
355  {
356  case MBEDTLS_ERR_SSL_ALLOC_FAILED:
357  code = MCL_OUT_OF_MEMORY;
358  break;
359 
360  case MBEDTLS_ERR_SSL_BAD_INPUT_DATA:
361  code = MCL_INVALID_PARAMETER;
362  break;
363 
364  default:
365  code = MCL_FAIL;
366  break;
367  }
368  }
369  }
370 
371  if (MCL_OK == code)
372  {
373  mbedtls_ssl_set_bio(&tls_socket_handle->ssl_context, &tls_socket_handle->net_context, mbedtls_net_send, mbedtls_net_recv, MCL_NULL);
374 
375  do
376  {
377  mbedtls_code = mbedtls_ssl_handshake(&tls_socket_handle->ssl_context);
378  } while ((MBEDTLS_ERR_SSL_WANT_READ == mbedtls_code) || (MBEDTLS_ERR_SSL_WANT_WRITE == mbedtls_code));
379 
380  if (0 != mbedtls_code)
381  {
382  MCL_ERROR("mbedtls_ssl_handshake returned: -0x%x", (0 - mbedtls_code));
383 
384  switch (mbedtls_code)
385  {
386  case MBEDTLS_ERR_X509_CERT_VERIFY_FAILED:
388  break;
389 
390  case MBEDTLS_ERR_X509_ALLOC_FAILED:
391  code = MCL_OUT_OF_MEMORY;
392  break;
393 
394  case MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE:
395  case MBEDTLS_ERR_X509_UNKNOWN_OID:
396  case MBEDTLS_ERR_X509_FATAL_ERROR:
397  case MBEDTLS_ERR_X509_FILE_IO_ERROR:
398  code = MCL_SSL_HANDSHAKE_FAIL;
399  break;
400 
401  default:
403  break;
404  }
405  }
406  }
407 
408  MCL_DEBUG_LEAVE("retVal = <%d>", code);
409  return code;
410 }
411 
412 mcl_error_t mcl_tls_socket_send(mcl_tls_socket_handle tls_socket_handle, const mcl_uint8_t *buffer, mcl_size_t *size)
413 {
414  mcl_error_t code = MCL_OK;
415 
416  MCL_VERBOSE_ENTRY("mcl_tls_socket_handle tls_socket_handle = <%p>, const mcl_uint8_t *buffer = <%p>, mcl_size_t *size = <%p>", tls_socket_handle, buffer, size);
417 
418  if ((NULL == tls_socket_handle) || (NULL == size))
419  {
421  }
422  else if (0 == *size)
423  {
424  code = MCL_INVALID_PARAMETER;
425  }
426  else
427  {
428  int mbedtls_code;
429 
430  do
431  {
432  mbedtls_code = mbedtls_ssl_write(&tls_socket_handle->ssl_context, buffer, *size);
433  } while ((MBEDTLS_ERR_SSL_WANT_READ == mbedtls_code) || (MBEDTLS_ERR_SSL_WANT_WRITE == mbedtls_code));
434 
435  if (0 > mbedtls_code)
436  {
437  MCL_ERROR("mbedtls_ssl_write returned: -0x%x", (0 - mbedtls_code));
438  code = MCL_FAIL;
439  }
440  else
441  {
442  *size = mbedtls_code;
443  }
444 
445  }
446 
447  MCL_VERBOSE_LEAVE("retVal = <%d>", code);
448  return code;
449 }
450 
451 mcl_error_t mcl_tls_socket_receive(mcl_tls_socket_handle tls_socket_handle, mcl_uint8_t *buffer, mcl_size_t *size)
452 {
453  mcl_error_t code = MCL_OK;
454 
455  MCL_VERBOSE_ENTRY("mcl_tls_socket_handle tls_socket_handle = <%p>, const mcl_uint8_t *buffer = <%p>, mcl_size_t *size = <%p>", tls_socket_handle, buffer, size);
456 
457  if ((NULL == tls_socket_handle) || (NULL == size))
458  {
460  }
461  else if (0 == *size)
462  {
463  code = MCL_INVALID_PARAMETER;
464  }
465  else
466  {
467  int mbedtls_code;
468 
469  do
470  {
471  mbedtls_code = mbedtls_ssl_read(&tls_socket_handle->ssl_context, buffer, *size);
472  } while ((MBEDTLS_ERR_SSL_WANT_READ == mbedtls_code) || (MBEDTLS_ERR_SSL_WANT_WRITE == mbedtls_code));
473 
474  if (0 >= mbedtls_code)
475  {
476  MCL_ERROR("mbedtls_ssl_read returned: -0x%x", (0 - mbedtls_code));
477  code = MCL_FAIL;
478  }
479  else
480  {
481  *size = mbedtls_code;
482  }
483  }
484 
485  MCL_VERBOSE_LEAVE("retVal = <%d>", code);
486  return code;
487 }
488 
489 void mcl_tls_socket_destroy(mcl_tls_socket_handle *tls_socket_handle)
490 {
491  MCL_DEBUG_ENTRY("mcl_tls_socket_handle *tls_socket_handle = <%p>", tls_socket_handle);
492 
493  if ((MCL_NULL != tls_socket_handle) && (MCL_NULL != *tls_socket_handle))
494  {
495  mbedtls_net_free(&(*tls_socket_handle)->net_context);
496  mbedtls_ssl_free(&(*tls_socket_handle)->ssl_context);
497  mbedtls_ssl_config_free(&(*tls_socket_handle)->ssl_config);
498  mbedtls_ctr_drbg_free(&(*tls_socket_handle)->drbg_context);
499  mbedtls_entropy_free(&(*tls_socket_handle)->entropy_context);
500  MCL_FREE(*tls_socket_handle);
501  }
502 
503  MCL_DEBUG_LEAVE("retVal = void");
504 }
mbedtls_entropy_context entropy_context
mbedtls_ssl_config ssl_config
MCL failed to connect to the host or proxy.
#define MCL_LOG_ENABLED_COMPILE_TIME(level)
Definition: mcl_log_util.h:80
#define MCL_FUNCTION_LEAVE_LABEL
E_MCL_TLS_SOCKET_PARAMETER
uint16_t mcl_uint16_t
size_t mcl_size_t
mbedtls_x509_crt certificate_chain
mcl_error_t mcl_tls_socket_send(mcl_tls_socket_handle tls_socket_handle, const mcl_uint8_t *buffer, mcl_size_t *size)
Success.
Received parameter is null.
#define PORT_STRING_BUFFER_SIZE
A problem occured during SSL/TLS handshake.
mcl_int32_t mcl_error_t
#define MCL_DEBUG_ENTRY(...)
Definition: mcl_log_util.h:115
Requested operation is not supported.
MCL_CORE_EXPORT mcl_size_t mcl_string_util_strlen(const char *buffer)
Definition: string_util.c:23
#define MCL_LOG_ENABLED_RUN_TIME(level)
Definition: mcl_log_util.h:81
#define MCL_LOG_LEVEL_VERBOSE
Definition: mcl_config.h:12
#define MCL_NULL
Mindsphere certificate was not verified.
#define MCL_ERROR(...)
Definition: mcl_log_util.h:142
#define MCL_VERBOSE_LEAVE(...)
Definition: mcl_log_util.h:104
mcl_error_t mcl_tls_socket_connect(mcl_tls_socket_handle tls_socket_handle, const char *host, mcl_uint16_t port)
Host name given as a configuration parameter could not be resolved.
mcl_error_t mcl_tls_ca_chain_add_certificate(mcl_tls_ca_chain_handle tls_ca_chain_handle, const char *certificate, mcl_bool_t is_file)
static void mbedtls_debug_function(void *ctx, int level, const char *file, int line, const char *str)
mcl_error_t mcl_tls_socket_set_parameter(mcl_tls_socket_handle tls_socket_handle, E_MCL_TLS_SOCKET_PARAMETER parameter, const void *value)
MCL_CORE_EXPORT mcl_log_util_callback_t mcl_log_util_function
Definition: log_util.c:19
#define MCL_FREE(p)
Definition: mcl_memory.h:59
static const unsigned char entropy_string[]
mbedtls_ctr_drbg_context drbg_context
uint8_t mcl_uint8_t
#define MCL_ASSERT_NOT_NULL(argument, return_variable)
Definition: mcl_assert.h:38
MCL_CORE_EXPORT void * mcl_log_util_user_context
Definition: log_util.c:20
mcl_error_t mcl_tls_ca_chain_init(mcl_tls_ca_chain_handle *tls_ca_chain_handle)
MCL_CORE_EXPORT mcl_error_t mcl_string_util_snprintf(char *string, mcl_size_t length, const char *format,...)
Definition: string_util.c:158
#define MCL_ERROR_RETURN(return_value,...)
Definition: mcl_assert.h:26
mcl_error_t mcl_tls_socket_receive(mcl_tls_socket_handle tls_socket_handle, mcl_uint8_t *buffer, mcl_size_t *size)
The server certificate provided is in improper format and it can not be parsed.
mcl_uint8_t mcl_bool_t
Log utility module interface header file.
String utility module interface header file.
void mcl_tls_ca_chain_destroy(mcl_tls_ca_chain_handle *tls_ca_chain_handle)
mbedtls_net_context net_context
#define MCL_LOG_LEVEL_ERROR
Definition: mcl_config.h:16
Memory allocation fail.
#define MCL_NULL_CHAR_SIZE
#define MCL_MALLOC(bytes)
Definition: mcl_memory.h:54
mbedtls_ssl_context ssl_context
mcl_error_t mcl_tls_socket_open(mcl_tls_socket_handle tls_socket_handle)
General invalid parameter fail.
MCL_CORE_EXPORT mcl_bool_t mcl_string_util_memcmp(const void *block_1, const void *block_2, mcl_size_t count)
Definition: string_util.c:196
void mcl_tls_socket_destroy(mcl_tls_socket_handle *tls_socket_handle)
#define MCL_DEBUG_LEAVE(...)
Definition: mcl_log_util.h:116
#define MCL_TRUE
#define MCL_VERBOSE_ENTRY(...)
Definition: mcl_log_util.h:103
mcl_error_t mcl_tls_socket_init(mcl_tls_socket_handle *tls_socket_handle)
Internal failure in MCL.
#define MCL_LOG_LEVEL_DEBUG
Definition: mcl_config.h:13
Memory module interface header file.