Annotation of src/usr.bin/ssh/ssh-keysign.c, Revision 1.45
1.45 ! djm 1: /* $OpenBSD: ssh-keysign.c,v 1.44 2014/12/21 22:27:56 djm Exp $ */
1.1 markus 2: /*
3: * Copyright (c) 2002 Markus Friedl. All rights reserved.
4: *
5: * Redistribution and use in source and binary forms, with or without
6: * modification, are permitted provided that the following conditions
7: * are met:
8: * 1. Redistributions of source code must retain the above copyright
9: * notice, this list of conditions and the following disclaimer.
10: * 2. Redistributions in binary form must reproduce the above copyright
11: * notice, this list of conditions and the following disclaimer in the
12: * documentation and/or other materials provided with the distribution.
13: *
14: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24: */
1.20 stevesk 25:
1.24 stevesk 26: #include <sys/types.h>
1.1 markus 27:
28: #include <openssl/evp.h>
1.6 markus 29: #include <openssl/rsa.h>
1.24 stevesk 30:
1.25 stevesk 31: #include <fcntl.h>
1.24 stevesk 32: #include <paths.h>
33: #include <pwd.h>
1.28 stevesk 34: #include <stdlib.h>
1.27 stevesk 35: #include <string.h>
1.26 stevesk 36: #include <unistd.h>
1.1 markus 37:
1.29 deraadt 38: #include "xmalloc.h"
1.1 markus 39: #include "log.h"
40: #include "key.h"
1.7 markus 41: #include "ssh.h"
1.1 markus 42: #include "ssh2.h"
43: #include "misc.h"
44: #include "buffer.h"
45: #include "authfile.h"
46: #include "msg.h"
1.2 markus 47: #include "canohost.h"
1.1 markus 48: #include "pathnames.h"
1.7 markus 49: #include "readconf.h"
1.17 dtucker 50: #include "uidswap.h"
1.45 ! djm 51: #include "sshkey.h"
! 52: #include "ssherr.h"
1.7 markus 53:
1.12 djm 54: /* XXX readconf.c needs these */
55: uid_t original_real_uid;
1.1 markus 56:
57: static int
1.2 markus 58: valid_request(struct passwd *pw, char *host, Key **ret, u_char *data,
59: u_int datalen)
1.1 markus 60: {
61: Buffer b;
1.11 markus 62: Key *key = NULL;
1.2 markus 63: u_char *pkblob;
64: u_int blen, len;
65: char *pkalg, *p;
1.1 markus 66: int pktype, fail;
67:
1.45 ! djm 68: if (ret != NULL)
! 69: *ret = NULL;
1.1 markus 70: fail = 0;
71:
72: buffer_init(&b);
73: buffer_append(&b, data, datalen);
1.4 deraadt 74:
1.23 dtucker 75: /* session id, currently limited to SHA1 (20 bytes) or SHA256 (32) */
1.3 markus 76: p = buffer_get_string(&b, &len);
1.23 dtucker 77: if (len != 20 && len != 32)
1.3 markus 78: fail++;
1.37 djm 79: free(p);
1.3 markus 80:
1.1 markus 81: if (buffer_get_char(&b) != SSH2_MSG_USERAUTH_REQUEST)
82: fail++;
83:
84: /* server user */
85: buffer_skip_string(&b);
86:
87: /* service */
88: p = buffer_get_string(&b, NULL);
89: if (strcmp("ssh-connection", p) != 0)
90: fail++;
1.37 djm 91: free(p);
1.1 markus 92:
93: /* method */
94: p = buffer_get_string(&b, NULL);
95: if (strcmp("hostbased", p) != 0)
96: fail++;
1.37 djm 97: free(p);
1.1 markus 98:
99: /* pubkey */
100: pkalg = buffer_get_string(&b, NULL);
101: pkblob = buffer_get_string(&b, &blen);
102:
103: pktype = key_type_from_name(pkalg);
104: if (pktype == KEY_UNSPEC)
105: fail++;
106: else if ((key = key_from_blob(pkblob, blen)) == NULL)
107: fail++;
108: else if (key->type != pktype)
109: fail++;
1.37 djm 110: free(pkalg);
111: free(pkblob);
1.1 markus 112:
1.2 markus 113: /* client host name, handle trailing dot */
114: p = buffer_get_string(&b, &len);
115: debug2("valid_request: check expect chost %s got %s", host, p);
116: if (strlen(host) != len - 1)
117: fail++;
118: else if (p[len - 1] != '.')
1.4 deraadt 119: fail++;
1.2 markus 120: else if (strncasecmp(host, p, len - 1) != 0)
1.4 deraadt 121: fail++;
1.37 djm 122: free(p);
1.1 markus 123:
124: /* local user */
125: p = buffer_get_string(&b, NULL);
1.2 markus 126:
1.1 markus 127: if (strcmp(pw->pw_name, p) != 0)
128: fail++;
1.37 djm 129: free(p);
1.1 markus 130:
131: /* end of message */
132: if (buffer_len(&b) != 0)
133: fail++;
1.15 markus 134: buffer_free(&b);
1.1 markus 135:
136: debug3("valid_request: fail %d", fail);
137:
138: if (fail && key != NULL)
139: key_free(key);
140: else
141: *ret = key;
142:
143: return (fail ? -1 : 0);
144: }
145:
146: int
147: main(int argc, char **argv)
148: {
149: Buffer b;
1.7 markus 150: Options options;
1.39 markus 151: #define NUM_KEYTYPES 4
1.36 djm 152: Key *keys[NUM_KEYTYPES], *key = NULL;
1.1 markus 153: struct passwd *pw;
1.45 ! djm 154: int r, key_fd[NUM_KEYTYPES], i, found, version = 2, fd;
1.1 markus 155: u_char *signature, *data;
1.40 djm 156: char *host, *fp;
1.1 markus 157: u_int slen, dlen;
1.19 djm 158:
159: /* Ensure that stdin and stdout are connected */
160: if ((fd = open(_PATH_DEVNULL, O_RDWR)) < 2)
161: exit(1);
162: /* Leave /dev/null fd iff it is attached to stderr */
163: if (fd > 2)
164: close(fd);
1.1 markus 165:
1.36 djm 166: i = 0;
167: key_fd[i++] = open(_PATH_HOST_DSA_KEY_FILE, O_RDONLY);
168: key_fd[i++] = open(_PATH_HOST_ECDSA_KEY_FILE, O_RDONLY);
1.39 markus 169: key_fd[i++] = open(_PATH_HOST_ED25519_KEY_FILE, O_RDONLY);
1.36 djm 170: key_fd[i++] = open(_PATH_HOST_RSA_KEY_FILE, O_RDONLY);
1.1 markus 171:
1.18 dtucker 172: original_real_uid = getuid(); /* XXX readconf.c needs this */
173: if ((pw = getpwuid(original_real_uid)) == NULL)
1.17 dtucker 174: fatal("getpwuid failed");
175: pw = pwcopy(pw);
176:
177: permanently_set_uid(pw);
1.1 markus 178:
179: #ifdef DEBUG_SSH_KEYSIGN
180: log_init("ssh-keysign", SYSLOG_LEVEL_DEBUG3, SYSLOG_FACILITY_AUTH, 0);
1.4 deraadt 181: #endif
1.7 markus 182:
183: /* verify that ssh-keysign is enabled by the admin */
184: initialize_options(&options);
1.43 djm 185: (void)read_config_file(_PATH_HOST_CONFIG_FILE, pw, "", "", &options, 0);
1.7 markus 186: fill_default_options(&options);
1.8 markus 187: if (options.enable_ssh_keysign != 1)
188: fatal("ssh-keysign not enabled in %s",
1.7 markus 189: _PATH_HOST_CONFIG_FILE);
1.1 markus 190:
1.36 djm 191: for (i = found = 0; i < NUM_KEYTYPES; i++) {
192: if (key_fd[i] != -1)
193: found = 1;
194: }
195: if (found == 0)
1.1 markus 196: fatal("could not open any host key");
197:
1.35 djm 198: OpenSSL_add_all_algorithms();
1.1 markus 199:
200: found = 0;
1.36 djm 201: for (i = 0; i < NUM_KEYTYPES; i++) {
1.1 markus 202: keys[i] = NULL;
203: if (key_fd[i] == -1)
204: continue;
1.45 ! djm 205: r = sshkey_load_private_type_fd(key_fd[i], KEY_UNSPEC,
! 206: NULL, &key, NULL);
1.1 markus 207: close(key_fd[i]);
1.45 ! djm 208: if (r != 0)
! 209: debug("parse key %d: %s", i, ssh_err(r));
! 210: else if (key != NULL) {
! 211: keys[i] = key;
1.1 markus 212: found = 1;
1.45 ! djm 213: }
1.1 markus 214: }
215: if (!found)
216: fatal("no hostkey found");
217:
218: buffer_init(&b);
1.9 djm 219: if (ssh_msg_recv(STDIN_FILENO, &b) < 0)
220: fatal("ssh_msg_recv failed");
1.1 markus 221: if (buffer_get_char(&b) != version)
222: fatal("bad version");
1.2 markus 223: fd = buffer_get_int(&b);
224: if ((fd == STDIN_FILENO) || (fd == STDOUT_FILENO))
225: fatal("bad fd");
226: if ((host = get_local_name(fd)) == NULL)
1.30 dtucker 227: fatal("cannot get local name for fd");
1.4 deraadt 228:
1.1 markus 229: data = buffer_get_string(&b, &dlen);
1.2 markus 230: if (valid_request(pw, host, &key, data, dlen) < 0)
1.1 markus 231: fatal("not a valid request");
1.37 djm 232: free(host);
1.1 markus 233:
234: found = 0;
1.36 djm 235: for (i = 0; i < NUM_KEYTYPES; i++) {
1.1 markus 236: if (keys[i] != NULL &&
1.31 djm 237: key_equal_public(key, keys[i])) {
1.1 markus 238: found = 1;
239: break;
240: }
241: }
1.40 djm 242: if (!found) {
1.44 djm 243: fp = key_fingerprint(key, options.fingerprint_hash,
244: SSH_FP_DEFAULT);
1.40 djm 245: fatal("no matching hostkey found for key %s %s",
246: key_type(key), fp);
247: }
1.1 markus 248:
249: if (key_sign(keys[i], &signature, &slen, data, dlen) != 0)
250: fatal("key_sign failed");
1.37 djm 251: free(data);
1.4 deraadt 252:
1.1 markus 253: /* send reply */
254: buffer_clear(&b);
255: buffer_put_string(&b, signature, slen);
1.14 djm 256: if (ssh_msg_send(STDOUT_FILENO, version, &b) == -1)
257: fatal("ssh_msg_send failed");
1.1 markus 258:
259: return (0);
260: }