1 /*
2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
5 /*
6 * Author: Tatu Ylonen <ylo@cs.hut.fi>
7 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8 * All rights reserved
9 * Auxiliary functions for storing and retrieving various data types to/from
10 * Buffers.
11 *
12 * As far as I am concerned, the code I have written for this software
13 * can be used freely for any purpose. Any derived versions of this
14 * software must be clearly marked as such, and if the derived work is
15 * incompatible with the protocol description in the RFC file, it must be
16 * called by a name other than "ssh" or "Secure Shell".
17 *
18 *
19 * SSH2 packet format added by Markus Friedl
20 * Copyright (c) 2000 Markus Friedl. All rights reserved.
21 *
22 * Redistribution and use in source and binary forms, with or without
23 * modification, are permitted provided that the following conditions
24 * are met:
25 * 1. Redistributions of source code must retain the above copyright
26 * notice, this list of conditions and the following disclaimer.
27 * 2. Redistributions in binary form must reproduce the above copyright
28 * notice, this list of conditions and the following disclaimer in the
29 * documentation and/or other materials provided with the distribution.
30 *
31 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
32 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
33 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
34 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
35 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
36 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
37 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
38 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
39 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
40 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41 */
42
43 #include "includes.h"
44 RCSID("$OpenBSD: bufaux.c,v 1.27 2002/06/26 08:53:12 markus Exp $");
45
46 #include <openssl/opensslconf.h>
47 #include <langinfo.h>
48 #include <openssl/bn.h>
49 #include "bufaux.h"
50 #include "xmalloc.h"
51 #include "getput.h"
52 #include "log.h"
53 #include "g11n.h"
54
55 /*
56 * Stores an BIGNUM in the buffer with a 2-byte msb first bit count, followed
57 * by (bits+7)/8 bytes of binary data, msb first.
58 */
59 int
60 buffer_put_bignum_ret(Buffer *buffer, const BIGNUM *value)
61 {
62 int bits = BN_num_bits(value);
63 int bin_size = (bits + 7) / 8;
64 u_char *buf = xmalloc(bin_size);
65 int oi;
66 char msg[2];
67
68 /* Get the value of in binary */
69 oi = BN_bn2bin(value, buf);
70 if (oi != bin_size) {
71 error("buffer_put_bignum_ret: BN_bn2bin() failed: oi %d != bin_size %d",
72 oi, bin_size);
73 xfree(buf);
74 return (-1);
75 }
76
77 /* Store the number of bits in the buffer in two bytes, msb first. */
78 PUT_16BIT(msg, bits);
79 buffer_append(buffer, msg, 2);
80 /* Store the binary data. */
81 buffer_append(buffer, (char *)buf, oi);
82
83 memset(buf, 0, bin_size);
84 xfree(buf);
85
86 return (0);
87 }
88
89 void
90 buffer_put_bignum(Buffer *buffer, const BIGNUM *value)
91 {
92 if (buffer_put_bignum_ret(buffer, value) == -1)
93 fatal("buffer_put_bignum: buffer error");
94 }
95
96 /*
97 * Retrieves an BIGNUM from the buffer.
98 */
99 int
100 buffer_get_bignum_ret(Buffer *buffer, BIGNUM *value)
101 {
102 u_int bits, bytes;
103 u_char buf[2], *bin;
104
105 /* Get the number for bits. */
106 if (buffer_get_ret(buffer, (char *) buf, 2) == -1) {
107 error("buffer_get_bignum_ret: invalid length");
108 return (-1);
109 }
110 bits = GET_16BIT(buf);
111 /* Compute the number of binary bytes that follow. */
112 bytes = (bits + 7) / 8;
113 if (bytes > 8 * 1024) {
114 error("buffer_get_bignum_ret: cannot handle BN of size %d", bytes);
115 return (-1);
116 }
117 if (buffer_len(buffer) < bytes) {
118 error("buffer_get_bignum_ret: input buffer too small");
119 return (-1);
120 }
121 bin = buffer_ptr(buffer);
122 BN_bin2bn(bin, bytes, value);
123 if (buffer_consume_ret(buffer, bytes) == -1) {
124 error("buffer_get_bignum_ret: buffer_consume failed");
125 return (-1);
126 }
127 return (0);
128 }
129
130 void
131 buffer_get_bignum(Buffer *buffer, BIGNUM *value)
132 {
133 if (buffer_get_bignum_ret(buffer, value) == -1)
134 fatal("buffer_get_bignum: buffer error");
135 }
136
137 /*
138 * Stores an BIGNUM in the buffer in SSH2 format.
139 */
140 int
141 buffer_put_bignum2_ret(Buffer *buffer, const BIGNUM *value)
142 {
143 u_int bytes;
144 u_char *buf;
145 int oi;
146 u_int hasnohigh = 0;
147
148 if (BN_is_zero(value)) {
149 buffer_put_int(buffer, 0);
150 return 0;
151 }
152 if (value->neg) {
153 error("buffer_put_bignum2_ret: negative numbers not supported");
154 return (-1);
155 }
156 bytes = BN_num_bytes(value) + 1; /* extra padding byte */
157 if (bytes < 2) {
158 error("buffer_put_bignum2_ret: BN too small");
159 return (-1);
160 }
161 buf = xmalloc(bytes);
162 buf[0] = 0x00;
163 /* Get the value of in binary */
164 oi = BN_bn2bin(value, buf+1);
165 if (oi < 0 || (u_int)oi != bytes - 1) {
166 error("buffer_put_bignum2_ret: BN_bn2bin() failed: "
167 "oi %d != bin_size %d", oi, bytes);
168 xfree(buf);
169 return (-1);
170 }
171 hasnohigh = (buf[1] & 0x80) ? 0 : 1;
172 buffer_put_string(buffer, buf+hasnohigh, bytes-hasnohigh);
173 memset(buf, 0, bytes);
174 xfree(buf);
175 return (0);
176 }
177
178 void
179 buffer_put_bignum2(Buffer *buffer, const BIGNUM *value)
180 {
181 if (buffer_put_bignum2_ret(buffer, value) == -1)
182 fatal("buffer_put_bignum2: buffer error");
183 }
184
185 /* XXX does not handle negative BNs */
186 int
187 buffer_get_bignum2_ret(Buffer *buffer, BIGNUM *value)
188 {
189 u_int len;
190 u_char *bin;
191
192 if ((bin = buffer_get_string_ret(buffer, &len)) == NULL) {
193 error("buffer_get_bignum2_ret: invalid bignum");
194 return (-1);
195 }
196
197 if (len > 0 && (bin[0] & 0x80)) {
198 error("buffer_get_bignum2_ret: negative numbers not supported");
199 xfree(bin);
200 return (-1);
201 }
202 if (len > 8 * 1024) {
203 error("buffer_get_bignum2_ret: cannot handle BN of size %d", len);
204 xfree(bin);
205 return (-1);
206 }
207 BN_bin2bn(bin, len, value);
208 xfree(bin);
209 return (0);
210 }
211
212 void
213 buffer_get_bignum2(Buffer *buffer, BIGNUM *value)
214 {
215 if (buffer_get_bignum2_ret(buffer, value) == -1)
216 fatal("buffer_get_bignum2: buffer error");
217 }
218
219 /*
220 * Returns integers from the buffer (msb first).
221 */
222
223 int
224 buffer_get_short_ret(u_short *ret, Buffer *buffer)
225 {
226 u_char buf[2];
227
228 if (buffer_get_ret(buffer, (char *) buf, 2) == -1)
229 return (-1);
230 *ret = GET_16BIT(buf);
231 return (0);
232 }
233
234 u_short
235 buffer_get_short(Buffer *buffer)
236 {
237 u_short ret;
238
239 if (buffer_get_short_ret(&ret, buffer) == -1)
240 fatal("buffer_get_short: buffer error");
241
242 return (ret);
243 }
244
245 int
246 buffer_get_int_ret(u_int *ret, Buffer *buffer)
247 {
248 u_char buf[4];
249
250 if (buffer_get_ret(buffer, (char *) buf, 4) == -1)
251 return (-1);
252 *ret = GET_32BIT(buf);
253 return (0);
254 }
255
256 u_int
257 buffer_get_int(Buffer *buffer)
258 {
259 u_int ret;
260
261 if (buffer_get_int_ret(&ret, buffer) == -1)
262 fatal("buffer_get_int: buffer error");
263
264 return (ret);
265 }
266
267 #ifdef HAVE_U_INT64_T
268 int
269 buffer_get_int64_ret(u_int64_t *ret, Buffer *buffer)
270 {
271 u_char buf[8];
272
273 if (buffer_get_ret(buffer, (char *) buf, 8) == -1)
274 return (-1);
275 *ret = GET_64BIT(buf);
276 return (0);
277 }
278
279 u_int64_t
280 buffer_get_int64(Buffer *buffer)
281 {
282 u_int64_t ret;
283
284 if (buffer_get_int64_ret(&ret, buffer) == -1)
285 fatal("buffer_get_int: buffer error");
286
287 return (ret);
288 }
289 #endif
290
291 /*
292 * Stores integers in the buffer, msb first.
293 */
294 void
295 buffer_put_short(Buffer *buffer, u_short value)
296 {
297 char buf[2];
298
299 PUT_16BIT(buf, value);
300 buffer_append(buffer, buf, 2);
301 }
302
303 void
304 buffer_put_int(Buffer *buffer, u_int value)
305 {
306 char buf[4];
307
308 PUT_32BIT(buf, value);
309 buffer_append(buffer, buf, 4);
310 }
311
312 #ifdef HAVE_U_INT64_T
313 void
314 buffer_put_int64(Buffer *buffer, u_int64_t value)
315 {
316 char buf[8];
317
318 PUT_64BIT(buf, value);
319 buffer_append(buffer, buf, 8);
320 }
321 #endif
322
323 /*
324 * Returns an arbitrary binary string from the buffer. The string cannot
325 * be longer than 256k. The returned value points to memory allocated
326 * with xmalloc; it is the responsibility of the calling function to free
327 * the data. If length_ptr is non-NULL, the length of the returned data
328 * will be stored there. A null character will be automatically appended
329 * to the returned string, and is not counted in length.
330 */
331 void *
332 buffer_get_string_ret(Buffer *buffer, u_int *length_ptr)
333 {
334 u_char *value;
335 u_int len;
336
337 /* Get the length. */
338 len = buffer_get_int(buffer);
339 if (len > 256 * 1024) {
340 error("buffer_get_string_ret: bad string length %u", len);
341 return (NULL);
342 }
343 /* Allocate space for the string. Add one byte for a null character. */
344 value = xmalloc(len + 1);
345 /* Get the string. */
346 if (buffer_get_ret(buffer, value, len) == -1) {
347 error("buffer_get_string_ret: buffer_get failed");
348 xfree(value);
349 return (NULL);
350 }
351 /* Append a null character to make processing easier. */
352 value[len] = 0;
353 /* Optionally return the length of the string. */
354 if (length_ptr)
355 *length_ptr = len;
356 return (value);
357 }
358
359 void *
360 buffer_get_string(Buffer *buffer, u_int *length_ptr)
361 {
362 void *ret;
363
364 if ((ret = buffer_get_string_ret(buffer, length_ptr)) == NULL)
365 fatal("buffer_get_string: buffer error");
366 return (ret);
367 }
368
369 char *
370 buffer_get_utf8_string(Buffer *buffer, uint_t *length_ptr)
371 {
372 char *value, *converted, *estr;
373 uint_t len;
374
375 if ((value = buffer_get_string(buffer, &len)) == NULL)
376 return (value);
377
378 converted = g11n_convert_from_utf8(value, &len, &estr);
379 if (converted == NULL) {
380 if (estr != NULL)
381 error("invalid UTF-8 sequence: %s", estr);
382 converted = value;
383 } else {
384 xfree(value);
385 }
386
387 if (length_ptr != NULL)
388 *length_ptr = len;
389
390 return (converted);
391 }
392
393 /*
394 * Stores and arbitrary binary string in the buffer.
395 */
396 void
397 buffer_put_string(Buffer *buffer, const void *buf, u_int len)
398 {
399 buffer_put_int(buffer, len);
400 buffer_append(buffer, buf, len);
401 }
402 void
403 buffer_put_cstring(Buffer *buffer, const char *s)
404 {
405 if (s == NULL)
406 fatal("buffer_put_cstring: s == NULL");
407 buffer_put_string(buffer, s, strlen(s));
408 }
409
410 /*
411 * UTF-8 versions of the above.
412 */
413 void
414 buffer_put_utf8_string(Buffer *buffer, const char *s, uint_t len)
415 {
416 char *converted, *estr;
417 uint_t nlen = len;
418
419 converted = g11n_convert_to_utf8(s, &nlen, 0, &estr);
420 if (converted == NULL) {
421 if (estr != NULL)
422 error("Can't convert to UTF-8: %s", estr);
423 converted = (char *)s;
424 }
425
426 buffer_put_string(buffer, converted, nlen);
427
428 if (converted != s)
429 xfree(converted);
430 }
431
432 void
433 buffer_put_utf8_cstring(Buffer *buffer, const char *s)
434 {
435 buffer_put_utf8_string(buffer, s, strlen(s));
436 }
437
438 /*
439 * Returns a character from the buffer (0 - 255).
440 */
441 int
442 buffer_get_char_ret(char *ret, Buffer *buffer)
443 {
444 if (buffer_get_ret(buffer, ret, 1) == -1) {
445 error("buffer_get_char_ret: buffer_get_ret failed");
446 return (-1);
447 }
448 return (0);
449 }
450
451 int
452 buffer_get_char(Buffer *buffer)
453 {
454 char ch;
455
456 if (buffer_get_char_ret(&ch, buffer) == -1)
457 fatal("buffer_get_char: buffer error");
458 return (u_char) ch;
459 }
460
461 /*
462 * Stores a character in the buffer.
463 */
464 void
465 buffer_put_char(Buffer *buffer, int value)
466 {
467 char ch = value;
468
469 buffer_append(buffer, &ch, 1);
470 }