forked from libtom/libtomcrypt
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathssh_decode_sequence_multi.c
More file actions
164 lines (150 loc) · 4.59 KB
/
ssh_decode_sequence_multi.c
File metadata and controls
164 lines (150 loc) · 4.59 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file ssh_decode_sequence_multi.c
SSH data type representation as per RFC4251, Russ Williams
*/
#ifdef LTC_SSH
/**
Decode a SSH sequence using a VA list
@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*, unsigned long*)
@return CRYPT_OK on success
*/
int ssh_decode_sequence_multi(const unsigned char *in, unsigned long *inlen, ...)
{
int err;
va_list args;
ssh_data_type type;
void *vdata;
unsigned char *cdata;
char *sdata;
ulong32 *u32data;
ulong64 *u64data;
unsigned long *bufsize;
ulong32 size;
unsigned long remaining;
LTC_ARGCHK(in != NULL);
LTC_ARGCHK(inlen != NULL);
remaining = *inlen;
/* Decode values from buffer */
va_start(args, inlen);
while ((type = (ssh_data_type)va_arg(args, int)) != LTC_SSHDATA_EOL) {
/* Size of length field */
if (type == LTC_SSHDATA_STRING ||
type == LTC_SSHDATA_NAMELIST ||
type == LTC_SSHDATA_MPINT)
{
/* Check we'll not read too far */
if (remaining < 4) {
err = CRYPT_BUFFER_OVERFLOW;
goto error;
}
}
/* Calculate (or read) length of data */
size = 0xFFFFFFFFU;
switch (type) {
case LTC_SSHDATA_BYTE:
case LTC_SSHDATA_BOOLEAN:
size = 1;
break;
case LTC_SSHDATA_UINT32:
size = 4;
break;
case LTC_SSHDATA_UINT64:
size = 8;
break;
case LTC_SSHDATA_STRING:
case LTC_SSHDATA_NAMELIST:
case LTC_SSHDATA_MPINT:
LOAD32H(size, in);
in += 4;
remaining -= 4;
break;
case LTC_SSHDATA_EOL:
/* Should never get here */
err = CRYPT_INVALID_ARG;
goto error;
}
/* Check we'll not read too far */
if (remaining < size) {
err = CRYPT_BUFFER_OVERFLOW;
goto error;
} else {
remaining -= size;
}
vdata = va_arg(args, void*);
if (vdata == NULL) {
err = CRYPT_INVALID_ARG;
goto error;
}
/* Read data */
switch (type) {
case LTC_SSHDATA_BYTE:
cdata = vdata;
*cdata = *in++;
break;
case LTC_SSHDATA_BOOLEAN:
cdata = vdata;
/*
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.
*/
*cdata = (*in++)?1:0;
break;
case LTC_SSHDATA_UINT32:
u32data = vdata;
LOAD32H(*u32data, in);
in += 4;
break;
case LTC_SSHDATA_UINT64:
u64data = vdata;
LOAD64H(*u64data, in);
in += 8;
break;
case LTC_SSHDATA_STRING:
case LTC_SSHDATA_NAMELIST:
sdata = vdata;
bufsize = va_arg(args, unsigned long*);
if (bufsize == NULL) {
err = CRYPT_INVALID_ARG;
goto error;
}
if (size + 1 >= *bufsize) {
err = CRYPT_BUFFER_OVERFLOW;
goto error;
}
if (size > 0) {
XMEMCPY(sdata, (const char *)in, size);
}
sdata[size] = '\0';
*bufsize = size;
in += size;
break;
case LTC_SSHDATA_MPINT:
if (size == 0) {
if ((err = ltc_mp_set(vdata, 0)) != CRYPT_OK) { goto error; }
} else if ((in[0] & 0x80) != 0) {
/* Negative number - not supported */
err = CRYPT_INVALID_PACKET;
goto error;
} else {
if ((err = ltc_mp_read_unsigned_bin(vdata, in, size)) != CRYPT_OK) { goto error; }
}
in += size;
break;
case LTC_SSHDATA_EOL:
/* Should never get here */
err = CRYPT_INVALID_ARG;
goto error;
}
}
err = CRYPT_OK;
*inlen -= remaining;
error:
va_end(args);
return err;
}
#endif