xref: /titanic_44/usr/src/cmd/ssh/libssh/common/bufaux.c (revision 8eea8e29cc4374d1ee24c25a07f45af132db3499)
1 /*
2  * Copyright 2005 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 void
61 buffer_put_bignum(Buffer *buffer, 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 		fatal("buffer_put_bignum: BN_bn2bin() failed: oi %d != bin_size %d",
73 		    oi, bin_size);
74 
75 	/* Store the number of bits in the buffer in two bytes, msb first. */
76 	PUT_16BIT(msg, bits);
77 	buffer_append(buffer, msg, 2);
78 	/* Store the binary data. */
79 	buffer_append(buffer, (char *)buf, oi);
80 
81 	memset(buf, 0, bin_size);
82 	xfree(buf);
83 }
84 
85 /*
86  * Retrieves an BIGNUM from the buffer.
87  */
88 void
89 buffer_get_bignum(Buffer *buffer, BIGNUM *value)
90 {
91 	int bits, bytes;
92 	u_char buf[2], *bin;
93 
94 	/* Get the number for bits. */
95 	buffer_get(buffer, (char *) buf, 2);
96 	bits = GET_16BIT(buf);
97 	/* Compute the number of binary bytes that follow. */
98 	bytes = (bits + 7) / 8;
99 	if (bytes > 8 * 1024)
100 		fatal("buffer_get_bignum: cannot handle BN of size %d", bytes);
101 	if (buffer_len(buffer) < bytes)
102 		fatal("buffer_get_bignum: input buffer too small");
103 	bin = buffer_ptr(buffer);
104 	BN_bin2bn(bin, bytes, value);
105 	buffer_consume(buffer, bytes);
106 }
107 
108 /*
109  * Stores an BIGNUM in the buffer in SSH2 format.
110  */
111 void
112 buffer_put_bignum2(Buffer *buffer, BIGNUM *value)
113 {
114 	int bytes = BN_num_bytes(value) + 1;
115 	u_char *buf = xmalloc(bytes);
116 	int oi;
117 	int hasnohigh = 0;
118 
119 	buf[0] = '\0';
120 	/* Get the value of in binary */
121 	oi = BN_bn2bin(value, buf+1);
122 	if (oi != bytes-1)
123 		fatal("buffer_put_bignum: BN_bn2bin() failed: oi %d != bin_size %d",
124 		    oi, bytes);
125 	hasnohigh = (buf[1] & 0x80) ? 0 : 1;
126 	if (value->neg) {
127 		/**XXX should be two's-complement */
128 		int i, carry;
129 		u_char *uc = buf;
130 		log("negativ!");
131 		for (i = bytes-1, carry = 1; i>=0; i--) {
132 			uc[i] ^= 0xff;
133 			if (carry)
134 				carry = !++uc[i];
135 		}
136 	}
137 	buffer_put_string(buffer, buf+hasnohigh, bytes-hasnohigh);
138 	memset(buf, 0, bytes);
139 	xfree(buf);
140 }
141 
142 /* XXX does not handle negative BNs */
143 void
144 buffer_get_bignum2(Buffer *buffer, BIGNUM *value)
145 {
146 	u_int len;
147 	u_char *bin = buffer_get_string(buffer, &len);
148 
149 	if (len > 8 * 1024)
150 		fatal("buffer_get_bignum2: cannot handle BN of size %d", len);
151 	BN_bin2bn(bin, len, value);
152 	xfree(bin);
153 }
154 /*
155  * Returns integers from the buffer (msb first).
156  */
157 
158 u_short
159 buffer_get_short(Buffer *buffer)
160 {
161 	u_char buf[2];
162 
163 	buffer_get(buffer, (char *) buf, 2);
164 	return GET_16BIT(buf);
165 }
166 
167 u_int
168 buffer_get_int(Buffer *buffer)
169 {
170 	u_char buf[4];
171 
172 	buffer_get(buffer, (char *) buf, 4);
173 	return GET_32BIT(buf);
174 }
175 
176 #ifdef HAVE_U_INT64_T
177 u_int64_t
178 buffer_get_int64(Buffer *buffer)
179 {
180 	u_char buf[8];
181 
182 	buffer_get(buffer, (char *) buf, 8);
183 	return GET_64BIT(buf);
184 }
185 #endif
186 
187 /*
188  * Stores integers in the buffer, msb first.
189  */
190 void
191 buffer_put_short(Buffer *buffer, u_short value)
192 {
193 	char buf[2];
194 
195 	PUT_16BIT(buf, value);
196 	buffer_append(buffer, buf, 2);
197 }
198 
199 void
200 buffer_put_int(Buffer *buffer, u_int value)
201 {
202 	char buf[4];
203 
204 	PUT_32BIT(buf, value);
205 	buffer_append(buffer, buf, 4);
206 }
207 
208 #ifdef HAVE_U_INT64_T
209 void
210 buffer_put_int64(Buffer *buffer, u_int64_t value)
211 {
212 	char buf[8];
213 
214 	PUT_64BIT(buf, value);
215 	buffer_append(buffer, buf, 8);
216 }
217 #endif
218 
219 /*
220  * Returns an arbitrary binary string from the buffer.  The string cannot
221  * be longer than 256k.  The returned value points to memory allocated
222  * with xmalloc; it is the responsibility of the calling function to free
223  * the data.  If length_ptr is non-NULL, the length of the returned data
224  * will be stored there.  A null character will be automatically appended
225  * to the returned string, and is not counted in length.
226  */
227 void *
228 buffer_get_string(Buffer *buffer, u_int *length_ptr)
229 {
230 	u_char *value;
231 	u_int len;
232 
233 	/* Get the length. */
234 	len = buffer_get_int(buffer);
235 	if (len > 256 * 1024)
236 		fatal("buffer_get_string: bad string length %d", len);
237 	/* Allocate space for the string.  Add one byte for a null character. */
238 	value = xmalloc(len + 1);
239 	/* Get the string. */
240 	buffer_get(buffer, value, len);
241 	/* Append a null character to make processing easier. */
242 	value[len] = 0;
243 	/* Optionally return the length of the string. */
244 	if (length_ptr)
245 		*length_ptr = len;
246 	return value;
247 }
248 char *
249 buffer_get_ascii_cstring(Buffer *buffer)
250 {
251 	char *value;
252 	u_char *p;
253 	u_int len;
254 	value = buffer_get_string(buffer, &len);
255 
256 	/* Look for NULL or high-bit set bytes */
257 	for (p = (u_char *) value ;
258 	     p && *p && (!(*p & 0x80)) && (p - (u_char *) value) < len ;
259 	     p++) ;
260 
261 	/* If there were any, bomb */
262 	if ((p - (u_char *) value) != len) {
263 	    xfree(value);
264 	    errno = EILSEQ;
265 	    return NULL;
266 	}
267 	return value;
268 }
269 u_char *
270 buffer_get_utf8_cstring(Buffer *buffer)
271 {
272 	u_char	*value, *converted, *estr;
273 	u_int	len;
274 	int	err;
275 
276 	if ((value = buffer_get_string(buffer, &len)) == NULL) {
277 		return value;
278 	}
279 
280 	converted = g11n_convert_from_utf8(value, &err, &estr);
281 
282 	if (converted != value) xfree(value);
283 
284 	if (err)
285 	    fatal("invalid UTF-8 sequence; %s", estr);
286 
287 	return converted;
288 }
289 
290 /*
291  * Stores and arbitrary binary string in the buffer.
292  */
293 void
294 buffer_put_string(Buffer *buffer, const void *buf, u_int len)
295 {
296 	buffer_put_int(buffer, len);
297 	buffer_append(buffer, buf, len);
298 }
299 void
300 buffer_put_cstring(Buffer *buffer, const char *s)
301 {
302 	if (s == NULL)
303 		fatal("buffer_put_cstring: s == NULL");
304 	buffer_put_string(buffer, s, strlen(s));
305 }
306 
307 /*
308  * ASCII versions of the above
309  */
310 #if 0
311 void
312 buffer_put_ascii_string(Buffer *buffer, const void *buf, u_int len)
313 {
314 	u_char *p;
315 	for (p = (u_char *) buf ;
316 	     p && ((p - (u_char *) buf) < len) && *p && (!(*p & 0x80)) ;
317 	     p++) ;
318 
319 	if ((p - (u_char *) buf) != len)
320 		verbose("buffer_put_ascii_string: storing a non-ASCII string");
321 	buffer_put_int(buffer, len);
322 	buffer_append(buffer, buf, len);
323 }
324 #endif
325 void
326 buffer_put_ascii_cstring(Buffer *buffer, const char *s)
327 {
328 	u_char *estr;
329 	if (s == NULL)
330 		fatal("buffer_put_cstring: s == NULL");
331 
332 	if (!g11n_validate_ascii(s, strlen(s), &estr))
333 	    verbose("buffer_put_ascii_cstring: non-ASCII string; %s", estr);
334 
335 	buffer_put_cstring(buffer, s);
336 }
337 
338 /*
339  * UTF-8 versions of the above.
340  */
341 
342 #if 0
343 void
344 buffer_put_utf8_string(Buffer *buffer, const void *buf, u_int len)
345 {
346 	char *converted *estr;
347 
348 	converted = g11n_convert_to_utf8(buf, &err, &estr);
349 
350 	if (!converted && err)
351 		fatal("buffer_put_utf8_string: input not a valid UTF-8 encoding; %s", estr);
352 
353 	if (err)
354 		verbose("buffer_put_utf8_string: input not a valid UTF-8 encoding; %s", estr);
355 
356 	buffer_put_string(buffer, converted, strlen(converted));
357 
358 	if (converted != bug) xfree(converted);
359 
360 	return;
361 }
362 #endif
363 void
364 buffer_put_utf8_cstring(Buffer *buffer, const u_char *s)
365 {
366 	u_char *converted, *estr;
367 	int err;
368 
369 	if (s == NULL)
370 		fatal("buffer_put_cstring: s == NULL");
371 
372 	converted = g11n_convert_to_utf8(s, &err, &estr);
373 
374 	if (!converted && err)
375 		fatal("buffer_put_utf8_string: input not a valid UTF-8 encoding; %s", estr);
376 
377 	if (err)
378 		verbose("buffer_put_utf8_string: input not a valid UTF-8 encoding; %s", estr);
379 
380 	buffer_put_cstring(buffer, (const char *) converted);
381 
382 	if (converted != s) xfree(converted);
383 
384 	return;
385 }
386 
387 
388 /*
389  * Returns a character from the buffer (0 - 255).
390  */
391 int
392 buffer_get_char(Buffer *buffer)
393 {
394 	char ch;
395 
396 	buffer_get(buffer, &ch, 1);
397 	return (u_char) ch;
398 }
399 
400 /*
401  * Stores a character in the buffer.
402  */
403 void
404 buffer_put_char(Buffer *buffer, int value)
405 {
406 	char ch = value;
407 
408 	buffer_append(buffer, &ch, 1);
409 }
410