]> andersk Git - openssh.git/blame - auth-rsa.c
- OpenBSD CVS updates.
[openssh.git] / auth-rsa.c
CommitLineData
8efc0c15 1/*
6ae2364d 2 *
5260325f 3 * auth-rsa.c
6ae2364d 4 *
5260325f 5 * Author: Tatu Ylonen <ylo@cs.hut.fi>
6ae2364d 6 *
5260325f 7 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8 * All rights reserved
6ae2364d 9 *
5260325f 10 * Created: Mon Mar 27 01:46:52 1995 ylo
6ae2364d 11 *
5260325f 12 * RSA-based authentication. This code determines whether to admit a login
13 * based on RSA authentication. This file also contains functions to check
14 * validity of the host key.
6ae2364d 15 *
5260325f 16 */
8efc0c15 17
18#include "includes.h"
19RCSID("$Id$");
20
21#include "rsa.h"
22#include "packet.h"
23#include "xmalloc.h"
24#include "ssh.h"
25#include "mpaux.h"
26#include "uidswap.h"
4fe2af09 27#include "match.h"
6fa724bc 28#include "servconf.h"
8efc0c15 29
5881cd60 30#ifdef HAVE_OPENSSL
8efc0c15 31#include <openssl/rsa.h>
32#include <openssl/md5.h>
5881cd60 33#endif
34#ifdef HAVE_SSL
35#include <ssl/rsa.h>
36#include <ssl/md5.h>
37#endif
8efc0c15 38
39/* Flags that may be set in authorized_keys options. */
40extern int no_port_forwarding_flag;
41extern int no_agent_forwarding_flag;
42extern int no_x11_forwarding_flag;
43extern int no_pty_flag;
44extern char *forced_command;
45extern struct envstring *custom_environment;
46
aa3378df 47/*
48 * Session identifier that is used to bind key exchange and authentication
49 * responses to a particular session.
50 */
8efc0c15 51extern unsigned char session_id[16];
52
aa3378df 53/*
54 * The .ssh/authorized_keys file contains public keys, one per line, in the
55 * following format:
56 * options bits e n comment
57 * where bits, e and n are decimal numbers,
58 * and comment is any string of characters up to newline. The maximum
59 * length of a line is 8000 characters. See the documentation for a
60 * description of the options.
61 */
8efc0c15 62
aa3378df 63/*
64 * Performs the RSA authentication challenge-response dialog with the client,
65 * and returns true (non-zero) if the client gave the correct answer to
66 * our challenge; returns zero if the client gives a wrong answer.
67 */
8efc0c15 68
69int
4fe2af09 70auth_rsa_challenge_dialog(RSA *pk)
8efc0c15 71{
c8d54615 72 BIGNUM *challenge, *encrypted_challenge;
c8d54615 73 BN_CTX *ctx;
5260325f 74 unsigned char buf[32], mdbuf[16], response[16];
75 MD5_CTX md;
76 unsigned int i;
77 int plen, len;
78
79 encrypted_challenge = BN_new();
80 challenge = BN_new();
5260325f 81
82 /* Generate a random challenge. */
83 BN_rand(challenge, 256, 0, 0);
c8d54615 84 ctx = BN_CTX_new();
4fe2af09 85 BN_mod(challenge, challenge, pk->n, ctx);
c8d54615 86 BN_CTX_free(ctx);
5260325f 87
5260325f 88 /* Encrypt the challenge with the public key. */
89 rsa_public_encrypt(encrypted_challenge, challenge, pk);
5260325f 90
91 /* Send the encrypted challenge to the client. */
92 packet_start(SSH_SMSG_AUTH_RSA_CHALLENGE);
93 packet_put_bignum(encrypted_challenge);
94 packet_send();
c8d54615 95 BN_clear_free(encrypted_challenge);
5260325f 96 packet_write_wait();
97
c8d54615 98 /* Wait for a response. */
99 packet_read_expect(&plen, SSH_CMSG_AUTH_RSA_RESPONSE);
100 packet_integrity_check(plen, 16, SSH_CMSG_AUTH_RSA_RESPONSE);
101 for (i = 0; i < 16; i++)
102 response[i] = packet_get_char();
103
5260325f 104 /* The response is MD5 of decrypted challenge plus session id. */
105 len = BN_num_bytes(challenge);
106 if (len <= 0 || len > 32)
107 fatal("auth_rsa_challenge_dialog: bad challenge length %d", len);
108 memset(buf, 0, 32);
109 BN_bn2bin(challenge, buf + 32 - len);
110 MD5_Init(&md);
111 MD5_Update(&md, buf, 32);
112 MD5_Update(&md, session_id, 16);
113 MD5_Final(mdbuf, &md);
5260325f 114 BN_clear_free(challenge);
5260325f 115
116 /* Verify that the response is the original challenge. */
117 if (memcmp(response, mdbuf, 16) != 0) {
118 /* Wrong answer. */
119 return 0;
120 }
121 /* Correct answer. */
122 return 1;
8efc0c15 123}
124
aa3378df 125/*
126 * Performs the RSA authentication dialog with the client. This returns
127 * 0 if the client could not be authenticated, and 1 if authentication was
128 * successful. This may exit if there is a serious protocol violation.
129 */
8efc0c15 130
131int
6fa724bc 132auth_rsa(struct passwd *pw, BIGNUM *client_n)
8efc0c15 133{
5260325f 134 extern ServerOptions options;
135 char line[8192], file[1024];
136 int authenticated;
137 unsigned int bits;
138 FILE *f;
139 unsigned long linenum = 0;
140 struct stat st;
4fe2af09 141 RSA *pk;
5260325f 142
143 /* Temporarily use the user's uid. */
144 temporarily_use_uid(pw->pw_uid);
145
146 /* The authorized keys. */
147 snprintf(file, sizeof file, "%.500s/%.100s", pw->pw_dir,
148 SSH_USER_PERMITTED_KEYS);
149
150 /* Fail quietly if file does not exist */
151 if (stat(file, &st) < 0) {
152 /* Restore the privileged uid. */
153 restore_uid();
154 return 0;
8efc0c15 155 }
5260325f 156 /* Open the file containing the authorized keys. */
157 f = fopen(file, "r");
158 if (!f) {
159 /* Restore the privileged uid. */
160 restore_uid();
161 packet_send_debug("Could not open %.900s for reading.", file);
162 packet_send_debug("If your home is on an NFS volume, it may need to be world-readable.");
163 return 0;
8efc0c15 164 }
5260325f 165 if (options.strict_modes) {
166 int fail = 0;
167 char buf[1024];
168 /* Check open file in order to avoid open/stat races */
169 if (fstat(fileno(f), &st) < 0 ||
170 (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
171 (st.st_mode & 022) != 0) {
172 snprintf(buf, sizeof buf, "RSA authentication refused for %.100s: "
173 "bad ownership or modes for '%s'.", pw->pw_name, file);
174 fail = 1;
175 } else {
176 /* Check path to SSH_USER_PERMITTED_KEYS */
177 int i;
178 static const char *check[] = {
179 "", SSH_USER_DIR, NULL
180 };
181 for (i = 0; check[i]; i++) {
182 snprintf(line, sizeof line, "%.500s/%.100s", pw->pw_dir, check[i]);
183 if (stat(line, &st) < 0 ||
184 (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
185 (st.st_mode & 022) != 0) {
186 snprintf(buf, sizeof buf, "RSA authentication refused for %.100s: "
187 "bad ownership or modes for '%s'.", pw->pw_name, line);
188 fail = 1;
189 break;
190 }
191 }
8efc0c15 192 }
5260325f 193 if (fail) {
194 log(buf);
195 packet_send_debug(buf);
196 restore_uid();
197 return 0;
8efc0c15 198 }
5260325f 199 }
200 /* Flag indicating whether authentication has succeeded. */
201 authenticated = 0;
202
4fe2af09 203 pk = RSA_new();
204 pk->e = BN_new();
205 pk->n = BN_new();
5260325f 206
aa3378df 207 /*
208 * Go though the accepted keys, looking for the current key. If
209 * found, perform a challenge-response dialog to verify that the
210 * user really has the corresponding private key.
211 */
5260325f 212 while (fgets(line, sizeof(line), f)) {
213 char *cp;
214 char *options;
215
216 linenum++;
217
aa3378df 218 /* Skip leading whitespace, empty and comment lines. */
219 for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
220 ;
5260325f 221 if (!*cp || *cp == '\n' || *cp == '#')
222 continue;
223
aa3378df 224 /*
225 * Check if there are options for this key, and if so,
226 * save their starting address and skip the option part
227 * for now. If there are no options, set the starting
228 * address to NULL.
229 */
5260325f 230 if (*cp < '0' || *cp > '9') {
231 int quoted = 0;
232 options = cp;
233 for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
234 if (*cp == '\\' && cp[1] == '"')
235 cp++; /* Skip both */
236 else if (*cp == '"')
237 quoted = !quoted;
8efc0c15 238 }
5260325f 239 } else
240 options = NULL;
241
242 /* Parse the key from the line. */
4fe2af09 243 if (!auth_rsa_read_key(&cp, &bits, pk->e, pk->n)) {
5260325f 244 debug("%.100s, line %lu: bad key syntax",
245 SSH_USER_PERMITTED_KEYS, linenum);
246 packet_send_debug("%.100s, line %lu: bad key syntax",
6ae2364d 247 SSH_USER_PERMITTED_KEYS, linenum);
5260325f 248 continue;
8efc0c15 249 }
5260325f 250 /* cp now points to the comment part. */
251
5260325f 252 /* Check if the we have found the desired key (identified by its modulus). */
4fe2af09 253 if (BN_cmp(pk->n, client_n) != 0)
aa3378df 254 continue;
5260325f 255
57112b5a 256 /* check the real bits */
4fe2af09 257 if (bits != BN_num_bits(pk->n))
57112b5a 258 log("Warning: %s, line %ld: keysize mismatch: "
259 "actual %d vs. announced %d.",
4fe2af09 260 file, linenum, BN_num_bits(pk->n), bits);
57112b5a 261
5260325f 262 /* We have found the desired key. */
263
4fe2af09 264
5260325f 265 /* Perform the challenge-response dialog for this key. */
4fe2af09 266 if (!auth_rsa_challenge_dialog(pk)) {
5260325f 267 /* Wrong response. */
268 verbose("Wrong response to RSA authentication challenge.");
269 packet_send_debug("Wrong response to RSA authentication challenge.");
270 continue;
8efc0c15 271 }
aa3378df 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 */
5260325f 278 authenticated = 1;
279
280 /* RSA part of authentication was accepted. Now process the options. */
281 if (options) {
282 while (*options && *options != ' ' && *options != '\t') {
283 cp = "no-port-forwarding";
284 if (strncmp(options, cp, strlen(cp)) == 0) {
285 packet_send_debug("Port forwarding disabled.");
286 no_port_forwarding_flag = 1;
287 options += strlen(cp);
288 goto next_option;
289 }
290 cp = "no-agent-forwarding";
291 if (strncmp(options, cp, strlen(cp)) == 0) {
292 packet_send_debug("Agent forwarding disabled.");
293 no_agent_forwarding_flag = 1;
294 options += strlen(cp);
295 goto next_option;
296 }
297 cp = "no-X11-forwarding";
298 if (strncmp(options, cp, strlen(cp)) == 0) {
299 packet_send_debug("X11 forwarding disabled.");
300 no_x11_forwarding_flag = 1;
301 options += strlen(cp);
302 goto next_option;
303 }
304 cp = "no-pty";
305 if (strncmp(options, cp, strlen(cp)) == 0) {
306 packet_send_debug("Pty allocation disabled.");
307 no_pty_flag = 1;
308 options += strlen(cp);
309 goto next_option;
310 }
311 cp = "command=\"";
312 if (strncmp(options, cp, strlen(cp)) == 0) {
313 int i;
314 options += strlen(cp);
315 forced_command = xmalloc(strlen(options) + 1);
316 i = 0;
317 while (*options) {
318 if (*options == '"')
319 break;
320 if (*options == '\\' && options[1] == '"') {
321 options += 2;
322 forced_command[i++] = '"';
323 continue;
324 }
325 forced_command[i++] = *options++;
326 }
327 if (!*options) {
328 debug("%.100s, line %lu: missing end quote",
329 SSH_USER_PERMITTED_KEYS, linenum);
330 packet_send_debug("%.100s, line %lu: missing end quote",
331 SSH_USER_PERMITTED_KEYS, linenum);
332 continue;
333 }
334 forced_command[i] = 0;
335 packet_send_debug("Forced command: %.900s", forced_command);
336 options++;
337 goto next_option;
338 }
339 cp = "environment=\"";
340 if (strncmp(options, cp, strlen(cp)) == 0) {
341 int i;
342 char *s;
343 struct envstring *new_envstring;
344 options += strlen(cp);
345 s = xmalloc(strlen(options) + 1);
346 i = 0;
347 while (*options) {
348 if (*options == '"')
349 break;
350 if (*options == '\\' && options[1] == '"') {
351 options += 2;
352 s[i++] = '"';
353 continue;
354 }
355 s[i++] = *options++;
356 }
357 if (!*options) {
358 debug("%.100s, line %lu: missing end quote",
359 SSH_USER_PERMITTED_KEYS, linenum);
360 packet_send_debug("%.100s, line %lu: missing end quote",
361 SSH_USER_PERMITTED_KEYS, linenum);
362 continue;
363 }
364 s[i] = 0;
365 packet_send_debug("Adding to environment: %.900s", s);
366 debug("Adding to environment: %.900s", s);
367 options++;
368 new_envstring = xmalloc(sizeof(struct envstring));
369 new_envstring->s = s;
370 new_envstring->next = custom_environment;
371 custom_environment = new_envstring;
372 goto next_option;
373 }
374 cp = "from=\"";
375 if (strncmp(options, cp, strlen(cp)) == 0) {
376 char *patterns = xmalloc(strlen(options) + 1);
377 int i;
378 options += strlen(cp);
379 i = 0;
380 while (*options) {
381 if (*options == '"')
382 break;
383 if (*options == '\\' && options[1] == '"') {
384 options += 2;
385 patterns[i++] = '"';
386 continue;
387 }
388 patterns[i++] = *options++;
389 }
390 if (!*options) {
391 debug("%.100s, line %lu: missing end quote",
392 SSH_USER_PERMITTED_KEYS, linenum);
393 packet_send_debug("%.100s, line %lu: missing end quote",
394 SSH_USER_PERMITTED_KEYS, linenum);
395 continue;
396 }
397 patterns[i] = 0;
398 options++;
399 if (!match_hostname(get_canonical_hostname(), patterns,
400 strlen(patterns)) &&
401 !match_hostname(get_remote_ipaddr(), patterns,
402 strlen(patterns))) {
403 log("RSA authentication tried for %.100s with correct key but not from a permitted host (host=%.200s, ip=%.200s).",
404 pw->pw_name, get_canonical_hostname(),
405 get_remote_ipaddr());
406 packet_send_debug("Your host '%.200s' is not permitted to use this key for login.",
407 get_canonical_hostname());
408 xfree(patterns);
7b2ea3a1 409 /* key invalid for this host, reset flags */
5260325f 410 authenticated = 0;
7b2ea3a1 411 no_agent_forwarding_flag = 0;
412 no_port_forwarding_flag = 0;
413 no_pty_flag = 0;
414 no_x11_forwarding_flag = 0;
415 while (custom_environment) {
416 struct envstring *ce = custom_environment;
417 custom_environment = ce->next;
418 xfree(ce->s);
419 xfree(ce);
420 }
421 if (forced_command) {
422 xfree(forced_command);
423 forced_command = NULL;
424 }
5260325f 425 break;
426 }
427 xfree(patterns);
428 /* Host name matches. */
429 goto next_option;
430 }
431 bad_option:
5260325f 432 log("Bad options in %.100s file, line %lu: %.50s",
433 SSH_USER_PERMITTED_KEYS, linenum, options);
434 packet_send_debug("Bad options in %.100s file, line %lu: %.50s",
435 SSH_USER_PERMITTED_KEYS, linenum, options);
436 authenticated = 0;
437 break;
438
439 next_option:
aa3378df 440 /*
441 * Skip the comma, and move to the next option
442 * (or break out if there are no more).
443 */
5260325f 444 if (!*options)
445 fatal("Bugs in auth-rsa.c option processing.");
446 if (*options == ' ' || *options == '\t')
aa3378df 447 break; /* End of options. */
5260325f 448 if (*options != ',')
449 goto bad_option;
450 options++;
451 /* Process the next option. */
452 continue;
8efc0c15 453 }
8efc0c15 454 }
aa3378df 455 /*
456 * Break out of the loop if authentication was successful;
457 * otherwise continue searching.
458 */
5260325f 459 if (authenticated)
460 break;
8efc0c15 461 }
462
5260325f 463 /* Restore the privileged uid. */
464 restore_uid();
8efc0c15 465
5260325f 466 /* Close the file. */
467 fclose(f);
8efc0c15 468
4fe2af09 469 RSA_free(pk);
8efc0c15 470
5260325f 471 if (authenticated)
472 packet_send_debug("RSA authentication accepted.");
8efc0c15 473
5260325f 474 /* Return authentication result. */
475 return authenticated;
8efc0c15 476}
This page took 0.119349 seconds and 5 git commands to generate.