diff --git a/doc/crypt.tex b/doc/crypt.tex
index cd001dbab..816ee0047 100644
--- a/doc/crypt.tex
+++ b/doc/crypt.tex
@@ -5631,6 +5631,7 @@ \subsection{Signature Formats}
\hline LTC\_ECCSIG\_ANSIX962 & ASN.1 encoded, ANSI X9.62 \\
\hline LTC\_ECCSIG\_RFC7518 & raw R, S values as defined in RFC7518 \\
\hline LTC\_ECCSIG\_ETH27 & raw R, S, V values (V has 27 added) \\
+\hline LTC\_ECCSIG\_RFC5656 & SSH+ECDSA format as defined in RFC5656 \\
\hline
\end{tabular}
\end{center}
@@ -7792,7 +7793,7 @@ \subsubsection{Endianness}
There are also options you can specify from the \textit{tomcrypt\_custom.h} header file.
\subsection{X memory routines}
-\index{XMALLOC}\index{XREALLOC}\index{XCALLOC}\index{XFREE}\index{XMEMSET}\index{XMEMCPY}\index{XMEMMOVE}\index{XMEMCMP}\index{XSTRCMP}
+\index{XMALLOC}\index{XREALLOC}\index{XCALLOC}\index{XFREE}\index{XMEMSET}\index{XMEMCPY}\index{XMEMMOVE}\index{XMEMCMP}\index{XSTRCMP}\index{XSTRNCPY}
At the top of tomcrypt\_custom.h are a series of macros denoted as XMALLOC, XCALLOC, XREALLOC, XFREE, and so on. They resolve to
the name of the respective functions from the standard C library by default. This lets you substitute in your own memory routines.
If you substitute in your own functions they must behave like the standard C library functions in terms of what they expect as input and
diff --git a/helper.pl b/helper.pl
index 90b743e88..22fac916a 100755
--- a/helper.pl
+++ b/helper.pl
@@ -53,6 +53,8 @@ sub check_source {
push @{$troubles->{unwanted_memmove}}, $lineno if $file =~ /^src\/.*\.c$/ && $l =~ /\bmemmove\s*\(/;
push @{$troubles->{unwanted_memcmp}}, $lineno if $file =~ /^src\/.*\.c$/ && $l =~ /\bmemcmp\s*\(/;
push @{$troubles->{unwanted_strcmp}}, $lineno if $file =~ /^src\/.*\.c$/ && $l =~ /\bstrcmp\s*\(/;
+ push @{$troubles->{unwanted_strcpy}}, $lineno if $file =~ /^src\/.*\.c$/ && $l =~ /\bstrcpy\s*\(/;
+ push @{$troubles->{unwanted_strncpy}}, $lineno if $file =~ /^src\/.*\.c$/ && $l =~ /\bstrncpy\s*\(/;
push @{$troubles->{unwanted_clock}}, $lineno if $file =~ /^src\/.*\.c$/ && $l =~ /\bclock\s*\(/;
push @{$troubles->{unwanted_qsort}}, $lineno if $file =~ /^src\/.*\.c$/ && $l =~ /\bqsort\s*\(/;
push @{$troubles->{sizeof_no_brackets}}, $lineno if $file =~ /^src\/.*\.c$/ && $l =~ /\bsizeof\s*[^\(]/;
diff --git a/libtomcrypt_VS2008.vcproj b/libtomcrypt_VS2008.vcproj
index 1f07c419d..8bc1c62c9 100644
--- a/libtomcrypt_VS2008.vcproj
+++ b/libtomcrypt_VS2008.vcproj
@@ -1607,6 +1607,18 @@
>
+
+
+
+
+
+
+
+
diff --git a/makefile.mingw b/makefile.mingw
index 8cad94e91..9d0a70f9d 100644
--- a/makefile.mingw
+++ b/makefile.mingw
@@ -112,7 +112,8 @@ src/misc/crypt/crypt_unregister_prng.o src/misc/error_to_string.o src/misc/hkdf/
src/misc/hkdf/hkdf_test.o src/misc/mem_neq.o src/misc/padding/padding_depad.o \
src/misc/padding/padding_pad.o src/misc/pbes/pbes.o src/misc/pbes/pbes1.o src/misc/pbes/pbes2.o \
src/misc/pkcs12/pkcs12_kdf.o src/misc/pkcs12/pkcs12_utf8_to_utf16.o src/misc/pkcs5/pkcs_5_1.o \
-src/misc/pkcs5/pkcs_5_2.o src/misc/pkcs5/pkcs_5_test.o src/misc/zeromem.o src/modes/cbc/cbc_decrypt.o \
+src/misc/pkcs5/pkcs_5_2.o src/misc/pkcs5/pkcs_5_test.o src/misc/ssh/ssh_decode_sequence_multi.o \
+src/misc/ssh/ssh_encode_sequence_multi.o src/misc/zeromem.o src/modes/cbc/cbc_decrypt.o \
src/modes/cbc/cbc_done.o src/modes/cbc/cbc_encrypt.o src/modes/cbc/cbc_getiv.o \
src/modes/cbc/cbc_setiv.o src/modes/cbc/cbc_start.o src/modes/cfb/cfb_decrypt.o \
src/modes/cfb/cfb_done.o src/modes/cfb/cfb_encrypt.o src/modes/cfb/cfb_getiv.o \
@@ -184,18 +185,19 @@ src/pk/ecc/ecc_free.o src/pk/ecc/ecc_get_key.o src/pk/ecc/ecc_get_oid_str.o src/
src/pk/ecc/ecc_import.o src/pk/ecc/ecc_import_openssl.o src/pk/ecc/ecc_import_pkcs8.o \
src/pk/ecc/ecc_import_x509.o src/pk/ecc/ecc_make_key.o src/pk/ecc/ecc_recover_key.o \
src/pk/ecc/ecc_set_curve.o src/pk/ecc/ecc_set_curve_internal.o src/pk/ecc/ecc_set_key.o \
-src/pk/ecc/ecc_shared_secret.o src/pk/ecc/ecc_sign_hash.o src/pk/ecc/ecc_sizes.o src/pk/ecc/ecc_test.o \
-src/pk/ecc/ecc_verify_hash.o src/pk/ecc/ltc_ecc_export_point.o src/pk/ecc/ltc_ecc_import_point.o \
-src/pk/ecc/ltc_ecc_is_point.o src/pk/ecc/ltc_ecc_is_point_at_infinity.o src/pk/ecc/ltc_ecc_map.o \
-src/pk/ecc/ltc_ecc_mul2add.o src/pk/ecc/ltc_ecc_mulmod.o src/pk/ecc/ltc_ecc_mulmod_timing.o \
-src/pk/ecc/ltc_ecc_points.o src/pk/ecc/ltc_ecc_projective_add_point.o \
-src/pk/ecc/ltc_ecc_projective_dbl_point.o src/pk/ecc/ltc_ecc_verify_key.o src/pk/pkcs1/pkcs_1_i2osp.o \
-src/pk/pkcs1/pkcs_1_mgf1.o src/pk/pkcs1/pkcs_1_oaep_decode.o src/pk/pkcs1/pkcs_1_oaep_encode.o \
-src/pk/pkcs1/pkcs_1_os2ip.o src/pk/pkcs1/pkcs_1_pss_decode.o src/pk/pkcs1/pkcs_1_pss_encode.o \
-src/pk/pkcs1/pkcs_1_v1_5_decode.o src/pk/pkcs1/pkcs_1_v1_5_encode.o src/pk/rsa/rsa_decrypt_key.o \
-src/pk/rsa/rsa_encrypt_key.o src/pk/rsa/rsa_export.o src/pk/rsa/rsa_exptmod.o src/pk/rsa/rsa_free.o \
-src/pk/rsa/rsa_get_size.o src/pk/rsa/rsa_import.o src/pk/rsa/rsa_import_pkcs8.o \
-src/pk/rsa/rsa_import_x509.o src/pk/rsa/rsa_make_key.o src/pk/rsa/rsa_set.o src/pk/rsa/rsa_sign_hash.o \
+src/pk/ecc/ecc_shared_secret.o src/pk/ecc/ecc_sign_hash.o src/pk/ecc/ecc_sizes.o \
+src/pk/ecc/ecc_ssh_ecdsa_encode_name.o src/pk/ecc/ecc_test.o src/pk/ecc/ecc_verify_hash.o \
+src/pk/ecc/ltc_ecc_export_point.o src/pk/ecc/ltc_ecc_import_point.o src/pk/ecc/ltc_ecc_is_point.o \
+src/pk/ecc/ltc_ecc_is_point_at_infinity.o src/pk/ecc/ltc_ecc_map.o src/pk/ecc/ltc_ecc_mul2add.o \
+src/pk/ecc/ltc_ecc_mulmod.o src/pk/ecc/ltc_ecc_mulmod_timing.o src/pk/ecc/ltc_ecc_points.o \
+src/pk/ecc/ltc_ecc_projective_add_point.o src/pk/ecc/ltc_ecc_projective_dbl_point.o \
+src/pk/ecc/ltc_ecc_verify_key.o src/pk/pkcs1/pkcs_1_i2osp.o src/pk/pkcs1/pkcs_1_mgf1.o \
+src/pk/pkcs1/pkcs_1_oaep_decode.o src/pk/pkcs1/pkcs_1_oaep_encode.o src/pk/pkcs1/pkcs_1_os2ip.o \
+src/pk/pkcs1/pkcs_1_pss_decode.o src/pk/pkcs1/pkcs_1_pss_encode.o src/pk/pkcs1/pkcs_1_v1_5_decode.o \
+src/pk/pkcs1/pkcs_1_v1_5_encode.o src/pk/rsa/rsa_decrypt_key.o src/pk/rsa/rsa_encrypt_key.o \
+src/pk/rsa/rsa_export.o src/pk/rsa/rsa_exptmod.o src/pk/rsa/rsa_free.o src/pk/rsa/rsa_get_size.o \
+src/pk/rsa/rsa_import.o src/pk/rsa/rsa_import_pkcs8.o src/pk/rsa/rsa_import_x509.o \
+src/pk/rsa/rsa_make_key.o src/pk/rsa/rsa_set.o src/pk/rsa/rsa_sign_hash.o \
src/pk/rsa/rsa_sign_saltlen_get.o src/pk/rsa/rsa_verify_hash.o src/prngs/chacha20.o src/prngs/fortuna.o \
src/prngs/rc4.o src/prngs/rng_get_bytes.o src/prngs/rng_make_prng.o src/prngs/sober128.o \
src/prngs/sprng.o src/prngs/yarrow.o src/stream/chacha/chacha_crypt.o src/stream/chacha/chacha_done.o \
@@ -218,7 +220,7 @@ tests/common.o tests/der_test.o tests/dh_test.o tests/dsa_test.o tests/ecc_test.
tests/mac_test.o tests/misc_test.o tests/modes_test.o tests/mpi_test.o tests/multi_test.o tests/no_prng.o \
tests/padding_test.o tests/pkcs_1_eme_test.o tests/pkcs_1_emsa_test.o tests/pkcs_1_oaep_test.o \
tests/pkcs_1_pss_test.o tests/pkcs_1_test.o tests/prng_test.o tests/rotate_test.o tests/rsa_test.o \
-tests/store_test.o tests/test.o
+tests/ssh_test.o tests/store_test.o tests/test.o
#The following headers will be installed by "make install"
HEADERS_PUB=src/headers/tomcrypt.h src/headers/tomcrypt_argchk.h src/headers/tomcrypt_cfg.h \
diff --git a/makefile.msvc b/makefile.msvc
index e819c2ccf..6b2c10061 100644
--- a/makefile.msvc
+++ b/makefile.msvc
@@ -105,7 +105,8 @@ src/misc/crypt/crypt_unregister_prng.obj src/misc/error_to_string.obj src/misc/h
src/misc/hkdf/hkdf_test.obj src/misc/mem_neq.obj src/misc/padding/padding_depad.obj \
src/misc/padding/padding_pad.obj src/misc/pbes/pbes.obj src/misc/pbes/pbes1.obj src/misc/pbes/pbes2.obj \
src/misc/pkcs12/pkcs12_kdf.obj src/misc/pkcs12/pkcs12_utf8_to_utf16.obj src/misc/pkcs5/pkcs_5_1.obj \
-src/misc/pkcs5/pkcs_5_2.obj src/misc/pkcs5/pkcs_5_test.obj src/misc/zeromem.obj src/modes/cbc/cbc_decrypt.obj \
+src/misc/pkcs5/pkcs_5_2.obj src/misc/pkcs5/pkcs_5_test.obj src/misc/ssh/ssh_decode_sequence_multi.obj \
+src/misc/ssh/ssh_encode_sequence_multi.obj src/misc/zeromem.obj src/modes/cbc/cbc_decrypt.obj \
src/modes/cbc/cbc_done.obj src/modes/cbc/cbc_encrypt.obj src/modes/cbc/cbc_getiv.obj \
src/modes/cbc/cbc_setiv.obj src/modes/cbc/cbc_start.obj src/modes/cfb/cfb_decrypt.obj \
src/modes/cfb/cfb_done.obj src/modes/cfb/cfb_encrypt.obj src/modes/cfb/cfb_getiv.obj \
@@ -177,18 +178,19 @@ src/pk/ecc/ecc_free.obj src/pk/ecc/ecc_get_key.obj src/pk/ecc/ecc_get_oid_str.ob
src/pk/ecc/ecc_import.obj src/pk/ecc/ecc_import_openssl.obj src/pk/ecc/ecc_import_pkcs8.obj \
src/pk/ecc/ecc_import_x509.obj src/pk/ecc/ecc_make_key.obj src/pk/ecc/ecc_recover_key.obj \
src/pk/ecc/ecc_set_curve.obj src/pk/ecc/ecc_set_curve_internal.obj src/pk/ecc/ecc_set_key.obj \
-src/pk/ecc/ecc_shared_secret.obj src/pk/ecc/ecc_sign_hash.obj src/pk/ecc/ecc_sizes.obj src/pk/ecc/ecc_test.obj \
-src/pk/ecc/ecc_verify_hash.obj src/pk/ecc/ltc_ecc_export_point.obj src/pk/ecc/ltc_ecc_import_point.obj \
-src/pk/ecc/ltc_ecc_is_point.obj src/pk/ecc/ltc_ecc_is_point_at_infinity.obj src/pk/ecc/ltc_ecc_map.obj \
-src/pk/ecc/ltc_ecc_mul2add.obj src/pk/ecc/ltc_ecc_mulmod.obj src/pk/ecc/ltc_ecc_mulmod_timing.obj \
-src/pk/ecc/ltc_ecc_points.obj src/pk/ecc/ltc_ecc_projective_add_point.obj \
-src/pk/ecc/ltc_ecc_projective_dbl_point.obj src/pk/ecc/ltc_ecc_verify_key.obj src/pk/pkcs1/pkcs_1_i2osp.obj \
-src/pk/pkcs1/pkcs_1_mgf1.obj src/pk/pkcs1/pkcs_1_oaep_decode.obj src/pk/pkcs1/pkcs_1_oaep_encode.obj \
-src/pk/pkcs1/pkcs_1_os2ip.obj src/pk/pkcs1/pkcs_1_pss_decode.obj src/pk/pkcs1/pkcs_1_pss_encode.obj \
-src/pk/pkcs1/pkcs_1_v1_5_decode.obj src/pk/pkcs1/pkcs_1_v1_5_encode.obj src/pk/rsa/rsa_decrypt_key.obj \
-src/pk/rsa/rsa_encrypt_key.obj src/pk/rsa/rsa_export.obj src/pk/rsa/rsa_exptmod.obj src/pk/rsa/rsa_free.obj \
-src/pk/rsa/rsa_get_size.obj src/pk/rsa/rsa_import.obj src/pk/rsa/rsa_import_pkcs8.obj \
-src/pk/rsa/rsa_import_x509.obj src/pk/rsa/rsa_make_key.obj src/pk/rsa/rsa_set.obj src/pk/rsa/rsa_sign_hash.obj \
+src/pk/ecc/ecc_shared_secret.obj src/pk/ecc/ecc_sign_hash.obj src/pk/ecc/ecc_sizes.obj \
+src/pk/ecc/ecc_ssh_ecdsa_encode_name.obj src/pk/ecc/ecc_test.obj src/pk/ecc/ecc_verify_hash.obj \
+src/pk/ecc/ltc_ecc_export_point.obj src/pk/ecc/ltc_ecc_import_point.obj src/pk/ecc/ltc_ecc_is_point.obj \
+src/pk/ecc/ltc_ecc_is_point_at_infinity.obj src/pk/ecc/ltc_ecc_map.obj src/pk/ecc/ltc_ecc_mul2add.obj \
+src/pk/ecc/ltc_ecc_mulmod.obj src/pk/ecc/ltc_ecc_mulmod_timing.obj src/pk/ecc/ltc_ecc_points.obj \
+src/pk/ecc/ltc_ecc_projective_add_point.obj src/pk/ecc/ltc_ecc_projective_dbl_point.obj \
+src/pk/ecc/ltc_ecc_verify_key.obj src/pk/pkcs1/pkcs_1_i2osp.obj src/pk/pkcs1/pkcs_1_mgf1.obj \
+src/pk/pkcs1/pkcs_1_oaep_decode.obj src/pk/pkcs1/pkcs_1_oaep_encode.obj src/pk/pkcs1/pkcs_1_os2ip.obj \
+src/pk/pkcs1/pkcs_1_pss_decode.obj src/pk/pkcs1/pkcs_1_pss_encode.obj src/pk/pkcs1/pkcs_1_v1_5_decode.obj \
+src/pk/pkcs1/pkcs_1_v1_5_encode.obj src/pk/rsa/rsa_decrypt_key.obj src/pk/rsa/rsa_encrypt_key.obj \
+src/pk/rsa/rsa_export.obj src/pk/rsa/rsa_exptmod.obj src/pk/rsa/rsa_free.obj src/pk/rsa/rsa_get_size.obj \
+src/pk/rsa/rsa_import.obj src/pk/rsa/rsa_import_pkcs8.obj src/pk/rsa/rsa_import_x509.obj \
+src/pk/rsa/rsa_make_key.obj src/pk/rsa/rsa_set.obj src/pk/rsa/rsa_sign_hash.obj \
src/pk/rsa/rsa_sign_saltlen_get.obj src/pk/rsa/rsa_verify_hash.obj src/prngs/chacha20.obj src/prngs/fortuna.obj \
src/prngs/rc4.obj src/prngs/rng_get_bytes.obj src/prngs/rng_make_prng.obj src/prngs/sober128.obj \
src/prngs/sprng.obj src/prngs/yarrow.obj src/stream/chacha/chacha_crypt.obj src/stream/chacha/chacha_done.obj \
@@ -211,7 +213,7 @@ tests/common.obj tests/der_test.obj tests/dh_test.obj tests/dsa_test.obj tests/e
tests/mac_test.obj tests/misc_test.obj tests/modes_test.obj tests/mpi_test.obj tests/multi_test.obj tests/no_prng.obj \
tests/padding_test.obj tests/pkcs_1_eme_test.obj tests/pkcs_1_emsa_test.obj tests/pkcs_1_oaep_test.obj \
tests/pkcs_1_pss_test.obj tests/pkcs_1_test.obj tests/prng_test.obj tests/rotate_test.obj tests/rsa_test.obj \
-tests/store_test.obj tests/test.obj
+tests/ssh_test.obj tests/store_test.obj tests/test.obj
#The following headers will be installed by "make install"
HEADERS_PUB=src/headers/tomcrypt.h src/headers/tomcrypt_argchk.h src/headers/tomcrypt_cfg.h \
diff --git a/makefile.unix b/makefile.unix
index 5f911050d..20f9a0d9b 100644
--- a/makefile.unix
+++ b/makefile.unix
@@ -122,7 +122,8 @@ src/misc/crypt/crypt_unregister_prng.o src/misc/error_to_string.o src/misc/hkdf/
src/misc/hkdf/hkdf_test.o src/misc/mem_neq.o src/misc/padding/padding_depad.o \
src/misc/padding/padding_pad.o src/misc/pbes/pbes.o src/misc/pbes/pbes1.o src/misc/pbes/pbes2.o \
src/misc/pkcs12/pkcs12_kdf.o src/misc/pkcs12/pkcs12_utf8_to_utf16.o src/misc/pkcs5/pkcs_5_1.o \
-src/misc/pkcs5/pkcs_5_2.o src/misc/pkcs5/pkcs_5_test.o src/misc/zeromem.o src/modes/cbc/cbc_decrypt.o \
+src/misc/pkcs5/pkcs_5_2.o src/misc/pkcs5/pkcs_5_test.o src/misc/ssh/ssh_decode_sequence_multi.o \
+src/misc/ssh/ssh_encode_sequence_multi.o src/misc/zeromem.o src/modes/cbc/cbc_decrypt.o \
src/modes/cbc/cbc_done.o src/modes/cbc/cbc_encrypt.o src/modes/cbc/cbc_getiv.o \
src/modes/cbc/cbc_setiv.o src/modes/cbc/cbc_start.o src/modes/cfb/cfb_decrypt.o \
src/modes/cfb/cfb_done.o src/modes/cfb/cfb_encrypt.o src/modes/cfb/cfb_getiv.o \
@@ -194,18 +195,19 @@ src/pk/ecc/ecc_free.o src/pk/ecc/ecc_get_key.o src/pk/ecc/ecc_get_oid_str.o src/
src/pk/ecc/ecc_import.o src/pk/ecc/ecc_import_openssl.o src/pk/ecc/ecc_import_pkcs8.o \
src/pk/ecc/ecc_import_x509.o src/pk/ecc/ecc_make_key.o src/pk/ecc/ecc_recover_key.o \
src/pk/ecc/ecc_set_curve.o src/pk/ecc/ecc_set_curve_internal.o src/pk/ecc/ecc_set_key.o \
-src/pk/ecc/ecc_shared_secret.o src/pk/ecc/ecc_sign_hash.o src/pk/ecc/ecc_sizes.o src/pk/ecc/ecc_test.o \
-src/pk/ecc/ecc_verify_hash.o src/pk/ecc/ltc_ecc_export_point.o src/pk/ecc/ltc_ecc_import_point.o \
-src/pk/ecc/ltc_ecc_is_point.o src/pk/ecc/ltc_ecc_is_point_at_infinity.o src/pk/ecc/ltc_ecc_map.o \
-src/pk/ecc/ltc_ecc_mul2add.o src/pk/ecc/ltc_ecc_mulmod.o src/pk/ecc/ltc_ecc_mulmod_timing.o \
-src/pk/ecc/ltc_ecc_points.o src/pk/ecc/ltc_ecc_projective_add_point.o \
-src/pk/ecc/ltc_ecc_projective_dbl_point.o src/pk/ecc/ltc_ecc_verify_key.o src/pk/pkcs1/pkcs_1_i2osp.o \
-src/pk/pkcs1/pkcs_1_mgf1.o src/pk/pkcs1/pkcs_1_oaep_decode.o src/pk/pkcs1/pkcs_1_oaep_encode.o \
-src/pk/pkcs1/pkcs_1_os2ip.o src/pk/pkcs1/pkcs_1_pss_decode.o src/pk/pkcs1/pkcs_1_pss_encode.o \
-src/pk/pkcs1/pkcs_1_v1_5_decode.o src/pk/pkcs1/pkcs_1_v1_5_encode.o src/pk/rsa/rsa_decrypt_key.o \
-src/pk/rsa/rsa_encrypt_key.o src/pk/rsa/rsa_export.o src/pk/rsa/rsa_exptmod.o src/pk/rsa/rsa_free.o \
-src/pk/rsa/rsa_get_size.o src/pk/rsa/rsa_import.o src/pk/rsa/rsa_import_pkcs8.o \
-src/pk/rsa/rsa_import_x509.o src/pk/rsa/rsa_make_key.o src/pk/rsa/rsa_set.o src/pk/rsa/rsa_sign_hash.o \
+src/pk/ecc/ecc_shared_secret.o src/pk/ecc/ecc_sign_hash.o src/pk/ecc/ecc_sizes.o \
+src/pk/ecc/ecc_ssh_ecdsa_encode_name.o src/pk/ecc/ecc_test.o src/pk/ecc/ecc_verify_hash.o \
+src/pk/ecc/ltc_ecc_export_point.o src/pk/ecc/ltc_ecc_import_point.o src/pk/ecc/ltc_ecc_is_point.o \
+src/pk/ecc/ltc_ecc_is_point_at_infinity.o src/pk/ecc/ltc_ecc_map.o src/pk/ecc/ltc_ecc_mul2add.o \
+src/pk/ecc/ltc_ecc_mulmod.o src/pk/ecc/ltc_ecc_mulmod_timing.o src/pk/ecc/ltc_ecc_points.o \
+src/pk/ecc/ltc_ecc_projective_add_point.o src/pk/ecc/ltc_ecc_projective_dbl_point.o \
+src/pk/ecc/ltc_ecc_verify_key.o src/pk/pkcs1/pkcs_1_i2osp.o src/pk/pkcs1/pkcs_1_mgf1.o \
+src/pk/pkcs1/pkcs_1_oaep_decode.o src/pk/pkcs1/pkcs_1_oaep_encode.o src/pk/pkcs1/pkcs_1_os2ip.o \
+src/pk/pkcs1/pkcs_1_pss_decode.o src/pk/pkcs1/pkcs_1_pss_encode.o src/pk/pkcs1/pkcs_1_v1_5_decode.o \
+src/pk/pkcs1/pkcs_1_v1_5_encode.o src/pk/rsa/rsa_decrypt_key.o src/pk/rsa/rsa_encrypt_key.o \
+src/pk/rsa/rsa_export.o src/pk/rsa/rsa_exptmod.o src/pk/rsa/rsa_free.o src/pk/rsa/rsa_get_size.o \
+src/pk/rsa/rsa_import.o src/pk/rsa/rsa_import_pkcs8.o src/pk/rsa/rsa_import_x509.o \
+src/pk/rsa/rsa_make_key.o src/pk/rsa/rsa_set.o src/pk/rsa/rsa_sign_hash.o \
src/pk/rsa/rsa_sign_saltlen_get.o src/pk/rsa/rsa_verify_hash.o src/prngs/chacha20.o src/prngs/fortuna.o \
src/prngs/rc4.o src/prngs/rng_get_bytes.o src/prngs/rng_make_prng.o src/prngs/sober128.o \
src/prngs/sprng.o src/prngs/yarrow.o src/stream/chacha/chacha_crypt.o src/stream/chacha/chacha_done.o \
@@ -228,7 +230,7 @@ tests/common.o tests/der_test.o tests/dh_test.o tests/dsa_test.o tests/ecc_test.
tests/mac_test.o tests/misc_test.o tests/modes_test.o tests/mpi_test.o tests/multi_test.o tests/no_prng.o \
tests/padding_test.o tests/pkcs_1_eme_test.o tests/pkcs_1_emsa_test.o tests/pkcs_1_oaep_test.o \
tests/pkcs_1_pss_test.o tests/pkcs_1_test.o tests/prng_test.o tests/rotate_test.o tests/rsa_test.o \
-tests/store_test.o tests/test.o
+tests/ssh_test.o tests/store_test.o tests/test.o
#The following headers will be installed by "make install"
HEADERS_PUB=src/headers/tomcrypt.h src/headers/tomcrypt_argchk.h src/headers/tomcrypt_cfg.h \
diff --git a/makefile_include.mk b/makefile_include.mk
index f6345eb8b..4bcec2206 100644
--- a/makefile_include.mk
+++ b/makefile_include.mk
@@ -282,7 +282,8 @@ src/misc/crypt/crypt_unregister_prng.o src/misc/error_to_string.o src/misc/hkdf/
src/misc/hkdf/hkdf_test.o src/misc/mem_neq.o src/misc/padding/padding_depad.o \
src/misc/padding/padding_pad.o src/misc/pbes/pbes.o src/misc/pbes/pbes1.o src/misc/pbes/pbes2.o \
src/misc/pkcs12/pkcs12_kdf.o src/misc/pkcs12/pkcs12_utf8_to_utf16.o src/misc/pkcs5/pkcs_5_1.o \
-src/misc/pkcs5/pkcs_5_2.o src/misc/pkcs5/pkcs_5_test.o src/misc/zeromem.o src/modes/cbc/cbc_decrypt.o \
+src/misc/pkcs5/pkcs_5_2.o src/misc/pkcs5/pkcs_5_test.o src/misc/ssh/ssh_decode_sequence_multi.o \
+src/misc/ssh/ssh_encode_sequence_multi.o src/misc/zeromem.o src/modes/cbc/cbc_decrypt.o \
src/modes/cbc/cbc_done.o src/modes/cbc/cbc_encrypt.o src/modes/cbc/cbc_getiv.o \
src/modes/cbc/cbc_setiv.o src/modes/cbc/cbc_start.o src/modes/cfb/cfb_decrypt.o \
src/modes/cfb/cfb_done.o src/modes/cfb/cfb_encrypt.o src/modes/cfb/cfb_getiv.o \
@@ -354,18 +355,19 @@ src/pk/ecc/ecc_free.o src/pk/ecc/ecc_get_key.o src/pk/ecc/ecc_get_oid_str.o src/
src/pk/ecc/ecc_import.o src/pk/ecc/ecc_import_openssl.o src/pk/ecc/ecc_import_pkcs8.o \
src/pk/ecc/ecc_import_x509.o src/pk/ecc/ecc_make_key.o src/pk/ecc/ecc_recover_key.o \
src/pk/ecc/ecc_set_curve.o src/pk/ecc/ecc_set_curve_internal.o src/pk/ecc/ecc_set_key.o \
-src/pk/ecc/ecc_shared_secret.o src/pk/ecc/ecc_sign_hash.o src/pk/ecc/ecc_sizes.o src/pk/ecc/ecc_test.o \
-src/pk/ecc/ecc_verify_hash.o src/pk/ecc/ltc_ecc_export_point.o src/pk/ecc/ltc_ecc_import_point.o \
-src/pk/ecc/ltc_ecc_is_point.o src/pk/ecc/ltc_ecc_is_point_at_infinity.o src/pk/ecc/ltc_ecc_map.o \
-src/pk/ecc/ltc_ecc_mul2add.o src/pk/ecc/ltc_ecc_mulmod.o src/pk/ecc/ltc_ecc_mulmod_timing.o \
-src/pk/ecc/ltc_ecc_points.o src/pk/ecc/ltc_ecc_projective_add_point.o \
-src/pk/ecc/ltc_ecc_projective_dbl_point.o src/pk/ecc/ltc_ecc_verify_key.o src/pk/pkcs1/pkcs_1_i2osp.o \
-src/pk/pkcs1/pkcs_1_mgf1.o src/pk/pkcs1/pkcs_1_oaep_decode.o src/pk/pkcs1/pkcs_1_oaep_encode.o \
-src/pk/pkcs1/pkcs_1_os2ip.o src/pk/pkcs1/pkcs_1_pss_decode.o src/pk/pkcs1/pkcs_1_pss_encode.o \
-src/pk/pkcs1/pkcs_1_v1_5_decode.o src/pk/pkcs1/pkcs_1_v1_5_encode.o src/pk/rsa/rsa_decrypt_key.o \
-src/pk/rsa/rsa_encrypt_key.o src/pk/rsa/rsa_export.o src/pk/rsa/rsa_exptmod.o src/pk/rsa/rsa_free.o \
-src/pk/rsa/rsa_get_size.o src/pk/rsa/rsa_import.o src/pk/rsa/rsa_import_pkcs8.o \
-src/pk/rsa/rsa_import_x509.o src/pk/rsa/rsa_make_key.o src/pk/rsa/rsa_set.o src/pk/rsa/rsa_sign_hash.o \
+src/pk/ecc/ecc_shared_secret.o src/pk/ecc/ecc_sign_hash.o src/pk/ecc/ecc_sizes.o \
+src/pk/ecc/ecc_ssh_ecdsa_encode_name.o src/pk/ecc/ecc_test.o src/pk/ecc/ecc_verify_hash.o \
+src/pk/ecc/ltc_ecc_export_point.o src/pk/ecc/ltc_ecc_import_point.o src/pk/ecc/ltc_ecc_is_point.o \
+src/pk/ecc/ltc_ecc_is_point_at_infinity.o src/pk/ecc/ltc_ecc_map.o src/pk/ecc/ltc_ecc_mul2add.o \
+src/pk/ecc/ltc_ecc_mulmod.o src/pk/ecc/ltc_ecc_mulmod_timing.o src/pk/ecc/ltc_ecc_points.o \
+src/pk/ecc/ltc_ecc_projective_add_point.o src/pk/ecc/ltc_ecc_projective_dbl_point.o \
+src/pk/ecc/ltc_ecc_verify_key.o src/pk/pkcs1/pkcs_1_i2osp.o src/pk/pkcs1/pkcs_1_mgf1.o \
+src/pk/pkcs1/pkcs_1_oaep_decode.o src/pk/pkcs1/pkcs_1_oaep_encode.o src/pk/pkcs1/pkcs_1_os2ip.o \
+src/pk/pkcs1/pkcs_1_pss_decode.o src/pk/pkcs1/pkcs_1_pss_encode.o src/pk/pkcs1/pkcs_1_v1_5_decode.o \
+src/pk/pkcs1/pkcs_1_v1_5_encode.o src/pk/rsa/rsa_decrypt_key.o src/pk/rsa/rsa_encrypt_key.o \
+src/pk/rsa/rsa_export.o src/pk/rsa/rsa_exptmod.o src/pk/rsa/rsa_free.o src/pk/rsa/rsa_get_size.o \
+src/pk/rsa/rsa_import.o src/pk/rsa/rsa_import_pkcs8.o src/pk/rsa/rsa_import_x509.o \
+src/pk/rsa/rsa_make_key.o src/pk/rsa/rsa_set.o src/pk/rsa/rsa_sign_hash.o \
src/pk/rsa/rsa_sign_saltlen_get.o src/pk/rsa/rsa_verify_hash.o src/prngs/chacha20.o src/prngs/fortuna.o \
src/prngs/rc4.o src/prngs/rng_get_bytes.o src/prngs/rng_make_prng.o src/prngs/sober128.o \
src/prngs/sprng.o src/prngs/yarrow.o src/stream/chacha/chacha_crypt.o src/stream/chacha/chacha_done.o \
@@ -388,7 +390,7 @@ tests/common.o tests/der_test.o tests/dh_test.o tests/dsa_test.o tests/ecc_test.
tests/mac_test.o tests/misc_test.o tests/modes_test.o tests/mpi_test.o tests/multi_test.o tests/no_prng.o \
tests/padding_test.o tests/pkcs_1_eme_test.o tests/pkcs_1_emsa_test.o tests/pkcs_1_oaep_test.o \
tests/pkcs_1_pss_test.o tests/pkcs_1_test.o tests/prng_test.o tests/rotate_test.o tests/rsa_test.o \
-tests/store_test.o tests/test.o
+tests/ssh_test.o tests/store_test.o tests/test.o
# The following headers will be installed by "make install"
HEADERS_PUB=src/headers/tomcrypt.h src/headers/tomcrypt_argchk.h src/headers/tomcrypt_cfg.h \
diff --git a/src/headers/tomcrypt_custom.h b/src/headers/tomcrypt_custom.h
index 1ec2a304b..aedf08bc3 100644
--- a/src/headers/tomcrypt_custom.h
+++ b/src/headers/tomcrypt_custom.h
@@ -43,7 +43,10 @@
#define XMEM_NEQ mem_neq
#endif
#ifndef XSTRCMP
-#define XSTRCMP strcmp
+#define XSTRCMP strcmp
+#endif
+#ifndef XSTRNCPY
+#define XSTRNCPY strncpy
#endif
#ifndef XCLOCK
@@ -56,7 +59,7 @@
#if ( defined(malloc) || defined(realloc) || defined(calloc) || defined(free) || \
defined(memset) || defined(memcpy) || defined(memcmp) || defined(strcmp) || \
- defined(clock) || defined(qsort) ) && !defined(LTC_NO_PROTOTYPES)
+ defined(strncpy) || defined(clock) || defined(qsort) ) && !defined(LTC_NO_PROTOTYPES)
#define LTC_NO_PROTOTYPES
#endif
@@ -494,6 +497,8 @@
#define LTC_CRC32
+#define LTC_SSH
+
#define LTC_PADDING
#define LTC_PBES
diff --git a/src/headers/tomcrypt_misc.h b/src/headers/tomcrypt_misc.h
index a5dd130ee..78e233d77 100644
--- a/src/headers/tomcrypt_misc.h
+++ b/src/headers/tomcrypt_misc.h
@@ -154,6 +154,23 @@ int padding_pad(unsigned char *data, unsigned long length, unsigned long* padded
int padding_depad(const unsigned char *data, unsigned long *length, unsigned long mode);
#endif /* LTC_PADDING */
+#ifdef LTC_SSH
+typedef enum ssh_data_type_ {
+ LTC_SSHDATA_BYTE,
+ LTC_SSHDATA_BOOLEAN,
+ LTC_SSHDATA_UINT32,
+ LTC_SSHDATA_UINT64,
+ LTC_SSHDATA_STRING,
+ LTC_SSHDATA_MPINT,
+ LTC_SSHDATA_NAMELIST,
+ LTC_SSHDATA_EOL
+} ssh_data_type;
+
+/* VA list handy helpers with tuples of */
+int ssh_encode_sequence_multi(unsigned char *out, unsigned long *outlen, ...);
+int ssh_decode_sequence_multi(const unsigned char *in, unsigned long inlen, ...);
+#endif /* LTC_SSH */
+
int compare_testvector(const void* is, const unsigned long is_len, const void* should, const unsigned long should_len, const char* what, int which);
/* ref: $Format:%D$ */
diff --git a/src/headers/tomcrypt_pk.h b/src/headers/tomcrypt_pk.h
index 64b39db52..49eeda595 100644
--- a/src/headers/tomcrypt_pk.h
+++ b/src/headers/tomcrypt_pk.h
@@ -251,7 +251,9 @@ typedef enum ecc_signature_type_ {
/* raw R, S values */
LTC_ECCSIG_RFC7518 = 0x1,
/* raw R, S, V (+27) values */
- LTC_ECCSIG_ETH27 = 0x2
+ LTC_ECCSIG_ETH27 = 0x2,
+ /* SSH + ECDSA signature format defined by RFC5656 */
+ LTC_ECCSIG_RFC5656 = 0x3,
} ecc_signature_type;
/** the ECC params provided */
diff --git a/src/headers/tomcrypt_private.h b/src/headers/tomcrypt_private.h
index 5da8f7299..e536d579e 100644
--- a/src/headers/tomcrypt_private.h
+++ b/src/headers/tomcrypt_private.h
@@ -226,6 +226,10 @@ int ecc_copy_curve(const ecc_key *srckey, ecc_key *key);
int ecc_set_curve_by_size(int size, ecc_key *key);
int ecc_import_subject_public_key_info(const unsigned char *in, unsigned long inlen, ecc_key *key);
+#ifdef LTC_SSH
+int ecc_ssh_ecdsa_encode_name(char *buffer, unsigned long *buflen, const ecc_key *key);
+#endif
+
/* low level functions */
ecc_point *ltc_ecc_new_point(void);
void ltc_ecc_del_point(ecc_point *p);
diff --git a/src/misc/crypt/crypt.c b/src/misc/crypt/crypt.c
index a90732fad..b6b25c1e2 100644
--- a/src/misc/crypt/crypt.c
+++ b/src/misc/crypt/crypt.c
@@ -452,6 +452,9 @@ const char *crypt_build_settings =
" PBES1 "
" PBES2 "
#endif
+#if defined(LTC_SSH)
+ " SSH "
+#endif
#if defined(LTC_DEVRANDOM)
" LTC_DEVRANDOM "
#endif
diff --git a/src/misc/ssh/ssh_decode_sequence_multi.c b/src/misc/ssh/ssh_decode_sequence_multi.c
new file mode 100644
index 000000000..f01a03199
--- /dev/null
+++ b/src/misc/ssh/ssh_decode_sequence_multi.c
@@ -0,0 +1,161 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt_private.h"
+#include
+
+/**
+ @file ssh_decode_sequence_multi.c
+ SSH data type representation as per RFC4251, Russ Williams
+*/
+
+#ifdef LTC_SSH
+
+/**
+ Decode a SSH sequence using a VA list
+ @param in Data to decode
+ @param inlen Length of buffer to decode
+ @remark <...> is of the form (int, void*) except for string
+ @return CRYPT_OK on success
+*/
+int ssh_decode_sequence_multi(const unsigned char *in, unsigned long inlen, ...)
+{
+ int err;
+ va_list args;
+ ssh_data_type type;
+ void *vdata;
+ unsigned char *cdata;
+ char *sdata;
+ ulong32 *u32data;
+ ulong64 *u64data;
+ unsigned long size, bufsize;
+
+ LTC_ARGCHK(in != NULL);
+
+ /* Decode values from buffer */
+ va_start(args, inlen);
+ while ((type = (ssh_data_type)va_arg(args, int)) != LTC_SSHDATA_EOL) {
+ /* Size of length field */
+ if (type == LTC_SSHDATA_STRING ||
+ type == LTC_SSHDATA_NAMELIST ||
+ type == LTC_SSHDATA_MPINT)
+ {
+ /* Check we'll not read too far */
+ if (inlen < 4) {
+ err = CRYPT_BUFFER_OVERFLOW;
+ goto error;
+ }
+ }
+
+ /* Calculate (or read) length of data */
+ size = (unsigned long)-1;
+ switch (type) {
+ case LTC_SSHDATA_BYTE:
+ case LTC_SSHDATA_BOOLEAN:
+ size = 1;
+ break;
+ case LTC_SSHDATA_UINT32:
+ size = 4;
+ break;
+ case LTC_SSHDATA_UINT64:
+ size = 8;
+ break;
+ case LTC_SSHDATA_STRING:
+ case LTC_SSHDATA_NAMELIST:
+ case LTC_SSHDATA_MPINT:
+ LOAD32H(size, in);
+ in += 4;
+ inlen -= 4;
+ break;
+
+ case LTC_SSHDATA_EOL:
+ /* Should never get here */
+ err = CRYPT_INVALID_ARG;
+ goto error;
+ }
+
+ /* Check we'll not read too far */
+ if (inlen < size) {
+ err = CRYPT_BUFFER_OVERFLOW;
+ goto error;
+ } else {
+ inlen -= size;
+ }
+
+ /* Read data */
+ switch (type) {
+ case LTC_SSHDATA_BYTE:
+ cdata = va_arg(args, unsigned char*);
+ *cdata = *in++;
+ break;
+ case LTC_SSHDATA_BOOLEAN:
+ cdata = va_arg(args, unsigned char*);
+ /*
+ The value 0 represents FALSE, and the value 1 represents TRUE. All non-zero values MUST be
+ interpreted as TRUE; however, applications MUST NOT store values other than 0 and 1.
+ */
+ *cdata = (*in++)?1:0;
+ break;
+ case LTC_SSHDATA_UINT32:
+ u32data = va_arg(args, ulong32*);
+ LOAD32H(*u32data, in);
+ in += 4;
+ break;
+ case LTC_SSHDATA_UINT64:
+ u64data = va_arg(args, ulong64*);
+ LOAD64H(*u64data, in);
+ in += 8;
+ break;
+ case LTC_SSHDATA_STRING:
+ case LTC_SSHDATA_NAMELIST:
+ sdata = va_arg(args, char*);
+ bufsize = va_arg(args, unsigned long);
+ if (size >= bufsize) {
+ err = CRYPT_BUFFER_OVERFLOW;
+ goto error;
+ }
+ if (size > 0) {
+ XSTRNCPY(sdata, (const char *)in, size);
+ sdata[size] = '\0'; /* strncpy doesn't NUL-terminate */
+ } else {
+ *sdata = '\0';
+ }
+ in += size;
+ break;
+ case LTC_SSHDATA_MPINT:
+ vdata = va_arg(args, void*);
+ if (size == 0) {
+ if ((err = mp_set(vdata, 0)) != CRYPT_OK) { goto error; }
+ } else if ((in[0] & 0x80) != 0) {
+ /* Negative number - not supported */
+ err = CRYPT_INVALID_PACKET;
+ goto error;
+ } else {
+ if ((err = mp_read_unsigned_bin(vdata, (unsigned char *)in, size)) != CRYPT_OK) { goto error; }
+ }
+ in += size;
+ break;
+
+ case LTC_SSHDATA_EOL:
+ /* Should never get here */
+ err = CRYPT_INVALID_ARG;
+ goto error;
+ }
+ }
+ err = CRYPT_OK;
+
+error:
+ va_end(args);
+ return err;
+}
+
+#endif
+
+/* ref: $Format:%D$ */
+/* git commit: $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/src/misc/ssh/ssh_encode_sequence_multi.c b/src/misc/ssh/ssh_encode_sequence_multi.c
new file mode 100644
index 000000000..0fe237850
--- /dev/null
+++ b/src/misc/ssh/ssh_encode_sequence_multi.c
@@ -0,0 +1,168 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt_private.h"
+#include
+
+/**
+ @file ssh_encode_sequence_multi.c
+ SSH data type representation as per RFC4251, Russ Williams
+*/
+
+#ifdef LTC_SSH
+
+/**
+ Encode a SSH sequence using a VA list
+ @param out [out] Destination for data
+ @param outlen [in/out] Length of buffer and resulting length of output
+ @remark <...> is of the form (int, void*)
+ @return CRYPT_OK on success
+*/
+int ssh_encode_sequence_multi(unsigned char *out, unsigned long *outlen, ...)
+{
+ int err;
+ va_list args;
+ unsigned long size;
+ ssh_data_type type;
+ void *vdata;
+ const char *sdata;
+ int idata;
+ ulong32 u32data;
+ ulong64 u64data;
+
+ LTC_ARGCHK(out != NULL);
+ LTC_ARGCHK(outlen != NULL);
+
+ /* Check values and calculate output size */
+ size = 0;
+ va_start(args, outlen);
+ while ((type = (ssh_data_type)va_arg(args, int)) != LTC_SSHDATA_EOL) {
+ switch (type) {
+ case LTC_SSHDATA_BYTE:
+ case LTC_SSHDATA_BOOLEAN: /* Both stored as 1 byte */
+ LTC_UNUSED_PARAM( va_arg(args, int) );
+ size++;
+ break;
+ case LTC_SSHDATA_UINT32:
+ LTC_UNUSED_PARAM( va_arg(args, ulong32) );
+ size += 4;
+ break;
+ case LTC_SSHDATA_UINT64:
+ LTC_UNUSED_PARAM( va_arg(args, ulong64) );
+ size += 8;
+ break;
+ case LTC_SSHDATA_STRING:
+ case LTC_SSHDATA_NAMELIST:
+ sdata = va_arg(args, char*);
+ size += 4;
+ size += strlen(sdata);
+ break;
+ case LTC_SSHDATA_MPINT:
+ vdata = va_arg(args, void*);
+ /* Calculate size */
+ size += 4;
+ if (mp_iszero(vdata) != LTC_MP_YES) {
+ size += mp_unsigned_bin_size(vdata);
+ if ((mp_count_bits(vdata) & 7) == 0) size++; /* Zero padding if high bit set */
+ }
+ break;
+
+ case LTC_SSHDATA_EOL: /* Should never get here */
+ err = CRYPT_INVALID_ARG;
+ goto error;
+ }
+ }
+ va_end(args);
+
+ /* Check we have sufficient space */
+ if (*outlen < size) {
+ *outlen = size;
+ err = CRYPT_BUFFER_OVERFLOW;
+ goto errornoargs;
+ }
+ *outlen = size;
+
+ /* Encode values into buffer */
+ va_start(args, outlen);
+ while ((type = (ssh_data_type)va_arg(args, int)) != LTC_SSHDATA_EOL) {
+ switch (type) {
+ case LTC_SSHDATA_BYTE:
+ idata = va_arg(args, int);
+
+ *out++ = (unsigned char)(idata & 255);
+ break;
+ case LTC_SSHDATA_BOOLEAN:
+ idata = va_arg(args, int);
+
+ /*
+ The value 0 represents FALSE, and the value 1 represents TRUE. All non-zero values MUST be
+ interpreted as TRUE; however, applications MUST NOT store values other than 0 and 1.
+ */
+ *out++ = (idata)?1:0;
+ break;
+ case LTC_SSHDATA_UINT32:
+ u32data = va_arg(args, ulong32);
+ STORE32H(u32data, out);
+ out += 4;
+ break;
+ case LTC_SSHDATA_UINT64:
+ u64data = va_arg(args, ulong64);
+ STORE64H(u64data, out);
+ out += 8;
+ break;
+ case LTC_SSHDATA_STRING:
+ case LTC_SSHDATA_NAMELIST:
+ sdata = va_arg(args, char*);
+ size = strlen(sdata);
+ STORE32H(size, out);
+ out += 4;
+ XSTRNCPY((char *)out, sdata, size);
+ out += size;
+ break;
+ case LTC_SSHDATA_MPINT:
+ vdata = va_arg(args, void*);
+ if (mp_iszero(vdata) == LTC_MP_YES) {
+ STORE32H(0, out);
+ out += 4;
+ } else {
+ size = mp_unsigned_bin_size(vdata);
+ if ((mp_count_bits(vdata) & 7) == 0) {
+ /* Zero padding if high bit set */
+ STORE32H(size+1, out);
+ out += 4;
+ *out++ = 0;
+ } else {
+ STORE32H(size, out);
+ out += 4;
+ }
+ if ((err = mp_to_unsigned_bin(vdata, out)) != CRYPT_OK) {
+ err = CRYPT_ERROR;
+ goto error;
+ }
+ out += size;
+ }
+ break;
+
+ case LTC_SSHDATA_EOL: /* Should never get here */
+ err = CRYPT_INVALID_ARG;
+ goto error;
+ }
+ }
+ err = CRYPT_OK;
+
+error:
+ va_end(args);
+errornoargs:
+ return err;
+}
+
+#endif
+
+/* ref: $Format:%D$ */
+/* git commit: $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/src/pk/ecc/ecc_recover_key.c b/src/pk/ecc/ecc_recover_key.c
index 25562a239..d3a70df7a 100644
--- a/src/pk/ecc/ecc_recover_key.c
+++ b/src/pk/ecc/ecc_recover_key.c
@@ -92,8 +92,7 @@ int ecc_recover_key(const unsigned char *sig, unsigned long siglen,
}
else if (sigformat == LTC_ECCSIG_ETH27) {
/* Ethereum (v,r,s) format */
- if (key->dp.oidlen != 5 || key->dp.oid[0] != 1 || key->dp.oid[1] != 3 ||
- key->dp.oid[2] != 132 || key->dp.oid[3] != 0 || key->dp.oid[4] != 10) {
+ if (pk_oid_cmp_with_ulong("1.3.132.0.10", key->dp.oid, key->dp.oidlen) != CRYPT_OK) {
/* Only valid for secp256k1 - OID 1.3.132.0.10 */
err = CRYPT_ERROR; goto error;
}
@@ -112,6 +111,27 @@ int ecc_recover_key(const unsigned char *sig, unsigned long siglen,
if ((err = mp_read_unsigned_bin(r, (unsigned char *)sig, 32)) != CRYPT_OK) { goto error; }
if ((err = mp_read_unsigned_bin(s, (unsigned char *)sig+32, 32)) != CRYPT_OK) { goto error; }
}
+#ifdef LTC_SSH
+ else if (sigformat == LTC_ECCSIG_RFC5656) {
+ char name[64], name2[64];
+ unsigned long namelen = sizeof(name2);
+
+ /* Decode as SSH data sequence, per RFC4251 */
+ if ((err = ssh_decode_sequence_multi(sig, siglen,
+ LTC_SSHDATA_STRING, name, 64,
+ LTC_SSHDATA_MPINT, r,
+ LTC_SSHDATA_MPINT, s,
+ LTC_SSHDATA_EOL, NULL)) != CRYPT_OK) { goto error; }
+
+
+ /* Check curve matches identifier string */
+ if ((err = ecc_ssh_ecdsa_encode_name(name2, &namelen, key)) != CRYPT_OK) { goto error; }
+ if (XSTRCMP(name,name2) != 0) {
+ err = CRYPT_INVALID_ARG;
+ goto error;
+ }
+ }
+#endif
else {
/* Unknown signature format */
err = CRYPT_ERROR;
diff --git a/src/pk/ecc/ecc_sign_hash.c b/src/pk/ecc/ecc_sign_hash.c
index 6764dae66..c7a808d8d 100644
--- a/src/pk/ecc/ecc_sign_hash.c
+++ b/src/pk/ecc/ecc_sign_hash.c
@@ -141,8 +141,7 @@ int ecc_sign_hash_ex(const unsigned char *in, unsigned long inlen,
}
else if (sigformat == LTC_ECCSIG_ETH27) {
/* Ethereum (v,r,s) format */
- if (key->dp.oidlen != 5 || key->dp.oid[0] != 1 || key->dp.oid[1] != 3 ||
- key->dp.oid[2] != 132 || key->dp.oid[3] != 0 || key->dp.oid[4] != 10) {
+ if (pk_oid_cmp_with_ulong("1.3.132.0.10", key->dp.oid, key->dp.oidlen) != CRYPT_OK) {
/* Only valid for secp256k1 - OID 1.3.132.0.10 */
err = CRYPT_ERROR; goto errnokey;
}
@@ -156,6 +155,21 @@ int ecc_sign_hash_ex(const unsigned char *in, unsigned long inlen,
*outlen = 65;
err = CRYPT_OK;
}
+#ifdef LTC_SSH
+ else if (sigformat == LTC_ECCSIG_RFC5656) {
+ /* Get identifier string */
+ char name[64];
+ unsigned long namelen = sizeof(name);
+ if ((err = ecc_ssh_ecdsa_encode_name(name, &namelen, key)) != CRYPT_OK) { goto errnokey; }
+
+ /* Store as SSH data sequence, per RFC4251 */
+ err = ssh_encode_sequence_multi(out, outlen,
+ LTC_SSHDATA_STRING, name,
+ LTC_SSHDATA_MPINT, r,
+ LTC_SSHDATA_MPINT, s,
+ LTC_SSHDATA_EOL, NULL);
+ }
+#endif
else {
/* Unknown signature format */
err = CRYPT_ERROR;
diff --git a/src/pk/ecc/ecc_ssh_ecdsa_encode_name.c b/src/pk/ecc/ecc_ssh_ecdsa_encode_name.c
new file mode 100644
index 000000000..048f29d24
--- /dev/null
+++ b/src/pk/ecc/ecc_ssh_ecdsa_encode_name.c
@@ -0,0 +1,70 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt_private.h"
+
+/**
+ @file ecc_ssh_ecdsa_encode_name.c
+ Curve/OID to SSH+ECDSA name string mapping per RFC5656
+ Russ Williams
+*/
+
+/**
+ Curve/OID to SSH+ECDSA name string mapping
+ @param buffer [out] The destination for the name
+ @param buflen [in/out] The max size and resulting size (including terminator) of the name
+ @param key A public or private ECC key
+ @return CRYPT_OK if successful
+*/
+int ecc_ssh_ecdsa_encode_name(char *buffer, unsigned long *buflen, const ecc_key *key)
+{
+ char oidstr[64];
+ unsigned long oidlen = sizeof(oidstr);
+ unsigned long size = 0;
+ int err;
+
+ LTC_ARGCHK(buffer != NULL);
+ LTC_ARGCHK(buflen != NULL);
+ LTC_ARGCHK(key != NULL);
+
+ /* Get the OID of the curve */
+ if ((err = ecc_get_oid_str(oidstr, &oidlen, key)) != CRYPT_OK) goto error;
+
+ /* Check for three named curves: nistp256, nistp384, nistp521 */
+ if (XSTRCMP("1.2.840.10045.3.1.7", oidstr) == 0) {
+ /* nistp256 - secp256r1 - OID 1.2.840.10045.3.1.7 */
+ size = snprintf(buffer, *buflen, "ecdsa-sha2-nistp256");
+ }
+ else if (XSTRCMP("1.3.132.0.34", oidstr) == 0) {
+ /* nistp384 - secp384r1 - OID 1.3.132.0.34 */
+ size = snprintf(buffer, *buflen, "ecdsa-sha2-nistp384");
+ }
+ else if (XSTRCMP("1.3.132.0.35", oidstr) == 0) {
+ /* nistp521 - secp521r1 - OID 1.3.132.0.35 */
+ size = snprintf(buffer, *buflen, "ecdsa-sha2-nistp521");
+ } else {
+ /* Otherwise we use the OID... */
+ size = snprintf(buffer, *buflen, "ecdsa-sha2-%s", oidstr);
+ }
+
+ /* snprintf returns size that would have been written, but limits to buflen-1 chars plus terminator */
+ if (size >= *buflen) {
+ err = CRYPT_BUFFER_OVERFLOW;
+ } else {
+ err = CRYPT_OK;
+ }
+ *buflen = size + 1; /* the string length + NUL byte */
+
+error:
+ return err;
+}
+
+
+/* ref: $Format:%D$ */
+/* git commit: $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/src/pk/ecc/ecc_verify_hash.c b/src/pk/ecc/ecc_verify_hash.c
index 98b8ac1ce..e89db8c0e 100644
--- a/src/pk/ecc/ecc_verify_hash.c
+++ b/src/pk/ecc/ecc_verify_hash.c
@@ -86,8 +86,7 @@ int ecc_verify_hash_ex(const unsigned char *sig, unsigned long siglen,
}
else if (sigformat == LTC_ECCSIG_ETH27) {
/* Ethereum (v,r,s) format */
- if (key->dp.oidlen != 5 || key->dp.oid[0] != 1 || key->dp.oid[1] != 3 ||
- key->dp.oid[2] != 132 || key->dp.oid[3] != 0 || key->dp.oid[4] != 10) {
+ if (pk_oid_cmp_with_ulong("1.3.132.0.10", key->dp.oid, key->dp.oidlen) != CRYPT_OK) {
/* Only valid for secp256k1 - OID 1.3.132.0.10 */
err = CRYPT_ERROR; goto error;
}
@@ -98,6 +97,27 @@ int ecc_verify_hash_ex(const unsigned char *sig, unsigned long siglen,
if ((err = mp_read_unsigned_bin(r, (unsigned char *)sig, 32)) != CRYPT_OK) { goto error; }
if ((err = mp_read_unsigned_bin(s, (unsigned char *)sig+32, 32)) != CRYPT_OK) { goto error; }
}
+#ifdef LTC_SSH
+ else if (sigformat == LTC_ECCSIG_RFC5656) {
+ char name[64], name2[64];
+ unsigned long namelen = sizeof(name2);
+
+ /* Decode as SSH data sequence, per RFC4251 */
+ if ((err = ssh_decode_sequence_multi(sig, siglen,
+ LTC_SSHDATA_STRING, name, 64,
+ LTC_SSHDATA_MPINT, r,
+ LTC_SSHDATA_MPINT, s,
+ LTC_SSHDATA_EOL, NULL)) != CRYPT_OK) { goto error; }
+
+
+ /* Check curve matches identifier string */
+ if ((err = ecc_ssh_ecdsa_encode_name(name2, &namelen, key)) != CRYPT_OK) { goto error; }
+ if (XSTRCMP(name,name2) != 0) {
+ err = CRYPT_INVALID_ARG;
+ goto error;
+ }
+ }
+#endif
else {
/* Unknown signature format */
err = CRYPT_ERROR;
diff --git a/tests/common.h b/tests/common.h
index d44949328..5f2ac3cc7 100644
--- a/tests/common.h
+++ b/tests/common.h
@@ -23,6 +23,7 @@ extern prng_state yarrow_prng;
#define SHOULD_FAIL(x) do { run_cmd((x) != CRYPT_OK ? CRYPT_OK : CRYPT_FAIL_TESTVECTOR, __LINE__, __FILE__, #x, NULL); } while (0)
#endif
+#define COMPARE_TESTVECTOR(i, il, s, sl, wa, wi) do { DO(do_compare_testvector((i), (il), (s), (sl), (wa), (wi))); } while(0)
#if !((defined(_WIN32) || defined(_WIN32_WCE)) && !defined(__GNUC__))
#define LTC_TEST_READDIR
diff --git a/tests/ecc_test.c b/tests/ecc_test.c
index f0bf41d35..d017f720b 100644
--- a/tests/ecc_test.c
+++ b/tests/ecc_test.c
@@ -37,6 +37,93 @@ static unsigned int sizes[] = {
#endif
};
+static const char* curvenames[] = {
+#ifdef LTC_ECC_SECP112R1
+ "SECP112R1", "ECC-112",
+ "secp112r1", /* name is case-insensitive */
+ "S E C-P-1_1_2r1", /* should pass fuzzy matching */
+#endif
+#ifdef LTC_ECC_SECP112R2
+ "SECP112R2",
+#endif
+#ifdef LTC_ECC_SECP128R1
+ "SECP128R1", "ECC-128",
+#endif
+#ifdef LTC_ECC_SECP128R2
+ "SECP128R2",
+#endif
+#ifdef LTC_ECC_SECP160R1
+ "SECP160R1", "ECC-160",
+#endif
+#ifdef LTC_ECC_SECP160R2
+ "SECP160R2",
+#endif
+#ifdef LTC_ECC_SECP160K1
+ "SECP160K1",
+#endif
+#ifdef LTC_ECC_BRAINPOOLP160R1
+ "BRAINPOOLP160R1",
+#endif
+#ifdef LTC_ECC_SECP192R1
+ "SECP192R1", "NISTP192", "PRIME192V1", "ECC-192", "P-192",
+#endif
+#ifdef LTC_ECC_PRIME192V2
+ "PRIME192V2",
+#endif
+#ifdef LTC_ECC_PRIME192V3
+ "PRIME192V3",
+#endif
+#ifdef LTC_ECC_SECP192K1
+ "SECP192K1",
+#endif
+#ifdef LTC_ECC_BRAINPOOLP192R1
+ "BRAINPOOLP192R1",
+#endif
+#ifdef LTC_ECC_SECP224R1
+ "SECP224R1", "NISTP224", "ECC-224", "P-224",
+#endif
+#ifdef LTC_ECC_SECP224K1
+ "SECP224K1",
+#endif
+#ifdef LTC_ECC_BRAINPOOLP224R1
+ "BRAINPOOLP224R1",
+#endif
+#ifdef LTC_ECC_PRIME239V1
+ "PRIME239V1",
+#endif
+#ifdef LTC_ECC_PRIME239V2
+ "PRIME239V2",
+#endif
+#ifdef LTC_ECC_PRIME239V3
+ "PRIME239V3",
+#endif
+#ifdef LTC_ECC_SECP256R1
+ "SECP256R1", "NISTP256", "PRIME256V1", "ECC-256", "P-256",
+#endif
+#ifdef LTC_ECC_SECP256K1
+ "SECP256K1",
+#endif
+#ifdef LTC_ECC_BRAINPOOLP256R1
+ "BRAINPOOLP256R1",
+#endif
+#ifdef LTC_ECC_BRAINPOOLP320R1
+ "BRAINPOOLP320R1",
+#endif
+#ifdef LTC_ECC_SECP384R1
+ "SECP384R1", "NISTP384", "ECC-384", "P-384",
+#endif
+#ifdef LTC_ECC_BRAINPOOLP384R1
+ "BRAINPOOLP384R1",
+#endif
+#ifdef LTC_ECC_BRAINPOOLP512R1
+ "BRAINPOOLP512R1",
+#endif
+#ifdef LTC_ECC_SECP521R1
+ "SECP521R1", "NISTP521", "ECC-521", "P-521",
+#endif
+};
+
+
#ifdef LTC_ECC_SHAMIR
static int _ecc_test_shamir(void)
{
@@ -423,91 +510,6 @@ static int _ecc_key_cmp(const int should_type, const ecc_key *should, const ecc_
static int _ecc_new_api(void)
{
- const char* names[] = {
-#ifdef LTC_ECC_SECP112R1
- "SECP112R1", "ECC-112",
- "secp112r1", /* name is case-insensitive */
- "S E C-P-1_1_2r1", /* should pass fuzzy matching */
-#endif
-#ifdef LTC_ECC_SECP112R2
- "SECP112R2",
-#endif
-#ifdef LTC_ECC_SECP128R1
- "SECP128R1", "ECC-128",
-#endif
-#ifdef LTC_ECC_SECP128R2
- "SECP128R2",
-#endif
-#ifdef LTC_ECC_SECP160R1
- "SECP160R1", "ECC-160",
-#endif
-#ifdef LTC_ECC_SECP160R2
- "SECP160R2",
-#endif
-#ifdef LTC_ECC_SECP160K1
- "SECP160K1",
-#endif
-#ifdef LTC_ECC_BRAINPOOLP160R1
- "BRAINPOOLP160R1",
-#endif
-#ifdef LTC_ECC_SECP192R1
- "SECP192R1", "NISTP192", "PRIME192V1", "ECC-192", "P-192",
-#endif
-#ifdef LTC_ECC_PRIME192V2
- "PRIME192V2",
-#endif
-#ifdef LTC_ECC_PRIME192V3
- "PRIME192V3",
-#endif
-#ifdef LTC_ECC_SECP192K1
- "SECP192K1",
-#endif
-#ifdef LTC_ECC_BRAINPOOLP192R1
- "BRAINPOOLP192R1",
-#endif
-#ifdef LTC_ECC_SECP224R1
- "SECP224R1", "NISTP224", "ECC-224", "P-224",
-#endif
-#ifdef LTC_ECC_SECP224K1
- "SECP224K1",
-#endif
-#ifdef LTC_ECC_BRAINPOOLP224R1
- "BRAINPOOLP224R1",
-#endif
-#ifdef LTC_ECC_PRIME239V1
- "PRIME239V1",
-#endif
-#ifdef LTC_ECC_PRIME239V2
- "PRIME239V2",
-#endif
-#ifdef LTC_ECC_PRIME239V3
- "PRIME239V3",
-#endif
-#ifdef LTC_ECC_SECP256R1
- "SECP256R1", "NISTP256", "PRIME256V1", "ECC-256", "P-256",
-#endif
-#ifdef LTC_ECC_SECP256K1
- "SECP256K1",
-#endif
-#ifdef LTC_ECC_BRAINPOOLP256R1
- "BRAINPOOLP256R1",
-#endif
-#ifdef LTC_ECC_BRAINPOOLP320R1
- "BRAINPOOLP320R1",
-#endif
-#ifdef LTC_ECC_SECP384R1
- "SECP384R1", "NISTP384", "ECC-384", "P-384",
-#endif
-#ifdef LTC_ECC_BRAINPOOLP384R1
- "BRAINPOOLP384R1",
-#endif
-#ifdef LTC_ECC_BRAINPOOLP512R1
- "BRAINPOOLP512R1",
-#endif
-#ifdef LTC_ECC_SECP521R1
- "SECP521R1", "NISTP521", "ECC-521", "P-521",
-#endif
- };
int i, j, stat;
const ltc_ecc_curve* dp;
ecc_key key, privkey, pubkey;
@@ -516,8 +518,8 @@ static int _ecc_new_api(void)
unsigned char data16[16] = { 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1 };
unsigned long len16;
- for (i = 0; i < (int)(sizeof(names)/sizeof(names[0])); i++) {
- DO(ecc_find_curve(names[i], &dp));
+ for (i = 0; i < (int)(sizeof(curvenames)/sizeof(curvenames[0])); i++) {
+ DO(ecc_find_curve(curvenames[i], &dp));
/* make new key */
DO(ecc_make_key_ex(&yarrow_prng, find_prng ("yarrow"), &key, dp));
len = sizeof(buf);
@@ -572,6 +574,16 @@ static int _ecc_new_api(void)
DO(ecc_verify_hash(buf, len, data16, 16, &stat, &pubkey));
if (stat != 1) return CRYPT_FAIL_TESTVECTOR;
+#ifdef LTC_SSH
+ /* test SSH+ECDSA/RFC5656 signature */
+ len = sizeof(buf);
+ DO(ecc_sign_hash_ex(data16, 16, buf, &len, &yarrow_prng, find_prng ("yarrow"),
+ LTC_ECCSIG_RFC5656, NULL, &privkey));
+ stat = 0;
+ DO(ecc_verify_hash_ex(buf, len, data16, 16, LTC_ECCSIG_RFC5656, &stat, &pubkey));
+ if (stat != 1) return CRYPT_FAIL_TESTVECTOR;
+#endif
+
#ifdef LTC_ECC_SHAMIR
if (strcmp(ltc_mp.name, "TomsFastMath") != 0) {
/* XXX-FIXME: TFM does not support sqrtmod_prime */
@@ -1477,91 +1489,6 @@ static int _ecc_import_export(void) {
#ifdef LTC_ECC_SHAMIR
static int _ecc_test_recovery(void)
{
- const char* names[] = {
-#ifdef LTC_ECC_SECP112R1
- "SECP112R1", "ECC-112",
- "secp112r1", /* name is case-insensitive */
- "S E C-P-1_1_2r1", /* should pass fuzzy matching */
-#endif
-#ifdef LTC_ECC_SECP112R2
- "SECP112R2",
-#endif
-#ifdef LTC_ECC_SECP128R1
- "SECP128R1", "ECC-128",
-#endif
-#ifdef LTC_ECC_SECP128R2
- "SECP128R2",
-#endif
-#ifdef LTC_ECC_SECP160R1
- "SECP160R1", "ECC-160",
-#endif
-#ifdef LTC_ECC_SECP160R2
- "SECP160R2",
-#endif
-#ifdef LTC_ECC_SECP160K1
- "SECP160K1",
-#endif
-#ifdef LTC_ECC_BRAINPOOLP160R1
- "BRAINPOOLP160R1",
-#endif
-#ifdef LTC_ECC_SECP192R1
- "SECP192R1", "NISTP192", "PRIME192V1", "ECC-192", "P-192",
-#endif
-#ifdef LTC_ECC_PRIME192V2
- "PRIME192V2",
-#endif
-#ifdef LTC_ECC_PRIME192V3
- "PRIME192V3",
-#endif
-#ifdef LTC_ECC_SECP192K1
- "SECP192K1",
-#endif
-#ifdef LTC_ECC_BRAINPOOLP192R1
- "BRAINPOOLP192R1",
-#endif
-#ifdef LTC_ECC_SECP224R1
- "SECP224R1", "NISTP224", "ECC-224", "P-224",
-#endif
-#ifdef LTC_ECC_SECP224K1
- "SECP224K1",
-#endif
-#ifdef LTC_ECC_BRAINPOOLP224R1
- "BRAINPOOLP224R1",
-#endif
-#ifdef LTC_ECC_PRIME239V1
- "PRIME239V1",
-#endif
-#ifdef LTC_ECC_PRIME239V2
- "PRIME239V2",
-#endif
-#ifdef LTC_ECC_PRIME239V3
- "PRIME239V3",
-#endif
-#ifdef LTC_ECC_SECP256R1
- "SECP256R1", "NISTP256", "PRIME256V1", "ECC-256", "P-256",
-#endif
-#ifdef LTC_ECC_SECP256K1
- "SECP256K1",
-#endif
-#ifdef LTC_ECC_BRAINPOOLP256R1
- "BRAINPOOLP256R1",
-#endif
-#ifdef LTC_ECC_BRAINPOOLP320R1
- "BRAINPOOLP320R1",
-#endif
-#ifdef LTC_ECC_SECP384R1
- "SECP384R1", "NISTP384", "ECC-384", "P-384",
-#endif
-#ifdef LTC_ECC_BRAINPOOLP384R1
- "BRAINPOOLP384R1",
-#endif
-#ifdef LTC_ECC_BRAINPOOLP512R1
- "BRAINPOOLP512R1",
-#endif
-#ifdef LTC_ECC_SECP521R1
- "SECP521R1", "NISTP521", "ECC-521", "P-521",
-#endif
- };
int i, recid, stat;
const ltc_ecc_curve* dp;
ecc_key key, privkey, pubkey, reckey;
@@ -1611,8 +1538,8 @@ static int _ecc_test_recovery(void)
ecc_free(&pubkey);
#endif
- for (i = 0; i < (int)(sizeof(names)/sizeof(names[0])); i++) {
- DO(ecc_find_curve(names[i], &dp));
+ for (i = 0; i < (int)(sizeof(curvenames)/sizeof(curvenames[0])); i++) {
+ DO(ecc_find_curve(curvenames[i], &dp));
/* generate new key */
DO(ecc_set_curve(dp, &key));
diff --git a/tests/misc_test.c b/tests/misc_test.c
index c20418035..67648f973 100644
--- a/tests/misc_test.c
+++ b/tests/misc_test.c
@@ -33,6 +33,9 @@ int misc_test(void)
#endif
#ifdef LTC_CRC32
DO(crc32_test());
+#endif
+#ifdef LTC_SSH
+ DO(ssh_test());
#endif
return 0;
}
diff --git a/tests/ssh_test.c b/tests/ssh_test.c
new file mode 100644
index 000000000..942a745de
--- /dev/null
+++ b/tests/ssh_test.c
@@ -0,0 +1,310 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt_test.h"
+
+/**
+ @file ssh_test.c
+ Support for SSH data formats (RFC4251), Russ Williams
+*/
+
+#ifdef LTC_SSH
+
+#define BUFSIZE 64
+
+/**
+ Test vectors from from RFC4251, section 5
+
+ uint32: "the value 699921578 (0x29b7f4aa) is stored as 29 b7 f4 aa"
+
+ string: "the US-ASCII string "testing" is represented as 00 00 00 07 t e s t i n g"
+
+ mpint:
+ value (hex) representation (hex)
+ ----------- --------------------
+ 0 00 00 00 00
+ 9a378f9b2e332a7 00 00 00 08 09 a3 78 f9 b2 e3 32 a7
+ 80 00 00 00 02 00 80
+ -1234 00 00 00 02 ed cc
+ -deadbeef 00 00 00 05 ff 21 52 41 11
+
+ name-list:
+ value representation (hex)
+ ----- --------------------
+ (), the empty name-list 00 00 00 00
+ ("zlib") 00 00 00 04 7a 6c 69 62
+ ("zlib,none") 00 00 00 09 7a 6c 69 62 2c 6e 6f 6e 65
+*/
+static const unsigned char byte1[] = {0x01};
+static const unsigned char byte2[] = {0x71};
+static const unsigned char uint32[] = {0x29, 0xb7, 0xf4, 0xaa};
+static const unsigned char uint64[] = {0x09, 0xa3, 0x78, 0xf9, 0xb2, 0xe3, 0x32, 0xa7};
+static const unsigned char string[] = {0x00, 0x00, 0x00, 0x07, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67};
+static const unsigned char mpint1[] = {0x00, 0x00, 0x00, 0x00};
+static const unsigned char mpint2[] = {0x00, 0x00, 0x00, 0x08, 0x09, 0xa3, 0x78, 0xf9, 0xb2, 0xe3, 0x32, 0xa7};
+static const unsigned char mpint3[] = {0x00, 0x00, 0x00, 0x02, 0x00, 0x80};
+static const unsigned char nlist1[] = {0x00, 0x00, 0x00, 0x00};
+static const unsigned char nlist2[] = {0x00, 0x00, 0x00, 0x04, 0x7a, 0x6c, 0x69, 0x62};
+static const unsigned char nlist3[] = {0x00, 0x00, 0x00, 0x09, 0x7a, 0x6c, 0x69, 0x62, 0x2c, 0x6e, 0x6f, 0x6e, 0x65};
+
+
+/**
+ LTC_SSH encoding test
+ @return CRYPT_OK if successful
+*/
+static int _ssh_encoding_test(void)
+{
+ unsigned char buffer[BUFSIZE];
+ unsigned long buflen;
+ void *v, *zero;
+ int err;
+
+ /* Buffer too short */
+ buflen = 3;
+ zeromem(buffer, BUFSIZE);
+ err = ssh_encode_sequence_multi(buffer, &buflen,
+ LTC_SSHDATA_UINT32, 0x29b7f4aa,
+ LTC_SSHDATA_EOL, NULL);
+ if (err != CRYPT_BUFFER_OVERFLOW) return CRYPT_FAIL_TESTVECTOR;
+
+
+ /* byte */
+ buflen = BUFSIZE;
+ zeromem(buffer, BUFSIZE);
+ DO(ssh_encode_sequence_multi(buffer, &buflen,
+ LTC_SSHDATA_BYTE, 0x01,
+ LTC_SSHDATA_EOL, NULL));
+ COMPARE_TESTVECTOR(buffer, buflen, byte1, sizeof(byte1), "enc-byte", 1);
+
+ buflen = BUFSIZE;
+ zeromem(buffer, BUFSIZE);
+ DO(ssh_encode_sequence_multi(buffer, &buflen,
+ LTC_SSHDATA_BYTE, 0x71,
+ LTC_SSHDATA_EOL, NULL));
+ COMPARE_TESTVECTOR(buffer, buflen, byte2, sizeof(byte2), "enc-byte", 2);
+ if (XMEMCMP(buffer, byte2, buflen) != 0) return CRYPT_FAIL_TESTVECTOR;
+
+ /* boolean */
+ buflen = BUFSIZE;
+ zeromem(buffer, BUFSIZE);
+ DO(ssh_encode_sequence_multi(buffer, &buflen,
+ LTC_SSHDATA_BOOLEAN, 0x01,
+ LTC_SSHDATA_EOL, NULL));
+ COMPARE_TESTVECTOR(buffer, buflen, byte1, sizeof(byte1), "enc-boolean", 1);
+
+ buflen = BUFSIZE;
+ zeromem(buffer, BUFSIZE);
+ DO(ssh_encode_sequence_multi(buffer, &buflen,
+ LTC_SSHDATA_BOOLEAN, 0x71,
+ LTC_SSHDATA_EOL, NULL));
+ /* Should be written out as 0x01 */
+ COMPARE_TESTVECTOR(buffer, buflen, byte1, sizeof(byte1), "enc-boolean", 2);
+
+ /* uint32 */
+ buflen = BUFSIZE;
+ zeromem(buffer, BUFSIZE);
+ DO(ssh_encode_sequence_multi(buffer, &buflen,
+ LTC_SSHDATA_UINT32, 0x29b7f4aa,
+ LTC_SSHDATA_EOL, NULL));
+ COMPARE_TESTVECTOR(buffer, buflen, uint32, sizeof(uint32), "enc-uint32", 1);
+
+ /* uint64 */
+ buflen = BUFSIZE;
+ zeromem(buffer, BUFSIZE);
+ DO(ssh_encode_sequence_multi(buffer, &buflen,
+ LTC_SSHDATA_UINT64, CONST64(0x09a378f9b2e332a7),
+ LTC_SSHDATA_EOL, NULL));
+ COMPARE_TESTVECTOR(buffer, buflen, uint64, sizeof(uint64), "enc-uint64", 1);
+
+
+ /* string */
+ buflen = BUFSIZE;
+ zeromem(buffer, BUFSIZE);
+ DO(ssh_encode_sequence_multi(buffer, &buflen,
+ LTC_SSHDATA_STRING, "testing",
+ LTC_SSHDATA_EOL, NULL));
+ COMPARE_TESTVECTOR(buffer, buflen, string, sizeof(string), "enc-string", 1);
+
+
+ /* mpint */
+ if ((err = mp_init_multi(&zero, &v, NULL)) != CRYPT_OK) {
+ return err;
+ }
+
+ buflen = BUFSIZE;
+ zeromem(buffer, BUFSIZE);
+ DO(mp_set(zero, 0));
+ DO(ssh_encode_sequence_multi(buffer, &buflen,
+ LTC_SSHDATA_MPINT, zero,
+ LTC_SSHDATA_EOL, NULL));
+ COMPARE_TESTVECTOR(buffer, buflen, mpint1, sizeof(mpint1), "enc-mpint", 1);
+
+ buflen = BUFSIZE;
+ zeromem(buffer, BUFSIZE);
+ DO(mp_read_radix(v, "9a378f9b2e332a7", 16));
+ DO(ssh_encode_sequence_multi(buffer, &buflen,
+ LTC_SSHDATA_MPINT, v,
+ LTC_SSHDATA_EOL, NULL));
+ COMPARE_TESTVECTOR(buffer, buflen, mpint2, sizeof(mpint2), "enc-mpint", 2);
+
+ buflen = BUFSIZE;
+ zeromem(buffer, BUFSIZE);
+ DO(mp_set(v, 0x80));
+ DO(ssh_encode_sequence_multi(buffer, &buflen,
+ LTC_SSHDATA_MPINT, v,
+ LTC_SSHDATA_EOL, NULL));
+ COMPARE_TESTVECTOR(buffer, buflen, mpint3, sizeof(mpint3), "enc-mpint", 3);
+
+ mp_clear_multi(v, zero, NULL);
+
+
+ /* name-list */
+ buflen = BUFSIZE;
+ zeromem(buffer, BUFSIZE);
+ DO(ssh_encode_sequence_multi(buffer, &buflen,
+ LTC_SSHDATA_NAMELIST, "",
+ LTC_SSHDATA_EOL, NULL));
+ COMPARE_TESTVECTOR(buffer, buflen, nlist1, sizeof(nlist1), "enc-nlist", 1);
+
+ buflen = BUFSIZE;
+ zeromem(buffer, BUFSIZE);
+ DO(ssh_encode_sequence_multi(buffer, &buflen,
+ LTC_SSHDATA_NAMELIST, "zlib",
+ LTC_SSHDATA_EOL, NULL));
+ COMPARE_TESTVECTOR(buffer, buflen, nlist2, sizeof(nlist2), "enc-nlist", 2);
+
+ buflen = BUFSIZE;
+ zeromem(buffer, BUFSIZE);
+ DO(ssh_encode_sequence_multi(buffer, &buflen,
+ LTC_SSHDATA_NAMELIST, "zlib,none",
+ LTC_SSHDATA_EOL, NULL));
+ COMPARE_TESTVECTOR(buffer, buflen, nlist3, sizeof(nlist3), "enc-nlist", 3);
+
+ return CRYPT_OK;
+}
+
+/**
+ LTC_SSH decoding test
+ @return CRYPT_OK if successful
+*/
+static int _ssh_decoding_test(void)
+{
+ char strbuf[BUFSIZE];
+ void *u, *v;
+ ulong32 tmp32;
+ ulong64 tmp64;
+ unsigned char tmp8;
+ int err;
+
+ /* byte */
+ DO(ssh_decode_sequence_multi(byte1, sizeof(byte1),
+ LTC_SSHDATA_BYTE, &tmp8,
+ LTC_SSHDATA_EOL, NULL));
+ if (tmp8 != 0x01) return CRYPT_FAIL_TESTVECTOR;
+
+ DO(ssh_decode_sequence_multi(byte2, sizeof(byte2),
+ LTC_SSHDATA_BYTE, &tmp8,
+ LTC_SSHDATA_EOL, NULL));
+ if (tmp8 != 0x71) return CRYPT_FAIL_TESTVECTOR;
+
+ /* boolean */
+ DO(ssh_decode_sequence_multi(byte1, sizeof(byte1),
+ LTC_SSHDATA_BOOLEAN, &tmp8,
+ LTC_SSHDATA_EOL, NULL));
+ if (tmp8 != 0x01) return CRYPT_FAIL_TESTVECTOR;
+
+ DO(ssh_decode_sequence_multi(byte2, sizeof(byte2),
+ LTC_SSHDATA_BOOLEAN, &tmp8,
+ LTC_SSHDATA_EOL, NULL));
+ if (tmp8 != 0x01) return CRYPT_FAIL_TESTVECTOR;
+
+ /* uint32 */
+ DO(ssh_decode_sequence_multi(uint32, sizeof(uint32),
+ LTC_SSHDATA_UINT32, &tmp32,
+ LTC_SSHDATA_EOL, NULL));
+ if (tmp32 != 0x29b7f4aa) return CRYPT_FAIL_TESTVECTOR;
+
+ /* uint64 */
+ DO(ssh_decode_sequence_multi(uint64, sizeof(uint64),
+ LTC_SSHDATA_UINT64, &tmp64,
+ LTC_SSHDATA_EOL, NULL));
+ if (tmp64 != CONST64(0x09a378f9b2e332a7)) return CRYPT_FAIL_TESTVECTOR;
+
+ /* string */
+ zeromem(strbuf, BUFSIZE);
+ DO(ssh_decode_sequence_multi(string, sizeof(string),
+ LTC_SSHDATA_STRING, strbuf, BUFSIZE,
+ LTC_SSHDATA_EOL, NULL));
+ if (XSTRCMP(strbuf, "testing") != 0) return CRYPT_FAIL_TESTVECTOR;
+
+ /* mpint */
+ if ((err = mp_init_multi(&u, &v, NULL)) != CRYPT_OK) {
+ return err;
+ }
+
+ DO(ssh_decode_sequence_multi(mpint1, sizeof(mpint1),
+ LTC_SSHDATA_MPINT, v,
+ LTC_SSHDATA_EOL, NULL));
+ if (mp_cmp_d(v, 0) != LTC_MP_EQ) return CRYPT_FAIL_TESTVECTOR;
+
+ DO(mp_read_radix(u, "9a378f9b2e332a7", 16));
+ DO(ssh_decode_sequence_multi(mpint2, sizeof(mpint2),
+ LTC_SSHDATA_MPINT, v,
+ LTC_SSHDATA_EOL, NULL));
+ if (mp_cmp(u, v) != LTC_MP_EQ) return CRYPT_FAIL_TESTVECTOR;
+
+ DO(ssh_decode_sequence_multi(mpint3, sizeof(mpint3),
+ LTC_SSHDATA_MPINT, v,
+ LTC_SSHDATA_EOL, NULL));
+ if (mp_cmp_d(v, 0x80) != LTC_MP_EQ) return CRYPT_FAIL_TESTVECTOR;
+
+ mp_clear_multi(v, u, NULL);
+
+ /* name-list */
+ zeromem(strbuf, BUFSIZE);
+ DO(ssh_decode_sequence_multi(nlist1, sizeof(nlist1),
+ LTC_SSHDATA_NAMELIST, strbuf, BUFSIZE,
+ LTC_SSHDATA_EOL, NULL));
+ if (XSTRCMP(strbuf, "") != 0) return CRYPT_FAIL_TESTVECTOR;
+
+ zeromem(strbuf, BUFSIZE);
+ DO(ssh_decode_sequence_multi(nlist2, sizeof(nlist2),
+ LTC_SSHDATA_NAMELIST, strbuf, BUFSIZE,
+ LTC_SSHDATA_EOL, NULL));
+ if (XSTRCMP(strbuf, "zlib") != 0) return CRYPT_FAIL_TESTVECTOR;
+
+ zeromem(strbuf, BUFSIZE);
+ DO(ssh_decode_sequence_multi(nlist3, sizeof(nlist3),
+ LTC_SSHDATA_NAMELIST, strbuf, BUFSIZE,
+ LTC_SSHDATA_EOL, NULL));
+ if (XSTRCMP(strbuf, "zlib,none") != 0) return CRYPT_FAIL_TESTVECTOR;
+
+
+ return CRYPT_OK;
+}
+
+/**
+ LTC_SSH self-test
+ @return CRYPT_OK if successful, CRYPT_NOP if tests have been disabled.
+*/
+int ssh_test(void)
+{
+ DO(_ssh_encoding_test());
+ DO(_ssh_decoding_test());
+
+ return CRYPT_OK;
+}
+
+
+
+#endif
+
+
+/* ref: $Format:%D$ */
+/* git commit: $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/tests/tomcrypt_test.h b/tests/tomcrypt_test.h
index 22fbe0006..00304534d 100644
--- a/tests/tomcrypt_test.h
+++ b/tests/tomcrypt_test.h
@@ -45,6 +45,9 @@ int prng_test(void);
int mpi_test(void);
int padding_test(void);
+#ifdef LTC_SSH
+int ssh_test(void);
+#endif
#ifdef LTC_PKCS_1
struct ltc_prng_descriptor* no_prng_desc_get(void);