Browse Source

improve SSH decoding & doc

Steffen Jaeckel 6 years ago
parent
commit
27ec31d4f3

+ 65 - 0
doc/crypt.tex

@@ -7233,6 +7233,71 @@ int hkdf(           int  hash_idx,
 
 
 Parameters are as in \textit{hkdf\_extract()} and \textit{hkdf\_expand()}.
 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)}.
+
+
+\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*)}.
+
 \chapter{Miscellaneous}
 \chapter{Miscellaneous}
 \mysection{Base64 Encoding and Decoding}
 \mysection{Base64 Encoding and Decoding}
 The library provides functions to encode and decode a RFC 4648 Base64 coding scheme.
 The library provides functions to encode and decode a RFC 4648 Base64 coding scheme.

+ 1 - 1
src/headers/tomcrypt_misc.h

@@ -175,7 +175,7 @@ typedef enum ssh_data_type_ {
 
 
 /* VA list handy helpers with tuples of <type, data> */
 /* VA list handy helpers with tuples of <type, data> */
 int ssh_encode_sequence_multi(unsigned char *out, unsigned long *outlen, ...);
 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 */
 #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);
 int compare_testvector(const void* is, const unsigned long is_len, const void* should, const unsigned long should_len, const char* what, int which);

+ 14 - 9
src/misc/ssh/ssh_decode_sequence_multi.c

@@ -18,12 +18,12 @@
 
 
 /**
 /**
   Decode a SSH sequence using a VA list
   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> (int, void*, ulong32*)
+  @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*, ulong32*)
   @return CRYPT_OK on success
   @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;
    int           err;
    va_list       args;
    va_list       args;
@@ -35,9 +35,12 @@ int ssh_decode_sequence_multi(const unsigned char *in, unsigned long inlen, ...)
    ulong64       *u64data;
    ulong64       *u64data;
    ulong32       *bufsize;
    ulong32       *bufsize;
    ulong32       size;
    ulong32       size;
+   unsigned long remaining;
 
 
    LTC_ARGCHK(in    != NULL);
    LTC_ARGCHK(in    != NULL);
+   LTC_ARGCHK(inlen != NULL);
 
 
+   remaining = *inlen;
    /* Decode values from buffer */
    /* Decode values from buffer */
    va_start(args, inlen);
    va_start(args, inlen);
    while ((type = (ssh_data_type)va_arg(args, int)) != LTC_SSHDATA_EOL) {
    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)
           type == LTC_SSHDATA_MPINT)
       {
       {
          /* Check we'll not read too far */
          /* Check we'll not read too far */
-         if (inlen < 4) {
+         if (remaining < 4) {
             err = CRYPT_BUFFER_OVERFLOW;
             err = CRYPT_BUFFER_OVERFLOW;
             goto error;
             goto error;
          }
          }
@@ -71,7 +74,7 @@ int ssh_decode_sequence_multi(const unsigned char *in, unsigned long inlen, ...)
          case LTC_SSHDATA_MPINT:
          case LTC_SSHDATA_MPINT:
             LOAD32H(size, in);
             LOAD32H(size, in);
             in += 4;
             in += 4;
-            inlen -= 4;
+            remaining -= 4;
             break;
             break;
 
 
          case LTC_SSHDATA_EOL:
          case LTC_SSHDATA_EOL:
@@ -81,11 +84,11 @@ int ssh_decode_sequence_multi(const unsigned char *in, unsigned long inlen, ...)
       }
       }
 
 
       /* Check we'll not read too far */
       /* Check we'll not read too far */
-      if (inlen < size) {
+      if (remaining < size) {
          err = CRYPT_BUFFER_OVERFLOW;
          err = CRYPT_BUFFER_OVERFLOW;
          goto error;
          goto error;
       } else {
       } else {
-         inlen -= size;
+         remaining -= size;
       }
       }
 
 
       vdata = va_arg(args, void*);
       vdata = va_arg(args, void*);
