Annotation of src/usr.bin/gzsig/ssh2.c, Revision 1.3
1.3 ! jsg 1: /* $OpenBSD: ssh2.c,v 1.2 2005/05/29 09:10:23 djm Exp $ */
1.1 marius 2: /*
3: * ssh2.c
4: *
5: * Copyright (c) 2005 Marius Eriksen <marius@openbsd.org>
6: *
7: * Permission to use, copy, modify, and distribute this software for any
8: * purpose with or without fee is hereby granted, provided that the above
9: * copyright notice and this permission notice appear in all copies.
10: *
11: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18: */
19:
20: #include <sys/types.h>
21: #include <sys/uio.h>
22:
1.2 djm 23: #include <netinet/in.h>
1.1 marius 24: #include <arpa/nameser.h>
25: #include <openssl/ssl.h>
26: #include <openssl/des.h>
27: #include <openssl/md5.h>
28:
29: #include <errno.h>
30: #include <stdio.h>
31: #include <stdlib.h>
32: #include <string.h>
33: #include <unistd.h>
1.2 djm 34: #include <resolv.h>
1.1 marius 35: #include <err.h>
36:
37: #include "key.h"
38: #include "ssh2.h"
39:
40: #define GET_32BIT(cp) (((u_long)(u_char)(cp)[0] << 24) | \
41: ((u_long)(u_char)(cp)[1] << 16) | \
42: ((u_long)(u_char)(cp)[2] << 8) | \
43: ((u_long)(u_char)(cp)[3]))
44:
45: /* From OpenSSH */
46: static int
47: _uudecode(const char *src, u_char *target, size_t targsize)
48: {
49: int len;
50: char *encoded, *p;
51:
52: /* copy the 'readonly' source */
53: if ((encoded = strdup(src)) == NULL)
1.2 djm 54: err(1, "strdup");
1.1 marius 55: /* skip whitespace and data */
56: for (p = encoded; *p == ' ' || *p == '\t'; p++)
57: ;
58: for (; *p != '\0' && *p != ' ' && *p != '\t'; p++)
59: ;
60: /* and remove trailing whitespace because __b64_pton needs this */
61: *p = '\0';
62: len = __b64_pton(encoded, target, targsize);
63:
64: free(encoded);
65:
66: return len;
67: }
68:
69: /*
70: * Small compatibility layer for the OpenSSH buffers. Only what we
71: * need here.
72: */
73:
74: static int
75: _keyfromstr(char *str, int len)
76: {
77: if (strncmp(str, "rsa", len) == 0 ||
78: strncmp(str, "ssh-rsa", len) == 0)
79: return KEY_RSA;
80: else if (strncmp(str, "dsa", len) == 0 ||
81: strncmp(str, "ssh-dss", len) == 0)
82: return KEY_DSA;
83:
84: return (-1);
85: }
86:
87: static int
88: _read_int(struct iovec *iov, int *ival)
89: {
90: iov->iov_len -= 4;
91: if (iov->iov_len < 0)
92: return (-1);
93: *ival = GET_32BIT((u_char *)iov->iov_base);
1.3 ! jsg 94: iov->iov_base = (u_char*)iov->iov_base + 4;
1.1 marius 95:
96: return (0);
97: }
98:
99: static int
100: _read_opaque(struct iovec *iov, u_char **buf, int *len)
101: {
102: if (_read_int(iov, len) < 0 || *len < 0)
103: return (-1);
104:
105: iov->iov_len -= *len;
106: if (iov->iov_len < 0)
107: return (-1);
108:
109: *buf = iov->iov_base;
1.3 ! jsg 110: iov->iov_base = (u_char*)iov->iov_base + *len;
1.1 marius 111:
112: return (0);
113: }
114:
115: static int
116: _read_bignum(struct iovec *iov, BIGNUM *bn)
117: {
118: u_char *bp;
119: int blen;
120:
121: if (_read_opaque(iov, &bp, &blen) < 0)
122: return (-1);
123:
124: if ((blen > 0 && bp[0] & 0x80) || /* No negative values */
125: (blen > 8*1024)) /* Too large */
126: return (-1);
127:
128: BN_bin2bn(bp, blen, bn);
129:
130: return (0);
131: }
132:
133: int
134: ssh2_load_public(struct key *k, struct iovec *iovp)
135: {
1.2 djm 136: int len, keytype, error = 0;
1.1 marius 137: u_char *bp;
138: struct iovec iov;
139: /* iov->iov_base is NULL terminated */
140: char *cp0, *savep = NULL, *cp = iovp->iov_base;
141:
142: if ((cp0 = strchr(cp, ' ')) == NULL)
143: return (-1);
144:
145: len = cp0 - cp;
146:
147: if ((keytype = _keyfromstr(cp, len)) < 0)
148: return (-1);
149:
150: /* cp0 is a space (' '), so we have at least one more */
151: cp = cp0 + 1;
152:
153: len = 2*strlen(cp);
154: if ((savep = iov.iov_base = malloc(len)) == NULL)
1.2 djm 155: err(1, "malloc(%d)", len);
1.1 marius 156: iov.iov_len = _uudecode(cp, iov.iov_base, len);
157:
158: if (_read_opaque(&iov, &bp, &len) < 0 ||
159: keytype != _keyfromstr(bp, len)) {
160: error = -1;
161: goto out;
162: }
163:
164: k->type = keytype;
165: switch (keytype) {
166: case KEY_RSA: {
167: RSA *rsa;
168:
169: if ((rsa = RSA_new()) == NULL ||
170: (rsa->e = BN_new()) == NULL ||
171: (rsa->n = BN_new()) == NULL)
1.2 djm 172: errx(1, "BN_new");
1.1 marius 173:
174: if (_read_bignum(&iov, rsa->e) < 0 ||
175: _read_bignum(&iov, rsa->n) < 0) {
176: error = -1;
177: RSA_free(rsa);
178: goto out;
179: }
180:
181: k->data = (void *)rsa;
182:
183: break;
184: }
185: case KEY_DSA: {
186: DSA *dsa;
187:
188: if ((dsa = DSA_new()) == NULL ||
189: (dsa->p = BN_new()) == NULL ||
190: (dsa->q = BN_new()) == NULL ||
191: (dsa->g = BN_new()) == NULL ||
192: (dsa->pub_key = BN_new()) == NULL)
1.2 djm 193: errx(1, "BN_new");
1.1 marius 194:
195: if (_read_bignum(&iov, dsa->p) < 0 ||
196: _read_bignum(&iov, dsa->q) < 0 ||
197: _read_bignum(&iov, dsa->g) < 0 ||
198: _read_bignum(&iov, dsa->pub_key) < 0) {
199: error = -1;
200: DSA_free(dsa);
201: goto out;
202: }
203:
204: k->data = (void *)dsa;
205:
206: break;
207: }
208: default:
209: error = -1;
210: }
211:
212: #if 0
213: if (iov->iov_len != 0)
214: /* Sanity check. */
215: return (-1);
216: #endif
217:
218:
219: out:
220: if (savep != NULL)
221: free(savep);
222: return (error);
223: }