1 /* $Id: ncbi_gnutls.c,v 1.3 2016/10/13 20:49:14 fukanchi Exp $
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 * GNUTLS 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 <connect/ncbi_connutil.h>
37 #include <connect/ncbi_gnutls.h>
38 #include <stdlib.h>
39
40 #ifdef HAVE_LIBGNUTLS
41
42 # include <gnutls/gnutls.h>
43
44 # if defined(ENOTSUP)
45 # define NCBI_NOTSUPPORTED ENOTSUP
46 # elif defined(ENOSYS)
47 # define NCBI_NOTSUPPORTED ENOSYS
48 # else
49 # define NCBI_NOTSUPPORTED EINVAL
50 # endif /*not implemented*/
51
52 # ifdef HAVE_LIBGCRYPT
53
54 # include <gcrypt.h>
55
56 # if defined(NCBI_POSIX_THREADS)
57
58 # include <pthread.h>
59 # ifdef __cplusplus
60 extern "C" {
61 # endif /*__cplusplus*/
62 GCRY_THREAD_OPTION_PTHREAD_IMPL;
63 # ifdef __cplusplus
64 } /* extern "C" */
65 # endif /*__cplusplus*/
66
67 # elif defined(NCBI_THREADS)
68
69 # ifdef __cplusplus
70 extern "C" {
71 # endif /*__cplusplus*/
gcry_user_mutex_init(void ** lock)72 static int gcry_user_mutex_init(void** lock)
73 {
74 return !(*lock = CORE_GetLOCK()) ? NCBI_NOTSUPPORTED : 0;
75 }
gcry_user_mutex_destroy(void ** lock)76 static int gcry_user_mutex_destroy(void** lock)
77 {
78 *lock = 0;
79 return 0;
80 }
gcry_user_mutex_lock(void ** lock)81 static int gcry_user_mutex_lock(void** lock)
82 {
83 return MT_LOCK_Do((MT_LOCK)(*lock), eMT_Lock) > 0 ? 0 : NCBI_NOTSUPPORTED;
84 }
gcry_user_mutex_unlock(void ** lock)85 static int gcry_user_mutex_unlock(void** lock)
86 {
87 return MT_LOCK_Do((MT_LOCK)(*lock), eMT_Unlock) ? 0 : NCBI_NOTSUPPORTED;
88 }
89 static struct gcry_thread_cbs gcry_threads_user = {
90 GCRY_THREAD_OPTION_USER, NULL/*gcry_user_init*/,
91 gcry_user_mutex_init, gcry_user_mutex_destroy,
92 gcry_user_mutex_lock, gcry_user_mutex_unlock,
93 NULL/*all other fields NULL-inited*/
94 };
95 # ifdef __cplusplus
96 } /* extern "C" */
97 # endif /*__cplusplus*/
98
99 # endif /*NCBI_POSIX_THREADS*/
100
101 # endif /*HAVE_LIBGCRYPT*/
102
103 # ifdef __cplusplus
104 extern "C" {
105 # endif /*__cplusplus*/
106
107 static EIO_Status s_GnuTlsInit (FSSLPull pull, FSSLPush push);
108 static void* s_GnuTlsCreate(ESOCK_Side side, SOCK sock,
109 NCBI_CRED cred, int* error);
110 static EIO_Status s_GnuTlsOpen (void* session, int* error, char** desc);
111 static EIO_Status s_GnuTlsRead (void* session, void* buf, size_t size,
112 size_t* done, int* error);
113 static EIO_Status s_GnuTlsWrite (void* session, const void* data, size_t size,
114 size_t* done, int* error);
115 static EIO_Status s_GnuTlsClose (void* session, int how, int* error);
116 static void s_GnuTlsDelete(void* session);
117 static void s_GnuTlsExit (void);
118 static const char* s_GnuTlsError (void* session, int error);
119
120 static void x_GnuTlsLogger(int level, const char* message);
121 static ssize_t x_GnuTlsPull (gnutls_transport_ptr_t, void*, size_t);
122 static ssize_t x_GnuTlsPush (gnutls_transport_ptr_t, const void*, size_t);
123
124 # ifdef __cplusplus
125 }
126 # endif /*__cplusplus*/
127
128
129 # if LIBGNUTLS_VERSION_NUMBER < 0x030306
130 static const int kGnuTlsCertPrio[] = {
131 GNUTLS_CRT_X509,
132 /*GNUTLS_CRT_OPENPGP,*/
133 0
134 };
135 static const int kGnuTlsCompPrio[] = {
136 GNUTLS_COMP_ZLIB,
137 GNUTLS_COMP_NULL,
138 0
139 };
140 # endif /*LIBGNUTLS_VERSION_NUMBER<3.3.6*/
141
142
143 static int s_GnuTlsLogLevel;
144 static gnutls_anon_client_credentials_t s_GnuTlsCredAnon;
145 static gnutls_certificate_credentials_t s_GnuTlsCredCert;
146 static FSSLPull s_Pull;
147 static FSSLPush s_Push;
148
149
x_GnuTlsLogger(int level,const char * message)150 static void x_GnuTlsLogger(int level, const char* message)
151 {
152 /* do some basic filtering and EOL cut-offs */
153 int len = message ? strlen(message) : 0;
154 if (!len || *message == '\n')
155 return;
156 if (strncasecmp(message, "ASSERT: ", 8) == 0)
157 return;
158 if (message[len - 1] == '\n')
159 len--;
160 CORE_LOGF(eLOG_Note, ("GNUTLS%d: %.*s", level, len, message));
161 }
162
163
164 # ifdef __GNUC__
165 inline
166 # endif /*__GNUC__*/
x_RetryStatus(gnutls_session_t session,EIO_Event direction)167 static EIO_Status x_RetryStatus(gnutls_session_t session, EIO_Event direction)
168 {
169 SOCK sock = (SOCK) gnutls_session_get_ptr(session);
170 EIO_Status status;
171 if (direction == eIO_Open) {
172 EIO_Status r_status = SOCK_Status(sock, eIO_Read);
173 EIO_Status w_status = SOCK_Status(sock, eIO_Write);
174 status = r_status > w_status ? r_status : w_status;
175 } else
176 status = SOCK_Status(sock, direction);
177 return status == eIO_Success ? eIO_Timeout : status;
178 }
179
180
181 # ifdef __GNUC__
182 inline
183 # endif /*__GNUC__*/
x_ErrorToStatus(int * error,gnutls_session_t session,EIO_Event direction)184 static EIO_Status x_ErrorToStatus(int* error,
185 gnutls_session_t session,EIO_Event direction)
186 {
187 EIO_Status status;
188 SOCK sock = (SOCK) gnutls_transport_get_ptr(session);
189
190 assert(error && *error <= 0);
191
192 if (!*error)
193 return eIO_Success;
194 else if (*error == GNUTLS_E_AGAIN)
195 status = x_RetryStatus(session, direction);
196 else if (*error == GNUTLS_E_INTERRUPTED)
197 status = eIO_Interrupt;
198 else if (*error == GNUTLS_E_WARNING_ALERT_RECEIVED) {
199 status = eIO_Unknown;
200 *error = GNUTLS_E_APPLICATION_ERROR_MAX - gnutls_alert_get(session);
201 }
202 else if (*error == GNUTLS_E_FATAL_ALERT_RECEIVED) {
203 status = eIO_Closed;
204 *error = GNUTLS_E_APPLICATION_ERROR_MAX - gnutls_alert_get(session);
205 }
206 else if (*error == GNUTLS_E_PULL_ERROR
207 && sock->r_status != eIO_Success
208 && sock->r_status != eIO_Unknown) {
209 status = sock->r_status;
210 }
211 else if (*error == GNUTLS_E_PUSH_ERROR
212 && sock->w_status != eIO_Success
213 && sock->w_status != eIO_Unknown) {
214 status = sock->w_status;
215 }
216 else if (gnutls_error_is_fatal(*error))
217 status = eIO_Closed;
218 else
219 status = eIO_Unknown;
220 #if 0
221 CORE_TRACEF(("GNUTLS error %d -> CONNECT status %s",
222 *error, IO_StatusStr(status)));
223 #endif
224 return status;
225 }
226
227
228 # ifdef __GNUC__
229 inline
230 # endif /*__GNUC__*/
x_IsTimeout(SOCK sock,EIO_Event direction)231 static int/*bool*/ x_IsTimeout(SOCK sock, EIO_Event direction)
232 {
233 int retval;
234 switch (direction) {
235 case eIO_Read:
236 retval = !sock->r_tv_set || (sock->r_tv.tv_sec | sock->r_tv.tv_usec);
237 break;
238 case eIO_Write:
239 retval = !sock->w_tv_set || (sock->w_tv.tv_sec | sock->w_tv.tv_usec);
240 break;
241 default:
242 retval = 0;
243 assert(0);
244 break;
245 }
246 return retval;
247 }
248
249
250 # ifdef __GNUC__
251 inline
252 # endif /*__GNUC__*/
x_StatusToError(EIO_Status status,SOCK sock,EIO_Event direction)253 static int x_StatusToError(EIO_Status status, SOCK sock, EIO_Event direction)
254 {
255 int error;
256
257 assert(status != eIO_Success);
258
259 switch (status) {
260 case eIO_Timeout:
261 error = x_IsTimeout(sock, direction) ? SOCK_ETIMEDOUT : EAGAIN;
262 break;
263 case eIO_Closed:
264 error = SOCK_ENOTCONN;
265 break;
266 case eIO_Interrupt:
267 error = SOCK_EINTR;
268 break;
269 case eIO_NotSupported:
270 error = NCBI_NOTSUPPORTED;
271 break;
272 case eIO_Unknown:
273 error = 0/*keep*/;
274 break;
275 default:
276 /*NB:eIO_InvalidArg*/
277 error = EINVAL;
278 break;
279 }
280 #if 0
281 CORE_TRACEF(("CONNECT status %s -> %s %d", IO_StatusStr(status),
282 error ? "error" : "errno",
283 error ? error : errno));
284 #endif
285 return error;
286 }
287
288
s_GnuTlsCreate(ESOCK_Side side,SOCK sock,NCBI_CRED cred,int * error)289 static void* s_GnuTlsCreate(ESOCK_Side side, SOCK sock,
290 NCBI_CRED cred, int* error)
291 {
292 gnutls_transport_ptr_t ptr = (gnutls_transport_ptr_t) sock;
293 gnutls_connection_end_t end = (side == eSOCK_Client
294 ? GNUTLS_CLIENT
295 : GNUTLS_SERVER);
296 gnutls_certificate_credentials_t xcred;
297 gnutls_anon_client_credentials_t acred;
298 gnutls_session_t session;
299 char val[128];
300 int err;
301
302 if (end == GNUTLS_SERVER) {
303 /*FIXME: not yet supported*/
304 *error = 0;
305 return 0;
306 }
307
308 CORE_LOCK_READ;
309 xcred = s_GnuTlsCredCert;
310 acred = s_GnuTlsCredAnon;
311 CORE_UNLOCK;
312
313 if (!acred
314 || (cred && (cred->type != eNcbiCred_GnuTls || !cred->data))) {
315 /*FIXME: there's a NULL(data)-terminated array of credentials */
316 *error = 0;
317 return 0;
318 }
319
320 if ((*error = gnutls_init(&session, end)) != GNUTLS_E_SUCCESS/*0*/)
321 return 0;
322
323 ConnNetInfo_GetValue(0, "GNUTLS_PRIORITY", val, sizeof(val), 0);
324
325 if ((err = gnutls_set_default_priority(session)) != 0 ||
326 # if LIBGNUTLS_VERSION_NUMBER >= 0x020200
327 ( *val &&
328 (err = gnutls_priority_set_direct(session, val, 0)) != 0) ||
329 # endif /*LIBGNUTLS_VERSION_NUMBER>=2.2.0*/
330 # if LIBGNUTLS_VERSION_NUMBER < 0x030306
331 (!*val &&
332 (err = gnutls_compression_set_priority(session,
333 kGnuTlsCompPrio)) != 0) ||
334 (!*val &&
335 (err = gnutls_certificate_type_set_priority(session,
336 kGnuTlsCertPrio)) != 0) ||
337 # endif /*LIBGNUTLS_VERSION_NUMBER<3.3.6*/
338 (err = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE,
339 cred ? cred->data : xcred)) != 0 ||
340 (err = gnutls_credentials_set(session, GNUTLS_CRD_ANON, acred))!= 0) {
341 gnutls_deinit(session);
342 *error = err;
343 return 0;
344 }
345
346 gnutls_transport_set_pull_function(session, x_GnuTlsPull);
347 gnutls_transport_set_push_function(session, x_GnuTlsPush);
348 gnutls_transport_set_ptr(session, ptr);
349 gnutls_session_set_ptr(session, sock);
350
351 # if LIBGNUTLS_VERSION_NUMBER >= 0x030000
352 gnutls_handshake_set_timeout(session, 0);
353 # endif /*LIBGNUTLS_VERSION_NUMBER>=3.0.0*/
354
355 return session;
356 }
357
358
s_GnuTlsOpen(void * session,int * error,char ** desc)359 static EIO_Status s_GnuTlsOpen(void* session, int* error, char** desc)
360 {
361 EIO_Status status;
362 int x_error;
363
364 *desc = 0;
365
366 do {
367 x_error = gnutls_handshake((gnutls_session_t) session);
368 } while (x_error && x_error == GNUTLS_E_REHANDSHAKE);
369
370 if (x_error < 0) {
371 status = x_ErrorToStatus(&x_error,
372 (gnutls_session_t) session, eIO_Open);
373 *error = x_error;
374 } else {
375 # if LIBGNUTLS_VERSION_NUMBER >= 0x030110
376 char* temp = gnutls_session_get_desc(session);
377 if (temp) {
378 *desc = strdup(temp);
379 gnutls_free(temp);
380 }
381 # endif /*LIBGNUTLS_VERSION_NUMBER<3.1.10*/
382 status = eIO_Success;
383 }
384 return status;
385 }
386
387
388 #ifdef __GNUC__
389 inline
390 #endif /*__GNUC__*/
x_IfToLog(void)391 static int x_IfToLog(void)
392 {
393 return 7 < s_GnuTlsLogLevel && s_GnuTlsLogLevel <= 10 ? 1/*T*/ : 0/*F*/;
394 }
395
396
397 /*ARGSUSED*/
x_set_errno(gnutls_session_t session,int error)398 static void x_set_errno(gnutls_session_t session, int error)
399 {
400 # if LIBGNUTLS_VERSION_NUMBER >= 0x010504
401 gnutls_transport_set_errno(session, error);
402 # else
403 if (error)
404 errno = error;
405 # endif /*LIBGNUTLS_VERSION>=1.5.4*/
406 }
407
408
x_GnuTlsPull(gnutls_transport_ptr_t ptr,void * buf,size_t size)409 static ssize_t x_GnuTlsPull(gnutls_transport_ptr_t ptr,
410 void* buf, size_t size)
411 {
412 int x_error;
413 EIO_Status status;
414 SOCK sock = (SOCK) ptr;
415 FSSLPull pull = s_Pull;
416
417 if (pull) {
418 size_t x_read = 0;
419 status = pull(sock, buf, size, &x_read, x_IfToLog());
420 if (x_read > 0 || status == eIO_Success/*&& x_read==0*/) {
421 assert(status == eIO_Success);
422 assert(x_read <= size);
423 x_set_errno((gnutls_session_t) sock->session, 0);
424 return x_read;
425 }
426 } else
427 status = eIO_NotSupported;
428
429 x_error = x_StatusToError(status, sock, eIO_Read);
430 if (x_error)
431 x_set_errno((gnutls_session_t) sock->session, x_error);
432 return -1;
433 }
434
435
x_GnuTlsPush(gnutls_transport_ptr_t ptr,const void * data,size_t size)436 static ssize_t x_GnuTlsPush(gnutls_transport_ptr_t ptr,
437 const void* data, size_t size)
438 {
439 int x_error;
440 EIO_Status status;
441 SOCK sock = (SOCK) ptr;
442 FSSLPush push = s_Push;
443
444 if (push) {
445 ssize_t n_written = 0;
446 do {
447 size_t x_written = 0;
448 status = push(sock, data, size, &x_written, x_IfToLog());
449 if (!x_written) {
450 assert(!size || status != eIO_Success);
451 if (size || status != eIO_Success)
452 goto out;
453 } else {
454 assert(status == eIO_Success);
455 assert(x_written <= size);
456 n_written += x_written;
457 size -= x_written;
458 data = (const char*) data + x_written;
459 }
460 } while (size);
461 x_set_errno((gnutls_session_t) sock->session, 0);
462 return n_written;
463 } else
464 status = eIO_NotSupported;
465
466 out:
467 x_error = x_StatusToError(status, sock, eIO_Write);
468 if (x_error)
469 x_set_errno((gnutls_session_t) sock->session, x_error);
470 return -1;
471 }
472
473
s_GnuTlsRead(void * session,void * buf,size_t n_todo,size_t * n_done,int * error)474 static EIO_Status s_GnuTlsRead(void* session, void* buf, size_t n_todo,
475 size_t* n_done, int* error)
476 {
477 EIO_Status status;
478 int x_read;
479
480 assert(session);
481
482 x_read = gnutls_record_recv((gnutls_session_t) session, buf, n_todo);
483 assert(x_read < 0 || x_read <= n_todo);
484
485 if (x_read <= 0) {
486 status = x_ErrorToStatus(&x_read,
487 (gnutls_session_t) session, eIO_Read);
488 *error = x_read;
489 x_read = 0;
490 } else
491 status = eIO_Success;
492
493 *n_done = x_read;
494 return status;
495 }
496
497
x_GnuTlsWrite(void * session,const void * data,size_t n_todo,size_t * n_done,int * error)498 static EIO_Status x_GnuTlsWrite(void* session, const void* data, size_t n_todo,
499 size_t* n_done, int* error)
500 {
501 EIO_Status status;
502 int x_written;
503
504 assert(session);
505
506 x_written = gnutls_record_send((gnutls_session_t) session, data, n_todo);
507 assert(x_written < 0 || x_written <= n_todo);
508
509 if (x_written <= 0) {
510 status = x_ErrorToStatus(&x_written,
511 (gnutls_session_t) session, eIO_Write);
512 *error = x_written;
513 x_written = 0;
514 } else
515 status = eIO_Success;
516
517 *n_done = x_written;
518 return status;
519 }
520
521
s_GnuTlsWrite(void * session,const void * data,size_t n_todo,size_t * n_done,int * error)522 static EIO_Status s_GnuTlsWrite(void* session, const void* data, size_t n_todo,
523 size_t* n_done, int* error)
524 {
525 size_t max_size = gnutls_record_get_max_size((gnutls_session_t) session);
526 EIO_Status status;
527
528 *n_done = 0;
529
530 do {
531 size_t x_todo = n_todo > max_size ? max_size : n_todo;
532 size_t x_done;
533 status = x_GnuTlsWrite(session, data, x_todo, &x_done, error);
534 assert((status == eIO_Success) == (x_done > 0));
535 assert(status == eIO_Success || *error);
536 assert(x_done <= x_todo);
537 if (status != eIO_Success)
538 break;
539 *n_done += x_done;
540 if (x_todo != x_done)
541 break;
542 n_todo -= x_done;
543 data = (const char*) data + x_done;
544 } while (n_todo);
545
546 return *n_done ? eIO_Success : status;
547 }
548
549
s_GnuTlsClose(void * session,int how,int * error)550 static EIO_Status s_GnuTlsClose(void* session, int how, int* error)
551 {
552 int x_error;
553
554 assert(session);
555
556 x_error = gnutls_bye((gnutls_session_t) session,
557 how == SOCK_SHUTDOWN_RDWR
558 ? GNUTLS_SHUT_RDWR
559 : GNUTLS_SHUT_WR);
560 if (x_error != GNUTLS_E_SUCCESS) {
561 *error = x_error;
562 return eIO_Unknown;
563 }
564
565 return eIO_Success;
566 }
567
568
s_GnuTlsDelete(void * session)569 static void s_GnuTlsDelete(void* session)
570 {
571 assert(session);
572
573 gnutls_deinit((gnutls_session_t) session);
574 }
575
576
577 /* NB: Called under a lock */
s_GnuTlsInit(FSSLPull pull,FSSLPush push)578 static EIO_Status s_GnuTlsInit(FSSLPull pull, FSSLPush push)
579 {
580 gnutls_anon_client_credentials_t acred;
581 gnutls_certificate_credentials_t xcred;
582 const char* version;
583 const char* val;
584 char buf[32];
585
586 assert(!s_GnuTlsCredAnon);
587
588 version = gnutls_check_version(0);
589 if (strcasecmp(GNUTLS_VERSION, version) != 0) {
590 CORE_LOGF(eLOG_Critical,
591 ("GNUTLS version mismatch: %s headers vs. %s runtime",
592 GNUTLS_VERSION, version));
593 assert(0);
594 }
595
596 val = ConnNetInfo_GetValue(0, "GNUTLS_LOGLEVEL", buf, sizeof(buf), 0);
597 CORE_LOCK_READ;
598 if (!val || !*val)
599 val = getenv("GNUTLS_DEBUG_LEVEL");
600 if (val && *val) {
601 s_GnuTlsLogLevel = atoi(val);
602 CORE_UNLOCK;
603 if (s_GnuTlsLogLevel) {
604 gnutls_global_set_log_function(x_GnuTlsLogger);
605 if (val == buf)
606 gnutls_global_set_log_level(s_GnuTlsLogLevel);
607 CORE_LOGF(eLOG_Note, ("GNUTLS V%s (Loglevel=%d)",
608 version, s_GnuTlsLogLevel));
609 }
610 } else
611 CORE_UNLOCK;
612
613 # ifdef HAVE_LIBGCRYPT
614 # if defined(NCBI_POSIX_THREADS)
615 if (gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread) != 0)
616 goto out;
617 # elif defined(NCBI_THREADS)
618 if (gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_user) != 0)
619 goto out;
620 # elif defined(_MT)
621 CORE_LOG(eLOG_Critical,"LIBGCRYPT uninitialized: Unknown threading model");
622 # endif /*NCBI_POSIX_THREADS*/
623 # endif /*HAVE_LIBGCRYPT*/
624
625 if (!pull || !push || !gnutls_check_version(LIBGNUTLS_VERSION)
626 || gnutls_global_init() != GNUTLS_E_SUCCESS/*0*/) {
627 goto out;
628 }
629 if (gnutls_anon_allocate_client_credentials(&acred) != 0) {
630 gnutls_global_deinit();
631 goto out;
632 }
633 if (gnutls_certificate_allocate_credentials(&xcred) != 0) {
634 gnutls_anon_free_client_credentials(acred);
635 gnutls_global_deinit();
636 goto out;
637 }
638
639 s_GnuTlsCredAnon = acred;
640 s_GnuTlsCredCert = xcred;
641 s_Pull = pull;
642 s_Push = push;
643
644 return eIO_Success;
645
646 out:
647 gnutls_global_set_log_level(s_GnuTlsLogLevel = 0);
648 gnutls_global_set_log_function(0);
649 return eIO_NotSupported;
650 }
651
652
653 /* NB: Called under a lock */
s_GnuTlsExit(void)654 static void s_GnuTlsExit(void)
655 {
656 gnutls_anon_client_credentials_t acred = s_GnuTlsCredAnon;
657 gnutls_certificate_credentials_t xcred = s_GnuTlsCredCert;
658
659 assert(acred);
660
661 s_Push = 0;
662 s_Pull = 0;
663 s_GnuTlsCredCert = 0;
664 s_GnuTlsCredAnon = 0;
665
666 gnutls_certificate_free_credentials(xcred);
667 gnutls_anon_free_client_credentials(acred);
668 gnutls_global_deinit();
669
670 gnutls_global_set_log_level(s_GnuTlsLogLevel = 0);
671 gnutls_global_set_log_function(0);
672 }
673
674
s_GnuTlsError(void * session,int error)675 static const char* s_GnuTlsError(void* session/*unused*/, int error)
676 {
677 /* GNUTLS defines only negative error codes */
678 return error >= 0 ? 0 : error < GNUTLS_E_APPLICATION_ERROR_MAX
679 ? gnutls_alert_get_name(GNUTLS_E_APPLICATION_ERROR_MAX - error)
680 : gnutls_strerror(error);
681 }
682
683
684 #else
685
686
687 /*ARGSUSED*/
s_GnuTlsInit(FSSLPull unused_pull,FSSLPush unused_push)688 static EIO_Status s_GnuTlsInit(FSSLPull unused_pull, FSSLPush unused_push)
689 {
690 CORE_LOG(eLOG_Critical, "Unavailable feature GNUTLS");
691 return eIO_NotSupported;
692 }
693
694
695 #endif /*HAVE_LIBGNUTLS*/
696
697
NcbiSetupGnuTls(void)698 extern SOCKSSL NcbiSetupGnuTls(void)
699 {
700 static const struct SOCKSSL_struct kGnuTlsOps = {
701 s_GnuTlsInit
702 #ifdef HAVE_LIBGNUTLS
703 , s_GnuTlsCreate
704 , s_GnuTlsOpen
705 , s_GnuTlsRead
706 , s_GnuTlsWrite
707 , s_GnuTlsClose
708 , s_GnuTlsDelete
709 , s_GnuTlsExit
710 , s_GnuTlsError
711 #endif /*HAVE_LIBGNUTLS*/
712 };
713 #ifndef HAVE_LIBGNUTLS
714 CORE_LOG(eLOG_Warning, "Unavailable feature GNUTLS");
715 #endif /*!HAVE_LIBGNUTLS*/
716 return &kGnuTlsOps;
717 }
718
719
NcbiCredGnuTls(void * xcred)720 extern NCBI_CRED NcbiCredGnuTls(void* xcred)
721 {
722 struct SNcbiCred* cred = (NCBI_CRED) calloc(xcred ? 2 : 1, sizeof(*cred));
723 if (cred && xcred) {
724 cred->type = eNcbiCred_GnuTls;
725 cred->data = xcred;
726 }
727 return cred;
728 }
729