xref: /titanic_44/usr/src/cmd/ssh/libssh/common/bufaux.c (revision d2ec54f7875f7e05edd56195adbeb593c947763f)
1 /*
2  * Copyright 2006 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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
47 
48 #include <langinfo.h>
49 #include <openssl/bn.h>
50 #include "bufaux.h"
51 #include "xmalloc.h"
52 #include "getput.h"
53 #include "log.h"
54 #include "g11n.h"
55 
56 /*
57  * Stores an BIGNUM in the buffer with a 2-byte msb first bit count, followed
58  * by (bits+7)/8 bytes of binary data, msb first.
59  */
60 int
61 buffer_put_bignum_ret(Buffer *buffer, const BIGNUM *value)
62 {
63 	int bits = BN_num_bits(value);
64 	int bin_size = (bits + 7) / 8;
65 	u_char *buf = xmalloc(bin_size);
66 	int oi;
67 	char msg[2];
68 
69 	/* Get the value of in binary */
70 	oi = BN_bn2bin(value, buf);
71 	if (oi != bin_size) {
72 		error("buffer_put_bignum_ret: BN_bn2bin() failed: oi %d != bin_size %d",
73 		    oi, bin_size);
74 		xfree(buf);
75 		return (-1);
76 	}
77 
78 	/* Store the number of bits in the buffer in two bytes, msb first. */
79 	PUT_16BIT(msg, bits);
80 	buffer_append(buffer, msg, 2);
81 	/* Store the binary data. */
82 	buffer_append(buffer, (char *)buf, oi);
83 
84 	memset(buf, 0, bin_size);
85 	xfree(buf);
86 
87 	return (0);
88 }
89 
90 void
91 buffer_put_bignum(Buffer *buffer, const BIGNUM *value)
92 {
93 	if (buffer_put_bignum_ret(buffer, value) == -1)
94 		fatal("buffer_put_bignum: buffer error");
95 }
96 
97 /*
98  * Retrieves an BIGNUM from the buffer.
99  */
100 int
101 buffer_get_bignum_ret(Buffer *buffer, BIGNUM *value)
102 {
103 	u_int bits, bytes;
104 	u_char buf[2], *bin;
105 
106 	/* Get the number for bits. */
107 	if (buffer_get_ret(buffer, (char *) buf, 2) == -1) {
108 		error("buffer_get_bignum_ret: invalid length");
109 		return (-1);
110 	}
111 	bits = GET_16BIT(buf);
112 	/* Compute the number of binary bytes that follow. */
113 	bytes = (bits + 7) / 8;
114 	if (bytes > 8 * 1024) {
115 		error("buffer_get_bignum_ret: cannot handle BN of size %d", bytes);
116 		return (-1);
117 	}
118 	if (buffer_len(buffer) < bytes) {
119 		error("buffer_get_bignum_ret: input buffer too small");
120 		return (-1);
121 	}
122 	bin = buffer_ptr(buffer);
123 	BN_bin2bn(bin, bytes, value);
124 	if (buffer_consume_ret(buffer, bytes) == -1) {
125 		error("buffer_get_bignum_ret: buffer_consume failed");
126 		return (-1);
127 	}
128 	return (0);
129 }
130 
131 void
132 buffer_get_bignum(Buffer *buffer, BIGNUM *value)
133 {
134 	if (buffer_get_bignum_ret(buffer, value) == -1)
135 		fatal("buffer_get_bignum: buffer error");
136 }
137 
138 /*
139  * Stores an BIGNUM in the buffer in SSH2 format.
140  */
141 int
142 buffer_put_bignum2_ret(Buffer *buffer, const BIGNUM *value)
143 {
144 	u_int bytes;
145 	u_char *buf;
146 	int oi;
147 	u_int hasnohigh = 0;
148 
149 	if (BN_is_zero(value)) {
150 		buffer_put_int(buffer, 0);
151 		return 0;
152 	}
153 	if (value->neg) {
154 		error("buffer_put_bignum2_ret: negative numbers not supported");
155 		return (-1);
156 	}
157 	bytes = BN_num_bytes(value) + 1; /* extra padding byte */
158 	if (bytes < 2) {
159 		error("buffer_put_bignum2_ret: BN too small");
160 		return (-1);
161 	}
162 	buf = xmalloc(bytes);
163 	buf[0] = 0x00;
164 	/* Get the value of in binary */
165 	oi = BN_bn2bin(value, buf+1);
166 	if (oi < 0 || (u_int)oi != bytes - 1) {
167 		error("buffer_put_bignum2_ret: BN_bn2bin() failed: "
168 		    "oi %d != bin_size %d", oi, bytes);
169 		xfree(buf);
170 		return (-1);
171 	}
172 	hasnohigh = (buf[1] & 0x80) ? 0 : 1;
173 	buffer_put_string(buffer, buf+hasnohigh, bytes-hasnohigh);
174 	memset(buf, 0, bytes);
175 	xfree(buf);
176 	return (0);
177 }
178 
179 void
180 buffer_put_bignum2(Buffer *buffer, const BIGNUM *value)
181 {
182 	if (buffer_put_bignum2_ret(buffer, value) == -1)
183 		fatal("buffer_put_bignum2: buffer error");
184 }
185 
186 /* XXX does not handle negative BNs */
187 int
188 buffer_get_bignum2_ret(Buffer *buffer, BIGNUM *value)
189 {
190 	u_int len;
191 	u_char *bin;
192 
193 	if ((bin = buffer_get_string_ret(buffer, &len)) == NULL) {
194 		error("buffer_get_bignum2_ret: invalid bignum");
195 		return (-1);
196 	}
197 
198 	if (len > 0 && (bin[0] & 0x80)) {
199 		error("buffer_get_bignum2_ret: negative numbers not supported");
200 		xfree(bin);
201 		return (-1);
202 	}
203 	if (len > 8 * 1024) {
204 		error("buffer_get_bignum2_ret: cannot handle BN of size %d", len);
205 		xfree(bin);
206 		return (-1);
207 	}
208 	BN_bin2bn(bin, len, value);
209 	xfree(bin);
210 	return (0);
211 }
212 
213 void
214 buffer_get_bignum2(Buffer *buffer, BIGNUM *value)
215 {
216 	if (buffer_get_bignum2_ret(buffer, value) == -1)
217 		fatal("buffer_get_bignum2: buffer error");
218 }
219 
220 /*
221  * Returns integers from the buffer (msb first).
222  */
223 
224 int
225 buffer_get_short_ret(u_short *ret, Buffer *buffer)
226 {
227 	u_char buf[2];
228 
229 	if (buffer_get_ret(buffer, (char *) buf, 2) == -1)
230 		return (-1);
231 	*ret = GET_16BIT(buf);
232 	return (0);
233 }
234 
235 u_short
236 buffer_get_short(Buffer *buffer)
237 {
238 	u_short ret;
239 
240 	if (buffer_get_short_ret(&ret, buffer) == -1)
241 		fatal("buffer_get_short: buffer error");
242 
243 	return (ret);
244 }
245 
246 int
247 buffer_get_int_ret(u_int *ret, Buffer *buffer)
248 {
249 	u_char buf[4];
250 
251 	if (buffer_get_ret(buffer, (char *) buf, 4) == -1)
252 		return (-1);
253 	*ret = GET_32BIT(buf);
254 	return (0);
255 }
256 
257 u_int
258 buffer_get_int(Buffer *buffer)
259 {
260 	u_int ret;
261 
262 	if (buffer_get_int_ret(&ret, buffer) == -1)
263 		fatal("buffer_get_int: buffer error");
264 
265 	return (ret);
266 }
267 
268 #ifdef HAVE_U_INT64_T
269 int
270 buffer_get_int64_ret(u_int64_t *ret, Buffer *buffer)
271 {
272 	u_char buf[8];
273 
274 	if (buffer_get_ret(buffer, (char *) buf, 8) == -1)
275 		return (-1);
276 	*ret = GET_64BIT(buf);
277 	return (0);
278 }
279 
280 u_int64_t
281 buffer_get_int64(Buffer *buffer)
282 {
283 	u_int64_t ret;
284 
285 	if (buffer_get_int64_ret(&ret, buffer) == -1)
286 		fatal("buffer_get_int: buffer error");
287 
288 	return (ret);
289 }
290 #endif
291 
292 /*
293  * Stores integers in the buffer, msb first.
294  */
295 void
296 buffer_put_short(Buffer *buffer, u_short value)
297 {
298 	char buf[2];
299 
300 	PUT_16BIT(buf, value);
301 	buffer_append(buffer, buf, 2);
302 }
303 
304 void
305 buffer_put_int(Buffer *buffer, u_int value)
306 {
307 	char buf[4];
308 
309 	PUT_32BIT(buf, value);
310 	buffer_append(buffer, buf, 4);
311 }
312 
313 #ifdef HAVE_U_INT64_T
314 void
315 buffer_put_int64(Buffer *buffer, u_int64_t value)
316 {
317 	char buf[8];
318 
319 	PUT_64BIT(buf, value);
320 	buffer_append(buffer, buf, 8);
321 }
322 #endif
323 
324 /*
325  * Returns an arbitrary binary string from the buffer.  The string cannot
326  * be longer than 256k.  The returned value points to memory allocated
327  * with xmalloc; it is the responsibility of the calling function to free
328  * the data.  If length_ptr is non-NULL, the length of the returned data
329  * will be stored there.  A null character will be automatically appended
330  * to the returned string, and is not counted in length.
331  */
332 void *
333 buffer_get_string_ret(Buffer *buffer, u_int *length_ptr)
334 {
335 	u_char *value;
336 	u_int len;
337 
338 	/* Get the length. */
339 	len = buffer_get_int(buffer);
340 	if (len > 256 * 1024) {
341 		error("buffer_get_string_ret: bad string length %u", len);
342 		return (NULL);
343 	}
344 	/* Allocate space for the string.  Add one byte for a null character. */
345 	value = xmalloc(len + 1);
346 	/* Get the string. */
347 	if (buffer_get_ret(buffer, value, len) == -1) {
348 		error("buffer_get_string_ret: buffer_get failed");
349 		xfree(value);
350 		return (NULL);
351 	}
352 	/* Append a null character to make processing easier. */
353 	value[len] = 0;
354 	/* Optionally return the length of the string. */
355 	if (length_ptr)
356 		*length_ptr = len;
357 	return (value);
358 }
359 
360 void *
361 buffer_get_string(Buffer *buffer, u_int *length_ptr)
362 {
363 	void *ret;
364 
365 	if ((ret = buffer_get_string_ret(buffer, length_ptr)) == NULL)
366 		fatal("buffer_get_string: buffer error");
367 	return (ret);
368 }
369 
370 char *
371 buffer_get_ascii_cstring(Buffer *buffer)
372 {
373 	char *value;
374 	u_char *p;
375 	u_int len;
376 	value = buffer_get_string(buffer, &len);
377 
378 	/* Look for NULL or high-bit set bytes */
379 	for (p = (u_char *) value ;
380 	     p && *p && (!(*p & 0x80)) && (p - (u_char *) value) < len ;
381 	     p++) ;
382 
383 	/* If there were any, bomb */
384 	if ((p - (u_char *) value) != len) {
385 	    xfree(value);
386 	    errno = EILSEQ;
387 	    return NULL;
388 	}
389 	return value;
390 }
391 u_char *
392 buffer_get_utf8_cstring(Buffer *buffer)
393 {
394 	u_char	*value, *converted, *estr;
395 	u_int	len;
396 	int	err;
397 
398 	if ((value = buffer_get_string(buffer, &len)) == NULL) {
399 		return value;
400 	}
401 
402 	converted = g11n_convert_from_utf8(value, &err, &estr);
403 
404 	if (converted != value) xfree(value);
405 
406 	if (err)
407 	    fatal("invalid UTF-8 sequence; %s", estr);
408 
409 	return converted;
410 }
411 
412 /*
413  * Stores and arbitrary binary string in the buffer.
414  */
415 void
416 buffer_put_string(Buffer *buffer, const void *buf, u_int len)
417 {
418 	buffer_put_int(buffer, len);
419 	buffer_append(buffer, buf, len);
420 }
421 void
422 buffer_put_cstring(Buffer *buffer, const char *s)
423 {
424 	if (s == NULL)
425 		fatal("buffer_put_cstring: s == NULL");
426 	buffer_put_string(buffer, s, strlen(s));
427 }
428 
429 /*
430  * ASCII versions of the above
431  */
432 #if 0
433 void
434 buffer_put_ascii_string(Buffer *buffer, const void *buf, u_int len)
435 {
436 	u_char *p;
437 	for (p = (u_char *) buf ;
438 	     p && ((p - (u_char *) buf) < len) && *p && (!(*p & 0x80)) ;
439 	     p++) ;
440 
441 	if ((p - (u_char *) buf) != len)
442 		verbose("buffer_put_ascii_string: storing a non-ASCII string");
443 	buffer_put_int(buffer, len);
444 	buffer_append(buffer, buf, len);
445 }
446 #endif
447 void
448 buffer_put_ascii_cstring(Buffer *buffer, const char *s)
449 {
450 	u_char *estr;
451 	if (s == NULL)
452 		fatal("buffer_put_cstring: s == NULL");
453 
454 	if (!g11n_validate_ascii(s, strlen(s), &estr))
455 	    verbose("buffer_put_ascii_cstring: non-ASCII string; %s", estr);
456 
457 	buffer_put_cstring(buffer, s);
458 }
459 
460 /*
461  * UTF-8 versions of the above.
462  */
463 
464 #if 0
465 void
466 buffer_put_utf8_string(Buffer *buffer, const void *buf, u_int len)
467 {
468 	char *converted *estr;
469 
470 	converted = g11n_convert_to_utf8(buf, &err, &estr);
471 
472 	if (!converted && err)
473 		fatal("buffer_put_utf8_string: input not a valid UTF-8 encoding; %s", estr);
474 
475 	if (err)
476 		verbose("buffer_put_utf8_string: input not a valid UTF-8 encoding; %s", estr);
477 
478 	buffer_put_string(buffer, converted, strlen(converted));
479 
480 	if (converted != bug) xfree(converted);
481 
482 	return;
483 }
484 #endif
485 void
486 buffer_put_utf8_cstring(Buffer *buffer, const u_char *s)
487 {
488 	u_char *converted, *estr;
489 	int err;
490 
491 	if (s == NULL)
492 		fatal("buffer_put_cstring: s == NULL");
493 
494 	converted = g11n_convert_to_utf8(s, &err, &estr);
495 
496 	if (!converted && err)
497 		fatal("buffer_put_utf8_string: input not a valid UTF-8 encoding; %s", estr);
498 
499 	if (err)
500 		verbose("buffer_put_utf8_string: input not a valid UTF-8 encoding; %s", estr);
501 
502 	buffer_put_cstring(buffer, (const char *) converted);
503 
504 	if (converted != s) xfree(converted);
505 
506 	return;
507 }
508 
509 
510 /*
511  * Returns a character from the buffer (0 - 255).
512  */
513 int
514 buffer_get_char_ret(char *ret, Buffer *buffer)
515 {
516 	if (buffer_get_ret(buffer, ret, 1) == -1) {
517 		error("buffer_get_char_ret: buffer_get_ret failed");
518 		return (-1);
519 	}
520 	return (0);
521 }
522 
523 int
524 buffer_get_char(Buffer *buffer)
525 {
526 	char ch;
527 
528 	if (buffer_get_char_ret(&ch, buffer) == -1)
529 		fatal("buffer_get_char: buffer error");
530 	return (u_char) ch;
531 }
532 
533 /*
534  * Stores a character in the buffer.
535  */
536 void
537 buffer_put_char(Buffer *buffer, int value)
538 {
539 	char ch = value;
540 
541 	buffer_append(buffer, &ch, 1);
542 }
543