зеркало из https://github.com/Azure/sonic-openssh.git
- (djm) Big OpenBSD sync:
- markus@cvs.openbsd.org 2000/09/30 10:27:44 [log.c] allow loglevel debug - markus@cvs.openbsd.org 2000/10/03 11:59:57 [packet.c] hmac->mac - markus@cvs.openbsd.org 2000/10/03 12:03:03 [auth-krb4.c auth-passwd.c auth-rh-rsa.c auth-rhosts.c auth-rsa.c auth1.c] move fake-auth from auth1.c to individual auth methods, disables s/key in debug-msg - markus@cvs.openbsd.org 2000/10/03 12:16:48 ssh.c do not resolve canonname, i have no idea why this was added oin ossh - markus@cvs.openbsd.org 2000/10/09 15:30:44 ssh-keygen.1 ssh-keygen.c -X now reads private ssh.com DSA keys, too. - markus@cvs.openbsd.org 2000/10/09 15:32:34 auth-options.c clear options on every call. - markus@cvs.openbsd.org 2000/10/09 15:51:00 authfd.c authfd.h interop with ssh-agent2, from <res@shore.net> - markus@cvs.openbsd.org 2000/10/10 14:20:45 compat.c use rexexp for version string matching - provos@cvs.openbsd.org 2000/10/10 22:02:18 [kex.c kex.h myproposal.h ssh.h ssh2.h sshconnect2.c sshd.c dh.c dh.h] First rough implementation of the diffie-hellman group exchange. The client can ask the server for bigger groups to perform the diffie-hellman in, thus increasing the attack complexity when using ciphers with longer keys. University of Windsor provided network, T the company. - markus@cvs.openbsd.org 2000/10/11 13:59:52 [auth-rsa.c auth2.c] clear auth options unless auth sucessfull - markus@cvs.openbsd.org 2000/10/11 14:00:27 [auth-options.h] clear auth options unless auth sucessfull - markus@cvs.openbsd.org 2000/10/11 14:03:27 [scp.1 scp.c] support 'scp -o' with help from mouring@pconline.com - markus@cvs.openbsd.org 2000/10/11 14:11:35 [dh.c] Wall - markus@cvs.openbsd.org 2000/10/11 14:14:40 [auth.h auth2.c readconf.c readconf.h readpass.c servconf.c servconf.h] [ssh.h sshconnect2.c sshd_config auth2-skey.c cli.c cli.h] add support for s/key (kbd-interactive) to ssh2, based on work by mkiernan@avantgo.com and me - markus@cvs.openbsd.org 2000/10/11 14:27:24 [auth.c auth1.c auth2.c authfile.c cipher.c cipher.h kex.c kex.h] [myproposal.h packet.c readconf.c session.c ssh.c ssh.h sshconnect1.c] [sshconnect2.c sshd.c] new cipher framework - markus@cvs.openbsd.org 2000/10/11 14:45:21 [cipher.c] remove DES - markus@cvs.openbsd.org 2000/10/12 03:59:20 [cipher.c cipher.h sshconnect1.c sshconnect2.c sshd.c] enable DES in SSH-1 clients only - markus@cvs.openbsd.org 2000/10/12 08:21:13 [kex.h packet.c] remove unused - markus@cvs.openbsd.org 2000/10/13 12:34:46 [sshd.c] Kludge for F-Secure Macintosh < 1.0.2; appro@fy.chalmers.se - markus@cvs.openbsd.org 2000/10/13 12:59:15 [cipher.c cipher.h myproposal.h rijndael.c rijndael.h] rijndael/aes support - markus@cvs.openbsd.org 2000/10/13 13:10:54 [sshd.8] more info about -V - markus@cvs.openbsd.org 2000/10/13 13:12:02 [myproposal.h] prefer no compression
This commit is contained in:
Родитель
89d9796fbe
Коммит
874d77bb13
75
ChangeLog
75
ChangeLog
|
@ -3,6 +3,81 @@
|
|||
- (djm) Revert SSH2 serverloop hack, will find a better way.
|
||||
- (djm) Add workaround for Linux 2.4's gratuitious errno change. Patch
|
||||
from Martin Johansson <fatbob@acc.umu.se>
|
||||
- (djm) Big OpenBSD sync:
|
||||
- markus@cvs.openbsd.org 2000/09/30 10:27:44
|
||||
[log.c]
|
||||
allow loglevel debug
|
||||
- markus@cvs.openbsd.org 2000/10/03 11:59:57
|
||||
[packet.c]
|
||||
hmac->mac
|
||||
- markus@cvs.openbsd.org 2000/10/03 12:03:03
|
||||
[auth-krb4.c auth-passwd.c auth-rh-rsa.c auth-rhosts.c auth-rsa.c auth1.c]
|
||||
move fake-auth from auth1.c to individual auth methods, disables s/key in
|
||||
debug-msg
|
||||
- markus@cvs.openbsd.org 2000/10/03 12:16:48
|
||||
ssh.c
|
||||
do not resolve canonname, i have no idea why this was added oin ossh
|
||||
- markus@cvs.openbsd.org 2000/10/09 15:30:44
|
||||
ssh-keygen.1 ssh-keygen.c
|
||||
-X now reads private ssh.com DSA keys, too.
|
||||
- markus@cvs.openbsd.org 2000/10/09 15:32:34
|
||||
auth-options.c
|
||||
clear options on every call.
|
||||
- markus@cvs.openbsd.org 2000/10/09 15:51:00
|
||||
authfd.c authfd.h
|
||||
interop with ssh-agent2, from <res@shore.net>
|
||||
- markus@cvs.openbsd.org 2000/10/10 14:20:45
|
||||
compat.c
|
||||
use rexexp for version string matching
|
||||
- provos@cvs.openbsd.org 2000/10/10 22:02:18
|
||||
[kex.c kex.h myproposal.h ssh.h ssh2.h sshconnect2.c sshd.c dh.c dh.h]
|
||||
First rough implementation of the diffie-hellman group exchange. The
|
||||
client can ask the server for bigger groups to perform the diffie-hellman
|
||||
in, thus increasing the attack complexity when using ciphers with longer
|
||||
keys. University of Windsor provided network, T the company.
|
||||
- markus@cvs.openbsd.org 2000/10/11 13:59:52
|
||||
[auth-rsa.c auth2.c]
|
||||
clear auth options unless auth sucessfull
|
||||
- markus@cvs.openbsd.org 2000/10/11 14:00:27
|
||||
[auth-options.h]
|
||||
clear auth options unless auth sucessfull
|
||||
- markus@cvs.openbsd.org 2000/10/11 14:03:27
|
||||
[scp.1 scp.c]
|
||||
support 'scp -o' with help from mouring@pconline.com
|
||||
- markus@cvs.openbsd.org 2000/10/11 14:11:35
|
||||
[dh.c]
|
||||
Wall
|
||||
- markus@cvs.openbsd.org 2000/10/11 14:14:40
|
||||
[auth.h auth2.c readconf.c readconf.h readpass.c servconf.c servconf.h]
|
||||
[ssh.h sshconnect2.c sshd_config auth2-skey.c cli.c cli.h]
|
||||
add support for s/key (kbd-interactive) to ssh2, based on work by
|
||||
mkiernan@avantgo.com and me
|
||||
- markus@cvs.openbsd.org 2000/10/11 14:27:24
|
||||
[auth.c auth1.c auth2.c authfile.c cipher.c cipher.h kex.c kex.h]
|
||||
[myproposal.h packet.c readconf.c session.c ssh.c ssh.h sshconnect1.c]
|
||||
[sshconnect2.c sshd.c]
|
||||
new cipher framework
|
||||
- markus@cvs.openbsd.org 2000/10/11 14:45:21
|
||||
[cipher.c]
|
||||
remove DES
|
||||
- markus@cvs.openbsd.org 2000/10/12 03:59:20
|
||||
[cipher.c cipher.h sshconnect1.c sshconnect2.c sshd.c]
|
||||
enable DES in SSH-1 clients only
|
||||
- markus@cvs.openbsd.org 2000/10/12 08:21:13
|
||||
[kex.h packet.c]
|
||||
remove unused
|
||||
- markus@cvs.openbsd.org 2000/10/13 12:34:46
|
||||
[sshd.c]
|
||||
Kludge for F-Secure Macintosh < 1.0.2; appro@fy.chalmers.se
|
||||
- markus@cvs.openbsd.org 2000/10/13 12:59:15
|
||||
[cipher.c cipher.h myproposal.h rijndael.c rijndael.h]
|
||||
rijndael/aes support
|
||||
- markus@cvs.openbsd.org 2000/10/13 13:10:54
|
||||
[sshd.8]
|
||||
more info about -V
|
||||
- markus@cvs.openbsd.org 2000/10/13 13:12:02
|
||||
[myproposal.h]
|
||||
prefer no compression
|
||||
|
||||
20001007
|
||||
- (stevesk) Print PAM return value in PAM log messages to aid
|
||||
|
|
|
@ -35,13 +35,13 @@ INSTALL_SSH_PRNG_CMDS=@INSTALL_SSH_PRNG_CMDS@
|
|||
|
||||
TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) sftp-server$(EXEEXT) $(EXTRA_TARGETS)
|
||||
|
||||
LIBSSH_OBJS=atomicio.o authfd.o authfile.o bufaux.o buffer.o canohost.o channels.o cipher.o compat.o compress.o crc32.o cygwin_util.o deattack.o dispatch.o dsa.o hmac.o hostfile.o key.o kex.o log.o match.o mpaux.o nchan.o packet.o radix.o entropy.o readpass.o rsa.o tildexpand.o ttymodes.o uidswap.o util.o uuencode.o xmalloc.o
|
||||
LIBSSH_OBJS=atomicio.o authfd.o authfile.o bufaux.o buffer.o canohost.o channels.o cipher.o cli.o compat.o compress.o crc32.o cygwin_util.o deattack.o dispatch.o dsa.o hmac.o hostfile.o key.o kex.o log.o match.o mpaux.o nchan.o packet.o radix.o rijndael.o entropy.o readpass.o rsa.o tildexpand.o ttymodes.o uidswap.o util.o uuencode.o xmalloc.o
|
||||
|
||||
LIBOPENBSD_COMPAT_OBJS=bsd-arc4random.o bsd-base64.o bsd-bindresvport.o bsd-daemon.o bsd-inet_aton.o bsd-inet_ntoa.o bsd-misc.o bsd-mktemp.o bsd-rresvport.o bsd-setenv.o bsd-sigaction.o bsd-snprintf.o bsd-strlcat.o bsd-strlcpy.o bsd-strsep.o bsd-strtok.o fake-getaddrinfo.o fake-getnameinfo.o next-posix.o
|
||||
LIBOPENBSD_COMPAT_OBJS=bsd-arc4random.o bsd-base64.o bsd-bindresvport.o bsd-daemon.o bsd-inet_aton.o bsd-inet_ntoa.o bsd-misc.o bsd-mktemp.o bsd-rresvport.o bsd-setenv.o bsd-sigaction.o bsd-snprintf.o bsd-strlcat.o bsd-strlcpy.o bsd-strsep.o bsd-strtok.o bsd-vis.o fake-getaddrinfo.o fake-getnameinfo.o next-posix.o
|
||||
|
||||
SSHOBJS= ssh.o sshconnect.o sshconnect1.o sshconnect2.o log-client.o readconf.o clientloop.o
|
||||
|
||||
SSHDOBJS= sshd.o auth.o auth1.o auth2.o auth-rhosts.o auth-options.o auth-krb4.o auth-pam.o auth-passwd.o auth-rsa.o auth-rh-rsa.o pty.o log-server.o login.o loginrec.o servconf.o serverloop.o md5crypt.o session.o
|
||||
SSHDOBJS= sshd.o auth.o auth1.o auth2.o auth-rhosts.o auth-options.o auth-krb4.o auth-pam.o auth-passwd.o auth-rsa.o auth-rh-rsa.o dh.o pty.o log-server.o login.o loginrec.o servconf.o serverloop.o md5crypt.o session.o
|
||||
|
||||
TROFFMAN = scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh.1 sshd.8 sftp-server.8
|
||||
CATMAN = scp.0 ssh-add.0 ssh-agent.0 ssh-keygen.0 ssh.0 sshd.0 sftp-server.0
|
||||
|
|
16
auth-krb4.c
16
auth-krb4.c
|
@ -28,7 +28,7 @@
|
|||
#include "ssh.h"
|
||||
#include "servconf.h"
|
||||
|
||||
RCSID("$OpenBSD: auth-krb4.c,v 1.18 2000/09/07 20:27:49 deraadt Exp $");
|
||||
RCSID("$OpenBSD: auth-krb4.c,v 1.19 2000/10/03 18:03:02 markus Exp $");
|
||||
|
||||
#ifdef KRB4
|
||||
char *ticket = NULL;
|
||||
|
@ -280,6 +280,8 @@ auth_kerberos_tgt(struct passwd *pw, const char *string)
|
|||
{
|
||||
CREDENTIALS creds;
|
||||
|
||||
if (pw == NULL)
|
||||
goto auth_kerberos_tgt_failure;
|
||||
if (!radix_to_creds(string, &creds)) {
|
||||
log("Protocol error decoding Kerberos V4 tgt");
|
||||
packet_send_debug("Protocol error decoding Kerberos V4 tgt");
|
||||
|
@ -334,8 +336,16 @@ int
|
|||
auth_afs_token(struct passwd *pw, const char *token_string)
|
||||
{
|
||||
CREDENTIALS creds;
|
||||
uid_t uid = pw->pw_uid;
|
||||
uid_t uid;
|
||||
|
||||
if (pw == NULL) {
|
||||
/* XXX fake protocol error */
|
||||
packet_send_debug("Protocol error decoding AFS token");
|
||||
packet_start(SSH_SMSG_FAILURE);
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
return 0;
|
||||
}
|
||||
if (!radix_to_creds(token_string, &creds)) {
|
||||
log("Protocol error decoding AFS token");
|
||||
packet_send_debug("Protocol error decoding AFS token");
|
||||
|
@ -349,6 +359,8 @@ auth_afs_token(struct passwd *pw, const char *token_string)
|
|||
|
||||
if (strncmp(creds.pname, "AFS ID ", 7) == 0)
|
||||
uid = atoi(creds.pname + 7);
|
||||
else
|
||||
uid = pw->pw_uid;
|
||||
|
||||
if (kafs_settoken(creds.realm, uid, &creds)) {
|
||||
log("AFS token (%s@%s) rejected for %s", creds.pname, creds.realm,
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$OpenBSD: auth-options.c,v 1.4 2000/09/07 21:13:36 markus Exp $");
|
||||
RCSID("$OpenBSD: auth-options.c,v 1.5 2000/10/09 21:32:34 markus Exp $");
|
||||
|
||||
#include "ssh.h"
|
||||
#include "packet.h"
|
||||
|
@ -33,6 +33,25 @@ char *forced_command = NULL;
|
|||
/* "environment=" options. */
|
||||
struct envstring *custom_environment = NULL;
|
||||
|
||||
void
|
||||
auth_clear_options(void)
|
||||
{
|
||||
no_agent_forwarding_flag = 0;
|
||||
no_port_forwarding_flag = 0;
|
||||
no_pty_flag = 0;
|
||||
no_x11_forwarding_flag = 0;
|
||||
while (custom_environment) {
|
||||
struct envstring *ce = custom_environment;
|
||||
custom_environment = ce->next;
|
||||
xfree(ce->s);
|
||||
xfree(ce);
|
||||
}
|
||||
if (forced_command) {
|
||||
xfree(forced_command);
|
||||
forced_command = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* return 1 if access is granted, 0 if not. side effect: sets key option flags */
|
||||
int
|
||||
auth_parse_options(struct passwd *pw, char *options, unsigned long linenum)
|
||||
|
@ -40,6 +59,10 @@ auth_parse_options(struct passwd *pw, char *options, unsigned long linenum)
|
|||
const char *cp;
|
||||
if (!options)
|
||||
return 1;
|
||||
|
||||
/* reset options */
|
||||
auth_clear_options();
|
||||
|
||||
while (*options && *options != ' ' && *options != '\t') {
|
||||
cp = "no-port-forwarding";
|
||||
if (strncmp(options, cp, strlen(cp)) == 0) {
|
||||
|
@ -87,9 +110,9 @@ auth_parse_options(struct passwd *pw, char *options, unsigned long linenum)
|
|||
}
|
||||
if (!*options) {
|
||||
debug("%.100s, line %lu: missing end quote",
|
||||
SSH_USER_PERMITTED_KEYS, linenum);
|
||||
SSH_USER_PERMITTED_KEYS, linenum);
|
||||
packet_send_debug("%.100s, line %lu: missing end quote",
|
||||
SSH_USER_PERMITTED_KEYS, linenum);
|
||||
SSH_USER_PERMITTED_KEYS, linenum);
|
||||
continue;
|
||||
}
|
||||
forced_command[i] = 0;
|
||||
|
@ -117,9 +140,9 @@ auth_parse_options(struct passwd *pw, char *options, unsigned long linenum)
|
|||
}
|
||||
if (!*options) {
|
||||
debug("%.100s, line %lu: missing end quote",
|
||||
SSH_USER_PERMITTED_KEYS, linenum);
|
||||
SSH_USER_PERMITTED_KEYS, linenum);
|
||||
packet_send_debug("%.100s, line %lu: missing end quote",
|
||||
SSH_USER_PERMITTED_KEYS, linenum);
|
||||
SSH_USER_PERMITTED_KEYS, linenum);
|
||||
continue;
|
||||
}
|
||||
s[i] = 0;
|
||||
|
@ -175,21 +198,6 @@ auth_parse_options(struct passwd *pw, char *options, unsigned long linenum)
|
|||
get_remote_ipaddr());
|
||||
packet_send_debug("Your host '%.200s' is not permitted to use this key for login.",
|
||||
get_canonical_hostname());
|
||||
/* key invalid for this host, reset flags */
|
||||
no_agent_forwarding_flag = 0;
|
||||
no_port_forwarding_flag = 0;
|
||||
no_pty_flag = 0;
|
||||
no_x11_forwarding_flag = 0;
|
||||
while (custom_environment) {
|
||||
struct envstring *ce = custom_environment;
|
||||
custom_environment = ce->next;
|
||||
xfree(ce->s);
|
||||
xfree(ce);
|
||||
}
|
||||
if (forced_command) {
|
||||
xfree(forced_command);
|
||||
forced_command = NULL;
|
||||
}
|
||||
/* deny access */
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -22,4 +22,7 @@ extern struct envstring *custom_environment;
|
|||
|
||||
/* return 1 if access is granted, 0 if not. side effect: sets key option flags */
|
||||
int auth_parse_options(struct passwd *pw, char *options, unsigned long linenum);
|
||||
/* reset options flags */
|
||||
void auth_clear_options(void);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
#include "xmalloc.h"
|
||||
#include "servconf.h"
|
||||
|
||||
RCSID("$Id: auth-pam.c,v 1.15 2000/10/14 00:16:12 djm Exp $");
|
||||
RCSID("$Id: auth-pam.c,v 1.16 2000/10/14 05:23:11 djm Exp $");
|
||||
|
||||
#define NEW_AUTHTOK_MSG \
|
||||
"Warning: Your password has expired, please change it now"
|
||||
|
@ -257,7 +257,7 @@ void do_pam_setcred()
|
|||
pam_retval = pam_setcred(pamh, PAM_ESTABLISH_CRED);
|
||||
if (pam_retval != PAM_SUCCESS) {
|
||||
fatal("PAM setcred failed[%d]: %.200s",
|
||||
pam_setcred, PAM_STRERROR(pamh, pam_retval));
|
||||
pam_retval, PAM_STRERROR(pamh, pam_retval));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -59,7 +59,7 @@
|
|||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$OpenBSD: auth-passwd.c,v 1.17 2000/09/07 20:27:49 deraadt Exp $");
|
||||
RCSID("$OpenBSD: auth-passwd.c,v 1.18 2000/10/03 18:03:03 markus Exp $");
|
||||
|
||||
#if !defined(USE_PAM) && !defined(HAVE_OSF_SIA)
|
||||
|
||||
|
@ -156,7 +156,7 @@ auth_password(struct passwd * pw, const char *password)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef SKEY
|
||||
#ifdef SKEY_VIA_PASSWD_IS_DISABLED
|
||||
if (options.skey_authentication == 1) {
|
||||
int ret = auth_skey_password(pw, password);
|
||||
if (ret == 1 || ret == 0)
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$OpenBSD: auth-rh-rsa.c,v 1.16 2000/09/07 21:13:36 markus Exp $");
|
||||
RCSID("$OpenBSD: auth-rh-rsa.c,v 1.17 2000/10/03 18:03:03 markus Exp $");
|
||||
|
||||
#include "packet.h"
|
||||
#include "ssh.h"
|
||||
|
@ -39,9 +39,9 @@ auth_rhosts_rsa(struct passwd *pw, const char *client_user, RSA *client_host_key
|
|||
HostStatus host_status;
|
||||
Key *client_key, *found;
|
||||
|
||||
debug("Trying rhosts with RSA host authentication for %.100s", client_user);
|
||||
debug("Trying rhosts with RSA host authentication for client user %.100s", client_user);
|
||||
|
||||
if (client_host_key == NULL)
|
||||
if (pw == NULL || client_host_key == NULL)
|
||||
return 0;
|
||||
|
||||
/* Check if we would accept it using rhosts authentication. */
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$OpenBSD: auth-rhosts.c,v 1.15 2000/09/07 20:27:49 deraadt Exp $");
|
||||
RCSID("$OpenBSD: auth-rhosts.c,v 1.16 2000/10/03 18:03:03 markus Exp $");
|
||||
|
||||
#include "packet.h"
|
||||
#include "ssh.h"
|
||||
|
@ -154,6 +154,9 @@ auth_rhosts(struct passwd *pw, const char *client_user)
|
|||
static const char *rhosts_files[] = {".shosts", ".rhosts", NULL};
|
||||
unsigned int rhosts_file_index;
|
||||
|
||||
/* no user given */
|
||||
if (pw == NULL)
|
||||
return 0;
|
||||
/* Switch to the user's uid. */
|
||||
temporarily_use_uid(pw->pw_uid);
|
||||
/*
|
||||
|
|
13
auth-rsa.c
13
auth-rsa.c
|
@ -14,7 +14,7 @@
|
|||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$OpenBSD: auth-rsa.c,v 1.29 2000/09/07 21:13:36 markus Exp $");
|
||||
RCSID("$OpenBSD: auth-rsa.c,v 1.31 2000/10/11 19:59:52 markus Exp $");
|
||||
|
||||
#include "rsa.h"
|
||||
#include "packet.h"
|
||||
|
@ -29,6 +29,10 @@ RCSID("$OpenBSD: auth-rsa.c,v 1.29 2000/09/07 21:13:36 markus Exp $");
|
|||
#include <openssl/rsa.h>
|
||||
#include <openssl/md5.h>
|
||||
|
||||
|
||||
/* import */
|
||||
extern ServerOptions options;
|
||||
|
||||
/*
|
||||
* Session identifier that is used to bind key exchange and authentication
|
||||
* responses to a particular session.
|
||||
|
@ -116,7 +120,6 @@ auth_rsa_challenge_dialog(RSA *pk)
|
|||
int
|
||||
auth_rsa(struct passwd *pw, BIGNUM *client_n)
|
||||
{
|
||||
extern ServerOptions options;
|
||||
char line[8192], file[1024];
|
||||
int authenticated;
|
||||
unsigned int bits;
|
||||
|
@ -125,6 +128,10 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
|
|||
struct stat st;
|
||||
RSA *pk;
|
||||
|
||||
/* no user given */
|
||||
if (pw == NULL)
|
||||
return 0;
|
||||
|
||||
/* Temporarily use the user's uid. */
|
||||
temporarily_use_uid(pw->pw_uid);
|
||||
|
||||
|
@ -277,6 +284,8 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
|
|||
|
||||
if (authenticated)
|
||||
packet_send_debug("RSA authentication accepted.");
|
||||
else
|
||||
auth_clear_options();
|
||||
|
||||
/* Return authentication result. */
|
||||
return authenticated;
|
||||
|
|
3
auth.c
3
auth.c
|
@ -33,7 +33,7 @@
|
|||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$OpenBSD: auth.c,v 1.10 2000/09/07 21:13:36 markus Exp $");
|
||||
RCSID("$OpenBSD: auth.c,v 1.11 2000/10/11 20:27:23 markus Exp $");
|
||||
|
||||
#include "xmalloc.h"
|
||||
#include "rsa.h"
|
||||
|
@ -41,7 +41,6 @@ RCSID("$OpenBSD: auth.c,v 1.10 2000/09/07 21:13:36 markus Exp $");
|
|||
#include "pty.h"
|
||||
#include "packet.h"
|
||||
#include "buffer.h"
|
||||
#include "cipher.h"
|
||||
#include "mpaux.h"
|
||||
#include "servconf.h"
|
||||
#include "compat.h"
|
||||
|
|
20
auth.h
20
auth.h
|
@ -24,17 +24,29 @@
|
|||
#ifndef AUTH_H
|
||||
#define AUTH_H
|
||||
|
||||
typedef struct Authctxt Authctxt;
|
||||
struct Authctxt {
|
||||
int success;
|
||||
int valid;
|
||||
int attempt;
|
||||
char *user;
|
||||
char *service;
|
||||
struct passwd *pw;
|
||||
};
|
||||
|
||||
void do_authentication(void);
|
||||
void do_authentication2(void);
|
||||
|
||||
struct passwd *
|
||||
auth_get_user(void);
|
||||
void userauth_log(Authctxt *authctxt, int authenticated, char *method);
|
||||
void userauth_reply(Authctxt *authctxt, int authenticated);
|
||||
|
||||
int allowed_user(struct passwd * pw);
|
||||
int auth2_skey(Authctxt *authctxt);
|
||||
|
||||
int allowed_user(struct passwd * pw);
|
||||
struct passwd * auth_get_user(void);
|
||||
|
||||
#define AUTH_FAIL_MAX 6
|
||||
#define AUTH_FAIL_LOG (AUTH_FAIL_MAX/2)
|
||||
#define AUTH_FAIL_MSG "Too many authentication failures for %.100s"
|
||||
|
||||
#endif
|
||||
|
||||
|
|
258
auth1.c
258
auth1.c
|
@ -10,28 +10,31 @@
|
|||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$OpenBSD: auth1.c,v 1.4 2000/09/07 20:27:49 deraadt Exp $");
|
||||
|
||||
#include "xmalloc.h"
|
||||
#include "rsa.h"
|
||||
#include "ssh.h"
|
||||
#include "packet.h"
|
||||
#include "buffer.h"
|
||||
#include "cipher.h"
|
||||
#include "mpaux.h"
|
||||
#include "servconf.h"
|
||||
#include "compat.h"
|
||||
#include "auth.h"
|
||||
#include "session.h"
|
||||
RCSID("$OpenBSD: auth1.c,v 1.6 2000/10/11 20:27:23 markus Exp $");
|
||||
|
||||
#ifdef HAVE_OSF_SIA
|
||||
# include <sia.h>
|
||||
# include <siad.h>
|
||||
#endif
|
||||
|
||||
#include "xmalloc.h"
|
||||
#include "rsa.h"
|
||||
#include "ssh.h"
|
||||
#include "packet.h"
|
||||
#include "buffer.h"
|
||||
#include "mpaux.h"
|
||||
#include "servconf.h"
|
||||
#include "compat.h"
|
||||
#include "auth.h"
|
||||
#include "session.h"
|
||||
|
||||
/* import */
|
||||
extern ServerOptions options;
|
||||
extern char *forced_command;
|
||||
|
||||
#ifdef WITH_AIXAUTHENTICATE
|
||||
extern char *aixloginmsg;
|
||||
#endif /* WITH_AIXAUTHENTICATE */
|
||||
#ifdef HAVE_OSF_SIA
|
||||
extern int saved_argc;
|
||||
extern char **saved_argv;
|
||||
|
@ -67,89 +70,21 @@ get_authname(int type)
|
|||
}
|
||||
|
||||
/*
|
||||
* The user does not exist or access is denied,
|
||||
* but fake indication that authentication is needed.
|
||||
* read packets and try to authenticate local user 'luser'.
|
||||
* return if authentication is successfull. not that pw == NULL
|
||||
* if the user does not exists or is not allowed to login.
|
||||
* each auth method has to 'fake' authentication for nonexisting
|
||||
* users.
|
||||
*/
|
||||
void
|
||||
do_fake_authloop1(char *user)
|
||||
{
|
||||
int attempt = 0;
|
||||
|
||||
log("Faking authloop for illegal user %.200s from %.200s port %d",
|
||||
user,
|
||||
get_remote_ipaddr(),
|
||||
get_remote_port());
|
||||
|
||||
#ifdef WITH_AIXAUTHENTICATE
|
||||
loginfailed(user,get_canonical_hostname(),"ssh");
|
||||
#endif /* WITH_AIXAUTHENTICATE */
|
||||
|
||||
/* Indicate that authentication is needed. */
|
||||
packet_start(SSH_SMSG_FAILURE);
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
|
||||
/*
|
||||
* Keep reading packets, and always respond with a failure. This is
|
||||
* to avoid disclosing whether such a user really exists.
|
||||
*/
|
||||
for (attempt = 1;; attempt++) {
|
||||
/* Read a packet. This will not return if the client disconnects. */
|
||||
int plen;
|
||||
#ifndef SKEY
|
||||
(void)packet_read(&plen);
|
||||
#else /* SKEY */
|
||||
int type = packet_read(&plen);
|
||||
unsigned int dlen;
|
||||
char *password, *skeyinfo;
|
||||
password = NULL;
|
||||
/* Try to send a fake s/key challenge. */
|
||||
if (options.skey_authentication == 1 &&
|
||||
(skeyinfo = skey_fake_keyinfo(user)) != NULL) {
|
||||
if (type == SSH_CMSG_AUTH_TIS) {
|
||||
packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE);
|
||||
packet_put_string(skeyinfo, strlen(skeyinfo));
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
continue;
|
||||
} else if (type == SSH_CMSG_AUTH_PASSWORD &&
|
||||
options.password_authentication &&
|
||||
(password = packet_get_string(&dlen)) != NULL &&
|
||||
dlen == 5 &&
|
||||
strncasecmp(password, "s/key", 5) == 0 ) {
|
||||
packet_send_debug(skeyinfo);
|
||||
}
|
||||
}
|
||||
if (password != NULL)
|
||||
xfree(password);
|
||||
#endif
|
||||
if (attempt > AUTH_FAIL_MAX)
|
||||
packet_disconnect(AUTH_FAIL_MSG, user);
|
||||
|
||||
/*
|
||||
* Send failure. This should be indistinguishable from a
|
||||
* failed authentication.
|
||||
*/
|
||||
packet_start(SSH_SMSG_FAILURE);
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
}
|
||||
/* NOTREACHED */
|
||||
abort();
|
||||
}
|
||||
|
||||
/*
|
||||
* read packets and try to authenticate local user *pw.
|
||||
* return if authentication is successfull
|
||||
*/
|
||||
void
|
||||
do_authloop(struct passwd * pw)
|
||||
do_authloop(struct passwd * pw, char *luser)
|
||||
{
|
||||
int authenticated = 0;
|
||||
int attempt = 0;
|
||||
unsigned int bits;
|
||||
RSA *client_host_key;
|
||||
BIGNUM *n;
|
||||
char *client_user = NULL, *password = NULL;
|
||||
char *client_user, *password;
|
||||
char user[1024];
|
||||
unsigned int dlen;
|
||||
int plen, nlen, elen;
|
||||
|
@ -162,8 +97,12 @@ do_authloop(struct passwd * pw)
|
|||
packet_send();
|
||||
packet_write_wait();
|
||||
|
||||
client_user = NULL;
|
||||
|
||||
for (attempt = 1;; attempt++) {
|
||||
int authenticated = 0;
|
||||
/* default to fail */
|
||||
authenticated = 0;
|
||||
|
||||
strlcpy(user, "", sizeof user);
|
||||
|
||||
/* Get a packet from the client. */
|
||||
|
@ -174,7 +113,6 @@ do_authloop(struct passwd * pw)
|
|||
#ifdef AFS
|
||||
case SSH_CMSG_HAVE_KERBEROS_TGT:
|
||||
if (!options.kerberos_tgt_passing) {
|
||||
/* packet_get_all(); */
|
||||
verbose("Kerberos tgt passing disabled.");
|
||||
break;
|
||||
} else {
|
||||
|
@ -182,14 +120,13 @@ do_authloop(struct passwd * pw)
|
|||
char *tgt = packet_get_string(&dlen);
|
||||
packet_integrity_check(plen, 4 + dlen, type);
|
||||
if (!auth_kerberos_tgt(pw, tgt))
|
||||
verbose("Kerberos tgt REFUSED for %s", pw->pw_name);
|
||||
verbose("Kerberos tgt REFUSED for %.100s", luser);
|
||||
xfree(tgt);
|
||||
}
|
||||
continue;
|
||||
|
||||
case SSH_CMSG_HAVE_AFS_TOKEN:
|
||||
if (!options.afs_token_passing || !k_hasafs()) {
|
||||
/* packet_get_all(); */
|
||||
verbose("AFS token passing disabled.");
|
||||
break;
|
||||
} else {
|
||||
|
@ -197,7 +134,7 @@ do_authloop(struct passwd * pw)
|
|||
char *token_string = packet_get_string(&dlen);
|
||||
packet_integrity_check(plen, 4 + dlen, type);
|
||||
if (!auth_afs_token(pw, token_string))
|
||||
verbose("AFS token REFUSED for %s", pw->pw_name);
|
||||
verbose("AFS token REFUSED for %.100s", luser);
|
||||
xfree(token_string);
|
||||
}
|
||||
continue;
|
||||
|
@ -219,11 +156,12 @@ do_authloop(struct passwd * pw)
|
|||
memcpy(auth.dat, kdata, auth.length);
|
||||
xfree(kdata);
|
||||
|
||||
authenticated = auth_krb4(pw->pw_name, &auth, &tkt_user);
|
||||
|
||||
if (authenticated) {
|
||||
snprintf(user, sizeof user, " tktuser %s", tkt_user);
|
||||
xfree(tkt_user);
|
||||
if (pw != NULL) {
|
||||
authenticated = auth_krb4(pw->pw_name, &auth, &tkt_user);
|
||||
if (authenticated) {
|
||||
snprintf(user, sizeof user, " tktuser %s", tkt_user);
|
||||
xfree(tkt_user);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -243,8 +181,7 @@ do_authloop(struct passwd * pw)
|
|||
client_user = packet_get_string(&ulen);
|
||||
packet_integrity_check(plen, 4 + ulen, type);
|
||||
|
||||
/* Try to authenticate using /etc/hosts.equiv and
|
||||
.rhosts. */
|
||||
/* Try to authenticate using /etc/hosts.equiv and .rhosts. */
|
||||
authenticated = auth_rhosts(pw, client_user);
|
||||
|
||||
snprintf(user, sizeof user, " ruser %s", client_user);
|
||||
|
@ -275,7 +212,7 @@ do_authloop(struct passwd * pw)
|
|||
packet_get_bignum(client_host_key->n, &nlen);
|
||||
|
||||
if (bits != BN_num_bits(client_host_key->n))
|
||||
log("Warning: keysize mismatch for client_host_key: "
|
||||
verbose("Warning: keysize mismatch for client_host_key: "
|
||||
"actual %d, announced %d", BN_num_bits(client_host_key->n), bits);
|
||||
packet_integrity_check(plen, (4 + ulen) + 4 + elen + nlen, type);
|
||||
|
||||
|
@ -322,7 +259,7 @@ do_authloop(struct passwd * pw)
|
|||
authenticated = 1;
|
||||
}
|
||||
#else /* !USE_PAM && !HAVE_OSF_SIA */
|
||||
/* Try authentication with the password. */
|
||||
/* Try authentication with the password. */
|
||||
authenticated = auth_password(pw, password);
|
||||
#endif /* USE_PAM */
|
||||
|
||||
|
@ -334,16 +271,18 @@ do_authloop(struct passwd * pw)
|
|||
case SSH_CMSG_AUTH_TIS:
|
||||
debug("rcvd SSH_CMSG_AUTH_TIS");
|
||||
if (options.skey_authentication == 1) {
|
||||
char *skeyinfo = skey_keyinfo(pw->pw_name);
|
||||
char *skeyinfo = NULL;
|
||||
if (pw != NULL)
|
||||
skey_keyinfo(pw->pw_name);
|
||||
if (skeyinfo == NULL) {
|
||||
debug("generating fake skeyinfo for %.100s.", pw->pw_name);
|
||||
skeyinfo = skey_fake_keyinfo(pw->pw_name);
|
||||
debug("generating fake skeyinfo for %.100s.", luser);
|
||||
skeyinfo = skey_fake_keyinfo(luser);
|
||||
}
|
||||
if (skeyinfo != NULL) {
|
||||
/* we send our s/key- in tis-challenge messages */
|
||||
debug("sending challenge '%s'", skeyinfo);
|
||||
packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE);
|
||||
packet_put_string(skeyinfo, strlen(skeyinfo));
|
||||
packet_put_cstring(skeyinfo);
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
continue;
|
||||
|
@ -356,8 +295,9 @@ do_authloop(struct passwd * pw)
|
|||
char *response = packet_get_string(&dlen);
|
||||
debug("skey response == '%s'", response);
|
||||
packet_integrity_check(plen, 4 + dlen, type);
|
||||
authenticated = (skey_haskey(pw->pw_name) == 0 &&
|
||||
skey_passcheck(pw->pw_name, response) != -1);
|
||||
authenticated = (pw != NULL &&
|
||||
skey_haskey(pw->pw_name) == 0 &&
|
||||
skey_passcheck(pw->pw_name, response) != -1);
|
||||
xfree(response);
|
||||
}
|
||||
break;
|
||||
|
@ -376,12 +316,14 @@ do_authloop(struct passwd * pw)
|
|||
log("Unknown message during authentication: type %d", type);
|
||||
break;
|
||||
}
|
||||
if (authenticated && pw == NULL)
|
||||
fatal("internal error: authenticated for pw == NULL");
|
||||
|
||||
#ifdef HAVE_CYGWIN
|
||||
if (authenticated &&
|
||||
if (authenticated &&
|
||||
!check_nt_auth(type == SSH_CMSG_AUTH_PASSWORD,pw->pw_uid)) {
|
||||
packet_disconnect("Authentication rejected for uid %d.",
|
||||
(int) pw->pw_uid);
|
||||
(int)pw->pw_uid);
|
||||
authenticated = 0;
|
||||
}
|
||||
#endif
|
||||
|
@ -391,7 +333,7 @@ do_authloop(struct passwd * pw)
|
|||
* are disallowed.
|
||||
* Note that root login is allowed for forced commands.
|
||||
*/
|
||||
if (authenticated && pw->pw_uid == 0 && !options.permit_root_login) {
|
||||
if (authenticated && pw && pw->pw_uid == 0 && !options.permit_root_login) {
|
||||
if (forced_command) {
|
||||
log("Root login accepted for forced command.");
|
||||
} else {
|
||||
|
@ -407,41 +349,33 @@ do_authloop(struct passwd * pw)
|
|||
type == SSH_CMSG_AUTH_PASSWORD)
|
||||
authlog = log;
|
||||
|
||||
authlog("%s %s for %.200s from %.200s port %d%s",
|
||||
authlog("%s %s for %s%.100s from %.200s port %d%s",
|
||||
authenticated ? "Accepted" : "Failed",
|
||||
get_authname(type),
|
||||
pw->pw_uid == 0 ? "ROOT" : pw->pw_name,
|
||||
pw ? "" : "illegal user ",
|
||||
pw && pw->pw_uid == 0 ? "ROOT" : luser,
|
||||
get_remote_ipaddr(),
|
||||
get_remote_port(),
|
||||
user);
|
||||
|
||||
#ifdef USE_PAM
|
||||
if (authenticated) {
|
||||
if (!do_pam_account(pw->pw_name, client_user)) {
|
||||
if (client_user != NULL) {
|
||||
xfree(client_user);
|
||||
client_user = NULL;
|
||||
}
|
||||
do_fake_authloop1(pw->pw_name);
|
||||
}
|
||||
return;
|
||||
}
|
||||
#else /* USE_PAM */
|
||||
if (authenticated) {
|
||||
return;
|
||||
}
|
||||
#endif /* USE_PAM */
|
||||
if (authenticated && !do_pam_account(pw->pw_name, client_user))
|
||||
authenticated = 0;
|
||||
#endif
|
||||
|
||||
if (client_user != NULL) {
|
||||
xfree(client_user);
|
||||
client_user = NULL;
|
||||
}
|
||||
|
||||
if (authenticated)
|
||||
return;
|
||||
|
||||
if (attempt > AUTH_FAIL_MAX) {
|
||||
#ifdef WITH_AIXAUTHENTICATE
|
||||
loginfailed(pw->pw_name,get_canonical_hostname(),"ssh");
|
||||
loginfailed(user,get_canonical_hostname(),"ssh");
|
||||
#endif /* WITH_AIXAUTHENTICATE */
|
||||
packet_disconnect(AUTH_FAIL_MSG, pw->pw_name);
|
||||
packet_disconnect(AUTH_FAIL_MSG, luser);
|
||||
}
|
||||
|
||||
/* Send a message indicating that the authentication attempt failed. */
|
||||
|
@ -462,9 +396,6 @@ do_authentication()
|
|||
int plen;
|
||||
unsigned int ulen;
|
||||
char *user;
|
||||
#ifdef WITH_AIXAUTHENTICATE
|
||||
extern char *aixloginmsg;
|
||||
#endif /* WITH_AIXAUTHENTICATE */
|
||||
|
||||
/* Get the name of the user that we wish to log in as. */
|
||||
packet_read_expect(&plen, SSH_CMSG_USER);
|
||||
|
@ -485,38 +416,38 @@ do_authentication()
|
|||
|
||||
/* Verify that the user is a valid user. */
|
||||
pw = getpwnam(user);
|
||||
if (!pw || !allowed_user(pw))
|
||||
do_fake_authloop1(user);
|
||||
xfree(user);
|
||||
|
||||
/* Take a copy of the returned structure. */
|
||||
memset(&pwcopy, 0, sizeof(pwcopy));
|
||||
pwcopy.pw_name = xstrdup(pw->pw_name);
|
||||
pwcopy.pw_passwd = xstrdup(pw->pw_passwd);
|
||||
pwcopy.pw_uid = pw->pw_uid;
|
||||
pwcopy.pw_gid = pw->pw_gid;
|
||||
if (pw && allowed_user(pw)) {
|
||||
/* Take a copy of the returned structure. */
|
||||
memset(&pwcopy, 0, sizeof(pwcopy));
|
||||
pwcopy.pw_name = xstrdup(pw->pw_name);
|
||||
pwcopy.pw_passwd = xstrdup(pw->pw_passwd);
|
||||
pwcopy.pw_uid = pw->pw_uid;
|
||||
pwcopy.pw_gid = pw->pw_gid;
|
||||
#ifdef HAVE_PW_CLASS_IN_PASSWD
|
||||
pwcopy.pw_class = xstrdup(pw->pw_class);
|
||||
pwcopy.pw_class = xstrdup(pw->pw_class);
|
||||
#endif
|
||||
pwcopy.pw_dir = xstrdup(pw->pw_dir);
|
||||
pwcopy.pw_shell = xstrdup(pw->pw_shell);
|
||||
pw = &pwcopy;
|
||||
pwcopy.pw_dir = xstrdup(pw->pw_dir);
|
||||
pwcopy.pw_shell = xstrdup(pw->pw_shell);
|
||||
pw = &pwcopy;
|
||||
} else {
|
||||
pw = NULL;
|
||||
}
|
||||
|
||||
#ifdef USE_PAM
|
||||
start_pam(pw);
|
||||
if (pw)
|
||||
start_pam(pw);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_CYGWIN
|
||||
/*
|
||||
* If we are not running as root, the user must have the same uid as
|
||||
* the server.
|
||||
* Rule not valid on Windows systems.
|
||||
* the server. (Unless you are running Windows)
|
||||
*/
|
||||
if (getuid() != 0 && pw->pw_uid != getuid())
|
||||
#ifndef HAVE_CYGWIN
|
||||
if (getuid() != 0 && pw && pw->pw_uid != getuid())
|
||||
packet_disconnect("Cannot change user when server not running as root.");
|
||||
#endif
|
||||
|
||||
debug("Attempting authentication for %.100s.", pw->pw_name);
|
||||
debug("Attempting authentication for %s%.100s.", pw ? "" : "illegal user ", user);
|
||||
|
||||
/* If the user has no password, accept authentication immediately. */
|
||||
if (options.password_authentication &&
|
||||
|
@ -527,30 +458,33 @@ do_authentication()
|
|||
auth_pam_password(pw, "")) {
|
||||
#elif defined(HAVE_OSF_SIA)
|
||||
(sia_validate_user(NULL, saved_argc, saved_argv,
|
||||
get_canonical_hostname(), pw->pw_name, NULL, 0, NULL,
|
||||
"") == SIASUCCESS)) {
|
||||
get_canonical_hostname(), pw->pw_name, NULL, 0,
|
||||
NULL, "") == SIASUCCESS)) {
|
||||
#else /* !HAVE_OSF_SIA && !USE_PAM */
|
||||
auth_password(pw, "")) {
|
||||
auth_password(pw, "")) {
|
||||
#endif /* USE_PAM */
|
||||
/* Authentication with empty password succeeded. */
|
||||
log("Login for user %s from %.100s, accepted without authentication.",
|
||||
pw->pw_name, get_remote_ipaddr());
|
||||
user, get_remote_ipaddr());
|
||||
} else {
|
||||
/* Loop until the user has been authenticated or the
|
||||
connection is closed, do_authloop() returns only if
|
||||
authentication is successfull */
|
||||
do_authloop(pw);
|
||||
do_authloop(pw, user);
|
||||
}
|
||||
if (pw == NULL)
|
||||
fatal("internal error, authentication successfull for user '%.100s'", user);
|
||||
|
||||
/* The user has been authenticated and accepted. */
|
||||
packet_start(SSH_SMSG_SUCCESS);
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
|
||||
#ifdef WITH_AIXAUTHENTICATE
|
||||
/* We don't have a pty yet, so just label the line as "ssh" */
|
||||
if (loginsuccess(user,get_canonical_hostname(),"ssh",&aixloginmsg) < 0)
|
||||
aixloginmsg = NULL;
|
||||
#endif /* WITH_AIXAUTHENTICATE */
|
||||
packet_start(SSH_SMSG_SUCCESS);
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
|
||||
/* Perform session preparation. */
|
||||
do_authenticated(pw);
|
||||
|
|
432
auth2.c
432
auth2.c
|
@ -23,7 +23,12 @@
|
|||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$OpenBSD: auth2.c,v 1.16 2000/09/27 21:41:34 markus Exp $");
|
||||
RCSID("$OpenBSD: auth2.c,v 1.19 2000/10/11 20:27:23 markus Exp $");
|
||||
|
||||
#ifdef HAVE_OSF_SIA
|
||||
# include <sia.h>
|
||||
# include <siad.h>
|
||||
#endif
|
||||
|
||||
#include <openssl/dsa.h>
|
||||
#include <openssl/rsa.h>
|
||||
|
@ -35,7 +40,6 @@ RCSID("$OpenBSD: auth2.c,v 1.16 2000/09/27 21:41:34 markus Exp $");
|
|||
#include "pty.h"
|
||||
#include "packet.h"
|
||||
#include "buffer.h"
|
||||
#include "cipher.h"
|
||||
#include "servconf.h"
|
||||
#include "compat.h"
|
||||
#include "channels.h"
|
||||
|
@ -52,59 +56,85 @@ RCSID("$OpenBSD: auth2.c,v 1.16 2000/09/27 21:41:34 markus Exp $");
|
|||
#include "uidswap.h"
|
||||
#include "auth-options.h"
|
||||
|
||||
#ifdef HAVE_OSF_SIA
|
||||
# include <sia.h>
|
||||
# include <siad.h>
|
||||
#endif
|
||||
|
||||
/* import */
|
||||
extern ServerOptions options;
|
||||
extern unsigned char *session_id2;
|
||||
extern int session_id2_len;
|
||||
|
||||
#ifdef WITH_AIXAUTHENTICATE
|
||||
extern char *aixloginmsg;
|
||||
#endif
|
||||
#ifdef HAVE_OSF_SIA
|
||||
extern int saved_argc;
|
||||
extern char **saved_argv;
|
||||
#endif
|
||||
|
||||
static Authctxt *x_authctxt = NULL;
|
||||
static int one = 1;
|
||||
|
||||
typedef struct Authmethod Authmethod;
|
||||
struct Authmethod {
|
||||
char *name;
|
||||
int (*userauth)(Authctxt *authctxt);
|
||||
int *enabled;
|
||||
};
|
||||
|
||||
/* protocol */
|
||||
|
||||
void input_service_request(int type, int plen, void *ctxt);
|
||||
void input_userauth_request(int type, int plen, void *ctxt);
|
||||
void protocol_error(int type, int plen, void *ctxt);
|
||||
|
||||
/* auth */
|
||||
int ssh2_auth_none(struct passwd *pw);
|
||||
int ssh2_auth_password(struct passwd *pw);
|
||||
int ssh2_auth_pubkey(struct passwd *pw, char *service);
|
||||
|
||||
/* helper */
|
||||
struct passwd* auth_set_user(char *u, char *s);
|
||||
Authmethod *authmethod_lookup(const char *name);
|
||||
struct passwd *pwcopy(struct passwd *pw);
|
||||
int user_dsa_key_allowed(struct passwd *pw, Key *key);
|
||||
char *authmethods_get(void);
|
||||
|
||||
typedef struct Authctxt Authctxt;
|
||||
struct Authctxt {
|
||||
char *user;
|
||||
char *service;
|
||||
struct passwd pw;
|
||||
int valid;
|
||||
/* auth */
|
||||
int userauth_none(Authctxt *authctxt);
|
||||
int userauth_passwd(Authctxt *authctxt);
|
||||
int userauth_pubkey(Authctxt *authctxt);
|
||||
int userauth_kbdint(Authctxt *authctxt);
|
||||
|
||||
Authmethod authmethods[] = {
|
||||
{"none",
|
||||
userauth_none,
|
||||
&one},
|
||||
{"publickey",
|
||||
userauth_pubkey,
|
||||
&options.dsa_authentication},
|
||||
{"keyboard-interactive",
|
||||
userauth_kbdint,
|
||||
&options.kbd_interactive_authentication},
|
||||
{"password",
|
||||
userauth_passwd,
|
||||
&options.password_authentication},
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
static Authctxt *authctxt = NULL;
|
||||
static int userauth_success = 0;
|
||||
|
||||
/*
|
||||
* loop until userauth_success == TRUE
|
||||
* loop until authctxt->success == TRUE
|
||||
*/
|
||||
|
||||
void
|
||||
do_authentication2()
|
||||
{
|
||||
/* turn off skey/kerberos, not supported by SSH2 */
|
||||
#ifdef SKEY
|
||||
options.skey_authentication = 0;
|
||||
#endif
|
||||
Authctxt *authctxt = xmalloc(sizeof(*authctxt));
|
||||
memset(authctxt, 'a', sizeof(*authctxt));
|
||||
authctxt->valid = 0;
|
||||
authctxt->attempt = 0;
|
||||
authctxt->success = 0;
|
||||
x_authctxt = authctxt; /*XXX*/
|
||||
|
||||
#ifdef KRB4
|
||||
/* turn off kerberos, not supported by SSH2 */
|
||||
options.kerberos_authentication = 0;
|
||||
#endif
|
||||
|
||||
dispatch_init(&protocol_error);
|
||||
dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);
|
||||
dispatch_run(DISPATCH_BLOCK, &userauth_success, NULL);
|
||||
dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt);
|
||||
do_authenticated2();
|
||||
}
|
||||
|
||||
|
@ -121,13 +151,17 @@ protocol_error(int type, int plen, void *ctxt)
|
|||
void
|
||||
input_service_request(int type, int plen, void *ctxt)
|
||||
{
|
||||
Authctxt *authctxt = ctxt;
|
||||
unsigned int len;
|
||||
int accept = 0;
|
||||
char *service = packet_get_string(&len);
|
||||
packet_done();
|
||||
|
||||
if (authctxt == NULL)
|
||||
fatal("input_service_request: no authctxt");
|
||||
|
||||
if (strcmp(service, "ssh-userauth") == 0) {
|
||||
if (!userauth_success) {
|
||||
if (!authctxt->success) {
|
||||
accept = 1;
|
||||
/* now we can handle user-auth requests */
|
||||
dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request);
|
||||
|
@ -150,65 +184,99 @@ input_service_request(int type, int plen, void *ctxt)
|
|||
void
|
||||
input_userauth_request(int type, int plen, void *ctxt)
|
||||
{
|
||||
static void (*authlog) (const char *fmt,...) = verbose;
|
||||
static int attempt = 0;
|
||||
unsigned int len;
|
||||
Authctxt *authctxt = ctxt;
|
||||
Authmethod *m = NULL;
|
||||
char *user, *service, *method;
|
||||
int authenticated = 0;
|
||||
char *user, *service, *method, *authmsg = NULL;
|
||||
struct passwd *pw;
|
||||
#ifdef WITH_AIXAUTHENTICATE
|
||||
extern char *aixloginmsg;
|
||||
#endif /* WITH_AIXAUTHENTICATE */
|
||||
|
||||
user = packet_get_string(&len);
|
||||
service = packet_get_string(&len);
|
||||
method = packet_get_string(&len);
|
||||
if (++attempt == AUTH_FAIL_MAX) {
|
||||
if (authctxt == NULL)
|
||||
fatal("input_userauth_request: no authctxt");
|
||||
if (authctxt->attempt++ >= AUTH_FAIL_MAX) {
|
||||
#ifdef WITH_AIXAUTHENTICATE
|
||||
loginfailed(user,get_canonical_hostname(),"ssh");
|
||||
#endif /* WITH_AIXAUTHENTICATE */
|
||||
packet_disconnect("too many failed userauth_requests");
|
||||
}
|
||||
debug("userauth-request for user %s service %s method %s", user, service, method);
|
||||
|
||||
/* XXX we only allow the ssh-connection service */
|
||||
pw = auth_set_user(user, service);
|
||||
if (pw && strcmp(service, "ssh-connection")==0) {
|
||||
if (strcmp(method, "none") == 0) {
|
||||
authenticated = ssh2_auth_none(pw);
|
||||
} else if (strcmp(method, "password") == 0) {
|
||||
authenticated = ssh2_auth_password(pw);
|
||||
} else if (strcmp(method, "publickey") == 0) {
|
||||
authenticated = ssh2_auth_pubkey(pw, service);
|
||||
user = packet_get_string(NULL);
|
||||
service = packet_get_string(NULL);
|
||||
method = packet_get_string(NULL);
|
||||
debug("userauth-request for user %s service %s method %s", user, service, method);
|
||||
debug("attempt #%d", authctxt->attempt);
|
||||
|
||||
if (authctxt->attempt == 1) {
|
||||
/* setup auth context */
|
||||
struct passwd *pw = NULL;
|
||||
setproctitle("%s", user);
|
||||
pw = getpwnam(user);
|
||||
if (pw && allowed_user(pw) && strcmp(service, "ssh-connection")==0) {
|
||||
authctxt->pw = pwcopy(pw);
|
||||
authctxt->valid = 1;
|
||||
debug2("input_userauth_request: setting up authctxt for %s", user);
|
||||
#ifdef USE_PAM
|
||||
start_pam(pw);
|
||||
#endif
|
||||
} else {
|
||||
log("input_userauth_request: illegal user %s", user);
|
||||
}
|
||||
authctxt->user = xstrdup(user);
|
||||
authctxt->service = xstrdup(service);
|
||||
} else if (authctxt->valid) {
|
||||
if (strcmp(user, authctxt->user) != 0 ||
|
||||
strcmp(service, authctxt->service) != 0) {
|
||||
log("input_userauth_request: missmatch: (%s,%s)!=(%s,%s)",
|
||||
user, service, authctxt->user, authctxt->service);
|
||||
authctxt->valid = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_CYGWIN
|
||||
if (authenticated && !check_nt_auth(strcmp(method, "password") == 0, pw->pw_uid)) {
|
||||
packet_disconnect("Authentication rejected for uid %d.",
|
||||
(int) pw->pw_uid);
|
||||
m = authmethod_lookup(method);
|
||||
if (m != NULL) {
|
||||
debug2("input_userauth_request: try method %s", method);
|
||||
authenticated = m->userauth(authctxt);
|
||||
} else {
|
||||
debug2("input_userauth_request: unsupported method %s", method);
|
||||
}
|
||||
if (!authctxt->valid && authenticated == 1) {
|
||||
log("input_userauth_request: INTERNAL ERROR: authenticated invalid user %s service %s", user, method);
|
||||
authenticated = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (authenticated && pw && pw->pw_uid == 0 && !options.permit_root_login) {
|
||||
/* Special handling for root */
|
||||
if (authenticated == 1 &&
|
||||
authctxt->valid && authctxt->pw->pw_uid == 0 && !options.permit_root_login) {
|
||||
authenticated = 0;
|
||||
log("ROOT LOGIN REFUSED FROM %.200s",
|
||||
get_canonical_hostname());
|
||||
log("ROOT LOGIN REFUSED FROM %.200s", get_canonical_hostname());
|
||||
}
|
||||
|
||||
#ifdef USE_PAM
|
||||
if (authenticated && !do_pam_account(pw->pw_name, NULL))
|
||||
if (authenticated && !do_pam_account(authctxt->pw->pw_name, NULL))
|
||||
authenticated = 0;
|
||||
#endif /* USE_PAM */
|
||||
|
||||
/* Log before sending the reply */
|
||||
userauth_log(authctxt, authenticated, method);
|
||||
userauth_reply(authctxt, authenticated);
|
||||
|
||||
xfree(service);
|
||||
xfree(user);
|
||||
xfree(method);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
userauth_log(Authctxt *authctxt, int authenticated, char *method)
|
||||
{
|
||||
void (*authlog) (const char *fmt,...) = verbose;
|
||||
char *user = NULL, *authmsg = NULL;
|
||||
|
||||
/* Raise logging level */
|
||||
if (authenticated == 1 ||
|
||||
attempt == AUTH_FAIL_LOG ||
|
||||
!authctxt->valid ||
|
||||
authctxt->attempt >= AUTH_FAIL_LOG ||
|
||||
strcmp(method, "password") == 0)
|
||||
authlog = log;
|
||||
|
||||
/* Log before sending the reply */
|
||||
if (authenticated == 1) {
|
||||
authmsg = "Accepted";
|
||||
} else if (authenticated == 0) {
|
||||
|
@ -216,18 +284,29 @@ input_userauth_request(int type, int plen, void *ctxt)
|
|||
} else {
|
||||
authmsg = "Postponed";
|
||||
}
|
||||
authlog("%s %s for %.200s from %.200s port %d ssh2",
|
||||
authmsg,
|
||||
method,
|
||||
pw && pw->pw_uid == 0 ? "ROOT" : user,
|
||||
get_remote_ipaddr(),
|
||||
get_remote_port());
|
||||
|
||||
if (authctxt->valid) {
|
||||
user = authctxt->pw->pw_uid == 0 ? "ROOT" : authctxt->user;
|
||||
} else {
|
||||
user = "NOUSER";
|
||||
}
|
||||
|
||||
authlog("%s %s for %.200s from %.200s port %d ssh2",
|
||||
authmsg,
|
||||
method,
|
||||
user,
|
||||
get_remote_ipaddr(),
|
||||
get_remote_port());
|
||||
}
|
||||
|
||||
void
|
||||
userauth_reply(Authctxt *authctxt, int authenticated)
|
||||
{
|
||||
/* XXX todo: check if multiple auth methods are needed */
|
||||
if (authenticated == 1) {
|
||||
#ifdef WITH_AIXAUTHENTICATE
|
||||
/* We don't have a pty yet, so just label the line as "ssh" */
|
||||
if (loginsuccess(user,get_canonical_hostname(),"ssh",
|
||||
if (loginsuccess(user, get_canonical_hostname(), "ssh",
|
||||
&aixloginmsg) < 0)
|
||||
aixloginmsg = NULL;
|
||||
#endif /* WITH_AIXAUTHENTICATE */
|
||||
|
@ -237,73 +316,106 @@ input_userauth_request(int type, int plen, void *ctxt)
|
|||
packet_send();
|
||||
packet_write_wait();
|
||||
/* now we can break out */
|
||||
userauth_success = 1;
|
||||
authctxt->success = 1;
|
||||
} else if (authenticated == 0) {
|
||||
char *methods = authmethods_get();
|
||||
packet_start(SSH2_MSG_USERAUTH_FAILURE);
|
||||
packet_put_cstring("publickey,password"); /* XXX dynamic */
|
||||
packet_put_char(0); /* XXX partial success, unused */
|
||||
packet_put_cstring(methods);
|
||||
packet_put_char(0); /* XXX partial success, unused */
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
xfree(methods);
|
||||
} else {
|
||||
/* do nothing, we did already send a reply */
|
||||
}
|
||||
|
||||
xfree(service);
|
||||
xfree(user);
|
||||
xfree(method);
|
||||
}
|
||||
|
||||
int
|
||||
ssh2_auth_none(struct passwd *pw)
|
||||
userauth_none(Authctxt *authctxt)
|
||||
{
|
||||
#ifdef HAVE_OSF_SIA
|
||||
extern int saved_argc;
|
||||
extern char **saved_argv;
|
||||
#endif
|
||||
|
||||
/* disable method "none", only allowed one time */
|
||||
Authmethod *m = authmethod_lookup("none");
|
||||
if (m != NULL)
|
||||
m->enabled = NULL;
|
||||
packet_done();
|
||||
|
||||
if (authctxt->valid == 0)
|
||||
return(0);
|
||||
|
||||
#ifdef HAVE_CYGWIN
|
||||
if (check_nt_auth(1, authctxt->pw->pw_uid) == 0)
|
||||
return(0);
|
||||
#endif
|
||||
#ifdef USE_PAM
|
||||
return auth_pam_password(pw, "");
|
||||
return auth_pam_password(authctxt->pw, "");
|
||||
#elif defined(HAVE_OSF_SIA)
|
||||
return(sia_validate_user(NULL, saved_argc, saved_argv,
|
||||
get_canonical_hostname(), pw->pw_name, NULL, 0, NULL,
|
||||
"") == SIASUCCESS);
|
||||
return (sia_validate_user(NULL, saved_argc, saved_argv,
|
||||
get_canonical_hostname(), authctxt->pw->pw_name, NULL,
|
||||
0, NULL, "") == SIASUCCESS);
|
||||
#else /* !HAVE_OSF_SIA && !USE_PAM */
|
||||
return auth_password(pw, "");
|
||||
return auth_password(authctxt->pw, "");
|
||||
#endif /* USE_PAM */
|
||||
}
|
||||
|
||||
int
|
||||
ssh2_auth_password(struct passwd *pw)
|
||||
userauth_passwd(Authctxt *authctxt)
|
||||
{
|
||||
char *password;
|
||||
int authenticated = 0;
|
||||
int change;
|
||||
unsigned int len;
|
||||
#ifdef HAVE_OSF_SIA
|
||||
extern int saved_argc;
|
||||
extern char **saved_argv;
|
||||
#endif
|
||||
change = packet_get_char();
|
||||
if (change)
|
||||
log("password change not supported");
|
||||
password = packet_get_string(&len);
|
||||
packet_done();
|
||||
if (options.password_authentication &&
|
||||
if (authctxt->valid &&
|
||||
#ifdef HAVE_CYGWIN
|
||||
check_nt_auth(1, authctxt->pw->pw_uid) &&
|
||||
#endif
|
||||
#ifdef USE_PAM
|
||||
auth_pam_password(pw, password) == 1)
|
||||
auth_pam_password(authctxt->pw, password) == 1)
|
||||
#elif defined(HAVE_OSF_SIA)
|
||||
sia_validate_user(NULL, saved_argc, saved_argv,
|
||||
get_canonical_hostname(), pw->pw_name, NULL, 0,
|
||||
get_canonical_hostname(), authctxt->pw->pw_name, NULL, 0,
|
||||
NULL, password) == SIASUCCESS)
|
||||
#else /* !USE_PAM && !HAVE_OSF_SIA */
|
||||
auth_password(pw, password) == 1)
|
||||
auth_password(authctxt->pw, password) == 1)
|
||||
#endif /* USE_PAM */
|
||||
authenticated = 1;
|
||||
memset(password, 0, len);
|
||||
xfree(password);
|
||||
return authenticated;
|
||||
}
|
||||
|
||||
int
|
||||
ssh2_auth_pubkey(struct passwd *pw, char *service)
|
||||
userauth_kbdint(Authctxt *authctxt)
|
||||
{
|
||||
int authenticated = 0;
|
||||
char *lang = NULL;
|
||||
char *devs = NULL;
|
||||
|
||||
lang = packet_get_string(NULL);
|
||||
devs = packet_get_string(NULL);
|
||||
packet_done();
|
||||
|
||||
debug("keyboard-interactive language %s devs %s", lang, devs);
|
||||
#ifdef SKEY
|
||||
/* XXX hardcoded, we should look at devs */
|
||||
if (options.skey_authentication != 0)
|
||||
authenticated = auth2_skey(authctxt);
|
||||
#endif
|
||||
xfree(lang);
|
||||
xfree(devs);
|
||||
#ifdef HAVE_CYGWIN
|
||||
if (check_nt_auth(0, authctxt->pw->pw_uid) == 0)
|
||||
return(0);
|
||||
#endif
|
||||
return authenticated;
|
||||
}
|
||||
|
||||
int
|
||||
userauth_pubkey(Authctxt *authctxt)
|
||||
{
|
||||
Buffer b;
|
||||
Key *key;
|
||||
|
@ -312,15 +424,15 @@ ssh2_auth_pubkey(struct passwd *pw, char *service)
|
|||
int have_sig;
|
||||
int authenticated = 0;
|
||||
|
||||
if (options.dsa_authentication == 0) {
|
||||
debug("pubkey auth disabled");
|
||||
if (!authctxt->valid) {
|
||||
debug2("userauth_pubkey: disabled because of invalid user");
|
||||
return 0;
|
||||
}
|
||||
have_sig = packet_get_char();
|
||||
pkalg = packet_get_string(&alen);
|
||||
if (strcmp(pkalg, KEX_DSS) != 0) {
|
||||
xfree(pkalg);
|
||||
log("bad pkalg %s", pkalg); /*XXX*/
|
||||
xfree(pkalg);
|
||||
return 0;
|
||||
}
|
||||
pkblob = packet_get_string(&blen);
|
||||
|
@ -337,11 +449,11 @@ ssh2_auth_pubkey(struct passwd *pw, char *service)
|
|||
}
|
||||
/* reconstruct packet */
|
||||
buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
|
||||
buffer_put_cstring(&b, pw->pw_name);
|
||||
buffer_put_cstring(&b, authctxt->user);
|
||||
buffer_put_cstring(&b,
|
||||
datafellows & SSH_BUG_PUBKEYAUTH ?
|
||||
"ssh-userauth" :
|
||||
service);
|
||||
authctxt->service);
|
||||
buffer_put_cstring(&b, "publickey");
|
||||
buffer_put_char(&b, have_sig);
|
||||
buffer_put_cstring(&b, KEX_DSS);
|
||||
|
@ -350,15 +462,15 @@ ssh2_auth_pubkey(struct passwd *pw, char *service)
|
|||
buffer_dump(&b);
|
||||
#endif
|
||||
/* test for correct signature */
|
||||
if (user_dsa_key_allowed(pw, key) &&
|
||||
if (user_dsa_key_allowed(authctxt->pw, key) &&
|
||||
dsa_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1)
|
||||
authenticated = 1;
|
||||
buffer_clear(&b);
|
||||
xfree(sig);
|
||||
} else {
|
||||
debug("test whether pkalg/pkblob are acceptable");
|
||||
packet_done();
|
||||
debug("test key...");
|
||||
/* test whether pkalg/pkblob are acceptable */
|
||||
|
||||
/* XXX fake reply and always send PK_OK ? */
|
||||
/*
|
||||
* XXX this allows testing whether a user is allowed
|
||||
|
@ -367,7 +479,7 @@ ssh2_auth_pubkey(struct passwd *pw, char *service)
|
|||
* if a user is not allowed to login. is this an
|
||||
* issue? -markus
|
||||
*/
|
||||
if (user_dsa_key_allowed(pw, key)) {
|
||||
if (user_dsa_key_allowed(authctxt->pw, key)) {
|
||||
packet_start(SSH2_MSG_USERAUTH_PK_OK);
|
||||
packet_put_string(pkalg, alen);
|
||||
packet_put_string(pkblob, blen);
|
||||
|
@ -376,61 +488,73 @@ ssh2_auth_pubkey(struct passwd *pw, char *service)
|
|||
authenticated = -1;
|
||||
}
|
||||
}
|
||||
if (authenticated != 1)
|
||||
auth_clear_options();
|
||||
key_free(key);
|
||||
}
|
||||
xfree(pkalg);
|
||||
xfree(pkblob);
|
||||
#ifdef HAVE_CYGWIN
|
||||
if (check_nt_auth(0, authctxt->pw->pw_uid) == 0)
|
||||
return(0);
|
||||
#endif
|
||||
return authenticated;
|
||||
}
|
||||
|
||||
/* set and get current user */
|
||||
/* get current user */
|
||||
|
||||
struct passwd*
|
||||
auth_get_user(void)
|
||||
{
|
||||
return (authctxt != NULL && authctxt->valid) ? &authctxt->pw : NULL;
|
||||
return (x_authctxt != NULL && x_authctxt->valid) ? x_authctxt->pw : NULL;
|
||||
}
|
||||
|
||||
struct passwd*
|
||||
auth_set_user(char *u, char *s)
|
||||
{
|
||||
struct passwd *pw, *copy;
|
||||
#define DELIM ","
|
||||
|
||||
if (authctxt == NULL) {
|
||||
authctxt = xmalloc(sizeof(*authctxt));
|
||||
authctxt->valid = 0;
|
||||
authctxt->user = xstrdup(u);
|
||||
authctxt->service = xstrdup(s);
|
||||
setproctitle("%s", u);
|
||||
pw = getpwnam(u);
|
||||
if (!pw || !allowed_user(pw)) {
|
||||
log("auth_set_user: illegal user %s", u);
|
||||
return NULL;
|
||||
}
|
||||
#ifdef USE_PAM
|
||||
start_pam(pw);
|
||||
#endif
|
||||
copy = &authctxt->pw;
|
||||
memset(copy, 0, sizeof(*copy));
|
||||
copy->pw_name = xstrdup(pw->pw_name);
|
||||
copy->pw_passwd = xstrdup(pw->pw_passwd);
|
||||
copy->pw_uid = pw->pw_uid;
|
||||
copy->pw_gid = pw->pw_gid;
|
||||
#ifdef HAVE_PW_CLASS_IN_PASSWD
|
||||
copy->pw_class = xstrdup(pw->pw_class);
|
||||
#endif
|
||||
copy->pw_dir = xstrdup(pw->pw_dir);
|
||||
copy->pw_shell = xstrdup(pw->pw_shell);
|
||||
authctxt->valid = 1;
|
||||
} else {
|
||||
if (strcmp(u, authctxt->user) != 0 ||
|
||||
strcmp(s, authctxt->service) != 0) {
|
||||
log("auth_set_user: missmatch: (%s,%s)!=(%s,%s)",
|
||||
u, s, authctxt->user, authctxt->service);
|
||||
return NULL;
|
||||
char *
|
||||
authmethods_get(void)
|
||||
{
|
||||
Authmethod *method = NULL;
|
||||
unsigned int size = 0;
|
||||
char *list;
|
||||
|
||||
for (method = authmethods; method->name != NULL; method++) {
|
||||
if (strcmp(method->name, "none") == 0)
|
||||
continue;
|
||||
if (method->enabled != NULL && *(method->enabled) != 0) {
|
||||
if (size != 0)
|
||||
size += strlen(DELIM);
|
||||
size += strlen(method->name);
|
||||
}
|
||||
}
|
||||
return auth_get_user();
|
||||
size++; /* trailing '\0' */
|
||||
list = xmalloc(size);
|
||||
list[0] = '\0';
|
||||
|
||||
for (method = authmethods; method->name != NULL; method++) {
|
||||
if (strcmp(method->name, "none") == 0)
|
||||
continue;
|
||||
if (method->enabled != NULL && *(method->enabled) != 0) {
|
||||
if (list[0] != '\0')
|
||||
strlcat(list, DELIM, size);
|
||||
strlcat(list, method->name, size);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
Authmethod *
|
||||
authmethod_lookup(const char *name)
|
||||
{
|
||||
Authmethod *method = NULL;
|
||||
if (name != NULL)
|
||||
for (method = authmethods; method->name != NULL; method++)
|
||||
if (method->enabled != NULL &&
|
||||
*(method->enabled) != 0 &&
|
||||
strcmp(name, method->name) == 0)
|
||||
return method;
|
||||
debug2("Unrecognized authentication method name: %s", name ? name : "NULL");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* return 1 if user allows given key */
|
||||
|
@ -445,6 +569,9 @@ user_dsa_key_allowed(struct passwd *pw, Key *key)
|
|||
struct stat st;
|
||||
Key *found;
|
||||
|
||||
if (pw == NULL)
|
||||
return 0;
|
||||
|
||||
/* Temporarily use the user's uid. */
|
||||
temporarily_use_uid(pw->pw_uid);
|
||||
|
||||
|
@ -550,3 +677,20 @@ user_dsa_key_allowed(struct passwd *pw, Key *key)
|
|||
key_free(found);
|
||||
return found_key;
|
||||
}
|
||||
|
||||
struct passwd *
|
||||
pwcopy(struct passwd *pw)
|
||||
{
|
||||
struct passwd *copy = xmalloc(sizeof(*copy));
|
||||
memset(copy, 0, sizeof(*copy));
|
||||
copy->pw_name = xstrdup(pw->pw_name);
|
||||
copy->pw_passwd = xstrdup(pw->pw_passwd);
|
||||
copy->pw_uid = pw->pw_uid;
|
||||
copy->pw_gid = pw->pw_gid;
|
||||
#ifdef HAVE_PW_CLASS_IN_PASSWD
|
||||
copy->pw_class = xstrdup(pw->pw_class);
|
||||
#endif
|
||||
copy->pw_dir = xstrdup(pw->pw_dir);
|
||||
copy->pw_shell = xstrdup(pw->pw_shell);
|
||||
return copy;
|
||||
}
|
||||
|
|
13
authfd.c
13
authfd.c
|
@ -35,7 +35,7 @@
|
|||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$OpenBSD: authfd.c,v 1.28 2000/09/21 11:07:50 markus Exp $");
|
||||
RCSID("$OpenBSD: authfd.c,v 1.29 2000/10/09 21:51:00 markus Exp $");
|
||||
|
||||
#include "ssh.h"
|
||||
#include "rsa.h"
|
||||
|
@ -56,6 +56,10 @@ RCSID("$OpenBSD: authfd.c,v 1.28 2000/09/21 11:07:50 markus Exp $");
|
|||
/* helper */
|
||||
int decode_reply(int type);
|
||||
|
||||
/* macro to check for "agent failure" message */
|
||||
#define agent_failed(x) \
|
||||
((x == SSH_AGENT_FAILURE) || (x == SSH_COM_AGENT2_FAILURE))
|
||||
|
||||
/* Returns the number of the authentication fd, or -1 if there is none. */
|
||||
|
||||
int
|
||||
|
@ -242,7 +246,7 @@ ssh_get_first_identity(AuthenticationConnection *auth, char **comment, int versi
|
|||
|
||||
/* Get message type, and verify that we got a proper answer. */
|
||||
type = buffer_get_char(&auth->identities);
|
||||
if (type == SSH_AGENT_FAILURE) {
|
||||
if (agent_failed(type)) {
|
||||
return NULL;
|
||||
} else if (type != code2) {
|
||||
fatal("Bad authentication reply message type: %d", type);
|
||||
|
@ -341,7 +345,7 @@ ssh_decrypt_challenge(AuthenticationConnection *auth,
|
|||
}
|
||||
type = buffer_get_char(&buffer);
|
||||
|
||||
if (type == SSH_AGENT_FAILURE) {
|
||||
if (agent_failed(type)) {
|
||||
log("Agent admitted failure to authenticate using the key.");
|
||||
} else if (type != SSH_AGENT_RSA_RESPONSE) {
|
||||
fatal("Bad authentication response: %d", type);
|
||||
|
@ -390,7 +394,7 @@ ssh_agent_sign(AuthenticationConnection *auth,
|
|||
return -1;
|
||||
}
|
||||
type = buffer_get_char(&msg);
|
||||
if (type == SSH_AGENT_FAILURE) {
|
||||
if (agent_failed(type)) {
|
||||
log("Agent admitted failure to sign using the key.");
|
||||
} else if (type != SSH2_AGENT_SIGN_RESPONSE) {
|
||||
fatal("Bad authentication response: %d", type);
|
||||
|
@ -537,6 +541,7 @@ decode_reply(int type)
|
|||
{
|
||||
switch (type) {
|
||||
case SSH_AGENT_FAILURE:
|
||||
case SSH_COM_AGENT2_FAILURE:
|
||||
log("SSH_AGENT_FAILURE");
|
||||
return 0;
|
||||
case SSH_AGENT_SUCCESS:
|
||||
|
|
6
authfd.h
6
authfd.h
|
@ -11,7 +11,7 @@
|
|||
* called by a name other than "ssh" or "Secure Shell".
|
||||
*/
|
||||
|
||||
/* RCSID("$OpenBSD: authfd.h,v 1.12 2000/09/21 11:07:51 markus Exp $"); */
|
||||
/* RCSID("$OpenBSD: authfd.h,v 1.13 2000/10/09 21:51:00 markus Exp $"); */
|
||||
|
||||
#ifndef AUTHFD_H
|
||||
#define AUTHFD_H
|
||||
|
@ -29,6 +29,7 @@
|
|||
#define SSH_AGENTC_REMOVE_RSA_IDENTITY 8
|
||||
#define SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES 9
|
||||
|
||||
/* private OpenSSH extensions for SSH2 */
|
||||
#define SSH2_AGENTC_REQUEST_IDENTITIES 11
|
||||
#define SSH2_AGENT_IDENTITIES_ANSWER 12
|
||||
#define SSH2_AGENTC_SIGN_REQUEST 13
|
||||
|
@ -37,6 +38,9 @@
|
|||
#define SSH2_AGENTC_REMOVE_IDENTITY 18
|
||||
#define SSH2_AGENTC_REMOVE_ALL_IDENTITIES 19
|
||||
|
||||
/* additional error code for ssh.com's ssh-agent2 */
|
||||
#define SSH_COM_AGENT2_FAILURE 102
|
||||
|
||||
#define SSH_AGENT_OLD_SIGNATURE 0x01
|
||||
|
||||
|
||||
|
|
44
authfile.c
44
authfile.c
|
@ -36,7 +36,7 @@
|
|||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$OpenBSD: authfile.c,v 1.19 2000/09/07 20:27:49 deraadt Exp $");
|
||||
RCSID("$OpenBSD: authfile.c,v 1.20 2000/10/11 20:27:23 markus Exp $");
|
||||
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/dsa.h>
|
||||
|
@ -47,7 +47,6 @@ RCSID("$OpenBSD: authfile.c,v 1.19 2000/09/07 20:27:49 deraadt Exp $");
|
|||
#include "xmalloc.h"
|
||||
#include "buffer.h"
|
||||
#include "bufaux.h"
|
||||
#include "cipher.h"
|
||||
#include "ssh.h"
|
||||
#include "key.h"
|
||||
|
||||
|
@ -68,8 +67,8 @@ save_private_key_rsa(const char *filename, const char *passphrase,
|
|||
Buffer buffer, encrypted;
|
||||
char buf[100], *cp;
|
||||
int fd, i;
|
||||
CipherContext cipher;
|
||||
int cipher_type;
|
||||
CipherContext ciphercontext;
|
||||
Cipher *cipher;
|
||||
u_int32_t rand;
|
||||
|
||||
/*
|
||||
|
@ -77,9 +76,11 @@ save_private_key_rsa(const char *filename, const char *passphrase,
|
|||
* to another cipher; otherwise use SSH_AUTHFILE_CIPHER.
|
||||
*/
|
||||
if (strcmp(passphrase, "") == 0)
|
||||
cipher_type = SSH_CIPHER_NONE;
|
||||
cipher = cipher_by_number(SSH_CIPHER_NONE);
|
||||
else
|
||||
cipher_type = SSH_AUTHFILE_CIPHER;
|
||||
cipher = cipher_by_number(SSH_AUTHFILE_CIPHER);
|
||||
if (cipher == NULL)
|
||||
fatal("save_private_key_rsa: bad cipher");
|
||||
|
||||
/* This buffer is used to built the secret part of the private key. */
|
||||
buffer_init(&buffer);
|
||||
|
@ -116,7 +117,7 @@ save_private_key_rsa(const char *filename, const char *passphrase,
|
|||
buffer_put_char(&encrypted, 0);
|
||||
|
||||
/* Store cipher type. */
|
||||
buffer_put_char(&encrypted, cipher_type);
|
||||
buffer_put_char(&encrypted, cipher->number);
|
||||
buffer_put_int(&encrypted, 0); /* For future extension */
|
||||
|
||||
/* Store public key. This will be in plain text. */
|
||||
|
@ -128,11 +129,10 @@ save_private_key_rsa(const char *filename, const char *passphrase,
|
|||
/* Allocate space for the private part of the key in the buffer. */
|
||||
buffer_append_space(&encrypted, &cp, buffer_len(&buffer));
|
||||
|
||||
cipher_set_key_string(&cipher, cipher_type, passphrase);
|
||||
cipher_encrypt(&cipher, (unsigned char *) cp,
|
||||
(unsigned char *) buffer_ptr(&buffer),
|
||||
buffer_len(&buffer));
|
||||
memset(&cipher, 0, sizeof(cipher));
|
||||
cipher_set_key_string(&ciphercontext, cipher, passphrase);
|
||||
cipher_encrypt(&ciphercontext, (unsigned char *) cp,
|
||||
(unsigned char *) buffer_ptr(&buffer), buffer_len(&buffer));
|
||||
memset(&ciphercontext, 0, sizeof(ciphercontext));
|
||||
|
||||
/* Destroy temporary data. */
|
||||
memset(buf, 0, sizeof(buf));
|
||||
|
@ -313,7 +313,8 @@ load_private_key_rsa(int fd, const char *filename,
|
|||
off_t len;
|
||||
Buffer buffer, decrypted;
|
||||
char *cp;
|
||||
CipherContext cipher;
|
||||
CipherContext ciphercontext;
|
||||
Cipher *cipher;
|
||||
BN_CTX *ctx;
|
||||
BIGNUM *aux;
|
||||
|
||||
|
@ -364,10 +365,10 @@ load_private_key_rsa(int fd, const char *filename,
|
|||
xfree(buffer_get_string(&buffer, NULL));
|
||||
|
||||
/* Check that it is a supported cipher. */
|
||||
if (((cipher_mask1() | SSH_CIPHER_NONE | SSH_AUTHFILE_CIPHER) &
|
||||
(1 << cipher_type)) == 0) {
|
||||
debug("Unsupported cipher %.100s used in key file %.200s.",
|
||||
cipher_name(cipher_type), filename);
|
||||
cipher = cipher_by_number(cipher_type);
|
||||
if (cipher == NULL) {
|
||||
debug("Unsupported cipher %d used in key file %.200s.",
|
||||
cipher_type, filename);
|
||||
buffer_free(&buffer);
|
||||
goto fail;
|
||||
}
|
||||
|
@ -376,11 +377,10 @@ load_private_key_rsa(int fd, const char *filename,
|
|||
buffer_append_space(&decrypted, &cp, buffer_len(&buffer));
|
||||
|
||||
/* Rest of the buffer is encrypted. Decrypt it using the passphrase. */
|
||||
cipher_set_key_string(&cipher, cipher_type, passphrase);
|
||||
cipher_decrypt(&cipher, (unsigned char *) cp,
|
||||
(unsigned char *) buffer_ptr(&buffer),
|
||||
buffer_len(&buffer));
|
||||
|
||||
cipher_set_key_string(&ciphercontext, cipher, passphrase);
|
||||
cipher_decrypt(&ciphercontext, (unsigned char *) cp,
|
||||
(unsigned char *) buffer_ptr(&buffer), buffer_len(&buffer));
|
||||
memset(&ciphercontext, 0, sizeof(ciphercontext));
|
||||
buffer_free(&buffer);
|
||||
|
||||
check1 = buffer_get_char(&decrypted);
|
||||
|
|
|
@ -0,0 +1,137 @@
|
|||
/*-
|
||||
* Copyright (c) 1989, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
static char rcsid[] = "$OpenBSD: vis.c,v 1.5 2000/07/19 15:25:13 deraadt Exp $";
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
#ifndef HAVE_VIS
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#define isoctal(c) (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7')
|
||||
|
||||
/*
|
||||
* vis - visually encode characters
|
||||
*/
|
||||
char *vis(char *dst, int c, int flag, int nextc)
|
||||
{
|
||||
if (((u_int)c <= UCHAR_MAX && isascii((u_char)c) &&
|
||||
isgraph((u_char)c)) ||
|
||||
((flag & VIS_SP) == 0 && c == ' ') ||
|
||||
((flag & VIS_TAB) == 0 && c == '\t') ||
|
||||
((flag & VIS_NL) == 0 && c == '\n') ||
|
||||
((flag & VIS_SAFE) && (c == '\b' || c == '\007' || c == '\r'))) {
|
||||
*dst++ = c;
|
||||
if (c == '\\' && (flag & VIS_NOSLASH) == 0)
|
||||
*dst++ = '\\';
|
||||
*dst = '\0';
|
||||
return (dst);
|
||||
}
|
||||
|
||||
if (flag & VIS_CSTYLE) {
|
||||
switch(c) {
|
||||
case '\n':
|
||||
*dst++ = '\\';
|
||||
*dst++ = 'n';
|
||||
goto done;
|
||||
case '\r':
|
||||
*dst++ = '\\';
|
||||
*dst++ = 'r';
|
||||
goto done;
|
||||
case '\b':
|
||||
*dst++ = '\\';
|
||||
*dst++ = 'b';
|
||||
goto done;
|
||||
#ifdef __STDC__
|
||||
case '\a':
|
||||
#else
|
||||
case '\007':
|
||||
#endif
|
||||
*dst++ = '\\';
|
||||
*dst++ = 'a';
|
||||
goto done;
|
||||
case '\v':
|
||||
*dst++ = '\\';
|
||||
*dst++ = 'v';
|
||||
goto done;
|
||||
case '\t':
|
||||
*dst++ = '\\';
|
||||
*dst++ = 't';
|
||||
goto done;
|
||||
case '\f':
|
||||
*dst++ = '\\';
|
||||
*dst++ = 'f';
|
||||
goto done;
|
||||
case ' ':
|
||||
*dst++ = '\\';
|
||||
*dst++ = 's';
|
||||
goto done;
|
||||
case '\0':
|
||||
*dst++ = '\\';
|
||||
*dst++ = '0';
|
||||
if (isoctal(nextc)) {
|
||||
*dst++ = '0';
|
||||
*dst++ = '0';
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
if (((c & 0177) == ' ') || (flag & VIS_OCTAL)) {
|
||||
*dst++ = '\\';
|
||||
*dst++ = ((u_char)c >> 6 & 07) + '0';
|
||||
*dst++ = ((u_char)c >> 3 & 07) + '0';
|
||||
*dst++ = ((u_char)c & 07) + '0';
|
||||
goto done;
|
||||
}
|
||||
if ((flag & VIS_NOSLASH) == 0)
|
||||
*dst++ = '\\';
|
||||
if (c & 0200) {
|
||||
c &= 0177;
|
||||
*dst++ = 'M';
|
||||
}
|
||||
if (iscntrl(c)) {
|
||||
*dst++ = '^';
|
||||
if (c == 0177)
|
||||
*dst++ = '?';
|
||||
else
|
||||
*dst++ = c + '@';
|
||||
} else {
|
||||
*dst++ = '-';
|
||||
*dst++ = c;
|
||||
}
|
||||
done:
|
||||
*dst = '\0';
|
||||
return (dst);
|
||||
}
|
||||
#endif /* HAVE_VIS */
|
|
@ -0,0 +1,32 @@
|
|||
#ifndef _BSD_VIS_H
|
||||
#define _BSD_VIS_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifndef HAVE_VIS
|
||||
|
||||
/*
|
||||
* to select alternate encoding format
|
||||
*/
|
||||
#define VIS_OCTAL 0x01 /* use octal \ddd format */
|
||||
#define VIS_CSTYLE 0x02 /* use \[nrft0..] where appropriate */
|
||||
|
||||
/*
|
||||
* to alter set of characters encoded (default is to encode all
|
||||
* non-graphic except space, tab, and newline).
|
||||
*/
|
||||
#define VIS_SP 0x04 /* also encode space */
|
||||
#define VIS_TAB 0x08 /* also encode tab */
|
||||
#define VIS_NL 0x10 /* also encode newline */
|
||||
#define VIS_WHITE (VIS_SP | VIS_TAB | VIS_NL)
|
||||
#define VIS_SAFE 0x20 /* only encode "unsafe" characters */
|
||||
|
||||
/*
|
||||
* other
|
||||
*/
|
||||
#define VIS_NOSLASH 0x40 /* inhibit printing '\' */
|
||||
|
||||
char *vis (char *, int, int, int);
|
||||
#endif /* HAVE_VIS */
|
||||
|
||||
#endif /* _BSD_VIS_H */
|
705
cipher.c
705
cipher.c
|
@ -35,14 +35,91 @@
|
|||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$OpenBSD: cipher.c,v 1.31 2000/09/12 00:38:32 deraadt Exp $");
|
||||
RCSID("$OpenBSD: cipher.c,v 1.35 2000/10/13 18:59:13 markus Exp $");
|
||||
|
||||
#include "ssh.h"
|
||||
#include "cipher.h"
|
||||
#include "xmalloc.h"
|
||||
|
||||
#include <openssl/md5.h>
|
||||
|
||||
|
||||
/* no encryption */
|
||||
void
|
||||
none_setkey(CipherContext *cc, const u_char *key, u_int keylen)
|
||||
{
|
||||
}
|
||||
void
|
||||
none_setiv(CipherContext *cc, const u_char *iv, u_int ivlen)
|
||||
{
|
||||
}
|
||||
void
|
||||
none_crypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
|
||||
{
|
||||
memcpy(dest, src, len);
|
||||
}
|
||||
|
||||
/* DES */
|
||||
void
|
||||
des_ssh1_setkey(CipherContext *cc, const u_char *key, u_int keylen)
|
||||
{
|
||||
static int dowarn = 1;
|
||||
if (dowarn) {
|
||||
error("Warning: use of DES is strongly discouraged "
|
||||
"due to cryptographic weaknesses");
|
||||
dowarn = 0;
|
||||
}
|
||||
des_set_key((void *)key, cc->u.des.key);
|
||||
}
|
||||
void
|
||||
des_ssh1_setiv(CipherContext *cc, const u_char *iv, u_int ivlen)
|
||||
{
|
||||
memset(cc->u.des.iv, 0, sizeof(cc->u.des.iv));
|
||||
}
|
||||
void
|
||||
des_ssh1_encrypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
|
||||
{
|
||||
des_ncbc_encrypt(src, dest, len, cc->u.des.key, &cc->u.des.iv,
|
||||
DES_ENCRYPT);
|
||||
}
|
||||
void
|
||||
des_ssh1_decrypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
|
||||
{
|
||||
des_ncbc_encrypt(src, dest, len, cc->u.des.key, &cc->u.des.iv,
|
||||
DES_DECRYPT);
|
||||
}
|
||||
|
||||
/* 3DES */
|
||||
void
|
||||
des3_setkey(CipherContext *cc, const u_char *key, u_int keylen)
|
||||
{
|
||||
des_set_key((void *) key, cc->u.des3.key1);
|
||||
des_set_key((void *) (key+8), cc->u.des3.key2);
|
||||
des_set_key((void *) (key+16), cc->u.des3.key3);
|
||||
}
|
||||
void
|
||||
des3_setiv(CipherContext *cc, const u_char *iv, u_int ivlen)
|
||||
{
|
||||
memset(cc->u.des3.iv2, 0, sizeof(cc->u.des3.iv2));
|
||||
memset(cc->u.des3.iv3, 0, sizeof(cc->u.des3.iv3));
|
||||
if (iv == NULL)
|
||||
return;
|
||||
memcpy(cc->u.des3.iv3, (char *)iv, 8);
|
||||
}
|
||||
void
|
||||
des3_cbc_encrypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
|
||||
{
|
||||
des_ede3_cbc_encrypt(src, dest, len,
|
||||
cc->u.des3.key1, cc->u.des3.key2, cc->u.des3.key3,
|
||||
&cc->u.des3.iv3, DES_ENCRYPT);
|
||||
}
|
||||
void
|
||||
des3_cbc_decrypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
|
||||
{
|
||||
des_ede3_cbc_encrypt(src, dest, len,
|
||||
cc->u.des3.key1, cc->u.des3.key2, cc->u.des3.key3,
|
||||
&cc->u.des3.iv3, DES_DECRYPT);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is used by SSH1:
|
||||
*
|
||||
|
@ -58,48 +135,84 @@ RCSID("$OpenBSD: cipher.c,v 1.31 2000/09/12 00:38:32 deraadt Exp $");
|
|||
* choosing the X block.
|
||||
*/
|
||||
void
|
||||
SSH_3CBC_ENCRYPT(des_key_schedule ks1,
|
||||
des_key_schedule ks2, des_cblock * iv2,
|
||||
des_key_schedule ks3, des_cblock * iv3,
|
||||
unsigned char *dest, unsigned char *src,
|
||||
unsigned int len)
|
||||
des3_ssh1_setkey(CipherContext *cc, const u_char *key, u_int keylen)
|
||||
{
|
||||
des_set_key((void *) key, cc->u.des3.key1);
|
||||
des_set_key((void *) (key+8), cc->u.des3.key2);
|
||||
if (keylen <= 16)
|
||||
des_set_key((void *) key, cc->u.des3.key3);
|
||||
else
|
||||
des_set_key((void *) (key+16), cc->u.des3.key3);
|
||||
}
|
||||
void
|
||||
des3_ssh1_encrypt(CipherContext *cc, u_char *dest, const u_char *src,
|
||||
u_int len)
|
||||
{
|
||||
des_cblock iv1;
|
||||
des_cblock *iv2 = &cc->u.des3.iv2;
|
||||
des_cblock *iv3 = &cc->u.des3.iv3;
|
||||
|
||||
memcpy(&iv1, iv2, 8);
|
||||
|
||||
des_cbc_encrypt(src, dest, len, ks1, &iv1, DES_ENCRYPT);
|
||||
des_cbc_encrypt(src, dest, len, cc->u.des3.key1, &iv1, DES_ENCRYPT);
|
||||
memcpy(&iv1, dest + len - 8, 8);
|
||||
|
||||
des_cbc_encrypt(dest, dest, len, ks2, iv2, DES_DECRYPT);
|
||||
des_cbc_encrypt(dest, dest, len, cc->u.des3.key2, iv2, DES_DECRYPT);
|
||||
memcpy(iv2, &iv1, 8); /* Note how iv1 == iv2 on entry and exit. */
|
||||
|
||||
des_cbc_encrypt(dest, dest, len, ks3, iv3, DES_ENCRYPT);
|
||||
des_cbc_encrypt(dest, dest, len, cc->u.des3.key3, iv3, DES_ENCRYPT);
|
||||
memcpy(iv3, dest + len - 8, 8);
|
||||
}
|
||||
|
||||
void
|
||||
SSH_3CBC_DECRYPT(des_key_schedule ks1,
|
||||
des_key_schedule ks2, des_cblock * iv2,
|
||||
des_key_schedule ks3, des_cblock * iv3,
|
||||
unsigned char *dest, unsigned char *src,
|
||||
unsigned int len)
|
||||
des3_ssh1_decrypt(CipherContext *cc, u_char *dest, const u_char *src,
|
||||
u_int len)
|
||||
{
|
||||
des_cblock iv1;
|
||||
des_cblock *iv2 = &cc->u.des3.iv2;
|
||||
des_cblock *iv3 = &cc->u.des3.iv3;
|
||||
|
||||
memcpy(&iv1, iv2, 8);
|
||||
|
||||
des_cbc_encrypt(src, dest, len, ks3, iv3, DES_DECRYPT);
|
||||
des_cbc_encrypt(src, dest, len, cc->u.des3.key3, iv3, DES_DECRYPT);
|
||||
memcpy(iv3, src + len - 8, 8);
|
||||
|
||||
des_cbc_encrypt(dest, dest, len, ks2, iv2, DES_ENCRYPT);
|
||||
des_cbc_encrypt(dest, dest, len, cc->u.des3.key2, iv2, DES_ENCRYPT);
|
||||
memcpy(iv2, dest + len - 8, 8);
|
||||
|
||||
des_cbc_encrypt(dest, dest, len, ks1, &iv1, DES_DECRYPT);
|
||||
des_cbc_encrypt(dest, dest, len, cc->u.des3.key1, &iv1, DES_DECRYPT);
|
||||
/* memcpy(&iv1, iv2, 8); */
|
||||
/* Note how iv1 == iv2 on entry and exit. */
|
||||
}
|
||||
|
||||
/* Blowfish */
|
||||
void
|
||||
blowfish_setkey(CipherContext *cc, const u_char *key, u_int keylen)
|
||||
{
|
||||
BF_set_key(&cc->u.bf.key, keylen, (unsigned char *)key);
|
||||
}
|
||||
void
|
||||
blowfish_setiv(CipherContext *cc, const u_char *iv, u_int ivlen)
|
||||
{
|
||||
if (iv == NULL)
|
||||
memset(cc->u.bf.iv, 0, 8);
|
||||
else
|
||||
memcpy(cc->u.bf.iv, (char *)iv, 8);
|
||||
}
|
||||
void
|
||||
blowfish_cbc_encrypt(CipherContext *cc, u_char *dest, const u_char *src,
|
||||
u_int len)
|
||||
{
|
||||
BF_cbc_encrypt((void *)src, dest, len, &cc->u.bf.key, cc->u.bf.iv,
|
||||
BF_ENCRYPT);
|
||||
}
|
||||
void
|
||||
blowfish_cbc_decrypt(CipherContext *cc, u_char *dest, const u_char *src,
|
||||
u_int len)
|
||||
{
|
||||
BF_cbc_encrypt((void *)src, dest, len, &cc->u.bf.key, cc->u.bf.iv,
|
||||
BF_DECRYPT);
|
||||
}
|
||||
|
||||
/*
|
||||
* SSH1 uses a variation on Blowfish, all bytes must be swapped before
|
||||
* and after encryption/decryption. Thus the swap_bytes stuff (yuk).
|
||||
|
@ -130,88 +243,255 @@ swap_bytes(const unsigned char *src, unsigned char *dst_, int n)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Names of all encryption algorithms.
|
||||
* These must match the numbers defined in cipher.h.
|
||||
*/
|
||||
static char *cipher_names[] =
|
||||
void
|
||||
blowfish_ssh1_encrypt(CipherContext *cc, u_char *dest, const u_char *src,
|
||||
u_int len)
|
||||
{
|
||||
"none",
|
||||
"idea",
|
||||
"des",
|
||||
"3des",
|
||||
"tss",
|
||||
"rc4", /* Alleged RC4 */
|
||||
"blowfish",
|
||||
"reserved",
|
||||
"blowfish-cbc",
|
||||
"3des-cbc",
|
||||
"arcfour",
|
||||
"cast128-cbc"
|
||||
swap_bytes(src, dest, len);
|
||||
BF_cbc_encrypt((void *)dest, dest, len, &cc->u.bf.key, cc->u.bf.iv,
|
||||
BF_ENCRYPT);
|
||||
swap_bytes(dest, dest, len);
|
||||
}
|
||||
void
|
||||
blowfish_ssh1_decrypt(CipherContext *cc, u_char *dest, const u_char *src,
|
||||
u_int len)
|
||||
{
|
||||
swap_bytes(src, dest, len);
|
||||
BF_cbc_encrypt((void *)dest, dest, len, &cc->u.bf.key, cc->u.bf.iv,
|
||||
BF_DECRYPT);
|
||||
swap_bytes(dest, dest, len);
|
||||
}
|
||||
|
||||
/* alleged rc4 */
|
||||
void
|
||||
arcfour_setkey(CipherContext *cc, const u_char *key, u_int keylen)
|
||||
{
|
||||
RC4_set_key(&cc->u.rc4, keylen, (u_char *)key);
|
||||
}
|
||||
void
|
||||
arcfour_crypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
|
||||
{
|
||||
RC4(&cc->u.rc4, len, (u_char *)src, dest);
|
||||
}
|
||||
|
||||
/* CAST */
|
||||
void
|
||||
cast_setkey(CipherContext *cc, const u_char *key, u_int keylen)
|
||||
{
|
||||
CAST_set_key(&cc->u.cast.key, keylen, (unsigned char *) key);
|
||||
}
|
||||
void
|
||||
cast_setiv(CipherContext *cc, const u_char *iv, u_int ivlen)
|
||||
{
|
||||
if (iv == NULL)
|
||||
fatal("no IV for %s.", cc->cipher->name);
|
||||
memcpy(cc->u.cast.iv, (char *)iv, 8);
|
||||
}
|
||||
void
|
||||
cast_cbc_encrypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
|
||||
{
|
||||
CAST_cbc_encrypt(src, dest, len, &cc->u.cast.key, cc->u.cast.iv,
|
||||
CAST_ENCRYPT);
|
||||
}
|
||||
void
|
||||
cast_cbc_decrypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
|
||||
{
|
||||
CAST_cbc_encrypt(src, dest, len, &cc->u.cast.key, cc->u.cast.iv,
|
||||
CAST_DECRYPT);
|
||||
}
|
||||
|
||||
/* RIJNDAEL */
|
||||
|
||||
#define RIJNDAEL_BLOCKSIZE 16
|
||||
void
|
||||
rijndael_setkey(CipherContext *cc, const u_char *key, u_int keylen)
|
||||
{
|
||||
rijndael_set_key(&cc->u.rijndael.enc, (u4byte *)key, 8*keylen, 1);
|
||||
rijndael_set_key(&cc->u.rijndael.dec, (u4byte *)key, 8*keylen, 0);
|
||||
}
|
||||
void
|
||||
rijndael_setiv(CipherContext *cc, const u_char *iv, u_int ivlen)
|
||||
{
|
||||
if (iv == NULL)
|
||||
fatal("no IV for %s.", cc->cipher->name);
|
||||
memcpy((u_char *)cc->u.rijndael.iv, iv, RIJNDAEL_BLOCKSIZE);
|
||||
}
|
||||
void
|
||||
rijndael_cbc_encrypt(CipherContext *cc, u_char *dest, const u_char *src,
|
||||
u_int len)
|
||||
{
|
||||
rijndael_ctx *ctx = &cc->u.rijndael.enc;
|
||||
u4byte *iv = cc->u.rijndael.iv;
|
||||
u4byte in[4];
|
||||
u4byte *cprev, *cnow, *plain;
|
||||
int i, blocks = len / RIJNDAEL_BLOCKSIZE;
|
||||
if (len == 0)
|
||||
return;
|
||||
if (len % RIJNDAEL_BLOCKSIZE)
|
||||
fatal("rijndael_cbc_encrypt: bad len %d", len);
|
||||
cnow = (u4byte*) dest;
|
||||
plain = (u4byte*) src;
|
||||
cprev = iv;
|
||||
for(i = 0; i < blocks; i++, plain+=4, cnow+=4) {
|
||||
in[0] = plain[0] ^ cprev[0];
|
||||
in[1] = plain[1] ^ cprev[1];
|
||||
in[2] = plain[2] ^ cprev[2];
|
||||
in[3] = plain[3] ^ cprev[3];
|
||||
rijndael_encrypt(ctx, in, cnow);
|
||||
cprev = cnow;
|
||||
}
|
||||
memcpy(iv, cprev, RIJNDAEL_BLOCKSIZE);
|
||||
}
|
||||
|
||||
void
|
||||
rijndael_cbc_decrypt(CipherContext *cc, u_char *dest, const u_char *src,
|
||||
u_int len)
|
||||
{
|
||||
rijndael_ctx *ctx = &cc->u.rijndael.dec;
|
||||
u4byte *iv = cc->u.rijndael.iv;
|
||||
u4byte ivsaved[4];
|
||||
u4byte *cnow = (u4byte*) (src+len-RIJNDAEL_BLOCKSIZE);
|
||||
u4byte *plain = (u4byte*) (dest+len-RIJNDAEL_BLOCKSIZE);
|
||||
u4byte *ivp;
|
||||
int i, blocks = len / RIJNDAEL_BLOCKSIZE;
|
||||
if (len == 0)
|
||||
return;
|
||||
if (len % RIJNDAEL_BLOCKSIZE)
|
||||
fatal("rijndael_cbc_decrypt: bad len %d", len);
|
||||
memcpy(ivsaved, cnow, RIJNDAEL_BLOCKSIZE);
|
||||
for(i = blocks; i > 0; i--, cnow-=4, plain-=4) {
|
||||
rijndael_decrypt(ctx, cnow, plain);
|
||||
ivp = (i == 1) ? iv : cnow-4;
|
||||
plain[0] ^= ivp[0];
|
||||
plain[1] ^= ivp[1];
|
||||
plain[2] ^= ivp[2];
|
||||
plain[3] ^= ivp[3];
|
||||
}
|
||||
memcpy(iv, ivsaved, RIJNDAEL_BLOCKSIZE);
|
||||
}
|
||||
|
||||
Cipher ciphers[] = {
|
||||
{ "none",
|
||||
SSH_CIPHER_NONE, 8, 0,
|
||||
none_setkey, none_setiv,
|
||||
none_crypt, none_crypt },
|
||||
{ "des",
|
||||
SSH_CIPHER_DES, 8, 8,
|
||||
des_ssh1_setkey, des_ssh1_setiv,
|
||||
des_ssh1_encrypt, des_ssh1_decrypt },
|
||||
{ "3des",
|
||||
SSH_CIPHER_3DES, 8, 16,
|
||||
des3_ssh1_setkey, des3_setiv,
|
||||
des3_ssh1_encrypt, des3_ssh1_decrypt },
|
||||
{ "blowfish",
|
||||
SSH_CIPHER_BLOWFISH, 8, 16,
|
||||
blowfish_setkey, blowfish_setiv,
|
||||
blowfish_ssh1_encrypt, blowfish_ssh1_decrypt },
|
||||
|
||||
{ "3des-cbc",
|
||||
SSH_CIPHER_SSH2, 8, 24,
|
||||
des3_setkey, des3_setiv,
|
||||
des3_cbc_encrypt, des3_cbc_decrypt },
|
||||
{ "blowfish-cbc",
|
||||
SSH_CIPHER_SSH2, 8, 16,
|
||||
blowfish_setkey, blowfish_setiv,
|
||||
blowfish_cbc_encrypt, blowfish_cbc_decrypt },
|
||||
{ "cast128-cbc",
|
||||
SSH_CIPHER_SSH2, 8, 16,
|
||||
cast_setkey, cast_setiv,
|
||||
cast_cbc_encrypt, cast_cbc_decrypt },
|
||||
{ "arcfour",
|
||||
SSH_CIPHER_SSH2, 8, 16,
|
||||
arcfour_setkey, none_setiv,
|
||||
arcfour_crypt, arcfour_crypt },
|
||||
{ "aes128-cbc",
|
||||
SSH_CIPHER_SSH2, 16, 16,
|
||||
rijndael_setkey, rijndael_setiv,
|
||||
rijndael_cbc_encrypt, rijndael_cbc_decrypt },
|
||||
{ "aes192-cbc",
|
||||
SSH_CIPHER_SSH2, 16, 24,
|
||||
rijndael_setkey, rijndael_setiv,
|
||||
rijndael_cbc_encrypt, rijndael_cbc_decrypt },
|
||||
{ "aes256-cbc",
|
||||
SSH_CIPHER_SSH2, 16, 32,
|
||||
rijndael_setkey, rijndael_setiv,
|
||||
rijndael_cbc_encrypt, rijndael_cbc_decrypt },
|
||||
{ "rijndael128-cbc",
|
||||
SSH_CIPHER_SSH2, 16, 16,
|
||||
rijndael_setkey, rijndael_setiv,
|
||||
rijndael_cbc_encrypt, rijndael_cbc_decrypt },
|
||||
{ "rijndael192-cbc",
|
||||
SSH_CIPHER_SSH2, 16, 24,
|
||||
rijndael_setkey, rijndael_setiv,
|
||||
rijndael_cbc_encrypt, rijndael_cbc_decrypt },
|
||||
{ "rijndael256-cbc",
|
||||
SSH_CIPHER_SSH2, 16, 32,
|
||||
rijndael_setkey, rijndael_setiv,
|
||||
rijndael_cbc_encrypt, rijndael_cbc_decrypt },
|
||||
{ "rijndael-cbc@lysator.liu.se",
|
||||
SSH_CIPHER_SSH2, 16, 32,
|
||||
rijndael_setkey, rijndael_setiv,
|
||||
rijndael_cbc_encrypt, rijndael_cbc_decrypt },
|
||||
{ NULL, SSH_CIPHER_ILLEGAL, 0, 0, NULL, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
/*
|
||||
* Returns a bit mask indicating which ciphers are supported by this
|
||||
* implementation. The bit mask has the corresponding bit set of each
|
||||
* supported cipher.
|
||||
*/
|
||||
/*--*/
|
||||
|
||||
unsigned int
|
||||
cipher_mask1()
|
||||
cipher_mask_ssh1(int client)
|
||||
{
|
||||
unsigned int mask = 0;
|
||||
mask |= 1 << SSH_CIPHER_3DES; /* Mandatory */
|
||||
mask |= 1 << SSH_CIPHER_3DES; /* Mandatory */
|
||||
mask |= 1 << SSH_CIPHER_BLOWFISH;
|
||||
if (client) {
|
||||
mask |= 1 << SSH_CIPHER_DES;
|
||||
}
|
||||
return mask;
|
||||
}
|
||||
unsigned int
|
||||
cipher_mask2()
|
||||
|
||||
Cipher *
|
||||
cipher_by_name(const char *name)
|
||||
{
|
||||
unsigned int mask = 0;
|
||||
mask |= 1 << SSH_CIPHER_BLOWFISH_CBC;
|
||||
mask |= 1 << SSH_CIPHER_3DES_CBC;
|
||||
mask |= 1 << SSH_CIPHER_ARCFOUR;
|
||||
mask |= 1 << SSH_CIPHER_CAST128_CBC;
|
||||
return mask;
|
||||
}
|
||||
unsigned int
|
||||
cipher_mask()
|
||||
{
|
||||
return cipher_mask1() | cipher_mask2();
|
||||
Cipher *c;
|
||||
for (c = ciphers; c->name != NULL; c++)
|
||||
if (strcasecmp(c->name, name) == 0)
|
||||
return c;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Returns the name of the cipher. */
|
||||
|
||||
const char *
|
||||
cipher_name(int cipher)
|
||||
Cipher *
|
||||
cipher_by_number(int id)
|
||||
{
|
||||
if (cipher < 0 || cipher >= sizeof(cipher_names) / sizeof(cipher_names[0]) ||
|
||||
cipher_names[cipher] == NULL)
|
||||
fatal("cipher_name: bad cipher name: %d", cipher);
|
||||
return cipher_names[cipher];
|
||||
Cipher *c;
|
||||
for (c = ciphers; c->name != NULL; c++)
|
||||
if (c->number == id)
|
||||
return c;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Returns 1 if the name of the ciphers are valid. */
|
||||
|
||||
#define CIPHER_SEP ","
|
||||
int
|
||||
ciphers_valid(const char *names)
|
||||
{
|
||||
Cipher *c;
|
||||
char *ciphers, *cp;
|
||||
char *p;
|
||||
int i;
|
||||
|
||||
if (names == NULL || strcmp(names, "") == 0)
|
||||
return 0;
|
||||
ciphers = cp = xstrdup(names);
|
||||
for ((p = strsep(&cp, CIPHER_SEP)); p && *p != '\0';
|
||||
for ((p = strsep(&cp, CIPHER_SEP)); p && *p != '\0';
|
||||
(p = strsep(&cp, CIPHER_SEP))) {
|
||||
i = cipher_number(p);
|
||||
if (i == -1 || !(cipher_mask2() & (1 << i))) {
|
||||
c = cipher_by_name(p);
|
||||
if (c == NULL || c->number != SSH_CIPHER_SSH2) {
|
||||
debug("bad cipher %s [%s]", p, names);
|
||||
xfree(ciphers);
|
||||
return 0;
|
||||
} else {
|
||||
debug("cipher ok: %s [%s]", p, names);
|
||||
}
|
||||
}
|
||||
debug("ciphers ok: [%s]", names);
|
||||
xfree(ciphers);
|
||||
return 1;
|
||||
}
|
||||
|
@ -224,14 +504,49 @@ ciphers_valid(const char *names)
|
|||
int
|
||||
cipher_number(const char *name)
|
||||
{
|
||||
int i;
|
||||
Cipher *c;
|
||||
if (name == NULL)
|
||||
return -1;
|
||||
for (i = 0; i < sizeof(cipher_names) / sizeof(cipher_names[0]); i++)
|
||||
if (strcmp(cipher_names[i], name) == 0 &&
|
||||
(cipher_mask() & (1 << i)))
|
||||
return i;
|
||||
return -1;
|
||||
c = cipher_by_name(name);
|
||||
return (c==NULL) ? -1 : c->number;
|
||||
}
|
||||
|
||||
char *
|
||||
cipher_name(int id)
|
||||
{
|
||||
Cipher *c = cipher_by_number(id);
|
||||
return (c==NULL) ? "<unknown>" : c->name;
|
||||
}
|
||||
|
||||
void
|
||||
cipher_init(CipherContext *cc, Cipher *cipher,
|
||||
const u_char *key, u_int keylen, const u_char *iv, u_int ivlen)
|
||||
{
|
||||
if (keylen < cipher->key_len)
|
||||
fatal("cipher_init: key length %d is insufficient for %s.",
|
||||
keylen, cipher->name);
|
||||
if (iv != NULL && ivlen < cipher->block_size)
|
||||
fatal("cipher_init: iv length %d is insufficient for %s.",
|
||||
ivlen, cipher->name);
|
||||
cc->cipher = cipher;
|
||||
cipher->setkey(cc, key, keylen);
|
||||
cipher->setiv(cc, iv, ivlen);
|
||||
}
|
||||
|
||||
void
|
||||
cipher_encrypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
|
||||
{
|
||||
if (len % cc->cipher->block_size)
|
||||
fatal("cipher_encrypt: bad plaintext length %d", len);
|
||||
cc->cipher->encrypt(cc, dest, src, len);
|
||||
}
|
||||
|
||||
void
|
||||
cipher_decrypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
|
||||
{
|
||||
if (len % cc->cipher->block_size)
|
||||
fatal("cipher_decrypt: bad ciphertext length %d", len);
|
||||
cc->cipher->decrypt(cc, dest, src, len);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -240,248 +555,18 @@ cipher_number(const char *name)
|
|||
*/
|
||||
|
||||
void
|
||||
cipher_set_key_string(CipherContext *context, int cipher, const char *passphrase)
|
||||
cipher_set_key_string(CipherContext *cc, Cipher *cipher,
|
||||
const char *passphrase)
|
||||
{
|
||||
MD5_CTX md;
|
||||
unsigned char digest[16];
|
||||
|
||||
MD5_Init(&md);
|
||||
MD5_Update(&md, (const unsigned char *) passphrase, strlen(passphrase));
|
||||
MD5_Update(&md, (const u_char *)passphrase, strlen(passphrase));
|
||||
MD5_Final(digest, &md);
|
||||
|
||||
cipher_set_key(context, cipher, digest, 16);
|
||||
cipher_init(cc, cipher, digest, 16, NULL, 0);
|
||||
|
||||
memset(digest, 0, sizeof(digest));
|
||||
memset(&md, 0, sizeof(md));
|
||||
}
|
||||
|
||||
/* Selects the cipher to use and sets the key. */
|
||||
|
||||
void
|
||||
cipher_set_key(CipherContext *context, int cipher, const unsigned char *key,
|
||||
int keylen)
|
||||
{
|
||||
unsigned char padded[32];
|
||||
|
||||
/* Set cipher type. */
|
||||
context->type = cipher;
|
||||
|
||||
/* Get 32 bytes of key data. Pad if necessary. (So that code
|
||||
below does not need to worry about key size). */
|
||||
memset(padded, 0, sizeof(padded));
|
||||
memcpy(padded, key, keylen < sizeof(padded) ? keylen : sizeof(padded));
|
||||
|
||||
/* Initialize the initialization vector. */
|
||||
switch (cipher) {
|
||||
case SSH_CIPHER_NONE:
|
||||
/*
|
||||
* Has to stay for authfile saving of private key with no
|
||||
* passphrase
|
||||
*/
|
||||
break;
|
||||
|
||||
case SSH_CIPHER_3DES:
|
||||
/*
|
||||
* Note: the least significant bit of each byte of key is
|
||||
* parity, and must be ignored by the implementation. 16
|
||||
* bytes of key are used (first and last keys are the same).
|
||||
*/
|
||||
if (keylen < 16)
|
||||
error("Key length %d is insufficient for 3DES.", keylen);
|
||||
des_set_key((void *) padded, context->u.des3.key1);
|
||||
des_set_key((void *) (padded + 8), context->u.des3.key2);
|
||||
if (keylen <= 16)
|
||||
des_set_key((void *) padded, context->u.des3.key3);
|
||||
else
|
||||
des_set_key((void *) (padded + 16), context->u.des3.key3);
|
||||
memset(context->u.des3.iv2, 0, sizeof(context->u.des3.iv2));
|
||||
memset(context->u.des3.iv3, 0, sizeof(context->u.des3.iv3));
|
||||
break;
|
||||
|
||||
case SSH_CIPHER_BLOWFISH:
|
||||
if (keylen < 16)
|
||||
error("Key length %d is insufficient for blowfish.", keylen);
|
||||
BF_set_key(&context->u.bf.key, keylen, padded);
|
||||
memset(context->u.bf.iv, 0, 8);
|
||||
break;
|
||||
|
||||
case SSH_CIPHER_3DES_CBC:
|
||||
case SSH_CIPHER_BLOWFISH_CBC:
|
||||
case SSH_CIPHER_ARCFOUR:
|
||||
case SSH_CIPHER_CAST128_CBC:
|
||||
fatal("cipher_set_key: illegal cipher: %s", cipher_name(cipher));
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("cipher_set_key: unknown cipher: %s", cipher_name(cipher));
|
||||
}
|
||||
memset(padded, 0, sizeof(padded));
|
||||
}
|
||||
|
||||
void
|
||||
cipher_set_key_iv(CipherContext * context, int cipher,
|
||||
const unsigned char *key, int keylen,
|
||||
const unsigned char *iv, int ivlen)
|
||||
{
|
||||
/* Set cipher type. */
|
||||
context->type = cipher;
|
||||
|
||||
/* Initialize the initialization vector. */
|
||||
switch (cipher) {
|
||||
case SSH_CIPHER_NONE:
|
||||
break;
|
||||
|
||||
case SSH_CIPHER_3DES:
|
||||
case SSH_CIPHER_BLOWFISH:
|
||||
fatal("cipher_set_key_iv: illegal cipher: %s", cipher_name(cipher));
|
||||
break;
|
||||
|
||||
case SSH_CIPHER_3DES_CBC:
|
||||
if (keylen < 24)
|
||||
error("Key length %d is insufficient for 3des-cbc.", keylen);
|
||||
des_set_key((void *) key, context->u.des3.key1);
|
||||
des_set_key((void *) (key+8), context->u.des3.key2);
|
||||
des_set_key((void *) (key+16), context->u.des3.key3);
|
||||
if (ivlen < 8)
|
||||
error("IV length %d is insufficient for 3des-cbc.", ivlen);
|
||||
memcpy(context->u.des3.iv3, (char *)iv, 8);
|
||||
break;
|
||||
|
||||
case SSH_CIPHER_BLOWFISH_CBC:
|
||||
if (keylen < 16)
|
||||
error("Key length %d is insufficient for blowfish.", keylen);
|
||||
if (ivlen < 8)
|
||||
error("IV length %d is insufficient for blowfish.", ivlen);
|
||||
BF_set_key(&context->u.bf.key, keylen, (unsigned char *)key);
|
||||
memcpy(context->u.bf.iv, (char *)iv, 8);
|
||||
break;
|
||||
|
||||
case SSH_CIPHER_ARCFOUR:
|
||||
if (keylen < 16)
|
||||
error("Key length %d is insufficient for arcfour.", keylen);
|
||||
RC4_set_key(&context->u.rc4, keylen, (unsigned char *)key);
|
||||
break;
|
||||
|
||||
case SSH_CIPHER_CAST128_CBC:
|
||||
if (keylen < 16)
|
||||
error("Key length %d is insufficient for cast128.", keylen);
|
||||
if (ivlen < 8)
|
||||
error("IV length %d is insufficient for cast128.", ivlen);
|
||||
CAST_set_key(&context->u.cast.key, keylen, (unsigned char *) key);
|
||||
memcpy(context->u.cast.iv, (char *)iv, 8);
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("cipher_set_key: unknown cipher: %s", cipher_name(cipher));
|
||||
}
|
||||
}
|
||||
|
||||
/* Encrypts data using the cipher. */
|
||||
|
||||
void
|
||||
cipher_encrypt(CipherContext *context, unsigned char *dest,
|
||||
const unsigned char *src, unsigned int len)
|
||||
{
|
||||
if ((len & 7) != 0)
|
||||
fatal("cipher_encrypt: bad plaintext length %d", len);
|
||||
|
||||
switch (context->type) {
|
||||
case SSH_CIPHER_NONE:
|
||||
memcpy(dest, src, len);
|
||||
break;
|
||||
|
||||
case SSH_CIPHER_3DES:
|
||||
SSH_3CBC_ENCRYPT(context->u.des3.key1,
|
||||
context->u.des3.key2, &context->u.des3.iv2,
|
||||
context->u.des3.key3, &context->u.des3.iv3,
|
||||
dest, (unsigned char *) src, len);
|
||||
break;
|
||||
|
||||
case SSH_CIPHER_BLOWFISH:
|
||||
swap_bytes(src, dest, len);
|
||||
BF_cbc_encrypt(dest, dest, len,
|
||||
&context->u.bf.key, context->u.bf.iv,
|
||||
BF_ENCRYPT);
|
||||
swap_bytes(dest, dest, len);
|
||||
break;
|
||||
|
||||
case SSH_CIPHER_BLOWFISH_CBC:
|
||||
BF_cbc_encrypt((void *)src, dest, len,
|
||||
&context->u.bf.key, context->u.bf.iv,
|
||||
BF_ENCRYPT);
|
||||
break;
|
||||
|
||||
case SSH_CIPHER_3DES_CBC:
|
||||
des_ede3_cbc_encrypt(src, dest, len,
|
||||
context->u.des3.key1, context->u.des3.key2,
|
||||
context->u.des3.key3, &context->u.des3.iv3, DES_ENCRYPT);
|
||||
break;
|
||||
|
||||
case SSH_CIPHER_ARCFOUR:
|
||||
RC4(&context->u.rc4, len, (unsigned char *)src, dest);
|
||||
break;
|
||||
|
||||
case SSH_CIPHER_CAST128_CBC:
|
||||
CAST_cbc_encrypt(src, dest, len,
|
||||
&context->u.cast.key, context->u.cast.iv, CAST_ENCRYPT);
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("cipher_encrypt: unknown cipher: %s", cipher_name(context->type));
|
||||
}
|
||||
}
|
||||
|
||||
/* Decrypts data using the cipher. */
|
||||
|
||||
void
|
||||
cipher_decrypt(CipherContext *context, unsigned char *dest,
|
||||
const unsigned char *src, unsigned int len)
|
||||
{
|
||||
if ((len & 7) != 0)
|
||||
fatal("cipher_decrypt: bad ciphertext length %d", len);
|
||||
|
||||
switch (context->type) {
|
||||
case SSH_CIPHER_NONE:
|
||||
memcpy(dest, src, len);
|
||||
break;
|
||||
|
||||
case SSH_CIPHER_3DES:
|
||||
SSH_3CBC_DECRYPT(context->u.des3.key1,
|
||||
context->u.des3.key2, &context->u.des3.iv2,
|
||||
context->u.des3.key3, &context->u.des3.iv3,
|
||||
dest, (unsigned char *) src, len);
|
||||
break;
|
||||
|
||||
case SSH_CIPHER_BLOWFISH:
|
||||
swap_bytes(src, dest, len);
|
||||
BF_cbc_encrypt((void *) dest, dest, len,
|
||||
&context->u.bf.key, context->u.bf.iv,
|
||||
BF_DECRYPT);
|
||||
swap_bytes(dest, dest, len);
|
||||
break;
|
||||
|
||||
case SSH_CIPHER_BLOWFISH_CBC:
|
||||
BF_cbc_encrypt((void *) src, dest, len,
|
||||
&context->u.bf.key, context->u.bf.iv,
|
||||
BF_DECRYPT);
|
||||
break;
|
||||
|
||||
case SSH_CIPHER_3DES_CBC:
|
||||
des_ede3_cbc_encrypt(src, dest, len,
|
||||
context->u.des3.key1, context->u.des3.key2,
|
||||
context->u.des3.key3, &context->u.des3.iv3, DES_DECRYPT);
|
||||
break;
|
||||
|
||||
case SSH_CIPHER_ARCFOUR:
|
||||
RC4(&context->u.rc4, len, (unsigned char *)src, dest);
|
||||
break;
|
||||
|
||||
case SSH_CIPHER_CAST128_CBC:
|
||||
CAST_cbc_encrypt(src, dest, len,
|
||||
&context->u.cast.key, context->u.cast.iv, CAST_DECRYPT);
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("cipher_decrypt: unknown cipher: %s", cipher_name(context->type));
|
||||
}
|
||||
}
|
||||
|
|
129
cipher.h
129
cipher.h
|
@ -8,9 +8,31 @@
|
|||
* software must be clearly marked as such, and if the derived work is
|
||||
* incompatible with the protocol description in the RFC file, it must be
|
||||
* called by a name other than "ssh" or "Secure Shell".
|
||||
*
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* RCSID("$OpenBSD: cipher.h,v 1.19 2000/09/07 20:27:50 deraadt Exp $"); */
|
||||
/* RCSID("$OpenBSD: cipher.h,v 1.22 2000/10/13 18:59:14 markus Exp $"); */
|
||||
|
||||
#ifndef CIPHER_H
|
||||
#define CIPHER_H
|
||||
|
@ -19,9 +41,12 @@
|
|||
#include <openssl/blowfish.h>
|
||||
#include <openssl/rc4.h>
|
||||
#include <openssl/cast.h>
|
||||
|
||||
/* Cipher types. New types can be added, but old types should not be removed
|
||||
for compatibility. The maximum allowed value is 31. */
|
||||
#include "rijndael.h"
|
||||
/*
|
||||
* Cipher types for SSH-1. New types can be added, but old types should not
|
||||
* be removed for compatibility. The maximum allowed value is 31.
|
||||
*/
|
||||
#define SSH_CIPHER_SSH2 -3
|
||||
#define SSH_CIPHER_ILLEGAL -2 /* No valid cipher selected. */
|
||||
#define SSH_CIPHER_NOT_SET -1 /* None selected (invalid number). */
|
||||
#define SSH_CIPHER_NONE 0 /* no encryption */
|
||||
|
@ -32,16 +57,17 @@
|
|||
#define SSH_CIPHER_BROKEN_RC4 5 /* Alleged RC4 */
|
||||
#define SSH_CIPHER_BLOWFISH 6
|
||||
#define SSH_CIPHER_RESERVED 7
|
||||
#define SSH_CIPHER_MAX 31
|
||||
|
||||
/* these ciphers are used in SSH2: */
|
||||
#define SSH_CIPHER_BLOWFISH_CBC 8
|
||||
#define SSH_CIPHER_3DES_CBC 9
|
||||
#define SSH_CIPHER_ARCFOUR 10 /* Alleged RC4 */
|
||||
#define SSH_CIPHER_CAST128_CBC 11
|
||||
typedef struct Cipher Cipher;
|
||||
typedef struct CipherContext CipherContext;
|
||||
|
||||
typedef struct {
|
||||
unsigned int type;
|
||||
struct CipherContext {
|
||||
union {
|
||||
struct {
|
||||
des_key_schedule key;
|
||||
des_cblock iv;
|
||||
} des;
|
||||
struct {
|
||||
des_key_schedule key1;
|
||||
des_key_schedule key2;
|
||||
|
@ -51,64 +77,41 @@ typedef struct {
|
|||
} des3;
|
||||
struct {
|
||||
struct bf_key_st key;
|
||||
unsigned char iv[8];
|
||||
u_char iv[8];
|
||||
} bf;
|
||||
struct {
|
||||
CAST_KEY key;
|
||||
unsigned char iv[8];
|
||||
u_char iv[8];
|
||||
} cast;
|
||||
struct {
|
||||
u4byte iv[4];
|
||||
rijndael_ctx enc;
|
||||
rijndael_ctx dec;
|
||||
} rijndael;
|
||||
RC4_KEY rc4;
|
||||
} u;
|
||||
} CipherContext;
|
||||
/*
|
||||
* Returns a bit mask indicating which ciphers are supported by this
|
||||
* implementation. The bit mask has the corresponding bit set of each
|
||||
* supported cipher.
|
||||
*/
|
||||
unsigned int cipher_mask();
|
||||
unsigned int cipher_mask1();
|
||||
unsigned int cipher_mask2();
|
||||
Cipher *cipher;
|
||||
};
|
||||
struct Cipher {
|
||||
char *name;
|
||||
int number; /* for ssh1 only */
|
||||
u_int block_size;
|
||||
u_int key_len;
|
||||
void (*setkey)(CipherContext *, const u_char *, u_int);
|
||||
void (*setiv)(CipherContext *, const u_char *, u_int);
|
||||
void (*encrypt)(CipherContext *, u_char *, const u_char *, u_int);
|
||||
void (*decrypt)(CipherContext *, u_char *, const u_char *, u_int);
|
||||
};
|
||||
|
||||
/* Returns the name of the cipher. */
|
||||
const char *cipher_name(int cipher);
|
||||
|
||||
/*
|
||||
* Parses the name of the cipher. Returns the number of the corresponding
|
||||
* cipher, or -1 on error.
|
||||
*/
|
||||
int cipher_number(const char *name);
|
||||
|
||||
/* returns 1 if all ciphers are supported (ssh2 only) */
|
||||
int ciphers_valid(const char *names);
|
||||
|
||||
/*
|
||||
* Selects the cipher to use and sets the key. If for_encryption is true,
|
||||
* the key is setup for encryption; otherwise it is setup for decryption.
|
||||
*/
|
||||
void
|
||||
cipher_set_key(CipherContext * context, int cipher,
|
||||
const unsigned char *key, int keylen);
|
||||
void
|
||||
cipher_set_key_iv(CipherContext * context, int cipher,
|
||||
const unsigned char *key, int keylen,
|
||||
const unsigned char *iv, int ivlen);
|
||||
|
||||
/*
|
||||
* Sets key for the cipher by computing the MD5 checksum of the passphrase,
|
||||
* and using the resulting 16 bytes as the key.
|
||||
*/
|
||||
void
|
||||
cipher_set_key_string(CipherContext * context, int cipher,
|
||||
const char *passphrase);
|
||||
|
||||
/* Encrypts data using the cipher. */
|
||||
void
|
||||
cipher_encrypt(CipherContext * context, unsigned char *dest,
|
||||
const unsigned char *src, unsigned int len);
|
||||
|
||||
/* Decrypts data using the cipher. */
|
||||
void
|
||||
cipher_decrypt(CipherContext * context, unsigned char *dest,
|
||||
const unsigned char *src, unsigned int len);
|
||||
unsigned int cipher_mask_ssh1(int client);
|
||||
Cipher *cipher_by_name(const char *name);
|
||||
Cipher *cipher_by_number(int id);
|
||||
int cipher_number(const char *name);
|
||||
char *cipher_name(int id);
|
||||
int ciphers_valid(const char *names);
|
||||
void cipher_init(CipherContext *, Cipher *, const u_char *, u_int, const u_char *, u_int);
|
||||
void cipher_encrypt(CipherContext *context, u_char *dest, const u_char *src, u_int len);
|
||||
void cipher_decrypt(CipherContext *context, u_char *dest, const u_char *src, u_int len);
|
||||
void cipher_set_key_string(CipherContext *context, Cipher *cipher, const char *passphrase);
|
||||
|
||||
#endif /* CIPHER_H */
|
||||
|
|
|
@ -0,0 +1,195 @@
|
|||
#include "includes.h"
|
||||
RCSID("$Id: cli.c,v 1.1 2000/10/14 05:23:12 djm Exp $");
|
||||
|
||||
#include "xmalloc.h"
|
||||
#include "ssh.h"
|
||||
|
||||
static int cli_input = -1;
|
||||
static int cli_output = -1;
|
||||
static int cli_from_stdin = 0;
|
||||
|
||||
sigset_t oset;
|
||||
sigset_t nset;
|
||||
struct sigaction nsa;
|
||||
struct sigaction osa;
|
||||
struct termios ntio;
|
||||
struct termios otio;
|
||||
int echo_modified;
|
||||
|
||||
volatile int intr;
|
||||
|
||||
static int
|
||||
cli_open(int from_stdin)
|
||||
{
|
||||
if (cli_input >= 0 && cli_output >= 0 && cli_from_stdin == from_stdin)
|
||||
return 1;
|
||||
|
||||
if (from_stdin) {
|
||||
if (!cli_from_stdin && cli_input >= 0) {
|
||||
(void)close(cli_input);
|
||||
}
|
||||
cli_input = STDIN_FILENO;
|
||||
cli_output = STDERR_FILENO;
|
||||
} else {
|
||||
cli_input = cli_output = open("/dev/tty", O_RDWR);
|
||||
if (cli_input < 0)
|
||||
fatal("You have no controlling tty. Cannot read passphrase.");
|
||||
}
|
||||
|
||||
cli_from_stdin = from_stdin;
|
||||
|
||||
return cli_input >= 0 && cli_output >= 0 && cli_from_stdin == from_stdin;
|
||||
}
|
||||
|
||||
static void
|
||||
cli_close()
|
||||
{
|
||||
if (!cli_from_stdin && cli_input >= 0)
|
||||
close(cli_input);
|
||||
cli_input = -1;
|
||||
cli_output = -1;
|
||||
cli_from_stdin = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
intrcatch()
|
||||
{
|
||||
intr = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
cli_echo_disable()
|
||||
{
|
||||
sigemptyset(&nset);
|
||||
sigaddset(&nset, SIGTSTP);
|
||||
(void) sigprocmask(SIG_BLOCK, &nset, &oset);
|
||||
|
||||
intr = 0;
|
||||
|
||||
memset(&nsa, 0, sizeof(nsa));
|
||||
nsa.sa_handler = intrcatch;
|
||||
(void) sigaction(SIGINT, &nsa, &osa);
|
||||
|
||||
echo_modified = 0;
|
||||
if (tcgetattr(cli_input, &otio) == 0 && (otio.c_lflag & ECHO)) {
|
||||
echo_modified = 1;
|
||||
ntio = otio;
|
||||
ntio.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
|
||||
(void) tcsetattr(cli_input, TCSANOW, &ntio);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
cli_echo_restore()
|
||||
{
|
||||
if (echo_modified != 0) {
|
||||
tcsetattr(cli_input, TCSANOW, &otio);
|
||||
echo_modified = 0;
|
||||
}
|
||||
|
||||
(void) sigprocmask(SIG_SETMASK, &oset, NULL);
|
||||
(void) sigaction(SIGINT, &osa, NULL);
|
||||
|
||||
if (intr != 0) {
|
||||
kill(getpid(), SIGINT);
|
||||
sigemptyset(&nset);
|
||||
/* XXX tty has not neccessarily drained by now? */
|
||||
sigsuspend(&nset);
|
||||
intr = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static int
|
||||
cli_read(char* buf, int size, int echo)
|
||||
{
|
||||
char ch = 0;
|
||||
int i = 0;
|
||||
|
||||
if (!echo)
|
||||
cli_echo_disable();
|
||||
|
||||
while (ch != '\n') {
|
||||
if (read(cli_input, &ch, 1) != 1)
|
||||
break;
|
||||
if (ch == '\n' || intr != 0)
|
||||
break;
|
||||
if (i < size)
|
||||
buf[i++] = ch;
|
||||
}
|
||||
buf[i] = '\0';
|
||||
|
||||
if (!echo)
|
||||
cli_echo_restore();
|
||||
if (!intr && !echo)
|
||||
(void) write(cli_output, "\n", 1);
|
||||
return i;
|
||||
}
|
||||
|
||||
static int
|
||||
cli_write(char* buf, int size)
|
||||
{
|
||||
int i, len, pos, ret = 0;
|
||||
char *output, *p;
|
||||
|
||||
output = xmalloc(4*size);
|
||||
for (p = output, i = 0; i < size; i++) {
|
||||
if (buf[i] == '\n')
|
||||
*p++ = buf[i];
|
||||
else
|
||||
p = vis(p, buf[i], 0, 0);
|
||||
}
|
||||
len = p - output;
|
||||
|
||||
for (pos = 0; pos < len; pos += ret) {
|
||||
ret = write(cli_output, output + pos, len - pos);
|
||||
if (ret == -1)
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Presents a prompt and returns the response allocated with xmalloc().
|
||||
* Uses /dev/tty or stdin/out depending on arg. Optionally disables echo
|
||||
* of response depending on arg. Tries to ensure that no other userland
|
||||
* buffer is storing the response.
|
||||
*/
|
||||
char*
|
||||
cli_read_passphrase(char* prompt, int from_stdin, int echo_enable)
|
||||
{
|
||||
char buf[BUFSIZ];
|
||||
char* p;
|
||||
|
||||
if (!cli_open(from_stdin))
|
||||
fatal("Cannot read passphrase.");
|
||||
|
||||
fflush(stdout);
|
||||
|
||||
cli_write(prompt, strlen(prompt));
|
||||
cli_read(buf, sizeof buf, echo_enable);
|
||||
|
||||
cli_close();
|
||||
|
||||
p = xstrdup(buf);
|
||||
memset(buf, 0, sizeof(buf));
|
||||
return (p);
|
||||
}
|
||||
|
||||
char*
|
||||
cli_prompt(char* prompt, int echo_enable)
|
||||
{
|
||||
return cli_read_passphrase(prompt, 0, echo_enable);
|
||||
}
|
||||
|
||||
void
|
||||
cli_mesg(char* mesg)
|
||||
{
|
||||
cli_open(0);
|
||||
cli_write(mesg, strlen(mesg));
|
||||
cli_write("\n", strlen("\n"));
|
||||
cli_close();
|
||||
return;
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
#ifndef CLI_H
|
||||
#define CLI_H
|
||||
|
||||
/*
|
||||
* Presents a prompt and returns the response allocated with xmalloc().
|
||||
* Uses /dev/tty or stdin/out depending on arg. Optionally disables echo
|
||||
* of response depending on arg. Tries to ensure that no other userland
|
||||
* buffer is storing the response.
|
||||
*/
|
||||
char* cli_read_passphrase(char* prompt, int from_stdin, int echo_enable);
|
||||
char* cli_prompt(char* prompt, int echo_enable);
|
||||
void cli_mesg(char* mesg);
|
||||
|
||||
#endif /* CLI_H */
|
41
compat.c
41
compat.c
|
@ -23,12 +23,13 @@
|
|||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$OpenBSD: compat.c,v 1.23 2000/09/07 21:13:37 markus Exp $");
|
||||
RCSID("$OpenBSD: compat.c,v 1.24 2000/10/10 20:20:45 markus Exp $");
|
||||
|
||||
#include "ssh.h"
|
||||
#include "packet.h"
|
||||
#include "xmalloc.h"
|
||||
#include "compat.h"
|
||||
#include <regex.h>
|
||||
|
||||
int compat13 = 0;
|
||||
int compat20 = 0;
|
||||
|
@ -50,27 +51,39 @@ enable_compat13(void)
|
|||
void
|
||||
compat_datafellows(const char *version)
|
||||
{
|
||||
int i;
|
||||
size_t len;
|
||||
struct {
|
||||
char *version;
|
||||
int i, ret;
|
||||
char ebuf[1024];
|
||||
regex_t reg;
|
||||
static struct {
|
||||
char *pat;
|
||||
int bugs;
|
||||
} check[] = {
|
||||
{"2.1.0", SSH_BUG_SIGBLOB|SSH_BUG_HMAC},
|
||||
{"2.0.1", SSH_BUG_SIGBLOB|SSH_BUG_HMAC|SSH_BUG_PUBKEYAUTH|SSH_BUG_X11FWD},
|
||||
{"2.", SSH_BUG_HMAC|SSH_COMPAT_SESSIONID_ENCODING},
|
||||
{NULL, 0}
|
||||
{"^.*MindTerm", 0},
|
||||
{"^2\\.1\\.0 ", SSH_BUG_SIGBLOB|SSH_BUG_HMAC},
|
||||
{"^2\\.0\\.", SSH_BUG_SIGBLOB|SSH_BUG_HMAC|SSH_BUG_PUBKEYAUTH|SSH_BUG_X11FWD},
|
||||
{"^2\\.[23]\\.0 ", SSH_BUG_HMAC|SSH_COMPAT_SESSIONID_ENCODING},
|
||||
{"^2\\.[2-9]\\.", SSH_COMPAT_SESSIONID_ENCODING},
|
||||
{"^2\\.", SSH_BUG_HMAC|SSH_COMPAT_SESSIONID_ENCODING},
|
||||
{NULL, 0}
|
||||
};
|
||||
/* process table, return first match */
|
||||
for (i = 0; check[i].version; i++) {
|
||||
len = strlen(check[i].version);
|
||||
if (strlen(version) >= len &&
|
||||
(strncmp(version, check[i].version, len) == 0)) {
|
||||
verbose("datafellows: %.200s", version);
|
||||
for (i = 0; check[i].pat; i++) {
|
||||
ret = regcomp(®, check[i].pat, REG_EXTENDED|REG_NOSUB);
|
||||
if (ret != 0) {
|
||||
regerror(ret, ®, ebuf, sizeof(ebuf));
|
||||
ebuf[sizeof(ebuf)-1] = '\0';
|
||||
error("regerror: %s", ebuf);
|
||||
continue;
|
||||
}
|
||||
ret = regexec(®, version, 0, NULL, 0);
|
||||
regfree(®);
|
||||
if (ret == 0) {
|
||||
debug("match: %s pat %s\n", version, check[i].pat);
|
||||
datafellows = check[i].bugs;
|
||||
return;
|
||||
}
|
||||
}
|
||||
debug("no match: %s", version);
|
||||
}
|
||||
|
||||
#define SEP ","
|
||||
|
|
|
@ -265,10 +265,10 @@ if test -z "$no_libnsl" ; then
|
|||
fi
|
||||
|
||||
# Checks for header files.
|
||||
AC_CHECK_HEADERS(bstring.h endian.h floatingpoint.h getopt.h lastlog.h limits.h login.h login_cap.h maillock.h netdb.h netgroup.h netinet/in_systm.h paths.h poll.h pty.h shadow.h security/pam_appl.h sys/bitypes.h sys/bsdtty.h sys/cdefs.h sys/poll.h sys/select.h sys/stat.h sys/stropts.h sys/sysmacros.h sys/time.h sys/ttcompat.h sys/un.h stddef.h time.h ttyent.h usersec.h util.h utmp.h utmpx.h)
|
||||
AC_CHECK_HEADERS(bstring.h endian.h floatingpoint.h getopt.h lastlog.h limits.h login.h login_cap.h maillock.h netdb.h netgroup.h netinet/in_systm.h paths.h poll.h pty.h shadow.h security/pam_appl.h sys/bitypes.h sys/bsdtty.h sys/cdefs.h sys/poll.h sys/select.h sys/stat.h sys/stropts.h sys/sysmacros.h sys/time.h sys/ttcompat.h sys/un.h stddef.h time.h ttyent.h usersec.h util.h utmp.h utmpx.h vis.h)
|
||||
|
||||
dnl Checks for library functions.
|
||||
AC_CHECK_FUNCS(arc4random atexit b64_ntop bcopy bindresvport_af clock fchmod freeaddrinfo futimes gai_strerror getaddrinfo getnameinfo getrusage getttyent inet_aton inet_ntoa innetgr login_getcapbool md5_crypt memmove mkdtemp on_exit openpty rresvport_af setenv seteuid setlogin setproctitle setreuid setrlimit sigaction sigvec snprintf strerror strlcat strlcpy strsep strtok_r vsnprintf vhangup _getpty __b64_ntop)
|
||||
AC_CHECK_FUNCS(arc4random atexit b64_ntop bcopy bindresvport_af clock fchmod freeaddrinfo futimes gai_strerror getaddrinfo getnameinfo getrusage getttyent inet_aton inet_ntoa innetgr login_getcapbool md5_crypt memmove mkdtemp on_exit openpty rresvport_af setenv seteuid setlogin setproctitle setreuid setrlimit sigaction sigvec snprintf strerror strlcat strlcpy strsep strtok_r vsnprintf vhangup vis _getpty __b64_ntop)
|
||||
dnl Checks for time functions
|
||||
AC_CHECK_FUNCS(gettimeofday time)
|
||||
dnl Checks for libutil functions
|
||||
|
|
|
@ -0,0 +1,157 @@
|
|||
/*
|
||||
* Copyright (c) 2000 Niels Provos. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$OpenBSD: dh.c,v 1.2 2000/10/11 20:11:35 markus Exp $");
|
||||
|
||||
#include "xmalloc.h"
|
||||
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/dh.h>
|
||||
#include <openssl/evp.h>
|
||||
|
||||
#include "ssh.h"
|
||||
#include "buffer.h"
|
||||
#include "kex.h"
|
||||
#include "dh.h"
|
||||
|
||||
int
|
||||
parse_prime(int linenum, char *line, struct dhgroup *dhg)
|
||||
{
|
||||
char *cp, *arg;
|
||||
char *strsize, *gen, *prime;
|
||||
|
||||
cp = line;
|
||||
arg = strdelim(&cp);
|
||||
/* Ignore leading whitespace */
|
||||
if (*arg == '\0')
|
||||
arg = strdelim(&cp);
|
||||
if (!*arg || *arg == '#')
|
||||
return 0;
|
||||
|
||||
/* time */
|
||||
if (cp == NULL || *arg == '\0')
|
||||
goto fail;
|
||||
arg = strsep(&cp, " "); /* type */
|
||||
if (cp == NULL || *arg == '\0')
|
||||
goto fail;
|
||||
arg = strsep(&cp, " "); /* tests */
|
||||
if (cp == NULL || *arg == '\0')
|
||||
goto fail;
|
||||
arg = strsep(&cp, " "); /* tries */
|
||||
if (cp == NULL || *arg == '\0')
|
||||
goto fail;
|
||||
strsize = strsep(&cp, " "); /* size */
|
||||
if (cp == NULL || *strsize == '\0' ||
|
||||
(dhg->size = atoi(strsize)) == 0)
|
||||
goto fail;
|
||||
gen = strsep(&cp, " "); /* gen */
|
||||
if (cp == NULL || *gen == '\0')
|
||||
goto fail;
|
||||
prime = strsep(&cp, " "); /* prime */
|
||||
if (cp != NULL || *prime == '\0')
|
||||
goto fail;
|
||||
|
||||
dhg->g = BN_new();
|
||||
if (BN_hex2bn(&dhg->g, gen) < 0) {
|
||||
BN_free(dhg->g);
|
||||
goto fail;
|
||||
}
|
||||
dhg->p = BN_new();
|
||||
if (BN_hex2bn(&dhg->p, prime) < 0) {
|
||||
BN_free(dhg->g);
|
||||
BN_free(dhg->p);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return (1);
|
||||
fail:
|
||||
fprintf(stderr, "Bad prime description in line %d\n", linenum);
|
||||
return (0);
|
||||
}
|
||||
|
||||
DH *
|
||||
choose_dh(int minbits)
|
||||
{
|
||||
FILE *f;
|
||||
char line[1024];
|
||||
int best, bestcount, which;
|
||||
int linenum;
|
||||
struct dhgroup dhg;
|
||||
|
||||
f = fopen(DH_PRIMES, "r");
|
||||
if (!f) {
|
||||
perror(DH_PRIMES);
|
||||
log("WARNING: %s does not exist, using old prime", DH_PRIMES);
|
||||
return (dh_new_group1());
|
||||
}
|
||||
|
||||
linenum = 0;
|
||||
best = bestcount = 0;
|
||||
while (fgets(line, sizeof(line), f)) {
|
||||
linenum++;
|
||||
if (!parse_prime(linenum, line, &dhg))
|
||||
continue;
|
||||
BN_free(dhg.g);
|
||||
BN_free(dhg.p);
|
||||
|
||||
if ((dhg.size > minbits && dhg.size < best) ||
|
||||
(dhg.size > best && best < minbits)) {
|
||||
best = dhg.size;
|
||||
bestcount = 0;
|
||||
}
|
||||
if (dhg.size == best)
|
||||
bestcount++;
|
||||
}
|
||||
fclose (f);
|
||||
|
||||
if (bestcount == 0) {
|
||||
log("WARNING: no primes in %s, using old prime", DH_PRIMES);
|
||||
return (dh_new_group1());
|
||||
}
|
||||
|
||||
f = fopen(DH_PRIMES, "r");
|
||||
if (!f) {
|
||||
perror(DH_PRIMES);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
linenum = 0;
|
||||
which = arc4random() % bestcount;
|
||||
while (fgets(line, sizeof(line), f)) {
|
||||
if (!parse_prime(linenum, line, &dhg))
|
||||
continue;
|
||||
if (dhg.size != best)
|
||||
continue;
|
||||
if (linenum++ != which) {
|
||||
BN_free(dhg.g);
|
||||
BN_free(dhg.p);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
return (dh_new_group(dhg.g, dhg.p));
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright (c) 2000 Niels Provos. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef DH_H
|
||||
#define DH_H
|
||||
|
||||
struct dhgroup {
|
||||
int size;
|
||||
BIGNUM *g;
|
||||
BIGNUM *p;
|
||||
};
|
||||
|
||||
DH *choose_dh(int minbits);
|
||||
|
||||
#endif
|
|
@ -87,7 +87,9 @@ static /**/const char *const rcsid[] = { (char *)rcsid, "\100(#)" msg }
|
|||
#ifdef HAVE_SYS_SYSMACROS_H
|
||||
# include <sys/sysmacros.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_VIS_H
|
||||
# include <vis.h>
|
||||
#endif
|
||||
#include "version.h"
|
||||
#include "openbsd-compat.h"
|
||||
#include "cygwin_util.h"
|
||||
|
|
169
kex.c
169
kex.c
|
@ -23,7 +23,7 @@
|
|||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$OpenBSD: kex.c,v 1.10 2000/09/07 20:27:51 deraadt Exp $");
|
||||
RCSID("$OpenBSD: kex.c,v 1.12 2000/10/11 20:27:23 markus Exp $");
|
||||
|
||||
#include "ssh.h"
|
||||
#include "ssh2.h"
|
||||
|
@ -31,7 +31,6 @@ RCSID("$OpenBSD: kex.c,v 1.10 2000/09/07 20:27:51 deraadt Exp $");
|
|||
#include "buffer.h"
|
||||
#include "bufaux.h"
|
||||
#include "packet.h"
|
||||
#include "cipher.h"
|
||||
#include "compat.h"
|
||||
|
||||
#include <openssl/bn.h>
|
||||
|
@ -123,11 +122,6 @@ dh_pub_is_valid(DH *dh, BIGNUM *dh_pub)
|
|||
int n = BN_num_bits(dh_pub);
|
||||
int bits_set = 0;
|
||||
|
||||
/* we only accept g==2 */
|
||||
if (!BN_is_word(dh->g, 2)) {
|
||||
log("invalid DH base != 2");
|
||||
return 0;
|
||||
}
|
||||
if (dh_pub->neg) {
|
||||
log("invalid public DH value: negativ");
|
||||
return 0;
|
||||
|
@ -145,27 +139,10 @@ dh_pub_is_valid(DH *dh, BIGNUM *dh_pub)
|
|||
}
|
||||
|
||||
DH *
|
||||
dh_new_group1()
|
||||
dh_gen_key(DH *dh)
|
||||
{
|
||||
static char *group1 =
|
||||
"FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
|
||||
"29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
|
||||
"EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
|
||||
"E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
|
||||
"EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381"
|
||||
"FFFFFFFF" "FFFFFFFF";
|
||||
DH *dh;
|
||||
int ret, tries = 0;
|
||||
dh = DH_new();
|
||||
if(dh == NULL)
|
||||
fatal("DH_new");
|
||||
ret = BN_hex2bn(&dh->p, group1);
|
||||
if(ret<0)
|
||||
fatal("BN_hex2bn");
|
||||
dh->g = BN_new();
|
||||
if(dh->g == NULL)
|
||||
fatal("DH_new g");
|
||||
BN_set_word(dh->g, 2);
|
||||
int tries = 0;
|
||||
|
||||
do {
|
||||
if (DH_generate_key(dh) == 0)
|
||||
fatal("DH_generate_key");
|
||||
|
@ -175,6 +152,52 @@ dh_new_group1()
|
|||
return dh;
|
||||
}
|
||||
|
||||
DH *
|
||||
dh_new_group_asc(const char *gen, const char *modulus)
|
||||
{
|
||||
DH *dh;
|
||||
int ret;
|
||||
|
||||
dh = DH_new();
|
||||
if (dh == NULL)
|
||||
fatal("DH_new");
|
||||
|
||||
if ((ret = BN_hex2bn(&dh->p, modulus)) < 0)
|
||||
fatal("BN_hex2bn p");
|
||||
if ((ret = BN_hex2bn(&dh->g, gen)) < 0)
|
||||
fatal("BN_hex2bn g");
|
||||
|
||||
return (dh_gen_key(dh));
|
||||
}
|
||||
|
||||
DH *
|
||||
dh_new_group(BIGNUM *gen, BIGNUM *modulus)
|
||||
{
|
||||
DH *dh;
|
||||
|
||||
dh = DH_new();
|
||||
if (dh == NULL)
|
||||
fatal("DH_new");
|
||||
dh->p = modulus;
|
||||
dh->g = gen;
|
||||
|
||||
return (dh_gen_key(dh));
|
||||
}
|
||||
|
||||
DH *
|
||||
dh_new_group1()
|
||||
{
|
||||
static char *gen = "2", *group1 =
|
||||
"FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
|
||||
"29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
|
||||
"EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
|
||||
"E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
|
||||
"EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381"
|
||||
"FFFFFFFF" "FFFFFFFF";
|
||||
|
||||
return (dh_new_group_asc(gen, group1));
|
||||
}
|
||||
|
||||
void
|
||||
dump_digest(unsigned char *digest, int len)
|
||||
{
|
||||
|
@ -236,6 +259,59 @@ kex_hash(
|
|||
return digest;
|
||||
}
|
||||
|
||||
unsigned char *
|
||||
kex_hash_gex(
|
||||
char *client_version_string,
|
||||
char *server_version_string,
|
||||
char *ckexinit, int ckexinitlen,
|
||||
char *skexinit, int skexinitlen,
|
||||
char *serverhostkeyblob, int sbloblen,
|
||||
int minbits, BIGNUM *prime, BIGNUM *gen,
|
||||
BIGNUM *client_dh_pub,
|
||||
BIGNUM *server_dh_pub,
|
||||
BIGNUM *shared_secret)
|
||||
{
|
||||
Buffer b;
|
||||
static unsigned char digest[EVP_MAX_MD_SIZE];
|
||||
EVP_MD *evp_md = EVP_sha1();
|
||||
EVP_MD_CTX md;
|
||||
|
||||
buffer_init(&b);
|
||||
buffer_put_string(&b, client_version_string, strlen(client_version_string));
|
||||
buffer_put_string(&b, server_version_string, strlen(server_version_string));
|
||||
|
||||
/* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
|
||||
buffer_put_int(&b, ckexinitlen+1);
|
||||
buffer_put_char(&b, SSH2_MSG_KEXINIT);
|
||||
buffer_append(&b, ckexinit, ckexinitlen);
|
||||
buffer_put_int(&b, skexinitlen+1);
|
||||
buffer_put_char(&b, SSH2_MSG_KEXINIT);
|
||||
buffer_append(&b, skexinit, skexinitlen);
|
||||
|
||||
buffer_put_string(&b, serverhostkeyblob, sbloblen);
|
||||
buffer_put_int(&b, minbits);
|
||||
buffer_put_bignum2(&b, prime);
|
||||
buffer_put_bignum2(&b, gen);
|
||||
buffer_put_bignum2(&b, client_dh_pub);
|
||||
buffer_put_bignum2(&b, server_dh_pub);
|
||||
buffer_put_bignum2(&b, shared_secret);
|
||||
|
||||
#ifdef DEBUG_KEX
|
||||
buffer_dump(&b);
|
||||
#endif
|
||||
|
||||
EVP_DigestInit(&md, evp_md);
|
||||
EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
|
||||
EVP_DigestFinal(&md, digest, NULL);
|
||||
|
||||
buffer_free(&b);
|
||||
|
||||
#ifdef DEBUG_KEX
|
||||
dump_digest(digest, evp_md->md_size);
|
||||
#endif
|
||||
return digest;
|
||||
}
|
||||
|
||||
unsigned char *
|
||||
derive_key(int id, int need, char unsigned *hash, BIGNUM *shared_secret)
|
||||
{
|
||||
|
@ -318,28 +394,9 @@ choose_enc(Enc *enc, char *client, char *server)
|
|||
char *name = get_match(client, server);
|
||||
if (name == NULL)
|
||||
fatal("no matching cipher found: client %s server %s", client, server);
|
||||
enc->type = cipher_number(name);
|
||||
|
||||
switch (enc->type) {
|
||||
case SSH_CIPHER_3DES_CBC:
|
||||
enc->key_len = 24;
|
||||
enc->iv_len = 8;
|
||||
enc->block_size = 8;
|
||||
break;
|
||||
case SSH_CIPHER_BLOWFISH_CBC:
|
||||
case SSH_CIPHER_CAST128_CBC:
|
||||
enc->key_len = 16;
|
||||
enc->iv_len = 8;
|
||||
enc->block_size = 8;
|
||||
break;
|
||||
case SSH_CIPHER_ARCFOUR:
|
||||
enc->key_len = 16;
|
||||
enc->iv_len = 0;
|
||||
enc->block_size = 8;
|
||||
break;
|
||||
default:
|
||||
fatal("unsupported cipher %s", name);
|
||||
}
|
||||
enc->cipher = cipher_by_name(name);
|
||||
if (enc->cipher == NULL)
|
||||
fatal("matching cipher is not supported: %s", name);
|
||||
enc->name = name;
|
||||
enc->enabled = 0;
|
||||
enc->iv = NULL;
|
||||
|
@ -387,7 +444,11 @@ choose_kex(Kex *k, char *client, char *server)
|
|||
k->name = get_match(client, server);
|
||||
if (k->name == NULL)
|
||||
fatal("no kex alg");
|
||||
if (strcmp(k->name, KEX_DH1) != 0)
|
||||
if (strcmp(k->name, KEX_DH1) == 0) {
|
||||
k->kex_type = DH_GRP1_SHA1;
|
||||
} else if (strcmp(k->name, KEX_DHGEX) == 0) {
|
||||
k->kex_type = DH_GEX_SHA1;
|
||||
} else
|
||||
fatal("bad kex alg %s", k->name);
|
||||
}
|
||||
void
|
||||
|
@ -432,10 +493,10 @@ kex_choose_conf(char *cprop[PROPOSAL_MAX], char *sprop[PROPOSAL_MAX], int server
|
|||
sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]);
|
||||
need = 0;
|
||||
for (mode = 0; mode < MODE_MAX; mode++) {
|
||||
if (need < k->enc[mode].key_len)
|
||||
need = k->enc[mode].key_len;
|
||||
if (need < k->enc[mode].iv_len)
|
||||
need = k->enc[mode].iv_len;
|
||||
if (need < k->enc[mode].cipher->key_len)
|
||||
need = k->enc[mode].cipher->key_len;
|
||||
if (need < k->enc[mode].cipher->block_size)
|
||||
need = k->enc[mode].cipher->block_size;
|
||||
if (need < k->mac[mode].key_len)
|
||||
need = k->mac[mode].key_len;
|
||||
}
|
||||
|
|
35
kex.h
35
kex.h
|
@ -24,8 +24,9 @@
|
|||
#ifndef KEX_H
|
||||
#define KEX_H
|
||||
|
||||
#define KEX_DH1 "diffie-hellman-group1-sha1"
|
||||
#define KEX_DSS "ssh-dss"
|
||||
#define KEX_DH1 "diffie-hellman-group1-sha1"
|
||||
#define KEX_DHGEX "diffie-hellman-group-exchange-sha1"
|
||||
#define KEX_DSS "ssh-dss"
|
||||
|
||||
enum kex_init_proposals {
|
||||
PROPOSAL_KEX_ALGS,
|
||||
|
@ -47,28 +48,30 @@ enum kex_modes {
|
|||
MODE_MAX
|
||||
};
|
||||
|
||||
enum kex_exchange {
|
||||
DH_GRP1_SHA1,
|
||||
DH_GEX_SHA1
|
||||
};
|
||||
|
||||
typedef struct Kex Kex;
|
||||
typedef struct Mac Mac;
|
||||
typedef struct Comp Comp;
|
||||
typedef struct Enc Enc;
|
||||
|
||||
struct Enc {
|
||||
int type;
|
||||
char *name;
|
||||
Cipher *cipher;
|
||||
int enabled;
|
||||
int block_size;
|
||||
unsigned char *key;
|
||||
unsigned char *iv;
|
||||
int key_len;
|
||||
int iv_len;
|
||||
char *name;
|
||||
};
|
||||
struct Mac {
|
||||
EVP_MD *md;
|
||||
char *name;
|
||||
int enabled;
|
||||
EVP_MD *md;
|
||||
int mac_len;
|
||||
unsigned char *key;
|
||||
int key_len;
|
||||
char *name;
|
||||
};
|
||||
struct Comp {
|
||||
int type;
|
||||
|
@ -83,6 +86,7 @@ struct Kex {
|
|||
int server;
|
||||
char *name;
|
||||
char *hostkeyalg;
|
||||
int kex_type;
|
||||
};
|
||||
|
||||
Buffer *kex_init(char *myproposal[PROPOSAL_MAX]);
|
||||
|
@ -96,6 +100,8 @@ kex_choose_conf(char *cprop[PROPOSAL_MAX],
|
|||
int kex_derive_keys(Kex *k, unsigned char *hash, BIGNUM *shared_secret);
|
||||
void packet_set_kex(Kex *k);
|
||||
int dh_pub_is_valid(DH *dh, BIGNUM *dh_pub);
|
||||
DH *dh_new_group_asc(const char *, const char *);
|
||||
DH *dh_new_group(BIGNUM *, BIGNUM *);
|
||||
DH *dh_new_group1();
|
||||
|
||||
unsigned char *
|
||||
|
@ -109,4 +115,15 @@ kex_hash(
|
|||
BIGNUM *server_dh_pub,
|
||||
BIGNUM *shared_secret);
|
||||
|
||||
unsigned char *
|
||||
kex_hash_gex(
|
||||
char *client_version_string,
|
||||
char *server_version_string,
|
||||
char *ckexinit, int ckexinitlen,
|
||||
char *skexinit, int skexinitlen,
|
||||
char *serverhostkeyblob, int sbloblen,
|
||||
int minbits, BIGNUM *prime, BIGNUM *gen,
|
||||
BIGNUM *client_dh_pub,
|
||||
BIGNUM *server_dh_pub,
|
||||
BIGNUM *shared_secret);
|
||||
#endif
|
||||
|
|
3
log.c
3
log.c
|
@ -36,7 +36,7 @@
|
|||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$OpenBSD: log.c,v 1.10 2000/09/12 20:53:10 markus Exp $");
|
||||
RCSID("$OpenBSD: log.c,v 1.11 2000/09/30 16:27:43 markus Exp $");
|
||||
|
||||
#include "ssh.h"
|
||||
#include "xmalloc.h"
|
||||
|
@ -208,6 +208,7 @@ static struct {
|
|||
{ "ERROR", SYSLOG_LEVEL_ERROR },
|
||||
{ "INFO", SYSLOG_LEVEL_INFO },
|
||||
{ "VERBOSE", SYSLOG_LEVEL_VERBOSE },
|
||||
{ "DEBUG", SYSLOG_LEVEL_DEBUG1 },
|
||||
{ "DEBUG1", SYSLOG_LEVEL_DEBUG1 },
|
||||
{ "DEBUG2", SYSLOG_LEVEL_DEBUG2 },
|
||||
{ "DEBUG3", SYSLOG_LEVEL_DEBUG3 },
|
||||
|
|
10
myproposal.h
10
myproposal.h
|
@ -21,11 +21,15 @@
|
|||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#define KEX_DEFAULT_KEX "diffie-hellman-group1-sha1"
|
||||
#define KEX_DEFAULT_KEX "diffie-hellman-group-exchange-sha1,diffie-hellman-group1-sha1"
|
||||
#define KEX_DEFAULT_PK_ALG "ssh-dss"
|
||||
#define KEX_DEFAULT_ENCRYPT "3des-cbc,blowfish-cbc,arcfour,cast128-cbc"
|
||||
#define KEX_DEFAULT_ENCRYPT \
|
||||
"3des-cbc,blowfish-cbc,cast128-cbc,arcfour," \
|
||||
"aes128-cbc,aes192-cbc,aes256-cbc," \
|
||||
"rijndael128-cbc,rijndael192-cbc,rijndael256-cbc," \
|
||||
"rijndael-cbc@lysator.liu.se"
|
||||
#define KEX_DEFAULT_MAC "hmac-sha1,hmac-md5,hmac-ripemd160@openssh.com"
|
||||
#define KEX_DEFAULT_COMP "zlib,none"
|
||||
#define KEX_DEFAULT_COMP "none,zlib"
|
||||
#define KEX_DEFAULT_LANG ""
|
||||
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "bsd-inet_ntoa.h"
|
||||
#include "bsd-strsep.h"
|
||||
#include "bsd-strtok.h"
|
||||
#include "bsd-vis.h"
|
||||
|
||||
/* rfc2553 socket API replacements */
|
||||
#include "fake-getaddrinfo.h"
|
||||
|
|
72
packet.c
72
packet.c
|
@ -37,7 +37,7 @@
|
|||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$OpenBSD: packet.c,v 1.35 2000/09/07 20:27:52 deraadt Exp $");
|
||||
RCSID("$OpenBSD: packet.c,v 1.38 2000/10/12 14:21:12 markus Exp $");
|
||||
|
||||
#include "xmalloc.h"
|
||||
#include "buffer.h"
|
||||
|
@ -45,7 +45,6 @@ RCSID("$OpenBSD: packet.c,v 1.35 2000/09/07 20:27:52 deraadt Exp $");
|
|||
#include "bufaux.h"
|
||||
#include "ssh.h"
|
||||
#include "crc32.h"
|
||||
#include "cipher.h"
|
||||
#include "getput.h"
|
||||
|
||||
#include "compress.h"
|
||||
|
@ -59,6 +58,7 @@ RCSID("$OpenBSD: packet.c,v 1.35 2000/09/07 20:27:52 deraadt Exp $");
|
|||
#include <openssl/dh.h>
|
||||
#include <openssl/hmac.h>
|
||||
#include "buffer.h"
|
||||
#include "cipher.h"
|
||||
#include "kex.h"
|
||||
#include "hmac.h"
|
||||
|
||||
|
@ -161,11 +161,14 @@ packet_set_ssh2_format(void)
|
|||
void
|
||||
packet_set_connection(int fd_in, int fd_out)
|
||||
{
|
||||
Cipher *none = cipher_by_name("none");
|
||||
if (none == NULL)
|
||||
fatal("packet_set_connection: cannot load cipher 'none'");
|
||||
connection_in = fd_in;
|
||||
connection_out = fd_out;
|
||||
cipher_type = SSH_CIPHER_NONE;
|
||||
cipher_set_key(&send_context, SSH_CIPHER_NONE, (unsigned char *) "", 0);
|
||||
cipher_set_key(&receive_context, SSH_CIPHER_NONE, (unsigned char *) "", 0);
|
||||
cipher_init(&send_context, none, (unsigned char *) "", 0, NULL, 0);
|
||||
cipher_init(&receive_context, none, (unsigned char *) "", 0, NULL, 0);
|
||||
if (!initialized) {
|
||||
initialized = 1;
|
||||
buffer_init(&input);
|
||||
|
@ -326,28 +329,18 @@ packet_encrypt(CipherContext * cc, void *dest, void *src,
|
|||
*/
|
||||
|
||||
void
|
||||
packet_decrypt(CipherContext * cc, void *dest, void *src,
|
||||
unsigned int bytes)
|
||||
packet_decrypt(CipherContext *context, void *dest, void *src, unsigned int bytes)
|
||||
{
|
||||
int i;
|
||||
|
||||
if ((bytes % 8) != 0)
|
||||
fatal("packet_decrypt: bad ciphertext length %d", bytes);
|
||||
|
||||
/*
|
||||
* Cryptographic attack detector for ssh - Modifications for packet.c
|
||||
* (C)1998 CORE-SDI, Buenos Aires Argentina Ariel Futoransky(futo@core-sdi.com)
|
||||
*/
|
||||
|
||||
if (cc->type == SSH_CIPHER_NONE || compat20) {
|
||||
i = DEATTACK_OK;
|
||||
} else {
|
||||
i = detect_attack(src, bytes, NULL);
|
||||
}
|
||||
if (i == DEATTACK_DETECTED)
|
||||
if (!compat20 &&
|
||||
context->cipher->number != SSH_CIPHER_NONE &&
|
||||
detect_attack(src, bytes, NULL) == DEATTACK_DETECTED)
|
||||
packet_disconnect("crc32 compensation attack: network attack detected");
|
||||
|
||||
cipher_decrypt(cc, dest, src, bytes);
|
||||
cipher_decrypt(context, dest, src, bytes);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -358,14 +351,15 @@ packet_decrypt(CipherContext * cc, void *dest, void *src,
|
|||
|
||||
void
|
||||
packet_set_encryption_key(const unsigned char *key, unsigned int keylen,
|
||||
int cipher)
|
||||
int number)
|
||||
{
|
||||
Cipher *cipher = cipher_by_number(number);
|
||||
if (cipher == NULL)
|
||||
fatal("packet_set_encryption_key: unknown cipher number %d", number);
|
||||
if (keylen < 20)
|
||||
fatal("keylen too small: %d", keylen);
|
||||
|
||||
/* All other ciphers use the same key in both directions for now. */
|
||||
cipher_set_key(&receive_context, cipher, key, keylen);
|
||||
cipher_set_key(&send_context, cipher, key, keylen);
|
||||
fatal("packet_set_encryption_key: keylen too small: %d", keylen);
|
||||
cipher_init(&receive_context, cipher, key, keylen, NULL, 0);
|
||||
cipher_init(&send_context, cipher, key, keylen, NULL, 0);
|
||||
}
|
||||
|
||||
/* Starts constructing a packet to send. */
|
||||
|
@ -553,7 +547,7 @@ packet_send2()
|
|||
mac = &kex->mac[MODE_OUT];
|
||||
comp = &kex->comp[MODE_OUT];
|
||||
}
|
||||
block_size = enc ? enc->block_size : 8;
|
||||
block_size = enc ? enc->cipher->block_size : 8;
|
||||
|
||||
cp = buffer_ptr(&outgoing_packet);
|
||||
type = cp[5] & 0xff;
|
||||
|
@ -588,7 +582,7 @@ packet_send2()
|
|||
if (padlen < 4)
|
||||
padlen += block_size;
|
||||
buffer_append_space(&outgoing_packet, &cp, padlen);
|
||||
if (enc && enc->type != SSH_CIPHER_NONE) {
|
||||
if (enc && enc->cipher->number != SSH_CIPHER_NONE) {
|
||||
/* random padding */
|
||||
for (i = 0; i < padlen; i++) {
|
||||
if (i % 4 == 0)
|
||||
|
@ -614,7 +608,7 @@ packet_send2()
|
|||
buffer_len(&outgoing_packet),
|
||||
mac->key, mac->key_len
|
||||
);
|
||||
DBG(debug("done calc HMAC out #%d", seqnr));
|
||||
DBG(debug("done calc MAC out #%d", seqnr));
|
||||
}
|
||||
/* encrypt packet and append to output buffer. */
|
||||
buffer_append_space(&output, &cp, buffer_len(&outgoing_packet));
|
||||
|
@ -637,10 +631,10 @@ packet_send2()
|
|||
fatal("packet_send2: no KEX");
|
||||
if (mac->md != NULL)
|
||||
mac->enabled = 1;
|
||||
DBG(debug("cipher_set_key_iv send_context"));
|
||||
cipher_set_key_iv(&send_context, enc->type,
|
||||
enc->key, enc->key_len,
|
||||
enc->iv, enc->iv_len);
|
||||
DBG(debug("cipher_init send_context"));
|
||||
cipher_init(&send_context, enc->cipher,
|
||||
enc->key, enc->cipher->key_len,
|
||||
enc->iv, enc->cipher->block_size);
|
||||
clear_enc_keys(enc, kex->we_need);
|
||||
if (comp->type != 0 && comp->enabled == 0) {
|
||||
comp->enabled = 1;
|
||||
|
@ -841,7 +835,7 @@ packet_read_poll2(int *payload_len_ptr)
|
|||
comp = &kex->comp[MODE_IN];
|
||||
}
|
||||
maclen = mac && mac->enabled ? mac->mac_len : 0;
|
||||
block_size = enc ? enc->block_size : 8;
|
||||
block_size = enc ? enc->cipher->block_size : 8;
|
||||
|
||||
if (packet_length == 0) {
|
||||
/*
|
||||
|
@ -894,8 +888,8 @@ packet_read_poll2(int *payload_len_ptr)
|
|||
mac->key, mac->key_len
|
||||
);
|
||||
if (memcmp(macbuf, buffer_ptr(&input), mac->mac_len) != 0)
|
||||
packet_disconnect("Corrupted HMAC on input.");
|
||||
DBG(debug("HMAC #%d ok", seqnr));
|
||||
packet_disconnect("Corrupted MAC on input.");
|
||||
DBG(debug("MAC #%d ok", seqnr));
|
||||
buffer_consume(&input, mac->mac_len);
|
||||
}
|
||||
if (++seqnr == 0)
|
||||
|
@ -939,10 +933,10 @@ packet_read_poll2(int *payload_len_ptr)
|
|||
fatal("packet_read_poll2: no KEX");
|
||||
if (mac->md != NULL)
|
||||
mac->enabled = 1;
|
||||
DBG(debug("cipher_set_key_iv receive_context"));
|
||||
cipher_set_key_iv(&receive_context, enc->type,
|
||||
enc->key, enc->key_len,
|
||||
enc->iv, enc->iv_len);
|
||||
DBG(debug("cipher_init receive_context"));
|
||||
cipher_init(&receive_context, enc->cipher,
|
||||
enc->key, enc->cipher->key_len,
|
||||
enc->iv, enc->cipher->block_size);
|
||||
clear_enc_keys(enc, kex->we_need);
|
||||
if (comp->type != 0 && comp->enabled == 0) {
|
||||
comp->enabled = 1;
|
||||
|
|
20
readconf.c
20
readconf.c
|
@ -12,10 +12,9 @@
|
|||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$OpenBSD: readconf.c,v 1.47 2000/09/07 21:13:37 markus Exp $");
|
||||
RCSID("$OpenBSD: readconf.c,v 1.49 2000/10/11 20:27:23 markus Exp $");
|
||||
|
||||
#include "ssh.h"
|
||||
#include "cipher.h"
|
||||
#include "readconf.h"
|
||||
#include "match.h"
|
||||
#include "xmalloc.h"
|
||||
|
@ -103,7 +102,8 @@ typedef enum {
|
|||
oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
|
||||
oCompressionLevel, oKeepAlives, oNumberOfPasswordPrompts, oTISAuthentication,
|
||||
oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oIdentityFile2,
|
||||
oGlobalKnownHostsFile2, oUserKnownHostsFile2, oDSAAuthentication
|
||||
oGlobalKnownHostsFile2, oUserKnownHostsFile2, oDSAAuthentication,
|
||||
oKbdInteractiveAuthentication, oKbdInteractiveDevices
|
||||
} OpCodes;
|
||||
|
||||
/* Textual representations of the tokens. */
|
||||
|
@ -119,6 +119,8 @@ static struct {
|
|||
{ "useprivilegedport", oUsePrivilegedPort },
|
||||
{ "rhostsauthentication", oRhostsAuthentication },
|
||||
{ "passwordauthentication", oPasswordAuthentication },
|
||||
{ "kbdinteractiveauthentication", oKbdInteractiveAuthentication },
|
||||
{ "kbdinteractivedevices", oKbdInteractiveDevices },
|
||||
{ "rsaauthentication", oRSAAuthentication },
|
||||
{ "dsaauthentication", oDSAAuthentication },
|
||||
{ "skeyauthentication", oSkeyAuthentication },
|
||||
|
@ -290,6 +292,14 @@ parse_flag:
|
|||
intptr = &options->password_authentication;
|
||||
goto parse_flag;
|
||||
|
||||
case oKbdInteractiveAuthentication:
|
||||
intptr = &options->kbd_interactive_authentication;
|
||||
goto parse_flag;
|
||||
|
||||
case oKbdInteractiveDevices:
|
||||
charptr = &options->kbd_interactive_devices;
|
||||
goto parse_string;
|
||||
|
||||
case oDSAAuthentication:
|
||||
intptr = &options->dsa_authentication;
|
||||
goto parse_flag;
|
||||
|
@ -664,6 +674,8 @@ initialize_options(Options * options)
|
|||
options->afs_token_passing = -1;
|
||||
#endif
|
||||
options->password_authentication = -1;
|
||||
options->kbd_interactive_authentication = -1;
|
||||
options->kbd_interactive_devices = NULL;
|
||||
options->rhosts_rsa_authentication = -1;
|
||||
options->fallback_to_rsh = -1;
|
||||
options->use_rsh = -1;
|
||||
|
@ -734,6 +746,8 @@ fill_default_options(Options * options)
|
|||
#endif /* AFS */
|
||||
if (options->password_authentication == -1)
|
||||
options->password_authentication = 1;
|
||||
if (options->kbd_interactive_authentication == -1)
|
||||
options->kbd_interactive_authentication = 0;
|
||||
if (options->rhosts_rsa_authentication == -1)
|
||||
options->rhosts_rsa_authentication = 1;
|
||||
if (options->fallback_to_rsh == -1)
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
* called by a name other than "ssh" or "Secure Shell".
|
||||
*/
|
||||
|
||||
/* RCSID("$OpenBSD: readconf.h,v 1.21 2000/09/07 20:27:53 deraadt Exp $"); */
|
||||
/* RCSID("$OpenBSD: readconf.h,v 1.22 2000/10/11 20:14:39 markus Exp $"); */
|
||||
|
||||
#ifndef READCONF_H
|
||||
#define READCONF_H
|
||||
|
@ -47,6 +47,8 @@ typedef struct {
|
|||
#endif
|
||||
int password_authentication; /* Try password
|
||||
* authentication. */
|
||||
int kbd_interactive_authentication; /* Try keyboard-interactive auth. */
|
||||
char *kbd_interactive_devices; /* Keyboard-interactive auth devices. */
|
||||
int fallback_to_rsh;/* Use rsh if cannot connect with ssh. */
|
||||
int use_rsh; /* Always use rsh (don\'t try ssh). */
|
||||
int batch_mode; /* Batch mode: do not ask for passwords. */
|
||||
|
|
82
readpass.c
82
readpass.c
|
@ -32,88 +32,24 @@
|
|||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$OpenBSD: readpass.c,v 1.11 2000/06/20 01:39:44 markus Exp $");
|
||||
RCSID("$OpenBSD: readpass.c,v 1.12 2000/10/11 20:14:39 markus Exp $");
|
||||
|
||||
#include "xmalloc.h"
|
||||
#include "ssh.h"
|
||||
|
||||
volatile int intr;
|
||||
|
||||
void
|
||||
intcatch()
|
||||
{
|
||||
intr = 1;
|
||||
}
|
||||
#include "cli.h"
|
||||
|
||||
/*
|
||||
* Reads a passphrase from /dev/tty with echo turned off. Returns the
|
||||
* passphrase (allocated with xmalloc), being very careful to ensure that
|
||||
* no other userland buffer is storing the password.
|
||||
*/
|
||||
/*
|
||||
* Note: the funcationallity of this routing has been moved to
|
||||
* cli_read_passphrase(). This routing remains to maintain
|
||||
* compatibility with existing code.
|
||||
*/
|
||||
char *
|
||||
read_passphrase(const char *prompt, int from_stdin)
|
||||
read_passphrase(char *prompt, int from_stdin)
|
||||
{
|
||||
char buf[1024], *p, ch;
|
||||
struct termios tio, saved_tio;
|
||||
sigset_t oset, nset;
|
||||
struct sigaction sa, osa;
|
||||
int input, output, echo = 0;
|
||||
|
||||
if (from_stdin) {
|
||||
input = STDIN_FILENO;
|
||||
output = STDERR_FILENO;
|
||||
} else
|
||||
input = output = open("/dev/tty", O_RDWR);
|
||||
|
||||
if (input == -1)
|
||||
fatal("You have no controlling tty. Cannot read passphrase.\n");
|
||||
|
||||
/* block signals, get terminal modes and turn off echo */
|
||||
sigemptyset(&nset);
|
||||
sigaddset(&nset, SIGTSTP);
|
||||
(void) sigprocmask(SIG_BLOCK, &nset, &oset);
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.sa_handler = intcatch;
|
||||
(void) sigaction(SIGINT, &sa, &osa);
|
||||
|
||||
intr = 0;
|
||||
|
||||
if (tcgetattr(input, &saved_tio) == 0 && (saved_tio.c_lflag & ECHO)) {
|
||||
echo = 1;
|
||||
tio = saved_tio;
|
||||
tio.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
|
||||
(void) tcsetattr(input, TCSANOW, &tio);
|
||||
}
|
||||
|
||||
fflush(stdout);
|
||||
|
||||
(void)write(output, prompt, strlen(prompt));
|
||||
for (p = buf; read(input, &ch, 1) == 1 && ch != '\n';) {
|
||||
if (intr)
|
||||
break;
|
||||
if (p < buf + sizeof(buf) - 1)
|
||||
*p++ = ch;
|
||||
}
|
||||
*p = '\0';
|
||||
if (!intr)
|
||||
(void)write(output, "\n", 1);
|
||||
|
||||
/* restore terminal modes and allow signals */
|
||||
if (echo)
|
||||
tcsetattr(input, TCSANOW, &saved_tio);
|
||||
(void) sigprocmask(SIG_SETMASK, &oset, NULL);
|
||||
(void) sigaction(SIGINT, &osa, NULL);
|
||||
|
||||
if (intr) {
|
||||
kill(getpid(), SIGINT);
|
||||
sigemptyset(&nset);
|
||||
/* XXX tty has not neccessarily drained by now? */
|
||||
sigsuspend(&nset);
|
||||
}
|
||||
|
||||
if (!from_stdin)
|
||||
(void)close(input);
|
||||
p = xstrdup(buf);
|
||||
memset(buf, 0, sizeof(buf));
|
||||
return (p);
|
||||
return cli_read_passphrase(prompt, from_stdin, 0);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,493 @@
|
|||
/* $OpenBSD: rijndael.c,v 1.1 2000/10/13 18:59:14 markus Exp $ */
|
||||
|
||||
/* This is an independent implementation of the encryption algorithm: */
|
||||
/* */
|
||||
/* RIJNDAEL by Joan Daemen and Vincent Rijmen */
|
||||
/* */
|
||||
/* which is a candidate algorithm in the Advanced Encryption Standard */
|
||||
/* programme of the US National Institute of Standards and Technology. */
|
||||
/* */
|
||||
/* Copyright in this implementation is held by Dr B R Gladman but I */
|
||||
/* hereby give permission for its free direct or derivative use subject */
|
||||
/* to acknowledgment of its origin and compliance with any conditions */
|
||||
/* that the originators of the algorithm place on its exploitation. */
|
||||
/* */
|
||||
/* Dr Brian Gladman (gladman@seven77.demon.co.uk) 14th January 1999 */
|
||||
|
||||
/* Timing data for Rijndael (rijndael.c)
|
||||
|
||||
Algorithm: rijndael (rijndael.c)
|
||||
|
||||
128 bit key:
|
||||
Key Setup: 305/1389 cycles (encrypt/decrypt)
|
||||
Encrypt: 374 cycles = 68.4 mbits/sec
|
||||
Decrypt: 352 cycles = 72.7 mbits/sec
|
||||
Mean: 363 cycles = 70.5 mbits/sec
|
||||
|
||||
192 bit key:
|
||||
Key Setup: 277/1595 cycles (encrypt/decrypt)
|
||||
Encrypt: 439 cycles = 58.3 mbits/sec
|
||||
Decrypt: 425 cycles = 60.2 mbits/sec
|
||||
Mean: 432 cycles = 59.3 mbits/sec
|
||||
|
||||
256 bit key:
|
||||
Key Setup: 374/1960 cycles (encrypt/decrypt)
|
||||
Encrypt: 502 cycles = 51.0 mbits/sec
|
||||
Decrypt: 498 cycles = 51.4 mbits/sec
|
||||
Mean: 500 cycles = 51.2 mbits/sec
|
||||
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include "rijndael.h"
|
||||
|
||||
void gen_tabs __P((void));
|
||||
|
||||
/* 3. Basic macros for speeding up generic operations */
|
||||
|
||||
/* Circular rotate of 32 bit values */
|
||||
|
||||
#define rotr(x,n) (((x) >> ((int)(n))) | ((x) << (32 - (int)(n))))
|
||||
#define rotl(x,n) (((x) << ((int)(n))) | ((x) >> (32 - (int)(n))))
|
||||
|
||||
/* Invert byte order in a 32 bit variable */
|
||||
|
||||
#define bswap(x) (rotl(x, 8) & 0x00ff00ff | rotr(x, 8) & 0xff00ff00)
|
||||
|
||||
/* Extract byte from a 32 bit quantity (little endian notation) */
|
||||
|
||||
#define byte(x,n) ((u1byte)((x) >> (8 * n)))
|
||||
|
||||
#if BYTE_ORDER != LITTLE_ENDIAN
|
||||
#define BLOCK_SWAP
|
||||
#endif
|
||||
|
||||
/* For inverting byte order in input/output 32 bit words if needed */
|
||||
|
||||
#ifdef BLOCK_SWAP
|
||||
#define BYTE_SWAP
|
||||
#define WORD_SWAP
|
||||
#endif
|
||||
|
||||
#ifdef BYTE_SWAP
|
||||
#define io_swap(x) bswap(x)
|
||||
#else
|
||||
#define io_swap(x) (x)
|
||||
#endif
|
||||
|
||||
/* For inverting the byte order of input/output blocks if needed */
|
||||
|
||||
#ifdef WORD_SWAP
|
||||
|
||||
#define get_block(x) \
|
||||
((u4byte*)(x))[0] = io_swap(in_blk[3]); \
|
||||
((u4byte*)(x))[1] = io_swap(in_blk[2]); \
|
||||
((u4byte*)(x))[2] = io_swap(in_blk[1]); \
|
||||
((u4byte*)(x))[3] = io_swap(in_blk[0])
|
||||
|
||||
#define put_block(x) \
|
||||
out_blk[3] = io_swap(((u4byte*)(x))[0]); \
|
||||
out_blk[2] = io_swap(((u4byte*)(x))[1]); \
|
||||
out_blk[1] = io_swap(((u4byte*)(x))[2]); \
|
||||
out_blk[0] = io_swap(((u4byte*)(x))[3])
|
||||
|
||||
#define get_key(x,len) \
|
||||
((u4byte*)(x))[4] = ((u4byte*)(x))[5] = \
|
||||
((u4byte*)(x))[6] = ((u4byte*)(x))[7] = 0; \
|
||||
switch((((len) + 63) / 64)) { \
|
||||
case 2: \
|
||||
((u4byte*)(x))[0] = io_swap(in_key[3]); \
|
||||
((u4byte*)(x))[1] = io_swap(in_key[2]); \
|
||||
((u4byte*)(x))[2] = io_swap(in_key[1]); \
|
||||
((u4byte*)(x))[3] = io_swap(in_key[0]); \
|
||||
break; \
|
||||
case 3: \
|
||||
((u4byte*)(x))[0] = io_swap(in_key[5]); \
|
||||
((u4byte*)(x))[1] = io_swap(in_key[4]); \
|
||||
((u4byte*)(x))[2] = io_swap(in_key[3]); \
|
||||
((u4byte*)(x))[3] = io_swap(in_key[2]); \
|
||||
((u4byte*)(x))[4] = io_swap(in_key[1]); \
|
||||
((u4byte*)(x))[5] = io_swap(in_key[0]); \
|
||||
break; \
|
||||
case 4: \
|
||||
((u4byte*)(x))[0] = io_swap(in_key[7]); \
|
||||
((u4byte*)(x))[1] = io_swap(in_key[6]); \
|
||||
((u4byte*)(x))[2] = io_swap(in_key[5]); \
|
||||
((u4byte*)(x))[3] = io_swap(in_key[4]); \
|
||||
((u4byte*)(x))[4] = io_swap(in_key[3]); \
|
||||
((u4byte*)(x))[5] = io_swap(in_key[2]); \
|
||||
((u4byte*)(x))[6] = io_swap(in_key[1]); \
|
||||
((u4byte*)(x))[7] = io_swap(in_key[0]); \
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define get_block(x) \
|
||||
((u4byte*)(x))[0] = io_swap(in_blk[0]); \
|
||||
((u4byte*)(x))[1] = io_swap(in_blk[1]); \
|
||||
((u4byte*)(x))[2] = io_swap(in_blk[2]); \
|
||||
((u4byte*)(x))[3] = io_swap(in_blk[3])
|
||||
|
||||
#define put_block(x) \
|
||||
out_blk[0] = io_swap(((u4byte*)(x))[0]); \
|
||||
out_blk[1] = io_swap(((u4byte*)(x))[1]); \
|
||||
out_blk[2] = io_swap(((u4byte*)(x))[2]); \
|
||||
out_blk[3] = io_swap(((u4byte*)(x))[3])
|
||||
|
||||
#define get_key(x,len) \
|
||||
((u4byte*)(x))[4] = ((u4byte*)(x))[5] = \
|
||||
((u4byte*)(x))[6] = ((u4byte*)(x))[7] = 0; \
|
||||
switch((((len) + 63) / 64)) { \
|
||||
case 4: \
|
||||
((u4byte*)(x))[6] = io_swap(in_key[6]); \
|
||||
((u4byte*)(x))[7] = io_swap(in_key[7]); \
|
||||
case 3: \
|
||||
((u4byte*)(x))[4] = io_swap(in_key[4]); \
|
||||
((u4byte*)(x))[5] = io_swap(in_key[5]); \
|
||||
case 2: \
|
||||
((u4byte*)(x))[0] = io_swap(in_key[0]); \
|
||||
((u4byte*)(x))[1] = io_swap(in_key[1]); \
|
||||
((u4byte*)(x))[2] = io_swap(in_key[2]); \
|
||||
((u4byte*)(x))[3] = io_swap(in_key[3]); \
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#define LARGE_TABLES
|
||||
|
||||
u1byte pow_tab[256];
|
||||
u1byte log_tab[256];
|
||||
u1byte sbx_tab[256];
|
||||
u1byte isb_tab[256];
|
||||
u4byte rco_tab[ 10];
|
||||
u4byte ft_tab[4][256];
|
||||
u4byte it_tab[4][256];
|
||||
|
||||
#ifdef LARGE_TABLES
|
||||
u4byte fl_tab[4][256];
|
||||
u4byte il_tab[4][256];
|
||||
#endif
|
||||
|
||||
u4byte tab_gen = 0;
|
||||
|
||||
#define ff_mult(a,b) (a && b ? pow_tab[(log_tab[a] + log_tab[b]) % 255] : 0)
|
||||
|
||||
#define f_rn(bo, bi, n, k) \
|
||||
bo[n] = ft_tab[0][byte(bi[n],0)] ^ \
|
||||
ft_tab[1][byte(bi[(n + 1) & 3],1)] ^ \
|
||||
ft_tab[2][byte(bi[(n + 2) & 3],2)] ^ \
|
||||
ft_tab[3][byte(bi[(n + 3) & 3],3)] ^ *(k + n)
|
||||
|
||||
#define i_rn(bo, bi, n, k) \
|
||||
bo[n] = it_tab[0][byte(bi[n],0)] ^ \
|
||||
it_tab[1][byte(bi[(n + 3) & 3],1)] ^ \
|
||||
it_tab[2][byte(bi[(n + 2) & 3],2)] ^ \
|
||||
it_tab[3][byte(bi[(n + 1) & 3],3)] ^ *(k + n)
|
||||
|
||||
#ifdef LARGE_TABLES
|
||||
|
||||
#define ls_box(x) \
|
||||
( fl_tab[0][byte(x, 0)] ^ \
|
||||
fl_tab[1][byte(x, 1)] ^ \
|
||||
fl_tab[2][byte(x, 2)] ^ \
|
||||
fl_tab[3][byte(x, 3)] )
|
||||
|
||||
#define f_rl(bo, bi, n, k) \
|
||||
bo[n] = fl_tab[0][byte(bi[n],0)] ^ \
|
||||
fl_tab[1][byte(bi[(n + 1) & 3],1)] ^ \
|
||||
fl_tab[2][byte(bi[(n + 2) & 3],2)] ^ \
|
||||
fl_tab[3][byte(bi[(n + 3) & 3],3)] ^ *(k + n)
|
||||
|
||||
#define i_rl(bo, bi, n, k) \
|
||||
bo[n] = il_tab[0][byte(bi[n],0)] ^ \
|
||||
il_tab[1][byte(bi[(n + 3) & 3],1)] ^ \
|
||||
il_tab[2][byte(bi[(n + 2) & 3],2)] ^ \
|
||||
il_tab[3][byte(bi[(n + 1) & 3],3)] ^ *(k + n)
|
||||
|
||||
#else
|
||||
|
||||
#define ls_box(x) \
|
||||
((u4byte)sbx_tab[byte(x, 0)] << 0) ^ \
|
||||
((u4byte)sbx_tab[byte(x, 1)] << 8) ^ \
|
||||
((u4byte)sbx_tab[byte(x, 2)] << 16) ^ \
|
||||
((u4byte)sbx_tab[byte(x, 3)] << 24)
|
||||
|
||||
#define f_rl(bo, bi, n, k) \
|
||||
bo[n] = (u4byte)sbx_tab[byte(bi[n],0)] ^ \
|
||||
rotl(((u4byte)sbx_tab[byte(bi[(n + 1) & 3],1)]), 8) ^ \
|
||||
rotl(((u4byte)sbx_tab[byte(bi[(n + 2) & 3],2)]), 16) ^ \
|
||||
rotl(((u4byte)sbx_tab[byte(bi[(n + 3) & 3],3)]), 24) ^ *(k + n)
|
||||
|
||||
#define i_rl(bo, bi, n, k) \
|
||||
bo[n] = (u4byte)isb_tab[byte(bi[n],0)] ^ \
|
||||
rotl(((u4byte)isb_tab[byte(bi[(n + 3) & 3],1)]), 8) ^ \
|
||||
rotl(((u4byte)isb_tab[byte(bi[(n + 2) & 3],2)]), 16) ^ \
|
||||
rotl(((u4byte)isb_tab[byte(bi[(n + 1) & 3],3)]), 24) ^ *(k + n)
|
||||
|
||||
#endif
|
||||
|
||||
void
|
||||
gen_tabs(void)
|
||||
{
|
||||
u4byte i, t;
|
||||
u1byte p, q;
|
||||
|
||||
/* log and power tables for GF(2**8) finite field with */
|
||||
/* 0x11b as modular polynomial - the simplest prmitive */
|
||||
/* root is 0x11, used here to generate the tables */
|
||||
|
||||
for(i = 0,p = 1; i < 256; ++i) {
|
||||
pow_tab[i] = (u1byte)p; log_tab[p] = (u1byte)i;
|
||||
|
||||
p = p ^ (p << 1) ^ (p & 0x80 ? 0x01b : 0);
|
||||
}
|
||||
|
||||
log_tab[1] = 0; p = 1;
|
||||
|
||||
for(i = 0; i < 10; ++i) {
|
||||
rco_tab[i] = p;
|
||||
|
||||
p = (p << 1) ^ (p & 0x80 ? 0x1b : 0);
|
||||
}
|
||||
|
||||
/* note that the affine byte transformation matrix in */
|
||||
/* rijndael specification is in big endian format with */
|
||||
/* bit 0 as the most significant bit. In the remainder */
|
||||
/* of the specification the bits are numbered from the */
|
||||
/* least significant end of a byte. */
|
||||
|
||||
for(i = 0; i < 256; ++i) {
|
||||
p = (i ? pow_tab[255 - log_tab[i]] : 0); q = p;
|
||||
q = (q >> 7) | (q << 1); p ^= q;
|
||||
q = (q >> 7) | (q << 1); p ^= q;
|
||||
q = (q >> 7) | (q << 1); p ^= q;
|
||||
q = (q >> 7) | (q << 1); p ^= q ^ 0x63;
|
||||
sbx_tab[i] = (u1byte)p; isb_tab[p] = (u1byte)i;
|
||||
}
|
||||
|
||||
for(i = 0; i < 256; ++i) {
|
||||
p = sbx_tab[i];
|
||||
|
||||
#ifdef LARGE_TABLES
|
||||
|
||||
t = p; fl_tab[0][i] = t;
|
||||
fl_tab[1][i] = rotl(t, 8);
|
||||
fl_tab[2][i] = rotl(t, 16);
|
||||
fl_tab[3][i] = rotl(t, 24);
|
||||
#endif
|
||||
t = ((u4byte)ff_mult(2, p)) |
|
||||
((u4byte)p << 8) |
|
||||
((u4byte)p << 16) |
|
||||
((u4byte)ff_mult(3, p) << 24);
|
||||
|
||||
ft_tab[0][i] = t;
|
||||
ft_tab[1][i] = rotl(t, 8);
|
||||
ft_tab[2][i] = rotl(t, 16);
|
||||
ft_tab[3][i] = rotl(t, 24);
|
||||
|
||||
p = isb_tab[i];
|
||||
|
||||
#ifdef LARGE_TABLES
|
||||
|
||||
t = p; il_tab[0][i] = t;
|
||||
il_tab[1][i] = rotl(t, 8);
|
||||
il_tab[2][i] = rotl(t, 16);
|
||||
il_tab[3][i] = rotl(t, 24);
|
||||
#endif
|
||||
t = ((u4byte)ff_mult(14, p)) |
|
||||
((u4byte)ff_mult( 9, p) << 8) |
|
||||
((u4byte)ff_mult(13, p) << 16) |
|
||||
((u4byte)ff_mult(11, p) << 24);
|
||||
|
||||
it_tab[0][i] = t;
|
||||
it_tab[1][i] = rotl(t, 8);
|
||||
it_tab[2][i] = rotl(t, 16);
|
||||
it_tab[3][i] = rotl(t, 24);
|
||||
}
|
||||
|
||||
tab_gen = 1;
|
||||
};
|
||||
|
||||
#define star_x(x) (((x) & 0x7f7f7f7f) << 1) ^ ((((x) & 0x80808080) >> 7) * 0x1b)
|
||||
|
||||
#define imix_col(y,x) \
|
||||
u = star_x(x); \
|
||||
v = star_x(u); \
|
||||
w = star_x(v); \
|
||||
t = w ^ (x); \
|
||||
(y) = u ^ v ^ w; \
|
||||
(y) ^= rotr(u ^ t, 8) ^ \
|
||||
rotr(v ^ t, 16) ^ \
|
||||
rotr(t,24)
|
||||
|
||||
/* initialise the key schedule from the user supplied key */
|
||||
|
||||
#define loop4(i) \
|
||||
{ t = ls_box(rotr(t, 8)) ^ rco_tab[i]; \
|
||||
t ^= e_key[4 * i]; e_key[4 * i + 4] = t; \
|
||||
t ^= e_key[4 * i + 1]; e_key[4 * i + 5] = t; \
|
||||
t ^= e_key[4 * i + 2]; e_key[4 * i + 6] = t; \
|
||||
t ^= e_key[4 * i + 3]; e_key[4 * i + 7] = t; \
|
||||
}
|
||||
|
||||
#define loop6(i) \
|
||||
{ t = ls_box(rotr(t, 8)) ^ rco_tab[i]; \
|
||||
t ^= e_key[6 * i]; e_key[6 * i + 6] = t; \
|
||||
t ^= e_key[6 * i + 1]; e_key[6 * i + 7] = t; \
|
||||
t ^= e_key[6 * i + 2]; e_key[6 * i + 8] = t; \
|
||||
t ^= e_key[6 * i + 3]; e_key[6 * i + 9] = t; \
|
||||
t ^= e_key[6 * i + 4]; e_key[6 * i + 10] = t; \
|
||||
t ^= e_key[6 * i + 5]; e_key[6 * i + 11] = t; \
|
||||
}
|
||||
|
||||
#define loop8(i) \
|
||||
{ t = ls_box(rotr(t, 8)) ^ rco_tab[i]; \
|
||||
t ^= e_key[8 * i]; e_key[8 * i + 8] = t; \
|
||||
t ^= e_key[8 * i + 1]; e_key[8 * i + 9] = t; \
|
||||
t ^= e_key[8 * i + 2]; e_key[8 * i + 10] = t; \
|
||||
t ^= e_key[8 * i + 3]; e_key[8 * i + 11] = t; \
|
||||
t = e_key[8 * i + 4] ^ ls_box(t); \
|
||||
e_key[8 * i + 12] = t; \
|
||||
t ^= e_key[8 * i + 5]; e_key[8 * i + 13] = t; \
|
||||
t ^= e_key[8 * i + 6]; e_key[8 * i + 14] = t; \
|
||||
t ^= e_key[8 * i + 7]; e_key[8 * i + 15] = t; \
|
||||
}
|
||||
|
||||
rijndael_ctx *
|
||||
rijndael_set_key(rijndael_ctx *ctx, const u4byte *in_key, const u4byte key_len,
|
||||
int encrypt)
|
||||
{
|
||||
u4byte i, t, u, v, w;
|
||||
u4byte *e_key = ctx->e_key;
|
||||
u4byte *d_key = ctx->d_key;
|
||||
|
||||
ctx->decrypt = !encrypt;
|
||||
|
||||
if(!tab_gen)
|
||||
gen_tabs();
|
||||
|
||||
ctx->k_len = (key_len + 31) / 32;
|
||||
|
||||
e_key[0] = in_key[0]; e_key[1] = in_key[1];
|
||||
e_key[2] = in_key[2]; e_key[3] = in_key[3];
|
||||
|
||||
switch(ctx->k_len) {
|
||||
case 4: t = e_key[3];
|
||||
for(i = 0; i < 10; ++i)
|
||||
loop4(i);
|
||||
break;
|
||||
|
||||
case 6: e_key[4] = in_key[4]; t = e_key[5] = in_key[5];
|
||||
for(i = 0; i < 8; ++i)
|
||||
loop6(i);
|
||||
break;
|
||||
|
||||
case 8: e_key[4] = in_key[4]; e_key[5] = in_key[5];
|
||||
e_key[6] = in_key[6]; t = e_key[7] = in_key[7];
|
||||
for(i = 0; i < 7; ++i)
|
||||
loop8(i);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!encrypt) {
|
||||
d_key[0] = e_key[0]; d_key[1] = e_key[1];
|
||||
d_key[2] = e_key[2]; d_key[3] = e_key[3];
|
||||
|
||||
for(i = 4; i < 4 * ctx->k_len + 24; ++i) {
|
||||
imix_col(d_key[i], e_key[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return ctx;
|
||||
};
|
||||
|
||||
/* encrypt a block of text */
|
||||
|
||||
#define f_nround(bo, bi, k) \
|
||||
f_rn(bo, bi, 0, k); \
|
||||
f_rn(bo, bi, 1, k); \
|
||||
f_rn(bo, bi, 2, k); \
|
||||
f_rn(bo, bi, 3, k); \
|
||||
k += 4
|
||||
|
||||
#define f_lround(bo, bi, k) \
|
||||
f_rl(bo, bi, 0, k); \
|
||||
f_rl(bo, bi, 1, k); \
|
||||
f_rl(bo, bi, 2, k); \
|
||||
f_rl(bo, bi, 3, k)
|
||||
|
||||
void
|
||||
rijndael_encrypt(rijndael_ctx *ctx, const u4byte *in_blk, u4byte *out_blk)
|
||||
{
|
||||
u4byte k_len = ctx->k_len;
|
||||
u4byte *e_key = ctx->e_key;
|
||||
u4byte b0[4], b1[4], *kp;
|
||||
|
||||
b0[0] = in_blk[0] ^ e_key[0]; b0[1] = in_blk[1] ^ e_key[1];
|
||||
b0[2] = in_blk[2] ^ e_key[2]; b0[3] = in_blk[3] ^ e_key[3];
|
||||
|
||||
kp = e_key + 4;
|
||||
|
||||
if(k_len > 6) {
|
||||
f_nround(b1, b0, kp); f_nround(b0, b1, kp);
|
||||
}
|
||||
|
||||
if(k_len > 4) {
|
||||
f_nround(b1, b0, kp); f_nround(b0, b1, kp);
|
||||
}
|
||||
|
||||
f_nround(b1, b0, kp); f_nround(b0, b1, kp);
|
||||
f_nround(b1, b0, kp); f_nround(b0, b1, kp);
|
||||
f_nround(b1, b0, kp); f_nround(b0, b1, kp);
|
||||
f_nround(b1, b0, kp); f_nround(b0, b1, kp);
|
||||
f_nround(b1, b0, kp); f_lround(b0, b1, kp);
|
||||
|
||||
out_blk[0] = b0[0]; out_blk[1] = b0[1];
|
||||
out_blk[2] = b0[2]; out_blk[3] = b0[3];
|
||||
};
|
||||
|
||||
/* decrypt a block of text */
|
||||
|
||||
#define i_nround(bo, bi, k) \
|
||||
i_rn(bo, bi, 0, k); \
|
||||
i_rn(bo, bi, 1, k); \
|
||||
i_rn(bo, bi, 2, k); \
|
||||
i_rn(bo, bi, 3, k); \
|
||||
k -= 4
|
||||
|
||||
#define i_lround(bo, bi, k) \
|
||||
i_rl(bo, bi, 0, k); \
|
||||
i_rl(bo, bi, 1, k); \
|
||||
i_rl(bo, bi, 2, k); \
|
||||
i_rl(bo, bi, 3, k)
|
||||
|
||||
void
|
||||
rijndael_decrypt(rijndael_ctx *ctx, const u4byte *in_blk, u4byte *out_blk)
|
||||
{
|
||||
u4byte b0[4], b1[4], *kp;
|
||||
u4byte k_len = ctx->k_len;
|
||||
u4byte *e_key = ctx->e_key;
|
||||
u4byte *d_key = ctx->d_key;
|
||||
|
||||
b0[0] = in_blk[0] ^ e_key[4 * k_len + 24]; b0[1] = in_blk[1] ^ e_key[4 * k_len + 25];
|
||||
b0[2] = in_blk[2] ^ e_key[4 * k_len + 26]; b0[3] = in_blk[3] ^ e_key[4 * k_len + 27];
|
||||
|
||||
kp = d_key + 4 * (k_len + 5);
|
||||
|
||||
if(k_len > 6) {
|
||||
i_nround(b1, b0, kp); i_nround(b0, b1, kp);
|
||||
}
|
||||
|
||||
if(k_len > 4) {
|
||||
i_nround(b1, b0, kp); i_nround(b0, b1, kp);
|
||||
}
|
||||
|
||||
i_nround(b1, b0, kp); i_nround(b0, b1, kp);
|
||||
i_nround(b1, b0, kp); i_nround(b0, b1, kp);
|
||||
i_nround(b1, b0, kp); i_nround(b0, b1, kp);
|
||||
i_nround(b1, b0, kp); i_nround(b0, b1, kp);
|
||||
i_nround(b1, b0, kp); i_lround(b0, b1, kp);
|
||||
|
||||
out_blk[0] = b0[0]; out_blk[1] = b0[1];
|
||||
out_blk[2] = b0[2]; out_blk[3] = b0[3];
|
||||
};
|
|
@ -0,0 +1,31 @@
|
|||
#ifndef _RIJNDAEL_H_
|
||||
#define _RIJNDAEL_H_
|
||||
|
||||
/* 1. Standard types for AES cryptography source code */
|
||||
|
||||
typedef u_int8_t u1byte; /* an 8 bit unsigned character type */
|
||||
typedef u_int16_t u2byte; /* a 16 bit unsigned integer type */
|
||||
typedef u_int32_t u4byte; /* a 32 bit unsigned integer type */
|
||||
|
||||
typedef int8_t s1byte; /* an 8 bit signed character type */
|
||||
typedef int16_t s2byte; /* a 16 bit signed integer type */
|
||||
typedef int32_t s4byte; /* a 32 bit signed integer type */
|
||||
|
||||
typedef struct _rijndael_ctx {
|
||||
u4byte k_len;
|
||||
int decrypt;
|
||||
u4byte e_key[64];
|
||||
u4byte d_key[64];
|
||||
} rijndael_ctx;
|
||||
|
||||
|
||||
/* 2. Standard interface for AES cryptographic routines */
|
||||
|
||||
/* These are all based on 32 bit unsigned values and will therefore */
|
||||
/* require endian conversions for big-endian architectures */
|
||||
|
||||
rijndael_ctx *rijndael_set_key __P((rijndael_ctx *, const u4byte *, u4byte, int));
|
||||
void rijndael_encrypt __P((rijndael_ctx *, const u4byte *, u4byte *));
|
||||
void rijndael_decrypt __P((rijndael_ctx *, const u4byte *, u4byte *));
|
||||
|
||||
#endif /* _RIJNDAEL_H_ */
|
9
scp.1
9
scp.1
|
@ -9,7 +9,7 @@
|
|||
.\"
|
||||
.\" Created: Sun May 7 00:14:37 1995 ylo
|
||||
.\"
|
||||
.\" $Id: scp.1,v 1.10 2000/09/05 02:34:54 djm Exp $
|
||||
.\" $Id: scp.1,v 1.11 2000/10/14 05:23:12 djm Exp $
|
||||
.\"
|
||||
.Dd September 25, 1999
|
||||
.Dt SCP 1
|
||||
|
@ -24,6 +24,7 @@
|
|||
.Op Fl P Ar port
|
||||
.Op Fl c Ar cipher
|
||||
.Op Fl i Ar identity_file
|
||||
.Op Fl o Ar option
|
||||
.Sm off
|
||||
.Oo
|
||||
.Op Ar user@
|
||||
|
@ -102,9 +103,13 @@ is already reserved for preserving the times and modes of the file in
|
|||
.It Fl S Ar program
|
||||
Name of
|
||||
.Ar program
|
||||
to use for the encrypted connection. The program must understand
|
||||
to use for the encrypted connection.
|
||||
The program must understand
|
||||
.Xr ssh 1
|
||||
options.
|
||||
.It Fl o Ar option
|
||||
The given option is directly passed to
|
||||
.Xr ssh 1 .
|
||||
.It Fl 4
|
||||
Forces
|
||||
.Nm
|
||||
|
|
155
scp.c
155
scp.c
|
@ -75,7 +75,7 @@
|
|||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$OpenBSD: scp.c,v 1.40 2000/09/21 11:11:42 markus Exp $");
|
||||
RCSID("$OpenBSD: scp.c,v 1.41 2000/10/11 20:03:27 markus Exp $");
|
||||
|
||||
#include "ssh.h"
|
||||
#include "xmalloc.h"
|
||||
|
@ -102,6 +102,9 @@ void progressmeter(int);
|
|||
int getttywidth(void);
|
||||
int do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc);
|
||||
|
||||
/* setup arguments for the call to ssh */
|
||||
void addargs(char *fmt, ...) __attribute__((format(printf, 1, 2)));
|
||||
|
||||
/* Time a transfer started. */
|
||||
static struct timeval start;
|
||||
|
||||
|
@ -114,12 +117,6 @@ off_t totalbytes = 0;
|
|||
/* Name of current file being transferred. */
|
||||
char *curfile;
|
||||
|
||||
/* This is set to non-zero if IPv4 is desired. */
|
||||
int IPv4 = 0;
|
||||
|
||||
/* This is set to non-zero if IPv6 is desired. */
|
||||
int IPv6 = 0;
|
||||
|
||||
/* This is set to non-zero to enable verbose mode. */
|
||||
int verbose_mode = 0;
|
||||
|
||||
|
@ -129,23 +126,16 @@ int compress_flag = 0;
|
|||
/* This is set to zero if the progressmeter is not desired. */
|
||||
int showprogress = 1;
|
||||
|
||||
/* This is set to non-zero if running in batch mode (that is, password
|
||||
and passphrase queries are not allowed). */
|
||||
int batchmode = 0;
|
||||
|
||||
/* This is set to the cipher type string if given on the command line. */
|
||||
char *cipher = NULL;
|
||||
|
||||
/* This is set to the RSA authentication identity file name if given on
|
||||
the command line. */
|
||||
char *identity = NULL;
|
||||
|
||||
/* This is the port to use in contacting the remote site (is non-NULL). */
|
||||
char *port = NULL;
|
||||
|
||||
/* This is the program to execute for the secured connection. ("ssh" or -S) */
|
||||
char *ssh_program = SSH_PROGRAM;
|
||||
|
||||
/* This is the list of arguments that scp passes to ssh */
|
||||
struct {
|
||||
char **list;
|
||||
int num;
|
||||
int nalloc;
|
||||
} args;
|
||||
|
||||
/*
|
||||
* This function executes the given command as the specified user on the
|
||||
* given host. This returns < 0 if execution fails, and >= 0 otherwise. This
|
||||
|
@ -158,8 +148,8 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc)
|
|||
int pin[2], pout[2], reserved[2];
|
||||
|
||||
if (verbose_mode)
|
||||
fprintf(stderr, "Executing: host %s, user %s, command %s\n",
|
||||
host, remuser ? remuser : "(unspecified)", cmd);
|
||||
fprintf(stderr, "Executing: program %s host %s, user %s, command %s\n",
|
||||
ssh_program, host, remuser ? remuser : "(unspecified)", cmd);
|
||||
|
||||
/*
|
||||
* Reserve two descriptors so that the real pipes won't get
|
||||
|
@ -178,10 +168,7 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc)
|
|||
close(reserved[1]);
|
||||
|
||||
/* For a child to execute the command on the remote host using ssh. */
|
||||
if (fork() == 0) {
|
||||
char *args[100]; /* XXX careful */
|
||||
unsigned int i;
|
||||
|
||||
if (fork() == 0) {
|
||||
/* Child. */
|
||||
close(pin[1]);
|
||||
close(pout[0]);
|
||||
|
@ -190,41 +177,13 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc)
|
|||
close(pin[0]);
|
||||
close(pout[1]);
|
||||
|
||||
i = 0;
|
||||
args[i++] = ssh_program;
|
||||
args[i++] = "-x";
|
||||
args[i++] = "-oFallBackToRsh no";
|
||||
if (IPv4)
|
||||
args[i++] = "-4";
|
||||
if (IPv6)
|
||||
args[i++] = "-6";
|
||||
if (verbose_mode)
|
||||
args[i++] = "-v";
|
||||
if (compress_flag)
|
||||
args[i++] = "-C";
|
||||
if (batchmode)
|
||||
args[i++] = "-oBatchMode yes";
|
||||
if (cipher != NULL) {
|
||||
args[i++] = "-c";
|
||||
args[i++] = cipher;
|
||||
}
|
||||
if (identity != NULL) {
|
||||
args[i++] = "-i";
|
||||
args[i++] = identity;
|
||||
}
|
||||
if (port != NULL) {
|
||||
args[i++] = "-p";
|
||||
args[i++] = port;
|
||||
}
|
||||
if (remuser != NULL) {
|
||||
args[i++] = "-l";
|
||||
args[i++] = remuser;
|
||||
}
|
||||
args[i++] = host;
|
||||
args[i++] = cmd;
|
||||
args[i++] = NULL;
|
||||
args.list[0] = ssh_program;
|
||||
if (remuser != NULL)
|
||||
addargs("-l %s", remuser);
|
||||
addargs("%s", host);
|
||||
addargs("%s", cmd);
|
||||
|
||||
execvp(ssh_program, args);
|
||||
execvp(ssh_program, args.list);
|
||||
perror(ssh_program);
|
||||
exit(1);
|
||||
}
|
||||
|
@ -290,27 +249,45 @@ main(argc, argv)
|
|||
extern char *optarg;
|
||||
extern int optind;
|
||||
|
||||
args.list = NULL;
|
||||
addargs("ssh"); /* overwritten with ssh_program */
|
||||
addargs("-x");
|
||||
addargs("-oFallBackToRsh no");
|
||||
|
||||
fflag = tflag = 0;
|
||||
while ((ch = getopt(argc, argv, "dfprtvBCc:i:P:q46S:")) != EOF)
|
||||
while ((ch = getopt(argc, argv, "dfprtvBCc:i:P:q46S:o:")) != EOF)
|
||||
switch (ch) {
|
||||
/* User-visible flags. */
|
||||
case '4':
|
||||
IPv4 = 1;
|
||||
break;
|
||||
case '6':
|
||||
IPv6 = 1;
|
||||
case 'C':
|
||||
addargs("-%c", ch);
|
||||
break;
|
||||
case 'o':
|
||||
case 'c':
|
||||
case 'i':
|
||||
addargs("-%c %s", ch, optarg);
|
||||
break;
|
||||
case 'P':
|
||||
addargs("-p %s", optarg);
|
||||
break;
|
||||
case 'B':
|
||||
addargs("-o Batchmode yes");
|
||||
break;
|
||||
case 'p':
|
||||
pflag = 1;
|
||||
break;
|
||||
case 'P':
|
||||
port = optarg;
|
||||
break;
|
||||
case 'r':
|
||||
iamrecursive = 1;
|
||||
break;
|
||||
case 'S':
|
||||
ssh_program = optarg;
|
||||
ssh_program = xstrdup(optarg);
|
||||
break;
|
||||
case 'v':
|
||||
verbose_mode = 1;
|
||||
break;
|
||||
case 'q':
|
||||
showprogress = 0;
|
||||
break;
|
||||
|
||||
/* Server options. */
|
||||
|
@ -325,24 +302,6 @@ main(argc, argv)
|
|||
iamremote = 1;
|
||||
tflag = 1;
|
||||
break;
|
||||
case 'c':
|
||||
cipher = optarg;
|
||||
break;
|
||||
case 'i':
|
||||
identity = optarg;
|
||||
break;
|
||||
case 'v':
|
||||
verbose_mode = 1;
|
||||
break;
|
||||
case 'B':
|
||||
batchmode = 1;
|
||||
break;
|
||||
case 'C':
|
||||
compress_flag = 1;
|
||||
break;
|
||||
case 'q':
|
||||
showprogress = 0;
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
usage();
|
||||
|
@ -1287,3 +1246,25 @@ getttywidth(void)
|
|||
else
|
||||
return (80);
|
||||
}
|
||||
|
||||
void
|
||||
addargs(char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char buf[1024];
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(buf, sizeof(buf), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (args.list == NULL) {
|
||||
args.nalloc = 32;
|
||||
args.num = 0;
|
||||
args.list = xmalloc(args.nalloc * sizeof(char *));
|
||||
} else if (args.num+2 >= args.nalloc) {
|
||||
args.nalloc *= 2;
|
||||
args.list = xrealloc(args.list, args.nalloc * sizeof(char *));
|
||||
}
|
||||
args.list[args.num++] = xstrdup(buf);
|
||||
args.list[args.num] = NULL;
|
||||
}
|
||||
|
|
12
servconf.c
12
servconf.c
|
@ -10,7 +10,7 @@
|
|||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$OpenBSD: servconf.c,v 1.51 2000/09/07 20:27:53 deraadt Exp $");
|
||||
RCSID("$OpenBSD: servconf.c,v 1.52 2000/10/11 20:14:39 markus Exp $");
|
||||
|
||||
#include "ssh.h"
|
||||
#include "servconf.h"
|
||||
|
@ -61,6 +61,7 @@ initialize_server_options(ServerOptions *options)
|
|||
options->afs_token_passing = -1;
|
||||
#endif
|
||||
options->password_authentication = -1;
|
||||
options->kbd_interactive_authentication = -1;
|
||||
#ifdef SKEY
|
||||
options->skey_authentication = -1;
|
||||
#endif
|
||||
|
@ -148,6 +149,8 @@ fill_default_server_options(ServerOptions *options)
|
|||
#endif /* AFS */
|
||||
if (options->password_authentication == -1)
|
||||
options->password_authentication = 1;
|
||||
if (options->kbd_interactive_authentication == -1)
|
||||
options->kbd_interactive_authentication = 0;
|
||||
#ifdef SKEY
|
||||
if (options->skey_authentication == -1)
|
||||
options->skey_authentication = 1;
|
||||
|
@ -183,7 +186,7 @@ typedef enum {
|
|||
#ifdef SKEY
|
||||
sSkeyAuthentication,
|
||||
#endif
|
||||
sPasswordAuthentication, sListenAddress,
|
||||
sPasswordAuthentication, sKbdInteractiveAuthentication, sListenAddress,
|
||||
sPrintMotd, sIgnoreRhosts, sX11Forwarding, sX11DisplayOffset,
|
||||
sStrictModes, sEmptyPasswd, sRandomSeedFile, sKeepAlives, sCheckMail,
|
||||
sUseLogin, sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups,
|
||||
|
@ -220,6 +223,7 @@ static struct {
|
|||
{ "afstokenpassing", sAFSTokenPassing },
|
||||
#endif
|
||||
{ "passwordauthentication", sPasswordAuthentication },
|
||||
{ "kbdinteractiveauthentication", sKbdInteractiveAuthentication },
|
||||
#ifdef SKEY
|
||||
{ "skeyauthentication", sSkeyAuthentication },
|
||||
#endif
|
||||
|
@ -497,6 +501,10 @@ parse_flag:
|
|||
intptr = &options->password_authentication;
|
||||
goto parse_flag;
|
||||
|
||||
case sKbdInteractiveAuthentication:
|
||||
intptr = &options->kbd_interactive_authentication;
|
||||
goto parse_flag;
|
||||
|
||||
case sCheckMail:
|
||||
intptr = &options->check_mail;
|
||||
goto parse_flag;
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
* called by a name other than "ssh" or "Secure Shell".
|
||||
*/
|
||||
|
||||
/* RCSID("$OpenBSD: servconf.h,v 1.28 2000/09/07 20:27:53 deraadt Exp $"); */
|
||||
/* RCSID("$OpenBSD: servconf.h,v 1.29 2000/10/11 20:14:39 markus Exp $"); */
|
||||
|
||||
#ifndef SERVCONF_H
|
||||
#define SERVCONF_H
|
||||
|
@ -78,6 +78,7 @@ typedef struct {
|
|||
#endif
|
||||
int password_authentication; /* If true, permit password
|
||||
* authentication. */
|
||||
int kbd_interactive_authentication; /* If true, permit */
|
||||
#ifdef SKEY
|
||||
int skey_authentication; /* If true, permit s/key
|
||||
* authentication. */
|
||||
|
|
|
@ -33,14 +33,13 @@
|
|||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$OpenBSD: session.c,v 1.37 2000/09/07 20:27:53 deraadt Exp $");
|
||||
RCSID("$OpenBSD: session.c,v 1.38 2000/10/11 20:27:23 markus Exp $");
|
||||
|
||||
#include "xmalloc.h"
|
||||
#include "ssh.h"
|
||||
#include "pty.h"
|
||||
#include "packet.h"
|
||||
#include "buffer.h"
|
||||
#include "cipher.h"
|
||||
#include "mpaux.h"
|
||||
#include "servconf.h"
|
||||
#include "uidswap.h"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
.\" $OpenBSD: sftp-server.8,v 1.2 2000/09/07 20:27:53 deraadt Exp $
|
||||
.\" $OpenBSD: sftp-server.8,v 1.3 2000/10/13 17:20:44 aaron Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
.\"
|
||||
|
|
|
@ -168,8 +168,9 @@ removed once the RSA patent expires.
|
|||
This option will read a private
|
||||
OpenSSH DSA format file and print a SSH2-compatible public key to stdout.
|
||||
.It Fl X
|
||||
This option will read a
|
||||
SSH2-compatible public key file and print an OpenSSH DSA compatible public key to stdout.
|
||||
This option will read a unencrypted
|
||||
SSH2-compatible private (or public) key file and
|
||||
print an OpenSSH compatible private (or public) key to stdout.
|
||||
.It Fl y
|
||||
This option will read a private
|
||||
OpenSSH DSA format file and print an OpenSSH DSA public key to stdout.
|
||||
|
|
105
ssh-keygen.c
105
ssh-keygen.c
|
@ -12,7 +12,7 @@
|
|||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$OpenBSD: ssh-keygen.c,v 1.31 2000/09/07 20:27:54 deraadt Exp $");
|
||||
RCSID("$OpenBSD: ssh-keygen.c,v 1.32 2000/10/09 21:30:44 markus Exp $");
|
||||
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/pem.h>
|
||||
|
@ -27,6 +27,9 @@ RCSID("$OpenBSD: ssh-keygen.c,v 1.31 2000/09/07 20:27:54 deraadt Exp $");
|
|||
#include "authfile.h"
|
||||
#include "uuencode.h"
|
||||
|
||||
#include "buffer.h"
|
||||
#include "bufaux.h"
|
||||
|
||||
/* Number of bits in the RSA/DSA key. This value can be changed on the command line. */
|
||||
int bits = 1024;
|
||||
|
||||
|
@ -108,8 +111,10 @@ try_load_key(char *filename, Key *k)
|
|||
return success;
|
||||
}
|
||||
|
||||
#define SSH_COM_MAGIC_BEGIN "---- BEGIN SSH2 PUBLIC KEY ----"
|
||||
#define SSH_COM_MAGIC_END "---- END SSH2 PUBLIC KEY ----"
|
||||
#define SSH_COM_PUBLIC_BEGIN "---- BEGIN SSH2 PUBLIC KEY ----"
|
||||
#define SSH_COM_PUBLIC_END "---- END SSH2 PUBLIC KEY ----"
|
||||
#define SSH_COM_PRIVATE_BEGIN "---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----"
|
||||
#define SSH_COM_PRIVATE_KEY_MAGIC 0x3f6ff9eb
|
||||
|
||||
void
|
||||
do_convert_to_ssh2(struct passwd *pw)
|
||||
|
@ -131,18 +136,83 @@ do_convert_to_ssh2(struct passwd *pw)
|
|||
exit(1);
|
||||
}
|
||||
dsa_make_key_blob(k, &blob, &len);
|
||||
fprintf(stdout, "%s\n", SSH_COM_MAGIC_BEGIN);
|
||||
fprintf(stdout, "%s\n", SSH_COM_PUBLIC_BEGIN);
|
||||
fprintf(stdout,
|
||||
"Comment: \"%d-bit DSA, converted from openssh by %s@%s\"\n",
|
||||
BN_num_bits(k->dsa->p),
|
||||
"Comment: \"%d-bit %s, converted from OpenSSH by %s@%s\"\n",
|
||||
key_size(k), key_type(k),
|
||||
pw->pw_name, hostname);
|
||||
dump_base64(stdout, blob, len);
|
||||
fprintf(stdout, "%s\n", SSH_COM_MAGIC_END);
|
||||
fprintf(stdout, "%s\n", SSH_COM_PUBLIC_END);
|
||||
key_free(k);
|
||||
xfree(blob);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void
|
||||
buffer_get_bignum_bits(Buffer *b, BIGNUM *value)
|
||||
{
|
||||
int bits = buffer_get_int(b);
|
||||
int bytes = (bits + 7) / 8;
|
||||
if (buffer_len(b) < bytes)
|
||||
fatal("buffer_get_bignum_bits: input buffer too small");
|
||||
BN_bin2bn((unsigned char *)buffer_ptr(b), bytes, value);
|
||||
buffer_consume(b, bytes);
|
||||
}
|
||||
|
||||
Key *
|
||||
do_convert_private_ssh2_from_blob(char *blob, int blen)
|
||||
{
|
||||
Buffer b;
|
||||
DSA *dsa;
|
||||
Key *key = NULL;
|
||||
int ignore, magic, rlen;
|
||||
char *type, *cipher;
|
||||
|
||||
buffer_init(&b);
|
||||
buffer_append(&b, blob, blen);
|
||||
|
||||
magic = buffer_get_int(&b);
|
||||
if (magic != SSH_COM_PRIVATE_KEY_MAGIC) {
|
||||
error("bad magic 0x%x != 0x%x", magic, SSH_COM_PRIVATE_KEY_MAGIC);
|
||||
buffer_free(&b);
|
||||
return NULL;
|
||||
}
|
||||
ignore = buffer_get_int(&b);
|
||||
type = buffer_get_string(&b, NULL);
|
||||
cipher = buffer_get_string(&b, NULL);
|
||||
ignore = buffer_get_int(&b);
|
||||
ignore = buffer_get_int(&b);
|
||||
ignore = buffer_get_int(&b);
|
||||
xfree(type);
|
||||
|
||||
if (strcmp(cipher, "none") != 0) {
|
||||
error("unsupported cipher %s", cipher);
|
||||
xfree(cipher);
|
||||
buffer_free(&b);
|
||||
return NULL;
|
||||
}
|
||||
xfree(cipher);
|
||||
|
||||
key = key_new(KEY_DSA);
|
||||
dsa = key->dsa;
|
||||
dsa->priv_key = BN_new();
|
||||
if (dsa->priv_key == NULL) {
|
||||
error("alloc priv_key failed");
|
||||
key_free(key);
|
||||
return NULL;
|
||||
}
|
||||
buffer_get_bignum_bits(&b, dsa->p);
|
||||
buffer_get_bignum_bits(&b, dsa->g);
|
||||
buffer_get_bignum_bits(&b, dsa->q);
|
||||
buffer_get_bignum_bits(&b, dsa->pub_key);
|
||||
buffer_get_bignum_bits(&b, dsa->priv_key);
|
||||
rlen = buffer_len(&b);
|
||||
if(rlen != 0)
|
||||
error("do_convert_private_ssh2_from_blob: remaining bytes in key blob %d", rlen);
|
||||
buffer_free(&b);
|
||||
return key;
|
||||
}
|
||||
|
||||
void
|
||||
do_convert_from_ssh2(struct passwd *pw)
|
||||
{
|
||||
|
@ -152,7 +222,7 @@ do_convert_from_ssh2(struct passwd *pw)
|
|||
char blob[8096];
|
||||
char encoded[8096];
|
||||
struct stat st;
|
||||
int escaped = 0;
|
||||
int escaped = 0, private = 0, ok;
|
||||
FILE *fp;
|
||||
|
||||
if (!have_identity)
|
||||
|
@ -176,6 +246,8 @@ do_convert_from_ssh2(struct passwd *pw)
|
|||
escaped++;
|
||||
if (strncmp(line, "----", 4) == 0 ||
|
||||
strstr(line, ": ") != NULL) {
|
||||
if (strstr(line, SSH_COM_PRIVATE_BEGIN) != NULL)
|
||||
private = 1;
|
||||
fprintf(stderr, "ignore: %s", line);
|
||||
continue;
|
||||
}
|
||||
|
@ -192,9 +264,20 @@ do_convert_from_ssh2(struct passwd *pw)
|
|||
fprintf(stderr, "uudecode failed.\n");
|
||||
exit(1);
|
||||
}
|
||||
k = dsa_key_from_blob(blob, blen);
|
||||
if (!key_write(k, stdout))
|
||||
fprintf(stderr, "key_write failed");
|
||||
k = private ?
|
||||
do_convert_private_ssh2_from_blob(blob, blen) :
|
||||
dsa_key_from_blob(blob, blen);
|
||||
if (k == NULL) {
|
||||
fprintf(stderr, "decode blob failed.\n");
|
||||
exit(1);
|
||||
}
|
||||
ok = private ?
|
||||
PEM_write_DSAPrivateKey(stdout, k->dsa, NULL, NULL, 0, NULL, NULL) :
|
||||
key_write(k, stdout);
|
||||
if (!ok) {
|
||||
fprintf(stderr, "key write failed");
|
||||
exit(1);
|
||||
}
|
||||
key_free(k);
|
||||
fprintf(stdout, "\n");
|
||||
fclose(fp);
|
||||
|
|
8
ssh.1
8
ssh.1
|
@ -374,8 +374,9 @@ is a fast block cipher, it appears very secure and is much faster than
|
|||
.Ar 3des .
|
||||
.It Fl c Ar "3des-cbc,blowfish-cbc,arcfour,cast128-cbc"
|
||||
Additionally, for protocol version 2 a comma-separated list of ciphers can
|
||||
be specified in order of preference. Protocol version 2 supports
|
||||
3DES, Blowfish and CAST128 in CBC mode and Arcfour.
|
||||
be specified in order of preference.
|
||||
Protocol version 2 supports 3DES, Blowfish, and CAST128 in CBC mode
|
||||
and Arcfour.
|
||||
.It Fl e Ar ch|^ch|none
|
||||
Sets the escape character for sessions with a pty (default:
|
||||
.Ql ~ ) .
|
||||
|
@ -483,7 +484,8 @@ debugging connection, authentication, and configuration problems.
|
|||
The verbose mode is also used to display
|
||||
.Xr skey 1
|
||||
challenges, if the user entered "s/key" as password.
|
||||
Multiple -v options increases the verbosity. Maximum is 3.
|
||||
Multiple -v options increases the verbosity.
|
||||
Maximum is 3.
|
||||
.It Fl x
|
||||
Disables X11 forwarding.
|
||||
.It Fl X
|
||||
|
|
23
ssh.c
23
ssh.c
|
@ -39,7 +39,7 @@
|
|||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$OpenBSD: ssh.c,v 1.66 2000/09/12 20:53:10 markus Exp $");
|
||||
RCSID("$OpenBSD: ssh.c,v 1.68 2000/10/11 20:27:24 markus Exp $");
|
||||
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/dsa.h>
|
||||
|
@ -425,11 +425,12 @@ main(int ac, char **av)
|
|||
options.cipher = SSH_CIPHER_ILLEGAL;
|
||||
} else {
|
||||
/* SSH1 only */
|
||||
options.cipher = cipher_number(optarg);
|
||||
if (options.cipher == -1) {
|
||||
Cipher *c = cipher_by_name(optarg);
|
||||
if (c == NULL || c->number < 0) {
|
||||
fprintf(stderr, "Unknown cipher type '%s'\n", optarg);
|
||||
exit(1);
|
||||
}
|
||||
options.cipher = c->number;
|
||||
}
|
||||
break;
|
||||
case 'p':
|
||||
|
@ -582,22 +583,6 @@ main(int ac, char **av)
|
|||
if (options.hostname != NULL)
|
||||
host = options.hostname;
|
||||
|
||||
/* Find canonic host name. */
|
||||
if (strchr(host, '.') == 0) {
|
||||
struct addrinfo hints;
|
||||
struct addrinfo *ai = NULL;
|
||||
int errgai;
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = IPv4or6;
|
||||
hints.ai_flags = AI_CANONNAME;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
errgai = getaddrinfo(host, NULL, &hints, &ai);
|
||||
if (errgai == 0) {
|
||||
if (ai->ai_canonname != NULL)
|
||||
host = xstrdup(ai->ai_canonname);
|
||||
freeaddrinfo(ai);
|
||||
}
|
||||
}
|
||||
/* Disable rhosts authentication if not running as root. */
|
||||
#ifdef HAVE_CYGWIN
|
||||
/* Ignore uid if running under Windows */
|
||||
|
|
13
ssh.h
13
ssh.h
|
@ -12,7 +12,7 @@
|
|||
* called by a name other than "ssh" or "Secure Shell".
|
||||
*/
|
||||
|
||||
/* RCSID("$OpenBSD: ssh.h,v 1.51 2000/09/12 20:53:10 markus Exp $"); */
|
||||
/* RCSID("$OpenBSD: ssh.h,v 1.54 2000/10/11 20:27:24 markus Exp $"); */
|
||||
|
||||
#ifndef SSH_H
|
||||
#define SSH_H
|
||||
|
@ -28,14 +28,6 @@
|
|||
#include "rsa.h"
|
||||
#include "cipher.h"
|
||||
|
||||
/*
|
||||
* XXX
|
||||
* The default cipher used if IDEA is not supported by the remote host. It is
|
||||
* recommended that this be one of the mandatory ciphers (DES, 3DES), though
|
||||
* that is not required.
|
||||
*/
|
||||
#define SSH_FALLBACK_CIPHER SSH_CIPHER_3DES
|
||||
|
||||
/* Cipher used for encrypting authentication files. */
|
||||
#define SSH_AUTHFILE_CIPHER SSH_CIPHER_3DES
|
||||
|
||||
|
@ -98,6 +90,7 @@
|
|||
#define SERVER_CONFIG_FILE ETCDIR "/sshd_config"
|
||||
#define HOST_CONFIG_FILE ETCDIR "/ssh_config"
|
||||
#define HOST_DSA_KEY_FILE ETCDIR "/ssh_host_dsa_key"
|
||||
#define DH_PRIMES ETCDIR "/primes"
|
||||
|
||||
#ifndef SSH_PROGRAM
|
||||
#define SSH_PROGRAM "/usr/bin/ssh"
|
||||
|
@ -423,7 +416,7 @@ int auth_rsa_challenge_dialog(RSA *pk);
|
|||
* passphrase (allocated with xmalloc). Exits if EOF is encountered. If
|
||||
* from_stdin is true, the passphrase will be read from stdin instead.
|
||||
*/
|
||||
char *read_passphrase(const char *prompt, int from_stdin);
|
||||
char *read_passphrase(char *prompt, int from_stdin);
|
||||
|
||||
|
||||
/*------------ Definitions for logging. -----------------------*/
|
||||
|
|
8
ssh2.h
8
ssh2.h
|
@ -52,7 +52,7 @@
|
|||
*
|
||||
* 192-255 Local extensions
|
||||
*/
|
||||
/* RCSID("$OpenBSD: ssh2.h,v 1.4 2000/09/07 20:27:54 deraadt Exp $"); */
|
||||
/* RCSID("$OpenBSD: ssh2.h,v 1.5 2000/10/11 04:02:17 provos Exp $"); */
|
||||
|
||||
/* transport layer: generic */
|
||||
|
||||
|
@ -73,6 +73,12 @@
|
|||
#define SSH2_MSG_KEXDH_INIT 30
|
||||
#define SSH2_MSG_KEXDH_REPLY 31
|
||||
|
||||
/* dh-group-exchange */
|
||||
#define SSH2_MSG_KEX_DH_GEX_REQUEST 30
|
||||
#define SSH2_MSG_KEX_DH_GEX_GROUP 31
|
||||
#define SSH2_MSG_KEX_DH_GEX_INIT 32
|
||||
#define SSH2_MSG_KEX_DH_GEX_REPLY 33
|
||||
|
||||
/* user authentication: generic */
|
||||
|
||||
#define SSH2_MSG_USERAUTH_REQUEST 50
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$OpenBSD: sshconnect1.c,v 1.6 2000/09/07 20:27:54 deraadt Exp $");
|
||||
RCSID("$OpenBSD: sshconnect1.c,v 1.8 2000/10/12 09:59:19 markus Exp $");
|
||||
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/dsa.h>
|
||||
|
@ -25,7 +25,6 @@ RCSID("$OpenBSD: sshconnect1.c,v 1.6 2000/09/07 20:27:54 deraadt Exp $");
|
|||
#include "ssh.h"
|
||||
#include "buffer.h"
|
||||
#include "packet.h"
|
||||
#include "cipher.h"
|
||||
#include "mpaux.h"
|
||||
#include "uidswap.h"
|
||||
#include "readconf.h"
|
||||
|
@ -836,17 +835,11 @@ ssh_kex(char *host, struct sockaddr *hostaddr)
|
|||
|
||||
if (options.cipher == SSH_CIPHER_ILLEGAL) {
|
||||
log("No valid SSH1 cipher, using %.100s instead.",
|
||||
cipher_name(SSH_FALLBACK_CIPHER));
|
||||
options.cipher = SSH_FALLBACK_CIPHER;
|
||||
cipher_name(ssh_cipher_default));
|
||||
options.cipher = ssh_cipher_default;
|
||||
} else if (options.cipher == SSH_CIPHER_NOT_SET) {
|
||||
if (cipher_mask1() & supported_ciphers & (1 << ssh_cipher_default))
|
||||
if (cipher_mask_ssh1(1) & supported_ciphers & (1 << ssh_cipher_default))
|
||||
options.cipher = ssh_cipher_default;
|
||||
else {
|
||||
debug("Cipher %s not supported, using %.100s instead.",
|
||||
cipher_name(ssh_cipher_default),
|
||||
cipher_name(SSH_FALLBACK_CIPHER));
|
||||
options.cipher = SSH_FALLBACK_CIPHER;
|
||||
}
|
||||
}
|
||||
/* Check that the selected cipher is supported. */
|
||||
if (!(supported_ciphers & (1 << options.cipher)))
|
||||
|
|
467
sshconnect2.c
467
sshconnect2.c
|
@ -23,7 +23,7 @@
|
|||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$OpenBSD: sshconnect2.c,v 1.21 2000/09/27 21:41:34 markus Exp $");
|
||||
RCSID("$OpenBSD: sshconnect2.c,v 1.25 2000/10/12 09:59:19 markus Exp $");
|
||||
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/rsa.h>
|
||||
|
@ -37,7 +37,6 @@ RCSID("$OpenBSD: sshconnect2.c,v 1.21 2000/09/27 21:41:34 markus Exp $");
|
|||
#include "rsa.h"
|
||||
#include "buffer.h"
|
||||
#include "packet.h"
|
||||
#include "cipher.h"
|
||||
#include "uidswap.h"
|
||||
#include "compat.h"
|
||||
#include "readconf.h"
|
||||
|
@ -49,9 +48,13 @@ RCSID("$OpenBSD: sshconnect2.c,v 1.21 2000/09/27 21:41:34 markus Exp $");
|
|||
#include "dsa.h"
|
||||
#include "sshconnect.h"
|
||||
#include "authfile.h"
|
||||
#include "cli.h"
|
||||
#include "dispatch.h"
|
||||
#include "authfd.h"
|
||||
|
||||
void ssh_dh1_client(Kex *, char *, struct sockaddr *, Buffer *, Buffer *);
|
||||
void ssh_dhgex_client(Kex *, char *, struct sockaddr *, Buffer *, Buffer *);
|
||||
|
||||
/* import */
|
||||
extern char *client_version_string;
|
||||
extern char *server_version_string;
|
||||
|
@ -65,8 +68,90 @@ unsigned char *session_id2 = NULL;
|
|||
int session_id2_len = 0;
|
||||
|
||||
void
|
||||
ssh_kex_dh(Kex *kex, char *host, struct sockaddr *hostaddr,
|
||||
Buffer *client_kexinit, Buffer *server_kexinit)
|
||||
ssh_kex2(char *host, struct sockaddr *hostaddr)
|
||||
{
|
||||
int i, plen;
|
||||
Kex *kex;
|
||||
Buffer *client_kexinit, *server_kexinit;
|
||||
char *sprop[PROPOSAL_MAX];
|
||||
|
||||
if (options.ciphers == NULL) {
|
||||
if (options.cipher == SSH_CIPHER_3DES) {
|
||||
options.ciphers = "3des-cbc";
|
||||
} else if (options.cipher == SSH_CIPHER_BLOWFISH) {
|
||||
options.ciphers = "blowfish-cbc";
|
||||
} else if (options.cipher == SSH_CIPHER_DES) {
|
||||
fatal("cipher DES not supported for protocol version 2");
|
||||
}
|
||||
}
|
||||
if (options.ciphers != NULL) {
|
||||
myproposal[PROPOSAL_ENC_ALGS_CTOS] =
|
||||
myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers;
|
||||
}
|
||||
if (options.compression) {
|
||||
myproposal[PROPOSAL_COMP_ALGS_CTOS] = "zlib";
|
||||
myproposal[PROPOSAL_COMP_ALGS_STOC] = "zlib";
|
||||
} else {
|
||||
myproposal[PROPOSAL_COMP_ALGS_CTOS] = "none";
|
||||
myproposal[PROPOSAL_COMP_ALGS_STOC] = "none";
|
||||
}
|
||||
|
||||
/* buffers with raw kexinit messages */
|
||||
server_kexinit = xmalloc(sizeof(*server_kexinit));
|
||||
buffer_init(server_kexinit);
|
||||
client_kexinit = kex_init(myproposal);
|
||||
|
||||
/* algorithm negotiation */
|
||||
kex_exchange_kexinit(client_kexinit, server_kexinit, sprop);
|
||||
kex = kex_choose_conf(myproposal, sprop, 0);
|
||||
for (i = 0; i < PROPOSAL_MAX; i++)
|
||||
xfree(sprop[i]);
|
||||
|
||||
/* server authentication and session key agreement */
|
||||
switch(kex->kex_type) {
|
||||
case DH_GRP1_SHA1:
|
||||
ssh_dh1_client(kex, host, hostaddr,
|
||||
client_kexinit, server_kexinit);
|
||||
break;
|
||||
case DH_GEX_SHA1:
|
||||
ssh_dhgex_client(kex, host, hostaddr, client_kexinit,
|
||||
server_kexinit);
|
||||
break;
|
||||
default:
|
||||
fatal("Unsupported key exchange %d", kex->kex_type);
|
||||
}
|
||||
|
||||
buffer_free(client_kexinit);
|
||||
buffer_free(server_kexinit);
|
||||
xfree(client_kexinit);
|
||||
xfree(server_kexinit);
|
||||
|
||||
debug("Wait SSH2_MSG_NEWKEYS.");
|
||||
packet_read_expect(&plen, SSH2_MSG_NEWKEYS);
|
||||
packet_done();
|
||||
debug("GOT SSH2_MSG_NEWKEYS.");
|
||||
|
||||
debug("send SSH2_MSG_NEWKEYS.");
|
||||
packet_start(SSH2_MSG_NEWKEYS);
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
debug("done: send SSH2_MSG_NEWKEYS.");
|
||||
|
||||
#ifdef DEBUG_KEXDH
|
||||
/* send 1st encrypted/maced/compressed message */
|
||||
packet_start(SSH2_MSG_IGNORE);
|
||||
packet_put_cstring("markus");
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
#endif
|
||||
debug("done: KEX2.");
|
||||
}
|
||||
|
||||
/* diffie-hellman-group1-sha1 */
|
||||
|
||||
void
|
||||
ssh_dh1_client(Kex *kex, char *host, struct sockaddr *hostaddr,
|
||||
Buffer *client_kexinit, Buffer *server_kexinit)
|
||||
{
|
||||
#ifdef DEBUG_KEXDH
|
||||
int i;
|
||||
|
@ -116,7 +201,7 @@ ssh_kex_dh(Kex *kex, char *host, struct sockaddr *hostaddr,
|
|||
fatal("cannot decode server_host_key_blob");
|
||||
|
||||
check_host_key(host, hostaddr, server_host_key,
|
||||
options.user_hostfile2, options.system_hostfile2);
|
||||
options.user_hostfile2, options.system_hostfile2);
|
||||
|
||||
/* DH paramter f, server public DH key */
|
||||
dh_server_pub = BN_new();
|
||||
|
@ -186,72 +271,175 @@ ssh_kex_dh(Kex *kex, char *host, struct sockaddr *hostaddr,
|
|||
memcpy(session_id2, hash, session_id2_len);
|
||||
}
|
||||
|
||||
void
|
||||
ssh_kex2(char *host, struct sockaddr *hostaddr)
|
||||
/* diffie-hellman-group-exchange-sha1 */
|
||||
|
||||
/*
|
||||
* Estimates the group order for a Diffie-Hellman group that has an
|
||||
* attack complexity approximately the same as O(2**bits). Estimate
|
||||
* with: O(exp(1.9223 * (ln q)^(1/3) (ln ln q)^(2/3)))
|
||||
*/
|
||||
|
||||
int
|
||||
dh_estimate(int bits)
|
||||
{
|
||||
int i, plen;
|
||||
Kex *kex;
|
||||
Buffer *client_kexinit, *server_kexinit;
|
||||
char *sprop[PROPOSAL_MAX];
|
||||
|
||||
if (bits < 64)
|
||||
return (512); /* O(2**63) */
|
||||
if (bits < 128)
|
||||
return (1024); /* O(2**86) */
|
||||
if (bits < 192)
|
||||
return (2048); /* O(2**116) */
|
||||
return (4096); /* O(2**156) */
|
||||
}
|
||||
|
||||
if (options.ciphers != NULL) {
|
||||
myproposal[PROPOSAL_ENC_ALGS_CTOS] =
|
||||
myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers;
|
||||
} else if (options.cipher == SSH_CIPHER_3DES) {
|
||||
myproposal[PROPOSAL_ENC_ALGS_CTOS] =
|
||||
myproposal[PROPOSAL_ENC_ALGS_STOC] =
|
||||
(char *) cipher_name(SSH_CIPHER_3DES_CBC);
|
||||
} else if (options.cipher == SSH_CIPHER_BLOWFISH) {
|
||||
myproposal[PROPOSAL_ENC_ALGS_CTOS] =
|
||||
myproposal[PROPOSAL_ENC_ALGS_STOC] =
|
||||
(char *) cipher_name(SSH_CIPHER_BLOWFISH_CBC);
|
||||
}
|
||||
if (options.compression) {
|
||||
myproposal[PROPOSAL_COMP_ALGS_CTOS] = "zlib";
|
||||
myproposal[PROPOSAL_COMP_ALGS_STOC] = "zlib";
|
||||
} else {
|
||||
myproposal[PROPOSAL_COMP_ALGS_CTOS] = "none";
|
||||
myproposal[PROPOSAL_COMP_ALGS_STOC] = "none";
|
||||
}
|
||||
void
|
||||
ssh_dhgex_client(Kex *kex, char *host, struct sockaddr *hostaddr,
|
||||
Buffer *client_kexinit, Buffer *server_kexinit)
|
||||
{
|
||||
#ifdef DEBUG_KEXDH
|
||||
int i;
|
||||
#endif
|
||||
int plen, dlen;
|
||||
unsigned int klen, kout;
|
||||
char *signature = NULL;
|
||||
unsigned int slen, nbits;
|
||||
char *server_host_key_blob = NULL;
|
||||
Key *server_host_key;
|
||||
unsigned int sbloblen;
|
||||
DH *dh;
|
||||
BIGNUM *dh_server_pub = 0;
|
||||
BIGNUM *shared_secret = 0;
|
||||
BIGNUM *p = 0, *g = 0;
|
||||
unsigned char *kbuf;
|
||||
unsigned char *hash;
|
||||
|
||||
/* buffers with raw kexinit messages */
|
||||
server_kexinit = xmalloc(sizeof(*server_kexinit));
|
||||
buffer_init(server_kexinit);
|
||||
client_kexinit = kex_init(myproposal);
|
||||
nbits = dh_estimate(kex->enc[MODE_OUT].cipher->key_len * 8);
|
||||
|
||||
/* algorithm negotiation */
|
||||
kex_exchange_kexinit(client_kexinit, server_kexinit, sprop);
|
||||
kex = kex_choose_conf(myproposal, sprop, 0);
|
||||
for (i = 0; i < PROPOSAL_MAX; i++)
|
||||
xfree(sprop[i]);
|
||||
|
||||
/* server authentication and session key agreement */
|
||||
ssh_kex_dh(kex, host, hostaddr, client_kexinit, server_kexinit);
|
||||
|
||||
buffer_free(client_kexinit);
|
||||
buffer_free(server_kexinit);
|
||||
xfree(client_kexinit);
|
||||
xfree(server_kexinit);
|
||||
|
||||
debug("Wait SSH2_MSG_NEWKEYS.");
|
||||
packet_read_expect(&plen, SSH2_MSG_NEWKEYS);
|
||||
packet_done();
|
||||
debug("GOT SSH2_MSG_NEWKEYS.");
|
||||
|
||||
debug("send SSH2_MSG_NEWKEYS.");
|
||||
packet_start(SSH2_MSG_NEWKEYS);
|
||||
debug("Sending SSH2_MSG_KEX_DH_GEX_REQUEST.");
|
||||
packet_start(SSH2_MSG_KEX_DH_GEX_REQUEST);
|
||||
packet_put_int(nbits);
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
debug("done: send SSH2_MSG_NEWKEYS.");
|
||||
|
||||
#ifdef DEBUG_KEXDH
|
||||
/* send 1st encrypted/maced/compressed message */
|
||||
packet_start(SSH2_MSG_IGNORE);
|
||||
packet_put_cstring("markus");
|
||||
fprintf(stderr, "\nnbits = %d", nbits);
|
||||
#endif
|
||||
|
||||
debug("Wait SSH2_MSG_KEX_DH_GEX_GROUP.");
|
||||
|
||||
packet_read_expect(&plen, SSH2_MSG_KEX_DH_GEX_GROUP);
|
||||
|
||||
debug("Got SSH2_MSG_KEX_DH_GEX_GROUP.");
|
||||
|
||||
if ((p = BN_new()) == NULL)
|
||||
fatal("BN_new");
|
||||
packet_get_bignum2(p, &dlen);
|
||||
if ((g = BN_new()) == NULL)
|
||||
fatal("BN_new");
|
||||
packet_get_bignum2(g, &dlen);
|
||||
if ((dh = dh_new_group(g, p)) == NULL)
|
||||
fatal("dh_new_group");
|
||||
|
||||
#ifdef DEBUG_KEXDH
|
||||
fprintf(stderr, "\np= ");
|
||||
BN_print_fp(stderr, dh->p);
|
||||
fprintf(stderr, "\ng= ");
|
||||
BN_print_fp(stderr, dh->g);
|
||||
fprintf(stderr, "\npub= ");
|
||||
BN_print_fp(stderr, dh->pub_key);
|
||||
fprintf(stderr, "\n");
|
||||
DHparams_print_fp(stderr, dh);
|
||||
#endif
|
||||
|
||||
debug("Sending SSH2_MSG_KEX_DH_GEX_INIT.");
|
||||
/* generate and send 'e', client DH public key */
|
||||
packet_start(SSH2_MSG_KEX_DH_GEX_INIT);
|
||||
packet_put_bignum2(dh->pub_key);
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
|
||||
debug("Wait SSH2_MSG_KEX_DH_GEX_REPLY.");
|
||||
|
||||
packet_read_expect(&plen, SSH2_MSG_KEX_DH_GEX_REPLY);
|
||||
|
||||
debug("Got SSH2_MSG_KEXDH_REPLY.");
|
||||
|
||||
/* key, cert */
|
||||
server_host_key_blob = packet_get_string(&sbloblen);
|
||||
server_host_key = dsa_key_from_blob(server_host_key_blob, sbloblen);
|
||||
if (server_host_key == NULL)
|
||||
fatal("cannot decode server_host_key_blob");
|
||||
|
||||
check_host_key(host, hostaddr, server_host_key,
|
||||
options.user_hostfile2, options.system_hostfile2);
|
||||
|
||||
/* DH paramter f, server public DH key */
|
||||
dh_server_pub = BN_new();
|
||||
if (dh_server_pub == NULL)
|
||||
fatal("dh_server_pub == NULL");
|
||||
packet_get_bignum2(dh_server_pub, &dlen);
|
||||
|
||||
#ifdef DEBUG_KEXDH
|
||||
fprintf(stderr, "\ndh_server_pub= ");
|
||||
BN_print_fp(stderr, dh_server_pub);
|
||||
fprintf(stderr, "\n");
|
||||
debug("bits %d", BN_num_bits(dh_server_pub));
|
||||
#endif
|
||||
debug("done: KEX2.");
|
||||
|
||||
/* signed H */
|
||||
signature = packet_get_string(&slen);
|
||||
packet_done();
|
||||
|
||||
if (!dh_pub_is_valid(dh, dh_server_pub))
|
||||
packet_disconnect("bad server public DH value");
|
||||
|
||||
klen = DH_size(dh);
|
||||
kbuf = xmalloc(klen);
|
||||
kout = DH_compute_key(kbuf, dh_server_pub, dh);
|
||||
#ifdef DEBUG_KEXDH
|
||||
debug("shared secret: len %d/%d", klen, kout);
|
||||
fprintf(stderr, "shared secret == ");
|
||||
for (i = 0; i< kout; i++)
|
||||
fprintf(stderr, "%02x", (kbuf[i])&0xff);
|
||||
fprintf(stderr, "\n");
|
||||
#endif
|
||||
shared_secret = BN_new();
|
||||
|
||||
BN_bin2bn(kbuf, kout, shared_secret);
|
||||
memset(kbuf, 0, klen);
|
||||
xfree(kbuf);
|
||||
|
||||
/* calc and verify H */
|
||||
hash = kex_hash_gex(
|
||||
client_version_string,
|
||||
server_version_string,
|
||||
buffer_ptr(client_kexinit), buffer_len(client_kexinit),
|
||||
buffer_ptr(server_kexinit), buffer_len(server_kexinit),
|
||||
server_host_key_blob, sbloblen,
|
||||
nbits, dh->p, dh->g,
|
||||
dh->pub_key,
|
||||
dh_server_pub,
|
||||
shared_secret
|
||||
);
|
||||
xfree(server_host_key_blob);
|
||||
DH_free(dh);
|
||||
#ifdef DEBUG_KEXDH
|
||||
fprintf(stderr, "hash == ");
|
||||
for (i = 0; i< 20; i++)
|
||||
fprintf(stderr, "%02x", (hash[i])&0xff);
|
||||
fprintf(stderr, "\n");
|
||||
#endif
|
||||
if (dsa_verify(server_host_key, (unsigned char *)signature, slen, hash, 20) != 1)
|
||||
fatal("dsa_verify failed for server_host_key");
|
||||
key_free(server_host_key);
|
||||
|
||||
kex_derive_keys(kex, hash, shared_secret);
|
||||
packet_set_kex(kex);
|
||||
|
||||
/* save session id */
|
||||
session_id2_len = 20;
|
||||
session_id2 = xmalloc(session_id2_len);
|
||||
memcpy(session_id2, hash, session_id2_len);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -270,8 +458,8 @@ struct Authctxt {
|
|||
const char *host;
|
||||
const char *service;
|
||||
AuthenticationConnection *agent;
|
||||
int success;
|
||||
Authmethod *method;
|
||||
int success;
|
||||
};
|
||||
struct Authmethod {
|
||||
char *name; /* string to compare against server's list */
|
||||
|
@ -283,11 +471,16 @@ struct Authmethod {
|
|||
void input_userauth_success(int type, int plen, void *ctxt);
|
||||
void input_userauth_failure(int type, int plen, void *ctxt);
|
||||
void input_userauth_error(int type, int plen, void *ctxt);
|
||||
void input_userauth_info_req(int type, int plen, void *ctxt);
|
||||
|
||||
int userauth_none(Authctxt *authctxt);
|
||||
int userauth_pubkey(Authctxt *authctxt);
|
||||
int userauth_passwd(Authctxt *authctxt);
|
||||
int userauth_kbdint(Authctxt *authctxt);
|
||||
|
||||
void authmethod_clear();
|
||||
Authmethod *authmethod_get(char *auth_list);
|
||||
Authmethod *authmethod_get(char *authlist);
|
||||
Authmethod *authmethod_lookup(const char *name);
|
||||
|
||||
Authmethod authmethods[] = {
|
||||
{"publickey",
|
||||
|
@ -298,6 +491,14 @@ Authmethod authmethods[] = {
|
|||
userauth_passwd,
|
||||
&options.password_authentication,
|
||||
&options.batch_mode},
|
||||
{"keyboard-interactive",
|
||||
userauth_kbdint,
|
||||
&options.kbd_interactive_authentication,
|
||||
&options.batch_mode},
|
||||
{"none",
|
||||
userauth_none,
|
||||
NULL,
|
||||
NULL},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
|
@ -334,17 +535,13 @@ ssh_userauth2(const char *server_user, char *host)
|
|||
authctxt.host = host;
|
||||
authctxt.service = "ssh-connection"; /* service name */
|
||||
authctxt.success = 0;
|
||||
authctxt.method = NULL;
|
||||
authctxt.method = authmethod_lookup("none");
|
||||
if (authctxt.method == NULL)
|
||||
fatal("ssh_userauth2: internal error: cannot send userauth none request");
|
||||
authmethod_clear();
|
||||
|
||||
/* initial userauth request */
|
||||
packet_start(SSH2_MSG_USERAUTH_REQUEST);
|
||||
packet_put_cstring(authctxt.server_user);
|
||||
packet_put_cstring(authctxt.service);
|
||||
packet_put_cstring("none");
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
|
||||
authmethod_clear();
|
||||
userauth_none(&authctxt);
|
||||
|
||||
dispatch_init(&input_userauth_error);
|
||||
dispatch_set(SSH2_MSG_USERAUTH_SUCCESS, &input_userauth_success);
|
||||
|
@ -354,7 +551,7 @@ ssh_userauth2(const char *server_user, char *host)
|
|||
if (authctxt.agent != NULL)
|
||||
ssh_close_authentication_connection(authctxt.agent);
|
||||
|
||||
debug("ssh-userauth2 successfull");
|
||||
debug("ssh-userauth2 successfull: method %s", authctxt.method->name);
|
||||
}
|
||||
void
|
||||
input_userauth_error(int type, int plen, void *ctxt)
|
||||
|
@ -376,12 +573,11 @@ input_userauth_failure(int type, int plen, void *ctxt)
|
|||
Authctxt *authctxt = ctxt;
|
||||
char *authlist = NULL;
|
||||
int partial;
|
||||
int dlen;
|
||||
|
||||
if (authctxt == NULL)
|
||||
fatal("input_userauth_failure: no authentication context");
|
||||
|
||||
authlist = packet_get_string(&dlen);
|
||||
authlist = packet_get_string(NULL);
|
||||
partial = packet_get_char();
|
||||
packet_done();
|
||||
|
||||
|
@ -390,12 +586,12 @@ input_userauth_failure(int type, int plen, void *ctxt)
|
|||
debug("authentications that can continue: %s", authlist);
|
||||
|
||||
for (;;) {
|
||||
/* try old method or get next method */
|
||||
method = authmethod_get(authlist);
|
||||
if (method == NULL)
|
||||
fatal("Unable to find an authentication method");
|
||||
authctxt->method = method;
|
||||
if (method->userauth(authctxt) != 0) {
|
||||
debug2("we sent a packet, wait for reply");
|
||||
debug2("we sent a %s packet, wait for reply", method->name);
|
||||
break;
|
||||
} else {
|
||||
debug2("we did not send a packet, disable method");
|
||||
|
@ -405,6 +601,19 @@ input_userauth_failure(int type, int plen, void *ctxt)
|
|||
xfree(authlist);
|
||||
}
|
||||
|
||||
int
|
||||
userauth_none(Authctxt *authctxt)
|
||||
{
|
||||
/* initial userauth request */
|
||||
packet_start(SSH2_MSG_USERAUTH_REQUEST);
|
||||
packet_put_cstring(authctxt->server_user);
|
||||
packet_put_cstring(authctxt->service);
|
||||
packet_put_cstring(authctxt->method->name);
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
userauth_passwd(Authctxt *authctxt)
|
||||
{
|
||||
|
@ -424,7 +633,7 @@ userauth_passwd(Authctxt *authctxt)
|
|||
packet_start(SSH2_MSG_USERAUTH_REQUEST);
|
||||
packet_put_cstring(authctxt->server_user);
|
||||
packet_put_cstring(authctxt->service);
|
||||
packet_put_cstring("password");
|
||||
packet_put_cstring(authctxt->method->name);
|
||||
packet_put_char(0);
|
||||
packet_put_cstring(password);
|
||||
memset(password, 0, strlen(password));
|
||||
|
@ -442,6 +651,7 @@ sign_and_send_pubkey(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback)
|
|||
int bloblen, slen;
|
||||
int skip = 0;
|
||||
int ret = -1;
|
||||
int have_sig = 1;
|
||||
|
||||
dsa_make_key_blob(k, &blob, &bloblen);
|
||||
|
||||
|
@ -460,8 +670,8 @@ sign_and_send_pubkey(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback)
|
|||
datafellows & SSH_BUG_PUBKEYAUTH ?
|
||||
"ssh-userauth" :
|
||||
authctxt->service);
|
||||
buffer_put_cstring(&b, "publickey");
|
||||
buffer_put_char(&b, 1);
|
||||
buffer_put_cstring(&b, authctxt->method->name);
|
||||
buffer_put_char(&b, have_sig);
|
||||
buffer_put_cstring(&b, KEX_DSS);
|
||||
buffer_put_string(&b, blob, bloblen);
|
||||
|
||||
|
@ -481,8 +691,8 @@ sign_and_send_pubkey(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback)
|
|||
buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
|
||||
buffer_put_cstring(&b, authctxt->server_user);
|
||||
buffer_put_cstring(&b, authctxt->service);
|
||||
buffer_put_cstring(&b, "publickey");
|
||||
buffer_put_char(&b, 1);
|
||||
buffer_put_cstring(&b, authctxt->method->name);
|
||||
buffer_put_char(&b, have_sig);
|
||||
buffer_put_cstring(&b, KEX_DSS);
|
||||
buffer_put_string(&b, blob, bloblen);
|
||||
}
|
||||
|
@ -606,6 +816,92 @@ userauth_pubkey(Authctxt *authctxt)
|
|||
return sent;
|
||||
}
|
||||
|
||||
/*
|
||||
* Send userauth request message specifying keyboard-interactive method.
|
||||
*/
|
||||
int
|
||||
userauth_kbdint(Authctxt *authctxt)
|
||||
{
|
||||
static int attempt = 0;
|
||||
|
||||
if (attempt++ >= options.number_of_password_prompts)
|
||||
return 0;
|
||||
|
||||
debug2("userauth_kbdint");
|
||||
packet_start(SSH2_MSG_USERAUTH_REQUEST);
|
||||
packet_put_cstring(authctxt->server_user);
|
||||
packet_put_cstring(authctxt->service);
|
||||
packet_put_cstring(authctxt->method->name);
|
||||
packet_put_cstring(""); /* lang */
|
||||
packet_put_cstring(options.kbd_interactive_devices ?
|
||||
options.kbd_interactive_devices : "");
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
|
||||
dispatch_set(SSH2_MSG_USERAUTH_INFO_REQUEST, &input_userauth_info_req);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* parse SSH2_MSG_USERAUTH_INFO_REQUEST, prompt user and send
|
||||
* SSH2_MSG_USERAUTH_INFO_RESPONSE
|
||||
*/
|
||||
void
|
||||
input_userauth_info_req(int type, int plen, void *ctxt)
|
||||
{
|
||||
Authctxt *authctxt = ctxt;
|
||||
char *name = NULL;
|
||||
char *inst = NULL;
|
||||
char *lang = NULL;
|
||||
char *prompt = NULL;
|
||||
char *response = NULL;
|
||||
unsigned int num_prompts, i;
|
||||
int echo = 0;
|
||||
|
||||
debug2("input_userauth_info_req");
|
||||
|
||||
if (authctxt == NULL)
|
||||
fatal("input_userauth_info_req: no authentication context");
|
||||
|
||||
name = packet_get_string(NULL);
|
||||
inst = packet_get_string(NULL);
|
||||
lang = packet_get_string(NULL);
|
||||
|
||||
if (strlen(name) > 0)
|
||||
cli_mesg(name);
|
||||
xfree(name);
|
||||
|
||||
if (strlen(inst) > 0)
|
||||
cli_mesg(inst);
|
||||
xfree(inst);
|
||||
xfree(lang); /* unused */
|
||||
|
||||
num_prompts = packet_get_int();
|
||||
/*
|
||||
* Begin to build info response packet based on prompts requested.
|
||||
* We commit to providing the correct number of responses, so if
|
||||
* further on we run into a problem that prevents this, we have to
|
||||
* be sure and clean this up and send a correct error response.
|
||||
*/
|
||||
packet_start(SSH2_MSG_USERAUTH_INFO_RESPONSE);
|
||||
packet_put_int(num_prompts);
|
||||
|
||||
for (i = 0; i < num_prompts; i++) {
|
||||
prompt = packet_get_string(NULL);
|
||||
echo = packet_get_char();
|
||||
|
||||
response = cli_prompt(prompt, echo);
|
||||
|
||||
packet_put_cstring(response);
|
||||
memset(response, 0, strlen(response));
|
||||
xfree(response);
|
||||
xfree(prompt);
|
||||
}
|
||||
packet_done(); /* done with parsing incoming message. */
|
||||
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
}
|
||||
|
||||
/* find auth method */
|
||||
|
||||
|
@ -692,6 +988,7 @@ authmethod_get(char *authlist)
|
|||
|
||||
if (authlist_current == NULL || strcmp(authlist, authlist_current) != 0) {
|
||||
/* start over if passed a different list */
|
||||
debug3("start over, passed a different list");
|
||||
authmethod_clear();
|
||||
authlist_current = xstrdup(authlist);
|
||||
authlist_working = xstrdup(authlist);
|
||||
|
@ -706,16 +1003,20 @@ authmethod_get(char *authlist)
|
|||
}
|
||||
|
||||
while (name != NULL) {
|
||||
debug3("authmethod_lookup %s", name);
|
||||
method = authmethod_lookup(name);
|
||||
if (method != NULL && authmethod_is_enabled(method))
|
||||
if (method != NULL && authmethod_is_enabled(method)) {
|
||||
debug3("authmethod_is_enabled %s", name);
|
||||
break;
|
||||
}
|
||||
name = strtok_r(NULL, DELIM, &authlist_state);
|
||||
method = NULL;
|
||||
}
|
||||
|
||||
if (authname_current != NULL)
|
||||
xfree(authname_current);
|
||||
|
||||
if (name != NULL) {
|
||||
if (method != NULL) {
|
||||
debug("next auth method to try is %s", name);
|
||||
authname_current = xstrdup(name);
|
||||
return method;
|
||||
|
|
16
sshd.8
16
sshd.8
|
@ -186,7 +186,8 @@ The server sends verbose debug output to the system
|
|||
log, and does not put itself in the background.
|
||||
The server also will not fork and will only process one connection.
|
||||
This option is only intended for debugging for the server.
|
||||
Multiple -d options increases the debugging level. Maximum is 3.
|
||||
Multiple -d options increases the debugging level.
|
||||
Maximum is 3.
|
||||
.It Fl f Ar configuration_file
|
||||
Specifies the name of the configuration file.
|
||||
The default is
|
||||
|
@ -255,12 +256,13 @@ file.
|
|||
.It Fl Q
|
||||
Do not print an error message if RSA support is missing.
|
||||
.It Fl V Ar client_protocol_id
|
||||
SSH2 compatibility mode.
|
||||
SSH-2 compatibility mode.
|
||||
When this option is specified
|
||||
.Nm
|
||||
assumes the client has sent the supplied version string
|
||||
and skips the
|
||||
Protocol Version Identification Exchange.
|
||||
This option is not intended to be called directly.
|
||||
.It Fl 4
|
||||
Forces
|
||||
.Nm
|
||||
|
@ -424,7 +426,8 @@ Specifies whether Kerberos authentication is allowed.
|
|||
This can be in the form of a Kerberos ticket, or if
|
||||
.Cm PasswordAuthentication
|
||||
is yes, the password provided by the user will be validated through
|
||||
the Kerberos KDC. To use this option, the server needs a
|
||||
the Kerberos KDC.
|
||||
To use this option, the server needs a
|
||||
Kerberos servtab which allows the verification of the KDC's identity.
|
||||
Default is
|
||||
.Dq yes .
|
||||
|
@ -488,7 +491,7 @@ The default is 10.
|
|||
Alternatively, random early drop can be enabled by specifying
|
||||
the three colon separated values
|
||||
.Dq start:rate:full
|
||||
(e.g. "10:30:60").
|
||||
(e.g., "10:30:60").
|
||||
.Nm
|
||||
will refuse connection attempts with a probabillity of
|
||||
.Dq rate/100
|
||||
|
@ -610,8 +613,9 @@ directory or files world-writable.
|
|||
The default is
|
||||
.Dq yes .
|
||||
.It Cm Subsystem
|
||||
Configures an external subsystem (e.g. file transfer daemon).
|
||||
Arguments should be a subsystem name and a command to execute upon subsystem request.
|
||||
Configures an external subsystem (e.g., file transfer daemon).
|
||||
Arguments should be a subsystem name and a command to execute upon subsystem
|
||||
request.
|
||||
The command
|
||||
.Xr sftp-server 8
|
||||
implements the
|
||||
|
|
227
sshd.c
227
sshd.c
|
@ -40,14 +40,13 @@
|
|||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$OpenBSD: sshd.c,v 1.128 2000/09/17 15:38:59 markus Exp $");
|
||||
RCSID("$OpenBSD: sshd.c,v 1.132 2000/10/13 18:34:46 markus Exp $");
|
||||
|
||||
#include "xmalloc.h"
|
||||
#include "rsa.h"
|
||||
#include "ssh.h"
|
||||
#include "pty.h"
|
||||
#include "packet.h"
|
||||
#include "cipher.h"
|
||||
#include "mpaux.h"
|
||||
#include "servconf.h"
|
||||
#include "uidswap.h"
|
||||
|
@ -63,6 +62,7 @@ RCSID("$OpenBSD: sshd.c,v 1.128 2000/09/17 15:38:59 markus Exp $");
|
|||
#include <openssl/rsa.h>
|
||||
#include "key.h"
|
||||
#include "dsa.h"
|
||||
#include "dh.h"
|
||||
|
||||
#include "auth.h"
|
||||
#include "myproposal.h"
|
||||
|
@ -172,6 +172,9 @@ unsigned int utmp_len = MAXHOSTNAMELEN;
|
|||
void do_ssh1_kex();
|
||||
void do_ssh2_kex();
|
||||
|
||||
void ssh_dh1_server(Kex *, Buffer *_kexinit, Buffer *);
|
||||
void ssh_dhgex_server(Kex *, Buffer *_kexinit, Buffer *);
|
||||
|
||||
/*
|
||||
* Close all listening sockets
|
||||
*/
|
||||
|
@ -333,6 +336,10 @@ sshd_exchange_identification(int sock_in, int sock_out)
|
|||
if (buf[i] == '\r') {
|
||||
buf[i] = '\n';
|
||||
buf[i + 1] = 0;
|
||||
/* Kludge for F-Secure Macintosh < 1.0.2 */
|
||||
if (i == 12 &&
|
||||
strncmp(buf, "SSH-1.5-W1.0", 12) == 0)
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
if (buf[i] == '\n') {
|
||||
|
@ -1151,7 +1158,7 @@ do_ssh1_kex()
|
|||
packet_put_int(SSH_PROTOFLAG_HOST_IN_FWD_OPEN);
|
||||
|
||||
/* Declare which ciphers we support. */
|
||||
packet_put_int(cipher_mask1());
|
||||
packet_put_int(cipher_mask_ssh1(0));
|
||||
|
||||
/* Declare supported authentication types. */
|
||||
auth_mask = 0;
|
||||
|
@ -1192,7 +1199,7 @@ do_ssh1_kex()
|
|||
/* Get cipher type and check whether we accept this. */
|
||||
cipher_type = packet_get_char();
|
||||
|
||||
if (!(cipher_mask() & (1 << cipher_type)))
|
||||
if (!(cipher_mask_ssh1(0) & (1 << cipher_type)))
|
||||
packet_disconnect("Warning: client selects unsupported cipher.");
|
||||
|
||||
/* Get check bytes from the packet. These must match those we
|
||||
|
@ -1296,18 +1303,8 @@ do_ssh2_kex()
|
|||
{
|
||||
Buffer *server_kexinit;
|
||||
Buffer *client_kexinit;
|
||||
int payload_len, dlen;
|
||||
int slen;
|
||||
unsigned int klen, kout;
|
||||
unsigned char *signature = NULL;
|
||||
unsigned char *server_host_key_blob = NULL;
|
||||
unsigned int sbloblen;
|
||||
DH *dh;
|
||||
BIGNUM *dh_client_pub = 0;
|
||||
BIGNUM *shared_secret = 0;
|
||||
int payload_len;
|
||||
int i;
|
||||
unsigned char *kbuf;
|
||||
unsigned char *hash;
|
||||
Kex *kex;
|
||||
char *cprop[PROPOSAL_MAX];
|
||||
|
||||
|
@ -1327,8 +1324,63 @@ do_ssh2_kex()
|
|||
for (i = 0; i < PROPOSAL_MAX; i++)
|
||||
xfree(cprop[i]);
|
||||
|
||||
/* KEXDH */
|
||||
switch (kex->kex_type) {
|
||||
case DH_GRP1_SHA1:
|
||||
ssh_dh1_server(kex, client_kexinit, server_kexinit);
|
||||
break;
|
||||
case DH_GEX_SHA1:
|
||||
ssh_dhgex_server(kex, client_kexinit, server_kexinit);
|
||||
break;
|
||||
default:
|
||||
fatal("Unsupported key exchange %d", kex->kex_type);
|
||||
}
|
||||
|
||||
debug("send SSH2_MSG_NEWKEYS.");
|
||||
packet_start(SSH2_MSG_NEWKEYS);
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
debug("done: send SSH2_MSG_NEWKEYS.");
|
||||
|
||||
debug("Wait SSH2_MSG_NEWKEYS.");
|
||||
packet_read_expect(&payload_len, SSH2_MSG_NEWKEYS);
|
||||
debug("GOT SSH2_MSG_NEWKEYS.");
|
||||
|
||||
#ifdef DEBUG_KEXDH
|
||||
/* send 1st encrypted/maced/compressed message */
|
||||
packet_start(SSH2_MSG_IGNORE);
|
||||
packet_put_cstring("markus");
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
#endif
|
||||
|
||||
debug("done: KEX2.");
|
||||
}
|
||||
|
||||
/*
|
||||
* SSH2 key exchange
|
||||
*/
|
||||
|
||||
/* diffie-hellman-group1-sha1 */
|
||||
|
||||
void
|
||||
ssh_dh1_server(Kex *kex, Buffer *client_kexinit, Buffer *server_kexinit)
|
||||
{
|
||||
#ifdef DEBUG_KEXDH
|
||||
int i;
|
||||
#endif
|
||||
int payload_len, dlen;
|
||||
int slen;
|
||||
unsigned char *signature = NULL;
|
||||
unsigned char *server_host_key_blob = NULL;
|
||||
unsigned int sbloblen;
|
||||
unsigned int klen, kout;
|
||||
unsigned char *kbuf;
|
||||
unsigned char *hash;
|
||||
BIGNUM *shared_secret = 0;
|
||||
DH *dh;
|
||||
BIGNUM *dh_client_pub = 0;
|
||||
|
||||
/* KEXDH */
|
||||
debug("Wait SSH2_MSG_KEXDH_INIT.");
|
||||
packet_read_expect(&payload_len, SSH2_MSG_KEXDH_INIT);
|
||||
|
||||
|
@ -1379,7 +1431,8 @@ do_ssh2_kex()
|
|||
xfree(kbuf);
|
||||
|
||||
/* XXX precompute? */
|
||||
dsa_make_key_blob(sensitive_data.dsa_host_key, &server_host_key_blob, &sbloblen);
|
||||
dsa_make_key_blob(sensitive_data.dsa_host_key,
|
||||
&server_host_key_blob, &sbloblen);
|
||||
|
||||
/* calc H */ /* XXX depends on 'kex' */
|
||||
hash = kex_hash(
|
||||
|
@ -1429,23 +1482,139 @@ do_ssh2_kex()
|
|||
|
||||
/* have keys, free DH */
|
||||
DH_free(dh);
|
||||
}
|
||||
|
||||
debug("send SSH2_MSG_NEWKEYS.");
|
||||
packet_start(SSH2_MSG_NEWKEYS);
|
||||
/* diffie-hellman-group-exchange-sha1 */
|
||||
|
||||
void
|
||||
ssh_dhgex_server(Kex *kex, Buffer *client_kexinit, Buffer *server_kexinit)
|
||||
{
|
||||
#ifdef DEBUG_KEXDH
|
||||
int i;
|
||||
#endif
|
||||
int payload_len, dlen;
|
||||
int slen, nbits;
|
||||
unsigned char *signature = NULL;
|
||||
unsigned char *server_host_key_blob = NULL;
|
||||
unsigned int sbloblen;
|
||||
unsigned int klen, kout;
|
||||
unsigned char *kbuf;
|
||||
unsigned char *hash;
|
||||
BIGNUM *shared_secret = 0;
|
||||
DH *dh;
|
||||
BIGNUM *dh_client_pub = 0;
|
||||
|
||||
/* KEXDHGEX */
|
||||
debug("Wait SSH2_MSG_KEX_DH_GEX_REQUEST.");
|
||||
packet_read_expect(&payload_len, SSH2_MSG_KEX_DH_GEX_REQUEST);
|
||||
nbits = packet_get_int();
|
||||
dh = choose_dh(nbits);
|
||||
|
||||
debug("Sending SSH2_MSG_KEX_DH_GEX_GROUP.");
|
||||
packet_start(SSH2_MSG_KEX_DH_GEX_GROUP);
|
||||
packet_put_bignum2(dh->p);
|
||||
packet_put_bignum2(dh->g);
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
debug("done: send SSH2_MSG_NEWKEYS.");
|
||||
|
||||
debug("Wait SSH2_MSG_NEWKEYS.");
|
||||
packet_read_expect(&payload_len, SSH2_MSG_NEWKEYS);
|
||||
debug("GOT SSH2_MSG_NEWKEYS.");
|
||||
debug("Wait SSH2_MSG_KEX_DH_GEX_INIT.");
|
||||
packet_read_expect(&payload_len, SSH2_MSG_KEX_DH_GEX_INIT);
|
||||
|
||||
/* key, cert */
|
||||
dh_client_pub = BN_new();
|
||||
if (dh_client_pub == NULL)
|
||||
fatal("dh_client_pub == NULL");
|
||||
packet_get_bignum2(dh_client_pub, &dlen);
|
||||
|
||||
#ifdef DEBUG_KEXDH
|
||||
/* send 1st encrypted/maced/compressed message */
|
||||
packet_start(SSH2_MSG_IGNORE);
|
||||
packet_put_cstring("markus");
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
fprintf(stderr, "\ndh_client_pub= ");
|
||||
BN_print_fp(stderr, dh_client_pub);
|
||||
fprintf(stderr, "\n");
|
||||
debug("bits %d", BN_num_bits(dh_client_pub));
|
||||
#endif
|
||||
debug("done: KEX2.");
|
||||
|
||||
#ifdef DEBUG_KEXDH
|
||||
fprintf(stderr, "\np= ");
|
||||
BN_print_fp(stderr, dh->p);
|
||||
fprintf(stderr, "\ng= ");
|
||||
bn_print(dh->g);
|
||||
fprintf(stderr, "\npub= ");
|
||||
BN_print_fp(stderr, dh->pub_key);
|
||||
fprintf(stderr, "\n");
|
||||
DHparams_print_fp(stderr, dh);
|
||||
#endif
|
||||
if (!dh_pub_is_valid(dh, dh_client_pub))
|
||||
packet_disconnect("bad client public DH value");
|
||||
|
||||
klen = DH_size(dh);
|
||||
kbuf = xmalloc(klen);
|
||||
kout = DH_compute_key(kbuf, dh_client_pub, dh);
|
||||
|
||||
#ifdef DEBUG_KEXDH
|
||||
debug("shared secret: len %d/%d", klen, kout);
|
||||
fprintf(stderr, "shared secret == ");
|
||||
for (i = 0; i< kout; i++)
|
||||
fprintf(stderr, "%02x", (kbuf[i])&0xff);
|
||||
fprintf(stderr, "\n");
|
||||
#endif
|
||||
shared_secret = BN_new();
|
||||
|
||||
BN_bin2bn(kbuf, kout, shared_secret);
|
||||
memset(kbuf, 0, klen);
|
||||
xfree(kbuf);
|
||||
|
||||
/* XXX precompute? */
|
||||
dsa_make_key_blob(sensitive_data.dsa_host_key,
|
||||
&server_host_key_blob, &sbloblen);
|
||||
|
||||
/* calc H */ /* XXX depends on 'kex' */
|
||||
hash = kex_hash_gex(
|
||||
client_version_string,
|
||||
server_version_string,
|
||||
buffer_ptr(client_kexinit), buffer_len(client_kexinit),
|
||||
buffer_ptr(server_kexinit), buffer_len(server_kexinit),
|
||||
(char *)server_host_key_blob, sbloblen,
|
||||
nbits, dh->p, dh->g,
|
||||
dh_client_pub,
|
||||
dh->pub_key,
|
||||
shared_secret
|
||||
);
|
||||
buffer_free(client_kexinit);
|
||||
buffer_free(server_kexinit);
|
||||
xfree(client_kexinit);
|
||||
xfree(server_kexinit);
|
||||
#ifdef DEBUG_KEXDH
|
||||
fprintf(stderr, "hash == ");
|
||||
for (i = 0; i< 20; i++)
|
||||
fprintf(stderr, "%02x", (hash[i])&0xff);
|
||||
fprintf(stderr, "\n");
|
||||
#endif
|
||||
/* save session id := H */
|
||||
/* XXX hashlen depends on KEX */
|
||||
session_id2_len = 20;
|
||||
session_id2 = xmalloc(session_id2_len);
|
||||
memcpy(session_id2, hash, session_id2_len);
|
||||
|
||||
/* sign H */
|
||||
/* XXX hashlen depends on KEX */
|
||||
dsa_sign(sensitive_data.dsa_host_key, &signature, &slen, hash, 20);
|
||||
|
||||
destroy_sensitive_data();
|
||||
|
||||
/* send server hostkey, DH pubkey 'f' and singed H */
|
||||
packet_start(SSH2_MSG_KEX_DH_GEX_REPLY);
|
||||
packet_put_string((char *)server_host_key_blob, sbloblen);
|
||||
packet_put_bignum2(dh->pub_key); /* f */
|
||||
packet_put_string((char *)signature, slen);
|
||||
packet_send();
|
||||
xfree(signature);
|
||||
xfree(server_host_key_blob);
|
||||
packet_write_wait();
|
||||
|
||||
kex_derive_keys(kex, hash, shared_secret);
|
||||
packet_set_kex(kex);
|
||||
|
||||
/* have keys, free DH */
|
||||
DH_free(dh);
|
||||
}
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@ PasswordAuthentication yes
|
|||
PermitEmptyPasswords no
|
||||
# Uncomment to disable s/key passwords
|
||||
#SkeyAuthentication no
|
||||
#KbdInteractiveAuthentication yes
|
||||
|
||||
# To change Kerberos options
|
||||
#KerberosAuthentication no
|
||||
|
|
Загрузка…
Ссылка в новой задаче