19 Commits

Author SHA1 Message Date
jjj333_p
60b3b91698 Fix SChannel pointer mismatches 2026-07-28 14:57:07 +02:00
Steffen Jaeckel
89922116f8 Update Doxyfile
Signed-off-by: Steffen Jaeckel <s@jaeckel.eu>
2026-02-18 15:45:45 +01:00
Steffen Jaeckel
4b40c30e7f Ignore potential OOT build folders.
Signed-off-by: Steffen Jaeckel <s@jaeckel.eu>
2026-02-18 15:24:09 +01:00
Steffen Jaeckel
090b10caa4 Update xSSL CI jobs.
Signed-off-by: Steffen Jaeckel <s@jaeckel.eu>
2025-12-20 17:15:48 +01:00
Steffen Jaeckel
aab9cdd406 Add support to retrieve the fingerprint of a public key from a cert.
Related-to: https://github.com/profanity-im/profanity/issues/2069
Signed-off-by: Steffen Jaeckel <s@jaeckel.eu>
2025-12-20 16:48:04 +01:00
Steffen Jaeckel
d38ecd5453 Add XMPP_CONN_FLAG_DIRECT_TLS.
... which aliases `XMPP_CONN_FLAG_LEGACY_SSL`. This was called 'legacy',
when everyone thought STARTTLS is the future, but that turned out
differently and direct TLS is recommended nowadays.

Signed-off-by: Steffen Jaeckel <s@jaeckel.eu>
2025-12-20 16:47:06 +01:00
Steffen Jaeckel
b7a30589d3 Fix documentation of xmpp_tlscert_get_dnsname()
`MAX_NUM_DNSNAMES` was replaced by a dynamically sized array, but the
documentation hasn't been updated.

Fixes: f23ac83 ("add callback functionality on certificate verification failure")
Signed-off-by: Steffen Jaeckel <s@jaeckel.eu>
2025-12-20 16:47:03 +01:00
Dmitry Podgorny
0dc045af35 conn: Fix cross compilation with mingw
Mingw doesn't find netinet/in.h which is not supposed to be used for a
windows build. This header is conditionally compiled when _MSC_VER is
not defined, however, mingw defines only _WIN32 and not the _MSC_VER.

Add also _WIN32 to the condition, so mingw ignores the header and relies
on winsock2.h from common.h->sock.h.

Fixes #265.
2025-12-20 13:46:19 +02:00
Steffen Jaeckel
b9eead3b90 Cancel running GH action on update of PR branch
Signed-off-by: Steffen Jaeckel <s@jaeckel.eu>
2025-10-31 16:54:02 +01:00
Steffen Jaeckel
979724b326 Update issue template according to the new way how GH wants it.
Signed-off-by: Steffen Jaeckel <s@jaeckel.eu>
2025-10-31 16:40:31 +01:00
Steffen Jaeckel
e869c1d26f Improve stanza tests.
Signed-off-by: Steffen Jaeckel <s@jaeckel.eu>
2025-10-31 16:34:58 +01:00
YuguoZhang
79066d797b fixes for building with MSVC 2025-10-31 16:22:54 +01:00
Stephen Paul Weber
f8cda0f65c Actually set the tlscert conn reference
Previously it was always NULL
2025-08-12 12:25:13 +02:00
Steffen Jaeckel
649a3b4fca Bump ubuntu version of release-test CI job
Signed-off-by: Steffen Jaeckel <s@jaeckel.eu>
2025-07-15 16:22:30 +02:00
Steffen Jaeckel
a2b3b6b9e2 Add xmpp_tlscert_get_userdata()
This fixes #249

Signed-off-by: Steffen Jaeckel <s@jaeckel.eu>
2025-04-02 10:17:21 +02:00
Steffen Jaeckel
dfb3e86824 Use void* to store function pointer when compiled as C23.
[0] decided that `rettype (*foo)();` must now be interpreted as
`rettype (*foo)(void);`. Luckily it also allows now to store function
pointers in a `void*` (c.f. Ch. J.5.7).

[0]: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3096.pdf

Signed-off-by: Steffen Jaeckel <s@jaeckel.eu>
2025-03-26 17:24:12 +01:00
Steffen Jaeckel
a81f0a8a5f Auto-format according to new clang-format.
Signed-off-by: Steffen Jaeckel <s@jaeckel.eu>
2025-03-26 15:18:52 +01:00
Steffen Jaeckel
5509ec3b35 Update CI
Signed-off-by: Steffen Jaeckel <s@jaeckel.eu>
2025-03-26 14:17:54 +01:00
Steffen Jaeckel
67b1a2f3f4 Add support for DragonFlyBSD in configure.ac
Hinted to by gnemmi in profanity@rooms.dismail.de

Signed-off-by: Steffen Jaeckel <s@jaeckel.eu>
2025-03-13 19:49:14 +01:00
25 changed files with 882 additions and 414 deletions

View File

@@ -1,3 +1,12 @@
---
name: Bug report
about: Create a bug report
title: ''
labels: bug
assignees: ''
---
<!-- <!--
Provide a general summary of the issue in the Title above Provide a general summary of the issue in the Title above

View File

