+/* $OpenBSD: auth-rsa.c,v 1.72 2006/11/06 21:25:27 markus Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
*/
#include "includes.h"
-RCSID("$OpenBSD: auth-rsa.c,v 1.51 2002/03/14 16:56:33 markus Exp $");
+
+#include <sys/types.h>
+#include <sys/stat.h>
#include <openssl/rsa.h>
#include <openssl/md5.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "xmalloc.h"
#include "rsa.h"
#include "packet.h"
-#include "xmalloc.h"
#include "ssh1.h"
-#include "mpaux.h"
#include "uidswap.h"
#include "match.h"
+#include "buffer.h"
#include "auth-options.h"
#include "pathnames.h"
#include "log.h"
#include "servconf.h"
-#include "auth.h"
+#include "key.h"
#include "hostfile.h"
+#include "auth.h"
+#ifdef GSSAPI
+#include "ssh-gss.h"
+#endif
+#include "monitor_wrap.h"
+#include "ssh.h"
+#include "misc.h"
/* import */
extern ServerOptions options;
* options bits e n comment
* where bits, e and n are decimal numbers,
* and comment is any string of characters up to newline. The maximum
- * length of a line is 8000 characters. See the documentation for a
+ * length of a line is SSH_MAX_PUBKEY_BYTES characters. See sshd(8) for a
* description of the options.
*/
-static BIGNUM *
+BIGNUM *
auth_rsa_generate_challenge(Key *key)
{
BIGNUM *challenge;
if ((challenge = BN_new()) == NULL)
fatal("auth_rsa_generate_challenge: BN_new() failed");
/* Generate a random challenge. */
- BN_rand(challenge, 256, 0, 0);
+ if (BN_rand(challenge, 256, 0, 0) == 0)
+ fatal("auth_rsa_generate_challenge: BN_rand failed");
if ((ctx = BN_CTX_new()) == NULL)
- fatal("auth_rsa_generate_challenge: BN_CTX_new() failed");
- BN_mod(challenge, challenge, key->rsa->n, ctx);
+ fatal("auth_rsa_generate_challenge: BN_CTX_new failed");
+ if (BN_mod(challenge, challenge, key->rsa->n, ctx) == 0)
+ fatal("auth_rsa_generate_challenge: BN_mod failed");
BN_CTX_free(ctx);
return challenge;
}
-static int
+int
auth_rsa_verify_response(Key *key, BIGNUM *challenge, u_char response[16])
{
u_char buf[32], mdbuf[16];
MD5_CTX md;
int len;
+ /* don't allow short keys */
+ if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
+ error("auth_rsa_verify_response: RSA modulus too small: %d < minimum %d bits",
+ BN_num_bits(key->rsa->n), SSH_RSA_MINIMUM_MODULUS_SIZE);
+ return (0);
+ }
+
/* The response is MD5 of decrypted challenge plus session id. */
len = BN_num_bytes(challenge);
if (len <= 0 || len > 32)
if ((encrypted_challenge = BN_new()) == NULL)
fatal("auth_rsa_challenge_dialog: BN_new() failed");
- challenge = auth_rsa_generate_challenge(key);
+ challenge = PRIVSEP(auth_rsa_generate_challenge(key));
/* Encrypt the challenge with the public key. */
rsa_public_encrypt(encrypted_challenge, challenge, key->rsa);
/* Wait for a response. */
packet_read_expect(SSH_CMSG_AUTH_RSA_RESPONSE);
for (i = 0; i < 16; i++)
- response[i] = packet_get_char();
+ response[i] = (u_char)packet_get_char();
packet_check_eom();
- success = auth_rsa_verify_response(key, challenge, response);
+ success = PRIVSEP(auth_rsa_verify_response(key, challenge, response));
BN_clear_free(challenge);
return (success);
}
* return key if login is allowed, NULL otherwise
*/
-static int
+int
auth_rsa_key_allowed(struct passwd *pw, BIGNUM *client_n, Key **rkey)
{
- char line[8192], *file;
- int allowed;
+ char line[SSH_MAX_PUBKEY_BYTES], *file;
+ int allowed = 0;
u_int bits;
FILE *f;
u_long linenum = 0;
/* Restore the privileged uid. */
restore_uid();
xfree(file);
- return (NULL);
+ return (0);
}
/* Open the file containing the authorized keys. */
f = fopen(file, "r");
/* Restore the privileged uid. */
restore_uid();
xfree(file);
- return (NULL);
+ return (0);
}
if (options.strict_modes &&
secure_filename(f, file, pw, line, sizeof(line)) != 0) {
xfree(file);
fclose(f);
- log("Authentication refused: %s", line);
+ logit("Authentication refused: %s", line);
restore_uid();
- return (NULL);
+ return (0);
}
/* Flag indicating whether the key is allowed. */
* found, perform a challenge-response dialog to verify that the
* user really has the corresponding private key.
*/
- while (fgets(line, sizeof(line), f)) {
+ while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) {
char *cp;
- char *options;
-
- linenum++;
+ char *key_options;
+ int keybits;
/* Skip leading whitespace, empty and comment lines. */
for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
*/
if (*cp < '0' || *cp > '9') {
int quoted = 0;
- options = cp;
+ key_options = cp;
for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
if (*cp == '\\' && cp[1] == '"')
cp++; /* Skip both */
quoted = !quoted;
}
} else
- options = NULL;
+ key_options = NULL;
/* Parse the key from the line. */
if (hostfile_read_key(&cp, &bits, key) == 0) {
continue;
/* check the real bits */
- if (bits != BN_num_bits(key->rsa->n))
- log("Warning: %s, line %lu: keysize mismatch: "
+ keybits = BN_num_bits(key->rsa->n);
+ if (keybits < 0 || bits != (u_int)keybits)
+ logit("Warning: %s, line %lu: keysize mismatch: "
"actual %d vs. announced %d.",
file, linenum, BN_num_bits(key->rsa->n), bits);
* If our options do not allow this key to be used,
* do not send challenge.
*/
- if (!auth_parse_options(pw, options, file, linenum))
+ if (!auth_parse_options(pw, key_options, file, linenum))
continue;
/* break out, this key is allowed */
* successful. This may exit if there is a serious protocol violation.
*/
int
-auth_rsa(struct passwd *pw, BIGNUM *client_n)
+auth_rsa(Authctxt *authctxt, BIGNUM *client_n)
{
Key *key;
char *fp;
+ struct passwd *pw = authctxt->pw;
/* no user given */
- if (pw == NULL)
+ if (!authctxt->valid)
return 0;
- if (auth_rsa_key_allowed(pw, client_n, &key) == 0) {
+ if (!PRIVSEP(auth_rsa_key_allowed(pw, client_n, &key))) {
auth_clear_options();
return (0);
}