On Thu, 2014-07-31 at 10:28 -0700, Kevin Cernekee wrote: > Don't know if anyone has tried to build libstoken under MinGW. I had a quick look at this but Fedora doesn't have a mingw32-libtomcrypt package. Here's an almost completely untested patch to make it use nettle as an alternative. And then I get: [dwoodhou at i7 stoken]$ make -k make all-am make[1]: Entering directory `/ssd/git/stoken' CC src/libstoken_la-library.lo src/library.c: In function '__stoken_parse_and_decode_token': src/library.c:71:3: error: implicit declaration of function 'strcasestr' [-Werror=implicit-function-declaration] p = strcasestr(str, "ctfData=3D"); ^ src/library.c:71:3: warning: nested extern declaration of 'strcasestr' [-Wnested-externs] src/library.c:71:5: warning: assignment makes pointer from integer without a cast [enabled by default] p = strcasestr(str, "ctfData=3D"); ^ src/library.c:78:5: warning: assignment makes pointer from integer without a cast [enabled by default] p = strcasestr(str, "ctfData="); ^ src/library.c:85:5: warning: assignment makes pointer from integer without a cast [enabled by default] p = strcasestr(str, "<?xml "); ^ cc1: some warnings being treated as errors make[1]: *** [src/libstoken_la-library.lo] Error 1 CC src/libstoken_la-securid.lo src/securid.c: In function 'securid_compute_tokencode': src/securid.c:984:2: error: implicit declaration of function 'gmtime_r' [-Werror=implicit-function-declaration] gmtime_r(&now, &gmt); ^ src/securid.c:984:2: warning: nested extern declaration of 'gmtime_r' [-Wnested-externs] cc1: some warnings being treated as errors make[1]: *** [src/libstoken_la-securid.lo] Error 1 CC src/libstoken_la-sdtid.lo src/sdtid.c: In function 'format_date': src/sdtid.c:660:2: error: implicit declaration of function 'gmtime_r' [-Werror=implicit-function-declaration] gmtime_r(&t, &tm); ^ src/sdtid.c:660:2: warning: nested extern declaration of 'gmtime_r' [-Wnested-externs] cc1: some warnings being treated as errors make[1]: *** [src/libstoken_la-sdtid.lo] Error 1 CC src/cli.o src/cli.c:29:21: fatal error: termios.h: No such file or directory #include <termios.h> ^ compilation terminated. make[1]: *** [src/cli.o] Error 1 CC src/common.o src/common.c:29:22: fatal error: sys/mman.h: No such file or directory #include <sys/mman.h> ^ compilation terminated. make[1]: *** [src/common.o] Error 1 make[1]: Target `all-am' not remade because of errors. make[1]: Leaving directory `/ssd/git/stoken' make: *** [all] Error 2 [dwoodhou at i7 stoken]$ diff --git a/Makefile.am b/Makefile.am index 565af85..8e94842 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,7 +1,16 @@ +if CRYPTO_NETTLE +CRYPTO_LIBS = $(NETTLE_LIBS) +CRYPTO_CFLAGS = $(NETTLE_CFLAGS) +endif +if CRYPTO_TOMCRYPT +CRYPTO_LIBS = $(TOMCRYPT_LIBS) +CRYPTO_CFLAGS = $(TOMCRYPT_CFLAGS) +endif + AUTOMAKE_OPTIONS = foreign subdir-objects AM_CPPFLAGS = -DDATA_DIR=\"$(datadir)\" -AM_CFLAGS = $(TOMCRYPT_CFLAGS) $(LIBXML2_CFLAGS) $(WFLAGS) +AM_CFLAGS = $(CRYPTO_CFLAGS) $(LIBXML2_CFLAGS) $(WFLAGS) dist_man_MANS = stoken.1 @@ -10,7 +19,7 @@ libstoken_la_SOURCES = src/library.c src/securid.c src/sdtid.c libstoken_la_CFLAGS = $(AM_CFLAGS) libstoken_la_LDFLAGS = -version-number @APIMAJOR@:@APIMINOR@ libstoken_la_LDFLAGS += -Wl,--version-script, at srcdir@/libstoken.map -libstoken_la_LIBADD = $(TOMCRYPT_LIBS) $(LIBXML2_LIBS) +libstoken_la_LIBADD = $(CRYPTO_LIBS) $(LIBXML2_LIBS) libstoken_la_DEPENDENCIES = libstoken.map include_HEADERS = src/stoken.h noinst_HEADERS = src/common.h src/securid.h src/stoken-internal.h \ diff --git a/configure.ac b/configure.ac index 0e10d07..24128bd 100644 --- a/configure.ac +++ b/configure.ac @@ -113,41 +113,60 @@ AM_CONDITIONAL([ENABLE_GUI], [test $enable_gui = yes]) PKG_CHECK_MODULES([LIBXML2], [libxml-2.0]) -# libtomcrypt -# Some distributions add a libtomcrypt.pc file, but it isn't in the upstream -# libtomcrypt distribution so we can't count on it. - -tomcrypt_pkg=no - -if test "x$PKG_CONFIG" != x; then - PKG_CHECK_EXISTS([libtomcrypt], [tomcrypt_pkg=yes], []) +AC_ARG_WITH([crypto], + [AS_HELP_STRING([--with-crypto=PACKAGE], + [Use PACKAGE (nettle/tomcrypt) for crypto [default=tomcrypt]])]) +if test "x$with_crypto" = "x"; then + with_crypto=tomcrypt fi -if test $tomcrypt_pkg = no; then - AC_SUBST(TOMCRYPT_LIBS, [-ltomcrypt]) - AC_SUBST(LIBTOMCRYPT_PC, []) - EXTRA_PC_LIBS="$EXTRA_PC_LIBS -ltomcrypt" -else - AC_SUBST(LIBTOMCRYPT_PC, [libtomcrypt]) - PKG_CHECK_MODULES([TOMCRYPT], libtomcrypt) -fi +case "$with_crypto" in + nettle) + PKG_CHECK_MODULES(NETTLE, nettle) + AC_SUBST(CRYPTO_PC, [nettle]) + AC_DEFINE(CRYPTO_NETTLE, [1], [Use nettle for crypto]) + ;; + tomcrypt) + tomcrypt_pkg=no + + # Try libtomcrypt + if test "x$PKG_CONFIG" != x; then + PKG_CHECK_EXISTS([libtomcrypt], [tomcrypt_pkg=yes], []) + fi -saved_LIBS="$LIBS" -saved_CFLAGS="$CFLAGS" -LIBS="$LIBS $TOMCRYPT_LIBS" -CFLAGS="$CFLAGS $TOMCRYPT_CFLAGS" + if test $tomcrypt_pkg = no; then + AC_SUBST(TOMCRYPT_LIBS, [-ltomcrypt]) + AC_SUBST(LIBTOMCRYPT_PC, []) + EXTRA_PC_LIBS="$EXTRA_PC_LIBS -ltomcrypt" + else + AC_SUBST(CRYPTO_PC, [libtomcrypt]) + PKG_CHECK_MODULES([TOMCRYPT], libtomcrypt) + fi -AC_MSG_CHECKING([if libtomcrypt is usable]) -AC_TRY_LINK([#include <tomcrypt.h>], - [rijndael_ecb_encrypt(NULL,NULL,NULL);], - [AC_MSG_RESULT([yes])], - [AC_MSG_FAILURE([unable to link libtomcrypt test program])]) + saved_LIBS="$LIBS" + saved_CFLAGS="$CFLAGS" + LIBS="$LIBS $TOMCRYPT_LIBS" + CFLAGS="$CFLAGS $TOMCRYPT_CFLAGS" -LIBS="$saved_LIBS" -CFLAGS="$saved_CFLAGS" + AC_MSG_CHECKING([if libtomcrypt is usable]) + AC_TRY_LINK([#include <tomcrypt.h>], + [rijndael_ecb_encrypt(NULL,NULL,NULL);], + [AC_MSG_RESULT([yes])], + [AC_MSG_FAILURE([unable to link libtomcrypt test program])]) + LIBS="$saved_LIBS" + CFLAGS="$saved_CFLAGS" + AC_DEFINE(CRYPTO_TOMCRYPT, [1], [Use libtomcrypt for crypto]) + ;; + *) + AC_MSG_FAILURE([Unrecognised crypto library "$with_crypto"]) + ;; +esac AC_SUBST(EXTRA_PC_LIBS, [$EXTRA_PC_LIBS]) +AM_CONDITIONAL([CRYPTO_NETTLE], [test "$with_crypto" = "nettle"]) +AM_CONDITIONAL([CRYPTO_TOMCRYPT], [test "$with_crypto" = "tomcrypt"]) + # JNI AC_ARG_WITH([java], diff --git a/src/sdtid.c b/src/sdtid.c index 89990f7..ba00b60 100644 --- a/src/sdtid.c +++ b/src/sdtid.c @@ -27,10 +27,13 @@ #include <string.h> #include <time.h> #include <unistd.h> +#include <ctype.h> #include <libxml/parser.h> #include <libxml/tree.h> +#ifdef CRYPTO_TOMCRYPT #include <tomcrypt.h> +#endif #include "securid.h" #include "sdtid.h" @@ -338,8 +341,7 @@ static int lookup_b64(struct sdtid *s, const char *name, uint8_t *out, if (*p && !strcmp(name, "Seed")) p++; - len = base64_decode(p, strlen(p), out, &actual) == CRYPT_OK ? - actual : -1; + len = base64_decode(p, strlen(p), out, &actual) ? -1 : actual; free(data); return len == buf_len ? 0 : -1; diff --git a/src/securid.c b/src/securid.c index 602880a..5f0148a 100644 --- a/src/securid.c +++ b/src/securid.c @@ -27,7 +27,6 @@ #include <stdlib.h> #include <string.h> #include <time.h> -#include <tomcrypt.h> #include <sys/stat.h> #include <sys/time.h> #include <sys/types.h> @@ -81,6 +80,36 @@ static uint8_t hex2byte(const char *in) return (hex2nibble(in[0]) << 4) | hex2nibble(in[1]); } +static int read_dev_random(const char *dev, void *out, int len) +{ + /* + * Use /dev/random for long lived key material but not for + * test purposes. This can block for a long time if entropy + * is limited. + */ + int fd; + char *p = out; + + fd = open(dev, O_RDONLY); + if (fd < 0) + return ERR_GENERAL; + + while (len) { + ssize_t ret = read(fd, p, len); + if (ret < 0) { + close(fd); + return ERR_GENERAL; + } + p += ret; + len -= ret; + } + close(fd); + return ERR_NONE; +} + +#ifdef CRYPTO_TOMCRYPT +#include <tomcrypt.h> + void aes128_ecb_encrypt(const uint8_t *key, const uint8_t *in, uint8_t *out) { symmetric_key skey; @@ -153,36 +182,175 @@ static void aes256_cbc_encrypt(const uint8_t *key, const uint8_t *in, int in_len int securid_rand(void *out, int len, int paranoid) { - if (paranoid) { - /* - * Use /dev/random for long lived key material but not for - * test purposes. This can block for a long time if entropy - * is limited. - */ - int fd; - char *p = out; + if (paranoid) + return read_dev_random("/dev/random", out, len); - fd = open("/dev/random", O_RDONLY); - if (fd < 0) - return ERR_GENERAL; + if (rng_get_bytes(out, len, NULL) != len) + return ERR_GENERAL; - while (len) { - ssize_t ret = read(fd, p, len); - if (ret < 0) { - close(fd); - return ERR_GENERAL; - } - p += ret; - len -= ret; - } - close(fd); - } else { - if (rng_get_bytes(out, len, NULL) != len) - return ERR_GENERAL; - } return ERR_NONE; } +static void sha256_hash(const uint8_t *in, int in_len, uint8_t *out) +{ + hash_state md; + sha256_init(&md); + sha256_process(&md, in, in_len); + sha256_done(&md, out); +} + +static void sha256_hmac(const uint8_t *key, int key_len, + const uint8_t *msg, int msg_len, uint8_t *out) +{ + hash_state md; + uint8_t tmp_key[SHA256_HASH_SIZE], o_key_pad[SHA256_BLOCK_SIZE], + i_key_pad[SHA256_BLOCK_SIZE], inner_hash[SHA256_BLOCK_SIZE]; + int i; + + if (key_len > SHA256_BLOCK_SIZE) { + sha256_hash(key, key_len, tmp_key); + key = tmp_key; + key_len = SHA256_HASH_SIZE; + } + + memset(o_key_pad, 0x5c, SHA256_BLOCK_SIZE); + memset(i_key_pad, 0x36, SHA256_BLOCK_SIZE); + for (i = 0; i < key_len; i++) { + o_key_pad[i] ^= key[i]; + i_key_pad[i] ^= key[i]; + } + + sha256_init(&md); + sha256_process(&md, i_key_pad, SHA256_BLOCK_SIZE); + sha256_process(&md, msg, msg_len); + sha256_done(&md, inner_hash); + + sha256_init(&md); + sha256_process(&md, o_key_pad, SHA256_BLOCK_SIZE); + sha256_process(&md, inner_hash, SHA256_HASH_SIZE); + sha256_done(&md, out); +} +#elif defined (CRYPTO_NETTLE) +#include <nettle/base64.h> +#include <nettle/sha2.h> +#include <nettle/hmac.h> +#include <nettle/aes.h> +#include <nettle/cbc.h> + +/* Ick. */ +#undef AES_KEY_SIZE +#define AES_KEY_SIZE 16 + +void aes128_ecb_encrypt(const uint8_t *key, const uint8_t *in, uint8_t *out) +{ + struct aes_ctx ctx; + + memset(&ctx, 0, sizeof(ctx)); + aes_set_encrypt_key(&ctx, AES_MIN_KEY_SIZE, key); + aes_encrypt(&ctx, AES_BLOCK_SIZE, out, in); +} + +void aes128_ecb_decrypt(const uint8_t *key, const uint8_t *in, uint8_t *out) +{ + struct aes_ctx ctx; + + memset(&ctx, 0, sizeof(ctx)); + aes_set_decrypt_key(&ctx, AES_MIN_KEY_SIZE, key); + aes_decrypt(&ctx, AES_BLOCK_SIZE, out, in); +} + + + +static void aes256_cbc_encrypt(const uint8_t *key, const uint8_t *in, int in_len, + const uint8_t *iv, uint8_t *out) +{ + struct CBC_CTX(struct aes_ctx, AES_BLOCK_SIZE) cbc; + + memset(&cbc.ctx, 0, sizeof(cbc.ctx)); + aes_set_encrypt_key(&cbc.ctx, AES_MAX_KEY_SIZE, key); + CBC_SET_IV(&cbc, iv); + + CBC_ENCRYPT(&cbc, aes_encrypt, in_len, out, in); +} + +static void aes256_cbc_decrypt(const uint8_t *key, const uint8_t *in, int in_len, + const uint8_t *iv, uint8_t *out) +{ + struct CBC_CTX(struct aes_ctx, AES_BLOCK_SIZE) cbc; + + memset(&cbc.ctx, 0, sizeof(cbc.ctx)); + aes_set_decrypt_key(&cbc.ctx, AES_MAX_KEY_SIZE, key); + CBC_SET_IV(&cbc, iv); + + CBC_DECRYPT(&cbc, aes_decrypt, in_len, out, in); +} + +int securid_rand(void *out, int len, int paranoid) +{ + + return read_dev_random(paranoid ? "/dev/random" : "/dev/urandom", + out, len); +} + +static void sha256_hash(const uint8_t *in, int in_len, uint8_t *out) +{ + struct sha256_ctx ctx; + + sha256_init(&ctx); + sha256_update(&ctx, in_len, in); + sha256_digest(&ctx, SHA256_DIGEST_SIZE, out); +} + +static void sha256_hmac(const uint8_t *key, int key_len, + const uint8_t *msg, int msg_len, uint8_t *out) +{ + struct hmac_sha256_ctx hmac; + + hmac_sha256_set_key(&hmac, key_len, key); + hmac_sha256_update(&hmac, msg_len, msg); + hmac_sha256_digest(&hmac, SHA256_DIGEST_SIZE, out); +} + +int __stoken_base64_encode(const uint8_t *in, unsigned long in_len, + uint8_t *out, unsigned long *out_len) +{ + struct base64_encode_ctx ctx; + + base64_encode_init(&ctx); + + /* This should never happen and the callers don't check */ + if (*out_len < BASE64_ENCODE_LENGTH(in_len)) + abort(); + *out_len = base64_encode_update(&ctx, out, in_len, in); + out += *out_len; + *out_len += base64_encode_final(&ctx, out); + + return 0; +} + +int __stoken_base64_decode(const uint8_t *in, unsigned long in_len, + uint8_t *out, unsigned long *out_len) +{ + struct base64_decode_ctx ctx; + unsigned int s; + + base64_decode_init(&ctx); + + /* This should never happen and the callers don't check */ + if (*out_len < BASE64_DECODE_LENGTH(in_len)) + abort(); + if (!base64_decode_update(&ctx, &s, out, in_len, in)) + return -EILSEQ; + if (!base64_decode_final(&ctx)) + return -EILSEQ; + + *out_len = s; + + return 0; +} + +#endif /* Nettle */ + static void encrypt_then_xor(const uint8_t *key, uint8_t *work, uint8_t *enc) { int i; @@ -236,46 +404,6 @@ static uint16_t securid_shortmac(const uint8_t *in, int in_len) return (hash[0] << 7) | (hash[1] >> 1); } -static void sha256_hash(const uint8_t *in, int in_len, uint8_t *out) -{ - hash_state md; - sha256_init(&md); - sha256_process(&md, in, in_len); - sha256_done(&md, out); -} - -static void sha256_hmac(const uint8_t *key, int key_len, - const uint8_t *msg, int msg_len, uint8_t *out) -{ - hash_state md; - uint8_t tmp_key[SHA256_HASH_SIZE], o_key_pad[SHA256_BLOCK_SIZE], - i_key_pad[SHA256_BLOCK_SIZE], inner_hash[SHA256_BLOCK_SIZE]; - int i; - - if (key_len > SHA256_BLOCK_SIZE) { - sha256_hash(key, key_len, tmp_key); - key = tmp_key; - key_len = SHA256_HASH_SIZE; - } - - memset(o_key_pad, 0x5c, SHA256_BLOCK_SIZE); - memset(i_key_pad, 0x36, SHA256_BLOCK_SIZE); - for (i = 0; i < key_len; i++) { - o_key_pad[i] ^= key[i]; - i_key_pad[i] ^= key[i]; - } - - sha256_init(&md); - sha256_process(&md, i_key_pad, SHA256_BLOCK_SIZE); - sha256_process(&md, msg, msg_len); - sha256_done(&md, inner_hash); - - sha256_init(&md); - sha256_process(&md, o_key_pad, SHA256_BLOCK_SIZE); - sha256_process(&md, inner_hash, SHA256_HASH_SIZE); - sha256_done(&md, out); -} - static void sha256_pbkdf2(const uint8_t *pass, int pass_len, const uint8_t *salt, int salt_len, int n_rounds, uint8_t *key_out) @@ -609,7 +737,7 @@ static int v3_decode_token(const char *in, struct securid_token *t) return ERR_NO_MEMORY; if (base64_decode(decoded, strlen(decoded), - (void *)t->v3, &actual) != CRYPT_OK || + (void *)t->v3, &actual) || actual != sizeof(struct v3_token) || t->v3->version != 0x03) { free(t->v3); diff --git a/src/stoken-internal.h b/src/stoken-internal.h index 2b94217..7792102 100644 --- a/src/stoken-internal.h +++ b/src/stoken-internal.h @@ -22,6 +22,7 @@ #define __STOKEN_INTERNAL_H__ #include "stoken.h" +#include <stdint.h> #define BUFLEN 2048 #define RC_NAME ".stokenrc" @@ -62,6 +63,15 @@ int __stoken_write_rcfile(const char *override, const struct stoken_cfg *cfg, warn_fn_t warn_fn); void __stoken_zap_rcfile_data(struct stoken_cfg *cfg); +#ifdef CRYPTO_NETTLE +int __stoken_base64_decode(const uint8_t *in, unsigned long in_len, + uint8_t *out, unsigned long *out_len); +int __stoken_base64_encode(const uint8_t *in, unsigned long in_len, + uint8_t *out, unsigned long *out_len); +#define base64_decode __stoken_base64_decode +#define base64_encode __stoken_base64_encode +#endif + #ifdef __ANDROID__ /* Sigh. This exists but it isn't in the Bionic headers. */ int mkstemps(char *path, int slen); diff --git a/stoken.pc.in b/stoken.pc.in index d605bbc..73a812c 100644 --- a/stoken.pc.in +++ b/stoken.pc.in @@ -6,6 +6,6 @@ includedir=@includedir@ Name: stoken Description: Software token Version: @VERSION@ -Requires.private: @LIBTOMCRYPT_PC@ +Requires.private: @CRYPTO_PC@ Libs: -L${libdir} -lstoken @EXTRA_PC_LIBS@ Cflags: -I${includedir} -- dwmw2 -------------- next part -------------- A non-text attachment was scrubbed... Name: smime.p7s Type: application/x-pkcs7-signature Size: 5745 bytes Desc: not available URL: <http://lists.infradead.org/pipermail/openconnect-devel/attachments/20140801/e503c88a/attachment.bin>