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_encode_sequence_multi.c
15    SSH data type representation as per RFC4251, Russ Williams
16 */
17 
18 #ifdef LTC_SSH
19 
20 /**
21   Encode a SSH sequence using a VA list
22   @param out    [out] Destination for data
23   @param outlen [in/out] Length of buffer and resulting length of output
24   @remark <...> is of the form <type, data> (int, void*)
25   @return CRYPT_OK on success
26 */
ssh_encode_sequence_multi(unsigned char * out,unsigned long * outlen,...)27 int ssh_encode_sequence_multi(unsigned char *out, unsigned long *outlen, ...)
28 {
29    int           err;
30    va_list       args;
31    ulong32       size;
32    ssh_data_type type;
33    void         *vdata;
34    const char   *sdata;
35    int           idata;
36    ulong32       u32data;
37    ulong64       u64data;
38 
39    LTC_ARGCHK(out    != NULL);
40    LTC_ARGCHK(outlen != NULL);
41 
42    /* Check values and calculate output size */
43    size = 0;
44    va_start(args, outlen);
45    while ((type = (ssh_data_type)va_arg(args, int)) != LTC_SSHDATA_EOL) {
46       switch (type) {
47          case LTC_SSHDATA_BYTE:
48          case LTC_SSHDATA_BOOLEAN: /* Both stored as 1 byte */
49             LTC_UNUSED_PARAM( va_arg(args, int) );
50             size++;
51             break;
52          case LTC_SSHDATA_UINT32:
53             LTC_UNUSED_PARAM( va_arg(args, ulong32) );
54             size += 4;
55             break;
56          case LTC_SSHDATA_UINT64:
57             LTC_UNUSED_PARAM( va_arg(args, ulong64) );
58             size += 8;
59             break;
60          case LTC_SSHDATA_STRING:
61          case LTC_SSHDATA_NAMELIST:
62             sdata = va_arg(args, char*);
63             size += 4;
64             size += strlen(sdata);
65             break;
66          case LTC_SSHDATA_MPINT:
67             vdata = va_arg(args, void*);
68             /* Calculate size */
69             size += 4;
70             if (mp_iszero(vdata) != LTC_MP_YES) {
71                size += mp_unsigned_bin_size(vdata);
72                if ((mp_count_bits(vdata) & 7) == 0) size++; /* Zero padding if high bit set */
73             }
74             break;
75 
76          case LTC_SSHDATA_EOL: /* Should never get here */
77 	 default:
78             err = CRYPT_INVALID_ARG;
79             goto error;
80       }
81    }
82    va_end(args);
83 
84    /* Check we have sufficient space */
85    if (*outlen < size) {
86       *outlen = size;
87       err = CRYPT_BUFFER_OVERFLOW;
88       goto errornoargs;
89    }
90    *outlen = size;
91 
92    /* Encode values into buffer */
93    va_start(args, outlen);
94    while ((type = (ssh_data_type)va_arg(args, int)) != LTC_SSHDATA_EOL) {
95       switch (type) {
96          case LTC_SSHDATA_BYTE:
97             idata = va_arg(args, int);
98 
99             *out++ = (unsigned char)(idata & 255);
100             break;
101          case LTC_SSHDATA_BOOLEAN:
102             idata = va_arg(args, int);
103 
104             /*
105                The value 0 represents FALSE, and the value 1 represents TRUE.  All non-zero values MUST be
106                interpreted as TRUE; however, applications MUST NOT store values other than 0 and 1.
107             */
108             *out++ = (idata)?1:0;
109             break;
110          case LTC_SSHDATA_UINT32:
111             u32data = va_arg(args, ulong32);
112             STORE32H(u32data, out);
113             out += 4;
114             break;
115          case LTC_SSHDATA_UINT64:
116             u64data = va_arg(args, ulong64);
117             STORE64H(u64data, out);
118             out += 8;
119             break;
120          case LTC_SSHDATA_STRING:
121          case LTC_SSHDATA_NAMELIST:
122             sdata = va_arg(args, char*);
123             size = strlen(sdata);
124             STORE32H(size, out);
125             out += 4;
126             XMEMCPY(out, sdata, size);
127             out += size;
128             break;
129          case LTC_SSHDATA_MPINT:
130             vdata = va_arg(args, void*);
131             if (mp_iszero(vdata) == LTC_MP_YES) {
132                STORE32H(0, out);
133                out += 4;
134             } else {
135                size = mp_unsigned_bin_size(vdata);
136                if ((mp_count_bits(vdata) & 7) == 0) {
137                   /* Zero padding if high bit set */
138                   STORE32H(size+1, out);
139                   out += 4;
140                   *out++ = 0;
141                } else {
142                   STORE32H(size, out);
143                   out += 4;
144                }
145                if ((err = mp_to_unsigned_bin(vdata, out)) != CRYPT_OK) {
146                   err = CRYPT_ERROR;
147                   goto error;
148                }
149                out += size;
150             }
151             break;
152 
153          case LTC_SSHDATA_EOL: /* Should never get here */
154 	 default:
155             err = CRYPT_INVALID_ARG;
156             goto error;
157       }
158    }
159    err = CRYPT_OK;
160 
161 error:
162    va_end(args);
163 errornoargs:
164    return err;
165 }
166 
167 #endif
168 
169 /* ref:         $Format:%D$ */
170 /* git commit:  $Format:%H$ */
171 /* commit time: $Format:%ai$ */
172