Annotation of src/usr.bin/ssh/sshbuf-getput-crypto.c, Revision 1.3
1.3 ! djm 1: /* $OpenBSD: sshbuf-getput-crypto.c,v 1.2 2014/06/18 15:42:09 naddy Exp $ */
1.1 djm 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 <sys/types.h>
19: #include <stdlib.h>
20: #include <stdio.h>
21: #include <string.h>
22:
23: #include <openssl/bn.h>
24: #include <openssl/ec.h>
25:
26: #include "ssherr.h"
27: #define SSHBUF_INTERNAL
28: #include "sshbuf.h"
29:
30: int
31: sshbuf_get_bignum2(struct sshbuf *buf, BIGNUM *v)
32: {
33: const u_char *d;
34: size_t len;
35: int r;
36:
37: if ((r = sshbuf_peek_string_direct(buf, &d, &len)) < 0)
38: return r;
1.2 naddy 39: /* Refuse negative (MSB set) bignums */
1.1 djm 40: if ((len != 0 && (*d & 0x80) != 0))
41: return SSH_ERR_BIGNUM_IS_NEGATIVE;
1.2 naddy 42: /* Refuse overlong bignums, allow prepended \0 to avoid MSB set */
43: if (len > SSHBUF_MAX_BIGNUM + 1 ||
44: (len == SSHBUF_MAX_BIGNUM + 1 && *d != 0))
1.1 djm 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:
58: int
59: sshbuf_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;
1.2 naddy 70: if (len_bytes > SSHBUF_MAX_BIGNUM)
1.1 djm 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: static int
85: get_ec(const u_char *d, size_t len, EC_POINT *v, const EC_GROUP *g)
86: {
87: /* Refuse overlong bignums */
88: if (len == 0 || len > SSHBUF_MAX_ECPOINT)
89: return SSH_ERR_ECPOINT_TOO_LARGE;
90: /* Only handle uncompressed points */
91: if (*d != POINT_CONVERSION_UNCOMPRESSED)
92: return SSH_ERR_INVALID_FORMAT;
93: if (v != NULL && EC_POINT_oct2point(g, v, d, len, NULL) != 1)
94: return SSH_ERR_INVALID_FORMAT; /* XXX assumption */
95: return 0;
96: }
97:
98: int
99: sshbuf_get_ec(struct sshbuf *buf, EC_POINT *v, const EC_GROUP *g)
100: {
101: const u_char *d;
102: size_t len;
103: int r;
104:
105: if ((r = sshbuf_peek_string_direct(buf, &d, &len)) < 0)
106: return r;
107: if ((r = get_ec(d, len, v, g)) != 0)
108: return r;
109: /* Skip string */
110: if (sshbuf_get_string_direct(buf, NULL, NULL) != 0) {
111: /* Shouldn't happen */
112: SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
113: SSHBUF_ABORT();
114: return SSH_ERR_INTERNAL_ERROR;
115: }
116: return 0;
117: }
118:
119: int
120: sshbuf_get_eckey(struct sshbuf *buf, EC_KEY *v)
121: {
122: EC_POINT *pt = EC_POINT_new(EC_KEY_get0_group(v));
123: int r;
124: const u_char *d;
125: size_t len;
126:
127: if (pt == NULL) {
128: SSHBUF_DBG(("SSH_ERR_ALLOC_FAIL"));
129: return SSH_ERR_ALLOC_FAIL;
130: }
131: if ((r = sshbuf_peek_string_direct(buf, &d, &len)) < 0) {
132: EC_POINT_free(pt);
133: return r;
134: }
135: if ((r = get_ec(d, len, pt, EC_KEY_get0_group(v))) != 0) {
136: EC_POINT_free(pt);
137: return r;
138: }
139: if (EC_KEY_set_public_key(v, pt) != 1) {
140: EC_POINT_free(pt);
141: return SSH_ERR_ALLOC_FAIL; /* XXX assumption */
142: }
143: EC_POINT_free(pt);
144: /* Skip string */
145: if (sshbuf_get_string_direct(buf, NULL, NULL) != 0) {
146: /* Shouldn't happen */
147: SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
148: SSHBUF_ABORT();
149: return SSH_ERR_INTERNAL_ERROR;
150: }
151: return 0;
152: }
153:
154: int
155: sshbuf_put_bignum2(struct sshbuf *buf, const BIGNUM *v)
156: {
157: u_char d[SSHBUF_MAX_BIGNUM + 1];
158: int len = BN_num_bytes(v), prepend = 0, r;
159:
160: if (len < 0 || len > SSHBUF_MAX_BIGNUM)
161: return SSH_ERR_INVALID_ARGUMENT;
162: *d = '\0';
163: if (BN_bn2bin(v, d + 1) != len)
164: return SSH_ERR_INTERNAL_ERROR; /* Shouldn't happen */
165: /* If MSB is set, prepend a \0 */
166: if (len > 0 && (d[1] & 0x80) != 0)
167: prepend = 1;
168: if ((r = sshbuf_put_string(buf, d + 1 - prepend, len + prepend)) < 0) {
169: bzero(d, sizeof(d));
170: return r;
171: }
172: bzero(d, sizeof(d));
173: return 0;
174: }
175:
176: int
177: sshbuf_put_bignum1(struct sshbuf *buf, const BIGNUM *v)
178: {
179: int r, len_bits = BN_num_bits(v);
180: size_t len_bytes = (len_bits + 7) / 8;
181: u_char d[SSHBUF_MAX_BIGNUM], *dp;
182:
183: if (len_bits < 0 || len_bytes > SSHBUF_MAX_BIGNUM)
184: return SSH_ERR_INVALID_ARGUMENT;
185: if (BN_bn2bin(v, d) != (int)len_bytes)
186: return SSH_ERR_INTERNAL_ERROR; /* Shouldn't happen */
187: if ((r = sshbuf_reserve(buf, len_bytes + 2, &dp)) < 0) {
188: bzero(d, sizeof(d));
189: return r;
190: }
191: POKE_U16(dp, len_bits);
1.3 ! djm 192: if (len_bytes != 0)
! 193: memcpy(dp + 2, d, len_bytes);
1.1 djm 194: bzero(d, sizeof(d));
195: return 0;
196: }
197:
198: int
199: sshbuf_put_ec(struct sshbuf *buf, const EC_POINT *v, const EC_GROUP *g)
200: {
201: u_char d[SSHBUF_MAX_ECPOINT];
202: BN_CTX *bn_ctx;
203: size_t len;
204: int ret;
205:
206: if ((bn_ctx = BN_CTX_new()) == NULL)
207: return SSH_ERR_ALLOC_FAIL;
208: if ((len = EC_POINT_point2oct(g, v, POINT_CONVERSION_UNCOMPRESSED,
209: NULL, 0, bn_ctx)) > SSHBUF_MAX_ECPOINT) {
210: BN_CTX_free(bn_ctx);
211: return SSH_ERR_INVALID_ARGUMENT;
212: }
213: if (EC_POINT_point2oct(g, v, POINT_CONVERSION_UNCOMPRESSED,
214: d, len, bn_ctx) != len) {
215: BN_CTX_free(bn_ctx);
216: return SSH_ERR_INTERNAL_ERROR; /* Shouldn't happen */
217: }
218: BN_CTX_free(bn_ctx);
219: ret = sshbuf_put_string(buf, d, len);
220: bzero(d, len);
221: return ret;
222: }
223:
224: int
225: sshbuf_put_eckey(struct sshbuf *buf, const EC_KEY *v)
226: {
227: return sshbuf_put_ec(buf, EC_KEY_get0_public_key(v),
228: EC_KEY_get0_group(v));
229: }
230: