5 Commits

Author SHA1 Message Date
Dmitry Podgorny
06cb1459f1 tls/securetransport: add client cert stub functions 2021-03-30 00:46:13 +03:00
Dmitry Podgorny
82f372fa49 Add tls_securetransport.c to EXTRA_DIST 2021-03-30 00:30:30 +03:00
Dmitry Podgorny
9ddc881102 tls/securetransport: tls_new() accepts xmpp_conn_t object 2021-03-30 00:30:30 +03:00
Dmitry Podgorny
f6ef50d134 tls/securetransport: fix indentation 2021-03-30 00:30:30 +03:00
Chris A. Taylor
bd87653c76 Add Secure Transport implementation of TLS 2021-03-30 00:30:30 +03:00
26 changed files with 366 additions and 1247 deletions

View File

@@ -5,22 +5,10 @@
xmpp_conn_set_jid(), the xmppAddr is chosen as JID
- <stream> element contains "from" attribute over TLS connections now
- GnuTLS can be selected optionally with configure script
- Support for manual certificate verification
- New API:
- xmpp_conn_set_client_cert()
- xmpp_conn_cert_xmppaddr_num()
- xmpp_conn_cert_xmppaddr()
- xmpp_conn_set_cafile()
- xmpp_conn_set_capath()
- xmpp_conn_set_certfail_handler()
- xmpp_conn_get_peer_cert()
- xmpp_tlscert_get_ctx()
- xmpp_tlscert_get_conn()
- xmpp_tlscert_get_pem()
- xmpp_tlscert_get_dnsname()
- xmpp_tlscert_get_string()
- xmpp_tlscert_get_description()
- xmpp_tlscert_free()
0.10.1
- Fixed compilation error when LibreSSL is used

View File

@@ -38,7 +38,7 @@ PROJECT_NAME = Strophe
# could be handy for archiving the generated documentation or if some version
# control system is used.
PROJECT_NUMBER = 0.11
PROJECT_NUMBER = 0.10
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a

View File

@@ -48,7 +48,6 @@ libstrophe_la_SOURCES = \
src/snprintf.c \
src/sock.c \
src/stanza.c \
src/tls.c \
src/util.c \
src/uuid.c
libstrophe_la_SOURCES += \
@@ -98,10 +97,12 @@ EXTRA_DIST = \
MIT-LICENSE.txt \
bootstrap.sh \
build-android.sh \
docs/footer.html \
examples/README.md \
jni/Android.mk \
jni/Application.mk \
src/tls_schannel.c \
src/tls_securetransport.c \
tests/res_query_dump.c
if TLS_WITH_GNUTLS
@@ -171,16 +172,6 @@ endif
check_PROGRAMS = $(TESTS)
if FUZZ
check_PROGRAMS += tests/test_fuzz
tests_test_fuzz_SOURCES = tests/test_fuzz.c
tests_test_fuzz_CFLAGS = -fsanitize=fuzzer,address $(PARSER_CFLAGS) $(STROPHE_FLAGS) \
-I$(top_srcdir)/src
tests_test_fuzz_LDADD = $(STROPHE_LIBS)
tests_test_fuzz_LDFLAGS = -static
endif
tests_check_parser_SOURCES = tests/check_parser.c tests/test.h
tests_check_parser_CFLAGS = $(PARSER_CFLAGS) $(STROPHE_FLAGS) \
-I$(top_srcdir)/src
@@ -239,8 +230,8 @@ tests_test_string_CFLAGS = $(STROPHE_FLAGS) -I$(top_srcdir)/src
tests_test_string_LDADD = $(STROPHE_LIBS)
tests_test_string_LDFLAGS = -static
tests_test_stanza_SOURCES = tests/test_stanza.c tests/test.h
tests_test_stanza_CFLAGS = $(STROPHE_FLAGS) -I$(top_srcdir)/src
tests_test_stanza_SOURCES = tests/test_stanza.c
tests_test_stanza_CFLAGS = $(STROPHE_FLAGS)
tests_test_stanza_LDADD = $(STROPHE_LIBS)
tests_test_stanza_LDFLAGS = -static

View File

@@ -8,7 +8,6 @@ BinPackParameters: 'false'
BreakBeforeBraces: Linux
ColumnLimit: '80'
DerivePointerAlignment: 'false'
IndentGotoLabels: false
IndentWidth: '4'
PointerAlignment: Right
SortIncludes: 'false'

View File

