unable to use RSA SecureID on Unbuntu 14.04 LTS 64 bit
David Woodhouse
dwmw2 at infradead.org
Thu Jul 31 17:21:24 PDT 2014
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>
More information about the openconnect-devel
mailing list