1 // SPDX-License-Identifier: BSD-2-Clause
2 /* LibTomCrypt, modular cryptographic library -- Tom St Denis
3  *
4  * LibTomCrypt is a library that provides various cryptographic
5  * algorithms in a highly modular and flexible manner.
6  *
7  * The library is free for all purposes without any express
8  * guarantee it works.
9  */
10 #include "tomcrypt_private.h"
11 #include <stdarg.h>
12 
13 /**
14    @file ssh_decode_sequence_multi.c
15    SSH data type representation as per RFC4251, Russ Williams
16 */
17 
18 #ifdef LTC_SSH
19 
20 /**
21   Decode a SSH sequence using a VA list
22   @param in     Data to decode
23   @param inlen  Length of buffer to decode
24   @remark <...> is of the form <type, data> (int, void*) except for string <type, data, size>
25   @return CRYPT_OK on success
26 */
ssh_decode_sequence_multi(const unsigned char * in,unsigned long inlen,...)27 int ssh_decode_sequence_multi(const unsigned char *in, unsigned long inlen, ...)
28 {
29    int           err;
30    va_list       args;
31    ssh_data_type type;
32    void          *vdata;
33    unsigned char *cdata;
34    char          *sdata;
35    ulong32       *u32data;
36    ulong64       *u64data;
37    unsigned long bufsize;
38    ulong32       size;
39 
40    LTC_ARGCHK(in    != NULL);
41 
42    /* Decode values from buffer */
43    va_start(args, inlen);
44    while ((type = (ssh_data_type)va_arg(args, int)) != LTC_SSHDATA_EOL) {
45       /* Size of length field */
46       if (type == LTC_SSHDATA_STRING ||
47           type == LTC_SSHDATA_NAMELIST ||
48           type == LTC_SSHDATA_MPINT)
49       {
50          /* Check we'll not read too far */
51          if (inlen < 4) {
52             err = CRYPT_BUFFER_OVERFLOW;
53             goto error;
54          }
55       }
56 
57       /* Calculate (or read) length of data */
58       size = 0xFFFFFFFFU;
59       switch (type) {
60          case LTC_SSHDATA_BYTE:
61          case LTC_SSHDATA_BOOLEAN:
62             size = 1;
63             break;
64          case LTC_SSHDATA_UINT32:
65             size = 4;
66             break;
67          case LTC_SSHDATA_UINT64:
68             size = 8;
69             break;
70          case LTC_SSHDATA_STRING:
71          case LTC_SSHDATA_NAMELIST:
72          case LTC_SSHDATA_MPINT:
73             LOAD32H(size, in);
74             in += 4;
75             inlen -= 4;
76             break;
77 
78          case LTC_SSHDATA_EOL:
79          default:
80             /* Should never get here */
81             err = CRYPT_INVALID_ARG;
82             goto error;
83       }
84 
85       /* Check we'll not read too far */
86       if (inlen < size) {
87          err = CRYPT_BUFFER_OVERFLOW;
88          goto error;
89       } else {
90          inlen -= size;
91       }
92 
93       /* Read data */
94       switch (type) {
95          case LTC_SSHDATA_BYTE:
96             cdata = va_arg(args, unsigned char*);
97             *cdata = *in++;
98             break;
99          case LTC_SSHDATA_BOOLEAN:
100             cdata = va_arg(args, unsigned char*);
101             /*
102                The value 0 represents FALSE, and the value 1 represents TRUE.  All non-zero values MUST be
103                interpreted as TRUE; however, applications MUST NOT store values other than 0 and 1.
104             */
105             *cdata = (*in++)?1:0;
106             break;
107          case LTC_SSHDATA_UINT32:
108             u32data = va_arg(args, ulong32*);
109             LOAD32H(*u32data, in);
110             in += 4;
111             break;
112          case LTC_SSHDATA_UINT64:
113             u64data = va_arg(args, ulong64*);
114             LOAD64H(*u64data, in);
115             in += 8;
116             break;
117          case LTC_SSHDATA_STRING:
118          case LTC_SSHDATA_NAMELIST:
119             sdata = va_arg(args, char*);
120             bufsize = va_arg(args, unsigned long);
121             if (size >= bufsize) {
122                err = CRYPT_BUFFER_OVERFLOW;
123                goto error;
124             }
125             if (size > 0) {
126                XSTRNCPY(sdata, (const char *)in, size);
127                sdata[size] = '\0'; /* strncpy doesn't NUL-terminate */
128             } else {
129                *sdata = '\0';
130             }
131             in += size;
132             break;
133          case LTC_SSHDATA_MPINT:
134             vdata = va_arg(args, void*);
135             if (size == 0) {
136                if ((err = mp_set(vdata, 0)) != CRYPT_OK)                                                { goto error; }
137             } else if ((in[0] & 0x80) != 0) {
138                /* Negative number - not supported */
139                err = CRYPT_INVALID_PACKET;
140                goto error;
141             } else {
142                if ((err = mp_read_unsigned_bin(vdata, (unsigned char *)in, size)) != CRYPT_OK)          { goto error; }
143             }
144             in += size;
145             break;
146 
147          case LTC_SSHDATA_EOL:
148          default:
149             /* Should never get here */
150             err = CRYPT_INVALID_ARG;
151             goto error;
152       }
153    }
154    err = CRYPT_OK;
155 
156 error:
157    va_end(args);
158    return err;
159 }
160 
161 #endif
162 
163 /* ref:         $Format:%D$ */
164 /* git commit:  $Format:%H$ */
165 /* commit time: $Format:%ai$ */
166