From ece37f13905ca39e028c13be372fc79eae87639a Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Sat, 3 Jun 2017 20:26:07 -0400 Subject: [PATCH 01/12] Initial add of rsa_tools. This is just a simple RSA public key digital signature thing built on libtomcrypt. The gist: Some admin will generate a public/private key with rsa_make_keys, keeping the private key secret. Using the private key and rsa_sign, the admin will sign the autoupdater manifests, generating manifest.txt.sig. The public key ships with the game (adding 270 bytes to the download), the .sig is downloaded with the manifest by the autoupdater (256 bytes extra download), then the autoupdater checks the manifest against the signature with the public key. if the signature isn't valid (the manifest was tampered with or corrupt), the autoupdater refuses to continue. If the manifest is to be trusted, it lists sha256 checksums for every file to download, so there's no need to sign every file; if they can't tamper with the manifest, they can't tamper with any other file to be updated since the file's listed sha256 won't match. If the private key is compromised, we generate new keys and ship new installers, so new installations will be able to update but existing ones will need to do a new install to keep getting updates. Don't let the private key get compromised. The private key doesn't go on a public server. Maybe it doesn't even live on the admin's laptop hard drive. If the download server is compromised and serving malware, the autoupdater will reject it outright if they haven't compromised the private key, generated a new manifest, and signed it with the private key. libtomcrypt is sort of a big pile of source code, so instead of putting it in revision control, we have a script to download it. Most things don't need it. It lives on GitHub, so we _could_ do a git submodule, but most people don't need it, so why waste their disk and bandwidth? That said, when compiled you end up with a few hundred kilobytes of binary code to verify a signature and no external dependencies, so it seems like a win. --- .../rsa_tools/build-libtom-unix.sh | 68 +++++++++++++++++ code/autoupdater/rsa_tools/build-rsa-tools.sh | 23 ++++++ code/autoupdater/rsa_tools/rsa_common.c | 61 +++++++++++++++ code/autoupdater/rsa_tools/rsa_common.h | 30 ++++++++ code/autoupdater/rsa_tools/rsa_make_keys.c | 45 +++++++++++ code/autoupdater/rsa_tools/rsa_sign.c | 75 +++++++++++++++++++ code/autoupdater/rsa_tools/rsa_verify.c | 60 +++++++++++++++ code/autoupdater/rsa_tools/test-rsa-tools.sh | 17 +++++ 8 files changed, 379 insertions(+) create mode 100755 code/autoupdater/rsa_tools/build-libtom-unix.sh create mode 100755 code/autoupdater/rsa_tools/build-rsa-tools.sh create mode 100644 code/autoupdater/rsa_tools/rsa_common.c create mode 100644 code/autoupdater/rsa_tools/rsa_common.h create mode 100644 code/autoupdater/rsa_tools/rsa_make_keys.c create mode 100644 code/autoupdater/rsa_tools/rsa_sign.c create mode 100644 code/autoupdater/rsa_tools/rsa_verify.c create mode 100755 code/autoupdater/rsa_tools/test-rsa-tools.sh diff --git a/code/autoupdater/rsa_tools/build-libtom-unix.sh b/code/autoupdater/rsa_tools/build-libtom-unix.sh new file mode 100755 index 00000000..8700e868 --- /dev/null +++ b/code/autoupdater/rsa_tools/build-libtom-unix.sh @@ -0,0 +1,68 @@ +#!/bin/bash + +TFMVER=0.13.1 +LTCVER=1.17 +set -e + +OSTYPE=`uname -s` +if [ "$OSTYPE" = "Linux" ]; then + NCPU=`cat /proc/cpuinfo |grep vendor_id |wc -l` + let NCPU=$NCPU+1 +elif [ "$OSTYPE" = "Darwin" ]; then + NCPU=`sysctl -n hw.ncpu` +elif [ "$OSTYPE" = "SunOS" ]; then + NCPU=`/usr/sbin/psrinfo |wc -l |sed -e 's/^ *//g;s/ *$//g'` +else + NCPU=1 +fi + +if [ -z "$NCPU" ]; then + NCPU=1 +elif [ "$NCPU" = "0" ]; then + NCPU=1 +fi + +if [ ! -f ./crypt-$LTCVER.tar.bz2 ]; then + echo "Downloading LibTomCrypt $LTCVER sources..." + curl -L -o crypt-$LTCVER.tar.bz2 https://github.com/libtom/libtomcrypt/releases/download/$LTCVER/crypt-$LTCVER.tar.bz2 || exit 1 +fi + +if [ ! -f tfm-$TFMVER.tar.xz ]; then + echo "Downloading TomsFastMath $TFMVER sources..." + curl -L -o tfm-$TFMVER.tar.xz https://github.com/libtom/tomsfastmath/releases/download/v$TFMVER/tfm-$TFMVER.tar.xz || exit 1 +fi + +if [ ! -d tomsfastmath-$TFMVER ]; then + echo "Unpacking TomsFastMath $TFMVER sources..." + tar -xJvvf ./tfm-$TFMVER.tar.xz +fi + +if [ ! -d libtomcrypt-$LTCVER ]; then + echo "Unpacking LibTomCrypt $LTCVER sources..." + tar -xjvvf ./crypt-$LTCVER.tar.bz2 +fi + +echo +echo +echo "Will use make -j$NCPU. If this is wrong, check NCPU at top of script." +echo +echo + +set -e +set -x + +# Some compilers can't handle the ROLC inline asm; just turn it off. +cd tomsfastmath-$TFMVER +make -j$NCPU +cd .. + +export CFLAGS="$CFLAGS -DTFM_DESC -DLTC_NO_ROLC -I ../tomsfastmath-$TFMVER/src/headers" +cd libtomcrypt-$LTCVER +make -j$NCPU +cd .. + +set +x +echo "All done." + +# end of build-libtom-unix.sh ... + diff --git a/code/autoupdater/rsa_tools/build-rsa-tools.sh b/code/autoupdater/rsa_tools/build-rsa-tools.sh new file mode 100755 index 00000000..212d6e70 --- /dev/null +++ b/code/autoupdater/rsa_tools/build-rsa-tools.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +# You don't need these to be built with the autoupdater, so here's a simple +# shell file to make them on a Mac. + +export TFMDIR="tomsfastmath-0.13.1" +export LTCDIR="libtomcrypt-1.17" + +function build { + clang -I $TFMDIR/src/headers -I $LTCDIR/src/headers -o "$1" -Wall -O3 "$1.c" rsa_common.c $LTCDIR/libtomcrypt.a $TFMDIR/libtfm.a +} + +set -e +set -x + +./build-libtom-unix.sh +build rsa_make_keys +build rsa_sign +build rsa_verify + +set +x +echo "rsa_tools are compiled!" + diff --git a/code/autoupdater/rsa_tools/rsa_common.c b/code/autoupdater/rsa_tools/rsa_common.c new file mode 100644 index 00000000..d0a10a0a --- /dev/null +++ b/code/autoupdater/rsa_tools/rsa_common.c @@ -0,0 +1,61 @@ +#include "rsa_common.h" + +void fail(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + fputs("\n", stderr); + fflush(stderr); + exit(1); +} + +void write_file(const char *fname, const void *buf, const unsigned long len) +{ + FILE *io = fopen(fname, "wb"); + if (!io) { + fail("Can't open '%s' for writing: %s", fname, strerror(errno)); + } + + if (fwrite(buf, len, 1, io) != 1) { + fail("Couldn't write '%s': %s", fname, strerror(errno)); + } + + if (fclose(io) != 0) { + fail("Couldn't flush '%s' to disk: %s", fname, strerror(errno)); + } +} + +void read_file(const char *fname, void *buf, unsigned long *len) +{ + ssize_t br; + FILE *io = fopen(fname, "rb"); + if (!io) { + fail("Can't open '%s' for reading: %s", fname, strerror(errno)); + } + + br = fread(buf, 1, *len, io); + if (ferror(io)) { + fail("Couldn't read '%s': %s", fname, strerror(errno)); + } else if (!feof(io)) { + fail("Buffer too small to read '%s'", fname); + } + fclose(io); + + *len = (unsigned long) br; +} + +void read_rsakey(rsa_key *key, const char *fname) +{ + unsigned char buf[4096]; + unsigned long len = sizeof (buf); + int rc; + + read_file(fname, buf, &len); + + if ((rc = rsa_import(buf, len, key)) != CRYPT_OK) { + fail("rsa_import for '%s' failed: %s", fname, error_to_string(rc)); + } +} + diff --git a/code/autoupdater/rsa_tools/rsa_common.h b/code/autoupdater/rsa_tools/rsa_common.h new file mode 100644 index 00000000..48695522 --- /dev/null +++ b/code/autoupdater/rsa_tools/rsa_common.h @@ -0,0 +1,30 @@ +#ifndef _INCL_RSA_COMMON_H_ +#define _INCL_RSA_COMMON_H_ 1 + +#include +#include +#include + +#define TFM_DESC +#define LTC_NO_ROLC +#include "tomcrypt.h" + +#define SALT_LEN 8 + +#if defined(__GNUC__) || defined(__clang__) +#define NEVER_RETURNS __attribute__((noreturn)) +#define PRINTF_FUNC(fmtargnum, dotargnum) __attribute__ (( format( __printf__, fmtargnum, dotargnum ))) +#else +#define NEVER_RETURNS +#define PRINTF_FUNC(fmtargnum, dotargnum) +#endif + +void fail(const char *fmt, ...) NEVER_RETURNS PRINTF_FUNC(1, 2); +void write_file(const char *fname, const void *buf, const unsigned long len); +void read_file(const char *fname, void *buf, unsigned long *len); +void read_rsakey(rsa_key *key, const char *fname); + +#endif + +/* end of rsa_common.h ... */ + diff --git a/code/autoupdater/rsa_tools/rsa_make_keys.c b/code/autoupdater/rsa_tools/rsa_make_keys.c new file mode 100644 index 00000000..a7f801c0 --- /dev/null +++ b/code/autoupdater/rsa_tools/rsa_make_keys.c @@ -0,0 +1,45 @@ +#include "rsa_common.h" + +static void write_rsakey(rsa_key *key, const int type, const char *fname) +{ + unsigned char buf[4096]; + unsigned long len = sizeof (buf); + int rc; + + if ((rc = rsa_export(buf, &len, type, key)) != CRYPT_OK) { + fail("rsa_export for '%s' failed: %s", fname, error_to_string(rc)); + } + write_file(fname, buf, len); +} + +int main(int argc, char **argv) +{ + int rc = 0; + prng_state prng; + int prng_index; + rsa_key key; + + ltc_mp = tfm_desc; + prng_index = register_prng(&sprng_desc); /* (fortuna_desc is a good choice if your platform's PRNG sucks.) */ + + if (prng_index == -1) { + fail("Failed to register a RNG"); + } + + if ((rc = rng_make_prng(128, prng_index, &prng, NULL)) != CRYPT_OK) { + fail("rng_make_prng failed: %s", error_to_string(rc)); + } + + if ((rc = rsa_make_key(&prng, prng_index, 256, 65537, &key)) != CRYPT_OK) { + fail("rng_make_key failed: %s", error_to_string(rc)); + } + + write_rsakey(&key, PK_PRIVATE, "privatekey.bin"); + write_rsakey(&key, PK_PUBLIC, "publickey.bin"); + + rsa_free(&key); + + return 0; +} + +/* end of rsa_make_keys.c ... */ diff --git a/code/autoupdater/rsa_tools/rsa_sign.c b/code/autoupdater/rsa_tools/rsa_sign.c new file mode 100644 index 00000000..5eec24dd --- /dev/null +++ b/code/autoupdater/rsa_tools/rsa_sign.c @@ -0,0 +1,75 @@ +#include "rsa_common.h" + +static void sign_file(const char *fname, rsa_key *key, prng_state *prng, const int prng_index, const int hash_index) +{ + const size_t sigfnamelen = strlen(fname) + 5; + char *sigfname = (char *) malloc(sigfnamelen); + unsigned char hash[256]; + unsigned long hashlen = sizeof (hash); + unsigned char sig[1024]; + unsigned long siglen = sizeof (sig); + int rc = 0; + int status = 0; + + if (!sigfname) { + fail("out of memory"); + } + + if ((rc = hash_file(hash_index, fname, hash, &hashlen)) != CRYPT_OK) { + fail("hash_file for '%s' failed: %s", fname, error_to_string(rc)); + } + + if ((rc = rsa_sign_hash(hash, hashlen, sig, &siglen, prng, prng_index, hash_index, SALT_LEN, key)) != CRYPT_OK) { + fail("rsa_sign_hash for '%s' failed: %s", fname, error_to_string(rc)); + } + + if ((rc = rsa_verify_hash(sig, siglen, hash, hashlen, hash_index, SALT_LEN, &status, key)) != CRYPT_OK) { + fail("rsa_verify_hash for '%s' failed: %s", fname, error_to_string(rc)); + } + + if (!status) { + fail("Generated signature isn't valid! Bug in the program!"); + } + + snprintf(sigfname, sigfnamelen, "%s.sig", fname); + write_file(sigfname, sig, siglen); + free(sigfname); +} + +int main(int argc, char **argv) +{ + int rc = 0; + prng_state prng; + int prng_index, hash_index; + rsa_key key; + int i; + + ltc_mp = tfm_desc; + + prng_index = register_prng(&sprng_desc); /* (fortuna_desc is a good choice if your platform's PRNG sucks.) */ + if (prng_index == -1) { + fail("Failed to register a RNG"); + } + + hash_index = register_hash(&sha256_desc); + if (hash_index == -1) { + fail("Failed to register sha256 hasher"); + } + + if ((rc = rng_make_prng(128, prng_index, &prng, NULL)) != CRYPT_OK) { + fail("rng_make_prng failed: %s", error_to_string(rc)); + } + + read_rsakey(&key, "privatekey.bin"); + + for (i = 1; i < argc; i++) { + sign_file(argv[i], &key, &prng, prng_index, hash_index); + } + + rsa_free(&key); + + return 0; +} + +/* end of rsa_sign.c ... */ + diff --git a/code/autoupdater/rsa_tools/rsa_verify.c b/code/autoupdater/rsa_tools/rsa_verify.c new file mode 100644 index 00000000..09abfb24 --- /dev/null +++ b/code/autoupdater/rsa_tools/rsa_verify.c @@ -0,0 +1,60 @@ +#include "rsa_common.h" + +static void verify_file(const char *fname, rsa_key *key, const int hash_index) +{ + const size_t sigfnamelen = strlen(fname) + 5; + char *sigfname = (char *) malloc(sigfnamelen); + unsigned char hash[256]; + unsigned long hashlen = sizeof (hash); + unsigned char sig[1024]; + unsigned long siglen = sizeof (sig); + int status = 0; + int rc = 0; + + if (!sigfname) { + fail("out of memory"); + } + + snprintf(sigfname, sigfnamelen, "%s.sig", fname); + read_file(sigfname, sig, &siglen); + free(sigfname); + + if ((rc = hash_file(hash_index, fname, hash, &hashlen)) != CRYPT_OK) { + fail("hash_file for '%s' failed: %s", fname, error_to_string(rc)); + } + + if ((rc = rsa_verify_hash(sig, siglen, hash, hashlen, hash_index, SALT_LEN, &status, key)) != CRYPT_OK) { + fail("rsa_verify_hash for '%s' failed: %s", fname, error_to_string(rc)); + } + + if (!status) { + fail("Invalid signature for '%s'! Don't trust this file!", fname); + } +} + +int main(int argc, char **argv) +{ + int hash_index; + rsa_key key; + int i; + + ltc_mp = tfm_desc; + + hash_index = register_hash(&sha256_desc); + if (hash_index == -1) { + fail("Failed to register sha256 hasher"); + } + + read_rsakey(&key, "publickey.bin"); + + for (i = 1; i < argc; i++) { + verify_file(argv[i], &key, hash_index); + } + + rsa_free(&key); + + return 0; +} + +/* end of rsa_verify.c ... */ + diff --git a/code/autoupdater/rsa_tools/test-rsa-tools.sh b/code/autoupdater/rsa_tools/test-rsa-tools.sh new file mode 100755 index 00000000..f4b4bdb0 --- /dev/null +++ b/code/autoupdater/rsa_tools/test-rsa-tools.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +if [ -f privatekey.bin ]; then + echo "move your existing keys out of the way." + exit 1 +fi + +( ./rsa_make_keys && echo "key making okay") || echo "key making NOT okay" +echo "The quick brown fox jumped over the lazy dog." >testmsg.txt +( ./rsa_sign testmsg.txt && echo "signing okay" ) || echo "signing NOT okay" +( ./rsa_verify testmsg.txt && echo "basic verifying okay" ) || echo "basic verifying NOT okay" +echo "The quick brown fox jumped over the lazy dog!" >testmsg.txt +( ./rsa_verify testmsg.txt 2>/dev/null && echo "tamper test NOT okay" ) || echo "tamper test okay" +echo "The quick brown fox jumped over the lazy dog." >testmsg.txt +( ./rsa_verify testmsg.txt && echo "reverify okay" ) || echo "reverify NOT okay" +rm -f testmsg.txt testmsg.txt.sig publickey.bin privatekey.bin + From 7542966e3360ab994972f9d3db5aac8a3edec06d Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Sun, 4 Jun 2017 01:15:38 -0400 Subject: [PATCH 02/12] Verify libTom source archives aren't tampered with. --- .../rsa_tools/build-libtom-unix.sh | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/code/autoupdater/rsa_tools/build-libtom-unix.sh b/code/autoupdater/rsa_tools/build-libtom-unix.sh index 8700e868..4e61732f 100755 --- a/code/autoupdater/rsa_tools/build-libtom-unix.sh +++ b/code/autoupdater/rsa_tools/build-libtom-unix.sh @@ -22,22 +22,31 @@ elif [ "$NCPU" = "0" ]; then NCPU=1 fi -if [ ! -f ./crypt-$LTCVER.tar.bz2 ]; then - echo "Downloading LibTomCrypt $LTCVER sources..." - curl -L -o crypt-$LTCVER.tar.bz2 https://github.com/libtom/libtomcrypt/releases/download/$LTCVER/crypt-$LTCVER.tar.bz2 || exit 1 -fi - if [ ! -f tfm-$TFMVER.tar.xz ]; then echo "Downloading TomsFastMath $TFMVER sources..." curl -L -o tfm-$TFMVER.tar.xz https://github.com/libtom/tomsfastmath/releases/download/v$TFMVER/tfm-$TFMVER.tar.xz || exit 1 fi +if [ ! -f ./crypt-$LTCVER.tar.bz2 ]; then + echo "Downloading LibTomCrypt $LTCVER sources..." + curl -L -o crypt-$LTCVER.tar.bz2 https://github.com/libtom/libtomcrypt/releases/download/$LTCVER/crypt-$LTCVER.tar.bz2 || exit 1 +fi + if [ ! -d tomsfastmath-$TFMVER ]; then + echo "Checking TomsFastMath archive hash..." + if [ "`shasum -a 256 tfm-$TFMVER.tar.xz |awk '{print $1;}'`" != "47c97a1ada3ccc9fcbd2a8a922d5859a84b4ba53778c84c1d509c1a955ac1738" ]; then + echo "Uhoh, tfm-$TFMVER.tar.xz does not have the sha256sum we expected!" + exit 1 + fi echo "Unpacking TomsFastMath $TFMVER sources..." tar -xJvvf ./tfm-$TFMVER.tar.xz fi if [ ! -d libtomcrypt-$LTCVER ]; then + if [ "`shasum -a 256 crypt-$LTCVER.tar.bz2 |awk '{print $1;}'`" != "e33b47d77a495091c8703175a25c8228aff043140b2554c08a3c3cd71f79d116" ]; then + echo "Uhoh, crypt-$LTCVER.tar.bz2 does not have the sha256sum we expected!" + exit 1 + fi echo "Unpacking LibTomCrypt $LTCVER sources..." tar -xjvvf ./crypt-$LTCVER.tar.bz2 fi From 62f6f0c7e0be4bcd6dc45631fc8cf6350168a281 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Sun, 4 Jun 2017 01:16:37 -0400 Subject: [PATCH 03/12] Wire up libTom stuff to build system. --- Makefile | 9 ++++++--- code/autoupdater/rsa_tools/build-libtom-unix.sh | 2 ++ code/autoupdater/rsa_tools/build-rsa-tools.sh | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 4714655c..b5be7703 100644 --- a/Makefile +++ b/Makefile @@ -270,6 +270,8 @@ Q3CPPDIR=$(MOUNT_DIR)/tools/lcc/cpp Q3LCCETCDIR=$(MOUNT_DIR)/tools/lcc/etc Q3LCCSRCDIR=$(MOUNT_DIR)/tools/lcc/src AUTOUPDATERSRCDIR=$(MOUNT_DIR)/autoupdater +LIBTOMCRYPTSRCDIR=$(AUTOUPDATERSRCDIR)/rsa_tools/libtomcrypt-1.17 +TOMSFASTMATHSRCDIR=$(AUTOUPDATERSRCDIR)/rsa_tools/tomsfastmath-0.13.1 LOKISETUPDIR=misc/setup NSISDIR=misc/nsis SDLHDIR=$(MOUNT_DIR)/SDL2 @@ -376,7 +378,7 @@ ifneq (,$(findstring "$(PLATFORM)", "linux" "gnu_kfreebsd" "kfreebsd-gnu" "gnu") THREAD_LIBS=-lpthread LIBS=-ldl -lm - AUTOUPDATER_LIBS += -ldl + AUTOUPDATER_LIBS += -ldl $(LIBTOMCRYPTSRCDIR)/libtomcrypt.a $(TOMSFASTMATHSRCDIR)/libtfm.a CLIENT_LIBS=$(SDL_LIBS) RENDERER_LIBS = $(SDL_LIBS) -lGL @@ -419,6 +421,8 @@ ifeq ($(PLATFORM),darwin) RENDERER_LIBS= OPTIMIZEVM= + AUTOUPDATER_LIBS += $(LIBTOMCRYPTSRCDIR)/libtomcrypt.a $(TOMSFASTMATHSRCDIR)/libtfm.a + # Default minimum Mac OS X version ifeq ($(MACOSX_VERSION_MIN),) MACOSX_VERSION_MIN=10.7 @@ -1601,12 +1605,11 @@ $(Q3ASM): $(Q3ASMOBJ) define DO_AUTOUPDATER_CC $(echo_cmd) "AUTOUPDATER_CC $<" -$(Q)$(CC) $(CFLAGS) $(CURL_CFLAGS) -o $@ -c $< +$(Q)$(CC) $(CFLAGS) -I$(LIBTOMCRYPTSRCDIR)/src/headers -I$(TOMSFASTMATHSRCDIR)/src/headers $(CURL_CFLAGS) -o $@ -c $< endef Q3AUTOUPDATEROBJ = \ $(B)/autoupdater/autoupdater.o \ - $(B)/autoupdater/sha256.o $(B)/autoupdater/%.o: $(AUTOUPDATERSRCDIR)/%.c $(DO_AUTOUPDATER_CC) diff --git a/code/autoupdater/rsa_tools/build-libtom-unix.sh b/code/autoupdater/rsa_tools/build-libtom-unix.sh index 4e61732f..bbd86312 100755 --- a/code/autoupdater/rsa_tools/build-libtom-unix.sh +++ b/code/autoupdater/rsa_tools/build-libtom-unix.sh @@ -10,6 +10,8 @@ if [ "$OSTYPE" = "Linux" ]; then let NCPU=$NCPU+1 elif [ "$OSTYPE" = "Darwin" ]; then NCPU=`sysctl -n hw.ncpu` + export CFLAGS="$CFLAGS -mmacosx-version-min=10.7 -DMAC_OS_X_VERSION_MIN_REQUIRED=1070" + export LDFLAGS="$LDFLAGS -mmacosx-version-min=10.7" elif [ "$OSTYPE" = "SunOS" ]; then NCPU=`/usr/sbin/psrinfo |wc -l |sed -e 's/^ *//g;s/ *$//g'` else diff --git a/code/autoupdater/rsa_tools/build-rsa-tools.sh b/code/autoupdater/rsa_tools/build-rsa-tools.sh index 212d6e70..422e48d5 100755 --- a/code/autoupdater/rsa_tools/build-rsa-tools.sh +++ b/code/autoupdater/rsa_tools/build-rsa-tools.sh @@ -7,7 +7,7 @@ export TFMDIR="tomsfastmath-0.13.1" export LTCDIR="libtomcrypt-1.17" function build { - clang -I $TFMDIR/src/headers -I $LTCDIR/src/headers -o "$1" -Wall -O3 "$1.c" rsa_common.c $LTCDIR/libtomcrypt.a $TFMDIR/libtfm.a + clang -mmacosx-version-min=10.7 -DMAC_OS_X_VERSION_MIN_REQUIRED=1070 -I $TFMDIR/src/headers -I $LTCDIR/src/headers -o "$1" -Wall -O3 "$1.c" rsa_common.c $LTCDIR/libtomcrypt.a $TFMDIR/libtfm.a } set -e From f71260eb8c5287761f1f2c15b74d64f65a04fe6e Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Sun, 4 Jun 2017 01:17:17 -0400 Subject: [PATCH 04/12] Replace sha256.c with libTomCrypt equivalent, since we'll be using it anyway. --- code/autoupdater/autoupdater.c | 46 +++++----- code/autoupdater/sha256.c | 156 --------------------------------- code/autoupdater/sha256.h | 42 --------- 3 files changed, 22 insertions(+), 222 deletions(-) delete mode 100644 code/autoupdater/sha256.c delete mode 100644 code/autoupdater/sha256.h diff --git a/code/autoupdater/autoupdater.c b/code/autoupdater/autoupdater.c index 0e8392b8..fcaf006a 100644 --- a/code/autoupdater/autoupdater.c +++ b/code/autoupdater/autoupdater.c @@ -34,7 +34,13 @@ typedef pid_t PID; #define PIDFMTCAST unsigned long long #endif -#include "sha256.h" +/* If your build fails here with tomcrypt.h missing, you probably need to + run the build-libtom script in the rsa_tools subdirectory. */ +#define TFM_DESC +#define LTC_NO_ROLC +#include "tomcrypt.h" + +static int sha256_hash_index = 0; #ifndef AUTOUPDATE_USER_AGENT @@ -524,7 +530,7 @@ static int hexcvt(const int ch) return 0; } -static void convertSha256(char *str, uint8 *sha256) +static void convertSha256(char *str, unsigned char *sha256) { int i; for (i = 0; i < 32; i++) { @@ -696,29 +702,12 @@ static const char *justFilename(const char *path) static void hashFile(const char *fname, unsigned char *sha256) { - SHA256_CTX sha256ctx; - uint8 buf[512]; - FILE *io; - - io = fopen(fname, "rb"); - if (!io) { - die("Failed to open file for hashing"); + int rc = 0; + unsigned long hashlen = 32; + if ((rc = hash_file(sha256_hash_index, fname, sha256, &hashlen)) != CRYPT_OK) { + infof("hash_file failed for '%s': %s", fname, error_to_string(rc)); + die("Can't hash file"); } - - sha256_init(&sha256ctx); - do { - size_t br = fread(buf, 1, sizeof (buf), io); - if (br > 0) { - sha256_update(&sha256ctx, buf, br); - } - if (ferror(io)) { - die("Error reading file for hashing"); - } - } while (!feof(io)); - - fclose(io); - - sha256_final(&sha256ctx, sha256); } static int fileHashMatches(const char *fname, const unsigned char *wanted) @@ -941,6 +930,13 @@ int main(int argc, char **argv) parseArgv(argc, argv); + /* set up crypto */ + ltc_mp = tfm_desc; + sha256_hash_index = register_hash(&sha256_desc); + if (sha256_hash_index == -1) { + die("Failed to register sha256 hasher"); + } + /* if we have downloaded a new updater and restarted with that binary, replace the original updater and restart again in the right place. */ if (options.updateself) { @@ -965,6 +961,8 @@ int main(int argc, char **argv) freeManifest(); shutdownHttpLib(); + unregister_hash(&sha256_desc); + infof("Updater ending, %s", timestamp()); return 0; diff --git a/code/autoupdater/sha256.c b/code/autoupdater/sha256.c deleted file mode 100644 index 0861860f..00000000 --- a/code/autoupdater/sha256.c +++ /dev/null @@ -1,156 +0,0 @@ -/********************************************************************* -* Filename: sha256.c -* Author: Brad Conte (brad AT bradconte.com) -* Copyright: -* Disclaimer: This code is presented "as is" without any guarantees. -* Details: Implementation of the SHA-256 hashing algorithm. - SHA-256 is one of the three algorithms in the SHA2 - specification. The others, SHA-384 and SHA-512, are not - offered in this implementation. - Algorithm specification can be found here: - * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf - This implementation uses little endian byte order. -*********************************************************************/ - -/*************************** HEADER FILES ***************************/ -#include -#include -#include "sha256.h" - -/****************************** MACROS ******************************/ -#define ROTLEFT(a,b) (((a) << (b)) | ((a) >> (32-(b)))) -#define ROTRIGHT(a,b) (((a) >> (b)) | ((a) << (32-(b)))) - -#define CH(x,y,z) (((x) & (y)) ^ (~(x) & (z))) -#define MAJ(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) -#define EP0(x) (ROTRIGHT(x,2) ^ ROTRIGHT(x,13) ^ ROTRIGHT(x,22)) -#define EP1(x) (ROTRIGHT(x,6) ^ ROTRIGHT(x,11) ^ ROTRIGHT(x,25)) -#define SIG0(x) (ROTRIGHT(x,7) ^ ROTRIGHT(x,18) ^ ((x) >> 3)) -#define SIG1(x) (ROTRIGHT(x,17) ^ ROTRIGHT(x,19) ^ ((x) >> 10)) - -/**************************** VARIABLES *****************************/ -static const uint32 k[64] = { - 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5, - 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174, - 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da, - 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967, - 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85, - 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070, - 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3, - 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2 -}; - -/*********************** FUNCTION DEFINITIONS ***********************/ -void sha256_transform(SHA256_CTX *ctx, const uint8 data[]) -{ - uint32 a, b, c, d, e, f, g, h, i, j, t1, t2, m[64]; - - for (i = 0, j = 0; i < 16; ++i, j += 4) - m[i] = (data[j] << 24) | (data[j + 1] << 16) | (data[j + 2] << 8) | (data[j + 3]); - for ( ; i < 64; ++i) - m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16]; - - a = ctx->state[0]; - b = ctx->state[1]; - c = ctx->state[2]; - d = ctx->state[3]; - e = ctx->state[4]; - f = ctx->state[5]; - g = ctx->state[6]; - h = ctx->state[7]; - - for (i = 0; i < 64; ++i) { - t1 = h + EP1(e) + CH(e,f,g) + k[i] + m[i]; - t2 = EP0(a) + MAJ(a,b,c); - h = g; - g = f; - f = e; - e = d + t1; - d = c; - c = b; - b = a; - a = t1 + t2; - } - - ctx->state[0] += a; - ctx->state[1] += b; - ctx->state[2] += c; - ctx->state[3] += d; - ctx->state[4] += e; - ctx->state[5] += f; - ctx->state[6] += g; - ctx->state[7] += h; -} - -void sha256_init(SHA256_CTX *ctx) -{ - ctx->datalen = 0; - ctx->bitlen = 0; - ctx->state[0] = 0x6a09e667; - ctx->state[1] = 0xbb67ae85; - ctx->state[2] = 0x3c6ef372; - ctx->state[3] = 0xa54ff53a; - ctx->state[4] = 0x510e527f; - ctx->state[5] = 0x9b05688c; - ctx->state[6] = 0x1f83d9ab; - ctx->state[7] = 0x5be0cd19; -} - -void sha256_update(SHA256_CTX *ctx, const uint8 data[], size_t len) -{ - size_t i; - - for (i = 0; i < len; ++i) { - ctx->data[ctx->datalen] = data[i]; - ctx->datalen++; - if (ctx->datalen == 64) { - sha256_transform(ctx, ctx->data); - ctx->bitlen += 512; - ctx->datalen = 0; - } - } -} - -void sha256_final(SHA256_CTX *ctx, uint8 hash[]) -{ - uint32 i = ctx->datalen; - - // Pad whatever data is left in the buffer. - if (ctx->datalen < 56) { - ctx->data[i++] = 0x80; - while (i < 56) - ctx->data[i++] = 0x00; - } - else { - ctx->data[i++] = 0x80; - while (i < 64) - ctx->data[i++] = 0x00; - sha256_transform(ctx, ctx->data); - memset(ctx->data, 0, 56); - } - - // Append to the padding the total message's length in bits and transform. - ctx->bitlen += ctx->datalen * 8; - ctx->data[63] = ctx->bitlen; - ctx->data[62] = ctx->bitlen >> 8; - ctx->data[61] = ctx->bitlen >> 16; - ctx->data[60] = ctx->bitlen >> 24; - ctx->data[59] = ctx->bitlen >> 32; - ctx->data[58] = ctx->bitlen >> 40; - ctx->data[57] = ctx->bitlen >> 48; - ctx->data[56] = ctx->bitlen >> 56; - sha256_transform(ctx, ctx->data); - - // Since this implementation uses little endian byte ordering and SHA uses big endian, - // reverse all the bytes when copying the final state to the output hash. - for (i = 0; i < 4; ++i) { - hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff; - hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0x000000ff; - hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0x000000ff; - hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0x000000ff; - hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0x000000ff; - hash[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0x000000ff; - hash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0x000000ff; - hash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0x000000ff; - } -} diff --git a/code/autoupdater/sha256.h b/code/autoupdater/sha256.h deleted file mode 100644 index fc9a09a9..00000000 --- a/code/autoupdater/sha256.h +++ /dev/null @@ -1,42 +0,0 @@ -/********************************************************************* -* Filename: sha256.h -* Author: Brad Conte (brad AT bradconte.com) -* Copyright: -* Disclaimer: This code is presented "as is" without any guarantees. -* Details: Defines the API for the corresponding SHA1 implementation. -*********************************************************************/ - -#ifndef SHA256_H -#define SHA256_H - -/*************************** HEADER FILES ***************************/ -#include - -/****************************** MACROS ******************************/ -#define SHA256_BLOCK_SIZE 32 // SHA256 outputs a 32 byte digest - -/**************************** DATA TYPES ****************************/ -#ifdef _MSC_VER -typedef unsigned __int8 uint8; -typedef unsigned __int32 uint32; -typedef unsigned __int64 uint64; -#else -#include -typedef uint8_t uint8; -typedef uint32_t uint32; -typedef uint64_t uint64; -#endif - -typedef struct { - uint8 data[64]; - uint32 datalen; - uint64 bitlen; - uint32 state[8]; -} SHA256_CTX; - -/*********************** FUNCTION DECLARATIONS **********************/ -void sha256_init(SHA256_CTX *ctx); -void sha256_update(SHA256_CTX *ctx, const uint8 data[], size_t len); -void sha256_final(SHA256_CTX *ctx, uint8 hash[]); - -#endif // SHA256_H From e04bfd49676b5ed88abc930befb7724c171abb35 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Sun, 4 Jun 2017 01:32:10 -0400 Subject: [PATCH 05/12] Autoupdater now checks RSA digital signature for manifest. --- code/autoupdater/autoupdater.c | 74 +++++++++++++++++++++++++++++++++- 1 file changed, 73 insertions(+), 1 deletion(-) diff --git a/code/autoupdater/autoupdater.c b/code/autoupdater/autoupdater.c index fcaf006a..d7aa51d8 100644 --- a/code/autoupdater/autoupdater.c +++ b/code/autoupdater/autoupdater.c @@ -7,6 +7,7 @@ is licensed under the GPLv2. Do not mingle code, please! #include #include #include +#include #if defined(_MSC_VER) && (_MSC_VER < 1600) typedef __int64 int64_t; @@ -40,6 +41,8 @@ typedef pid_t PID; #define LTC_NO_ROLC #include "tomcrypt.h" +#define PUBLICKEY_FNAME "updater-publickey.bin" +#define SALT_LEN 8 static int sha256_hash_index = 0; @@ -599,11 +602,80 @@ static void parseManifest(const char *fname) fclose(io); } +static void read_file(const char *fname, void *buf, unsigned long *len) +{ + ssize_t br; + FILE *io = fopen(fname, "rb"); + if (!io) { + infof("Can't open '%s' for reading: %s", fname, strerror(errno)); + die("Failed to read file"); + } + + br = fread(buf, 1, *len, io); + if (ferror(io)) { + infof("Couldn't read '%s': %s", fname, strerror(errno)); + die("Failed to read file"); + } else if (!feof(io)) { + infof("Buffer too small to read '%s'", fname); + die("Failed to read file"); + } + fclose(io); + + *len = (unsigned long) br; +} + +static void read_rsakey(rsa_key *key, const char *fname) +{ + unsigned char buf[4096]; + unsigned long len = sizeof (buf); + int rc; + + read_file(fname, buf, &len); + + if ((rc = rsa_import(buf, len, key)) != CRYPT_OK) { + infof("rsa_import for '%s' failed: %s", fname, error_to_string(rc)); + die("Couldn't import public key"); + } +} + +static void verifySignature(const char *fname, const char *sigfname, const char *keyfname) +{ + rsa_key key; + unsigned char hash[256]; + unsigned long hashlen = sizeof (hash); + unsigned char sig[1024]; + unsigned long siglen = sizeof (sig); + int status = 0; + int rc = 0; + + read_rsakey(&key, keyfname); + read_file(sigfname, sig, &siglen); + + if ((rc = hash_file(sha256_hash_index, fname, hash, &hashlen)) != CRYPT_OK) { + infof("hash_file for '%s' failed: %s", fname, error_to_string(rc)); + die("Couldn't verify manifest signature"); + } + + if ((rc = rsa_verify_hash(sig, siglen, hash, hashlen, sha256_hash_index, SALT_LEN, &status, &key)) != CRYPT_OK) { + infof("rsa_verify_hash for '%s' failed: %s", fname, error_to_string(rc)); + die("Couldn't verify manifest signature"); + } + + if (!status) { + infof("Invalid signature for '%s'! Don't trust this file!", fname); + die("Manifest is incomplete, corrupt, or compromised"); + } + + rsa_free(&key); +} + static void downloadManifest(void) { const char *manifestfname = "updates/manifest.txt"; + const char *manifestsigfname = "updates/manifest.txt.sig"; downloadURL("manifest.txt", manifestfname); - /* !!! FIXME: verify manifest download is complete... */ + downloadURL("manifest.txt.sig", manifestsigfname); + verifySignature(manifestfname, manifestsigfname, PUBLICKEY_FNAME); parseManifest(manifestfname); } From ced74370426e63d751ee64ed46cec9f6d1ac7eb9 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Sun, 4 Jun 2017 01:32:41 -0400 Subject: [PATCH 06/12] Updated autoupdater-readme.txt with manifest signing details. --- autoupdater-readme.txt | 52 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 46 insertions(+), 6 deletions(-) diff --git a/autoupdater-readme.txt b/autoupdater-readme.txt index 1353f4f0..34561b7c 100644 --- a/autoupdater-readme.txt +++ b/autoupdater-readme.txt @@ -1,7 +1,8 @@ The updater program's code is public domain. The rest of ioquake3 is not. The source code to the autoupdater is in the code/autoupdater directory. -There is a small piece of code in ioquake3 itself at startup, too. +There is a small piece of code in ioquake3 itself at startup, too; this is +in code/sys/sys_autoupdater.c ... (This is all Unix terminology, but similar approaches on Windows apply.) @@ -20,8 +21,14 @@ The basic flow looks like this: - The updater downloads a manifest from a known URL over https://, using libCurl. The base URL is platform-specific (it might be https://example.com/mac/, or https://example.com/linux-x86/, whatever). + The url might have other features, like a updater version or a specific + product name, etc. The manifest is at $BASEURL/manifest.txt -- The manifest looks like this: three lines per file... +- The updater also downloads $BASEURL/manifest.txt.sig, which is a digital + signature for the manifest. It checks the manifest against this signature + and a known public RSA key; if the manifest doesn't match the signature, + the updater refuses to continue. +- The manifest looks like this: three lines per item... Contents/MacOS/baseq3/uix86_64.dylib 332428 @@ -105,13 +112,46 @@ Failure points: - If an update bricks ioquake3 to the point where it can't run the updater, running the updater directly should let it recover (assuming a future update fixes the problem). +- If the download server is compromised, they would need the private key + (not stored on the download server) to alter the manifest to serve + compromised files to players. If they try to change a file or the manifest, + the updater will know to abort without updating anything. +- If the private key is compromised, we generate a new one, ship new + installers with an updated public key, and re-sign the manifest with the + new private key. Existing installations will never update again until they + do a fresh install, or at least update their copy of the public key. + + +How manifest signing works: + +Some admin will generate a public/private key with the rsa_make_keys program, +keeping the private key secret. Using the private key and the rsa_sign +program, the admin will sign the manifest, generating manifest.txt.sig. + +The public key ships with the game (adding 270 bytes to the download), the +.sig is downloaded with the manifest by the autoupdater (256 bytes extra +download), then the autoupdater checks the manifest against the signature +with the public key. if the signature isn't valid (the manifest was tampered +with or corrupt), the autoupdater refuses to continue. + +If the manifest is to be trusted, it lists sha256 checksums for every file to +download, so there's no need to sign every file; if they can't tamper with the +manifest, they can't tamper with any other file to be updated since the file's +listed sha256 won't match. + +If the private key is compromised, we generate new keys and ship new +installers, so new installations will be able to update but existing ones +will need to do a new install to keep getting updates. Don't let the private +key get compromised. The private key doesn't go on a public server. Maybe it +doesn't even live on the admin's laptop hard drive. + +If the download server is compromised and serving malware, the autoupdater +will reject it outright if they haven't compromised the private key, generated +a new manifest, and signed it with the private key. + Items to consider for future revisions: -- GPG sign the manifest; if we can be confident that the manifest isn't - compromised, then the sha256 hashes of each file it contains should protect - the rest of the process. As it currently stands, we trust the download - server isn't compromised. - Maybe put a limit on the number manifest downloads, so we only check once every hour? Every day? - Channels? Stable (what everyone gets by default), Nightly (once a day), From 06cc3a4e1bfcb3f2936ef5f4f0fec4aa7b6885e6 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Sun, 4 Jun 2017 01:44:39 -0400 Subject: [PATCH 07/12] build-rsa-tools.sh now works on Linux. --- code/autoupdater/rsa_tools/build-rsa-tools.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/code/autoupdater/rsa_tools/build-rsa-tools.sh b/code/autoupdater/rsa_tools/build-rsa-tools.sh index 422e48d5..23e65c68 100755 --- a/code/autoupdater/rsa_tools/build-rsa-tools.sh +++ b/code/autoupdater/rsa_tools/build-rsa-tools.sh @@ -7,7 +7,11 @@ export TFMDIR="tomsfastmath-0.13.1" export LTCDIR="libtomcrypt-1.17" function build { - clang -mmacosx-version-min=10.7 -DMAC_OS_X_VERSION_MIN_REQUIRED=1070 -I $TFMDIR/src/headers -I $LTCDIR/src/headers -o "$1" -Wall -O3 "$1.c" rsa_common.c $LTCDIR/libtomcrypt.a $TFMDIR/libtfm.a + if [ "$OSTYPE" = "Darwin" ]; then + clang -mmacosx-version-min=10.7 -DMAC_OS_X_VERSION_MIN_REQUIRED=1070 -I $TFMDIR/src/headers -I $LTCDIR/src/headers -o "$1" -Wall -O3 "$1.c" rsa_common.c $LTCDIR/libtomcrypt.a $TFMDIR/libtfm.a + else + gcc -I $TFMDIR/src/headers -I $LTCDIR/src/headers -o "$1" -Wall -O3 "$1.c" rsa_common.c $LTCDIR/libtomcrypt.a $TFMDIR/libtfm.a + fi } set -e From c9c5d8710a9981c784d8b7271aca49d0f912c6ea Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Sun, 4 Jun 2017 01:49:33 -0400 Subject: [PATCH 08/12] Added .gitignore for rsa_tools directory. --- code/autoupdater/rsa_tools/.gitignore | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 code/autoupdater/rsa_tools/.gitignore diff --git a/code/autoupdater/rsa_tools/.gitignore b/code/autoupdater/rsa_tools/.gitignore new file mode 100644 index 00000000..8182fafc --- /dev/null +++ b/code/autoupdater/rsa_tools/.gitignore @@ -0,0 +1,8 @@ +crypt-*.tar.bz2 +tfm-*.tar.xz +libtomcrypt-* +tomsfastmath-* +rsa_make_keys +rsa_sign +rsa_verify +*.exe From a761684a2356ddac693697e758ce3232af69a395 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Sun, 4 Jun 2017 02:21:55 -0400 Subject: [PATCH 09/12] Windows support for autoupdater manifest signatures. --- Makefile | 8 +++++--- code/autoupdater/rsa_tools/build-rsa-tools.sh | 16 +++++++++++----- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index b5be7703..a048ba9b 100644 --- a/Makefile +++ b/Makefile @@ -378,7 +378,7 @@ ifneq (,$(findstring "$(PLATFORM)", "linux" "gnu_kfreebsd" "kfreebsd-gnu" "gnu") THREAD_LIBS=-lpthread LIBS=-ldl -lm - AUTOUPDATER_LIBS += -ldl $(LIBTOMCRYPTSRCDIR)/libtomcrypt.a $(TOMSFASTMATHSRCDIR)/libtfm.a + AUTOUPDATER_LIBS += -ldl CLIENT_LIBS=$(SDL_LIBS) RENDERER_LIBS = $(SDL_LIBS) -lGL @@ -421,8 +421,6 @@ ifeq ($(PLATFORM),darwin) RENDERER_LIBS= OPTIMIZEVM= - AUTOUPDATER_LIBS += $(LIBTOMCRYPTSRCDIR)/libtomcrypt.a $(TOMSFASTMATHSRCDIR)/libtfm.a - # Default minimum Mac OS X version ifeq ($(MACOSX_VERSION_MIN),) MACOSX_VERSION_MIN=10.7 @@ -1120,6 +1118,10 @@ ifeq ($(USE_AUTOUPDATER),1) SERVER_CFLAGS += -DUSE_AUTOUPDATER -DAUTOUPDATER_BIN=\\\"$(AUTOUPDATER_BIN)\\\" endif +ifeq ($(BUILD_AUTOUPDATER),1) + AUTOUPDATER_LIBS += $(LIBTOMCRYPTSRCDIR)/libtomcrypt.a $(TOMSFASTMATHSRCDIR)/libtfm.a +endif + ifeq ("$(CC)", $(findstring "$(CC)", "clang" "clang++")) BASE_CFLAGS += -Qunused-arguments endif diff --git a/code/autoupdater/rsa_tools/build-rsa-tools.sh b/code/autoupdater/rsa_tools/build-rsa-tools.sh index 23e65c68..dda9396c 100755 --- a/code/autoupdater/rsa_tools/build-rsa-tools.sh +++ b/code/autoupdater/rsa_tools/build-rsa-tools.sh @@ -1,16 +1,22 @@ #!/bin/bash -# You don't need these to be built with the autoupdater, so here's a simple -# shell file to make them on a Mac. - export TFMDIR="tomsfastmath-0.13.1" export LTCDIR="libtomcrypt-1.17" +OSTYPE=`uname -s` +if [ -z "$CC" ]; then + if [ "`uname -o`" = "Cygwin" ]; then + export CC=/usr/bin/i686-w64-mingw32-gcc + else + export CC=cc + fi +fi + function build { if [ "$OSTYPE" = "Darwin" ]; then - clang -mmacosx-version-min=10.7 -DMAC_OS_X_VERSION_MIN_REQUIRED=1070 -I $TFMDIR/src/headers -I $LTCDIR/src/headers -o "$1" -Wall -O3 "$1.c" rsa_common.c $LTCDIR/libtomcrypt.a $TFMDIR/libtfm.a + $CC -mmacosx-version-min=10.7 -DMAC_OS_X_VERSION_MIN_REQUIRED=1070 -I $TFMDIR/src/headers -I $LTCDIR/src/headers -o "$1" -Wall -O3 "$1.c" rsa_common.c $LTCDIR/libtomcrypt.a $TFMDIR/libtfm.a else - gcc -I $TFMDIR/src/headers -I $LTCDIR/src/headers -o "$1" -Wall -O3 "$1.c" rsa_common.c $LTCDIR/libtomcrypt.a $TFMDIR/libtfm.a + $CC -I $TFMDIR/src/headers -I $LTCDIR/src/headers -o "$1" -Wall -O3 "$1.c" rsa_common.c $LTCDIR/libtomcrypt.a $TFMDIR/libtfm.a fi } From 749e17ab1dd7cc31f4189a8050d24b21e82800b2 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Sun, 4 Jun 2017 02:23:49 -0400 Subject: [PATCH 10/12] Add a log message if manifest is valid. --- code/autoupdater/autoupdater.c | 1 + 1 file changed, 1 insertion(+) diff --git a/code/autoupdater/autoupdater.c b/code/autoupdater/autoupdater.c index d7aa51d8..221381b5 100644 --- a/code/autoupdater/autoupdater.c +++ b/code/autoupdater/autoupdater.c @@ -666,6 +666,7 @@ static void verifySignature(const char *fname, const char *sigfname, const char die("Manifest is incomplete, corrupt, or compromised"); } + info("Manifest signature appears to be valid"); rsa_free(&key); } From b771192d52da1aea6987f53ad34b318300c34bec Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Sun, 4 Jun 2017 02:46:49 -0400 Subject: [PATCH 11/12] Use "x86_64" and not "x86-64" like everything else in ioq3. --- code/autoupdater/autoupdater.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/autoupdater/autoupdater.c b/code/autoupdater/autoupdater.c index 221381b5..4a052027 100644 --- a/code/autoupdater/autoupdater.c +++ b/code/autoupdater/autoupdater.c @@ -74,7 +74,7 @@ static int sha256_hash_index = 0; #ifdef __i386__ #define AUTOUPDATE_ARCH "x86" #elif defined(__x86_64__) -#define AUTOUPDATE_ARCH "x86-64" +#define AUTOUPDATE_ARCH "x86_64" #else #error Please define your platform. #endif From 76e6b3c53442d125e65dee927caec56b272e2ba9 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Sun, 4 Jun 2017 16:43:50 -0400 Subject: [PATCH 12/12] Removed unnecessary trailing backslash. --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index a048ba9b..bfe14a5b 100644 --- a/Makefile +++ b/Makefile @@ -1611,7 +1611,7 @@ $(Q)$(CC) $(CFLAGS) -I$(LIBTOMCRYPTSRCDIR)/src/headers -I$(TOMSFASTMATHSRCDIR)/s endef Q3AUTOUPDATEROBJ = \ - $(B)/autoupdater/autoupdater.o \ + $(B)/autoupdater/autoupdater.o $(B)/autoupdater/%.o: $(AUTOUPDATERSRCDIR)/%.c $(DO_AUTOUPDATER_CC)