@@ -105,7 +108,7 @@ int ssh_decode_sequence_multi(const unsigned char *in, unsigned long inlen, ...)
             /*
             /*
                The value 0 represents FALSE, and the value 1 represents TRUE.  All non-zero values MUST be
                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.
                interpreted as TRUE; however, applications MUST NOT store values other than 0 and 1.
-            */
+             */
             *cdata = (*in++)?1:0;
             *cdata = (*in++)?1:0;
             break;
             break;
          case LTC_SSHDATA_UINT32:
          case LTC_SSHDATA_UINT32:
@@ -158,6 +161,8 @@ int ssh_decode_sequence_multi(const unsigned char *in, unsigned long inlen, ...)
    }
    }
    err = CRYPT_OK;
    err = CRYPT_OK;
 
 
+   *inlen -= remaining;
+
 error:
 error:
    va_end(args);
    va_end(args);
    return err;
    return err;

+ 2 - 3
src/misc/ssh/ssh_encode_sequence_multi.c

@@ -20,7 +20,7 @@
   Encode a SSH sequence using a VA list
   Encode a SSH sequence using a VA list
   @param out    [out] Destination for data
   @param out    [out] Destination for data
   @param outlen [in/out] Length of buffer and resulting length of output
   @param outlen [in/out] Length of buffer and resulting length of output
-  @remark <...> is of the form <type, data> (int, void*) except for string <type, data, size> (int, void*, ulong32)
+  @remark <...> is of the form <type, data> (int, <int,ulong32,ulong64>) except for string&name-list <type, data, size> (int, void*, ulong32)
   @return CRYPT_OK on success
   @return CRYPT_OK on success
 */
 */
 int ssh_encode_sequence_multi(unsigned char *out, unsigned long *outlen, ...)
 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, ...)
    void          *vdata;
    void          *vdata;
    const char    *sdata;
    const char    *sdata;
    int           idata;
    int           idata;
-   ulong32       *psize;
    ulong32       u32data;
    ulong32       u32data;
    ulong64       u64data;
    ulong64       u64data;
 
 
@@ -103,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
                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.
                interpreted as TRUE; however, applications MUST NOT store values other than 0 and 1.
-            */
+             */
             *out++ = (idata)?1:0;
             *out++ = (idata)?1:0;
             break;
             break;
          case LTC_SSHDATA_UINT32:
          case LTC_SSHDATA_UINT32:

+ 1 - 1
src/pk/ecc/ecc_recover_key.c

