diff --git a/Changelog-NG.txt b/Changelog-NG.txt index d50c061533c..99cb35fea5d 100644 --- a/Changelog-NG.txt +++ b/Changelog-NG.txt @@ -1,6 +1,19 @@ Asuswrt-Merlin 386/NG Changelog =============================== +386.2_4 (30-Apr-2021) + - NEW: Added jitterentropy-rngd to non-HND models, in addition + to HND models. + - UPDATED: OpenVPN to 2.5.2. + - UPDATED: jitterentropy-rngd to 1.2.2 (library 3.0.3) + - FIXED: Scheduled new FW checks wouldn't display the webui + notification icon when the local router had a + new release available. + - FIXED: OpenVPN server would flip into an error state (being + shown as "initializing" on the webui) whenever an + inbound client failed to connect to it. + + 386.2_2 (13-Apr-2021) - FIXED: IPv6 pings were blocked if sent below the rate limit instead of above (issue introduced in 42095) diff --git a/release/src-rt/version.conf b/release/src-rt/version.conf index c00d98ded19..66f7f3fb1db 100644 --- a/release/src-rt/version.conf +++ b/release/src-rt/version.conf @@ -1,5 +1,5 @@ KERNEL_VER=3.0 FS_VER=0.4 SERIALNO=386.2 -EXTENDNO=2 +EXTENDNO=4 RCNO=0 diff --git a/release/src/router/Makefile b/release/src/router/Makefile index 7170d4ed06a..44bc68b10bd 100644 --- a/release/src/router/Makefile +++ b/release/src/router/Makefile @@ -1465,9 +1465,7 @@ obj-$(RTCONFIG_DNSSEC) += $(if $(RTCONFIG_DNSSEC_OPENSSL),openssl,) $(if $(RTCON obj-$(RTCONFIG_SAMBA36X) += libiconv-1.14 obj-$(RTCONFIG_TELENET) += lanauth obj-y += wsdd2 -ifeq ($(HND_ROUTER),y) obj-y += jitterentropy-rngd -endif #obj-$(RTCONFIG_BWDPI) += faketc ifneq ($(HND_ROUTER),y) @@ -7748,7 +7746,7 @@ libovpn: shared nvram$(BCMEX)$(EX7) jitterentropy-rngd: @$(SEP) - $(MAKE) CFLAGS+="-fPIC" -C $@ + $(MAKE) CFLAGS+="-fPIC -O0" -C $@ jitterentropy-rngd-install: install -D jitterentropy-rngd/jitterentropy-rngd $(INSTALLDIR)/jitterentropy-rngd/usr/sbin/jitterentropy-rngd diff --git a/release/src/router/jitterentropy-rngd/CHANGES.md b/release/src/router/jitterentropy-rngd/CHANGES.md index 3c295837043..2d0b00877a4 100644 --- a/release/src/router/jitterentropy-rngd/CHANGES.md +++ b/release/src/router/jitterentropy-rngd/CHANGES.md @@ -1,3 +1,10 @@ +1.2.2: + * enhancement: Add SP800-90B compliant entropy injection + * fix: proper use of the RNDRESEEDCRNG IOCTL which otherwise causes an + endless loop due to kernel change 11a0b5e0ec8c13bef06f7414f9e914506140d5cb + * enhancement: Catch runtime FIPS health failures + * enhancement: use Jitter RNG library 3.0.2 + 1.2.1: * on older GCC versions use -fstack-protector as suggested by Warszawski, Diego diff --git a/release/src/router/jitterentropy-rngd/Makefile b/release/src/router/jitterentropy-rngd/Makefile index f1e20f23149..3d4907dcbde 100644 --- a/release/src/router/jitterentropy-rngd/Makefile +++ b/release/src/router/jitterentropy-rngd/Makefile @@ -2,7 +2,7 @@ CC ?= $(CROSS_COMPILE)gcc STRIP ?= $(CROSS_COMPILE)strip -CFLAGS ?=-Wextra -Wall -pedantic -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 -fwrapv --param ssp-buffer-size=4 -fvisibility=hidden -fPIE -Wcast-align -Wmissing-field-initializers -Wshadow -Wswitch-enum -O2 +CFLAGS ?=-Wextra -Wall -pedantic -fwrapv --param ssp-buffer-size=4 -fvisibility=hidden -fPIE -Wcast-align -Wmissing-field-initializers -Wshadow -Wswitch-enum -O0 LDFLAGS ?=-Wl,-z,relro,-z,now -pie GCCVERSIONFORMAT := $(shell echo `$(CC) -dumpversion | sed 's/\./\n/g' | wc -l`) diff --git a/release/src/router/jitterentropy-rngd/jitterentropy-base-user.h b/release/src/router/jitterentropy-rngd/jitterentropy-base-user.h index 41ff44d6947..8f442ddc268 100644 --- a/release/src/router/jitterentropy-rngd/jitterentropy-base-user.h +++ b/release/src/router/jitterentropy-rngd/jitterentropy-base-user.h @@ -132,9 +132,8 @@ static inline void jent_get_nstime(uint64_t *out) struct timespec time; if (clock_gettime(CLOCK_REALTIME, &time) == 0) { - tmp = (uint32_t)time.tv_sec; - tmp = tmp << 32; - tmp = tmp | (uint32_t)time.tv_nsec; + tmp = ((uint64_t)time.tv_sec & 0xFFFFFFFF) * 1000000000UL; + tmp = tmp + (uint64_t)time.tv_nsec; } *out = tmp; # endif /* __MACH__ */ diff --git a/release/src/router/jitterentropy-rngd/jitterentropy-base.c b/release/src/router/jitterentropy-rngd/jitterentropy-base.c index 6dbb48482aa..3822134f88a 100644 --- a/release/src/router/jitterentropy-rngd/jitterentropy-base.c +++ b/release/src/router/jitterentropy-rngd/jitterentropy-base.c @@ -58,7 +58,7 @@ #define MINVERSION 0 /* API compatible, ABI may change, functional * enhancements only, consumer can be left unchanged if * enhancements are not considered */ -#define PATCHLEVEL 1 /* API / ABI compatible, no functional changes, no +#define PATCHLEVEL 2 /* API / ABI compatible, no functional changes, no * enhancements, bug fixes only */ /*************************************************************************** @@ -67,6 +67,10 @@ * None of the following should be altered ***************************************************************************/ +#ifdef __OPTIMIZE__ + #error "The CPU Jitter random number generator must not be compiled with optimizations. See documentation. Use the compiler switch -O0 for compiling jitterentropy.c." +#endif + /* * JENT_POWERUP_TESTLOOPCOUNT needs some loops to identify edge * systems. 100 is definitely too little. @@ -113,11 +117,11 @@ unsigned int jent_version(void) * * @ec [in] Reference to entropy collector */ -static void jent_apt_reset(struct rand_data *ec, unsigned int delta_masked) +static void jent_apt_reset(struct rand_data *ec, uint64_t current_delta) { /* Reset APT counter */ ec->apt_count = 0; - ec->apt_base = delta_masked; + ec->apt_base = current_delta; ec->apt_observations = 0; } @@ -125,18 +129,18 @@ static void jent_apt_reset(struct rand_data *ec, unsigned int delta_masked) * Insert a new entropy event into APT * * @ec [in] Reference to entropy collector - * @delta_masked [in] Masked time delta to process + * @current_delta [in] Current time delta */ -static void jent_apt_insert(struct rand_data *ec, unsigned int delta_masked) +static void jent_apt_insert(struct rand_data *ec, uint64_t current_delta) { /* Initialize the base reference */ if (!ec->apt_base_set) { - ec->apt_base = delta_masked; + ec->apt_base = current_delta; ec->apt_base_set = 1; return; } - if (delta_masked == ec->apt_base) { + if (current_delta == ec->apt_base) { ec->apt_count++; if (ec->apt_count >= JENT_APT_CUTOFF) @@ -146,7 +150,7 @@ static void jent_apt_insert(struct rand_data *ec, unsigned int delta_masked) ec->apt_observations++; if (ec->apt_observations >= JENT_APT_WINDOW_SIZE) - jent_apt_reset(ec, delta_masked); + jent_apt_reset(ec, current_delta); } /*************************************************************************** @@ -246,7 +250,6 @@ static unsigned int jent_stuck(struct rand_data *ec, uint64_t current_delta) { uint64_t delta2 = jent_delta(ec->last_delta, current_delta); uint64_t delta3 = jent_delta(ec->last_delta2, delta2); - unsigned int delta_masked = current_delta & JENT_APT_WORD_MASK; ec->last_delta = current_delta; ec->last_delta2 = delta2; @@ -255,7 +258,7 @@ static unsigned int jent_stuck(struct rand_data *ec, uint64_t current_delta) * Insert the result of the comparison of two back-to-back time * deltas. */ - jent_apt_insert(ec, delta_masked); + jent_apt_insert(ec, current_delta); if (!current_delta || !delta2 || !delta3) { /* RCT with a stuck bit */ @@ -303,10 +306,14 @@ struct sha_ctx { uint8_t partial[SHA3_MAX_SIZE_BLOCK]; }; +#define aligned(val) __attribute__((aligned(val))) +#define ALIGNED_BUFFER(name, size, type) \ + type name[(size + sizeof(type)-1) / sizeof(type)] aligned(sizeof(type)); + /* CTX size allows any hash type up to SHA3-224 */ #define SHA_MAX_CTX_SIZE 368 -#define HASH_CTX_ON_STACK(name) \ - uint8_t name ## _ctx_buf[SHA_MAX_CTX_SIZE]; \ +#define HASH_CTX_ON_STACK(name) \ + ALIGNED_BUFFER(name ## _ctx_buf, SHA_MAX_CTX_SIZE, uint64_t) \ struct sha_ctx *name = (struct sha_ctx *) name ## _ctx_buf /* @@ -822,6 +829,15 @@ static inline void jent_notime_unsettick(struct rand_data *ec) { (void)ec; } static uint64_t jent_loop_shuffle(struct rand_data *ec, unsigned int bits, unsigned int min) { +#ifdef JENT_CONF_DISABLE_LOOP_SHUFFLE + + (void)ec; + (void)bits; + + return (1<data, SHA3_256_SIZE_DIGEST); sha3_update(ctx, (uint8_t *)&time, sizeof(uint64_t)); sha3_update(ctx, (uint8_t *)&j, sizeof(uint64_t)); @@ -898,13 +923,19 @@ static void jent_hash_time(struct rand_data *ec, uint64_t time, * requires that any conditioning operation to have an identical * amount of input data according to section 3.1.5. */ - if (stuck) - sha3_init(ctx); + + /* + * The sha3_final operations re-initialize the context for the + * next loop iteration. + */ + if (stuck || (j < hash_loop_cnt - 1)) + sha3_final(ctx, itermediary); else sha3_final(ctx, ec->data); } jent_memset_secure(ctx, SHA_MAX_CTX_SIZE); + jent_memset_secure(itermediary, sizeof(itermediary)); } /** @@ -950,7 +981,6 @@ static void jent_memaccess(struct rand_data *ec, uint64_t loop_cnt) */ if (loop_cnt) acc_loop_cnt = loop_cnt; - for (i = 0; i < (ec->memaccessloops + acc_loop_cnt); i++) { unsigned char *tmpval = ec->mem + ec->memlocation; /* @@ -983,17 +1013,21 @@ static void jent_memaccess(struct rand_data *ec, uint64_t loop_cnt) * and not using its result. * * @ec [in] Reference to entropy collector + * @loop_cnt [in] see jent_hash_time + * @ret_current_delta [out] Test interface: return time delta - may be NULL * * @return: result of stuck test */ -static unsigned int jent_measure_jitter(struct rand_data *ec) +static unsigned int jent_measure_jitter(struct rand_data *ec, + uint64_t loop_cnt, + uint64_t *ret_current_delta) { uint64_t time = 0; uint64_t current_delta = 0; unsigned int stuck; /* Invoke one noise source before time measurement to add variations */ - jent_memaccess(ec, 0); + jent_memaccess(ec, loop_cnt); /* * Get time stamp and calculate time delta to previous @@ -1007,7 +1041,11 @@ static unsigned int jent_measure_jitter(struct rand_data *ec) stuck = jent_stuck(ec, current_delta); /* Now call the next noise sources which also injects the data */ - jent_hash_time(ec, current_delta, 0, stuck); + jent_hash_time(ec, current_delta, loop_cnt, stuck); + + /* return the raw entropy value */ + if (ret_current_delta) + *ret_current_delta = current_delta; return stuck; } @@ -1023,11 +1061,11 @@ static void jent_random_data(struct rand_data *ec) unsigned int k = 0; /* priming of the ->prev_time value */ - jent_measure_jitter(ec); + jent_measure_jitter(ec, 0, NULL); while (1) { /* If a stuck measurement is received, repeat measurement */ - if (jent_measure_jitter(ec)) + if (jent_measure_jitter(ec, 0, NULL)) continue; /* @@ -1138,6 +1176,22 @@ struct rand_data *jent_entropy_collector_alloc(unsigned int osr, { struct rand_data *entropy_collector; + /* + * Requesting disabling and forcing of internal timer + * makes no sense. + */ + if ((flags & JENT_DISABLE_INTERNAL_TIMER) && + (flags & JENT_FORCE_INTERNAL_TIMER)) + return NULL; + + /* + * If the initial test code concludes to force the internal timer + * and the user requests it not to be used, do not allocate + * the Jitter RNG instance. + */ + if (jent_force_internal_timer && (flags & JENT_DISABLE_INTERNAL_TIMER)) + return NULL; + entropy_collector = jent_zalloc(sizeof(struct rand_data)); if (NULL == entropy_collector) return NULL; @@ -1157,16 +1211,18 @@ struct rand_data *jent_entropy_collector_alloc(unsigned int osr, } /* verify and set the oversampling rate */ - if (osr == 0) - osr = 1; /* minimum sampling rate is 1 */ + if (osr < JENT_MIN_OSR) + osr = JENT_MIN_OSR; entropy_collector->osr = osr; - if (jent_fips_enabled()) + if (jent_fips_enabled() || (flags & JENT_FORCE_FIPS)) entropy_collector->fips_enabled = 1; /* Use timer-less noise source */ - if (jent_notime_enable(entropy_collector, flags)) - goto err; + if (!(flags & JENT_DISABLE_INTERNAL_TIMER)) { + if (jent_notime_enable(entropy_collector, flags)) + goto err; + } /* fill the data pad with non-zero values */ if (jent_notime_settick(entropy_collector)) @@ -1350,7 +1406,7 @@ static int jent_time_entropy_init(unsigned int enable_notime) * than 1 to ensure the entropy estimation * implied with 1 is preserved */ - if ((delta_sum) <= 1) { + if ((delta_sum) <= JENT_POWERUP_TESTLOOPCOUNT) { ret = EMINVARVAR; goto out; } @@ -1360,7 +1416,7 @@ static int jent_time_entropy_init(unsigned int enable_notime) * least 10% of all checks -- on some platforms, the counter increments * in multiples of 100, but not always */ - if ((JENT_POWERUP_TESTLOOPCOUNT/10 * 9) < count_mod) { + if (JENT_STUCK_INIT_THRES(JENT_POWERUP_TESTLOOPCOUNT) < count_mod) { ret = ECOARSETIME; goto out; } @@ -1369,7 +1425,7 @@ static int jent_time_entropy_init(unsigned int enable_notime) * If we have more than 90% stuck results, then this Jitter RNG is * likely to not work well. */ - if ((JENT_POWERUP_TESTLOOPCOUNT/10 * 9) < count_stuck) + if (JENT_STUCK_INIT_THRES(JENT_POWERUP_TESTLOOPCOUNT) < count_stuck) ret = ESTUCK; out: diff --git a/release/src/router/jitterentropy-rngd/jitterentropy-rngd.c b/release/src/router/jitterentropy-rngd/jitterentropy-rngd.c index 4f9994dded4..f4867250b06 100644 --- a/release/src/router/jitterentropy-rngd/jitterentropy-rngd.c +++ b/release/src/router/jitterentropy-rngd/jitterentropy-rngd.c @@ -42,9 +42,11 @@ #include #include #include +#include #include #include #include +#include #define _GNU_SOURCE #include #include @@ -62,10 +64,11 @@ #define MINVERSION 2 /* API compatible, ABI may change, functional * enhancements only, consumer can be left unchanged if * enhancements are not considered */ -#define PATCHLEVEL 1 /* API / ABI compatible, no functional changes, no +#define PATCHLEVEL 2 /* API / ABI compatible, no functional changes, no * enhancements, bug fixes only */ static int Verbosity = 0; +static int force_sp80090b = 0; struct kernel_rng { int fd; @@ -75,7 +78,7 @@ struct kernel_rng { }; static struct kernel_rng Random = { - /*.fd = */ 0, + /*.fd = */ -1, /*.ec = */ NULL, /*.rpi = */ NULL, /*.dev = */ "/dev/random" @@ -91,11 +94,11 @@ static struct kernel_rng Urandom = { }; */ -static int Pidfile_fd = 0; +static int Pidfile_fd = -1; /* "/var/run/jitterentropy-rngd.pid" */ static char *Pidfile = NULL; -static int Entropy_avail_fd = 0; +static int Entropy_avail_fd = -1; #define ENTROPYBYTES 32 #define OVERSAMPLINGFACTOR 2 @@ -114,12 +117,89 @@ static void install_alarm(void); static void dealloc(void); static void dealloc_rng(struct kernel_rng *rng); +static unsigned long kern_maj = ULONG_MAX, kern_minor, kern_patchlevel; + static void jentrng_versionstring(char *buf, size_t buflen) { snprintf(buf, buflen, "jitterentropy-rngd %d.%d.%d", MAJVERSION, MINVERSION, PATCHLEVEL); } +/* Is the LRNG present instead of the legacy /dev/random? */ +static int lrng_present(void) +{ + struct stat buf; + static int lrng_present = -1; + + if (lrng_present < 0) { + int ret = stat(LRNG_FILE, &buf); + + if (ret == -1 && errno == ENOENT) + lrng_present = 0; + else + lrng_present = 1; + } + + return lrng_present; +} + +static int get_kernver(void) +{ + struct utsname kernel; + char *saveptr = NULL; + char *res = NULL; + + if (kern_maj != ULONG_MAX) + return 0; + + if (uname(&kernel)) + return -errno; + + /* 5.11.2 */ + res = strtok_r(kernel.release, ".", &saveptr); + if (!res) { + printf("Could not parse kernel version"); + return -EFAULT; + } + kern_maj = strtoul(res, NULL, 10); + + res = strtok_r(NULL, ".", &saveptr); + if (!res) { + printf("Could not parse kernel version"); + return -EFAULT; + } + kern_minor = strtoul(res, NULL, 10); + + res = strtok_r(NULL, ".", &saveptr); + if (!res) { + printf("Could not parse kernel version"); + return -EFAULT; + } + kern_patchlevel = strtoul(res, NULL, 10); + + return 0; +} + +/* return true if kernel is greater or equal to given values, otherwise false */ +static int kernver_ge(unsigned int maj, unsigned int minor, + unsigned int patchlevel) +{ + if (get_kernver()) + return 0; + + if (maj < kern_maj) + return 1; + if (maj == kern_maj) { + if (minor < kern_minor) + return 1; + if (minor == kern_minor) { + if (patchlevel <= kern_patchlevel) + return 1; + } + } + return 0; +} + static void usage(void) { unsigned int ver = jent_version(); @@ -137,6 +217,9 @@ static void usage(void) fprintf(stderr, "\t-v --verbose\tVerbose logging, multiple options increase verbosity\n"); fprintf(stderr, "\t\t\tVerbose logging implies running in foreground\n"); fprintf(stderr, "\t-p --pid\tWrite daemon PID to file\n"); + fprintf(stderr, "\t-s --sp800-90b\tForce SP800-90B compliance\n"); + fprintf(stderr, "LRNG presence %sdetected\n", + lrng_present() ? "" : "not "); exit(1); } @@ -152,9 +235,10 @@ static void parse_opts(int argc, char *argv[]) {"pid", 1, 0, 0}, {"help", 0, 0, 0}, {"version", 0, 0, 0}, + {"sp800-90b", 0, 0, 0}, {0, 0, 0, 0} }; - c = getopt_long(argc, argv, "vp:h", opts, &opt_index); + c = getopt_long(argc, argv, "svp:h", opts, &opt_index); if (-1 == c) break; switch (c) { @@ -175,6 +259,9 @@ static void parse_opts(int argc, char *argv[]) fprintf(stderr, "Version Jitterentropy Core %u\n", jent_version()); exit(0); break; + case 4: + force_sp80090b = 1; + break; default: usage(); } @@ -188,6 +275,9 @@ static void parse_opts(int argc, char *argv[]) case 'h': usage(); break; + case 's': + force_sp80090b = 1; + break; default: usage(); } @@ -245,7 +335,7 @@ static inline void memset_secure(void *s, int c, size_t n) *******************************************************************/ static size_t write_random(struct kernel_rng *rng, char *buf, size_t len, - size_t entropy_bytes) + size_t entropy_bytes, int force_reseed) { size_t written = 0; int ret; @@ -254,7 +344,6 @@ static size_t write_random(struct kernel_rng *rng, char *buf, size_t len, rng->rpi->entropy_count = (entropy_bytes * 8); rng->rpi->buf_size = len; memcpy(rng->rpi->buf, buf, len); - memset(buf, 0, len); ret = ioctl(rng->fd, RNDADDENTROPY, rng->rpi); if (0 > ret) @@ -270,7 +359,13 @@ static size_t write_random(struct kernel_rng *rng, char *buf, size_t len, memset(rng->rpi->buf, 0, len); #if LINUX_VERSION_CODE >= KERNEL_VERSION(4,17,0) - if (ioctl(rng->fd, RNDRESEEDCRNG) < 0 && errno != EINVAL) { + /* + * The LRNG does not require this IOCTL as the reseed is automatically + * triggered. + */ + if (force_reseed && kernver_ge(4, 17, 0) && + !lrng_present() && + ioctl(rng->fd, RNDRESEEDCRNG) < 0 && errno != EINVAL) { dolog(LOG_WARN, "Error triggering a reseed of the kernel DRNG: %s\n", strerror(errno)); @@ -280,10 +375,111 @@ static size_t write_random(struct kernel_rng *rng, char *buf, size_t len, return written; } -static size_t gather_entropy(struct kernel_rng *rng) +/* + * Inject the data 90B-compliant considering the minimum n_out of 80 bits + * of the folded SHA-1 operation reading the input_pool. + * + * The following seeding strategy is applied to ensure SP800-90B compliance: + * + * - If the LRNG is present, 90B compliance is always given and no special + * handling is needed. + * + * - If the default /dev/random implementation is provided and the kernel offers + * the RNDRESEEDCRNG, use it after injecting 80 bits of entropy to feed + * the entropy into the ChaCha20 DRNG. In this case, the caller should use + * the getrandom(2) system call or /dev/urandom to get SP800-90B compliant + * data. + * + * - Kernels without the RNDRESEEDCRNG will never offer SP800-90B compliant + * data via /dev/urandom or getrandom(2). Those should always use /dev/random. + * In this case, the Jitter-RNG will feed only 80 bit chunks into the kernel. + * This means that after /dev/random consumed 80 bits, new data is requested + * from the Jitter-RNG. + */ +#define SHA1_FOLD_OUTPUT_SIZE 10 +static size_t write_random_90B(struct kernel_rng *rng, char *buf, size_t len, + size_t entropy_bytes, int force_reseed) +{ + size_t written = 0, ptr; + + if (!force_reseed) + return write_random(rng, buf, len, entropy_bytes, force_reseed); + + for (ptr = 0; ptr < len; ptr += SHA1_FOLD_OUTPUT_SIZE) { + size_t todo = len - ptr, ent; + + if (todo > SHA1_FOLD_OUTPUT_SIZE) + todo = SHA1_FOLD_OUTPUT_SIZE; + + ent = todo; + if (ent > entropy_bytes) + ent = entropy_bytes; + entropy_bytes -= ent; + + written += write_random(rng, buf + ptr, todo, ent, + force_reseed); + } + + return written; +} + +static ssize_t read_jent(struct kernel_rng *rng, char *buf, size_t buflen) +{ + unsigned int i; + ssize_t ret = jent_read_entropy(rng->ec, buf, buflen); + + if (ret >= 0) + return ret; + + dolog(LOG_WARN, "Cannot read entropy"); + + /* Only catch the FIPS test failures in the loop below */ + if (ret != -2 && ret != -3) + return ret; + + for (i = 1; i <= 10; i++) { + dolog(LOG_WARN, + "Re-allocation attempt %u to clear permanent Jitter RNG error", + i); + + jent_entropy_collector_free(rng->ec); + rng->ec = jent_entropy_collector_alloc(1, 0); + if (!rng->ec) { + dolog(LOG_WARN, + "Allocation of entropy collector failed"); + } else { + ret = jent_read_entropy(rng->ec, buf, buflen); + if (ret >= 0) + return ret; + + dolog(LOG_WARN, "Cannot read entropy"); + + if (ret != -2 && ret != -3) + return ret; + } + } + + dolog(LOG_ERR, + "Failed to allocate new Jitter RNG instance and obtain entropy"); + + return -EFAULT; +} + +static size_t gather_entropy(struct kernel_rng *rng, int init) { sigset_t blocking_set, previous_set; - char buf[(ENTROPYBYTES * OVERSAMPLINGFACTOR)]; +#define ENTBLOCKSIZE (ENTROPYBYTES * OVERSAMPLINGFACTOR) +/* + * Maximum numbers of blocks is determined by numbers of reseed IOCTLs: if + * the reseed IOCTL is used, we call ceil(256 / 80) numbers of IOCTLs. As + * each IOCTL may drain the entropy pool by 256 bits, we need to ensure that + * after the numbers of IOCTLs, we finally inject more blocks than the numbers + * of IOCTLs into the input_pool. Otherwise the entropy estimator will never + * rise and we encounter an endless loop. + */ +#define ENTBLOCKS (4 + 2 + 1) + char buf[(ENTBLOCKSIZE * ENTBLOCKS)]; + size_t buflen = ENTBLOCKSIZE; size_t ret = 0; sigemptyset(&previous_set); @@ -292,17 +488,59 @@ static size_t gather_entropy(struct kernel_rng *rng) sigprocmask(SIG_BLOCK, &blocking_set, &previous_set); - if (0 > jent_read_entropy(rng->ec, buf, sizeof(buf))) { - dolog(LOG_WARN, "Cannot read entropy"); - return 0; + if (lrng_present()) { + /* + * The LRNG operates fully 90B compliant, no special handling + * is necessary. + */ + if (read_jent(rng, buf, buflen) < 0) + return 0; + + /* LRNG seeds automatically */ + ret = write_random(rng, buf, buflen, ENTROPYBYTES, 0); + } else if (kernver_ge(4, 17, 0)) { + unsigned int numblocks = 1, i; + + if (force_sp80090b || init) { + numblocks = ENTBLOCKS; + buflen *= numblocks; + } + + /* + * Generate twice the entropy data, once for the input_pool + * and once for ChaCha20. + */ + if (read_jent(rng, buf, buflen) < 0) + return 0; + + dolog(LOG_DEBUG, "Inject entropy into %s", + force_sp80090b ? "ChaCha20 DRNG" : "input pool"); + ret = write_random_90B(rng, buf, ENTBLOCKSIZE, ENTROPYBYTES, + force_sp80090b || init); + numblocks--; + + for (i = 0; i < numblocks; i++) { + dolog(LOG_DEBUG, "Inject entropy into input_pool"); + ret += write_random_90B(rng, buf + ENTBLOCKSIZE * i, + ENTBLOCKSIZE, ENTROPYBYTES, 0); + } + } else { + if (force_sp80090b) + buflen = SHA1_FOLD_OUTPUT_SIZE; + + if (read_jent(rng, buf, buflen) < 0) + return 0; + + ret = write_random_90B(rng, buf, buflen, + buflen / OVERSAMPLINGFACTOR, 0); } - ret = write_random(rng, buf, sizeof(buf), ENTROPYBYTES); - if (sizeof(buf) != ret) + + if (buflen != ret) { dolog(LOG_WARN, "Injected %lu bytes into %s, expected %d", - ret, rng->dev, sizeof(buf)); - else - ret = sizeof(buf); - memset_secure(buf, 0, sizeof(buf)); + ret, rng->dev, buflen); + ret = 0; + } + memset_secure(buf, 0, buflen); sigprocmask(SIG_SETMASK, &previous_set, NULL); @@ -319,7 +557,8 @@ static int read_entropy_avail(int fd) lseek(fd, 0, SEEK_SET); if (0 > data) { - dolog(LOG_WARN, "Error reading data from entropy_avail: %s", strerror(errno)); + dolog(LOG_WARN, "Error reading data from entropy_avail: %s", + strerror(errno)); return 0; } if (0 == data) { @@ -357,7 +596,7 @@ static void sig_entropy_avail(int sig) if (--force_reseed == 0) { force_reseed = FORCE_RESEED_WAKEUPS; dolog(LOG_DEBUG, "Force reseed", entropy); - written = gather_entropy(&Random); + written = gather_entropy(&Random, 0); dolog(LOG_VERBOSE, "%lu bytes written to /dev/random", written); goto out; } @@ -371,24 +610,13 @@ static void sig_entropy_avail(int sig) goto out; } dolog(LOG_DEBUG, "Insufficient entropy %d available", entropy); - written = gather_entropy(&Random); + written = gather_entropy(&Random, 0); dolog(LOG_VERBOSE, "%lu bytes written to /dev/random", written); out: install_alarm(); return; } -/* Is the LRNG present instead of the legacy /dev/random? */ -static int lrng_present(void) -{ - struct stat buf; - int ret = stat(LRNG_FILE, &buf); - - if (ret == -1 && errno == ENOENT) - return 0; - return 1; -} - /* terminate the daemon cleanly */ static void sig_term(int sig) { @@ -428,7 +656,7 @@ static void select_fd(void) dolog(LOG_ERR, "Select returned with error %s", strerror(errno)); if (0 <= ret) { dolog(LOG_VERBOSE, "Wakeup call for select on /dev/random"); - written = gather_entropy(&Random); + written = gather_entropy(&Random, 0); dolog(LOG_VERBOSE, "%lu bytes written to /dev/random", written); } } @@ -456,41 +684,6 @@ static void install_term(void) * allocation functions *******************************************************************/ -static void alloc_rng(struct kernel_rng *rng) -{ - rng->ec = jent_entropy_collector_alloc(1, 0); - if (!rng->ec) - dolog(LOG_ERR, "Allocation of entropy collector failed"); - - rng->rpi = malloc((sizeof(struct rand_pool_info) + - (ENTROPYBYTES * OVERSAMPLINGFACTOR * sizeof(char)))); - if (!rng->rpi) - dolog(LOG_ERR, "Cannot allocate memory for random bytes"); - - rng->fd = open(rng->dev, O_WRONLY); - if (-1 == rng->fd) - dolog(LOG_ERR, "Open of %s failed: %s", rng->dev, strerror(errno)); -} - -static void alloc(void) -{ - int ret = 0; - size_t written = 0; - - ret = jent_entropy_init(); - if (ret) - dolog(LOG_ERR, "The initialization of CPU Jitter RNG failed with error code %d\n", ret); - - alloc_rng(&Random); - - Entropy_avail_fd = open(ENTROPYAVAIL, O_RDONLY); - if (-1 == Entropy_avail_fd) - dolog(LOG_ERR, "Open of %s failed: %s", ENTROPYAVAIL, strerror(errno)); - - written = gather_entropy(&Random); - dolog(LOG_VERBOSE, "%lu bytes written to /dev/random", written); -} - static void dealloc_rng(struct kernel_rng *rng) { if (NULL != rng->ec) { @@ -504,28 +697,84 @@ static void dealloc_rng(struct kernel_rng *rng) free(rng->rpi); rng->rpi = NULL; } - if (0 != rng->fd) { + if (-1 != rng->fd) { close(rng->fd); - rng->fd = 0; + rng->fd = -1; } } static void dealloc(void) { dealloc_rng(&Random); - if(0 != Entropy_avail_fd) { + if (-1 != Entropy_avail_fd) { close(Entropy_avail_fd); - Entropy_avail_fd = 0; + Entropy_avail_fd = -1; } - if (0 != Pidfile_fd) { + if (-1 != Pidfile_fd) { close(Pidfile_fd); - Pidfile_fd = 0; + Pidfile_fd = -1; if (NULL != Pidfile) unlink(Pidfile); } +} - +static int alloc_rng(struct kernel_rng *rng) +{ + rng->ec = jent_entropy_collector_alloc(1, 0); + if (!rng->ec) { + dolog(LOG_ERR, "Allocation of entropy collector failed"); + return -EAGAIN; + } + + rng->rpi = malloc((sizeof(struct rand_pool_info) + + (ENTROPYBYTES * OVERSAMPLINGFACTOR * sizeof(char)))); + if (!rng->rpi) { + dolog(LOG_ERR, "Cannot allocate memory for random bytes"); + dealloc_rng(rng); + return -ENOMEM; + } + + rng->fd = open(rng->dev, O_WRONLY); + if (-1 == rng->fd) { + int errsv = errno; + + dolog(LOG_ERR, "Open of %s failed: %s", rng->dev, strerror(errno)); + dealloc_rng(rng); + return -errsv; + } + + return 0; +} + +static int alloc(void) +{ + int ret = 0; + size_t written = 0; + + ret = jent_entropy_init(); + if (ret) { + dolog(LOG_ERR, "The initialization of CPU Jitter RNG failed with error code %d\n", ret); + return ret; + } + + ret = alloc_rng(&Random); + if (ret) + return ret; + + Entropy_avail_fd = open(ENTROPYAVAIL, O_RDONLY); + if (-1 == Entropy_avail_fd) { + int errsv = errno; + + dolog(LOG_ERR, "Open of %s failed: %s", ENTROPYAVAIL, strerror(errno)); + dealloc(); + return -errsv; + } + + written = gather_entropy(&Random, 1); + dolog(LOG_VERBOSE, "%lu bytes written to /dev/random", written); + + return 0; } static void create_pid_file(const char *pid_file) @@ -559,7 +808,6 @@ static void create_pid_file(const char *pid_file) } } - static void daemonize(void) { pid_t pid; @@ -592,23 +840,32 @@ static void daemonize(void) create_pid_file(Pidfile); /* Redirect standard files to /dev/null */ +#if defined(__GNUC__) && __GNUC__ >= 5 #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-result" +#endif freopen( "/dev/null", "r", stdin); freopen( "/dev/null", "w", stdout); freopen( "/dev/null", "w", stderr); +#if defined(__GNUC__) && __GNUC__ >= 5 #pragma GCC diagnostic pop +#endif } int main(int argc, char *argv[]) { + int ret; + parse_opts(argc, argv); if (geteuid()) dolog(LOG_ERR, "Program must start as root!"); - alloc(); + ret = alloc(); + if (ret) + return -ret; + if (0 == Verbosity) daemonize(); install_term(); diff --git a/release/src/router/jitterentropy-rngd/jitterentropy.h b/release/src/router/jitterentropy-rngd/jitterentropy.h index 7467714e59e..5eea673192d 100644 --- a/release/src/router/jitterentropy-rngd/jitterentropy.h +++ b/release/src/router/jitterentropy-rngd/jitterentropy.h @@ -61,6 +61,25 @@ */ #define JENT_CONF_ENABLE_INTERNAL_TIMER +/* + * Disable the loop shuffle operation + * + * The shuffle operation enlarges the timing of the conditioning function + * by a variable length defined by the LSB of a time stamp. Some mathematicians + * are concerned that this pseudo-random selection of the loop iteration count + * may create some form of dependency between the different loop counts + * and the associated time duration of the conditioning function. It + * also complicates entropy assessment because it effectively combines a bunch + * of shifted/scaled copies the same distribution and masks failures from the + * health testing. + * + * By enabling this flag, the loop shuffle operation is disabled and + * the entropy collection operates in a way that honor the concerns. + * + * By enabling this flag, the time of collecting entropy may be enlarged. + */ +#define JENT_CONF_DISABLE_LOOP_SHUFFLE + /*************************************************************************** * Jitter RNG State Definition Section ***************************************************************************/ @@ -106,7 +125,7 @@ struct rand_data #define JENT_APT_WORD_MASK (JENT_APT_LSB - 1) unsigned int apt_observations; /* Number of collected observations */ unsigned int apt_count; /* APT counter */ - unsigned int apt_base; /* APT base reference */ + uint64_t apt_base; /* APT base reference */ unsigned int apt_base_set:1; /* APT base reference set? */ unsigned int fips_enabled:1; @@ -130,6 +149,17 @@ struct rand_data entropy collector */ #define JENT_FORCE_INTERNAL_TIMER (1<<3) /* Force the use of the internal timer */ +#define JENT_DISABLE_INTERNAL_TIMER (1<<4) /* Disable the potential use of + the internal timer. */ +#define JENT_FORCE_FIPS (1<<5) /* Force FIPS compliant mode + including full SP800-90B + compliance. */ + +#ifdef JENT_CONF_DISABLE_LOOP_SHUFFLE +# define JENT_MIN_OSR 3 +#else +# define JENT_MIN_OSR 1 +#endif /* -- BEGIN Main interface functions -- */ @@ -140,7 +170,7 @@ struct rand_data * * It is allowed to change this value as required for the intended environment. */ -#define JENT_STUCK_INIT_THRES(x) (x/10 * 9) +#define JENT_STUCK_INIT_THRES(x) ((x*9) / 10) #endif #ifdef JENT_PRIVATE_COMPILE diff --git a/release/src/router/openvpn/ChangeLog b/release/src/router/openvpn/ChangeLog index 1b26873e13d..35a04775a0f 100644 --- a/release/src/router/openvpn/ChangeLog +++ b/release/src/router/openvpn/ChangeLog @@ -1,6 +1,37 @@ OpenVPN Change Log Copyright (C) 2002-2020 OpenVPN Inc +2021.04.20 -- Version 2.5.2 + +Arne Schwabe (10): + Avoid generating unecessary mbed debug messages + Restore also ping related options on a reconnect + Cleanup print_details and add signature/ED certificate print + Always disable TLS renegotiations + Also restore/save route-gateway options on SIGUSR1 reconnects + Move context_auth from context_2 to tls_multi and name it multi_state + Fix condition to generate session keys + Move auth_token_state from multi to key_state + Ensure auth-token is only sent on a fully authenticated session + Ensure key state is authenticated before sending push reply + +Gert Doering (2): + Fix potential NULL ptr crash if compiled with DMALLOC + +Max Fillinger (2): + In init_ssl, open the correct CRL path pre-chroot + Abort if CRL file can't be stat-ed in ssl_init + +Richard Bonhomme (1): + Do not print Diffie Hellman parameters file to log file + +Simon Rozman (1): + openvpnserv: Cache last error before it is overridden + +Vladislav Grishenko (1): + Fix IPv4 default gateway with multiple route tables + + 2021.02.24 -- Version 2.5.1 Arne Schwabe (5): diff --git a/release/src/router/openvpn/Changes.rst b/release/src/router/openvpn/Changes.rst index 6128275cc6f..b0a6b273c7e 100644 --- a/release/src/router/openvpn/Changes.rst +++ b/release/src/router/openvpn/Changes.rst @@ -1,3 +1,48 @@ +Overview of changes in 2.5.2 +============================ + +Bugfixes +-------- +- CVE-2020-15078 + see https://community.openvpn.net/openvpn/wiki/SecurityAnnouncements + + This bug allows - under very specific circumstances - to trick a + server using delayed authentication (plugin or management) into + returning a PUSH_REPLY before the AUTH_FAILED message, which can + possibly be used to gather information about a VPN setup. + + In combination with "--auth-gen-token" or an user-specific token auth + solution it can be possible to get access to a VPN with an + otherwise-invalid account. + +- restore pushed "ping" settings correctly on a SIGUSR1 restart + +- avoid generating unecessary mbed debug messages - this is actually + a workaround for an mbedTLS 2.25 bug when using Curve25519 and Curve448 + ED curves - mbedTLS crashes on preparing debug infos that we do not + actually need unless running with "--verb 8" + +- do not print inlined (...) Diffie Hellman parameters to log file + +- fix Linux/SITNL default route lookup in case of multiple routing tables + with more than one default route present (always use "main table" for now) + +- Fix CRL file handling in combination with chroot + +User-visible Changes +-------------------- + +- OpenVPN will now refuse to start if CRL file is not present at startup + time. At "reload time" absense of the CRL file is still OK (and the + in memory copy is used) but at startup it is now considered an error. + + +New features +------------ +- printing of the TLS ciphers negotiated has been extended, especially + displaying TLS 1.3 and EC certificates more correctly. + + Overview of changes in 2.5.1 ============================ diff --git a/release/src/router/openvpn/include/openvpn-plugin.h b/release/src/router/openvpn/include/openvpn-plugin.h index 00957459e0e..c67dd55454a 100644 --- a/release/src/router/openvpn/include/openvpn-plugin.h +++ b/release/src/router/openvpn/include/openvpn-plugin.h @@ -53,7 +53,7 @@ extern "C" { */ #define OPENVPN_VERSION_MAJOR 2 #define OPENVPN_VERSION_MINOR 5 -#define OPENVPN_VERSION_PATCH ".1" +#define OPENVPN_VERSION_PATCH ".2" /* * Plug-in types. These types correspond to the set of script callbacks diff --git a/release/src/router/openvpn/sample/sample-plugins/Makefile b/release/src/router/openvpn/sample/sample-plugins/Makefile index f7099983999..6a24fff7936 100644 --- a/release/src/router/openvpn/sample/sample-plugins/Makefile +++ b/release/src/router/openvpn/sample/sample-plugins/Makefile @@ -210,7 +210,7 @@ OPENSSL_CFLAGS = OPENSSL_LIBS = -lssl -lcrypto OPENVPN_VERSION_MAJOR = 2 OPENVPN_VERSION_MINOR = 5 -OPENVPN_VERSION_PATCH = .1 +OPENVPN_VERSION_PATCH = .2 OPTIONAL_CRYPTO_CFLAGS = OPTIONAL_CRYPTO_LIBS = -lssl -lcrypto OPTIONAL_DL_LIBS = -ldl @@ -231,10 +231,10 @@ P11KIT_LIBS = PACKAGE = openvpn PACKAGE_BUGREPORT = openvpn-users@lists.sourceforge.net PACKAGE_NAME = OpenVPN -PACKAGE_STRING = OpenVPN 2.5.1 +PACKAGE_STRING = OpenVPN 2.5.2 PACKAGE_TARNAME = openvpn PACKAGE_URL = -PACKAGE_VERSION = 2.5.1 +PACKAGE_VERSION = 2.5.2 PATH_SEPARATOR = : PKCS11_HELPER_CFLAGS = PKCS11_HELPER_LIBS = -lpthread -ldl -lcrypto -lpkcs11-helper @@ -264,7 +264,7 @@ TAP_WIN_MIN_MINOR = 9 TEST_CFLAGS = -I$(top_srcdir)/include TEST_LDFLAGS = -lssl -lcrypto -llzo2 TMPFILES_DIR = -VERSION = 2.5.1 +VERSION = 2.5.2 abs_builddir = /home/samuli/opt/openvpninc/openvpn-release-scripts/release/openvpn/sample/sample-plugins abs_srcdir = /home/samuli/opt/openvpninc/openvpn-release-scripts/release/openvpn/sample/sample-plugins abs_top_builddir = /home/samuli/opt/openvpninc/openvpn-release-scripts/release/openvpn diff --git a/release/src/router/openvpn/src/openvpn/auth_token.c b/release/src/router/openvpn/src/openvpn/auth_token.c index cc70c06c355..0ea6d183288 100644 --- a/release/src/router/openvpn/src/openvpn/auth_token.c +++ b/release/src/router/openvpn/src/openvpn/auth_token.c @@ -57,6 +57,7 @@ add_session_token_env(struct tls_session *session, struct tls_multi *multi, return; } + int auth_token_state_flags = session->key[KS_PRIMARY].auth_token_state_flags; const char *state; @@ -64,9 +65,9 @@ add_session_token_env(struct tls_session *session, struct tls_multi *multi, { state = "Initial"; } - else if (multi->auth_token_state_flags & AUTH_TOKEN_HMAC_OK) + else if (auth_token_state_flags & AUTH_TOKEN_HMAC_OK) { - switch (multi->auth_token_state_flags & (AUTH_TOKEN_VALID_EMPTYUSER|AUTH_TOKEN_EXPIRED)) + switch (auth_token_state_flags & (AUTH_TOKEN_VALID_EMPTYUSER|AUTH_TOKEN_EXPIRED)) { case 0: state = "Authenticated"; @@ -98,8 +99,8 @@ add_session_token_env(struct tls_session *session, struct tls_multi *multi, /* We had a valid session id before */ const char *session_id_source; - if (multi->auth_token_state_flags & AUTH_TOKEN_HMAC_OK - &!(multi->auth_token_state_flags & AUTH_TOKEN_EXPIRED)) + if (auth_token_state_flags & AUTH_TOKEN_HMAC_OK + && !(auth_token_state_flags & AUTH_TOKEN_EXPIRED)) { session_id_source = up->password; } @@ -236,7 +237,8 @@ generate_auth_token(const struct user_pass *up, struct tls_multi *multi) * a new token with the empty username since we do not want to loose * the information that the username cannot be trusted */ - if (multi->auth_token_state_flags & AUTH_TOKEN_VALID_EMPTYUSER) + struct key_state *ks = &multi->session[TM_ACTIVE].key[KS_PRIMARY]; + if (ks->auth_token_state_flags & AUTH_TOKEN_VALID_EMPTYUSER) { hmac_ctx_update(ctx, (const uint8_t *) "", 0); } diff --git a/release/src/router/openvpn/src/openvpn/buffer.c b/release/src/router/openvpn/src/openvpn/buffer.c index b32bc8b2629..890f31a6cc5 100644 --- a/release/src/router/openvpn/src/openvpn/buffer.c +++ b/release/src/router/openvpn/src/openvpn/buffer.c @@ -709,7 +709,6 @@ string_alloc(const char *str, struct gc_arena *gc) */ #ifdef DMALLOC ret = openvpn_dmalloc(file, line, n); - memset(ret, 0, n); #else ret = calloc(1, n); #endif diff --git a/release/src/router/openvpn/src/openvpn/forward.c b/release/src/router/openvpn/src/openvpn/forward.c index 7ed8d0d7518..fd7412f73d8 100644 --- a/release/src/router/openvpn/src/openvpn/forward.c +++ b/release/src/router/openvpn/src/openvpn/forward.c @@ -526,9 +526,10 @@ encrypt_sign(struct context *c, bool comp_frag) /* * Drop non-TLS outgoing packet if client-connect script/plugin - * has not yet succeeded. + * has not yet succeeded. In non-TLS mode tls_multi is not defined + * and we always pass packets. */ - if (c->c2.context_auth != CAS_SUCCEEDED) + if (c->c2.tls_multi && c->c2.tls_multi->multi_state != CAS_SUCCEEDED) { c->c2.buf.len = 0; } @@ -973,9 +974,10 @@ process_incoming_link_part1(struct context *c, struct link_socket_info *lsi, boo /* * Drop non-TLS packet if client-connect script/plugin and cipher selection - * has not yet succeeded. + * has not yet succeeded. In non-TLS mode tls_multi is not defined + * and we always pass packets. */ - if (c->c2.context_auth != CAS_SUCCEEDED) + if (c->c2.tls_multi && c->c2.tls_multi->multi_state != CAS_SUCCEEDED) { c->c2.buf.len = 0; } diff --git a/release/src/router/openvpn/src/openvpn/init.c b/release/src/router/openvpn/src/openvpn/init.c index f465cabf356..2f41d2cfc7f 100644 --- a/release/src/router/openvpn/src/openvpn/init.c +++ b/release/src/router/openvpn/src/openvpn/init.c @@ -2736,7 +2736,7 @@ do_init_crypto_tls_c1(struct context *c) * Initialize the OpenSSL library's global * SSL context. */ - init_ssl(options, &(c->c1.ks.ssl_ctx)); + init_ssl(options, &(c->c1.ks.ssl_ctx), c->c0 && c->c0->uid_gid_chroot_set); if (!tls_ctx_initialised(&c->c1.ks.ssl_ctx)) { #if P2MP diff --git a/release/src/router/openvpn/src/openvpn/misc.c b/release/src/router/openvpn/src/openvpn/misc.c index c0c72dd706d..84825c995fe 100644 --- a/release/src/router/openvpn/src/openvpn/misc.c +++ b/release/src/router/openvpn/src/openvpn/misc.c @@ -787,3 +787,14 @@ get_num_elements(const char *string, char delimiter) return element_count; } + +struct buffer +prepend_dir(const char *dir, const char *path, struct gc_arena *gc) +{ + size_t len = strlen(dir) + strlen(PATH_SEPARATOR_STR) + strlen(path) + 1; + struct buffer combined_path = alloc_buf_gc(len, gc); + buf_printf(&combined_path, "%s%s%s", dir, PATH_SEPARATOR_STR, path); + ASSERT(combined_path.len > 0); + + return combined_path; +} diff --git a/release/src/router/openvpn/src/openvpn/misc.h b/release/src/router/openvpn/src/openvpn/misc.h index e4342b0d8b2..df08597c3ea 100644 --- a/release/src/router/openvpn/src/openvpn/misc.h +++ b/release/src/router/openvpn/src/openvpn/misc.h @@ -197,4 +197,10 @@ void output_peer_info_env(struct env_set *es, const char *peer_info); int get_num_elements(const char *string, char delimiter); +/** + * Prepend a directory to a path. + */ +struct buffer +prepend_dir(const char *dir, const char *path, struct gc_arena *gc); + #endif /* ifndef MISC_H */ diff --git a/release/src/router/openvpn/src/openvpn/multi.c b/release/src/router/openvpn/src/openvpn/multi.c index 137381805f7..599ffd86d21 100644 --- a/release/src/router/openvpn/src/openvpn/multi.c +++ b/release/src/router/openvpn/src/openvpn/multi.c @@ -678,7 +678,7 @@ multi_close_instance(struct multi_context *m, #ifdef MANAGEMENT_DEF_AUTH set_cc_config(mi, NULL); #endif - if (mi->context.c2.context_auth == CAS_SUCCEEDED) + if (mi->context.c2.tls_multi->multi_state == CAS_SUCCEEDED) { multi_client_disconnect_script(mi); } @@ -788,7 +788,7 @@ multi_create_instance(struct multi_context *m, const struct mroute_addr *real) goto err; } - mi->context.c2.context_auth = CAS_PENDING; + mi->context.c2.tls_multi->multi_state = CAS_PENDING; if (hash_n_elements(m->hash) >= m->max_clients) { @@ -2436,18 +2436,18 @@ multi_client_connect_late_setup(struct multi_context *m, mi->reporting_addr_ipv6 = mi->context.c2.push_ifconfig_ipv6_local; /* set context-level authentication flag */ - mi->context.c2.context_auth = CAS_SUCCEEDED; + mi->context.c2.tls_multi->multi_state = CAS_SUCCEEDED; /* authentication complete, calculate dynamic client specific options */ if (!multi_client_set_protocol_options(&mi->context)) { - mi->context.c2.context_auth = CAS_FAILED; + mi->context.c2.tls_multi->multi_state = CAS_FAILED; } /* Generate data channel keys only if setting protocol options * has not failed */ else if (!multi_client_generate_tls_keys(&mi->context)) { - mi->context.c2.context_auth = CAS_FAILED; + mi->context.c2.tls_multi->multi_state = CAS_FAILED; } /* send push reply if ready */ @@ -2595,7 +2595,7 @@ multi_connection_established(struct multi_context *m, struct multi_instance *mi) /* We are only called for the CAS_PENDING_x states, so we * can ignore other states here */ - bool from_deferred = (mi->context.c2.context_auth != CAS_PENDING); + bool from_deferred = (mi->context.c2.tls_multi->multi_state != CAS_PENDING); int *cur_handler_index = &mi->client_connect_defer_state.cur_handler_index; unsigned int *option_types_found = @@ -2607,7 +2607,7 @@ multi_connection_established(struct multi_context *m, struct multi_instance *mi) *cur_handler_index = 0; *option_types_found = 0; /* Initially we have no handler that has returned a result */ - mi->context.c2.context_auth = CAS_PENDING_DEFERRED; + mi->context.c2.tls_multi->multi_state = CAS_PENDING_DEFERRED; multi_client_connect_early_setup(m, mi); } @@ -2630,7 +2630,7 @@ multi_connection_established(struct multi_context *m, struct multi_instance *mi) * Remember that we already had at least one handler * returning a result should we go to into deferred state */ - mi->context.c2.context_auth = CAS_PENDING_DEFERRED_PARTIAL; + mi->context.c2.tls_multi->multi_state = CAS_PENDING_DEFERRED_PARTIAL; break; case CC_RET_SKIPPED: @@ -2682,12 +2682,12 @@ multi_connection_established(struct multi_context *m, struct multi_instance *mi) { /* run the disconnect script if we had a connect script that * did not fail */ - if (mi->context.c2.context_auth == CAS_PENDING_DEFERRED_PARTIAL) + if (mi->context.c2.tls_multi->multi_state == CAS_PENDING_DEFERRED_PARTIAL) { multi_client_disconnect_script(mi); } - mi->context.c2.context_auth = CAS_FAILED; + mi->context.c2.tls_multi->multi_state = CAS_FAILED; } /* increment number of current authenticated clients */ @@ -2990,13 +2990,13 @@ multi_process_post(struct multi_context *m, struct multi_instance *mi, const uns { /* connection is "established" when SSL/TLS key negotiation succeeds * and (if specified) auth user/pass succeeds */ - if (is_cas_pending(mi->context.c2.context_auth) + if (is_cas_pending(mi->context.c2.tls_multi->multi_state) && CONNECTION_ESTABLISHED(&mi->context)) { multi_connection_established(m, mi); } #if defined(ENABLE_ASYNC_PUSH) && defined(ENABLE_DEF_AUTH) - if (is_cas_pending(mi->context.c2.context_auth) + if (is_cas_pending(mi->context.c2.tls_multi->multi_state) && mi->client_connect_defer_state.deferred_ret_file) { add_inotify_file_watch(m, mi, m->top.c2.inotify_fd, @@ -3953,7 +3953,7 @@ management_client_auth(void *arg, { if (auth) { - if (is_cas_pending(mi->context.c2.context_auth)) + if (is_cas_pending(mi->context.c2.tls_multi->multi_state)) { set_cc_config(mi, cc_config); cc_config_owned = false; @@ -3965,7 +3965,7 @@ management_client_auth(void *arg, { msg(D_MULTI_LOW, "MULTI: connection rejected: %s, CLI:%s", reason, np(client_reason)); } - if (!is_cas_pending(mi->context.c2.context_auth)) + if (!is_cas_pending(mi->context.c2.tls_multi->multi_state)) { send_auth_failed(&mi->context, client_reason); /* mid-session reauth failed */ multi_schedule_context_wakeup(m, mi); diff --git a/release/src/router/openvpn/src/openvpn/networking_sitnl.c b/release/src/router/openvpn/src/openvpn/networking_sitnl.c index 2bc70a50466..ea1621edb9d 100644 --- a/release/src/router/openvpn/src/openvpn/networking_sitnl.c +++ b/release/src/router/openvpn/src/openvpn/networking_sitnl.c @@ -426,6 +426,7 @@ typedef struct { inet_address_t gw; char iface[IFNAMSIZ]; bool default_only; + unsigned int table; } route_res_t; static int @@ -435,7 +436,8 @@ sitnl_route_save(struct nlmsghdr *n, void *arg) struct rtmsg *r = NLMSG_DATA(n); struct rtattr *rta = RTM_RTA(r); int len = n->nlmsg_len - NLMSG_LENGTH(sizeof(*r)); - unsigned int ifindex = 0; + unsigned int table, ifindex = 0; + void *gw = NULL; /* filter-out non-zero dst prefixes */ if (res->default_only && r->rtm_dst_len != 0) @@ -443,6 +445,9 @@ sitnl_route_save(struct nlmsghdr *n, void *arg) return 1; } + /* route table, ignored with RTA_TABLE */ + table = r->rtm_table; + while (RTA_OK(rta, len)) { switch (rta->rta_type) @@ -458,13 +463,24 @@ sitnl_route_save(struct nlmsghdr *n, void *arg) /* GW for the route */ case RTA_GATEWAY: - memcpy(&res->gw, RTA_DATA(rta), res->addr_size); + gw = RTA_DATA(rta); + break; + + /* route table */ + case RTA_TABLE: + table = *(unsigned int *)RTA_DATA(rta); break; } rta = RTA_NEXT(rta, len); } + /* filter out any route not coming from the selected table */ + if (res->table && res->table != table) + { + return 1; + } + if (!if_indextoname(ifindex, res->iface)) { msg(M_WARN | M_ERRNO, "%s: rtnl: can't get ifname for index %d", @@ -472,6 +488,11 @@ sitnl_route_save(struct nlmsghdr *n, void *arg) return -1; } + if (gw) + { + memcpy(&res->gw, gw, res->addr_size); + } + return 0; } @@ -507,6 +528,7 @@ sitnl_route_best_gw(sa_family_t af_family, const inet_address_t *dst, { req.n.nlmsg_flags |= NLM_F_DUMP; res.default_only = true; + res.table = RT_TABLE_MAIN; } else { diff --git a/release/src/router/openvpn/src/openvpn/openvpn.h b/release/src/router/openvpn/src/openvpn/openvpn.h index a7b5977494b..d131ac59eea 100644 --- a/release/src/router/openvpn/src/openvpn/openvpn.h +++ b/release/src/router/openvpn/src/openvpn/openvpn.h @@ -211,17 +211,6 @@ struct context_1 }; -/* client authentication state, CAS_SUCCEEDED must be 0 since - * non multi code path still checks this variable but does not initialise it - * so the code depends on zero initialisation */ -enum client_connect_status { - CAS_SUCCEEDED=0, - CAS_PENDING, - CAS_PENDING_DEFERRED, - CAS_PENDING_DEFERRED_PARTIAL, /**< at least handler succeeded, no result yet*/ - CAS_FAILED, -}; - static inline bool is_cas_pending(enum client_connect_status cas) { @@ -458,9 +447,6 @@ struct context_2 int push_ifconfig_ipv6_netbits; struct in6_addr push_ifconfig_ipv6_remote; - - enum client_connect_status context_auth; - struct event_timeout push_request_interval; int n_sent_push_requests; bool did_pre_pull_restore; diff --git a/release/src/router/openvpn/src/openvpn/options.c b/release/src/router/openvpn/src/openvpn/options.c index 33edf75e96a..c7f7cc55bb8 100644 --- a/release/src/router/openvpn/src/openvpn/options.c +++ b/release/src/router/openvpn/src/openvpn/options.c @@ -1700,7 +1700,7 @@ show_settings(const struct options *o) SHOW_BOOL(tls_client); SHOW_STR_INLINE(ca_file); SHOW_STR(ca_path); - SHOW_STR(dh_file); + SHOW_STR_INLINE(dh_file); #ifdef ENABLE_MANAGEMENT if ((o->management_flags & MF_EXTERNAL_CERT)) { @@ -3328,14 +3328,8 @@ check_file_access_chroot(const char *chroot, const int type, const char *file, c { struct gc_arena gc = gc_new(); struct buffer chroot_file; - int len = 0; - - /* Build up a new full path including chroot directory */ - len = strlen(chroot) + strlen(PATH_SEPARATOR_STR) + strlen(file) + 1; - chroot_file = alloc_buf_gc(len, &gc); - buf_printf(&chroot_file, "%s%s%s", chroot, PATH_SEPARATOR_STR, file); - ASSERT(chroot_file.len > 0); + chroot_file = prepend_dir(chroot, file, &gc); ret = check_file_access(type, BSTR(&chroot_file), mode, opt); gc_free(&gc); } @@ -3597,6 +3591,14 @@ pre_pull_save(struct options *o) o->pre_pull->client_nat = clone_client_nat_option_list(o->client_nat, &o->gc); o->pre_pull->client_nat_defined = true; } + + o->pre_pull->route_default_gateway = o->route_default_gateway; + o->pre_pull->route_ipv6_default_gateway = o->route_ipv6_default_gateway; + + /* Ping related options should be reset to the config values on reconnect */ + o->pre_pull->ping_rec_timeout = o->ping_rec_timeout; + o->pre_pull->ping_rec_timeout_action = o->ping_rec_timeout_action; + o->pre_pull->ping_send_timeout = o->ping_send_timeout; } } @@ -3632,6 +3634,9 @@ pre_pull_restore(struct options *o, struct gc_arena *gc) o->routes_ipv6 = NULL; } + o->route_default_gateway = pp->route_default_gateway; + o->route_ipv6_default_gateway = pp->route_ipv6_default_gateway; + if (pp->client_nat_defined) { cnol_check_alloc(o); @@ -3643,6 +3648,10 @@ pre_pull_restore(struct options *o, struct gc_arena *gc) } o->foreign_option_index = pp->foreign_option_index; + + o->ping_rec_timeout = pp->ping_rec_timeout; + o->ping_rec_timeout_action = pp->ping_rec_timeout_action; + o->ping_send_timeout = pp->ping_send_timeout; } o->push_continuation = 0; @@ -6008,6 +6017,12 @@ add_option(struct options *options, { VERIFY_PERMISSION(OPT_P_MESSAGES); options->verbosity = positive_atoi(p[1]); + if (options->verbosity >= (D_TLS_DEBUG_MED & M_DEBUG_LEVEL)) + { + /* We pass this flag to the SSL library to avoid + * mbed TLS always generating debug level logging */ + options->ssl_flags |= SSLF_TLS_DEBUG_ENABLED; + } #if !defined(ENABLE_DEBUG) && !defined(ENABLE_SMALL) /* Warn when a debug verbosity is supplied when built without debug support */ if (options->verbosity >= 7) diff --git a/release/src/router/openvpn/src/openvpn/options.h b/release/src/router/openvpn/src/openvpn/options.h index 877e9396248..15ef9677ffb 100644 --- a/release/src/router/openvpn/src/openvpn/options.h +++ b/release/src/router/openvpn/src/openvpn/options.h @@ -72,9 +72,16 @@ struct options_pre_pull bool routes_ipv6_defined; struct route_ipv6_option_list *routes_ipv6; + const char *route_default_gateway; + const char *route_ipv6_default_gateway; + bool client_nat_defined; struct client_nat_option_list *client_nat; + int ping_send_timeout; + int ping_rec_timeout; + int ping_rec_timeout_action; + int foreign_option_index; }; diff --git a/release/src/router/openvpn/src/openvpn/push.c b/release/src/router/openvpn/src/openvpn/push.c index 70d5e139839..66f88d021d4 100644 --- a/release/src/router/openvpn/src/openvpn/push.c +++ b/release/src/router/openvpn/src/openvpn/push.c @@ -736,14 +736,17 @@ int process_incoming_push_request(struct context *c) { int ret = PUSH_MSG_ERROR; + struct key_state *ks = &c->c2.tls_multi->session[TM_ACTIVE].key[KS_PRIMARY]; - if (tls_authentication_status(c->c2.tls_multi, 0) == TLS_AUTHENTICATION_FAILED || c->c2.context_auth == CAS_FAILED) + if (tls_authentication_status(c->c2.tls_multi, 0) == TLS_AUTHENTICATION_FAILED + || c->c2.tls_multi->multi_state == CAS_FAILED) { const char *client_reason = tls_client_reason(c->c2.tls_multi); send_auth_failed(c, client_reason); ret = PUSH_MSG_AUTH_FAILURE; } - else if (c->c2.context_auth == CAS_SUCCEEDED) + else if (c->c2.tls_multi->multi_state == CAS_SUCCEEDED + && ks->authenticated == KS_AUTH_TRUE) { time_t now; diff --git a/release/src/router/openvpn/src/openvpn/ssl.c b/release/src/router/openvpn/src/openvpn/ssl.c index 76da1fc9a14..80753183546 100644 --- a/release/src/router/openvpn/src/openvpn/ssl.c +++ b/release/src/router/openvpn/src/openvpn/ssl.c @@ -558,7 +558,15 @@ tls_ctx_reload_crl(struct tls_root_ctx *ssl_ctx, const char *crl_file, } else if (platform_stat(crl_file, &crl_stat) < 0) { - msg(M_WARN, "WARNING: Failed to stat CRL file, not (re)loading CRL."); + /* If crl_last_mtime is zero, the CRL file has not been read before. */ + if (ssl_ctx->crl_last_mtime == 0) + { + msg(M_FATAL, "ERROR: Failed to stat CRL file during initialization, exiting."); + } + else + { + msg(M_WARN, "WARNING: Failed to stat CRL file, not reloading CRL."); + } return; } @@ -583,7 +591,7 @@ tls_ctx_reload_crl(struct tls_root_ctx *ssl_ctx, const char *crl_file, * All files are in PEM format. */ void -init_ssl(const struct options *options, struct tls_root_ctx *new_ctx) +init_ssl(const struct options *options, struct tls_root_ctx *new_ctx, bool in_chroot) { ASSERT(NULL != new_ctx); @@ -701,7 +709,24 @@ init_ssl(const struct options *options, struct tls_root_ctx *new_ctx) /* Read CRL */ if (options->crl_file && !(options->ssl_flags & SSLF_CRL_VERIFY_DIR)) { - tls_ctx_reload_crl(new_ctx, options->crl_file, options->crl_file_inline); + /* If we're running with the chroot option, we may run init_ssl() before + * and after chroot-ing. We can use the crl_file path as-is if we're + * not going to chroot, or if we already are inside the chroot. + * + * If we're going to chroot later, we need to prefix the path of the + * chroot directory to crl_file. + */ + if (!options->chroot_dir || in_chroot || options->crl_file_inline) + { + tls_ctx_reload_crl(new_ctx, options->crl_file, options->crl_file_inline); + } + else + { + struct gc_arena gc = gc_new(); + struct buffer crl_file_buf = prepend_dir(options->chroot_dir, options->crl_file, &gc); + tls_ctx_reload_crl(new_ctx, BSTR(&crl_file_buf), options->crl_file_inline); + gc_free(&gc); + } } /* Once keys and cert are loaded, load ECDH parameters */ @@ -2295,7 +2320,8 @@ push_peer_info(struct buffer *buf, struct tls_session *session) * to the TLS control channel (cleartext). */ static bool -key_method_2_write(struct buffer *buf, struct tls_session *session) +key_method_2_write(struct buffer *buf, struct tls_multi *multi, + struct tls_session *session) { struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */ @@ -2386,12 +2412,17 @@ key_method_2_write(struct buffer *buf, struct tls_session *session) goto error; } - /* Generate tunnel keys if we're a TLS server. - * If we're a p2mp server and IV_NCP >= 2 is negotiated, the first key - * generation is postponed until after the pull/push, so we can process pushed - * cipher directives. + /* + * Generate tunnel keys if we're a TLS server. + * + * If we're a p2mp server to allow NCP, the first key + * generation is postponed until after the connect script finished and the + * NCP options can be processed. Since that always happens at after connect + * script options are available the CAS_SUCCEEDED status is identical to + * NCP options are processed and we have no extra state for NCP finished. */ - if (session->opt->server && !(session->opt->mode == MODE_SERVER && ks->key_id <= 0)) + if (session->opt->server && (session->opt->mode != MODE_SERVER + || multi->multi_state == CAS_SUCCEEDED)) { if (ks->authenticated > KS_AUTH_FALSE) { @@ -2847,7 +2878,7 @@ tls_process(struct tls_multi *multi, if (!buf->len && ((ks->state == S_START && !session->opt->server) || (ks->state == S_GOT_KEY && session->opt->server))) { - if (!key_method_2_write(buf, session)) + if (!key_method_2_write(buf, multi, session)) { goto error; } diff --git a/release/src/router/openvpn/src/openvpn/ssl.h b/release/src/router/openvpn/src/openvpn/ssl.h index 97d721bbf23..bb6240d5b05 100644 --- a/release/src/router/openvpn/src/openvpn/ssl.h +++ b/release/src/router/openvpn/src/openvpn/ssl.h @@ -154,7 +154,7 @@ void free_ssl_lib(void); * Build master SSL context object that serves for the whole of OpenVPN * instantiation */ -void init_ssl(const struct options *options, struct tls_root_ctx *ctx); +void init_ssl(const struct options *options, struct tls_root_ctx *ctx, bool in_chroot); /** @addtogroup control_processor * @{ */ diff --git a/release/src/router/openvpn/src/openvpn/ssl_common.h b/release/src/router/openvpn/src/openvpn/ssl_common.h index 96897e48b26..d6fd50bd367 100644 --- a/release/src/router/openvpn/src/openvpn/ssl_common.h +++ b/release/src/router/openvpn/src/openvpn/ssl_common.h @@ -166,6 +166,8 @@ enum ks_auth_state { struct key_state { int state; + /** The state of the auth-token sent from the client */ + int auth_token_state_flags; /** * Key id for this key_state, inherited from struct tls_session. @@ -347,6 +349,7 @@ struct tls_options #define SSLF_TLS_VERSION_MIN_MASK 0xF /* (uses bit positions 6 to 9) */ #define SSLF_TLS_VERSION_MAX_SHIFT 10 #define SSLF_TLS_VERSION_MAX_MASK 0xF /* (uses bit positions 10 to 13) */ +#define SSLF_TLS_DEBUG_ENABLED (1<<14) unsigned int ssl_flags; #ifdef MANAGEMENT_DEF_AUTH @@ -478,6 +481,19 @@ struct tls_session */ #define KEY_SCAN_SIZE 3 + +/* client authentication state, CAS_SUCCEEDED must be 0 since + * non multi code path still checks this variable but does not initialise it + * so the code depends on zero initialisation */ +enum client_connect_status { + CAS_SUCCEEDED=0, + CAS_PENDING, + CAS_PENDING_DEFERRED, + CAS_PENDING_DEFERRED_PARTIAL, /**< at least handler succeeded, no result yet*/ + CAS_FAILED, +}; + + /** * Security parameter state for a single VPN tunnel. * @ingroup control_processor @@ -518,6 +534,7 @@ struct tls_multi int n_sessions; /**< Number of sessions negotiated thus * far. */ + enum client_connect_status multi_state; /* * Number of errors. @@ -567,8 +584,6 @@ struct tls_multi * OpenVPN 3 clients sometimes wipes or replaces the username with a * username hint from their config. */ - int auth_token_state_flags; - /**< The state of the auth-token sent from the client last time */ /* For P_DATA_V2 */ uint32_t peer_id; diff --git a/release/src/router/openvpn/src/openvpn/ssl_mbedtls.c b/release/src/router/openvpn/src/openvpn/ssl_mbedtls.c index 9c8747888a2..881d089eaee 100644 --- a/release/src/router/openvpn/src/openvpn/ssl_mbedtls.c +++ b/release/src/router/openvpn/src/openvpn/ssl_mbedtls.c @@ -1070,7 +1070,18 @@ key_state_ssl_init(struct key_state_ssl *ks_ssl, mbedtls_ssl_config_defaults(ks_ssl->ssl_config, ssl_ctx->endpoint, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT); #ifdef MBEDTLS_DEBUG_C - mbedtls_debug_set_threshold(3); + /* We only want to have mbed TLS generate debug level logging when we would + * also display it. + * In fact mbed TLS 2.25.0 crashes generating debug log if Curve25591 is + * selected for DH (https://github.com/ARMmbed/mbedtls/issues/4208) */ + if (session->opt->ssl_flags & SSLF_TLS_DEBUG_ENABLED) + { + mbedtls_debug_set_threshold(3); + } + else + { + mbedtls_debug_set_threshold(2); + } #endif mbedtls_ssl_conf_dbg(ks_ssl->ssl_config, my_debug, NULL); mbedtls_ssl_conf_rng(ks_ssl->ssl_config, mbedtls_ctr_drbg_random, @@ -1087,6 +1098,10 @@ key_state_ssl_init(struct key_state_ssl *ks_ssl, { mbedtls_ssl_conf_curves(ks_ssl->ssl_config, ssl_ctx->groups); } + /* Disable TLS renegotiations. OpenVPN's renegotiation creates new SSL + * session and does not depend on this feature. And TLS renegotiations have + * been problematic in the past */ + mbedtls_ssl_conf_renegotiation(ks_ssl->ssl_config, MBEDTLS_SSL_RENEGOTIATION_DISABLED); /* Disable record splitting (for now). OpenVPN assumes records are sent * unfragmented, and changing that will require thorough review and diff --git a/release/src/router/openvpn/src/openvpn/ssl_openssl.c b/release/src/router/openvpn/src/openvpn/ssl_openssl.c index 5ba74402fc1..7b06beb7c7d 100644 --- a/release/src/router/openvpn/src/openvpn/ssl_openssl.c +++ b/release/src/router/openvpn/src/openvpn/ssl_openssl.c @@ -335,6 +335,12 @@ tls_ctx_set_options(struct tls_root_ctx *ctx, unsigned int ssl_flags) sslopt |= SSL_OP_CIPHER_SERVER_PREFERENCE; #endif sslopt |= SSL_OP_NO_COMPRESSION; + /* Disable TLS renegotiations. OpenVPN's renegotiation creates new SSL + * session and does not depend on this feature. And TLS renegotiations have + * been problematic in the past */ +#ifdef SSL_OP_NO_RENEGOTIATION + sslopt |= SSL_OP_NO_RENEGOTIATION; +#endif SSL_CTX_set_options(ctx->ctx, sslopt); @@ -2040,6 +2046,80 @@ key_state_read_plaintext(struct key_state_ssl *ks_ssl, struct buffer *buf, return ret; } +/** + * Print human readable information about the certifcate into buf + * @param cert the certificate being used + * @param buf output buffer + * @param buflen output buffer length + */ +static void +print_cert_details(X509 *cert, char *buf, size_t buflen) +{ + const char *curve = ""; + const char *type = "(error getting type)"; + EVP_PKEY *pkey = X509_get_pubkey(cert); + + if (pkey == NULL) + { + buf[0] = 0; + return; + } + + int typeid = EVP_PKEY_id(pkey); + +#ifndef OPENSSL_NO_EC + if (typeid == EVP_PKEY_EC && EVP_PKEY_get0_EC_KEY(pkey) != NULL) + { + EC_KEY *ec = EVP_PKEY_get0_EC_KEY(pkey); + const EC_GROUP *group = EC_KEY_get0_group(ec); + + int nid = EC_GROUP_get_curve_name(group); + if (nid == 0 || (curve = OBJ_nid2sn(nid)) == NULL) + { + curve = "(error getting curve name)"; + } + } +#endif + if (EVP_PKEY_id(pkey) != 0) + { + int typeid = EVP_PKEY_id(pkey); + type = OBJ_nid2sn(typeid); + + /* OpenSSL reports rsaEncryption, dsaEncryption and + * id-ecPublicKey, map these values to nicer ones */ + if (typeid == EVP_PKEY_RSA) + { + type = "RSA"; + } + else if (typeid == EVP_PKEY_DSA) + { + type = "DSA"; + } + else if (typeid == EVP_PKEY_EC) + { + /* EC gets the curve appended after the type */ + type = "EC, curve "; + } + else if (type == NULL) + { + type = "unknown type"; + } + } + + char sig[128] = { 0 }; + int signature_nid = X509_get_signature_nid(cert); + if (signature_nid != 0) + { + openvpn_snprintf(sig, sizeof(sig), ", signature: %s", + OBJ_nid2sn(signature_nid)); + } + + openvpn_snprintf(buf, buflen, ", peer certificate: %d bit %s%s%s", + EVP_PKEY_bits(pkey), type, curve, sig); + + EVP_PKEY_free(pkey); +} + /* ************************************** * * Information functions @@ -2051,7 +2131,6 @@ void print_details(struct key_state_ssl *ks_ssl, const char *prefix) { const SSL_CIPHER *ciph; - X509 *cert; char s1[256]; char s2[256]; @@ -2062,48 +2141,13 @@ print_details(struct key_state_ssl *ks_ssl, const char *prefix) SSL_get_version(ks_ssl->ssl), SSL_CIPHER_get_version(ciph), SSL_CIPHER_get_name(ciph)); - cert = SSL_get_peer_certificate(ks_ssl->ssl); - if (cert != NULL) - { - EVP_PKEY *pkey = X509_get_pubkey(cert); - if (pkey != NULL) - { - if ((EVP_PKEY_id(pkey) == EVP_PKEY_RSA) && (EVP_PKEY_get0_RSA(pkey) != NULL)) - { - RSA *rsa = EVP_PKEY_get0_RSA(pkey); - openvpn_snprintf(s2, sizeof(s2), ", %d bit RSA", - RSA_bits(rsa)); - } - else if ((EVP_PKEY_id(pkey) == EVP_PKEY_DSA) && (EVP_PKEY_get0_DSA(pkey) != NULL)) - { - DSA *dsa = EVP_PKEY_get0_DSA(pkey); - openvpn_snprintf(s2, sizeof(s2), ", %d bit DSA", - DSA_bits(dsa)); - } -#ifndef OPENSSL_NO_EC - else if ((EVP_PKEY_id(pkey) == EVP_PKEY_EC) && (EVP_PKEY_get0_EC_KEY(pkey) != NULL)) - { - EC_KEY *ec = EVP_PKEY_get0_EC_KEY(pkey); - const EC_GROUP *group = EC_KEY_get0_group(ec); - const char *curve; + X509 *cert = SSL_get_peer_certificate(ks_ssl->ssl); - int nid = EC_GROUP_get_curve_name(group); - if (nid == 0 || (curve = OBJ_nid2sn(nid)) == NULL) - { - curve = "Error getting curve name"; - } - - openvpn_snprintf(s2, sizeof(s2), ", %d bit EC, curve: %s", - EC_GROUP_order_bits(group), curve); - - } -#endif - EVP_PKEY_free(pkey); - } + if (cert) + { + print_cert_details(cert, s2, sizeof(s2)); X509_free(cert); } - /* The SSL API does not allow us to look at temporary RSA/DH keys, - * otherwise we should print their lengths too */ msg(D_HANDSHAKE, "%s%s", s1, s2); } diff --git a/release/src/router/openvpn/src/openvpn/ssl_verify.c b/release/src/router/openvpn/src/openvpn/ssl_verify.c index 33115eb6c1c..55e7fedc0fc 100644 --- a/release/src/router/openvpn/src/openvpn/ssl_verify.c +++ b/release/src/router/openvpn/src/openvpn/ssl_verify.c @@ -906,6 +906,39 @@ key_state_test_auth_control_file(struct key_state *ks) #endif /* ifdef PLUGIN_DEF_AUTH */ +/* This function is called when a session's primary key state first becomes KS_TRUE */ +void ssl_session_fully_authenticated(struct tls_multi *multi, struct tls_session* session) +{ + struct key_state *ks = &session->key[KS_PRIMARY]; + if (ks->key_id == 0) + { + /* A key id of 0 indicates a new session and the client will + * get the auth-token as part of the initial push reply */ + return; + } + + /* + * Auth token already sent to client, update auth-token on client. + * The initial auth-token is sent as part of the push message, for this + * update we need to schedule an extra push message. + * + * Otherwise the auth-token get pushed out as part of the "normal" + * push-reply + */ + if (multi->auth_token_initial) + { + /* + * We do not explicitly schedule the sending of the + * control message here but control message are only + * postponed when the control channel is not yet fully + * established and furthermore since this is called in + * the middle of authentication, there are other messages + * (new data channel keys) that are sent anyway and will + * trigger scheduling + */ + send_push_reply_auth_token(multi); + } +} /* * Return current session authentication state. Return * value is TLS_AUTHENTICATION_x. @@ -975,6 +1008,12 @@ tls_authentication_status(struct tls_multi *multi, const int latency) case ACF_SUCCEEDED: case ACF_DISABLED: success = true; + /* i=0 is the TM_ACTIVE/KS_PRIMARY session */ + if (i == 0 && ks->authenticated == KS_AUTH_DEFERRED) + { + ssl_session_fully_authenticated(multi, + &multi->session[TM_ACTIVE]); + } ks->authenticated = KS_AUTH_TRUE; break; @@ -1269,7 +1308,7 @@ verify_user_pass(struct user_pass *up, struct tls_multi *multi, */ if (session->opt->auth_token_generate && is_auth_token(up->password)) { - multi->auth_token_state_flags = verify_auth_token(up, multi, session); + ks->auth_token_state_flags = verify_auth_token(up, multi, session); if (session->opt->auth_token_call_auth) { /* @@ -1278,7 +1317,7 @@ verify_user_pass(struct user_pass *up, struct tls_multi *multi, * decide what to do with the result */ } - else if (multi->auth_token_state_flags == AUTH_TOKEN_HMAC_OK) + else if (ks->auth_token_state_flags == AUTH_TOKEN_HMAC_OK) { /* * We do not want the EXPIRED or EMPTY USER flags here so check @@ -1373,8 +1412,8 @@ verify_user_pass(struct user_pass *up, struct tls_multi *multi, * the initial timestamp and session id can be extracted from it */ if (!multi->auth_token - && (multi->auth_token_state_flags & AUTH_TOKEN_HMAC_OK) - && !(multi->auth_token_state_flags & AUTH_TOKEN_EXPIRED)) + && (ks->auth_token_state_flags & AUTH_TOKEN_HMAC_OK) + && !(ks->auth_token_state_flags & AUTH_TOKEN_EXPIRED)) { multi->auth_token = strdup(up->password); } @@ -1385,31 +1424,14 @@ verify_user_pass(struct user_pass *up, struct tls_multi *multi, */ generate_auth_token(up, multi); } - /* - * Auth token already sent to client, update auth-token on client. - * The initial auth-token is sent as part of the push message, for this - * update we need to schedule an extra push message. - * - * Otherwise the auth-token get pushed out as part of the "normal" - * push-reply - */ - if (multi->auth_token_initial) - { - /* - * We do not explicitly schedule the sending of the - * control message here but control message are only - * postponed when the control channel is not yet fully - * established and furthermore since this is called in - * the middle of authentication, there are other messages - * (new data channel keys) that are sent anyway and will - * trigger schedueling - */ - send_push_reply_auth_token(multi); - } msg(D_HANDSHAKE, "TLS: Username/Password authentication %s for username '%s' %s", (ks->authenticated == KS_AUTH_DEFERRED) ? "deferred" : "succeeded", up->username, (session->opt->ssl_flags & SSLF_USERNAME_AS_COMMON_NAME) ? "[CN SET]" : ""); + if (ks->authenticated == KS_AUTH_TRUE) + { + ssl_session_fully_authenticated(multi, session); + } } else { diff --git a/release/src/router/openvpn/src/openvpn/status.c b/release/src/router/openvpn/src/openvpn/status.c index 79d4348db18..9829edd007f 100644 --- a/release/src/router/openvpn/src/openvpn/status.c +++ b/release/src/router/openvpn/src/openvpn/status.c @@ -330,29 +330,39 @@ void update_nvram_status(int event) char cmd[128] = {0}; char name[16] = {0}; char *p = NULL; + int is_client = 0; prctl(PR_GET_NAME, name); //e.g. vpnserverX or vpnclientX p = name + 3; + if (!strcmp(p, "client")) + is_client = 1; + switch(event) { case EVENT_AUTH_FAILED: - snprintf(cmd, sizeof(cmd), "nvram set vpn_%s_errno=%d", p, ERRNO_AUTH); - system(cmd); - snprintf(cmd, sizeof(cmd), "nvram set vpn_%s_state=%d", p, ST_ERROR); - system(cmd); + if (is_client) { + snprintf(cmd, sizeof(cmd), "nvram set vpn_client_errno=%d", ERRNO_AUTH); + system(cmd); + snprintf(cmd, sizeof(cmd), "nvram set vpn_client_state=%d", ST_ERROR); + system(cmd); + } break; case EVENT_TLS_ERROR: - snprintf(cmd, sizeof(cmd), "nvram set vpn_%s_errno=%d", p, ERRNO_SSL); - system(cmd); - snprintf(cmd, sizeof(cmd), "nvram set vpn_%s_state=%d", p, ST_ERROR); - system(cmd); + if (is_client) { + snprintf(cmd, sizeof(cmd), "nvram set vpn_client_errno=%d", ERRNO_SSL); + system(cmd); + snprintf(cmd, sizeof(cmd), "nvram set vpn_client_state=%d", ST_ERROR); + system(cmd); + } break; case EVENT_NET_CONN: - snprintf(cmd, sizeof(cmd), "nvram set vpn_%s_errno=%d", p, ERRNO_NET_CONN); - system(cmd); - snprintf(cmd, sizeof(cmd), "nvram set vpn_%s_state=%d", p, ST_ERROR); - system(cmd); + if (is_client) { + snprintf(cmd, sizeof(cmd), "nvram set vpn_client_errno=%d", ERRNO_NET_CONN); + system(cmd); + snprintf(cmd, sizeof(cmd), "nvram set vpn_client_state=%d", ST_ERROR); + system(cmd); + } break; case EVENT_CONF_ERROR: snprintf(cmd, sizeof(cmd), "nvram set vpn_%s_errno=%d", p, ERRNO_CONF); diff --git a/release/src/router/openvpn/src/openvpnserv/common.c b/release/src/router/openvpn/src/openvpnserv/common.c index 958643dfd0e..6e6deae6353 100644 --- a/release/src/router/openvpn/src/openvpnserv/common.c +++ b/release/src/router/openvpn/src/openvpnserv/common.c @@ -228,12 +228,14 @@ GetOpenvpnSettings(settings_t *s) LPCTSTR GetLastErrorText() { + DWORD error; static TCHAR buf[256]; DWORD len; LPTSTR tmp = NULL; + error = GetLastError(); len = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY, - NULL, GetLastError(), LANG_NEUTRAL, (LPTSTR)&tmp, 0, NULL); + NULL, error, LANG_NEUTRAL, (LPTSTR)&tmp, 0, NULL); if (len == 0 || (long) _countof(buf) < (long) len + 14) { @@ -242,7 +244,7 @@ GetLastErrorText() else { tmp[_tcslen(tmp) - 2] = TEXT('\0'); /* remove CR/LF characters */ - openvpn_sntprintf(buf, _countof(buf), TEXT("%s (0x%x)"), tmp, GetLastError()); + openvpn_sntprintf(buf, _countof(buf), TEXT("%s (0x%x)"), tmp, error); } if (tmp) diff --git a/release/src/router/openvpn/tests/unit_tests/openvpn/test_auth_token.c b/release/src/router/openvpn/tests/unit_tests/openvpn/test_auth_token.c index dbde8631871..69fc1f8c94e 100644 --- a/release/src/router/openvpn/tests/unit_tests/openvpn/test_auth_token.c +++ b/release/src/router/openvpn/tests/unit_tests/openvpn/test_auth_token.c @@ -45,7 +45,7 @@ struct test_context { struct tls_multi multi; struct key_type kt; struct user_pass up; - struct tls_session session; + struct tls_session *session; }; /* Dummy functions that do nothing to mock the functionality */ @@ -100,10 +100,11 @@ setup(void **state) } ctx->multi.opt.auth_token_generate = true; ctx->multi.opt.auth_token_lifetime = 3000; + ctx->session = &ctx->multi.session[TM_ACTIVE]; - ctx->session.opt = calloc(1, sizeof(struct tls_options)); - ctx->session.opt->renegotiate_seconds = 120; - ctx->session.opt->auth_token_lifetime = 3000; + ctx->session->opt = calloc(1, sizeof(struct tls_options)); + ctx->session->opt->renegotiate_seconds = 120; + ctx->session->opt->auth_token_lifetime = 3000; strcpy(ctx->up.username, "test user name"); strcpy(ctx->up.password, "ignored"); @@ -122,7 +123,7 @@ teardown(void **state) free_key_ctx(&ctx->multi.opt.auth_token_key); wipe_auth_token(&ctx->multi); - free(ctx->session.opt); + free(ctx->session->opt); free(ctx); return 0; @@ -135,7 +136,7 @@ auth_token_basic_test(void **state) generate_auth_token(&ctx->up, &ctx->multi); strcpy(ctx->up.password, ctx->multi.auth_token); - assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session), + assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session), AUTH_TOKEN_HMAC_OK); } @@ -146,7 +147,7 @@ auth_token_fail_invalid_key(void **state) generate_auth_token(&ctx->up, &ctx->multi); strcpy(ctx->up.password, ctx->multi.auth_token); - assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session), + assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session), AUTH_TOKEN_HMAC_OK); /* Change auth-token key */ @@ -155,13 +156,13 @@ auth_token_fail_invalid_key(void **state) free_key_ctx(&ctx->multi.opt.auth_token_key); init_key_ctx(&ctx->multi.opt.auth_token_key, &key, &ctx->kt, false, "TEST"); - assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session), 0); + assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session), 0); /* Load original test key again */ memset(&key, 0, sizeof(key)); free_key_ctx(&ctx->multi.opt.auth_token_key); init_key_ctx(&ctx->multi.opt.auth_token_key, &key, &ctx->kt, false, "TEST"); - assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session), + assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session), AUTH_TOKEN_HMAC_OK); } @@ -176,32 +177,32 @@ auth_token_test_timeout(void **state) strcpy(ctx->up.password, ctx->multi.auth_token); /* No time has passed */ - assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session), + assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session), AUTH_TOKEN_HMAC_OK); /* Token before validity, should be rejected */ now = 100000 - 100; - assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session), + assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session), AUTH_TOKEN_HMAC_OK|AUTH_TOKEN_EXPIRED); /* Token still in validity, should be accepted */ - now = 100000 + 2*ctx->session.opt->renegotiate_seconds - 20; - assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session), + now = 100000 + 2*ctx->session->opt->renegotiate_seconds - 20; + assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session), AUTH_TOKEN_HMAC_OK); /* Token past validity, should be rejected */ - now = 100000 + 2*ctx->session.opt->renegotiate_seconds + 20; - assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session), + now = 100000 + 2*ctx->session->opt->renegotiate_seconds + 20; + assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session), AUTH_TOKEN_HMAC_OK|AUTH_TOKEN_EXPIRED); /* Check if the mode for a client that never updates its token works */ ctx->multi.auth_token_initial = strdup(ctx->up.password); - assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session), + assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session), AUTH_TOKEN_HMAC_OK); /* But not when we reached our timeout */ - now = 100000 + ctx->session.opt->auth_token_lifetime + 1; - assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session), + now = 100000 + ctx->session->opt->auth_token_lifetime + 1; + assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session), AUTH_TOKEN_HMAC_OK|AUTH_TOKEN_EXPIRED); free(ctx->multi.auth_token_initial); @@ -209,22 +210,22 @@ auth_token_test_timeout(void **state) /* regenerate the token util it hits the expiry */ now = 100000; - while (now < 100000 + ctx->session.opt->auth_token_lifetime + 1) + while (now < 100000 + ctx->session->opt->auth_token_lifetime + 1) { - assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session), + assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session), AUTH_TOKEN_HMAC_OK); generate_auth_token(&ctx->up, &ctx->multi); strcpy(ctx->up.password, ctx->multi.auth_token); - now += ctx->session.opt->renegotiate_seconds; + now += ctx->session->opt->renegotiate_seconds; } - assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session), + assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session), AUTH_TOKEN_HMAC_OK|AUTH_TOKEN_EXPIRED); ctx->multi.opt.auth_token_lifetime = 0; /* Non expiring token should be fine */ - assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session), + assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session), AUTH_TOKEN_HMAC_OK); } @@ -253,7 +254,7 @@ auth_token_test_known_keys(void **state) assert_string_equal(now0key0, ctx->multi.auth_token); strcpy(ctx->up.password, ctx->multi.auth_token); - assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session), + assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session), AUTH_TOKEN_HMAC_OK); } @@ -277,25 +278,25 @@ auth_token_test_empty_user(void **state) generate_auth_token(&ctx->up, &ctx->multi); strcpy(ctx->up.password, ctx->multi.auth_token); - assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session), + assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session), AUTH_TOKEN_HMAC_OK); now = 100000; - assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session), + assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session), AUTH_TOKEN_HMAC_OK|AUTH_TOKEN_EXPIRED); strcpy(ctx->up.username, "test user name"); now = 0; - assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session), + assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session), AUTH_TOKEN_HMAC_OK|AUTH_TOKEN_VALID_EMPTYUSER); strcpy(ctx->up.username, "test user name"); now = 100000; - assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session), + assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session), AUTH_TOKEN_HMAC_OK|AUTH_TOKEN_EXPIRED|AUTH_TOKEN_VALID_EMPTYUSER); zerohmac(ctx->up.password); - assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session), + assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session), 0); } @@ -304,30 +305,32 @@ auth_token_test_env(void **state) { struct test_context *ctx = (struct test_context *) *state; - ctx->multi.auth_token_state_flags = 0; + struct key_state *ks = &ctx->multi.session[TM_ACTIVE].key[KS_PRIMARY]; + + ks->auth_token_state_flags = 0; ctx->multi.auth_token = NULL; - add_session_token_env(&ctx->session, &ctx->multi, &ctx->up); + add_session_token_env(ctx->session, &ctx->multi, &ctx->up); assert_string_equal(lastsesion_statevalue, "Initial"); - ctx->multi.auth_token_state_flags = 0; + ks->auth_token_state_flags = 0; strcpy(ctx->up.password, now0key0); - add_session_token_env(&ctx->session, &ctx->multi, &ctx->up); + add_session_token_env(ctx->session, &ctx->multi, &ctx->up); assert_string_equal(lastsesion_statevalue, "Invalid"); - ctx->multi.auth_token_state_flags = AUTH_TOKEN_HMAC_OK; - add_session_token_env(&ctx->session, &ctx->multi, &ctx->up); + ks->auth_token_state_flags = AUTH_TOKEN_HMAC_OK; + add_session_token_env(ctx->session, &ctx->multi, &ctx->up); assert_string_equal(lastsesion_statevalue, "Authenticated"); - ctx->multi.auth_token_state_flags = AUTH_TOKEN_HMAC_OK|AUTH_TOKEN_EXPIRED; - add_session_token_env(&ctx->session, &ctx->multi, &ctx->up); + ks->auth_token_state_flags = AUTH_TOKEN_HMAC_OK|AUTH_TOKEN_EXPIRED; + add_session_token_env(ctx->session, &ctx->multi, &ctx->up); assert_string_equal(lastsesion_statevalue, "Expired"); - ctx->multi.auth_token_state_flags = AUTH_TOKEN_HMAC_OK|AUTH_TOKEN_VALID_EMPTYUSER; - add_session_token_env(&ctx->session, &ctx->multi, &ctx->up); + ks->auth_token_state_flags = AUTH_TOKEN_HMAC_OK|AUTH_TOKEN_VALID_EMPTYUSER; + add_session_token_env(ctx->session, &ctx->multi, &ctx->up); assert_string_equal(lastsesion_statevalue, "AuthenticatedEmptyUser"); - ctx->multi.auth_token_state_flags = AUTH_TOKEN_HMAC_OK|AUTH_TOKEN_EXPIRED|AUTH_TOKEN_VALID_EMPTYUSER; - add_session_token_env(&ctx->session, &ctx->multi, &ctx->up); + ks->auth_token_state_flags = AUTH_TOKEN_HMAC_OK|AUTH_TOKEN_EXPIRED|AUTH_TOKEN_VALID_EMPTYUSER; + add_session_token_env(ctx->session, &ctx->multi, &ctx->up); assert_string_equal(lastsesion_statevalue, "ExpiredEmptyUser"); } @@ -351,7 +354,7 @@ auth_token_test_random_keys(void **state) assert_string_equal(random_token, ctx->multi.auth_token); strcpy(ctx->up.password, ctx->multi.auth_token); - assert_true(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session)); + assert_true(verify_auth_token(&ctx->up, &ctx->multi, ctx->session)); } @@ -363,11 +366,11 @@ auth_token_test_key_load(void **state) free_key_ctx(&ctx->multi.opt.auth_token_key); auth_token_init_secret(&ctx->multi.opt.auth_token_key, zeroinline, true); strcpy(ctx->up.password, now0key0); - assert_true(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session)); + assert_true(verify_auth_token(&ctx->up, &ctx->multi, ctx->session)); free_key_ctx(&ctx->multi.opt.auth_token_key); auth_token_init_secret(&ctx->multi.opt.auth_token_key, allx01inline, true); - assert_false(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session)); + assert_false(verify_auth_token(&ctx->up, &ctx->multi, ctx->session)); } int diff --git a/release/src/router/openvpn/version.m4 b/release/src/router/openvpn/version.m4 index 66832fcc0a9..bbb6372ae76 100644 --- a/release/src/router/openvpn/version.m4 +++ b/release/src/router/openvpn/version.m4 @@ -3,12 +3,12 @@ define([PRODUCT_NAME], [OpenVPN]) define([PRODUCT_TARNAME], [openvpn]) define([PRODUCT_VERSION_MAJOR], [2]) define([PRODUCT_VERSION_MINOR], [5]) -define([PRODUCT_VERSION_PATCH], [.1]) +define([PRODUCT_VERSION_PATCH], [.2]) m4_append([PRODUCT_VERSION], [PRODUCT_VERSION_MAJOR]) m4_append([PRODUCT_VERSION], [PRODUCT_VERSION_MINOR], [[.]]) m4_append([PRODUCT_VERSION], [PRODUCT_VERSION_PATCH], [[]]) define([PRODUCT_BUGREPORT], [openvpn-users@lists.sourceforge.net]) -define([PRODUCT_VERSION_RESOURCE], [2,5,1,0]) +define([PRODUCT_VERSION_RESOURCE], [2,5,2,0]) dnl define the TAP version define([PRODUCT_TAP_WIN_COMPONENT_ID], [tap0901]) define([PRODUCT_TAP_WIN_MIN_MAJOR], [9]) diff --git a/release/src/router/rc/services.c b/release/src/router/rc/services.c index 9e3c21eb6c6..44032c8a8c1 100644 --- a/release/src/router/rc/services.c +++ b/release/src/router/rc/services.c @@ -175,10 +175,8 @@ void start_cron(void); void start_wlcscan(void); void stop_wlcscan(void); -#ifdef HND_ROUTER void start_jitterentropy(void); void stop_jitterentropy(void); -#endif /* HND_ROUTER */ #ifndef MS_MOVE #define MS_MOVE 8192 @@ -9335,9 +9333,7 @@ start_aura_rgb_sw(void) int start_services(void) { -#ifdef HND_ROUTER start_jitterentropy(); -#endif /* HND_ROUTER */ #if defined(RTAX82U) || defined(DSL_AX82U) || defined(GSAX3000) || defined(GSAX5400) start_ledg(); start_ledbtn(); @@ -9994,12 +9990,9 @@ stop_services(void) #if defined(RTCONFIG_CFEZ) && defined(RTCONFIG_BCMARM) stop_envrams(); #endif -#ifdef HND_ROUTER stop_jitterentropy(); -#endif /* HND_ROUTER */ } -#ifdef HND_ROUTER void start_jitterentropy() { pid_t pid; @@ -10015,7 +10008,6 @@ void stop_jitterentropy() char *cmd_argv[] = { "killall", "jitterentropy-rngd", NULL}; _eval(cmd_argv, NULL, 0, &pid); } -#endif /* HND_ROUTER */ #ifdef RTCONFIG_QCA int stop_wifi_service(void) diff --git a/release/src/router/www/Tools_Sysinfo.asp b/release/src/router/www/Tools_Sysinfo.asp index 3ac458be098..db13943cbee 100644 --- a/release/src/router/www/Tools_Sysinfo.asp +++ b/release/src/router/www/Tools_Sysinfo.asp @@ -68,8 +68,11 @@ function initial(){ showbootTime(); - if (odmpid != "") - document.getElementById("model_id").innerHTML = odmpid; + if (odmpid != "") { + document.getElementById("model_id").innerHTML = "" + odmpid + ""; + if (odmpid != based_modelid) + document.getElementById("model_id").innerHTML += " (base model: " + based_modelid + ")"; + } else document.getElementById("model_id").innerHTML = productid; diff --git a/release/src/router/www/notification.js b/release/src/router/www/notification.js index e6ba7ecbd30..799d5d2ff7d 100644 --- a/release/src/router/www/notification.js +++ b/release/src/router/www/notification.js @@ -250,7 +250,7 @@ var notification = { notification.acpw = 0; if(amesh_support && ameshRouter_support) { - if(aimesh_system_new_fw_flag) { + if(aimesh_system_new_fw_flag || webs_state_flag == 1 || webs_state_flag == 2) { notification.array[1] = 'noti_upgrade'; notification.upgrade = 1; notification.desc[1] = '<#ASUSGATE_note2#>';