From cb8c15a231a9a8e49d6654a7d599fe9152159ae8 Mon Sep 17 00:00:00 2001
From: Toni Uhlig <matzeton@googlemail.com>
Date: Sat, 13 Jul 2019 17:59:42 +0200
Subject: SHA512 challenge response authentication

Signed-off-by: Toni Uhlig <matzeton@googlemail.com>
---
 README          |  2 +-
 README.md       |  2 +-
 configure.ac    | 17 +++++++++++++++++
 src/Makefile.am |  4 ++++
 src/challenge.c | 22 ++++++++++++++++++----
 src/options.c   | 23 ++++++-----------------
 src/options.h   |  2 --
 src/pkt.c       | 24 +++++++++++++++++++-----
 8 files changed, 66 insertions(+), 30 deletions(-)

diff --git a/README b/README
index c11df67..ee90c2a 100644
--- a/README
+++ b/README
@@ -123,7 +123,7 @@ installed.
 
 TODOs
 -----
-- challenge response: switch from md5 to sha-512 (WiP)
+- challenge response: switch from md5 to sha-512 (testing)
 - packet obfuscation
 - encryption (metadata + payload)
 
diff --git a/README.md b/README.md
index 5efc35c..11d8a7e 100644
--- a/README.md
+++ b/README.md
@@ -141,7 +141,7 @@ installed.
 
 ## TODOs
 ```
-- challenge response: switch from md5 to sha-512 (WiP)
+- challenge response: switch from md5 to sha-512 (testing)
 - packet obfuscation
 - encryption (metadata + payload)
 ```
