NCBI C++ ToolKit
ncbi_mbedtls.c
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* $Id: ncbi_mbedtls.c 96217 2022-02-25 14:51:41Z lavr $
2  * ===========================================================================
3  *
4  * PUBLIC DOMAIN NOTICE
5  * National Center for Biotechnology Information
6  *
7  * This software/database is a "United States Government Work" under the
8  * terms of the United States Copyright Act. It was written as part of
9  * the author's official duties as a United States Government employee and
10  * thus cannot be copyrighted. This software/database is freely available
11  * to the public for use. The National Library of Medicine and the U.S.
12  * Government have not placed any restriction on its use or reproduction.
13  *
14  * Although all reasonable efforts have been taken to ensure the accuracy
15  * and reliability of the software and data, the NLM and the U.S.
16  * Government do not and cannot warrant the performance or results that
17  * may be obtained by using this software or data. The NLM and the U.S.
18  * Government disclaim all warranties, express or implied, including
19  * warranties of performance, merchantability or fitness for any particular
20  * purpose.
21  *
22  * Please cite the author in any work or product based on this material.
23  *
24  * ===========================================================================
25  *
26  * Author: Anton Lavrentiev
27  *
28  * File Description:
29  * MBEDTLS support for SSL in connection library
30  *
31  */
32 
33 #include "ncbi_ansi_ext.h"
34 #include "ncbi_connssl.h"
35 #include "ncbi_priv.h"
36 #include "ncbi_servicep.h"
37 #include <connect/ncbi_mbedtls.h>
38 #include <connect/ncbi_tls.h>
39 #include <stdlib.h>
40 
41 #define NCBI_USE_ERRCODE_X Connect_TLS
42 
43 
44 #if defined(HAVE_LIBMBEDTLS) || defined(NCBI_CXX_TOOLKIT)
45 
46 # ifdef HAVE_LIBMBEDTLS /* external */
47 # include <mbedtls/ctr_drbg.h>
48 # include <mbedtls/debug.h>
49 # include <mbedtls/entropy.h>
50 # include <mbedtls/error.h>
51 # include <mbedtls/pk.h>
52 # include <mbedtls/net_sockets.h>
53 # include <mbedtls/ssl.h>
54 # include <mbedtls/threading.h>
55 # include <mbedtls/version.h>
56 # else /* embedded */
58 # include "mbedtls/mbedtls/debug.h"
59 # include "mbedtls/mbedtls/entropy.h"
60 # include "mbedtls/mbedtls/error.h"
61 # include "mbedtls/mbedtls/pk.h"
63 # include "mbedtls/mbedtls/ssl.h"
65 # include "mbedtls/mbedtls/version.h"
66 # endif /*HAVE_LIBMBEDTLS*/
67 
68 # if defined(ENOTSUP)
69 # define NCBI_NOTSUPPORTED ENOTSUP
70 # elif defined(ENOSYS)
71 # define NCBI_NOTSUPPORTED ENOSYS
72 # else
73 # define NCBI_NOTSUPPORTED EINVAL
74 # endif
75 
76 #else
77 
78 # define mbedtls_x509_crt void
79 # define mbedtls_pk_context void
80 
81 #endif /*HAVE_LIBMBEDTLS || NCBI_CXX_TOOLKIT*/
82 
83 
87 };
88 
89 
90 #if defined(HAVE_LIBMBEDTLS) || defined(NCBI_CXX_TOOLKIT)
91 
92 # if defined(MBEDTLS_THREADING_ALT) && defined(NCBI_THREADS)
93 # ifdef MBEDTLS_THREADING_PTHREAD
94 # error "MBEDTLS_THREADING_ALT and MBEDTLS_THREADING_PTHREAD conflict"
95 # endif /*MBEDTLS_THREADING_PTHREAD*/
96 static void mbtls_user_mutex_init(MT_LOCK* lock)
97 {
99 }
100 static void mbtls_user_mutex_deinit(MT_LOCK* lock)
101 {
102  if (*lock) {
103  if (!(*lock = MT_LOCK_Delete(*lock))) {
104  /* NB: Do not use CORE_SetLOCK() here! */
105  g_CORE_MT_Lock = 0;
106  } else
107  *lock = 0;
108  } else
109  CORE_LOG_X(50, eLOG_Warning, "NULL MT_LOCK deinit in MBEDTLS");
110 }
111 static int mbtls_user_mutex_lock(MT_LOCK* lock)
112 {
113  if (lock) {
114  switch (MT_LOCK_Do(*lock, eMT_Lock)) {
115  case -1:
117  case 0:
119  case 1:
120  return 0;
121  default:
122  break;
123  }
124  }
126 }
127 static int mbtls_user_mutex_unlock(MT_LOCK* lock)
128 {
129  if (lock) {
130  switch (MT_LOCK_Do(*lock, eMT_Unlock)) {
131  case -1:
133  case 0:
135  case 1:
136  return 0;
137  default:
138  break;
139  }
140  }
142 }
143 # endif /*MBEDTLS_THREADING_ALT && NCBI_THREADS*/
144 
145 # ifdef __cplusplus
146 extern "C" {
147 # endif /*__cplusplus*/
148 
150 static void* s_MbedTlsCreate(ESOCK_Side side, SNcbiSSLctx* ctx,
151  int* error);
152 static EIO_Status s_MbedTlsOpen (void* session, int* error, char** desc);
153 static EIO_Status s_MbedTlsRead (void* session, void* buf,
154  size_t size, size_t* done, int* error);
155 static EIO_Status s_MbedTlsWrite (void* session, const void* data,
156  size_t size, size_t* done, int* error);
157 static EIO_Status s_MbedTlsClose (void* session, int how, int* error);
158 static void s_MbedTlsDelete(void* session);
159 static void s_MbedTlsExit (void);
160 static const char* s_MbedTlsError (void* session, int error,
161  char* buf, size_t size);
162 
163 static void x_MbedTlsLogger(void* data, int level,
164  const char* file, int line,
165  const char* message);
166 static int x_MbedTlsPull (void*, unsigned char*, size_t);
167 static int x_MbedTlsPush (void*, const unsigned char*, size_t);
168 
169 # ifdef __cplusplus
170 }
171 # endif /*__cplusplus*/
172 
173 
174 static volatile int s_MbedTlsLogLevel;
178 static volatile FSSLPull s_Pull;
179 static volatile FSSLPush s_Push;
180 
181 
182 /*ARGSUSED*/
183 static void x_MbedTlsLogger(void* unused, int level,
184  const char* file, int line,
185  const char* message)
186 {
187  /* do some basic filtering and EOL cut-offs */
188  size_t len = message ? strlen(message) : 0;
189  if (!len || *message == '\n')
190  return;
191  if (message[len - 1] == '\n')
192  --len;
194  ("MBEDTLS%d: %.*s", level, (int) len, message));
195 }
196 
197 
198 # ifdef __GNUC__
199 inline
200 # endif /*__GNUC__*/
201 static EIO_Status x_RetryStatus(SOCK sock, EIO_Event direction)
202 {
203  EIO_Status status;
204  if (direction == eIO_Open) {
205  EIO_Status r_status = SOCK_Status(sock, eIO_Read);
206  EIO_Status w_status = SOCK_Status(sock, eIO_Write);
207  status = r_status != eIO_Closed && w_status != eIO_Closed
208  ? r_status > w_status ? r_status : w_status
209  : eIO_Closed;
210  } else
211  status = SOCK_Status(sock, direction);
212  return status == eIO_Success ? eIO_Timeout : status;
213 }
214 
215 
216 # ifdef __GNUC__
217 inline
218 # endif /*__GNUC__*/
220  EIO_Event direction)
221 {
222  SOCK sock;
223  EIO_Status status;
224 
225  assert(error <= 0);
226 
227  if (!error)
228  return eIO_Success;
229  sock = ((SNcbiSSLctx*)(session->p_bio))->sock;
230  switch (error) {
232  status = x_RetryStatus(sock, direction);
233  break;
235  status = x_RetryStatus(sock, direction);
236  break;
238  status = eIO_Timeout;
239  break;
245  status = eIO_NotSupported;
246  break;
249  status = eIO_InvalidArg;
250  break;
253  status = eIO_Closed;
254  break;
257  status = eIO_Unknown;
258  break;
260  if (sock->r_status != eIO_Success &&
261  sock->r_status != eIO_Closed) {
262  status = (EIO_Status) sock->r_status;
263  } else
264  status = eIO_Unknown;
265  break;
267  if (sock->w_status != eIO_Success)
268  status = (EIO_Status) sock->w_status;
269  else
270  status = eIO_Unknown;
271  break;
273  /*return eIO_Interrupt;*/
274  default:
275  status = eIO_Unknown;
276  break;
277  }
278 
279  assert(status != eIO_Success);
281  CORE_TRACEF(("MBEDTLS error %d -> CONNECT MBEDTLS status %s",
282  error, IO_StatusStr(status)));
283  return status;
284 }
285 
286 
287 # ifdef __GNUC__
288 inline
289 # endif /*__GNUC__*/
290 static int x_StatusToError(EIO_Status status, SOCK sock, EIO_Event direction)
291 {
292  int error;
293 
294  assert(status != eIO_Success);
295  assert(direction == eIO_Read || direction == eIO_Write);
296 
297  switch (status) {
298  case eIO_Timeout:
299  error = EAGAIN;
300  break;
301  case eIO_Interrupt:
302  error = SOCK_EINTR;
303  break;
304  case eIO_NotSupported:
306  break;
307  case eIO_Unknown:
308  error = 0/*keep*/;
309  break;
310  case eIO_Closed:
312  break;
313  default:
314  /*NB:eIO_InvalidArg*/
315  error = EINVAL;
316  break;
317  }
318 
319  {{
320  int x_err = error ? error : errno;
322  CORE_TRACEF(("CONNECT MBEDTLS status %s -> %s %d",
323  IO_StatusStr(status),
324  error ? "error" : "errno", x_err));
325  if (!error)
326  errno = x_err; /* restore errno that might have been clobbered */
327  }}
328 
329  if (error)
330  errno = error;
331  else if (!(error = errno))
332  error = EINVAL;
333 
334  switch (error) {
335  case EAGAIN:
336  case SOCK_EINTR:
337  return direction == eIO_Read
340  case SOCK_ENOTCONN:
342  default:
343  break;
344  }
346 }
347 
348 
349 static void* s_MbedTlsCreate(ESOCK_Side side, SNcbiSSLctx* ctx, int* error)
350 {
351  int end = (side == eSOCK_Client
354  struct SNcbiMbedTlsCred* xcred;
355  mbedtls_ssl_context* session;
356  int err;
357 
358  if (end == MBEDTLS_SSL_IS_SERVER) {
360  "Server-side SSL not yet supported with MBEDTLS");
362  return 0;
363  }
364 
365  if (ctx->cred) {
366  if (ctx->cred->type != eNcbiCred_MbedTls || !ctx->cred->data) {
367  /*FIXME: there's a NULL(data)-terminated array of credentials */
369  ("%s credentials in MBEDTLS session",
370  ctx->cred->type != eNcbiCred_MbedTls
371  ? "Foreign"
372  : "Empty"));
373  *error = EINVAL;
374  return 0;
375  }
376  xcred = (struct SNcbiMbedTlsCred*) ctx->cred->data;
377  } else
378  xcred = 0;
379 
381  CORE_TRACE("MbedTlsCreate(): Enter");
382 
383  if (!(session = (mbedtls_ssl_context*) malloc(sizeof(*session)))) {
384  *error = errno;
385  return 0;
386  }
387  mbedtls_ssl_init(session);
388 
389  if ((err = mbedtls_ssl_setup(session, &s_MbedTlsConf)) != 0 ||
390  (ctx->host && *ctx->host
391  && (err = mbedtls_ssl_set_hostname(session, ctx->host)) != 0) ||
392  (xcred
394  (session, xcred->cert, xcred->pkey)) != 0)) {
395  mbedtls_ssl_free(session);
396  free(session);
397  *error = err;
398  return 0;
399  }
400 
402 
404  CORE_TRACEF(("MbedTlsCreate(): Leave(%p)", session));
405 
406  return session;
407 }
408 
409 
410 static EIO_Status s_MbedTlsOpen(void* session, int* error, char** desc)
411 {
412  EIO_Status status;
413  int x_error;
414 
416  CORE_TRACEF(("MbedTlsOpen(%p): Enter", session));
417 
418  x_error = mbedtls_ssl_handshake((mbedtls_ssl_context*) session);
419 
420  if (x_error < 0) {
421  status = x_ErrorToStatus(x_error, (mbedtls_ssl_context*) session,
422  eIO_Open);
423  *error = x_error;
424  if (desc)
425  *desc = 0;
426  } else {
427  if (desc) {
428  const char* alpn
430  session);
431  size_t alpn_len = alpn ? strlen(alpn) : 0;
432  const char* sslv
434  session);
435  size_t sslv_len = sslv ? strlen(sslv) : 0;
436  const char* ciph
438  session);
439  size_t ciph_len = ciph ? strlen(ciph) : 0;
440  size_t len = alpn_len + sslv_len + ciph_len;
441  if (!len)
442  *desc = 0;
443  else if ((*desc = (char*) malloc(len + 3/*seps+EOL*/)) != 0) {
444  char* ptr = *desc;
445  if (alpn_len) {
446  memcpy(ptr, alpn, alpn_len);
447  ptr += alpn_len;
448  }
449  if (sslv_len) {
450  if (ptr != *desc)
451  *ptr++ = '/';
452  memcpy(ptr, sslv, sslv_len);
453  ptr += sslv_len;
454  }
455  if (ciph_len) {
456  if (ptr != *desc)
457  *ptr++ = '/';
458  memcpy(ptr, ciph, ciph_len);
459  ptr += ciph_len;
460  }
461  *ptr = '\0';
462  }
463  }
464  status = eIO_Success;
465  }
466 
468  CORE_TRACEF(("MbedTlsOpen(%p): Leave(%d)", session, status));
469 
470  return status;
471 }
472 
473 
474 #ifdef __GNUC__
475 inline
476 #endif /*__GNUC__*/
477 static int/*bool*/ x_IfToLog(void)
478 {
479  return 4 < s_MbedTlsLogLevel ? 1/*T*/ : 0/*F*/;
480 }
481 
482 
483 static int x_MbedTlsPull(void* ctx, unsigned char* buf, size_t size)
484 {
485  SOCK sock = ((SNcbiSSLctx*) ctx)->sock;
486  FSSLPull pull = s_Pull;
487  EIO_Status status;
488 
489  if (pull) {
490  size_t x_read = 0;
491  status = pull(sock, buf, size, &x_read, x_IfToLog());
492  if (x_read > 0 || status == eIO_Success/*&& x_read==0*/) {
493  assert(status == eIO_Success);
494  assert(x_read <= size);
495  return (int) x_read;
496  }
497  } else
498  status = eIO_NotSupported;
499 
500  return x_StatusToError(status, sock, eIO_Read);
501 }
502 
503 
504 static int x_MbedTlsPush(void* ctx, const unsigned char* data, size_t size)
505 {
506  SOCK sock = ((SNcbiSSLctx*) ctx)->sock;
507  FSSLPush push = s_Push;
508  EIO_Status status;
509 
510  if (push) {
511  ssize_t n_written = 0;
512  do {
513  size_t x_written = 0;
514  status = push(sock, data, size, &x_written, x_IfToLog());
515  if (!x_written) {
516  assert(!size || status != eIO_Success);
517  if (size || status != eIO_Success)
518  goto out;
519  } else {
520  assert(status == eIO_Success);
521  assert(x_written <= size);
522  n_written += (ssize_t) x_written;
523  size -= x_written;
524  data = data + x_written;
525  }
526  } while (size);
527  return (int) n_written;
528  } else
529  status = eIO_NotSupported;
530 
531  out:
532  return x_StatusToError(status, sock, eIO_Write);
533 }
534 
535 
536 static EIO_Status s_MbedTlsRead(void* session, void* buf, size_t n_todo,
537  size_t* n_done, int* error)
538 {
539  EIO_Status status;
540  int x_read;
541 
542  assert(session);
543 
544  x_read = mbedtls_ssl_read((mbedtls_ssl_context*) session,
545  (unsigned char*) buf, n_todo);
546  assert(x_read < 0 || (size_t) x_read <= n_todo);
547 
548  if (x_read <= 0) {
549  status = x_ErrorToStatus(x_read, (mbedtls_ssl_context*) session,
550  eIO_Read);
551  *error = x_read;
552  x_read = 0;
553  } else
554  status = eIO_Success;
555 
556  *n_done = (size_t) x_read;
557  return status;
558 }
559 
560 
561 static EIO_Status x_MbedTlsWrite(void* session, const void* data,
562  size_t n_todo, size_t* n_done, int* error)
563 {
564  EIO_Status status;
565  int x_written;
566 
567  assert(session);
568 
569  x_written = mbedtls_ssl_write((mbedtls_ssl_context*) session,
570  (const unsigned char*) data, n_todo);
571  assert(x_written < 0 || (size_t) x_written <= n_todo);
572 
573  if (x_written <= 0) {
574  status = x_ErrorToStatus(x_written, (mbedtls_ssl_context*) session,
575  eIO_Write);
576  *error = x_written;
577  x_written = 0;
578  } else
579  status = eIO_Success;
580 
581  *n_done = (size_t) x_written;
582  return status;
583 }
584 
585 
586 static EIO_Status s_MbedTlsWrite(void* session, const void* data,
587  size_t n_todo, size_t* n_done, int* error)
588 {
589  size_t max_size
591  EIO_Status status;
592 
593  *n_done = 0;
594 
595  do {
596  size_t x_todo = n_todo > max_size ? max_size : n_todo;
597  size_t x_done;
598  status = x_MbedTlsWrite(session, data, x_todo, &x_done, error);
599  assert((status == eIO_Success) == (x_done > 0));
600  assert(status == eIO_Success || *error);
601  assert(x_done <= x_todo);
602  if (status != eIO_Success)
603  break;
604  *n_done += x_done;
605  if (x_todo != x_done)
606  break;
607  n_todo -= x_done;
608  data = (const char*) data + x_done;
609  } while (n_todo);
610 
611  return *n_done ? eIO_Success : status;
612 }
613 
614 
615 /*ARGSUSED*/
616 static EIO_Status s_MbedTlsClose(void* session, int how/*unused*/, int* error)
617 {
618  int x_error;
619 
620  assert(session);
621 
623  CORE_TRACEF(("MbedTlsClose(%p): Enter", session));
624 
625  x_error = mbedtls_ssl_close_notify((mbedtls_ssl_context*) session);
626 
628  CORE_TRACEF(("MbedTlsClose(%p): Leave", session));
629 
630  if (x_error) {
631  *error = x_error;
632  return eIO_Unknown;
633  }
634  return eIO_Success;
635 }
636 
637 
638 static void s_MbedTlsDelete(void* session)
639 {
640  assert(session);
641 
643  CORE_TRACEF(("MbedTlsDelete(%p): Enter", session));
644 
646 
648  CORE_TRACEF(("MbedTlsDelete(%p): Leave", session));
649 
650  free(session);
651 }
652 
653 
655 {
656  EIO_Status status;
657 
658 # ifdef NCBI_THREADS
659  switch (mbedtls_version_check_feature("MBEDTLS_THREADING_C")) {
660  case 0:
661  break;
662  case -1:
663  return eIO_NotSupported;
664  case -2:
665  return eIO_InvalidArg;
666  default:
667  return eIO_Unknown;
668  }
669 # endif /*NCBI_THREADS*/
670 
671 # ifdef MBEDTLS_THREADING_PTHREAD
672  status = eIO_Success;
673 # elif defined(MBEDTLS_THREADING_ALT) && defined(NCBI_THREADS)
674  int locked;
675  MT_LOCK lock = CORE_GetLOCK();
676  if ((locked = MT_LOCK_Do(lock, eMT_Lock)) > 0) {
677  mbedtls_threading_set_alt(mbtls_user_mutex_init,
678  mbtls_user_mutex_deinit,
679  mbtls_user_mutex_lock,
680  mbtls_user_mutex_unlock);
681  MT_LOCK_Do(lock, eMT_Unlock);
682  status = eIO_Success;
683  } else
684  status = !locked ? eIO_Unknown : lock ? eIO_Success : eIO_NotSupported;
685 # elif !defined(NCBI_NO_THREADS) && defined(_MT)
687  "MBEDTLS locking uninited: Unknown threading model");
688  status = eIO_NotSupported;
689 # else
690  status = eIO_Success;
691 # endif
692 
693  return status;
694 }
695 
696 
697 static void x_MbedTlsExit(void)
698 {
699  s_Push = 0;
700  s_Pull = 0;
701 
706  memset(&s_MbedTlsCtrDrbg, 0, sizeof(s_MbedTlsCtrDrbg));
707  memset(&s_MbedTlsEntropy, 0, sizeof(s_MbedTlsEntropy));
708  memset(&s_MbedTlsConf, 0, sizeof(s_MbedTlsConf));
709 # if defined(MBEDTLS_THREADING_ALT) && defined(NCBI_THREADS)
711 # endif /*MBEDTLS_THREADING_ALT && NCBI_THREADS*/
712 }
713 
714 
715 /* NB: Called under a lock */
717 {
718  static const char kMbedTls[] =
719 # ifdef HAVE_LIBMBEDTLS
720  "External "
721 # else
722  "Embedded "
723 # endif /*HAVE_LIBMBEDTLS*/
724  "MBEDTLS";
725  EIO_Status status;
726  char version[80];
727  const char* val;
728  char buf[32];
729 
733  ("%s version mismatch: %s headers vs. %s runtime",
734  kMbedTls, MBEDTLS_VERSION_STRING, version));
735  assert(0);
736  }
737 
738  CORE_TRACE("MbedTlsInit(): Enter");
739 
740  if (!pull || !push)
741  return eIO_InvalidArg;
742 
749 
750  /* Check CONN_[MBED]TLS_LOGLEVEL or [CONN][MBED]TLS_LOGLEVEL */
752  buf, sizeof(buf),
754  if (!val || !*val) {
756  buf, sizeof(buf),
758  }
760  if (val && *val) {
761  ELOG_Level level;
762  s_MbedTlsLogLevel = atoi(val);
763  CORE_UNLOCK;
764  if (s_MbedTlsLogLevel) {
767  level = eLOG_Note;
768  } else
769  level = eLOG_Trace;
770  CORE_LOGF_X(6, level, ("%s V%s (LogLevel=%d)",
771  kMbedTls, version, s_MbedTlsLogLevel));
772  } else
773  CORE_UNLOCK;
774 
776  CORE_TRACE("MbedTlsInit(): Go-on");
777 
778  if ((status = x_InitLocking()) != eIO_Success) {
781  memset(&s_MbedTlsConf, 0, sizeof(s_MbedTlsConf));
782  return status;
783  }
784 
787 
789  &s_MbedTlsEntropy, 0, 0) != 0) {
790  x_MbedTlsExit();
791  return eIO_Unknown;
792  }
795 
796  s_Pull = pull;
797  s_Push = push;
798 
800  CORE_TRACE("MbedTlsInit(): Leave");
801  return eIO_Success;
802 }
803 
804 
805 /* NB: Called under a lock */
806 static void s_MbedTlsExit(void)
807 {
809  CORE_TRACE("MbedTlsExit(): Enter");
810 
811  x_MbedTlsExit();
812 
813  CORE_TRACE("MbedTlsExit(): Leave");
814 }
815 
816 
817 static const char* s_MbedTlsError(void* session/*unused*/, int error,
818  char* buf, size_t size)
819 {
821  return buf;
822 }
823 
824 #else
825 
826 /*ARGSUSED*/
827 static EIO_Status s_MbedTlsInit(FSSLPull unused_pull, FSSLPush unused_push)
828 {
829  CORE_LOG_X(7, eLOG_Critical, "Unavailable feature MBEDTLS");
830  return eIO_NotSupported;
831 }
832 
833 #endif /*HAVE_LIBMBEDTLS || NCBI_CXX_TOOLKIT*/
834 
835 
837 {
838  static const struct SOCKSSL_struct kMbedTlsOps = {
839  "MBEDTLS"
840  , s_MbedTlsInit
841 #if defined(HAVE_LIBMBEDTLS) || defined(NCBI_CXX_TOOLKIT)
843  , s_MbedTlsOpen
844  , s_MbedTlsRead
848  , s_MbedTlsExit
850 #endif /*HAVE_LIBMBEDTLS || NCBI_CXX_TOOLKIT*/
851  };
852 #if !defined(HAVE_LIBMBEDTLS) && !defined(NCBI_CXX_TOOLKIT)
853  CORE_LOG_X(8, eLOG_Warning, "Unavailable feature MBEDTLS");
854 #endif /*!HAVE_LIBMBEDTLS && !NCBI_CXX_TOOLKIT*/
855  return &kMbedTlsOps;
856 }
857 
858 
859 #define ALIGN2(s, a) ((((s) + ((a) - 1)) / (a)) * (a))
860 #define ALIGN(s) ALIGN2(s, sizeof(double))
861 
862 
863 extern NCBI_CRED NcbiCredMbedTls(void* xcert, void* xpkey)
864 {
865  struct SNcbiCred* cred;
866  struct SNcbiMbedTlsCred* xcred;
867  size_t size = ALIGN(sizeof(*cred));
868  if (xcert && xpkey) {
869  size <<= 1;
870  size += sizeof(*xcred);
871  }
872  cred = (NCBI_CRED) calloc(1, size);
873  if (cred) {
874  cred->type = eNcbiCred_MbedTls;
875  if (xcert && xpkey) {
876  xcred = (struct SNcbiMbedTlsCred*)
877  ((char*) cred + 2*ALIGN(sizeof(*cred)));
878  xcred->cert = (mbedtls_x509_crt*) xcert;
879  xcred->pkey = (mbedtls_pk_context*) xpkey;
880  cred->data = xcred;
881  }
882  }
883  return cred;
884 }
885 
886 
887 #if defined(HAVE_LIBMBEDTLS) || defined(NCBI_CXX_TOOLKIT)
888 
890 {
891  if (cred->type / 100 == eNcbiCred_MbedTls / 100 && !(cred->type % 100)) {
892  struct SNcbiMbedTlsCred* xcred = (struct SNcbiMbedTlsCred*) cred->data;
893  mbedtls_x509_crt_free(xcred->cert);
894  mbedtls_pk_free (xcred->pkey);
895  memset(xcred, 0, sizeof(*xcred));
896  } else {
897  char who[80];
898  switch (cred->type / 100) {
899  case eNcbiCred_GnuTls / 100:
900  strcpy(who, "GNUTLS");
901  break;
902  case eNcbiCred_MbedTls / 100:
903  strcpy(who, "MBEDTLS");
904  break;
905  default:
906  sprintf(who, "TLS 0x%08X", cred->type);
907  break;
908  }
910  ("Deleting unknown certificate credentials (%s/%u)",
911  who, cred->type % 100));
912  assert(0);
913  }
914  cred->type = (ENcbiCred) 0;
915  cred->data = 0;
916  free(cred);
917 }
918 
919 
921  size_t certsz,
922  const void* pkey,
923  size_t pkeysz)
924 {
925  struct SNcbiCred* ncbi_cred;
926  struct SNcbiMbedTlsCred* xcred;
927  const size_t size = (2*ALIGN(sizeof(*ncbi_cred))
928  + ALIGN(sizeof(*xcred))
929  + ALIGN(sizeof(*xcred->cert))
930  + sizeof(*xcred->pkey));
931  CORE_DEBUG_ARG(char tmp[1024];)
932  char errbuf[80];
933  int err;
934 
935  if (!(ncbi_cred = (NCBI_CRED) calloc(1, size))) {
936  CORE_LOGF_ERRNO_X(10, eLOG_Error, errno,
937  ("Cannot allocate NCBI_CRED (%lu bytes)",
938  (unsigned long) size));
939  return 0;
940  }
941 
942  xcred = (struct SNcbiMbedTlsCred*)
943  ((char*) ncbi_cred + 2*ALIGN(sizeof(*ncbi_cred)));
944  xcred->cert = (mbedtls_x509_crt*)
945  ((char*) xcred + ALIGN(sizeof(*xcred)));
946  xcred->pkey = (mbedtls_pk_context*)
947  ((char*) xcred->cert + ALIGN(sizeof(*xcred->cert)));
948  ncbi_cred->type = eNcbiCred_MbedTls;
949  ncbi_cred->data = xcred;
950 
951  /* these are not technically necessary as they just zero up the memory */
952  mbedtls_x509_crt_init(xcred->cert);
953  mbedtls_pk_init (xcred->pkey);
954 
955  err = mbedtls_x509_crt_parse(xcred->cert,
956  (const unsigned char*) cert, certsz ? certsz
957  : strlen((const char*) cert) + 1);
958  if (err) {
959  mbedtls_strerror(err, errbuf, sizeof(errbuf) - 1);
960  CORE_LOG_ERRNO_EXX(11, eLOG_Error, err, errbuf,
961  "mbedTLS cannot parse X.509 certificate");
962  goto out;
963  }
965  "", xcred->cert));
966  CORE_TRACEF(("Certificate loaded%s%s",
967  err > 0 ? ":\n" : "",
968  err > 0 ? tmp : ""));
969 
970  err = mbedtls_pk_parse_key(xcred->pkey,
971  (const unsigned char*) pkey, pkeysz ? pkeysz
972  : strlen((const char*) pkey) + 1, 0, 0);
973  if (err) {
974  mbedtls_strerror(err, errbuf, sizeof(errbuf) - 1);
975  CORE_LOG_ERRNO_EXX(12, eLOG_Error, err, errbuf,
976  "mbedTLS cannot parse private key");
977  goto out;
978  }
979  CORE_TRACEF(("Private key loaded: %s",
980  mbedtls_pk_get_name(xcred->pkey)));
981 
982  return ncbi_cred;
983 
984  out:
986  return 0;
987 }
988 
989 #endif /*HAVE_LIBMBEDTLS || NCBI_CXX_TOOLKIT*/
CS_CONTEXT * ctx
Definition: t0006.c:12
This file contains definitions and functions for the CTR_DRBG pseudorandom generator.
void mbedtls_ctr_drbg_free(mbedtls_ctr_drbg_context *ctx)
This function resets CTR_DRBG context to the state immediately after initial call of mbedtls_ctr_drbg...
void mbedtls_ctr_drbg_init(mbedtls_ctr_drbg_context *ctx)
This function initializes the CTR_DRBG context, and prepares it for mbedtls_ctr_drbg_seed() or mbedtl...
int mbedtls_ctr_drbg_seed(mbedtls_ctr_drbg_context *ctx, int(*f_entropy)(void *, unsigned char *, size_t), void *p_entropy, const unsigned char *custom, size_t len)
This function seeds and sets up the CTR_DRBG entropy source for future reseeds.
int mbedtls_ctr_drbg_random(void *p_rng, unsigned char *output, size_t output_len)
This function uses CTR_DRBG to generate random data.
Functions for controlling and providing debug output from the library.
void mbedtls_debug_set_threshold(int threshold)
Set the threshold error level to handle globally all debug output.
Entropy accumulator implementation.
void mbedtls_entropy_free(mbedtls_entropy_context *ctx)
Free the data in the context.
int mbedtls_entropy_func(void *data, unsigned char *output, size_t len)
Retrieve entropy from the accumulator (Maximum length: MBEDTLS_ENTROPY_BLOCK_SIZE) (Thread-safe if MB...
void mbedtls_entropy_init(mbedtls_entropy_context *ctx)
Initialize the context.
std::ofstream out("events_result.xml")
main entry point for tests
SOCKSSL NcbiSetupMbedTls(void)
Explicitly setup mbedTLS library to support SSL in ncbi_socket.h[pp].
Definition: ncbi_mbedtls.c:836
#define DEF_CONN_TLS_LOGLEVEL
Definition: ncbi_tls.h:89
struct SNcbiCred * NCBI_CRED
Opaque type for credentials.
Definition: ncbi_socket.h:2303
#define REG_CONN_TLS_LOGLEVEL
Definition: ncbi_tls.h:88
EIO_Status SOCK_Status(SOCK sock, EIO_Event direction)
Return low-level socket I/O status of *last* socket operation.
Definition: ncbi_socket.c:7463
ESOCK_Side
Sides of socket.
Definition: ncbi_socket.h:210
NCBI_CRED NcbiCredMbedTls(void *xcert, void *xpkey)
Convert native mbedTLS certificate credentials' handles into an abstract toolkit handle.
Definition: ncbi_mbedtls.c:863
@ eSOCK_Client
Definition: ncbi_socket.h:212
MT_LOCK CORE_GetLOCK(void)
Get the lock handle that is to be used by the core internals.
Definition: ncbi_util.c:111
ELOG_Level
Log severity level.
Definition: ncbi_core.h:292
MT_LOCK MT_LOCK_AddRef(MT_LOCK lk)
Increment internal reference count by 1, then return "lk".
Definition: ncbi_core.c:217
EIO_Status
I/O status.
Definition: ncbi_core.h:132
const char * IO_StatusStr(EIO_Status status)
Get the text form of an enum status value.
Definition: ncbi_core.c:56
MT_LOCK MT_LOCK_Delete(MT_LOCK lk)
Decrement internal reference count by 1, and if it reaches 0, then destroy the handle,...
Definition: ncbi_core.c:234
EIO_Event
I/O event (or direction).
Definition: ncbi_core.h:118
#define MT_LOCK_Do(lk, how)
Call "lk->handler(lk->data, how)".
Definition: ncbi_core.h:270
@ eLOG_Critical
Definition: ncbi_core.h:298
@ eLOG_Error
Definition: ncbi_core.h:297
@ eLOG_Note
Definition: ncbi_core.h:294
@ eLOG_Warning
Definition: ncbi_core.h:296
@ eLOG_Trace
Definition: ncbi_core.h:293
@ eMT_Unlock
unlock critical section
Definition: ncbi_core.h:183
@ eMT_Lock
lock critical section
Definition: ncbi_core.h:181
@ eIO_Timeout
timeout expired before any I/O succeeded
Definition: ncbi_core.h:134
@ eIO_Interrupt
signal arrival prevented any I/O to succeed
Definition: ncbi_core.h:136
@ eIO_NotSupported
operation is not supported or is not available
Definition: ncbi_core.h:138
@ eIO_Success
everything is fine, no error occurred
Definition: ncbi_core.h:133
@ eIO_Unknown
unknown I/O error (likely fatal but can retry)
Definition: ncbi_core.h:139
@ eIO_InvalidArg
bad argument / parameter value(s) supplied
Definition: ncbi_core.h:137
@ eIO_Write
write
Definition: ncbi_core.h:121
@ eIO_Open
also serves as no-event indicator in SOCK_Poll
Definition: ncbi_core.h:119
@ eIO_Read
read
Definition: ncbi_core.h:120
FILE * file
char * buf
int len
static int version
Definition: mdb_load.c:29
list< Ts... > push
const struct ncbi::grid::netcache::search::fields::SIZE size
#define strcasecmp
EIO_Status(* FSSLPush)(SOCK sock, const void *data, size_t size, size_t *done, int logdata)
Definition: ncbi_connssl.h:81
EIO_Status(* FSSLPull)(SOCK sock, void *buf, size_t size, size_t *done, int logdata)
Definition: ncbi_connssl.h:69
ENcbiCred
Definition: ncbi_connssl.h:45
@ eNcbiCred_MbedTls
Definition: ncbi_connssl.h:48
@ eNcbiCred_GnuTls
Definition: ncbi_connssl.h:47
const char * ConnNetInfo_GetValueInternal(const char *service, const char *param, char *value, size_t value_size, const char *def_value)
static int x_StatusToError(EIO_Status status, SOCK sock, EIO_Event direction)
Definition: ncbi_mbedtls.c:290
void NcbiDeleteMbedTlsCertCredentials(NCBI_CRED cred)
Definition: ncbi_mbedtls.c:889
static void x_MbedTlsExit(void)
Definition: ncbi_mbedtls.c:697
static void s_MbedTlsExit(void)
Definition: ncbi_mbedtls.c:806
static EIO_Status s_MbedTlsOpen(void *session, int *error, char **desc)
Definition: ncbi_mbedtls.c:410
NCBI_CRED NcbiCreateMbedTlsCertCredentials(const void *cert, size_t certsz, const void *pkey, size_t pkeysz)
Definition: ncbi_mbedtls.c:920
static EIO_Status x_MbedTlsWrite(void *session, const void *data, size_t n_todo, size_t *n_done, int *error)
Definition: ncbi_mbedtls.c:561
static EIO_Status s_MbedTlsRead(void *session, void *buf, size_t size, size_t *done, int *error)
Definition: ncbi_mbedtls.c:536
static int x_MbedTlsPull(void *, unsigned char *, size_t)
Definition: ncbi_mbedtls.c:483
static volatile int s_MbedTlsLogLevel
Definition: ncbi_mbedtls.c:174
static volatile FSSLPull s_Pull
Definition: ncbi_mbedtls.c:178
static EIO_Status s_MbedTlsInit(FSSLPull pull, FSSLPush push)
Definition: ncbi_mbedtls.c:716
static mbedtls_ssl_config s_MbedTlsConf
Definition: ncbi_mbedtls.c:177
static EIO_Status s_MbedTlsClose(void *session, int how, int *error)
Definition: ncbi_mbedtls.c:616
#define NCBI_NOTSUPPORTED
Definition: ncbi_mbedtls.c:73
static mbedtls_entropy_context s_MbedTlsEntropy
Definition: ncbi_mbedtls.c:175
static EIO_Status x_RetryStatus(SOCK sock, EIO_Event direction)
Definition: ncbi_mbedtls.c:201
static const char * s_MbedTlsError(void *session, int error, char *buf, size_t size)
Definition: ncbi_mbedtls.c:817
static int x_IfToLog(void)
Definition: ncbi_mbedtls.c:477
static void s_MbedTlsDelete(void *session)
Definition: ncbi_mbedtls.c:638
static volatile FSSLPush s_Push
Definition: ncbi_mbedtls.c:179
static EIO_Status x_InitLocking(void)
Definition: ncbi_mbedtls.c:654
static EIO_Status x_ErrorToStatus(int error, mbedtls_ssl_context *session, EIO_Event direction)
Definition: ncbi_mbedtls.c:219
static EIO_Status s_MbedTlsWrite(void *session, const void *data, size_t size, size_t *done, int *error)
Definition: ncbi_mbedtls.c:586
static void x_MbedTlsLogger(void *data, int level, const char *file, int line, const char *message)
Definition: ncbi_mbedtls.c:183
static int x_MbedTlsPush(void *, const unsigned char *, size_t)
Definition: ncbi_mbedtls.c:504
static mbedtls_ctr_drbg_context s_MbedTlsCtrDrbg
Definition: ncbi_mbedtls.c:176
#define ALIGN(s)
Definition: ncbi_mbedtls.c:860
static void * s_MbedTlsCreate(ESOCK_Side side, SNcbiSSLctx *ctx, int *error)
Definition: ncbi_mbedtls.c:349
MT_LOCK g_CORE_MT_Lock
Definition: ncbi_priv.c:48
#define CORE_DEBUG_ARG(arg)
Definition: ncbi_priv.h:139
#define CORE_LOGF_X(subcode, level, fmt_args)
Definition: ncbi_priv.h:150
#define CORE_LOG_ERRNO_EXX(subcode, level, error, descr, message)
Definition: ncbi_priv.h:178
#define CORE_LOGF_ERRNO_X(subcode, level, error, fmt_args)
Definition: ncbi_priv.h:166
#define CORE_TRACEF(fmt_args)
Definition: ncbi_priv.h:138
#define CORE_TRACE(message)
Definition: ncbi_priv.h:137
#define CORE_UNLOCK
Definition: ncbi_priv.h:273
#define CORE_LOG_X(subcode, level, message)
Definition: ncbi_priv.h:146
#define CORE_LOCK_READ
Definition: ncbi_priv.h:271
#define SOCK_ENOTCONN
Definition: ncbi_socketp.h:83
#define SOCK_EINTR
Definition: ncbi_socketp.h:75
int ssize_t
Definition: ncbiconf_msvc.h:92
#define mbedtls_version_get_string
#define mbedtls_pk_parse_key
#define mbedtls_ssl_set_hostname
#define mbedtls_x509_crt_init
#define mbedtls_version_check_feature
#define mbedtls_ssl_get_alpn_protocol
#define mbedtls_x509_crt_free
#define mbedtls_x509_crt_parse
#define mbedtls_ssl_get_output_max_frag_len
#define mbedtls_x509_crt_info
#define mbedtls_ssl_set_hs_own_cert
#define mbedtls_threading_set_alt
#define mbedtls_threading_free_alt
Network sockets abstraction layer to integrate Mbed TLS into a BSD-style sockets API.
#define MBEDTLS_ERR_NET_RECV_FAILED
Reading information from the socket failed.
Definition: net_sockets.h:63
#define MBEDTLS_ERR_NET_CONN_RESET
Connection was reset by peer.
Definition: net_sockets.h:67
#define MBEDTLS_ERR_NET_SEND_FAILED
Sending information through the socket failed.
Definition: net_sockets.h:65
static char tmp[2048]
Definition: utf8.c:42
Public Key abstraction layer.
const char * mbedtls_pk_get_name(const mbedtls_pk_context *ctx)
Access the type name.
void mbedtls_pk_init(mbedtls_pk_context *ctx)
Initialize a mbedtls_pk_context (as NONE).
void mbedtls_pk_free(mbedtls_pk_context *ctx)
Free the components of a mbedtls_pk_context.
Error to string translation.
void mbedtls_strerror(int errnum, char *buffer, size_t buflen)
Translate a mbed TLS error code into a string representation, Result is truncated if necessary and al...
Run-time version information.
#define MBEDTLS_VERSION_STRING
Definition: version.h:49
#define assert(x)
Definition: srv_diag.hpp:58
SSL/TLS functions.
#define MBEDTLS_ERR_SSL_NON_FATAL
The alert message received indicates a non-fatal error.
Definition: ssl.h:179
const char * mbedtls_ssl_get_ciphersuite(const mbedtls_ssl_context *ssl)
Return the name of the current ciphersuite.
#define MBEDTLS_SSL_VERIFY_NONE
Definition: ssl.h:242
const char * mbedtls_ssl_get_version(const mbedtls_ssl_context *ssl)
Return the current SSL version (SSLv3/TLSv1/etc)
#define MBEDTLS_SSL_IS_CLIENT
Definition: ssl.h:224
void mbedtls_ssl_free(mbedtls_ssl_context *ssl)
Free referenced items in an SSL context and clear memory.
#define MBEDTLS_ERR_SSL_TIMEOUT
The operation timed out.
Definition: ssl.h:173
void mbedtls_ssl_conf_rng(mbedtls_ssl_config *conf, int(*f_rng)(void *, unsigned char *, size_t), void *p_rng)
Set the random number generator callback.
int mbedtls_ssl_handshake(mbedtls_ssl_context *ssl)
Perform the SSL handshake.
#define MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE
None of the common ciphersuites is usable (eg, no suitable certificate, see debug messages).
Definition: ssl.h:167
void mbedtls_ssl_conf_authmode(mbedtls_ssl_config *conf, int authmode)
Set the certificate verification mode Default: NONE on server, REQUIRED on client.
int mbedtls_ssl_write(mbedtls_ssl_context *ssl, const unsigned char *buf, size_t len)
Try to write exactly 'len' application data bytes.
#define MBEDTLS_ERR_SSL_BAD_INPUT_DATA
Bad input parameters to function.
Definition: ssl.h:83
#define MBEDTLS_ERR_SSL_WANT_WRITE
Connection requires a write call.
Definition: ssl.h:171
#define MBEDTLS_ERR_SSL_WANT_READ
No data of requested type currently available on underlying transport.
Definition: ssl.h:169
#define MBEDTLS_SSL_IS_SERVER
Definition: ssl.h:225
void mbedtls_ssl_config_free(mbedtls_ssl_config *conf)
Free an SSL configuration context.
void mbedtls_ssl_init(mbedtls_ssl_context *ssl)
Initialize an SSL context Just makes the context ready for mbedtls_ssl_setup() or mbedtls_ssl_free()
void mbedtls_ssl_set_bio(mbedtls_ssl_context *ssl, void *p_bio, mbedtls_ssl_send_t *f_send, mbedtls_ssl_recv_t *f_recv, mbedtls_ssl_recv_timeout_t *f_recv_timeout)
Set the underlying BIO callbacks for write, read and read-with-timeout.
int mbedtls_ssl_config_defaults(mbedtls_ssl_config *conf, int endpoint, int transport, int preset)
Load reasonable default SSL configuration values.
int mbedtls_ssl_read(mbedtls_ssl_context *ssl, unsigned char *buf, size_t len)
Read at most 'len' application data bytes.
void mbedtls_ssl_conf_dbg(mbedtls_ssl_config *conf, void(*f_dbg)(void *, int, const char *, int, const char *), void *p_dbg)
Set the debug callback.
#define MBEDTLS_ERR_SSL_CONN_EOF
The connection indicated an EOF.
Definition: ssl.h:89
void mbedtls_ssl_config_init(mbedtls_ssl_config *conf)
Initialize an SSL configuration context Just makes the context ready for mbedtls_ssl_config_defaults(...
int mbedtls_ssl_close_notify(mbedtls_ssl_context *ssl)
Notify the peer that the connection is being closed.
#define MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY
The peer notified us that the connection is going to be closed.
Definition: ssl.h:113
#define MBEDTLS_ERR_SSL_UNKNOWN_CIPHER
An unknown cipher was received.
Definition: ssl.h:91
#define MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE
A fatal alert message was received from our peer.
Definition: ssl.h:109
#define MBEDTLS_SSL_TRANSPORT_STREAM
Definition: ssl.h:207
#define MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE
The requested feature is not available.
Definition: ssl.h:81
#define MBEDTLS_ERR_SSL_INTERNAL_ERROR
Internal error (eg, unexpected failure in lower-level module)
Definition: ssl.h:157
int mbedtls_ssl_setup(mbedtls_ssl_context *ssl, const mbedtls_ssl_config *conf)
Set up an SSL context for use.
#define MBEDTLS_SSL_PRESET_DEFAULT
Definition: ssl.h:276
ENcbiCred type
Definition: ncbi_connssl.h:53
void * data
Definition: ncbi_connssl.h:54
mbedtls_x509_crt * cert
Definition: ncbi_mbedtls.c:85
mbedtls_pk_context * pkey
Definition: ncbi_mbedtls.c:86
TSOCK_Handle sock
Definition: ncbi_socketp.h:230
EBIO_Status w_status
Definition: ncbi_socketp.h:249
EBIO_Status r_status
Definition: ncbi_socketp.h:246
The CTR_DRBG context structure.
Definition: ctr_drbg.h:173
Entropy context structure.
Definition: entropy.h:125
Public key container.
Definition: pk.h:197
SSL/TLS configuration to be shared between mbedtls_ssl_context structures.
Definition: ssl.h:1018
void * p_bio
Definition: ssl.h:1298
Container for an X.509 certificate.
Definition: x509_crt.h:52
Threading abstraction layer.
#define MBEDTLS_ERR_THREADING_MUTEX_ERROR
Locking / unlocking / free failed with error code.
Definition: threading.h:45
#define MBEDTLS_ERR_THREADING_BAD_INPUT_DATA
Bad input parameters to function.
Definition: threading.h:43
#define MBEDTLS_ERR_THREADING_FEATURE_UNAVAILABLE
The selected feature is not available.
Definition: threading.h:40
done
Definition: token1.c:1
void free(voidpf ptr)
voidp malloc(uInt size)
voidp calloc(uInt items, uInt size)
Modified on Tue Nov 28 02:28:14 2023 by modify_doxy.py rev. 669887