Source snapshot from Powershell/openssh-portable:latestw_all

This commit is contained in:
Yanbing Wang 2017-12-04 16:12:20 -08:00
parent d6ce465b15
commit 1ad6c956cc
14 changed files with 31 additions and 1098 deletions

View File

@ -1,4 +1,4 @@
version: 0.0.23.0.{build}
version: 0.0.24.0.{build}
image: Visual Studio 2015
branches:

View File

@ -337,7 +337,7 @@ function Install-OpenSSHTestDependencies
if (-not ($isModuleAvailable))
{
Write-Log -Message "Installing Pester..."
choco install Pester -y --force --limitoutput 2>&1 >> $Script:TestSetupLogFile
choco install Pester --version 3.4.6 -y --force --limitoutput 2>&1 >> $Script:TestSetupLogFile
}
if($Script:PostmortemDebugging -or (($OpenSSHTestInfo -ne $null) -and ($OpenSSHTestInfo["PostmortemDebugging"])))

View File

@ -264,10 +264,10 @@ if (Get-Service ssh-agent -ErrorAction SilentlyContinue)
sc.exe delete ssh-agent 1>$null
}
New-Service -Name ssh-agent -BinaryPathName $sshagentpath -Description "SSH Agent" -StartupType Manual | Out-Null
New-Service -Name ssh-agent -BinaryPathName `"$sshagentpath`" -Description "SSH Agent" -StartupType Manual | Out-Null
cmd.exe /c 'sc.exe sdset ssh-agent D:(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWLOCRRC;;;IU)(A;;CCLCSWLOCRRC;;;SU)(A;;RP;;;AU)'
New-Service -Name sshd -BinaryPathName $sshdpath -Description "SSH Daemon" -StartupType Manual -DependsOn ssh-agent | Out-Null
New-Service -Name sshd -BinaryPathName `"$sshdpath`" -Description "SSH Daemon" -StartupType Manual -DependsOn ssh-agent | Out-Null
sc.exe config sshd obj= $sshdAccount
sc.exe privs sshd SeAssignPrimaryTokenPrivilege

Binary file not shown.

View File

@ -811,7 +811,7 @@ cleanup:
}
long
fileio_lseek(struct w32_io* pio, long offset, int origin)
fileio_lseek(struct w32_io* pio, unsigned __int64 offset, int origin)
{
debug4("lseek - pio:%p", pio);
if (origin != SEEK_SET) {
@ -820,8 +820,9 @@ fileio_lseek(struct w32_io* pio, long offset, int origin)
return -1;
}
pio->read_overlapped.Offset = offset;
pio->write_overlapped.Offset = offset;
pio->write_overlapped.Offset = pio->read_overlapped.Offset = offset & 0xffffffff;
pio->write_overlapped.OffsetHigh = pio->read_overlapped.OffsetHigh = (offset & 0xffffffff00000000) >> 32;
return 0;
}

View File

@ -46,7 +46,7 @@ int w32_dup2(int oldfd, int newfd);
unsigned int w32_alarm(unsigned int seconds);
#define alarm w32_alarm
long w32_lseek(int fd, long offset, int origin);
long w32_lseek(int fd, unsigned __int64 offset, int origin);
#define lseek w32_lseek
#define getdtablesize() MAX_FDS

View File

