Compare commits
40 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2093aac817 | ||
|
|
29fa1bf27e | ||
|
|
f364ed184b | ||
|
|
40c9fe22b3 | ||
|
|
c33c0a6998 | ||
|
|
92e674e412 | ||
|
|
9f82aac8ce | ||
|
|
a3f1b83f3a | ||
|
|
b23104f920 | ||
|
|
057f9068c6 | ||
|
|
3231214344 | ||
|
|
55efc601cb | ||
|
|
dcbf3fb4d5 | ||
|
|
e2acd98612 | ||
|
|
ee4f6d4e3c | ||
|
|
db14f2bd4a | ||
|
|
e768604533 | ||
|
|
1afcd485db | ||
|
|
58613ea7f3 | ||
|
|
bf5bf96e95 | ||
|
|
529a9bed44 | ||
|
|
fd4f26e5d4 | ||
|
|
e7f87c652e | ||
|
|
65d2535302 | ||
|
|
a981c0a733 | ||
|
|
b08625ef4a | ||
|
|
ea719cd02a | ||
|
|
52dcd26b8c | ||
|
|
cf361d35fe | ||
|
|
077afae693 | ||
|
|
783bad0897 | ||
|
|
d693cc6d15 | ||
|
|
46f371b311 | ||
|
|
97c6e6d8d4 | ||
|
|
9af64e244e | ||
|
|
90075b5feb | ||
|
|
519edba5de | ||
|
|
7255b49623 | ||
|
|
2dc357438b | ||
|
|
4111cf772a |
9
.gitignore
vendored
9
.gitignore
vendored
@@ -22,22 +22,27 @@ autom4te.cache
|
||||
.sconsign*
|
||||
src/*.o
|
||||
examples/*.o
|
||||
tests/*.o
|
||||
tests/check_parser
|
||||
*.a
|
||||
*.pc
|
||||
*.tar.gz
|
||||
*.zip
|
||||
docs/html
|
||||
TAGS
|
||||
tags
|
||||
examples/basic
|
||||
examples/active
|
||||
examples/roster
|
||||
examples/bot
|
||||
test_stamp
|
||||
test-suite.log
|
||||
tests/*.o
|
||||
tests/*.log
|
||||
tests/*.trs
|
||||
tests/check_parser
|
||||
tests/test_base64
|
||||
tests/test_ctx
|
||||
tests/test_hash
|
||||
tests/test_jid
|
||||
tests/test_sasl
|
||||
tests/test_sock
|
||||
m4/
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
0.8.5
|
||||
- libtoolize to generate .so
|
||||
0.8.7
|
||||
- SCRAM-SHA-1 authentication mechanism
|
||||
- pkg-config support
|
||||
|
||||
0.8.5
|
||||
- libtoolize to generate .so
|
||||
|
||||
19
Makefile.am
19
Makefile.am
@@ -1,27 +1,31 @@
|
||||
AUTOMAKE_OPTIONS = subdir-objects
|
||||
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
AM_CFLAGS = -g -Wall
|
||||
|
||||
PARSER_CFLAGS=@PARSER_CFLAGS@
|
||||
PARSER_LIBS=@PARSER_LIBS@
|
||||
|
||||
SSL_LIBS = -lssl -lcrypto -lz
|
||||
SSL_LIBS = @openssl_LIBS@
|
||||
|
||||
STROPHE_FLAGS = -I$(top_srcdir)
|
||||
STROPHE_LIBS = -lstrophe $(PARSER_LIBS) $(SSL_LIBS)
|
||||
STROPHE_LIBS = libstrophe.la
|
||||
|
||||
## Main build targets
|
||||
lib_LTLIBRARIES = libstrophe.la
|
||||
|
||||
libstrophe_la_CFLAGS=$(STROPHE_FLAGS) $(PARSER_CFLAGS)
|
||||
libstrophe_la_LDFLAGS=$(SSL_LIBS) $(PARSER_LIBS)
|
||||
libstrophe_la_CFLAGS = $(STROPHE_FLAGS) $(PARSER_CFLAGS)
|
||||
libstrophe_la_LDFLAGS = $(SSL_LIBS) $(PARSER_LIBS)
|
||||
# Export only public API
|
||||
libstrophe_la_LDFLAGS += -export-symbols-regex '^xmpp_'
|
||||
libstrophe_la_SOURCES = src/auth.c src/conn.c src/ctx.c \
|
||||
src/event.c src/handler.c src/hash.c \
|
||||
src/jid.c src/md5.c src/sasl.c src/sha1.c \
|
||||
src/jid.c src/md5.c src/sasl.c src/scram.c src/sha1.c \
|
||||
src/snprintf.c src/sock.c src/stanza.c src/thread.c \
|
||||
src/tls_openssl.c src/util.c \
|
||||
src/common.h src/hash.h src/md5.h src/ostypes.h src/parser.h \
|
||||
src/sasl.h src/sha1.h src/sock.h src/thread.h src/tls.h src/util.h
|
||||
src/sasl.h src/scram.h src/sha1.h src/sock.h src/thread.h src/tls.h \
|
||||
src/util.h
|
||||
|
||||
if PARSER_EXPAT
|
||||
libstrophe_la_SOURCES += src/parser_expat.c
|
||||
@@ -32,6 +36,8 @@ endif
|
||||
include_HEADERS = strophe.h
|
||||
noinst_HEADERS = strophepp.h
|
||||
|
||||
pkgconfig_DATA = libstrophe.pc
|
||||
|
||||
EXTRA_DIST = docs
|
||||
|
||||
## Examples
|
||||
@@ -57,3 +63,4 @@ tests_check_parser_SOURCES = tests/check_parser.c tests/test.h
|
||||
tests_check_parser_CFLAGS = @check_CFLAGS@ $(PARSER_CFLAGS) $(STROPHE_FLAGS) \
|
||||
-I$(top_srcdir)/src
|
||||
tests_check_parser_LDADD = @check_LIBS@ $(STROPHE_LIBS)
|
||||
tests_check_parser_LDFLAGS = -static
|
||||
|
||||
@@ -56,10 +56,9 @@ check package.
|
||||
|
||||
### OS X (with Homebrew package manager)
|
||||
|
||||
You can install the requirements with:
|
||||
You can install libstrophe with:
|
||||
|
||||
brew install expat
|
||||
brew install check
|
||||
brew install libstrophe
|
||||
|
||||
## Documentation
|
||||
|
||||
|
||||
89
configure.ac
89
configure.ac
@@ -1,11 +1,26 @@
|
||||
AC_INIT([libstrophe], [0.8.5], [jack@metajack.im])
|
||||
AC_INIT([libstrophe], [0.8.7], [jack@metajack.im])
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
AM_INIT_AUTOMAKE([foreign])
|
||||
LT_INIT([dlopen])
|
||||
|
||||
AC_PROG_CC
|
||||
AM_PROG_CC_C_O
|
||||
PKG_PROG_PKG_CONFIG
|
||||
|
||||
AC_CANONICAL_HOST
|
||||
AS_CASE([$host_os],
|
||||
[freebsd*], [PLATFORM="freebsd"],
|
||||
[PLATFORM="nix"])
|
||||
|
||||
PKG_CHECK_MODULES([openssl], [openssl], [PC_REQUIRES+=(openssl)],
|
||||
[AC_CHECK_HEADER([openssl/ssl.h],
|
||||
[
|
||||
openssl_LIBS="-lssl -lcrypto"
|
||||
PC_LIBS+=($openssl_LIBS)
|
||||
],
|
||||
[AC_MSG_ERROR([openssl not found; openssl required])]
|
||||
)])
|
||||
|
||||
AC_CHECK_HEADER(openssl/ssl.h, [], [AC_MSG_ERROR([couldn't find openssl headers, openssl required])])
|
||||
PKG_CHECK_MODULES([check], [check >= 0.9.4], [], [AC_MSG_WARN([libcheck not found; unit tests will not be compilable])])
|
||||
|
||||
AC_ARG_WITH([libxml2],
|
||||
@@ -15,41 +30,79 @@ AC_ARG_WITH([libxml2],
|
||||
|
||||
if test "x$with_libxml2" != xno; then
|
||||
PKG_CHECK_MODULES([libxml2], [libxml-2.0 >= 2.7],
|
||||
[with_libxml2=yes], [dummy=1])
|
||||
if test "x$with_libxml2" != xyes; then
|
||||
old_CFLAGS=$CFLAGS
|
||||
CFLAGS="-I /usr/include/libxml2"
|
||||
AC_CHECK_HEADER([libxml/parser.h],
|
||||
[with_libxml2=yes; libxml2_CFLAGS="-I /usr/include/libxml2"; libxml2_LIBS="-lxml2"],
|
||||
[AC_MSG_ERROR([couldn't find libxml2])])
|
||||
CFLAGS=$old_CFLAGS
|
||||
fi
|
||||
[
|
||||
with_libxml2=yes
|
||||
PC_REQUIRES+=(libxml-2.0)
|
||||
],
|
||||
[
|
||||
old_CFLAGS=$CFLAGS
|
||||
CFLAGS="-I${includedir}/libxml2"
|
||||
AC_CHECK_HEADER([libxml/parser.h],
|
||||
[
|
||||
with_libxml2=yes
|
||||
libxml2_CFLAGS="-I${includedir}/libxml2"
|
||||
libxml2_LIBS="-lxml2"
|
||||
PC_LIBS+=($libxml2_LIBS)
|
||||
PC_CFLAGS+=($libxml2_CFLAGS)
|
||||
],
|
||||
[AC_MSG_ERROR([libxml2 not found.])])
|
||||
CFLAGS=$old_CFLAGS
|
||||
])
|
||||
else
|
||||
AC_CHECK_HEADER(expat.h, [], [AC_MSG_ERROR([couldn't find expat headers; expat required])])
|
||||
PKG_CHECK_MODULES([expat], [expat >= 2.0.0],
|
||||
[PC_REQUIRES+=(expat)],
|
||||
[AC_CHECK_HEADER([expat.h],
|
||||
[
|
||||
expat_LIBS="-lexpat"
|
||||
PC_LIBS+=($expat_LIBS)
|
||||
],
|
||||
[AC_MSG_ERROR([expat not found; expat required.])]
|
||||
)
|
||||
])
|
||||
fi
|
||||
|
||||
if test "x$with_libxml2" = xyes; then
|
||||
with_parser=libxml2
|
||||
PARSER_NAME=libxml2
|
||||
PARSER_CFLAGS=\$\(libxml2_CFLAGS\)
|
||||
PARSER_LIBS=\$\(libxml2_LIBS\)
|
||||
PARSER_CFLAGS=$libxml2_CFLAGS
|
||||
PARSER_LIBS=$libxml2_LIBS
|
||||
else
|
||||
with_parser=expat
|
||||
PARSER_NAME=expat
|
||||
PARSER_CFLAGS=
|
||||
PARSER_LIBS=-lexpat
|
||||
PARSER_CFLAGS=$expat_CFLAGS
|
||||
PARSER_LIBS=$expat_LIBS
|
||||
fi
|
||||
|
||||
AC_MSG_NOTICE([libstrophe will use the $with_parser XML parser])
|
||||
AC_SEARCH_LIBS([socket], [socket])
|
||||
|
||||
AC_LINK_IFELSE([AC_LANG_CALL([#include <resolv.h>], [res_query])], [],[LIBS="$LIBS -lresolv"])
|
||||
if test "x$PLATFORM" != xfreebsd; then
|
||||
AC_CHECK_LIB([resolv], [res_query], [],
|
||||
[AC_CHECK_LIB([resolv], [__res_query], [],
|
||||
[AC_MSG_ERROR([libresolv not found; libresolv required.])])])
|
||||
PC_LIBS+=(-lresolv)
|
||||
else
|
||||
AC_MSG_NOTICE([skipping libresolv checks for freebsd])
|
||||
fi
|
||||
|
||||
AC_CHECK_HEADERS([arpa/nameser_compat.h])
|
||||
|
||||
|
||||
m4_ifdef([PKG_INSTALLDIR], [PKG_INSTALLDIR],
|
||||
[AC_ARG_WITH([pkgconfigdir],
|
||||
[AS_HELP_STRING([--with-pkgconfigdir],
|
||||
[install directory for libstrophe.pc pkg-config file])],
|
||||
[],[with_pkgconfigdir='$(libdir)/pkgconfig'])
|
||||
AC_SUBST([pkgconfigdir], [${with_pkgconfigdir}])])
|
||||
|
||||
AM_CONDITIONAL([PARSER_EXPAT], [test x$with_parser != xlibxml2])
|
||||
|
||||
AC_SUBST([PC_REQUIRES], [${PC_REQUIRES[[@]]}])
|
||||
AC_SUBST([PC_CFLAGS], [${PC_CFLAGS[[@]]}])
|
||||
AC_SUBST([PC_LIBS], [${PC_LIBS[[@]]}])
|
||||
|
||||
AC_SUBST(PARSER_NAME)
|
||||
AC_SUBST(PARSER_CFLAGS)
|
||||
AC_SUBST(PARSER_LIBS)
|
||||
AC_CONFIG_FILES([Makefile])
|
||||
AC_CONFIG_FILES([Makefile libstrophe.pc])
|
||||
AC_OUTPUT
|
||||
|
||||
@@ -77,7 +77,7 @@ int message_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void
|
||||
xmpp_ctx_t *ctx = (xmpp_ctx_t*)userdata;
|
||||
|
||||
if(!xmpp_stanza_get_child_by_name(stanza, "body")) return 1;
|
||||
if(!strcmp(xmpp_stanza_get_attribute(stanza, "type"), "error")) return 1;
|
||||
if(xmpp_stanza_get_attribute(stanza, "type") !=NULL && !strcmp(xmpp_stanza_get_attribute(stanza, "type"), "error")) return 1;
|
||||
|
||||
intext = xmpp_stanza_get_text(xmpp_stanza_get_child_by_name(stanza, "body"));
|
||||
|
||||
|
||||
14
libstrophe.pc.in
Normal file
14
libstrophe.pc.in
Normal file
@@ -0,0 +1,14 @@
|
||||
prefix=@prefix@
|
||||
exec_prefix=@exec_prefix@
|
||||
libdir=@libdir@
|
||||
includedir=@includedir@
|
||||
|
||||
Name: libstrophe
|
||||
Description: A simple, lightweight C library for writing XMPP clients
|
||||
URL: http://strophe.im/libstrophe/
|
||||
Version: @VERSION@
|
||||
Requires:
|
||||
Requires.private: @PC_REQUIRES@
|
||||
Libs: -L${libdir} -lstrophe
|
||||
Libs.private: @PC_LIBS@
|
||||
Cflags: -I${includedir} @PC_CFLAGS@
|
||||
@@ -8,12 +8,24 @@ License: MIT/GPLv3
|
||||
URL: http://strophe.im/libstrophe/
|
||||
Source0: libstrophe_git.tar.gz
|
||||
|
||||
BuildRequires: automake
|
||||
BuildRequires: libtool
|
||||
BuildRequires: openssl-devel
|
||||
BuildRequires: expat-devel
|
||||
Requires: expat
|
||||
Requires: expat
|
||||
|
||||
%description
|
||||
XMPP library in C
|
||||
|
||||
%package devel
|
||||
Summary: Headers and libraries for building apps that use libstrophe
|
||||
Group: Development/Libraries
|
||||
Requires: %{name} = %{version}-%{release}
|
||||
|
||||
%description devel
|
||||
This package contains headers and libraries required to build applications that
|
||||
use the strophe XMPP library.
|
||||
|
||||
%prep
|
||||
%setup -n libstrophe
|
||||
./bootstrap.sh
|
||||
@@ -25,8 +37,21 @@ make %{?_smp_mflags}
|
||||
%install
|
||||
make install DESTDIR=%{buildroot}
|
||||
|
||||
%post -p /sbin/ldconfig
|
||||
|
||||
%postun -p /sbin/ldconfig
|
||||
|
||||
%files
|
||||
%defattr(-,root,root,-)
|
||||
%{_libdir}/libstrophe.so*
|
||||
%doc
|
||||
|
||||
%files devel
|
||||
%defattr(-,root,root,-)
|
||||
%{_libdir}/libstrophe.a
|
||||
%{_libdir}/libstrophe.la
|
||||
%{_libdir}/pkgconfig/libstrophe.pc
|
||||
%{_includedir}/strophe.h
|
||||
%doc
|
||||
|
||||
%changelog
|
||||
|
||||
168
src/auth.c
168
src/auth.c
@@ -19,12 +19,13 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "strophe.h"
|
||||
#include "common.h"
|
||||
#include "sasl.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifdef _MSC_VER
|
||||
#define strcasecmp stricmp
|
||||
#endif
|
||||
|
||||
@@ -56,7 +57,6 @@
|
||||
#endif
|
||||
|
||||
static void _auth(xmpp_conn_t * const conn);
|
||||
static void _handle_open_tls(xmpp_conn_t * const conn);
|
||||
static void _handle_open_sasl(xmpp_conn_t * const conn);
|
||||
static int _handle_missing_legacy(xmpp_conn_t * const conn,
|
||||
void * const userdata);
|
||||
@@ -75,6 +75,10 @@ static int _handle_digestmd5_challenge(xmpp_conn_t * const conn,
|
||||
static int _handle_digestmd5_rspauth(xmpp_conn_t * const conn,
|
||||
xmpp_stanza_t * const stanza,
|
||||
void * const userdata);
|
||||
static int _handle_scram_sha1_challenge(xmpp_conn_t * const conn,
|
||||
xmpp_stanza_t * const stanza,
|
||||
void * const userdata);
|
||||
static char *_make_scram_sha1_init_msg(xmpp_conn_t * const conn);
|
||||
|
||||
static int _handle_missing_features_sasl(xmpp_conn_t * const conn,
|
||||
void * const userdata);
|
||||
@@ -229,6 +233,8 @@ static int _handle_features(xmpp_conn_t * const conn,
|
||||
conn->sasl_support |= SASL_MASK_PLAIN;
|
||||
else if (strcasecmp(text, "DIGEST-MD5") == 0)
|
||||
conn->sasl_support |= SASL_MASK_DIGESTMD5;
|
||||
else if (strcasecmp(text, "SCRAM-SHA-1") == 0)
|
||||
conn->sasl_support |= SASL_MASK_SCRAMSHA1;
|
||||
else if (strcasecmp(text, "ANONYMOUS") == 0)
|
||||
conn->sasl_support |= SASL_MASK_ANONYMOUS;
|
||||
|
||||
@@ -416,6 +422,117 @@ static int _handle_digestmd5_rspauth(xmpp_conn_t * const conn,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* handle the challenge phase of SCRAM-SHA-1 auth */
|
||||
static int _handle_scram_sha1_challenge(xmpp_conn_t * const conn,
|
||||
xmpp_stanza_t * const stanza,
|
||||
void * const userdata)
|
||||
{
|
||||
char *text;
|
||||
char *response;
|
||||
xmpp_stanza_t *auth, *authdata;
|
||||
char *name;
|
||||
char *challenge;
|
||||
char *scram_init = (char *)userdata;
|
||||
|
||||
name = xmpp_stanza_get_name(stanza);
|
||||
xmpp_debug(conn->ctx, "xmpp",
|
||||
"handle SCRAM-SHA-1 (challenge) called for %s", name);
|
||||
|
||||
if (strcmp(name, "challenge") == 0) {
|
||||
text = xmpp_stanza_get_text(stanza);
|
||||
if (!text)
|
||||
goto err;
|
||||
|
||||
challenge = (char *)base64_decode(conn->ctx, text, strlen(text));
|
||||
xmpp_free(conn->ctx, text);
|
||||
if (!challenge)
|
||||
goto err;
|
||||
|
||||
response = sasl_scram_sha1(conn->ctx, challenge, scram_init,
|
||||
conn->jid, conn->pass);
|
||||
xmpp_free(conn->ctx, challenge);
|
||||
if (!response)
|
||||
goto err;
|
||||
|
||||
auth = xmpp_stanza_new(conn->ctx);
|
||||
if (!auth)
|
||||
goto err_free_response;
|
||||
xmpp_stanza_set_name(auth, "response");
|
||||
xmpp_stanza_set_ns(auth, XMPP_NS_SASL);
|
||||
|
||||
authdata = xmpp_stanza_new(conn->ctx);
|
||||
if (!authdata)
|
||||
goto err_release_auth;
|
||||
xmpp_stanza_set_text(authdata, response);
|
||||
xmpp_free(conn->ctx, response);
|
||||
|
||||
xmpp_stanza_add_child(auth, authdata);
|
||||
xmpp_stanza_release(authdata);
|
||||
|
||||
xmpp_send(conn, auth);
|
||||
xmpp_stanza_release(auth);
|
||||
|
||||
} else {
|
||||
xmpp_free(conn->ctx, scram_init);
|
||||
return _handle_sasl_result(conn, stanza, "SCRAM-SHA-1");
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
err_release_auth:
|
||||
xmpp_stanza_release(auth);
|
||||
err_free_response:
|
||||
xmpp_free(conn->ctx, response);
|
||||
err:
|
||||
xmpp_free(conn->ctx, scram_init);
|
||||
disconnect_mem_error(conn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *_get_nonce(xmpp_ctx_t *ctx)
|
||||
{
|
||||
unsigned char buffer[sizeof(clock_t) + sizeof(time_t)] = {0};
|
||||
clock_t ticks = clock();
|
||||
time_t t;
|
||||
|
||||
if (ticks != (clock_t)-1) {
|
||||
*(clock_t *)buffer = ticks;
|
||||
}
|
||||
t = time((time_t *)(buffer + sizeof(clock_t)));
|
||||
if (t == (time_t)-1) {
|
||||
*(time_t *)(buffer + sizeof(clock_t)) = (time_t)rand();
|
||||
}
|
||||
|
||||
return base64_encode(ctx, buffer, sizeof(buffer));
|
||||
}
|
||||
|
||||
static char *_make_scram_sha1_init_msg(xmpp_conn_t * const conn)
|
||||
{
|
||||
size_t message_len;
|
||||
char *node;
|
||||
char *message;
|
||||
char *nonce;
|
||||
|
||||
node = xmpp_jid_node(conn->ctx, conn->jid);
|
||||
if (!node) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
nonce = _get_nonce(conn->ctx);
|
||||
if (!nonce) {
|
||||
return NULL;
|
||||
}
|
||||
message_len = strlen(node) + strlen(nonce) + 8 + 1;
|
||||
message = xmpp_alloc(conn->ctx, message_len);
|
||||
if (message) {
|
||||
xmpp_snprintf(message, message_len, "n,,n=%s,r=%s", node, nonce);
|
||||
xmpp_free(conn->ctx, node);
|
||||
}
|
||||
xmpp_free(conn->ctx, nonce);
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
static xmpp_stanza_t *_make_starttls(xmpp_conn_t * const conn)
|
||||
{
|
||||
xmpp_stanza_t *starttls;
|
||||
@@ -455,6 +572,7 @@ static void _auth(xmpp_conn_t * const conn)
|
||||
{
|
||||
xmpp_stanza_t *auth, *authdata, *query, *child, *iq;
|
||||
char *str, *authid;
|
||||
char *scram_init;
|
||||
int anonjid;
|
||||
|
||||
/* if there is no node in conn->jid, we assume anonymous connect */
|
||||
@@ -517,6 +635,51 @@ static void _auth(xmpp_conn_t * const conn)
|
||||
xmpp_error(conn->ctx, "auth",
|
||||
"No node in JID, and SASL ANONYMOUS unsupported.");
|
||||
xmpp_disconnect(conn);
|
||||
} else if (conn->sasl_support & SASL_MASK_SCRAMSHA1) {
|
||||
auth = _make_sasl_auth(conn, "SCRAM-SHA-1");
|
||||
if (!auth) {
|
||||
disconnect_mem_error(conn);
|
||||
return;
|
||||
}
|
||||
|
||||
/* don't free scram_init on success */
|
||||
scram_init = _make_scram_sha1_init_msg(conn);
|
||||
if (!scram_init) {
|
||||
xmpp_stanza_release(auth);
|
||||
disconnect_mem_error(conn);
|
||||
return;
|
||||
}
|
||||
|
||||
str = (char *)base64_encode(conn->ctx, (unsigned char *)scram_init,
|
||||
strlen(scram_init));
|
||||
if (!str) {
|
||||
xmpp_free(conn->ctx, scram_init);
|
||||
xmpp_stanza_release(auth);
|
||||
disconnect_mem_error(conn);
|
||||
return;
|
||||
}
|
||||
|
||||
authdata = xmpp_stanza_new(conn->ctx);
|
||||
if (!authdata) {
|
||||
xmpp_free(conn->ctx, str);
|
||||
xmpp_free(conn->ctx, scram_init);
|
||||
xmpp_stanza_release(auth);
|
||||
disconnect_mem_error(conn);
|
||||
return;
|
||||
}
|
||||
xmpp_stanza_set_text(authdata, str);
|
||||
xmpp_free(conn->ctx, str);
|
||||
xmpp_stanza_add_child(auth, authdata);
|
||||
xmpp_stanza_release(authdata);
|
||||
|
||||
handler_add(conn, _handle_scram_sha1_challenge,
|
||||
XMPP_NS_SASL, NULL, NULL, (void *)scram_init);
|
||||
|
||||
xmpp_send(conn, auth);
|
||||
xmpp_stanza_release(auth);
|
||||
|
||||
/* SASL SCRAM-SHA-1 was tried, unset flag */
|
||||
conn->sasl_support &= ~SASL_MASK_SCRAMSHA1;
|
||||
} else if (conn->sasl_support & SASL_MASK_DIGESTMD5) {
|
||||
auth = _make_sasl_auth(conn, "DIGEST-MD5");
|
||||
if (!auth) {
|
||||
@@ -556,6 +719,7 @@ static void _auth(xmpp_conn_t * const conn)
|
||||
}
|
||||
xmpp_stanza_set_text(authdata, str);
|
||||
xmpp_free(conn->ctx, str);
|
||||
xmpp_free(conn->ctx, authid);
|
||||
|
||||
xmpp_stanza_add_child(auth, authdata);
|
||||
xmpp_stanza_release(authdata);
|
||||
|
||||
@@ -21,12 +21,10 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#ifndef _WIN32
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "strophe.h"
|
||||
#include "ostypes.h"
|
||||
#include "sock.h"
|
||||
#include "tls.h"
|
||||
#include "hash.h"
|
||||
@@ -147,6 +145,7 @@ struct _xmpp_handlist_t {
|
||||
#define SASL_MASK_PLAIN 0x01
|
||||
#define SASL_MASK_DIGESTMD5 0x02
|
||||
#define SASL_MASK_ANONYMOUS 0x04
|
||||
#define SASL_MASK_SCRAMSHA1 0x08
|
||||
|
||||
typedef void (*xmpp_open_handler)(xmpp_conn_t * const conn);
|
||||
|
||||
|
||||
@@ -270,7 +270,7 @@ int xmpp_conn_release(xmpp_conn_t * const conn)
|
||||
|
||||
if (conn->domain) xmpp_free(ctx, conn->domain);
|
||||
if (conn->jid) xmpp_free(ctx, conn->jid);
|
||||
if (conn->bound_jid) xmpp_free(ctx, conn->bound_jid);
|
||||
if (conn->bound_jid) xmpp_free(ctx, conn->bound_jid);
|
||||
if (conn->pass) xmpp_free(ctx, conn->pass);
|
||||
if (conn->stream_id) xmpp_free(ctx, conn->stream_id);
|
||||
if (conn->lang) xmpp_free(ctx, conn->lang);
|
||||
|
||||
15
src/ctx.c
15
src/ctx.c
@@ -252,29 +252,34 @@ void xmpp_log(const xmpp_ctx_t * const ctx,
|
||||
char *buf;
|
||||
va_list copy;
|
||||
|
||||
buf = smbuf;
|
||||
va_copy(copy, ap);
|
||||
ret = xmpp_vsnprintf(buf, 1023, fmt, ap);
|
||||
if (ret > 1023) {
|
||||
ret = xmpp_vsnprintf(smbuf, sizeof(smbuf), fmt, ap);
|
||||
if (ret >= (int)sizeof(smbuf)) {
|
||||
buf = (char *)xmpp_alloc(ctx, ret + 1);
|
||||
if (!buf) {
|
||||
buf = NULL;
|
||||
xmpp_error(ctx, "log", "Failed allocating memory for log message.");
|
||||
va_end(copy);
|
||||
va_end(copy);
|
||||
return;
|
||||
}
|
||||
oldret = ret;
|
||||
ret = xmpp_vsnprintf(buf, ret + 1, fmt, copy);
|
||||
if (ret > oldret) {
|
||||
xmpp_error(ctx, "log", "Unexpected error");
|
||||
xmpp_free(ctx, buf);
|
||||
va_end(copy);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
va_end(copy);
|
||||
buf = smbuf;
|
||||
}
|
||||
va_end(copy);
|
||||
|
||||
if (ctx->log->handler)
|
||||
ctx->log->handler(ctx->log->userdata, level, area, buf);
|
||||
|
||||
if (buf != smbuf)
|
||||
xmpp_free(ctx, buf);
|
||||
}
|
||||
|
||||
/** Write to the log at the ERROR level.
|
||||
|
||||
@@ -23,14 +23,9 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <stdint.h>
|
||||
#else
|
||||
#include "ostypes.h"
|
||||
#endif
|
||||
|
||||
#include "strophe.h"
|
||||
#include "common.h"
|
||||
#include "ostypes.h"
|
||||
|
||||
/** Fire off all stanza handlers that match.
|
||||
* This function is called internally by the event loop whenever stanzas
|
||||
|
||||
@@ -250,12 +250,13 @@ const char * hash_iter_next(hash_iterator_t *iter)
|
||||
{
|
||||
hash_t *table = iter->table;
|
||||
hashentry_t *entry = iter->entry;
|
||||
int i = iter->index + 1;
|
||||
int i;
|
||||
|
||||
/* advance until we find the next entry */
|
||||
if (entry != NULL) entry = entry->next;
|
||||
if (entry == NULL) {
|
||||
/* we're off the end of list, search for a new entry */
|
||||
i = iter->index + 1;
|
||||
while (i < iter->table->length) {
|
||||
entry = table->entries[i];
|
||||
if (entry != NULL) {
|
||||
@@ -266,7 +267,7 @@ const char * hash_iter_next(hash_iterator_t *iter)
|
||||
}
|
||||
}
|
||||
|
||||
if ((entry == NULL) || (i >= table->length)) {
|
||||
if (entry == NULL) {
|
||||
/* no more keys! */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -43,6 +43,9 @@
|
||||
(cp)[3] = ((value) >> 24) & 0xFF; \
|
||||
} while(0)
|
||||
|
||||
static void MD5Transform(uint32_t buf[4], const unsigned char inext[64],
|
||||
struct MD5Context *ctx);
|
||||
|
||||
/*
|
||||
* Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
|
||||
* initialization constants.
|
||||
@@ -179,8 +182,8 @@ void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
|
||||
* reflect the addition of 16 longwords of new data. MD5Update blocks
|
||||
* the data and converts bytes into longwords for this routine.
|
||||
*/
|
||||
void MD5Transform(uint32_t buf[4], const unsigned char inext[64],
|
||||
struct MD5Context *ctx)
|
||||
static void MD5Transform(uint32_t buf[4], const unsigned char inext[64],
|
||||
struct MD5Context *ctx)
|
||||
{
|
||||
register uint32_t a, b, c, d, i;
|
||||
uint32_t in[16];
|
||||
|
||||
11
src/md5.h
11
src/md5.h
@@ -11,15 +11,8 @@
|
||||
#ifndef MD5_H
|
||||
#define MD5_H
|
||||
|
||||
/* we use the uint32_t type from stdint.h
|
||||
* if it is not available, add a typedef here:
|
||||
*/
|
||||
/* make sure the stdint.h types are available */
|
||||
#if defined(_MSC_VER) /* Microsoft Visual C++ */
|
||||
typedef unsigned int uint32_t;
|
||||
#else
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
#include "ostypes.h"
|
||||
|
||||
struct MD5Context {
|
||||
uint32_t buf[4];
|
||||
@@ -31,8 +24,6 @@ void MD5Init(struct MD5Context *context);
|
||||
void MD5Update(struct MD5Context *context, unsigned char const *buf,
|
||||
uint32_t len);
|
||||
void MD5Final(unsigned char digest[16], struct MD5Context *context);
|
||||
void MD5Transform(uint32_t buf[4], const unsigned char in[64],
|
||||
struct MD5Context *ctx);
|
||||
|
||||
#ifdef DEBUG_MD5
|
||||
void MD5DumpBytes(unsigned char *b, int len);
|
||||
|
||||
@@ -20,8 +20,18 @@
|
||||
#ifndef __LIBSTROPHE_OSTYPES_H__
|
||||
#define __LIBSTROPHE_OSTYPES_H__
|
||||
|
||||
#ifdef _WIN32
|
||||
#if defined (_MSC_VER) && _MSC_VER < 1600
|
||||
typedef signed char int8_t;
|
||||
typedef short int int16_t;
|
||||
typedef int int32_t;
|
||||
typedef __int64 int64_t;
|
||||
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short int uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
#else
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#endif /* __LIBSTROPHE_OSTYPES_H__ */
|
||||
|
||||
128
src/sasl.c
128
src/sasl.c
@@ -16,26 +16,19 @@
|
||||
* SASL authentication.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "strophe.h"
|
||||
#include "common.h"
|
||||
#include "ostypes.h"
|
||||
#include "sasl.h"
|
||||
#include "md5.h"
|
||||
#include "sha1.h"
|
||||
#include "scram.h"
|
||||
|
||||
/* make sure the stdint.h types are available */
|
||||
#if defined(_MSC_VER) /* Microsoft Visual C++ */
|
||||
typedef signed char int8_t;
|
||||
typedef short int int16_t;
|
||||
typedef int int32_t;
|
||||
typedef __int64 int64_t;
|
||||
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short int uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
/* no uint64_t */
|
||||
#else
|
||||
#include <stdint.h>
|
||||
#ifdef _WIN32
|
||||
#define strtok_r strtok_s
|
||||
#endif
|
||||
|
||||
|
||||
@@ -360,6 +353,113 @@ char *sasl_digest_md5(xmpp_ctx_t *ctx, const char *challenge,
|
||||
return response;
|
||||
}
|
||||
|
||||
/** generate auth response string for the SASL SCRAM-SHA-1 mechanism */
|
||||
char *sasl_scram_sha1(xmpp_ctx_t *ctx, const char *challenge,
|
||||
const char *first_bare, const char *jid,
|
||||
const char *password)
|
||||
{
|
||||
uint8_t key[SHA1_DIGEST_SIZE];
|
||||
uint8_t sign[SHA1_DIGEST_SIZE];
|
||||
char *r = NULL;
|
||||
char *s = NULL;
|
||||
char *i = NULL;
|
||||
char *sval;
|
||||
size_t sval_len;
|
||||
long ival;
|
||||
char *tmp;
|
||||
char *ptr;
|
||||
char *saveptr = NULL;
|
||||
char *response;
|
||||
char *auth;
|
||||
char *response_b64;
|
||||
char *sign_b64;
|
||||
char *result = NULL;
|
||||
size_t response_len;
|
||||
size_t auth_len;
|
||||
int j;
|
||||
|
||||
tmp = xmpp_strdup(ctx, challenge);
|
||||
if (!tmp) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ptr = strtok_r(tmp, ",", &saveptr);
|
||||
while (ptr) {
|
||||
if (strncmp(ptr, "r=", 2) == 0) {
|
||||
r = ptr;
|
||||
} else if (strncmp(ptr, "s=", 2) == 0) {
|
||||
s = ptr + 2;
|
||||
} else if (strncmp(ptr, "i=", 2) == 0) {
|
||||
i = ptr + 2;
|
||||
}
|
||||
ptr = strtok_r(NULL, ",", &saveptr);
|
||||
}
|
||||
|
||||
if (!r || !s || !i) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
sval = (char *)base64_decode(ctx, s, strlen(s));
|
||||
if (!sval) {
|
||||
goto out;
|
||||
}
|
||||
sval_len = base64_decoded_len(ctx, s, strlen(s));
|
||||
ival = strtol(i, &saveptr, 10);
|
||||
|
||||
auth_len = 10 + strlen(r) + strlen(first_bare) + strlen(challenge);
|
||||
auth = xmpp_alloc(ctx, auth_len);
|
||||
if (!auth) {
|
||||
goto out_sval;
|
||||
}
|
||||
|
||||
response_len = 39 + strlen(r);
|
||||
response = xmpp_alloc(ctx, response_len);
|
||||
if (!response) {
|
||||
goto out_auth;
|
||||
}
|
||||
|
||||
xmpp_snprintf(response, response_len, "c=biws,%s", r);
|
||||
xmpp_snprintf(auth, auth_len, "%s,%s,%s", first_bare + 3, challenge,
|
||||
response);
|
||||
|
||||
SCRAM_SHA1_ClientKey((uint8_t *)password, strlen(password),
|
||||
(uint8_t *)sval, sval_len, (uint32_t)ival, key);
|
||||
SCRAM_SHA1_ClientSignature(key, (uint8_t *)auth, strlen(auth), sign);
|
||||
for (j = 0; j < SHA1_DIGEST_SIZE; j++) {
|
||||
sign[j] ^= key[j];
|
||||
}
|
||||
|
||||
sign_b64 = base64_encode(ctx, sign, sizeof(sign));
|
||||
if (!sign_b64) {
|
||||
goto out_response;
|
||||
}
|
||||
|
||||
if (strlen(response) + strlen(sign_b64) + 3 + 1 > response_len) {
|
||||
xmpp_free(ctx, sign_b64);
|
||||
goto out_response;
|
||||
}
|
||||
strcat(response, ",p=");
|
||||
strcat(response, sign_b64);
|
||||
xmpp_free(ctx, sign_b64);
|
||||
|
||||
response_b64 = base64_encode(ctx, (unsigned char *)response,
|
||||
strlen(response));
|
||||
if (!response_b64) {
|
||||
goto out_response;
|
||||
}
|
||||
result = response_b64;
|
||||
|
||||
out_response:
|
||||
xmpp_free(ctx, response);
|
||||
out_auth:
|
||||
xmpp_free(ctx, auth);
|
||||
out_sval:
|
||||
xmpp_free(ctx, sval);
|
||||
out:
|
||||
xmpp_free(ctx, tmp);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/** Base64 encoding routines. Implemented according to RFC 3548 */
|
||||
|
||||
@@ -552,8 +652,8 @@ unsigned char *base64_decode(xmpp_ctx_t *ctx,
|
||||
if (hextet != 64) goto _base64_decode_error;
|
||||
break;
|
||||
}
|
||||
*d = '\0';
|
||||
}
|
||||
*d = '\0';
|
||||
return dbuf;
|
||||
|
||||
_base64_decode_error:
|
||||
|
||||
@@ -26,6 +26,9 @@
|
||||
char *sasl_plain(xmpp_ctx_t *ctx, const char *authid, const char *password);
|
||||
char *sasl_digest_md5(xmpp_ctx_t *ctx, const char *challenge,
|
||||
const char *jid, const char *password);
|
||||
char *sasl_scram_sha1(xmpp_ctx_t *ctx, const char *challenge,
|
||||
const char *first_bare, const char *jid,
|
||||
const char *password);
|
||||
|
||||
|
||||
/** Base64 encoding routines. Implemented according to RFC 3548 */
|
||||
|
||||
146
src/scram.c
Normal file
146
src/scram.c
Normal file
@@ -0,0 +1,146 @@
|
||||
/* scram.c
|
||||
* strophe XMPP client library
|
||||
*
|
||||
* SCRAM-SHA1 helper functions according to RFC5802
|
||||
* HMAC-SHA1 implementation according to RFC2104
|
||||
*
|
||||
* Copyright (C) 2013 Dmitry Podgorny <pasis.ua@gmail.com>
|
||||
*
|
||||
* This software is provided AS-IS with no warranty, either express
|
||||
* or implied.
|
||||
*
|
||||
* This software is distributed under license and may not be copied,
|
||||
* modified or distributed except as expressly authorized under the
|
||||
* terms of the license contained in the file LICENSE.txt in this
|
||||
* distribution.
|
||||
*/
|
||||
|
||||
/** @file
|
||||
* SCRAM-SHA1 helper functions.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "sha1.h"
|
||||
#include "ostypes.h"
|
||||
|
||||
#include "scram.h"
|
||||
|
||||
/* block size for HMAC */
|
||||
#define BLOCK_SIZE 64
|
||||
#if BLOCK_SIZE < SHA1_DIGEST_SIZE
|
||||
#error BLOCK_SIZE must not be less than SHA1_DIGEST_SIZE
|
||||
#endif
|
||||
|
||||
static const uint8_t ipad = 0x36;
|
||||
static const uint8_t opad = 0x5C;
|
||||
|
||||
static void SHA1(const uint8_t* data, size_t len,
|
||||
uint8_t digest[SHA1_DIGEST_SIZE])
|
||||
{
|
||||
SHA1_CTX ctx;
|
||||
SHA1_Init(&ctx);
|
||||
SHA1_Update(&ctx, data, len);
|
||||
SHA1_Final(&ctx, digest);
|
||||
}
|
||||
|
||||
static void HMAC_SHA1(const uint8_t *key, size_t key_len,
|
||||
const uint8_t *text, size_t len,
|
||||
uint8_t digest[SHA1_DIGEST_SIZE])
|
||||
{
|
||||
uint8_t key_pad[BLOCK_SIZE];
|
||||
uint8_t key_ipad[BLOCK_SIZE];
|
||||
uint8_t key_opad[BLOCK_SIZE];
|
||||
uint8_t sha_digest[SHA1_DIGEST_SIZE];
|
||||
int i;
|
||||
SHA1_CTX ctx;
|
||||
|
||||
memset(key_pad, 0, sizeof(key_pad));
|
||||
if (key_len <= BLOCK_SIZE) {
|
||||
memcpy(key_pad, key, key_len);
|
||||
} else {
|
||||
/* according to RFC2104 */
|
||||
SHA1(key, key_len, key_pad);
|
||||
}
|
||||
|
||||
for (i = 0; i < BLOCK_SIZE; i++) {
|
||||
key_ipad[i] = key_pad[i] ^ ipad;
|
||||
key_opad[i] = key_pad[i] ^ opad;
|
||||
}
|
||||
|
||||
SHA1_Init(&ctx);
|
||||
SHA1_Update(&ctx, key_ipad, BLOCK_SIZE);
|
||||
SHA1_Update(&ctx, text, len);
|
||||
SHA1_Final(&ctx, sha_digest);
|
||||
|
||||
SHA1_Init(&ctx);
|
||||
SHA1_Update(&ctx, key_opad, BLOCK_SIZE);
|
||||
SHA1_Update(&ctx, sha_digest, SHA1_DIGEST_SIZE);
|
||||
SHA1_Final(&ctx, digest);
|
||||
}
|
||||
|
||||
static void SCRAM_SHA1_Hi(const uint8_t *text, size_t len,
|
||||
const uint8_t *salt, size_t salt_len, uint32_t i,
|
||||
uint8_t digest[SHA1_DIGEST_SIZE])
|
||||
{
|
||||
int j, k;
|
||||
uint8_t tmp[128];
|
||||
|
||||
static uint8_t int1[] = {0x0, 0x0, 0x0, 0x1};
|
||||
|
||||
/* assume salt + INT(1) isn't longer than sizeof(tmp) */
|
||||
assert(salt_len <= sizeof(tmp) - sizeof(int1));
|
||||
|
||||
memset(digest, 0, SHA1_DIGEST_SIZE);
|
||||
if (i == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(tmp, salt, salt_len);
|
||||
memcpy(&tmp[salt_len], int1, sizeof(int1));
|
||||
|
||||
/* 'text' for Hi is a 'key' for HMAC */
|
||||
HMAC_SHA1(text, len, tmp, salt_len + sizeof(int1), digest);
|
||||
memcpy(tmp, digest, SHA1_DIGEST_SIZE);
|
||||
|
||||
for (j = 1; j < i; j++) {
|
||||
HMAC_SHA1(text, len, tmp, SHA1_DIGEST_SIZE, tmp);
|
||||
for (k = 0; k < SHA1_DIGEST_SIZE; k++) {
|
||||
digest[k] ^= tmp[k];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SCRAM_SHA1_ClientKey(const uint8_t *password, size_t len,
|
||||
const uint8_t *salt, size_t salt_len, uint32_t i,
|
||||
uint8_t key[SHA1_DIGEST_SIZE])
|
||||
{
|
||||
uint8_t salted[SHA1_DIGEST_SIZE];
|
||||
|
||||
/* XXX: Normalize(password) is omitted */
|
||||
|
||||
SCRAM_SHA1_Hi(password, len, salt, salt_len, i, salted);
|
||||
HMAC_SHA1(salted, SHA1_DIGEST_SIZE, (uint8_t *)"Client Key",
|
||||
strlen("Client Key"), key);
|
||||
}
|
||||
|
||||
void SCRAM_SHA1_ClientSignature(const uint8_t ClientKey[SHA1_DIGEST_SIZE],
|
||||
const uint8_t *AuthMessage, size_t len,
|
||||
uint8_t sign[SHA1_DIGEST_SIZE])
|
||||
{
|
||||
uint8_t stored[SHA1_DIGEST_SIZE];
|
||||
|
||||
SHA1(ClientKey, SHA1_DIGEST_SIZE, stored);
|
||||
HMAC_SHA1(stored, SHA1_DIGEST_SIZE, AuthMessage, len, sign);
|
||||
}
|
||||
|
||||
void SCRAM_SHA1_ClientProof(const uint8_t ClientKey[SHA1_DIGEST_SIZE],
|
||||
const uint8_t ClientSignature[SHA1_DIGEST_SIZE],
|
||||
uint8_t proof[SHA1_DIGEST_SIZE])
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < SHA1_DIGEST_SIZE; i++) {
|
||||
proof[i] = ClientKey[i] ^ ClientSignature[i];
|
||||
}
|
||||
}
|
||||
39
src/scram.h
Normal file
39
src/scram.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/* scram.h
|
||||
* strophe XMPP client library -- SCRAM-SHA1 helper functions
|
||||
*
|
||||
* Copyright (C) 2013 Dmitry Podgorny <pasis.ua@gmail.com>
|
||||
*
|
||||
* This software is provided AS-IS with no warranty, either express
|
||||
* or implied.
|
||||
*
|
||||
* This software is distributed under license and may not be copied,
|
||||
* modified or distributed except as expressly authorized under the
|
||||
* terms of the license contained in the file LICENSE.txt in this
|
||||
* distribution.
|
||||
*/
|
||||
|
||||
/** @file
|
||||
* SCRAM-SHA1 helper functions.
|
||||
*/
|
||||
|
||||
#ifndef __LIBSTROPHE_SCRAM_H__
|
||||
#define __LIBSTROPHE_SCRAM_H__
|
||||
|
||||
/* make sure the stdint.h types are available */
|
||||
#include "ostypes.h"
|
||||
|
||||
#include "sha1.h"
|
||||
|
||||
void SCRAM_SHA1_ClientKey(const uint8_t *password, size_t len,
|
||||
const uint8_t *salt, size_t salt_len, uint32_t i,
|
||||
uint8_t key[SHA1_DIGEST_SIZE]);
|
||||
|
||||
void SCRAM_SHA1_ClientSignature(const uint8_t ClientKey[SHA1_DIGEST_SIZE],
|
||||
const uint8_t *AuthMessage, size_t len,
|
||||
uint8_t sign[SHA1_DIGEST_SIZE]);
|
||||
|
||||
void SCRAM_SHA1_ClientProof(const uint8_t ClientKey[SHA1_DIGEST_SIZE],
|
||||
const uint8_t ClientSignature[SHA1_DIGEST_SIZE],
|
||||
uint8_t proof[SHA1_DIGEST_SIZE]);
|
||||
|
||||
#endif /* __LIBSTROPHE_SCRAM_H__ */
|
||||
47
src/sha1.c
47
src/sha1.c
@@ -86,35 +86,18 @@ A million repetitions of "a"
|
||||
#include <string.h>
|
||||
|
||||
/* make sure the stdint.h types are available */
|
||||
#if defined(_MSC_VER) /* Microsoft Visual C++ */
|
||||
typedef signed char int8_t;
|
||||
typedef short int int16_t;
|
||||
typedef int int32_t;
|
||||
typedef __int64 int64_t;
|
||||
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short int uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
/* no uint64_t */
|
||||
#else
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
#include "ostypes.h"
|
||||
|
||||
#include "sha1.h"
|
||||
|
||||
void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64]);
|
||||
static uint32_t host_to_be(uint32_t i);
|
||||
static void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64]);
|
||||
|
||||
#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
|
||||
|
||||
/* blk0() and blk() perform the initial expand. */
|
||||
/* I got the idea of expanding during the round function from SSLeay */
|
||||
/* FIXME: can we do this in an endian-proof way? */
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
#define blk0(i) block->l[i]
|
||||
#else
|
||||
#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \
|
||||
|(rol(block->l[i],8)&0x00FF00FF))
|
||||
#endif
|
||||
#define blk0(i) (block->l[i] = host_to_be(block->l[i]))
|
||||
#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
|
||||
^block->l[(i+2)&15]^block->l[i&15],1))
|
||||
|
||||
@@ -139,8 +122,28 @@ void SHAPrintContext(SHA1_CTX *context, char *msg){
|
||||
}
|
||||
#endif /* VERBOSE */
|
||||
|
||||
static uint32_t host_to_be(uint32_t i)
|
||||
{
|
||||
#define le_to_be(i) ((rol((i),24) & 0xFF00FF00) | (rol((i),8) & 0x00FF00FF))
|
||||
#if defined(__BIG_ENDIAN__) || \
|
||||
(defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \
|
||||
__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
|
||||
return i;
|
||||
#elif defined(__LITTLE_ENDIAN__) || \
|
||||
(defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \
|
||||
__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
|
||||
return le_to_be(i);
|
||||
#else /* fallback to run-time check */
|
||||
static const union {
|
||||
uint32_t u;
|
||||
unsigned char c;
|
||||
} check = {1};
|
||||
return check.c ? le_to_be(i) : i;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Hash a single 512-bit block. This is the core of the algorithm. */
|
||||
void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64])
|
||||
static void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64])
|
||||
{
|
||||
uint32_t a, b, c, d, e;
|
||||
typedef union {
|
||||
|
||||
@@ -12,6 +12,9 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* make sure the stdint.h types are available */
|
||||
#include "ostypes.h"
|
||||
|
||||
typedef struct {
|
||||
uint32_t state[5];
|
||||
uint32_t count[2];
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#endif
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/rand.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "tls.h"
|
||||
|
||||
@@ -75,11 +75,11 @@ tls_t *tls_new(xmpp_ctx_t *ctx, sock_t sock)
|
||||
SecPkgCred_CipherStrengths spc_cs;
|
||||
SecPkgCred_SupportedProtocols spc_sp;
|
||||
|
||||
OSVERSIONINFO osvi;
|
||||
|
||||
memset(&osvi, 0, sizeof(osvi));
|
||||
osvi.dwOSVersionInfoSize = sizeof(osvi);
|
||||
|
||||
OSVERSIONINFO osvi;
|
||||
|
||||
memset(&osvi, 0, sizeof(osvi));
|
||||
osvi.dwOSVersionInfoSize = sizeof(osvi);
|
||||
|
||||
GetVersionEx(&osvi);
|
||||
|
||||
/* no TLS support on win9x/me, despite what anyone says */
|
||||
@@ -102,7 +102,7 @@ tls_t *tls_new(xmpp_ctx_t *ctx, sock_t sock)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(pInitSecurityInterface =
|
||||
if (!(pInitSecurityInterface =
|
||||
(void *)GetProcAddress(tls->hsec32, "InitSecurityInterfaceA"))) {
|
||||
tls_free(tls);
|
||||
return NULL;
|
||||
@@ -148,26 +148,26 @@ tls_t *tls_new(xmpp_ctx_t *ctx, sock_t sock)
|
||||
|
||||
/* This bunch of queries should trip up wine until someone fixes
|
||||
* schannel support there */
|
||||
ret = tls->sft->QueryCredentialsAttributes(&(tls->hcred), SECPKG_ATTR_SUPPORTED_ALGS, &spc_sa);
|
||||
if (ret != SEC_E_OK)
|
||||
{
|
||||
tls_free(tls);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = tls->sft->QueryCredentialsAttributes(&(tls->hcred), SECPKG_ATTR_CIPHER_STRENGTHS, &spc_cs);
|
||||
if (ret != SEC_E_OK)
|
||||
{
|
||||
tls_free(tls);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = tls->sft->QueryCredentialsAttributes(&(tls->hcred), SECPKG_ATTR_SUPPORTED_PROTOCOLS, &spc_sp);
|
||||
if (ret != SEC_E_OK)
|
||||
{
|
||||
tls_free(tls);
|
||||
return NULL;
|
||||
}
|
||||
ret = tls->sft->QueryCredentialsAttributes(&(tls->hcred), SECPKG_ATTR_SUPPORTED_ALGS, &spc_sa);
|
||||
if (ret != SEC_E_OK)
|
||||
{
|
||||
tls_free(tls);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = tls->sft->QueryCredentialsAttributes(&(tls->hcred), SECPKG_ATTR_CIPHER_STRENGTHS, &spc_cs);
|
||||
if (ret != SEC_E_OK)
|
||||
{
|
||||
tls_free(tls);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = tls->sft->QueryCredentialsAttributes(&(tls->hcred), SECPKG_ATTR_SUPPORTED_PROTOCOLS, &spc_sp);
|
||||
if (ret != SEC_E_OK)
|
||||
{
|
||||
tls_free(tls);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return tls;
|
||||
}
|
||||
@@ -196,7 +196,7 @@ void tls_free(tls_t *tls)
|
||||
FreeLibrary(tls->hsec32);
|
||||
tls->hsec32 = NULL;
|
||||
}
|
||||
|
||||
|
||||
xmpp_free(tls->ctx, tls);
|
||||
return;
|
||||
}
|
||||
@@ -360,7 +360,7 @@ int tls_start(tls_t *tls)
|
||||
return 0;
|
||||
}
|
||||
|
||||
tls->sft->QueryContextAttributes(&(tls->hctxt), SECPKG_ATTR_STREAM_SIZES,
|
||||
tls->sft->QueryContextAttributes(&(tls->hctxt), SECPKG_ATTR_STREAM_SIZES,
|
||||
&(tls->spcss));
|
||||
|
||||
tls->recvbuffermaxlen = tls->spcss.cbHeader + tls->spcss.cbMaximumMessage
|
||||
@@ -401,7 +401,7 @@ int tls_is_recoverable(int error)
|
||||
int tls_pending(tls_t *tls) {
|
||||
// There are 3 cases:
|
||||
// - there is data in ready buffer, so it is by default pending
|
||||
// - there is data in recv buffer. If it is not decrypted yet, means it
|
||||
// - there is data in recv buffer. If it is not decrypted yet, means it
|
||||
// was incomplete. This should be processed again only if there is data
|
||||
// on the physical connection
|
||||
// - there is data on the physical connection. This case is treated
|
||||
@@ -440,7 +440,7 @@ int tls_read(tls_t *tls, void * const buff, const size_t len)
|
||||
read = tls_read(tls, newbuff, len - bytes);
|
||||
|
||||
if (read == -1) {
|
||||
if (tls_is_recoverable(tls->lasterror)) {
|
||||
if (tls_is_recoverable(tls->lasterror)) {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@@ -454,11 +454,11 @@ int tls_read(tls_t *tls, void * const buff, const size_t len)
|
||||
/* next, top up our recv buffer */
|
||||
bytes = sock_read(tls->sock, tls->recvbuffer + tls->recvbufferpos,
|
||||
tls->recvbuffermaxlen - tls->recvbufferpos);
|
||||
|
||||
|
||||
if (bytes == 0) {
|
||||
tls->lasterror = WSAECONNRESET;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (bytes == -1) {
|
||||
if (!tls_is_recoverable(sock_error())) {
|
||||
@@ -499,7 +499,7 @@ int tls_read(tls_t *tls, void * const buff, const size_t len)
|
||||
ret = tls->sft->DecryptMessage(&(tls->hctxt), &sbddec, 0, NULL);
|
||||
|
||||
if (ret == SEC_E_OK) {
|
||||
memcpy(tls->readybuffer, sbdec[1].pvBuffer, sbdec[1].cbBuffer);
|
||||
memcpy(tls->readybuffer, sbdec[1].pvBuffer, sbdec[1].cbBuffer);
|
||||
tls->readybufferpos = 0;
|
||||
tls->readybufferlen = sbdec[1].cbBuffer;
|
||||
/* have we got some data left over? If so, copy it to the start
|
||||
@@ -631,8 +631,8 @@ int tls_write(tls_t *tls, const void * const buff, const size_t len)
|
||||
|
||||
if (ret == -1 && !tls_is_recoverable(tls_error(tls))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (remain > tls->spcss.cbMaximumMessage) {
|
||||
sent += tls->spcss.cbMaximumMessage;
|
||||
remain -= tls->spcss.cbMaximumMessage;
|
||||
|
||||
@@ -24,11 +24,11 @@
|
||||
#else
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#include "strophe.h"
|
||||
#include "common.h"
|
||||
#include "ostypes.h"
|
||||
#include "util.h"
|
||||
|
||||
/** implement our own strdup that uses the ctx allocator */
|
||||
|
||||
@@ -19,11 +19,7 @@
|
||||
#ifndef __LIBSTROPHE_UTIL_H__
|
||||
#define __LIBSTROPHE_UTIL_H__
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <stdint.h>
|
||||
#else
|
||||
#include "ostypes.h"
|
||||
#endif
|
||||
|
||||
/* timing functions */
|
||||
uint64_t time_stamp(void);
|
||||
|
||||
Reference in New Issue
Block a user