diff --git a/configure.ac b/configure.ac
index 457497f..239a78b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -128,6 +128,16 @@ case ${pcap_enabled} in
 	*) AC_MSG_ERROR([Unknown option \`${pcap_enabled}\` for --disable-pcap]) ;;
 esac
 
+dnl `--disable-ssl`: Enabled if found.
+AC_ARG_ENABLE([ssl],
+    [AS_HELP_STRING([--disable-ssl], [Disable ssl support. (default: enabled if found)])],,[ssl_enabled=yes])
+ssl_enabled=$(echo ${ssl_enabled})
+case ${ssl_enabled} in
+    1|y|yes) ssl_enabled=yes ;;
+    ''|0|n|no) ssl_enabled= ;;
+    *) AC_MSG_ERROR([Unknown option \`${ssl_enabled}\' for --disable-ssl]) ;;
+esac
+
 dnl `--enable-npcap`: Enable npcap interface (Windows only!)
 AC_ARG_ENABLE([npcap],
     [AS_HELP_STRING([--enable-npcap], [Enable npcap support. (Windows only; default: disabled)])],[npcap_enabled=yes],)
@@ -175,6 +185,12 @@ if test x"${pcap_enabled}" != x -a \
 	    [pcap_enabled=])
 fi
 
+dnl Check openssl headers/functions.
+if test x"${ssl_enabled}" != x; then
+    AC_CHECK_HEADERS([openssl/sha.h],,[ssl_enabled=])
+    AC_SEARCH_LIBS([CRYPTO_new_ex_data],[crypto],,[ssl_enabled=])
+fi
+
 dnl Check for more secure randomization functions
 if test x"${use_customrng}" != xyes; then
 	AC_CHECK_HEADERS([bsd/stdlib.h],,)
@@ -213,6 +229,7 @@ AC_SEARCH_LIBS([__android_log_vprint], [log],,,)
 
 dnl Set automake conf vars
 AM_CONDITIONAL([HAVE_PCAP], [test x"${pcap_enabled}" = xyes])
+AM_CONDITIONAL([ENABLE_SHA512], [test x"${ssl_enabled}" = xyes])
 AM_CONDITIONAL([HAVE_NPCAP], [test x"${npcap_enabled}" = xyes])
 AM_CONDITIONAL([HAVE_SELINUX], [test x"${selinux_enabled}" = xyes])
 AM_CONDITIONAL([IS_WINDOWS], [test x"${use_msw}" = xyes])
diff --git a/src/Makefile.am b/src/Makefile.am
index 552c894..6f9ca23 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -10,6 +10,10 @@ if HAVE_PCAP
 ptunnel_ng_CFLAGS += -DHAVE_PCAP=1
 endif
 
+if ENABLE_SHA512
+ptunnel_ng_CFLAGS += -DENABLE_SHA512=1
+endif
+
 if HAVE_SELINUX
 ptunnel_ng_CFLAGS += -DHAVE_SELINUX=1
 endif
diff --git a/src/challenge.c b/src/challenge.c
index f0b02ad..d12beea 100644
--- a/src/challenge.c
+++ b/src/challenge.c
@@ -109,13 +109,27 @@ int validate_challenge_md5(challenge_t *local, challenge_digest_t *remote) {
 }
 
 #ifdef ENABLE_SHA512
-void generate_response_sha512(challenge_t *challenge)
+void generate_response_sha512(challenge_plain_t *plain, challenge_digest_t *digest)
 {
-    /* TODO: Implement me! */
+    unsigned char buf[sizeof(*plain) + kSHA512_digest_size];
+
+    digest->hash_type = HT_SHA512;
+	memcpy(buf, plain, sizeof(*plain));
+	memcpy(&buf[sizeof(*plain)], opts.sha512_password_digest, kSHA512_digest_size);
+	memset(plain, 0, sizeof(*plain));
+
+    SHA512(buf, sizeof(*plain) + kSHA512_digest_size, &digest->sha512[0]);
 }
 
-int validate_challenge_sha512(challenge_t *local, challenge_t *remote)
+int validate_challenge_sha512(challenge_t *local, challenge_digest_t *remote)
 {
-	/* TODO: Implement me! */
+    generate_response_sha512(&local->plain, &local->digest);
+
+    if (remote->hash_type == HT_SHA512 &&
+        memcmp(&local->digest.sha512[0], &remote->sha512[0], sizeof(local->digest.sha512)) == 0)
+    {
+        return 1;
+    }
+    return 0;
 }
 #endif /* ENABLE_SHA512 */
diff --git a/src/options.c b/src/options.c
index 10838ad..ee8e249 100644
--- a/src/options.c
+++ b/src/options.c
@@ -172,13 +172,6 @@ static const struct option_usage usage[] = {
 		"Tune the number of empty pings to send with each explicit acknowledgement.\n"
 		"Empty pings can compensate for ICMP sequence number inspection.\n"
 	},
-	/** --force-md5 */
-	{"force-md5",    0, OPT_BOOL,   {.num = 0},
-		"Force MD5 as challenge response checksum generator.\n"
-#ifndef ENABLE_SHA512
-		"This is the default for this configuration.\n"
-#endif
-	},
 	/** --force-sha512 */
 	{"force-sha512", 0, OPT_BOOL,   {.num = 0},
 		"Force SHA512 as challenge response checksum generator.\n"
@@ -256,7 +249,6 @@ static struct option long_options[] = {
 	{"resend-interval", required_argument, 0, 't'},
 	{"payload-size", required_argument, 0, 'y'},
 	{"empty-pings", required_argument, 0, 'E'},
-	{"force-md5",         no_argument, &opts.force_md5, 1},
 	{"force-sha512",      no_argument, &opts.force_sha512, 1},
 	{"daemon",      optional_argument, 0, 'd'},
 	{"syslog",            no_argument, 0, 'S'},
@@ -522,14 +514,14 @@ int parse_options(int argc, char **argv) {
 				pt_log(kLog_debug, "%s\n", "Password set - unauthenicated connections will be refused.");
 				/* Compute the md5 password digest */
 				md5_init(&state);
-				md5_append(&state, (md5_byte_t*)optarg, strnlen(opts.password, BUFSIZ /* not optimal */));
+				md5_append(&state, (md5_byte_t *)optarg, strnlen(opts.password, BUFSIZ /* not optimal */));
 				md5_finish(&state, &opts.md5_password_digest[0]);
-				//  Hide the password in process listing
-				memset(optarg, '*', strnlen(optarg, BUFSIZ /* not optimal */));
 #ifdef ENABLE_SHA512
 				pt_log(kLog_debug, "%s\n", "Password set - sha512 authentication enabled.");
-				SHA512(optarg, strnlen(opts.password, BUFSIZ /* not optimal */), &opts.sha512_password_digest[0]);
+				SHA512((const unsigned char *)optarg, strnlen(opts.password, BUFSIZ /* not optimal */), &opts.sha512_password_digest[0]);
 #endif
+				//  Hide the password in process listing
+				memset(optarg, '*', strnlen(optarg, BUFSIZ /* not optimal */));
 				break;
 #ifndef WIN32
 			case 'd':
@@ -634,13 +626,10 @@ int parse_options(int argc, char **argv) {
 		exit(1);
 	}
 
-#if ENABLE_SHA512
-	if (opts.force_md5) {
-		pt_log(kLog_error, "%s\n", "You are forcing md5 but sha512 is available.");
-	}
-#else
+#ifndef ENABLE_SHA512
 	if (opts.force_sha512) {
 		pt_log(kLog_error, "%s\n", "You are forcing sha512 but it isn't available.");
+		return 1;
 	}
 #endif
 
diff --git a/src/options.h b/src/options.h
index 5551426..b950d70 100644
--- a/src/options.h
+++ b/src/options.h
@@ -75,8 +75,6 @@ struct options {
 	/** Device to capture packets from */
 	char *pcap_device;
 #endif
-	/** Force MD5 based challenge response. */
-	int force_md5;
 	/** Force SHA512 based challenge response. */
 	int force_sha512;
 	/** List all available pcap devices and exit */
diff --git a/src/pkt.c b/src/pkt.c
index bc87720..fd4614f 100644
--- a/src/pkt.c
+++ b/src/pkt.c
@@ -235,8 +235,17 @@ void handle_packet(char *buf, unsigned bytes, int is_pcap, struct sockaddr_in *a
 							cur->should_remove  = 1;
 							return;
 						}
-						pt_log(kLog_debug, "Got authentication challenge - sending response\n");
-						generate_response_md5(&challenge->plain, &challenge->digest);
+#ifdef ENABLE_SHA512
+						if (opts.force_sha512) {
+							pt_log(kLog_debug, "Got authentication challenge - sending SHA512 response\n");
+							generate_response_sha512(&challenge->plain, &challenge->digest);
+						} else
+#endif
+						{
+							pt_log(kLog_debug, "Got authentication challenge - sending MD5 response\n");
+							generate_response_md5(&challenge->plain, &challenge->digest);
+						}
+
 						queue_packet(icmp_sock, cur->pkt_type, (char*)challenge,
 						             sizeof(challenge_t), cur->id_no, cur->icmp_id,
 						             &cur->my_seq, cur->send_ring, &cur->send_idx,
@@ -253,9 +262,14 @@ void handle_packet(char *buf, unsigned bytes, int is_pcap, struct sockaddr_in *a
 					}
 					/* If proxy: Handle client's response to challenge */
 					else if (type_flag == proxy_flag) {
-						pt_log(kLog_debug, "Received remote challenge response.\n");
-						if (validate_challenge_md5(cur->challenge, &challenge->digest) ||
-						                           cur->authenticated)
+						pt_log(kLog_debug, "Received remote %s challenge response.\n",
+						                   (challenge->digest.hash_type == HT_SHA512 ?
+						                    "SHA512" : "MD5"));
+						if ((!opts.force_sha512 && challenge->digest.hash_type == HT_MD5 &&
+						     validate_challenge_md5(cur->challenge, &challenge->digest)) ||
+						    (challenge->digest.hash_type == HT_SHA512 &&
+						     validate_challenge_sha512(cur->challenge, &challenge->digest)) ||
+						    cur->authenticated)
 						{
 							pt_log(kLog_verbose, "Remote end authenticated successfully.\n");
 							handle_extended_options(cur);
-- 
cgit v1.2.3