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 102329 2024-04-23 19:21:48Z ucko $
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 # include <mbedtls/ctr_drbg.h>
47 # include <mbedtls/debug.h>
48 # include <mbedtls/entropy.h>
49 # include <mbedtls/error.h>
50 # include <mbedtls/pk.h>
51 # include <mbedtls/net_sockets.h>
52 # include <mbedtls/ssl.h>
53 # include <mbedtls/threading.h>
54 # include <mbedtls/version.h>
55 # include <psa/crypto.h>
56 
57 # if defined(ENOTSUP)
58 # define NCBI_NOTSUPPORTED ENOTSUP
59 # elif defined(ENOSYS)
60 # define NCBI_NOTSUPPORTED ENOSYS
61 # else
62 # define NCBI_NOTSUPPORTED EINVAL
63 # endif
64 
65 #else
66 
67 # define mbedtls_x509_crt void
68 # define mbedtls_pk_context void
69 
70 #endif /*HAVE_LIBMBEDTLS || NCBI_CXX_TOOLKIT*/
71 
72 
76 };
77 
78 
79 #if defined(HAVE_LIBMBEDTLS) || defined(NCBI_CXX_TOOLKIT)
80 
81 # if defined(MBEDTLS_THREADING_ALT) && defined(NCBI_THREADS)
82 # ifdef MBEDTLS_THREADING_PTHREAD
83 # error "MBEDTLS_THREADING_ALT and MBEDTLS_THREADING_PTHREAD conflict"
84 # endif /*MBEDTLS_THREADING_PTHREAD*/
85 static void mbtls_user_mutex_init(MT_LOCK* lock)
86 {
88 }
89 static void mbtls_user_mutex_deinit(MT_LOCK* lock)
90 {
91  if (*lock) {
92  if (!(*lock = MT_LOCK_Delete(*lock))) {
93  /* NB: Do not use CORE_SetLOCK() here! */
94  g_CORE_MT_Lock = 0;
95  } else
96  *lock = 0;
97  } else
98  CORE_LOG_X(50, eLOG_Warning, "NULL MT_LOCK deinit in MBEDTLS");
99 }
100 static int mbtls_user_mutex_lock(MT_LOCK* lock)
101 {
102  if (lock) {
103  switch (MT_LOCK_Do(*lock, eMT_Lock)) {
104  case -1:
105 #ifdef MBEDTLS_ERR_THREADING_FEATURE_UNAVAILABLE
106  return MBEDTLS_ERR_THREADING_FEATURE_UNAVAILABLE;
107 #else
109 #endif
110  case 0:
112  case 1:
113  return 0;
114  default:
115  break;
116  }
117  }
119 }
120 static int mbtls_user_mutex_unlock(MT_LOCK* lock)
121 {
122  if (lock) {
123  switch (MT_LOCK_Do(*lock, eMT_Unlock)) {
124  case -1:
125 #ifdef MBEDTLS_ERR_THREADING_FEATURE_UNAVAILABLE
126  return MBEDTLS_ERR_THREADING_FEATURE_UNAVAILABLE;
127 #else
129 #endif
130  case 0:
132  case 1:
133  return 0;
134  default:
135  break;
136  }
137  }
139 }
140 # endif /*MBEDTLS_THREADING_ALT && NCBI_THREADS*/
141 
142 # ifdef __cplusplus
143 extern "C" {
144 # endif /*__cplusplus*/
145 
147 static void* s_MbedTlsCreate(ESOCK_Side side, SNcbiSSLctx* ctx,
148  int* error);
149 static EIO_Status s_MbedTlsOpen (void* session, int* error, char** desc);
150 static EIO_Status s_MbedTlsRead (void* session, void* buf,
151  size_t size, size_t* done, int* error);
152 static EIO_Status s_MbedTlsWrite (void* session, const void* data,
153  size_t size, size_t* done, int* error);
154 static EIO_Status s_MbedTlsClose (void* session, int how, int* error);
155 static void s_MbedTlsDelete(void* session);
156 static void s_MbedTlsExit (void);
157 static const char* s_MbedTlsError (void* session, int error,
158  char* buf, size_t size);
159 
160 static void x_MbedTlsLogger(void* data, int level,
161  const char* file, int line,
162  const char* message);
163 static int x_MbedTlsPull (void*, unsigned char*, size_t);
164 static int x_MbedTlsPush (void*, const unsigned char*, size_t);
165 
166 # ifdef __cplusplus
167 }
168 # endif /*__cplusplus*/
169 
170 
171 static volatile int s_MbedTlsLogLevel;
175 static volatile FSSLPull s_Pull;
176 static volatile FSSLPush s_Push;
177 
178 
179 /*ARGSUSED*/
180 static void x_MbedTlsLogger(void* unused, int level,
181  const char* file, int line,
182  const char* message)
183 {
184  /* do some basic filtering and EOL cut-offs */
185  size_t len = message ? strlen(message) : 0;
186  if (!len || *message == '\n')
187  return;
188  if (message[len - 1] == '\n')
189  --len;
191  ("MBEDTLS%d: %.*s", level, (int) len, message));
192 }
193 
194 
195 # ifdef __GNUC__
196 inline
197 # endif /*__GNUC__*/
198 static EIO_Status x_RetryStatus(SOCK sock, EIO_Event direction)
199 {
200  EIO_Status status;
201  if (direction == eIO_Open) {
202  EIO_Status r_status = SOCK_Status(sock, eIO_Read);
203  EIO_Status w_status = SOCK_Status(sock, eIO_Write);
204  status = r_status != eIO_Closed && w_status != eIO_Closed
205  ? r_status > w_status ? r_status : w_status
206  : eIO_Closed;
207  } else
208  status = SOCK_Status(sock, direction);
209  return status == eIO_Success ? eIO_Timeout : status;
210 }
211 
212 
213 # ifdef __GNUC__
214 inline
215 # endif /*__GNUC__*/
217  EIO_Event direction)
218 {
219  SOCK sock;
220  EIO_Status status;
221 
222  assert(error <= 0);
223 
224  if (!error)
225  return eIO_Success;
226 #if MBEDTLS_VERSION_MAJOR >= 3
227  sock = ((SNcbiSSLctx*)(session->MBEDTLS_PRIVATE(p_bio)))->sock;
228 #else
229  sock = ((SNcbiSSLctx*)(session->p_bio))->sock;
230 #endif
231  switch (error) {
233  status = x_RetryStatus(sock, direction);
234  break;
236  status = x_RetryStatus(sock, direction);
237  break;
239  status = eIO_Timeout;
240  break;
241 #ifdef MBEDTLS_ERR_THREADING_FEATURE_UNAVAILABLE
242  case MBEDTLS_ERR_THREADING_FEATURE_UNAVAILABLE:
243 #endif
244 #ifdef MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE
245  case MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE:
246 #endif
248 #ifdef MBEDTLS_ERR_SSL_UNKNOWN_CIPHER
249  case MBEDTLS_ERR_SSL_UNKNOWN_CIPHER:
250 #endif
252 #ifdef MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED
254 #endif
255  status = eIO_NotSupported;
256  break;
259  status = eIO_InvalidArg;
260  break;
263  status = eIO_Closed;
264  break;
267  status = eIO_Unknown;
268  break;
270  if (sock->r_status != eIO_Success &&
271  sock->r_status != eIO_Closed) {
272  status = (EIO_Status) sock->r_status;
273  } else
274  status = eIO_Unknown;
275  break;
277  if (sock->w_status != eIO_Success)
278  status = (EIO_Status) sock->w_status;
279  else
280  status = eIO_Unknown;
281  break;
283  /*return eIO_Interrupt;*/
284  default:
285  status = eIO_Unknown;
286  break;
287  }
288 
289  assert(status != eIO_Success);
291  CORE_TRACEF(("MBEDTLS error %d -> CONNECT MBEDTLS status %s",
292  error, IO_StatusStr(status)));
293  return status;
294 }
295 
296 
297 # ifdef __GNUC__
298 inline
299 # endif /*__GNUC__*/
300 static int x_StatusToError(EIO_Status status, SOCK sock, EIO_Event direction)
301 {
302  int error;
303 
304  assert(status != eIO_Success);
305  assert(direction == eIO_Read || direction == eIO_Write);
306 
307  switch (status) {
308  case eIO_Timeout:
309  error = EAGAIN;
310  break;
311  case eIO_Interrupt:
312  error = SOCK_EINTR;
313  break;
314  case eIO_NotSupported:
316  break;
317  case eIO_Unknown:
318  error = 0/*keep*/;
319  break;
320  case eIO_Closed:
322  break;
323  default:
324  /*NB:eIO_InvalidArg*/
325  error = EINVAL;
326  break;
327  }
328 
329  {{
330  int x_err = error ? error : errno;
332  CORE_TRACEF(("CONNECT MBEDTLS status %s -> %s %d",
333  IO_StatusStr(status),
334  error ? "error" : "errno", x_err));
335  if (!error)
336  errno = x_err; /* restore errno that might have been clobbered */
337  }}
338 
339  if (error)
340  errno = error;
341  else if (!(error = errno))
342  error = EINVAL;
343 
344  switch (error) {
345  case EAGAIN:
346  case SOCK_EINTR:
347  return direction == eIO_Read
350  case SOCK_ENOTCONN:
352  default:
353  break;
354  }
356 }
357 
358 
359 static void* s_MbedTlsCreate(ESOCK_Side side, SNcbiSSLctx* ctx, int* error)
360 {
361  int end = (side == eSOCK_Client
364  struct SNcbiMbedTlsCred* xcred;
365  mbedtls_ssl_context* session;
366  int err;
367 
368  if (end == MBEDTLS_SSL_IS_SERVER) {
370  "Server-side SSL not yet supported with MBEDTLS");
372  return 0;
373  }
374 
375  if (ctx->cred) {
376  if (ctx->cred->type != eNcbiCred_MbedTls || !ctx->cred->data) {
377  /*FIXME: there's a NULL(data)-terminated array of credentials */
379  ("%s credentials in MBEDTLS session",
380  ctx->cred->type != eNcbiCred_MbedTls
381  ? "Foreign"
382  : "Empty"));
383  *error = EINVAL;
384  return 0;
385  }
386  xcred = (struct SNcbiMbedTlsCred*) ctx->cred->data;
387  } else
388  xcred = 0;
389 
391  CORE_TRACE("MbedTlsCreate(): Enter");
392 
393  if (!(session = (mbedtls_ssl_context*) malloc(sizeof(*session)))) {
394  *error = errno;
395  return 0;
396  }
397  mbedtls_ssl_init(session);
398 
399  if ((err = mbedtls_ssl_setup(session, &s_MbedTlsConf)) != 0 ||
400  (ctx->host && *ctx->host
401  && (err = mbedtls_ssl_set_hostname(session, ctx->host)) != 0) ||
402  (xcred
404  (session, xcred->cert, xcred->pkey)) != 0)) {
405  mbedtls_ssl_free(session);
406  free(session);
407  *error = err;
408  return 0;
409  }
410 
412 
414  CORE_TRACEF(("MbedTlsCreate(): Leave(%p)", session));
415 
416  return session;
417 }
418 
419 
420 static EIO_Status s_MbedTlsOpen(void* session, int* error, char** desc)
421 {
422  EIO_Status status;
423  int x_error;
424 
426  CORE_TRACEF(("MbedTlsOpen(%p): Enter", session));
427 
428  x_error = mbedtls_ssl_handshake((mbedtls_ssl_context*) session);
429 
430  if (x_error < 0) {
431  status = x_ErrorToStatus(x_error, (mbedtls_ssl_context*) session,
432  eIO_Open);
433  *error = x_error;
434  if (desc)
435  *desc = 0;
436  } else {
437  if (desc) {
438  const char* alpn
440  session);
441  size_t alpn_len = alpn ? strlen(alpn) : 0;
442  const char* sslv
444  session);
445  size_t sslv_len = sslv ? strlen(sslv) : 0;
446  const char* ciph
448  session);
449  size_t ciph_len = ciph ? strlen(ciph) : 0;
450  size_t len = alpn_len + sslv_len + ciph_len;
451  if (!len)
452  *desc = 0;
453  else if ((*desc = (char*) malloc(len + 3/*seps+EOL*/)) != 0) {
454  char* ptr = *desc;
455  if (alpn_len) {
456  memcpy(ptr, alpn, alpn_len);
457  ptr += alpn_len;
458  }
459  if (sslv_len) {
460  if (ptr != *desc)
461  *ptr++ = '/';
462  memcpy(ptr, sslv, sslv_len);
463  ptr += sslv_len;
464  }
465  if (ciph_len) {
466  if (ptr != *desc)
467  *ptr++ = '/';
468  memcpy(ptr, ciph, ciph_len);
469  ptr += ciph_len;
470  }
471  *ptr = '\0';
472  }
473  }
474  status = eIO_Success;
475  }
476 
478  CORE_TRACEF(("MbedTlsOpen(%p): Leave(%d)", session, status));
479 
480  return status;
481 }
482 
483 
484 #ifdef __GNUC__
485 inline
486 #endif /*__GNUC__*/
487 static int/*bool*/ x_IfToLog(void)
488 {
489  return 4 < s_MbedTlsLogLevel ? 1/*T*/ : 0/*F*/;
490 }
491 
492 
493 static int x_MbedTlsPull(void* ctx, unsigned char* buf, size_t size)
494 {
495  SOCK sock = ((SNcbiSSLctx*) ctx)->sock;
496  FSSLPull pull = s_Pull;
497  EIO_Status status;
498 
499  if (pull) {
500  size_t x_read = 0;
501  status = pull(sock, buf, size, &x_read, x_IfToLog());
502  if (x_read > 0 || status == eIO_Success/*&& x_read==0*/) {
503  assert(status == eIO_Success);
504  assert(x_read <= size);
505  return (int) x_read;
506  }
507  } else
508  status = eIO_NotSupported;
509 
510  return x_StatusToError(status, sock, eIO_Read);
511 }
512 
513 
514 static int x_MbedTlsPush(void* ctx, const unsigned char* data, size_t size)
515 {
516  SOCK sock = ((SNcbiSSLctx*) ctx)->sock;
517  FSSLPush push = s_Push;
518  EIO_Status status;
519 
520  if (push) {
521  ssize_t n_written = 0;
522  do {
523  size_t x_written = 0;
524  status = push(sock, data, size, &x_written, x_IfToLog());
525  if (!x_written) {
526  assert(!size || status != eIO_Success);
527  if (size || status != eIO_Success)
528  goto out;
529  } else {
530  assert(status == eIO_Success);
531  assert(x_written <= size);
532  n_written += (ssize_t) x_written;
533  size -= x_written;
534  data = data + x_written;
535  }
536  } while (size);
537  return (int) n_written;
538  } else
539  status = eIO_NotSupported;
540 
541  out:
542  return x_StatusToError(status, sock, eIO_Write);
543 }
544 
545 
546 static EIO_Status s_MbedTlsRead(void* session, void* buf, size_t n_todo,
547  size_t* n_done, int* error)
548 {
549  EIO_Status status;
550  int x_read;
551 
552  assert(session);
553 
554  x_read = mbedtls_ssl_read((mbedtls_ssl_context*) session,
555  (unsigned char*) buf, n_todo);
556  assert(x_read < 0 || (size_t) x_read <= n_todo);
557 
558  if (x_read <= 0) {
559  status = x_ErrorToStatus(x_read, (mbedtls_ssl_context*) session,
560  eIO_Read);
561  *error = x_read;
562  x_read = 0;
563  } else
564  status = eIO_Success;
565 
566  *n_done = (size_t) x_read;
567  return status;
568 }
569 
570 
571 static EIO_Status x_MbedTlsWrite(void* session, const void* data,
572  size_t n_todo, size_t* n_done, int* error)
573 {
574  EIO_Status status;
575  int x_written;
576 
577  assert(session);
578 
579  x_written = mbedtls_ssl_write((mbedtls_ssl_context*) session,
580  (const unsigned char*) data, n_todo);
581  assert(x_written < 0 || (size_t) x_written <= n_todo);
582 
583  if (x_written <= 0) {
584  status = x_ErrorToStatus(x_written, (mbedtls_ssl_context*) session,
585  eIO_Write);
586  *error = x_written;
587  x_written = 0;
588  } else
589  status = eIO_Success;
590 
591  *n_done = (size_t) x_written;
592  return status;
593 }
594 
595 
596 static EIO_Status s_MbedTlsWrite(void* session, const void* data,
597  size_t n_todo, size_t* n_done, int* error)
598 {
600  ((mbedtls_ssl_context*) session);
601  EIO_Status status;
602 
603  *n_done = 0;
604 
605  do {
606  size_t x_todo = n_todo > max_size ? max_size : n_todo;
607  size_t x_done;
608  status = x_MbedTlsWrite(session, data, x_todo, &x_done, error);
609  assert((status == eIO_Success) == (x_done > 0));
610  assert(status == eIO_Success || *error);
611  assert(x_done <= x_todo);
612  if (status != eIO_Success)
613  break;
614  *n_done += x_done;
615  if (x_todo != x_done)
616  break;
617  n_todo -= x_done;
618  data = (const char*) data + x_done;
619  } while (n_todo);
620 
621  return *n_done ? eIO_Success : status;
622 }
623 
624 
625 /*ARGSUSED*/
626 static EIO_Status s_MbedTlsClose(void* session, int how/*unused*/, int* error)
627 {
628  int x_error;
629 
630  assert(session);
631 
633  CORE_TRACEF(("MbedTlsClose(%p): Enter", session));
634 
635  x_error = mbedtls_ssl_close_notify((mbedtls_ssl_context*) session);
636 
638  CORE_TRACEF(("MbedTlsClose(%p): Leave", session));
639 
640  if (x_error) {
641  *error = x_error;
642  return eIO_Unknown;
643  }
644  return eIO_Success;
645 }
646 
647 
648 static void s_MbedTlsDelete(void* session)
649 {
650  assert(session);
651 
653  CORE_TRACEF(("MbedTlsDelete(%p): Enter", session));
654 
656 
658  CORE_TRACEF(("MbedTlsDelete(%p): Leave", session));
659 
660  free(session);
661 }
662 
663 
665 {
666  EIO_Status status;
667 
668 # ifdef NCBI_THREADS
669  switch (mbedtls_version_check_feature("MBEDTLS_THREADING_C")) {
670  case 0:
671  break;
672  case -1:
673  return eIO_NotSupported;
674  case -2:
675  return eIO_InvalidArg;
676  default:
677  return eIO_Unknown;
678  }
679 # endif /*NCBI_THREADS*/
680 
681 # ifdef MBEDTLS_THREADING_PTHREAD
682  status = eIO_Success;
683 # elif defined(MBEDTLS_THREADING_ALT) && defined(NCBI_THREADS)
684  int locked;
685  MT_LOCK lock = CORE_GetLOCK();
686  if ((locked = MT_LOCK_Do(lock, eMT_Lock)) > 0) {
687  mbedtls_threading_set_alt(mbtls_user_mutex_init,
688  mbtls_user_mutex_deinit,
689  mbtls_user_mutex_lock,
690  mbtls_user_mutex_unlock);
691  MT_LOCK_Do(lock, eMT_Unlock);
692  status = eIO_Success;
693  } else
694  status = !locked ? eIO_Unknown : lock ? eIO_Success : eIO_NotSupported;
695 # elif !defined(NCBI_NO_THREADS) && defined(_MT)
697  "MBEDTLS locking uninited: Unknown threading model");
698  status = eIO_NotSupported;
699 # else
700  status = eIO_Success;
701 # endif
702 
703  return status;
704 }
705 
706 
707 static void x_MbedTlsExit(void)
708 {
709  s_Push = 0;
710  s_Pull = 0;
711 
716  memset(&s_MbedTlsCtrDrbg, 0, sizeof(s_MbedTlsCtrDrbg));
717  memset(&s_MbedTlsEntropy, 0, sizeof(s_MbedTlsEntropy));
718  memset(&s_MbedTlsConf, 0, sizeof(s_MbedTlsConf));
719 # if defined(MBEDTLS_THREADING_ALT) && defined(NCBI_THREADS)
721 # endif /*MBEDTLS_THREADING_ALT && NCBI_THREADS*/
722 }
723 
724 
725 /* NB: Called under a lock */
727 {
728  static const char kMbedTls[] =
729 # ifdef HAVE_LIBMBEDTLS
730  "External "
731 # else
732  "Embedded "
733 # endif /*HAVE_LIBMBEDTLS*/
734  "MBEDTLS";
735  EIO_Status status;
736  char version[80];
737  const char* val;
738  char buf[32];
739  psa_status_t psa_status;
740 
744  ("%s version mismatch: %s headers vs. %s runtime",
745  kMbedTls, MBEDTLS_VERSION_STRING, version));
746  assert(0);
747  }
748 
749  CORE_TRACE("MbedTlsInit(): Enter");
750 
751  if (!pull || !push)
752  return eIO_InvalidArg;
753 
760 #if MBEDTLS_VERSION_MAJOR >= 3
761  /* The above line can otherwise be ineffective. */
764 #endif
765 
766  /* Check CONN_[MBED]TLS_LOGLEVEL or [CONN][MBED]TLS_LOGLEVEL */
768  buf, sizeof(buf),
770  if (!val || !*val) {
772  buf, sizeof(buf),
774  }
775  if (val && *val) {
776  ELOG_Level level;
777  s_MbedTlsLogLevel = atoi(val);
778  if (s_MbedTlsLogLevel) {
781  level = eLOG_Note;
782  } else
783  level = eLOG_Trace;
784  CORE_LOGF_X(6, level, ("%s V%s (LogLevel=%d)",
785  kMbedTls, version, s_MbedTlsLogLevel));
786  }
787 
789  CORE_TRACE("MbedTlsInit(): Go-on");
790 
791  if ((status = x_InitLocking()) != eIO_Success) {
794  memset(&s_MbedTlsConf, 0, sizeof(s_MbedTlsConf));
795  return status;
796  }
797 
800 
802  &s_MbedTlsEntropy, 0, 0) != 0) {
803  x_MbedTlsExit();
804  return eIO_Unknown;
805  }
808 
809  if ((psa_status = psa_crypto_init()) != PSA_SUCCESS) {
811  ("psa_crypto_init failed with status %d", psa_status));
812  return eIO_NotSupported;
813  }
814 
815  s_Pull = pull;
816  s_Push = push;
817 
819  CORE_TRACE("MbedTlsInit(): Leave");
820  return eIO_Success;
821 }
822 
823 
824 /* NB: Called under a lock */
825 static void s_MbedTlsExit(void)
826 {
828  CORE_TRACE("MbedTlsExit(): Enter");
829 
830  x_MbedTlsExit();
831 
832  CORE_TRACE("MbedTlsExit(): Leave");
833 }
834 
835 
836 static const char* s_MbedTlsError(void* session/*unused*/, int error,
837  char* buf, size_t size)
838 {
840  return buf;
841 }
842 
843 #else
844 
845 /*ARGSUSED*/
846 static EIO_Status s_MbedTlsInit(FSSLPull unused_pull, FSSLPush unused_push)
847 {
848  CORE_LOG_X(7, eLOG_Critical, "Unavailable feature MBEDTLS");
849  return eIO_NotSupported;
850 }
851 
852 #endif /*HAVE_LIBMBEDTLS || NCBI_CXX_TOOLKIT*/
853 
854 
856 {
857  static const struct SOCKSSL_struct kMbedTlsOps = {
858  "MBEDTLS"
859  , s_MbedTlsInit
860 #if defined(HAVE_LIBMBEDTLS) || defined(NCBI_CXX_TOOLKIT)
862  , s_MbedTlsOpen
863  , s_MbedTlsRead
867  , s_MbedTlsExit
869 #endif /*HAVE_LIBMBEDTLS || NCBI_CXX_TOOLKIT*/
870  };
871 #if !defined(HAVE_LIBMBEDTLS) && !defined(NCBI_CXX_TOOLKIT)
872  CORE_LOG_X(8, eLOG_Warning, "Unavailable feature MBEDTLS");
873 #endif /*!HAVE_LIBMBEDTLS && !NCBI_CXX_TOOLKIT*/
874  return &kMbedTlsOps;
875 }
876 
877 
878 #define ALIGN2(s, a) ((((s) + ((a) - 1)) / (a)) * (a))
879 #define ALIGN(s) ALIGN2(s, sizeof(double))
880 
881 
882 extern NCBI_CRED NcbiCredMbedTls(void* xcert, void* xpkey)
883 {
884  struct SNcbiCred* cred;
885  struct SNcbiMbedTlsCred* xcred;
886  size_t size = ALIGN(sizeof(*cred));
887  if (xcert && xpkey) {
888  size <<= 1;
889  size += sizeof(*xcred);
890  }
891  cred = (NCBI_CRED) calloc(1, size);
892  if (cred) {
893  cred->type = eNcbiCred_MbedTls;
894  if (xcert && xpkey) {
895  xcred = (struct SNcbiMbedTlsCred*)
896  ((char*) cred + 2*ALIGN(sizeof(*cred)));
897  xcred->cert = (mbedtls_x509_crt*) xcert;
898  xcred->pkey = (mbedtls_pk_context*) xpkey;
899  cred->data = xcred;
900  }
901  }
902  return cred;
903 }
904 
905 
906 #if defined(HAVE_LIBMBEDTLS) || defined(NCBI_CXX_TOOLKIT)
907 
909 {
910  if (cred->type / 100 == eNcbiCred_MbedTls / 100 && !(cred->type % 100)) {
911  struct SNcbiMbedTlsCred* xcred = (struct SNcbiMbedTlsCred*) cred->data;
912  mbedtls_x509_crt_free(xcred->cert);
913  mbedtls_pk_free (xcred->pkey);
914  memset(xcred, 0, sizeof(*xcred));
915  } else {
916  char who[80];
917  switch (cred->type / 100) {
918  case eNcbiCred_GnuTls / 100:
919  strcpy(who, "GNUTLS");
920  break;
921  case eNcbiCred_MbedTls / 100:
922  strcpy(who, "MBEDTLS");
923  break;
924  default:
925  sprintf(who, "TLS 0x%08X", cred->type);
926  break;
927  }
929  ("Deleting unknown certificate credentials (%s/%u)",
930  who, cred->type % 100));
931  assert(0);
932  }
933  cred->type = (ENcbiCred) 0;
934  cred->data = 0;
935  free(cred);
936 }
937 
938 
940  size_t certsz,
941  const void* pkey,
942  size_t pkeysz)
943 {
944  struct SNcbiCred* ncbi_cred;
945  struct SNcbiMbedTlsCred* xcred;
946  const size_t size = (2*ALIGN(sizeof(*ncbi_cred))
947  + ALIGN(sizeof(*xcred))
948  + ALIGN(sizeof(*xcred->cert))
949  + sizeof(*xcred->pkey));
950  CORE_DEBUG_ARG(char tmp[1024];)
951  char errbuf[80];
952  int err;
953 
954  if (!(ncbi_cred = (NCBI_CRED) calloc(1, size))) {
955  CORE_LOGF_ERRNO_X(10, eLOG_Error, errno,
956  ("Cannot allocate NCBI_CRED (%lu bytes)",
957  (unsigned long) size));
958  return 0;
959  }
960 
961  xcred = (struct SNcbiMbedTlsCred*)
962  ((char*) ncbi_cred + 2*ALIGN(sizeof(*ncbi_cred)));
963  xcred->cert = (mbedtls_x509_crt*)
964  ((char*) xcred + ALIGN(sizeof(*xcred)));
965  xcred->pkey = (mbedtls_pk_context*)
966  ((char*) xcred->cert + ALIGN(sizeof(*xcred->cert)));
967  ncbi_cred->type = eNcbiCred_MbedTls;
968  ncbi_cred->data = xcred;
969 
970  /* these are not technically necessary as they just zero up the memory */
971  mbedtls_x509_crt_init(xcred->cert);
972  mbedtls_pk_init (xcred->pkey);
973 
974  err = mbedtls_x509_crt_parse(xcred->cert,
975  (const unsigned char*) cert, certsz ? certsz
976  : strlen((const char*) cert) + 1);
977  if (err) {
978  mbedtls_strerror(err, errbuf, sizeof(errbuf) - 1);
979  CORE_LOG_ERRNO_EXX(11, eLOG_Error, err, errbuf,
980  "mbedTLS cannot parse X.509 certificate");
981  goto out;
982  }
984  "", xcred->cert));
985  CORE_TRACEF(("Certificate loaded%s%s",
986  err > 0 ? ":\n" : "",
987  err > 0 ? tmp : ""));
988 
989  err = mbedtls_pk_parse_key(xcred->pkey,
990  (const unsigned char*) pkey, pkeysz ? pkeysz
991  : strlen((const char*) pkey) + 1, 0, 0
992 #if MBEDTLS_VERSION_MAJOR >= 3
994 #endif
995  );
996  if (err) {
997  mbedtls_strerror(err, errbuf, sizeof(errbuf) - 1);
998  CORE_LOG_ERRNO_EXX(12, eLOG_Error, err, errbuf,
999  "mbedTLS cannot parse private key");
1000  goto out;
1001  }
1002  CORE_TRACEF(("Private key loaded: %s",
1003  mbedtls_pk_get_name(xcred->pkey)));
1004 
1005  return ncbi_cred;
1006 
1007  out:
1009  return 0;
1010 }
1011 
1012 #endif /*HAVE_LIBMBEDTLS || NCBI_CXX_TOOLKIT*/
Platform Security Architecture cryptography module.
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
CS_CONTEXT * ctx
Definition: t0006.c:12
static char tmp[3200]
Definition: utf8.c:42
char data[12]
Definition: iconv.c:80
SOCKSSL NcbiSetupMbedTls(void)
Explicitly setup mbedTLS library to support SSL in ncbi_socket.h[pp].
Definition: ncbi_mbedtls.c:855
#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:7459
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:882
@ 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
int32_t psa_status_t
Function return status.
Definition: crypto_types.h:59
#define PSA_SUCCESS
The action was completed successfully.
Definition: crypto_values.h:57
psa_status_t psa_crypto_init(void)
Library initialization.
FILE * file
char * buf
int len
static const CS_INT unused
Definition: long_binary.c:20
#define MBEDTLS_VERSION_STRING
Definition: build_info.h:37
#define MBEDTLS_VERSION_MAJOR
The version number x.y.z is split into three parts.
Definition: build_info.h:27
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:300
void NcbiDeleteMbedTlsCertCredentials(NCBI_CRED cred)
Definition: ncbi_mbedtls.c:908
static void x_MbedTlsExit(void)
Definition: ncbi_mbedtls.c:707
static void s_MbedTlsExit(void)
Definition: ncbi_mbedtls.c:825
static EIO_Status s_MbedTlsOpen(void *session, int *error, char **desc)
Definition: ncbi_mbedtls.c:420
NCBI_CRED NcbiCreateMbedTlsCertCredentials(const void *cert, size_t certsz, const void *pkey, size_t pkeysz)
Definition: ncbi_mbedtls.c:939
static EIO_Status x_MbedTlsWrite(void *session, const void *data, size_t n_todo, size_t *n_done, int *error)
Definition: ncbi_mbedtls.c:571
static EIO_Status s_MbedTlsRead(void *session, void *buf, size_t size, size_t *done, int *error)
Definition: ncbi_mbedtls.c:546
static int x_MbedTlsPull(void *, unsigned char *, size_t)
Definition: ncbi_mbedtls.c:493
static volatile int s_MbedTlsLogLevel
Definition: ncbi_mbedtls.c:171
static volatile FSSLPull s_Pull
Definition: ncbi_mbedtls.c:175
static EIO_Status s_MbedTlsInit(FSSLPull pull, FSSLPush push)
Definition: ncbi_mbedtls.c:726
static mbedtls_ssl_config s_MbedTlsConf
Definition: ncbi_mbedtls.c:174
static EIO_Status s_MbedTlsClose(void *session, int how, int *error)
Definition: ncbi_mbedtls.c:626
#define NCBI_NOTSUPPORTED
Definition: ncbi_mbedtls.c:62
static mbedtls_entropy_context s_MbedTlsEntropy
Definition: ncbi_mbedtls.c:172
static EIO_Status x_RetryStatus(SOCK sock, EIO_Event direction)
Definition: ncbi_mbedtls.c:198
static const char * s_MbedTlsError(void *session, int error, char *buf, size_t size)
Definition: ncbi_mbedtls.c:836
static int x_IfToLog(void)
Definition: ncbi_mbedtls.c:487
static void s_MbedTlsDelete(void *session)
Definition: ncbi_mbedtls.c:648
static volatile FSSLPush s_Push
Definition: ncbi_mbedtls.c:176
static EIO_Status x_InitLocking(void)
Definition: ncbi_mbedtls.c:664
static EIO_Status x_ErrorToStatus(int error, mbedtls_ssl_context *session, EIO_Event direction)
Definition: ncbi_mbedtls.c:216
static EIO_Status s_MbedTlsWrite(void *session, const void *data, size_t size, size_t *done, int *error)
Definition: ncbi_mbedtls.c:596
static void x_MbedTlsLogger(void *data, int level, const char *file, int line, const char *message)
Definition: ncbi_mbedtls.c:180
static int x_MbedTlsPush(void *, const unsigned char *, size_t)
Definition: ncbi_mbedtls.c:514
static mbedtls_ctr_drbg_context s_MbedTlsCtrDrbg
Definition: ncbi_mbedtls.c:173
#define ALIGN(s)
Definition: ncbi_mbedtls.c:879
static void * s_MbedTlsCreate(ESOCK_Side side, SNcbiSSLctx *ctx, int *error)
Definition: ncbi_mbedtls.c:359
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_LOG_X(subcode, level, message)
Definition: ncbi_priv.h:146
#define SOCK_ENOTCONN
Definition: ncbi_socketp.h:83
#define SOCK_EINTR
Definition: ncbi_socketp.h:75
int ssize_t
Definition: ncbiconf_msvc.h:93
#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_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:48
#define MBEDTLS_ERR_NET_CONN_RESET
Connection was reset by peer.
Definition: net_sockets.h:52
#define MBEDTLS_ERR_NET_SEND_FAILED
Sending information through the socket failed.
Definition: net_sockets.h:50
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.
#define MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED
The requested feature is not supported by the platform.
Definition: error.h:105
void mbedtls_strerror(int errnum, char *buffer, size_t buflen)
Translate an Mbed TLS error code into a string representation.
Run-time version information.
#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:149
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:299
const char * mbedtls_ssl_get_version(const mbedtls_ssl_context *ssl)
Return the current TLS version.
#define MBEDTLS_SSL_IS_CLIENT
Definition: ssl.h:285
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:143
@ MBEDTLS_SSL_VERSION_TLS1_2
Definition: ssl.h:1216
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.
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_get_max_out_record_payload(const mbedtls_ssl_context *ssl)
Return the current maximum outgoing record payload in bytes.
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:51
#define MBEDTLS_ERR_SSL_WANT_WRITE
Connection requires a write call.
Definition: ssl.h:141
#define MBEDTLS_ERR_SSL_WANT_READ
No data of requested type currently available on underlying transport.
Definition: ssl.h:139
#define MBEDTLS_SSL_IS_SERVER
Definition: ssl.h:286
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:57
void mbedtls_ssl_config_init(mbedtls_ssl_config *conf)
Initialize an SSL configuration context Just makes the context ready for mbedtls_ssl_config_defaults(...
static void mbedtls_ssl_conf_max_tls_version(mbedtls_ssl_config *conf, mbedtls_ssl_protocol_version tls_version)
Set the maximum supported version sent from the client side and/or accepted at the server side.
Definition: ssl.h:4301
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:80
#define MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE
A fatal alert message was received from our peer.
Definition: ssl.h:76
#define MBEDTLS_SSL_TRANSPORT_STREAM
Definition: ssl.h:268
#define MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE
The requested feature is not available.
Definition: ssl.h:49
#define MBEDTLS_ERR_SSL_INTERNAL_ERROR
Internal error (eg, unexpected failure in lower-level module)
Definition: ssl.h:128
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:327
ENcbiCred type
Definition: ncbi_connssl.h:53
void * data
Definition: ncbi_connssl.h:54
mbedtls_x509_crt * cert
Definition: ncbi_mbedtls.c:74
mbedtls_pk_context * pkey
Definition: ncbi_mbedtls.c:75
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:170
Entropy context structure.
Definition: entropy.h:105
Public key container.
Definition: pk.h:220
SSL/TLS configuration to be shared between mbedtls_ssl_context structures.
Definition: ssl.h:1411
const mbedtls_ssl_config * MBEDTLS_PRIVATE(conf)
Container for an X.509 certificate.
Definition: x509_crt.h:41
Threading abstraction layer.
#define MBEDTLS_ERR_THREADING_MUTEX_ERROR
Locking / unlocking / free failed with error code.
Definition: threading.h:25
#define MBEDTLS_ERR_THREADING_BAD_INPUT_DATA
Bad input parameters to function.
Definition: threading.h:23
done
Definition: token1.c:1
void free(voidpf ptr)
voidp malloc(uInt size)
voidp calloc(uInt items, uInt size)
Modified on Mon May 20 05:04:53 2024 by modify_doxy.py rev. 669887