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