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