@@ -1,4 +1,4 @@
AC_INIT([libstrophe], [0.11.0], [jack@metajack.im])
AC_INIT([libstrophe], [0.10.1], [jack@metajack.im])
AC_CONFIG_MACRO_DIR([m4])
AM_INIT_AUTOMAKE([foreign])
LT_INIT([dlopen])
@@ -33,17 +33,6 @@ AC_ARG_ENABLE([tls],
AC_ARG_ENABLE([cares],
[AS_HELP_STRING([--enable-cares], [use c-ares for DNS resolution])])
AC_ARG_ENABLE([fuzzing],
[AS_HELP_STRING([--enable-fuzzing], [turn on fuzzing test])],
[case "${enableval}" in yes) fuzzing=true ;; no) fuzzing=false ;; *) AC_MSG_ERROR([bad value ${enableval} for --enable-fuzzing]) ;; esac],[fuzzing=false])
AM_CONDITIONAL([FUZZ], [test x$fuzzing = xtrue])
if test "x$enable_fuzzing" = "xyes" ; then
if test "x$CC" != "xclang" ; then
AC_MSG_ERROR(["You need to set CC=clang to use --enable-fuzzing, used $CC"])
fi
fi
AC_SEARCH_LIBS([socket], [network socket])
AC_CHECK_FUNCS([snprintf vsnprintf])
AC_CHECK_DECLS([va_copy], [], [], [#include <stdarg.h>])

View File

@@ -19,26 +19,12 @@
#define KA_TIMEOUT 60
#define KA_INTERVAL 1
static void print_tlscert(const xmpp_tlscert_t *cert)
{
const char *name;
size_t n;
for (n = 0; n < (unsigned)XMPP_CERT_ELEMENT_MAX; ++n) {
printf("\t%32s: %s\n", xmpp_tlscert_get_description(n),
xmpp_tlscert_get_string(cert, n));
}
n = 0;
while ((name = xmpp_tlscert_get_dnsname(cert, n++)) != NULL)
printf("\t%32s: %s\n", "dnsName", name);
printf("PEM:\n%s\n", xmpp_tlscert_get_pem(cert));
}
/* define a handler for connection events */
static void conn_handler(xmpp_conn_t *conn,
xmpp_conn_event_t status,
int error,
xmpp_stream_error_t *stream_error,
void *userdata)
void conn_handler(xmpp_conn_t *conn,
xmpp_conn_event_t status,
int error,
xmpp_stream_error_t *stream_error,
void *userdata)
{
xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata;
int secured;
@@ -51,11 +37,6 @@ static void conn_handler(xmpp_conn_t *conn,
secured = xmpp_conn_is_secured(conn);
fprintf(stderr, "DEBUG: connection is %s.\n",
secured ? "secured" : "NOT secured");
if (secured) {
xmpp_tlscert_t *cert = xmpp_conn_get_peer_cert(conn);
print_tlscert(cert);
xmpp_tlscert_free(cert);
}
xmpp_disconnect(conn);
} else {
fprintf(stderr, "DEBUG: disconnected\n");
@@ -63,23 +44,6 @@ static void conn_handler(xmpp_conn_t *conn,
}
}
static int certfail_handler(const xmpp_tlscert_t *cert,
const char *const errormsg)
{
char read_char[16] = {0};
printf("Received certificate can't be validated!\n");
printf("Reason: %s\n", errormsg);
print_tlscert(cert);
printf("Do you agree to connect?\n[y(es)|n(o)]: ");
fflush(stdout);
if (fgets(read_char, sizeof(read_char), stdin) == NULL) {
printf("fgets() failed\n");
return 0;
}
printf("\n");
return read_char[0] == 'y' || read_char[0] == 'Y';
}
static void usage(int exit_code)
{
fprintf(stderr,
@@ -88,18 +52,12 @@ static void usage(int exit_code)
" --jid <jid> The JID to use to authenticate.\n"
" --pass <pass> The password of the JID.\n"
" --tls-cert <cert> Path to client certificate.\n"
" --capath <path> Path to an additional CA trust store "
"(directory).\n"
" --cafile <path> Path to an additional CA trust store "
"(single file).\n"
" --tls-key <key> Path to private key.\n\n"
" --disable-tls Disable TLS.\n"
" --mandatory-tls Deny plaintext connection.\n"
" --trust-tls Trust TLS certificate.\n"
" --enable-certfail Enable certfail handler.\n"
" --legacy-ssl Use old style SSL.\n"
" --legacy-auth Allow legacy authentication.\n"
" --verbose Increase the verbosity level.\n"
" --tcp-keepalive Configure TCP keepalive.\n\n"
"Note: --disable-tls conflicts with --mandatory-tls or "
"--legacy-ssl\n");
@@ -112,10 +70,9 @@ int main(int argc, char **argv)
xmpp_ctx_t *ctx;
xmpp_conn_t *conn;
xmpp_log_t *log;
char *jid = NULL, *password = NULL, *cert = NULL, *key = NULL, *host = NULL,
*capath = NULL, *cafile = NULL;
char *jid = NULL, *password = NULL, *cert = NULL, *key = NULL, *host = NULL;
long flags = 0;
int tcp_keepalive = 0, verbosity = 0, certfail = 0;
int tcp_keepalive = 0;
int i;
unsigned long port = 0;
@@ -133,12 +90,8 @@ int main(int argc, char **argv)
flags |= XMPP_CONN_FLAG_LEGACY_SSL;
else if (strcmp(argv[i], "--legacy-auth") == 0)
flags |= XMPP_CONN_FLAG_LEGACY_AUTH;
else if (strcmp(argv[i], "--verbose") == 0)
verbosity++;
else if (strcmp(argv[i], "--tcp-keepalive") == 0)
tcp_keepalive = 1;
else if (strcmp(argv[i], "--enable-certfail") == 0)
certfail = 1;
else if ((strcmp(argv[i], "--jid") == 0) && (++i < argc))
jid = argv[i];
else if ((strcmp(argv[i], "--pass") == 0) && (++i < argc))
@@ -147,10 +100,6 @@ int main(int argc, char **argv)
cert = argv[i];
else if ((strcmp(argv[i], "--tls-key") == 0) && (++i < argc))
key = argv[i];
else if ((strcmp(argv[i], "--capath") == 0) && (++i < argc))
capath = argv[i];
else if ((strcmp(argv[i], "--cafile") == 0) && (++i < argc))
cafile = argv[i];
else
break;
}
@@ -175,7 +124,6 @@ int main(int argc, char **argv)
log = xmpp_get_default_logger(XMPP_LEVEL_DEBUG);
/* create a context */
ctx = xmpp_ctx_new(NULL, log);
xmpp_ctx_set_verbosity(ctx, verbosity);
/* create a connection */
conn = xmpp_conn_new(ctx);
@@ -195,13 +143,6 @@ int main(int argc, char **argv)
if (password)
xmpp_conn_set_pass(conn, password);
if (certfail)
xmpp_conn_set_certfail_handler(conn, certfail_handler);
if (capath)
xmpp_conn_set_capath(conn, capath);
if (cafile)
xmpp_conn_set_cafile(conn, cafile);
/* initiate connection */
if (xmpp_connect_client(conn, host, port, conn_handler, ctx) == XMPP_EOK) {

View File

@@ -77,7 +77,6 @@ typedef struct _xmpp_connlist_t {
struct _xmpp_ctx_t {
const xmpp_mem_t *mem;
const xmpp_log_t *log;
int verbosity;
xmpp_rand_t *rand;
xmpp_loop_status_t loop_status;
@@ -91,7 +90,6 @@ struct _xmpp_ctx_t {
void *xmpp_alloc(const xmpp_ctx_t *ctx, size_t size);
void *xmpp_realloc(const xmpp_ctx_t *ctx, void *p, size_t size);
char *xmpp_strdup(const xmpp_ctx_t *ctx, const char *s);
char *xmpp_strndup(const xmpp_ctx_t *ctx, const char *s, size_t len);
void xmpp_log(const xmpp_ctx_t *ctx,
const xmpp_log_level_t level,
@@ -104,8 +102,6 @@ void xmpp_error(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...);
void xmpp_warn(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...);
void xmpp_info(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...);
void xmpp_debug(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...);
void xmpp_debug_verbose(
int level, const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...);
/** connection **/
@@ -169,8 +165,6 @@ struct _xmpp_conn_t {
int tls_mandatory;
int tls_legacy_ssl;
int tls_trust;
char *tls_cafile;
char *tls_capath;
char *tls_client_cert;
char *tls_client_key;
int tls_failed; /* set when tls fails, so we don't try again */
@@ -178,7 +172,6 @@ struct _xmpp_conn_t {
mechanisms */
int auth_legacy_enabled;
int secured; /* set when stream is secured with TLS */
xmpp_certfail_handler certfail_handler;
/* if server returns <bind/> or <session/> we must do them */
int bind_required;

View File

@@ -75,7 +75,6 @@ static int _conn_connect(xmpp_conn_t *conn,
xmpp_conn_type_t type,
xmpp_conn_handler callback,
void *userdata);
static int _send_raw(xmpp_conn_t *conn, char *data, size_t len);
void xmpp_send_error(xmpp_conn_t *conn, xmpp_error_type_t type, char *text)
{
@@ -144,14 +143,11 @@ xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t *ctx)
conn->tls_legacy_ssl = 0;
conn->tls_trust = 0;
conn->tls_failed = 0;
conn->tls_cafile = NULL;
conn->tls_capath = NULL;
conn->tls_client_cert = NULL;
conn->tls_client_key = NULL;
conn->sasl_support = 0;
conn->auth_legacy_enabled = 0;
conn->secured = 0;
conn->certfail_handler = NULL;
conn->bind_required = 0;
conn->session_required = 0;
@@ -348,10 +344,6 @@ int xmpp_conn_release(xmpp_conn_t *conn)
xmpp_free(ctx, conn->tls_client_cert);
if (conn->tls_client_key)
xmpp_free(ctx, conn->tls_client_key);
if (conn->tls_cafile)
xmpp_free(ctx, conn->tls_cafile);
if (conn->tls_capath)
xmpp_free(ctx, conn->tls_capath);
xmpp_free(ctx, conn);
released = 1;
}
@@ -408,64 +400,6 @@ void xmpp_conn_set_jid(xmpp_conn_t *conn, const char *jid)
conn->jid = xmpp_strdup(conn->ctx, jid);
}
/** Set the Handler function which will be called when the TLS stack can't
* verify the CA of the server we're trying to connect to.
*
* @param conn a Strophe connection object
* @param hndl certfail Handler function
*
* @ingroup Connections
* @ingroup TLS
*/
void xmpp_conn_set_certfail_handler(xmpp_conn_t *const conn,
xmpp_certfail_handler hndl)
{
conn->certfail_handler = hndl;
}
/** Set the CAfile
*
* @param conn a Strophe connection object
* @param cert path to a certificate file
*
* @ingroup Connections
* @ingroup TLS
*/
void xmpp_conn_set_cafile(xmpp_conn_t *const conn, const char *path)
{
conn->tls_cafile = xmpp_strdup(conn->ctx, path);
}
/** Set the CApath
*
* @param conn a Strophe connection object
* @param cert path to a folder containing certificates
*
* @ingroup Connections
* @ingroup TLS
*/
void xmpp_conn_set_capath(xmpp_conn_t *const conn, const char *path)
{
conn->tls_capath = xmpp_strdup(conn->ctx, path);
}
/** Retrieve the peer certificate
*
* The returned Certificate object must be free'd by calling
* \ref xmpp_tlscert_free
*
* @param conn a Strophe connection object
*
* @return a Strophe Certificate object
*
* @ingroup Connections
* @ingroup TLS
*/
xmpp_tlscert_t *xmpp_conn_get_peer_cert(xmpp_conn_t *const conn)
{
return tls_peer_cert(conn);
}
/** Set the Client Certificate and Private Key that will be bound to the
* connection. If any of the both was previously set, it will be discarded.
* This should not be used after a connection is created. The function will
@@ -477,7 +411,6 @@ xmpp_tlscert_t *xmpp_conn_get_peer_cert(xmpp_conn_t *const conn)
* @param key path to a private key file
*
* @ingroup Connections
* @ingroup TLS
*/
void xmpp_conn_set_client_cert(xmpp_conn_t *const conn,
const char *const cert,
@@ -499,7 +432,6 @@ void xmpp_conn_set_client_cert(xmpp_conn_t *const conn,
* @return the number of xmppAddr entries in the client certificate
*
* @ingroup Connections
* @ingroup TLS
*/
unsigned int xmpp_conn_cert_xmppaddr_num(xmpp_conn_t *const conn)
{
@@ -514,7 +446,6 @@ unsigned int xmpp_conn_cert_xmppaddr_num(xmpp_conn_t *const conn)
* @return a string containing the xmppAddr or NULL if n is out of range
*
* @ingroup Connections
* @ingroup TLS
*/
char *xmpp_conn_cert_xmppaddr(xmpp_conn_t *const conn, unsigned int n)
{
@@ -917,9 +848,6 @@ void xmpp_send_raw_string(xmpp_conn_t *conn, const char *fmt, ...)
char buf[1024]; /* small buffer for common case */
char *bigbuf;
if (conn->state != XMPP_STATE_CONNECTED)
return;
va_start(ap, fmt);
len = xmpp_vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
@@ -938,10 +866,14 @@ void xmpp_send_raw_string(xmpp_conn_t *conn, const char *fmt, ...)
xmpp_vsnprintf(bigbuf, len, fmt, ap);
va_end(ap);
xmpp_debug(conn->ctx, "conn", "SENT: %s", bigbuf);
/* len - 1 so we don't send trailing \0 */
_send_raw(conn, bigbuf, len - 1);
xmpp_send_raw(conn, bigbuf, len - 1);
xmpp_free(conn->ctx, bigbuf);
} else {
/* go through xmpp_send_raw() which does the strdup() for us */
xmpp_debug(conn->ctx, "conn", "SENT: %s", buf);
xmpp_send_raw(conn, buf, len);
}
}
@@ -960,18 +892,37 @@ void xmpp_send_raw_string(xmpp_conn_t *conn, const char *fmt, ...)
*/
void xmpp_send_raw(xmpp_conn_t *conn, const char *data, size_t len)
{
char *d;
xmpp_send_queue_t *item;
if (conn->state != XMPP_STATE_CONNECTED)
return;
d = xmpp_strndup(conn->ctx, data, len);
if (!d) {
xmpp_error(conn->ctx, "conn", "Failed to strndup");
/* create send queue item for queue */
item = xmpp_alloc(conn->ctx, sizeof(xmpp_send_queue_t));
if (!item)
return;
item->data = xmpp_alloc(conn->ctx, len);
if (!item->data) {
xmpp_free(conn->ctx, item);
return;
}
memcpy(item->data, data, len);
item->len = len;
item->next = NULL;
item->written = 0;
_send_raw(conn, d, len);
/* add item to the send queue */
if (!conn->send_queue_tail) {
/* first item, set head and tail */
conn->send_queue_head = item;
conn->send_queue_tail = item;
} else {
/* add to the tail */
conn->send_queue_tail->next = item;
conn->send_queue_tail = item;
}
conn->send_queue_len++;
}
/** Send an XML stanza to the XMPP server.
@@ -985,18 +936,16 @@ void xmpp_send_raw(xmpp_conn_t *conn, const char *data, size_t len)
*/
void xmpp_send(xmpp_conn_t *conn, xmpp_stanza_t *stanza)
{
char *buf = NULL;
char *buf;
size_t len;
if (conn->state != XMPP_STATE_CONNECTED)
return;
if (xmpp_stanza_to_text(stanza, &buf, &len) != 0) {
xmpp_error(conn->ctx, "conn", "Failed to stanza_to_text");
return;
if (conn->state == XMPP_STATE_CONNECTED) {
if (xmpp_stanza_to_text(stanza, &buf, &len) == 0) {
xmpp_send_raw(conn, buf, len);
xmpp_debug(conn->ctx, "conn", "SENT: %s", buf);
xmpp_free(conn->ctx, buf);
}
}
_send_raw(conn, buf, len);
}
/** Send the opening &lt;stream:stream&gt; tag to the server.
@@ -1516,36 +1465,3 @@ static int _conn_connect(xmpp_conn_t *conn,
return 0;
}
static int _send_raw(xmpp_conn_t *conn, char *data, size_t len)
{
xmpp_send_queue_t *item;
/* create send queue item for queue */
item = xmpp_alloc(conn->ctx, sizeof(xmpp_send_queue_t));
if (!item) {
xmpp_error(conn->ctx, "conn", "DROPPED: %s", data);
xmpp_free(conn->ctx, data);
return XMPP_EMEM;
}
item->data = data;
item->len = len;
item->next = NULL;
item->written = 0;
/* add item to the send queue */
if (!conn->send_queue_tail) {
/* first item, set head and tail */
conn->send_queue_head = item;
conn->send_queue_tail = item;
} else {
/* add to the tail */
conn->send_queue_tail->next = item;
conn->send_queue_tail = item;
}
conn->send_queue_len++;
xmpp_debug_verbose(2, conn->ctx, "conn", "QUEUED: %s", data);
xmpp_debug_verbose(1, conn->ctx, "conn", "Added queue element: %p", item);
return XMPP_EOK;
}

View File

@@ -265,13 +265,6 @@ void xmpp_log(const xmpp_ctx_t *ctx,
char *buf;
va_list copy;
if (!ctx->log->handler)
return;
if (ctx->log->handler == xmpp_default_logger &&
level < *(xmpp_log_level_t *)ctx->log->userdata)
return;
va_copy(copy, ap);
ret = xmpp_vsnprintf(smbuf, sizeof(smbuf), fmt, ap);
if (ret >= (int)sizeof(smbuf)) {
@@ -295,7 +288,8 @@ void xmpp_log(const xmpp_ctx_t *ctx,
}
va_end(copy);
ctx->log->handler(ctx->log->userdata, level, area, buf);
if (ctx->log->handler)
ctx->log->handler(ctx->log->userdata, level, area, buf);
if (buf != smbuf)
xmpp_free(ctx, buf);
@@ -377,30 +371,6 @@ void xmpp_debug(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...)
va_end(ap);
}
/** Write to the log at the DEBUG level if verbosity is enabled.
* This is a convenience function for writing to the log at the DEBUG level.
* It takes a printf-style format string followed by a variable list of
* arguments for formatting.
*
* @param level the verbosity level
* @param ctx a Strophe context object
* @param area the area to log for
* @param fmt a printf-style format string followed by a variable list of
* arguments to format
*/
void xmpp_debug_verbose(
int level, const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...)
{
va_list ap;
if (ctx->verbosity < level)
return;
va_start(ap, fmt);
xmpp_log(ctx, XMPP_LEVEL_DEBUG, area, fmt, ap);
va_end(ap);
}
/** Create and initialize a Strophe context object.
* If mem is NULL, a default allocation setup will be used which
* wraps malloc(), free(), and realloc() from the standard library.
@@ -473,15 +443,3 @@ void xmpp_ctx_set_timeout(xmpp_ctx_t *ctx, unsigned long timeout)
{
ctx->timeout = timeout;
}
/** Set the verbosity level of a Strophe context.
*
* @param ctx a Strophe context object
* @param level the verbosity level
*
* @ingroup Context
*/
void xmpp_ctx_set_verbosity(xmpp_ctx_t *ctx, int level)
{
ctx->verbosity = level;
}

View File

@@ -110,7 +110,6 @@ void xmpp_run_once(xmpp_ctx_t *ctx, unsigned long timeout)
xmpp_debug(ctx, "xmpp", "Send error occurred, disconnecting.");
conn->error = ECONNABORTED;
conn_disconnect(conn);
goto NEXT_ITEM;
}
}
@@ -134,9 +133,6 @@ void xmpp_run_once(xmpp_ctx_t *ctx, unsigned long timeout)
break; /* partial write or an error */
/* all data for this queue item written, delete and move on */
xmpp_debug(conn->ctx, "conn", "SENT: %s", sq->data);
xmpp_debug_verbose(1, ctx, "xmpp",
"Finished writing queue element: %p.", sq);
xmpp_free(ctx, sq->data);
tsq = sq;
sq = sq->next;
@@ -158,7 +154,7 @@ void xmpp_run_once(xmpp_ctx_t *ctx, unsigned long timeout)
conn->error = ECONNABORTED;
conn_disconnect(conn);
}
NEXT_ITEM:
connitem = connitem->next;
}

View File

@@ -295,26 +295,12 @@ char *parser_attr_name(xmpp_ctx_t *ctx, char *nsname)
return _xml_name(ctx, nsname);
}
static void _free_parent_stanza(xmpp_stanza_t *stanza)
{
xmpp_stanza_t *parent;
for (parent = stanza; parent->parent != NULL; parent = parent->parent)
;
xmpp_stanza_release(parent);
}
/* free a parser */
void parser_free(parser_t *parser)
{
if (parser->expat)
XML_ParserFree(parser->expat);
if (parser->stanza) {
_free_parent_stanza(parser->stanza);
parser->stanza = NULL;
}
if (parser->inner_text) {
xmpp_free(parser->ctx, parser->inner_text);
parser->inner_text = NULL;
@@ -344,7 +330,7 @@ int parser_reset(parser_t *parser)
}
if (parser->stanza) {
_free_parent_stanza(parser->stanza);
xmpp_stanza_release(parser->stanza);
parser->stanza = NULL;
}

View File

@@ -262,22 +262,13 @@ char *parser_attr_name(xmpp_ctx_t *ctx, char *nsname)
return xmpp_strdup(ctx, nsname);
}
static void _free_parent_stanza(xmpp_stanza_t *stanza)
{
xmpp_stanza_t *parent;
for (parent = stanza; parent->parent != NULL; parent = parent->parent)
;
xmpp_stanza_release(parent);
}
/* free a parser */
void parser_free(parser_t *parser)
{
if (parser->xmlctx)
xmlFreeParserCtxt(parser->xmlctx);
if (parser->stanza)
_free_parent_stanza(parser->stanza);
xmpp_stanza_release(parser->stanza);
xmpp_free(parser->ctx, parser);
}
@@ -287,7 +278,7 @@ int parser_reset(parser_t *parser)
if (parser->xmlctx)
xmlFreeParserCtxt(parser->xmlctx);
if (parser->stanza)
_free_parent_stanza(parser->stanza);
xmpp_stanza_release(parser->stanza);
parser->stanza = NULL;
parser->depth = 0;

View File

@@ -1210,9 +1210,9 @@ xmpp_stanza_t *xmpp_stanza_reply_error(xmpp_stanza_t *stanza,
{
xmpp_ctx_t *ctx = stanza->ctx;
xmpp_stanza_t *reply = NULL;
xmpp_stanza_t *error = NULL;
xmpp_stanza_t *item = NULL;
xmpp_stanza_t *text_stanza = NULL;
xmpp_stanza_t *error;
xmpp_stanza_t *item;
xmpp_stanza_t *text_stanza;
const char *to;
if (!error_type || !condition)
@@ -1221,53 +1221,41 @@ xmpp_stanza_t *xmpp_stanza_reply_error(xmpp_stanza_t *stanza,
reply = xmpp_stanza_reply(stanza);
if (!reply)
goto quit_err;
if (xmpp_stanza_set_type(reply, "error") != XMPP_EOK)
goto quit_err;
xmpp_stanza_set_type(reply, "error");
to = xmpp_stanza_get_to(stanza);
if (to)
if (xmpp_stanza_set_from(reply, to) != XMPP_EOK)
goto quit_err;
xmpp_stanza_set_from(reply, to);
error = xmpp_stanza_new(ctx);
if (!error)
goto quit_err;
if (xmpp_stanza_set_name(error, "error") != XMPP_EOK)
goto quit_err;
if (xmpp_stanza_set_type(error, error_type) != XMPP_EOK)
goto quit_err;
if (xmpp_stanza_add_child(reply, error) != XMPP_EOK)
goto quit_err;
xmpp_stanza_set_name(error, "error");
xmpp_stanza_set_type(error, error_type);
xmpp_stanza_add_child(reply, error);
xmpp_stanza_release(error);
item = xmpp_stanza_new(ctx);
if (!item)
goto quit_err;
if (xmpp_stanza_set_name(item, condition) != XMPP_EOK)
goto quit_err;
if (xmpp_stanza_set_ns(item, XMPP_NS_STANZAS_IETF) != XMPP_EOK)
goto quit_err;
if (xmpp_stanza_add_child(error, item) != XMPP_EOK)
goto quit_err;
xmpp_stanza_set_name(item, condition);
xmpp_stanza_set_ns(item, XMPP_NS_STANZAS_IETF);
xmpp_stanza_add_child(error, item);
xmpp_stanza_release(item);
if (text) {
item = xmpp_stanza_new(ctx);
if (!item)
goto quit_err;
if (xmpp_stanza_set_name(item, "text") != XMPP_EOK)
goto quit_err;
if (xmpp_stanza_set_ns(item, XMPP_NS_STANZAS_IETF) != XMPP_EOK)
goto quit_err;
if (xmpp_stanza_add_child(error, item) != XMPP_EOK)
goto quit_err;
xmpp_stanza_set_name(item, "text");
xmpp_stanza_set_ns(item, XMPP_NS_STANZAS_IETF);
xmpp_stanza_add_child(error, item);
xmpp_stanza_release(item);
text_stanza = xmpp_stanza_new(ctx);
if (!text_stanza)
goto quit_err;
if (xmpp_stanza_set_text(text_stanza, text) != XMPP_EOK)
goto quit_err;
if (xmpp_stanza_add_child(item, text_stanza) != XMPP_EOK)
goto quit_err;
xmpp_stanza_set_text(text_stanza, text);
xmpp_stanza_add_child(item, text_stanza);
xmpp_stanza_release(text_stanza);
}
@@ -1276,12 +1264,6 @@ xmpp_stanza_t *xmpp_stanza_reply_error(xmpp_stanza_t *stanza,
quit_err:
if (reply)
xmpp_stanza_release(reply);
if (error)
xmpp_stanza_release(error);
if (item)
xmpp_stanza_release(item);
if (text_stanza)
xmpp_stanza_release(text_stanza);
return NULL;
}

214
src/tls.c
View File

@@ -1,214 +0,0 @@
/* tls.c
** strophe XMPP client library -- generic TLS functions
**
** Copyright (C) 2021 Steffen Jaeckel <jaeckel-floss@eyet-services.de>
**
** This software is provided AS-IS with no warranty, either express
** or implied.
**
** This program is dual licensed under the MIT and GPLv3 licenses.
*/
/** @file
* Generic TLS functionality.
*/
/** @defgroup TLS SSL/TLS specific functionality
* These functions provide SSL/TLS specific functionality.
*/
#include <errno.h>
#include <stdarg.h>
#include <string.h>
#include "strophe.h"
#include "common.h"
struct _dnsname_t {
char **data;
size_t cur, max;
};
const size_t tlscert_dnsnames_increment = 4;
/** Get the Strophe context which is assigned to this certificate.
*
* @param cert a Strophe TLS certificate object
*
* @return the Strophe context object where this certificate originates from
*
* @ingroup TLS
*/
xmpp_ctx_t *xmpp_tlscert_get_ctx(const xmpp_tlscert_t *cert)
{
return cert->ctx;
}
/** Get the Strophe connection which is assigned to this certificate.
*
* @param cert a Strophe TLS certificate object
*
* @return the Strophe connection object where this certificate originates from
*
* @ingroup TLS
*/
xmpp_conn_t *xmpp_tlscert_get_conn(const xmpp_tlscert_t *cert)
{
return cert->conn;
}
/** Get the complete PEM of this certificate.
*
* @param cert a Strophe TLS certificate object
*
* @return a string containing the PEM of this certificate
*
* @ingroup TLS
*/
const char *xmpp_tlscert_get_pem(const xmpp_tlscert_t *cert)
{
return cert->pem;
}
/** Get the dnsName entries out of the SubjectAlternativeNames.
*
* Note: Max. `MAX_NUM_DNSNAMES` are supported.
*
* @param cert a Strophe TLS certificate object
* @param n which dnsName entry
*
* @return a string with the n'th dnsName
*
* @ingroup TLS
*/
const char *xmpp_tlscert_get_dnsname(const xmpp_tlscert_t *cert, size_t n)
{
if (n >= cert->dnsnames->cur)
return NULL;
return cert->dnsnames->data[n];
}
/** Get various parts of the certificate as String.
*
* c.f. \ref xmpp_cert_element_t for details.
*
* @param cert a Strophe TLS certificate object
* @param elmnt which part of the certificate
*
* @return a string with the part of the certificate
*
* @ingroup TLS
*/
const char *xmpp_tlscert_get_string(const xmpp_tlscert_t *cert,
xmpp_cert_element_t elmnt)
{
if (elmnt >= XMPP_CERT_ELEMENT_MAX)
return NULL;
return cert->elements[elmnt];
}
/** Get a descriptive string for each xmpp_cert_element_t.
*
* c.f. \ref xmpp_cert_element_t for details.
*
* @param cert a Strophe TLS certificate object
* @param elmnt which element
*
* @return a string with the description
*
* @ingroup TLS
*/
const char *xmpp_tlscert_get_description(xmpp_cert_element_t elmnt)
{
static const char *descriptions[] = {
"X.509 Version",
"SerialNumber",
"Subject",
"Issuer",
"Issued On",
"Expires On",
"Public Key Algorithm",
"Certificate Signature Algorithm",
"Fingerprint SHA-1",
"Fingerprint SHA-256",
};
if (elmnt >= XMPP_CERT_ELEMENT_MAX)
return NULL;
return descriptions[elmnt];
}
/** Allocate and initialize a Strophe TLS certificate object.
*
* @param ctx a Strophe context object
*
* @return a certificate object or NULL
*/
xmpp_tlscert_t *tlscert_new(xmpp_ctx_t *ctx)
{
xmpp_tlscert_t *tlscert = xmpp_alloc(ctx, sizeof(*tlscert));
if (!tlscert)
return NULL;
memset(tlscert, 0, sizeof(*tlscert));
tlscert->dnsnames = xmpp_alloc(ctx, sizeof(*tlscert->dnsnames));
if (!tlscert->dnsnames) {
xmpp_free(ctx, tlscert);
return NULL;
}
memset(tlscert->dnsnames, 0, sizeof(*tlscert->dnsnames));
tlscert->ctx = ctx;
return tlscert;
}
/** Free a certificate object.
*
* @param cert a Strophe TLS certificate object
*
* @ingroup TLS
*/
void xmpp_tlscert_free(xmpp_tlscert_t *cert)
{
size_t n;
for (n = 0; n < ARRAY_SIZE(cert->elements); ++n) {
if (cert->elements[n])
xmpp_free(cert->ctx, cert->elements[n]);
}
if (cert->dnsnames->data) {
for (n = 0; n < cert->dnsnames->cur; ++n) {
if (cert->dnsnames->data[n])
xmpp_free(cert->ctx, cert->dnsnames->data[n]);
}
}
xmpp_free(cert->ctx, cert->dnsnames->data);
xmpp_free(cert->ctx, cert->dnsnames);
if (cert->pem)
xmpp_free(cert->ctx, cert->pem);
xmpp_free(cert->ctx, cert);
}
/** Add a dnsName to the Strophe TLS certificate object.
*
* @param cert a Strophe TLS certificate object
* @param dnsname dnsName that shall be stored
*
* @return classic Unix style - 0=success, 1=error
*/
int tlscert_add_dnsname(xmpp_tlscert_t *cert, const char *dnsname)
{
if ((cert->dnsnames->cur + 1) >= cert->dnsnames->max) {
char **dnsnames =
xmpp_realloc(cert->ctx, cert->dnsnames->data,
(cert->dnsnames->max + tlscert_dnsnames_increment) *
sizeof(char **));
if (!dnsnames)
return 1;
cert->dnsnames->data = dnsnames;
cert->dnsnames->max += tlscert_dnsnames_increment;
}
cert->dnsnames->data[cert->dnsnames->cur++] =
xmpp_strdup(cert->ctx, dnsname);
return 0;
}

View File

@@ -21,18 +21,6 @@
typedef struct _tls tls_t;
typedef struct _dnsname_t dnsname_t;
struct _xmpp_tlscert_t {
xmpp_ctx_t *ctx;
xmpp_conn_t *conn;
char *pem;
char *elements[XMPP_CERT_ELEMENT_MAX];
dnsname_t *dnsnames;
};
/* provided by the real TLS implementation */
void tls_initialize(void);
void tls_shutdown(void);
@@ -42,7 +30,6 @@ void tls_free(tls_t *tls);
char *tls_id_on_xmppaddr(xmpp_conn_t *conn, unsigned int n);
unsigned int tls_id_on_xmppaddr_num(xmpp_conn_t *conn);
xmpp_tlscert_t *tls_peer_cert(xmpp_conn_t *conn);
int tls_set_credentials(tls_t *tls, const char *cafilename);
int tls_start(tls_t *tls);
@@ -57,9 +44,4 @@ int tls_write(tls_t *tls, const void *buff, size_t len);
int tls_clear_pending_write(tls_t *tls);
int tls_is_recoverable(int error);
/* provided by tls.c */
xmpp_tlscert_t *tlscert_new(xmpp_ctx_t *ctx);
int tlscert_add_dnsname(xmpp_tlscert_t *cert, const char *dnsname);
#endif /* __LIBSTROPHE_TLS_H__ */

View File

@@ -61,12 +61,6 @@ void tls_free(tls_t *tls)
return;
}
xmpp_tlscert_t *tls_peer_cert(xmpp_conn_t *conn)
{
UNUSED(conn);
return NULL;
}
int tls_set_credentials(tls_t *tls, const char *cafilename)
{
UNUSED(tls);

View File

@@ -22,9 +22,12 @@
#include "tls.h"
#include "sock.h"
/* FIXME this shouldn't be a constant string */
#define CAFILE "/etc/ssl/certs/ca-certificates.crt"
struct _tls {
xmpp_ctx_t *ctx; /* do we need this? */
xmpp_conn_t *conn;
sock_t sock;
gnutls_session_t session;
gnutls_certificate_credentials_t cred;
gnutls_x509_crt_t client_cert;
@@ -120,10 +123,10 @@ static int _tls_get_id_on_xmppaddr(xmpp_conn_t *conn,
return GNUTLS_E_X509_UNKNOWN_SAN;
}
static int _tls_id_on_xmppaddr(xmpp_conn_t *conn,
gnutls_x509_crt_t cert,
unsigned int n,
char **ret)
int _tls_id_on_xmppaddr(xmpp_conn_t *conn,
gnutls_x509_crt_t cert,
unsigned int n,
char **ret)
{
int res = GNUTLS_E_SUCCESS;
unsigned int i, j;
@@ -170,144 +173,6 @@ unsigned int tls_id_on_xmppaddr_num(xmpp_conn_t *conn)
return ret;
}
static xmpp_tlscert_t *_x509_to_tlscert(xmpp_ctx_t *ctx, gnutls_x509_crt_t cert)
{
int res;
char buf[512], smallbuf[64];
size_t size, m;
unsigned int algo, n;
gnutls_datum_t data;
time_t time_val;
xmpp_tlscert_t *tlscert = tlscert_new(ctx);
gnutls_x509_crt_export2(cert, GNUTLS_X509_FMT_PEM, &data);
tlscert->pem = xmpp_alloc(ctx, data.size + 1);
memcpy(tlscert->pem, data.data, data.size);
tlscert->pem[data.size] = '\0';
gnutls_free(data.data);
size = sizeof(buf);
gnutls_x509_crt_get_dn(cert, buf, &size);
tlscert->elements[XMPP_CERT_SUBJECT] = xmpp_strdup(ctx, buf);
size = sizeof(buf);
gnutls_x509_crt_get_issuer_dn(cert, buf, &size);
tlscert->elements[XMPP_CERT_ISSUER] = xmpp_strdup(ctx, buf);
time_val = gnutls_x509_crt_get_activation_time(cert);
tlscert->elements[XMPP_CERT_NOTBEFORE] = xmpp_strdup(ctx, ctime(&time_val));
tlscert->elements[XMPP_CERT_NOTBEFORE]
[strlen(tlscert->elements[XMPP_CERT_NOTBEFORE]) - 1] =
'\0';
time_val = gnutls_x509_crt_get_expiration_time(cert);
tlscert->elements[XMPP_CERT_NOTAFTER] = xmpp_strdup(ctx, ctime(&time_val));
tlscert->elements[XMPP_CERT_NOTAFTER]
[strlen(tlscert->elements[XMPP_CERT_NOTAFTER]) - 1] = '\0';
size = sizeof(smallbuf);
gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_SHA1, smallbuf, &size);
hex_encode(buf, smallbuf, size);
tlscert->elements[XMPP_CERT_FINGERPRINT_SHA1] = xmpp_strdup(ctx, buf);
size = sizeof(smallbuf);
gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_SHA256, smallbuf, &size);
hex_encode(buf, smallbuf, size);
tlscert->elements[XMPP_CERT_FINGERPRINT_SHA256] = xmpp_strdup(ctx, buf);
xmpp_snprintf(buf, sizeof(buf), "%d", gnutls_x509_crt_get_version(cert));
tlscert->elements[XMPP_CERT_VERSION] = xmpp_strdup(ctx, buf);
algo = gnutls_x509_crt_get_pk_algorithm(cert, NULL);
tlscert->elements[XMPP_CERT_KEYALG] =
xmpp_strdup(ctx, gnutls_pk_algorithm_get_name(algo));
algo = gnutls_x509_crt_get_signature_algorithm(cert);
tlscert->elements[XMPP_CERT_SIGALG] =
xmpp_strdup(ctx, gnutls_sign_get_name(algo));
size = sizeof(smallbuf);
gnutls_x509_crt_get_serial(cert, smallbuf, &size);
hex_encode(buf, smallbuf, size);
tlscert->elements[XMPP_CERT_SERIALNUMBER] = xmpp_strdup(ctx, buf);
for (n = 0, m = 0, res = 0; res != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
++n) {
size = sizeof(buf);
res = gnutls_x509_crt_get_subject_alt_name(cert, n, buf, &size, NULL);
if (res == GNUTLS_SAN_DNSNAME) {
if (tlscert_add_dnsname(tlscert, buf))
xmpp_debug(ctx, "tls", "Can't store dnsName(%zu): %s", m, buf);
m++;
}
}
return tlscert;
}
static int _tls_verify(gnutls_session_t session)
{
tls_t *tls = gnutls_session_get_ptr(session);
const gnutls_datum_t *cert_list;
gnutls_certificate_type_t type;
gnutls_datum_t out;
unsigned int cert_list_size = 0, status;
gnutls_x509_crt_t cert;
if (gnutls_certificate_type_get(session) != GNUTLS_CRT_X509)
return -1;
if (gnutls_certificate_verify_peers2(session, &status) < 0) {
xmpp_error(tls->ctx, "tls", "Verify peers failed");
return -1;
}
type = gnutls_certificate_type_get(session);
if (gnutls_certificate_verification_status_print(status, type, &out, 0) <
0) {
xmpp_error(tls->ctx, "tls", "Status print failed");
return -1;
}
/* Return early if the Certificate is trusted
* OR if we trust all Certificates */
if (status == 0 || tls->conn->tls_trust)
return 0;
if (!tls->conn->certfail_handler) {
xmpp_error(tls->ctx, "tls",
"No certfail handler set, canceling connection attempt");
return -1;
}
cert_list = gnutls_certificate_get_peers(session, &cert_list_size);
/* OpenSSL displays the certificate chain in reverse order than GnuTLS.
* To show consistent behavior to the user, traverse the list from the
* end.
*/
while (cert_list_size--) {
gnutls_x509_crt_init(&cert);
gnutls_x509_crt_import(cert, &cert_list[cert_list_size],
GNUTLS_X509_FMT_DER);
xmpp_tlscert_t *tlscert = _x509_to_tlscert(tls->ctx, cert);
if (!tlscert) {
gnutls_x509_crt_deinit(cert);
gnutls_free(out.data);
return -1;
}
if (tls->conn->certfail_handler(tlscert, (char *)out.data) == 0) {
xmpp_tlscert_free(tlscert);
gnutls_x509_crt_deinit(cert);
gnutls_free(out.data);
return -1;
}
xmpp_tlscert_free(tlscert);
gnutls_x509_crt_deinit(cert);
}
gnutls_free(out.data);
return 0;
}
tls_t *tls_new(xmpp_conn_t *conn)
{
tls_t *tls = xmpp_alloc(conn->ctx, sizeof(tls_t));
@@ -315,11 +180,11 @@ tls_t *tls_new(xmpp_conn_t *conn)
if (tls) {
memset(tls, 0, sizeof(*tls));
tls->ctx = conn->ctx;
tls->conn = conn;
tls->sock = conn->sock;
gnutls_init(&tls->session, GNUTLS_CLIENT);
gnutls_certificate_allocate_credentials(&tls->cred);
tls_set_credentials(tls, NULL);
tls_set_credentials(tls, CAFILE);
if (conn->tls_client_cert && conn->tls_client_key) {
tls->client_cert = _tls_load_cert(conn);
@@ -336,10 +201,7 @@ tls_t *tls_new(xmpp_conn_t *conn)
GNUTLS_X509_FMT_PEM);
}
gnutls_certificate_set_verify_function(tls->cred, _tls_verify);
gnutls_set_default_priority(tls->session);
gnutls_session_set_ptr(tls->session, tls);
/* fixme: this may require setting a callback on win32? */
gnutls_transport_set_int(tls->session, conn->sock);
@@ -357,38 +219,13 @@ void tls_free(tls_t *tls)
xmpp_free(tls->ctx, tls);
}
xmpp_tlscert_t *tls_peer_cert(xmpp_conn_t *conn)
{
xmpp_tlscert_t *tlscert = NULL;
if (conn && conn->tls && conn->tls->session) {
unsigned int list_size = 0;
const gnutls_datum_t *der_cert =
gnutls_certificate_get_peers(conn->tls->session, &list_size);
if (der_cert && list_size) {
gnutls_x509_crt_t cert;
if (gnutls_x509_crt_init(&cert) < 0)
return NULL;
if (gnutls_x509_crt_import(cert, der_cert, GNUTLS_X509_FMT_DER) ==
0)
tlscert = _x509_to_tlscert(conn->ctx, cert);
gnutls_x509_crt_deinit(cert);
}
}
return tlscert;
}
int tls_set_credentials(tls_t *tls, const char *cafilename)
{
UNUSED(cafilename);
int err;
/* set trusted credentials -- takes a .pem filename */
int err = gnutls_certificate_set_x509_system_trust(tls->cred);
if (err >= 0 && tls->conn->tls_cafile)
err = gnutls_certificate_set_x509_trust_file(
tls->cred, tls->conn->tls_cafile, GNUTLS_X509_FMT_PEM);
if (err >= 0 && tls->conn->tls_capath)
err = gnutls_certificate_set_x509_trust_dir(
tls->cred, tls->conn->tls_capath, GNUTLS_X509_FMT_PEM);
err = gnutls_certificate_set_x509_trust_file(tls->cred, cafilename,
GNUTLS_X509_FMT_PEM);
if (err >= 0) {
err = gnutls_credentials_set(tls->session, GNUTLS_CRD_CERTIFICATE,
tls->cred);
@@ -400,9 +237,9 @@ int tls_set_credentials(tls_t *tls, const char *cafilename)
int tls_start(tls_t *tls)
{
sock_set_blocking(tls->conn->sock);
sock_set_blocking(tls->sock);
tls->lasterror = gnutls_handshake(tls->session);
sock_set_nonblocking(tls->conn->sock);
sock_set_nonblocking(tls->sock);
return tls->lasterror == GNUTLS_E_SUCCESS;
}

View File

@@ -91,10 +91,8 @@ static void _tls_log_error(xmpp_ctx_t *ctx);
static void _tls_dump_cert_info(tls_t *tls);
static X509 *_tls_cert_read(xmpp_conn_t *conn);
static int _tls_xaddr_nid(void);
static int _tls_xmppaddr_to_string(GENERAL_NAME *name, char **res);
static int _tls_dnsname_to_string(GENERAL_NAME *name, char **res);
static GENERAL_NAMES *_tls_conn_get_names(xmpp_conn_t *conn);
static GENERAL_NAMES *_tls_cert_get_names(X509 *client_cert);
static int _tls_name_to_xmppaddr(GENERAL_NAME *name, char **res);
static GENERAL_NAMES *_tls_cert_get_names(xmpp_conn_t *conn);
#define TLS_ERROR_STR(error, table) \
_tls_error_str(error, table, ARRAY_SIZE(table))
@@ -257,7 +255,7 @@ char *tls_id_on_xmppaddr(xmpp_conn_t *conn, unsigned int n)
{
char *ret = NULL;
int i, j;
GENERAL_NAMES *names = _tls_conn_get_names(conn);
GENERAL_NAMES *names = _tls_cert_get_names(conn);
if (!names)
return NULL;
int num_names = sk_GENERAL_NAME_num(names);
@@ -266,7 +264,7 @@ char *tls_id_on_xmppaddr(xmpp_conn_t *conn, unsigned int n)
GENERAL_NAME *name = sk_GENERAL_NAME_value(names, i);
if (name == NULL)
break;
if (_tls_xmppaddr_to_string(name, &res))
if (_tls_name_to_xmppaddr(name, &res))
continue;
if (j == (int)n) {
xmpp_debug(conn->ctx, "tls", "extracted jid %s from id-on-xmppAddr",
@@ -285,13 +283,13 @@ char *tls_id_on_xmppaddr(xmpp_conn_t *conn, unsigned int n)
unsigned int tls_id_on_xmppaddr_num(xmpp_conn_t *conn)
{
unsigned int ret = 0;
GENERAL_NAMES *names = _tls_conn_get_names(conn);
GENERAL_NAMES *names = _tls_cert_get_names(conn);
if (!names)
return 0;
int j, num_names = sk_GENERAL_NAME_num(names);
for (j = 0; j < num_names; ++j) {
GENERAL_NAME *name = sk_GENERAL_NAME_value(names, j);
if (_tls_xmppaddr_to_string(name, NULL))
if (_tls_name_to_xmppaddr(name, NULL))
continue;
ret++;
}
@@ -299,216 +297,10 @@ unsigned int tls_id_on_xmppaddr_num(xmpp_conn_t *conn)
return ret;
}
static int _convert_ASN1TIME(ASN1_TIME *ansi_time, char *buf, size_t len)
{
BIO *bio = BIO_new(BIO_s_mem());
int rc = ASN1_TIME_print(bio, ansi_time);
if (rc <= 0) {
BIO_free(bio);
return 0;
}
rc = BIO_gets(bio, buf, len);
if (rc <= 0) {
BIO_free(bio);
return 0;
}
BIO_free(bio);
return 1;
}
static char *_asn1_time_to_str(const xmpp_ctx_t *ctx, ASN1_TIME *t)
{
char buf[128];
int res = _convert_ASN1TIME(t, buf, sizeof(buf));
if (res) {
return xmpp_strdup(ctx, buf);
}
return NULL;
}
static char *
_get_fingerprint(const xmpp_ctx_t *ctx, X509 *err_cert, xmpp_cert_element_t el)
{
unsigned char buf[EVP_MAX_MD_SIZE];
unsigned int len;
const EVP_MD *digest;
switch (el) {
case XMPP_CERT_FINGERPRINT_SHA1:
digest = EVP_sha1();
break;
case XMPP_CERT_FINGERPRINT_SHA256:
digest = EVP_sha256();
break;
default:
return NULL;
}
if (X509_digest(err_cert, digest, buf, &len) != 0) {
char fingerprint[4 * EVP_MAX_MD_SIZE];
hex_encode(fingerprint, buf, len);
return xmpp_strdup(ctx, fingerprint);
}
return NULL;
}
static char *
_get_alg(const xmpp_ctx_t *ctx, X509 *err_cert, xmpp_cert_element_t el)
{
int rc, alg_nid = NID_undef;
switch (el) {
case XMPP_CERT_KEYALG: {
#if OPENSSL_VERSION_NUMBER < 0x10100000L
alg_nid = OBJ_obj2nid(err_cert->cert_info->key->algor->algorithm);
#else
X509_PUBKEY *pubkey = X509_get_X509_PUBKEY(err_cert);
ASN1_OBJECT *ppkalg = NULL;
rc = X509_PUBKEY_get0_param(&ppkalg, NULL, NULL, NULL, pubkey);
if (rc) {
alg_nid = OBJ_obj2nid(ppkalg);
}
#endif
} break;
case XMPP_CERT_SIGALG: {
#if OPENSSL_VERSION_NUMBER < 0x10100000L
alg_nid = OBJ_obj2nid(err_cert->sig_alg->algorithm);
#else
const X509_ALGOR *palg;
X509_get0_signature(NULL, &palg, err_cert);
alg_nid = OBJ_obj2nid(palg->algorithm);
#endif
} break;
default:
break;
}
if (alg_nid != NID_undef) {
const char *alg = OBJ_nid2ln(alg_nid);
if (alg) {
return xmpp_strdup(ctx, alg);
}
}
return NULL;
}
static xmpp_tlscert_t *_x509_to_tlscert(xmpp_ctx_t *ctx, X509 *cert)
{
char *subject, *issuer, buf[32];
xmpp_tlscert_t *tlscert = tlscert_new(ctx);
if (!tlscert)
return NULL;
BIO *b = BIO_new(BIO_s_mem());
if (!b)
goto ERR_OUT;
PEM_write_bio_X509(b, cert);
BUF_MEM *bptr;
BIO_get_mem_ptr(b, &bptr);
tlscert->pem = xmpp_alloc(ctx, bptr->length + 1);
if (!tlscert->pem)
goto ERR_OUT;
memcpy(tlscert->pem, bptr->data, bptr->length);
tlscert->pem[bptr->length] = '\0';
BIO_free(b);
subject = X509_NAME_oneline(X509_get_subject_name(cert), NULL, 0);
if (!subject)
goto ERR_OUT;
tlscert->elements[XMPP_CERT_SUBJECT] = xmpp_strdup(ctx, subject);
OPENSSL_free(subject);
issuer = X509_NAME_oneline(X509_get_issuer_name(cert), NULL, 0);
if (!issuer)
goto ERR_OUT;
tlscert->elements[XMPP_CERT_ISSUER] = xmpp_strdup(ctx, issuer);
OPENSSL_free(issuer);
tlscert->elements[XMPP_CERT_NOTBEFORE] =
_asn1_time_to_str(ctx, X509_get_notBefore(cert));
tlscert->elements[XMPP_CERT_NOTAFTER] =
_asn1_time_to_str(ctx, X509_get_notAfter(cert));
tlscert->elements[XMPP_CERT_FINGERPRINT_SHA1] =
_get_fingerprint(ctx, cert, XMPP_CERT_FINGERPRINT_SHA1);
tlscert->elements[XMPP_CERT_FINGERPRINT_SHA256] =
_get_fingerprint(ctx, cert, XMPP_CERT_FINGERPRINT_SHA256);
xmpp_snprintf(buf, sizeof(buf), "%ld", X509_get_version(cert) + 1);
tlscert->elements[XMPP_CERT_VERSION] = xmpp_strdup(ctx, buf);
tlscert->elements[XMPP_CERT_KEYALG] = _get_alg(ctx, cert, XMPP_CERT_KEYALG);
tlscert->elements[XMPP_CERT_SIGALG] = _get_alg(ctx, cert, XMPP_CERT_SIGALG);
ASN1_INTEGER *serial = X509_get_serialNumber(cert);
BIGNUM *bn = ASN1_INTEGER_to_BN(serial, NULL);
if (bn) {
char *serialnumber = BN_bn2hex(bn);
if (serialnumber) {
tlscert->elements[XMPP_CERT_SERIALNUMBER] =
xmpp_strdup(ctx, serialnumber);
OPENSSL_free(serialnumber);
}
BN_free(bn);
}
GENERAL_NAMES *names = _tls_cert_get_names(cert);
if (names) {
int j, num_names = sk_GENERAL_NAME_num(names);
size_t n = 0;
for (j = 0; j < num_names; ++j) {
char *res;
GENERAL_NAME *name = sk_GENERAL_NAME_value(names, j);
if (_tls_dnsname_to_string(name, &res))
continue;
if (tlscert_add_dnsname(tlscert, res))
xmpp_debug(ctx, "tls", "Can't store dnsName(%zu): %s", n, res);
n++;
OPENSSL_free(res);
}
GENERAL_NAMES_free(names);
}
return tlscert;
ERR_OUT:
xmpp_tlscert_free(tlscert);
return NULL;
}
static int _tls_verify(int preverify_ok, X509_STORE_CTX *x509_ctx)
{
if (preverify_ok == 1)
return 1;
SSL *ssl = X509_STORE_CTX_get_ex_data(x509_ctx,
SSL_get_ex_data_X509_STORE_CTX_idx());
xmpp_conn_t *conn = SSL_get_app_data(ssl);
if (!conn->certfail_handler) {
xmpp_error(conn->ctx, "tls",
"No certfail handler set, canceling connection attempt");
return 0;
}
X509 *err_cert = X509_STORE_CTX_get_current_cert(x509_ctx);
xmpp_tlscert_t *tlscert = _x509_to_tlscert(conn->ctx, err_cert);
if (!tlscert)
return 0;
xmpp_debug(conn->ctx, "tls", "preverify_ok:%d\nSubject: %s\nIssuer: %s",
preverify_ok, tlscert->elements[XMPP_CERT_SUBJECT],
tlscert->elements[XMPP_CERT_ISSUER]);
int ret = conn->certfail_handler(
tlscert,
X509_verify_cert_error_string(X509_STORE_CTX_get_error(x509_ctx)));
xmpp_tlscert_free(tlscert);
return ret;
}
tls_t *tls_new(xmpp_conn_t *conn)
{
tls_t *tls = xmpp_alloc(conn->ctx, sizeof(*tls));
int mode;
if (tls) {
int ret;
@@ -567,16 +359,6 @@ tls_t *tls_new(xmpp_conn_t *conn)
goto err_free_cert;
}
if (conn->tls_cafile || conn->tls_capath) {
if (SSL_CTX_load_verify_locations(tls->ssl_ctx, conn->tls_cafile,
conn->tls_capath) == 0) {
xmpp_error(tls->ctx, "tls",
"SSL_CTX_load_verify_locations() failed");
_tls_log_error(tls->ctx);
goto err_free_cert;
}
}
tls->ssl = SSL_new(tls->ssl_ctx);
if (tls->ssl == NULL)
goto err_free_cert;
@@ -586,13 +368,9 @@ tls_t *tls_new(xmpp_conn_t *conn)
SSL_set_tlsext_host_name(tls->ssl, conn->domain);
#endif
/* Trust server's certificate when user sets the flag explicitly.
* Otherwise call the verification callback */
if (conn->tls_trust)
SSL_set_verify(tls->ssl, SSL_VERIFY_NONE, NULL);
else
SSL_set_verify(tls->ssl, SSL_VERIFY_PEER, _tls_verify);
SSL_set_app_data(tls->ssl, conn);
/* Trust server's certificate when user sets the flag explicitly. */
mode = conn->tls_trust ? SSL_VERIFY_NONE : SSL_VERIFY_PEER;
SSL_set_verify(tls->ssl, mode, NULL);
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
/* Hostname verification is supported in OpenSSL 1.0.2 and newer. */
param = SSL_get0_param(tls->ssl);
@@ -636,19 +414,6 @@ void tls_free(tls_t *tls)
xmpp_free(tls->ctx, tls);
}
xmpp_tlscert_t *tls_peer_cert(xmpp_conn_t *conn)
{
if (conn && conn->tls && conn->tls->ssl) {
X509 *cert = SSL_get_peer_certificate(conn->tls->ssl);
if (cert) {
xmpp_tlscert_t *tlscert = _x509_to_tlscert(conn->ctx, cert);
X509_free(cert);
return tlscert;
}
}
return NULL;
}
int tls_set_credentials(tls_t *tls, const char *cafilename)
{
UNUSED(tls);
@@ -685,8 +450,6 @@ int tls_start(tls_t *tls)
xmpp_debug(tls->ctx, "tls",
"Certificate verification FAILED, result=%s(%ld)",
TLS_ERROR_STR((int)x509_res, cert_errors), x509_res);
if (ret > 0)
xmpp_debug(tls->ctx, "tls", "User decided to connect anyways");
}
_tls_dump_cert_info(tls);
@@ -879,32 +642,28 @@ static int _tls_xaddr_nid(void)
return xaddr_nid;
}
static GENERAL_NAMES *_tls_conn_get_names(xmpp_conn_t *conn)
static GENERAL_NAMES *_tls_cert_get_names(xmpp_conn_t *conn)
{
X509 *client_cert;
GENERAL_NAMES *names = NULL;
client_cert = _tls_cert_read(conn);
if (!client_cert)
return NULL;
names = _tls_cert_get_names(client_cert);
if (!conn->tls || !conn->tls->client_cert)
X509_free(client_cert);
return names;
}
static GENERAL_NAMES *_tls_cert_get_names(X509 *client_cert)
{
int san = X509_get_ext_by_NID(client_cert, NID_subject_alt_name, 0);
X509_EXTENSION *san_ext = X509_get_ext(client_cert, san);
if (!san_ext)
return NULL;
goto OUT;
ASN1_OCTET_STRING *data = X509_EXTENSION_get_data(san_ext);
if (!data)
return NULL;
goto OUT;
const unsigned char *d = ASN1_STRING_get0_data(data);
if (!d)
return NULL;
return d2i_GENERAL_NAMES(NULL, &d, ASN1_STRING_length(data));
goto OUT;
names = d2i_GENERAL_NAMES(NULL, &d, ASN1_STRING_length(data));
OUT:
if (!conn->tls || !conn->tls->client_cert)
X509_free(client_cert);
return names;
}
/** Convert GENERAL_NAME* to a string
@@ -921,7 +680,7 @@ static GENERAL_NAMES *_tls_cert_get_names(X509 *client_cert)
*
* @return classic Unix style - 0=success, 1=error
*/
static int _tls_xmppaddr_to_string(GENERAL_NAME *name, char **res)
static int _tls_name_to_xmppaddr(GENERAL_NAME *name, char **res)
{
ASN1_OBJECT *oid;
ASN1_TYPE *val;
@@ -937,18 +696,3 @@ static int _tls_xmppaddr_to_string(GENERAL_NAME *name, char **res)
return 1;
return 0;
}
static int _tls_dnsname_to_string(GENERAL_NAME *name, char **res)
{
ASN1_STRING *str;
if (!name || name->type != GEN_DNS)
return 1;
str = GENERAL_NAME_get0_value(name, NULL);
if (str == NULL)
return 1;
if (!res)
return 0;
if (ASN1_STRING_to_UTF8((unsigned char **)res, str) < 0)
return 1;
return 0;
}

View File

@@ -222,13 +222,6 @@ void tls_free(tls_t *tls)
return;
}
xmpp_tlscert_t *tls_peer_cert(xmpp_conn_t *conn)
{
/* always fail */
xmpp_error(conn->ctx, "tls", "tls_peer_cert() not implemented");
return NULL;
}
int tls_set_credentials(tls_t *tls, const char *cafilename)
{
UNUSED(tls);

252
src/tls_securetransport.c Normal file
View File

@@ -0,0 +1,252 @@
// Secure Transport implementation of TLS by Christopher A. Taylor (2013)
#include <Security/Security.h>
#include <Security/SecureTransport.h>
#include <CoreFoundation/CoreFoundation.h>
#include <CommonCrypto/CommonDigest.h>
#include "common.h"
#include "tls.h"
#include "sock.h"
struct _tls {
xmpp_ctx_t *ctx;
sock_t sock;
SSLContextRef sslctx;
};
void tls_initialize(void)
{
}
void tls_shutdown(void)
{
}
char *tls_id_on_xmppaddr(xmpp_conn_t *conn, unsigned int n)
{
UNUSED(n);
/* always fail */
xmpp_error(conn->ctx, "tls", "Client-Authentication not implemented");
return NULL;
}
unsigned int tls_id_on_xmppaddr_num(xmpp_conn_t *conn)
{
/* always fail */
xmpp_error(conn->ctx, "tls", "Client-Authentication not implemented");
return 0;
}
OSStatus MySSLReadFunction(SSLConnectionRef connection, void *data, size_t *dataLength) {
size_t bytesToGo = *dataLength;
size_t initLen = bytesToGo;
UInt8 *currData = (UInt8 *)data;
/*int sock = *(int *)connection;*/
tls_t *connssl = (tls_t *)connection;
int sock = connssl->sock;
OSStatus rtn = noErr;
size_t bytesRead;
ssize_t rrtn;
int theErr;
*dataLength = 0;
for(;;) {
bytesRead = 0;
rrtn = read(sock, currData, bytesToGo);
if(rrtn <= 0) {
/* this is guesswork... */
theErr = errno;
if(rrtn == 0) { /* EOF = server hung up */
/* the framework will turn this into errSSLClosedNoNotify */
rtn = errSSLClosedGraceful;
}
else /* do the switch */
switch(theErr) {
case ENOENT:
/* connection closed */
rtn = errSSLClosedGraceful;
break;
case ECONNRESET:
rtn = errSSLClosedAbort;
break;
case EAGAIN:
rtn = errSSLWouldBlock;
//connssl->ssl_direction = false;
break;
default:
rtn = errSSLClosedAbort;
break;
}
break;
}
else {
bytesRead = rrtn;
}
bytesToGo -= bytesRead;
currData += bytesRead;
if(bytesToGo == 0) {
/* filled buffer with incoming data, done */
break;
}
}
*dataLength = initLen - bytesToGo;
return rtn;
}
OSStatus MySSLWriteFunction(SSLConnectionRef connection, const void *data, size_t *dataLength) {
size_t bytesSent = 0;
/*int sock = *(int *)connection;*/
tls_t *connssl = (tls_t *)connection;
int sock = connssl->sock;
ssize_t length;
size_t dataLen = *dataLength;
const UInt8 *dataPtr = (UInt8 *)data;
OSStatus ortn;
int theErr;
*dataLength = 0;
do {
length = write(sock,
(char*)dataPtr + bytesSent,
dataLen - bytesSent);
} while((length > 0) &&
( (bytesSent += length) < dataLen) );
if(length <= 0) {
theErr = errno;
if(theErr == EAGAIN) {
ortn = errSSLWouldBlock;
//connssl->ssl_direction = true;
}
else {
ortn = errSSLClosedAbort;
}
}
else {
ortn = noErr;
}
*dataLength = bytesSent;
return ortn;
}
tls_t *tls_new(xmpp_conn_t *conn)
{
tls_t *tls = xmpp_alloc(conn->ctx, sizeof(tls_t));
if (tls) {
tls->ctx = conn->ctx;
tls->sock = conn->sock;
tls->sslctx = SSLCreateContext(NULL, kSSLClientSide, kSSLStreamType);
SSLSetIOFuncs(tls->sslctx, MySSLReadFunction, MySSLWriteFunction);
SSLSetConnection(tls->sslctx, tls);
}
return tls;
}
void tls_free(tls_t *tls)
{
CFRelease(tls->sslctx);
xmpp_free(tls->ctx, tls);
}
int tls_set_credentials(tls_t *tls, const char *cafilename)
{
/*
Not implemented in OpenSSL version so we should not need it either.
But if we want to do it here's a place to start:
FILE * ret = fopen(cafilename, options);
void *data = malloc(bytes);
fread(data, 1, bytes, ret);
fclose(ret);
NSData *myCertData = [NSData dataWithBytesNoCopy:data length:bytes]; <- requires -ObjC compile option?
SecCertificateRef cert = SecCertificateCreateWithData(kCFAllocatorDefault, myCertData);
CFArrayRef certRefs = CFArrayCreate(kCFAllocatorDefault, (const void **)&cert, 1, NULL);
SSLSetCertificate(tls->sslctx, certRefs);
*/
return -1;
}
int tls_start(tls_t *tls)
{
int ret;
/* Since we're non-blocking, loop the connect call until it
succeeds or fails */
do {
ret = SSLHandshake(tls->sslctx);
} while (ret == errSSLWouldBlock);
return ret < 0 ? -1 : 0;
}
int tls_stop(tls_t *tls)
{
SSLClose(tls->sslctx);
return 0;
}
int tls_is_recoverable(int error)
{
switch (error) {
case errSSLWouldBlock:
return true;
default:
break;
}
return false;
}
int tls_error(tls_t *tls)
{
/* todo: some kind of error polling/dump */
return 0;
}
int tls_pending(tls_t *tls)
{
size_t buffer;
if (SSLGetBufferedReadSize(tls->sslctx, &buffer) < 0) {
return 0;
}
return buffer;
}
int tls_read(tls_t *tls, void * const buff, const size_t len)
{
size_t processed;
SSLRead(tls->sslctx, buff, len, &processed);
return processed;
}
int tls_write(tls_t *tls, const void * const buff, const size_t len)
{
size_t processed;
SSLWrite(tls->sslctx, buff, len, &processed);
return processed;
}
int tls_clear_pending_write(tls_t *tls)
{
return 0;
}

View File

@@ -36,41 +36,21 @@
* @param ctx a Strophe context object
* @param s a string
*
* @return a newly allocated string with the same data as s or NULL on error
* @return a new allocates string with the same data as s or NULL on error
*/
char *xmpp_strdup(const xmpp_ctx_t *ctx, const char *s)
{
return xmpp_strndup(ctx, s, SIZE_MAX);
}
/** Duplicate a string with a maximum length.
* This function replaces the standard strndup library call with a version
* that uses the Strophe context object's allocator.
*
* @param ctx a Strophe context object
* @param s a string
* @param len the maximum length of the string to copy
*
* @return a newly allocated string that contains at most `len` symbols
* of the original string or NULL on error
*/
char *xmpp_strndup(const xmpp_ctx_t *ctx, const char *s, size_t len)
{
size_t len;
char *copy;
size_t l;
l = strlen(s);
if (l > len)
l = len;
copy = xmpp_alloc(ctx, l + 1);
len = strlen(s);
copy = xmpp_alloc(ctx, len + 1);
if (!copy) {
xmpp_error(ctx, "xmpp", "failed to allocate required memory");
return NULL;
}
memcpy(copy, s, l);
copy[l] = '\0';
memcpy(copy, s, len + 1);
return copy;
}
@@ -160,12 +140,3 @@ void disconnect_mem_error(xmpp_conn_t *conn)
xmpp_error(conn->ctx, "xmpp", "Memory allocation error");
xmpp_disconnect(conn);
}
void hex_encode(char *writebuf, void *readbuf, size_t len)
{
size_t i;
for (i = 0; i < len; i++) {
sprintf(writebuf, "%02x", ((unsigned char *)readbuf)[i]);
writebuf += 2;
}
}

View File

@@ -32,7 +32,4 @@ char *xmpp_strtok_r(char *s, const char *delim, char **saveptr);
uint64_t time_stamp(void);
uint64_t time_elapsed(uint64_t t1, uint64_t t2);
/* misc functions */
void hex_encode(char *writebuf, void *readbuf, size_t len);
#endif /* __LIBSTROPHE_UTIL_H__ */

View File

@@ -122,14 +122,9 @@ typedef struct _xmpp_log_t xmpp_log_t;
/* opaque run time context containing the above hooks */
typedef struct _xmpp_ctx_t xmpp_ctx_t;
typedef struct _xmpp_tlscert_t xmpp_tlscert_t;
xmpp_ctx_t *xmpp_ctx_new(const xmpp_mem_t *mem, const xmpp_log_t *log);
void xmpp_ctx_free(xmpp_ctx_t *ctx);
/* set the verbosity level of the ctx */
void xmpp_ctx_set_verbosity(xmpp_ctx_t *ctx, int level);
/* free some blocks returned by other APIs, for example the
buffer you get from xmpp_stanza_to_text */
void xmpp_free(const xmpp_ctx_t *ctx, void *p);
@@ -217,24 +212,6 @@ typedef enum {
XMPP_SE_XML_NOT_WELL_FORMED
} xmpp_error_type_t;
/** Certificate Elements
*
* @ingroup TLS
*/
typedef enum {
XMPP_CERT_VERSION, /**< X.509 Version */
XMPP_CERT_SERIALNUMBER, /**< SerialNumber */
XMPP_CERT_SUBJECT, /**< Subject */
XMPP_CERT_ISSUER, /**< Issuer */
XMPP_CERT_NOTBEFORE, /**< Issued on */
XMPP_CERT_NOTAFTER, /**< Expires on */
XMPP_CERT_KEYALG, /**< Public Key Algorithm */
XMPP_CERT_SIGALG, /**< Certificate Signature Algorithm */
XMPP_CERT_FINGERPRINT_SHA1, /**< Fingerprint SHA-1 */
XMPP_CERT_FINGERPRINT_SHA256, /**< Fingerprint SHA-256 */
XMPP_CERT_ELEMENT_MAX /**< Last element of the enum */
} xmpp_cert_element_t;
typedef struct {
xmpp_error_type_t type;
char *text;
@@ -247,28 +224,6 @@ typedef void (*xmpp_conn_handler)(xmpp_conn_t *conn,
xmpp_stream_error_t *stream_error,
void *userdata);
/** The Handler function which will be called when the TLS stack can't
* verify the authenticity of a Certificate that gets presented by
* the server we're trying to connect to.
*
* When this function is called and details of the `cert` have to be
* kept, please copy them yourself. The `cert` object will be free'd
* automatically when this function returns.
*
* NB: `errormsg` is specific per certificate on OpenSSL and the same
* for all certificates on GnuTLS.
*
* @param cert a Strophe certificate object
* @param errormsg The error that caused this.
*
* @return 0 if the connection attempt should be terminated,
* 1 if the connection should be established.
*
* @ingroup TLS
*/
typedef int (*xmpp_certfail_handler)(const xmpp_tlscert_t *cert,
const char *const errormsg);
void xmpp_send_error(xmpp_conn_t *conn, xmpp_error_type_t type, char *text);
xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t *ctx);
xmpp_conn_t *xmpp_conn_clone(xmpp_conn_t *conn);
@@ -279,11 +234,6 @@ int xmpp_conn_set_flags(xmpp_conn_t *conn, long flags);
const char *xmpp_conn_get_jid(const xmpp_conn_t *conn);
const char *xmpp_conn_get_bound_jid(const xmpp_conn_t *conn);
void xmpp_conn_set_jid(xmpp_conn_t *conn, const char *jid);
void xmpp_conn_set_cafile(xmpp_conn_t *const conn, const char *path);
void xmpp_conn_set_capath(xmpp_conn_t *const conn, const char *path);
void xmpp_conn_set_certfail_handler(xmpp_conn_t *const conn,
xmpp_certfail_handler hndl);
xmpp_tlscert_t *xmpp_conn_get_peer_cert(xmpp_conn_t *const conn);
void xmpp_conn_set_client_cert(xmpp_conn_t *conn,
const char *cert,
const char *key);
@@ -484,17 +434,6 @@ void xmpp_run(xmpp_ctx_t *ctx);
void xmpp_stop(xmpp_ctx_t *ctx);
void xmpp_ctx_set_timeout(xmpp_ctx_t *ctx, unsigned long timeout);
/* TLS certificates */
xmpp_ctx_t *xmpp_tlscert_get_ctx(const xmpp_tlscert_t *cert);
xmpp_conn_t *xmpp_tlscert_get_conn(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_string(const xmpp_tlscert_t *cert,
xmpp_cert_element_t elmnt);
const char *xmpp_tlscert_get_description(xmpp_cert_element_t elmnt);
void xmpp_tlscert_free(xmpp_tlscert_t *cert);
/* UUID */
char *xmpp_uuid_gen(xmpp_ctx_t *ctx);

View File

@@ -14,7 +14,6 @@
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "ostypes.h"

View File

@@ -1,49 +0,0 @@
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "strophe.h"
#include "parser.h"
void xmpp_initialize(void);
void cbtest_handle_start(char *name, char **attrs, void *userdata)
{
(void)name;
(void)attrs;
(void)userdata;
}
void cbtest_handle_end(char *name, void *userdata)
{
(void)name;
(void)userdata;
}
void cbtest_handle_stanza(xmpp_stanza_t *stanza, void *userdata)
{
(void)stanza;
(void)userdata;
}
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size)
{
xmpp_ctx_t *ctx;
parser_t *parser;
char *dup = malloc(Size);
memcpy(dup, Data, Size);
ctx = xmpp_ctx_new(NULL, NULL);
parser = parser_new(ctx, cbtest_handle_start, cbtest_handle_end,
cbtest_handle_stanza, NULL);
parser_feed(parser, dup, Size);
free(dup);
parser_free(parser);
xmpp_ctx_free(ctx);
return 0;
}

View File

@@ -17,8 +17,6 @@
#include <stdlib.h>
#include <string.h>
#include "test.h"
#define MAGICPTR ((void *)0xfeedbeef)
static unsigned long used_blocks = 0;
@@ -109,62 +107,9 @@ static void test_stanza_from_string(xmpp_ctx_t *ctx)
assert(stanza != NULL);
ret = xmpp_stanza_to_text(stanza, &buf, &buflen);
assert(ret == XMPP_EOK);
COMPARE(str, buf);
assert(strcmp(buf, str) == 0);
xmpp_free(ctx, buf);
xmpp_stanza_release(stanza);
/* Error path. */
stanza = xmpp_stanza_new_from_string(ctx, "<uu><uu>tt");
assert(stanza == NULL);
}
static void test_stanza_error(xmpp_ctx_t *ctx)
{
xmpp_stanza_t *stanza;
xmpp_stanza_t *error;
xmpp_stanza_t *item;
char *buf;
size_t buflen;
const char *attr[10];
int attrlen = ARRAY_SIZE(attr);
int ret;
static const char *str =
"<iq from='romeo@montague.lit/home' to='juliet@capulet.lit/chamber' "
"type='get' id='e2e1'><ping xmlns='urn:xmpp:ping'/></iq>";
static const char *str_error =
"<error type=\"cancel\"><service-unavailable "
"xmlns=\"urn:ietf:params:xml:ns:xmpp-stanzas\"/></error>";
stanza = xmpp_stanza_new_from_string(ctx, str);
assert(stanza != NULL);
error =
xmpp_stanza_reply_error(stanza, "cancel", "service-unavailable", NULL);
assert(error != NULL);
assert(xmpp_stanza_get_to(error) != NULL);
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));
assert(xmpp_stanza_get_id(error) != NULL);
COMPARE("e2e1", xmpp_stanza_get_id(error));
assert(xmpp_stanza_get_type(error) != NULL);
COMPARE("error", xmpp_stanza_get_type(error));
ret = xmpp_stanza_get_attributes(error, attr, attrlen);
/* attr contains both attribute name and value. */
assert(ret == 8);
item = xmpp_stanza_get_child_by_name(error, "error");
assert(item != NULL);
ret = xmpp_stanza_to_text(item, &buf, &buflen);
assert(ret == XMPP_EOK);
COMPARE(str_error, buf);
xmpp_free(ctx, buf);
xmpp_stanza_release(stanza);
xmpp_stanza_release(error);
}
int main()
@@ -177,7 +122,6 @@ int main()
test_stanza_add_child(ctx);
test_stanza_from_string(ctx);
test_stanza_error(ctx);
xmpp_ctx_free(ctx);
xmpp_shutdown();