Skip to content

Commit 27ec31d

Browse files
committed
improve SSH decoding & doc
1 parent c13dc10 commit 27ec31d

File tree

7 files changed

+134
-29
lines changed

7 files changed

+134
-29
lines changed

doc/crypt.tex

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7233,6 +7233,71 @@ \subsection{HKDF Extract-and-Expand}
72337233

72347234
Parameters are as in \textit{hkdf\_extract()} and \textit{hkdf\_expand()}.
72357235

7236+
7237+
\mysection{SSH}
7238+
7239+
The library provides functions to encode and decode SSH data as specified in RFC4251 Ch. 5.
7240+
7241+
\subsection{Data types}
7242+
7243+
The following enum is used to indicate a specific SSH data type
7244+
(besides EOL which is an internal one that indicates the end of a sequence).
7245+
7246+
\begin{figure}[h]
7247+
\begin{center}
7248+
\begin{small}
7249+
\begin{tabular}{|l|l|l|}
7250+
\hline \textbf{Definition} & \textbf{arg data Type} & \textbf{SSH Type} \\
7251+
\hline LTC\_SSHDATA\_EOL & - & End of SSH data sequence. \\
7252+
\hline LTC\_SSHDATA\_BYTE & \texttt{unsigned char} & \texttt{byte} type \\
7253+
\hline LTC\_SSHDATA\_BOOLEAN & \texttt{unsigned char} & \texttt{boolean} type \\
7254+
\hline LTC\_SSHDATA\_UINT32 & \texttt{ulong32} & \texttt{uint32} \\
7255+
\hline LTC\_SSHDATA\_UINT64 & \texttt{ulong64} & \texttt{uint64} \\
7256+
\hline LTC\_SSHDATA\_STRING & \texttt{char*} & \texttt{string} (one octet per char) \\
7257+
\hline LTC\_SSHDATA\_MPINT & \texttt{mp\_int} & \texttt{mpint} \\
7258+
\hline LTC\_SSHDATA\_NAMELIST & \texttt{char*} & \texttt{name-list} (which works exactly like a \texttt{string}) \\
7259+
\hline
7260+
\end{tabular}
7261+
\caption{List of SSH Supported Types}
7262+
\index{ssh\_data\_type}
7263+
\end{small}
7264+
\end{center}
7265+
\end{figure}
7266+
7267+
\subsection{De- and Encoding with Multiple Argument Lists}
7268+
7269+
\index{ssh\_encode\_sequence\_multi()}
7270+
\index{ssh\_decode\_sequence\_multi()}
7271+
7272+
7273+
The API works similar to the ASN.1 SEQUENCE multi en- and decoders.
7274+
7275+
They either encode or decode a sequence of the supported SSH types where the items are specified after the length parameter.
7276+
7277+
7278+
\begin{verbatim}
7279+
int ssh_encode_sequence_multi(unsigned char *out, unsigned long *outlen, ...);
7280+
\end{verbatim}
7281+
7282+
Where \texttt{out} points to the destination buffer and \texttt{outlen} points
7283+
on function invocation to the length of the destination buffer
7284+
and after returning it will be filled with the number of octets written to the buffer.
7285+
7286+
The encoding function \texttt{ssh\_encode\_sequence\_multi()} expects its items to be a pair of \texttt{(type, data)},
7287+
except for the \texttt{string} resp. \texttt{name-list} type, which expects the triple \texttt{(type, data, size)}.
7288+
7289+
7290+
\begin{verbatim}
7291+
int ssh_decode_sequence_multi(const unsigned char *in, unsigned long *inlen, ...);
7292+
\end{verbatim}
7293+
7294+
Where \texttt{in} points to the buffer with the sequence to decode and \texttt{inlen} points
7295+
on function invocation to the length of the sequence
7296+
and after returning it will be filled with the decoded number of octets.
7297+
7298+
The decoding function \texttt{ssh\_decode\_sequence\_multi()} expects its items to be a pair of \texttt{(type, data*)},
7299+
except for the \texttt{string} resp. \texttt{name-list} type, which expects the triple \texttt{(type, data, size*)}.
7300+
72367301
\chapter{Miscellaneous}
72377302
\mysection{Base64 Encoding and Decoding}
72387303
The library provides functions to encode and decode a RFC 4648 Base64 coding scheme.

