From ad933c652e5b721fb63f64a365297d690cc8ee2f Mon Sep 17 00:00:00 2001 From: gcr Date: Tue, 23 Jul 2024 13:12:46 +0000 Subject: [PATCH] Implement Hybrid SSH Keys This finishes the work in PR #160 which applied the upstream `sshkey.c` refactor to the OQS fork by adding support for hybrid SSH keys. More importantly, this brings the `OQS-v9` branch up to parity with `OQS-v8` in terms of supported algorithms and functionality. Therefore, we can do more in depth and thorough validation to increase confidence in cutting over to this newer branch. Speaking to the code changes for hybrid SSH key support, this works by adding logic to `ssh-oqs` which branches on hybrid SSH key implementations to handle the classical portion of the key and combine it with the PQ portion as-appropriate. The main trick is to introduce a small lookup table for the RSA/ECDSA implementation and exposing the symbols to `ssh-oqs` via an extern declaration. One notable oddity is that upstream OpenSSH multiplexes the underlying EC curves by placing a generic implementation behind the P-256 struct and allowing the implementation to fork based on the `bits` or `key->type` parameters. Depending on the context, this is how `sshkey` does things so I followed their convention. Related to issue #135 Asserted that Circle CI jobs pass. These tests run through a subset of the OpenSSH unit tests that have been documented to pass against the OQS fork and skip tests that depend on missing/broken functionality. This demonstrates internal consistency and parity with the testing bar set by `OQS-v8`. Performed interop testing between `OQS-v8` and `OQS-v9` to assert that we have no regressions from pulling in 2 years of upstream changes and re-implementing PQ+Hybrid SSH Keys. This was done by modifying `try_connection.py` which tests all PQ+Hybrid signatures and key exchanges by connecting the built SSH client to the SSHD server and explicitly specifying each algorithm. By adding CLI flags to override this test to use an SSH or SSHD binary from somewhere else, we can perform thorough interop testing between an `OQS-v8` server and `OQS-v9` client or vice versa. Detailed process/commands outlined below. ``` git clone git@github.com:open-quantum-safe/openssh.git oqs-openssh-clean cd oqs-openssh-clean git checkout OQS-v8 ./oqs-scripts/clone_liboqs.sh ./oqs-scripts/build_liboqs.sh ./oqs-scripts/build_openssh.sh python3 oqs-test/try_connection.py --sshd `readlink -f ../oqs-openssh-clean/sshd` doall Success! Key Exchange Algorithm: frodokem-640-aes-sha256. Signature Algorithm: ssh-falcon512. Success! Key Exchange Algorithm: frodokem-640-aes-sha256. Signature Algorithm: ssh-rsa3072-falcon512. Success! Key Exchange Algorithm: frodokem-640-aes-sha256. Signature Algorithm: ssh-ecdsa-nistp256-falcon512. Success! Key Exchange Algorithm: frodokem-640-aes-sha256. Signature Algorithm: ssh-falcon1024. Success! Key Exchange Algorithm: frodokem-640-aes-sha256. Signature Algorithm: ssh-ecdsa-nistp521-falcon1024. Success! Key Exchange Algorithm: frodokem-640-aes-sha256. Signature Algorithm: ssh-dilithium2. ... python3 oqs-test/try_connection.py --ssh `readlink -f ../oqs-openssh-clean/ssh` doall Success! Key Exchange Algorithm: frodokem-640-aes-sha256. Signature Algorithm: ssh-falcon512. Success! Key Exchange Algorithm: frodokem-640-aes-sha256. Signature Algorithm: ssh-rsa3072-falcon512. Success! Key Exchange Algorithm: frodokem-640-aes-sha256. Signature Algorithm: ssh-ecdsa-nistp256-falcon512. Success! Key Exchange Algorithm: frodokem-640-aes-sha256. Signature Algorithm: ssh-falcon1024. Success! Key Exchange Algorithm: frodokem-640-aes-sha256. Signature Algorithm: ssh-ecdsa-nistp521-falcon1024. Success! Key Exchange Algorithm: frodokem-640-aes-sha256. Signature Algorithm: ssh-dilithium2. ... ``` Signed-off-by: Gerardo Ravago --- .../try_connection.py/list_all_kexs.fragment | 2 +- .../try_connection.py/list_all_sigs.fragment | 2 +- .../ssh-keygen.c/define_key_types.fragment | 4 +- .../ssh-oqs.c/define_sig_functions.fragment | 55 +- .../ssh-oqs.c/impl_lookup_cases.fragment | 9 + .../sshkey.c/define_keytypes.fragment | 3 +- .../sshkey.c/extern_key_impls.fragment | 3 +- oqs-test/try_connection.py | 80 +-- ssh-ecdsa.c | 4 +- ssh-keygen.c | 20 +- ssh-oqs.c | 536 ++++++++++++++++-- sshkey.c | 6 +- 12 files changed, 602 insertions(+), 122 deletions(-) create mode 100644 oqs-template/ssh-oqs.c/impl_lookup_cases.fragment diff --git a/oqs-template/oqs-test/try_connection.py/list_all_kexs.fragment b/oqs-template/oqs-test/try_connection.py/list_all_kexs.fragment index ac70cab70a93..e59f9dc47acc 100644 --- a/oqs-template/oqs-test/try_connection.py/list_all_kexs.fragment +++ b/oqs-template/oqs-test/try_connection.py/list_all_kexs.fragment @@ -1,7 +1,7 @@ {%- for kex in config['kexs'] %} "{{ kex['pretty_name'] }}", {%- for curve in kex['mix_with'] %} - # "{{ curve['pretty_name'] }}", + "{{ curve['pretty_name'] }}", {%- endfor -%} {%- endfor %} diff --git a/oqs-template/oqs-test/try_connection.py/list_all_sigs.fragment b/oqs-template/oqs-test/try_connection.py/list_all_sigs.fragment index 63f0e3338200..b8f64005742a 100644 --- a/oqs-template/oqs-test/try_connection.py/list_all_sigs.fragment +++ b/oqs-template/oqs-test/try_connection.py/list_all_sigs.fragment @@ -1,7 +1,7 @@ {%- for sig in config['sigs'] %} "ssh-{{ sig['name']|replace('_','') }}", {%- for alg in sig['mix_with'] %} - # "ssh-{{ alg['name']|replace('_','-') }}-{{ sig['name']|replace('_','') }}", + "ssh-{{ alg['name']|replace('_','-') }}-{{ sig['name']|replace('_','') }}", {%- endfor -%} {%- endfor %} diff --git a/oqs-template/ssh-keygen.c/define_key_types.fragment b/oqs-template/ssh-keygen.c/define_key_types.fragment index 0cbad36601a7..f524ca24fa05 100644 --- a/oqs-template/ssh-keygen.c/define_key_types.fragment +++ b/oqs-template/ssh-keygen.c/define_key_types.fragment @@ -4,13 +4,13 @@ #ifdef WITH_OPENSSL {%- for sig in config['sigs'] %} {%- for alg in sig['mix_with'] if alg['rsa'] %} - // { "{{ alg['name'] }}_{{ sig['name']|replace('_','') }}", "{{ alg['name']|upper }}_{{ sig['name']|upper }}", _PATH_HOST_{{ alg['name']|upper }}_{{ sig['name']|upper }}_KEY_FILE }, + { "{{ alg['name'] }}_{{ sig['name']|replace('_','') }}", "{{ alg['name']|upper }}_{{ sig['name']|upper }}", _PATH_HOST_{{ alg['name']|upper }}_{{ sig['name']|upper }}_KEY_FILE }, {%- endfor %} {%- endfor %} #ifdef OPENSSL_HAS_ECC {%- for sig in config['sigs'] %} {%- for alg in sig['mix_with'] if not alg['rsa'] %} - // { "{{ alg['name'] }}_{{ sig['name']|replace('_','') }}", "{{ alg['name']|upper }}_{{ sig['name']|upper }}", _PATH_HOST_{{ alg['name']|upper }}_{{ sig['name']|upper }}_KEY_FILE }, + { "{{ alg['name'] }}_{{ sig['name']|replace('_','') }}", "{{ alg['name']|upper }}_{{ sig['name']|upper }}", _PATH_HOST_{{ alg['name']|upper }}_{{ sig['name']|upper }}_KEY_FILE }, {%- endfor %} {%- endfor %} #endif /* OPENSSL_HAS_ECC */ diff --git a/oqs-template/ssh-oqs.c/define_sig_functions.fragment b/oqs-template/ssh-oqs.c/define_sig_functions.fragment index 18cb6d37c7d5..1eba7a910a27 100644 --- a/oqs-template/ssh-oqs.c/define_sig_functions.fragment +++ b/oqs-template/ssh-oqs.c/define_sig_functions.fragment @@ -15,7 +15,7 @@ static int ssh_{{ symbol_base_name }}_generate(struct sshkey *k, int bits) return OQS_SIG_{{ sig['name'] }}_keypair(k->oqs_pk, k->oqs_sk); } -int ssh_{{ symbol_base_name }}_sign(const struct sshkey *key, +int ssh_{{ symbol_base_name }}_sign(struct sshkey *key, u_char **sigp, size_t *lenp, const u_char *data, @@ -29,7 +29,7 @@ int ssh_{{ symbol_base_name }}_sign(const struct sshkey *key, if (sig == NULL) { return SSH_ERR_ALLOC_FAIL; } - int r = ssh_generic_sign(sig, "{{ symbol_base_name }}", key, sigp, lenp, data, datalen, compat); + int r = oqs_sign(sig, "{{ symbol_base_name }}", key, sigp, lenp, data, datalen, compat); OQS_SIG_free(sig); return r; } @@ -40,13 +40,14 @@ int ssh_{{ symbol_base_name }}_verify(const struct sshkey *key, const u_char *data, size_t datalen, const char *alg, - u_int compat) + u_int compat, + struct sshkey_sig_details **detailsp) { OQS_SIG *sig = OQS_SIG_new(OQS_SIG_alg_{{ sig['name'] }}); if (sig == NULL) { return SSH_ERR_ALLOC_FAIL; } - int r = ssh_generic_verify(sig, "{{ symbol_base_name }}", key, signature, signaturelen, data, datalen, compat); + int r = oqs_verify(sig, "{{ symbol_base_name }}", key, signature, signaturelen, data, datalen, compat); OQS_SIG_free(sig); return r; } @@ -79,8 +80,7 @@ const struct sshkey_impl sshkey_{{ symbol_base_name }}_impl = { }; {%- endfor %} -#ifdef HYBRID_IMPLEMENTATION_EXISTS -// #ifdef WITH_OPENSSL +#ifdef WITH_OPENSSL {%- for sig in config['sigs'] %} {%- for alg in sig['mix_with'] if alg['rsa'] %} {%- set symbol_base_name = alg['name']|replace('_','') + '_' + sig['name']|replace('_','') %} @@ -93,17 +93,17 @@ static const struct sshkey_impl_funcs sshkey_{{ symbol_base_name }}_funcs = { /* .ssh_deserialize_public = */ ssh_generic_deserialize_public, /* .ssh_serialize_private = */ ssh_generic_serialize_private, /* .ssh_deserialize_private = */ ssh_generic_deserialize_private, - /* .generate = */ ssh_{{ symbol_base_name }}_generate, + /* .generate = */ ssh_generic_generate, /* .copy_public = */ ssh_generic_copy_public, - /* .sign = */ ssh_{{ symbol_base_name }}_sign, - /* .verify = */ ssh_{{ symbol_base_name }}_verify, + /* .sign = */ ssh_generic_sign, + /* .verify = */ ssh_generic_verify, }; const struct sshkey_impl sshkey_{{ symbol_base_name }}_impl = { - /* .name = */ "ssh-{{ symbol_base_name }}", + /* .name = */ "ssh-{{ alg['name']|replace('_','') + '-' + sig['name']|replace('_','') }}", /* .shortname = */ "{{ symbol_base_name|upper }}", /* .sigalg = */ NULL, - /* .type = */ KEY_{{ sig['name']|upper }}, + /* .type = */ KEY_{{ alg['name']|upper }}_{{ sig['name']|upper }}, /* .nid = */ 0, /* .cert = */ 0, /* .sigonly = */ 0, @@ -112,5 +112,38 @@ const struct sshkey_impl sshkey_{{ symbol_base_name }}_impl = { }; {%- endfor %} {%- endfor %} +#ifdef OPENSSL_HAS_ECC +{%- for sig in config['sigs'] %} +{%- for alg in sig['mix_with'] if not alg['rsa'] %} +{%- set symbol_base_name = alg['name']|replace('_','') + '_' + sig['name']|replace('_','') %} +static const struct sshkey_impl_funcs sshkey_{{ symbol_base_name }}_funcs = { + /* .size = */ ssh_generic_size, + /* .alloc = */ ssh_generic_alloc, + /* .cleanup = */ ssh_generic_cleanup, + /* .equal = */ ssh_generic_equal, + /* .ssh_serialize_public = */ ssh_generic_serialize_public, + /* .ssh_deserialize_public = */ ssh_generic_deserialize_public, + /* .ssh_serialize_private = */ ssh_generic_serialize_private, + /* .ssh_deserialize_private = */ ssh_generic_deserialize_private, + /* .generate = */ ssh_generic_generate, + /* .copy_public = */ ssh_generic_copy_public, + /* .sign = */ ssh_generic_sign, + /* .verify = */ ssh_generic_verify, +}; + +const struct sshkey_impl sshkey_{{ symbol_base_name }}_impl = { + /* .name = */ "ssh-{{ alg['name']|replace('_','-') + '-' + sig['name']|replace('_','') }}", + /* .shortname = */ "{{ alg['name']|upper + '_' + sig['name']|replace('_','')|upper }}", + /* .sigalg = */ NULL, + /* .type = */ KEY_{{ alg['name']|upper }}_{{ sig['name']|upper }}, + /* .nid = */ {{ alg['openssl_nid'] }}, + /* .cert = */ 0, + /* .sigonly = */ 0, + /* .keybits = */ 256, // TODO - What should be here? + /* .funcs = */ &sshkey_{{ symbol_base_name }}_funcs, +}; +{%- endfor %} +{%- endfor %} +#endif /* OPENSSL_HAS_ECC */ #endif /* WITH_OPENSSL */ diff --git a/oqs-template/ssh-oqs.c/impl_lookup_cases.fragment b/oqs-template/ssh-oqs.c/impl_lookup_cases.fragment new file mode 100644 index 000000000000..2c17a5334e9d --- /dev/null +++ b/oqs-template/ssh-oqs.c/impl_lookup_cases.fragment @@ -0,0 +1,9 @@ +{% for sig in config['sigs'] %} + case KEY_{{ sig['name']|upper }}: + {%- for alg in sig['mix_with'] %} + case KEY_{{ alg['name']|upper }}_{{ sig['name']|upper }}: + {%- endfor %} + impl = &sshkey_{{ sig['name']|replace('_','') }}_impl; + break; +{%- endfor %} + diff --git a/oqs-template/sshkey.c/define_keytypes.fragment b/oqs-template/sshkey.c/define_keytypes.fragment index 2bf9d9345b99..3bbd36d32953 100644 --- a/oqs-template/sshkey.c/define_keytypes.fragment +++ b/oqs-template/sshkey.c/define_keytypes.fragment @@ -1,8 +1,7 @@ {%- for sig in config['sigs'] %} &sshkey_{{ sig['name']|replace('_','') }}_impl, {%- endfor %} -#ifdef HYBRID_IMPLEMENTATION_EXISTS -// #ifdef WITH_OPENSSL +#ifdef WITH_OPENSSL {%- for sig in config['sigs'] %} {%- for alg in sig['mix_with'] if alg['rsa'] %} &sshkey_{{ alg['name']|replace('_','') }}_{{ sig['name']|replace('_','') }}_impl, diff --git a/oqs-template/sshkey.c/extern_key_impls.fragment b/oqs-template/sshkey.c/extern_key_impls.fragment index 6cb7e3c1acc8..9f5858a8ba95 100644 --- a/oqs-template/sshkey.c/extern_key_impls.fragment +++ b/oqs-template/sshkey.c/extern_key_impls.fragment @@ -2,8 +2,7 @@ extern const struct sshkey_impl sshkey_{{ sig['name']|replace('_','') }}_impl; {%- endfor %} -#ifdef HYBRID_IMPLEMENTATION_EXISTS -// #ifdef WITH_OPENSSL +#ifdef WITH_OPENSSL {%- for sig in config['sigs'] %} {%- for alg in sig['mix_with'] if alg['rsa'] %} extern const struct sshkey_impl sshkey_{{ alg['name']|replace('_','') }}_{{ sig['name']|replace('_','') }}_impl; diff --git a/oqs-test/try_connection.py b/oqs-test/try_connection.py index 512873e5cb0d..3f4ce9175c63 100644 --- a/oqs-test/try_connection.py +++ b/oqs-test/try_connection.py @@ -2,6 +2,7 @@ # and signature algorithm, and checks whether the stock BoringSSL # client and server can establish a handshake with the choices. +import argparse import os import random import subprocess @@ -13,75 +14,75 @@ kexs = [ ##### OQS_TEMPLATE_FRAGMENT_LIST_ALL_KEXS_START "frodokem-640-aes-sha256", - # "ecdh-nistp256-frodokem-640-aesr2-sha256@openquantumsafe.org", + "ecdh-nistp256-frodokem-640-aesr2-sha256@openquantumsafe.org", "frodokem-976-aes-sha384", - # "ecdh-nistp384-frodokem-976-aesr2-sha384@openquantumsafe.org", + "ecdh-nistp384-frodokem-976-aesr2-sha384@openquantumsafe.org", "frodokem-1344-aes-sha512", - # "ecdh-nistp521-frodokem-1344-aesr2-sha512@openquantumsafe.org", + "ecdh-nistp521-frodokem-1344-aesr2-sha512@openquantumsafe.org", "frodokem-640-shake-sha256", - # "ecdh-nistp256-frodokem-640-shaker2-sha256@openquantumsafe.org", + "ecdh-nistp256-frodokem-640-shaker2-sha256@openquantumsafe.org", "frodokem-976-shake-sha384", - # "ecdh-nistp384-frodokem-976-shaker2-sha384@openquantumsafe.org", + "ecdh-nistp384-frodokem-976-shaker2-sha384@openquantumsafe.org", "frodokem-1344-shake-sha512", - # "ecdh-nistp521-frodokem-1344-shaker2-sha512@openquantumsafe.org", + "ecdh-nistp521-frodokem-1344-shaker2-sha512@openquantumsafe.org", "kyber-512-sha256", - # "ecdh-nistp256-kyber-512r3-sha256-d00@openquantumsafe.org", + "ecdh-nistp256-kyber-512r3-sha256-d00@openquantumsafe.org", "kyber-768-sha384", - # "ecdh-nistp384-kyber-768r3-sha384-d00@openquantumsafe.org", + "ecdh-nistp384-kyber-768r3-sha384-d00@openquantumsafe.org", "kyber-1024-sha512", - # "ecdh-nistp521-kyber-1024r3-sha512-d00@openquantumsafe.org", + "ecdh-nistp521-kyber-1024r3-sha512-d00@openquantumsafe.org", "bike-l1-sha512", - # "ecdh-nistp256-bike-l1r3-sha512@openquantumsafe.org", + "ecdh-nistp256-bike-l1r3-sha512@openquantumsafe.org", "bike-l3-sha512", - # "ecdh-nistp384-bike-l3r3-sha512@openquantumsafe.org", + "ecdh-nistp384-bike-l3r3-sha512@openquantumsafe.org", "classic-mceliece-348864-sha256", - # "ecdh-nistp256-classic-mceliece-348864r4-sha256@openquantumsafe.org", + "ecdh-nistp256-classic-mceliece-348864r4-sha256@openquantumsafe.org", "classic-mceliece-348864f-sha256", - # "ecdh-nistp256-classic-mceliece-348864fr4-sha256@openquantumsafe.org", + "ecdh-nistp256-classic-mceliece-348864fr4-sha256@openquantumsafe.org", "classic-mceliece-460896-sha512", - # "ecdh-nistp384-classic-mceliece-460896r4-sha512@openquantumsafe.org", + "ecdh-nistp384-classic-mceliece-460896r4-sha512@openquantumsafe.org", "classic-mceliece-460896f-sha512", - # "ecdh-nistp384-classic-mceliece-460896fr4-sha512@openquantumsafe.org", + "ecdh-nistp384-classic-mceliece-460896fr4-sha512@openquantumsafe.org", "classic-mceliece-6688128-sha512", - # "ecdh-nistp521-classic-mceliece-6688128r4-sha512@openquantumsafe.org", + "ecdh-nistp521-classic-mceliece-6688128r4-sha512@openquantumsafe.org", "classic-mceliece-6688128f-sha512", - # "ecdh-nistp521-classic-mceliece-6688128fr4-sha512@openquantumsafe.org", + "ecdh-nistp521-classic-mceliece-6688128fr4-sha512@openquantumsafe.org", "classic-mceliece-6960119-sha512", - # "ecdh-nistp521-classic-mceliece-6960119r4-sha512@openquantumsafe.org", + "ecdh-nistp521-classic-mceliece-6960119r4-sha512@openquantumsafe.org", "classic-mceliece-6960119f-sha512", - # "ecdh-nistp521-classic-mceliece-6960119fr4-sha512@openquantumsafe.org", + "ecdh-nistp521-classic-mceliece-6960119fr4-sha512@openquantumsafe.org", "classic-mceliece-8192128-sha512", - # "ecdh-nistp521-classic-mceliece-8192128r4-sha512@openquantumsafe.org", + "ecdh-nistp521-classic-mceliece-8192128r4-sha512@openquantumsafe.org", "classic-mceliece-8192128f-sha512", - # "ecdh-nistp521-classic-mceliece-8192128fr4-sha512@openquantumsafe.org", + "ecdh-nistp521-classic-mceliece-8192128fr4-sha512@openquantumsafe.org", "hqc-128-sha256", - # "ecdh-nistp256-hqc-128r3-sha256@openquantumsafe.org", + "ecdh-nistp256-hqc-128r3-sha256@openquantumsafe.org", "hqc-192-sha384", - # "ecdh-nistp384-hqc-192r3-sha384@openquantumsafe.org", + "ecdh-nistp384-hqc-192r3-sha384@openquantumsafe.org", "hqc-256-sha512", - # "ecdh-nistp521-hqc-256r3-sha512@openquantumsafe.org", + "ecdh-nistp521-hqc-256r3-sha512@openquantumsafe.org", ##### OQS_TEMPLATE_FRAGMENT_LIST_ALL_KEXS_END ] sigs = [ ##### OQS_TEMPLATE_FRAGMENT_LIST_ALL_SIGS_START "ssh-falcon512", - # "ssh-rsa3072-falcon512", - # "ssh-ecdsa-nistp256-falcon512", + "ssh-rsa3072-falcon512", + "ssh-ecdsa-nistp256-falcon512", "ssh-falcon1024", - # "ssh-ecdsa-nistp521-falcon1024", + "ssh-ecdsa-nistp521-falcon1024", "ssh-dilithium2", - # "ssh-rsa3072-dilithium2", - # "ssh-ecdsa-nistp256-dilithium2", + "ssh-rsa3072-dilithium2", + "ssh-ecdsa-nistp256-dilithium2", "ssh-dilithium3", - # "ssh-ecdsa-nistp384-dilithium3", + "ssh-ecdsa-nistp384-dilithium3", "ssh-dilithium5", - # "ssh-ecdsa-nistp521-dilithium5", + "ssh-ecdsa-nistp521-dilithium5", "ssh-sphincssha2128fsimple", - # "ssh-rsa3072-sphincssha2128fsimple", - # "ssh-ecdsa-nistp256-sphincssha2128fsimple", + "ssh-rsa3072-sphincssha2128fsimple", + "ssh-ecdsa-nistp256-sphincssha2128fsimple", "ssh-sphincssha2256fsimple", - # "ssh-ecdsa-nistp521-sphincssha2256fsimple", + "ssh-ecdsa-nistp521-sphincssha2256fsimple", ##### OQS_TEMPLATE_FRAGMENT_LIST_ALL_SIGS_END ] @@ -131,8 +132,11 @@ def try_handshake(ssh, sshd, dorandom="random"): do_handshake(ssh, sshd, test_sig, test_kex) if __name__ == '__main__': - if len(sys.argv)==1: - try_handshake(os.path.abspath('ssh'), os.path.abspath('sshd')) - else: - try_handshake(os.path.abspath('ssh'), os.path.abspath('sshd'), dorandom=sys.argv[1]) + parser = argparse.ArgumentParser(description="Test connections between ssh and sshd using PQ algorithms.") + parser.add_argument("--ssh", default=os.path.abspath('ssh'), type=str, help="Override the ssh binary.") + parser.add_argument("--sshd", default=os.path.abspath('sshd'), type=str, help="Override the sshd binary.") + parser.add_argument("dorandom", type=str, default="random", choices=["doall", "doone", "random"], + help="Slice of test cases to run.") + args = parser.parse_args() + try_handshake(args.ssh, args.sshd, args.dorandom) diff --git a/ssh-ecdsa.c b/ssh-ecdsa.c index cd815a509d31..ca959aa8b991 100644 --- a/ssh-ecdsa.c +++ b/ssh-ecdsa.c @@ -305,8 +305,8 @@ ssh_ecdsa_verify(const struct sshkey *key, char *ktype = NULL; if (key == NULL || key->ecdsa == NULL || - sshkey_type_plain(key->type) != KEY_ECDSA && - !oqs_utils_is_ecdsa_hybrid(sshkey_type_plain(key->type)) || + (sshkey_type_plain(key->type) != KEY_ECDSA && + !oqs_utils_is_ecdsa_hybrid(sshkey_type_plain(key->type))) || sig == NULL || siglen == 0) return SSH_ERR_INVALID_ARGUMENT; diff --git a/ssh-keygen.c b/ssh-keygen.c index 8d2dbb27609b..c2866b373f92 100644 --- a/ssh-keygen.c +++ b/ssh-keygen.c @@ -1170,17 +1170,17 @@ do_gen_all_hostkeys(struct passwd *pw) { "sphincssha2128fsimple", "SPHINCS_SHA2_128F_SIMPLE", _PATH_HOST_SPHINCS_SHA2_128F_SIMPLE_KEY_FILE }, { "sphincssha2256fsimple", "SPHINCS_SHA2_256F_SIMPLE", _PATH_HOST_SPHINCS_SHA2_256F_SIMPLE_KEY_FILE }, #ifdef WITH_OPENSSL - // { "rsa3072_falcon512", "RSA3072_FALCON_512", _PATH_HOST_RSA3072_FALCON_512_KEY_FILE }, - // { "rsa3072_dilithium2", "RSA3072_DILITHIUM_2", _PATH_HOST_RSA3072_DILITHIUM_2_KEY_FILE }, - // { "rsa3072_sphincssha2128fsimple", "RSA3072_SPHINCS_SHA2_128F_SIMPLE", _PATH_HOST_RSA3072_SPHINCS_SHA2_128F_SIMPLE_KEY_FILE }, + { "rsa3072_falcon512", "RSA3072_FALCON_512", _PATH_HOST_RSA3072_FALCON_512_KEY_FILE }, + { "rsa3072_dilithium2", "RSA3072_DILITHIUM_2", _PATH_HOST_RSA3072_DILITHIUM_2_KEY_FILE }, + { "rsa3072_sphincssha2128fsimple", "RSA3072_SPHINCS_SHA2_128F_SIMPLE", _PATH_HOST_RSA3072_SPHINCS_SHA2_128F_SIMPLE_KEY_FILE }, #ifdef OPENSSL_HAS_ECC - // { "ecdsa_nistp256_falcon512", "ECDSA_NISTP256_FALCON_512", _PATH_HOST_ECDSA_NISTP256_FALCON_512_KEY_FILE }, - // { "ecdsa_nistp521_falcon1024", "ECDSA_NISTP521_FALCON_1024", _PATH_HOST_ECDSA_NISTP521_FALCON_1024_KEY_FILE }, - // { "ecdsa_nistp256_dilithium2", "ECDSA_NISTP256_DILITHIUM_2", _PATH_HOST_ECDSA_NISTP256_DILITHIUM_2_KEY_FILE }, - // { "ecdsa_nistp384_dilithium3", "ECDSA_NISTP384_DILITHIUM_3", _PATH_HOST_ECDSA_NISTP384_DILITHIUM_3_KEY_FILE }, - // { "ecdsa_nistp521_dilithium5", "ECDSA_NISTP521_DILITHIUM_5", _PATH_HOST_ECDSA_NISTP521_DILITHIUM_5_KEY_FILE }, - // { "ecdsa_nistp256_sphincssha2128fsimple", "ECDSA_NISTP256_SPHINCS_SHA2_128F_SIMPLE", _PATH_HOST_ECDSA_NISTP256_SPHINCS_SHA2_128F_SIMPLE_KEY_FILE }, - // { "ecdsa_nistp521_sphincssha2256fsimple", "ECDSA_NISTP521_SPHINCS_SHA2_256F_SIMPLE", _PATH_HOST_ECDSA_NISTP521_SPHINCS_SHA2_256F_SIMPLE_KEY_FILE }, + { "ecdsa_nistp256_falcon512", "ECDSA_NISTP256_FALCON_512", _PATH_HOST_ECDSA_NISTP256_FALCON_512_KEY_FILE }, + { "ecdsa_nistp521_falcon1024", "ECDSA_NISTP521_FALCON_1024", _PATH_HOST_ECDSA_NISTP521_FALCON_1024_KEY_FILE }, + { "ecdsa_nistp256_dilithium2", "ECDSA_NISTP256_DILITHIUM_2", _PATH_HOST_ECDSA_NISTP256_DILITHIUM_2_KEY_FILE }, + { "ecdsa_nistp384_dilithium3", "ECDSA_NISTP384_DILITHIUM_3", _PATH_HOST_ECDSA_NISTP384_DILITHIUM_3_KEY_FILE }, + { "ecdsa_nistp521_dilithium5", "ECDSA_NISTP521_DILITHIUM_5", _PATH_HOST_ECDSA_NISTP521_DILITHIUM_5_KEY_FILE }, + { "ecdsa_nistp256_sphincssha2128fsimple", "ECDSA_NISTP256_SPHINCS_SHA2_128F_SIMPLE", _PATH_HOST_ECDSA_NISTP256_SPHINCS_SHA2_128F_SIMPLE_KEY_FILE }, + { "ecdsa_nistp521_sphincssha2256fsimple", "ECDSA_NISTP521_SPHINCS_SHA2_256F_SIMPLE", _PATH_HOST_ECDSA_NISTP521_SPHINCS_SHA2_256F_SIMPLE_KEY_FILE }, #endif /* OPENSSL_HAS_ECC */ #endif /* WITH_OPENSSL */ ///// OQS_TEMPLATE_FRAGMENT_DEFINE_KEY_TYPES_END diff --git a/ssh-oqs.c b/ssh-oqs.c index ad290511e8e7..6f642be91716 100644 --- a/ssh-oqs.c +++ b/ssh-oqs.c @@ -19,6 +19,9 @@ #include #include +#ifdef WITH_OPENSSL +#include +#endif #include "crypto_api.h" @@ -26,6 +29,7 @@ #include #include "log.h" +#include "oqs-utils.h" #include "sshbuf.h" #define SSHKEY_INTERNAL #include "sshkey.h" @@ -34,6 +38,12 @@ #include "oqs/oqs.h" +extern const struct sshkey_impl sshkey_rsa_impl; +extern const struct sshkey_impl sshkey_ecdsa_nistp256_impl; + +const struct sshkey_impl *oqs_pq_sshkey_impl(const struct sshkey *k); +const struct sshkey_impl *oqs_classical_sshkey_impl(const struct sshkey *k); + /* returns the size of an oqs public key */ static size_t oqs_sig_pk_len(int type) { @@ -95,30 +105,49 @@ static size_t oqs_sig_sk_len(int type) return 0; } -static int ssh_generic_size(struct sshkey *k) +static unsigned int ssh_generic_size(const struct sshkey *k) { - return k->oqs_pk_len; + int size; + const struct sshkey_impl *classical; + size = k->oqs_pk_len; + classical = oqs_classical_sshkey_impl(k); + if ((classical != NULL) && (classical->funcs->size != NULL)) { + size += classical->funcs->size(k); + } + return size; } static int ssh_generic_alloc(struct sshkey *k) { + const struct sshkey_impl *classical; k->oqs_sk = NULL; k->oqs_pk = NULL; k->oqs_pk_len = oqs_sig_pk_len(k->type); k->oqs_sk_len = oqs_sig_sk_len(k->type); + classical = oqs_classical_sshkey_impl(k); + if ((classical != NULL) && (classical->funcs->alloc != NULL)) { + classical->funcs->alloc(k); + } return 0; } static void ssh_generic_cleanup(struct sshkey *k) { + const struct sshkey_impl *classical; freezero(k->oqs_sk, k->oqs_sk_len); k->oqs_sk = NULL; freezero(k->oqs_pk, k->oqs_pk_len); k->oqs_pk = NULL; + classical = oqs_classical_sshkey_impl(k); + if ((classical != NULL) && (classical->funcs->cleanup != NULL)) { + classical->funcs->cleanup(k); + } + return; } static int ssh_generic_equal(const struct sshkey *a, const struct sshkey *b) { + const struct sshkey_impl *classical; if (a->oqs_pk == NULL || b->oqs_pk == NULL) { return 0; } @@ -128,13 +157,24 @@ static int ssh_generic_equal(const struct sshkey *a, const struct sshkey *b) if (memcmp(a->oqs_pk, b->oqs_pk, a->oqs_pk_len) != 0) { return 0; } + classical = oqs_classical_sshkey_impl(a); + if (classical) { + return classical->funcs->equal(a, b); + } return 1; } static int ssh_generic_serialize_public(const struct sshkey *key, struct sshbuf *b, enum sshkey_serialize_rep opts) { + const struct sshkey_impl *classical; int r; + classical = oqs_classical_sshkey_impl(key); + if (classical) { + if((r = classical->funcs->serialize_public(key, b, opts)) != 0) { + return r; + } + } if (key->oqs_pk == NULL) { return SSH_ERR_INVALID_ARGUMENT; } @@ -147,10 +187,17 @@ static int ssh_generic_serialize_public(const struct sshkey *key, static int ssh_generic_deserialize_public(const char *ktype, struct sshbuf *b, struct sshkey *key) { + const struct sshkey_impl *classical; u_char *pk = NULL; size_t len = 0; int r; + classical = oqs_classical_sshkey_impl(key); + if (classical) { + if ((r = classical->funcs->deserialize_public(ktype, b, key)) != 0) { + return r; + } + } if ((r = sshbuf_get_string(b, &pk, &len)) != 0) { return r; } @@ -165,7 +212,14 @@ static int ssh_generic_deserialize_public(const char *ktype, struct sshbuf *b, static int ssh_generic_serialize_private(const struct sshkey *key, struct sshbuf *b, enum sshkey_serialize_rep opts) { + const struct sshkey_impl *classical; int r; + classical = oqs_classical_sshkey_impl(key); + if (classical) { + if ((r = classical->funcs->serialize_private(key, b, opts)) != 0) { + return r; + } + } if ((r = sshbuf_put_string(b, key->oqs_pk, key->oqs_pk_len)) != 0 || (r = sshbuf_put_string(b, key->oqs_sk, key->oqs_sk_len)) != 0) { return r; @@ -176,11 +230,18 @@ static int ssh_generic_serialize_private(const struct sshkey *key, static int ssh_generic_deserialize_private(const char *ktype, struct sshbuf *b, struct sshkey *key) { + const struct sshkey_impl *classical; int r; size_t pklen = 0; size_t sklen = 0; u_char *oqs_pk = NULL; u_char *oqs_sk = NULL; + classical = oqs_classical_sshkey_impl(key); + if (classical) { + if ((r = classical->funcs->deserialize_private(ktype, b, key)) != 0) { + return r; + } + } if ((r = sshbuf_get_string(b, &oqs_pk, &pklen)) != 0 || (r = sshbuf_get_string(b, &oqs_sk, &sklen)) != 0) { goto out; @@ -202,6 +263,14 @@ static int ssh_generic_deserialize_private(const char *ktype, struct sshbuf *b, static int ssh_generic_copy_public(const struct sshkey *from, struct sshkey *to) { + const struct sshkey_impl *classical; + int r; + classical = oqs_classical_sshkey_impl(from); + if (classical) { + if ((r = classical->funcs->copy_public(from, to)) != 0) { + return r; + } + } if (from->oqs_pk != NULL) { if ((to->oqs_pk = malloc(from->oqs_pk_len)) == NULL) { return SSH_ERR_ALLOC_FAIL; @@ -211,7 +280,125 @@ static int ssh_generic_copy_public(const struct sshkey *from, struct sshkey *to) return 0; } -static int ssh_generic_sign(OQS_SIG *oqs_sig, +static int ssh_generic_generate(struct sshkey *k, int bits) +{ + const struct sshkey_impl *impl; + int r; + impl = oqs_classical_sshkey_impl(k); + if ((impl != NULL) && (impl->funcs->generate != NULL)) { + if ((r = impl->funcs->generate(k, bits)) != 0) { + return r; + } + } + impl = oqs_pq_sshkey_impl(k); + if ((r = impl->funcs->generate(k, bits)) != 0) { + return r; + } + return 0; +} + +static int ssh_generic_sign(struct sshkey *key, u_char **sigp, + size_t *lenp, const u_char *data, size_t datalen, const char *alg, + const char *sk_provider, const char *sk_pin, u_int compat) +{ + u_char *sig_classical = NULL, *sig_pq = NULL; + size_t len_classical = 0, len_pq = 0; + int index = 0; + int r; + const struct sshkey_impl *impl; + if (lenp != NULL) { + *lenp = 0; + } + if (sigp != NULL) { + *sigp = NULL; + } + impl = oqs_pq_sshkey_impl(key); + if ((r = impl->funcs->sign(key, &sig_pq, &len_pq, data, datalen, alg, + sk_provider, sk_pin, compat)) != 0) { + free(sig_pq); + return r; + } + + impl = oqs_classical_sshkey_impl(key); + if ((impl != NULL) && (impl->funcs->sign != NULL)) { + if ((r = impl->funcs->sign(key, &sig_classical, &len_classical, data, + datalen, alg, sk_provider, sk_pin, compat)) + != 0) { + free(sig_classical); + free(sig_pq); + return r; + } + *lenp = 4 + len_classical + 4 + len_pq; + if ((*sigp = malloc(*lenp)) == NULL) { + free(sig_classical); + free(sig_pq); + return SSH_ERR_ALLOC_FAIL; + } + /* encode the classical sig length */ + POKE_U32(*sigp + index, (size_t) len_classical); + index += 4; + /* encode the classical sig */ + memcpy(*sigp + index, sig_classical, (size_t) len_classical); + index += len_classical; + free(sig_classical); + /* encode the PQ sig length */ + POKE_U32(*sigp + index, len_pq); + index += 4; + /* encode the PQ sig */ + memcpy(*sigp + index, sig_pq, len_pq); + index += len_pq; + free(sig_pq); + } else { + *sigp = sig_pq; + *lenp = len_pq; + } + return 0; +} + +static int ssh_generic_verify(const struct sshkey *key, + const u_char *sig, size_t siglen, const u_char *data, size_t dlen, + const char *alg, u_int compat, struct sshkey_sig_details **detailsp) +{ + const struct sshkey_impl *impl; + const u_char *sig_classical = NULL; + size_t siglen_classical = 0; + int index = 0; + const u_char *sig_pq = NULL; + size_t siglen_pq = 0; + int r; + impl = oqs_classical_sshkey_impl(key); + if (impl) { + /* classical-PQ hybrid: we separate the signatures */ + /* decode the classical sig length */ + siglen_classical = (size_t) PEEK_U32(sig + index); + index += 4; + /* point to the classical sig */ + sig_classical = sig + index; + index += siglen_classical; + /* decode the PQ sig length */ + siglen_pq = (size_t) PEEK_U32(sig + index); + index += 4; + /* point to the PQ sig */ + sig_pq = sig + index; + index += siglen_pq; + if ((r = impl->funcs->verify(key, sig_classical, siglen_classical, data, + dlen, alg, compat, detailsp)) != 0) { + return r; + } + } else { + /* PQ signature */ + sig_pq = sig; + siglen_pq = siglen; + } + impl = oqs_pq_sshkey_impl(key); + if ((r = impl->funcs->verify(key, sig_pq, siglen_pq, data, + dlen, alg, compat, detailsp)) != 0) { + return r; + } + return 0; +} + +static int oqs_sign(OQS_SIG *oqs_sig, const char *alg_pretty_name, const struct sshkey *key, u_char **sigp, @@ -287,7 +474,7 @@ static int ssh_generic_sign(OQS_SIG *oqs_sig, return r; } -static int ssh_generic_verify(OQS_SIG *oqs_sig, +static int oqs_verify(OQS_SIG *oqs_sig, const char *alg_pretty_name, const struct sshkey *key, const u_char *signature, @@ -370,7 +557,7 @@ static int ssh_falcon512_generate(struct sshkey *k, int bits) return OQS_SIG_falcon_512_keypair(k->oqs_pk, k->oqs_sk); } -int ssh_falcon512_sign(const struct sshkey *key, +int ssh_falcon512_sign(struct sshkey *key, u_char **sigp, size_t *lenp, const u_char *data, @@ -384,7 +571,7 @@ int ssh_falcon512_sign(const struct sshkey *key, if (sig == NULL) { return SSH_ERR_ALLOC_FAIL; } - int r = ssh_generic_sign(sig, "falcon512", key, sigp, lenp, data, datalen, compat); + int r = oqs_sign(sig, "falcon512", key, sigp, lenp, data, datalen, compat); OQS_SIG_free(sig); return r; } @@ -395,13 +582,14 @@ int ssh_falcon512_verify(const struct sshkey *key, const u_char *data, size_t datalen, const char *alg, - u_int compat) + u_int compat, + struct sshkey_sig_details **detailsp) { OQS_SIG *sig = OQS_SIG_new(OQS_SIG_alg_falcon_512); if (sig == NULL) { return SSH_ERR_ALLOC_FAIL; } - int r = ssh_generic_verify(sig, "falcon512", key, signature, signaturelen, data, datalen, compat); + int r = oqs_verify(sig, "falcon512", key, signature, signaturelen, data, datalen, compat); OQS_SIG_free(sig); return r; } @@ -447,7 +635,7 @@ static int ssh_falcon1024_generate(struct sshkey *k, int bits) return OQS_SIG_falcon_1024_keypair(k->oqs_pk, k->oqs_sk); } -int ssh_falcon1024_sign(const struct sshkey *key, +int ssh_falcon1024_sign(struct sshkey *key, u_char **sigp, size_t *lenp, const u_char *data, @@ -461,7 +649,7 @@ int ssh_falcon1024_sign(const struct sshkey *key, if (sig == NULL) { return SSH_ERR_ALLOC_FAIL; } - int r = ssh_generic_sign(sig, "falcon1024", key, sigp, lenp, data, datalen, compat); + int r = oqs_sign(sig, "falcon1024", key, sigp, lenp, data, datalen, compat); OQS_SIG_free(sig); return r; } @@ -472,13 +660,14 @@ int ssh_falcon1024_verify(const struct sshkey *key, const u_char *data, size_t datalen, const char *alg, - u_int compat) + u_int compat, + struct sshkey_sig_details **detailsp) { OQS_SIG *sig = OQS_SIG_new(OQS_SIG_alg_falcon_1024); if (sig == NULL) { return SSH_ERR_ALLOC_FAIL; } - int r = ssh_generic_verify(sig, "falcon1024", key, signature, signaturelen, data, datalen, compat); + int r = oqs_verify(sig, "falcon1024", key, signature, signaturelen, data, datalen, compat); OQS_SIG_free(sig); return r; } @@ -524,7 +713,7 @@ static int ssh_dilithium2_generate(struct sshkey *k, int bits) return OQS_SIG_dilithium_2_keypair(k->oqs_pk, k->oqs_sk); } -int ssh_dilithium2_sign(const struct sshkey *key, +int ssh_dilithium2_sign(struct sshkey *key, u_char **sigp, size_t *lenp, const u_char *data, @@ -538,7 +727,7 @@ int ssh_dilithium2_sign(const struct sshkey *key, if (sig == NULL) { return SSH_ERR_ALLOC_FAIL; } - int r = ssh_generic_sign(sig, "dilithium2", key, sigp, lenp, data, datalen, compat); + int r = oqs_sign(sig, "dilithium2", key, sigp, lenp, data, datalen, compat); OQS_SIG_free(sig); return r; } @@ -549,13 +738,14 @@ int ssh_dilithium2_verify(const struct sshkey *key, const u_char *data, size_t datalen, const char *alg, - u_int compat) + u_int compat, + struct sshkey_sig_details **detailsp) { OQS_SIG *sig = OQS_SIG_new(OQS_SIG_alg_dilithium_2); if (sig == NULL) { return SSH_ERR_ALLOC_FAIL; } - int r = ssh_generic_verify(sig, "dilithium2", key, signature, signaturelen, data, datalen, compat); + int r = oqs_verify(sig, "dilithium2", key, signature, signaturelen, data, datalen, compat); OQS_SIG_free(sig); return r; } @@ -601,7 +791,7 @@ static int ssh_dilithium3_generate(struct sshkey *k, int bits) return OQS_SIG_dilithium_3_keypair(k->oqs_pk, k->oqs_sk); } -int ssh_dilithium3_sign(const struct sshkey *key, +int ssh_dilithium3_sign(struct sshkey *key, u_char **sigp, size_t *lenp, const u_char *data, @@ -615,7 +805,7 @@ int ssh_dilithium3_sign(const struct sshkey *key, if (sig == NULL) { return SSH_ERR_ALLOC_FAIL; } - int r = ssh_generic_sign(sig, "dilithium3", key, sigp, lenp, data, datalen, compat); + int r = oqs_sign(sig, "dilithium3", key, sigp, lenp, data, datalen, compat); OQS_SIG_free(sig); return r; } @@ -626,13 +816,14 @@ int ssh_dilithium3_verify(const struct sshkey *key, const u_char *data, size_t datalen, const char *alg, - u_int compat) + u_int compat, + struct sshkey_sig_details **detailsp) { OQS_SIG *sig = OQS_SIG_new(OQS_SIG_alg_dilithium_3); if (sig == NULL) { return SSH_ERR_ALLOC_FAIL; } - int r = ssh_generic_verify(sig, "dilithium3", key, signature, signaturelen, data, datalen, compat); + int r = oqs_verify(sig, "dilithium3", key, signature, signaturelen, data, datalen, compat); OQS_SIG_free(sig); return r; } @@ -678,7 +869,7 @@ static int ssh_dilithium5_generate(struct sshkey *k, int bits) return OQS_SIG_dilithium_5_keypair(k->oqs_pk, k->oqs_sk); } -int ssh_dilithium5_sign(const struct sshkey *key, +int ssh_dilithium5_sign(struct sshkey *key, u_char **sigp, size_t *lenp, const u_char *data, @@ -692,7 +883,7 @@ int ssh_dilithium5_sign(const struct sshkey *key, if (sig == NULL) { return SSH_ERR_ALLOC_FAIL; } - int r = ssh_generic_sign(sig, "dilithium5", key, sigp, lenp, data, datalen, compat); + int r = oqs_sign(sig, "dilithium5", key, sigp, lenp, data, datalen, compat); OQS_SIG_free(sig); return r; } @@ -703,13 +894,14 @@ int ssh_dilithium5_verify(const struct sshkey *key, const u_char *data, size_t datalen, const char *alg, - u_int compat) + u_int compat, + struct sshkey_sig_details **detailsp) { OQS_SIG *sig = OQS_SIG_new(OQS_SIG_alg_dilithium_5); if (sig == NULL) { return SSH_ERR_ALLOC_FAIL; } - int r = ssh_generic_verify(sig, "dilithium5", key, signature, signaturelen, data, datalen, compat); + int r = oqs_verify(sig, "dilithium5", key, signature, signaturelen, data, datalen, compat); OQS_SIG_free(sig); return r; } @@ -755,7 +947,7 @@ static int ssh_sphincssha2128fsimple_generate(struct sshkey *k, int bits) return OQS_SIG_sphincs_sha2_128f_simple_keypair(k->oqs_pk, k->oqs_sk); } -int ssh_sphincssha2128fsimple_sign(const struct sshkey *key, +int ssh_sphincssha2128fsimple_sign(struct sshkey *key, u_char **sigp, size_t *lenp, const u_char *data, @@ -769,7 +961,7 @@ int ssh_sphincssha2128fsimple_sign(const struct sshkey *key, if (sig == NULL) { return SSH_ERR_ALLOC_FAIL; } - int r = ssh_generic_sign(sig, "sphincssha2128fsimple", key, sigp, lenp, data, datalen, compat); + int r = oqs_sign(sig, "sphincssha2128fsimple", key, sigp, lenp, data, datalen, compat); OQS_SIG_free(sig); return r; } @@ -780,13 +972,14 @@ int ssh_sphincssha2128fsimple_verify(const struct sshkey *key, const u_char *data, size_t datalen, const char *alg, - u_int compat) + u_int compat, + struct sshkey_sig_details **detailsp) { OQS_SIG *sig = OQS_SIG_new(OQS_SIG_alg_sphincs_sha2_128f_simple); if (sig == NULL) { return SSH_ERR_ALLOC_FAIL; } - int r = ssh_generic_verify(sig, "sphincssha2128fsimple", key, signature, signaturelen, data, datalen, compat); + int r = oqs_verify(sig, "sphincssha2128fsimple", key, signature, signaturelen, data, datalen, compat); OQS_SIG_free(sig); return r; } @@ -832,7 +1025,7 @@ static int ssh_sphincssha2256fsimple_generate(struct sshkey *k, int bits) return OQS_SIG_sphincs_sha2_256f_simple_keypair(k->oqs_pk, k->oqs_sk); } -int ssh_sphincssha2256fsimple_sign(const struct sshkey *key, +int ssh_sphincssha2256fsimple_sign(struct sshkey *key, u_char **sigp, size_t *lenp, const u_char *data, @@ -846,7 +1039,7 @@ int ssh_sphincssha2256fsimple_sign(const struct sshkey *key, if (sig == NULL) { return SSH_ERR_ALLOC_FAIL; } - int r = ssh_generic_sign(sig, "sphincssha2256fsimple", key, sigp, lenp, data, datalen, compat); + int r = oqs_sign(sig, "sphincssha2256fsimple", key, sigp, lenp, data, datalen, compat); OQS_SIG_free(sig); return r; } @@ -857,13 +1050,14 @@ int ssh_sphincssha2256fsimple_verify(const struct sshkey *key, const u_char *data, size_t datalen, const char *alg, - u_int compat) + u_int compat, + struct sshkey_sig_details **detailsp) { OQS_SIG *sig = OQS_SIG_new(OQS_SIG_alg_sphincs_sha2_256f_simple); if (sig == NULL) { return SSH_ERR_ALLOC_FAIL; } - int r = ssh_generic_verify(sig, "sphincssha2256fsimple", key, signature, signaturelen, data, datalen, compat); + int r = oqs_verify(sig, "sphincssha2256fsimple", key, signature, signaturelen, data, datalen, compat); OQS_SIG_free(sig); return r; } @@ -895,8 +1089,7 @@ const struct sshkey_impl sshkey_sphincssha2256fsimple_impl = { /* .funcs = */ &sshkey_sphincssha2256fsimple_funcs, }; -#ifdef HYBRID_IMPLEMENTATION_EXISTS -// #ifdef WITH_OPENSSL +#ifdef WITH_OPENSSL static const struct sshkey_impl_funcs sshkey_rsa3072_falcon512_funcs = { /* .size = */ ssh_generic_size, /* .alloc = */ ssh_generic_alloc, @@ -906,17 +1099,17 @@ static const struct sshkey_impl_funcs sshkey_rsa3072_falcon512_funcs = { /* .ssh_deserialize_public = */ ssh_generic_deserialize_public, /* .ssh_serialize_private = */ ssh_generic_serialize_private, /* .ssh_deserialize_private = */ ssh_generic_deserialize_private, - /* .generate = */ ssh_rsa3072_falcon512_generate, + /* .generate = */ ssh_generic_generate, /* .copy_public = */ ssh_generic_copy_public, - /* .sign = */ ssh_rsa3072_falcon512_sign, - /* .verify = */ ssh_rsa3072_falcon512_verify, + /* .sign = */ ssh_generic_sign, + /* .verify = */ ssh_generic_verify, }; const struct sshkey_impl sshkey_rsa3072_falcon512_impl = { - /* .name = */ "ssh-rsa3072_falcon512", + /* .name = */ "ssh-rsa3072-falcon512", /* .shortname = */ "RSA3072_FALCON512", /* .sigalg = */ NULL, - /* .type = */ KEY_FALCON_512, + /* .type = */ KEY_RSA3072_FALCON_512, /* .nid = */ 0, /* .cert = */ 0, /* .sigonly = */ 0, @@ -932,17 +1125,17 @@ static const struct sshkey_impl_funcs sshkey_rsa3072_dilithium2_funcs = { /* .ssh_deserialize_public = */ ssh_generic_deserialize_public, /* .ssh_serialize_private = */ ssh_generic_serialize_private, /* .ssh_deserialize_private = */ ssh_generic_deserialize_private, - /* .generate = */ ssh_rsa3072_dilithium2_generate, + /* .generate = */ ssh_generic_generate, /* .copy_public = */ ssh_generic_copy_public, - /* .sign = */ ssh_rsa3072_dilithium2_sign, - /* .verify = */ ssh_rsa3072_dilithium2_verify, + /* .sign = */ ssh_generic_sign, + /* .verify = */ ssh_generic_verify, }; const struct sshkey_impl sshkey_rsa3072_dilithium2_impl = { - /* .name = */ "ssh-rsa3072_dilithium2", + /* .name = */ "ssh-rsa3072-dilithium2", /* .shortname = */ "RSA3072_DILITHIUM2", /* .sigalg = */ NULL, - /* .type = */ KEY_DILITHIUM_2, + /* .type = */ KEY_RSA3072_DILITHIUM_2, /* .nid = */ 0, /* .cert = */ 0, /* .sigonly = */ 0, @@ -958,22 +1151,267 @@ static const struct sshkey_impl_funcs sshkey_rsa3072_sphincssha2128fsimple_funcs /* .ssh_deserialize_public = */ ssh_generic_deserialize_public, /* .ssh_serialize_private = */ ssh_generic_serialize_private, /* .ssh_deserialize_private = */ ssh_generic_deserialize_private, - /* .generate = */ ssh_rsa3072_sphincssha2128fsimple_generate, + /* .generate = */ ssh_generic_generate, /* .copy_public = */ ssh_generic_copy_public, - /* .sign = */ ssh_rsa3072_sphincssha2128fsimple_sign, - /* .verify = */ ssh_rsa3072_sphincssha2128fsimple_verify, + /* .sign = */ ssh_generic_sign, + /* .verify = */ ssh_generic_verify, }; const struct sshkey_impl sshkey_rsa3072_sphincssha2128fsimple_impl = { - /* .name = */ "ssh-rsa3072_sphincssha2128fsimple", + /* .name = */ "ssh-rsa3072-sphincssha2128fsimple", /* .shortname = */ "RSA3072_SPHINCSSHA2128FSIMPLE", /* .sigalg = */ NULL, - /* .type = */ KEY_SPHINCS_SHA2_128F_SIMPLE, + /* .type = */ KEY_RSA3072_SPHINCS_SHA2_128F_SIMPLE, /* .nid = */ 0, /* .cert = */ 0, /* .sigonly = */ 0, /* .keybits = */ 256, // TODO - What should be here? /* .funcs = */ &sshkey_rsa3072_sphincssha2128fsimple_funcs, }; +#ifdef OPENSSL_HAS_ECC +static const struct sshkey_impl_funcs sshkey_ecdsanistp256_falcon512_funcs = { + /* .size = */ ssh_generic_size, + /* .alloc = */ ssh_generic_alloc, + /* .cleanup = */ ssh_generic_cleanup, + /* .equal = */ ssh_generic_equal, + /* .ssh_serialize_public = */ ssh_generic_serialize_public, + /* .ssh_deserialize_public = */ ssh_generic_deserialize_public, + /* .ssh_serialize_private = */ ssh_generic_serialize_private, + /* .ssh_deserialize_private = */ ssh_generic_deserialize_private, + /* .generate = */ ssh_generic_generate, + /* .copy_public = */ ssh_generic_copy_public, + /* .sign = */ ssh_generic_sign, + /* .verify = */ ssh_generic_verify, +}; + +const struct sshkey_impl sshkey_ecdsanistp256_falcon512_impl = { + /* .name = */ "ssh-ecdsa-nistp256-falcon512", + /* .shortname = */ "ECDSA_NISTP256_FALCON512", + /* .sigalg = */ NULL, + /* .type = */ KEY_ECDSA_NISTP256_FALCON_512, + /* .nid = */ NID_X9_62_prime256v1, + /* .cert = */ 0, + /* .sigonly = */ 0, + /* .keybits = */ 256, // TODO - What should be here? + /* .funcs = */ &sshkey_ecdsanistp256_falcon512_funcs, +}; +static const struct sshkey_impl_funcs sshkey_ecdsanistp521_falcon1024_funcs = { + /* .size = */ ssh_generic_size, + /* .alloc = */ ssh_generic_alloc, + /* .cleanup = */ ssh_generic_cleanup, + /* .equal = */ ssh_generic_equal, + /* .ssh_serialize_public = */ ssh_generic_serialize_public, + /* .ssh_deserialize_public = */ ssh_generic_deserialize_public, + /* .ssh_serialize_private = */ ssh_generic_serialize_private, + /* .ssh_deserialize_private = */ ssh_generic_deserialize_private, + /* .generate = */ ssh_generic_generate, + /* .copy_public = */ ssh_generic_copy_public, + /* .sign = */ ssh_generic_sign, + /* .verify = */ ssh_generic_verify, +}; + +const struct sshkey_impl sshkey_ecdsanistp521_falcon1024_impl = { + /* .name = */ "ssh-ecdsa-nistp521-falcon1024", + /* .shortname = */ "ECDSA_NISTP521_FALCON1024", + /* .sigalg = */ NULL, + /* .type = */ KEY_ECDSA_NISTP521_FALCON_1024, + /* .nid = */ NID_secp521r1, + /* .cert = */ 0, + /* .sigonly = */ 0, + /* .keybits = */ 256, // TODO - What should be here? + /* .funcs = */ &sshkey_ecdsanistp521_falcon1024_funcs, +}; +static const struct sshkey_impl_funcs sshkey_ecdsanistp256_dilithium2_funcs = { + /* .size = */ ssh_generic_size, + /* .alloc = */ ssh_generic_alloc, + /* .cleanup = */ ssh_generic_cleanup, + /* .equal = */ ssh_generic_equal, + /* .ssh_serialize_public = */ ssh_generic_serialize_public, + /* .ssh_deserialize_public = */ ssh_generic_deserialize_public, + /* .ssh_serialize_private = */ ssh_generic_serialize_private, + /* .ssh_deserialize_private = */ ssh_generic_deserialize_private, + /* .generate = */ ssh_generic_generate, + /* .copy_public = */ ssh_generic_copy_public, + /* .sign = */ ssh_generic_sign, + /* .verify = */ ssh_generic_verify, +}; + +const struct sshkey_impl sshkey_ecdsanistp256_dilithium2_impl = { + /* .name = */ "ssh-ecdsa-nistp256-dilithium2", + /* .shortname = */ "ECDSA_NISTP256_DILITHIUM2", + /* .sigalg = */ NULL, + /* .type = */ KEY_ECDSA_NISTP256_DILITHIUM_2, + /* .nid = */ NID_X9_62_prime256v1, + /* .cert = */ 0, + /* .sigonly = */ 0, + /* .keybits = */ 256, // TODO - What should be here? + /* .funcs = */ &sshkey_ecdsanistp256_dilithium2_funcs, +}; +static const struct sshkey_impl_funcs sshkey_ecdsanistp384_dilithium3_funcs = { + /* .size = */ ssh_generic_size, + /* .alloc = */ ssh_generic_alloc, + /* .cleanup = */ ssh_generic_cleanup, + /* .equal = */ ssh_generic_equal, + /* .ssh_serialize_public = */ ssh_generic_serialize_public, + /* .ssh_deserialize_public = */ ssh_generic_deserialize_public, + /* .ssh_serialize_private = */ ssh_generic_serialize_private, + /* .ssh_deserialize_private = */ ssh_generic_deserialize_private, + /* .generate = */ ssh_generic_generate, + /* .copy_public = */ ssh_generic_copy_public, + /* .sign = */ ssh_generic_sign, + /* .verify = */ ssh_generic_verify, +}; + +const struct sshkey_impl sshkey_ecdsanistp384_dilithium3_impl = { + /* .name = */ "ssh-ecdsa-nistp384-dilithium3", + /* .shortname = */ "ECDSA_NISTP384_DILITHIUM3", + /* .sigalg = */ NULL, + /* .type = */ KEY_ECDSA_NISTP384_DILITHIUM_3, + /* .nid = */ NID_secp384r1, + /* .cert = */ 0, + /* .sigonly = */ 0, + /* .keybits = */ 256, // TODO - What should be here? + /* .funcs = */ &sshkey_ecdsanistp384_dilithium3_funcs, +}; +static const struct sshkey_impl_funcs sshkey_ecdsanistp521_dilithium5_funcs = { + /* .size = */ ssh_generic_size, + /* .alloc = */ ssh_generic_alloc, + /* .cleanup = */ ssh_generic_cleanup, + /* .equal = */ ssh_generic_equal, + /* .ssh_serialize_public = */ ssh_generic_serialize_public, + /* .ssh_deserialize_public = */ ssh_generic_deserialize_public, + /* .ssh_serialize_private = */ ssh_generic_serialize_private, + /* .ssh_deserialize_private = */ ssh_generic_deserialize_private, + /* .generate = */ ssh_generic_generate, + /* .copy_public = */ ssh_generic_copy_public, + /* .sign = */ ssh_generic_sign, + /* .verify = */ ssh_generic_verify, +}; + +const struct sshkey_impl sshkey_ecdsanistp521_dilithium5_impl = { + /* .name = */ "ssh-ecdsa-nistp521-dilithium5", + /* .shortname = */ "ECDSA_NISTP521_DILITHIUM5", + /* .sigalg = */ NULL, + /* .type = */ KEY_ECDSA_NISTP521_DILITHIUM_5, + /* .nid = */ NID_secp521r1, + /* .cert = */ 0, + /* .sigonly = */ 0, + /* .keybits = */ 256, // TODO - What should be here? + /* .funcs = */ &sshkey_ecdsanistp521_dilithium5_funcs, +}; +static const struct sshkey_impl_funcs sshkey_ecdsanistp256_sphincssha2128fsimple_funcs = { + /* .size = */ ssh_generic_size, + /* .alloc = */ ssh_generic_alloc, + /* .cleanup = */ ssh_generic_cleanup, + /* .equal = */ ssh_generic_equal, + /* .ssh_serialize_public = */ ssh_generic_serialize_public, + /* .ssh_deserialize_public = */ ssh_generic_deserialize_public, + /* .ssh_serialize_private = */ ssh_generic_serialize_private, + /* .ssh_deserialize_private = */ ssh_generic_deserialize_private, + /* .generate = */ ssh_generic_generate, + /* .copy_public = */ ssh_generic_copy_public, + /* .sign = */ ssh_generic_sign, + /* .verify = */ ssh_generic_verify, +}; + +const struct sshkey_impl sshkey_ecdsanistp256_sphincssha2128fsimple_impl = { + /* .name = */ "ssh-ecdsa-nistp256-sphincssha2128fsimple", + /* .shortname = */ "ECDSA_NISTP256_SPHINCSSHA2128FSIMPLE", + /* .sigalg = */ NULL, + /* .type = */ KEY_ECDSA_NISTP256_SPHINCS_SHA2_128F_SIMPLE, + /* .nid = */ NID_X9_62_prime256v1, + /* .cert = */ 0, + /* .sigonly = */ 0, + /* .keybits = */ 256, // TODO - What should be here? + /* .funcs = */ &sshkey_ecdsanistp256_sphincssha2128fsimple_funcs, +}; +static const struct sshkey_impl_funcs sshkey_ecdsanistp521_sphincssha2256fsimple_funcs = { + /* .size = */ ssh_generic_size, + /* .alloc = */ ssh_generic_alloc, + /* .cleanup = */ ssh_generic_cleanup, + /* .equal = */ ssh_generic_equal, + /* .ssh_serialize_public = */ ssh_generic_serialize_public, + /* .ssh_deserialize_public = */ ssh_generic_deserialize_public, + /* .ssh_serialize_private = */ ssh_generic_serialize_private, + /* .ssh_deserialize_private = */ ssh_generic_deserialize_private, + /* .generate = */ ssh_generic_generate, + /* .copy_public = */ ssh_generic_copy_public, + /* .sign = */ ssh_generic_sign, + /* .verify = */ ssh_generic_verify, +}; + +const struct sshkey_impl sshkey_ecdsanistp521_sphincssha2256fsimple_impl = { + /* .name = */ "ssh-ecdsa-nistp521-sphincssha2256fsimple", + /* .shortname = */ "ECDSA_NISTP521_SPHINCSSHA2256FSIMPLE", + /* .sigalg = */ NULL, + /* .type = */ KEY_ECDSA_NISTP521_SPHINCS_SHA2_256F_SIMPLE, + /* .nid = */ NID_secp521r1, + /* .cert = */ 0, + /* .sigonly = */ 0, + /* .keybits = */ 256, // TODO - What should be here? + /* .funcs = */ &sshkey_ecdsanistp521_sphincssha2256fsimple_funcs, +}; +#endif /* OPENSSL_HAS_ECC */ #endif /* WITH_OPENSSL */ ///// OQS_TEMPLATE_FRAGMENT_DEFINE_SIG_FUNCTIONS_END + + +const struct sshkey_impl *oqs_classical_sshkey_impl(const struct sshkey *k) +{ + const struct sshkey_impl *impl = NULL; + switch(k->type) { + CASE_KEY_RSA_HYBRID: + impl = &sshkey_rsa_impl; + break; + CASE_KEY_ECDSA_HYBRID: + // Behind the P-256 impl struct is a generic ECDSA implementation which + // multiplexes off of either the bits or key->nid parameters passed into + // the interface. This behavior is in-line with the "normal" ECDSA code. + impl = &sshkey_ecdsa_nistp256_impl; + break; + } + return impl; +} + +const struct sshkey_impl *oqs_pq_sshkey_impl(const struct sshkey *k) +{ + const struct sshkey_impl *impl = NULL; + switch(k->type) { +///// OQS_TEMPLATE_FRAGMENT_IMPL_LOOKUP_CASES_START + case KEY_FALCON_512: + case KEY_RSA3072_FALCON_512: + case KEY_ECDSA_NISTP256_FALCON_512: + impl = &sshkey_falcon512_impl; + break; + case KEY_FALCON_1024: + case KEY_ECDSA_NISTP521_FALCON_1024: + impl = &sshkey_falcon1024_impl; + break; + case KEY_DILITHIUM_2: + case KEY_RSA3072_DILITHIUM_2: + case KEY_ECDSA_NISTP256_DILITHIUM_2: + impl = &sshkey_dilithium2_impl; + break; + case KEY_DILITHIUM_3: + case KEY_ECDSA_NISTP384_DILITHIUM_3: + impl = &sshkey_dilithium3_impl; + break; + case KEY_DILITHIUM_5: + case KEY_ECDSA_NISTP521_DILITHIUM_5: + impl = &sshkey_dilithium5_impl; + break; + case KEY_SPHINCS_SHA2_128F_SIMPLE: + case KEY_RSA3072_SPHINCS_SHA2_128F_SIMPLE: + case KEY_ECDSA_NISTP256_SPHINCS_SHA2_128F_SIMPLE: + impl = &sshkey_sphincssha2128fsimple_impl; + break; + case KEY_SPHINCS_SHA2_256F_SIMPLE: + case KEY_ECDSA_NISTP521_SPHINCS_SHA2_256F_SIMPLE: + impl = &sshkey_sphincssha2256fsimple_impl; + break; +///// OQS_TEMPLATE_FRAGMENT_IMPL_LOOKUP_CASES_END + default: + break; + } + return impl; +} diff --git a/sshkey.c b/sshkey.c index d81c956462b0..14b3e9732654 100644 --- a/sshkey.c +++ b/sshkey.c @@ -142,8 +142,7 @@ extern const struct sshkey_impl sshkey_dilithium5_impl; extern const struct sshkey_impl sshkey_sphincssha2128fsimple_impl; extern const struct sshkey_impl sshkey_sphincssha2256fsimple_impl; -#ifdef HYBRID_IMPLEMENTATION_EXISTS -// #ifdef WITH_OPENSSL +#ifdef WITH_OPENSSL extern const struct sshkey_impl sshkey_rsa3072_falcon512_impl; extern const struct sshkey_impl sshkey_rsa3072_dilithium2_impl; extern const struct sshkey_impl sshkey_rsa3072_sphincssha2128fsimple_impl; @@ -205,8 +204,7 @@ const struct sshkey_impl * const keyimpls[] = { &sshkey_dilithium5_impl, &sshkey_sphincssha2128fsimple_impl, &sshkey_sphincssha2256fsimple_impl, -#ifdef HYBRID_IMPLEMENTATION_EXISTS -// #ifdef WITH_OPENSSL +#ifdef WITH_OPENSSL &sshkey_rsa3072_falcon512_impl, &sshkey_rsa3072_dilithium2_impl, &sshkey_rsa3072_sphincssha2128fsimple_impl,