diff --git a/INSTALL b/INSTALL index 79d40e3a5..282feceb5 100644 --- a/INSTALL +++ b/INSTALL @@ -138,14 +138,19 @@ 15. Building with liboqs for TLS 1.3 [EXPERIMENTAL] In order be able to use liboqs, you must have it built and installed on your - system. We support the 0.7.0 release of liboqs. You can download it from - the following link: + system. We support liboqs at a specific git commit. - https://github.com/open-quantum-safe/liboqs/archive/refs/tags/0.7.0.tar.gz + NOTE: Even if you have already installed liboqs, you need to follow these + steps to install liboqs again as we support sphincs variants that are + disabled by default in OQS's fork of OpenSSL. - Once unpacked, this would be sufficient: + Here are instructions for obtaining and building liboqs: - $ cd liboqs-0.7.0 + $ mkdir ~/oqs + $ cd ~/oqs + $ git clone --single-branch https://github.com/open-quantum-safe/liboqs.git + $ cd liboqs/ + $ git checkout af76ca3b1f2fbc1f4f0967595f3bb07692fb3d82 $ mkdir build $ cd build $ cmake -DOQS_USE_OPENSSL=0 .. @@ -176,32 +181,24 @@ Using Post-Quantum KEM: P521_KYBER_LEVEL5 ``` - For authentication, you can generate a certificate chain using the Open - Quantum Safe project's fork of OpenSSL. We support certificates and keys - generated by the 2021-08 snapshot of the OQS-OpenSSL_1_1_1-stable branch - of the fork. You can download it from the following link: + For authentication, you can generate a certificate chain using a patch on + top of the Open Quantum Safe project's fork of OpenSSL. We support + certificates and keys generated by the patched version which is maintained + in our OSP repo. - https://github.com/open-quantum-safe/openssl/archive/refs/tags/OQS-OpenSSL_1_1_1-stable-snapshot-2021-08.tar.gz + Instructions for obtaining and building our patched version of OQS's fork of + OpenSSL can be found at: - Once unpacked, this would be sufficient for building it: + https://github.com/wolfSSL/osp/tree/master/oqs/README.md - $ cd openssl-OQS-OpenSSL_1_1_1-stable-snapshot-2021-08/ - $ ./config no-shared - $ make all - - Note that installation is NOT required. - - There is a script for generating a Falcon NIST Level 1 and NIST Level 5 - certificate chain which can be found in the wolfssl-examples github repo at - pq/generate_falcon_chains.sh. Please find detailed instructions on how to - generate and verify the keys and certificates in pq/README.md. As a quick- - start, simply copy generate_falcon_chains.sh into the - openssl-OQS-OpenSSL_1_1_1-stable-snapshot-2021-08 directory and execute the - script. + There are scripts for generating FALCON, Dilithium and SPHINCS+ certificate + chains which can be found in the same directory as the `README.md` file in + the `osp` github repo. Please find instructions on how to generate the keys + and certificates in the `README.md` file. Once the certificates and keys are generated, copy them from the - openssl-OQS-OpenSSL_1_1_1-stable-snapshot-2021-08/ directory to the certs - directory of wolfssl. Now you can run the server and client like this: + to the certs directory of wolfssl. Now you can run the server and client + like this: $ examples/server/server -v 4 -l TLS_AES_256_GCM_SHA384 \ -A certs/falcon_level5_root_cert.pem \ @@ -218,13 +215,18 @@ Congratulations! You have just achieved a fully quantum-safe TLS 1.3 connection! - The following NIST Competition Round 3 Finalist algorithms are supported: + The following NIST Competition winning algorithms are supported: - CRYSTALS-KYBER (KEM) + - Dilithium (signature scheme) + - FALCON (signature scheme) + - SPHINCS+ (signature scheme) + + The following NIST Competition Round 3 finalist algorithms are supported, + but are deprecated and will be removed soon: - SABER (KEM) - NTRU (KEM) - - FALCON (signature scheme) - Links to more information about these algorithms can be found here: + Links to more information about all of these algorithms can be found here: https://csrc.nist.gov/projects/post-quantum-cryptography/round-3-submissions diff --git a/certs/include.am b/certs/include.am index f81c2c36d..be19b392e 100644 --- a/certs/include.am +++ b/certs/include.am @@ -130,4 +130,5 @@ include certs/intermediate/include.am include certs/falcon/include.am include certs/rsapss/include.am include certs/dilithium/include.am +include certs/sphincs/include.am diff --git a/certs/sphincs/bench_sphincs_fast_level1_key.der b/certs/sphincs/bench_sphincs_fast_level1_key.der new file mode 100644 index 000000000..fa3dd5b23 Binary files /dev/null and b/certs/sphincs/bench_sphincs_fast_level1_key.der differ diff --git a/certs/sphincs/bench_sphincs_fast_level3_key.der b/certs/sphincs/bench_sphincs_fast_level3_key.der new file mode 100644 index 000000000..4aac53289 Binary files /dev/null and b/certs/sphincs/bench_sphincs_fast_level3_key.der differ diff --git a/certs/sphincs/bench_sphincs_fast_level5_key.der b/certs/sphincs/bench_sphincs_fast_level5_key.der new file mode 100644 index 000000000..8fa2a3241 Binary files /dev/null and b/certs/sphincs/bench_sphincs_fast_level5_key.der differ diff --git a/certs/sphincs/bench_sphincs_small_level1_key.der b/certs/sphincs/bench_sphincs_small_level1_key.der new file mode 100644 index 000000000..72f750c58 Binary files /dev/null and b/certs/sphincs/bench_sphincs_small_level1_key.der differ diff --git a/certs/sphincs/bench_sphincs_small_level3_key.der b/certs/sphincs/bench_sphincs_small_level3_key.der new file mode 100644 index 000000000..1b3d32561 Binary files /dev/null and b/certs/sphincs/bench_sphincs_small_level3_key.der differ diff --git a/certs/sphincs/bench_sphincs_small_level5_key.der b/certs/sphincs/bench_sphincs_small_level5_key.der new file mode 100644 index 000000000..ba78786af Binary files /dev/null and b/certs/sphincs/bench_sphincs_small_level5_key.der differ diff --git a/certs/sphincs/include.am b/certs/sphincs/include.am new file mode 100644 index 000000000..2d44e66b7 --- /dev/null +++ b/certs/sphincs/include.am @@ -0,0 +1,11 @@ +# vim:ft=automake +# All paths should be given relative to the root +# + +EXTRA_DIST += \ + certs/sphincs/bench_sphincs_fast_level1_key.der \ + certs/sphincs/bench_sphincs_fast_level3_key.der \ + certs/sphincs/bench_sphincs_fast_level5_key.der \ + certs/sphincs/bench_sphincs_small_level1_key.der \ + certs/sphincs/bench_sphincs_small_level3_key.der \ + certs/sphincs/bench_sphincs_small_level5_key.der diff --git a/gencertbuf.pl b/gencertbuf.pl index 59c2c6253..27bc80cfb 100755 --- a/gencertbuf.pl +++ b/gencertbuf.pl @@ -116,6 +116,18 @@ my @fileList_dilithium = ( ["certs/dilithium/bench_dilithium_aes_level5_key.der", "bench_dilithium_aes_level5_key" ], ); +#Sphincs+ Post-Quantum Keys +#Used with HAVE_PQC +my @fileList_sphincs = ( + ["certs/sphincs/bench_sphincs_fast_level1_key.der", "bench_sphincs_fast_level1_key" ], + ["certs/sphincs/bench_sphincs_fast_level3_key.der", "bench_sphincs_fast_level3_key" ], + ["certs/sphincs/bench_sphincs_fast_level5_key.der", "bench_sphincs_fast_level5_key" ], + ["certs/sphincs/bench_sphincs_small_level1_key.der", "bench_sphincs_small_level1_key" ], + ["certs/sphincs/bench_sphincs_small_level3_key.der", "bench_sphincs_small_level3_key" ], + ["certs/sphincs/bench_sphincs_small_level5_key.der", "bench_sphincs_small_level5_key" ], + ); + + # ---------------------------------------------------------------------------- my $num_ecc = @fileList_ecc; @@ -126,6 +138,7 @@ my $num_3072 = @fileList_3072; my $num_4096 = @fileList_4096; my $num_falcon = @fileList_falcon; my $num_dilithium = @fileList_dilithium; +my $num_sphincs = @fileList_sphincs; # open our output file, "+>" creates and/or truncates open OUT_FILE, "+>", $outputFile or die $!; @@ -206,7 +219,7 @@ for (my $i = 0; $i < $num_4096; $i++) { print OUT_FILE "#endif /* USE_CERT_BUFFERS_4096 */\n\n"; # convert and print falcon keys -print OUT_FILE "#ifdef HAVE_PQC && HAVE_FALCON\n\n"; +print OUT_FILE "#if defined(HAVE_PQC) && defined(HAVE_FALCON)\n\n"; for (my $i = 0; $i < $num_falcon; $i++) { my $fname = $fileList_falcon[$i][0]; @@ -223,7 +236,7 @@ for (my $i = 0; $i < $num_falcon; $i++) { print OUT_FILE "#endif /* HAVE_PQC && HAVE_FALCON */\n\n"; # convert and print dilithium keys -print OUT_FILE "#ifdef HAVE_PQC && HAVE_DILITHIUM\n\n"; +print OUT_FILE "#if defined (HAVE_PQC) && defined(HAVE_DILITHIUM)\n\n"; for (my $i = 0; $i < $num_dilithium; $i++) { my $fname = $fileList_dilithium[$i][0]; @@ -239,6 +252,23 @@ for (my $i = 0; $i < $num_dilithium; $i++) { print OUT_FILE "#endif /* HAVE_PQC && HAVE_DILITHIUM */\n\n"; +# convert and print sphincs keys +print OUT_FILE "#if defined(HAVE_PQC) && defined(HAVE_SPHINCS)\n\n"; +for (my $i = 0; $i < $num_sphincs; $i++) { + + my $fname = $fileList_sphincs[$i][0]; + my $sname = $fileList_sphincs[$i][1]; + + print OUT_FILE "/* $fname */\n"; + print OUT_FILE "static const unsigned char $sname\[] =\n"; + print OUT_FILE "{\n"; + file_to_hex($fname); + print OUT_FILE "};\n"; + print OUT_FILE "static const int sizeof_$sname = sizeof($sname);\n\n"; +} + +print OUT_FILE "#endif /* HAVE_PQC && HAVE_SPHINCS */\n\n"; + # convert and print 256-bit cert/keys print OUT_FILE "#if defined(HAVE_ECC) && defined(USE_CERT_BUFFERS_256)\n\n"; for (my $i = 0; $i < $num_ecc; $i++) { diff --git a/rpm/spec.in b/rpm/spec.in index 4fb5e61d1..8b60193e1 100644 --- a/rpm/spec.in +++ b/rpm/spec.in @@ -269,6 +269,7 @@ mkdir -p $RPM_BUILD_ROOT/ %{_includedir}/wolfssl/wolfcrypt/error-crypt.h %{_includedir}/wolfssl/wolfcrypt/falcon.h %{_includedir}/wolfssl/wolfcrypt/dilithium.h +%{_includedir}/wolfssl/wolfcrypt/sphincs.h %{_includedir}/wolfssl/wolfcrypt/fe_448.h %{_includedir}/wolfssl/wolfcrypt/fe_operations.h %{_includedir}/wolfssl/wolfcrypt/fips_test.h @@ -318,8 +319,9 @@ mkdir -p $RPM_BUILD_ROOT/ %changelog * Tue Aug 30 2022 Jacob Barthelmeh <jacob@wolfssl.com> - Add include of QUIC documentation -- Add a new header dilithium.h. -* Wed Jul 20 2022 Anthony Hu <anthony@wolfssl.com> +* Wed Aug 17 2022 Anthony Hu <anthony@wolfssl.com> +- Add a new header sphincs.h. +* Fri Jul 20 2022 Anthony Hu <anthony@wolfssl.com> - Add a new header dilithium.h. * Fri Jul 8 2022 Jacob Barthelmeh <jacob@wolfssl.com> - Add missing sp_int.h file diff --git a/src/include.am b/src/include.am index 064d59ee7..ab12ae4e9 100644 --- a/src/include.am +++ b/src/include.am @@ -662,6 +662,7 @@ endif if BUILD_LIBOQS src_libwolfssl_la_SOURCES += wolfcrypt/src/falcon.c src_libwolfssl_la_SOURCES += wolfcrypt/src/dilithium.c +src_libwolfssl_la_SOURCES += wolfcrypt/src/sphincs.c endif if BUILD_LIBZ diff --git a/wolfcrypt/benchmark/benchmark.c b/wolfcrypt/benchmark/benchmark.c index 32047f277..c31d2c222 100644 --- a/wolfcrypt/benchmark/benchmark.c +++ b/wolfcrypt/benchmark/benchmark.c @@ -262,16 +262,19 @@ #endif #ifdef HAVE_LIBOQS #include <oqs/kem.h> + #include <oqs/sig.h> #endif + #if defined(HAVE_PQC) #if defined(HAVE_FALCON) #include <wolfssl/wolfcrypt/falcon.h> #endif -#endif -#if defined(HAVE_PQC) #if defined(HAVE_DILITHIUM) #include <wolfssl/wolfcrypt/dilithium.h> #endif + #if defined(HAVE_SPHINCS) + #include <wolfssl/wolfcrypt/sphincs.h> + #endif #endif #ifdef HAVE_PQM4 @@ -483,6 +486,14 @@ #define BENCH_DILITHIUM_AES_LEVEL3_SIGN 0x40000000 #define BENCH_DILITHIUM_AES_LEVEL5_SIGN 0x80000000 +/* Post-Quantum Asymmetric algorithms. (Part 2) */ +#define BENCH_SPHINCS_FAST_LEVEL1_SIGN 0x00000001 +#define BENCH_SPHINCS_FAST_LEVEL3_SIGN 0x00000002 +#define BENCH_SPHINCS_FAST_LEVEL5_SIGN 0x00000004 +#define BENCH_SPHINCS_SMALL_LEVEL1_SIGN 0x00000008 +#define BENCH_SPHINCS_SMALL_LEVEL3_SIGN 0x00000010 +#define BENCH_SPHINCS_SMALL_LEVEL5_SIGN 0x00000020 + /* Other */ #define BENCH_RNG 0x00000001 #define BENCH_SCRYPT 0x00000002 @@ -503,6 +514,8 @@ static int bench_mac_algs = 0; static int bench_asym_algs = 0; /* Post-Quantum Asymmetric algorithms to benchmark. */ static int bench_pq_asym_algs = 0; +/* Post-Quantum Asymmetric algorithms to benchmark. (Part 2)*/ +static int bench_pq_asym_algs2 = 0; /* Other cryptographic algorithms to benchmark. */ static int bench_other_algs = 0; @@ -764,7 +777,6 @@ static const bench_pq_alg bench_pq_asym_opt[] = { OQS_SIG_alg_dilithium_3_aes }, { "-dilithium_aes_level5", BENCH_DILITHIUM_AES_LEVEL5_SIGN, OQS_SIG_alg_dilithium_5_aes }, - { "-kyber_level1-kg", BENCH_KYBER_LEVEL1_KEYGEN, OQS_KEM_alg_kyber_512 }, { "-kyber_level1-ed", BENCH_KYBER_LEVEL1_ENCAP, @@ -813,10 +825,31 @@ static const bench_pq_alg bench_pq_asym_opt[] = { OQS_KEM_alg_ntru_hps4096821 }, { "-ntruHPS_level5-ed", BENCH_NTRUHPS_LEVEL5_ENCAP, OQS_KEM_alg_ntru_hps4096821 }, -#endif +#endif /* HAVE_LIBOQS */ { NULL, 0, NULL } }; -#endif + +#ifdef HAVE_LIBOQS +/* All recognized post-quantum asymmetric algorithm choosing command line + * options. (Part 2) */ +static const bench_pq_alg bench_pq_asym_opt2[] = { + { "-pq", 0xffffffff, NULL}, + { "-sphincs_fast_level1", BENCH_SPHINCS_FAST_LEVEL1_SIGN, + OQS_SIG_alg_sphincs_shake256_128f_simple }, + { "-sphincs_fast_level3", BENCH_SPHINCS_FAST_LEVEL3_SIGN, + OQS_SIG_alg_sphincs_shake256_192f_simple }, + { "-sphincs_fast_level5", BENCH_SPHINCS_FAST_LEVEL5_SIGN, + OQS_SIG_alg_sphincs_shake256_256f_simple }, + { "-sphincs_small_level1", BENCH_SPHINCS_SMALL_LEVEL1_SIGN, + OQS_SIG_alg_sphincs_shake256_128s_simple }, + { "-sphincs_small_level3", BENCH_SPHINCS_SMALL_LEVEL3_SIGN, + OQS_SIG_alg_sphincs_shake256_192s_simple }, + { "-sphincs_small_level5", BENCH_SPHINCS_SMALL_LEVEL5_SIGN, + OQS_SIG_alg_sphincs_shake256_256s_simple }, + { NULL, 0, NULL } +}; +#endif /* HAVE_LIBOQS */ +#endif /* HAVE_PQC */ #ifdef HAVE_WNR const char* wnrConfigFile = "wnr-example.conf"; @@ -2374,6 +2407,20 @@ static void* benchmarks_do(void* args) bench_dilithiumKeySign(5, AES_VARIANT); #endif +#ifdef HAVE_SPHINCS + if (bench_all || (bench_pq_asym_algs2 & BENCH_SPHINCS_FAST_LEVEL1_SIGN)) + bench_sphincsKeySign(1, FAST_VARIANT); + if (bench_all || (bench_pq_asym_algs2 & BENCH_SPHINCS_FAST_LEVEL3_SIGN)) + bench_sphincsKeySign(3, FAST_VARIANT); + if (bench_all || (bench_pq_asym_algs2 & BENCH_SPHINCS_FAST_LEVEL5_SIGN)) + bench_sphincsKeySign(5, FAST_VARIANT); + if (bench_all || (bench_pq_asym_algs2 & BENCH_SPHINCS_SMALL_LEVEL1_SIGN)) + bench_sphincsKeySign(1, SMALL_VARIANT); + if (bench_all || (bench_pq_asym_algs2 & BENCH_SPHINCS_SMALL_LEVEL3_SIGN)) + bench_sphincsKeySign(3, SMALL_VARIANT); + if (bench_all || (bench_pq_asym_algs2 & BENCH_SPHINCS_SMALL_LEVEL5_SIGN)) + bench_sphincsKeySign(5, SMALL_VARIANT); +#endif #endif /* HAVE_LIBOQS */ #ifdef WOLFCRYPT_HAVE_SAKKE @@ -2419,6 +2466,7 @@ exit: (void)bench_asym_algs; (void)bench_other_algs; (void)bench_pq_asym_algs; + (void)bench_pq_asym_algs2; return NULL; } @@ -7455,6 +7503,145 @@ void bench_dilithiumKeySign(byte level, byte sym) wc_dilithium_free(&key); } #endif /* HAVE_DILITHIUM */ + +#ifdef HAVE_SPHINCS +void bench_sphincsKeySign(byte level, byte optim) +{ + int ret = 0; + sphincs_key key; + double start; + int i, count; + byte sig[SPHINCS_MAX_SIG_SIZE]; + byte msg[512]; + word32 x = 0; + const char**desc = bench_desc_words[lng_index]; + + ret = wc_sphincs_init(&key); + if (ret != 0) { + printf("wc_sphincs_init failed %d\n", ret); + return; + } + + ret = wc_sphincs_set_level_and_optim(&key, level, optim); + if (ret != 0) { + printf("wc_sphincs_set_level_and_optim() failed %d\n", ret); + } + + if (ret == 0) { + ret = -1; + if ((level == 1) && (optim == FAST_VARIANT)) { + ret = wc_sphincs_import_private_key(bench_sphincs_fast_level1_key, + sizeof_bench_sphincs_fast_level1_key, NULL, 0, &key); + } + else if ((level == 3) && (optim == FAST_VARIANT)) { + ret = wc_sphincs_import_private_key(bench_sphincs_fast_level3_key, + sizeof_bench_sphincs_fast_level3_key, NULL, 0, &key); + } + else if ((level == 5) && (optim == FAST_VARIANT)) { + ret = wc_sphincs_import_private_key(bench_sphincs_fast_level5_key, + sizeof_bench_sphincs_fast_level5_key, NULL, 0, &key); + } + else if ((level == 1) && (optim == SMALL_VARIANT)) { + ret = wc_sphincs_import_private_key( + bench_sphincs_small_level1_key, + sizeof_bench_sphincs_small_level1_key, NULL, 0, &key); + } + else if ((level == 3) && (optim == SMALL_VARIANT)) { + ret = wc_sphincs_import_private_key( + bench_sphincs_small_level3_key, + sizeof_bench_sphincs_small_level3_key, NULL, 0, &key); + } + else if ((level == 5) && (optim == SMALL_VARIANT)) { + ret = wc_sphincs_import_private_key( + bench_sphincs_small_level5_key, + sizeof_bench_sphincs_small_level5_key, NULL, 0, &key); + } + + if (ret != 0) { + printf("wc_sphincs_import_private_key failed %d\n", ret); + } + } + + /* make dummy msg */ + for (i = 0; i < (int)sizeof(msg); i++) { + msg[i] = (byte)i; + } + + bench_stats_start(&count, &start); + do { + for (i = 0; i < agreeTimes; i++) { + if (ret == 0) { + if ((level == 1) && (optim == FAST_VARIANT)) { + x = SPHINCS_FAST_LEVEL1_SIG_SIZE; + } + else if ((level == 3) && (optim == FAST_VARIANT)) { + x = SPHINCS_FAST_LEVEL3_SIG_SIZE; + } + else if ((level == 5) && (optim == FAST_VARIANT)) { + x = SPHINCS_FAST_LEVEL5_SIG_SIZE; + } + else if ((level == 1) && (optim == SMALL_VARIANT)) { + x = SPHINCS_SMALL_LEVEL1_SIG_SIZE; + } + else if ((level == 3) && (optim == SMALL_VARIANT)) { + x = SPHINCS_SMALL_LEVEL3_SIG_SIZE; + } + else if ((level == 5) && (optim == SMALL_VARIANT)) { + x = SPHINCS_SMALL_LEVEL5_SIG_SIZE; + } + + ret = wc_sphincs_sign_msg(msg, sizeof(msg), sig, &x, &key); + if (ret != 0) { + printf("wc_sphincs_sign_msg failed\n"); + } + } + } + count += i; + } while (bench_stats_sym_check(start)); + + if (ret == 0) { + if (optim == FAST_VARIANT) { + bench_stats_asym_finish("SPHINCS-FAST", level, desc[4], 0, count, + start, ret); + } + else { + bench_stats_asym_finish("SPHINCS-SMALL", level, desc[4], 0, count, + start, ret); + } + } + + bench_stats_start(&count, &start); + do { + for (i = 0; i < agreeTimes; i++) { + if (ret == 0) { + int verify = 0; + ret = wc_sphincs_verify_msg(sig, x, msg, sizeof(msg), &verify, + &key); + + if (ret != 0 || verify != 1) { + printf("wc_sphincs_verify_msg failed %d, verify %d\n", + ret, verify); + ret = -1; + } + } + } + count += i; + } while (bench_stats_sym_check(start)); + + if (ret == 0) { + if (optim == FAST_VARIANT) { + bench_stats_asym_finish("SPHINCS-FAST", level, desc[5], 0, count, + start, ret); + } + else { + bench_stats_asym_finish("SPHINCS-SMALL", level, desc[5], 0, count, + start, ret); + } + } + + wc_sphincs_free(&key); +} +#endif /* HAVE_SPHINCS */ #endif /* HAVE_PQC */ #ifndef HAVE_STACK_SIZE @@ -7786,8 +7973,18 @@ static void Usage(void) line = 13; for (i=0; bench_other_opt[i].str != NULL; i++) print_alg(bench_other_opt[i].str + 1, &line); + printf("\n "); +#if defined(HAVE_PQC) + line = 13; + for (i=0; bench_pq_asym_opt[i].str != NULL; i++) + print_alg(bench_pq_asym_opt[i].str + 1, &line); +#if defined(HAVE_LIBOQS) + for (i=0; bench_pq_asym_opt2[i].str != NULL; i++) + print_alg(bench_pq_asym_opt2[i].str + 1, &line); printf("\n"); -#endif +#endif /* HAVE_LIBOQS */ +#endif /* HAVE_PQC */ +#endif /* !WOLFSSL_BENCHMARK_ALL */ printf("%s", bench_Usage_msg1[lng_index][14]); /* option -lng */ printf("%s", bench_Usage_msg1[lng_index][15]); /* option <num> */ #ifdef WC_ENABLE_BENCH_THREADING @@ -7963,7 +8160,20 @@ int main(int argc, char** argv) optMatched = 1; } } - #endif + #if defined(HAVE_LIBOQS) + /* Both bench_pq_asym_opt and bench_pq_asym_opt2 are looking for + * -pq, so we need to reset optMatched in case it was set to 1 just + * above. */ + optMatched = 0; + for (i=0; !optMatched && bench_pq_asym_opt2[i].str != NULL; i++) { + if (string_matches(argv[1], bench_pq_asym_opt2[i].str)) { + bench_pq_asym_algs2 |= bench_pq_asym_opt2[i].val; + bench_all = 0; + optMatched = 1; + } + } + #endif /* HAVE_LIBOQS*/ + #endif /* HAVE_PQC */ /* Other known cryptographic algorithms */ for (i=0; !optMatched && bench_other_opt[i].str != NULL; i++) { if (string_matches(argv[1], bench_other_opt[i].str)) { diff --git a/wolfcrypt/benchmark/benchmark.h b/wolfcrypt/benchmark/benchmark.h index eafb262ab..2cc16d14c 100644 --- a/wolfcrypt/benchmark/benchmark.h +++ b/wolfcrypt/benchmark/benchmark.h @@ -109,6 +109,7 @@ void bench_blake2s(void); void bench_pbkdf2(void); void bench_falconKeySign(byte level); void bench_dilithiumKeySign(byte level, byte sym); +void bench_sphincsKeySign(byte level, byte optim); void bench_pqcKemKeygen(word32 alg); void bench_pqcKemEncapDecap(word32 alg); diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index abfa27ee1..0716d8a5e 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -148,6 +148,9 @@ ASN Options: #if defined(HAVE_DILITHIUM) #include <wolfssl/wolfcrypt/dilithium.h> #endif + #if defined(HAVE_SPHINCS) + #include <wolfssl/wolfcrypt/sphincs.h> + #endif #endif #ifdef WOLFSSL_QNX_CAAM @@ -4017,6 +4020,31 @@ static word32 SetBitString16Bit(word16 val, byte* output) static const byte sigDilithiumAes_Level5Oid[] = {43, 6, 1, 4, 1, 2, 130, 11, 11, 8, 7}; #endif /* HAVE_DILITHIUM */ +#ifdef HAVE_SPHINCS + /* Sphincs Fast Level 1: 1 3 9999 6 7 4 */ + static const byte sigSphincsFast_Level1Oid[] = + {43, 206, 15, 6, 7, 4}; + + /* Sphincs Fast Level 3: 1 3 9999 6 8 3 */ + static const byte sigSphincsFast_Level3Oid[] = + {43, 206, 15, 6, 8, 3}; + + /* Sphincs Fast Level 5: 1 3 9999 6 9 3 */ + static const byte sigSphincsFast_Level5Oid[] = + {43, 206, 15, 6, 9, 3}; + + /* Sphincs Small Level 1: 1 3 9999 6 7 10 */ + static const byte sigSphincsSmall_Level1Oid[] = + {43, 206, 15, 6, 7, 10}; + + /* Sphincs Small Level 3: 1 3 9999 6 8 7 */ + static const byte sigSphincsSmall_Level3Oid[] = + {43, 206, 15, 6, 8, 7}; + + /* Sphincs Small Level 5: 1 3 9999 6 9 7 */ + static const byte sigSphincsSmall_Level5Oid[] = + {43, 206, 15, 6, 9, 7}; +#endif /* HAVE_SPHINCS */ #endif /* HAVE_PQC */ /* keyType */ @@ -4080,6 +4108,31 @@ static word32 SetBitString16Bit(word16 val, byte* output) static const byte keyDilithiumAes_Level5Oid[] = {43, 6, 1, 4, 1, 2, 130, 11, 11, 8, 7}; #endif /* HAVE_DILITHIUM */ +#ifdef HAVE_SPHINCS + /* Sphincs Fast Level 1: 1 3 9999 6 7 4 */ + static const byte keySphincsFast_Level1Oid[] = + {43, 206, 15, 6, 7, 4}; + + /* Sphincs Fast Level 3: 1 3 9999 6 8 3 */ + static const byte keySphincsFast_Level3Oid[] = + {43, 206, 15, 6, 8, 3}; + + /* Sphincs Fast Level 5: 1 3 9999 6 9 3 */ + static const byte keySphincsFast_Level5Oid[] = + {43, 206, 15, 6, 9, 3}; + + /* Sphincs Small Level 1: 1 3 9999 6 7 10 */ + static const byte keySphincsSmall_Level1Oid[] = + {43, 206, 15, 6, 7, 10}; + + /* Sphincs Small Level 3: 1 3 9999 6 8 7 */ + static const byte keySphincsSmall_Level3Oid[] = + {43, 206, 15, 6, 8, 7}; + + /* Sphincs Small Level 5: 1 3 9999 6 9 7 */ + static const byte keySphincsSmall_Level5Oid[] = + {43, 206, 15, 6, 9, 7}; +#endif /* HAVE_SPHINCS */ #endif /* HAVE_PQC */ /* curveType */ @@ -4614,6 +4667,32 @@ const byte* OidFromId(word32 id, word32 type, word32* oidSz) *oidSz = sizeof(sigDilithiumAes_Level5Oid); break; #endif /* HAVE_DILITHIUM */ + #ifdef HAVE_SPHINCS + case CTC_SPHINCS_FAST_LEVEL1: + oid = sigSphincsFast_Level1Oid; + *oidSz = sizeof(sigSphincsFast_Level1Oid); + break; + case CTC_SPHINCS_FAST_LEVEL3: + oid = sigSphincsFast_Level3Oid; + *oidSz = sizeof(sigSphincsFast_Level3Oid); + break; + case CTC_SPHINCS_FAST_LEVEL5: + oid = sigSphincsFast_Level5Oid; + *oidSz = sizeof(sigSphincsFast_Level5Oid); + break; + case CTC_SPHINCS_SMALL_LEVEL1: + oid = sigSphincsSmall_Level1Oid; + *oidSz = sizeof(sigSphincsSmall_Level1Oid); + break; + case CTC_SPHINCS_SMALL_LEVEL3: + oid = sigSphincsSmall_Level3Oid; + *oidSz = sizeof(sigSphincsSmall_Level3Oid); + break; + case CTC_SPHINCS_SMALL_LEVEL5: + oid = sigSphincsSmall_Level5Oid; + *oidSz = sizeof(sigSphincsSmall_Level5Oid); + break; + #endif /* HAVE_SPHINCS */ #endif /* HAVE_PQC */ default: break; @@ -4713,6 +4792,32 @@ const byte* OidFromId(word32 id, word32 type, word32* oidSz) *oidSz = sizeof(keyDilithiumAes_Level5Oid); break; #endif /* HAVE_DILITHIUM */ + #ifdef HAVE_SPHINCS + case SPHINCS_FAST_LEVEL1k: + oid = keySphincsFast_Level1Oid; + *oidSz = sizeof(keySphincsFast_Level1Oid); + break; + case SPHINCS_FAST_LEVEL3k: + oid = keySphincsFast_Level3Oid; + *oidSz = sizeof(keySphincsFast_Level3Oid); + break; + case SPHINCS_FAST_LEVEL5k: + oid = keySphincsFast_Level5Oid; + *oidSz = sizeof(keySphincsFast_Level5Oid); + break; + case SPHINCS_SMALL_LEVEL1k: + oid = keySphincsSmall_Level1Oid; + *oidSz = sizeof(keySphincsSmall_Level1Oid); + break; + case SPHINCS_SMALL_LEVEL3k: + oid = keySphincsSmall_Level3Oid; + *oidSz = sizeof(keySphincsSmall_Level3Oid); + break; + case SPHINCS_SMALL_LEVEL5k: + oid = keySphincsSmall_Level5Oid; + *oidSz = sizeof(keySphincsSmall_Level5Oid); + break; + #endif /* HAVE_SPHINCS */ #endif /* HAVE_PQC */ default: break; @@ -5575,16 +5680,15 @@ static int GetOID(const byte* input, word32* inOutIdx, word32* oid, { int ret = 0; word32 idx = *inOutIdx; -#ifdef HAVE_PQC - int found_collision = 0; -#endif /* HAVE_PQC */ #ifndef NO_VERIFY_OID word32 actualOidSz; const byte* actualOid; const byte* checkOid = NULL; word32 checkOidSz; #endif /* NO_VERIFY_OID */ - +#ifdef HAVE_PQC + word32 found_collision = 0; +#endif (void)oidType; *oid = 0; @@ -5609,13 +5713,20 @@ static int GetOID(const byte* input, word32* inOutIdx, word32* oid, * * As a small hack, we're going to look for the special case of * DILITHIUM_AES_LEVEL3k and if we find it, instead of *oid being set to 220 - * we will set it to 221. This hack will hopefully disappear when new - * standardized OIDs appear. Note that DILITHIUM_AES_LEVEL3k is defined to - * be 221. + * we will set it to 221. Note that DILITHIUM_AES_LEVEL3k is defined as 221. + * + * Same thing for SPHINCS_FAST_LEVEL1 and SPHINCS_FAST_LEVEL3. We will look + * for the special case of SPHINCS_FAST_LEVEL3 and set *oid to 283 instead + * of 281; 282 is taken. + * + * These hacks will hopefully disappear when new standardized OIDs appear. */ - if (memcmp(sigDilithiumAes_Level3Oid, &input[idx], - sizeof(sigDilithiumAes_Level3Oid)) == 0) { - found_collision = 1; + if (memcmp(&input[idx], sigDilithiumAes_Level3Oid, + sizeof(sigDilithiumAes_Level3Oid)) == 0) { + found_collision = DILITHIUM_AES_LEVEL3k; + } else if (memcmp(&input[idx], sigSphincsFast_Level3Oid, + sizeof(sigSphincsFast_Level3Oid)) == 0) { + found_collision = SPHINCS_FAST_LEVEL3k; } #endif /* HAVE_PQC */ @@ -5628,7 +5739,7 @@ static int GetOID(const byte* input, word32* inOutIdx, word32* oid, #ifdef HAVE_PQC if (found_collision) { - *oid = DILITHIUM_AES_LEVEL3k; + *oid = found_collision; } #endif /* HAVE_PQC */ @@ -6672,7 +6783,7 @@ int ToTraditionalInline_ex(const byte* input, word32* inOutIdx, word32 sz, break; #endif /* DSAk not supported. */ - /* Falcon and Dilithium not supported. */ + /* Falcon, Dilithium and Sphincs not supported. */ /* Ignore OID lookup failures. */ default: break; @@ -7220,7 +7331,7 @@ int wc_CheckPrivateKey(const byte* privKey, word32 privKeySz, } if ((ret = wc_Falcon_PrivateKeyDecode(privKey, &keyIdx, key_pair, privKeySz)) == 0) { - WOLFSSL_MSG("Checking Falcon_ key pair"); + WOLFSSL_MSG("Checking Falcon key pair"); keyIdx = 0; if ((ret = wc_falcon_import_public(pubKey, pubKeySz, key_pair)) == 0) { @@ -7298,7 +7409,7 @@ int wc_CheckPrivateKey(const byte* privKey, word32 privKeySz, } if ((ret = wc_Dilithium_PrivateKeyDecode(privKey, &keyIdx, key_pair, privKeySz)) == 0) { - WOLFSSL_MSG("Checking Dilithium_ key pair"); + WOLFSSL_MSG("Checking Dilithium key pair"); keyIdx = 0; if ((ret = wc_dilithium_import_public(pubKey, pubKeySz, key_pair)) == 0) { @@ -7314,6 +7425,77 @@ int wc_CheckPrivateKey(const byte* privKey, word32 privKeySz, } else #endif /* HAVE_DILITHIUM */ + #if defined(HAVE_SPHINCS) + if ((ks == SPHINCS_FAST_LEVEL1k) || + (ks == SPHINCS_FAST_LEVEL3k) || + (ks == SPHINCS_FAST_LEVEL5k) || + (ks == SPHINCS_SMALL_LEVEL1k) || + (ks == SPHINCS_SMALL_LEVEL3k) || + (ks == SPHINCS_SMALL_LEVEL5k)) { + #ifdef WOLFSSL_SMALL_STACK + sphincs_key* key_pair = NULL; + #else + sphincs_key key_pair[1]; + #endif + word32 keyIdx = 0; + + #ifdef WOLFSSL_SMALL_STACK + key_pair = (sphincs_key*)XMALLOC(sizeof(sphincs_key), NULL, + DYNAMIC_TYPE_SPHINCS); + if (key_pair == NULL) + return MEMORY_E; + #endif + ret = wc_sphincs_init(key_pair); + if (ret < 0) { + #ifdef WOLFSSL_SMALL_STACK + XFREE(key_pair, NULL, DYNAMIC_TYPE_SPHINCS); + #endif + return ret; + } + + if (ks == SPHINCS_FAST_LEVEL1k) { + ret = wc_sphincs_set_level_and_optim(key_pair, 1, FAST_VARIANT); + } + else if (ks == SPHINCS_FAST_LEVEL3k) { + ret = wc_sphincs_set_level_and_optim(key_pair, 3, FAST_VARIANT); + } + else if (ks == SPHINCS_FAST_LEVEL5k) { + ret = wc_sphincs_set_level_and_optim(key_pair, 5, FAST_VARIANT); + } + else if (ks == SPHINCS_SMALL_LEVEL1k) { + ret = wc_sphincs_set_level_and_optim(key_pair, 1, SMALL_VARIANT); + } + else if (ks == SPHINCS_SMALL_LEVEL3k) { + ret = wc_sphincs_set_level_and_optim(key_pair, 3, SMALL_VARIANT); + } + else if (ks == SPHINCS_SMALL_LEVEL5k) { + ret = wc_sphincs_set_level_and_optim(key_pair, 5, SMALL_VARIANT); + } + + if (ret < 0) { + #ifdef WOLFSSL_SMALL_STACK + XFREE(key_pair, NULL, DYNAMIC_TYPE_SPHINCS); + #endif + return ret; + } + if ((ret = wc_Sphincs_PrivateKeyDecode(privKey, &keyIdx, key_pair, + privKeySz)) == 0) { + WOLFSSL_MSG("Checking Sphincs key pair"); + keyIdx = 0; + if ((ret = wc_sphincs_import_public(pubKey, pubKeySz, + key_pair)) == 0) { + /* Public and private extracted successfully. Sanity check. */ + if ((ret = wc_sphincs_check_key(key_pair)) == 0) + ret = 1; + } + } + wc_sphincs_free(key_pair); + #ifdef WOLFSSL_SMALL_STACK + XFREE(key_pair, NULL, DYNAMIC_TYPE_SPHINCS); + #endif + } + else + #endif /* HAVE_SPHINCS */ #endif /* HAVE_PQC */ { ret = 0; @@ -7730,6 +7912,83 @@ int wc_GetKeyOID(byte* key, word32 keySz, const byte** curveOID, word32* oidSz, XFREE(dilithium, heap, DYNAMIC_TYPE_TMP_BUFFER); } #endif /* HAVE_DILITHIUM */ +#if defined(HAVE_SPHINCS) + if (*algoID == 0) { + sphincs_key *sphincs = (sphincs_key *)XMALLOC(sizeof(*sphincs), + heap, DYNAMIC_TYPE_TMP_BUFFER); + if (sphincs == NULL) + return MEMORY_E; + + if (wc_sphincs_init(sphincs) != 0) { + tmpIdx = 0; + if (wc_sphincs_set_level_and_optim(sphincs, 1, FAST_VARIANT) + == 0) { + if (wc_Sphincs_PrivateKeyDecode(key, &tmpIdx, sphincs, + keySz) == 0) { + *algoID = SPHINCS_FAST_LEVEL1k; + } + else { + WOLFSSL_MSG("Not Sphincs-fast Level 1 DER key"); + } + } + else if (wc_sphincs_set_level_and_optim(sphincs, 3, FAST_VARIANT) + == 0) { + if (wc_Sphincs_PrivateKeyDecode(key, &tmpIdx, sphincs, + keySz) == 0) { + *algoID = SPHINCS_FAST_LEVEL3k; + } + else { + WOLFSSL_MSG("Not Sphincs-fast Level 3 DER key"); + } + } + else if (wc_sphincs_set_level_and_optim(sphincs, 5, FAST_VARIANT) + == 0) { + if (wc_Sphincs_PrivateKeyDecode(key, &tmpIdx, sphincs, + keySz) == 0) { + *algoID = SPHINCS_FAST_LEVEL5k; + } + else { + WOLFSSL_MSG("Not Sphincs-fast Level 5 DER key"); + } + } + else if (wc_sphincs_set_level_and_optim(sphincs, 1, SMALL_VARIANT) + == 0) { + if (wc_Sphincs_PrivateKeyDecode(key, &tmpIdx, sphincs, + keySz) == 0) { + *algoID = SPHINCS_SMALL_LEVEL1k; + } + else { + WOLFSSL_MSG("Not Sphincs-small Level 1 DER key"); + } + } + else if (wc_sphincs_set_level_and_optim(sphincs, 3, SMALL_VARIANT) + == 0) { + if (wc_Sphincs_PrivateKeyDecode(key, &tmpIdx, sphincs, + keySz) == 0) { + *algoID = SPHINCS_SMALL_LEVEL3k; + } + else { + WOLFSSL_MSG("Not Sphincs-small Level 3 DER key"); + } + } + else if (wc_sphincs_set_level_and_optim(sphincs, 5, SMALL_VARIANT) + == 0) { + if (wc_Sphincs_PrivateKeyDecode(key, &tmpIdx, sphincs, + keySz) == 0) { + *algoID = SPHINCS_SMALL_LEVEL5k; + } + else { + WOLFSSL_MSG("Not Sphincs-small Level 5 DER key"); + } + } + else { + WOLFSSL_MSG("GetKeyOID sphincs initialization failed"); + } + wc_sphincs_free(sphincs); + } + XFREE(sphincs, heap, DYNAMIC_TYPE_TMP_BUFFER); + } +#endif /* HAVE_SPHINCS */ #endif /* HAVE_PQC */ /* if flag is not set then this is not a key that we understand. */ @@ -11537,6 +11796,32 @@ static int GetCertKey(DecodedCert* cert, const byte* source, word32* inOutIdx, ret = StoreKey(cert, source, &srcIdx, maxIdx); break; #endif /* HAVE_DILITHIUM */ + #ifdef HAVE_SPHINCS + case SPHINCS_FAST_LEVEL1k: + cert->pkCurveOID = SPHINCS_FAST_LEVEL1k; + ret = StoreKey(cert, source, &srcIdx, maxIdx); + break; + case SPHINCS_FAST_LEVEL3k: + cert->pkCurveOID = SPHINCS_FAST_LEVEL3k; + ret = StoreKey(cert, source, &srcIdx, maxIdx); + break; + case SPHINCS_FAST_LEVEL5k: + cert->pkCurveOID = SPHINCS_FAST_LEVEL5k; + ret = StoreKey(cert, source, &srcIdx, maxIdx); + break; + case SPHINCS_SMALL_LEVEL1k: + cert->pkCurveOID = SPHINCS_SMALL_LEVEL1k; + ret = StoreKey(cert, source, &srcIdx, maxIdx); + break; + case SPHINCS_SMALL_LEVEL3k: + cert->pkCurveOID = SPHINCS_SMALL_LEVEL3k; + ret = StoreKey(cert, source, &srcIdx, maxIdx); + break; + case SPHINCS_SMALL_LEVEL5k: + cert->pkCurveOID = SPHINCS_SMALL_LEVEL5k; + ret = StoreKey(cert, source, &srcIdx, maxIdx); + break; + #endif /* HAVE_SPHINCS */ #endif /* HAVE_PQC */ #ifndef NO_DSA case DSAk: @@ -14517,6 +14802,14 @@ static WC_INLINE int IsSigAlgoECC(int algoOID) || (algoOID == DILITHIUM_AES_LEVEL3k) || (algoOID == DILITHIUM_AES_LEVEL5k) #endif + #ifdef HAVE_SPHINCS + || (algoOID == SPHINCS_FAST_LEVEL1k) + || (algoOID == SPHINCS_FAST_LEVEL3k) + || (algoOID == SPHINCS_FAST_LEVEL5k) + || (algoOID == SPHINCS_SMALL_LEVEL1k) + || (algoOID == SPHINCS_SMALL_LEVEL3k) + || (algoOID == SPHINCS_SMALL_LEVEL5k) + #endif #endif /* HAVE_PQC */ ); } @@ -14829,6 +15122,19 @@ void FreeSignatureCtx(SignatureCtx* sigCtx) sigCtx->key.dilithium = NULL; break; #endif /* HAVE_DILITHIUM */ + #if defined(HAVE_SPHINCS) + case SPHINCS_FAST_LEVEL1k: + case SPHINCS_FAST_LEVEL3k: + case SPHINCS_FAST_LEVEL5k: + case SPHINCS_SMALL_LEVEL1k: + case SPHINCS_SMALL_LEVEL3k: + case SPHINCS_SMALL_LEVEL5k: + wc_sphincs_free(sigCtx->key.sphincs); + XFREE(sigCtx->key.sphincs, sigCtx->heap, + DYNAMIC_TYPE_SPHINCS); + sigCtx->key.sphincs = NULL; + break; + #endif /* HAVE_SPHINCS */ #endif /* HAVE_PQC */ default: break; @@ -14984,6 +15290,16 @@ static int HashForSignature(const byte* buf, word32 bufSz, word32 sigOID, /* Hashes done in signing operation. */ break; #endif + #ifdef HAVE_SPHINCS + case CTC_SPHINCS_FAST_LEVEL1: + case CTC_SPHINCS_FAST_LEVEL3: + case CTC_SPHINCS_FAST_LEVEL5: + case CTC_SPHINCS_SMALL_LEVEL1: + case CTC_SPHINCS_SMALL_LEVEL3: + case CTC_SPHINCS_SMALL_LEVEL5: + /* Hashes done in signing operation. */ + break; + #endif #endif /* HAVE_PQC */ default: @@ -15532,6 +15848,159 @@ static int ConfirmSignature(SignatureCtx* sigCtx, break; } #endif /* HAVE_DILITHIUM */ + #if defined(HAVE_SPHINCS) + case SPHINCS_FAST_LEVEL1k: + { + sigCtx->verify = 0; + sigCtx->key.sphincs = + (sphincs_key*)XMALLOC(sizeof(sphincs_key), + sigCtx->heap, + DYNAMIC_TYPE_SPHINCS); + if (sigCtx->key.sphincs == NULL) { + ERROR_OUT(MEMORY_E, exit_cs); + } + if ((ret = wc_sphincs_init(sigCtx->key.sphincs)) < 0) { + goto exit_cs; + } + if ((ret = wc_sphincs_set_level_and_optim( + sigCtx->key.sphincs, 1, FAST_VARIANT)) + < 0) { + goto exit_cs; + } + if ((ret = wc_sphincs_import_public(key, keySz, + sigCtx->key.sphincs)) < 0) { + WOLFSSL_MSG("ASN Key import err: Sphincs-fast Level1"); + goto exit_cs; + } + break; + } + case SPHINCS_FAST_LEVEL3k: + { + sigCtx->verify = 0; + sigCtx->key.sphincs = + (sphincs_key*)XMALLOC(sizeof(sphincs_key), + sigCtx->heap, + DYNAMIC_TYPE_SPHINCS); + if (sigCtx->key.sphincs == NULL) { + ERROR_OUT(MEMORY_E, exit_cs); + } + if ((ret = wc_sphincs_init(sigCtx->key.sphincs)) < 0) { + goto exit_cs; + } + if ((ret = wc_sphincs_set_level_and_optim( + sigCtx->key.sphincs, 3, FAST_VARIANT)) + < 0) { + goto exit_cs; + } + if ((ret = wc_sphincs_import_public(key, keySz, + sigCtx->key.sphincs)) < 0) { + WOLFSSL_MSG("ASN Key import err: Sphincs-fast Level3"); + goto exit_cs; + } + break; + } + case SPHINCS_FAST_LEVEL5k: + { + sigCtx->verify = 0; + sigCtx->key.sphincs = + (sphincs_key*)XMALLOC(sizeof(sphincs_key), + sigCtx->heap, + DYNAMIC_TYPE_SPHINCS); + if (sigCtx->key.sphincs == NULL) { + ERROR_OUT(MEMORY_E, exit_cs); + } + if ((ret = wc_sphincs_init(sigCtx->key.sphincs)) < 0) { + goto exit_cs; + } + if ((ret = wc_sphincs_set_level_and_optim( + sigCtx->key.sphincs, 5, FAST_VARIANT)) + < 0) { + goto exit_cs; + } + if ((ret = wc_sphincs_import_public(key, keySz, + sigCtx->key.sphincs)) < 0) { + WOLFSSL_MSG("ASN Key import err: Sphincs-fast Level5"); + goto exit_cs; + } + break; + } + + case SPHINCS_SMALL_LEVEL1k: + { + sigCtx->verify = 0; + sigCtx->key.sphincs = + (sphincs_key*)XMALLOC(sizeof(sphincs_key), + sigCtx->heap, + DYNAMIC_TYPE_SPHINCS); + if (sigCtx->key.sphincs == NULL) { + ERROR_OUT(MEMORY_E, exit_cs); + } + if ((ret = wc_sphincs_init(sigCtx->key.sphincs)) < 0) { + goto exit_cs; + } + if ((ret = wc_sphincs_set_level_and_optim( + sigCtx->key.sphincs, 1, SMALL_VARIANT)) + < 0) { + goto exit_cs; + } + if ((ret = wc_sphincs_import_public(key, keySz, + sigCtx->key.sphincs)) < 0) { + WOLFSSL_MSG("ASN Key import err: Sphincs-fast Level1"); + goto exit_cs; + } + break; + } + case SPHINCS_SMALL_LEVEL3k: + { + sigCtx->verify = 0; + sigCtx->key.sphincs = + (sphincs_key*)XMALLOC(sizeof(sphincs_key), + sigCtx->heap, + DYNAMIC_TYPE_SPHINCS); + if (sigCtx->key.sphincs == NULL) { + ERROR_OUT(MEMORY_E, exit_cs); + } + if ((ret = wc_sphincs_init(sigCtx->key.sphincs)) < 0) { + goto exit_cs; + } + if ((ret = wc_sphincs_set_level_and_optim( + sigCtx->key.sphincs, 3, SMALL_VARIANT)) + < 0) { + goto exit_cs; + } + if ((ret = wc_sphincs_import_public(key, keySz, + sigCtx->key.sphincs)) < 0) { + WOLFSSL_MSG("ASN Key import err: Sphincs-fast Level3"); + goto exit_cs; + } + break; + } + case SPHINCS_SMALL_LEVEL5k: + { + sigCtx->verify = 0; + sigCtx->key.sphincs = + (sphincs_key*)XMALLOC(sizeof(sphincs_key), + sigCtx->heap, + DYNAMIC_TYPE_SPHINCS); + if (sigCtx->key.sphincs == NULL) { + ERROR_OUT(MEMORY_E, exit_cs); + } + if ((ret = wc_sphincs_init(sigCtx->key.sphincs)) < 0) { + goto exit_cs; + } + if ((ret = wc_sphincs_set_level_and_optim( + sigCtx->key.sphincs, 5, SMALL_VARIANT)) + < 0) { + goto exit_cs; + } + if ((ret = wc_sphincs_import_public(key, keySz, + sigCtx->key.sphincs)) < 0) { + WOLFSSL_MSG("ASN Key import err: Sphincs-fast Level5"); + goto exit_cs; + } + break; + } + #endif /* HAVE_SPHINCS */ #endif /* HAVE_PQC */ default: WOLFSSL_MSG("Verify Key type unknown"); @@ -15668,6 +16137,20 @@ static int ConfirmSignature(SignatureCtx* sigCtx, break; } #endif /* HAVE_DILITHIUM */ + #if defined(HAVE_SPHINCS) + case SPHINCS_FAST_LEVEL1k: + case SPHINCS_FAST_LEVEL3k: + case SPHINCS_FAST_LEVEL5k: + case SPHINCS_SMALL_LEVEL1k: + case SPHINCS_SMALL_LEVEL3k: + case SPHINCS_SMALL_LEVEL5k: + { + ret = wc_sphincs_verify_msg(sig, sigSz, buf, bufSz, + &sigCtx->verify, + sigCtx->key.sphincs); + break; + } + #endif /* HAVE_SPHINCS */ #endif /* HAVE_PQC */ default: break; @@ -15908,6 +16391,74 @@ static int ConfirmSignature(SignatureCtx* sigCtx, break; } #endif /* HAVE_DILITHIUM */ + #ifdef HAVE_SPHINCS + case SPHINCS_FAST_LEVEL1k: + { + if (sigCtx->verify == 1) { + ret = 0; + } + else { + WOLFSSL_MSG("SPHINCS_FAST_LEVEL1 Verify didn't match"); + ret = ASN_SIG_CONFIRM_E; + } + break; + } + case SPHINCS_FAST_LEVEL3k: + { + if (sigCtx->verify == 1) { + ret = 0; + } + else { + WOLFSSL_MSG("SPHINCS_FAST_LEVEL3 Verify didn't match"); + ret = ASN_SIG_CONFIRM_E; + } + break; + } + case SPHINCS_FAST_LEVEL5k: + { + if (sigCtx->verify == 1) { + ret = 0; + } + else { + WOLFSSL_MSG("SPHINCS_FAST_LEVEL5 Verify didn't match"); + ret = ASN_SIG_CONFIRM_E; + } + break; + } + case SPHINCS_SMALL_LEVEL1k: + { + if (sigCtx->verify == 1) { + ret = 0; + } + else { + WOLFSSL_MSG("SPHINCS_SMALL_LEVEL1 Verify didn't match"); + ret = ASN_SIG_CONFIRM_E; + } + break; + } + case SPHINCS_SMALL_LEVEL3k: + { + if (sigCtx->verify == 1) { + ret = 0; + } + else { + WOLFSSL_MSG("SPHINCS_SMALL_LEVEL3 Verify didn't match"); + ret = ASN_SIG_CONFIRM_E; + } + break; + } + case SPHINCS_SMALL_LEVEL5k: + { + if (sigCtx->verify == 1) { + ret = 0; + } + else { + WOLFSSL_MSG("SPHINCS_SMALL_LEVEL5 Verify didn't match"); + ret = ASN_SIG_CONFIRM_E; + } + break; + } + #endif /* HAVE_SPHINCS */ #endif /* HAVE_PQC */ default: break; @@ -21939,6 +22490,21 @@ wcchar END_PUB_KEY = "-----END PUBLIC KEY-----"; wcchar BEGIN_DILITHIUM_AES_LEVEL5_PRIV = "-----BEGIN DILITHIUM_AES_LEVEL5 PRIVATE KEY-----"; wcchar END_DILITHIUM_AES_LEVEL5_PRIV = "-----END DILITHIUM_AES_LEVEL5 PRIVATE KEY-----"; #endif /* HAVE_DILITHIUM */ +#if defined(HAVE_SPHINCS) + wcchar BEGIN_SPHINCS_FAST_LEVEL1_PRIV = "-----BEGIN SPHINCS_FAST_LEVEL1 PRIVATE KEY-----"; + wcchar END_SPHINCS_FAST_LEVEL1_PRIV = "-----END SPHINCS_FAST_LEVEL1 PRIVATE KEY-----"; + wcchar BEGIN_SPHINCS_FAST_LEVEL3_PRIV = "-----BEGIN SPHINCS_FAST_LEVEL3 PRIVATE KEY-----"; + wcchar END_SPHINCS_FAST_LEVEL3_PRIV = "-----END SPHINCS_FAST_LEVEL3 PRIVATE KEY-----"; + wcchar BEGIN_SPHINCS_FAST_LEVEL5_PRIV = "-----BEGIN SPHINCS_FAST_LEVEL5 PRIVATE KEY-----"; + wcchar END_SPHINCS_FAST_LEVEL5_PRIV = "-----END SPHINCS_FAST_LEVEL5 PRIVATE KEY-----"; + + wcchar BEGIN_SPHINCS_SMALL_LEVEL1_PRIV = "-----BEGIN SPHINCS_SMALL_LEVEL1 PRIVATE KEY-----"; + wcchar END_SPHINCS_SMALL_LEVEL1_PRIV = "-----END SPHINCS_SMALL_LEVEL1 PRIVATE KEY-----"; + wcchar BEGIN_SPHINCS_SMALL_LEVEL3_PRIV = "-----BEGIN SPHINCS_SMALL_LEVEL3 PRIVATE KEY-----"; + wcchar END_SPHINCS_SMALL_LEVEL3_PRIV = "-----END SPHINCS_SMALL_LEVEL3 PRIVATE KEY-----"; + wcchar BEGIN_SPHINCS_SMALL_LEVEL5_PRIV = "-----BEGIN SPHINCS_SMALL_LEVEL5 PRIVATE KEY-----"; + wcchar END_SPHINCS_SMALL_LEVEL5_PRIV = "-----END SPHINCS_SMALL_LEVEL5 PRIVATE KEY-----"; +#endif /* HAVE_SPHINCS */ #endif /* HAVE_PQC */ const int pem_struct_min_sz = XSTR_SIZEOF("-----BEGIN X509 CRL-----" @@ -22079,6 +22645,38 @@ int wc_PemGetHeaderFooter(int type, const char** header, const char** footer) ret = 0; break; #endif /* HAVE_DILITHIUM */ +#ifdef HAVE_SPHINCS + case SPHINCS_FAST_LEVEL1_TYPE: + if (header) *header = BEGIN_SPHINCS_FAST_LEVEL1_PRIV; + if (footer) *footer = END_SPHINCS_FAST_LEVEL1_PRIV; + ret = 0; + break; + case SPHINCS_FAST_LEVEL3_TYPE: + if (header) *header = BEGIN_SPHINCS_FAST_LEVEL3_PRIV; + if (footer) *footer = END_SPHINCS_FAST_LEVEL3_PRIV; + ret = 0; + break; + case SPHINCS_FAST_LEVEL5_TYPE: + if (header) *header = BEGIN_SPHINCS_FAST_LEVEL5_PRIV; + if (footer) *footer = END_SPHINCS_FAST_LEVEL5_PRIV; + ret = 0; + break; + case SPHINCS_SMALL_LEVEL1_TYPE: + if (header) *header = BEGIN_SPHINCS_SMALL_LEVEL1_PRIV; + if (footer) *footer = END_SPHINCS_SMALL_LEVEL1_PRIV; + ret = 0; + break; + case SPHINCS_SMALL_LEVEL3_TYPE: + if (header) *header = BEGIN_SPHINCS_SMALL_LEVEL3_PRIV; + if (footer) *footer = END_SPHINCS_SMALL_LEVEL3_PRIV; + ret = 0; + break; + case SPHINCS_SMALL_LEVEL5_TYPE: + if (header) *header = BEGIN_SPHINCS_SMALL_LEVEL5_PRIV; + if (footer) *footer = END_SPHINCS_SMALL_LEVEL5_PRIV; + ret = 0; + break; +#endif /* HAVE_SPHINCS */ #endif /* HAVE_PQC */ case PUBLICKEY_TYPE: case ECC_PUBLICKEY_TYPE: @@ -26720,7 +27318,7 @@ static int SetValidity(byte* before, byte* after, int daysValid) static int EncodeCert(Cert* cert, DerCert* der, RsaKey* rsaKey, ecc_key* eccKey, WC_RNG* rng, DsaKey* dsaKey, ed25519_key* ed25519Key, ed448_key* ed448Key, falcon_key* falconKey, - dilithium_key* dilithiumKey) + dilithium_key* dilithiumKey, sphincs_key* sphincsKey) { int ret; @@ -26730,7 +27328,7 @@ static int EncodeCert(Cert* cert, DerCert* der, RsaKey* rsaKey, ecc_key* eccKey, /* make sure at least one key type is provided */ if (rsaKey == NULL && eccKey == NULL && ed25519Key == NULL && dsaKey == NULL && ed448Key == NULL && falconKey == NULL && - dilithiumKey == NULL) { + dilithiumKey == NULL && sphincsKey == NULL) { return PUBLIC_KEY_E; } @@ -26833,6 +27431,21 @@ static int EncodeCert(Cert* cert, DerCert* der, RsaKey* rsaKey, ecc_key* eccKey, (word32)sizeof(der->publicKey), 1); } #endif /* HAVE_DILITHIUM */ +#if defined(HAVE_SPHINCS) + if ((cert->keyType == SPHINCS_FAST_LEVEL1_KEY) || + (cert->keyType == SPHINCS_FAST_LEVEL3_KEY) || + (cert->keyType == SPHINCS_FAST_LEVEL5_KEY) || + (cert->keyType == SPHINCS_SMALL_LEVEL1_KEY) || + (cert->keyType == SPHINCS_SMALL_LEVEL3_KEY) || + (cert->keyType == SPHINCS_SMALL_LEVEL5_KEY)) { + if (sphincsKey == NULL) + return PUBLIC_KEY_E; + + der->publicKeySz = + wc_Sphincs_PublicKeyToDer(sphincsKey, der->publicKey, + (word32)sizeof(der->publicKey), 1); + } +#endif /* HAVE_SPHINCS */ #endif /* HAVE_PQC */ if (der->publicKeySz <= 0) @@ -27227,7 +27840,8 @@ static int WriteCertBody(DerCert* der, byte* buf) static int MakeSignature(CertSignCtx* certSignCtx, const byte* buf, int sz, byte* sig, int sigSz, RsaKey* rsaKey, ecc_key* eccKey, ed25519_key* ed25519Key, ed448_key* ed448Key, falcon_key* falconKey, - dilithium_key* dilithiumKey, WC_RNG* rng, int sigAlgoType, void* heap) + dilithium_key* dilithiumKey, sphincs_key* sphincsKey, WC_RNG* rng, + int sigAlgoType, void* heap) { int digestSz = 0, typeH = 0, ret = 0; @@ -27243,6 +27857,7 @@ static int MakeSignature(CertSignCtx* certSignCtx, const byte* buf, int sz, (void)ed448Key; (void)falconKey; (void)dilithiumKey; + (void)sphincsKey; (void)rng; (void)heap; @@ -27343,6 +27958,15 @@ static int MakeSignature(CertSignCtx* certSignCtx, const byte* buf, int sz, ret = outSz; } #endif /* HAVE_DILITHIUM */ + #if defined(HAVE_SPHINCS) + if (!rsaKey && !eccKey && !ed25519Key && !ed448Key && !falconKey && + !dilithiumKey && sphincsKey) { + word32 outSz = sigSz; + ret = wc_sphincs_sign_msg(buf, sz, sig, &outSz, sphincsKey); + if (ret == 0) + ret = outSz; + } + #endif /* HAVE_SPHINCS */ #endif /* HAVE_PQC */ break; @@ -27524,7 +28148,7 @@ static int MakeAnyCert(Cert* cert, byte* derBuffer, word32 derSz, RsaKey* rsaKey, ecc_key* eccKey, WC_RNG* rng, DsaKey* dsaKey, ed25519_key* ed25519Key, ed448_key* ed448Key, falcon_key* falconKey, - dilithium_key* dilithiumKey) + dilithium_key* dilithiumKey, sphincs_key* sphincsKey) { #ifndef WOLFSSL_ASN_TEMPLATE int ret; @@ -27574,6 +28198,26 @@ static int MakeAnyCert(Cert* cert, byte* derBuffer, word32 derSz, && (dilithiumKey->sym == AES_VARIANT)) cert->keyType = DILITHIUM_AES_LEVEL5_KEY; #endif /* HAVE_DILITHIUM */ +#ifdef HAVE_SPHINCS + else if ((sphincsKey != NULL) && (sphincsKey->level == 1) + && (sphincsKey->optim == FAST_VARIANT)) + cert->keyType = SPHINCS_FAST_LEVEL1_KEY; + else if ((sphincsKey != NULL) && (sphincsKey->level == 3) + && (sphincsKey->optim == FAST_VARIANT)) + cert->keyType = SPHINCS_FAST_LEVEL3_KEY; + else if ((sphincsKey != NULL) && (sphincsKey->level == 5) + && (sphincsKey->optim == FAST_VARIANT)) + cert->keyType = SPHINCS_FAST_LEVEL5_KEY; + else if ((sphincsKey != NULL) && (sphincsKey->level == 1) + && (sphincsKey->optim == SMALL_VARIANT)) + cert->keyType = SPHINCS_SMALL_LEVEL1_KEY; + else if ((sphincsKey != NULL) && (sphincsKey->level == 3) + && (sphincsKey->optim == SMALL_VARIANT)) + cert->keyType = SPHINCS_SMALL_LEVEL3_KEY; + else if ((sphincsKey != NULL) && (sphincsKey->level == 5) + && (sphincsKey->optim == SMALL_VARIANT)) + cert->keyType = SPHINCS_SMALL_LEVEL5_KEY; +#endif /* HAVE_SPHINCS */ #endif /* HAVE_PQC */ else return BAD_FUNC_ARG; @@ -27585,7 +28229,7 @@ static int MakeAnyCert(Cert* cert, byte* derBuffer, word32 derSz, #endif ret = EncodeCert(cert, der, rsaKey, eccKey, rng, dsaKey, ed25519Key, - ed448Key, falconKey, dilithiumKey); + ed448Key, falconKey, dilithiumKey, sphincsKey); if (ret == 0) { if (der->total + MAX_SEQ_SZ * 2 > (int)derSz) ret = BUFFER_E; @@ -27610,8 +28254,10 @@ static int MakeAnyCert(Cert* cert, byte* derBuffer, word32 derSz, word32 issRawLen = 0; word32 sbjRawLen = 0; - (void)falconKey; /* Unused without OQS */ - (void)dilithiumKey; /* Unused without OQS */ + /* Unused without OQS */ + (void)falconKey; + (void)dilithiumKey; + (void)sphincsKey; CALLOC_ASNSETDATA(dataASN, x509CertASN_Length, ret, cert->heap); @@ -27667,6 +28313,32 @@ static int MakeAnyCert(Cert* cert, byte* derBuffer, word32 derSz, cert->keyType = DILITHIUM_AES_LEVEL5_KEY; } #endif /* HAVE_DILITHIUM */ +#ifdef HAVE_SPHINCS + else if ((sphincsKey != NULL) && (sphincsKey->level == 1) + && (sphincsKey->optim == FAST_VARIANT)) { + cert->keyType = SPHINCS_FAST_LEVEL1_KEY; + } + else if ((sphincsKey != NULL) && (sphincsKey->level == 3) + && (sphincsKey->optim == FAST_VARIANT)) { + cert->keyType = SPHINCS_FAST_LEVEL3_KEY; + } + else if ((sphincsKey != NULL) && (sphincsKey->level == 5) + && (sphincsKey->optim == FAST_VARIANT)) { + cert->keyType = SPHINCS_FAST_LEVEL5_KEY; + } + else if ((sphincsKey != NULL) && (sphincsKey->level == 1) + && (sphincsKey->optim == SMALL_VARIANT)) { + cert->keyType = SPHINCS_SMALL_LEVEL1_KEY; + } + else if ((sphincsKey != NULL) && (sphincsKey->level == 3) + && (sphincsKey->optim == SMALL_VARIANT)) { + cert->keyType = SPHINCS_SMALL_LEVEL3_KEY; + } + else if ((sphincsKey != NULL) && (sphincsKey->level == 5) + && (sphincsKey->optim == SMALL_VARIANT)) { + cert->keyType = SPHINCS_SMALL_LEVEL5_KEY; + } +#endif /* HAVE_SPHINCS */ #endif /* HAVE_PQC */ else { ret = BAD_FUNC_ARG; @@ -27908,6 +28580,7 @@ int wc_MakeCert_ex(Cert* cert, byte* derBuffer, word32 derSz, int keyType, ed448_key* ed448Key = NULL; falcon_key* falconKey = NULL; dilithium_key* dilithiumKey = NULL; + sphincs_key* sphincsKey = NULL; if (keyType == RSA_TYPE) rsaKey = (RsaKey*)key; @@ -27935,9 +28608,22 @@ int wc_MakeCert_ex(Cert* cert, byte* derBuffer, word32 derSz, int keyType, dilithiumKey = (dilithium_key*)key; else if (keyType == DILITHIUM_AES_LEVEL5_TYPE) dilithiumKey = (dilithium_key*)key; + else if (keyType == SPHINCS_FAST_LEVEL1_TYPE) + sphincsKey = (sphincs_key*)key; + else if (keyType == SPHINCS_FAST_LEVEL3_TYPE) + sphincsKey = (sphincs_key*)key; + else if (keyType == SPHINCS_FAST_LEVEL5_TYPE) + sphincsKey = (sphincs_key*)key; + else if (keyType == SPHINCS_SMALL_LEVEL1_TYPE) + sphincsKey = (sphincs_key*)key; + else if (keyType == SPHINCS_SMALL_LEVEL3_TYPE) + sphincsKey = (sphincs_key*)key; + else if (keyType == SPHINCS_SMALL_LEVEL5_TYPE) + sphincsKey = (sphincs_key*)key; return MakeAnyCert(cert, derBuffer, derSz, rsaKey, eccKey, rng, dsaKey, - ed25519Key, ed448Key, falconKey, dilithiumKey); + ed25519Key, ed448Key, falconKey, dilithiumKey, + sphincsKey); } /* Make an x509 Certificate v3 RSA or ECC from cert input, write to buffer */ @@ -27946,7 +28632,7 @@ int wc_MakeCert(Cert* cert, byte* derBuffer, word32 derSz, RsaKey* rsaKey, ecc_key* eccKey, WC_RNG* rng) { return MakeAnyCert(cert, derBuffer, derSz, rsaKey, eccKey, rng, NULL, NULL, - NULL, NULL, NULL); + NULL, NULL, NULL, NULL); } #ifdef WOLFSSL_CERT_REQ @@ -28110,7 +28796,8 @@ static int SetCustomObjectId(Cert* cert, byte* output, word32 outSz, static int EncodeCertReq(Cert* cert, DerCert* der, RsaKey* rsaKey, DsaKey* dsaKey, ecc_key* eccKey, ed25519_key* ed25519Key, ed448_key* ed448Key, - falcon_key* falconKey, dilithium_key* dilithiumKey) + falcon_key* falconKey, dilithium_key* dilithiumKey, + sphincs_key* sphincsKey) { int ret; @@ -28119,6 +28806,7 @@ static int EncodeCertReq(Cert* cert, DerCert* der, RsaKey* rsaKey, (void)ed448Key; (void)falconKey; (void)dilithiumKey; + (void)sphincsKey; if (cert == NULL || der == NULL) return BAD_FUNC_ARG; @@ -28230,6 +28918,19 @@ static int EncodeCertReq(Cert* cert, DerCert* der, RsaKey* rsaKey, der->publicKey, (word32)sizeof(der->publicKey), 1); } #endif +#if defined(HAVE_SPHINCS) + if ((cert->keyType == SPHINCS_FAST_LEVEL1_KEY) || + (cert->keyType == SPHINCS_FAST_LEVEL3_KEY) || + (cert->keyType == SPHINCS_FAST_LEVEL5_KEY) || + (cert->keyType == SPHINCS_SMALL_LEVEL1_KEY) || + (cert->keyType == SPHINCS_SMALL_LEVEL3_KEY) || + (cert->keyType == SPHINCS_SMALL_LEVEL5_KEY)) { + if (sphincsKey == NULL) + return PUBLIC_KEY_E; + der->publicKeySz = wc_Sphincs_PublicKeyToDer(sphincsKey, + der->publicKey, (word32)sizeof(der->publicKey), 1); + } +#endif #endif /* HAVE_PQC */ if (der->publicKeySz <= 0) @@ -28514,7 +29215,8 @@ enum { static int MakeCertReq(Cert* cert, byte* derBuffer, word32 derSz, RsaKey* rsaKey, DsaKey* dsaKey, ecc_key* eccKey, ed25519_key* ed25519Key, ed448_key* ed448Key, - falcon_key* falconKey, dilithium_key* dilithiumKey) + falcon_key* falconKey, dilithium_key* dilithiumKey, + sphincs_key* sphincsKey) { #ifndef WOLFSSL_ASN_TEMPLATE int ret; @@ -28561,6 +29263,26 @@ static int MakeCertReq(Cert* cert, byte* derBuffer, word32 derSz, && (dilithiumKey->sym == AES_VARIANT)) cert->keyType = DILITHIUM_AES_LEVEL5_KEY; #endif /* HAVE_DILITHIUM */ +#ifdef HAVE_SPHINCS + else if ((sphincsKey != NULL) && (sphincsKey->level == 1) + && (sphincsKey->optim == FAST_VARIANT)) + cert->keyType = SPHINCS_FAST_LEVEL1_KEY; + else if ((sphincsKey != NULL) && (sphincsKey->level == 3) + && (sphincsKey->optim == FAST_VARIANT)) + cert->keyType = SPHINCS_FAST_LEVEL3_KEY; + else if ((sphincsKey != NULL) && (sphincsKey->level == 5) + && (sphincsKey->optim == FAST_VARIANT)) + cert->keyType = SPHINCS_FAST_LEVEL5_KEY; + else if ((sphincsKey != NULL) && (sphincsKey->level == 1) + && (sphincsKey->optim == SMALL_VARIANT)) + cert->keyType = SPHINCS_SMALL_LEVEL1_KEY; + else if ((sphincsKey != NULL) && (sphincsKey->level == 3) + && (sphincsKey->optim == SMALL_VARIANT)) + cert->keyType = SPHINCS_SMALL_LEVEL3_KEY; + else if ((sphincsKey != NULL) && (sphincsKey->level == 5) + && (sphincsKey->optim == SMALL_VARIANT)) + cert->keyType = SPHINCS_SMALL_LEVEL5_KEY; +#endif /* HAVE_SPHINCS */ #endif /* HAVE_PQC */ else return BAD_FUNC_ARG; @@ -28573,7 +29295,7 @@ static int MakeCertReq(Cert* cert, byte* derBuffer, word32 derSz, #endif ret = EncodeCertReq(cert, der, rsaKey, dsaKey, eccKey, ed25519Key, ed448Key, - falconKey, dilithiumKey); + falconKey, dilithiumKey, sphincsKey); if (ret == 0) { if (der->total + MAX_SEQ_SZ * 2 > (int)derSz) @@ -28601,6 +29323,7 @@ static int MakeCertReq(Cert* cert, byte* derBuffer, word32 derSz, /* Unused without OQS */ (void)falconKey; (void)dilithiumKey; + (void)sphincsKey; CALLOC_ASNSETDATA(dataASN, certReqBodyASN_Length, ret, cert->heap); @@ -28656,6 +29379,32 @@ static int MakeCertReq(Cert* cert, byte* derBuffer, word32 derSz, cert->keyType = DILITHIUM_AES_LEVEL5_KEY; } #endif /* HAVE_DILITHIUM */ +#ifdef HAVE_SPHINCS + else if ((sphincsKey != NULL) && (sphincsKey->level == 1) + && (sphincsKey->optim == FAST_VARIANT)) { + cert->keyType = SPHINCS_FAST_LEVEL1_KEY; + } + else if ((sphincsKey != NULL) && (sphincsKey->level == 3) + && (sphincsKey->optim == FAST_VARIANT)) { + cert->keyType = SPHINCS_FAST_LEVEL3_KEY; + } + else if ((sphincsKey != NULL) && (sphincsKey->level == 5) + && (sphincsKey->optim == FAST_VARIANT)) { + cert->keyType = SPHINCS_FAST_LEVEL5_KEY; + } + else if ((sphincsKey != NULL) && (sphincsKey->level == 1) + && (sphincsKey->optim == SMALL_VARIANT)) { + cert->keyType = SPHINCS_SMALL_LEVEL1_KEY; + } + else if ((sphincsKey != NULL) && (sphincsKey->level == 3) + && (sphincsKey->optim == SMALL_VARIANT)) { + cert->keyType = SPHINCS_SMALL_LEVEL3_KEY; + } + else if ((sphincsKey != NULL) && (sphincsKey->level == 5) + && (sphincsKey->optim == SMALL_VARIANT)) { + cert->keyType = SPHINCS_SMALL_LEVEL5_KEY; + } +#endif /* HAVE_SPHINCS */ #endif /* HAVE_PQC */ else { ret = BAD_FUNC_ARG; @@ -28804,6 +29553,7 @@ int wc_MakeCertReq_ex(Cert* cert, byte* derBuffer, word32 derSz, int keyType, ed448_key* ed448Key = NULL; falcon_key* falconKey = NULL; dilithium_key* dilithiumKey = NULL; + sphincs_key* sphincsKey = NULL; if (keyType == RSA_TYPE) rsaKey = (RsaKey*)key; @@ -28831,9 +29581,22 @@ int wc_MakeCertReq_ex(Cert* cert, byte* derBuffer, word32 derSz, int keyType, dilithiumKey = (dilithium_key*)key; else if (keyType == DILITHIUM_AES_LEVEL5_TYPE) dilithiumKey = (dilithium_key*)key; + else if (keyType == SPHINCS_FAST_LEVEL1_TYPE) + sphincsKey = (sphincs_key*)key; + else if (keyType == SPHINCS_FAST_LEVEL3_TYPE) + sphincsKey = (sphincs_key*)key; + else if (keyType == SPHINCS_FAST_LEVEL5_TYPE) + sphincsKey = (sphincs_key*)key; + else if (keyType == SPHINCS_SMALL_LEVEL1_TYPE) + sphincsKey = (sphincs_key*)key; + else if (keyType == SPHINCS_SMALL_LEVEL3_TYPE) + sphincsKey = (sphincs_key*)key; + else if (keyType == SPHINCS_SMALL_LEVEL5_TYPE) + sphincsKey = (sphincs_key*)key; return MakeCertReq(cert, derBuffer, derSz, rsaKey, dsaKey, eccKey, - ed25519Key, ed448Key, falconKey, dilithiumKey); + ed25519Key, ed448Key, falconKey, dilithiumKey, + sphincsKey); } WOLFSSL_ABI @@ -28841,7 +29604,7 @@ int wc_MakeCertReq(Cert* cert, byte* derBuffer, word32 derSz, RsaKey* rsaKey, ecc_key* eccKey) { return MakeCertReq(cert, derBuffer, derSz, rsaKey, NULL, eccKey, NULL, - NULL, NULL, NULL); + NULL, NULL, NULL, NULL); } #endif /* WOLFSSL_CERT_REQ */ @@ -28849,7 +29612,8 @@ int wc_MakeCertReq(Cert* cert, byte* derBuffer, word32 derSz, static int SignCert(int requestSz, int sType, byte* buf, word32 buffSz, RsaKey* rsaKey, ecc_key* eccKey, ed25519_key* ed25519Key, ed448_key* ed448Key, falcon_key* falconKey, - dilithium_key* dilithiumKey, WC_RNG* rng) + dilithium_key* dilithiumKey, sphincs_key* sphincsKey, + WC_RNG* rng) { int sigSz = 0; void* heap = NULL; @@ -28903,7 +29667,7 @@ static int SignCert(int requestSz, int sType, byte* buf, word32 buffSz, sigSz = MakeSignature(certSignCtx, buf, requestSz, certSignCtx->sig, MAX_ENCODED_SIG_SZ, rsaKey, eccKey, ed25519Key, ed448Key, - falconKey, dilithiumKey, rng, sType, heap); + falconKey, dilithiumKey, sphincsKey, rng, sType, heap); #ifdef WOLFSSL_ASYNC_CRYPT if (sigSz == WC_PENDING_E) { /* Not free'ing certSignCtx->sig here because it could still be in use @@ -28935,6 +29699,7 @@ int wc_SignCert_ex(int requestSz, int sType, byte* buf, word32 buffSz, ed448_key* ed448Key = NULL; falcon_key* falconKey = NULL; dilithium_key* dilithiumKey = NULL; + sphincs_key* sphincsKey = NULL; if (keyType == RSA_TYPE) rsaKey = (RsaKey*)key; @@ -28960,16 +29725,28 @@ int wc_SignCert_ex(int requestSz, int sType, byte* buf, word32 buffSz, dilithiumKey = (dilithium_key*)key; else if (keyType == DILITHIUM_AES_LEVEL5_TYPE) dilithiumKey = (dilithium_key*)key; + else if (keyType == SPHINCS_FAST_LEVEL1_TYPE) + sphincsKey = (sphincs_key*)key; + else if (keyType == SPHINCS_FAST_LEVEL3_TYPE) + sphincsKey = (sphincs_key*)key; + else if (keyType == SPHINCS_FAST_LEVEL5_TYPE) + sphincsKey = (sphincs_key*)key; + else if (keyType == SPHINCS_SMALL_LEVEL1_TYPE) + sphincsKey = (sphincs_key*)key; + else if (keyType == SPHINCS_SMALL_LEVEL3_TYPE) + sphincsKey = (sphincs_key*)key; + else if (keyType == SPHINCS_SMALL_LEVEL5_TYPE) + sphincsKey = (sphincs_key*)key; return SignCert(requestSz, sType, buf, buffSz, rsaKey, eccKey, ed25519Key, - ed448Key, falconKey, dilithiumKey, rng); + ed448Key, falconKey, dilithiumKey, sphincsKey, rng); } int wc_SignCert(int requestSz, int sType, byte* buf, word32 buffSz, RsaKey* rsaKey, ecc_key* eccKey, WC_RNG* rng) { return SignCert(requestSz, sType, buf, buffSz, rsaKey, eccKey, NULL, NULL, - NULL, NULL, rng); + NULL, NULL, NULL, rng); } WOLFSSL_ABI @@ -29006,14 +29783,16 @@ int wc_GetSubjectRaw(byte **subjectRaw, Cert *cert) static int SetKeyIdFromPublicKey(Cert *cert, RsaKey *rsakey, ecc_key *eckey, ed25519_key* ed25519Key, ed448_key* ed448Key, falcon_key* falconKey, - dilithium_key* dilithiumKey, int kid_type) + dilithium_key* dilithiumKey, + sphincs_key *sphincsKey, int kid_type) { byte *buf; int bufferSz, ret; if (cert == NULL || (rsakey == NULL && eckey == NULL && ed25519Key == NULL && - ed448Key == NULL && falconKey == NULL && dilithiumKey == NULL) || + ed448Key == NULL && falconKey == NULL && dilithiumKey == NULL && + sphincsKey == NULL) || (kid_type != SKID_TYPE && kid_type != AKID_TYPE)) return BAD_FUNC_ARG; @@ -29059,6 +29838,12 @@ static int SetKeyIdFromPublicKey(Cert *cert, RsaKey *rsakey, ecc_key *eckey, MAX_PUBLIC_KEY_SZ, 0); } #endif +#if defined(HAVE_SPHINCS) + if (sphincsKey != NULL) { + bufferSz = wc_Sphincs_PublicKeyToDer(sphincsKey, buf, + MAX_PUBLIC_KEY_SZ, 0); + } +#endif #endif /* HAVE_PQC */ if (bufferSz <= 0) { @@ -29090,6 +29875,7 @@ int wc_SetSubjectKeyIdFromPublicKey_ex(Cert *cert, int keyType, void* key) ed448_key* ed448Key = NULL; falcon_key* falconKey = NULL; dilithium_key* dilithiumKey = NULL; + sphincs_key* sphincsKey = NULL; if (keyType == RSA_TYPE) rsaKey = (RsaKey*)key; @@ -29115,16 +29901,29 @@ int wc_SetSubjectKeyIdFromPublicKey_ex(Cert *cert, int keyType, void* key) dilithiumKey = (dilithium_key*)key; else if (keyType == DILITHIUM_AES_LEVEL5_TYPE) dilithiumKey = (dilithium_key*)key; + else if (keyType == SPHINCS_FAST_LEVEL1_TYPE) + sphincsKey = (sphincs_key*)key; + else if (keyType == SPHINCS_FAST_LEVEL3_TYPE) + sphincsKey = (sphincs_key*)key; + else if (keyType == SPHINCS_FAST_LEVEL5_TYPE) + sphincsKey = (sphincs_key*)key; + else if (keyType == SPHINCS_SMALL_LEVEL1_TYPE) + sphincsKey = (sphincs_key*)key; + else if (keyType == SPHINCS_SMALL_LEVEL3_TYPE) + sphincsKey = (sphincs_key*)key; + else if (keyType == SPHINCS_SMALL_LEVEL5_TYPE) + sphincsKey = (sphincs_key*)key; return SetKeyIdFromPublicKey(cert, rsaKey, eccKey, ed25519Key, ed448Key, - falconKey, dilithiumKey, SKID_TYPE); + falconKey, dilithiumKey, sphincsKey, + SKID_TYPE); } /* Set SKID from RSA or ECC public key */ int wc_SetSubjectKeyIdFromPublicKey(Cert *cert, RsaKey *rsakey, ecc_key *eckey) { return SetKeyIdFromPublicKey(cert, rsakey, eckey, NULL, NULL, NULL, NULL, - SKID_TYPE); + NULL, SKID_TYPE); } int wc_SetAuthKeyIdFromPublicKey_ex(Cert *cert, int keyType, void* key) @@ -29135,6 +29934,7 @@ int wc_SetAuthKeyIdFromPublicKey_ex(Cert *cert, int keyType, void* key) ed448_key* ed448Key = NULL; falcon_key* falconKey = NULL; dilithium_key* dilithiumKey = NULL; + sphincs_key* sphincsKey = NULL; if (keyType == RSA_TYPE) rsaKey = (RsaKey*)key; @@ -29160,16 +29960,29 @@ int wc_SetAuthKeyIdFromPublicKey_ex(Cert *cert, int keyType, void* key) dilithiumKey = (dilithium_key*)key; else if (keyType == DILITHIUM_AES_LEVEL5_TYPE) dilithiumKey = (dilithium_key*)key; + else if (keyType == SPHINCS_FAST_LEVEL1_TYPE) + sphincsKey = (sphincs_key*)key; + else if (keyType == SPHINCS_FAST_LEVEL3_TYPE) + sphincsKey = (sphincs_key*)key; + else if (keyType == SPHINCS_FAST_LEVEL5_TYPE) + sphincsKey = (sphincs_key*)key; + else if (keyType == SPHINCS_SMALL_LEVEL1_TYPE) + sphincsKey = (sphincs_key*)key; + else if (keyType == SPHINCS_SMALL_LEVEL3_TYPE) + sphincsKey = (sphincs_key*)key; + else if (keyType == SPHINCS_SMALL_LEVEL5_TYPE) + sphincsKey = (sphincs_key*)key; return SetKeyIdFromPublicKey(cert, rsaKey, eccKey, ed25519Key, ed448Key, - falconKey, dilithiumKey, AKID_TYPE); + falconKey, dilithiumKey, sphincsKey, + AKID_TYPE); } /* Set SKID from RSA or ECC public key */ int wc_SetAuthKeyIdFromPublicKey(Cert *cert, RsaKey *rsakey, ecc_key *eckey) { return SetKeyIdFromPublicKey(cert, rsakey, eckey, NULL, NULL, NULL, NULL, - AKID_TYPE); + NULL, AKID_TYPE); } @@ -31911,7 +32724,8 @@ enum { || (defined(HAVE_ED448) && defined(HAVE_ED448_KEY_IMPORT)) \ || (defined(HAVE_CURVE448) && defined(HAVE_CURVE448_KEY_IMPORT)) \ || (defined(HAVE_PQC) && defined(HAVE_FALCON)) \ - || (defined(HAVE_PQC) && defined(HAVE_DILITHIUM))) + || (defined(HAVE_PQC) && defined(HAVE_DILITHIUM)) \ + || (defined(HAVE_PQC) && defined(HAVE_SPHINCS))) int DecodeAsymKey(const byte* input, word32* inOutIdx, word32 inSz, byte* privKey, word32* privKeyLen, diff --git a/wolfcrypt/src/sphincs.c b/wolfcrypt/src/sphincs.c new file mode 100644 index 000000000..8b8658549 --- /dev/null +++ b/wolfcrypt/src/sphincs.c @@ -0,0 +1,1053 @@ +/* sphincs.c + * + * Copyright (C) 2006-2022 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +/* Based on dilithium.c and Reworked for Sphincs by Anthony Hu. */ + +#ifdef HAVE_CONFIG_H + #include <config.h> +#endif + +/* in case user set HAVE_PQC there */ +#include <wolfssl/wolfcrypt/settings.h> + +#include <wolfssl/wolfcrypt/asn.h> + +#if defined(HAVE_PQC) && defined(HAVE_SPHINCS) + +#ifdef HAVE_LIBOQS +#include <oqs/oqs.h> +#endif + +#include <wolfssl/wolfcrypt/sphincs.h> +#include <wolfssl/wolfcrypt/error-crypt.h> +#ifdef NO_INLINE + #include <wolfssl/wolfcrypt/misc.h> +#else + #define WOLFSSL_MISC_INCLUDED + #include <wolfcrypt/src/misc.c> +#endif + +/* Sign the message using the sphincs private key. + * + * in [in] Message to sign. + * inLen [in] Length of the message in bytes. + * out [in] Buffer to write signature into. + * outLen [in/out] On in, size of buffer. + * On out, the length of the signature in bytes. + * key [in] Sphincs key to use when signing + * returns BAD_FUNC_ARG when a parameter is NULL or public key not set, + * BUFFER_E when outLen is less than SPHINCS_FAST_LEVEL1_SIG_SIZE, + * 0 otherwise. + */ +int wc_sphincs_sign_msg(const byte* in, word32 inLen, byte* out, word32 *outLen, + sphincs_key* key) +{ + int ret = 0; +#ifdef HAVE_LIBOQS + OQS_SIG *oqssig = NULL; + size_t localOutLen = 0; + + /* sanity check on arguments */ + if ((in == NULL) || (out == NULL) || (outLen == NULL) || (key == NULL)) { + ret = BAD_FUNC_ARG; + } + + if ((ret == 0) && (!key->prvKeySet)) { + ret = BAD_FUNC_ARG; + } + + if (ret == 0) { + if ((key->optim == FAST_VARIANT) && (key->level == 1)) { + oqssig = OQS_SIG_new(OQS_SIG_alg_sphincs_shake256_128f_simple); + } + else if ((key->optim == FAST_VARIANT) && (key->level == 3)) { + oqssig = OQS_SIG_new(OQS_SIG_alg_sphincs_shake256_192f_simple); + } + else if ((key->optim == FAST_VARIANT) && (key->level == 5)) { + oqssig = OQS_SIG_new(OQS_SIG_alg_sphincs_shake256_256f_simple); + } + else if ((key->optim == SMALL_VARIANT) && (key->level == 1)) { + oqssig = OQS_SIG_new(OQS_SIG_alg_sphincs_shake256_128s_simple); + } + else if ((key->optim == SMALL_VARIANT) && (key->level == 3)) { + oqssig = OQS_SIG_new(OQS_SIG_alg_sphincs_shake256_192s_simple); + } + else if ((key->optim == SMALL_VARIANT) && (key->level == 5)) { + oqssig = OQS_SIG_new(OQS_SIG_alg_sphincs_shake256_256s_simple); + } + + if (oqssig == NULL) { + ret = SIG_TYPE_E; + } + } + + /* check and set up out length */ + if (ret == 0) { + if ((key->level == 1) && (key->optim == FAST_VARIANT) && + (*outLen < SPHINCS_FAST_LEVEL1_SIG_SIZE)) { + *outLen = SPHINCS_FAST_LEVEL1_SIG_SIZE; + ret = BUFFER_E; + } + else if ((key->level == 3) && (key->optim == FAST_VARIANT) && + (*outLen < SPHINCS_FAST_LEVEL3_SIG_SIZE)) { + *outLen = SPHINCS_FAST_LEVEL3_SIG_SIZE; + ret = BUFFER_E; + } + else if ((key->level == 5) && (key->optim == FAST_VARIANT) && + (*outLen < SPHINCS_FAST_LEVEL5_SIG_SIZE)) { + *outLen = SPHINCS_FAST_LEVEL5_SIG_SIZE; + ret = BUFFER_E; + } + else if ((key->level == 1) && (key->optim == SMALL_VARIANT) && + (*outLen < SPHINCS_SMALL_LEVEL1_SIG_SIZE)) { + *outLen = SPHINCS_SMALL_LEVEL1_SIG_SIZE; + ret = BUFFER_E; + } + else if ((key->level == 3) && (key->optim == SMALL_VARIANT) && + (*outLen < SPHINCS_SMALL_LEVEL3_SIG_SIZE)) { + *outLen = SPHINCS_SMALL_LEVEL3_SIG_SIZE; + ret = BUFFER_E; + } + else if ((key->level == 5) && (key->optim == SMALL_VARIANT) && + (*outLen < SPHINCS_SMALL_LEVEL5_SIG_SIZE)) { + *outLen = SPHINCS_SMALL_LEVEL5_SIG_SIZE; + ret = BUFFER_E; + } + + localOutLen = *outLen; + } + + if ((ret == 0) && + (OQS_SIG_sign(oqssig, out, &localOutLen, in, inLen, key->k) + == OQS_ERROR)) { + ret = BAD_FUNC_ARG; + } + + if (ret == 0) { + *outLen = (word32)localOutLen; + } + + if (oqssig != NULL) { + OQS_SIG_free(oqssig); + } +#else + ret = NOT_COMPILED_IN; +#endif + return ret; +} + +/* Verify the message using the sphincs public key. + * + * sig [in] Signature to verify. + * sigLen [in] Size of signature in bytes. + * msg [in] Message to verify. + * msgLen [in] Length of the message in bytes. + * res [out] *res is set to 1 on successful verification. + * key [in] Sphincs key to use to verify. + * returns BAD_FUNC_ARG when a parameter is NULL or contextLen is zero when and + * BUFFER_E when sigLen is less than SPHINCS_FAST_LEVEL1_SIG_SIZE, + * 0 otherwise. + */ +int wc_sphincs_verify_msg(const byte* sig, word32 sigLen, const byte* msg, + word32 msgLen, int* res, sphincs_key* key) +{ + int ret = 0; +#ifdef HAVE_LIBOQS + OQS_SIG *oqssig = NULL; + + if (key == NULL || sig == NULL || msg == NULL || res == NULL) { + ret = BAD_FUNC_ARG; + } + + if ((ret == 0) && (!key->pubKeySet)) { + ret = BAD_FUNC_ARG; + } + + if (ret == 0) { + if ((key->optim == FAST_VARIANT) && (key->level == 1)) { + oqssig = OQS_SIG_new(OQS_SIG_alg_sphincs_shake256_128f_simple); + } + else if ((key->optim == FAST_VARIANT) && (key->level == 3)) { + oqssig = OQS_SIG_new(OQS_SIG_alg_sphincs_shake256_192f_simple); + } + else if ((key->optim == FAST_VARIANT) && (key->level == 5)) { + oqssig = OQS_SIG_new(OQS_SIG_alg_sphincs_shake256_256f_simple); + } + else if ((key->optim == SMALL_VARIANT) && (key->level == 1)) { + oqssig = OQS_SIG_new(OQS_SIG_alg_sphincs_shake256_128s_simple); + } + else if ((key->optim == SMALL_VARIANT) && (key->level == 3)) { + oqssig = OQS_SIG_new(OQS_SIG_alg_sphincs_shake256_192s_simple); + } + else if ((key->optim == SMALL_VARIANT) && (key->level == 5)) { + oqssig = OQS_SIG_new(OQS_SIG_alg_sphincs_shake256_256s_simple); + } + + if (oqssig == NULL) { + ret = SIG_TYPE_E; + } + } + + if ((ret == 0) && + (OQS_SIG_verify(oqssig, msg, msgLen, sig, sigLen, key->p) + == OQS_ERROR)) { + ret = SIG_VERIFY_E; + } + + if (ret == 0) { + *res = 1; + } + + if (oqssig != NULL) { + OQS_SIG_free(oqssig); + } +#else + ret = NOT_COMPILED_IN; +#endif + + return ret; +} + +/* Initialize the sphincs private/public key. + * + * key [in] Sphincs key. + * returns BAD_FUNC_ARG when key is NULL + */ +int wc_sphincs_init(sphincs_key* key) +{ + if (key == NULL) { + return BAD_FUNC_ARG; + } + + ForceZero(key, sizeof(key)); + return 0; +} + +/* Set the level of the sphincs private/public key. + * + * key [out] Sphincs key. + * level [in] Either 2,3 or 5. + * optim [in] Either FAST_VARIANT or SMALL_VARIANT. + * returns BAD_FUNC_ARG when key is NULL or level or optim are bad values. + */ +int wc_sphincs_set_level_and_optim(sphincs_key* key, byte level, byte optim) +{ + if (key == NULL) { + return BAD_FUNC_ARG; + } + + if (level != 1 && level != 3 && level != 5) { + return BAD_FUNC_ARG; + } + + if (optim != FAST_VARIANT && optim != SMALL_VARIANT) { + return BAD_FUNC_ARG; + } + + key->level = level; + key->optim = optim; + key->pubKeySet = 0; + key->prvKeySet = 0; + return 0; +} + +/* Get the level and optimization variant of the sphincs private/public key. + * + * key [in] Sphincs key. + * level [out] The level. + * optim [out] The optimization variant. FAST_VARIANT or SMALL_VARIANT. + * returns BAD_FUNC_ARG when key is NULL or level has not been set. + */ +int wc_sphincs_get_level_and_optim(sphincs_key* key, byte* level, byte* optim) +{ + if (key == NULL || level == NULL) { + return BAD_FUNC_ARG; + } + + if (key->level != 1 && key->level != 3 && key->level != 5) { + return BAD_FUNC_ARG; + } + + if (key->optim != FAST_VARIANT && key->optim != SMALL_VARIANT) { + return BAD_FUNC_ARG; + } + + *level = key->level; + *optim = key->optim; + return 0; +} + +/* Clears the sphincs key data + * + * key [in] Sphincs key. + */ +void wc_sphincs_free(sphincs_key* key) +{ + if (key != NULL) { + ForceZero(key, sizeof(key)); + } +} + +/* Export the sphincs public key. + * + * key [in] Sphincs public key. + * out [in] Array to hold public key. + * outLen [in/out] On in, the number of bytes in array. + * On out, the number bytes put into array. + * returns BAD_FUNC_ARG when a parameter is NULL, + * BUFFER_E when outLen is less than SPHINCS_FAST_LEVEL1_PUB_KEY_SIZE, + * 0 otherwise. + */ +int wc_sphincs_export_public(sphincs_key* key, + byte* out, word32* outLen) +{ + /* sanity check on arguments */ + if ((key == NULL) || (out == NULL) || (outLen == NULL)) { + return BAD_FUNC_ARG; + } + + if ((key->level != 1) && (key->level != 5)) { + return BAD_FUNC_ARG; + } + + if (!key->pubKeySet) { + return BAD_FUNC_ARG; + } + + /* check and set up out length */ + if ((key->level == 1) && (*outLen < SPHINCS_LEVEL1_PUB_KEY_SIZE)) { + *outLen = SPHINCS_LEVEL1_PUB_KEY_SIZE; + return BUFFER_E; + } + else if ((key->level == 3) && (*outLen < SPHINCS_LEVEL3_PUB_KEY_SIZE)) { + *outLen = SPHINCS_LEVEL3_PUB_KEY_SIZE; + return BUFFER_E; + } + else if ((key->level == 5) && (*outLen < SPHINCS_LEVEL5_PUB_KEY_SIZE)) { + *outLen = SPHINCS_LEVEL5_PUB_KEY_SIZE; + return BUFFER_E; + } + + if (key->level == 1) { + *outLen = SPHINCS_LEVEL1_PUB_KEY_SIZE; + XMEMCPY(out, key->p, SPHINCS_LEVEL1_PUB_KEY_SIZE); + } + else if (key->level == 3) { + *outLen = SPHINCS_LEVEL3_PUB_KEY_SIZE; + XMEMCPY(out, key->p, SPHINCS_LEVEL3_PUB_KEY_SIZE); + } + else if (key->level == 5) { + *outLen = SPHINCS_LEVEL5_PUB_KEY_SIZE; + XMEMCPY(out, key->p, SPHINCS_LEVEL5_PUB_KEY_SIZE); + } + + return 0; +} + +/* Import a sphincs public key from a byte array. + * Public key encoded in big-endian. + * + * in [in] Array holding public key. + * inLen [in] Number of bytes of data in array. + * key [in] Sphincs public key. + * returns BAD_FUNC_ARG when a parameter is NULL or key format is not supported, + * 0 otherwise. + */ +int wc_sphincs_import_public(const byte* in, word32 inLen, + sphincs_key* key) +{ + /* sanity check on arguments */ + if ((in == NULL) || (key == NULL)) { + return BAD_FUNC_ARG; + } + + if ((key->level != 1) && (key->level != 3) && (key->level != 5)) { + return BAD_FUNC_ARG; + } + + if ((key->optim != FAST_VARIANT) && (key->optim != SMALL_VARIANT)) { + return BAD_FUNC_ARG; + } + + if ((key->level == 1) && (inLen != SPHINCS_LEVEL1_PUB_KEY_SIZE)) { + return BAD_FUNC_ARG; + } + else if ((key->level == 3) && (inLen != SPHINCS_LEVEL3_PUB_KEY_SIZE)) { + return BAD_FUNC_ARG; + } + else if ((key->level == 5) && (inLen != SPHINCS_LEVEL5_PUB_KEY_SIZE)) { + return BAD_FUNC_ARG; + } + + XMEMCPY(key->p, in, inLen); + key->pubKeySet = 1; + + return 0; +} + +static int parse_private_key(const byte* priv, word32 privSz, + byte** out, word32 *outSz, + sphincs_key* key) { + word32 idx = 0; + int ret = 0; + int length = 0; + + /* sanity check on arguments */ + if ((priv == NULL) || (key == NULL)) { + return BAD_FUNC_ARG; + } + + if ((key->level != 1) && (key->level != 3) && (key->level != 5)) { + return BAD_FUNC_ARG; + } + + if ((key->optim != FAST_VARIANT) && (key->optim != SMALL_VARIANT)) { + return BAD_FUNC_ARG; + } + + /* At this point, it is still a PKCS8 private key. */ + if ((ret = ToTraditionalInline(priv, &idx, privSz)) < 0) { + return ret; + } + + /* Now it is a octet_string(concat(priv,pub)) */ + if ((ret = GetOctetString(priv, &idx, &length, privSz)) < 0) { + return ret; + } + + *out = (byte *)priv + idx; + *outSz = privSz - idx; + + /* And finally it is concat(priv,pub). Key size check. */ + if ((key->level == 1) && (*outSz != SPHINCS_LEVEL1_KEY_SIZE + + SPHINCS_LEVEL1_PUB_KEY_SIZE)) { + return BAD_FUNC_ARG; + } + else if ((key->level == 3) && (*outSz != SPHINCS_LEVEL3_KEY_SIZE + + SPHINCS_LEVEL3_PUB_KEY_SIZE)) { + return BAD_FUNC_ARG; + } + else if ((key->level == 5) && (*outSz != SPHINCS_LEVEL5_KEY_SIZE + + SPHINCS_LEVEL5_PUB_KEY_SIZE)) { + return BAD_FUNC_ARG; + } + + return 0; +} + +/* Import a sphincs private key from a byte array. + * + * priv [in] Array holding private key. + * privSz [in] Number of bytes of data in array. + * key [in] Sphincs private key. + * returns BAD_FUNC_ARG when a parameter is NULL or privSz is less than + * SPHINCS_LEVEL1_KEY_SIZE, + * 0 otherwise. + */ +int wc_sphincs_import_private_only(const byte* priv, word32 privSz, + sphincs_key* key) +{ + int ret = 0; + byte *newPriv = NULL; + word32 newPrivSz = 0; + + if ((ret = parse_private_key(priv, privSz, &newPriv, &newPrivSz, key)) + != 0) { + return ret; + } + + if (key->level == 1) { + XMEMCPY(key->k, newPriv, SPHINCS_LEVEL1_KEY_SIZE); + } + else if (key->level == 3) { + XMEMCPY(key->k, newPriv, SPHINCS_LEVEL3_KEY_SIZE); + } + else if (key->level == 5) { + XMEMCPY(key->k, newPriv, SPHINCS_LEVEL5_KEY_SIZE); + } + key->prvKeySet = 1; + + return 0; +} + +/* Import a sphincs private and public keys from byte array(s). + * + * priv [in] Array holding private key or private+public keys + * privSz [in] Number of bytes of data in private key array. + * pub [in] Array holding public key (or NULL). + * pubSz [in] Number of bytes of data in public key array (or 0). + * key [in] Sphincs private/public key. + * returns BAD_FUNC_ARG when a required parameter is NULL or an invalid + * combination of keys/lengths is supplied, 0 otherwise. + */ +int wc_sphincs_import_private_key(const byte* priv, word32 privSz, + const byte* pub, word32 pubSz, + sphincs_key* key) +{ + int ret = 0; + byte *newPriv = NULL; + word32 newPrivSz = 0; + + if ((ret = parse_private_key(priv, privSz, &newPriv, &newPrivSz, key)) + != 0) { + return ret; + } + + if (pub == NULL) { + if (pubSz != 0) { + return BAD_FUNC_ARG; + } + + if ((newPrivSz != SPHINCS_LEVEL1_PRV_KEY_SIZE) && + (newPrivSz != SPHINCS_LEVEL3_PRV_KEY_SIZE) && + (newPrivSz != SPHINCS_LEVEL5_PRV_KEY_SIZE)) { + return BAD_FUNC_ARG; + } + + if (key->level == 1) { + pub = newPriv + SPHINCS_LEVEL1_KEY_SIZE; + pubSz = SPHINCS_LEVEL1_PUB_KEY_SIZE; + } + else if (key->level == 3) { + pub = newPriv + SPHINCS_LEVEL3_KEY_SIZE; + pubSz = SPHINCS_LEVEL3_PUB_KEY_SIZE; + } + else if (key->level == 5) { + pub = newPriv + SPHINCS_LEVEL5_KEY_SIZE; + pubSz = SPHINCS_LEVEL5_PUB_KEY_SIZE; + } + } + else if ((pubSz != SPHINCS_LEVEL1_PUB_KEY_SIZE) && + (pubSz != SPHINCS_LEVEL3_PUB_KEY_SIZE) && + (pubSz != SPHINCS_LEVEL5_PUB_KEY_SIZE)) { + return BAD_FUNC_ARG; + } + + /* import public key */ + ret = wc_sphincs_import_public(pub, pubSz, key); + + if (ret == 0) { + /* make the private key (priv + pub) */ + if (key->level == 1) { + XMEMCPY(key->k, newPriv, SPHINCS_LEVEL1_KEY_SIZE); + } + else if (key->level == 3) { + XMEMCPY(key->k, newPriv, SPHINCS_LEVEL3_KEY_SIZE); + } + else if (key->level == 5) { + XMEMCPY(key->k, newPriv, SPHINCS_LEVEL5_KEY_SIZE); + } + key->prvKeySet = 1; + } + + return ret; +} + +/* Export the sphincs private key. + * + * key [in] Sphincs private key. + * out [in] Array to hold private key. + * outLen [in/out] On in, the number of bytes in array. + * On out, the number bytes put into array. + * returns BAD_FUNC_ARG when a parameter is NULL, + * BUFFER_E when outLen is less than SPHINCS_LEVEL1_KEY_SIZE, + * 0 otherwise. + */ +int wc_sphincs_export_private_only(sphincs_key* key, byte* out, word32* outLen) +{ + /* sanity checks on arguments */ + if ((key == NULL) || (out == NULL) || (outLen == NULL)) { + return BAD_FUNC_ARG; + } + + if ((key->level != 1) && (key->level != 3) && (key->level != 5)) { + return BAD_FUNC_ARG; + } + + if ((key->optim != FAST_VARIANT) && (key->optim != SMALL_VARIANT)) { + return BAD_FUNC_ARG; + } + + /* check and set up out length */ + if ((key->level == 1) && (*outLen < SPHINCS_LEVEL1_KEY_SIZE)) { + *outLen = SPHINCS_LEVEL1_KEY_SIZE; + return BUFFER_E; + } + else if ((key->level == 3) && (*outLen < SPHINCS_LEVEL3_KEY_SIZE)) { + *outLen = SPHINCS_LEVEL3_KEY_SIZE; + return BUFFER_E; + } + else if ((key->level == 5) && (*outLen < SPHINCS_LEVEL5_KEY_SIZE)) { + *outLen = SPHINCS_LEVEL5_KEY_SIZE; + return BUFFER_E; + } + + if (key->level == 1) { + *outLen = SPHINCS_LEVEL1_KEY_SIZE; + } + else if (key->level == 3) { + *outLen = SPHINCS_LEVEL3_KEY_SIZE; + } + else if (key->level == 5) { + *outLen = SPHINCS_LEVEL5_KEY_SIZE; + } + + XMEMCPY(out, key->k, *outLen); + + return 0; +} + +/* Export the sphincs private and public key. + * + * key [in] Sphincs private/public key. + * out [in] Array to hold private and public key. + * outLen [in/out] On in, the number of bytes in array. + * On out, the number bytes put into array. + * returns BAD_FUNC_ARG when a parameter is NULL, + * BUFFER_E when outLen is less than required, 0 otherwise. + */ +int wc_sphincs_export_private(sphincs_key* key, byte* out, word32* outLen) +{ + /* sanity checks on arguments */ + if ((key == NULL) || (out == NULL) || (outLen == NULL)) { + return BAD_FUNC_ARG; + } + + if ((key->level != 1) && (key->level != 3) && (key->level != 5)) { + return BAD_FUNC_ARG; + } + + if ((key->optim != FAST_VARIANT) && (key->optim != SMALL_VARIANT)) { + return BAD_FUNC_ARG; + } + + if ((key->level == 1) && (*outLen < SPHINCS_LEVEL1_PRV_KEY_SIZE)) { + *outLen = SPHINCS_LEVEL1_PRV_KEY_SIZE; + return BUFFER_E; + } + else if ((key->level == 3) && (*outLen < SPHINCS_LEVEL3_PRV_KEY_SIZE)) { + *outLen = SPHINCS_LEVEL3_PRV_KEY_SIZE; + return BUFFER_E; + } + else if ((key->level == 5) && (*outLen < SPHINCS_LEVEL5_PRV_KEY_SIZE)) { + *outLen = SPHINCS_LEVEL5_PRV_KEY_SIZE; + return BUFFER_E; + } + + + if (key->level == 1) { + *outLen = SPHINCS_LEVEL1_PRV_KEY_SIZE; + XMEMCPY(out, key->k, SPHINCS_LEVEL1_PRV_KEY_SIZE); + XMEMCPY(out + SPHINCS_LEVEL1_PRV_KEY_SIZE, key->p, + SPHINCS_LEVEL1_PUB_KEY_SIZE); + } + else if (key->level == 3) { + *outLen = SPHINCS_LEVEL3_PRV_KEY_SIZE; + XMEMCPY(out, key->k, SPHINCS_LEVEL3_PRV_KEY_SIZE); + XMEMCPY(out + SPHINCS_LEVEL3_PRV_KEY_SIZE, key->p, + SPHINCS_LEVEL3_PUB_KEY_SIZE); + } + else if (key->level == 5) { + *outLen = SPHINCS_LEVEL5_PRV_KEY_SIZE; + XMEMCPY(out, key->k, SPHINCS_LEVEL5_PRV_KEY_SIZE); + XMEMCPY(out + SPHINCS_LEVEL5_PRV_KEY_SIZE, key->p, + SPHINCS_LEVEL5_PUB_KEY_SIZE); + } + + return 0; +} + +/* Export the sphincs private and public key. + * + * key [in] Sphincs private/public key. + * priv [in] Array to hold private key. + * privSz [in/out] On in, the number of bytes in private key array. + * pub [in] Array to hold public key. + * pubSz [in/out] On in, the number of bytes in public key array. + * On out, the number bytes put into array. + * returns BAD_FUNC_ARG when a parameter is NULL, + * BUFFER_E when privSz is or pubSz is less than required, + * 0 otherwise. + */ +int wc_sphincs_export_key(sphincs_key* key, byte* priv, word32 *privSz, + byte* pub, word32 *pubSz) +{ + int ret = 0; + + /* export private part */ + ret = wc_sphincs_export_private(key, priv, privSz); + if (ret == 0) { + /* export public part */ + ret = wc_sphincs_export_public(key, pub, pubSz); + } + + return ret; +} + +/* Check the public key of the sphincs key matches the private key. + * + * key [in] Sphincs private/public key. + * returns BAD_FUNC_ARG when key is NULL, + * PUBLIC_KEY_E when the public key is not set or doesn't match, + * other -ve value on hash failure, + * 0 otherwise. + */ +int wc_sphincs_check_key(sphincs_key* key) +{ + if (key == NULL) { + return BAD_FUNC_ARG; + } + + /* Assume everything is fine. */ + return 0; +} + +/* Returns the size of a sphincs private key. + * + * key [in] Sphincs private/public key. + * returns BAD_FUNC_ARG when key is NULL, + * SPHINCS_LEVELn_KEY_SIZE otherwise. + */ +int wc_sphincs_size(sphincs_key* key) +{ + if (key == NULL) { + return BAD_FUNC_ARG; + } + + if (key->level == 1) { + return SPHINCS_LEVEL1_KEY_SIZE; + } + else if (key->level == 3) { + return SPHINCS_LEVEL3_KEY_SIZE; + } + else if (key->level == 5) { + return SPHINCS_LEVEL5_KEY_SIZE; + } + + return BAD_FUNC_ARG; +} + +/* Returns the size of a sphincs private plus public key. + * + * key [in] Sphincs private/public key. + * returns BAD_FUNC_ARG when key is NULL, + * SPHINCS_LEVELn_PRV_KEY_SIZE otherwise. + */ +int wc_sphincs_priv_size(sphincs_key* key) +{ + if (key == NULL) { + return BAD_FUNC_ARG; + } + + if (key->level == 1) { + return SPHINCS_LEVEL1_PRV_KEY_SIZE; + } + else if (key->level == 3) { + return SPHINCS_LEVEL3_PRV_KEY_SIZE; + } + else if (key->level == 5) { + return SPHINCS_LEVEL5_PRV_KEY_SIZE; + } + + return BAD_FUNC_ARG; +} + +/* Returns the size of a sphincs public key. + * + * key [in] Sphincs private/public key. + * returns BAD_FUNC_ARG when key is NULL, + * SPHINCS_FAST_LEVEL1_PUB_KEY_SIZE otherwise. + */ +int wc_sphincs_pub_size(sphincs_key* key) +{ + if (key == NULL) { + return BAD_FUNC_ARG; + } + + if (key->level == 1) { + return SPHINCS_LEVEL1_PUB_KEY_SIZE; + } + else if (key->level == 3) { + return SPHINCS_LEVEL3_PUB_KEY_SIZE; + } + else if (key->level == 5) { + return SPHINCS_LEVEL5_PUB_KEY_SIZE; + } + + return BAD_FUNC_ARG; +} + +/* Returns the size of a sphincs signature. + * + * key [in] Sphincs private/public key. + * returns BAD_FUNC_ARG when key is NULL, + * SPHINCS_FAST_LEVEL1_SIG_SIZE otherwise. + */ +int wc_sphincs_sig_size(sphincs_key* key) +{ + if (key == NULL) { + return BAD_FUNC_ARG; + } + + if ((key->level == 1) && (key->optim == FAST_VARIANT)) { + return SPHINCS_FAST_LEVEL1_SIG_SIZE; + } + else if ((key->level == 3) && (key->optim == FAST_VARIANT)) { + return SPHINCS_FAST_LEVEL3_SIG_SIZE; + } + else if ((key->level == 5) && (key->optim == FAST_VARIANT)) { + return SPHINCS_FAST_LEVEL5_SIG_SIZE; + } + else if ((key->level == 1) && (key->optim == SMALL_VARIANT)) { + return SPHINCS_SMALL_LEVEL1_SIG_SIZE; + } + else if ((key->level == 3) && (key->optim == SMALL_VARIANT)) { + return SPHINCS_SMALL_LEVEL3_SIG_SIZE; + } + else if ((key->level == 5) && (key->optim == SMALL_VARIANT)) { + return SPHINCS_SMALL_LEVEL5_SIG_SIZE; + } + + return BAD_FUNC_ARG; +} + +int wc_Sphincs_PrivateKeyDecode(const byte* input, word32* inOutIdx, + sphincs_key* key, word32 inSz) +{ + int ret = 0; + byte privKey[SPHINCS_MAX_KEY_SIZE], pubKey[SPHINCS_MAX_PUB_KEY_SIZE]; + word32 privKeyLen = (word32)sizeof(privKey); + word32 pubKeyLen = (word32)sizeof(pubKey); + int keytype = 0; + + if (input == NULL || inOutIdx == NULL || key == NULL || inSz == 0) { + return BAD_FUNC_ARG; + } + + if ((key->level == 1) && (key->optim == FAST_VARIANT)) { + keytype = SPHINCS_FAST_LEVEL1k; + } + else if ((key->level == 3) && (key->optim == FAST_VARIANT)) { + keytype = SPHINCS_FAST_LEVEL3k; + } + else if ((key->level == 5) && (key->optim == FAST_VARIANT)) { + keytype = SPHINCS_FAST_LEVEL5k; + } + if ((key->level == 1) && (key->optim == SMALL_VARIANT)) { + keytype = SPHINCS_SMALL_LEVEL1k; + } + else if ((key->level == 3) && (key->optim == SMALL_VARIANT)) { + keytype = SPHINCS_SMALL_LEVEL3k; + } + else if ((key->level == 5) && (key->optim == SMALL_VARIANT)) { + keytype = SPHINCS_SMALL_LEVEL5k; + } + else { + return BAD_FUNC_ARG; + } + + ret = DecodeAsymKey(input, inOutIdx, inSz, privKey, &privKeyLen, + pubKey, &pubKeyLen, keytype); + if (ret == 0) { + if (pubKeyLen == 0) { + ret = wc_sphincs_import_private_only(input, inSz, key); + } + else { + ret = wc_sphincs_import_private_key(privKey, privKeyLen, + pubKey, pubKeyLen, key); + } + } + return ret; +} + +int wc_Sphincs_PublicKeyDecode(const byte* input, word32* inOutIdx, + sphincs_key* key, word32 inSz) +{ + int ret = 0; + byte pubKey[SPHINCS_MAX_PUB_KEY_SIZE]; + word32 pubKeyLen = (word32)sizeof(pubKey); + int keytype = 0; + + if (input == NULL || inOutIdx == NULL || key == NULL || inSz == 0) { + return BAD_FUNC_ARG; + } + + if ((key->level == 1) && (key->optim == FAST_VARIANT)) { + keytype = SPHINCS_FAST_LEVEL1k; + } + else if ((key->level == 3) && (key->optim == FAST_VARIANT)) { + keytype = SPHINCS_FAST_LEVEL3k; + } + else if ((key->level == 5) && (key->optim == FAST_VARIANT)) { + keytype = SPHINCS_FAST_LEVEL5k; + } + if ((key->level == 1) && (key->optim == SMALL_VARIANT)) { + keytype = SPHINCS_SMALL_LEVEL1k; + } + else if ((key->level == 3) && (key->optim == SMALL_VARIANT)) { + keytype = SPHINCS_SMALL_LEVEL3k; + } + else if ((key->level == 5) && (key->optim == SMALL_VARIANT)) { + keytype = SPHINCS_SMALL_LEVEL5k; + } + else { + return BAD_FUNC_ARG; + } + + ret = DecodeAsymKeyPublic(input, inOutIdx, inSz, pubKey, &pubKeyLen, + keytype); + if (ret == 0) { + ret = wc_sphincs_import_public(pubKey, pubKeyLen, key); + } + return ret; +} + +#ifdef WC_ENABLE_ASYM_KEY_EXPORT +/* Encode the public part of an Sphincs key in DER. + * + * Pass NULL for output to get the size of the encoding. + * + * @param [in] key Sphincs key object. + * @param [out] output Buffer to put encoded data in. + * @param [in] outLen Size of buffer in bytes. + * @param [in] withAlg Whether to use SubjectPublicKeyInfo format. + * @return Size of encoded data in bytes on success. + * @return BAD_FUNC_ARG when key is NULL. + * @return MEMORY_E when dynamic memory allocation failed. + */ +int wc_Sphincs_PublicKeyToDer(sphincs_key* key, byte* output, word32 inLen, + int withAlg) +{ + int ret; + byte pubKey[SPHINCS_MAX_PUB_KEY_SIZE]; + word32 pubKeyLen = (word32)sizeof(pubKey); + int keytype = 0; + + if (key == NULL || output == NULL) { + return BAD_FUNC_ARG; + } + + if ((key->level == 1) && (key->optim == FAST_VARIANT)) { + keytype = SPHINCS_FAST_LEVEL1k; + } + else if ((key->level == 3) && (key->optim == FAST_VARIANT)) { + keytype = SPHINCS_FAST_LEVEL3k; + } + else if ((key->level == 5) && (key->optim == FAST_VARIANT)) { + keytype = SPHINCS_FAST_LEVEL5k; + } + if ((key->level == 1) && (key->optim == SMALL_VARIANT)) { + keytype = SPHINCS_SMALL_LEVEL1k; + } + else if ((key->level == 3) && (key->optim == SMALL_VARIANT)) { + keytype = SPHINCS_SMALL_LEVEL3k; + } + else if ((key->level == 5) && (key->optim == SMALL_VARIANT)) { + keytype = SPHINCS_SMALL_LEVEL5k; + } + else { + return BAD_FUNC_ARG; + } + + ret = wc_sphincs_export_public(key, pubKey, &pubKeyLen); + if (ret == 0) { + ret = SetAsymKeyDerPublic(pubKey, pubKeyLen, output, inLen, keytype, + withAlg); + } + + return ret; +} +#endif + +int wc_Sphincs_KeyToDer(sphincs_key* key, byte* output, word32 inLen) +{ + if (key == NULL) { + return BAD_FUNC_ARG; + } + + if ((key->level == 1) && (key->optim == FAST_VARIANT)) { + return SetAsymKeyDer(key->k, SPHINCS_LEVEL1_KEY_SIZE, key->p, + SPHINCS_LEVEL1_KEY_SIZE, output, inLen, + SPHINCS_FAST_LEVEL1k); + } + else if ((key->level == 3) && (key->optim == FAST_VARIANT)) { + return SetAsymKeyDer(key->k, SPHINCS_LEVEL3_KEY_SIZE, key->p, + SPHINCS_LEVEL3_KEY_SIZE, output, inLen, + SPHINCS_FAST_LEVEL3k); + } + else if ((key->level == 5) && (key->optim == FAST_VARIANT)) { + return SetAsymKeyDer(key->k, SPHINCS_LEVEL5_KEY_SIZE, key->p, + SPHINCS_LEVEL5_KEY_SIZE, output, inLen, + SPHINCS_FAST_LEVEL5k); + } + else if ((key->level == 1) && (key->optim == SMALL_VARIANT)) { + return SetAsymKeyDer(key->k, SPHINCS_LEVEL1_KEY_SIZE, key->p, + SPHINCS_LEVEL1_KEY_SIZE, output, inLen, + SPHINCS_SMALL_LEVEL1k); + } + else if ((key->level == 3) && (key->optim == SMALL_VARIANT)) { + return SetAsymKeyDer(key->k, SPHINCS_LEVEL3_KEY_SIZE, key->p, + SPHINCS_LEVEL3_KEY_SIZE, output, inLen, + SPHINCS_SMALL_LEVEL3k); + } + else if ((key->level == 5) && (key->optim == SMALL_VARIANT)) { + return SetAsymKeyDer(key->k, SPHINCS_LEVEL5_KEY_SIZE, key->p, + SPHINCS_LEVEL5_KEY_SIZE, output, inLen, + SPHINCS_SMALL_LEVEL5k); + } + + return BAD_FUNC_ARG; +} + +int wc_Sphincs_PrivateKeyToDer(sphincs_key* key, byte* output, word32 inLen) +{ + if (key == NULL) { + return BAD_FUNC_ARG; + } + + if ((key->level == 1) && (key->optim == FAST_VARIANT)) { + return SetAsymKeyDer(key->k, SPHINCS_LEVEL1_KEY_SIZE, NULL, 0, output, + inLen, SPHINCS_FAST_LEVEL1k); + } + else if ((key->level == 3) && (key->optim == FAST_VARIANT)) { + return SetAsymKeyDer(key->k, SPHINCS_LEVEL3_KEY_SIZE, NULL, 0, output, + inLen, SPHINCS_FAST_LEVEL3k); + } + else if ((key->level == 5) && (key->optim == FAST_VARIANT)) { + return SetAsymKeyDer(key->k, SPHINCS_LEVEL5_KEY_SIZE, NULL, 0, output, + inLen, SPHINCS_FAST_LEVEL5k); + } + else if ((key->level == 1) && (key->optim == SMALL_VARIANT)) { + return SetAsymKeyDer(key->k, SPHINCS_LEVEL1_KEY_SIZE, NULL, 0, output, + inLen, SPHINCS_SMALL_LEVEL1k); + } + else if ((key->level == 3) && (key->optim == SMALL_VARIANT)) { + return SetAsymKeyDer(key->k, SPHINCS_LEVEL3_KEY_SIZE, NULL, 0, output, + inLen, SPHINCS_SMALL_LEVEL3k); + } + else if ((key->level == 5) && (key->optim == SMALL_VARIANT)) { + return SetAsymKeyDer(key->k, SPHINCS_LEVEL5_KEY_SIZE, NULL, 0, output, + inLen, SPHINCS_SMALL_LEVEL5k); + } + + return BAD_FUNC_ARG; +} +#endif /* HAVE_PQC && HAVE_SPHINCS */ diff --git a/wolfssl/certs_test.h b/wolfssl/certs_test.h index 77e6ee584..12372968b 100644 --- a/wolfssl/certs_test.h +++ b/wolfssl/certs_test.h @@ -3349,7 +3349,7 @@ static const int sizeof_dh_key_der_4096 = sizeof(dh_key_der_4096); #endif /* USE_CERT_BUFFERS_4096 */ -#ifdef HAVE_PQC +#if defined(HAVE_PQC) && defined(HAVE_FALCON) /* certs/falcon/bench_falcon_level1_key.der */ static const unsigned char bench_falcon_level1_key[] = @@ -3997,9 +3997,9 @@ static const unsigned char bench_falcon_level5_key[] = }; static const int sizeof_bench_falcon_level5_key = sizeof(bench_falcon_level5_key); -#endif /* HAVE_PQC */ +#endif /* HAVE_PQC && HAVE_FALCON */ -#ifdef HAVE_PQC +#if defined (HAVE_PQC) && defined(HAVE_DILITHIUM) /* certs/dilithium/bench_dilithium_level2_key.der */ static const unsigned char bench_dilithium_level2_key[] = @@ -7509,7 +7509,149 @@ static const unsigned char bench_dilithium_aes_level5_key[] = }; static const int sizeof_bench_dilithium_aes_level5_key = sizeof(bench_dilithium_aes_level5_key); -#endif /* HAVE_PQC */ +#endif /* HAVE_PQC && HAVE_DILITHIUM */ + +#if defined(HAVE_PQC) && defined(HAVE_SPHINCS) + +/* certs/sphincs/bench_sphincs_fast_level1_key.der */ +static const unsigned char bench_sphincs_fast_level1_key[] = +{ + 0x30, 0x71, 0x02, 0x01, 0x00, 0x30, 0x08, 0x06, 0x06, 0x2B, + 0xCE, 0x0F, 0x06, 0x07, 0x04, 0x04, 0x62, 0x04, 0x60, 0x59, + 0xE0, 0xD4, 0x1F, 0x22, 0x74, 0xBD, 0xAC, 0x46, 0x01, 0xE4, + 0x8C, 0x89, 0xB7, 0x39, 0x20, 0x9F, 0x6F, 0x96, 0xC4, 0xE7, + 0x78, 0x0F, 0xA1, 0x7D, 0xEC, 0xE8, 0xD5, 0xC3, 0xDD, 0x45, + 0x13, 0x56, 0xCF, 0xEA, 0x68, 0x70, 0x2A, 0xFF, 0xDA, 0x9A, + 0xA3, 0x2B, 0xEC, 0x4D, 0xBF, 0x7D, 0x09, 0xC0, 0xCC, 0xF4, + 0x2F, 0xF2, 0xAC, 0x74, 0xDF, 0x0E, 0x20, 0x9D, 0xC2, 0x9E, + 0xD1, 0xB4, 0x12, 0x56, 0xCF, 0xEA, 0x68, 0x70, 0x2A, 0xFF, + 0xDA, 0x9A, 0xA3, 0x2B, 0xEC, 0x4D, 0xBF, 0x7D, 0x09, 0xC0, + 0xCC, 0xF4, 0x2F, 0xF2, 0xAC, 0x74, 0xDF, 0x0E, 0x20, 0x9D, + 0xC2, 0x9E, 0xD1, 0xB4, 0x12 +}; +static const int sizeof_bench_sphincs_fast_level1_key = sizeof(bench_sphincs_fast_level1_key); + +/* certs/sphincs/bench_sphincs_fast_level3_key.der */ +static const unsigned char bench_sphincs_fast_level3_key[] = +{ + 0x30, 0x81, 0xA3, 0x02, 0x01, 0x00, 0x30, 0x08, 0x06, 0x06, + 0x2B, 0xCE, 0x0F, 0x06, 0x08, 0x03, 0x04, 0x81, 0x93, 0x04, + 0x81, 0x90, 0x00, 0x8E, 0xB0, 0x75, 0x2E, 0xC5, 0x61, 0x66, + 0xEE, 0x01, 0xEE, 0x97, 0x13, 0xD7, 0x65, 0x69, 0xEA, 0x5C, + 0x23, 0xAA, 0x6E, 0x86, 0x04, 0xE9, 0x2A, 0xEC, 0x8C, 0xA3, + 0xB7, 0x28, 0xEB, 0xDF, 0x0E, 0x77, 0x07, 0x59, 0x3F, 0xB6, + 0x10, 0xB3, 0xCC, 0xE1, 0x09, 0x64, 0xC4, 0x42, 0x37, 0x71, + 0xDC, 0xB4, 0x20, 0x2D, 0x03, 0x00, 0x6C, 0x4C, 0x3F, 0xE3, + 0x80, 0x28, 0xEC, 0x90, 0xF9, 0xDB, 0x50, 0xFC, 0x0A, 0x58, + 0xC2, 0x81, 0xE2, 0x17, 0x06, 0x7A, 0x58, 0xBB, 0x21, 0x90, + 0xC8, 0xE6, 0x64, 0x8B, 0xF4, 0x68, 0x70, 0x1D, 0xE2, 0xAB, + 0x8F, 0x50, 0x4D, 0xEE, 0x29, 0xD7, 0x15, 0x5E, 0xDC, 0xB4, + 0x20, 0x2D, 0x03, 0x00, 0x6C, 0x4C, 0x3F, 0xE3, 0x80, 0x28, + 0xEC, 0x90, 0xF9, 0xDB, 0x50, 0xFC, 0x0A, 0x58, 0xC2, 0x81, + 0xE2, 0x17, 0x06, 0x7A, 0x58, 0xBB, 0x21, 0x90, 0xC8, 0xE6, + 0x64, 0x8B, 0xF4, 0x68, 0x70, 0x1D, 0xE2, 0xAB, 0x8F, 0x50, + 0x4D, 0xEE, 0x29, 0xD7, 0x15, 0x5E +}; +static const int sizeof_bench_sphincs_fast_level3_key = sizeof(bench_sphincs_fast_level3_key); + +/* certs/sphincs/bench_sphincs_fast_level5_key.der */ +static const unsigned char bench_sphincs_fast_level5_key[] = +{ + 0x30, 0x81, 0xD3, 0x02, 0x01, 0x00, 0x30, 0x08, 0x06, 0x06, + 0x2B, 0xCE, 0x0F, 0x06, 0x09, 0x03, 0x04, 0x81, 0xC3, 0x04, + 0x81, 0xC0, 0x91, 0x8B, 0xB7, 0x1A, 0x08, 0x61, 0x50, 0x70, + 0x26, 0x71, 0xCD, 0x36, 0x10, 0xE2, 0xB8, 0x95, 0x0D, 0xA7, + 0x57, 0xC7, 0x18, 0xFF, 0x55, 0xA4, 0x16, 0x9D, 0x3C, 0xF8, + 0xA3, 0x48, 0xB0, 0x9B, 0xFD, 0x22, 0xBE, 0x20, 0x3D, 0x88, + 0x96, 0x0B, 0xF1, 0x6D, 0x05, 0x8A, 0x1B, 0x71, 0xCE, 0xCD, + 0x31, 0x01, 0xEA, 0xAC, 0x62, 0x61, 0x1F, 0x4A, 0xC1, 0x62, + 0x05, 0x36, 0xBB, 0x7F, 0xEF, 0x5B, 0x42, 0x8B, 0xC6, 0xCD, + 0xEF, 0xCE, 0xE1, 0x00, 0x39, 0x4F, 0x01, 0xBC, 0x03, 0x94, + 0x00, 0xA8, 0x7F, 0x22, 0xB9, 0x9F, 0x79, 0x51, 0x25, 0x61, + 0x1B, 0x43, 0x47, 0x52, 0xD0, 0x39, 0x2B, 0x93, 0xC5, 0xD4, + 0x2A, 0xE1, 0xEF, 0x0B, 0x01, 0x36, 0xC3, 0x54, 0xC8, 0xDE, + 0xF4, 0xA2, 0x6F, 0x4C, 0x4B, 0xEC, 0x5D, 0x9D, 0xEE, 0xC9, + 0xFA, 0xBE, 0xFA, 0x5F, 0xC4, 0x89, 0xC1, 0xFC, 0xEB, 0xA8, + 0x42, 0x8B, 0xC6, 0xCD, 0xEF, 0xCE, 0xE1, 0x00, 0x39, 0x4F, + 0x01, 0xBC, 0x03, 0x94, 0x00, 0xA8, 0x7F, 0x22, 0xB9, 0x9F, + 0x79, 0x51, 0x25, 0x61, 0x1B, 0x43, 0x47, 0x52, 0xD0, 0x39, + 0x2B, 0x93, 0xC5, 0xD4, 0x2A, 0xE1, 0xEF, 0x0B, 0x01, 0x36, + 0xC3, 0x54, 0xC8, 0xDE, 0xF4, 0xA2, 0x6F, 0x4C, 0x4B, 0xEC, + 0x5D, 0x9D, 0xEE, 0xC9, 0xFA, 0xBE, 0xFA, 0x5F, 0xC4, 0x89, + 0xC1, 0xFC, 0xEB, 0xA8 +}; +static const int sizeof_bench_sphincs_fast_level5_key = sizeof(bench_sphincs_fast_level5_key); + +/* certs/sphincs/bench_sphincs_small_level1_key.der */ +static const unsigned char bench_sphincs_small_level1_key[] = +{ + 0x30, 0x71, 0x02, 0x01, 0x00, 0x30, 0x08, 0x06, 0x06, 0x2B, + 0xCE, 0x0F, 0x06, 0x07, 0x0A, 0x04, 0x62, 0x04, 0x60, 0x44, + 0x7A, 0xCF, 0xB9, 0x03, 0xF2, 0xB2, 0x41, 0xBC, 0x1A, 0xE6, + 0x75, 0x29, 0x04, 0xDA, 0x6C, 0x6E, 0x08, 0x17, 0x1E, 0x46, + 0x75, 0xE8, 0x32, 0x23, 0xCD, 0x11, 0xC8, 0x88, 0xF7, 0x00, + 0x11, 0x4C, 0xBD, 0x14, 0x62, 0xC2, 0x4B, 0x83, 0x36, 0xDE, + 0x61, 0x78, 0x7F, 0x09, 0x16, 0x97, 0x98, 0x3D, 0x52, 0x70, + 0x7F, 0xED, 0x86, 0xDB, 0x75, 0x42, 0x52, 0xF3, 0xB1, 0xAE, + 0x70, 0x7F, 0xD3, 0x4C, 0xBD, 0x14, 0x62, 0xC2, 0x4B, 0x83, + 0x36, 0xDE, 0x61, 0x78, 0x7F, 0x09, 0x16, 0x97, 0x98, 0x3D, + 0x52, 0x70, 0x7F, 0xED, 0x86, 0xDB, 0x75, 0x42, 0x52, 0xF3, + 0xB1, 0xAE, 0x70, 0x7F, 0xD3 +}; +static const int sizeof_bench_sphincs_small_level1_key = sizeof(bench_sphincs_small_level1_key); + +/* certs/sphincs/bench_sphincs_small_level3_key.der */ +static const unsigned char bench_sphincs_small_level3_key[] = +{ + 0x30, 0x81, 0xA3, 0x02, 0x01, 0x00, 0x30, 0x08, 0x06, 0x06, + 0x2B, 0xCE, 0x0F, 0x06, 0x08, 0x07, 0x04, 0x81, 0x93, 0x04, + 0x81, 0x90, 0x7E, 0x80, 0x20, 0x6C, 0x20, 0xAE, 0x7D, 0xAB, + 0xC1, 0x4E, 0x15, 0x51, 0x0C, 0xDD, 0x96, 0xAC, 0xFB, 0xD2, + 0x5B, 0xF1, 0xEB, 0x51, 0xDC, 0xC3, 0xB3, 0x92, 0x33, 0xC2, + 0x54, 0x59, 0x4F, 0xB2, 0x33, 0x7C, 0x10, 0xC6, 0xA3, 0x49, + 0x8D, 0x07, 0x52, 0xB2, 0xA1, 0x14, 0x0C, 0x54, 0x21, 0xD4, + 0xB1, 0xCC, 0xBD, 0xB1, 0x20, 0xAC, 0xF1, 0xBD, 0xF5, 0x60, + 0x2F, 0x07, 0x98, 0x57, 0x4E, 0x31, 0x6F, 0x42, 0x84, 0xCE, + 0x71, 0x72, 0x74, 0x20, 0xDF, 0x38, 0x39, 0xFB, 0xD3, 0xEE, + 0xAD, 0xFB, 0xB6, 0x2B, 0x60, 0x61, 0x85, 0xF1, 0x2A, 0x59, + 0x00, 0xA5, 0xCA, 0xC8, 0xE3, 0x3F, 0x96, 0xE9, 0xB1, 0xCC, + 0xBD, 0xB1, 0x20, 0xAC, 0xF1, 0xBD, 0xF5, 0x60, 0x2F, 0x07, + 0x98, 0x57, 0x4E, 0x31, 0x6F, 0x42, 0x84, 0xCE, 0x71, 0x72, + 0x74, 0x20, 0xDF, 0x38, 0x39, 0xFB, 0xD3, 0xEE, 0xAD, 0xFB, + 0xB6, 0x2B, 0x60, 0x61, 0x85, 0xF1, 0x2A, 0x59, 0x00, 0xA5, + 0xCA, 0xC8, 0xE3, 0x3F, 0x96, 0xE9 +}; +static const int sizeof_bench_sphincs_small_level3_key = sizeof(bench_sphincs_small_level3_key); + +/* certs/sphincs/bench_sphincs_small_level5_key.der */ +static const unsigned char bench_sphincs_small_level5_key[] = +{ + 0x30, 0x81, 0xD3, 0x02, 0x01, 0x00, 0x30, 0x08, 0x06, 0x06, + 0x2B, 0xCE, 0x0F, 0x06, 0x09, 0x07, 0x04, 0x81, 0xC3, 0x04, + 0x81, 0xC0, 0x5E, 0xEA, 0x46, 0x6D, 0xE5, 0xA1, 0x70, 0x07, + 0xF0, 0x5C, 0x59, 0xD5, 0xD7, 0x37, 0x06, 0xC7, 0xD6, 0x1C, + 0xEA, 0x06, 0x15, 0x6E, 0xB3, 0x07, 0x71, 0x34, 0xE8, 0xD4, + 0x13, 0x65, 0x58, 0xAE, 0xAC, 0xE9, 0x32, 0x26, 0x76, 0xCD, + 0x2C, 0x3D, 0x11, 0xF7, 0xAB, 0x8A, 0x84, 0x4F, 0x56, 0x6F, + 0x2F, 0x63, 0x82, 0x1A, 0x37, 0xAA, 0xAA, 0x49, 0x50, 0xC8, + 0xA5, 0x92, 0x6E, 0x3F, 0xD6, 0x67, 0xEA, 0x5C, 0x18, 0x8A, + 0x99, 0xD2, 0xB6, 0xE3, 0xD7, 0x68, 0x9E, 0x65, 0x21, 0xDD, + 0xE3, 0x44, 0x8B, 0x32, 0x30, 0x31, 0xA8, 0xF2, 0xBB, 0xED, + 0xC0, 0x3E, 0x1A, 0x7B, 0x36, 0xD8, 0xAD, 0x2A, 0xA4, 0x81, + 0xAC, 0xD3, 0x08, 0xAC, 0x54, 0x2A, 0xAC, 0xAA, 0x1B, 0x64, + 0x58, 0x7B, 0x94, 0xE0, 0x16, 0x36, 0xC9, 0x92, 0x09, 0x6A, + 0x8C, 0x4D, 0xE3, 0xAB, 0x0F, 0x1C, 0xE8, 0x77, 0x1F, 0xE5, + 0xEA, 0x5C, 0x18, 0x8A, 0x99, 0xD2, 0xB6, 0xE3, 0xD7, 0x68, + 0x9E, 0x65, 0x21, 0xDD, 0xE3, 0x44, 0x8B, 0x32, 0x30, 0x31, + 0xA8, 0xF2, 0xBB, 0xED, 0xC0, 0x3E, 0x1A, 0x7B, 0x36, 0xD8, + 0xAD, 0x2A, 0xA4, 0x81, 0xAC, 0xD3, 0x08, 0xAC, 0x54, 0x2A, + 0xAC, 0xAA, 0x1B, 0x64, 0x58, 0x7B, 0x94, 0xE0, 0x16, 0x36, + 0xC9, 0x92, 0x09, 0x6A, 0x8C, 0x4D, 0xE3, 0xAB, 0x0F, 0x1C, + 0xE8, 0x77, 0x1F, 0xE5 +}; +static const int sizeof_bench_sphincs_small_level5_key = sizeof(bench_sphincs_small_level5_key); + +#endif /* HAVE_PQC && HAVE_SPHINCS */ #if defined(HAVE_ECC) && defined(USE_CERT_BUFFERS_256) diff --git a/wolfssl/wolfcrypt/asn.h b/wolfssl/wolfcrypt/asn.h index 902113759..72267f50c 100644 --- a/wolfssl/wolfcrypt/asn.h +++ b/wolfssl/wolfcrypt/asn.h @@ -1095,6 +1095,12 @@ enum Key_Sum { DILITHIUM_AES_LEVEL2k = 217,/* 1.3.6.1.4.1.2.267.11.4.4 */ DILITHIUM_AES_LEVEL3k = 221,/* 1.3.6.1.4.1.2.267.11.6.5 + 1 (See GetOID() in asn.c) */ DILITHIUM_AES_LEVEL5k = 224,/* 1.3.6.1.4.1.2.267.11.8.7 */ + SPHINCS_FAST_LEVEL1k = 281, /* 1 3 9999 6 7 4 */ + SPHINCS_FAST_LEVEL3k = 283, /* 1 3 9999 6 8 3 + 2 (See GetOID() in asn.c) */ + SPHINCS_FAST_LEVEL5k = 282, /* 1 3 9999 6 9 3 */ + SPHINCS_SMALL_LEVEL1k = 287, /* 1 3 9999 6 7 10 */ + SPHINCS_SMALL_LEVEL3k = 285, /* 1 3 9999 6 8 7 */ + SPHINCS_SMALL_LEVEL5k = 286, /* 1 3 9999 6 9 7 */ }; #if !defined(NO_AES) || defined(HAVE_PKCS7) @@ -1411,6 +1417,7 @@ struct SignatureCtx { #ifdef HAVE_PQC struct falcon_key* falcon; struct dilithium_key* dilithium; + struct sphincs_key* sphincs; #endif void* ptr; } key; @@ -2233,6 +2240,12 @@ enum cert_enums { DILITHIUM_AES_LEVEL2_KEY = 21, DILITHIUM_AES_LEVEL3_KEY = 22, DILITHIUM_AES_LEVEL5_KEY = 23, + SPHINCS_FAST_LEVEL1_KEY = 24, + SPHINCS_FAST_LEVEL3_KEY = 25, + SPHINCS_FAST_LEVEL5_KEY = 26, + SPHINCS_SMALL_LEVEL1_KEY = 27, + SPHINCS_SMALL_LEVEL3_KEY = 28, + SPHINCS_SMALL_LEVEL5_KEY = 29, }; #endif /* WOLFSSL_CERT_GEN */ @@ -2473,7 +2486,8 @@ WOLFSSL_LOCAL void FreeDecodedCRL(DecodedCRL* dcrl); || (defined(HAVE_ED448) && defined(HAVE_ED448_KEY_IMPORT)) \ || (defined(HAVE_CURVE448) && defined(HAVE_CURVE448_KEY_IMPORT)) \ || (defined(HAVE_PQC) && defined(HAVE_FALCON)) \ - || (defined(HAVE_PQC) && defined(HAVE_DILITHIUM))) + || (defined(HAVE_PQC) && defined(HAVE_DILITHIUM)) \ + || (defined(HAVE_PQC) && defined(HAVE_SPHINCS))) WOLFSSL_LOCAL int DecodeAsymKey(const byte* input, word32* inOutIdx, word32 inSz, byte* privKey, word32* privKeyLen, byte* pubKey, word32* pubKeyLen, int keyType); diff --git a/wolfssl/wolfcrypt/asn_public.h b/wolfssl/wolfcrypt/asn_public.h index dcfb00499..0f212b5fd 100644 --- a/wolfssl/wolfcrypt/asn_public.h +++ b/wolfssl/wolfcrypt/asn_public.h @@ -76,6 +76,10 @@ This library defines the interface APIs for X509 certificates. typedef struct dilithium_key dilithium_key; #define WC_DILITHIUMKEY_TYPE_DEFINED #endif +#ifndef WC_SPHINCSKEY_TYPE_DEFINED + typedef struct sphincs_key sphincs_key; + #define WC_SPHINCSKEY_TYPE_DEFINED +#endif enum Ecc_Sum { ECC_SECP112R1_OID = 182, @@ -147,6 +151,13 @@ enum CertType { DILITHIUM_AES_LEVEL2_TYPE, DILITHIUM_AES_LEVEL3_TYPE, DILITHIUM_AES_LEVEL5_TYPE, + SPHINCS_FAST_LEVEL1_TYPE, + SPHINCS_FAST_LEVEL3_TYPE, + SPHINCS_FAST_LEVEL5_TYPE, + SPHINCS_SMALL_LEVEL1_TYPE, + SPHINCS_SMALL_LEVEL3_TYPE, + SPHINCS_SMALL_LEVEL5_TYPE, + }; @@ -191,6 +202,13 @@ enum Ctc_SigType { CTC_DILITHIUM_AES_LEVEL2 = 217, CTC_DILITHIUM_AES_LEVEL3 = 221, CTC_DILITHIUM_AES_LEVEL5 = 224, + + CTC_SPHINCS_FAST_LEVEL1 = 281, + CTC_SPHINCS_FAST_LEVEL3 = 283, + CTC_SPHINCS_FAST_LEVEL5 = 282, + CTC_SPHINCS_SMALL_LEVEL1 = 287, + CTC_SPHINCS_SMALL_LEVEL3 = 285, + CTC_SPHINCS_SMALL_LEVEL5 = 286, }; enum Ctc_Encoding { @@ -725,7 +743,8 @@ WOLFSSL_API int wc_DhPrivKeyToDer(DhKey* key, byte* out, word32* outSz); (defined(HAVE_CURVE25519) && defined(HAVE_CURVE25519_KEY_EXPORT)) || \ (defined(HAVE_ED448) && defined(HAVE_ED448_KEY_EXPORT)) || \ (defined(HAVE_CURVE448) && defined(HAVE_CURVE448_KEY_EXPORT)) || \ - (defined(HAVE_PQC) && (defined(HAVE_FALCON) || defined(HAVE_DILITHIUM)))) + (defined(HAVE_PQC) && (defined(HAVE_FALCON) || \ + defined(HAVE_DILITHIUM) || defined(HAVE_SPHINCS)))) #define WC_ENABLE_ASYM_KEY_EXPORT #endif @@ -786,32 +805,6 @@ WOLFSSL_API int wc_Ed448PublicKeyToDer( #endif #endif /* HAVE_ED448 */ -#ifdef HAVE_PQC -WOLFSSL_API int wc_Falcon_PrivateKeyDecode(const byte* input, word32* inOutIdx, - falcon_key* key, word32 inSz); -WOLFSSL_API int wc_Falcon_PublicKeyDecode(const byte* input, word32* inOutIdx, - falcon_key* key, word32 inSz); -WOLFSSL_API int wc_Falcon_KeyToDer(falcon_key* key, byte* output, - word32 inLen); -WOLFSSL_API int wc_Falcon_PrivateKeyToDer(falcon_key* key, byte* output, - word32 inLen); -WOLFSSL_API int wc_Falcon_PublicKeyToDer(falcon_key* key, byte* output, - word32 inLen, int withAlg); - -WOLFSSL_API int wc_Dilithium_PrivateKeyDecode(const byte* input, - word32* inOutIdx, - dilithium_key* key, word32 inSz); -WOLFSSL_API int wc_Dilithium_PublicKeyDecode(const byte* input, - word32* inOutIdx, - dilithium_key* key, word32 inSz); -WOLFSSL_API int wc_Dilithium_KeyToDer(dilithium_key* key, byte* output, - word32 inLen); -WOLFSSL_API int wc_Dilithium_PrivateKeyToDer(dilithium_key* key, byte* output, - word32 inLen); -WOLFSSL_API int wc_Dilithium_PublicKeyToDer(dilithium_key* key, byte* output, - word32 inLen, int withAlg); -#endif /* HAVE_PQC */ - #ifdef HAVE_CURVE448 #ifdef HAVE_CURVE448_KEY_IMPORT WOLFSSL_API int wc_Curve448PrivateKeyDecode(const byte* input, word32* inOutIdx, diff --git a/wolfssl/wolfcrypt/dilithium.h b/wolfssl/wolfcrypt/dilithium.h index 8199c038d..316fae10c 100644 --- a/wolfssl/wolfcrypt/dilithium.h +++ b/wolfssl/wolfcrypt/dilithium.h @@ -134,6 +134,19 @@ int wc_dilithium_pub_size(dilithium_key* key); WOLFSSL_API int wc_dilithium_sig_size(dilithium_key* key); +WOLFSSL_API int wc_Dilithium_PrivateKeyDecode(const byte* input, + word32* inOutIdx, + dilithium_key* key, word32 inSz); +WOLFSSL_API int wc_Dilithium_PublicKeyDecode(const byte* input, + word32* inOutIdx, + dilithium_key* key, word32 inSz); +WOLFSSL_API int wc_Dilithium_KeyToDer(dilithium_key* key, byte* output, + word32 inLen); +WOLFSSL_API int wc_Dilithium_PrivateKeyToDer(dilithium_key* key, byte* output, + word32 inLen); +WOLFSSL_API int wc_Dilithium_PublicKeyToDer(dilithium_key* key, byte* output, + word32 inLen, int withAlg); + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/wolfssl/wolfcrypt/falcon.h b/wolfssl/wolfcrypt/falcon.h index 7f6116727..d4f0b352c 100644 --- a/wolfssl/wolfcrypt/falcon.h +++ b/wolfssl/wolfcrypt/falcon.h @@ -125,6 +125,17 @@ int wc_falcon_pub_size(falcon_key* key); WOLFSSL_API int wc_falcon_sig_size(falcon_key* key); +WOLFSSL_API int wc_Falcon_PrivateKeyDecode(const byte* input, word32* inOutIdx, + falcon_key* key, word32 inSz); +WOLFSSL_API int wc_Falcon_PublicKeyDecode(const byte* input, word32* inOutIdx, + falcon_key* key, word32 inSz); +WOLFSSL_API int wc_Falcon_KeyToDer(falcon_key* key, byte* output, + word32 inLen); +WOLFSSL_API int wc_Falcon_PrivateKeyToDer(falcon_key* key, byte* output, + word32 inLen); +WOLFSSL_API int wc_Falcon_PublicKeyToDer(falcon_key* key, byte* output, + word32 inLen, int withAlg); + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/wolfssl/wolfcrypt/include.am b/wolfssl/wolfcrypt/include.am index 9aea5a654..c68d784bc 100644 --- a/wolfssl/wolfcrypt/include.am +++ b/wolfssl/wolfcrypt/include.am @@ -23,6 +23,7 @@ nobase_include_HEADERS+= \ wolfssl/wolfcrypt/ed448.h \ wolfssl/wolfcrypt/falcon.h \ wolfssl/wolfcrypt/dilithium.h \ + wolfssl/wolfcrypt/sphincs.h \ wolfssl/wolfcrypt/fe_448.h \ wolfssl/wolfcrypt/ge_448.h \ wolfssl/wolfcrypt/eccsi.h \ diff --git a/wolfssl/wolfcrypt/settings.h b/wolfssl/wolfcrypt/settings.h index b79f27021..e23cd433b 100644 --- a/wolfssl/wolfcrypt/settings.h +++ b/wolfssl/wolfcrypt/settings.h @@ -2721,6 +2721,7 @@ extern void uITRON4_free(void *p) ; #define HAVE_PQC #define HAVE_FALCON #define HAVE_DILITHIUM +#define HAVE_SPHINCS #define HAVE_KYBER #endif diff --git a/wolfssl/wolfcrypt/sphincs.h b/wolfssl/wolfcrypt/sphincs.h new file mode 100644 index 000000000..a927a2234 --- /dev/null +++ b/wolfssl/wolfcrypt/sphincs.h @@ -0,0 +1,166 @@ +/* sphincs.h + * + * Copyright (C) 2022 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +/*! + \file wolfssl/wolfcrypt/sphincs.h +*/ + +/* Interfaces for Sphincs: + * - SPHINCS_FAST_LEVEL1 (AKA SPHINCS+-SHAKE256-128f-simple) + * - SPHINCS_FAST_LEVEL3 (AKA SPHINCS+-SHAKE256-192f-simple) + * - SPHINCS_FAST_LEVEL5 (AKA SPHINCS+-SHAKE256-256f-simple) + * - SPHINCS_SMALL_LEVEL1 (AKA SPHINCS+-SHAKE256-128s-simple) + * - SPHINCS_SMALL_LEVEL3 (AKA SPHINCS+-SHAKE256-192s-simple) + * - SPHINCS_SMALL_LEVEL5 (AKA SPHINCS+-SHAKE256-256s-simple) + */ + +#ifndef WOLF_CRYPT_SPHINCS_H +#define WOLF_CRYPT_SPHINCS_H + +#include <wolfssl/wolfcrypt/types.h> + +#if defined(HAVE_PQC) && defined(HAVE_SPHINCS) + +#ifdef HAVE_LIBOQS +#include <oqs/oqs.h> +#endif + +#ifdef __cplusplus + extern "C" { +#endif + +/* Macros Definitions */ + +#ifdef HAVE_LIBOQS + +#define SPHINCS_FAST_LEVEL1_SIG_SIZE OQS_SIG_sphincs_shake256_128f_simple_length_signature +#define SPHINCS_FAST_LEVEL3_SIG_SIZE OQS_SIG_sphincs_shake256_192f_simple_length_signature +#define SPHINCS_FAST_LEVEL5_SIG_SIZE OQS_SIG_sphincs_shake256_256f_simple_length_signature +#define SPHINCS_SMALL_LEVEL1_SIG_SIZE OQS_SIG_sphincs_shake256_128s_simple_length_signature +#define SPHINCS_SMALL_LEVEL3_SIG_SIZE OQS_SIG_sphincs_shake256_192s_simple_length_signature +#define SPHINCS_SMALL_LEVEL5_SIG_SIZE OQS_SIG_sphincs_shake256_256s_simple_length_signature + +#define SPHINCS_LEVEL1_KEY_SIZE OQS_SIG_sphincs_shake256_128f_simple_length_secret_key +#define SPHINCS_LEVEL1_PUB_KEY_SIZE OQS_SIG_sphincs_shake256_128f_simple_length_public_key +#define SPHINCS_LEVEL1_PRV_KEY_SIZE (SPHINCS_LEVEL1_PUB_KEY_SIZE+SPHINCS_LEVEL1_KEY_SIZE) + +#define SPHINCS_LEVEL3_KEY_SIZE OQS_SIG_sphincs_shake256_192f_simple_length_secret_key +#define SPHINCS_LEVEL3_PUB_KEY_SIZE OQS_SIG_sphincs_shake256_192f_simple_length_public_key +#define SPHINCS_LEVEL3_PRV_KEY_SIZE (SPHINCS_LEVEL3_PUB_KEY_SIZE+SPHINCS_LEVEL3_KEY_SIZE) + +#define SPHINCS_LEVEL5_KEY_SIZE OQS_SIG_sphincs_shake256_256f_simple_length_secret_key +#define SPHINCS_LEVEL5_PUB_KEY_SIZE OQS_SIG_sphincs_shake256_256f_simple_length_public_key +#define SPHINCS_LEVEL5_PRV_KEY_SIZE (SPHINCS_LEVEL5_PUB_KEY_SIZE+SPHINCS_LEVEL5_KEY_SIZE) +#endif + +#define SPHINCS_MAX_SIG_SIZE SPHINCS_FAST_LEVEL5_SIG_SIZE +#define SPHINCS_MAX_KEY_SIZE SPHINCS_LEVEL5_PRV_KEY_SIZE +#define SPHINCS_MAX_PUB_KEY_SIZE SPHINCS_LEVEL5_PUB_KEY_SIZE +#define SPHINCS_MAX_PRV_KEY_SIZE SPHINCS_LEVEL5_PRV_KEY_SIZE + +#define FAST_VARIANT 1 +#define SMALL_VARIANT 2 + +/* Structs */ + +struct sphincs_key { + bool pubKeySet; + bool prvKeySet; + byte level; /* 1,3 or 5 */ + byte optim; /* FAST_VARIANT or SMALL_VARIANT */ + byte p[SPHINCS_MAX_PUB_KEY_SIZE]; + byte k[SPHINCS_MAX_PRV_KEY_SIZE]; +}; + +#ifndef WC_SPHINCSKEY_TYPE_DEFINED + typedef struct sphincs_key sphincs_key; + #define WC_SPHINCSKEY_TYPE_DEFINED +#endif + +/* Functions */ + +WOLFSSL_API +int wc_sphincs_sign_msg(const byte* in, word32 inLen, byte* out, word32 *outLen, + sphincs_key* key); +WOLFSSL_API +int wc_sphincs_verify_msg(const byte* sig, word32 sigLen, const byte* msg, + word32 msgLen, int* res, sphincs_key* key); + +WOLFSSL_API +int wc_sphincs_init(sphincs_key* key); +WOLFSSL_API +int wc_sphincs_set_level_and_optim(sphincs_key* key, byte level, byte optim); +WOLFSSL_API +int wc_sphincs_get_level_and_optim(sphincs_key* key, byte* level, byte *optim); +WOLFSSL_API +void wc_sphincs_free(sphincs_key* key); + +WOLFSSL_API +int wc_sphincs_import_public(const byte* in, word32 inLen, sphincs_key* key); +WOLFSSL_API +int wc_sphincs_import_private_only(const byte* priv, word32 privSz, + sphincs_key* key); +WOLFSSL_API +int wc_sphincs_import_private_key(const byte* priv, word32 privSz, + const byte* pub, word32 pubSz, + sphincs_key* key); + +WOLFSSL_API +int wc_sphincs_export_public(sphincs_key*, byte* out, word32* outLen); +WOLFSSL_API +int wc_sphincs_export_private_only(sphincs_key* key, byte* out, word32* outLen); +WOLFSSL_API +int wc_sphincs_export_private(sphincs_key* key, byte* out, word32* outLen); +WOLFSSL_API +int wc_sphincs_export_key(sphincs_key* key, byte* priv, word32 *privSz, + byte* pub, word32 *pubSz); + +WOLFSSL_API +int wc_sphincs_check_key(sphincs_key* key); + +WOLFSSL_API +int wc_sphincs_size(sphincs_key* key); +WOLFSSL_API +int wc_sphincs_priv_size(sphincs_key* key); +WOLFSSL_API +int wc_sphincs_pub_size(sphincs_key* key); +WOLFSSL_API +int wc_sphincs_sig_size(sphincs_key* key); + +WOLFSSL_API int wc_Sphincs_PrivateKeyDecode(const byte* input, + word32* inOutIdx, + sphincs_key* key, word32 inSz); +WOLFSSL_API int wc_Sphincs_PublicKeyDecode(const byte* input, + word32* inOutIdx, + sphincs_key* key, word32 inSz); +WOLFSSL_API int wc_Sphincs_KeyToDer(sphincs_key* key, byte* output, + word32 inLen); +WOLFSSL_API int wc_Sphincs_PrivateKeyToDer(sphincs_key* key, byte* output, + word32 inLen); +WOLFSSL_API int wc_Sphincs_PublicKeyToDer(sphincs_key* key, byte* output, + word32 inLen, int withAlg); + +#ifdef __cplusplus + } /* extern "C" */ +#endif + +#endif /* HAVE_PQC && HAVE_SPHINCS */ +#endif /* WOLF_CRYPT_SPHINCS_H */ diff --git a/wolfssl/wolfcrypt/types.h b/wolfssl/wolfcrypt/types.h index 8b24626be..5da08120b 100644 --- a/wolfssl/wolfcrypt/types.h +++ b/wolfssl/wolfcrypt/types.h @@ -945,6 +945,7 @@ typedef struct w64wrapper { DYNAMIC_TYPE_FALCON = 95, DYNAMIC_TYPE_SESSION = 96, DYNAMIC_TYPE_DILITHIUM = 97, + DYNAMIC_TYPE_SPHINCS = 98, DYNAMIC_TYPE_SNIFFER_SERVER = 1000, DYNAMIC_TYPE_SNIFFER_SESSION = 1001, DYNAMIC_TYPE_SNIFFER_PB = 1002,