Annotation of src/usr.bin/ssh/auth-rsa.c, Revision 1.40
1.1 provos 1: /*
1.13 deraadt 2: * Author: Tatu Ylonen <ylo@cs.hut.fi>
3: * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4: * All rights reserved
5: * RSA-based authentication. This code determines whether to admit a login
6: * based on RSA authentication. This file also contains functions to check
7: * validity of the host key.
1.21 markus 8: *
1.28 deraadt 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".
1.13 deraadt 14: */
1.1 provos 15:
16: #include "includes.h"
1.40 ! markus 17: RCSID("$OpenBSD: auth-rsa.c,v 1.39 2001/03/01 02:45:10 deraadt Exp $");
1.38 markus 18:
19: #include <openssl/rsa.h>
20: #include <openssl/md5.h>
1.1 provos 21:
22: #include "rsa.h"
23: #include "packet.h"
24: #include "xmalloc.h"
1.35 markus 25: #include "ssh1.h"
1.1 provos 26: #include "mpaux.h"
27: #include "uidswap.h"
1.19 markus 28: #include "match.h"
1.25 markus 29: #include "auth-options.h"
1.35 markus 30: #include "pathnames.h"
1.38 markus 31: #include "log.h"
32: #include "servconf.h"
33: #include "auth.h"
1.30 markus 34:
35: /* import */
36: extern ServerOptions options;
37:
1.14 markus 38: /*
39: * Session identifier that is used to bind key exchange and authentication
40: * responses to a particular session.
41: */
1.34 markus 42: extern u_char session_id[16];
1.1 provos 43:
1.14 markus 44: /*
45: * The .ssh/authorized_keys file contains public keys, one per line, in the
46: * following format:
47: * options bits e n comment
48: * where bits, e and n are decimal numbers,
49: * and comment is any string of characters up to newline. The maximum
50: * length of a line is 8000 characters. See the documentation for a
51: * description of the options.
52: */
53:
54: /*
55: * Performs the RSA authentication challenge-response dialog with the client,
56: * and returns true (non-zero) if the client gave the correct answer to
57: * our challenge; returns zero if the client gives a wrong answer.
58: */
1.1 provos 59:
60: int
1.19 markus 61: auth_rsa_challenge_dialog(RSA *pk)
1.1 provos 62: {
1.18 markus 63: BIGNUM *challenge, *encrypted_challenge;
64: BN_CTX *ctx;
1.34 markus 65: u_char buf[32], mdbuf[16], response[16];
1.12 markus 66: MD5_CTX md;
1.34 markus 67: u_int i;
1.12 markus 68: int plen, len;
69:
70: encrypted_challenge = BN_new();
71: challenge = BN_new();
72:
73: /* Generate a random challenge. */
74: BN_rand(challenge, 256, 0, 0);
1.18 markus 75: ctx = BN_CTX_new();
1.19 markus 76: BN_mod(challenge, challenge, pk->n, ctx);
1.18 markus 77: BN_CTX_free(ctx);
1.12 markus 78:
79: /* Encrypt the challenge with the public key. */
80: rsa_public_encrypt(encrypted_challenge, challenge, pk);
81:
82: /* Send the encrypted challenge to the client. */
83: packet_start(SSH_SMSG_AUTH_RSA_CHALLENGE);
84: packet_put_bignum(encrypted_challenge);
85: packet_send();
1.18 markus 86: BN_clear_free(encrypted_challenge);
1.12 markus 87: packet_write_wait();
88:
1.18 markus 89: /* Wait for a response. */
90: packet_read_expect(&plen, SSH_CMSG_AUTH_RSA_RESPONSE);
91: packet_integrity_check(plen, 16, SSH_CMSG_AUTH_RSA_RESPONSE);
92: for (i = 0; i < 16; i++)
93: response[i] = packet_get_char();
94:
1.12 markus 95: /* The response is MD5 of decrypted challenge plus session id. */
96: len = BN_num_bytes(challenge);
97: if (len <= 0 || len > 32)
98: fatal("auth_rsa_challenge_dialog: bad challenge length %d", len);
99: memset(buf, 0, 32);
100: BN_bn2bin(challenge, buf + 32 - len);
101: MD5_Init(&md);
102: MD5_Update(&md, buf, 32);
103: MD5_Update(&md, session_id, 16);
104: MD5_Final(mdbuf, &md);
105: BN_clear_free(challenge);
106:
107: /* Verify that the response is the original challenge. */
108: if (memcmp(response, mdbuf, 16) != 0) {
109: /* Wrong answer. */
110: return 0;
111: }
112: /* Correct answer. */
113: return 1;
1.1 provos 114: }
115:
1.14 markus 116: /*
117: * Performs the RSA authentication dialog with the client. This returns
118: * 0 if the client could not be authenticated, and 1 if authentication was
119: * successful. This may exit if there is a serious protocol violation.
120: */
1.1 provos 121:
122: int
1.8 markus 123: auth_rsa(struct passwd *pw, BIGNUM *client_n)
1.1 provos 124: {
1.37 markus 125: char line[8192], file[MAXPATHLEN];
1.12 markus 126: int authenticated;
1.34 markus 127: u_int bits;
1.12 markus 128: FILE *f;
1.34 markus 129: u_long linenum = 0;
1.12 markus 130: struct stat st;
1.19 markus 131: RSA *pk;
1.30 markus 132:
133: /* no user given */
134: if (pw == NULL)
135: return 0;
1.12 markus 136:
137: /* Temporarily use the user's uid. */
1.40 ! markus 138: temporarily_use_uid(pw);
1.12 markus 139:
140: /* The authorized keys. */
141: snprintf(file, sizeof file, "%.500s/%.100s", pw->pw_dir,
1.35 markus 142: _PATH_SSH_USER_PERMITTED_KEYS);
1.12 markus 143:
144: /* Fail quietly if file does not exist */
145: if (stat(file, &st) < 0) {
146: /* Restore the privileged uid. */
147: restore_uid();
148: return 0;
149: }
150: /* Open the file containing the authorized keys. */
151: f = fopen(file, "r");
152: if (!f) {
153: /* Restore the privileged uid. */
154: restore_uid();
155: packet_send_debug("Could not open %.900s for reading.", file);
156: packet_send_debug("If your home is on an NFS volume, it may need to be world-readable.");
157: return 0;
1.1 provos 158: }
1.12 markus 159: if (options.strict_modes) {
160: int fail = 0;
161: char buf[1024];
162: /* Check open file in order to avoid open/stat races */
163: if (fstat(fileno(f), &st) < 0 ||
164: (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
165: (st.st_mode & 022) != 0) {
166: snprintf(buf, sizeof buf, "RSA authentication refused for %.100s: "
167: "bad ownership or modes for '%s'.", pw->pw_name, file);
168: fail = 1;
169: } else {
1.35 markus 170: /* Check path to _PATH_SSH_USER_PERMITTED_KEYS */
1.12 markus 171: int i;
172: static const char *check[] = {
1.35 markus 173: "", _PATH_SSH_USER_DIR, NULL
1.12 markus 174: };
175: for (i = 0; check[i]; i++) {
176: snprintf(line, sizeof line, "%.500s/%.100s", pw->pw_dir, check[i]);
177: if (stat(line, &st) < 0 ||
178: (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
179: (st.st_mode & 022) != 0) {
180: snprintf(buf, sizeof buf, "RSA authentication refused for %.100s: "
181: "bad ownership or modes for '%s'.", pw->pw_name, line);
182: fail = 1;
183: break;
184: }
185: }
186: }
187: if (fail) {
1.22 markus 188: fclose(f);
1.39 deraadt 189: log("%s", buf);
190: packet_send_debug("%s", buf);
1.12 markus 191: restore_uid();
192: return 0;
193: }
1.1 provos 194: }
1.12 markus 195: /* Flag indicating whether authentication has succeeded. */
196: authenticated = 0;
1.1 provos 197:
1.19 markus 198: pk = RSA_new();
199: pk->e = BN_new();
200: pk->n = BN_new();
1.12 markus 201:
1.14 markus 202: /*
203: * Go though the accepted keys, looking for the current key. If
204: * found, perform a challenge-response dialog to verify that the
205: * user really has the corresponding private key.
206: */
1.12 markus 207: while (fgets(line, sizeof(line), f)) {
208: char *cp;
209: char *options;
210:
211: linenum++;
212:
1.14 markus 213: /* Skip leading whitespace, empty and comment lines. */
214: for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
215: ;
1.12 markus 216: if (!*cp || *cp == '\n' || *cp == '#')
217: continue;
218:
1.14 markus 219: /*
220: * Check if there are options for this key, and if so,
221: * save their starting address and skip the option part
222: * for now. If there are no options, set the starting
223: * address to NULL.
224: */
1.12 markus 225: if (*cp < '0' || *cp > '9') {
226: int quoted = 0;
227: options = cp;
228: for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
229: if (*cp == '\\' && cp[1] == '"')
230: cp++; /* Skip both */
231: else if (*cp == '"')
232: quoted = !quoted;
233: }
234: } else
235: options = NULL;
1.1 provos 236:
1.12 markus 237: /* Parse the key from the line. */
1.19 markus 238: if (!auth_rsa_read_key(&cp, &bits, pk->e, pk->n)) {
1.12 markus 239: debug("%.100s, line %lu: bad key syntax",
1.36 markus 240: file, linenum);
1.12 markus 241: packet_send_debug("%.100s, line %lu: bad key syntax",
1.36 markus 242: file, linenum);
1.12 markus 243: continue;
1.1 provos 244: }
1.12 markus 245: /* cp now points to the comment part. */
246:
1.16 markus 247: /* Check if the we have found the desired key (identified by its modulus). */
1.19 markus 248: if (BN_cmp(pk->n, client_n) != 0)
1.16 markus 249: continue;
250:
1.12 markus 251: /* check the real bits */
1.19 markus 252: if (bits != BN_num_bits(pk->n))
1.15 markus 253: log("Warning: %s, line %ld: keysize mismatch: "
254: "actual %d vs. announced %d.",
1.19 markus 255: file, linenum, BN_num_bits(pk->n), bits);
1.12 markus 256:
257: /* We have found the desired key. */
1.33 markus 258: /*
259: * If our options do not allow this key to be used,
260: * do not send challenge.
261: */
1.36 markus 262: if (!auth_parse_options(pw, options, file, linenum))
1.33 markus 263: continue;
1.19 markus 264:
1.12 markus 265: /* Perform the challenge-response dialog for this key. */
1.19 markus 266: if (!auth_rsa_challenge_dialog(pk)) {
1.12 markus 267: /* Wrong response. */
268: verbose("Wrong response to RSA authentication challenge.");
269: packet_send_debug("Wrong response to RSA authentication challenge.");
270: continue;
1.1 provos 271: }
1.14 markus 272: /*
273: * Correct response. The client has been successfully
274: * authenticated. Note that we have not yet processed the
275: * options; this will be reset if the options cause the
276: * authentication to be rejected.
277: * Break out of the loop if authentication was successful;
278: * otherwise continue searching.
279: */
1.32 markus 280: authenticated = 1;
281: break;
1.1 provos 282: }
283:
1.12 markus 284: /* Restore the privileged uid. */
285: restore_uid();
286:
287: /* Close the file. */
288: fclose(f);
289:
1.19 markus 290: RSA_free(pk);
1.1 provos 291:
1.12 markus 292: if (authenticated)
293: packet_send_debug("RSA authentication accepted.");
1.31 markus 294: else
295: auth_clear_options();
1.1 provos 296:
1.12 markus 297: /* Return authentication result. */
298: return authenticated;
1.1 provos 299: }