From e87f0e84eeea14ca5921d037ede0c2d1209b6ddf Mon Sep 17 00:00:00 2001 From: xvzcf Date: Mon, 7 Jun 2021 13:57:12 -0400 Subject: [PATCH 1/2] oqs-test/try_connection.py tests what is in the README. --- README.md | 83 ++++++++++---------------------------- oqs-test/try_connection.py | 7 +++- ssh-oqs.c | 39 +++++++++++++----- 3 files changed, 57 insertions(+), 72 deletions(-) diff --git a/README.md b/README.md index 25a5358312e..a3dc94e942a 100644 --- a/README.md +++ b/README.md @@ -112,61 +112,39 @@ On **Ubuntu**, you need to install the following packages: On **Linux**, you also may need to do the following: -- You may need to create the privilege separation directory: +- Create the privilege separation directory: sudo mkdir -p -m 0755 /var/empty -- You may need to create the privilege separation user: +- Create the privilege separation user: sudo groupadd sshd sudo useradd -g sshd -c 'sshd privsep' -d /var/empty -s /bin/false sshd -On **macOS**, you need to install the following packages using brew (or a package manager of your choice): - - brew install autoconf automake cmake libtool ninja openssl@1.1 wget - ### Step 1: Build and install liboqs -The following instructions install liboqs into a subdirectory inside the OpenSSH source. If `` is the root of the OpenSSH source: +The following instructions install liboqs into a subdirectory inside the OpenSSH source. ``` -git clone --branch master --single-branch --depth 1 https://github.com/open-quantum-safe/liboqs.git -cd liboqs -mkdir build && cd build -cmake .. -GNinja -DOQS_ENABLE_SIG_PICNIC=OFF -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DCMAKE_INSTALL_PREFIX=/oqs -ninja -ninja install +./oqs-scripts/clone_liboqs.sh +./oqs-scripts/build_liboqs.sh ``` -Building liboqs requires your system to have OpenSSL 1.1.1 or higher already installed. It will automatically be detected if it in a standard location, such as `/usr` or `/usr/local/opt/openssl@1.1` (for brew on macOS). Otherwise, you may need to specify it with `-DOPENSSL_ROOT_DIR=` added to the `cmake` command. +Building liboqs requires your system to have OpenSSL 1.1.1 or higher already installed. It will automatically be detected if it is under `/usr` or another standard location. Otherwise, you may need to specify it with `-DOPENSSL_ROOT_DIR=` added to the `cmake` command. ### Step 2: Build the fork -In ``, first run: +Run the following: ``` -export OPENSSH_INSTALL= -autoreconf +env OPENSSL_SYS_DIR= ./oqs-scripts/build_openssh.sh ``` -Then, run the following: - - ./configure --with-ssl-dir=/include \ - --with-ldflags=-L/lib \ - --with-libs=-lm \ - --prefix=$OPENSSH_INSTALL \ - --sysconfdir=$OPENSSH_INSTALL \ - --with-liboqs-dir=`pwd`/oqs - make - make install +`OPENSSL_SYS_DIR` does not have to be specified if OpenSSL is present under `usr/`. -Again, the `path-to-openssl` (1.1.1) does not need to be specified if it is in one of the standard locations. +As not all tests in the stock regression suite pass, run `oqs-test/run_tests.sh` instead of simply executing `make tests` to ensure the build was successful. -So, in summary, if OpenSSL is installed in a default location and `oqs-openssh` is to be installed in `/opt/openssh` this command builds and installs `oqs-openssh`: `export OPENSSH_INSTALL=/opt/openssh && autoreconf && ./configure --with-libs=-lm --prefix=$OPENSSH_INSTALL --sysconfdir=$OPENSSH_INSTALL --with-liboqs-dir=`pwd`/oqs && make && make install` - -As not all stock `openssh` tests are passing, be sure to execute `oqs-test/run_tests.sh` instead of simply executing `make tests` to ensure the build was successful. - -To execute a connection test with one of the supported quantum-safe algorithms (chosen at random), run `python3 oqs-test/try_connection.py`. If all algorithms should be exercized, pass a parameter to this command, e.g., like this: `python3 oqs-test/try_connection.py all`. Be aware that this test can take a long time due to the number of algorithm combinations available. +To execute a connection test with a randomly chosen key-exchange and signature algorithm, run `python3 oqs-test/try_connection.py`. If it is desired that all such combinations should be tested, run `python3 oqs-test/try_connection.py all`. Be aware that this test can take a long time due to the number of algorithm combinations available. ### Running OQS-OpenSSH @@ -174,53 +152,34 @@ The following instructions explain how to establish an SSH connection that uses #### Generating quantum-safe authentication keys -To setup quantum-safe authentication, the server (and optionally, the client) need to generate quantum-safe keys. In what follows, `` is one of the quantum-safe digital signature algorithms listed in [Supported Algorithms](#supported-algorithms) section above. - -The server generates its key files with the right permissions, and then generates its key pair: - - mkdir ~/ssh_server/ - chmod 700 ~/ssh_server/ - touch ~/ssh_server/authorized_keys - chmod 600 ~/ssh_server/authorized_keys - /bin/ssh-keygen -t ssh- -f ~/ssh_server/id_ - -To enable client-side public-key authentication, the client generates its key pair: - - mkdir ~/ssh_client/ - /bin/ssh-keygen -t ssh- -f ~/ssh_client/id_ - -The server then adds the client's public key to its authorized keys - - cat ~/ssh_client/id_.pub >> ~/ssh_server/authorized_keys +To setup quantum-safe authentication, the server (and optionally, the client) need to generate quantum-safe keys. To generate keys for all the OQS algorithms supported by fork, simply run `make tests -e LTESTS=""`. #### Establishing a quantum-safe SSH connection -In one terminal, run a server: +In one terminal, run the ssh server: - /sbin/sshd -p 2222 -d \ + /sbin/sshd -D \ + -f /regress/sshd_config \ -o KexAlgorithms= \ - -o AuthorizedKeysFile=/ssh_server/authorized_keys \ -o HostKeyAlgorithms=ssh- \ -o PubkeyAcceptedKeyTypes=ssh- \ - -h /ssh_server/id_ + -h /regress/host. `` and `` are respectively one of the key exchange and signature (PQ-only or hybrid) algorithms listed in the [Supported Algorithms](#supported-algorithms) section above. The `-o` options can also be added to the server/client configuration file instead of being specified on the command line. -The server automatically supports all available hybrid and PQ-only key exchange algorithms. `sudo` is required on Linux so that sshd can read the shadow password file. - -In another terminal, run a client: +In another terminal, run the ssh client: - /bin/ssh -p 2222 localhost \ + /bin/ssh -F /regress/ssh_config \ -o KexAlgorithms= \ -o HostKeyAlgorithms=ssh-\ -o PubkeyAcceptedKeyTypes=ssh- \ - -o StrictHostKeyChecking=no \ -o PasswordAuthentication=no \ - -i ~/ssh_client/id_ + -i regress/ \ + somehost true -The `StrictHostKeyChecking` option is used to allow trusting the newly generated server key; alternatively, the key could be added manually to the client's trusted keys. The `PasswordAuthentication` option is used to ensure the test server does not fall back to password authentication if public key authentication fails for some reason. +The `PasswordAuthentication` option is used to ensure the test server does not fall back to password authentication if public key authentication fails for some reason. ## Contributing diff --git a/oqs-test/try_connection.py b/oqs-test/try_connection.py index 817356e6745..4aad03a8df0 100644 --- a/oqs-test/try_connection.py +++ b/oqs-test/try_connection.py @@ -156,10 +156,12 @@ ] def do_handshake(ssh, sshd, test_sig, test_kex): - sshd_process = subprocess.Popen([sshd, + sshd_process = subprocess.Popen([sshd, '-f', os.path.abspath('regress/sshd_config'), "-o", "KexAlgorithms={}".format(test_kex), "-o", "HostKeyAlgorithms={}".format(test_sig), + "-o", "PubkeyAcceptedKeyTypes={}".format(test_sig), + "-h", os.path.abspath("regress/host.{}".format(test_sig)), '-D'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) @@ -171,6 +173,9 @@ def do_handshake(ssh, sshd, test_sig, test_kex): ssh_process = subprocess.run([ssh, '-F', os.path.abspath('regress/ssh_config'), "-o", "HostKeyAlgorithms={}".format(test_sig), + "-o", "PubkeyAcceptedKeyTypes={}".format(test_sig), + "-o", "PasswordAuthentication=no", + "-i", os.path.abspath("regress/{}".format(test_sig)), 'somehost', 'true'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) diff --git a/ssh-oqs.c b/ssh-oqs.c index 9ce6286ef58..d3a7886a827 100644 --- a/ssh-oqs.c +++ b/ssh-oqs.c @@ -47,6 +47,8 @@ static int ssh_generic_sign(OQS_SIG *oqs_sig, size_t slen = 0, len; int r; struct sshbuf *b = NULL; + struct sshbuf *ssh_algname = NULL; + char *ssh_algname_str = NULL; if (lenp != NULL) *lenp = 0; @@ -72,8 +74,16 @@ static int ssh_generic_sign(OQS_SIG *oqs_sig, goto out; } - if ((r = sshbuf_put_cstring(b, "ssh-")) != 0 || - (r = sshbuf_put_cstring(b, alg_pretty_name)) != 0 || + if ((ssh_algname = sshbuf_new()) == NULL) { + r = SSH_ERR_ALLOC_FAIL; + goto out; + } + if ((r = sshbuf_putf(ssh_algname, "%s-%s", "ssh", alg_pretty_name)) != 0 || + (ssh_algname_str = sshbuf_dup_string(ssh_algname)) == NULL) { + goto out; + } + + if ((r = sshbuf_put_cstring(b, ssh_algname_str)) != 0 || (r = sshbuf_put_string(b, sig, slen)) != 0) goto out; @@ -93,6 +103,8 @@ static int ssh_generic_sign(OQS_SIG *oqs_sig, out: sshbuf_free(b); + sshbuf_free(ssh_algname); + free(ssh_algname_str); if (sig != NULL) freezero(sig, slen); return r; @@ -108,8 +120,9 @@ static int ssh_generic_verify(OQS_SIG *oqs_sig, u_int compat) { struct sshbuf *b = NULL; - char *ktype = NULL; - char *algnameprefix = NULL; + char *algname = NULL; + struct sshbuf *algname_expected = NULL; + char *algname_expected_str = NULL; const u_char *sigblob; size_t slen; int r; @@ -122,13 +135,20 @@ static int ssh_generic_verify(OQS_SIG *oqs_sig, if ((b = sshbuf_from(signature, signaturelen)) == NULL) return SSH_ERR_ALLOC_FAIL; - if ((r = sshbuf_get_cstring(b, &algnameprefix, NULL)) != 0 || - (r = sshbuf_get_cstring(b, &ktype, NULL)) != 0 || + if ((r = sshbuf_get_cstring(b, &algname, NULL)) != 0 || (r = sshbuf_get_string_direct(b, &sigblob, &slen)) != 0) goto out; - if ((strcmp("ssh-", algnameprefix) != 0) || - (strcmp(alg_pretty_name, ktype) != 0)) { + if ((algname_expected = sshbuf_new()) == NULL) { + r = SSH_ERR_ALLOC_FAIL; + goto out; + } + if ((r = sshbuf_putf(algname_expected, "%s-%s", "ssh", alg_pretty_name)) != 0 || + (algname_expected_str = sshbuf_dup_string(algname_expected)) == NULL) { + goto out; + } + + if (strcmp(algname, algname_expected_str) != 0) { r = SSH_ERR_KEY_TYPE_MISMATCH; goto out; } @@ -152,7 +172,8 @@ static int ssh_generic_verify(OQS_SIG *oqs_sig, out: sshbuf_free(b); - free(ktype); + sshbuf_free(algname_expected); + free(algname_expected_str); return r; } From 05b0bccdf0f807479ad1a2e47408611d13b5f06a Mon Sep 17 00:00:00 2001 From: xvzcf Date: Tue, 8 Jun 2021 08:56:26 -0400 Subject: [PATCH 2/2] Review comments. --- README.md | 38 ++++++++++++++++++++++-------------- oqs-scripts/build_openssh.sh | 6 +++--- 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index a3dc94e942a..a4edee30371 100644 --- a/README.md +++ b/README.md @@ -140,11 +140,11 @@ Run the following: env OPENSSL_SYS_DIR= ./oqs-scripts/build_openssh.sh ``` -`OPENSSL_SYS_DIR` does not have to be specified if OpenSSL is present under `usr/`. +`OPENSSL_SYS_DIR` does not have to be specified if OpenSSL is present under `/usr`. As not all tests in the stock regression suite pass, run `oqs-test/run_tests.sh` instead of simply executing `make tests` to ensure the build was successful. -To execute a connection test with a randomly chosen key-exchange and signature algorithm, run `python3 oqs-test/try_connection.py`. If it is desired that all such combinations should be tested, run `python3 oqs-test/try_connection.py all`. Be aware that this test can take a long time due to the number of algorithm combinations available. +To execute a connection test with a randomly chosen key-exchange and signature algorithm, run `python3 oqs-test/try_connection.py`. If it is desired that each such combination be tested (exactly once), run `python3 oqs-test/try_connection.py all`. Be aware that the latter can take a long time due to the number of algorithm combinations available. ### Running OQS-OpenSSH @@ -154,16 +154,22 @@ The following instructions explain how to establish an SSH connection that uses To setup quantum-safe authentication, the server (and optionally, the client) need to generate quantum-safe keys. To generate keys for all the OQS algorithms supported by fork, simply run `make tests -e LTESTS=""`. +Keys for a particular `` also be generated using the `ssh-keygen` command as follows: + +`/ssh-keygen -t ssh- -f ~/ssh_client/id_` + #### Establishing a quantum-safe SSH connection +Let `` denote the absolute path to the directory in which this source is present. + In one terminal, run the ssh server: - /sbin/sshd -D \ - -f /regress/sshd_config \ - -o KexAlgorithms= \ - -o HostKeyAlgorithms=ssh- \ - -o PubkeyAcceptedKeyTypes=ssh- \ - -h /regress/host. + /sshd -D \ + -f /regress/sshd_config \ + -o KexAlgorithms= \ + -o HostKeyAlgorithms=ssh- \ + -o PubkeyAcceptedKeyTypes=ssh- \ + -h /regress/host.ssh- `` and `` are respectively one of the key exchange and signature (PQ-only or hybrid) algorithms listed in the [Supported Algorithms](#supported-algorithms) section above. @@ -171,16 +177,18 @@ The `-o` options can also be added to the server/client configuration file inste In another terminal, run the ssh client: - /bin/ssh -F /regress/ssh_config \ - -o KexAlgorithms= \ - -o HostKeyAlgorithms=ssh-\ - -o PubkeyAcceptedKeyTypes=ssh- \ - -o PasswordAuthentication=no \ - -i regress/ \ - somehost true + /ssh -F /regress/ssh_config \ + -o KexAlgorithms= \ + -o HostKeyAlgorithms=ssh-\ + -o PubkeyAcceptedKeyTypes=ssh- \ + -o PasswordAuthentication=no \ + -i regress/ssh- \ + somehost true The `PasswordAuthentication` option is used to ensure the test server does not fall back to password authentication if public key authentication fails for some reason. +The -o options can also be added to the `regress/{ssh|sshd}_config` client/server configuration files instead of being specified on the command line. + ## Contributing Contributions are gratefully welcomed. See our [Contributing Guide](https://github.com/open-quantum-safe/openssh-portable/wiki/Contributing-Guide) for more details. diff --git a/oqs-scripts/build_openssh.sh b/oqs-scripts/build_openssh.sh index b0dc39bc1c0..fee22281414 100755 --- a/oqs-scripts/build_openssh.sh +++ b/oqs-scripts/build_openssh.sh @@ -8,7 +8,7 @@ set -exo pipefail -PREFIX=${PREFIX:-"`pwd`/oqs-test/tmp"} +INSTALL_PREFIX=${INSTALL_PREFIX:-"`pwd`/oqs-test/tmp"} WITH_OPENSSL=${WITH_OPENSSL:-"true"} case "$OSTYPE" in @@ -24,9 +24,9 @@ else fi if [ "x${WITH_OPENSSL}" == "xtrue" ]; then - ./configure --prefix="${PREFIX}" --with-ldflags="-Wl,-rpath -Wl,${PREFIX}/lib" --with-libs=-lm --with-ssl-dir="${OPENSSL_SYS_DIR}" --with-liboqs-dir="`pwd`/oqs" --with-cflags="-Wno-implicit-function-declaration -I${PREFIX}/include" --sysconfdir="${PREFIX}" + ./configure --prefix="${INSTALL_PREFIX}" --with-ldflags="-Wl,-rpath -Wl,${INSTALL_PREFIX}/lib" --with-libs=-lm --with-ssl-dir="${OPENSSL_SYS_DIR}" --with-liboqs-dir="`pwd`/oqs" --with-cflags="-Wno-implicit-function-declaration -I${INSTALL_PREFIX}/include" --sysconfdir="${INSTALL_PREFIX}" else - ./configure --prefix="${PREFIX}" --with-ldflags="-Wl,-rpath -Wl,${PREFIX}/lib" --with-libs=-lm --without-openssl --with-liboqs-dir="`pwd`/oqs" --with-cflags="-I${PREFIX}/include" --sysconfdir="${PREFIX}" + ./configure --prefix="${INSTALL_PREFIX}" --with-ldflags="-Wl,-rpath -Wl,${INSTALL_PREFIX}/lib" --with-libs=-lm --without-openssl --with-liboqs-dir="`pwd`/oqs" --with-cflags="-I${INSTALL_PREFIX}/include" --sysconfdir="${INSTALL_PREFIX}" fi if [ "x${CIRCLECI}" == "xtrue" ] || [ "x${TRAVIS}" == "xtrue" ]; then make -j2