Merge pull request #500 from libtom/fix-ssh-api

Fix SSH API
This commit is contained in:
Steffen Jaeckel 2019-10-16 23:16:46 +02:00 committed by GitHub
commit fcdb14ede1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 221 additions and 86 deletions

View File

@ -7233,6 +7233,73 @@ int hkdf( int hash_idx,
Parameters are as in \textit{hkdf\_extract()} and \textit{hkdf\_expand()}.
\mysection{SSH}
The library provides functions to encode and decode SSH data as specified in RFC4251 Ch. 5.
\subsection{Data types}
The following enum is used to indicate a specific SSH data type
(besides EOL which is an internal one that indicates the end of a sequence).
\begin{figure}[h]
\begin{center}
\begin{small}
\begin{tabular}{|l|l|l|}
\hline \textbf{Definition} & \textbf{arg data Type} & \textbf{SSH Type} \\
\hline LTC\_SSHDATA\_EOL & - & End of SSH data sequence. \\
\hline LTC\_SSHDATA\_BYTE & \texttt{unsigned char} & \texttt{byte} type \\
\hline LTC\_SSHDATA\_BOOLEAN & \texttt{unsigned char} & \texttt{boolean} type \\
\hline LTC\_SSHDATA\_UINT32 & \texttt{ulong32} & \texttt{uint32} \\
\hline LTC\_SSHDATA\_UINT64 & \texttt{ulong64} & \texttt{uint64} \\
\hline LTC\_SSHDATA\_STRING & \texttt{char*} & \texttt{string} (one octet per char) \\
\hline LTC\_SSHDATA\_MPINT & \texttt{mp\_int} & \texttt{mpint} \\
\hline LTC\_SSHDATA\_NAMELIST & \texttt{char*} & \texttt{name-list} (which works exactly like a \texttt{string}) \\
\hline
\end{tabular}
\caption{List of SSH Supported Types}
\index{ssh\_data\_type}
\end{small}
\end{center}
\end{figure}
\subsection{De- and Encoding with Multiple Argument Lists}
\index{ssh\_encode\_sequence\_multi()}
\index{ssh\_decode\_sequence\_multi()}
The API works similar to the ASN.1 SEQUENCE multi en- and decoders.
They either encode or decode a sequence of the supported SSH types where the items are specified after the length parameter.
\begin{verbatim}
int ssh_encode_sequence_multi(unsigned char *out, unsigned long *outlen, ...);
\end{verbatim}
Where \texttt{out} points to the destination buffer and \texttt{outlen} points
on function invocation to the length of the destination buffer
and after returning it will be filled with the number of octets written to the buffer.
The encoding function \texttt{ssh\_encode\_sequence\_multi()} expects its items to be a pair of \texttt{(type, data)},
except for the \texttt{string} resp. \texttt{name-list} type, which expects the triple \texttt{(type, data, size)}
with \texttt{size} being of type \texttt{unsigned long}.
\begin{verbatim}
int ssh_decode_sequence_multi(const unsigned char *in, unsigned long *inlen, ...);
\end{verbatim}
Where \texttt{in} points to the buffer with the sequence to decode and \texttt{inlen} points
on function invocation to the length of the sequence
and after returning it will be filled with the decoded number of octets.
The decoding function \texttt{ssh\_decode\_sequence\_multi()} expects its items to be a pair of \texttt{(type, data*)},
except for the \texttt{string} resp. \texttt{name-list} type, which expects the triple \texttt{(type, data, size*)}
with \texttt{size*} being of type \texttt{unsigned long*}.
\chapter{Miscellaneous}
\mysection{Base64 Encoding and Decoding}
The library provides functions to encode and decode a RFC 4648 Base64 coding scheme.

View File

@ -163,6 +163,7 @@ int padding_depad(const unsigned char *data, unsigned long *length, unsigned lon
#ifdef LTC_SSH
typedef enum ssh_data_type_ {
LTC_SSHDATA_EOL,
LTC_SSHDATA_BYTE,
LTC_SSHDATA_BOOLEAN,
LTC_SSHDATA_UINT32,
@ -170,12 +171,11 @@ typedef enum ssh_data_type_ {
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, ...);
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);

View File

@ -18,12 +18,12 @@
/**
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>
@param in The input buffer
@param inlen [in/out] The length of the input buffer and on output the amount of decoded data
@remark <...> is of the form <type, data*> (int, <unsigned char*,ulong32*,ulong64*>) except for string&name-list <type, data, size*> (int, void*, unsigned long*)
@return CRYPT_OK on success
*/
int ssh_decode_sequence_multi(const unsigned char *in, unsigned long inlen, ...)
int ssh_decode_sequence_multi(const unsigned char *in, unsigned long *inlen, ...)
{
int err;
va_list args;
@ -33,11 +33,14 @@ int ssh_decode_sequence_multi(const unsigned char *in, unsigned long inlen, ...)
char *sdata;
ulong32 *u32data;
ulong64 *u64data;
unsigned long bufsize;
unsigned long *bufsize;
ulong32 size;
unsigned long remaining;
LTC_ARGCHK(in != NULL);
LTC_ARGCHK(inlen != NULL);
remaining = *inlen;
/* Decode values from buffer */
va_start(args, inlen);
while ((type = (ssh_data_type)va_arg(args, int)) != LTC_SSHDATA_EOL) {
@ -47,7 +50,7 @@ int ssh_decode_sequence_multi(const unsigned char *in, unsigned long inlen, ...)
type == LTC_SSHDATA_MPINT)
{
/* Check we'll not read too far */
if (inlen < 4) {
if (remaining < 4) {
err = CRYPT_BUFFER_OVERFLOW;
goto error;
}
@ -71,7 +74,7 @@ int ssh_decode_sequence_multi(const unsigned char *in, unsigned long inlen, ...)
case LTC_SSHDATA_MPINT:
LOAD32H(size, in);
in += 4;
inlen -= 4;
remaining -= 4;
break;
case LTC_SSHDATA_EOL:
@ -81,55 +84,63 @@ int ssh_decode_sequence_multi(const unsigned char *in, unsigned long inlen, ...)
}
/* Check we'll not read too far */
if (inlen < size) {
if (remaining < size) {
err = CRYPT_BUFFER_OVERFLOW;
goto error;
} else {
inlen -= size;
remaining -= size;
}
vdata = va_arg(args, void*);
if (vdata == NULL) {
err = CRYPT_INVALID_ARG;
goto error;
}
/* Read data */
switch (type) {
case LTC_SSHDATA_BYTE:
cdata = va_arg(args, unsigned char*);
cdata = vdata;
*cdata = *in++;
break;
case LTC_SSHDATA_BOOLEAN:
cdata = va_arg(args, unsigned char*);
cdata = vdata;
/*
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*);
u32data = vdata;
LOAD32H(*u32data, in);
in += 4;
break;
case LTC_SSHDATA_UINT64:
u64data = va_arg(args, ulong64*);
u64data = vdata;
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) {
sdata = vdata;
bufsize = va_arg(args, unsigned long*);
if (bufsize == NULL) {
err = CRYPT_INVALID_ARG;
goto error;
}
if (size + 1 >= *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';
XMEMCPY(sdata, (const char *)in, size);
}
sdata[size] = '\0';
*bufsize = size;
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) {
@ -150,6 +161,8 @@ int ssh_decode_sequence_multi(const unsigned char *in, unsigned long inlen, ...)
}
err = CRYPT_OK;
*inlen -= remaining;
error:
va_end(args);
return err;

View File

@ -20,7 +20,7 @@
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*)
@remark <...> is of the form <type, data> (int, <int,ulong32,ulong64>) except for string&name-list <type, data, size> (int, void*, unsigned long)
@return CRYPT_OK on success
*/
int ssh_encode_sequence_multi(unsigned char *out, unsigned long *outlen, ...)
@ -29,8 +29,8 @@ int ssh_encode_sequence_multi(unsigned char *out, unsigned long *outlen, ...)
va_list args;
ulong32 size;
ssh_data_type type;
void *vdata;
const char *sdata;
void *vdata;
const char *sdata;
int idata;
ulong32 u32data;
ulong64 u64data;
@ -58,9 +58,9 @@ int ssh_encode_sequence_multi(unsigned char *out, unsigned long *outlen, ...)
break;
case LTC_SSHDATA_STRING:
case LTC_SSHDATA_NAMELIST:
sdata = va_arg(args, char*);
LTC_UNUSED_PARAM( va_arg(args, char*) );
size += va_arg(args, unsigned long);
size += 4;
size += strlen(sdata);
break;
case LTC_SSHDATA_MPINT:
vdata = va_arg(args, void*);
@ -102,7 +102,7 @@ int ssh_encode_sequence_multi(unsigned char *out, unsigned long *outlen, ...)
/*
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:
@ -118,7 +118,7 @@ int ssh_encode_sequence_multi(unsigned char *out, unsigned long *outlen, ...)
case LTC_SSHDATA_STRING:
case LTC_SSHDATA_NAMELIST:
sdata = va_arg(args, char*);
size = strlen(sdata);
size = va_arg(args, unsigned long);
STORE32H(size, out);
out += 4;
XMEMCPY(out, sdata, size);

View File

@ -114,19 +114,20 @@ int ecc_recover_key(const unsigned char *sig, unsigned long siglen,
#ifdef LTC_SSH
else if (sigformat == LTC_ECCSIG_RFC5656) {
char name[64], name2[64];
unsigned long namelen = sizeof(name2);
unsigned long namelen = sizeof(name);
unsigned long name2len = sizeof(name2);
/* Decode as SSH data sequence, per RFC4251 */
if ((err = ssh_decode_sequence_multi(sig, siglen,
LTC_SSHDATA_STRING, name, 64,
if ((err = ssh_decode_sequence_multi(sig, &siglen,
LTC_SSHDATA_STRING, name, &namelen,
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) {
if ((err = ecc_ssh_ecdsa_encode_name(name2, &name2len, key)) != CRYPT_OK) { goto error; }
if ((namelen != name2len) || (XSTRCMP(name, name2) != 0)) {
err = CRYPT_INVALID_ARG;
goto error;
}

View File

@ -164,7 +164,7 @@ int ecc_sign_hash_ex(const unsigned char *in, unsigned long inlen,
/* Store as SSH data sequence, per RFC4251 */
err = ssh_encode_sequence_multi(out, outlen,
LTC_SSHDATA_STRING, name,
LTC_SSHDATA_STRING, name, namelen,
LTC_SSHDATA_MPINT, r,
LTC_SSHDATA_MPINT, s,
LTC_SSHDATA_EOL, NULL);

View File

@ -25,8 +25,7 @@ int ecc_ssh_ecdsa_encode_name(char *buffer, unsigned long *buflen, const ecc_key
{
char oidstr[64];
unsigned long oidlen = sizeof(oidstr);
unsigned long size = 0;
int err;
int err, size = 0;
LTC_ARGCHK(buffer != NULL);
LTC_ARGCHK(buflen != NULL);
@ -52,8 +51,11 @@ int ecc_ssh_ecdsa_encode_name(char *buffer, unsigned long *buflen, const ecc_key
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) {
/* snprintf returns a negative value on error
* or the size that would have been written, but limits to buflen-1 chars plus terminator */
if (size < 0) {
err = CRYPT_ERROR;
} else if ((unsigned)size >= *buflen) {
err = CRYPT_BUFFER_OVERFLOW;
} else {
err = CRYPT_OK;

View File

@ -100,19 +100,20 @@ int ecc_verify_hash_ex(const unsigned char *sig, unsigned long siglen,
#ifdef LTC_SSH
else if (sigformat == LTC_ECCSIG_RFC5656) {
char name[64], name2[64];
unsigned long namelen = sizeof(name2);
unsigned long namelen = sizeof(name);
unsigned long name2len = sizeof(name2);
/* Decode as SSH data sequence, per RFC4251 */
if ((err = ssh_decode_sequence_multi(sig, siglen,
LTC_SSHDATA_STRING, name, 64,
if ((err = ssh_decode_sequence_multi(sig, &siglen,
LTC_SSHDATA_STRING, name, &namelen,
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) {
if ((err = ecc_ssh_ecdsa_encode_name(name2, &name2len, key)) != CRYPT_OK) { goto error; }
if ((namelen != name2len) || (XSTRCMP(name, name2) != 0)) {
err = CRYPT_INVALID_ARG;
goto error;
}

View File

@ -17,10 +17,12 @@ extern prng_state yarrow_prng;
#define DO(x) do { fprintf(stderr, "%s:\n", #x); run_cmd((x), __LINE__, __FILE__, #x, NULL); } while (0)
#define DOX(x, str) do { fprintf(stderr, "%s - %s:\n", #x, (str)); run_cmd((x), __LINE__, __FILE__, #x, (str)); } while (0)
#define SHOULD_FAIL(x) do { fprintf(stderr, "%s:\n", #x); run_cmd((x) != CRYPT_OK ? CRYPT_OK : CRYPT_FAIL_TESTVECTOR, __LINE__, __FILE__, #x, NULL); } while (0)
#define ENSURE(x) do { fprintf(stderr, "%s:\n", #x); run_cmd(((x)) ? CRYPT_OK : CRYPT_FAIL_TESTVECTOR, __LINE__, __FILE__, #x, NULL); } while (0)
#else
#define DO(x) do { run_cmd((x), __LINE__, __FILE__, #x, NULL); } while (0)
#define DOX(x, str) do { run_cmd((x), __LINE__, __FILE__, #x, (str)); } while (0)
#define SHOULD_FAIL(x) do { run_cmd((x) != CRYPT_OK ? CRYPT_OK : CRYPT_FAIL_TESTVECTOR, __LINE__, __FILE__, #x, NULL); } while (0)
#define ENSURE(x) do { run_cmd(((x)) ? 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)

View File

@ -61,16 +61,16 @@ static int _ssh_encoding_test(void)
{
unsigned char buffer[BUFSIZE];
unsigned long buflen;
unsigned long len;
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;
SHOULD_FAIL(ssh_encode_sequence_multi(buffer, &buflen,
LTC_SSHDATA_UINT32, 0x29b7f4aa,
LTC_SSHDATA_EOL, NULL));
/* byte */
@ -125,8 +125,9 @@ static int _ssh_encoding_test(void)
/* string */
buflen = BUFSIZE;
zeromem(buffer, BUFSIZE);
len = strlen("testing");
DO(ssh_encode_sequence_multi(buffer, &buflen,
LTC_SSHDATA_STRING, "testing",
LTC_SSHDATA_STRING, "testing", len,
LTC_SSHDATA_EOL, NULL));
COMPARE_TESTVECTOR(buffer, buflen, string, sizeof(string), "enc-string", 1);
@ -166,22 +167,25 @@ static int _ssh_encoding_test(void)
/* name-list */
buflen = BUFSIZE;
zeromem(buffer, BUFSIZE);
len = strlen("");
DO(ssh_encode_sequence_multi(buffer, &buflen,
LTC_SSHDATA_NAMELIST, "",
LTC_SSHDATA_NAMELIST, "", len,
LTC_SSHDATA_EOL, NULL));
COMPARE_TESTVECTOR(buffer, buflen, nlist1, sizeof(nlist1), "enc-nlist", 1);
buflen = BUFSIZE;
zeromem(buffer, BUFSIZE);
len = strlen("zlib");
DO(ssh_encode_sequence_multi(buffer, &buflen,
LTC_SSHDATA_NAMELIST, "zlib",
LTC_SSHDATA_NAMELIST, "zlib", len,
LTC_SSHDATA_EOL, NULL));
COMPARE_TESTVECTOR(buffer, buflen, nlist2, sizeof(nlist2), "enc-nlist", 2);
buflen = BUFSIZE;
zeromem(buffer, BUFSIZE);
len = strlen("zlib,none");
DO(ssh_encode_sequence_multi(buffer, &buflen,
LTC_SSHDATA_NAMELIST, "zlib,none",
LTC_SSHDATA_NAMELIST, "zlib,none", len,
LTC_SSHDATA_EOL, NULL));
COMPARE_TESTVECTOR(buffer, buflen, nlist3, sizeof(nlist3), "enc-nlist", 3);
@ -196,93 +200,138 @@ static int _ssh_decoding_test(void)
{
char strbuf[BUFSIZE];
void *u, *v;
unsigned long size;
ulong32 tmp32;
ulong64 tmp64;
unsigned char tmp8;
unsigned long len;
int err;
/* byte */
DO(ssh_decode_sequence_multi(byte1, sizeof(byte1),
/* Buffer longer */
len = sizeof(strbuf);
strbuf[0] = 0;
DO(ssh_decode_sequence_multi((unsigned char*)strbuf, &len,
LTC_SSHDATA_BYTE, &tmp8,
LTC_SSHDATA_EOL, NULL));
if (tmp8 != 0x01) return CRYPT_FAIL_TESTVECTOR;
ENSURE(tmp8 == 0x00);
ENSURE(len == 1);
DO(ssh_decode_sequence_multi(byte2, sizeof(byte2),
/* byte */
len = sizeof(byte1);
DO(ssh_decode_sequence_multi(byte1, &len,
LTC_SSHDATA_BYTE, &tmp8,
LTC_SSHDATA_EOL, NULL));
if (tmp8 != 0x71) return CRYPT_FAIL_TESTVECTOR;
ENSURE(tmp8 == 0x01);
ENSURE(len == 1);
len = sizeof(byte2);
DO(ssh_decode_sequence_multi(byte2, &len,
LTC_SSHDATA_BYTE, &tmp8,
LTC_SSHDATA_EOL, NULL));
ENSURE(tmp8 == 0x71);
ENSURE(len == 1);
/* boolean */
DO(ssh_decode_sequence_multi(byte1, sizeof(byte1),
len = sizeof(byte1);
DO(ssh_decode_sequence_multi(byte1, &len,
LTC_SSHDATA_BOOLEAN, &tmp8,
LTC_SSHDATA_EOL, NULL));
if (tmp8 != 0x01) return CRYPT_FAIL_TESTVECTOR;
ENSURE(tmp8 == 0x01);
ENSURE(len == 1);
DO(ssh_decode_sequence_multi(byte2, sizeof(byte2),
len = sizeof(byte2);
DO(ssh_decode_sequence_multi(byte2, &len,
LTC_SSHDATA_BOOLEAN, &tmp8,
LTC_SSHDATA_EOL, NULL));
if (tmp8 != 0x01) return CRYPT_FAIL_TESTVECTOR;
ENSURE(tmp8 == 0x01);
ENSURE(len == 1);
/* uint32 */
DO(ssh_decode_sequence_multi(uint32, sizeof(uint32),
len = sizeof(uint32);
DO(ssh_decode_sequence_multi(uint32, &len,
LTC_SSHDATA_UINT32, &tmp32,
LTC_SSHDATA_EOL, NULL));
if (tmp32 != 0x29b7f4aa) return CRYPT_FAIL_TESTVECTOR;
ENSURE(tmp32 == 0x29b7f4aa);
ENSURE(len == 4);
/* uint64 */
DO(ssh_decode_sequence_multi(uint64, sizeof(uint64),
len = sizeof(uint64);
DO(ssh_decode_sequence_multi(uint64, &len,
LTC_SSHDATA_UINT64, &tmp64,
LTC_SSHDATA_EOL, NULL));
if (tmp64 != CONST64(0x09a378f9b2e332a7)) return CRYPT_FAIL_TESTVECTOR;
ENSURE(len == 8);
/* string */
zeromem(strbuf, BUFSIZE);
DO(ssh_decode_sequence_multi(string, sizeof(string),
LTC_SSHDATA_STRING, strbuf, BUFSIZE,
size = BUFSIZE;
len = sizeof(string);
DO(ssh_decode_sequence_multi(string, &len,
LTC_SSHDATA_STRING, strbuf, &size,
LTC_SSHDATA_EOL, NULL));
if (XSTRCMP(strbuf, "testing") != 0) return CRYPT_FAIL_TESTVECTOR;
ENSURE(strlen("testing") == size);
ENSURE(XSTRCMP(strbuf, "testing") == 0);
ENSURE(strlen("testing") + 4 == len);
/* mpint */
if ((err = mp_init_multi(&u, &v, NULL)) != CRYPT_OK) {
return err;
}
DO(ssh_decode_sequence_multi(mpint1, sizeof(mpint1),
len = sizeof(mpint1);
DO(ssh_decode_sequence_multi(mpint1, &len,
LTC_SSHDATA_MPINT, v,
LTC_SSHDATA_EOL, NULL));
if (mp_cmp_d(v, 0) != LTC_MP_EQ) return CRYPT_FAIL_TESTVECTOR;
ENSURE(mp_cmp_d(v, 0) == LTC_MP_EQ);
ENSURE(sizeof(mpint1) == len);
len = sizeof(mpint2);
DO(ssh_decode_sequence_multi(mpint2, &len,
LTC_SSHDATA_MPINT, v,
LTC_SSHDATA_EOL, NULL));
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;
ENSURE(mp_cmp(u, v) == LTC_MP_EQ);
ENSURE(sizeof(mpint2) == len);
DO(ssh_decode_sequence_multi(mpint3, sizeof(mpint3),
len = sizeof(mpint3);
DO(ssh_decode_sequence_multi(mpint3, &len,
LTC_SSHDATA_MPINT, v,
LTC_SSHDATA_EOL, NULL));
if (mp_cmp_d(v, 0x80) != LTC_MP_EQ) return CRYPT_FAIL_TESTVECTOR;
ENSURE(mp_cmp_d(v, 0x80) == LTC_MP_EQ);
ENSURE(sizeof(mpint3) == len);
mp_clear_multi(v, u, NULL);
/* name-list */
zeromem(strbuf, BUFSIZE);
DO(ssh_decode_sequence_multi(nlist1, sizeof(nlist1),
LTC_SSHDATA_NAMELIST, strbuf, BUFSIZE,
size = BUFSIZE;
len = sizeof(nlist1);
DO(ssh_decode_sequence_multi(nlist1, &len,
LTC_SSHDATA_NAMELIST, strbuf, &size,
LTC_SSHDATA_EOL, NULL));
if (XSTRCMP(strbuf, "") != 0) return CRYPT_FAIL_TESTVECTOR;
ENSURE(strlen("") == size);
ENSURE(XSTRCMP(strbuf, "") == 0);
zeromem(strbuf, BUFSIZE);
DO(ssh_decode_sequence_multi(nlist2, sizeof(nlist2),
LTC_SSHDATA_NAMELIST, strbuf, BUFSIZE,
size = BUFSIZE;
len = sizeof(nlist2);
DO(ssh_decode_sequence_multi(nlist2, &len,
LTC_SSHDATA_NAMELIST, strbuf, &size,
LTC_SSHDATA_EOL, NULL));
if (XSTRCMP(strbuf, "zlib") != 0) return CRYPT_FAIL_TESTVECTOR;
ENSURE(strlen("zlib") == size);
ENSURE(XSTRCMP(strbuf, "zlib") == 0);
ENSURE(strlen("zlib") + 4 == len);
zeromem(strbuf, BUFSIZE);
DO(ssh_decode_sequence_multi(nlist3, sizeof(nlist3),
LTC_SSHDATA_NAMELIST, strbuf, BUFSIZE,
size = BUFSIZE;
len = sizeof(nlist3);
DO(ssh_decode_sequence_multi(nlist3, &len,
LTC_SSHDATA_NAMELIST, strbuf, &size,
LTC_SSHDATA_EOL, NULL));
if (XSTRCMP(strbuf, "zlib,none") != 0) return CRYPT_FAIL_TESTVECTOR;
ENSURE(strlen("zlib,none") == size);
ENSURE(XSTRCMP(strbuf, "zlib,none") == 0);
ENSURE(strlen("zlib,none") + 4 == len);
return CRYPT_OK;