Ver código fonte

Merge pull request #438 from rmw42/feature/ssh-ecdsa

LTC_ECCSIG_RFC5656 SSH+ECDSA signature format
karel-m 7 anos atrás
pai
commit
dec99ed99c

+ 2 - 1
doc/crypt.tex

@@ -5631,6 +5631,7 @@ The following signature formats are suported:
 \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 @@ Currently LibTomCrypt will detect x86-32, x86-64, MIPS R5900, SPARC and SPARC64
 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

+ 2 - 0
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*[^\(]/;

+ 16 - 0
libtomcrypt_VS2008.vcproj

@@ -1607,6 +1607,18 @@
 					>
 				</File>
 			</Filter>
+			<Filter
+				Name="ssh"
+				>
+				<File
+					RelativePath="src\misc\ssh\ssh_decode_sequence_multi.c"
+					>
+				</File>
+				<File
+					RelativePath="src\misc\ssh\ssh_encode_sequence_multi.c"
+					>
+				</File>
+			</Filter>
 		</Filter>
 		<Filter
 			Name="modes"
@@ -2394,6 +2406,10 @@
 					RelativePath="src\pk\ecc\ecc_sizes.c"
 					>
 				</File>
+				<File
+					RelativePath="src\pk\ecc\ecc_ssh_ecdsa_encode_name.c"
+					>
+				</File>
 				<File
 					RelativePath="src\pk\ecc\ecc_test.c"
 					>

+ 16 - 14
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 \

+ 16 - 14
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 \

+ 16 - 14
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 \

+ 16 - 14
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 \

+ 7 - 2
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

+ 17 - 0
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 <type, data> */
+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$ */

+ 3 - 1
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 */

+ 4 - 0
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);

+ 3 - 0
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

+ 161 - 0
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 <stdarg.h>
+
+/**
+   @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 <type, data> (int, void*) except for string <type, data, size>
+  @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$ */

+ 168 - 0
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 <stdarg.h>
+
+/**
+   @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 <type, data> (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$ */

+ 22 - 2
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;

+ 16 - 2
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;

+ 70 - 0
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$ */

+ 22 - 2
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;

+ 1 - 0
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

+ 101 - 174
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));

+ 3 - 0
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;
 }

+ 310 - 0
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$ */

+ 3 - 0
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);