LCOV - code coverage report
Current view: top level - src - tls.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 23 78 29.5 %
Date: 2024-02-24 00:00:00 Functions: 2 11 18.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 1.14