src/headers/tomcrypt_misc.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ typedef enum ssh_data_type_ {
175175

176176
/* VA list handy helpers with tuples of <type, data> */
177177
int ssh_encode_sequence_multi(unsigned char *out, unsigned long *outlen, ...);
178-
int ssh_decode_sequence_multi(const unsigned char *in, unsigned long inlen, ...);
178+
int ssh_decode_sequence_multi(const unsigned char *in, unsigned long *inlen, ...);
179179
#endif /* LTC_SSH */
180180

181181
int compare_testvector(const void* is, const unsigned long is_len, const void* should, const unsigned long should_len, const char* what, int which);

src/misc/ssh/ssh_decode_sequence_multi.c

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@
1818

1919
/**
2020
Decode a SSH sequence using a VA list
21-
@param in Data to decode
22-
@param inlen Length of buffer to decode
23-
@remark <...> is of the form <type, data> (int, void*) except for string <type, data, size> (int, void*, ulong32*)
21+
@param in The input buffer
22+
@param inlen [in/out] The length of the input buffer and on output the amount of decoded data
23+
@remark <...> is of the form <type, data*> (int, <unsigned char*,ulong32*,ulong64*>) except for string&name-list <type, data, size*> (int, void*, ulong32*)
2424
@return CRYPT_OK on success
2525
*/
26-
int ssh_decode_sequence_multi(const unsigned char *in, unsigned long inlen, ...)
26+
int ssh_decode_sequence_multi(const unsigned char *in, unsigned long *inlen, ...)
2727
{
2828
int err;
2929
va_list args;
@@ -35,9 +35,12 @@ int ssh_decode_sequence_multi(const unsigned char *in, unsigned long inlen, ...)
3535
ulong64 *u64data;
3636
ulong32 *bufsize;
3737
ulong32 size;
38+
unsigned long remaining;
3839

3940
LTC_ARGCHK(in != NULL);
41+
LTC_ARGCHK(inlen != NULL);
4042

43+
remaining = *inlen;
4144
/* Decode values from buffer */
4245
va_start(args, inlen);
4346
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, ...)
4750
type == LTC_SSHDATA_MPINT)
4851
{
4952
/* Check we'll not read too far */
50-
if (inlen < 4) {
53+
if (remaining < 4) {
5154
err = CRYPT_BUFFER_OVERFLOW;
5255
goto error;
5356
}
@@ -71,7 +74,7 @@ int ssh_decode_sequence_multi(const unsigned char *in, unsigned long inlen, ...)
7174
case LTC_SSHDATA_MPINT:
7275
LOAD32H(size, in);
7376
in += 4;
74-
inlen -= 4;
77+
remaining -= 4;
7578
break;
7679

7780
case LTC_SSHDATA_EOL:
@@ -81,11 +84,11 @@ int ssh_decode_sequence_multi(const unsigned char *in, unsigned long inlen, ...)
8184
}
8285

8386
/* Check we'll not read too far */
84-
if (inlen < size) {
87+
if (remaining < size) {
8588
err = CRYPT_BUFFER_OVERFLOW;
8689
goto error;
8790
} else {
88-
inlen -= size;
91+
remaining -= size;
8992
}
9093

9194
vdata = va_arg(args, void*);
@@ -105,7 +108,7 @@ int ssh_decode_sequence_multi(const unsigned char *in, unsigned long inlen, ...)
105108
/*
106109
The value 0 represents FALSE, and the value 1 represents TRUE. All non-zero values MUST be
107110
interpreted as TRUE; however, applications MUST NOT store values other than 0 and 1.
108-
*/
111+
*/
109112
*cdata = (*in++)?1:0;
110113
break;
111114
case LTC_SSHDATA_UINT32:
@@ -158,6 +161,8 @@ int ssh_decode_sequence_multi(const unsigned char *in, unsigned long inlen, ...)
158161
}
159162
err = CRYPT_OK;
160163

164+
*inlen -= remaining;
165+
161166
error:
162167
va_end(args);
163168
return err;

src/misc/ssh/ssh_encode_sequence_multi.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
Encode a SSH sequence using a VA list
2121
@param out [out] Destination for data
2222
@param outlen [in/out] Length of buffer and resulting length of output
23-
@remark <...> is of the form <type, data> (int, void*) except for string <type, data, size> (int, void*, ulong32)
23+
@remark <...> is of the form <type, data> (int, <int,ulong32,ulong64>) except for string&name-list <type, data, size> (int, void*, ulong32)
2424
@return CRYPT_OK on success
2525
*/
2626
int ssh_encode_sequence_multi(unsigned char *out, unsigned long *outlen, ...)
@@ -32,7 +32,6 @@ int ssh_encode_sequence_multi(unsigned char *out, unsigned long *outlen, ...)
3232
void *vdata;
3333
const char *sdata;
3434
int idata;
35-
ulong32 *psize;
3635
ulong32 u32data;
3736
ulong64 u64data;
3837

@@ -103,7 +102,7 @@ int ssh_encode_sequence_multi(unsigned char *out, unsigned long *outlen, ...)
103102
/*
104103
The value 0 represents FALSE, and the value 1 represents TRUE. All non-zero values MUST be
105104
interpreted as TRUE; however, applications MUST NOT store values other than 0 and 1.
106-
*/
105+
*/
107106
*out++ = (idata)?1:0;
108107
break;
109108
case LTC_SSHDATA_UINT32:

src/pk/ecc/ecc_recover_key.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ int ecc_recover_key(const unsigned char *sig, unsigned long siglen,
118118
ulong32 name2len = sizeof(name2);
119119

120120
/* Decode as SSH data sequence, per RFC4251 */
121-
if ((err = ssh_decode_sequence_multi(sig, siglen,
121+
if ((err = ssh_decode_sequence_multi(sig, &siglen,
122122
LTC_SSHDATA_STRING, name, &namelen,
123123
LTC_SSHDATA_MPINT, r,
124124
LTC_SSHDATA_MPINT, s,

src/pk/ecc/ecc_verify_hash.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ int ecc_verify_hash_ex(const unsigned char *sig, unsigned long siglen,
104104
ulong32 name2len = sizeof(name2);
105105

106106
/* Decode as SSH data sequence, per RFC4251 */
107-
if ((err = ssh_decode_sequence_multi(sig, siglen,
107+
if ((err = ssh_decode_sequence_multi(sig, &siglen,
108108
LTC_SSHDATA_STRING, name, &namelen,
109109
LTC_SSHDATA_MPINT, r,
110110
LTC_SSHDATA_MPINT, s,

tests/ssh_test.c

Lines changed: 50 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -204,98 +204,134 @@ static int _ssh_decoding_test(void)
204204
ulong32 tmp32;
205205
ulong64 tmp64;
206206
unsigned char tmp8;
207+
unsigned long len;
207208
int err;
208209

210+
/* Buffer longer */
211+
len = sizeof(strbuf);
212+
strbuf[0] = 0;
213+
DO(ssh_decode_sequence_multi((unsigned char*)strbuf, &len,
214+
LTC_SSHDATA_BYTE, &tmp8,
215+
LTC_SSHDATA_EOL, NULL));
216+
ENSURE(tmp8 == 0x00);
217+
ENSURE(len == 1);
218+
219+
209220
/* byte */
210-
DO(ssh_decode_sequence_multi(byte1, sizeof(byte1),
221+
len = sizeof(byte1);
222+
DO(ssh_decode_sequence_multi(byte1, &len,
211223
LTC_SSHDATA_BYTE, &tmp8,
212224
LTC_SSHDATA_EOL, NULL));
213225
ENSURE(tmp8 == 0x01);
226+
ENSURE(len == 1);
214227

215-
DO(ssh_decode_sequence_multi(byte2, sizeof(byte2),
228+
len = sizeof(byte2);
229+
DO(ssh_decode_sequence_multi(byte2, &len,
216230
LTC_SSHDATA_BYTE, &tmp8,
217231
LTC_SSHDATA_EOL, NULL));
218232
ENSURE(tmp8 == 0x71);
233+
ENSURE(len == 1);
219234

220235
/* boolean */
221-
DO(ssh_decode_sequence_multi(byte1, sizeof(byte1),
236+
len = sizeof(byte1);
237+
DO(ssh_decode_sequence_multi(byte1, &len,
222238
LTC_SSHDATA_BOOLEAN, &tmp8,
223239
LTC_SSHDATA_EOL, NULL));
224240
ENSURE(tmp8 == 0x01);
241+
ENSURE(len == 1);
225242

226-
DO(ssh_decode_sequence_multi(byte2, sizeof(byte2),
243+
len = sizeof(byte2);
244+
DO(ssh_decode_sequence_multi(byte2, &len,
227245
LTC_SSHDATA_BOOLEAN, &tmp8,
228246
LTC_SSHDATA_EOL, NULL));
229247
ENSURE(tmp8 == 0x01);
248+
ENSURE(len == 1);
230249

231250
/* uint32 */
232-
DO(ssh_decode_sequence_multi(uint32, sizeof(uint32),
251+
len = sizeof(uint32);
252+
DO(ssh_decode_sequence_multi(uint32, &len,
233253
LTC_SSHDATA_UINT32, &tmp32,
234254
LTC_SSHDATA_EOL, NULL));
235255
ENSURE(tmp32 == 0x29b7f4aa);
256+
ENSURE(len == 4);
236257

237258
/* uint64 */
238-
DO(ssh_decode_sequence_multi(uint64, sizeof(uint64),
259+
len = sizeof(uint64);
260+
DO(ssh_decode_sequence_multi(uint64, &len,
239261
LTC_SSHDATA_UINT64, &tmp64,
240262
LTC_SSHDATA_EOL, NULL));
241263
if (tmp64 != CONST64(0x09a378f9b2e332a7)) return CRYPT_FAIL_TESTVECTOR;
264+
ENSURE(len == 8);
242265

243266
/* string */
244267
zeromem(strbuf, BUFSIZE);
245268
size = BUFSIZE;
246-
DO(ssh_decode_sequence_multi(string, sizeof(string),
269+
len = sizeof(string);
270+
DO(ssh_decode_sequence_multi(string, &len,
247271
LTC_SSHDATA_STRING, strbuf, &size,
248272
LTC_SSHDATA_EOL, NULL));
249273
ENSURE(strlen("testing") == size);
250274
ENSURE(XSTRCMP(strbuf, "testing") == 0);
275+
ENSURE(strlen("testing") + 4 == len);
251276

252277
/* mpint */
253278
if ((err = mp_init_multi(&u, &v, NULL)) != CRYPT_OK) {
254279
return err;
255280
}
256281

257-
DO(ssh_decode_sequence_multi(mpint1, sizeof(mpint1),
282+
len = sizeof(mpint1);
283+
DO(ssh_decode_sequence_multi(mpint1, &len,
258284
LTC_SSHDATA_MPINT, v,
259285
LTC_SSHDATA_EOL, NULL));
260286
ENSURE(mp_cmp_d(v, 0) == LTC_MP_EQ);
287+
ENSURE(sizeof(mpint1) == len);
261288

262-
DO(mp_read_radix(u, "9a378f9b2e332a7", 16));
263-
DO(ssh_decode_sequence_multi(mpint2, sizeof(mpint2),
289+
len = sizeof(mpint2);
290+
DO(ssh_decode_sequence_multi(mpint2, &len,
264291
LTC_SSHDATA_MPINT, v,
265292
LTC_SSHDATA_EOL, NULL));
293+
DO(mp_read_radix(u, "9a378f9b2e332a7", 16));
266294
ENSURE(mp_cmp(u, v) == LTC_MP_EQ);
295+
ENSURE(sizeof(mpint2) == len);
267296

268-
DO(ssh_decode_sequence_multi(mpint3, sizeof(mpint3),
297+
len = sizeof(mpint3);
298+
DO(ssh_decode_sequence_multi(mpint3, &len,
269299
LTC_SSHDATA_MPINT, v,
270300
LTC_SSHDATA_EOL, NULL));
271301
ENSURE(mp_cmp_d(v, 0x80) == LTC_MP_EQ);
302+
ENSURE(sizeof(mpint3) == len);
272303

273304
mp_clear_multi(v, u, NULL);
274305

275306
/* name-list */
276307
zeromem(strbuf, BUFSIZE);
277308
size = BUFSIZE;
278-
DO(ssh_decode_sequence_multi(nlist1, sizeof(nlist1),
309+
len = sizeof(nlist1);
310+
DO(ssh_decode_sequence_multi(nlist1, &len,
279311
LTC_SSHDATA_NAMELIST, strbuf, &size,
280312
LTC_SSHDATA_EOL, NULL));
281313
ENSURE(strlen("") == size);
282314
ENSURE(XSTRCMP(strbuf, "") == 0);
283315

284316
zeromem(strbuf, BUFSIZE);
285317
size = BUFSIZE;
286-
DO(ssh_decode_sequence_multi(nlist2, sizeof(nlist2),
318+
len = sizeof(nlist2);
319+
DO(ssh_decode_sequence_multi(nlist2, &len,
287320
LTC_SSHDATA_NAMELIST, strbuf, &size,
288321
LTC_SSHDATA_EOL, NULL));
289322
ENSURE(strlen("zlib") == size);
290323
ENSURE(XSTRCMP(strbuf, "zlib") == 0);
324+
ENSURE(strlen("zlib") + 4 == len);
291325

292326
zeromem(strbuf, BUFSIZE);
293327
size = BUFSIZE;
294-
DO(ssh_decode_sequence_multi(nlist3, sizeof(nlist3),
328+
len = sizeof(nlist3);
329+
DO(ssh_decode_sequence_multi(nlist3, &len,
295330
LTC_SSHDATA_NAMELIST, strbuf, &size,
296331
LTC_SSHDATA_EOL, NULL));
297332
ENSURE(strlen("zlib,none") == size);
298333
ENSURE(XSTRCMP(strbuf, "zlib,none") == 0);
334+
ENSURE(strlen("zlib,none") + 4 == len);
299335

300336

301337
return CRYPT_OK;

0 commit comments

Comments
 (0)