LCOV - code coverage report
Current view: top level - src - tls.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 29.5 % 78 23
Test Date: 2024-07-22 12:36:40 Functions: 18.2 % 11 2

            Line data    Source code
       1              : /* SPDX-License-Identifier: MIT OR GPL-3.0-only */
       2              : /* tls.c
       3              : ** strophe XMPP client library -- generic TLS functions
       4              : **
       5              : ** Copyright (C) 2021 Steffen Jaeckel <jaeckel-floss@eyet-services.de>
       6              : **
       7              : **  This software is provided AS-IS with no warranty, either express
       8              : **  or implied.
       9              : **
      10              : **  This program is dual licensed under the MIT or GPLv3 licenses.
      11              : */
      12              : 
      13              : /** @file
      14              :  *  Generic TLS functionality.
      15              :  */
      16              : 
      17              : /** @defgroup TLS SSL/TLS specific functionality
      18              :  *  These functions provide SSL/TLS specific functionality.
      19              :  */
      20              : 
      21              : #include <errno.h>
      22              : #include <stdarg.h>
      23              : #include <string.h>
      24              : 
      25              : #if !defined(_WIN32)
      26              : #include <unistd.h>
      27              : #endif
      28              : 
      29              : #include "strophe.h"
      30              : 
      31              : #include "common.h"
      32              : 
      33              : const struct conn_interface tls_intf = {
      34              :     tls_read,
      35              :     tls_write,
      36              :     tls_clear_pending_write,
      37              :     tls_pending,
      38              :     tls_error,
      39              :     tls_is_recoverable,
      40              :     /* init conn */
      41              :     NULL,
      42              : };
      43              : 
      44              : struct _dnsname_t {
      45              :     char **data;
      46              :     size_t cur, max;
      47              : };
      48              : 
      49              : const size_t tlscert_dnsnames_increment = 4;
      50              : 
      51              : /** Get the Strophe context which is assigned to this certificate.
      52              :  *
      53              :  *  @param cert a Strophe TLS certificate object
      54              :  *
      55              :  *  @return the Strophe context object where this certificate originates from
      56              :  *
      57              :  *  @ingroup TLS
      58              :  */
      59            0 : xmpp_ctx_t *xmpp_tlscert_get_ctx(const xmpp_tlscert_t *cert)
      60              : {
      61            0 :     return cert->ctx;
      62              : }
      63              : 
      64              : /** Get the Strophe connection which is assigned to this certificate.
      65              :  *
      66              :  *  @param cert a Strophe TLS certificate object
      67              :  *
      68              :  *  @return the Strophe connection object where this certificate originates from
      69              :  *
      70              :  *  @ingroup TLS
      71              :  */
      72            0 : xmpp_conn_t *xmpp_tlscert_get_conn(const xmpp_tlscert_t *cert)
      73              : {
      74            0 :     return cert->conn;
      75              : }
      76              : 
      77              : /** Get the complete PEM of this certificate.
      78              :  *
      79              :  *  @param cert a Strophe TLS certificate object
      80              :  *
      81              :  *  @return a string containing the PEM of this certificate
      82              :  *
      83              :  *  @ingroup TLS
      84              :  */
      85            0 : const char *xmpp_tlscert_get_pem(const xmpp_tlscert_t *cert)
      86              : {
      87            0 :     return cert->pem;
      88              : }
      89              : 
      90              : /** Get the dnsName entries out of the SubjectAlternativeNames.
      91              :  *
      92              :  *  Note: Max. `MAX_NUM_DNSNAMES` are supported.
      93              :  *
      94              :  *  @param cert a Strophe TLS certificate object
      95              :  *  @param n which dnsName entry
      96              :  *
      97              :  *  @return a string with the n'th dnsName
      98              :  *
      99              :  *  @ingroup TLS
     100              :  */
     101            0 : const char *xmpp_tlscert_get_dnsname(const xmpp_tlscert_t *cert, size_t n)
     102              : {
     103            0 :     if (n >= cert->dnsnames->cur)
     104              :         return NULL;
     105            0 :     return cert->dnsnames->data[n];
     106              : }
     107              : 
     108              : /** Get various parts of the certificate as String.
     109              :  *
     110              :  *  c.f. \ref xmpp_cert_element_t for details.
     111              :  *
     112              :  *  @param cert a Strophe TLS certificate object
     113              :  *  @param elmnt which part of the certificate
     114              :  *
     115              :  *  @return a string with the part of the certificate
     116              :  *
     117              :  *  @ingroup TLS
     118              :  */
     119            0 : const char *xmpp_tlscert_get_string(const xmpp_tlscert_t *cert,
     120              :                                     xmpp_cert_element_t elmnt)
     121              : {
     122            0 :     if (elmnt < 0 || elmnt >= XMPP_CERT_ELEMENT_MAX)
     123              :         return NULL;
     124            0 :     return cert->elements[elmnt];
     125              : }
     126              : 
     127              : /** Get a descriptive string for each xmpp_cert_element_t.
     128              :  *
     129              :  *  c.f. \ref xmpp_cert_element_t for details.
     130              :  *
     131              :  *  @param elmnt which element
     132              :  *
     133              :  *  @return a string with the description
     134              :  *
     135              :  *  @ingroup TLS
     136              :  */
     137            0 : const char *xmpp_tlscert_get_description(xmpp_cert_element_t elmnt)
     138              : {
     139            0 :     static const char *descriptions[] = {
     140              :         "X.509 Version",
     141              :         "SerialNumber",
     142              :         "Subject",
     143              :         "Issuer",
     144              :         "Issued On",
     145              :         "Expires On",
     146              :         "Public Key Algorithm",
     147              :         "Certificate Signature Algorithm",
     148              :         "Fingerprint SHA-1",
     149              :         "Fingerprint SHA-256",
     150              :     };
     151            0 :     if (elmnt < 0 || elmnt >= XMPP_CERT_ELEMENT_MAX)
     152              :         return NULL;
     153            0 :     return descriptions[elmnt];
     154              : }
     155              : 
     156              : /** Allocate and initialize a Strophe TLS certificate object.
     157              :  *
     158              :  *  @param ctx a Strophe context object
     159              :  *
     160              :  *  @return a certificate object or NULL
     161              :  */
     162            0 : xmpp_tlscert_t *tlscert_new(xmpp_ctx_t *ctx)
     163              : {
     164            0 :     xmpp_tlscert_t *tlscert = strophe_alloc(ctx, sizeof(*tlscert));
     165            0 :     if (!tlscert)
     166              :         return NULL;
     167            0 :     memset(tlscert, 0, sizeof(*tlscert));
     168              : 
     169            0 :     tlscert->dnsnames = strophe_alloc(ctx, sizeof(*tlscert->dnsnames));
     170            0 :     if (!tlscert->dnsnames) {
     171            0 :         strophe_free(ctx, tlscert);
     172            0 :         return NULL;
     173              :     }
     174            0 :     memset(tlscert->dnsnames, 0, sizeof(*tlscert->dnsnames));
     175              : 
     176            0 :     tlscert->ctx = ctx;
     177              : 
     178            0 :     return tlscert;
     179              : }
     180              : 
     181              : /** Free a certificate object.
     182              :  *
     183              :  *  @param cert a Strophe TLS certificate object
     184              :  *
     185              :  *  @ingroup TLS
     186              :  */
     187            0 : void xmpp_tlscert_free(xmpp_tlscert_t *cert)
     188              : {
     189            0 :     size_t n;
     190            0 :     for (n = 0; n < ARRAY_SIZE(cert->elements); ++n) {
     191            0 :         if (cert->elements[n])
     192            0 :             strophe_free(cert->ctx, cert->elements[n]);
     193              :     }
     194            0 :     if (cert->dnsnames->data) {
     195            0 :         for (n = 0; n < cert->dnsnames->cur; ++n) {
     196            0 :             if (cert->dnsnames->data[n])
     197            0 :                 strophe_free(cert->ctx, cert->dnsnames->data[n]);
     198              :         }
     199              :     }
     200            0 :     strophe_free(cert->ctx, cert->dnsnames->data);
     201            0 :     strophe_free(cert->ctx, cert->dnsnames);
     202            0 :     if (cert->pem)
     203            0 :         strophe_free(cert->ctx, cert->pem);
     204            0 :     strophe_free(cert->ctx, cert);
     205            0 : }
     206              : 
     207              : /** Add a dnsName to the Strophe TLS certificate object.
     208              :  *
     209              :  *  @param cert a Strophe TLS certificate object
     210              :  *  @param dnsname dnsName that shall be stored
     211              :  *
     212              :  *  @return classic Unix style - 0=success, 1=error
     213              :  */
     214            0 : int tlscert_add_dnsname(xmpp_tlscert_t *cert, const char *dnsname)
     215              : {
     216            0 :     if ((cert->dnsnames->cur + 1) >= cert->dnsnames->max) {
     217            0 :         char **dnsnames =
     218            0 :             strophe_realloc(cert->ctx, cert->dnsnames->data,
     219            0 :                             (cert->dnsnames->max + tlscert_dnsnames_increment) *
     220              :                                 sizeof(char **));
     221            0 :         if (!dnsnames)
     222              :             return 1;
     223            0 :         cert->dnsnames->data = dnsnames;
     224            0 :         cert->dnsnames->max += tlscert_dnsnames_increment;
     225              :     }
     226            0 :     cert->dnsnames->data[cert->dnsnames->cur++] =
     227            0 :         strophe_strdup(cert->ctx, dnsname);
     228            0 :     return 0;
     229              : }
     230              : 
     231            8 : int tls_caching_password_callback(char *pw, size_t pw_max, xmpp_conn_t *conn)
     232              : {
     233            8 :     int ret;
     234            8 :     unsigned char hash[XMPP_SHA1_DIGEST_SIZE];
     235              : 
     236            8 :     const char *fname = conn->tls_client_cert;
     237            8 :     size_t fname_len = strlen(fname);
     238            8 :     xmpp_sha1_digest((void *)fname, fname_len, hash);
     239            8 :     if (fname_len && fname_len == conn->password_cache.fnamelen &&
     240            6 :         memcmp(hash, conn->password_cache.fname_hash, sizeof(hash)) == 0) {
     241            6 :         if (conn->password_cache.passlen) {
     242            6 :             memcpy(pw, conn->password_cache.pass,
     243              :                    conn->password_cache.passlen + 1);
     244            6 :             return conn->password_cache.passlen;
     245              :         }
     246              :     }
     247            2 :     size_t max_len = pw_max == 256 ? pw_max : sizeof(conn->password_cache.pass);
     248            2 :     ret = conn->password_callback(conn->password_cache.pass, max_len, conn,
     249              :                                   conn->password_callback_userdata);
     250              : 
     251            2 :     if (ret < 0 || ret >= (ssize_t)max_len) {
     252            0 :         memset(conn->password_cache.pass, 0, sizeof(conn->password_cache.pass));
     253            0 :         return -1;
     254              :     }
     255            2 :     conn->password_cache.pass[ret] = '\0';
     256            2 :     memcpy(pw, conn->password_cache.pass, ret + 1);
     257            2 :     conn->password_cache.passlen = ret;
     258            2 :     conn->password_cache.fnamelen = fname_len;
     259            2 :     memcpy(conn->password_cache.fname_hash, hash, sizeof(hash));
     260            2 :     return conn->password_cache.passlen;
     261              : }
     262              : 
     263           16 : void tls_clear_password_cache(xmpp_conn_t *conn)
     264              : {
     265           16 :     memset(&conn->password_cache, 0, sizeof(conn->password_cache));
     266           16 : }
        

Generated by: LCOV version 2.0-1