diff options
Diffstat (limited to 'bufbn.c')
-rw-r--r-- | bufbn.c | 210 |
1 files changed, 42 insertions, 168 deletions
@@ -1,229 +1,103 @@ | |||
1 | /* $OpenBSD: bufbn.c,v 1.11 2014/02/27 08:25:09 djm Exp $*/ | 1 | /* $OpenBSD: bufbn.c,v 1.12 2014/04/30 05:29:56 djm Exp $ */ |
2 | |||
2 | /* | 3 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 4 | * Copyright (c) 2012 Damien Miller <djm@mindrot.org> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | ||
5 | * All rights reserved | ||
6 | * Auxiliary functions for storing and retrieving various data types to/from | ||
7 | * Buffers. | ||
8 | * | ||
9 | * As far as I am concerned, the code I have written for this software | ||
10 | * can be used freely for any purpose. Any derived versions of this | ||
11 | * software must be clearly marked as such, and if the derived work is | ||
12 | * incompatible with the protocol description in the RFC file, it must be | ||
13 | * called by a name other than "ssh" or "Secure Shell". | ||
14 | * | ||
15 | * | ||
16 | * SSH2 packet format added by Markus Friedl | ||
17 | * Copyright (c) 2000 Markus Friedl. All rights reserved. | ||
18 | * | 5 | * |
19 | * Redistribution and use in source and binary forms, with or without | 6 | * Permission to use, copy, modify, and distribute this software for any |
20 | * modification, are permitted provided that the following conditions | 7 | * purpose with or without fee is hereby granted, provided that the above |
21 | * are met: | 8 | * copyright notice and this permission notice appear in all copies. |
22 | * 1. Redistributions of source code must retain the above copyright | ||
23 | * notice, this list of conditions and the following disclaimer. | ||
24 | * 2. Redistributions in binary form must reproduce the above copyright | ||
25 | * notice, this list of conditions and the following disclaimer in the | ||
26 | * documentation and/or other materials provided with the distribution. | ||
27 | * | 9 | * |
28 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
29 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
30 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
31 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
32 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
33 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
34 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
35 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
36 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
37 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
38 | */ | 17 | */ |
39 | 18 | ||
19 | /* Emulation wrappers for legacy OpenSSH buffer API atop sshbuf */ | ||
20 | |||
40 | #include "includes.h" | 21 | #include "includes.h" |
41 | 22 | ||
42 | #include <sys/types.h> | 23 | #include <sys/types.h> |
43 | 24 | ||
44 | #include <openssl/bn.h> | ||
45 | |||
46 | #include <string.h> | ||
47 | #include <stdarg.h> | ||
48 | #include <stdlib.h> | ||
49 | |||
50 | #include "xmalloc.h" | ||
51 | #include "buffer.h" | 25 | #include "buffer.h" |
52 | #include "log.h" | 26 | #include "log.h" |
53 | #include "misc.h" | 27 | #include "ssherr.h" |
54 | 28 | ||
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 | 29 | int |
60 | buffer_put_bignum_ret(Buffer *buffer, const BIGNUM *value) | 30 | buffer_put_bignum_ret(Buffer *buffer, const BIGNUM *value) |
61 | { | 31 | { |
62 | int bits = BN_num_bits(value); | 32 | int ret; |
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 | free(buf); | ||
74 | return (-1); | ||
75 | } | ||
76 | |||
77 | /* Store the number of bits in the buffer in two bytes, msb first. */ | ||
78 | put_u16(msg, bits); | ||
79 | buffer_append(buffer, msg, 2); | ||
80 | /* Store the binary data. */ | ||
81 | buffer_append(buffer, buf, oi); | ||
82 | |||
83 | explicit_bzero(buf, bin_size); | ||
84 | free(buf); | ||
85 | 33 | ||
86 | return (0); | 34 | if ((ret = sshbuf_put_bignum1(buffer, value)) != 0) { |
35 | error("%s: %s", __func__, ssh_err(ret)); | ||
36 | return -1; | ||
37 | } | ||
38 | return 0; | ||
87 | } | 39 | } |
88 | 40 | ||
89 | void | 41 | void |
90 | buffer_put_bignum(Buffer *buffer, const BIGNUM *value) | 42 | buffer_put_bignum(Buffer *buffer, const BIGNUM *value) |
91 | { | 43 | { |
92 | if (buffer_put_bignum_ret(buffer, value) == -1) | 44 | if (buffer_put_bignum_ret(buffer, value) == -1) |
93 | fatal("buffer_put_bignum: buffer error"); | 45 | fatal("%s: buffer error", __func__); |
94 | } | 46 | } |
95 | 47 | ||
96 | /* | ||
97 | * Retrieves a BIGNUM from the buffer. | ||
98 | */ | ||
99 | int | 48 | int |
100 | buffer_get_bignum_ret(Buffer *buffer, BIGNUM *value) | 49 | buffer_get_bignum_ret(Buffer *buffer, BIGNUM *value) |
101 | { | 50 | { |
102 | u_int bits, bytes; | 51 | int ret; |
103 | u_char buf[2], *bin; | ||
104 | 52 | ||
105 | /* Get the number of bits. */ | 53 | if ((ret = sshbuf_get_bignum1(buffer, value)) != 0) { |
106 | if (buffer_get_ret(buffer, (char *) buf, 2) == -1) { | 54 | error("%s: %s", __func__, ssh_err(ret)); |
107 | error("buffer_get_bignum_ret: invalid length"); | 55 | return -1; |
108 | return (-1); | ||
109 | } | 56 | } |
110 | bits = get_u16(buf); | 57 | return 0; |
111 | if (bits > 65535-7) { | ||
112 | error("buffer_get_bignum_ret: cannot handle BN of size %d", | ||
113 | bits); | ||
114 | return (-1); | ||
115 | } | ||
116 | /* Compute the number of binary bytes that follow. */ | ||
117 | bytes = (bits + 7) / 8; | ||
118 | if (bytes > 8 * 1024) { | ||
119 | error("buffer_get_bignum_ret: cannot handle BN of size %d", bytes); | ||
120 | return (-1); | ||
121 | } | ||
122 | if (buffer_len(buffer) < bytes) { | ||
123 | error("buffer_get_bignum_ret: input buffer too small"); | ||
124 | return (-1); | ||
125 | } | ||
126 | bin = buffer_ptr(buffer); | ||
127 | if (BN_bin2bn(bin, bytes, value) == NULL) { | ||
128 | error("buffer_get_bignum_ret: BN_bin2bn failed"); | ||
129 | return (-1); | ||
130 | } | ||
131 | if (buffer_consume_ret(buffer, bytes) == -1) { | ||
132 | error("buffer_get_bignum_ret: buffer_consume failed"); | ||
133 | return (-1); | ||
134 | } | ||
135 | return (0); | ||
136 | } | 58 | } |
137 | 59 | ||
138 | void | 60 | void |
139 | buffer_get_bignum(Buffer *buffer, BIGNUM *value) | 61 | buffer_get_bignum(Buffer *buffer, BIGNUM *value) |
140 | { | 62 | { |
141 | if (buffer_get_bignum_ret(buffer, value) == -1) | 63 | if (buffer_get_bignum_ret(buffer, value) == -1) |
142 | fatal("buffer_get_bignum: buffer error"); | 64 | fatal("%s: buffer error", __func__); |
143 | } | 65 | } |
144 | 66 | ||
145 | /* | ||
146 | * Stores a BIGNUM in the buffer in SSH2 format. | ||
147 | */ | ||
148 | int | 67 | int |
149 | buffer_put_bignum2_ret(Buffer *buffer, const BIGNUM *value) | 68 | buffer_put_bignum2_ret(Buffer *buffer, const BIGNUM *value) |
150 | { | 69 | { |
151 | u_int bytes; | 70 | int ret; |
152 | u_char *buf; | 71 | |
153 | int oi; | 72 | if ((ret = sshbuf_put_bignum2(buffer, value)) != 0) { |
154 | u_int hasnohigh = 0; | 73 | error("%s: %s", __func__, ssh_err(ret)); |
155 | 74 | return -1; | |
156 | if (BN_is_zero(value)) { | ||
157 | buffer_put_int(buffer, 0); | ||
158 | return 0; | ||
159 | } | ||
160 | if (value->neg) { | ||
161 | error("buffer_put_bignum2_ret: negative numbers not supported"); | ||
162 | return (-1); | ||
163 | } | ||
164 | bytes = BN_num_bytes(value) + 1; /* extra padding byte */ | ||
165 | if (bytes < 2) { | ||
166 | error("buffer_put_bignum2_ret: BN too small"); | ||
167 | return (-1); | ||
168 | } | ||
169 | buf = xmalloc(bytes); | ||
170 | buf[0] = 0x00; | ||
171 | /* Get the value of in binary */ | ||
172 | oi = BN_bn2bin(value, buf+1); | ||
173 | if (oi < 0 || (u_int)oi != bytes - 1) { | ||
174 | error("buffer_put_bignum2_ret: BN_bn2bin() failed: " | ||
175 | "oi %d != bin_size %d", oi, bytes); | ||
176 | free(buf); | ||
177 | return (-1); | ||
178 | } | 75 | } |
179 | hasnohigh = (buf[1] & 0x80) ? 0 : 1; | 76 | return 0; |
180 | buffer_put_string(buffer, buf+hasnohigh, bytes-hasnohigh); | ||
181 | explicit_bzero(buf, bytes); | ||
182 | free(buf); | ||
183 | return (0); | ||
184 | } | 77 | } |
185 | 78 | ||
186 | void | 79 | void |
187 | buffer_put_bignum2(Buffer *buffer, const BIGNUM *value) | 80 | buffer_put_bignum2(Buffer *buffer, const BIGNUM *value) |
188 | { | 81 | { |
189 | if (buffer_put_bignum2_ret(buffer, value) == -1) | 82 | if (buffer_put_bignum2_ret(buffer, value) == -1) |
190 | fatal("buffer_put_bignum2: buffer error"); | 83 | fatal("%s: buffer error", __func__); |
191 | } | 84 | } |
192 | 85 | ||
193 | int | 86 | int |
194 | buffer_get_bignum2_ret(Buffer *buffer, BIGNUM *value) | 87 | buffer_get_bignum2_ret(Buffer *buffer, BIGNUM *value) |
195 | { | 88 | { |
196 | u_int len; | 89 | int ret; |
197 | u_char *bin; | ||
198 | 90 | ||
199 | if ((bin = buffer_get_string_ret(buffer, &len)) == NULL) { | 91 | if ((ret = sshbuf_get_bignum2(buffer, value)) != 0) { |
200 | error("buffer_get_bignum2_ret: invalid bignum"); | 92 | error("%s: %s", __func__, ssh_err(ret)); |
201 | return (-1); | 93 | return -1; |
202 | } | ||
203 | |||
204 | if (len > 0 && (bin[0] & 0x80)) { | ||
205 | error("buffer_get_bignum2_ret: negative numbers not supported"); | ||
206 | free(bin); | ||
207 | return (-1); | ||
208 | } | ||
209 | if (len > 8 * 1024) { | ||
210 | error("buffer_get_bignum2_ret: cannot handle BN of size %d", | ||
211 | len); | ||
212 | free(bin); | ||
213 | return (-1); | ||
214 | } | ||
215 | if (BN_bin2bn(bin, len, value) == NULL) { | ||
216 | error("buffer_get_bignum2_ret: BN_bin2bn failed"); | ||
217 | free(bin); | ||
218 | return (-1); | ||
219 | } | 94 | } |
220 | free(bin); | 95 | return 0; |
221 | return (0); | ||
222 | } | 96 | } |
223 | 97 | ||
224 | void | 98 | void |
225 | buffer_get_bignum2(Buffer *buffer, BIGNUM *value) | 99 | buffer_get_bignum2(Buffer *buffer, BIGNUM *value) |
226 | { | 100 | { |
227 | if (buffer_get_bignum2_ret(buffer, value) == -1) | 101 | if (buffer_get_bignum2_ret(buffer, value) == -1) |
228 | fatal("buffer_get_bignum2: buffer error"); | 102 | fatal("%s: buffer error", __func__); |
229 | } | 103 | } |