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