Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

oqs-test/try_connection.py tests what is in the README. #103

Merged
merged 2 commits into from
Jun 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 33 additions & 66 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,115 +112,82 @@ 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 `<OPENSSH_ROOT>` 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=<OPENSSH_ROOT>/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=<path-to-system-openssl-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=<path-to-system-openssl-dir>` added to the `cmake` command.

### Step 2: Build the fork

In `<OPENSSH_ROOT>`, first run:
Run the following:

```
export OPENSSH_INSTALL=<path-to-install-openssh>
autoreconf
env OPENSSL_SYS_DIR=<PATH_TO_OPENSSL> ./oqs-scripts/build_openssh.sh
```

Then, run the following:

./configure --with-ssl-dir=<path-to-openssl>/include \
--with-ldflags=-L<path-to-openssl>/lib \
--with-libs=-lm \
--prefix=$OPENSSH_INSTALL \
--sysconfdir=$OPENSSH_INSTALL \
--with-liboqs-dir=`pwd`/oqs
make
make install

Again, the `path-to-openssl` (1.1.1) does not need to be specified if it is in one of the standard locations.

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`
`OPENSSL_SYS_DIR` does not have to be specified if OpenSSL is present under `/usr`.

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.
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 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 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

The following instructions explain how to establish an SSH connection that uses quantum-safe key exchange and authentication.

#### 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, `<SIG>` is one of the quantum-safe digital signature algorithms listed in [Supported Algorithms](#supported-algorithms) section above.
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=""`.

The server generates its key files with the right permissions, and then generates its key pair:
Keys for a particular `<SIG>` also be generated using the `ssh-keygen` command as follows:

mkdir ~/ssh_server/
chmod 700 ~/ssh_server/
touch ~/ssh_server/authorized_keys
chmod 600 ~/ssh_server/authorized_keys
<path-to-openssh>/bin/ssh-keygen -t ssh-<SIG> -f ~/ssh_server/id_<SIG>

To enable client-side public-key authentication, the client generates its key pair:

mkdir ~/ssh_client/
<path-to-openssh>/bin/ssh-keygen -t ssh-<SIG> -f ~/ssh_client/id_<SIG>

The server then adds the client's public key to its authorized keys

cat ~/ssh_client/id_<SIG>.pub >> ~/ssh_server/authorized_keys
`<OPENSSH_SRC>/ssh-keygen -t ssh-<SIG> -f ~/ssh_client/id_<SIG>`

#### Establishing a quantum-safe SSH connection

In one terminal, run a server:
Let `<OPENSSH_SRC>` denote the absolute path to the directory in which this source is present.

In one terminal, run the ssh server:

<path-to-openssh>/sbin/sshd -p 2222 -d \
-o KexAlgorithms=<KEX> \
-o AuthorizedKeysFile=<absolute-path-to>/ssh_server/authorized_keys \
-o HostKeyAlgorithms=ssh-<SIG> \
-o PubkeyAcceptedKeyTypes=ssh-<SIG> \
-h <absolute-path-to>/ssh_server/id_<SIG>
<OPENSSH_SRC>/sshd -D \
-f <OPENSSH_SRC>/regress/sshd_config \
-o KexAlgorithms=<KEX> \
-o HostKeyAlgorithms=ssh-<SIG> \
-o PubkeyAcceptedKeyTypes=ssh-<SIG> \
-h <OPENSSH_SRC>/regress/host.ssh-<SIG>

`<KEX>` and `<SIG>` 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 the ssh client:

In another terminal, run a client:
<OPENSSH_SRC>/ssh -F <OPENSSH_SRC>/regress/ssh_config \
-o KexAlgorithms=<KEX> \
-o HostKeyAlgorithms=ssh-<SIG>\
-o PubkeyAcceptedKeyTypes=ssh-<SIG> \
-o PasswordAuthentication=no \
-i regress/ssh-<SIG> \
somehost true

<path-to-openssh>/bin/ssh -p 2222 localhost \
-o KexAlgorithms=<KEX> \
-o HostKeyAlgorithms=ssh-<SIG>\
-o PubkeyAcceptedKeyTypes=ssh-<SIG> \
-o StrictHostKeyChecking=no \
-o PasswordAuthentication=no \
-i ~/ssh_client/id_<SIG>
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 `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 -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

Expand Down
6 changes: 3 additions & 3 deletions oqs-scripts/build_openssh.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
7 changes: 6 additions & 1 deletion oqs-test/try_connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
Expand Down
39 changes: 30 additions & 9 deletions ssh-oqs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;

Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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;
}
Expand All @@ -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;
}

Expand Down