From e18eb65e794c0be751473bd75332d8212e49a175 Mon Sep 17 00:00:00 2001 From: Gerardo Ravago Date: Tue, 2 Jul 2024 11:36:08 -0400 Subject: [PATCH] Apply upstream refactor to sshkey.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In PR #159 we resolved a massive merge conflict in `sshkey.c` by simply taking the upstream version and removing all PQ SSH key support from the trunk. This broke the build/tests and obviously the ability to use PQ SSH keys. This PR restores PQ SSH key support for "pure" PQ algorithms. A follow-up PR will bring back support for hybrid-PQ. This was done to break up the PRs and do things more incrementally. At a high-level, there was a major refactor of `sshkey` upstream which moved algorithm implementations to an OOP abstraction via the `sshkey_impl` struct. This allowed them to get rid of all the switch statements, encapsulate algorithm specific code, and standardize on a single factory method to get the right implementation. Some other minor things like the function signatures for sign/verify were updated to accept new optional arguments. Getting OQS over to this new system was a matter of defining these `sshkey_impl` structs and factoring out the relevant OQS bits to the proper functions. This involved a number of changes/renames/deletions to the templates. I also performed a 3-way merge to pull-in changes that weren't directly impacted by the refactor. There is no support for hybrid SSH Key support for now. This is to make sure that the baseline refactor is in a good shape before committing to a certain path. To support hybrid, I propose implementing generic hybrid versions of these classes. The only tricky thing is figuring out how to expose the RSA/EC implementations to the `ssh-oqs` file (probably declaring externs?). I considered doing this "on the outside", but that seems to go against what the refactor aimed to do and adds a lot more complexity to the sshkey source than seems necessary. What's working now? - `build_openssh.sh` now compiles and installs successfully 🎉 - `make tests` runs through a lot of tests before failing now. This is my next line of inquiry to chase down. Signed-off-by: Gerardo Ravago --- kexgen.c | 14 +- monitor.c | 2 +- oqs-template/generate.py | 0 .../print_resource_records.fragment | 4 +- .../ssh-oqs.c/define_sig_functions.fragment | 87 ++- oqs-template/ssh-oqs.c/return_pk_len.fragment | 8 + oqs-template/ssh-oqs.c/return_sk_len.fragment | 8 + .../sshkey.c/define_keytypes.fragment | 20 +- .../sshkey.c/extern_key_impls.fragment | 20 + oqs-template/sshkey.c/return_pk_len.fragment | 8 - oqs-template/sshkey.c/return_sk_len.fragment | 8 - .../sshkey_generate_switch_keytype.fragment | 24 - .../sshkey_sign_switch_keytype.fragment | 24 - .../sshkey_verify_switch_keytype.fragment | 21 - .../sshkey.h/declare_prototypes.fragment | 5 - ssh-keygen.c | 68 +-- ssh-keyscan.c | 2 +- ssh-oqs.c | 560 ++++++++++++++++++ ssh_api.c | 4 +- sshconnect2.c | 2 +- sshkey.c | 58 +- 21 files changed, 793 insertions(+), 154 deletions(-) mode change 100644 => 100755 oqs-template/generate.py create mode 100644 oqs-template/ssh-oqs.c/return_pk_len.fragment create mode 100644 oqs-template/ssh-oqs.c/return_sk_len.fragment create mode 100644 oqs-template/sshkey.c/extern_key_impls.fragment delete mode 100644 oqs-template/sshkey.c/return_pk_len.fragment delete mode 100644 oqs-template/sshkey.c/return_sk_len.fragment delete mode 100644 oqs-template/sshkey.c/sshkey_generate_switch_keytype.fragment delete mode 100644 oqs-template/sshkey.c/sshkey_sign_switch_keytype.fragment delete mode 100644 oqs-template/sshkey.c/sshkey_verify_switch_keytype.fragment delete mode 100644 oqs-template/sshkey.h/declare_prototypes.fragment diff --git a/kexgen.c b/kexgen.c index fd3639daf3a9..2eeafe6fedc7 100644 --- a/kexgen.c +++ b/kexgen.c @@ -619,31 +619,31 @@ input_kex_gen_init(int type, u_int32_t seq, struct ssh *ssh) ///// OQS_TEMPLATE_FRAGMENT_ADD_INIT_SWITCH_CASES_START case KEX_KEM_FRODOKEM_640_AES_SHA256: r = kex_kem_frodokem_640_aes_enc(kex, client_pubkey, - &server_pubkey, &shared_secret); + &server_pubkey, &shared_secret); break; case KEX_KEM_FRODOKEM_976_AES_SHA384: r = kex_kem_frodokem_976_aes_enc(kex, client_pubkey, - &server_pubkey, &shared_secret); + &server_pubkey, &shared_secret); break; case KEX_KEM_FRODOKEM_1344_AES_SHA512: r = kex_kem_frodokem_1344_aes_enc(kex, client_pubkey, - &server_pubkey, &shared_secret); + &server_pubkey, &shared_secret); break; case KEX_KEM_FRODOKEM_640_SHAKE_SHA256: r = kex_kem_frodokem_640_shake_enc(kex, client_pubkey, - &server_pubkey, &shared_secret); + &server_pubkey, &shared_secret); break; case KEX_KEM_FRODOKEM_976_SHAKE_SHA384: r = kex_kem_frodokem_976_shake_enc(kex, client_pubkey, - &server_pubkey, &shared_secret); + &server_pubkey, &shared_secret); break; case KEX_KEM_FRODOKEM_1344_SHAKE_SHA512: r = kex_kem_frodokem_1344_shake_enc(kex, client_pubkey, - &server_pubkey, &shared_secret); + &server_pubkey, &shared_secret); break; case KEX_KEM_KYBER_512_SHA256: r = kex_kem_kyber_512_enc(kex, client_pubkey, - &server_pubkey, &shared_secret); + &server_pubkey, &shared_secret); break; case KEX_KEM_KYBER_768_SHA384: r = kex_kem_kyber_768_enc(kex, client_pubkey, diff --git a/monitor.c b/monitor.c index 831373a19c3d..f1e8baafcc24 100644 --- a/monitor.c +++ b/monitor.c @@ -1775,7 +1775,7 @@ monitor_apply_keystate(struct ssh *ssh, struct monitor *pmonitor) kex->kex[KEX_KEM_HQC_192_SHA384] = kex_gen_server; kex->kex[KEX_KEM_HQC_256_SHA512] = kex_gen_server; #ifdef WITH_OPENSSL - #ifdef OPENSSL_HAS_ECC +#ifdef OPENSSL_HAS_ECC kex->kex[KEX_KEM_FRODOKEM_640_AES_ECDH_NISTP256_SHA256] = kex_gen_server; kex->kex[KEX_KEM_FRODOKEM_976_AES_ECDH_NISTP384_SHA384] = kex_gen_server; kex->kex[KEX_KEM_FRODOKEM_1344_AES_ECDH_NISTP521_SHA512] = kex_gen_server; diff --git a/oqs-template/generate.py b/oqs-template/generate.py old mode 100644 new mode 100755 diff --git a/oqs-template/ssh-keygen.c/print_resource_records.fragment b/oqs-template/ssh-keygen.c/print_resource_records.fragment index a9f54e82c774..5381a4def7d4 100644 --- a/oqs-template/ssh-keygen.c/print_resource_records.fragment +++ b/oqs-template/ssh-keygen.c/print_resource_records.fragment @@ -1,11 +1,11 @@ {%- for sig in config['sigs'] %} n += do_print_resource_record(pw, _PATH_HOST_{{ sig['name']|upper }}_KEY_FILE, rr_hostname, - print_generic); + print_generic, opts, nopts); {%- for alg in sig['mix_with'] %} n += do_print_resource_record(pw, _PATH_HOST_{{ alg['name']|upper }}_{{ sig['name']|upper }}_KEY_FILE, rr_hostname, - print_generic); + print_generic, opts, nopts); {%- endfor %} {%- endfor %} diff --git a/oqs-template/ssh-oqs.c/define_sig_functions.fragment b/oqs-template/ssh-oqs.c/define_sig_functions.fragment index 58fd0939c320..18cb6d37c7d5 100644 --- a/oqs-template/ssh-oqs.c/define_sig_functions.fragment +++ b/oqs-template/ssh-oqs.c/define_sig_functions.fragment @@ -1,37 +1,116 @@ {%- for sig in config['sigs'] %} +{%- set symbol_base_name = sig['name']|replace('_','') %} /*--------------------------------------------------- * {{ sig['name']|upper }} METHODS *--------------------------------------------------- */ -int ssh_{{ sig['name']|replace('_','') }}_sign(const struct sshkey *key, +static int ssh_{{ symbol_base_name }}_generate(struct sshkey *k, int bits) +{ + k->oqs_pk_len = oqs_sig_pk_len(k->type); + k->oqs_sk_len = oqs_sig_sk_len(k->type); + if ((k->oqs_pk = malloc(k->oqs_pk_len)) == NULL || + (k->oqs_sk = malloc(k->oqs_sk_len)) == NULL) { + return SSH_ERR_ALLOC_FAIL; + } + return OQS_SIG_{{ sig['name'] }}_keypair(k->oqs_pk, k->oqs_sk); +} + +int ssh_{{ symbol_base_name }}_sign(const 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) { OQS_SIG *sig = OQS_SIG_new(OQS_SIG_alg_{{ sig['name'] }}); if (sig == NULL) { return SSH_ERR_ALLOC_FAIL; } - int r = ssh_generic_sign(sig, "{{ sig['name']|replace('_','') }}", key, sigp, lenp, data, datalen, compat); + int r = ssh_generic_sign(sig, "{{ symbol_base_name }}", key, sigp, lenp, data, datalen, compat); OQS_SIG_free(sig); return r; } -int ssh_{{ sig['name']|replace('_','') }}_verify(const struct sshkey *key, + +int ssh_{{ symbol_base_name }}_verify(const struct sshkey *key, const u_char *signature, size_t signaturelen, const u_char *data, size_t datalen, + const char *alg, u_int compat) { 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, "{{ sig['name']|replace('_','') }}", key, signature, signaturelen, data, datalen, compat); + int r = ssh_generic_verify(sig, "{{ symbol_base_name }}", key, signature, signaturelen, data, datalen, compat); OQS_SIG_free(sig); return r; } + +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_{{ symbol_base_name }}_generate, + /* .copy_public = */ ssh_generic_copy_public, + /* .sign = */ ssh_{{ symbol_base_name }}_sign, + /* .verify = */ ssh_{{ symbol_base_name }}_verify, +}; + +const struct sshkey_impl sshkey_{{ symbol_base_name }}_impl = { + /* .name = */ "ssh-{{ symbol_base_name }}", + /* .shortname = */ "{{ symbol_base_name|upper }}", + /* .sigalg = */ NULL, + /* .type = */ KEY_{{ sig['name']|upper }}, + /* .nid = */ 0, + /* .cert = */ 0, + /* .sigonly = */ 0, + /* .keybits = */ 256, // TODO - What should be here? + /* .funcs = */ &sshkey_{{ symbol_base_name }}_funcs, +}; +{%- endfor %} + +#ifdef HYBRID_IMPLEMENTATION_EXISTS +// #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('_','') %} +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_{{ symbol_base_name }}_generate, + /* .copy_public = */ ssh_generic_copy_public, + /* .sign = */ ssh_{{ symbol_base_name }}_sign, + /* .verify = */ ssh_{{ symbol_base_name }}_verify, +}; + +const struct sshkey_impl sshkey_{{ symbol_base_name }}_impl = { + /* .name = */ "ssh-{{ symbol_base_name }}", + /* .shortname = */ "{{ symbol_base_name|upper }}", + /* .sigalg = */ NULL, + /* .type = */ KEY_{{ sig['name']|upper }}, + /* .nid = */ 0, + /* .cert = */ 0, + /* .sigonly = */ 0, + /* .keybits = */ 256, // TODO - What should be here? + /* .funcs = */ &sshkey_{{ symbol_base_name }}_funcs, +}; +{%- endfor %} {%- endfor %} +#endif /* WITH_OPENSSL */ diff --git a/oqs-template/ssh-oqs.c/return_pk_len.fragment b/oqs-template/ssh-oqs.c/return_pk_len.fragment new file mode 100644 index 000000000000..f873e6527ca4 --- /dev/null +++ b/oqs-template/ssh-oqs.c/return_pk_len.fragment @@ -0,0 +1,8 @@ +{%- 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 -%} + return OQS_SIG_{{ sig['name'] }}_length_public_key; +{%- endfor %} + diff --git a/oqs-template/ssh-oqs.c/return_sk_len.fragment b/oqs-template/ssh-oqs.c/return_sk_len.fragment new file mode 100644 index 000000000000..0d1c22cbc68c --- /dev/null +++ b/oqs-template/ssh-oqs.c/return_sk_len.fragment @@ -0,0 +1,8 @@ +{%- 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 %} + return OQS_SIG_{{ sig['name'] }}_length_secret_key; +{%- endfor %} + diff --git a/oqs-template/sshkey.c/define_keytypes.fragment b/oqs-template/sshkey.c/define_keytypes.fragment index e0afe2207f0b..2bf9d9345b99 100644 --- a/oqs-template/sshkey.c/define_keytypes.fragment +++ b/oqs-template/sshkey.c/define_keytypes.fragment @@ -1,20 +1,18 @@ {%- for sig in config['sigs'] %} - { "ssh-{{ sig['name']|replace('_','') }}", "{{ sig['name']|replace('_','')|upper }}", NULL, - KEY_{{ sig['name']|upper }}, 0, 0, 0 }, + &sshkey_{{ sig['name']|replace('_','') }}_impl, {%- endfor %} -#ifdef WITH_OPENSSL +#ifdef HYBRID_IMPLEMENTATION_EXISTS +// #ifdef WITH_OPENSSL {%- for sig in config['sigs'] %} - {%- for alg in sig['mix_with'] if alg['rsa'] %} - { "ssh-{{ alg['name'] }}-{{ sig['name']|replace('_','') }}", "{{ alg['name']|upper }}_{{ sig['name']|replace('_','')|upper }}", NULL, - KEY_{{ alg['name']|upper }}_{{ sig['name']|upper }}, 0, 0, 0 }, - {%- endfor %} + {%- for alg in sig['mix_with'] if alg['rsa'] %} + &sshkey_{{ alg['name']|replace('_','') }}_{{ sig['name']|replace('_','') }}_impl, + {%- endfor %} {%- endfor %} #ifdef OPENSSL_HAS_ECC {%- for sig in config['sigs'] %} - {%- for alg in sig['mix_with'] if not alg['rsa'] %} - { "ssh-{{ alg['name']|replace('_','-') }}-{{ sig['name']|replace('_','') }}", "{{ alg['name']|upper }}_{{ sig['name']|replace('_','')|upper }}", NULL, - KEY_{{ alg['name']|upper }}_{{ sig['name']|upper }}, {{ alg['openssl_nid'] }}, 0, 0 }, - {%- endfor %} + {%- for alg in sig['mix_with'] if not alg['rsa'] %} + &sshkey_{{ alg['name']|replace('_','') }}_{{ sig['name']|replace('_','') }}_impl, + {%- endfor %} {%- endfor %} #endif /* OPENSSL_HAS_ECC */ #endif /* WITH_OPENSSL */ diff --git a/oqs-template/sshkey.c/extern_key_impls.fragment b/oqs-template/sshkey.c/extern_key_impls.fragment new file mode 100644 index 000000000000..6cb7e3c1acc8 --- /dev/null +++ b/oqs-template/sshkey.c/extern_key_impls.fragment @@ -0,0 +1,20 @@ +{%- for sig in config['sigs'] %} +extern const struct sshkey_impl sshkey_{{ sig['name']|replace('_','') }}_impl; +{%- endfor %} + +#ifdef HYBRID_IMPLEMENTATION_EXISTS +// #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; + {%- endfor %} +{%- endfor %} +#ifdef OPENSSL_HAS_ECC +{%- for sig in config['sigs'] %} + {%- for alg in sig['mix_with'] if not alg['rsa'] %} +extern const struct sshkey_impl sshkey_{{ alg['name']|replace('_','') }}_{{ sig['name']|replace('_','') }}_impl; + {%- endfor %} +{%- endfor %} +#endif /* OPENSSL_HAS_ECC */ +#endif /* WITH_OPENSSL */ + diff --git a/oqs-template/sshkey.c/return_pk_len.fragment b/oqs-template/sshkey.c/return_pk_len.fragment deleted file mode 100644 index 4407e64b020d..000000000000 --- a/oqs-template/sshkey.c/return_pk_len.fragment +++ /dev/null @@ -1,8 +0,0 @@ -{%- 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 -%} - return OQS_SIG_{{ sig['name'] }}_length_public_key; -{%- endfor %} - diff --git a/oqs-template/sshkey.c/return_sk_len.fragment b/oqs-template/sshkey.c/return_sk_len.fragment deleted file mode 100644 index 4061a04021b4..000000000000 --- a/oqs-template/sshkey.c/return_sk_len.fragment +++ /dev/null @@ -1,8 +0,0 @@ -{%- 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 %} - return OQS_SIG_{{ sig['name'] }}_length_secret_key; -{%- endfor %} - diff --git a/oqs-template/sshkey.c/sshkey_generate_switch_keytype.fragment b/oqs-template/sshkey.c/sshkey_generate_switch_keytype.fragment deleted file mode 100644 index 9b168117b674..000000000000 --- a/oqs-template/sshkey.c/sshkey_generate_switch_keytype.fragment +++ /dev/null @@ -1,24 +0,0 @@ -{%- for sig in config['sigs'] %} - case KEY_{{ sig['name']|upper }}: - ret = OQS_SIG_{{ sig['name'] }}_keypair(k->oqs_pk, k->oqs_sk); - break; -{%- endfor %} -#ifdef WITH_OPENSSL -{%- for sig in config['sigs'] %} - {%- for alg in sig['mix_with'] if alg['rsa'] %} - case KEY_{{ alg['name']|upper }}_{{ sig['name']|upper }}: - ret = OQS_SIG_{{ sig['name'] }}_keypair(k->oqs_pk, k->oqs_sk); - break; - {%- endfor %} -{%- endfor %} -#ifdef OPENSSL_HAS_ECC -{%- for sig in config['sigs'] %} - {%- for alg in sig['mix_with'] if not alg['rsa'] %} - case KEY_{{ alg['name']|upper }}_{{ sig['name']|upper }}: - ret = OQS_SIG_{{ sig['name'] }}_keypair(k->oqs_pk, k->oqs_sk); - break; - {%- endfor %} -{%- endfor %} -#endif /* OPENSSL_HAS_ECC */ -#endif /* WITH_OPENSSL */ - diff --git a/oqs-template/sshkey.c/sshkey_sign_switch_keytype.fragment b/oqs-template/sshkey.c/sshkey_sign_switch_keytype.fragment deleted file mode 100644 index f1680a2dec32..000000000000 --- a/oqs-template/sshkey.c/sshkey_sign_switch_keytype.fragment +++ /dev/null @@ -1,24 +0,0 @@ -{%- for sig in config['sigs'] %} - case KEY_{{ sig['name']|upper }}: - r = ssh_{{ sig['name']|replace('_','') }}_sign(key, &sig_pq, &len_pq, data, datalen, compat); - break; -{%- endfor %} -#ifdef WITH_OPENSSL -{%- for sig in config['sigs'] %} - {%- for alg in sig['mix_with'] if alg['rsa'] %} - case KEY_{{ alg['name']|upper }}_{{ sig['name']|upper }}: - r = ssh_{{ sig['name']|replace('_','') }}_sign(key, &sig_pq, &len_pq, data, datalen, compat); - break; - {%- endfor %} -{%- endfor %} -#ifdef OPENSSL_HAS_ECC -{%- for sig in config['sigs'] %} - {%- for alg in sig['mix_with'] if not alg['rsa'] %} - case KEY_{{ alg['name']|upper }}_{{ sig['name']|upper }}: - r = ssh_{{ sig['name']|replace('_','') }}_sign(key, &sig_pq, &len_pq, data, datalen, compat); - break; - {%- endfor %} -{%- endfor %} -#endif /* OPENSSL_HAS_ECC */ -#endif /* WITH_OPENSSL */ - diff --git a/oqs-template/sshkey.c/sshkey_verify_switch_keytype.fragment b/oqs-template/sshkey.c/sshkey_verify_switch_keytype.fragment deleted file mode 100644 index 3bfa085d3de7..000000000000 --- a/oqs-template/sshkey.c/sshkey_verify_switch_keytype.fragment +++ /dev/null @@ -1,21 +0,0 @@ -{%- for sig in config['sigs'] %} - case KEY_{{ sig['name']|upper }}: - return ssh_{{ sig['name']|replace('_', '') }}_verify(key, sig_pq, siglen_pq, data, dlen, compat); -{%- endfor %} -#ifdef WITH_OPENSSL -{%- for sig in config['sigs'] %} - {%- for alg in sig['mix_with'] if alg['rsa'] %} - case KEY_{{ alg['name']|upper }}_{{ sig['name']|upper }}: - return ssh_{{ sig['name']|replace('_', '') }}_verify(key, sig_pq, siglen_pq, data, dlen, compat); - {%- endfor %} -{%- endfor %} -#ifdef OPENSSL_HAS_ECC -{%- for sig in config['sigs'] %} - {%- for alg in sig['mix_with'] if not alg['rsa'] %} - case KEY_{{ alg['name']|upper }}_{{ sig['name']|upper }}: - return ssh_{{ sig['name']|replace('_', '') }}_verify(key, sig_pq, siglen_pq, data, dlen, compat); - {%- endfor %} -{%- endfor %} -#endif /* OPENSSL_HAS_ECC */ -#endif /* WITH_OPENSSL */ - diff --git a/oqs-template/sshkey.h/declare_prototypes.fragment b/oqs-template/sshkey.h/declare_prototypes.fragment deleted file mode 100644 index de414e5ced64..000000000000 --- a/oqs-template/sshkey.h/declare_prototypes.fragment +++ /dev/null @@ -1,5 +0,0 @@ -{%- for sig in config['sigs'] %} -int ssh_{{ sig['name']|replace('_','') }}_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, const u_char *data, size_t datalen, u_int compat); -int ssh_{{ sig['name']|replace('_', '') }}_verify(const struct sshkey *key, const u_char *signature, size_t signaturelen, const u_char *data, size_t datalen, u_int compat); -{%- endfor %} - diff --git a/ssh-keygen.c b/ssh-keygen.c index aefaca0261d9..c2866b373f92 100644 --- a/ssh-keygen.c +++ b/ssh-keygen.c @@ -3924,56 +3924,56 @@ main(int argc, char **argv) print_generic, opts, nopts); ///// OQS_TEMPLATE_FRAGMENT_PRINT_RESOURCE_RECORDS_START n += do_print_resource_record(pw, - _PATH_HOST_FALCON_512_KEY_FILE, rr_hostname, - print_generic, opts, nopts); + _PATH_HOST_FALCON_512_KEY_FILE, rr_hostname, + print_generic, opts, nopts); n += do_print_resource_record(pw, - _PATH_HOST_RSA3072_FALCON_512_KEY_FILE, rr_hostname, - print_generic, opts, nopts); + _PATH_HOST_RSA3072_FALCON_512_KEY_FILE, rr_hostname, + print_generic, opts, nopts); n += do_print_resource_record(pw, - _PATH_HOST_ECDSA_NISTP256_FALCON_512_KEY_FILE, rr_hostname, - print_generic, opts, nopts); + _PATH_HOST_ECDSA_NISTP256_FALCON_512_KEY_FILE, rr_hostname, + print_generic, opts, nopts); n += do_print_resource_record(pw, - _PATH_HOST_FALCON_1024_KEY_FILE, rr_hostname, - print_generic, opts, nopts); + _PATH_HOST_FALCON_1024_KEY_FILE, rr_hostname, + print_generic, opts, nopts); n += do_print_resource_record(pw, - _PATH_HOST_ECDSA_NISTP521_FALCON_1024_KEY_FILE, rr_hostname, - print_generic, opts, nopts); + _PATH_HOST_ECDSA_NISTP521_FALCON_1024_KEY_FILE, rr_hostname, + print_generic, opts, nopts); n += do_print_resource_record(pw, - _PATH_HOST_DILITHIUM_2_KEY_FILE, rr_hostname, - print_generic, opts, nopts); + _PATH_HOST_DILITHIUM_2_KEY_FILE, rr_hostname, + print_generic, opts, nopts); n += do_print_resource_record(pw, - _PATH_HOST_RSA3072_DILITHIUM_2_KEY_FILE, rr_hostname, - print_generic, opts, nopts); + _PATH_HOST_RSA3072_DILITHIUM_2_KEY_FILE, rr_hostname, + print_generic, opts, nopts); n += do_print_resource_record(pw, - _PATH_HOST_ECDSA_NISTP256_DILITHIUM_2_KEY_FILE, rr_hostname, - print_generic, opts, nopts); + _PATH_HOST_ECDSA_NISTP256_DILITHIUM_2_KEY_FILE, rr_hostname, + print_generic, opts, nopts); n += do_print_resource_record(pw, - _PATH_HOST_DILITHIUM_3_KEY_FILE, rr_hostname, - print_generic, opts, nopts); + _PATH_HOST_DILITHIUM_3_KEY_FILE, rr_hostname, + print_generic, opts, nopts); n += do_print_resource_record(pw, - _PATH_HOST_ECDSA_NISTP384_DILITHIUM_3_KEY_FILE, rr_hostname, - print_generic, opts, nopts); + _PATH_HOST_ECDSA_NISTP384_DILITHIUM_3_KEY_FILE, rr_hostname, + print_generic, opts, nopts); n += do_print_resource_record(pw, - _PATH_HOST_DILITHIUM_5_KEY_FILE, rr_hostname, - print_generic, opts, nopts); + _PATH_HOST_DILITHIUM_5_KEY_FILE, rr_hostname, + print_generic, opts, nopts); n += do_print_resource_record(pw, - _PATH_HOST_ECDSA_NISTP521_DILITHIUM_5_KEY_FILE, rr_hostname, - print_generic, opts, nopts); + _PATH_HOST_ECDSA_NISTP521_DILITHIUM_5_KEY_FILE, rr_hostname, + print_generic, opts, nopts); n += do_print_resource_record(pw, - _PATH_HOST_SPHINCS_SHA2_128F_SIMPLE_KEY_FILE, rr_hostname, - print_generic, opts, nopts); + _PATH_HOST_SPHINCS_SHA2_128F_SIMPLE_KEY_FILE, rr_hostname, + print_generic, opts, nopts); n += do_print_resource_record(pw, - _PATH_HOST_RSA3072_SPHINCS_SHA2_128F_SIMPLE_KEY_FILE, rr_hostname, - print_generic, opts, nopts); + _PATH_HOST_RSA3072_SPHINCS_SHA2_128F_SIMPLE_KEY_FILE, rr_hostname, + print_generic, opts, nopts); n += do_print_resource_record(pw, - _PATH_HOST_ECDSA_NISTP256_SPHINCS_SHA2_128F_SIMPLE_KEY_FILE, rr_hostname, - print_generic, opts, nopts); + _PATH_HOST_ECDSA_NISTP256_SPHINCS_SHA2_128F_SIMPLE_KEY_FILE, rr_hostname, + print_generic, opts, nopts); n += do_print_resource_record(pw, - _PATH_HOST_SPHINCS_SHA2_256F_SIMPLE_KEY_FILE, rr_hostname, - print_generic, opts, nopts); + _PATH_HOST_SPHINCS_SHA2_256F_SIMPLE_KEY_FILE, rr_hostname, + print_generic, opts, nopts); n += do_print_resource_record(pw, - _PATH_HOST_ECDSA_NISTP521_SPHINCS_SHA2_256F_SIMPLE_KEY_FILE, rr_hostname, - print_generic, opts, nopts); + _PATH_HOST_ECDSA_NISTP521_SPHINCS_SHA2_256F_SIMPLE_KEY_FILE, rr_hostname, + print_generic, opts, nopts); ///// OQS_TEMPLATE_FRAGMENT_PRINT_RESOURCE_RECORDS_END if (n == 0) fatal("no keys found."); diff --git a/ssh-keyscan.c b/ssh-keyscan.c index adc0e576cedb..b1d82f17e63b 100644 --- a/ssh-keyscan.c +++ b/ssh-keyscan.c @@ -427,7 +427,7 @@ keygrab_ssh2(con *c) c->c_ssh->kex->kex[KEX_KEM_HQC_192_SHA384] = kex_gen_client; c->c_ssh->kex->kex[KEX_KEM_HQC_256_SHA512] = kex_gen_client; #ifdef WITH_OPENSSL - #ifdef OPENSSL_HAS_ECC +#ifdef OPENSSL_HAS_ECC c->c_ssh->kex->kex[KEX_KEM_FRODOKEM_640_AES_ECDH_NISTP256_SHA256] = kex_gen_client; c->c_ssh->kex->kex[KEX_KEM_FRODOKEM_976_AES_ECDH_NISTP384_SHA384] = kex_gen_client; c->c_ssh->kex->kex[KEX_KEM_FRODOKEM_1344_AES_ECDH_NISTP521_SHA512] = kex_gen_client; diff --git a/ssh-oqs.c b/ssh-oqs.c index 56b22a380b10..ad290511e8e7 100644 --- a/ssh-oqs.c +++ b/ssh-oqs.c @@ -34,6 +34,183 @@ #include "oqs/oqs.h" +/* returns the size of an oqs public key */ +static size_t oqs_sig_pk_len(int type) +{ + switch (type) { +///// OQS_TEMPLATE_FRAGMENT_RETURN_PK_LEN_START + case KEY_FALCON_512: + case KEY_RSA3072_FALCON_512: + case KEY_ECDSA_NISTP256_FALCON_512:return OQS_SIG_falcon_512_length_public_key; + case KEY_FALCON_1024: + case KEY_ECDSA_NISTP521_FALCON_1024:return OQS_SIG_falcon_1024_length_public_key; + case KEY_DILITHIUM_2: + case KEY_RSA3072_DILITHIUM_2: + case KEY_ECDSA_NISTP256_DILITHIUM_2:return OQS_SIG_dilithium_2_length_public_key; + case KEY_DILITHIUM_3: + case KEY_ECDSA_NISTP384_DILITHIUM_3:return OQS_SIG_dilithium_3_length_public_key; + case KEY_DILITHIUM_5: + case KEY_ECDSA_NISTP521_DILITHIUM_5:return OQS_SIG_dilithium_5_length_public_key; + case KEY_SPHINCS_SHA2_128F_SIMPLE: + case KEY_RSA3072_SPHINCS_SHA2_128F_SIMPLE: + case KEY_ECDSA_NISTP256_SPHINCS_SHA2_128F_SIMPLE:return OQS_SIG_sphincs_sha2_128f_simple_length_public_key; + case KEY_SPHINCS_SHA2_256F_SIMPLE: + case KEY_ECDSA_NISTP521_SPHINCS_SHA2_256F_SIMPLE:return OQS_SIG_sphincs_sha2_256f_simple_length_public_key; +///// OQS_TEMPLATE_FRAGMENT_RETURN_PK_LEN_END + } + return 0; +} + +/* returns the size of an oqs secret key */ +static size_t oqs_sig_sk_len(int type) +{ + switch (type) { +///// OQS_TEMPLATE_FRAGMENT_RETURN_SK_LEN_START + case KEY_FALCON_512: + case KEY_RSA3072_FALCON_512: + case KEY_ECDSA_NISTP256_FALCON_512: + return OQS_SIG_falcon_512_length_secret_key; + case KEY_FALCON_1024: + case KEY_ECDSA_NISTP521_FALCON_1024: + return OQS_SIG_falcon_1024_length_secret_key; + case KEY_DILITHIUM_2: + case KEY_RSA3072_DILITHIUM_2: + case KEY_ECDSA_NISTP256_DILITHIUM_2: + return OQS_SIG_dilithium_2_length_secret_key; + case KEY_DILITHIUM_3: + case KEY_ECDSA_NISTP384_DILITHIUM_3: + return OQS_SIG_dilithium_3_length_secret_key; + case KEY_DILITHIUM_5: + case KEY_ECDSA_NISTP521_DILITHIUM_5: + return OQS_SIG_dilithium_5_length_secret_key; + case KEY_SPHINCS_SHA2_128F_SIMPLE: + case KEY_RSA3072_SPHINCS_SHA2_128F_SIMPLE: + case KEY_ECDSA_NISTP256_SPHINCS_SHA2_128F_SIMPLE: + return OQS_SIG_sphincs_sha2_128f_simple_length_secret_key; + case KEY_SPHINCS_SHA2_256F_SIMPLE: + case KEY_ECDSA_NISTP521_SPHINCS_SHA2_256F_SIMPLE: + return OQS_SIG_sphincs_sha2_256f_simple_length_secret_key; +///// OQS_TEMPLATE_FRAGMENT_RETURN_SK_LEN_END + } + return 0; +} + +static int ssh_generic_size(struct sshkey *k) +{ + return k->oqs_pk_len; +} + +static int ssh_generic_alloc(struct sshkey *k) +{ + 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); + return 0; +} + +static void ssh_generic_cleanup(struct sshkey *k) +{ + freezero(k->oqs_sk, k->oqs_sk_len); + k->oqs_sk = NULL; + freezero(k->oqs_pk, k->oqs_pk_len); + k->oqs_pk = NULL; +} + +static int ssh_generic_equal(const struct sshkey *a, const struct sshkey *b) +{ + if (a->oqs_pk == NULL || b->oqs_pk == NULL) { + return 0; + } + if (a->oqs_pk_len != b->oqs_pk_len) { + return 0; + } + if (memcmp(a->oqs_pk, b->oqs_pk, a->oqs_pk_len) != 0) { + return 0; + } + return 1; +} + +static int ssh_generic_serialize_public(const struct sshkey *key, + struct sshbuf *b, enum sshkey_serialize_rep opts) +{ + int r; + if (key->oqs_pk == NULL) { + return SSH_ERR_INVALID_ARGUMENT; + } + if ((r = sshbuf_put_string(b, key->oqs_pk, key->oqs_pk_len)) != 0) { + return r; + } + return 0; +} + +static int ssh_generic_deserialize_public(const char *ktype, struct sshbuf *b, + struct sshkey *key) +{ + u_char *pk = NULL; + size_t len = 0; + int r; + + if ((r = sshbuf_get_string(b, &pk, &len)) != 0) { + return r; + } + if (len != key->oqs_pk_len) { + freezero(pk, len); + return SSH_ERR_INVALID_FORMAT; + } + key->oqs_pk = pk; + return 0; +} + +static int ssh_generic_serialize_private(const struct sshkey *key, + struct sshbuf *b, enum sshkey_serialize_rep opts) +{ + int 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; + } + return 0; +} + +static int ssh_generic_deserialize_private(const char *ktype, struct sshbuf *b, + struct sshkey *key) +{ + int r; + size_t pklen = 0; + size_t sklen = 0; + u_char *oqs_pk = NULL; + u_char *oqs_sk = NULL; + if ((r = sshbuf_get_string(b, &oqs_pk, &pklen)) != 0 || + (r = sshbuf_get_string(b, &oqs_sk, &sklen)) != 0) { + goto out; + } + if (pklen != key->oqs_pk_len || sklen != key->oqs_sk_len) { + r = SSH_ERR_INVALID_FORMAT; + goto out; + } + key->oqs_pk = oqs_pk; + key->oqs_sk = oqs_sk; + oqs_pk = NULL; + oqs_sk = NULL; + r = 0; + out: + freezero(oqs_pk, pklen); + freezero(oqs_sk, sklen); + return r; +} + +static int ssh_generic_copy_public(const struct sshkey *from, struct sshkey *to) +{ + if (from->oqs_pk != NULL) { + if ((to->oqs_pk = malloc(from->oqs_pk_len)) == NULL) { + return SSH_ERR_ALLOC_FAIL; + } + memcpy(to->oqs_pk, from->oqs_pk, from->oqs_pk_len); + } + return 0; +} + static int ssh_generic_sign(OQS_SIG *oqs_sig, const char *alg_pretty_name, const struct sshkey *key, @@ -182,11 +359,25 @@ static int ssh_generic_verify(OQS_SIG *oqs_sig, * FALCON_512 METHODS *--------------------------------------------------- */ +static int ssh_falcon512_generate(struct sshkey *k, int bits) +{ + k->oqs_pk_len = oqs_sig_pk_len(k->type); + k->oqs_sk_len = oqs_sig_sk_len(k->type); + if ((k->oqs_pk = malloc(k->oqs_pk_len)) == NULL || + (k->oqs_sk = malloc(k->oqs_sk_len)) == NULL) { + return SSH_ERR_ALLOC_FAIL; + } + return OQS_SIG_falcon_512_keypair(k->oqs_pk, k->oqs_sk); +} + int ssh_falcon512_sign(const 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) { OQS_SIG *sig = OQS_SIG_new(OQS_SIG_alg_falcon_512); @@ -197,11 +388,13 @@ int ssh_falcon512_sign(const struct sshkey *key, OQS_SIG_free(sig); return r; } + int ssh_falcon512_verify(const struct sshkey *key, const u_char *signature, size_t signaturelen, const u_char *data, size_t datalen, + const char *alg, u_int compat) { OQS_SIG *sig = OQS_SIG_new(OQS_SIG_alg_falcon_512); @@ -212,15 +405,56 @@ int ssh_falcon512_verify(const struct sshkey *key, OQS_SIG_free(sig); return r; } + +static const struct sshkey_impl_funcs sshkey_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_falcon512_generate, + /* .copy_public = */ ssh_generic_copy_public, + /* .sign = */ ssh_falcon512_sign, + /* .verify = */ ssh_falcon512_verify, +}; + +const struct sshkey_impl sshkey_falcon512_impl = { + /* .name = */ "ssh-falcon512", + /* .shortname = */ "FALCON512", + /* .sigalg = */ NULL, + /* .type = */ KEY_FALCON_512, + /* .nid = */ 0, + /* .cert = */ 0, + /* .sigonly = */ 0, + /* .keybits = */ 256, // TODO - What should be here? + /* .funcs = */ &sshkey_falcon512_funcs, +}; /*--------------------------------------------------- * FALCON_1024 METHODS *--------------------------------------------------- */ +static int ssh_falcon1024_generate(struct sshkey *k, int bits) +{ + k->oqs_pk_len = oqs_sig_pk_len(k->type); + k->oqs_sk_len = oqs_sig_sk_len(k->type); + if ((k->oqs_pk = malloc(k->oqs_pk_len)) == NULL || + (k->oqs_sk = malloc(k->oqs_sk_len)) == NULL) { + return SSH_ERR_ALLOC_FAIL; + } + return OQS_SIG_falcon_1024_keypair(k->oqs_pk, k->oqs_sk); +} + int ssh_falcon1024_sign(const 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) { OQS_SIG *sig = OQS_SIG_new(OQS_SIG_alg_falcon_1024); @@ -231,11 +465,13 @@ int ssh_falcon1024_sign(const struct sshkey *key, OQS_SIG_free(sig); return r; } + int ssh_falcon1024_verify(const struct sshkey *key, const u_char *signature, size_t signaturelen, const u_char *data, size_t datalen, + const char *alg, u_int compat) { OQS_SIG *sig = OQS_SIG_new(OQS_SIG_alg_falcon_1024); @@ -246,15 +482,56 @@ int ssh_falcon1024_verify(const struct sshkey *key, OQS_SIG_free(sig); return r; } + +static const struct sshkey_impl_funcs sshkey_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_falcon1024_generate, + /* .copy_public = */ ssh_generic_copy_public, + /* .sign = */ ssh_falcon1024_sign, + /* .verify = */ ssh_falcon1024_verify, +}; + +const struct sshkey_impl sshkey_falcon1024_impl = { + /* .name = */ "ssh-falcon1024", + /* .shortname = */ "FALCON1024", + /* .sigalg = */ NULL, + /* .type = */ KEY_FALCON_1024, + /* .nid = */ 0, + /* .cert = */ 0, + /* .sigonly = */ 0, + /* .keybits = */ 256, // TODO - What should be here? + /* .funcs = */ &sshkey_falcon1024_funcs, +}; /*--------------------------------------------------- * DILITHIUM_2 METHODS *--------------------------------------------------- */ +static int ssh_dilithium2_generate(struct sshkey *k, int bits) +{ + k->oqs_pk_len = oqs_sig_pk_len(k->type); + k->oqs_sk_len = oqs_sig_sk_len(k->type); + if ((k->oqs_pk = malloc(k->oqs_pk_len)) == NULL || + (k->oqs_sk = malloc(k->oqs_sk_len)) == NULL) { + return SSH_ERR_ALLOC_FAIL; + } + return OQS_SIG_dilithium_2_keypair(k->oqs_pk, k->oqs_sk); +} + int ssh_dilithium2_sign(const 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) { OQS_SIG *sig = OQS_SIG_new(OQS_SIG_alg_dilithium_2); @@ -265,11 +542,13 @@ int ssh_dilithium2_sign(const struct sshkey *key, OQS_SIG_free(sig); return r; } + int ssh_dilithium2_verify(const struct sshkey *key, const u_char *signature, size_t signaturelen, const u_char *data, size_t datalen, + const char *alg, u_int compat) { OQS_SIG *sig = OQS_SIG_new(OQS_SIG_alg_dilithium_2); @@ -280,15 +559,56 @@ int ssh_dilithium2_verify(const struct sshkey *key, OQS_SIG_free(sig); return r; } + +static const struct sshkey_impl_funcs sshkey_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_dilithium2_generate, + /* .copy_public = */ ssh_generic_copy_public, + /* .sign = */ ssh_dilithium2_sign, + /* .verify = */ ssh_dilithium2_verify, +}; + +const struct sshkey_impl sshkey_dilithium2_impl = { + /* .name = */ "ssh-dilithium2", + /* .shortname = */ "DILITHIUM2", + /* .sigalg = */ NULL, + /* .type = */ KEY_DILITHIUM_2, + /* .nid = */ 0, + /* .cert = */ 0, + /* .sigonly = */ 0, + /* .keybits = */ 256, // TODO - What should be here? + /* .funcs = */ &sshkey_dilithium2_funcs, +}; /*--------------------------------------------------- * DILITHIUM_3 METHODS *--------------------------------------------------- */ +static int ssh_dilithium3_generate(struct sshkey *k, int bits) +{ + k->oqs_pk_len = oqs_sig_pk_len(k->type); + k->oqs_sk_len = oqs_sig_sk_len(k->type); + if ((k->oqs_pk = malloc(k->oqs_pk_len)) == NULL || + (k->oqs_sk = malloc(k->oqs_sk_len)) == NULL) { + return SSH_ERR_ALLOC_FAIL; + } + return OQS_SIG_dilithium_3_keypair(k->oqs_pk, k->oqs_sk); +} + int ssh_dilithium3_sign(const 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) { OQS_SIG *sig = OQS_SIG_new(OQS_SIG_alg_dilithium_3); @@ -299,11 +619,13 @@ int ssh_dilithium3_sign(const struct sshkey *key, OQS_SIG_free(sig); return r; } + int ssh_dilithium3_verify(const struct sshkey *key, const u_char *signature, size_t signaturelen, const u_char *data, size_t datalen, + const char *alg, u_int compat) { OQS_SIG *sig = OQS_SIG_new(OQS_SIG_alg_dilithium_3); @@ -314,15 +636,56 @@ int ssh_dilithium3_verify(const struct sshkey *key, OQS_SIG_free(sig); return r; } + +static const struct sshkey_impl_funcs sshkey_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_dilithium3_generate, + /* .copy_public = */ ssh_generic_copy_public, + /* .sign = */ ssh_dilithium3_sign, + /* .verify = */ ssh_dilithium3_verify, +}; + +const struct sshkey_impl sshkey_dilithium3_impl = { + /* .name = */ "ssh-dilithium3", + /* .shortname = */ "DILITHIUM3", + /* .sigalg = */ NULL, + /* .type = */ KEY_DILITHIUM_3, + /* .nid = */ 0, + /* .cert = */ 0, + /* .sigonly = */ 0, + /* .keybits = */ 256, // TODO - What should be here? + /* .funcs = */ &sshkey_dilithium3_funcs, +}; /*--------------------------------------------------- * DILITHIUM_5 METHODS *--------------------------------------------------- */ +static int ssh_dilithium5_generate(struct sshkey *k, int bits) +{ + k->oqs_pk_len = oqs_sig_pk_len(k->type); + k->oqs_sk_len = oqs_sig_sk_len(k->type); + if ((k->oqs_pk = malloc(k->oqs_pk_len)) == NULL || + (k->oqs_sk = malloc(k->oqs_sk_len)) == NULL) { + return SSH_ERR_ALLOC_FAIL; + } + return OQS_SIG_dilithium_5_keypair(k->oqs_pk, k->oqs_sk); +} + int ssh_dilithium5_sign(const 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) { OQS_SIG *sig = OQS_SIG_new(OQS_SIG_alg_dilithium_5); @@ -333,11 +696,13 @@ int ssh_dilithium5_sign(const struct sshkey *key, OQS_SIG_free(sig); return r; } + int ssh_dilithium5_verify(const struct sshkey *key, const u_char *signature, size_t signaturelen, const u_char *data, size_t datalen, + const char *alg, u_int compat) { OQS_SIG *sig = OQS_SIG_new(OQS_SIG_alg_dilithium_5); @@ -348,15 +713,56 @@ int ssh_dilithium5_verify(const struct sshkey *key, OQS_SIG_free(sig); return r; } + +static const struct sshkey_impl_funcs sshkey_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_dilithium5_generate, + /* .copy_public = */ ssh_generic_copy_public, + /* .sign = */ ssh_dilithium5_sign, + /* .verify = */ ssh_dilithium5_verify, +}; + +const struct sshkey_impl sshkey_dilithium5_impl = { + /* .name = */ "ssh-dilithium5", + /* .shortname = */ "DILITHIUM5", + /* .sigalg = */ NULL, + /* .type = */ KEY_DILITHIUM_5, + /* .nid = */ 0, + /* .cert = */ 0, + /* .sigonly = */ 0, + /* .keybits = */ 256, // TODO - What should be here? + /* .funcs = */ &sshkey_dilithium5_funcs, +}; /*--------------------------------------------------- * SPHINCS_SHA2_128F_SIMPLE METHODS *--------------------------------------------------- */ +static int ssh_sphincssha2128fsimple_generate(struct sshkey *k, int bits) +{ + k->oqs_pk_len = oqs_sig_pk_len(k->type); + k->oqs_sk_len = oqs_sig_sk_len(k->type); + if ((k->oqs_pk = malloc(k->oqs_pk_len)) == NULL || + (k->oqs_sk = malloc(k->oqs_sk_len)) == NULL) { + return SSH_ERR_ALLOC_FAIL; + } + return OQS_SIG_sphincs_sha2_128f_simple_keypair(k->oqs_pk, k->oqs_sk); +} + int ssh_sphincssha2128fsimple_sign(const 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) { OQS_SIG *sig = OQS_SIG_new(OQS_SIG_alg_sphincs_sha2_128f_simple); @@ -367,11 +773,13 @@ int ssh_sphincssha2128fsimple_sign(const struct sshkey *key, OQS_SIG_free(sig); return r; } + int ssh_sphincssha2128fsimple_verify(const struct sshkey *key, const u_char *signature, size_t signaturelen, const u_char *data, size_t datalen, + const char *alg, u_int compat) { OQS_SIG *sig = OQS_SIG_new(OQS_SIG_alg_sphincs_sha2_128f_simple); @@ -382,15 +790,56 @@ int ssh_sphincssha2128fsimple_verify(const struct sshkey *key, OQS_SIG_free(sig); return r; } + +static const struct sshkey_impl_funcs sshkey_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_sphincssha2128fsimple_generate, + /* .copy_public = */ ssh_generic_copy_public, + /* .sign = */ ssh_sphincssha2128fsimple_sign, + /* .verify = */ ssh_sphincssha2128fsimple_verify, +}; + +const struct sshkey_impl sshkey_sphincssha2128fsimple_impl = { + /* .name = */ "ssh-sphincssha2128fsimple", + /* .shortname = */ "SPHINCSSHA2128FSIMPLE", + /* .sigalg = */ NULL, + /* .type = */ KEY_SPHINCS_SHA2_128F_SIMPLE, + /* .nid = */ 0, + /* .cert = */ 0, + /* .sigonly = */ 0, + /* .keybits = */ 256, // TODO - What should be here? + /* .funcs = */ &sshkey_sphincssha2128fsimple_funcs, +}; /*--------------------------------------------------- * SPHINCS_SHA2_256F_SIMPLE METHODS *--------------------------------------------------- */ +static int ssh_sphincssha2256fsimple_generate(struct sshkey *k, int bits) +{ + k->oqs_pk_len = oqs_sig_pk_len(k->type); + k->oqs_sk_len = oqs_sig_sk_len(k->type); + if ((k->oqs_pk = malloc(k->oqs_pk_len)) == NULL || + (k->oqs_sk = malloc(k->oqs_sk_len)) == NULL) { + return SSH_ERR_ALLOC_FAIL; + } + return OQS_SIG_sphincs_sha2_256f_simple_keypair(k->oqs_pk, k->oqs_sk); +} + int ssh_sphincssha2256fsimple_sign(const 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) { OQS_SIG *sig = OQS_SIG_new(OQS_SIG_alg_sphincs_sha2_256f_simple); @@ -401,11 +850,13 @@ int ssh_sphincssha2256fsimple_sign(const struct sshkey *key, OQS_SIG_free(sig); return r; } + int ssh_sphincssha2256fsimple_verify(const struct sshkey *key, const u_char *signature, size_t signaturelen, const u_char *data, size_t datalen, + const char *alg, u_int compat) { OQS_SIG *sig = OQS_SIG_new(OQS_SIG_alg_sphincs_sha2_256f_simple); @@ -416,4 +867,113 @@ int ssh_sphincssha2256fsimple_verify(const struct sshkey *key, OQS_SIG_free(sig); return r; } + +static const struct sshkey_impl_funcs sshkey_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_sphincssha2256fsimple_generate, + /* .copy_public = */ ssh_generic_copy_public, + /* .sign = */ ssh_sphincssha2256fsimple_sign, + /* .verify = */ ssh_sphincssha2256fsimple_verify, +}; + +const struct sshkey_impl sshkey_sphincssha2256fsimple_impl = { + /* .name = */ "ssh-sphincssha2256fsimple", + /* .shortname = */ "SPHINCSSHA2256FSIMPLE", + /* .sigalg = */ NULL, + /* .type = */ KEY_SPHINCS_SHA2_256F_SIMPLE, + /* .nid = */ 0, + /* .cert = */ 0, + /* .sigonly = */ 0, + /* .keybits = */ 256, // TODO - What should be here? + /* .funcs = */ &sshkey_sphincssha2256fsimple_funcs, +}; + +#ifdef HYBRID_IMPLEMENTATION_EXISTS +// #ifdef WITH_OPENSSL +static const struct sshkey_impl_funcs sshkey_rsa3072_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_rsa3072_falcon512_generate, + /* .copy_public = */ ssh_generic_copy_public, + /* .sign = */ ssh_rsa3072_falcon512_sign, + /* .verify = */ ssh_rsa3072_falcon512_verify, +}; + +const struct sshkey_impl sshkey_rsa3072_falcon512_impl = { + /* .name = */ "ssh-rsa3072_falcon512", + /* .shortname = */ "RSA3072_FALCON512", + /* .sigalg = */ NULL, + /* .type = */ KEY_FALCON_512, + /* .nid = */ 0, + /* .cert = */ 0, + /* .sigonly = */ 0, + /* .keybits = */ 256, // TODO - What should be here? + /* .funcs = */ &sshkey_rsa3072_falcon512_funcs, +}; +static const struct sshkey_impl_funcs sshkey_rsa3072_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_rsa3072_dilithium2_generate, + /* .copy_public = */ ssh_generic_copy_public, + /* .sign = */ ssh_rsa3072_dilithium2_sign, + /* .verify = */ ssh_rsa3072_dilithium2_verify, +}; + +const struct sshkey_impl sshkey_rsa3072_dilithium2_impl = { + /* .name = */ "ssh-rsa3072_dilithium2", + /* .shortname = */ "RSA3072_DILITHIUM2", + /* .sigalg = */ NULL, + /* .type = */ KEY_DILITHIUM_2, + /* .nid = */ 0, + /* .cert = */ 0, + /* .sigonly = */ 0, + /* .keybits = */ 256, // TODO - What should be here? + /* .funcs = */ &sshkey_rsa3072_dilithium2_funcs, +}; +static const struct sshkey_impl_funcs sshkey_rsa3072_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_rsa3072_sphincssha2128fsimple_generate, + /* .copy_public = */ ssh_generic_copy_public, + /* .sign = */ ssh_rsa3072_sphincssha2128fsimple_sign, + /* .verify = */ ssh_rsa3072_sphincssha2128fsimple_verify, +}; + +const struct sshkey_impl sshkey_rsa3072_sphincssha2128fsimple_impl = { + /* .name = */ "ssh-rsa3072_sphincssha2128fsimple", + /* .shortname = */ "RSA3072_SPHINCSSHA2128FSIMPLE", + /* .sigalg = */ NULL, + /* .type = */ KEY_SPHINCS_SHA2_128F_SIMPLE, + /* .nid = */ 0, + /* .cert = */ 0, + /* .sigonly = */ 0, + /* .keybits = */ 256, // TODO - What should be here? + /* .funcs = */ &sshkey_rsa3072_sphincssha2128fsimple_funcs, +}; +#endif /* WITH_OPENSSL */ ///// OQS_TEMPLATE_FRAGMENT_DEFINE_SIG_FUNCTIONS_END diff --git a/ssh_api.c b/ssh_api.c index 45dc3e5edc20..763002ac47bf 100644 --- a/ssh_api.c +++ b/ssh_api.c @@ -155,7 +155,7 @@ ssh_init(struct ssh **sshp, int is_server, struct kex_params *kex_params) ssh->kex->kex[KEX_KEM_HQC_192_SHA384] = kex_gen_server; ssh->kex->kex[KEX_KEM_HQC_256_SHA512] = kex_gen_server; #ifdef WITH_OPENSSL - #ifdef OPENSSL_HAS_ECC +#ifdef OPENSSL_HAS_ECC ssh->kex->kex[KEX_KEM_FRODOKEM_640_AES_ECDH_NISTP256_SHA256] = kex_gen_server; ssh->kex->kex[KEX_KEM_FRODOKEM_976_AES_ECDH_NISTP384_SHA384] = kex_gen_server; ssh->kex->kex[KEX_KEM_FRODOKEM_1344_AES_ECDH_NISTP521_SHA512] = kex_gen_server; @@ -227,7 +227,7 @@ ssh_init(struct ssh **sshp, int is_server, struct kex_params *kex_params) ssh->kex->kex[KEX_KEM_HQC_192_SHA384] = kex_gen_client; ssh->kex->kex[KEX_KEM_HQC_256_SHA512] = kex_gen_client; #ifdef WITH_OPENSSL - #ifdef OPENSSL_HAS_ECC +#ifdef OPENSSL_HAS_ECC ssh->kex->kex[KEX_KEM_FRODOKEM_640_AES_ECDH_NISTP256_SHA256] = kex_gen_client; ssh->kex->kex[KEX_KEM_FRODOKEM_976_AES_ECDH_NISTP384_SHA384] = kex_gen_client; ssh->kex->kex[KEX_KEM_FRODOKEM_1344_AES_ECDH_NISTP521_SHA512] = kex_gen_client; diff --git a/sshconnect2.c b/sshconnect2.c index 294d7be062d5..acadcce98779 100644 --- a/sshconnect2.c +++ b/sshconnect2.c @@ -303,7 +303,7 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port, ssh->kex->kex[KEX_KEM_HQC_192_SHA384] = kex_gen_client; ssh->kex->kex[KEX_KEM_HQC_256_SHA512] = kex_gen_client; #ifdef WITH_OPENSSL - #ifdef OPENSSL_HAS_ECC +#ifdef OPENSSL_HAS_ECC ssh->kex->kex[KEX_KEM_FRODOKEM_640_AES_ECDH_NISTP256_SHA256] = kex_gen_client; ssh->kex->kex[KEX_KEM_FRODOKEM_976_AES_ECDH_NISTP384_SHA384] = kex_gen_client; ssh->kex->kex[KEX_KEM_FRODOKEM_1344_AES_ECDH_NISTP521_SHA512] = kex_gen_client; diff --git a/sshkey.c b/sshkey.c index d4356e72cd61..d81c956462b0 100644 --- a/sshkey.c +++ b/sshkey.c @@ -67,6 +67,8 @@ #include "openbsd-compat/openssl-compat.h" +#include "oqs-utils.h" + /* openssh private key file format */ #define MARK_BEGIN "-----BEGIN OPENSSH PRIVATE KEY-----\n" #define MARK_END "-----END OPENSSH PRIVATE KEY-----\n" @@ -131,6 +133,32 @@ extern const struct sshkey_impl sshkey_xmss_impl; extern const struct sshkey_impl sshkey_xmss_cert_impl; #endif +///// OQS_TEMPLATE_FRAGMENT_EXTERN_KEY_IMPLS_START +extern const struct sshkey_impl sshkey_falcon512_impl; +extern const struct sshkey_impl sshkey_falcon1024_impl; +extern const struct sshkey_impl sshkey_dilithium2_impl; +extern const struct sshkey_impl sshkey_dilithium3_impl; +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 +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; +#ifdef OPENSSL_HAS_ECC +extern const struct sshkey_impl sshkey_ecdsanistp256_falcon512_impl; +extern const struct sshkey_impl sshkey_ecdsanistp521_falcon1024_impl; +extern const struct sshkey_impl sshkey_ecdsanistp256_dilithium2_impl; +extern const struct sshkey_impl sshkey_ecdsanistp384_dilithium3_impl; +extern const struct sshkey_impl sshkey_ecdsanistp521_dilithium5_impl; +extern const struct sshkey_impl sshkey_ecdsanistp256_sphincssha2128fsimple_impl; +extern const struct sshkey_impl sshkey_ecdsanistp521_sphincssha2256fsimple_impl; +#endif /* OPENSSL_HAS_ECC */ +#endif /* WITH_OPENSSL */ +///// OQS_TEMPLATE_FRAGMENT_EXTERN_KEY_IMPLS_END + const struct sshkey_impl * const keyimpls[] = { &sshkey_ed25519_impl, &sshkey_ed25519_cert_impl, @@ -169,6 +197,30 @@ const struct sshkey_impl * const keyimpls[] = { &sshkey_xmss_impl, &sshkey_xmss_cert_impl, #endif +///// OQS_TEMPLATE_FRAGMENT_DEFINE_KEYTYPES_START + &sshkey_falcon512_impl, + &sshkey_falcon1024_impl, + &sshkey_dilithium2_impl, + &sshkey_dilithium3_impl, + &sshkey_dilithium5_impl, + &sshkey_sphincssha2128fsimple_impl, + &sshkey_sphincssha2256fsimple_impl, +#ifdef HYBRID_IMPLEMENTATION_EXISTS +// #ifdef WITH_OPENSSL + &sshkey_rsa3072_falcon512_impl, + &sshkey_rsa3072_dilithium2_impl, + &sshkey_rsa3072_sphincssha2128fsimple_impl, +#ifdef OPENSSL_HAS_ECC + &sshkey_ecdsanistp256_falcon512_impl, + &sshkey_ecdsanistp521_falcon1024_impl, + &sshkey_ecdsanistp256_dilithium2_impl, + &sshkey_ecdsanistp384_dilithium3_impl, + &sshkey_ecdsanistp521_dilithium5_impl, + &sshkey_ecdsanistp256_sphincssha2128fsimple_impl, + &sshkey_ecdsanistp521_sphincssha2256fsimple_impl, +#endif /* OPENSSL_HAS_ECC */ +#endif /* WITH_OPENSSL */ +///// OQS_TEMPLATE_FRAGMENT_DEFINE_KEYTYPES_END NULL }; @@ -274,7 +326,7 @@ key_type_is_ecdsa_variant(int type) case KEY_ECDSA_SK_CERT: return 1; } - return 0; + return oqs_utils_is_ecdsa_hybrid(type); } int @@ -3317,7 +3369,9 @@ sshkey_private_to_fileblob(struct sshkey *key, struct sshbuf *blob, #endif /* WITH_XMSS */ #ifdef WITH_OPENSSL case KEY_ECDSA_SK: + CASE_KEY_HYBRID: #endif /* WITH_OPENSSL */ + CASE_KEY_OQS: return sshkey_private_to_blob2(key, blob, passphrase, comment, openssh_format_cipher, openssh_format_rounds); default: @@ -3575,6 +3629,8 @@ sshkey_parse_private_fileblob_type(struct sshbuf *blob, int type, switch (type) { case KEY_XMSS: + CASE_KEY_OQS: + CASE_KEY_HYBRID: /* No fallback for new-format-only keys */ return sshkey_parse_private2(blob, type, passphrase, keyp, commentp);