@@ -8,9 +8,13 @@ on:
pull_request: pull_request:
branches: [master] branches: [master]
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs: jobs:
linux-tests: linux-tests:
runs-on: ubuntu-20.04 runs-on: ubuntu-24.04
strategy: strategy:
matrix: matrix:
valgrind: valgrind:
@@ -46,15 +50,18 @@ jobs:
cat test-suite*.log || true cat test-suite*.log || true
xssl-tests: xssl-tests:
runs-on: ubuntu-22.04 runs-on: ubuntu-24.04
strategy: strategy:
matrix: matrix:
xssl_versions: xssl_versions:
- { version: "master", continue: true, libressl: true } - { version: "master", continue: true, libressl: true }
- { version: "OPENBSD_7_8", continue: true, libressl: true }
- { version: "v4.2.1", continue: true, libressl: true }
- { version: "OPENBSD_7_7", continue: true, libressl: true }
- { version: "v4.1.2", continue: true, libressl: true }
- { version: "OPENBSD_7_6", continue: true, libressl: true }
- { version: "OPENBSD_7_5", continue: true, libressl: true } - { version: "OPENBSD_7_5", continue: true, libressl: true }
- { version: "v3.9.2", continue: true, libressl: true }
- { version: "OPENBSD_7_4", continue: true, libressl: true } - { version: "OPENBSD_7_4", continue: true, libressl: true }
- { version: "v3.8.4", continue: true, libressl: true }
- { version: "OPENBSD_7_3", continue: true, libressl: true } - { version: "OPENBSD_7_3", continue: true, libressl: true }
- { version: "OPENBSD_7_2", continue: true, libressl: true } - { version: "OPENBSD_7_2", continue: true, libressl: true }
- { version: "OPENBSD_7_1", continue: true, libressl: true } - { version: "OPENBSD_7_1", continue: true, libressl: true }
@@ -68,13 +75,17 @@ jobs:
- { version: "v3.1.5", continue: true, libressl: true } - { version: "v3.1.5", continue: true, libressl: true }
- { version: "v2.1.10", continue: true, libressl: true } - { version: "v2.1.10", continue: true, libressl: true }
- { version: "openssl-3.0", continue: true, libressl: false } - { version: "openssl-3.0", continue: true, libressl: false }
- { version: "openssl-3.0.13", continue: false, libressl: false } - { version: "openssl-3.0.18", continue: false, libressl: false }
- { version: "openssl-3.1", continue: true, libressl: false }
- { version: "openssl-3.1.5", continue: false, libressl: false }
- { version: "openssl-3.2", continue: true, libressl: false } - { version: "openssl-3.2", continue: true, libressl: false }
- { version: "openssl-3.2.1", continue: false, libressl: false } - { version: "openssl-3.2.6", continue: false, libressl: false }
- { version: "openssl-3.3", continue: true, libressl: false } - { version: "openssl-3.3", continue: true, libressl: false }
- { version: "openssl-3.3.0", continue: false, libressl: false } - { version: "openssl-3.3.5", continue: false, libressl: false }
- { version: "openssl-3.4", continue: true, libressl: false }
- { version: "openssl-3.4.3", continue: false, libressl: false }
- { version: "openssl-3.5", continue: true, libressl: false }
- { version: "openssl-3.5.3", continue: false, libressl: false }
- { version: "openssl-3.6", continue: true, libressl: false }
- { version: "openssl-3.6.0", continue: false, libressl: false }
name: xSSL tests name: xSSL tests
continue-on-error: ${{ matrix.xssl_versions.continue }} continue-on-error: ${{ matrix.xssl_versions.continue }}
steps: steps:
@@ -111,7 +122,7 @@ jobs:
cat test-suite*.log || true cat test-suite*.log || true
release-test: release-test:
runs-on: ubuntu-20.04 runs-on: ubuntu-22.04
name: Check if release would work name: Check if release would work
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
@@ -142,7 +153,7 @@ jobs:
cat testerr.log || true cat testerr.log || true
code-style: code-style:
runs-on: ubuntu-20.04 runs-on: ubuntu-24.04
name: Check coding style name: Check coding style
continue-on-error: true continue-on-error: true
steps: steps:

1
.gitignore vendored
View File

@@ -88,3 +88,4 @@ coverage/
coverage.info coverage.info
configure~ configure~
fuzz-*.log fuzz-*.log
build*/

1033
Doxyfile

File diff suppressed because it is too large Load Diff

View File