@@ -118,7 +118,7 @@ int ecc_recover_key(const unsigned char *sig,  unsigned long siglen,
       ulong32 name2len = sizeof(name2);
       ulong32 name2len = sizeof(name2);
 
 
       /* Decode as SSH data sequence, per RFC4251 */
       /* Decode as SSH data sequence, per RFC4251 */
-      if ((err = ssh_decode_sequence_multi(sig, siglen,
+      if ((err = ssh_decode_sequence_multi(sig, &siglen,
                                            LTC_SSHDATA_STRING, name, &namelen,
                                            LTC_SSHDATA_STRING, name, &namelen,
                                            LTC_SSHDATA_MPINT,  r,
                                            LTC_SSHDATA_MPINT,  r,
                                            LTC_SSHDATA_MPINT,  s,
                                            LTC_SSHDATA_MPINT,  s,

+ 1 - 1
src/pk/ecc/ecc_verify_hash.c

@@ -104,7 +104,7 @@ int ecc_verify_hash_ex(const unsigned char *sig,  unsigned long siglen,
       ulong32 name2len = sizeof(name2);
       ulong32 name2len = sizeof(name2);
 
 
       /* Decode as SSH data sequence, per RFC4251 */
       /* Decode as SSH data sequence, per RFC4251 */
-      if ((err = ssh_decode_sequence_multi(sig, siglen,
+      if ((err = ssh_decode_sequence_multi(sig, &siglen,
                                            LTC_SSHDATA_STRING, name, &namelen,
                                            LTC_SSHDATA_STRING, name, &namelen,
                                            LTC_SSHDATA_MPINT,  r,
                                            LTC_SSHDATA_MPINT,  r,
                                            LTC_SSHDATA_MPINT,  s,
                                            LTC_SSHDATA_MPINT,  s,

+ 50 - 14
tests/ssh_test.c

@@ -204,78 +204,110 @@ static int _ssh_decoding_test(void)
    ulong32 tmp32;
    ulong32 tmp32;
    ulong64 tmp64;
    ulong64 tmp64;
    unsigned char tmp8;
    unsigned char tmp8;
+   unsigned long len;
    int err;
    int err;
 
 
+   /* 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));
+   ENSURE(tmp8 == 0x00);
+   ENSURE(len == 1);
+
+
    /* byte */
    /* byte */
-   DO(ssh_decode_sequence_multi(byte1, sizeof(byte1),
+   len = sizeof(byte1);
+   DO(ssh_decode_sequence_multi(byte1, &len,
                                 LTC_SSHDATA_BYTE, &tmp8,
                                 LTC_SSHDATA_BYTE, &tmp8,
                                 LTC_SSHDATA_EOL,  NULL));
                                 LTC_SSHDATA_EOL,  NULL));
    ENSURE(tmp8 == 0x01);
    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_BYTE, &tmp8,
                                 LTC_SSHDATA_BYTE, &tmp8,
                                 LTC_SSHDATA_EOL,  NULL));
                                 LTC_SSHDATA_EOL,  NULL));
    ENSURE(tmp8 == 0x71);
    ENSURE(tmp8 == 0x71);
+   ENSURE(len == 1);
 
 
    /* boolean */
    /* 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_BOOLEAN, &tmp8,
                                 LTC_SSHDATA_EOL,     NULL));
                                 LTC_SSHDATA_EOL,     NULL));
    ENSURE(tmp8 == 0x01);
    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_BOOLEAN, &tmp8,
                                 LTC_SSHDATA_EOL,     NULL));
                                 LTC_SSHDATA_EOL,     NULL));
    ENSURE(tmp8 == 0x01);
    ENSURE(tmp8 == 0x01);
+   ENSURE(len == 1);
 
 
    /* uint32 */
    /* 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_UINT32, &tmp32,
                                 LTC_SSHDATA_EOL,    NULL));
                                 LTC_SSHDATA_EOL,    NULL));
    ENSURE(tmp32 == 0x29b7f4aa);
    ENSURE(tmp32 == 0x29b7f4aa);
+   ENSURE(len == 4);
 
 
    /* uint64 */
    /* 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_UINT64, &tmp64,
                                 LTC_SSHDATA_EOL,    NULL));
                                 LTC_SSHDATA_EOL,    NULL));
    if (tmp64 != CONST64(0x09a378f9b2e332a7)) return CRYPT_FAIL_TESTVECTOR;
    if (tmp64 != CONST64(0x09a378f9b2e332a7)) return CRYPT_FAIL_TESTVECTOR;
+   ENSURE(len == 8);
 
 
    /* string */
    /* string */
    zeromem(strbuf, BUFSIZE);
    zeromem(strbuf, BUFSIZE);
    size = BUFSIZE;
    size = BUFSIZE;
-   DO(ssh_decode_sequence_multi(string, sizeof(string),
+   len = sizeof(string);
+   DO(ssh_decode_sequence_multi(string, &len,
                                 LTC_SSHDATA_STRING, strbuf, &size,
                                 LTC_SSHDATA_STRING, strbuf, &size,
                                 LTC_SSHDATA_EOL,    NULL));
                                 LTC_SSHDATA_EOL,    NULL));
    ENSURE(strlen("testing") == size);
    ENSURE(strlen("testing") == size);
    ENSURE(XSTRCMP(strbuf, "testing") == 0);
    ENSURE(XSTRCMP(strbuf, "testing") == 0);
+   ENSURE(strlen("testing") + 4 == len);
 
 
    /* mpint */
    /* mpint */
    if ((err = mp_init_multi(&u, &v, NULL)) != CRYPT_OK) {
    if ((err = mp_init_multi(&u, &v, NULL)) != CRYPT_OK) {
       return err;
       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_MPINT, v,
                                 LTC_SSHDATA_EOL,   NULL));
                                 LTC_SSHDATA_EOL,   NULL));
    ENSURE(mp_cmp_d(v, 0) == LTC_MP_EQ);
    ENSURE(mp_cmp_d(v, 0) == LTC_MP_EQ);
+   ENSURE(sizeof(mpint1) == len);
 
 
-   DO(mp_read_radix(u, "9a378f9b2e332a7", 16));
-   DO(ssh_decode_sequence_multi(mpint2, sizeof(mpint2),
+   len = sizeof(mpint2);
+   DO(ssh_decode_sequence_multi(mpint2, &len,
                                 LTC_SSHDATA_MPINT, v,
                                 LTC_SSHDATA_MPINT, v,
                                 LTC_SSHDATA_EOL,   NULL));
                                 LTC_SSHDATA_EOL,   NULL));
+   DO(mp_read_radix(u, "9a378f9b2e332a7", 16));
    ENSURE(mp_cmp(u, v) == LTC_MP_EQ);
    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_MPINT, v,
                                 LTC_SSHDATA_EOL,   NULL));
                                 LTC_SSHDATA_EOL,   NULL));
    ENSURE(mp_cmp_d(v, 0x80) == LTC_MP_EQ);
    ENSURE(mp_cmp_d(v, 0x80) == LTC_MP_EQ);
+   ENSURE(sizeof(mpint3) == len);
 
 
    mp_clear_multi(v, u, NULL);
    mp_clear_multi(v, u, NULL);
 
 
    /* name-list */
    /* name-list */
    zeromem(strbuf, BUFSIZE);
    zeromem(strbuf, BUFSIZE);
    size = BUFSIZE;
    size = BUFSIZE;
-   DO(ssh_decode_sequence_multi(nlist1, sizeof(nlist1),
+   len = sizeof(nlist1);
+   DO(ssh_decode_sequence_multi(nlist1, &len,
                                 LTC_SSHDATA_NAMELIST, strbuf, &size,
                                 LTC_SSHDATA_NAMELIST, strbuf, &size,
                                 LTC_SSHDATA_EOL,      NULL));
                                 LTC_SSHDATA_EOL,      NULL));
    ENSURE(strlen("") == size);
    ENSURE(strlen("") == size);
@@ -283,19 +315,23 @@ static int _ssh_decoding_test(void)
 
 
    zeromem(strbuf, BUFSIZE);
    zeromem(strbuf, BUFSIZE);
    size = BUFSIZE;
    size = BUFSIZE;
-   DO(ssh_decode_sequence_multi(nlist2, sizeof(nlist2),
+   len = sizeof(nlist2);
+   DO(ssh_decode_sequence_multi(nlist2, &len,
                                 LTC_SSHDATA_NAMELIST, strbuf, &size,
                                 LTC_SSHDATA_NAMELIST, strbuf, &size,
                                 LTC_SSHDATA_EOL,      NULL));
                                 LTC_SSHDATA_EOL,      NULL));
    ENSURE(strlen("zlib") == size);
    ENSURE(strlen("zlib") == size);
    ENSURE(XSTRCMP(strbuf, "zlib") == 0);
    ENSURE(XSTRCMP(strbuf, "zlib") == 0);
+   ENSURE(strlen("zlib") + 4 == len);
 
 
    zeromem(strbuf, BUFSIZE);
    zeromem(strbuf, BUFSIZE);
    size = BUFSIZE;
    size = BUFSIZE;
-   DO(ssh_decode_sequence_multi(nlist3, sizeof(nlist3),
+   len = sizeof(nlist3);
+   DO(ssh_decode_sequence_multi(nlist3, &len,
                                 LTC_SSHDATA_NAMELIST, strbuf, &size,
                                 LTC_SSHDATA_NAMELIST, strbuf, &size,
                                 LTC_SSHDATA_EOL,      NULL));
                                 LTC_SSHDATA_EOL,      NULL));
    ENSURE(strlen("zlib,none") == size);
    ENSURE(strlen("zlib,none") == size);
    ENSURE(XSTRCMP(strbuf, "zlib,none") == 0);
    ENSURE(XSTRCMP(strbuf, "zlib,none") == 0);
+   ENSURE(strlen("zlib,none") + 4 == len);
 
 
 
 
    return CRYPT_OK;
    return CRYPT_OK;