"Fossies" - the Fresh Open Source Software Archive

Member "msmtp-1.8.17/src/mtls-gnutls.c" (21 Feb 2021, 21465 Bytes) of package /linux/privat/msmtp-1.8.17.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "mtls-gnutls.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 1.8.14_vs_1.8.15.

    1 /*
    2  * mtls-gnutls.c
    3  *
    4  * This file is part of msmtp, an SMTP client, and of mpop, a POP3 client.
    5  *
    6  * Copyright (C) 2000, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011,
    7  * 2012, 2014, 2016, 2018, 2019, 2020
    8  * Martin Lambers <marlam@marlam.de>
    9  *
   10  *   This program is free software; you can redistribute it and/or modify
   11  *   it under the terms of the GNU General Public License as published by
   12  *   the Free Software Foundation; either version 3 of the License, or
   13  *   (at your option) any later version.
   14  *
   15  *   This program is distributed in the hope that it will be useful,
   16  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   17  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   18  *   GNU General Public License for more details.
   19  *
   20  *   You should have received a copy of the GNU General Public License
   21  *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   22  */
   23 
   24 #ifdef HAVE_CONFIG_H
   25 # include "config.h"
   26 #endif
   27 
   28 #include <stdio.h>
   29 #include <string.h>
   30 #include <stdlib.h>
   31 
   32 #include <gnutls/gnutls.h>
   33 #include <gnutls/x509.h>
   34 #include <gnutls/pkcs11.h>
   35 
   36 #ifdef HAVE_LIBIDN
   37 # include <idn2.h>
   38 #endif
   39 
   40 #include "gettext.h"
   41 #define _(string) gettext(string)
   42 #define N_(string) gettext_noop(string)
   43 
   44 #include "xalloc.h"
   45 #include "readbuf.h"
   46 #include "tools.h"
   47 #include "mtls.h"
   48 
   49 
   50 struct mtls_internals_t
   51 {
   52     gnutls_session_t session;
   53     gnutls_certificate_credentials_t cred;
   54 };
   55 
   56 
   57 /*
   58  * mtls_lib_init()
   59  *
   60  * see mtls.h
   61  */
   62 
   63 int mtls_lib_init(char **errstr)
   64 {
   65     /* Library initialization is implicit */
   66     (void)errstr;
   67     return TLS_EOK;
   68 }
   69 
   70 /* Helper function to get a certificate fingerprint because in the long run
   71  * it is probably unwise to expect the size requirements of
   72  * gnutls_x509_crt_get_fingerprint() to be what one would reasonably expect
   73  * them to be. So we have to use a temporary buffer. */
   74 static int mtls_gnutls_get_fingerprint(gnutls_x509_crt_t cert,
   75         gnutls_digest_algorithm_t algo, unsigned char* dest)
   76 {
   77     int e = 0;
   78     size_t size = 0;
   79     size_t real_size = 0;
   80     unsigned char* p = NULL;
   81 
   82     gnutls_x509_crt_get_fingerprint(cert, algo, NULL, &size);
   83     p = xmalloc(size);
   84     if ((e = gnutls_x509_crt_get_fingerprint(cert, algo, p, &size)) != 0) {
   85         free(p);
   86         return e;
   87     }
   88     if (algo == GNUTLS_DIG_SHA256) {
   89         real_size = 32;
   90     } else if (algo == GNUTLS_DIG_SHA) {
   91         real_size = 20;
   92     } else if (algo == GNUTLS_DIG_MD5) {
   93         real_size = 16;
   94     } else {
   95         free(p);
   96         return GNUTLS_E_INTERNAL_ERROR;
   97     }
   98     memcpy(dest, p, real_size);
   99     free(p);
  100     return 0;
  101 }
  102 
  103 
  104 /*
  105  * mtls_cert_info_get()
  106  *
  107  * see mtls.h
  108  */
  109 
  110 int mtls_cert_info_get(mtls_t *mtls, mtls_cert_info_t *tci, char **errstr)
  111 {
  112     const gnutls_datum_t *cert_list;
  113     unsigned int cert_list_size;
  114     gnutls_x509_crt_t cert;
  115     size_t size;
  116     int e;
  117     char *p;
  118     const char *errmsg;
  119 
  120     errmsg = _("cannot get TLS certificate info");
  121     if (!(cert_list =
  122                 gnutls_certificate_get_peers(mtls->internals->session, &cert_list_size))
  123             || cert_list_size == 0)
  124     {
  125         *errstr = xasprintf(_("%s: no certificate was found"), errmsg);
  126         return TLS_ECERT;
  127     }
  128     if (gnutls_x509_crt_init(&cert) != 0)
  129     {
  130         *errstr = xasprintf(_("%s: cannot initialize certificate structure"),
  131                 errmsg);
  132         return TLS_ECERT;
  133     }
  134     if (gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER) != 0)
  135     {
  136         *errstr = xasprintf(_("%s: error parsing certificate"), errmsg);
  137         gnutls_x509_crt_deinit(cert);
  138         return TLS_ECERT;
  139     }
  140 
  141     /* certificate information */
  142     if (mtls_gnutls_get_fingerprint(cert, GNUTLS_DIG_SHA256,
  143                 tci->sha256_fingerprint) != 0)
  144     {
  145         *errstr = xasprintf(_("%s: error getting SHA256 fingerprint"), errmsg);
  146         gnutls_x509_crt_deinit(cert);
  147         return TLS_ECERT;
  148     }
  149     if (mtls_gnutls_get_fingerprint(cert, GNUTLS_DIG_SHA,
  150                 tci->sha1_fingerprint) != 0)
  151     {
  152         *errstr = xasprintf(_("%s: error getting SHA1 fingerprint"), errmsg);
  153         gnutls_x509_crt_deinit(cert);
  154         return TLS_ECERT;
  155     }
  156     if ((tci->activation_time = gnutls_x509_crt_get_activation_time(cert)) < 0)
  157     {
  158         *errstr = xasprintf(_("%s: cannot get activation time"), errmsg);
  159         gnutls_x509_crt_deinit(cert);
  160         return TLS_ECERT;
  161     }
  162     if ((tci->expiration_time = gnutls_x509_crt_get_expiration_time(cert)) < 0)
  163     {
  164         *errstr = xasprintf(_("%s: cannot get expiration time"), errmsg);
  165         gnutls_x509_crt_deinit(cert);
  166         return TLS_ECERT;
  167     }
  168 
  169     /* subject information */
  170     e = gnutls_x509_crt_get_dn(cert, NULL, &size);
  171     if (e == GNUTLS_E_SHORT_MEMORY_BUFFER)
  172     {
  173         p = xmalloc(size);
  174         e = gnutls_x509_crt_get_dn(cert, p, &size);
  175         if (e == 0)
  176         {
  177             tci->subject_info = p;
  178         }
  179         else
  180         {
  181             free(p);
  182         }
  183     }
  184 
  185     /* issuer information */
  186     e = gnutls_x509_crt_get_issuer_dn(cert, NULL, &size);
  187     if (e == GNUTLS_E_SHORT_MEMORY_BUFFER)
  188     {
  189         p = xmalloc(size);
  190         e = gnutls_x509_crt_get_issuer_dn(cert, p, &size);
  191         if (e == 0)
  192         {
  193             tci->issuer_info = p;
  194         }
  195         else
  196         {
  197             free(p);
  198         }
  199     }
  200 
  201     gnutls_x509_crt_deinit(cert);
  202     return TLS_EOK;
  203 }
  204 
  205 
  206 /*
  207  * mtls_check_cert()
  208  *
  209  * If the 'mtls->have_trust_file' flag is set, perform a real verification of
  210  * the peer's certificate. If this succeeds, the connection can be considered
  211  * secure.
  212  * If one of the 'mtls->have_*_fingerprint' flags is
  213  * set, compare the 'mtls->fingerprint' data with the peer certificate's
  214  * fingerprint. If this succeeds, the connection can be considered secure.
  215  * If none of these flags is set, perform only a few sanity checks of the
  216  * peer's certificate. You cannot trust the connection when this succeeds.
  217  * Used error codes: TLS_ECERT
  218  */
  219 
  220 static int mtls_check_cert(mtls_t *mtls, char **errstr)
  221 {
  222     int error_code;
  223     unsigned int status;
  224     const char *error_msg = _("TLS certificate verification failed");
  225 
  226     /* The following fingerprint checking is deprecated and should be removed
  227      * in the next major version. */
  228     if (mtls->have_sha256_fingerprint
  229             || mtls->have_sha1_fingerprint || mtls->have_md5_fingerprint)
  230     {
  231         const gnutls_datum_t *cert_list;
  232         unsigned int cert_list_size;
  233         gnutls_x509_crt_t cert;
  234         unsigned char fingerprint[32];
  235 
  236         /* If one of these matches, we trust the peer and do not perform any
  237          * other checks. */
  238         if (!(cert_list = gnutls_certificate_get_peers(
  239                         mtls->internals->session, &cert_list_size)))
  240         {
  241             *errstr = xasprintf(_("%s: no certificate was found"), error_msg);
  242             return TLS_ECERT;
  243         }
  244         if (gnutls_x509_crt_init(&cert) < 0)
  245         {
  246             *errstr = xasprintf(
  247                     _("%s: cannot initialize certificate structure"),
  248                     error_msg);
  249             return TLS_ECERT;
  250         }
  251         if (gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER)
  252                 < 0)
  253         {
  254             *errstr = xasprintf(_("%s: error parsing certificate %u of %u"),
  255                     error_msg, 0 + 1, cert_list_size);
  256             return TLS_ECERT;
  257         }
  258         if (mtls->have_sha256_fingerprint)
  259         {
  260             if (mtls_gnutls_get_fingerprint(cert, GNUTLS_DIG_SHA256,
  261                         fingerprint) != 0)
  262             {
  263                 *errstr = xasprintf(_("%s: error getting SHA256 fingerprint"),
  264                         error_msg);
  265                 gnutls_x509_crt_deinit(cert);
  266                 return TLS_ECERT;
  267             }
  268             if (memcmp(fingerprint, mtls->fingerprint, 32) != 0)
  269             {
  270                 *errstr = xasprintf(_("%s: the certificate fingerprint "
  271                             "does not match"), error_msg);
  272                 gnutls_x509_crt_deinit(cert);
  273                 return TLS_ECERT;
  274             }
  275         }
  276         else if (mtls->have_sha1_fingerprint)
  277         {
  278             if (mtls_gnutls_get_fingerprint(cert, GNUTLS_DIG_SHA,
  279                         fingerprint) != 0)
  280             {
  281                 *errstr = xasprintf(_("%s: error getting SHA1 fingerprint"),
  282                         error_msg);
  283                 gnutls_x509_crt_deinit(cert);
  284                 return TLS_ECERT;
  285             }
  286             if (memcmp(fingerprint, mtls->fingerprint, 20) != 0)
  287             {
  288                 *errstr = xasprintf(_("%s: the certificate fingerprint "
  289                             "does not match"), error_msg);
  290                 gnutls_x509_crt_deinit(cert);
  291                 return TLS_ECERT;
  292             }
  293         }
  294         else
  295         {
  296             if (mtls_gnutls_get_fingerprint(cert, GNUTLS_DIG_MD5,
  297                         fingerprint) != 0)
  298             {
  299                 *errstr = xasprintf(_("%s: error getting MD5 fingerprint"),
  300                         error_msg);
  301                 gnutls_x509_crt_deinit(cert);
  302                 return TLS_ECERT;
  303             }
  304             if (memcmp(fingerprint, mtls->fingerprint, 16) != 0)
  305             {
  306                 *errstr = xasprintf(_("%s: the certificate fingerprint "
  307                             "does not match"), error_msg);
  308                 gnutls_x509_crt_deinit(cert);
  309                 return TLS_ECERT;
  310             }
  311         }
  312         gnutls_x509_crt_deinit(cert);
  313         return TLS_EOK;
  314     }
  315 
  316     /* Verify the certificate(s). */
  317     if ((error_code = gnutls_certificate_verify_peers3(mtls->internals->session,
  318                     mtls->hostname, &status)) != 0)
  319     {
  320         *errstr = xasprintf("%s: %s", error_msg, gnutls_strerror(error_code));
  321         return TLS_ECERT;
  322     }
  323     if (mtls->have_trust_file && status)
  324     {
  325         gnutls_datum_t txt;
  326         gnutls_certificate_verification_status_print(status,
  327                 GNUTLS_CRT_X509, &txt, 0);
  328         *errstr = xasprintf(_("%s: %s"), error_msg, txt.data);
  329         free(txt.data);
  330         return TLS_ECERT;
  331     }
  332 
  333     return TLS_EOK;
  334 }
  335 
  336 
  337 /*
  338  * mtls_pin_callback()
  339  *
  340  * Passes a PIN to GnuTLS for PKCS11 smart cards or similar
  341  */
  342 static int mtls_pin_callback(void *userdata, int attempt,
  343         const char *token_url, const char *token_label,
  344         unsigned int flags, char *pin, size_t pin_max)
  345 {
  346     (void)attempt;
  347     (void)token_url;
  348     (void)token_label;
  349     (void)flags;
  350 
  351     size_t len;
  352     if (userdata && (len = strlen(userdata)) < pin_max)
  353     {
  354         strcpy(pin, userdata);
  355         return 0;
  356     }
  357     else
  358     {
  359         return 1;
  360     }
  361 }
  362 
  363 
  364 /*
  365  * mtls_init()
  366  *
  367  * see mtls.h
  368  */
  369 
  370 int mtls_init(mtls_t *mtls,
  371         const char *key_file, const char *cert_file, const char *pin,
  372         const char *trust_file, const char *crl_file,
  373         const unsigned char *sha256_fingerprint,
  374         const unsigned char *sha1_fingerprint,
  375         const unsigned char *md5_fingerprint,
  376         int min_dh_prime_bits, const char *priorities,
  377         const char *hostname,
  378         int no_certcheck,
  379         char **errstr)
  380 {
  381     int error_code;
  382 
  383     mtls->internals = xmalloc(sizeof(struct mtls_internals_t));
  384 
  385     if ((error_code = gnutls_init(&mtls->internals->session, GNUTLS_CLIENT)) != 0)
  386     {
  387         *errstr = xasprintf(_("cannot initialize TLS session: %s"),
  388                 gnutls_strerror(error_code));
  389         return TLS_ELIBFAILED;
  390     }
  391     if (priorities)
  392     {
  393         const char *error_pos = NULL;
  394         if ((error_code = gnutls_priority_set_direct(mtls->internals->session,
  395                         priorities, &error_pos)) != 0)
  396         {
  397             if (error_pos)
  398             {
  399                 char *error_pos_str = xasprintf(
  400                         _("error in priority string at position %d"),
  401                         (int)(error_pos - priorities + 1));
  402                 *errstr = xasprintf(
  403                         _("cannot set priorities for TLS session: %s"),
  404                         error_pos_str);
  405                 free(error_pos_str);
  406             }
  407             else
  408             {
  409                 *errstr = xasprintf(
  410                         _("cannot set priorities for TLS session: %s"),
  411                         gnutls_strerror(error_code));
  412             }
  413             gnutls_deinit(mtls->internals->session);
  414             free(mtls->internals);
  415             mtls->internals = NULL;
  416             return TLS_ELIBFAILED;
  417         }
  418     }
  419     else
  420     {
  421         if ((error_code = gnutls_set_default_priority(mtls->internals->session)) != 0)
  422         {
  423             *errstr = xasprintf(_("cannot set default priority for TLS session: "
  424                         "%s"), gnutls_strerror(error_code));
  425             gnutls_deinit(mtls->internals->session);
  426             free(mtls->internals);
  427             mtls->internals = NULL;
  428             return TLS_ELIBFAILED;
  429         }
  430     }
  431     if (min_dh_prime_bits >= 0)
  432     {
  433         gnutls_dh_set_prime_bits(mtls->internals->session, min_dh_prime_bits);
  434     }
  435     if ((error_code = gnutls_certificate_allocate_credentials(&mtls->internals->cred)) < 0)
  436     {
  437         *errstr = xasprintf(
  438                 _("cannot allocate certificate for TLS session: %s"),
  439                 gnutls_strerror(error_code));
  440         gnutls_deinit(mtls->internals->session);
  441         free(mtls->internals);
  442         mtls->internals = NULL;
  443         return TLS_ELIBFAILED;
  444     }
  445     if (key_file && cert_file)
  446     {
  447         gnutls_pkcs11_set_pin_function(mtls_pin_callback, (void*)pin);
  448         if ((error_code = gnutls_certificate_set_x509_key_file(mtls->internals->cred,
  449                         cert_file, key_file, GNUTLS_X509_FMT_PEM)) < 0)
  450         {
  451             *errstr = xasprintf(_("cannot set X509 key file %s and/or "
  452                         "X509 cert file %s for TLS session: %s"),
  453                     key_file, cert_file, gnutls_strerror(error_code));
  454             gnutls_deinit(mtls->internals->session);
  455             gnutls_certificate_free_credentials(mtls->internals->cred);
  456             free(mtls->internals);
  457             mtls->internals = NULL;
  458             return TLS_EFILE;
  459         }
  460     }
  461     if (trust_file
  462             && !no_certcheck
  463             && !sha256_fingerprint
  464             && !sha1_fingerprint
  465             && !md5_fingerprint)
  466     {
  467         if (strcmp(trust_file, "system") == 0)
  468         {
  469             if ((error_code = gnutls_certificate_set_x509_system_trust(
  470                             mtls->internals->cred)) < 0)
  471             {
  472                 *errstr = xasprintf(
  473                         _("cannot set X509 system trust for TLS session: %s"),
  474                         gnutls_strerror(error_code));
  475                 gnutls_deinit(mtls->internals->session);
  476                 gnutls_certificate_free_credentials(mtls->internals->cred);
  477                 free(mtls->internals);
  478                 mtls->internals = NULL;
  479                 return TLS_ELIBFAILED;
  480             }
  481         }
  482         else
  483         {
  484             if ((error_code = gnutls_certificate_set_x509_trust_file(
  485                             mtls->internals->cred, trust_file, GNUTLS_X509_FMT_PEM)) <= 0)
  486             {
  487                 *errstr = xasprintf(
  488                         _("cannot set X509 trust file %s for TLS session: %s"),
  489                         trust_file, gnutls_strerror(error_code));
  490                 gnutls_deinit(mtls->internals->session);
  491                 gnutls_certificate_free_credentials(mtls->internals->cred);
  492                 free(mtls->internals);
  493                 mtls->internals = NULL;
  494                 return TLS_EFILE;
  495             }
  496         }
  497         if (crl_file)
  498         {
  499             if ((error_code = gnutls_certificate_set_x509_crl_file(
  500                             mtls->internals->cred, crl_file, GNUTLS_X509_FMT_PEM)) < 0)
  501             {
  502                 *errstr = xasprintf(
  503                         _("cannot set X509 CRL file %s for TLS session: %s"),
  504                         crl_file, gnutls_strerror(error_code));
  505                 gnutls_deinit(mtls->internals->session);
  506                 gnutls_certificate_free_credentials(mtls->internals->cred);
  507                 free(mtls->internals);
  508                 mtls->internals = NULL;
  509                 return TLS_EFILE;
  510             }
  511         }
  512         mtls->have_trust_file = 1;
  513     }
  514     if (sha256_fingerprint && !no_certcheck)
  515     {
  516         memcpy(mtls->fingerprint, sha256_fingerprint, 32);
  517         mtls->have_sha256_fingerprint = 1;
  518     }
  519     else if (sha1_fingerprint && !no_certcheck)
  520     {
  521         memcpy(mtls->fingerprint, sha1_fingerprint, 20);
  522         mtls->have_sha1_fingerprint = 1;
  523     }
  524     else if (md5_fingerprint && !no_certcheck)
  525     {
  526         memcpy(mtls->fingerprint, md5_fingerprint, 16);
  527         mtls->have_md5_fingerprint = 1;
  528     }
  529     if ((error_code = gnutls_credentials_set(mtls->internals->session,
  530                     GNUTLS_CRD_CERTIFICATE, mtls->internals->cred)) < 0)
  531     {
  532         *errstr = xasprintf(_("cannot set credentials for TLS session: %s"),
  533                 gnutls_strerror(error_code));
  534         gnutls_deinit(mtls->internals->session);
  535         gnutls_certificate_free_credentials(mtls->internals->cred);
  536         free(mtls->internals);
  537         mtls->internals = NULL;
  538         return TLS_ELIBFAILED;
  539     }
  540     mtls->no_certcheck = no_certcheck;
  541     mtls->hostname = xstrdup(hostname);
  542     return TLS_EOK;
  543 }
  544 
  545 
  546 /*
  547  * mtls_start()
  548  *
  549  * see mtls.h
  550  */
  551 
  552 int mtls_start(mtls_t *mtls, int fd,
  553         mtls_cert_info_t *tci, char **mtls_parameter_description, char **errstr)
  554 {
  555     int error_code;
  556 
  557     gnutls_server_name_set(mtls->internals->session, GNUTLS_NAME_DNS, mtls->hostname, strlen(mtls->hostname));
  558     gnutls_transport_set_int(mtls->internals->session, fd);
  559     do
  560     {
  561         error_code = gnutls_handshake(mtls->internals->session);
  562     }
  563     while (error_code < 0 && gnutls_error_is_fatal(error_code) == 0);
  564 
  565     if (error_code != 0)
  566     {
  567         *errstr = xasprintf(_("TLS handshake failed: %s"),
  568                 gnutls_strerror(error_code));
  569         gnutls_deinit(mtls->internals->session);
  570         gnutls_certificate_free_credentials(mtls->internals->cred);
  571         return TLS_EHANDSHAKE;
  572     }
  573     if (tci)
  574     {
  575         if ((error_code = mtls_cert_info_get(mtls, tci, errstr)) != TLS_EOK)
  576         {
  577             gnutls_deinit(mtls->internals->session);
  578             gnutls_certificate_free_credentials(mtls->internals->cred);
  579             return error_code;
  580         }
  581     }
  582     if (mtls_parameter_description)
  583     {
  584         *mtls_parameter_description = gnutls_session_get_desc(mtls->internals->session);
  585     }
  586     if (!mtls->no_certcheck)
  587     {
  588         if ((error_code = mtls_check_cert(mtls, errstr)) != TLS_EOK)
  589         {
  590             gnutls_deinit(mtls->internals->session);
  591             gnutls_certificate_free_credentials(mtls->internals->cred);
  592             return error_code;
  593         }
  594     }
  595     mtls->is_active = 1;
  596     return TLS_EOK;
  597 }
  598 
  599 
  600 /*
  601  * mtls_readbuf_read()
  602  *
  603  * Wraps TLS read function to provide buffering for mtls_gets().
  604  */
  605 
  606 int mtls_readbuf_read(mtls_t *mtls, readbuf_t *readbuf, char *ptr,
  607         char **errstr)
  608 {
  609     ssize_t ret;
  610 
  611     if (readbuf->count <= 0)
  612     {
  613         do
  614         {
  615             ret = gnutls_record_recv(mtls->internals->session,
  616                     readbuf->buf, sizeof(readbuf->buf));
  617         }
  618         while (ret == GNUTLS_E_AGAIN);
  619         if (ret < 0)
  620         {
  621             if (ret == GNUTLS_E_INTERRUPTED)
  622             {
  623                 *errstr = xasprintf(_("operation aborted"));
  624             }
  625             else
  626             {
  627                 *errstr = xasprintf(_("cannot read from TLS connection: %s"),
  628                         gnutls_strerror(ret));
  629             }
  630             return TLS_EIO;
  631         }
  632         else if (ret == 0)
  633         {
  634             return 0;
  635         }
  636         readbuf->count = (int)ret;
  637         readbuf->ptr = readbuf->buf;
  638     }
  639     readbuf->count--;
  640     *ptr = *((readbuf->ptr)++);
  641     return 1;
  642 }
  643 
  644 
  645 /*
  646  * mtls_puts()
  647  *
  648  * see mtls.h
  649  */
  650 
  651 int mtls_puts(mtls_t *mtls, const char *s, size_t len, char **errstr)
  652 {
  653     ssize_t ret;
  654 
  655     if (len < 1)
  656     {
  657         /* nothing to be done */
  658         return TLS_EOK;
  659     }
  660 
  661     do
  662     {
  663         ret = gnutls_record_send(mtls->internals->session, s, len);
  664     }
  665     while (ret == GNUTLS_E_AGAIN);
  666     if (ret < 0)
  667     {
  668         if (ret == GNUTLS_E_INTERRUPTED)
  669         {
  670             *errstr = xasprintf(_("operation aborted"));
  671         }
  672         else
  673         {
  674             *errstr = xasprintf(_("cannot write to TLS connection: %s"),
  675                     gnutls_strerror(ret));
  676         }
  677         return TLS_EIO;
  678     }
  679     else if ((size_t)ret == len)
  680     {
  681         return TLS_EOK;
  682     }
  683     else /* 0 <= error_code < len */
  684     {
  685         *errstr = xasprintf(_("cannot write to TLS connection: %s"),
  686                 _("unknown error"));
  687         return TLS_EIO;
  688     }
  689 }
  690 
  691 
  692 /*
  693  * mtls_close()
  694  *
  695  * see mtls.h
  696  */
  697 
  698 void mtls_close(mtls_t *mtls)
  699 {
  700     if (mtls->is_active)
  701     {
  702         int e;
  703         do
  704         {
  705             e = gnutls_bye(mtls->internals->session, GNUTLS_SHUT_WR);
  706         }
  707         while (e == GNUTLS_E_AGAIN);
  708         gnutls_deinit(mtls->internals->session);
  709         gnutls_certificate_free_credentials(mtls->internals->cred);
  710     }
  711     free(mtls->internals);
  712     mtls->internals = NULL;
  713     if (mtls->hostname)
  714     {
  715         free(mtls->hostname);
  716     }
  717     mtls_clear(mtls);
  718 }
  719 
  720 
  721 /*
  722  * mtls_lib_deinit()
  723  *
  724  * see mtls.h
  725  */
  726 
  727 void mtls_lib_deinit(void)
  728 {
  729 }