@ -43,6 +43,7 @@ LogonUserExExWHelper(wchar_t *user_name, wchar_t *domain, wchar_t *password, DWO
PVOID *profile_buffer, LPDWORD profile_length, PQUOTA_LIMITS quota_limits)
{
wchar_t sspicli_dll_path[MAX_PATH + 1] = { 0, };
wchar_t advapi32_dll_path[MAX_PATH + 1] = { 0, };
wchar_t system32_path[MAX_PATH + 1] = { 0, };
if (!GetSystemDirectoryW(system32_path, _countof(system32_path))) {
@ -51,14 +52,23 @@ LogonUserExExWHelper(wchar_t *user_name, wchar_t *domain, wchar_t *password, DWO
}
wcsncpy_s(sspicli_dll_path, _countof(sspicli_dll_path), system32_path, wcsnlen(system32_path, _countof(system32_path)) + 1);
wcscat_s(sspicli_dll_path, _countof(sspicli_dll_path), L"\\sspicli.dll");
if (hMod == NULL)
hMod = LoadLibraryW(sspicli_dll_path);
wcsncpy_s(advapi32_dll_path, _countof(advapi32_dll_path), system32_path, wcsnlen(system32_path, _countof(system32_path)) + 1);
wcscat_s(advapi32_dll_path, _countof(advapi32_dll_path), L"\\advapi32.dll");
if (hMod == NULL) {
hMod = LoadLibraryW(sspicli_dll_path);
if (hMod == NULL)
debug3("Failed to retrieve the module handle of sspicli.dll with error %d", GetLastError());
}
if (hMod == NULL)
hMod = LoadLibraryW(advapi32_dll_path);
if (hMod == NULL) {
debug3("Failed to retrieve the module handle of advapi32.dll with error %d", GetLastError());
return FALSE;
}
if (func == NULL)
func = (LogonUserExExWType)GetProcAddress(hMod, "LogonUserExExW");

View File

@ -484,7 +484,7 @@ w32_fstat(int fd, struct w32_stat *buf)
}
long
w32_lseek(int fd, long offset, int origin)
w32_lseek(int fd, unsigned __int64 offset, int origin)
{
CHECK_FD(fd);
return fileio_lseek(fd_table.w32_ios[fd], offset, origin);

View File

@ -163,5 +163,5 @@ int fileio_read(struct w32_io* pio, void *dst, size_t max);
int fileio_write(struct w32_io* pio, const void *buf, size_t max);
int fileio_fstat(struct w32_io* pio, struct _stat64 *buf);
int fileio_stat(const char *path, struct _stat64 *buf);
long fileio_lseek(struct w32_io* pio, long offset, int origin);
long fileio_lseek(struct w32_io* pio, unsigned __int64 offset, int origin);
FILE* fileio_fdopen(struct w32_io* pio, const char *mode);

View File

@ -124,13 +124,14 @@ int sshd_main(int argc, wchar_t **wargv) {
}
int wmain(int argc, wchar_t **wargv) {
if (!StartServiceCtrlDispatcherW(dispatch_table)) {
if (GetLastError() != ERROR_FAILED_SERVICE_CONTROLLER_CONNECT)
if (GetLastError() == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT)
return sshd_main(argc, wargv); /* sshd running NOT as service*/
else
return -1;
}
return sshd_main(argc, wargv);
return 0;
}
int scm_start_service(DWORD num, LPWSTR* args) {

188
rsa.c
View File

@ -1,188 +0,0 @@
/* $OpenBSD: rsa.c,v 1.32 2014/06/24 01:13:21 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
*
* As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* 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) 1999 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.
*
*
* Description of the RSA algorithm can be found e.g. from the following
* sources:
*
* Bruce Schneier: Applied Cryptography. John Wiley & Sons, 1994.
*
* Jennifer Seberry and Josed Pieprzyk: Cryptography: An Introduction to
* Computer Security. Prentice-Hall, 1989.
*
* Man Young Rhee: Cryptography and Secure Data Communications. McGraw-Hill,
* 1994.
*
* R. Rivest, A. Shamir, and L. M. Adleman: Cryptographic Communications
* System and Method. US Patent 4,405,829, 1983.
*
* Hans Riesel: Prime Numbers and Computer Methods for Factorization.
* Birkhauser, 1994.
*
* The RSA Frequently Asked Questions document by RSA Data Security,
* Inc., 1995.
*
* RSA in 3 lines of perl by Adam Back <aba@atlax.ex.ac.uk>, 1995, as
* included below:
*
* [gone - had to be deleted - what a pity]
*/
#include "includes.h"
#include <sys/types.h>
#include <stdarg.h>
#include <string.h>
#include "rsa.h"
#include "log.h"
#include "ssherr.h"
int
rsa_public_encrypt(BIGNUM *out, BIGNUM *in, RSA *key)
{
u_char *inbuf = NULL, *outbuf = NULL;
int len, ilen, olen, r = SSH_ERR_INTERNAL_ERROR;
if (BN_num_bits(key->e) < 2 || !BN_is_odd(key->e))
return SSH_ERR_INVALID_ARGUMENT;
olen = BN_num_bytes(key->n);
if ((outbuf = malloc(olen)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
ilen = BN_num_bytes(in);
if ((inbuf = malloc(ilen)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
BN_bn2bin(in, inbuf);
if ((len = RSA_public_encrypt(ilen, inbuf, outbuf, key,
RSA_PKCS1_PADDING)) <= 0) {
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
if (BN_bin2bn(outbuf, len, out) == NULL) {
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
r = 0;
out:
if (outbuf != NULL) {
explicit_bzero(outbuf, olen);
free(outbuf);
}
if (inbuf != NULL) {
explicit_bzero(inbuf, ilen);
free(inbuf);
}
return r;
}
int
rsa_private_decrypt(BIGNUM *out, BIGNUM *in, RSA *key)
{
u_char *inbuf = NULL, *outbuf = NULL;
int len, ilen, olen, r = SSH_ERR_INTERNAL_ERROR;
olen = BN_num_bytes(key->n);
if ((outbuf = malloc(olen)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
ilen = BN_num_bytes(in);
if ((inbuf = malloc(ilen)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
BN_bn2bin(in, inbuf);
if ((len = RSA_private_decrypt(ilen, inbuf, outbuf, key,
RSA_PKCS1_PADDING)) <= 0) {
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
} else if (BN_bin2bn(outbuf, len, out) == NULL) {
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
r = 0;
out:
if (outbuf != NULL) {
explicit_bzero(outbuf, olen);
free(outbuf);
}
if (inbuf != NULL) {
explicit_bzero(inbuf, ilen);
free(inbuf);
}
return r;
}
/* calculate p-1 and q-1 */
int
rsa_generate_additional_parameters(RSA *rsa)
{
BIGNUM *aux = NULL;
BN_CTX *ctx = NULL;
int r;
if ((ctx = BN_CTX_new()) == NULL)
return SSH_ERR_ALLOC_FAIL;
if ((aux = BN_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if ((BN_sub(aux, rsa->q, BN_value_one()) == 0) ||
(BN_mod(rsa->dmq1, rsa->d, aux, ctx) == 0) ||
(BN_sub(aux, rsa->p, BN_value_one()) == 0) ||
(BN_mod(rsa->dmp1, rsa->d, aux, ctx) == 0)) {
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
r = 0;
out:
BN_clear_free(aux);
BN_CTX_free(ctx);
return r;
}

26
rsa.h
View File

@ -1,26 +0,0 @@
/* $OpenBSD: rsa.h,v 1.17 2014/06/24 01:13:21 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
* RSA key generation, encryption and decryption.
*
* As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* 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".
*/
#ifndef RSA_H
#define RSA_H
#include <openssl/bn.h>
#include <openssl/rsa.h>
int rsa_public_encrypt(BIGNUM *, BIGNUM *, RSA *);
int rsa_private_decrypt(BIGNUM *, BIGNUM *, RSA *);
int rsa_generate_additional_parameters(RSA *);
#endif /* RSA_H */

91
ssh1.h
View File

@ -1,91 +0,0 @@
/* $OpenBSD: ssh1.h,v 1.7 2016/05/04 14:22:33 markus Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
*
* As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* 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".
*/
/*
* Definition of message types. New values can be added, but old values
* should not be removed or without careful consideration of the consequences
* for compatibility. The maximum value is 254; value 255 is reserved for
* future extension.
*/
/* Ranges */
#define SSH_MSG_MIN 1
#define SSH_MSG_MAX 254
/* Message name */ /* msg code */ /* arguments */
#define SSH_MSG_DISCONNECT 1 /* cause (string) */
#define SSH_SMSG_PUBLIC_KEY 2 /* ck,msk,srvk,hostk */
#define SSH_CMSG_SESSION_KEY 3 /* key (BIGNUM) */
#define SSH_CMSG_USER 4 /* user (string) */
#define SSH_CMSG_AUTH_RHOSTS 5 /* user (string) */
#define SSH_CMSG_AUTH_RSA 6 /* modulus (BIGNUM) */
#define SSH_SMSG_AUTH_RSA_CHALLENGE 7 /* int (BIGNUM) */
#define SSH_CMSG_AUTH_RSA_RESPONSE 8 /* int (BIGNUM) */
#define SSH_CMSG_AUTH_PASSWORD 9 /* pass (string) */
#define SSH_CMSG_REQUEST_PTY 10 /* TERM, tty modes */
#define SSH_CMSG_WINDOW_SIZE 11 /* row,col,xpix,ypix */
#define SSH_CMSG_EXEC_SHELL 12 /* */
#define SSH_CMSG_EXEC_CMD 13 /* cmd (string) */
#define SSH_SMSG_SUCCESS 14 /* */
#define SSH_SMSG_FAILURE 15 /* */
#define SSH_CMSG_STDIN_DATA 16 /* data (string) */
#define SSH_SMSG_STDOUT_DATA 17 /* data (string) */
#define SSH_SMSG_STDERR_DATA 18 /* data (string) */
#define SSH_CMSG_EOF 19 /* */
#define SSH_SMSG_EXITSTATUS 20 /* status (int) */
#define SSH_MSG_CHANNEL_OPEN_CONFIRMATION 21 /* channel (int) */
#define SSH_MSG_CHANNEL_OPEN_FAILURE 22 /* channel (int) */
#define SSH_MSG_CHANNEL_DATA 23 /* ch,data (int,str) */
#define SSH_MSG_CHANNEL_CLOSE 24 /* channel (int) */
#define SSH_MSG_CHANNEL_CLOSE_CONFIRMATION 25 /* channel (int) */
/* SSH_CMSG_X11_REQUEST_FORWARDING 26 OBSOLETE */
#define SSH_SMSG_X11_OPEN 27 /* channel (int) */
#define SSH_CMSG_PORT_FORWARD_REQUEST 28 /* p,host,hp (i,s,i) */
#define SSH_MSG_PORT_OPEN 29 /* ch,h,p (i,s,i) */
#define SSH_CMSG_AGENT_REQUEST_FORWARDING 30 /* */
#define SSH_SMSG_AGENT_OPEN 31 /* port (int) */
#define SSH_MSG_IGNORE 32 /* string */
#define SSH_CMSG_EXIT_CONFIRMATION 33 /* */
#define SSH_CMSG_X11_REQUEST_FORWARDING 34 /* proto,data (s,s) */
#define SSH_CMSG_AUTH_RHOSTS_RSA 35 /* user,mod (s,mpi) */
#define SSH_MSG_DEBUG 36 /* string */
#define SSH_CMSG_REQUEST_COMPRESSION 37 /* level 1-9 (int) */
#define SSH_CMSG_MAX_PACKET_SIZE 38 /* size 4k-1024k (int) */
#define SSH_CMSG_AUTH_TIS 39 /* we use this for s/key */
#define SSH_SMSG_AUTH_TIS_CHALLENGE 40 /* challenge (string) */
#define SSH_CMSG_AUTH_TIS_RESPONSE 41 /* response (string) */
#define SSH_CMSG_AUTH_KERBEROS 42 /* (KTEXT) */
#define SSH_SMSG_AUTH_KERBEROS_RESPONSE 43 /* (KTEXT) */
#define SSH_CMSG_HAVE_KERBEROS_TGT 44 /* credentials (s) */
#define SSH_CMSG_HAVE_AFS_TOKEN 65 /* token (s) */
/* protocol version 1.5 overloads some version 1.3 message types */
#define SSH_MSG_CHANNEL_INPUT_EOF SSH_MSG_CHANNEL_CLOSE
#define SSH_MSG_CHANNEL_OUTPUT_CLOSE SSH_MSG_CHANNEL_CLOSE_CONFIRMATION
/*
* Authentication methods. New types can be added, but old types should not
* be removed for compatibility. The maximum allowed value is 31.
*/
#define SSH_AUTH_RHOSTS 1
#define SSH_AUTH_RSA 2
#define SSH_AUTH_PASSWORD 3
#define SSH_AUTH_RHOSTS_RSA 4
#define SSH_AUTH_TIS 5
#define SSH_AUTH_KERBEROS 6
#define SSH_PASS_KERBEROS_TGT 7
/* 8 to 15 are reserved */
#define SSH_PASS_AFS_TOKEN 21
/* Protocol flags. These are bit masks. */
#define SSH_PROTOFLAG_SCREEN_NUMBER 1 /* X11 forwarding includes screen */
#define SSH_PROTOFLAG_HOST_IN_FWD_OPEN 2 /* forwarding opens contain host */

View File

@ -1,774 +0,0 @@
/* $OpenBSD: sshconnect1.c,v 1.80 2017/03/10 03:53:11 dtucker Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
* Code to connect to a remote host, and to perform the client side of the
* login (authentication) dialog.
*
* As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* 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".
*/
#include "includes.h"
#ifdef WITH_SSH1
#include <sys/types.h>
#include <sys/socket.h>
#include <openssl/bn.h>
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <pwd.h>
#include "xmalloc.h"
#include "ssh.h"
#include "ssh1.h"
#include "rsa.h"
#include "buffer.h"
#include "packet.h"
#include "key.h"
#include "cipher.h"
#include "kex.h"
#include "uidswap.h"
#include "log.h"
#include "misc.h"
#include "readconf.h"
#include "authfd.h"
#include "sshconnect.h"
#include "authfile.h"
#include "canohost.h"
#include "hostfile.h"
#include "auth.h"
#include "digest.h"
#include "ssherr.h"
/* Session id for the current session. */
u_char session_id[16];
u_int supported_authentications = 0;
extern Options options;
extern char *__progname;
/*
* Checks if the user has an authentication agent, and if so, tries to
* authenticate using the agent.
*/
static int
try_agent_authentication(void)
{
int r, type, agent_fd, ret = 0;
u_char response[16];
size_t i;
BIGNUM *challenge;
struct ssh_identitylist *idlist = NULL;
/* Get connection to the agent. */
if ((r = ssh_get_authentication_socket(&agent_fd)) != 0) {
if (r != SSH_ERR_AGENT_NOT_PRESENT)
debug("%s: ssh_get_authentication_socket: %s",
__func__, ssh_err(r));
return 0;
}
if ((challenge = BN_new()) == NULL)
fatal("try_agent_authentication: BN_new failed");
/* Loop through identities served by the agent. */
if ((r = ssh_fetch_identitylist(agent_fd, 1, &idlist)) != 0) {
if (r != SSH_ERR_AGENT_NO_IDENTITIES)
debug("%s: ssh_fetch_identitylist: %s",
__func__, ssh_err(r));
goto out;
}
for (i = 0; i < idlist->nkeys; i++) {
/* Try this identity. */
debug("Trying RSA authentication via agent with '%.100s'",
idlist->comments[i]);
/* Tell the server that we are willing to authenticate using this key. */
packet_start(SSH_CMSG_AUTH_RSA);
packet_put_bignum(idlist->keys[i]->rsa->n);
packet_send();
packet_write_wait();
/* Wait for server's response. */
type = packet_read();
/* The server sends failure if it doesn't like our key or
does not support RSA authentication. */
if (type == SSH_SMSG_FAILURE) {
debug("Server refused our key.");
continue;
}
/* Otherwise it should have sent a challenge. */
if (type != SSH_SMSG_AUTH_RSA_CHALLENGE)
packet_disconnect("Protocol error during RSA authentication: %d",
type);
packet_get_bignum(challenge);
packet_check_eom();
debug("Received RSA challenge from server.");
/* Ask the agent to decrypt the challenge. */
if ((r = ssh_decrypt_challenge(agent_fd, idlist->keys[i],
challenge, session_id, response)) != 0) {
/*
* The agent failed to authenticate this identifier
* although it advertised it supports this. Just
* return a wrong value.
*/
logit("Authentication agent failed to decrypt "
"challenge: %s", ssh_err(r));
explicit_bzero(response, sizeof(response));
}
debug("Sending response to RSA challenge.");
/* Send the decrypted challenge back to the server. */
packet_start(SSH_CMSG_AUTH_RSA_RESPONSE);
for (i = 0; i < 16; i++)
packet_put_char(response[i]);
packet_send();
packet_write_wait();
/* Wait for response from the server. */
type = packet_read();
/*
* The server returns success if it accepted the
* authentication.
*/
if (type == SSH_SMSG_SUCCESS) {
debug("RSA authentication accepted by server.");
ret = 1;
break;
} else if (type != SSH_SMSG_FAILURE)
packet_disconnect("Protocol error waiting RSA auth "
"response: %d", type);
}
if (ret != 1)
debug("RSA authentication using agent refused.");
out:
ssh_free_identitylist(idlist);
ssh_close_authentication_socket(agent_fd);
BN_clear_free(challenge);
return ret;
}
/*
* Computes the proper response to a RSA challenge, and sends the response to
* the server.
*/
static void
respond_to_rsa_challenge(BIGNUM * challenge, RSA * prv)
{
u_char buf[32], response[16];
struct ssh_digest_ctx *md;
int i, len;
/* Decrypt the challenge using the private key. */
/* XXX think about Bleichenbacher, too */
if (rsa_private_decrypt(challenge, challenge, prv) != 0)
packet_disconnect(
"respond_to_rsa_challenge: rsa_private_decrypt failed");
/* Compute the response. */
/* The response is MD5 of decrypted challenge plus session id. */
len = BN_num_bytes(challenge);
if (len <= 0 || (u_int)len > sizeof(buf))
packet_disconnect(
"respond_to_rsa_challenge: bad challenge length %d", len);
memset(buf, 0, sizeof(buf));
BN_bn2bin(challenge, buf + sizeof(buf) - len);
if ((md = ssh_digest_start(SSH_DIGEST_MD5)) == NULL ||
ssh_digest_update(md, buf, 32) < 0 ||
ssh_digest_update(md, session_id, 16) < 0 ||
ssh_digest_final(md, response, sizeof(response)) < 0)
fatal("%s: md5 failed", __func__);
ssh_digest_free(md);
debug("Sending response to host key RSA challenge.");
/* Send the response back to the server. */
packet_start(SSH_CMSG_AUTH_RSA_RESPONSE);
for (i = 0; i < 16; i++)
packet_put_char(response[i]);
packet_send();
packet_write_wait();
explicit_bzero(buf, sizeof(buf));
explicit_bzero(response, sizeof(response));
explicit_bzero(&md, sizeof(md));
}
/*
* Checks if the user has authentication file, and if so, tries to authenticate
* the user using it.
*/
static int
try_rsa_authentication(int idx)
{
BIGNUM *challenge;
Key *public, *private;
char buf[300], *passphrase = NULL, *comment, *authfile;
int i, perm_ok = 1, type, quit;
public = options.identity_keys[idx];
authfile = options.identity_files[idx];
comment = xstrdup(authfile);
debug("Trying RSA authentication with key '%.100s'", comment);
/* Tell the server that we are willing to authenticate using this key. */
packet_start(SSH_CMSG_AUTH_RSA);
packet_put_bignum(public->rsa->n);
packet_send();
packet_write_wait();
/* Wait for server's response. */
type = packet_read();
/*
* The server responds with failure if it doesn't like our key or
* doesn't support RSA authentication.
*/
if (type == SSH_SMSG_FAILURE) {
debug("Server refused our key.");
free(comment);
return 0;
}
/* Otherwise, the server should respond with a challenge. */
if (type != SSH_SMSG_AUTH_RSA_CHALLENGE)
packet_disconnect("Protocol error during RSA authentication: %d", type);
/* Get the challenge from the packet. */
if ((challenge = BN_new()) == NULL)
fatal("try_rsa_authentication: BN_new failed");
packet_get_bignum(challenge);
packet_check_eom();
debug("Received RSA challenge from server.");
/*
* If the key is not stored in external hardware, we have to
* load the private key. Try first with empty passphrase; if it
* fails, ask for a passphrase.
*/
if (public->flags & SSHKEY_FLAG_EXT)
private = public;
else
private = key_load_private_type(KEY_RSA1, authfile, "", NULL,
&perm_ok);
if (private == NULL && !options.batch_mode && perm_ok) {
snprintf(buf, sizeof(buf),
"Enter passphrase for RSA key '%.100s': ", comment);
for (i = 0; i < options.number_of_password_prompts; i++) {
passphrase = read_passphrase(buf, 0);
if (strcmp(passphrase, "") != 0) {
private = key_load_private_type(KEY_RSA1,
authfile, passphrase, NULL, NULL);
quit = 0;
} else {
debug2("no passphrase given, try next key");
quit = 1;
}
if (private != NULL || quit)
break;
debug2("bad passphrase given, try again...");
}
}
if (private != NULL)
maybe_add_key_to_agent(authfile, private, comment, passphrase);
if (passphrase != NULL) {
explicit_bzero(passphrase, strlen(passphrase));
free(passphrase);
}
/* We no longer need the comment. */
free(comment);
if (private == NULL) {
if (!options.batch_mode && perm_ok)
error("Bad passphrase.");
/* Send a dummy response packet to avoid protocol error. */
packet_start(SSH_CMSG_AUTH_RSA_RESPONSE);
for (i = 0; i < 16; i++)
packet_put_char(0);
packet_send();
packet_write_wait();
/* Expect the server to reject it... */
packet_read_expect(SSH_SMSG_FAILURE);
BN_clear_free(challenge);
return 0;
}
/* Compute and send a response to the challenge. */
respond_to_rsa_challenge(challenge, private->rsa);
/* Destroy the private key unless it in external hardware. */
if (!(private->flags & SSHKEY_FLAG_EXT))
key_free(private);
/* We no longer need the challenge. */
BN_clear_free(challenge);
/* Wait for response from the server. */
type = packet_read();
if (type == SSH_SMSG_SUCCESS) {
debug("RSA authentication accepted by server.");
return 1;
}
if (type != SSH_SMSG_FAILURE)
packet_disconnect("Protocol error waiting RSA auth response: %d", type);
debug("RSA authentication refused.");
return 0;
}
/*
* Tries to authenticate the user using combined rhosts or /etc/hosts.equiv
* authentication and RSA host authentication.
*/
static int
try_rhosts_rsa_authentication(const char *local_user, Key * host_key)
{
int type;
BIGNUM *challenge;
debug("Trying rhosts or /etc/hosts.equiv with RSA host authentication.");
/* Tell the server that we are willing to authenticate using this key. */
packet_start(SSH_CMSG_AUTH_RHOSTS_RSA);
packet_put_cstring(local_user);
packet_put_int(BN_num_bits(host_key->rsa->n));
packet_put_bignum(host_key->rsa->e);
packet_put_bignum(host_key->rsa->n);
packet_send();
packet_write_wait();
/* Wait for server's response. */
type = packet_read();
/* The server responds with failure if it doesn't admit our
.rhosts authentication or doesn't know our host key. */
if (type == SSH_SMSG_FAILURE) {
debug("Server refused our rhosts authentication or host key.");
return 0;
}
/* Otherwise, the server should respond with a challenge. */
if (type != SSH_SMSG_AUTH_RSA_CHALLENGE)
packet_disconnect("Protocol error during RSA authentication: %d", type);
/* Get the challenge from the packet. */
if ((challenge = BN_new()) == NULL)
fatal("try_rhosts_rsa_authentication: BN_new failed");
packet_get_bignum(challenge);
packet_check_eom();
debug("Received RSA challenge for host key from server.");
/* Compute a response to the challenge. */
respond_to_rsa_challenge(challenge, host_key->rsa);
/* We no longer need the challenge. */
BN_clear_free(challenge);
/* Wait for response from the server. */
type = packet_read();
if (type == SSH_SMSG_SUCCESS) {
debug("Rhosts or /etc/hosts.equiv with RSA host authentication accepted by server.");
return 1;
}
if (type != SSH_SMSG_FAILURE)
packet_disconnect("Protocol error waiting RSA auth response: %d", type);
debug("Rhosts or /etc/hosts.equiv with RSA host authentication refused.");
return 0;
}
/*
* Tries to authenticate with any string-based challenge/response system.
* Note that the client code is not tied to s/key or TIS.
*/
static int
try_challenge_response_authentication(void)
{
int type, i;
u_int clen;
char prompt[1024];
char *challenge, *response;
debug("Doing challenge response authentication.");
for (i = 0; i < options.number_of_password_prompts; i++) {
/* request a challenge */
packet_start(SSH_CMSG_AUTH_TIS);
packet_send();
packet_write_wait();
type = packet_read();
if (type != SSH_SMSG_FAILURE &&
type != SSH_SMSG_AUTH_TIS_CHALLENGE) {
packet_disconnect("Protocol error: got %d in response "
"to SSH_CMSG_AUTH_TIS", type);
}
if (type != SSH_SMSG_AUTH_TIS_CHALLENGE) {
debug("No challenge.");
return 0;
}
challenge = packet_get_string(&clen);
packet_check_eom();
snprintf(prompt, sizeof prompt, "%s%s", challenge,
strchr(challenge, '\n') ? "" : "\nResponse: ");
free(challenge);
if (i != 0)
error("Permission denied, please try again.");
if (options.cipher == SSH_CIPHER_NONE)
logit("WARNING: Encryption is disabled! "
"Response will be transmitted in clear text.");
response = read_passphrase(prompt, 0);
if (strcmp(response, "") == 0) {
free(response);
break;
}
packet_start(SSH_CMSG_AUTH_TIS_RESPONSE);
ssh_put_password(response);
explicit_bzero(response, strlen(response));
free(response);
packet_send();
packet_write_wait();
type = packet_read();
if (type == SSH_SMSG_SUCCESS)
return 1;
if (type != SSH_SMSG_FAILURE)
packet_disconnect("Protocol error: got %d in response "
"to SSH_CMSG_AUTH_TIS_RESPONSE", type);
}
/* failure */
return 0;
}
/*
* Tries to authenticate with plain passwd authentication.
*/
static int
try_password_authentication(char *prompt)
{
int type, i;
char *password;
debug("Doing password authentication.");
if (options.cipher == SSH_CIPHER_NONE)
logit("WARNING: Encryption is disabled! Password will be transmitted in clear text.");
for (i = 0; i < options.number_of_password_prompts; i++) {
if (i != 0)
error("Permission denied, please try again.");
password = read_passphrase(prompt, 0);
packet_start(SSH_CMSG_AUTH_PASSWORD);
ssh_put_password(password);
explicit_bzero(password, strlen(password));
free(password);
packet_send();
packet_write_wait();
type = packet_read();
if (type == SSH_SMSG_SUCCESS)
return 1;
if (type != SSH_SMSG_FAILURE)
packet_disconnect("Protocol error: got %d in response to passwd auth", type);
}
/* failure */
return 0;
}
/*
* SSH1 key exchange
*/
void
ssh_kex(char *host, struct sockaddr *hostaddr)
{
int i;
BIGNUM *key;
Key *host_key, *server_key;
int bits, rbits;
int ssh_cipher_default = SSH_CIPHER_3DES;
u_char session_key[SSH_SESSION_KEY_LENGTH];
u_char cookie[8];
u_int supported_ciphers;
u_int server_flags, client_flags;
debug("Waiting for server public key.");
/* Wait for a public key packet from the server. */
packet_read_expect(SSH_SMSG_PUBLIC_KEY);
/* Get cookie from the packet. */
for (i = 0; i < 8; i++)
cookie[i] = packet_get_char();
/* Get the public key. */
if ((server_key = key_new(KEY_RSA1)) == NULL)
fatal("%s: key_new(KEY_RSA1) failed", __func__);
bits = packet_get_int();
packet_get_bignum(server_key->rsa->e);
packet_get_bignum(server_key->rsa->n);
rbits = BN_num_bits(server_key->rsa->n);
if (bits != rbits) {
logit("Warning: Server lies about size of server public key: "
"actual size is %d bits vs. announced %d.", rbits, bits);
logit("Warning: This may be due to an old implementation of ssh.");
}
/* Get the host key. */
if ((host_key = key_new(KEY_RSA1)) == NULL)
fatal("%s: key_new(KEY_RSA1) failed", __func__);
bits = packet_get_int();
packet_get_bignum(host_key->rsa->e);
packet_get_bignum(host_key->rsa->n);
rbits = BN_num_bits(host_key->rsa->n);
if (bits != rbits) {
logit("Warning: Server lies about size of server host key: "
"actual size is %d bits vs. announced %d.", rbits, bits);
logit("Warning: This may be due to an old implementation of ssh.");
}
/* Get protocol flags. */
server_flags = packet_get_int();
packet_set_protocol_flags(server_flags);
supported_ciphers = packet_get_int();
supported_authentications = packet_get_int();
packet_check_eom();
debug("Received server public key (%d bits) and host key (%d bits).",
BN_num_bits(server_key->rsa->n), BN_num_bits(host_key->rsa->n));
if (verify_host_key(host, hostaddr, host_key) == -1)
fatal("Host key verification failed.");
client_flags = SSH_PROTOFLAG_SCREEN_NUMBER | SSH_PROTOFLAG_HOST_IN_FWD_OPEN;
derive_ssh1_session_id(host_key->rsa->n, server_key->rsa->n, cookie, session_id);
/*
* Generate an encryption key for the session. The key is a 256 bit
* random number, interpreted as a 32-byte key, with the least
* significant 8 bits being the first byte of the key.
*/
arc4random_buf(session_key, sizeof(session_key));
/*
* According to the protocol spec, the first byte of the session key
* is the highest byte of the integer. The session key is xored with
* the first 16 bytes of the session id.
*/
if ((key = BN_new()) == NULL)
fatal("ssh_kex: BN_new failed");
if (BN_set_word(key, 0) == 0)
fatal("ssh_kex: BN_set_word failed");
for (i = 0; i < SSH_SESSION_KEY_LENGTH; i++) {
if (BN_lshift(key, key, 8) == 0)
fatal("ssh_kex: BN_lshift failed");
if (i < 16) {
if (BN_add_word(key, session_key[i] ^ session_id[i])
== 0)
fatal("ssh_kex: BN_add_word failed");
} else {
if (BN_add_word(key, session_key[i]) == 0)
fatal("ssh_kex: BN_add_word failed");
}
}
/*
* Encrypt the integer using the public key and host key of the
* server (key with smaller modulus first).
*/
if (BN_cmp(server_key->rsa->n, host_key->rsa->n) < 0) {
/* Public key has smaller modulus. */
if (BN_num_bits(host_key->rsa->n) <
BN_num_bits(server_key->rsa->n) + SSH_KEY_BITS_RESERVED) {
fatal("respond_to_rsa_challenge: host_key %d < server_key %d + "
"SSH_KEY_BITS_RESERVED %d",
BN_num_bits(host_key->rsa->n),
BN_num_bits(server_key->rsa->n),
SSH_KEY_BITS_RESERVED);
}
if (rsa_public_encrypt(key, key, server_key->rsa) != 0 ||
rsa_public_encrypt(key, key, host_key->rsa) != 0)
fatal("%s: rsa_public_encrypt failed", __func__);
} else {
/* Host key has smaller modulus (or they are equal). */
if (BN_num_bits(server_key->rsa->n) <
BN_num_bits(host_key->rsa->n) + SSH_KEY_BITS_RESERVED) {
fatal("respond_to_rsa_challenge: server_key %d < host_key %d + "
"SSH_KEY_BITS_RESERVED %d",
BN_num_bits(server_key->rsa->n),
BN_num_bits(host_key->rsa->n),
SSH_KEY_BITS_RESERVED);
}
if (rsa_public_encrypt(key, key, host_key->rsa) != 0 ||
rsa_public_encrypt(key, key, server_key->rsa) != 0)
fatal("%s: rsa_public_encrypt failed", __func__);
}
/* Destroy the public keys since we no longer need them. */
key_free(server_key);
key_free(host_key);
if (options.cipher == SSH_CIPHER_NOT_SET) {
if (cipher_mask_ssh1(1) & supported_ciphers & (1 << ssh_cipher_default))
options.cipher = ssh_cipher_default;
} else if (options.cipher == SSH_CIPHER_INVALID ||
!(cipher_mask_ssh1(1) & (1 << options.cipher))) {
logit("No valid SSH1 cipher, using %.100s instead.",
cipher_name(ssh_cipher_default));
options.cipher = ssh_cipher_default;
}
/* Check that the selected cipher is supported. */
if (!(supported_ciphers & (1 << options.cipher)))
fatal("Selected cipher type %.100s not supported by server.",
cipher_name(options.cipher));
debug("Encryption type: %.100s", cipher_name(options.cipher));
/* Send the encrypted session key to the server. */
packet_start(SSH_CMSG_SESSION_KEY);
packet_put_char(options.cipher);
/* Send the cookie back to the server. */
for (i = 0; i < 8; i++)
packet_put_char(cookie[i]);
/* Send and destroy the encrypted encryption key integer. */
packet_put_bignum(key);
BN_clear_free(key);
/* Send protocol flags. */
packet_put_int(client_flags);
/* Send the packet now. */
packet_send();
packet_write_wait();
debug("Sent encrypted session key.");
/* Set the encryption key. */
packet_set_encryption_key(session_key, SSH_SESSION_KEY_LENGTH, options.cipher);
/*
* We will no longer need the session key here.
* Destroy any extra copies.
*/
explicit_bzero(session_key, sizeof(session_key));
/*
* Expect a success message from the server. Note that this message
* will be received in encrypted form.
*/
packet_read_expect(SSH_SMSG_SUCCESS);
debug("Received encrypted confirmation.");
}
/*
* Authenticate user
*/
void
ssh_userauth1(const char *local_user, const char *server_user, char *host,
Sensitive *sensitive)
{
int i, type;
if (supported_authentications == 0)
fatal("ssh_userauth1: server supports no auth methods");
/* Send the name of the user to log in as on the server. */
packet_start(SSH_CMSG_USER);
packet_put_cstring(server_user);
packet_send();
packet_write_wait();
/*
* The server should respond with success if no authentication is
* needed (the user has no password). Otherwise the server responds
* with failure.
*/
type = packet_read();
/* check whether the connection was accepted without authentication. */
if (type == SSH_SMSG_SUCCESS)
goto success;
if (type != SSH_SMSG_FAILURE)
packet_disconnect("Protocol error: got %d in response to SSH_CMSG_USER", type);
/*
* Try .rhosts or /etc/hosts.equiv authentication with RSA host
* authentication.
*/
if ((supported_authentications & (1 << SSH_AUTH_RHOSTS_RSA)) &&
options.rhosts_rsa_authentication) {
for (i = 0; i < sensitive->nkeys; i++) {
if (sensitive->keys[i] != NULL &&
sensitive->keys[i]->type == KEY_RSA1 &&
try_rhosts_rsa_authentication(local_user,
sensitive->keys[i]))
goto success;
}
}
/* Try RSA authentication if the server supports it. */
if ((supported_authentications & (1 << SSH_AUTH_RSA)) &&
options.rsa_authentication) {
/*
* Try RSA authentication using the authentication agent. The
* agent is tried first because no passphrase is needed for
* it, whereas identity files may require passphrases.
*/
if (try_agent_authentication())
goto success;
/* Try RSA authentication for each identity. */
for (i = 0; i < options.num_identity_files; i++)
if (options.identity_keys[i] != NULL &&
options.identity_keys[i]->type == KEY_RSA1 &&
try_rsa_authentication(i))
goto success;
}
/* Try challenge response authentication if the server supports it. */
if ((supported_authentications & (1 << SSH_AUTH_TIS)) &&
options.challenge_response_authentication && !options.batch_mode) {
if (try_challenge_response_authentication())
goto success;
}
/* Try password authentication if the server supports it. */
if ((supported_authentications & (1 << SSH_AUTH_PASSWORD)) &&
options.password_authentication && !options.batch_mode) {
char prompt[80];
snprintf(prompt, sizeof(prompt), "%.30s@%.128s's password: ",
server_user, host);
if (try_password_authentication(prompt))
goto success;
}
/* All authentication methods have failed. Exit with an error message. */
fatal("Permission denied.");
/* NOTREACHED */
success:
return; /* need statement after label */
}
#endif /* WITH_SSH1 */