summaryrefslogtreecommitdiff
path: root/sshbuf-getput-crypto.c
diff options
context:
space:
mode:
authorDamien Miller <djm@mindrot.org>2014-05-15 14:33:43 +1000
committerDamien Miller <djm@mindrot.org>2014-05-15 14:33:43 +1000
commit05e82c3b963c33048128baf72a6f6b3a1c10b4c1 (patch)
treecb238452459af2f8311d54ca509722497e799517 /sshbuf-getput-crypto.c
parent380948180f847a26f2d0c85b4dad3dca2ed2fd8b (diff)
- djm@cvs.openbsd.org 2014/04/30 05:29:56
[bufaux.c bufbn.c bufec.c buffer.c buffer.h sshbuf-getput-basic.c] [sshbuf-getput-crypto.c sshbuf-misc.c sshbuf.c sshbuf.h ssherr.c] [ssherr.h] New buffer API; the first installment of the conversion/replacement of OpenSSH's internals to make them usable as a standalone library. This includes a set of wrappers to make it compatible with the existing buffer API so replacement can occur incrementally. With and ok markus@ Thanks also to Ben Hawkes, David Tomaschik, Ivan Fratric, Matthew Dempsky and Ron Bowes for a detailed review.
Diffstat (limited to 'sshbuf-getput-crypto.c')
-rw-r--r--sshbuf-getput-crypto.c233
1 files changed, 233 insertions, 0 deletions
diff --git a/sshbuf-getput-crypto.c b/sshbuf-getput-crypto.c
new file mode 100644
index 000000000..9c801a45f
--- /dev/null
+++ b/sshbuf-getput-crypto.c
@@ -0,0 +1,233 @@
1/* $OpenBSD: sshbuf-getput-crypto.c,v 1.1 2014/04/30 05:29:56 djm Exp $ */
2/*
3 * Copyright (c) 2011 Damien Miller
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18#include "includes.h"
19
20#include <sys/types.h>
21#include <stdlib.h>
22#include <stdio.h>
23#include <string.h>
24
25#include <openssl/bn.h>
26#include <openssl/ec.h>
27
28#include "ssherr.h"
29#define SSHBUF_INTERNAL
30#include "sshbuf.h"
31
32int
33sshbuf_get_bignum2(struct sshbuf *buf, BIGNUM *v)
34{
35 const u_char *d;
36 size_t len;
37 int r;
38
39 if ((r = sshbuf_peek_string_direct(buf, &d, &len)) < 0)
40 return r;
41 /* Refuse negative (MSB set) and overlong bignums */
42 if ((len != 0 && (*d & 0x80) != 0))
43 return SSH_ERR_BIGNUM_IS_NEGATIVE;
44 if (len > SSHBUF_MAX_BIGNUM)
45 return SSH_ERR_BIGNUM_TOO_LARGE;
46 if (v != NULL && BN_bin2bn(d, len, v) == NULL)
47 return SSH_ERR_ALLOC_FAIL;
48 /* Consume the string */
49 if (sshbuf_get_string_direct(buf, NULL, NULL) != 0) {
50 /* Shouldn't happen */
51 SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
52 SSHBUF_ABORT();
53 return SSH_ERR_INTERNAL_ERROR;
54 }
55 return 0;
56}
57
58int
59sshbuf_get_bignum1(struct sshbuf *buf, BIGNUM *v)
60{
61 const u_char *d = sshbuf_ptr(buf);
62 u_int16_t len_bits;
63 size_t len_bytes;
64
65 /* Length in bits */
66 if (sshbuf_len(buf) < 2)
67 return SSH_ERR_MESSAGE_INCOMPLETE;
68 len_bits = PEEK_U16(d);
69 len_bytes = (len_bits + 7) >> 3;
70 if (len_bytes > SSHBUF_MAX_BIGNUM + 1)
71 return SSH_ERR_BIGNUM_TOO_LARGE;
72 if (sshbuf_len(buf) < 2 + len_bytes)
73 return SSH_ERR_MESSAGE_INCOMPLETE;
74 if (v != NULL && BN_bin2bn(d + 2, len_bytes, v) == NULL)
75 return SSH_ERR_ALLOC_FAIL;
76 if (sshbuf_consume(buf, 2 + len_bytes) != 0) {
77 SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
78 SSHBUF_ABORT();
79 return SSH_ERR_INTERNAL_ERROR;
80 }
81 return 0;
82}
83
84#ifdef OPENSSL_HAS_ECC
85static int
86get_ec(const u_char *d, size_t len, EC_POINT *v, const EC_GROUP *g)
87{
88 /* Refuse overlong bignums */
89 if (len == 0 || len > SSHBUF_MAX_ECPOINT)
90 return SSH_ERR_ECPOINT_TOO_LARGE;
91 /* Only handle uncompressed points */
92 if (*d != POINT_CONVERSION_UNCOMPRESSED)
93 return SSH_ERR_INVALID_FORMAT;
94 if (v != NULL && EC_POINT_oct2point(g, v, d, len, NULL) != 1)
95 return SSH_ERR_INVALID_FORMAT; /* XXX assumption */
96 return 0;
97}
98
99int
100sshbuf_get_ec(struct sshbuf *buf, EC_POINT *v, const EC_GROUP *g)
101{
102 const u_char *d;
103 size_t len;
104 int r;
105
106 if ((r = sshbuf_peek_string_direct(buf, &d, &len)) < 0)
107 return r;
108 if ((r = get_ec(d, len, v, g)) != 0)
109 return r;
110 /* Skip string */
111 if (sshbuf_get_string_direct(buf, NULL, NULL) != 0) {
112 /* Shouldn't happen */
113 SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
114 SSHBUF_ABORT();
115 return SSH_ERR_INTERNAL_ERROR;
116 }
117 return 0;
118}
119
120int
121sshbuf_get_eckey(struct sshbuf *buf, EC_KEY *v)
122{
123 EC_POINT *pt = EC_POINT_new(EC_KEY_get0_group(v));
124 int r;
125 const u_char *d;
126 size_t len;
127
128 if (pt == NULL) {
129 SSHBUF_DBG(("SSH_ERR_ALLOC_FAIL"));
130 return SSH_ERR_ALLOC_FAIL;
131 }
132 if ((r = sshbuf_peek_string_direct(buf, &d, &len)) < 0) {
133 EC_POINT_free(pt);
134 return r;
135 }
136 if ((r = get_ec(d, len, pt, EC_KEY_get0_group(v))) != 0) {
137 EC_POINT_free(pt);
138 return r;
139 }
140 if (EC_KEY_set_public_key(v, pt) != 1) {
141 EC_POINT_free(pt);
142 return SSH_ERR_ALLOC_FAIL; /* XXX assumption */
143 }
144 EC_POINT_free(pt);
145 /* Skip string */
146 if (sshbuf_get_string_direct(buf, NULL, NULL) != 0) {
147 /* Shouldn't happen */
148 SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
149 SSHBUF_ABORT();
150 return SSH_ERR_INTERNAL_ERROR;
151 }
152 return 0;
153}
154#endif /* OPENSSL_HAS_ECC */
155
156int
157sshbuf_put_bignum2(struct sshbuf *buf, const BIGNUM *v)
158{
159 u_char d[SSHBUF_MAX_BIGNUM + 1];
160 int len = BN_num_bytes(v), prepend = 0, r;
161
162 if (len < 0 || len > SSHBUF_MAX_BIGNUM)
163 return SSH_ERR_INVALID_ARGUMENT;
164 *d = '\0';
165 if (BN_bn2bin(v, d + 1) != len)
166 return SSH_ERR_INTERNAL_ERROR; /* Shouldn't happen */
167 /* If MSB is set, prepend a \0 */
168 if (len > 0 && (d[1] & 0x80) != 0)
169 prepend = 1;
170 if ((r = sshbuf_put_string(buf, d + 1 - prepend, len + prepend)) < 0) {
171 bzero(d, sizeof(d));
172 return r;
173 }
174 bzero(d, sizeof(d));
175 return 0;
176}
177
178int
179sshbuf_put_bignum1(struct sshbuf *buf, const BIGNUM *v)
180{
181 int r, len_bits = BN_num_bits(v);
182 size_t len_bytes = (len_bits + 7) / 8;
183 u_char d[SSHBUF_MAX_BIGNUM], *dp;
184
185 if (len_bits < 0 || len_bytes > SSHBUF_MAX_BIGNUM)
186 return SSH_ERR_INVALID_ARGUMENT;
187 if (BN_bn2bin(v, d) != (int)len_bytes)
188 return SSH_ERR_INTERNAL_ERROR; /* Shouldn't happen */
189 if ((r = sshbuf_reserve(buf, len_bytes + 2, &dp)) < 0) {
190 bzero(d, sizeof(d));
191 return r;
192 }
193 POKE_U16(dp, len_bits);
194 memcpy(dp + 2, d, len_bytes);
195 bzero(d, sizeof(d));
196 return 0;
197}
198
199#ifdef OPENSSL_HAS_ECC
200int
201sshbuf_put_ec(struct sshbuf *buf, const EC_POINT *v, const EC_GROUP *g)
202{
203 u_char d[SSHBUF_MAX_ECPOINT];
204 BN_CTX *bn_ctx;
205 size_t len;
206 int ret;
207
208 if ((bn_ctx = BN_CTX_new()) == NULL)
209 return SSH_ERR_ALLOC_FAIL;
210 if ((len = EC_POINT_point2oct(g, v, POINT_CONVERSION_UNCOMPRESSED,
211 NULL, 0, bn_ctx)) > SSHBUF_MAX_ECPOINT) {
212 BN_CTX_free(bn_ctx);
213 return SSH_ERR_INVALID_ARGUMENT;
214 }
215 if (EC_POINT_point2oct(g, v, POINT_CONVERSION_UNCOMPRESSED,
216 d, len, bn_ctx) != len) {
217 BN_CTX_free(bn_ctx);
218 return SSH_ERR_INTERNAL_ERROR; /* Shouldn't happen */
219 }
220 BN_CTX_free(bn_ctx);
221 ret = sshbuf_put_string(buf, d, len);
222 bzero(d, len);
223 return ret;
224}
225
226int
227sshbuf_put_eckey(struct sshbuf *buf, const EC_KEY *v)
228{
229 return sshbuf_put_ec(buf, EC_KEY_get0_public_key(v),
230 EC_KEY_get0_group(v));
231}
232#endif /* OPENSSL_HAS_ECC */
233