@@ -18,9 +18,10 @@ PKG_PROG_PKG_CONFIG
AC_CANONICAL_HOST AC_CANONICAL_HOST
AS_CASE([$host_os], AS_CASE([$host_os],
[dragonfly*], [PLATFORM="bsd"],
[freebsd*], [PLATFORM="bsd"], [freebsd*], [PLATFORM="bsd"],
[openbsd*], [PLATFORM="bsd"],
[netbsd*], [PLATFORM="bsd"], [netbsd*], [PLATFORM="bsd"],
[openbsd*], [PLATFORM="bsd"],
[*nto*|*qnx*], [PLATFORM="qnx"], [*nto*|*qnx*], [PLATFORM="qnx"],
[*solaris*], [PLATFORM="solaris"], [*solaris*], [PLATFORM="solaris"],
[*android*], [PLATFORM="android"], [*android*], [PLATFORM="android"],

View File

@@ -20,11 +20,12 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h>
#ifdef _WIN32 #ifdef _WIN32
#include <conio.h> #include <conio.h>
#include <ctype.h> #include <ctype.h>
#else
#include <unistd.h>
#endif #endif
#include <strophe.h> #include <strophe.h>

View File

@@ -13,7 +13,6 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h>
#ifdef _WIN32 #ifdef _WIN32
#include <conio.h> #include <conio.h>
@@ -23,6 +22,7 @@
#include <iphlpapi.h> #include <iphlpapi.h>
#include <mstcpip.h> /* tcp_keepalive */ #include <mstcpip.h> /* tcp_keepalive */
#else #else
#include <unistd.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <netinet/tcp.h> #include <netinet/tcp.h>

View File

@@ -11,11 +11,16 @@
*/ */
#include <assert.h> #include <assert.h>
#include <libgen.h> /* basename */
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <strophe.h> #include <strophe.h>
#ifndef _WIN32
#include <libgen.h> /* basename */
#else
#define strtok_r strtok_s
#define basename(x) "vcard"
#endif
typedef struct { typedef struct {
xmpp_ctx_t *ctx; xmpp_ctx_t *ctx;

View File

@@ -29,13 +29,29 @@
#include "parser.h" #include "parser.h"
#include "snprintf.h" #include "snprintf.h"
/** Define your own `STROPHE_STATIC_ASSERT` if your compiler doesn't support one
* of the below ones or define as noop if your compiler provides no replacement.
*/
#if !defined(STROPHE_STATIC_ASSERT)
#if (__STDC_VERSION__ >= 202000L)
#define STROPHE_STATIC_ASSERT(cond, msg) static_assert(cond, msg)
#else
#define STROPHE_STATIC_ASSERT(cond, msg) _Static_assert(cond, msg)
#endif
#endif
/** handlers **/ /** handlers **/
#if (__STDC_VERSION__ >= 202000L)
typedef void *xmpp_void_handler;
#else
typedef int (*xmpp_void_handler)();
#endif
typedef struct _xmpp_handlist_t xmpp_handlist_t; typedef struct _xmpp_handlist_t xmpp_handlist_t;
struct _xmpp_handlist_t { struct _xmpp_handlist_t {
/* common members */ /* common members */
int user_handler; int user_handler;
int (*handler)(); xmpp_void_handler handler;
void *userdata; void *userdata;
int enabled; /* handlers are added disabled and enabled after the int enabled; /* handlers are added disabled and enabled after the
* handler chain is processed to prevent stanzas from * handler chain is processed to prevent stanzas from

View File

@@ -18,6 +18,9 @@
#include <errno.h> #include <errno.h>
#include "common.h" #include "common.h"
#ifdef _MSC_VER
#define strcasecmp _stricmp
#endif
#ifndef STROPHE_COMPRESSION_BUFFER_SIZE #ifndef STROPHE_COMPRESSION_BUFFER_SIZE
/** Max buffer size for compressed data (send & receive). */ /** Max buffer size for compressed data (send & receive). */
@@ -110,7 +113,7 @@ static int
_compression_write(xmpp_conn_t *conn, const void *buff, size_t len, int flush) _compression_write(xmpp_conn_t *conn, const void *buff, size_t len, int flush)
{ {
int ret; int ret;
const void *buff_end = buff + len; const void *buff_end = (const char *)buff + len;
struct xmpp_compression *comp = conn->compression.state; struct xmpp_compression *comp = conn->compression.state;
comp->compression.stream.next_in = (Bytef *)buff; comp->compression.stream.next_in = (Bytef *)buff;
comp->compression.stream.avail_in = len; comp->compression.stream.avail_in = len;
@@ -201,7 +204,7 @@ static void *_zlib_alloc(void *opaque, unsigned int items, unsigned int size)
static void _init_zlib_compression(xmpp_ctx_t *ctx, struct zlib_compression *s) static void _init_zlib_compression(xmpp_ctx_t *ctx, struct zlib_compression *s)
{ {
s->buffer = strophe_alloc(ctx, STROPHE_COMPRESSION_BUFFER_SIZE); s->buffer = strophe_alloc(ctx, STROPHE_COMPRESSION_BUFFER_SIZE);
s->buffer_end = s->buffer + STROPHE_COMPRESSION_BUFFER_SIZE; s->buffer_end = (char *)s->buffer + STROPHE_COMPRESSION_BUFFER_SIZE;
s->stream.opaque = ctx; s->stream.opaque = ctx;
s->stream.zalloc = _zlib_alloc; s->stream.zalloc = _zlib_alloc;

View File

@@ -21,7 +21,9 @@
*/ */
#include <errno.h> #include <errno.h>
#if !defined(_MSC_VER) && !defined(_WIN32)
#include <netinet/in.h> #include <netinet/in.h>
#endif
#include <stdarg.h> #include <stdarg.h>
#include <string.h> #include <string.h>
#include <limits.h> #include <limits.h>

View File

@@ -39,7 +39,7 @@
#include <sys/select.h> #include <sys/select.h>
#include <errno.h> #include <errno.h>
#include <unistd.h> #include <unistd.h>
#define _sleep(x) usleep((x)*1000) #define _sleep(x) usleep((x) * 1000)
#else #else
#include <winsock2.h> #include <winsock2.h>
#ifndef ETIMEDOUT #ifndef ETIMEDOUT

View File

@@ -25,8 +25,6 @@
#include "common.h" #include "common.h"
#include "ostypes.h" #include "ostypes.h"
typedef int (*xmpp_void_handler)();
/* Remove item from the list pointed by head, but don't free it. /* Remove item from the list pointed by head, but don't free it.
* There can be a situation when user's handler deletes another handler which * There can be a situation when user's handler deletes another handler which
* is the previous in the list. handler_fire_stanza() and handler_fire_timed() * is the previous in the list. handler_fire_stanza() and handler_fire_timed()

View File

@@ -37,7 +37,7 @@
#define PUT_32BIT_LSB_FIRST(cp, value) \ #define PUT_32BIT_LSB_FIRST(cp, value) \
do { \ do { \
(cp)[0] = (value)&0xFF; \ (cp)[0] = (value) & 0xFF; \
(cp)[1] = ((value) >> 8) & 0xFF; \ (cp)[1] = ((value) >> 8) & 0xFF; \
(cp)[2] = ((value) >> 16) & 0xFF; \ (cp)[2] = ((value) >> 16) & 0xFF; \
(cp)[3] = ((value) >> 24) & 0xFF; \ (cp)[3] = ((value) >> 24) & 0xFF; \

View File

@@ -68,9 +68,9 @@ struct _xmpp_rand_t {
}; };
/* returns smallest number mupliple of y that not less than x */ /* returns smallest number mupliple of y that not less than x */
#define round_up(x, y) (((x) + (y)-1) / (y) * (y)) #define round_up(x, y) (((x) + (y) - 1) / (y) * (y))
/* returns smallest integer number that not less than x/y */ /* returns smallest integer number that not less than x/y */
#define div_round_up(x, y) (((x) + (y)-1) / (y)) #define div_round_up(x, y) (((x) + (y) - 1) / (y))
/* adds two arrays as numbers in big-endian representation and stores /* adds two arrays as numbers in big-endian representation and stores
* result in the first one. * result in the first one.

View File

@@ -630,7 +630,7 @@ static void netbuf_add_16bitnum(unsigned char *buf,
/* assuming big endian */ /* assuming big endian */
*p++ = (num >> 8) & 0xff; *p++ = (num >> 8) & 0xff;
*p++ = (num)&0xff; *p++ = (num) & 0xff;
*offset += 2; *offset += 2;
} }
@@ -982,7 +982,7 @@ resolver_win32_srv_query(const char *fulldomain, unsigned char *buf, size_t len)
insize = recvfrom(sock, (char *)buf, (int)len, 0, insize = recvfrom(sock, (char *)buf, (int)len, 0,
(struct sockaddr *)&dnsaddr, &addrlen); (struct sockaddr *)&dnsaddr, &addrlen);
if (insize == SOCKET_ERROR) { if (insize == SOCKET_ERROR) {
if (sock_error() == WSAEWOULDBLOCK) { if (sock_error(NULL) == WSAEWOULDBLOCK) {
Sleep(100); Sleep(100);
} else { } else {
break; break;

View File

@@ -53,7 +53,7 @@ extern "C" {
(y)[0] = (uint8_t)(((x) >> 24) & 255); \ (y)[0] = (uint8_t)(((x) >> 24) & 255); \
(y)[1] = (uint8_t)(((x) >> 16) & 255); \ (y)[1] = (uint8_t)(((x) >> 16) & 255); \
(y)[2] = (uint8_t)(((x) >> 8) & 255); \ (y)[2] = (uint8_t)(((x) >> 8) & 255); \
(y)[3] = (uint8_t)((x)&255); \ (y)[3] = (uint8_t)((x) & 255); \
} while (0) } while (0)
#define LOAD32H(x, y) \ #define LOAD32H(x, y) \
@@ -72,7 +72,7 @@ extern "C" {
(y)[4] = (uint8_t)(((x) >> 24) & 255); \ (y)[4] = (uint8_t)(((x) >> 24) & 255); \
(y)[5] = (uint8_t)(((x) >> 16) & 255); \ (y)[5] = (uint8_t)(((x) >> 16) & 255); \
(y)[6] = (uint8_t)(((x) >> 8) & 255); \ (y)[6] = (uint8_t)(((x) >> 8) & 255); \
(y)[7] = (uint8_t)((x)&255); \ (y)[7] = (uint8_t)((x) & 255); \
} while (0) } while (0)
#define LOAD64H(x, y) \ #define LOAD64H(x, y) \
@@ -96,13 +96,13 @@ extern "C" {
#define CONST64(n) n##ULL #define CONST64(n) n##ULL
#endif #endif
#define RORc(x, y) \ #define RORc(x, y) \
(((((uint32_t)(x)&0xFFFFFFFFUL) >> (uint32_t)((y)&31)) | \ (((((uint32_t)(x) & 0xFFFFFFFFUL) >> (uint32_t)((y) & 31)) | \
((uint32_t)(x) << (uint32_t)((32 - ((y)&31)) & 31))) & \ ((uint32_t)(x) << (uint32_t)((32 - ((y) & 31)) & 31))) & \
0xFFFFFFFFUL) 0xFFFFFFFFUL)
#define ROR64c(x, y) \ #define ROR64c(x, y) \
(((((x)&CONST64(0xFFFFFFFFFFFFFFFF)) >> ((uint64_t)(y)&CONST64(63))) | \ (((((x) & CONST64(0xFFFFFFFFFFFFFFFF)) >> ((uint64_t)(y) & CONST64(63))) | \
((x) << (((uint64_t)64 - ((y)&63)) & 63))) & \ ((x) << (((uint64_t)64 - ((y) & 63)) & 63))) & \
CONST64(0xFFFFFFFFFFFFFFFF)) CONST64(0xFFFFFFFFFFFFFFFF))
#ifdef __cplusplus #ifdef __cplusplus

View File

@@ -9,7 +9,7 @@
#define Ch(x, y, z) (z ^ (x & (y ^ z))) #define Ch(x, y, z) (z ^ (x & (y ^ z)))
#define Maj(x, y, z) (((x | y) & z) | (x & y)) #define Maj(x, y, z) (((x | y) & z) | (x & y))
#define S(x, n) RORc((x), (n)) #define S(x, n) RORc((x), (n))
#define R(x, n) (((x)&0xFFFFFFFFUL) >> (n)) #define R(x, n) (((x) & 0xFFFFFFFFUL) >> (n))
#define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22)) #define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22))
#define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25)) #define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25))
#define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3)) #define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3))

View File

@@ -52,7 +52,7 @@ static const uint64_t K[80] = {
#define Ch(x, y, z) (z ^ (x & (y ^ z))) #define Ch(x, y, z) (z ^ (x & (y ^ z)))
#define Maj(x, y, z) (((x | y) & z) | (x & y)) #define Maj(x, y, z) (((x | y) & z) | (x & y))
#define S(x, n) ROR64c(x, n) #define S(x, n) ROR64c(x, n)
#define R(x, n) (((x)&CONST64(0xFFFFFFFFFFFFFFFF)) >> ((uint64_t)n)) #define R(x, n) (((x) & CONST64(0xFFFFFFFFFFFFFFFF)) >> ((uint64_t)n))
#define Sigma0(x) (S(x, 28) ^ S(x, 34) ^ S(x, 39)) #define Sigma0(x) (S(x, 28) ^ S(x, 34) ^ S(x, 39))
#define Sigma1(x) (S(x, 14) ^ S(x, 18) ^ S(x, 41)) #define Sigma1(x) (S(x, 14) ^ S(x, 18) ^ S(x, 41))
#define Gamma0(x) (S(x, 1) ^ S(x, 8) ^ R(x, 7)) #define Gamma0(x) (S(x, 1) ^ S(x, 8) ^ R(x, 7))

View File

@@ -29,6 +29,10 @@
#include "strophe.h" #include "strophe.h"
#include "common.h" #include "common.h"
#ifdef _MSC_VER
#include <BaseTsd.h>
typedef SSIZE_T ssize_t;
#endif
const struct conn_interface tls_intf = { const struct conn_interface tls_intf = {
tls_read, tls_read,
@@ -74,6 +78,23 @@ xmpp_conn_t *xmpp_tlscert_get_conn(const xmpp_tlscert_t *cert)
return cert->conn; return cert->conn;
} }
/** Get the userdata of a Strophe connection which is assigned to this
* certificate.
*
* @param cert a Strophe TLS certificate object
*
* @return the userdata of a Strophe connection object where this certificate
* originates from
*
* @ingroup TLS
*/
void *xmpp_tlscert_get_userdata(const xmpp_tlscert_t *cert)
{
if (cert->conn == NULL)
return NULL;
return cert->conn->userdata;
}
/** Get the complete PEM of this certificate. /** Get the complete PEM of this certificate.
* *
* @param cert a Strophe TLS certificate object * @param cert a Strophe TLS certificate object
@@ -88,8 +109,6 @@ const char *xmpp_tlscert_get_pem(const xmpp_tlscert_t *cert)
} }
/** Get the dnsName entries out of the SubjectAlternativeNames. /** Get the dnsName entries out of the SubjectAlternativeNames.
*
* Note: Max. `MAX_NUM_DNSNAMES` are supported.
* *
* @param cert a Strophe TLS certificate object * @param cert a Strophe TLS certificate object
* @param n which dnsName entry * @param n which dnsName entry
@@ -145,9 +164,13 @@ const char *xmpp_tlscert_get_description(xmpp_cert_element_t elmnt)
"Expires On", "Expires On",
"Public Key Algorithm", "Public Key Algorithm",
"Certificate Signature Algorithm", "Certificate Signature Algorithm",
"Fingerprint SHA-1", "Certificate Fingerprint SHA-1",
"Fingerprint SHA-256", "Certificate Fingerprint SHA-256",
"Public Key Fingerprint SHA-256",
}; };
STROPHE_STATIC_ASSERT(
ARRAY_SIZE(descriptions) == XMPP_CERT_ELEMENT_MAX,
"descriptions don't match the number of enum elements");
if (elmnt < 0 || elmnt >= XMPP_CERT_ELEMENT_MAX) if (elmnt < 0 || elmnt >= XMPP_CERT_ELEMENT_MAX)
return NULL; return NULL;
return descriptions[elmnt]; return descriptions[elmnt];

View File

@@ -334,6 +334,12 @@ static xmpp_tlscert_t *_x509_to_tlscert(xmpp_ctx_t *ctx, gnutls_x509_crt_t cert)
gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_SHA256, smallbuf, &size); gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_SHA256, smallbuf, &size);
hex_encode(buf, smallbuf, size); hex_encode(buf, smallbuf, size);
tlscert->elements[XMPP_CERT_FINGERPRINT_SHA256] = strophe_strdup(ctx, buf); tlscert->elements[XMPP_CERT_FINGERPRINT_SHA256] = strophe_strdup(ctx, buf);
size = sizeof(smallbuf);
gnutls_x509_crt_get_key_id(cert, GNUTLS_KEYID_USE_SHA256, (void *)smallbuf,
&size);
hex_encode(buf, smallbuf, size);
tlscert->elements[XMPP_CERT_PUBKEY_FINGERPRINT_SHA256] =
strophe_strdup(ctx, buf);
strophe_snprintf(buf, sizeof(buf), "%d", gnutls_x509_crt_get_version(cert)); strophe_snprintf(buf, sizeof(buf), "%d", gnutls_x509_crt_get_version(cert));
tlscert->elements[XMPP_CERT_VERSION] = strophe_strdup(ctx, buf); tlscert->elements[XMPP_CERT_VERSION] = strophe_strdup(ctx, buf);
@@ -422,6 +428,8 @@ static int _tls_verify(gnutls_session_t session)
return -1; return -1;
} }
tlscert->conn = tls->conn;
if (tls->conn->certfail_handler(tlscert, (char *)out.data) == 0) { if (tls->conn->certfail_handler(tlscert, (char *)out.data) == 0) {
xmpp_tlscert_free(tlscert); xmpp_tlscert_free(tlscert);
gnutls_x509_crt_deinit(cert); gnutls_x509_crt_deinit(cert);

View File

@@ -376,18 +376,26 @@ _get_fingerprint(const xmpp_ctx_t *ctx, X509 *err_cert, xmpp_cert_element_t el)
{ {
unsigned char buf[EVP_MAX_MD_SIZE]; unsigned char buf[EVP_MAX_MD_SIZE];
unsigned int len; unsigned int len;
int (*digest_fn)(const X509 *data, const EVP_MD *type, unsigned char *md,
unsigned int *len);
const EVP_MD *digest; const EVP_MD *digest;
switch (el) { switch (el) {
case XMPP_CERT_FINGERPRINT_SHA1: case XMPP_CERT_FINGERPRINT_SHA1:
digest_fn = X509_digest;
digest = EVP_sha1(); digest = EVP_sha1();
break; break;
case XMPP_CERT_FINGERPRINT_SHA256: case XMPP_CERT_FINGERPRINT_SHA256:
digest_fn = X509_digest;
digest = EVP_sha256();
break;
case XMPP_CERT_PUBKEY_FINGERPRINT_SHA256:
digest_fn = X509_pubkey_digest;
digest = EVP_sha256(); digest = EVP_sha256();
break; break;
default: default:
return NULL; return NULL;
} }
if (X509_digest(err_cert, digest, buf, &len) != 0) { if (digest_fn(err_cert, digest, buf, &len) != 0) {
char fingerprint[4 * EVP_MAX_MD_SIZE]; char fingerprint[4 * EVP_MAX_MD_SIZE];
hex_encode(fingerprint, buf, len); hex_encode(fingerprint, buf, len);
return strophe_strdup(ctx, fingerprint); return strophe_strdup(ctx, fingerprint);
@@ -475,6 +483,8 @@ static xmpp_tlscert_t *_x509_to_tlscert(xmpp_ctx_t *ctx, X509 *cert)
_get_fingerprint(ctx, cert, XMPP_CERT_FINGERPRINT_SHA1); _get_fingerprint(ctx, cert, XMPP_CERT_FINGERPRINT_SHA1);
tlscert->elements[XMPP_CERT_FINGERPRINT_SHA256] = tlscert->elements[XMPP_CERT_FINGERPRINT_SHA256] =
_get_fingerprint(ctx, cert, XMPP_CERT_FINGERPRINT_SHA256); _get_fingerprint(ctx, cert, XMPP_CERT_FINGERPRINT_SHA256);
tlscert->elements[XMPP_CERT_PUBKEY_FINGERPRINT_SHA256] =
_get_fingerprint(ctx, cert, XMPP_CERT_PUBKEY_FINGERPRINT_SHA256);
strophe_snprintf(buf, sizeof(buf), "%ld", X509_get_version(cert) + 1); strophe_snprintf(buf, sizeof(buf), "%ld", X509_get_version(cert) + 1);
tlscert->elements[XMPP_CERT_VERSION] = strophe_strdup(ctx, buf); tlscert->elements[XMPP_CERT_VERSION] = strophe_strdup(ctx, buf);
@@ -540,6 +550,8 @@ static int _tls_verify(int preverify_ok, X509_STORE_CTX *x509_ctx)
if (!tlscert) if (!tlscert)
return 0; return 0;
tlscert->conn = conn;
strophe_debug(conn->ctx, "tls", "preverify_ok:%d\nSubject: %s\nIssuer: %s", strophe_debug(conn->ctx, "tls", "preverify_ok:%d\nSubject: %s\nIssuer: %s",
preverify_ok, tlscert->elements[XMPP_CERT_SUBJECT], preverify_ok, tlscert->elements[XMPP_CERT_SUBJECT],
tlscert->elements[XMPP_CERT_ISSUER]); tlscert->elements[XMPP_CERT_ISSUER]);

View File

@@ -266,7 +266,7 @@ int tls_start(tls_t *tls)
/* use the domain there as our name */ /* use the domain there as our name */
name = tls->conn->domain; name = tls->conn->domain;
intf = tls->conn->intf; intf = &tls->conn->intf;
ctxtreq = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT | ctxtreq = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT |
ISC_REQ_CONFIDENTIALITY | ISC_RET_EXTENDED_ERROR | ISC_REQ_CONFIDENTIALITY | ISC_RET_EXTENDED_ERROR |
@@ -479,7 +479,7 @@ int tls_read(struct conn_interface *intf, void *buff, size_t len)
int read; int read;
tls->readybufferpos += bytes; tls->readybufferpos += bytes;
newbuff += bytes; newbuff += bytes;
read = tls_read(tls, newbuff, len - bytes); read = tls_read(intf, newbuff, len - bytes);
if (read == -1) { if (read == -1) {
if (tls_is_recoverable(intf, tls->lasterror)) { if (tls_is_recoverable(intf, tls->lasterror)) {
@@ -553,7 +553,7 @@ int tls_read(struct conn_interface *intf, void *buff, size_t len)
tls->recvbufferpos = 0; tls->recvbufferpos = 0;
} }
return tls_read(tls, buff, len); return tls_read(intf, buff, len);
} else if (ret == SEC_E_INCOMPLETE_MESSAGE) { } else if (ret == SEC_E_INCOMPLETE_MESSAGE) {
tls->lasterror = SEC_E_INCOMPLETE_MESSAGE; tls->lasterror = SEC_E_INCOMPLETE_MESSAGE;
return -1; return -1;
@@ -611,7 +611,7 @@ int tls_write(struct conn_interface *intf, const void *buff, size_t len)
int sent = 0, ret, remain = len; int sent = 0, ret, remain = len;
tls_t *tls = intf->conn->tls; tls_t *tls = intf->conn->tls;
ret = tls_clear_pending_write(tls); ret = tls_clear_pending_write(intf);
if (ret <= 0) { if (ret <= 0) {
return ret; return ret;
} }
@@ -667,9 +667,9 @@ int tls_write(struct conn_interface *intf, const void *buff, size_t len)
tls->sendbufferpos = 0; tls->sendbufferpos = 0;
ret = tls_clear_pending_write(tls); ret = tls_clear_pending_write(intf);
if (ret == -1 && !tls_is_recoverable(intf, tls_error(tls))) { if (ret == -1 && !tls_is_recoverable(intf, tls_error(intf))) {
return -1; return -1;
} }
@@ -682,7 +682,7 @@ int tls_write(struct conn_interface *intf, const void *buff, size_t len)
} }
if (ret == 0 || if (ret == 0 ||
(ret == -1 && tls_is_recoverable(intf, tls_error(tls)))) { (ret == -1 && tls_is_recoverable(intf, tls_error(intf)))) {
return sent; return sent;
} }
} }

View File

@@ -188,6 +188,7 @@ typedef struct _xmpp_sm_t xmpp_sm_state_t;
#define XMPP_CONN_FLAG_DISABLE_TLS (1UL << 0) #define XMPP_CONN_FLAG_DISABLE_TLS (1UL << 0)
#define XMPP_CONN_FLAG_MANDATORY_TLS (1UL << 1) #define XMPP_CONN_FLAG_MANDATORY_TLS (1UL << 1)
#define XMPP_CONN_FLAG_LEGACY_SSL (1UL << 2) #define XMPP_CONN_FLAG_LEGACY_SSL (1UL << 2)
#define XMPP_CONN_FLAG_DIRECT_TLS XMPP_CONN_FLAG_LEGACY_SSL
/** @def XMPP_CONN_FLAG_TRUST_TLS /** @def XMPP_CONN_FLAG_TRUST_TLS
* Trust server's certificate even if it is invalid. * Trust server's certificate even if it is invalid.
*/ */
@@ -250,17 +251,18 @@ typedef enum {
* @ingroup TLS * @ingroup TLS
*/ */
typedef enum { typedef enum {
XMPP_CERT_VERSION, /**< X.509 Version */ XMPP_CERT_VERSION, /**< X.509 Version */
XMPP_CERT_SERIALNUMBER, /**< SerialNumber */ XMPP_CERT_SERIALNUMBER, /**< SerialNumber */
XMPP_CERT_SUBJECT, /**< Subject */ XMPP_CERT_SUBJECT, /**< Subject */
XMPP_CERT_ISSUER, /**< Issuer */ XMPP_CERT_ISSUER, /**< Issuer */
XMPP_CERT_NOTBEFORE, /**< Issued on */ XMPP_CERT_NOTBEFORE, /**< Issued on */
XMPP_CERT_NOTAFTER, /**< Expires on */ XMPP_CERT_NOTAFTER, /**< Expires on */
XMPP_CERT_KEYALG, /**< Public Key Algorithm */ XMPP_CERT_KEYALG, /**< Public Key Algorithm */
XMPP_CERT_SIGALG, /**< Certificate Signature Algorithm */ XMPP_CERT_SIGALG, /**< Certificate Signature Algorithm */
XMPP_CERT_FINGERPRINT_SHA1, /**< Fingerprint SHA-1 */ XMPP_CERT_FINGERPRINT_SHA1, /**< Fingerprint SHA-1 */
XMPP_CERT_FINGERPRINT_SHA256, /**< Fingerprint SHA-256 */ XMPP_CERT_FINGERPRINT_SHA256, /**< Fingerprint SHA-256 */
XMPP_CERT_ELEMENT_MAX /**< Last element of the enum */ XMPP_CERT_PUBKEY_FINGERPRINT_SHA256, /**< SHA-256 fingerprint of pubkey */
XMPP_CERT_ELEMENT_MAX /**< Last element of the enum */
} xmpp_cert_element_t; } xmpp_cert_element_t;
typedef struct { typedef struct {
@@ -642,6 +644,7 @@ void xmpp_ctx_set_timeout(xmpp_ctx_t *ctx, unsigned long timeout);
xmpp_ctx_t *xmpp_tlscert_get_ctx(const xmpp_tlscert_t *cert); xmpp_ctx_t *xmpp_tlscert_get_ctx(const xmpp_tlscert_t *cert);
xmpp_conn_t *xmpp_tlscert_get_conn(const xmpp_tlscert_t *cert); xmpp_conn_t *xmpp_tlscert_get_conn(const xmpp_tlscert_t *cert);
void *xmpp_tlscert_get_userdata(const xmpp_tlscert_t *cert);
const char *xmpp_tlscert_get_pem(const xmpp_tlscert_t *cert); const char *xmpp_tlscert_get_pem(const xmpp_tlscert_t *cert);
const char *xmpp_tlscert_get_dnsname(const xmpp_tlscert_t *cert, size_t n); const char *xmpp_tlscert_get_dnsname(const xmpp_tlscert_t *cert, size_t n);
const char *xmpp_tlscert_get_string(const xmpp_tlscert_t *cert, const char *xmpp_tlscert_get_string(const xmpp_tlscert_t *cert,

View File

@@ -177,13 +177,9 @@ static void test_stanza_error(xmpp_ctx_t *ctx)
mood = xmpp_stanza_new_from_string(ctx, str_mood); mood = xmpp_stanza_new_from_string(ctx, str_mood);
assert(mood != NULL); assert(mood != NULL);
assert(xmpp_stanza_get_to(error) != NULL);
COMPARE("romeo@montague.lit/home", xmpp_stanza_get_to(error)); COMPARE("romeo@montague.lit/home", xmpp_stanza_get_to(error));
assert(xmpp_stanza_get_from(error) != NULL);
COMPARE("juliet@capulet.lit/chamber", xmpp_stanza_get_from(error)); COMPARE("juliet@capulet.lit/chamber", xmpp_stanza_get_from(error));
assert(xmpp_stanza_get_id(error) != NULL);
COMPARE("e2e1", xmpp_stanza_get_id(error)); COMPARE("e2e1", xmpp_stanza_get_id(error));
assert(xmpp_stanza_get_type(error) != NULL);
COMPARE("error", xmpp_stanza_get_type(error)); COMPARE("error", xmpp_stanza_get_type(error));
/* FAIL - no list given */ /* FAIL - no list given */
@@ -212,7 +208,6 @@ static void test_stanza_error(xmpp_ctx_t *ctx)
"item", "mood", NULL); "item", "mood", NULL);
assert(item != NULL); assert(item != NULL);
assert(xmpp_stanza_get_children(item) != NULL); assert(xmpp_stanza_get_children(item) != NULL);
assert(xmpp_stanza_get_name(xmpp_stanza_get_children(item)) != NULL);
COMPARE("annoyed", xmpp_stanza_get_name(xmpp_stanza_get_children(item))); COMPARE("annoyed", xmpp_stanza_get_name(xmpp_stanza_get_children(item)));
item = xmpp_stanza_get_child_by_path( item = xmpp_stanza_get_child_by_path(
@@ -223,7 +218,6 @@ static void test_stanza_error(xmpp_ctx_t *ctx)
NULL); NULL);
assert(item != NULL); assert(item != NULL);
assert(xmpp_stanza_get_children(item) != NULL); assert(xmpp_stanza_get_children(item) != NULL);
assert(xmpp_stanza_get_name(xmpp_stanza_get_children(item)) != NULL);
COMPARE("annoyed", xmpp_stanza_get_name(xmpp_stanza_get_children(item))); COMPARE("annoyed", xmpp_stanza_get_name(xmpp_stanza_get_children(item)));
ret = xmpp_stanza_get_attributes(error, attr, attrlen); ret = xmpp_stanza_get_attributes(error, attr, attrlen);
@@ -243,6 +237,50 @@ static void test_stanza_error(xmpp_ctx_t *ctx)
xmpp_stanza_release(error); xmpp_stanza_release(error);
} }
static void test_stanza_bookmark(xmpp_ctx_t *ctx)
{
// clang-format off
static const char *str =
"<item xmlns=\"http://jabber.org/protocol/pubsub\" id=\"\">"
"<conference autojoin=\"\" name=\"Symbol(lit-nothing)\" xmlns=\"urn:xmpp:bookmarks:1\" />"
"</item>";
// clang-format on
xmpp_stanza_t *stanza = xmpp_stanza_new_from_string(ctx, str);
assert(stanza != NULL);
const char *id = xmpp_stanza_get_id(stanza);
assert(id != NULL);
assert(strcmp(id, "") == 0);
xmpp_stanza_t *child = xmpp_stanza_get_children(stanza);
COMPARE("conference", xmpp_stanza_get_name(child));
const char *autojoin = xmpp_stanza_get_attribute(child, "autojoin");
assert(autojoin != NULL);
assert(strcmp(autojoin, "") == 0);
xmpp_stanza_release(stanza);
}
static void test_stanza_copy(xmpp_ctx_t *ctx)
{
// clang-format off
static const char *str =
"<item xmlns=\"http://jabber.org/protocol/pubsub\" id=\"\">"
"<conference autojoin=\"\" name=\"Symbol(lit-nothing)\" xmlns=\"urn:xmpp:bookmarks:1\" />"
"</item>";
// clang-format on
xmpp_stanza_t *stanza = xmpp_stanza_new_from_string(ctx, str);
assert(stanza != NULL);
const char *id = xmpp_stanza_get_id(stanza);
assert(id != NULL);
assert(strcmp(id, "") == 0);
xmpp_stanza_t *child = xmpp_stanza_get_children(stanza);
COMPARE("conference", xmpp_stanza_get_name(child));
xmpp_stanza_t *copy = xmpp_stanza_copy(child);
xmpp_stanza_release(stanza);
COMPARE("conference", xmpp_stanza_get_name(copy));
xmpp_stanza_release(copy);
}
int main() int main()
{ {
xmpp_ctx_t *ctx; xmpp_ctx_t *ctx;
@@ -251,6 +289,8 @@ int main()
ctx = xmpp_ctx_new(&stanza_mem, NULL); ctx = xmpp_ctx_new(&stanza_mem, NULL);
assert(ctx != NULL); assert(ctx != NULL);
test_stanza_bookmark(ctx);
test_stanza_copy(ctx);
test_stanza_add_child(ctx); test_stanza_add_child(ctx);
test_stanza_from_string(ctx); test_stanza_from_string(ctx);
test_stanza_error(ctx); test_stanza_error(ctx);