Compare commits
5 Commits
0.11.0
...
tls-secure
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
06cb1459f1 | ||
|
|
82f372fa49 | ||
|
|
9ddc881102 | ||
|
|
f6ef50d134 | ||
|
|
bd87653c76 |
12
ChangeLog
12
ChangeLog
@@ -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
|
||||
|
||||
2
Doxyfile
2
Doxyfile
@@ -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
|
||||
|
||||
17
Makefile.am
17
Makefile.am
@@ -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
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ BinPackParameters: 'false'
|
||||
BreakBeforeBraces: Linux
|
||||
ColumnLimit: '80'
|
||||
DerivePointerAlignment: 'false'
|
||||
IndentGotoLabels: false
|
||||
IndentWidth: '4'
|
||||
PointerAlignment: Right
|
||||
SortIncludes: 'false'
|
||||
|
||||
13
configure.ac
13
configure.ac
@@ -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>])
|
||||
|
||||
@@ -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) {
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
158
src/conn.c
158
src/conn.c
@@ -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 <stream:stream> 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;
|
||||
}
|
||||
|
||||
46
src/ctx.c
46
src/ctx.c
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
52
src/stanza.c
52
src/stanza.c
@@ -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
214
src/tls.c
@@ -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;
|
||||
}
|
||||
18
src/tls.h
18
src/tls.h
@@ -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__ */
|
||||
|
||||
@@ -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);
|
||||
|
||||
193
src/tls_gnutls.c
193
src/tls_gnutls.c
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
252
src/tls_securetransport.c
Normal 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;
|
||||
}
|
||||
|
||||
39
src/util.c
39
src/util.c
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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__ */
|
||||
|
||||
61
strophe.h
61
strophe.h
@@ -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);
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "ostypes.h"
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user