forked from enlightenment/efl
Compare commits
5 Commits
master
...
devs/cedri
Author | SHA1 | Date |
---|---|---|
Cedric BAIL | 1649ad765c | |
Cedric BAIL | a0111289ba | |
Cedric BAIL | 161831a77a | |
Cedric BAIL | d80958648b | |
Cedric BAIL | c39786bd95 |
24
configure.ac
24
configure.ac
|
@ -404,6 +404,30 @@ AC_DEFINE_IF([ENABLE_LIBLZ4], [test "${want_liblz4}" = "yes"], [1], [Use liblz4
|
|||
AC_SUBST([want_liblz4])
|
||||
AC_SUBST([ENABLE_LIBLZ4])
|
||||
|
||||
# check for libassh
|
||||
want_libassh="no"
|
||||
AC_ARG_ENABLE([libassh],
|
||||
[AS_HELP_STRING([--enable-libassh],[Enable usage of libassh instead of our embedded copy. @<:@default=disabled@:>@])],
|
||||
[
|
||||
if test "x${enableval}" = "xyes"; then
|
||||
PKG_CHECK_MODULES([LIBASSH], [libassh])
|
||||
EFL_DEPEND_PKG([ECORE_CON], [libassh])
|
||||
want_libassh="yes"
|
||||
else
|
||||
want_libassh="no"
|
||||
fi
|
||||
],
|
||||
[want_libassh="no"])
|
||||
|
||||
AM_CONDITIONAL([ENABLE_LIBASSH], [test "x${want_libassh}" = "xyes"])
|
||||
AC_DEFINE_IF([ENABLE_LIBASSH], [test "x${want_libassh}" = "xyes"], [1], [Use libassh external library instead of embedded copy])
|
||||
AC_SUBST([want_libassh])
|
||||
AC_SUBST([ENABLE_LIBASSH])
|
||||
|
||||
if test "x${want_libassh}" = "xno"; then
|
||||
AC_CONFIG_SUBDIRS([src/static_libs/assh])
|
||||
fi
|
||||
|
||||
#### Checks for header files
|
||||
|
||||
# Common Checks (keep names sorted for ease of use):
|
||||
|
|
|
@ -24,6 +24,9 @@ check_PROGRAMS =
|
|||
TESTS =
|
||||
EXTRA_DIST =
|
||||
|
||||
if ! ENABLE_LIBASSH
|
||||
SUBDIRS += static_libs/assh
|
||||
endif
|
||||
|
||||
EFL_INSTALL_EXEC_HOOK=
|
||||
|
||||
|
|
|
@ -6,7 +6,10 @@ ecore_con_eolian_files = \
|
|||
lib/ecore_con/ecore_con_client.eo \
|
||||
lib/ecore_con/ecore_con_server.eo \
|
||||
lib/ecore_con/ecore_con_connector.eo \
|
||||
lib/ecore_con/ecore_con_url.eo
|
||||
lib/ecore_con/ecore_con_url.eo \
|
||||
lib/ecore_con/efl_network_ssh_client.eo \
|
||||
lib/ecore_con/efl_network_ssh_channel_base.eo \
|
||||
lib/ecore_con/efl_network_ssh_channel_interactive_session.eo
|
||||
|
||||
ecore_con_eolian_c = $(ecore_con_eolian_files:%.eo=%.eo.c)
|
||||
ecore_con_eolian_h = $(ecore_con_eolian_files:%.eo=%.eo.h) \
|
||||
|
@ -34,7 +37,8 @@ dist_installed_ecoreconmainheaders_DATA = \
|
|||
lib/ecore_con/Ecore_Con.h \
|
||||
lib/ecore_con/Ecore_Con_Legacy.h \
|
||||
lib/ecore_con/Ecore_Con_Eo.h \
|
||||
lib/ecore_con/Ecore_Con_Eet.h
|
||||
lib/ecore_con/Ecore_Con_Eet.h \
|
||||
lib/ecore_con/Ecore_Con_Ssh.h
|
||||
|
||||
nodist_installed_ecoreconmainheaders_DATA = \
|
||||
$(ecore_con_eolian_h)
|
||||
|
@ -46,7 +50,8 @@ lib/ecore_con/ecore_con_eet.c \
|
|||
lib/ecore_con/ecore_con_socks.c \
|
||||
lib/ecore_con/ecore_con_ssl.c \
|
||||
lib/ecore_con/ecore_con_url.c \
|
||||
lib/ecore_con/ecore_con_private.h
|
||||
lib/ecore_con/ecore_con_private.h \
|
||||
lib/ecore_con/ecore_con_ssh.c
|
||||
|
||||
if HAVE_WINDOWS
|
||||
lib_ecore_con_libecore_con_la_SOURCES += lib/ecore_con/ecore_con_local_win32.c
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
#ifndef _ECORE_CON_SSH_H
|
||||
#define _ECORE_CON_SSH_H
|
||||
|
||||
#include <time.h>
|
||||
#include <libgen.h>
|
||||
#ifdef _WIN32
|
||||
# include <ws2tcpip.h>
|
||||
#else
|
||||
# include <netdb.h>
|
||||
#endif
|
||||
#include <Eina.h>
|
||||
#include <Eo.h>
|
||||
|
||||
#ifdef EAPI
|
||||
# undef EAPI
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
# ifdef EFL_ECORE_CON_BUILD
|
||||
# ifdef DLL_EXPORT
|
||||
# define EAPI __declspec(dllexport)
|
||||
# else
|
||||
# define EAPI
|
||||
# endif
|
||||
# else
|
||||
# define EAPI __declspec(dllimport)
|
||||
# endif
|
||||
#else
|
||||
# ifdef __GNUC__
|
||||
# if __GNUC__ >= 4
|
||||
# define EAPI __attribute__ ((visibility("default")))
|
||||
# else
|
||||
# define EAPI
|
||||
# endif
|
||||
# else
|
||||
# define EAPI
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct _Efl_Network_Ssh_Request Efl_Network_Ssh_Request;
|
||||
typedef Eo Efl_Network_Ssh_Channel_Interactive_Session;
|
||||
|
||||
#ifndef EFL_NOLEGACY_API_SUPPORT
|
||||
# include "efl_network_ssh_client.eo.legacy.h"
|
||||
# include "efl_network_ssh_channel_base.eo.legacy.h"
|
||||
# include "efl_network_ssh_channel_interactive_session.eo.legacy.h"
|
||||
#endif
|
||||
#ifdef EFL_EO_API_SUPPORT
|
||||
# include "efl_network_ssh_client.eo.h"
|
||||
# include "efl_network_ssh_channel_base.eo.h"
|
||||
# include "efl_network_ssh_channel_interactive_session.eo.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#undef EAPI
|
||||
#define EAPI
|
||||
|
||||
#endif
|
|
@ -0,0 +1,139 @@
|
|||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <Eina.h>
|
||||
#include <Eo.h>
|
||||
#include <Ecore_Con.h>
|
||||
#include <Ecore_Con_Ssh.h>
|
||||
|
||||
typedef struct _Efl_Network_Ssh_Client_Data Efl_Network_Ssh_Client_Data;
|
||||
struct _Efl_Network_Ssh_Client_Data
|
||||
{
|
||||
};
|
||||
|
||||
typedef struct _Efl_Network_Ssh_Channel_Base_Data Efl_Network_Ssh_Channel_Base_Data;
|
||||
struct _Efl_Network_Ssh_Channel_Base_Data
|
||||
{
|
||||
};
|
||||
|
||||
typedef struct _Efl_Network_Ssh_Channel_Interactive_Session_Data Efl_Network_Ssh_Channel_Interactive_Session_Data;
|
||||
struct _Efl_Network_Ssh_Channel_Interactive_Session_Data
|
||||
{
|
||||
};
|
||||
|
||||
|
||||
|
||||
static void
|
||||
_efl_network_ssh_client_user_set(Eo *obj, Efl_Network_Ssh_Client_Data *pd, const char *user)
|
||||
{
|
||||
}
|
||||
|
||||
static const char *
|
||||
_efl_network_ssh_client_user_get(Eo *obj, Efl_Network_Ssh_Client_Data *pd)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
_efl_network_ssh_client_passwd_set(Eo *obj, Efl_Network_Ssh_Client_Data *pd, const char *passwd)
|
||||
{
|
||||
}
|
||||
|
||||
static const char *
|
||||
_efl_network_ssh_client_passwd_get(Eo *obj, Efl_Network_Ssh_Client_Data *pd)
|
||||
{
|
||||
}
|
||||
|
||||
static Eina_Iterator *
|
||||
_efl_network_ssh_client_keys_list(Eo *obj, Efl_Network_Ssh_Client_Data *pd)
|
||||
{
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_efl_network_ssh_client_key_add(Eo *obj, Efl_Network_Ssh_Client_Data *pd, const char *path)
|
||||
{
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_efl_network_ssh_client_key_del(Eo *obj, Efl_Network_Ssh_Client_Data *pd, const char *path)
|
||||
{
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_efl_network_ssh_client_hostkey(Eo *obj, Efl_Network_Ssh_Client_Data *pd, Eina_Bool validate)
|
||||
{
|
||||
}
|
||||
|
||||
static Efl_Network_Ssh_Channel_Interactive_Session *
|
||||
_efl_network_ssh_client_interactive_session_new(Eo *obj, Efl_Network_Ssh_Client_Data *pd)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
_efl_network_ssh_client_eo_base_constructor(Eo *obj, Efl_Network_Ssh_Client_Data *pd)
|
||||
{
|
||||
}
|
||||
|
||||
static Eo *
|
||||
_efl_network_ssh_client_eo_base_finalize(Eo *obj, Efl_Network_Ssh_Client_Data *pd)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
_efl_network_ssh_client_eo_base_destructor(Eo *obj, Efl_Network_Ssh_Client_Data *pd)
|
||||
{
|
||||
}
|
||||
|
||||
static int
|
||||
_efl_network_ssh_client_ecore_con_base_send(Eo *obj, Efl_Network_Ssh_Client_Data *pd, const void *data, int size)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
_efl_network_ssh_client_ecore_con_base_flush(Eo *obj, Efl_Network_Ssh_Client_Data *pd)
|
||||
{
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_efl_network_ssh_channel_base_data_send(Eo *obj, Efl_Network_Ssh_Channel_Base_Data *pd, const void *data, size_t size)
|
||||
{
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_efl_network_ssh_channel_base_binbuf_send(Eo *obj, Efl_Network_Ssh_Channel_Base_Data *pd, const Eina_Binbuf *data)
|
||||
{
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_efl_network_ssh_channel_base_data_ext_send(Eo *obj, Efl_Network_Ssh_Channel_Base_Data *pd, unsigned int type, const void *data, size_t size)
|
||||
{
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_efl_network_ssh_channel_base_binbuf_ext_send(Eo *obj, Efl_Network_Ssh_Channel_Base_Data *pd, unsigned int type, const Eina_Binbuf *data)
|
||||
{
|
||||
}
|
||||
|
||||
static Efl_Network_Ssh_Request *
|
||||
_efl_network_ssh_channel_interactive_session_pty_req(Eo *obj, Efl_Network_Ssh_Channel_Interactive_Session_Data *pd, const char *term, const char *modes, unsigned int columns, unsigned int rows, unsigned int width, unsigned int height)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
_efl_network_ssh_channel_interactive_session_env_req(Eo *obj, Efl_Network_Ssh_Channel_Interactive_Session_Data *pd, const char *name, const char *value)
|
||||
{
|
||||
}
|
||||
|
||||
static Efl_Network_Ssh_Request *
|
||||
_efl_network_ssh_channel_interactive_session_shell_req(Eo *obj, Efl_Network_Ssh_Channel_Interactive_Session_Data *pd)
|
||||
{
|
||||
}
|
||||
|
||||
static Efl_Network_Ssh_Request *
|
||||
_efl_network_ssh_channel_interactive_session_exec_req(Eo *obj, Efl_Network_Ssh_Channel_Interactive_Session_Data *pd, const char *command)
|
||||
{
|
||||
}
|
||||
|
||||
#include "efl_network_ssh_client.eo.c"
|
||||
#include "efl_network_ssh_channel_base.eo.c"
|
||||
#include "efl_network_ssh_channel_interactive_session.eo.c"
|
|
@ -0,0 +1,40 @@
|
|||
class Efl.Network.Ssh.Channel.Base
|
||||
{
|
||||
eo_prefix: efl_network_ssh_channel;
|
||||
legacy_prefix: ecore_con_ssh_channel;
|
||||
methods {
|
||||
data_send {
|
||||
params {
|
||||
const(void)* data;
|
||||
size_t size;
|
||||
}
|
||||
return: bool;
|
||||
}
|
||||
binbuf_send {
|
||||
params {
|
||||
const(Eina_Binbuf)* data;
|
||||
}
|
||||
return: bool;
|
||||
}
|
||||
data_ext_send {
|
||||
params {
|
||||
uint type;
|
||||
const(void)* data;
|
||||
size_t size;
|
||||
}
|
||||
return: bool;
|
||||
}
|
||||
binbuf_ext_send {
|
||||
params {
|
||||
uint type;
|
||||
const(Eina_Binbuf)* data;
|
||||
}
|
||||
return: bool;
|
||||
}
|
||||
}
|
||||
events {
|
||||
data,received;
|
||||
data,error;
|
||||
request,reply;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
class Efl.Network.Ssh.Channel.Interactive_Session (Efl.Network.Ssh.Channel.Base)
|
||||
{
|
||||
eo_prefix: efl_network_ssh_channel_interactive_session;
|
||||
legacy_prefix: ecore_con_ssh_channel_interactive_session;
|
||||
methods {
|
||||
pty_req {
|
||||
params {
|
||||
const(char)* term;
|
||||
const(char)* modes;
|
||||
uint columns;
|
||||
uint rows;
|
||||
uint width;
|
||||
uint height;
|
||||
}
|
||||
return: Efl_Network_Ssh_Request *;
|
||||
}
|
||||
env_req {
|
||||
params {
|
||||
const(char)* name;
|
||||
const(char)* value;
|
||||
}
|
||||
}
|
||||
shell_req {
|
||||
return: Efl_Network_Ssh_Request *;
|
||||
}
|
||||
exec_req {
|
||||
params {
|
||||
const(char)* command;
|
||||
}
|
||||
return: Efl_Network_Ssh_Request *;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
class Efl.Network.Ssh.Client (Ecore.Con.Connector)
|
||||
{
|
||||
eo_prefix: efl_network_ssh_client;
|
||||
legacy_prefix: ecore_con_ssh_client;
|
||||
properties {
|
||||
user {
|
||||
set {
|
||||
}
|
||||
get {
|
||||
}
|
||||
values {
|
||||
const(char)* user;
|
||||
}
|
||||
}
|
||||
passwd {
|
||||
set {
|
||||
}
|
||||
get {
|
||||
}
|
||||
values {
|
||||
const(char)* passwd;
|
||||
}
|
||||
}
|
||||
}
|
||||
methods {
|
||||
keys_list {
|
||||
return: free(own(iterator<const(char)*> *), eina_iterator_free);
|
||||
}
|
||||
key_add {
|
||||
params {
|
||||
const(char)* path @nonull;
|
||||
}
|
||||
return: bool;
|
||||
}
|
||||
key_del {
|
||||
params {
|
||||
const(char)* path @nonull;
|
||||
}
|
||||
return: bool;
|
||||
}
|
||||
hostkey {
|
||||
params {
|
||||
bool validate;
|
||||
}
|
||||
return: bool;
|
||||
}
|
||||
interactive_session_new {
|
||||
return: Efl_Network_Ssh_Channel_Interactive_Session *;
|
||||
}
|
||||
}
|
||||
implements {
|
||||
Eo.Base.constructor;
|
||||
Eo.Base.finalize;
|
||||
Eo.Base.destructor;
|
||||
Ecore.Con.Base.send;
|
||||
Ecore.Con.Base.flush;
|
||||
}
|
||||
events {
|
||||
hostkey,known;
|
||||
hostkey,unknown;
|
||||
auth,passwd;
|
||||
auth,keys;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
/INSTALL
|
||||
/assh.pc
|
||||
/autom4te.cache/
|
||||
/config.status
|
||||
/libtool
|
||||
/stamp-h1
|
||||
/config.h
|
||||
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
Alexandre Becoulet <alexandre.becoulet@free.fr>.
|
||||
|
|
@ -0,0 +1,502 @@
|
|||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 2.1, February 1999
|
||||
|
||||
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
[This is the first released version of the Lesser GPL. It also counts
|
||||
as the successor of the GNU Library Public License, version 2, hence
|
||||
the version number 2.1.]
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
Licenses are intended to guarantee your freedom to share and change
|
||||
free software--to make sure the software is free for all its users.
|
||||
|
||||
This license, the Lesser General Public License, applies to some
|
||||
specially designated software packages--typically libraries--of the
|
||||
Free Software Foundation and other authors who decide to use it. You
|
||||
can use it too, but we suggest you first think carefully about whether
|
||||
this license or the ordinary General Public License is the better
|
||||
strategy to use in any particular case, based on the explanations below.
|
||||
|
||||
When we speak of free software, we are referring to freedom of use,
|
||||
not price. Our General Public Licenses are designed to make sure that
|
||||
you have the freedom to distribute copies of free software (and charge
|
||||
for this service if you wish); that you receive source code or can get
|
||||
it if you want it; that you can change the software and use pieces of
|
||||
it in new free programs; and that you are informed that you can do
|
||||
these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
distributors to deny you these rights or to ask you to surrender these
|
||||
rights. These restrictions translate to certain responsibilities for
|
||||
you if you distribute copies of the library or if you modify it.
|
||||
|
||||
For example, if you distribute copies of the library, whether gratis
|
||||
or for a fee, you must give the recipients all the rights that we gave
|
||||
you. You must make sure that they, too, receive or can get the source
|
||||
code. If you link other code with the library, you must provide
|
||||
complete object files to the recipients, so that they can relink them
|
||||
with the library after making changes to the library and recompiling
|
||||
it. And you must show them these terms so they know their rights.
|
||||
|
||||
We protect your rights with a two-step method: (1) we copyright the
|
||||
library, and (2) we offer you this license, which gives you legal
|
||||
permission to copy, distribute and/or modify the library.
|
||||
|
||||
To protect each distributor, we want to make it very clear that
|
||||
there is no warranty for the free library. Also, if the library is
|
||||
modified by someone else and passed on, the recipients should know
|
||||
that what they have is not the original version, so that the original
|
||||
author's reputation will not be affected by problems that might be
|
||||
introduced by others.
|
||||
|
||||
Finally, software patents pose a constant threat to the existence of
|
||||
any free program. We wish to make sure that a company cannot
|
||||
effectively restrict the users of a free program by obtaining a
|
||||
restrictive license from a patent holder. Therefore, we insist that
|
||||
any patent license obtained for a version of the library must be
|
||||
consistent with the full freedom of use specified in this license.
|
||||
|
||||
Most GNU software, including some libraries, is covered by the
|
||||
ordinary GNU General Public License. This license, the GNU Lesser
|
||||
General Public License, applies to certain designated libraries, and
|
||||
is quite different from the ordinary General Public License. We use
|
||||
this license for certain libraries in order to permit linking those
|
||||
libraries into non-free programs.
|
||||
|
||||
When a program is linked with a library, whether statically or using
|
||||
a shared library, the combination of the two is legally speaking a
|
||||
combined work, a derivative of the original library. The ordinary
|
||||
General Public License therefore permits such linking only if the
|
||||
entire combination fits its criteria of freedom. The Lesser General
|
||||
Public License permits more lax criteria for linking other code with
|
||||
the library.
|
||||
|
||||
We call this license the "Lesser" General Public License because it
|
||||
does Less to protect the user's freedom than the ordinary General
|
||||
Public License. It also provides other free software developers Less
|
||||
of an advantage over competing non-free programs. These disadvantages
|
||||
are the reason we use the ordinary General Public License for many
|
||||
libraries. However, the Lesser license provides advantages in certain
|
||||
special circumstances.
|
||||
|
||||
For example, on rare occasions, there may be a special need to
|
||||
encourage the widest possible use of a certain library, so that it becomes
|
||||
a de-facto standard. To achieve this, non-free programs must be
|
||||
allowed to use the library. A more frequent case is that a free
|
||||
library does the same job as widely used non-free libraries. In this
|
||||
case, there is little to gain by limiting the free library to free
|
||||
software only, so we use the Lesser General Public License.
|
||||
|
||||
In other cases, permission to use a particular library in non-free
|
||||
programs enables a greater number of people to use a large body of
|
||||
free software. For example, permission to use the GNU C Library in
|
||||
non-free programs enables many more people to use the whole GNU
|
||||
operating system, as well as its variant, the GNU/Linux operating
|
||||
system.
|
||||
|
||||
Although the Lesser General Public License is Less protective of the
|
||||
users' freedom, it does ensure that the user of a program that is
|
||||
linked with the Library has the freedom and the wherewithal to run
|
||||
that program using a modified version of the Library.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow. Pay close attention to the difference between a
|
||||
"work based on the library" and a "work that uses the library". The
|
||||
former contains code derived from the library, whereas the latter must
|
||||
be combined with the library in order to run.
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library or other
|
||||
program which contains a notice placed by the copyright holder or
|
||||
other authorized party saying it may be distributed under the terms of
|
||||
this Lesser General Public License (also called "this License").
|
||||
Each licensee is addressed as "you".
|
||||
|
||||
A "library" means a collection of software functions and/or data
|
||||
prepared so as to be conveniently linked with application programs
|
||||
(which use some of those functions and data) to form executables.
|
||||
|
||||
The "Library", below, refers to any such software library or work
|
||||
which has been distributed under these terms. A "work based on the
|
||||
Library" means either the Library or any derivative work under
|
||||
copyright law: that is to say, a work containing the Library or a
|
||||
portion of it, either verbatim or with modifications and/or translated
|
||||
straightforwardly into another language. (Hereinafter, translation is
|
||||
included without limitation in the term "modification".)
|
||||
|
||||
"Source code" for a work means the preferred form of the work for
|
||||
making modifications to it. For a library, complete source code means
|
||||
all the source code for all modules it contains, plus any associated
|
||||
interface definition files, plus the scripts used to control compilation
|
||||
and installation of the library.
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running a program using the Library is not restricted, and output from
|
||||
such a program is covered only if its contents constitute a work based
|
||||
on the Library (independent of the use of the Library in a tool for
|
||||
writing it). Whether that is true depends on what the Library does
|
||||
and what the program that uses the Library does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Library's
|
||||
complete source code as you receive it, in any medium, provided that
|
||||
you conspicuously and appropriately publish on each copy an
|
||||
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||
all the notices that refer to this License and to the absence of any
|
||||
warranty; and distribute a copy of this License along with the
|
||||
Library.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy,
|
||||
and you may at your option offer warranty protection in exchange for a
|
||||
fee.
|
||||
|
||||
2. You may modify your copy or copies of the Library or any portion
|
||||
of it, thus forming a work based on the Library, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) The modified work must itself be a software library.
|
||||
|
||||
b) You must cause the files modified to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
c) You must cause the whole of the work to be licensed at no
|
||||
charge to all third parties under the terms of this License.
|
||||
|
||||
d) If a facility in the modified Library refers to a function or a
|
||||
table of data to be supplied by an application program that uses
|
||||
the facility, other than as an argument passed when the facility
|
||||
is invoked, then you must make a good faith effort to ensure that,
|
||||
in the event an application does not supply such function or
|
||||
table, the facility still operates, and performs whatever part of
|
||||
its purpose remains meaningful.
|
||||
|
||||
(For example, a function in a library to compute square roots has
|
||||
a purpose that is entirely well-defined independent of the
|
||||
application. Therefore, Subsection 2d requires that any
|
||||
application-supplied function or table used by this function must
|
||||
be optional: if the application does not supply it, the square
|
||||
root function must still compute square roots.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Library,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Library, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote
|
||||
it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Library.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Library
|
||||
with the Library (or with a work based on the Library) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||
License instead of this License to a given copy of the Library. To do
|
||||
this, you must alter all the notices that refer to this License, so
|
||||
that they refer to the ordinary GNU General Public License, version 2,
|
||||
instead of to this License. (If a newer version than version 2 of the
|
||||
ordinary GNU General Public License has appeared, then you can specify
|
||||
that version instead if you wish.) Do not make any other change in
|
||||
these notices.
|
||||
|
||||
Once this change is made in a given copy, it is irreversible for
|
||||
that copy, so the ordinary GNU General Public License applies to all
|
||||
subsequent copies and derivative works made from that copy.
|
||||
|
||||
This option is useful when you wish to copy part of the code of
|
||||
the Library into a program that is not a library.
|
||||
|
||||
4. You may copy and distribute the Library (or a portion or
|
||||
derivative of it, under Section 2) in object code or executable form
|
||||
under the terms of Sections 1 and 2 above provided that you accompany
|
||||
it with the complete corresponding machine-readable source code, which
|
||||
must be distributed under the terms of Sections 1 and 2 above on a
|
||||
medium customarily used for software interchange.
|
||||
|
||||
If distribution of object code is made by offering access to copy
|
||||
from a designated place, then offering equivalent access to copy the
|
||||
source code from the same place satisfies the requirement to
|
||||
distribute the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
5. A program that contains no derivative of any portion of the
|
||||
Library, but is designed to work with the Library by being compiled or
|
||||
linked with it, is called a "work that uses the Library". Such a
|
||||
work, in isolation, is not a derivative work of the Library, and
|
||||
therefore falls outside the scope of this License.
|
||||
|
||||
However, linking a "work that uses the Library" with the Library
|
||||
creates an executable that is a derivative of the Library (because it
|
||||
contains portions of the Library), rather than a "work that uses the
|
||||
library". The executable is therefore covered by this License.
|
||||
Section 6 states terms for distribution of such executables.
|
||||
|
||||
When a "work that uses the Library" uses material from a header file
|
||||
that is part of the Library, the object code for the work may be a
|
||||
derivative work of the Library even though the source code is not.
|
||||
Whether this is true is especially significant if the work can be
|
||||
linked without the Library, or if the work is itself a library. The
|
||||
threshold for this to be true is not precisely defined by law.
|
||||
|
||||
If such an object file uses only numerical parameters, data
|
||||
structure layouts and accessors, and small macros and small inline
|
||||
functions (ten lines or less in length), then the use of the object
|
||||
file is unrestricted, regardless of whether it is legally a derivative
|
||||
work. (Executables containing this object code plus portions of the
|
||||
Library will still fall under Section 6.)
|
||||
|
||||
Otherwise, if the work is a derivative of the Library, you may
|
||||
distribute the object code for the work under the terms of Section 6.
|
||||
Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
|
||||
6. As an exception to the Sections above, you may also combine or
|
||||
link a "work that uses the Library" with the Library to produce a
|
||||
work containing portions of the Library, and distribute that work
|
||||
under terms of your choice, provided that the terms permit
|
||||
modification of the work for the customer's own use and reverse
|
||||
engineering for debugging such modifications.
|
||||
|
||||
You must give prominent notice with each copy of the work that the
|
||||
Library is used in it and that the Library and its use are covered by
|
||||
this License. You must supply a copy of this License. If the work
|
||||
during execution displays copyright notices, you must include the
|
||||
copyright notice for the Library among them, as well as a reference
|
||||
directing the user to the copy of this License. Also, you must do one
|
||||
of these things:
|
||||
|
||||
a) Accompany the work with the complete corresponding
|
||||
machine-readable source code for the Library including whatever
|
||||
changes were used in the work (which must be distributed under
|
||||
Sections 1 and 2 above); and, if the work is an executable linked
|
||||
with the Library, with the complete machine-readable "work that
|
||||
uses the Library", as object code and/or source code, so that the
|
||||
user can modify the Library and then relink to produce a modified
|
||||
executable containing the modified Library. (It is understood
|
||||
that the user who changes the contents of definitions files in the
|
||||
Library will not necessarily be able to recompile the application
|
||||
to use the modified definitions.)
|
||||
|
||||
b) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (1) uses at run time a
|
||||
copy of the library already present on the user's computer system,
|
||||
rather than copying library functions into the executable, and (2)
|
||||
will operate properly with a modified version of the library, if
|
||||
the user installs one, as long as the modified version is
|
||||
interface-compatible with the version that the work was made with.
|
||||
|
||||
c) Accompany the work with a written offer, valid for at
|
||||
least three years, to give the same user the materials
|
||||
specified in Subsection 6a, above, for a charge no more
|
||||
than the cost of performing this distribution.
|
||||
|
||||
d) If distribution of the work is made by offering access to copy
|
||||
from a designated place, offer equivalent access to copy the above
|
||||
specified materials from the same place.
|
||||
|
||||
e) Verify that the user has already received a copy of these
|
||||
materials or that you have already sent this user a copy.
|
||||
|
||||
For an executable, the required form of the "work that uses the
|
||||
Library" must include any data and utility programs needed for
|
||||
reproducing the executable from it. However, as a special exception,
|
||||
the materials to be distributed need not include anything that is
|
||||
normally distributed (in either source or binary form) with the major
|
||||
components (compiler, kernel, and so on) of the operating system on
|
||||
which the executable runs, unless that component itself accompanies
|
||||
the executable.
|
||||
|
||||
It may happen that this requirement contradicts the license
|
||||
restrictions of other proprietary libraries that do not normally
|
||||
accompany the operating system. Such a contradiction means you cannot
|
||||
use both them and the Library together in an executable that you
|
||||
distribute.
|
||||
|
||||
7. You may place library facilities that are a work based on the
|
||||
Library side-by-side in a single library together with other library
|
||||
facilities not covered by this License, and distribute such a combined
|
||||
library, provided that the separate distribution of the work based on
|
||||
the Library and of the other library facilities is otherwise
|
||||
permitted, and provided that you do these two things:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work
|
||||
based on the Library, uncombined with any other library
|
||||
facilities. This must be distributed under the terms of the
|
||||
Sections above.
|
||||
|
||||
b) Give prominent notice with the combined library of the fact
|
||||
that part of it is a work based on the Library, and explaining
|
||||
where to find the accompanying uncombined form of the same work.
|
||||
|
||||
8. You may not copy, modify, sublicense, link with, or distribute
|
||||
the Library except as expressly provided under this License. Any
|
||||
attempt otherwise to copy, modify, sublicense, link with, or
|
||||
distribute the Library is void, and will automatically terminate your
|
||||
rights under this License. However, parties who have received copies,
|
||||
or rights, from you under this License will not have their licenses
|
||||
terminated so long as such parties remain in full compliance.
|
||||
|
||||
9. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Library or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Library (or any work based on the
|
||||
Library), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Library or works based on it.
|
||||
|
||||
10. Each time you redistribute the Library (or any work based on the
|
||||
Library), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute, link with or modify the Library
|
||||
subject to these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties with
|
||||
this License.
|
||||
|
||||
11. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Library at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Library by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Library.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under any
|
||||
particular circumstance, the balance of the section is intended to apply,
|
||||
and the section as a whole is intended to apply in other circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
12. If the distribution and/or use of the Library is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Library under this License may add
|
||||
an explicit geographical distribution limitation excluding those countries,
|
||||
so that distribution is permitted only in or among countries not thus
|
||||
excluded. In such case, this License incorporates the limitation as if
|
||||
written in the body of this License.
|
||||
|
||||
13. The Free Software Foundation may publish revised and/or new
|
||||
versions of the Lesser General Public License from time to time.
|
||||
Such new versions will be similar in spirit to the present version,
|
||||
but may differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Library
|
||||
specifies a version number of this License which applies to it and
|
||||
"any later version", you have the option of following the terms and
|
||||
conditions either of that version or of any later version published by
|
||||
the Free Software Foundation. If the Library does not specify a
|
||||
license version number, you may choose any version ever published by
|
||||
the Free Software Foundation.
|
||||
|
||||
14. If you wish to incorporate parts of the Library into other free
|
||||
programs whose distribution conditions are incompatible with these,
|
||||
write to the author to ask for permission. For software which is
|
||||
copyrighted by the Free Software Foundation, write to the Free
|
||||
Software Foundation; we sometimes make exceptions for this. Our
|
||||
decision will be guided by the two goals of preserving the free status
|
||||
of all derivatives of our free software and of promoting the sharing
|
||||
and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
||||
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
||||
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||||
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
||||
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||||
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Libraries
|
||||
|
||||
If you develop a new library, and you want it to be of the greatest
|
||||
possible use to the public, we recommend making it free software that
|
||||
everyone can redistribute and change. You can do so by permitting
|
||||
redistribution under these terms (or, alternatively, under the terms of the
|
||||
ordinary General Public License).
|
||||
|
||||
To apply these terms, attach the following notices to the library. It is
|
||||
safest to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least the
|
||||
"copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the library's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the library, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
||||
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1990
|
||||
Ty Coon, President of Vice
|
||||
|
||||
That's all there is to it!
|
|
@ -0,0 +1,34 @@
|
|||
# Copyright (C) 2013 Alexandre Becoulet
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 2.1 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this program. If not, see
|
||||
# <http://www.gnu.org/licenses/>.
|
||||
|
||||
SUBDIRS = src examples test
|
||||
ACLOCAL_AMFLAGS=-Im4
|
||||
|
||||
pkgconfig_DATA = assh.pc
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
|
||||
EXTRA_DIST = \
|
||||
NEWS \
|
||||
ChangeLog \
|
||||
README
|
||||
|
||||
doc: manual internals
|
||||
|
||||
manual:
|
||||
mkdoc -I doc/ -I src/ --conf-file manual.conf
|
||||
|
||||
internals:
|
||||
mkdoc -I doc/ -I src/ --conf-file internals.conf
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,14 @@
|
|||
prefix=@prefix@
|
||||
exec_prefix=@exec_prefix@
|
||||
libdir=@libdir@
|
||||
includedir=@includedir@
|
||||
datarootdir=@datarootdir@
|
||||
datadir=@datadir@
|
||||
|
||||
Name: Assh
|
||||
Description: Asynchronous SSH library
|
||||
Version: @PACKAGE_VERSION@
|
||||
Requires.private:
|
||||
Libs: -L${libdir} -lassh
|
||||
Libs.private:
|
||||
Cflags: -I${includedir}/assh/
|
|
@ -0,0 +1,347 @@
|
|||
#! /bin/sh
|
||||
# Wrapper for compilers which do not understand '-c -o'.
|
||||
|
||||
scriptversion=2012-10-14.11; # UTC
|
||||
|
||||
# Copyright (C) 1999-2014 Free Software Foundation, Inc.
|
||||
# Written by Tom Tromey <tromey@cygnus.com>.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
|
||||
# This file is maintained in Automake, please report
|
||||
# bugs to <bug-automake@gnu.org> or send patches to
|
||||
# <automake-patches@gnu.org>.
|
||||
|
||||
nl='
|
||||
'
|
||||
|
||||
# We need space, tab and new line, in precisely that order. Quoting is
|
||||
# there to prevent tools from complaining about whitespace usage.
|
||||
IFS=" "" $nl"
|
||||
|
||||
file_conv=
|
||||
|
||||
# func_file_conv build_file lazy
|
||||
# Convert a $build file to $host form and store it in $file
|
||||
# Currently only supports Windows hosts. If the determined conversion
|
||||
# type is listed in (the comma separated) LAZY, no conversion will
|
||||
# take place.
|
||||
func_file_conv ()
|
||||
{
|
||||
file=$1
|
||||
case $file in
|
||||
/ | /[!/]*) # absolute file, and not a UNC file
|
||||
if test -z "$file_conv"; then
|
||||
# lazily determine how to convert abs files
|
||||
case `uname -s` in
|
||||
MINGW*)
|
||||
file_conv=mingw
|
||||
;;
|
||||
CYGWIN*)
|
||||
file_conv=cygwin
|
||||
;;
|
||||
*)
|
||||
file_conv=wine
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
case $file_conv/,$2, in
|
||||
*,$file_conv,*)
|
||||
;;
|
||||
mingw/*)
|
||||
file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'`
|
||||
;;
|
||||
cygwin/*)
|
||||
file=`cygpath -m "$file" || echo "$file"`
|
||||
;;
|
||||
wine/*)
|
||||
file=`winepath -w "$file" || echo "$file"`
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# func_cl_dashL linkdir
|
||||
# Make cl look for libraries in LINKDIR
|
||||
func_cl_dashL ()
|
||||
{
|
||||
func_file_conv "$1"
|
||||
if test -z "$lib_path"; then
|
||||
lib_path=$file
|
||||
else
|
||||
lib_path="$lib_path;$file"
|
||||
fi
|
||||
linker_opts="$linker_opts -LIBPATH:$file"
|
||||
}
|
||||
|
||||
# func_cl_dashl library
|
||||
# Do a library search-path lookup for cl
|
||||
func_cl_dashl ()
|
||||
{
|
||||
lib=$1
|
||||
found=no
|
||||
save_IFS=$IFS
|
||||
IFS=';'
|
||||
for dir in $lib_path $LIB
|
||||
do
|
||||
IFS=$save_IFS
|
||||
if $shared && test -f "$dir/$lib.dll.lib"; then
|
||||
found=yes
|
||||
lib=$dir/$lib.dll.lib
|
||||
break
|
||||
fi
|
||||
if test -f "$dir/$lib.lib"; then
|
||||
found=yes
|
||||
lib=$dir/$lib.lib
|
||||
break
|
||||
fi
|
||||
if test -f "$dir/lib$lib.a"; then
|
||||
found=yes
|
||||
lib=$dir/lib$lib.a
|
||||
break
|
||||
fi
|
||||
done
|
||||
IFS=$save_IFS
|
||||
|
||||
if test "$found" != yes; then
|
||||
lib=$lib.lib
|
||||
fi
|
||||
}
|
||||
|
||||
# func_cl_wrapper cl arg...
|
||||
# Adjust compile command to suit cl
|
||||
func_cl_wrapper ()
|
||||
{
|
||||
# Assume a capable shell
|
||||
lib_path=
|
||||
shared=:
|
||||
linker_opts=
|
||||
for arg
|
||||
do
|
||||
if test -n "$eat"; then
|
||||
eat=
|
||||
else
|
||||
case $1 in
|
||||
-o)
|
||||
# configure might choose to run compile as 'compile cc -o foo foo.c'.
|
||||
eat=1
|
||||
case $2 in
|
||||
*.o | *.[oO][bB][jJ])
|
||||
func_file_conv "$2"
|
||||
set x "$@" -Fo"$file"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
func_file_conv "$2"
|
||||
set x "$@" -Fe"$file"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
-I)
|
||||
eat=1
|
||||
func_file_conv "$2" mingw
|
||||
set x "$@" -I"$file"
|
||||
shift
|
||||
;;
|
||||
-I*)
|
||||
func_file_conv "${1#-I}" mingw
|
||||
set x "$@" -I"$file"
|
||||
shift
|
||||
;;
|
||||
-l)
|
||||
eat=1
|
||||
func_cl_dashl "$2"
|
||||
set x "$@" "$lib"
|
||||
shift
|
||||
;;
|
||||
-l*)
|
||||
func_cl_dashl "${1#-l}"
|
||||
set x "$@" "$lib"
|
||||
shift
|
||||
;;
|
||||
-L)
|
||||
eat=1
|
||||
func_cl_dashL "$2"
|
||||
;;
|
||||
-L*)
|
||||
func_cl_dashL "${1#-L}"
|
||||
;;
|
||||
-static)
|
||||
shared=false
|
||||
;;
|
||||
-Wl,*)
|
||||
arg=${1#-Wl,}
|
||||
save_ifs="$IFS"; IFS=','
|
||||
for flag in $arg; do
|
||||
IFS="$save_ifs"
|
||||
linker_opts="$linker_opts $flag"
|
||||
done
|
||||
IFS="$save_ifs"
|
||||
;;
|
||||
-Xlinker)
|
||||
eat=1
|
||||
linker_opts="$linker_opts $2"
|
||||
;;
|
||||
-*)
|
||||
set x "$@" "$1"
|
||||
shift
|
||||
;;
|
||||
*.cc | *.CC | *.cxx | *.CXX | *.[cC]++)
|
||||
func_file_conv "$1"
|
||||
set x "$@" -Tp"$file"
|
||||
shift
|
||||
;;
|
||||
*.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO])
|
||||
func_file_conv "$1" mingw
|
||||
set x "$@" "$file"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
set x "$@" "$1"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
shift
|
||||
done
|
||||
if test -n "$linker_opts"; then
|
||||
linker_opts="-link$linker_opts"
|
||||
fi
|
||||
exec "$@" $linker_opts
|
||||
exit 1
|
||||
}
|
||||
|
||||
eat=
|
||||
|
||||
case $1 in
|
||||
'')
|
||||
echo "$0: No command. Try '$0 --help' for more information." 1>&2
|
||||
exit 1;
|
||||
;;
|
||||
-h | --h*)
|
||||
cat <<\EOF
|
||||
Usage: compile [--help] [--version] PROGRAM [ARGS]
|
||||
|
||||
Wrapper for compilers which do not understand '-c -o'.
|
||||
Remove '-o dest.o' from ARGS, run PROGRAM with the remaining
|
||||
arguments, and rename the output as expected.
|
||||
|
||||
If you are trying to build a whole package this is not the
|
||||
right script to run: please start by reading the file 'INSTALL'.
|
||||
|
||||
Report bugs to <bug-automake@gnu.org>.
|
||||
EOF
|
||||
exit $?
|
||||
;;
|
||||
-v | --v*)
|
||||
echo "compile $scriptversion"
|
||||
exit $?
|
||||
;;
|
||||
cl | *[/\\]cl | cl.exe | *[/\\]cl.exe )
|
||||
func_cl_wrapper "$@" # Doesn't return...
|
||||
;;
|
||||
esac
|
||||
|
||||
ofile=
|
||||
cfile=
|
||||
|
||||
for arg
|
||||
do
|
||||
if test -n "$eat"; then
|
||||
eat=
|
||||
else
|
||||
case $1 in
|
||||
-o)
|
||||
# configure might choose to run compile as 'compile cc -o foo foo.c'.
|
||||
# So we strip '-o arg' only if arg is an object.
|
||||
eat=1
|
||||
case $2 in
|
||||
*.o | *.obj)
|
||||
ofile=$2
|
||||
;;
|
||||
*)
|
||||
set x "$@" -o "$2"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
*.c)
|
||||
cfile=$1
|
||||
set x "$@" "$1"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
set x "$@" "$1"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
shift
|
||||
done
|
||||
|
||||
if test -z "$ofile" || test -z "$cfile"; then
|
||||
# If no '-o' option was seen then we might have been invoked from a
|
||||
# pattern rule where we don't need one. That is ok -- this is a
|
||||
# normal compilation that the losing compiler can handle. If no
|
||||
# '.c' file was seen then we are probably linking. That is also
|
||||
# ok.
|
||||
exec "$@"
|
||||
fi
|
||||
|
||||
# Name of file we expect compiler to create.
|
||||
cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'`
|
||||
|
||||
# Create the lock directory.
|
||||
# Note: use '[/\\:.-]' here to ensure that we don't use the same name
|
||||
# that we are using for the .o file. Also, base the name on the expected
|
||||
# object file name, since that is what matters with a parallel build.
|
||||
lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d
|
||||
while true; do
|
||||
if mkdir "$lockdir" >/dev/null 2>&1; then
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
# FIXME: race condition here if user kills between mkdir and trap.
|
||||
trap "rmdir '$lockdir'; exit 1" 1 2 15
|
||||
|
||||
# Run the compile.
|
||||
"$@"
|
||||
ret=$?
|
||||
|
||||
if test -f "$cofile"; then
|
||||
test "$cofile" = "$ofile" || mv "$cofile" "$ofile"
|
||||
elif test -f "${cofile}bj"; then
|
||||
test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile"
|
||||
fi
|
||||
|
||||
rmdir "$lockdir"
|
||||
exit $ret
|
||||
|
||||
# Local Variables:
|
||||
# mode: shell-script
|
||||
# sh-indentation: 2
|
||||
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,791 @@
|
|||
#! /bin/sh
|
||||
# depcomp - compile a program generating dependencies as side-effects
|
||||
|
||||
scriptversion=2013-05-30.07; # UTC
|
||||
|
||||
# Copyright (C) 1999-2014 Free Software Foundation, Inc.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
|
||||
# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>.
|
||||
|
||||
case $1 in
|
||||
'')
|
||||
echo "$0: No command. Try '$0 --help' for more information." 1>&2
|
||||
exit 1;
|
||||
;;
|
||||
-h | --h*)
|
||||
cat <<\EOF
|
||||
Usage: depcomp [--help] [--version] PROGRAM [ARGS]
|
||||
|
||||
Run PROGRAMS ARGS to compile a file, generating dependencies
|
||||
as side-effects.
|
||||
|
||||
Environment variables:
|
||||
depmode Dependency tracking mode.
|
||||
source Source file read by 'PROGRAMS ARGS'.
|
||||
object Object file output by 'PROGRAMS ARGS'.
|
||||
DEPDIR directory where to store dependencies.
|
||||
depfile Dependency file to output.
|
||||
tmpdepfile Temporary file to use when outputting dependencies.
|
||||
libtool Whether libtool is used (yes/no).
|
||||
|
||||
Report bugs to <bug-automake@gnu.org>.
|
||||
EOF
|
||||
exit $?
|
||||
;;
|
||||
-v | --v*)
|
||||
echo "depcomp $scriptversion"
|
||||
exit $?
|
||||
;;
|
||||
esac
|
||||
|
||||
# Get the directory component of the given path, and save it in the
|
||||
# global variables '$dir'. Note that this directory component will
|
||||
# be either empty or ending with a '/' character. This is deliberate.
|
||||
set_dir_from ()
|
||||
{
|
||||
case $1 in
|
||||
*/*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;;
|
||||
*) dir=;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Get the suffix-stripped basename of the given path, and save it the
|
||||
# global variable '$base'.
|
||||
set_base_from ()
|
||||
{
|
||||
base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'`
|
||||
}
|
||||
|
||||
# If no dependency file was actually created by the compiler invocation,
|
||||
# we still have to create a dummy depfile, to avoid errors with the
|
||||
# Makefile "include basename.Plo" scheme.
|
||||
make_dummy_depfile ()
|
||||
{
|
||||
echo "#dummy" > "$depfile"
|
||||
}
|
||||
|
||||
# Factor out some common post-processing of the generated depfile.
|
||||
# Requires the auxiliary global variable '$tmpdepfile' to be set.
|
||||
aix_post_process_depfile ()
|
||||
{
|
||||
# If the compiler actually managed to produce a dependency file,
|
||||
# post-process it.
|
||||
if test -f "$tmpdepfile"; then
|
||||
# Each line is of the form 'foo.o: dependency.h'.
|
||||
# Do two passes, one to just change these to
|
||||
# $object: dependency.h
|
||||
# and one to simply output
|
||||
# dependency.h:
|
||||
# which is needed to avoid the deleted-header problem.
|
||||
{ sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile"
|
||||
sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile"
|
||||
} > "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
else
|
||||
make_dummy_depfile
|
||||
fi
|
||||
}
|
||||
|
||||
# A tabulation character.
|
||||
tab=' '
|
||||
# A newline character.
|
||||
nl='
|
||||
'
|
||||
# Character ranges might be problematic outside the C locale.
|
||||
# These definitions help.
|
||||
upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ
|
||||
lower=abcdefghijklmnopqrstuvwxyz
|
||||
digits=0123456789
|
||||
alpha=${upper}${lower}
|
||||
|
||||
if test -z "$depmode" || test -z "$source" || test -z "$object"; then
|
||||
echo "depcomp: Variables source, object and depmode must be set" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
|
||||
depfile=${depfile-`echo "$object" |
|
||||
sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
|
||||
tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
|
||||
|
||||
rm -f "$tmpdepfile"
|
||||
|
||||
# Avoid interferences from the environment.
|
||||
gccflag= dashmflag=
|
||||
|
||||
# Some modes work just like other modes, but use different flags. We
|
||||
# parameterize here, but still list the modes in the big case below,
|
||||
# to make depend.m4 easier to write. Note that we *cannot* use a case
|
||||
# here, because this file can only contain one case statement.
|
||||
if test "$depmode" = hp; then
|
||||
# HP compiler uses -M and no extra arg.
|
||||
gccflag=-M
|
||||
depmode=gcc
|
||||
fi
|
||||
|
||||
if test "$depmode" = dashXmstdout; then
|
||||
# This is just like dashmstdout with a different argument.
|
||||
dashmflag=-xM
|
||||
depmode=dashmstdout
|
||||
fi
|
||||
|
||||
cygpath_u="cygpath -u -f -"
|
||||
if test "$depmode" = msvcmsys; then
|
||||
# This is just like msvisualcpp but w/o cygpath translation.
|
||||
# Just convert the backslash-escaped backslashes to single forward
|
||||
# slashes to satisfy depend.m4
|
||||
cygpath_u='sed s,\\\\,/,g'
|
||||
depmode=msvisualcpp
|
||||
fi
|
||||
|
||||
if test "$depmode" = msvc7msys; then
|
||||
# This is just like msvc7 but w/o cygpath translation.
|
||||
# Just convert the backslash-escaped backslashes to single forward
|
||||
# slashes to satisfy depend.m4
|
||||
cygpath_u='sed s,\\\\,/,g'
|
||||
depmode=msvc7
|
||||
fi
|
||||
|
||||
if test "$depmode" = xlc; then
|
||||
# IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information.
|
||||
gccflag=-qmakedep=gcc,-MF
|
||||
depmode=gcc
|
||||
fi
|
||||
|
||||
case "$depmode" in
|
||||
gcc3)
|
||||
## gcc 3 implements dependency tracking that does exactly what
|
||||
## we want. Yay! Note: for some reason libtool 1.4 doesn't like
|
||||
## it if -MD -MP comes after the -MF stuff. Hmm.
|
||||
## Unfortunately, FreeBSD c89 acceptance of flags depends upon
|
||||
## the command line argument order; so add the flags where they
|
||||
## appear in depend2.am. Note that the slowdown incurred here
|
||||
## affects only configure: in makefiles, %FASTDEP% shortcuts this.
|
||||
for arg
|
||||
do
|
||||
case $arg in
|
||||
-c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;;
|
||||
*) set fnord "$@" "$arg" ;;
|
||||
esac
|
||||
shift # fnord
|
||||
shift # $arg
|
||||
done
|
||||
"$@"
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
mv "$tmpdepfile" "$depfile"
|
||||
;;
|
||||
|
||||
gcc)
|
||||
## Note that this doesn't just cater to obsosete pre-3.x GCC compilers.
|
||||
## but also to in-use compilers like IMB xlc/xlC and the HP C compiler.
|
||||
## (see the conditional assignment to $gccflag above).
|
||||
## There are various ways to get dependency output from gcc. Here's
|
||||
## why we pick this rather obscure method:
|
||||
## - Don't want to use -MD because we'd like the dependencies to end
|
||||
## up in a subdir. Having to rename by hand is ugly.
|
||||
## (We might end up doing this anyway to support other compilers.)
|
||||
## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
|
||||
## -MM, not -M (despite what the docs say). Also, it might not be
|
||||
## supported by the other compilers which use the 'gcc' depmode.
|
||||
## - Using -M directly means running the compiler twice (even worse
|
||||
## than renaming).
|
||||
if test -z "$gccflag"; then
|
||||
gccflag=-MD,
|
||||
fi
|
||||
"$@" -Wp,"$gccflag$tmpdepfile"
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
echo "$object : \\" > "$depfile"
|
||||
# The second -e expression handles DOS-style file names with drive
|
||||
# letters.
|
||||
sed -e 's/^[^:]*: / /' \
|
||||
-e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
|
||||
## This next piece of magic avoids the "deleted header file" problem.
|
||||
## The problem is that when a header file which appears in a .P file
|
||||
## is deleted, the dependency causes make to die (because there is
|
||||
## typically no way to rebuild the header). We avoid this by adding
|
||||
## dummy dependencies for each header file. Too bad gcc doesn't do
|
||||
## this for us directly.
|
||||
## Some versions of gcc put a space before the ':'. On the theory
|
||||
## that the space means something, we add a space to the output as
|
||||
## well. hp depmode also adds that space, but also prefixes the VPATH
|
||||
## to the object. Take care to not repeat it in the output.
|
||||
## Some versions of the HPUX 10.20 sed can't process this invocation
|
||||
## correctly. Breaking it into two sed invocations is a workaround.
|
||||
tr ' ' "$nl" < "$tmpdepfile" \
|
||||
| sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \
|
||||
| sed -e 's/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
hp)
|
||||
# This case exists only to let depend.m4 do its work. It works by
|
||||
# looking at the text of this script. This case will never be run,
|
||||
# since it is checked for above.
|
||||
exit 1
|
||||
;;
|
||||
|
||||
sgi)
|
||||
if test "$libtool" = yes; then
|
||||
"$@" "-Wp,-MDupdate,$tmpdepfile"
|
||||
else
|
||||
"$@" -MDupdate "$tmpdepfile"
|
||||
fi
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
|
||||
if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
|
||||
echo "$object : \\" > "$depfile"
|
||||
# Clip off the initial element (the dependent). Don't try to be
|
||||
# clever and replace this with sed code, as IRIX sed won't handle
|
||||
# lines with more than a fixed number of characters (4096 in
|
||||
# IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
|
||||
# the IRIX cc adds comments like '#:fec' to the end of the
|
||||
# dependency line.
|
||||
tr ' ' "$nl" < "$tmpdepfile" \
|
||||
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \
|
||||
| tr "$nl" ' ' >> "$depfile"
|
||||
echo >> "$depfile"
|
||||
# The second pass generates a dummy entry for each header file.
|
||||
tr ' ' "$nl" < "$tmpdepfile" \
|
||||
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
|
||||
>> "$depfile"
|
||||
else
|
||||
make_dummy_depfile
|
||||
fi
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
xlc)
|
||||
# This case exists only to let depend.m4 do its work. It works by
|
||||
# looking at the text of this script. This case will never be run,
|
||||
# since it is checked for above.
|
||||
exit 1
|
||||
;;
|
||||
|
||||
aix)
|
||||
# The C for AIX Compiler uses -M and outputs the dependencies
|
||||
# in a .u file. In older versions, this file always lives in the
|
||||
# current directory. Also, the AIX compiler puts '$object:' at the
|
||||
# start of each line; $object doesn't have directory information.
|
||||
# Version 6 uses the directory in both cases.
|
||||
set_dir_from "$object"
|
||||
set_base_from "$object"
|
||||
if test "$libtool" = yes; then
|
||||
tmpdepfile1=$dir$base.u
|
||||
tmpdepfile2=$base.u
|
||||
tmpdepfile3=$dir.libs/$base.u
|
||||
"$@" -Wc,-M
|
||||
else
|
||||
tmpdepfile1=$dir$base.u
|
||||
tmpdepfile2=$dir$base.u
|
||||
tmpdepfile3=$dir$base.u
|
||||
"$@" -M
|
||||
fi
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
|
||||
exit $stat
|
||||
fi
|
||||
|
||||
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
|
||||
do
|
||||
test -f "$tmpdepfile" && break
|
||||
done
|
||||
aix_post_process_depfile
|
||||
;;
|
||||
|
||||
tcc)
|
||||
# tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26
|
||||
# FIXME: That version still under development at the moment of writing.
|
||||
# Make that this statement remains true also for stable, released
|
||||
# versions.
|
||||
# It will wrap lines (doesn't matter whether long or short) with a
|
||||
# trailing '\', as in:
|
||||
#
|
||||
# foo.o : \
|
||||
# foo.c \
|
||||
# foo.h \
|
||||
#
|
||||
# It will put a trailing '\' even on the last line, and will use leading
|
||||
# spaces rather than leading tabs (at least since its commit 0394caf7
|
||||
# "Emit spaces for -MD").
|
||||
"$@" -MD -MF "$tmpdepfile"
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
# Each non-empty line is of the form 'foo.o : \' or ' dep.h \'.
|
||||
# We have to change lines of the first kind to '$object: \'.
|
||||
sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile"
|
||||
# And for each line of the second kind, we have to emit a 'dep.h:'
|
||||
# dummy dependency, to avoid the deleted-header problem.
|
||||
sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
## The order of this option in the case statement is important, since the
|
||||
## shell code in configure will try each of these formats in the order
|
||||
## listed in this file. A plain '-MD' option would be understood by many
|
||||
## compilers, so we must ensure this comes after the gcc and icc options.
|
||||
pgcc)
|
||||
# Portland's C compiler understands '-MD'.
|
||||
# Will always output deps to 'file.d' where file is the root name of the
|
||||
# source file under compilation, even if file resides in a subdirectory.
|
||||
# The object file name does not affect the name of the '.d' file.
|
||||
# pgcc 10.2 will output
|
||||
# foo.o: sub/foo.c sub/foo.h
|
||||
# and will wrap long lines using '\' :
|
||||
# foo.o: sub/foo.c ... \
|
||||
# sub/foo.h ... \
|
||||
# ...
|
||||
set_dir_from "$object"
|
||||
# Use the source, not the object, to determine the base name, since
|
||||
# that's sadly what pgcc will do too.
|
||||
set_base_from "$source"
|
||||
tmpdepfile=$base.d
|
||||
|
||||
# For projects that build the same source file twice into different object
|
||||
# files, the pgcc approach of using the *source* file root name can cause
|
||||
# problems in parallel builds. Use a locking strategy to avoid stomping on
|
||||
# the same $tmpdepfile.
|
||||
lockdir=$base.d-lock
|
||||
trap "
|
||||
echo '$0: caught signal, cleaning up...' >&2
|
||||
rmdir '$lockdir'
|
||||
exit 1
|
||||
" 1 2 13 15
|
||||
numtries=100
|
||||
i=$numtries
|
||||
while test $i -gt 0; do
|
||||
# mkdir is a portable test-and-set.
|
||||
if mkdir "$lockdir" 2>/dev/null; then
|
||||
# This process acquired the lock.
|
||||
"$@" -MD
|
||||
stat=$?
|
||||
# Release the lock.
|
||||
rmdir "$lockdir"
|
||||
break
|
||||
else
|
||||
# If the lock is being held by a different process, wait
|
||||
# until the winning process is done or we timeout.
|
||||
while test -d "$lockdir" && test $i -gt 0; do
|
||||
sleep 1
|
||||
i=`expr $i - 1`
|
||||
done
|
||||
fi
|
||||
i=`expr $i - 1`
|
||||
done
|
||||
trap - 1 2 13 15
|
||||
if test $i -le 0; then
|
||||
echo "$0: failed to acquire lock after $numtries attempts" >&2
|
||||
echo "$0: check lockdir '$lockdir'" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
# Each line is of the form `foo.o: dependent.h',
|
||||
# or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
|
||||
# Do two passes, one to just change these to
|
||||
# `$object: dependent.h' and one to simply `dependent.h:'.
|
||||
sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
|
||||
# Some versions of the HPUX 10.20 sed can't process this invocation
|
||||
# correctly. Breaking it into two sed invocations is a workaround.
|
||||
sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \
|
||||
| sed -e 's/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
hp2)
|
||||
# The "hp" stanza above does not work with aCC (C++) and HP's ia64
|
||||
# compilers, which have integrated preprocessors. The correct option
|
||||
# to use with these is +Maked; it writes dependencies to a file named
|
||||
# 'foo.d', which lands next to the object file, wherever that
|
||||
# happens to be.
|
||||
# Much of this is similar to the tru64 case; see comments there.
|
||||
set_dir_from "$object"
|
||||
set_base_from "$object"
|
||||
if test "$libtool" = yes; then
|
||||
tmpdepfile1=$dir$base.d
|
||||
tmpdepfile2=$dir.libs/$base.d
|
||||
"$@" -Wc,+Maked
|
||||
else
|
||||
tmpdepfile1=$dir$base.d
|
||||
tmpdepfile2=$dir$base.d
|
||||
"$@" +Maked
|
||||
fi
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile1" "$tmpdepfile2"
|
||||
exit $stat
|
||||
fi
|
||||
|
||||
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2"
|
||||
do
|
||||
test -f "$tmpdepfile" && break
|
||||
done
|
||||
if test -f "$tmpdepfile"; then
|
||||
sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile"
|
||||
# Add 'dependent.h:' lines.
|
||||
sed -ne '2,${
|
||||
s/^ *//
|
||||
s/ \\*$//
|
||||
s/$/:/
|
||||
p
|
||||
}' "$tmpdepfile" >> "$depfile"
|
||||
else
|
||||
make_dummy_depfile
|
||||
fi
|
||||
rm -f "$tmpdepfile" "$tmpdepfile2"
|
||||
;;
|
||||
|
||||
tru64)
|
||||
# The Tru64 compiler uses -MD to generate dependencies as a side
|
||||
# effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'.
|
||||
# At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
|
||||
# dependencies in 'foo.d' instead, so we check for that too.
|
||||
# Subdirectories are respected.
|
||||
set_dir_from "$object"
|
||||
set_base_from "$object"
|
||||
|
||||
if test "$libtool" = yes; then
|
||||
# Libtool generates 2 separate objects for the 2 libraries. These
|
||||
# two compilations output dependencies in $dir.libs/$base.o.d and
|
||||
# in $dir$base.o.d. We have to check for both files, because
|
||||
# one of the two compilations can be disabled. We should prefer
|
||||
# $dir$base.o.d over $dir.libs/$base.o.d because the latter is
|
||||
# automatically cleaned when .libs/ is deleted, while ignoring
|
||||
# the former would cause a distcleancheck panic.
|
||||
tmpdepfile1=$dir$base.o.d # libtool 1.5
|
||||
tmpdepfile2=$dir.libs/$base.o.d # Likewise.
|
||||
tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504
|
||||
"$@" -Wc,-MD
|
||||
else
|
||||
tmpdepfile1=$dir$base.d
|
||||
tmpdepfile2=$dir$base.d
|
||||
tmpdepfile3=$dir$base.d
|
||||
"$@" -MD
|
||||
fi
|
||||
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
|
||||
exit $stat
|
||||
fi
|
||||
|
||||
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
|
||||
do
|
||||
test -f "$tmpdepfile" && break
|
||||
done
|
||||
# Same post-processing that is required for AIX mode.
|
||||
aix_post_process_depfile
|
||||
;;
|
||||
|
||||
msvc7)
|
||||
if test "$libtool" = yes; then
|
||||
showIncludes=-Wc,-showIncludes
|
||||
else
|
||||
showIncludes=-showIncludes
|
||||
fi
|
||||
"$@" $showIncludes > "$tmpdepfile"
|
||||
stat=$?
|
||||
grep -v '^Note: including file: ' "$tmpdepfile"
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
echo "$object : \\" > "$depfile"
|
||||
# The first sed program below extracts the file names and escapes
|
||||
# backslashes for cygpath. The second sed program outputs the file
|
||||
# name when reading, but also accumulates all include files in the
|
||||
# hold buffer in order to output them again at the end. This only
|
||||
# works with sed implementations that can handle large buffers.
|
||||
sed < "$tmpdepfile" -n '
|
||||
/^Note: including file: *\(.*\)/ {
|
||||
s//\1/
|
||||
s/\\/\\\\/g
|
||||
p
|
||||
}' | $cygpath_u | sort -u | sed -n '
|
||||
s/ /\\ /g
|
||||
s/\(.*\)/'"$tab"'\1 \\/p
|
||||
s/.\(.*\) \\/\1:/
|
||||
H
|
||||
$ {
|
||||
s/.*/'"$tab"'/
|
||||
G
|
||||
p
|
||||
}' >> "$depfile"
|
||||
echo >> "$depfile" # make sure the fragment doesn't end with a backslash
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
msvc7msys)
|
||||
# This case exists only to let depend.m4 do its work. It works by
|
||||
# looking at the text of this script. This case will never be run,
|
||||
# since it is checked for above.
|
||||
exit 1
|
||||
;;
|
||||
|
||||
#nosideeffect)
|
||||
# This comment above is used by automake to tell side-effect
|
||||
# dependency tracking mechanisms from slower ones.
|
||||
|
||||
dashmstdout)
|
||||
# Important note: in order to support this mode, a compiler *must*
|
||||
# always write the preprocessed file to stdout, regardless of -o.
|
||||
"$@" || exit $?
|
||||
|
||||
# Remove the call to Libtool.
|
||||
if test "$libtool" = yes; then
|
||||
while test "X$1" != 'X--mode=compile'; do
|
||||
shift
|
||||
done
|
||||
shift
|
||||
fi
|
||||
|
||||
# Remove '-o $object'.
|
||||
IFS=" "
|
||||
for arg
|
||||
do
|
||||
case $arg in
|
||||
-o)
|
||||
shift
|
||||
;;
|
||||
$object)
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
set fnord "$@" "$arg"
|
||||
shift # fnord
|
||||
shift # $arg
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
test -z "$dashmflag" && dashmflag=-M
|
||||
# Require at least two characters before searching for ':'
|
||||
# in the target name. This is to cope with DOS-style filenames:
|
||||
# a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise.
|
||||
"$@" $dashmflag |
|
||||
sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile"
|
||||
rm -f "$depfile"
|
||||
cat < "$tmpdepfile" > "$depfile"
|
||||
# Some versions of the HPUX 10.20 sed can't process this sed invocation
|
||||
# correctly. Breaking it into two sed invocations is a workaround.
|
||||
tr ' ' "$nl" < "$tmpdepfile" \
|
||||
| sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
|
||||
| sed -e 's/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
dashXmstdout)
|
||||
# This case only exists to satisfy depend.m4. It is never actually
|
||||
# run, as this mode is specially recognized in the preamble.
|
||||
exit 1
|
||||
;;
|
||||
|
||||
makedepend)
|
||||
"$@" || exit $?
|
||||
# Remove any Libtool call
|
||||
if test "$libtool" = yes; then
|
||||
while test "X$1" != 'X--mode=compile'; do
|
||||
shift
|
||||
done
|
||||
shift
|
||||
fi
|
||||
# X makedepend
|
||||
shift
|
||||
cleared=no eat=no
|
||||
for arg
|
||||
do
|
||||
case $cleared in
|
||||
no)
|
||||
set ""; shift
|
||||
cleared=yes ;;
|
||||
esac
|
||||
if test $eat = yes; then
|
||||
eat=no
|
||||
continue
|
||||
fi
|
||||
case "$arg" in
|
||||
-D*|-I*)
|
||||
set fnord "$@" "$arg"; shift ;;
|
||||
# Strip any option that makedepend may not understand. Remove
|
||||
# the object too, otherwise makedepend will parse it as a source file.
|
||||
-arch)
|
||||
eat=yes ;;
|
||||
-*|$object)
|
||||
;;
|
||||
*)
|
||||
set fnord "$@" "$arg"; shift ;;
|
||||
esac
|
||||
done
|
||||
obj_suffix=`echo "$object" | sed 's/^.*\././'`
|
||||
touch "$tmpdepfile"
|
||||
${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
|
||||
rm -f "$depfile"
|
||||
# makedepend may prepend the VPATH from the source file name to the object.
|
||||
# No need to regex-escape $object, excess matching of '.' is harmless.
|
||||
sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile"
|
||||
# Some versions of the HPUX 10.20 sed can't process the last invocation
|
||||
# correctly. Breaking it into two sed invocations is a workaround.
|
||||
sed '1,2d' "$tmpdepfile" \
|
||||
| tr ' ' "$nl" \
|
||||
| sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
|
||||
| sed -e 's/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile" "$tmpdepfile".bak
|
||||
;;
|
||||
|
||||
cpp)
|
||||
# Important note: in order to support this mode, a compiler *must*
|
||||
# always write the preprocessed file to stdout.
|
||||
"$@" || exit $?
|
||||
|
||||
# Remove the call to Libtool.
|
||||
if test "$libtool" = yes; then
|
||||
while test "X$1" != 'X--mode=compile'; do
|
||||
shift
|
||||
done
|
||||
shift
|
||||
fi
|
||||
|
||||
# Remove '-o $object'.
|
||||
IFS=" "
|
||||
for arg
|
||||
do
|
||||
case $arg in
|
||||
-o)
|
||||
shift
|
||||
;;
|
||||
$object)
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
set fnord "$@" "$arg"
|
||||
shift # fnord
|
||||
shift # $arg
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
"$@" -E \
|
||||
| sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
|
||||
-e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
|
||||
| sed '$ s: \\$::' > "$tmpdepfile"
|
||||
rm -f "$depfile"
|
||||
echo "$object : \\" > "$depfile"
|
||||
cat < "$tmpdepfile" >> "$depfile"
|
||||
sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
msvisualcpp)
|
||||
# Important note: in order to support this mode, a compiler *must*
|
||||
# always write the preprocessed file to stdout.
|
||||
"$@" || exit $?
|
||||
|
||||
# Remove the call to Libtool.
|
||||
if test "$libtool" = yes; then
|
||||
while test "X$1" != 'X--mode=compile'; do
|
||||
shift
|
||||
done
|
||||
shift
|
||||
fi
|
||||
|
||||
IFS=" "
|
||||
for arg
|
||||
do
|
||||
case "$arg" in
|
||||
-o)
|
||||
shift
|
||||
;;
|
||||
$object)
|
||||
shift
|
||||
;;
|
||||
"-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
|
||||
set fnord "$@"
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
set fnord "$@" "$arg"
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
"$@" -E 2>/dev/null |
|
||||
sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile"
|
||||
rm -f "$depfile"
|
||||
echo "$object : \\" > "$depfile"
|
||||
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile"
|
||||
echo "$tab" >> "$depfile"
|
||||
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
msvcmsys)
|
||||
# This case exists only to let depend.m4 do its work. It works by
|
||||
# looking at the text of this script. This case will never be run,
|
||||
# since it is checked for above.
|
||||
exit 1
|
||||
;;
|
||||
|
||||
none)
|
||||
exec "$@"
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "Unknown depmode $depmode" 1>&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
|
||||
# Local Variables:
|
||||
# mode: shell-script
|
||||
# sh-indentation: 2
|
||||
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
|
@ -0,0 +1,501 @@
|
|||
#!/bin/sh
|
||||
# install - install a program, script, or datafile
|
||||
|
||||
scriptversion=2013-12-25.23; # UTC
|
||||
|
||||
# This originates from X11R5 (mit/util/scripts/install.sh), which was
|
||||
# later released in X11R6 (xc/config/util/install.sh) with the
|
||||
# following copyright and license.
|
||||
#
|
||||
# Copyright (C) 1994 X Consortium
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to
|
||||
# deal in the Software without restriction, including without limitation the
|
||||
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
# sell copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
|
||||
# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
# Except as contained in this notice, the name of the X Consortium shall not
|
||||
# be used in advertising or otherwise to promote the sale, use or other deal-
|
||||
# ings in this Software without prior written authorization from the X Consor-
|
||||
# tium.
|
||||
#
|
||||
#
|
||||
# FSF changes to this file are in the public domain.
|
||||
#
|
||||
# Calling this script install-sh is preferred over install.sh, to prevent
|
||||
# 'make' implicit rules from creating a file called install from it
|
||||
# when there is no Makefile.
|
||||
#
|
||||
# This script is compatible with the BSD install script, but was written
|
||||
# from scratch.
|
||||
|
||||
tab=' '
|
||||
nl='
|
||||
'
|
||||
IFS=" $tab$nl"
|
||||
|
||||
# Set DOITPROG to "echo" to test this script.
|
||||
|
||||
doit=${DOITPROG-}
|
||||
doit_exec=${doit:-exec}
|
||||
|
||||
# Put in absolute file names if you don't have them in your path;
|
||||
# or use environment vars.
|
||||
|
||||
chgrpprog=${CHGRPPROG-chgrp}
|
||||
chmodprog=${CHMODPROG-chmod}
|
||||
chownprog=${CHOWNPROG-chown}
|
||||
cmpprog=${CMPPROG-cmp}
|
||||
cpprog=${CPPROG-cp}
|
||||
mkdirprog=${MKDIRPROG-mkdir}
|
||||
mvprog=${MVPROG-mv}
|
||||
rmprog=${RMPROG-rm}
|
||||
stripprog=${STRIPPROG-strip}
|
||||
|
||||
posix_mkdir=
|
||||
|
||||
# Desired mode of installed file.
|
||||
mode=0755
|
||||
|
||||
chgrpcmd=
|
||||
chmodcmd=$chmodprog
|
||||
chowncmd=
|
||||
mvcmd=$mvprog
|
||||
rmcmd="$rmprog -f"
|
||||
stripcmd=
|
||||
|
||||
src=
|
||||
dst=
|
||||
dir_arg=
|
||||
dst_arg=
|
||||
|
||||
copy_on_change=false
|
||||
is_target_a_directory=possibly
|
||||
|
||||
usage="\
|
||||
Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
|
||||
or: $0 [OPTION]... SRCFILES... DIRECTORY
|
||||
or: $0 [OPTION]... -t DIRECTORY SRCFILES...
|
||||
or: $0 [OPTION]... -d DIRECTORIES...
|
||||
|
||||
In the 1st form, copy SRCFILE to DSTFILE.
|
||||
In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
|
||||
In the 4th, create DIRECTORIES.
|
||||
|
||||
Options:
|
||||
--help display this help and exit.
|
||||
--version display version info and exit.
|
||||
|
||||
-c (ignored)
|
||||
-C install only if different (preserve the last data modification time)
|
||||
-d create directories instead of installing files.
|
||||
-g GROUP $chgrpprog installed files to GROUP.
|
||||
-m MODE $chmodprog installed files to MODE.
|
||||
-o USER $chownprog installed files to USER.
|
||||
-s $stripprog installed files.
|
||||
-t DIRECTORY install into DIRECTORY.
|
||||
-T report an error if DSTFILE is a directory.
|
||||
|
||||
Environment variables override the default commands:
|
||||
CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
|
||||
RMPROG STRIPPROG
|
||||
"
|
||||
|
||||
while test $# -ne 0; do
|
||||
case $1 in
|
||||
-c) ;;
|
||||
|
||||
-C) copy_on_change=true;;
|
||||
|
||||
-d) dir_arg=true;;
|
||||
|
||||
-g) chgrpcmd="$chgrpprog $2"
|
||||
shift;;
|
||||
|
||||
--help) echo "$usage"; exit $?;;
|
||||
|
||||
-m) mode=$2
|
||||
case $mode in
|
||||
*' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*)
|
||||
echo "$0: invalid mode: $mode" >&2
|
||||
exit 1;;
|
||||
esac
|
||||
shift;;
|
||||
|
||||
-o) chowncmd="$chownprog $2"
|
||||
shift;;
|
||||
|
||||
-s) stripcmd=$stripprog;;
|
||||
|
||||
-t)
|
||||
is_target_a_directory=always
|
||||
dst_arg=$2
|
||||
# Protect names problematic for 'test' and other utilities.
|
||||
case $dst_arg in
|
||||
-* | [=\(\)!]) dst_arg=./$dst_arg;;
|
||||
esac
|
||||
shift;;
|
||||
|
||||
-T) is_target_a_directory=never;;
|
||||
|
||||
--version) echo "$0 $scriptversion"; exit $?;;
|
||||
|
||||
--) shift
|
||||
break;;
|
||||
|
||||
-*) echo "$0: invalid option: $1" >&2
|
||||
exit 1;;
|
||||
|
||||
*) break;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
# We allow the use of options -d and -T together, by making -d
|
||||
# take the precedence; this is for compatibility with GNU install.
|
||||
|
||||
if test -n "$dir_arg"; then
|
||||
if test -n "$dst_arg"; then
|
||||
echo "$0: target directory not allowed when installing a directory." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
|
||||
# When -d is used, all remaining arguments are directories to create.
|
||||
# When -t is used, the destination is already specified.
|
||||
# Otherwise, the last argument is the destination. Remove it from $@.
|
||||
for arg
|
||||
do
|
||||
if test -n "$dst_arg"; then
|
||||
# $@ is not empty: it contains at least $arg.
|
||||
set fnord "$@" "$dst_arg"
|
||||
shift # fnord
|
||||
fi
|
||||
shift # arg
|
||||
dst_arg=$arg
|
||||
# Protect names problematic for 'test' and other utilities.
|
||||
case $dst_arg in
|
||||
-* | [=\(\)!]) dst_arg=./$dst_arg;;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
|
||||
if test $# -eq 0; then
|
||||
if test -z "$dir_arg"; then
|
||||
echo "$0: no input file specified." >&2
|
||||
exit 1
|
||||
fi
|
||||
# It's OK to call 'install-sh -d' without argument.
|
||||
# This can happen when creating conditional directories.
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if test -z "$dir_arg"; then
|
||||
if test $# -gt 1 || test "$is_target_a_directory" = always; then
|
||||
if test ! -d "$dst_arg"; then
|
||||
echo "$0: $dst_arg: Is not a directory." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -z "$dir_arg"; then
|
||||
do_exit='(exit $ret); exit $ret'
|
||||
trap "ret=129; $do_exit" 1
|
||||
trap "ret=130; $do_exit" 2
|
||||
trap "ret=141; $do_exit" 13
|
||||
trap "ret=143; $do_exit" 15
|
||||
|
||||
# Set umask so as not to create temps with too-generous modes.
|
||||
# However, 'strip' requires both read and write access to temps.
|
||||
case $mode in
|
||||
# Optimize common cases.
|
||||
*644) cp_umask=133;;
|
||||
*755) cp_umask=22;;
|
||||
|
||||
*[0-7])
|
||||
if test -z "$stripcmd"; then
|
||||
u_plus_rw=
|
||||
else
|
||||
u_plus_rw='% 200'
|
||||
fi
|
||||
cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
|
||||
*)
|
||||
if test -z "$stripcmd"; then
|
||||
u_plus_rw=
|
||||
else
|
||||
u_plus_rw=,u+rw
|
||||
fi
|
||||
cp_umask=$mode$u_plus_rw;;
|
||||
esac
|
||||
fi
|
||||
|
||||
for src
|
||||
do
|
||||
# Protect names problematic for 'test' and other utilities.
|
||||
case $src in
|
||||
-* | [=\(\)!]) src=./$src;;
|
||||
esac
|
||||
|
||||
if test -n "$dir_arg"; then
|
||||
dst=$src
|
||||
dstdir=$dst
|
||||
test -d "$dstdir"
|
||||
dstdir_status=$?
|
||||
else
|
||||
|
||||
# Waiting for this to be detected by the "$cpprog $src $dsttmp" command
|
||||
# might cause directories to be created, which would be especially bad
|
||||
# if $src (and thus $dsttmp) contains '*'.
|
||||
if test ! -f "$src" && test ! -d "$src"; then
|
||||
echo "$0: $src does not exist." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if test -z "$dst_arg"; then
|
||||
echo "$0: no destination specified." >&2
|
||||
exit 1
|
||||
fi
|
||||
dst=$dst_arg
|
||||
|
||||
# If destination is a directory, append the input filename; won't work
|
||||
# if double slashes aren't ignored.
|
||||
if test -d "$dst"; then
|
||||
if test "$is_target_a_directory" = never; then
|
||||
echo "$0: $dst_arg: Is a directory" >&2
|
||||
exit 1
|
||||
fi
|
||||
dstdir=$dst
|
||||
dst=$dstdir/`basename "$src"`
|
||||
dstdir_status=0
|
||||
else
|
||||
dstdir=`dirname "$dst"`
|
||||
test -d "$dstdir"
|
||||
dstdir_status=$?
|
||||
fi
|
||||
fi
|
||||
|
||||
obsolete_mkdir_used=false
|
||||
|
||||
if test $dstdir_status != 0; then
|
||||
case $posix_mkdir in
|
||||
'')
|
||||
# Create intermediate dirs using mode 755 as modified by the umask.
|
||||
# This is like FreeBSD 'install' as of 1997-10-28.
|
||||
umask=`umask`
|
||||
case $stripcmd.$umask in
|
||||
# Optimize common cases.
|
||||
*[2367][2367]) mkdir_umask=$umask;;
|
||||
.*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
|
||||
|
||||
*[0-7])
|
||||
mkdir_umask=`expr $umask + 22 \
|
||||
- $umask % 100 % 40 + $umask % 20 \
|
||||
- $umask % 10 % 4 + $umask % 2
|
||||
`;;
|
||||
*) mkdir_umask=$umask,go-w;;
|
||||
esac
|
||||
|
||||
# With -d, create the new directory with the user-specified mode.
|
||||
# Otherwise, rely on $mkdir_umask.
|
||||
if test -n "$dir_arg"; then
|
||||
mkdir_mode=-m$mode
|
||||
else
|
||||
mkdir_mode=
|
||||
fi
|
||||
|
||||
posix_mkdir=false
|
||||
case $umask in
|
||||
*[123567][0-7][0-7])
|
||||
# POSIX mkdir -p sets u+wx bits regardless of umask, which
|
||||
# is incompatible with FreeBSD 'install' when (umask & 300) != 0.
|
||||
;;
|
||||
*)
|
||||
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
|
||||
trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
|
||||
|
||||
if (umask $mkdir_umask &&
|
||||
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
|
||||
then
|
||||
if test -z "$dir_arg" || {
|
||||
# Check for POSIX incompatibilities with -m.
|
||||
# HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
|
||||
# other-writable bit of parent directory when it shouldn't.
|
||||
# FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
|
||||
ls_ld_tmpdir=`ls -ld "$tmpdir"`
|
||||
case $ls_ld_tmpdir in
|
||||
d????-?r-*) different_mode=700;;
|
||||
d????-?--*) different_mode=755;;
|
||||
*) false;;
|
||||
esac &&
|
||||
$mkdirprog -m$different_mode -p -- "$tmpdir" && {
|
||||
ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
|
||||
test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
|
||||
}
|
||||
}
|
||||
then posix_mkdir=:
|
||||
fi
|
||||
rmdir "$tmpdir/d" "$tmpdir"
|
||||
else
|
||||
# Remove any dirs left behind by ancient mkdir implementations.
|
||||
rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
|
||||
fi
|
||||
trap '' 0;;
|
||||
esac;;
|
||||
esac
|
||||
|
||||
if
|
||||
$posix_mkdir && (
|
||||
umask $mkdir_umask &&
|
||||
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
|
||||
)
|
||||
then :
|
||||
else
|
||||
|
||||
# The umask is ridiculous, or mkdir does not conform to POSIX,
|
||||
# or it failed possibly due to a race condition. Create the
|
||||
# directory the slow way, step by step, checking for races as we go.
|
||||
|
||||
case $dstdir in
|
||||
/*) prefix='/';;
|
||||
[-=\(\)!]*) prefix='./';;
|
||||
*) prefix='';;
|
||||
esac
|
||||
|
||||
oIFS=$IFS
|
||||
IFS=/
|
||||
set -f
|
||||
set fnord $dstdir
|
||||
shift
|
||||
set +f
|
||||
IFS=$oIFS
|
||||
|
||||
prefixes=
|
||||
|
||||
for d
|
||||
do
|
||||
test X"$d" = X && continue
|
||||
|
||||
prefix=$prefix$d
|
||||
if test -d "$prefix"; then
|
||||
prefixes=
|
||||
else
|
||||
if $posix_mkdir; then
|
||||
(umask=$mkdir_umask &&
|
||||
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
|
||||
# Don't fail if two instances are running concurrently.
|
||||
test -d "$prefix" || exit 1
|
||||
else
|
||||
case $prefix in
|
||||
*\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
|
||||
*) qprefix=$prefix;;
|
||||
esac
|
||||
prefixes="$prefixes '$qprefix'"
|
||||
fi
|
||||
fi
|
||||
prefix=$prefix/
|
||||
done
|
||||
|
||||
if test -n "$prefixes"; then
|
||||
# Don't fail if two instances are running concurrently.
|
||||
(umask $mkdir_umask &&
|
||||
eval "\$doit_exec \$mkdirprog $prefixes") ||
|
||||
test -d "$dstdir" || exit 1
|
||||
obsolete_mkdir_used=true
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -n "$dir_arg"; then
|
||||
{ test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
|
||||
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
|
||||
{ test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
|
||||
test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
|
||||
else
|
||||
|
||||
# Make a couple of temp file names in the proper directory.
|
||||
dsttmp=$dstdir/_inst.$$_
|
||||
rmtmp=$dstdir/_rm.$$_
|
||||
|
||||
# Trap to clean up those temp files at exit.
|
||||
trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
|
||||
|
||||
# Copy the file name to the temp name.
|
||||
(umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
|
||||
|
||||
# and set any options; do chmod last to preserve setuid bits.
|
||||
#
|
||||
# If any of these fail, we abort the whole thing. If we want to
|
||||
# ignore errors from any of these, just make sure not to ignore
|
||||
# errors from the above "$doit $cpprog $src $dsttmp" command.
|
||||
#
|
||||
{ test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
|
||||
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
|
||||
{ test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
|
||||
{ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
|
||||
|
||||
# If -C, don't bother to copy if it wouldn't change the file.
|
||||
if $copy_on_change &&
|
||||
old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
|
||||
new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
|
||||
set -f &&
|
||||
set X $old && old=:$2:$4:$5:$6 &&
|
||||
set X $new && new=:$2:$4:$5:$6 &&
|
||||
set +f &&
|
||||
test "$old" = "$new" &&
|
||||
$cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
|
||||
then
|
||||
rm -f "$dsttmp"
|
||||
else
|
||||
# Rename the file to the real destination.
|
||||
$doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
|
||||
|
||||
# The rename failed, perhaps because mv can't rename something else
|
||||
# to itself, or perhaps because mv is so ancient that it does not
|
||||
# support -f.
|
||||
{
|
||||
# Now remove or move aside any old file at destination location.
|
||||
# We try this two ways since rm can't unlink itself on some
|
||||
# systems and the destination file might be busy for other
|
||||
# reasons. In this case, the final cleanup might fail but the new
|
||||
# file should still install successfully.
|
||||
{
|
||||
test ! -f "$dst" ||
|
||||
$doit $rmcmd -f "$dst" 2>/dev/null ||
|
||||
{ $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
|
||||
{ $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
|
||||
} ||
|
||||
{ echo "$0: cannot unlink or rename $dst" >&2
|
||||
(exit 1); exit 1
|
||||
}
|
||||
} &&
|
||||
|
||||
# Now rename the file to the real destination.
|
||||
$doit $mvcmd "$dsttmp" "$dst"
|
||||
}
|
||||
fi || exit 1
|
||||
|
||||
trap '' 0
|
||||
fi
|
||||
done
|
||||
|
||||
# Local variables:
|
||||
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,215 @@
|
|||
#! /bin/sh
|
||||
# Common wrapper for a few potentially missing GNU programs.
|
||||
|
||||
scriptversion=2013-10-28.13; # UTC
|
||||
|
||||
# Copyright (C) 1996-2014 Free Software Foundation, Inc.
|
||||
# Originally written by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
|
||||
if test $# -eq 0; then
|
||||
echo 1>&2 "Try '$0 --help' for more information"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
case $1 in
|
||||
|
||||
--is-lightweight)
|
||||
# Used by our autoconf macros to check whether the available missing
|
||||
# script is modern enough.
|
||||
exit 0
|
||||
;;
|
||||
|
||||
--run)
|
||||
# Back-compat with the calling convention used by older automake.
|
||||
shift
|
||||
;;
|
||||
|
||||
-h|--h|--he|--hel|--help)
|
||||
echo "\
|
||||
$0 [OPTION]... PROGRAM [ARGUMENT]...
|
||||
|
||||
Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due
|
||||
to PROGRAM being missing or too old.
|
||||
|
||||
Options:
|
||||
-h, --help display this help and exit
|
||||
-v, --version output version information and exit
|
||||
|
||||
Supported PROGRAM values:
|
||||
aclocal autoconf autoheader autom4te automake makeinfo
|
||||
bison yacc flex lex help2man
|
||||
|
||||
Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and
|
||||
'g' are ignored when checking the name.
|
||||
|
||||
Send bug reports to <bug-automake@gnu.org>."
|
||||
exit $?
|
||||
;;
|
||||
|
||||
-v|--v|--ve|--ver|--vers|--versi|--versio|--version)
|
||||
echo "missing $scriptversion (GNU Automake)"
|
||||
exit $?
|
||||
;;
|
||||
|
||||
-*)
|
||||
echo 1>&2 "$0: unknown '$1' option"
|
||||
echo 1>&2 "Try '$0 --help' for more information"
|
||||
exit 1
|
||||
;;
|
||||
|
||||
esac
|
||||
|
||||
# Run the given program, remember its exit status.
|
||||
"$@"; st=$?
|
||||
|
||||
# If it succeeded, we are done.
|
||||
test $st -eq 0 && exit 0
|
||||
|
||||
# Also exit now if we it failed (or wasn't found), and '--version' was
|
||||
# passed; such an option is passed most likely to detect whether the
|
||||
# program is present and works.
|
||||
case $2 in --version|--help) exit $st;; esac
|
||||
|
||||
# Exit code 63 means version mismatch. This often happens when the user
|
||||
# tries to use an ancient version of a tool on a file that requires a
|
||||
# minimum version.
|
||||
if test $st -eq 63; then
|
||||
msg="probably too old"
|
||||
elif test $st -eq 127; then
|
||||
# Program was missing.
|
||||
msg="missing on your system"
|
||||
else
|
||||
# Program was found and executed, but failed. Give up.
|
||||
exit $st
|
||||
fi
|
||||
|
||||
perl_URL=http://www.perl.org/
|
||||
flex_URL=http://flex.sourceforge.net/
|
||||
gnu_software_URL=http://www.gnu.org/software
|
||||
|
||||
program_details ()
|
||||
{
|
||||
case $1 in
|
||||
aclocal|automake)
|
||||
echo "The '$1' program is part of the GNU Automake package:"
|
||||
echo "<$gnu_software_URL/automake>"
|
||||
echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:"
|
||||
echo "<$gnu_software_URL/autoconf>"
|
||||
echo "<$gnu_software_URL/m4/>"
|
||||
echo "<$perl_URL>"
|
||||
;;
|
||||
autoconf|autom4te|autoheader)
|
||||
echo "The '$1' program is part of the GNU Autoconf package:"
|
||||
echo "<$gnu_software_URL/autoconf/>"
|
||||
echo "It also requires GNU m4 and Perl in order to run:"
|
||||
echo "<$gnu_software_URL/m4/>"
|
||||
echo "<$perl_URL>"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
give_advice ()
|
||||
{
|
||||
# Normalize program name to check for.
|
||||
normalized_program=`echo "$1" | sed '
|
||||
s/^gnu-//; t
|
||||
s/^gnu//; t
|
||||
s/^g//; t'`
|
||||
|
||||
printf '%s\n' "'$1' is $msg."
|
||||
|
||||
configure_deps="'configure.ac' or m4 files included by 'configure.ac'"
|
||||
case $normalized_program in
|
||||
autoconf*)
|
||||
echo "You should only need it if you modified 'configure.ac',"
|
||||
echo "or m4 files included by it."
|
||||
program_details 'autoconf'
|
||||
;;
|
||||
autoheader*)
|
||||
echo "You should only need it if you modified 'acconfig.h' or"
|
||||
echo "$configure_deps."
|
||||
program_details 'autoheader'
|
||||
;;
|
||||
automake*)
|
||||
echo "You should only need it if you modified 'Makefile.am' or"
|
||||
echo "$configure_deps."
|
||||
program_details 'automake'
|
||||
;;
|
||||
aclocal*)
|
||||
echo "You should only need it if you modified 'acinclude.m4' or"
|
||||
echo "$configure_deps."
|
||||
program_details 'aclocal'
|
||||
;;
|
||||
autom4te*)
|
||||
echo "You might have modified some maintainer files that require"
|
||||
echo "the 'autom4te' program to be rebuilt."
|
||||
program_details 'autom4te'
|
||||
;;
|
||||
bison*|yacc*)
|
||||
echo "You should only need it if you modified a '.y' file."
|
||||
echo "You may want to install the GNU Bison package:"
|
||||
echo "<$gnu_software_URL/bison/>"
|
||||
;;
|
||||
lex*|flex*)
|
||||
echo "You should only need it if you modified a '.l' file."
|
||||
echo "You may want to install the Fast Lexical Analyzer package:"
|
||||
echo "<$flex_URL>"
|
||||
;;
|
||||
help2man*)
|
||||
echo "You should only need it if you modified a dependency" \
|
||||
"of a man page."
|
||||
echo "You may want to install the GNU Help2man package:"
|
||||
echo "<$gnu_software_URL/help2man/>"
|
||||
;;
|
||||
makeinfo*)
|
||||
echo "You should only need it if you modified a '.texi' file, or"
|
||||
echo "any other file indirectly affecting the aspect of the manual."
|
||||
echo "You might want to install the Texinfo package:"
|
||||
echo "<$gnu_software_URL/texinfo/>"
|
||||
echo "The spurious makeinfo call might also be the consequence of"
|
||||
echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might"
|
||||
echo "want to install GNU make:"
|
||||
echo "<$gnu_software_URL/make/>"
|
||||
;;
|
||||
*)
|
||||
echo "You might have modified some files without having the proper"
|
||||
echo "tools for further handling them. Check the 'README' file, it"
|
||||
echo "often tells you about the needed prerequisites for installing"
|
||||
echo "this package. You may also peek at any GNU archive site, in"
|
||||
echo "case some other package contains this missing '$1' program."
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
give_advice "$1" | sed -e '1s/^/WARNING: /' \
|
||||
-e '2,$s/^/ /' >&2
|
||||
|
||||
# Propagate the correct exit status (expected to be 127 for a program
|
||||
# not found, 63 for a program that failed due to version mismatch).
|
||||
exit $st
|
||||
|
||||
# Local variables:
|
||||
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
|
@ -0,0 +1,121 @@
|
|||
/* config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* SSH authentication max password length */
|
||||
#undef CONFIG_ASSH_AUTH_PASSWORD_LEN
|
||||
|
||||
/* SSH authentication max username length */
|
||||
#undef CONFIG_ASSH_AUTH_USERNAME_LEN
|
||||
|
||||
/* SSH client support */
|
||||
#undef CONFIG_ASSH_CLIENT
|
||||
|
||||
/* SSH client authentication: password support */
|
||||
#undef CONFIG_ASSH_CLIENT_AUTH_PASSWORD
|
||||
|
||||
/* SSH client authentication: public key support */
|
||||
#undef CONFIG_ASSH_CLIENT_AUTH_PUBLICKEY
|
||||
|
||||
/* SSH client authentication: public key signature is not sent directly */
|
||||
#undef CONFIG_ASSH_CLIENT_AUTH_USE_PKOK
|
||||
|
||||
/* SSH server support */
|
||||
#undef CONFIG_ASSH_SERVER
|
||||
|
||||
/* SSH server authentication: password support */
|
||||
#undef CONFIG_ASSH_SERVER_AUTH_PASSWORD
|
||||
|
||||
/* SSH server authentication: public key support */
|
||||
#undef CONFIG_ASSH_SERVER_AUTH_PUBLICKEY
|
||||
|
||||
/* Libgcrypt support */
|
||||
#undef CONFIG_ASSH_USE_GCRYPT
|
||||
|
||||
/* use of gcrypt secur memory allocation */
|
||||
#undef CONFIG_ASSH_USE_GCRYPT_ALLOC
|
||||
|
||||
/* use of gcrypt big number functions */
|
||||
#undef CONFIG_ASSH_USE_GCRYPT_BIGNUM
|
||||
|
||||
/* use of gcrypt cipherss */
|
||||
#undef CONFIG_ASSH_USE_GCRYPT_CIPHERS
|
||||
|
||||
/* use of gcrypt hash algorithms */
|
||||
#undef CONFIG_ASSH_USE_GCRYPT_HASH
|
||||
|
||||
/* use of gcrypt random number generation */
|
||||
#undef CONFIG_ASSH_USE_GCRYPT_PRNG
|
||||
|
||||
/* Define to 1 if you have the <assert.h> header file. */
|
||||
#undef HAVE_ASSERT_H
|
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
#undef HAVE_DLFCN_H
|
||||
|
||||
/* Define to 1 if you have the <gcrypt.h> header file. */
|
||||
#undef HAVE_GCRYPT_H
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#undef HAVE_INTTYPES_H
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#undef HAVE_MEMORY_H
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#undef HAVE_STDINT_H
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#undef HAVE_STDLIB_H
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#undef HAVE_STRINGS_H
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#undef HAVE_STRING_H
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#undef HAVE_SYS_STAT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#undef HAVE_SYS_TYPES_H
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#undef HAVE_UNISTD_H
|
||||
|
||||
/* Define to the sub-directory where libtool stores uninstalled libraries. */
|
||||
#undef LT_OBJDIR
|
||||
|
||||
/* Name of package */
|
||||
#undef PACKAGE
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#undef PACKAGE_BUGREPORT
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#undef PACKAGE_NAME
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#undef PACKAGE_STRING
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#undef PACKAGE_TARNAME
|
||||
|
||||
/* Define to the home page for this package. */
|
||||
#undef PACKAGE_URL
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#undef PACKAGE_VERSION
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#undef STDC_HEADERS
|
||||
|
||||
/* Version number of package */
|
||||
#undef VERSION
|
||||
|
||||
/* Define to empty if `const' does not conform to ANSI C. */
|
||||
#undef const
|
||||
|
||||
/* Define to `__inline__' or `__inline' if that's what the C compiler
|
||||
calls it, or to nothing if 'inline' is not supported under any name. */
|
||||
#ifndef __cplusplus
|
||||
#undef inline
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,138 @@
|
|||
# Copyright (C) 2013 Alexandre Becoulet
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 2.1 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this program. If not, see
|
||||
# <http://www.gnu.org/licenses/>.
|
||||
|
||||
AC_INIT(libassh, 1.0)
|
||||
AC_PREREQ(2.50)
|
||||
|
||||
AC_CONFIG_AUX_DIR(build)
|
||||
AM_INIT_AUTOMAKE(libassh, 1.0)
|
||||
AC_CONFIG_HEADERS(config.h)
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
|
||||
AC_PROG_CC
|
||||
|
||||
AM_PROG_LIBTOOL
|
||||
|
||||
AC_LANG(C)
|
||||
|
||||
AC_STDC_HEADERS
|
||||
AC_CHECK_HEADERS(assert.h, AC_DEFINE([HAVE_ASSERT_H]))
|
||||
|
||||
AC_C_CONST
|
||||
AC_C_INLINE
|
||||
|
||||
AC_ARG_ENABLE(server, AC_HELP_STRING(--disable-server, [Disable SSH server support]),
|
||||
enable_server=$enableval, enable_server=yes)
|
||||
|
||||
AC_ARG_ENABLE(client, AC_HELP_STRING(--disable-client, [Disable SSH client support]),
|
||||
enable_client=$enableval, enable_client=yes)
|
||||
|
||||
AC_ARG_ENABLE(gcrypt, AC_HELP_STRING(--disable-gcrypt, [Disable use of gcrypt support]),
|
||||
enable_gcrypt=$enableval, enable_gcrypt=yes)
|
||||
|
||||
AC_ARG_ENABLE(gcrypt_hash, AC_HELP_STRING(--disable-gcrypt-hash, [Disable use of gcrypt hash algorithms]),
|
||||
enable_gcrypt_hash=$enableval, enable_gcrypt_hash=yes)
|
||||
|
||||
AC_ARG_ENABLE(gcrypt_bignum, AC_HELP_STRING(--disable-gcrypt-bignum, [Disable use of gcrypt big number functions]),
|
||||
enable_gcrypt_bignum=$enableval, enable_gcrypt_bignum=yes)
|
||||
|
||||
AC_ARG_ENABLE(gcrypt_prng, AC_HELP_STRING(--disable-gcrypt-prng, [Disable use of gcrypt random number generation]),
|
||||
enable_gcrypt_prng=$enableval, enable_gcrypt_prng=yes)
|
||||
|
||||
AC_ARG_ENABLE(gcrypt_alloc, AC_HELP_STRING(--disable-gcrypt-alloc, [Disable use of gcrypt secur memory allocation]),
|
||||
enable_gcrypt_alloc=$enableval, enable_gcrypt_alloc=yes)
|
||||
|
||||
AC_ARG_ENABLE(gcrypt_ciphers, AC_HELP_STRING(--disable-gcrypt-ciphers, [Disable use of gcrypt cipherss]),
|
||||
enable_gcrypt_ciphers=$enableval, enable_gcrypt_ciphers=yes)
|
||||
|
||||
if test x$enable_gcrypt = xyes ; then
|
||||
AC_CHECK_LIB(gcrypt, gcry_check_version, [
|
||||
AC_CHECK_HEADERS(gcrypt.h, [
|
||||
LIBS="$LIBS -lgcrypt"
|
||||
AC_DEFINE([CONFIG_ASSH_USE_GCRYPT], [], [Libgcrypt support])
|
||||
|
||||
if test x$enable_gcrypt_hash = xyes ; then
|
||||
AC_DEFINE([CONFIG_ASSH_USE_GCRYPT_HASH], [], [use of gcrypt hash algorithms])
|
||||
fi
|
||||
|
||||
if test x$enable_gcrypt_bignum = xyes ; then
|
||||
AC_DEFINE([CONFIG_ASSH_USE_GCRYPT_BIGNUM], [], [use of gcrypt big number functions])
|
||||
fi
|
||||
|
||||
if test x$enable_gcrypt_prng = xyes ; then
|
||||
AC_DEFINE([CONFIG_ASSH_USE_GCRYPT_PRNG], [], [use of gcrypt random number generation])
|
||||
fi
|
||||
|
||||
if test x$enable_gcrypt_alloc = xyes ; then
|
||||
AC_DEFINE([CONFIG_ASSH_USE_GCRYPT_ALLOC], [], [use of gcrypt secur memory allocation])
|
||||
fi
|
||||
|
||||
if test x$enable_gcrypt_ciphers = xyes ; then
|
||||
AC_DEFINE([CONFIG_ASSH_USE_GCRYPT_CIPHERS], [], [use of gcrypt cipherss])
|
||||
fi
|
||||
|
||||
])
|
||||
])
|
||||
else
|
||||
enable_gcrypt_hash=no
|
||||
enable_gcrypt_bignum=no
|
||||
enable_gcrypt_prng=no
|
||||
enable_gcrypt_alloc=no
|
||||
enable_gcrypt_ciphers=no
|
||||
fi
|
||||
|
||||
|
||||
AM_CONDITIONAL(COND_server, [test x$enable_server = xyes])
|
||||
AM_CONDITIONAL(COND_client, [test x$enable_client = xyes])
|
||||
|
||||
AM_CONDITIONAL(COND_gcrypt_hash, [test x$enable_gcrypt_hash = xyes])
|
||||
AM_CONDITIONAL(COND_gcrypt_bignum, [test x$enable_gcrypt_bignum = xyes])
|
||||
AM_CONDITIONAL(COND_gcrypt_prng, [test x$enable_gcrypt_prng = xyes])
|
||||
AM_CONDITIONAL(COND_gcrypt_alloc, [test x$enable_gcrypt_alloc = xyes])
|
||||
AM_CONDITIONAL(COND_gcrypt_ciphers, [test x$enable_gcrypt_ciphers = xyes])
|
||||
|
||||
if test x$enable_server = xyes ; then
|
||||
AC_DEFINE([CONFIG_ASSH_SERVER], [], [SSH server support])
|
||||
AC_DEFINE([CONFIG_ASSH_SERVER_AUTH_PUBLICKEY], [], [SSH server authentication: public key support])
|
||||
AC_DEFINE([CONFIG_ASSH_SERVER_AUTH_PASSWORD], [], [SSH server authentication: password support])
|
||||
#AC_DEFINE([CONFIG_ASSH_SERVER_AUTH_NONE], [], [SSH server authentication: bypassed, grant access directly])
|
||||
fi
|
||||
|
||||
if test x$enable_client = xyes ; then
|
||||
AC_DEFINE([CONFIG_ASSH_CLIENT], [], [SSH client support])
|
||||
AC_DEFINE([CONFIG_ASSH_CLIENT_AUTH_PUBLICKEY], [], [SSH client authentication: public key support])
|
||||
AC_DEFINE([CONFIG_ASSH_CLIENT_AUTH_PASSWORD], [], [SSH client authentication: password support])
|
||||
AC_DEFINE([CONFIG_ASSH_CLIENT_AUTH_USE_PKOK], [], [SSH client authentication: public key signature is not sent directly])
|
||||
fi
|
||||
|
||||
AC_DEFINE([CONFIG_ASSH_AUTH_USERNAME_LEN], [32], [SSH authentication max username length])
|
||||
AC_DEFINE([CONFIG_ASSH_AUTH_PASSWORD_LEN], [32], [SSH authentication max password length])
|
||||
|
||||
#AC_DEFINE([CONFIG_ASSH_ALLOCA], [], [Enable storing key related material on stack])
|
||||
|
||||
if test "$GCC" = "yes" ; then
|
||||
CFLAGS="-Wall $CFLAGS"
|
||||
fi
|
||||
|
||||
AC_OUTPUT([
|
||||
assh.pc
|
||||
Makefile
|
||||
src/Makefile
|
||||
src/assh/Makefile
|
||||
examples/Makefile
|
||||
test/Makefile
|
||||
])
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/client
|
||||
/keygen
|
||||
/server
|
|
@ -0,0 +1,38 @@
|
|||
# Copyright (C) 2013 Alexandre Becoulet
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 2.1 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this program. If not, see
|
||||
# <http://www.gnu.org/licenses/>.
|
||||
|
||||
AM_CPPFLAGS = -I$(top_builddir)/src/assh
|
||||
|
||||
noinst_PROGRAMS = keygen
|
||||
|
||||
keygen_SOURCES = keygen.c
|
||||
keygen_LDADD = $(top_builddir)/src/libassh.la
|
||||
keygen_CFLAGS = -I$(top_srcdir)/src
|
||||
|
||||
if COND_client
|
||||
client_SOURCES = client.c
|
||||
client_LDADD = $(top_builddir)/src/libassh.la
|
||||
client_CFLAGS = -I$(top_srcdir)/src
|
||||
noinst_PROGRAMS += client
|
||||
endif
|
||||
|
||||
if COND_server
|
||||
server_SOURCES = server.c
|
||||
server_LDADD = $(top_builddir)/src/libassh.la
|
||||
server_CFLAGS = -I$(top_srcdir)/src
|
||||
noinst_PROGRAMS += server
|
||||
endif
|
||||
|
|
@ -0,0 +1,174 @@
|
|||
/*
|
||||
|
||||
libassh - asynchronous ssh2 client/server library.
|
||||
|
||||
Copyright (C) 2013 Alexandre Becoulet <alexandre.becoulet@free.fr>
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#include <assh/assh_session.h>
|
||||
#include <assh/assh_context.h>
|
||||
#include <assh/assh_service.h>
|
||||
#include <assh/assh_userauth_client.h>
|
||||
#include <assh/helper_key.h>
|
||||
#include <assh/assh_kex.h>
|
||||
#include <assh/helper_fd.h>
|
||||
#include <assh/assh_event.h>
|
||||
#include <assh/assh_algo.h>
|
||||
#include <assh/key_rsa.h>
|
||||
#include <assh/key_dsa.h>
|
||||
|
||||
#ifdef CONFIG_ASSH_USE_GCRYPT
|
||||
# include <gcrypt.h>
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <poll.h>
|
||||
#include <string.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <pthread.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
#ifdef CONFIG_ASSH_USE_GCRYPT
|
||||
if (!gcry_check_version(GCRYPT_VERSION))
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
int port = 22;
|
||||
|
||||
if (argc > 1)
|
||||
port = atoi(argv[1]);
|
||||
|
||||
int sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
assert(sock >= 0);
|
||||
|
||||
struct sockaddr_in sin;
|
||||
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_addr.s_addr = htonl(0x7f000001);
|
||||
sin.sin_port = htons(port);
|
||||
|
||||
int r = connect(sock, (struct sockaddr*)(&sin), sizeof(sin));
|
||||
assert(r == 0);
|
||||
|
||||
struct assh_context_s *context;
|
||||
|
||||
if (assh_context_create(&context, ASSH_CLIENT, NULL, NULL))
|
||||
abort();
|
||||
|
||||
if (assh_service_register_default(context) != ASSH_OK)
|
||||
return -1;
|
||||
|
||||
if (assh_algo_register_default(context, 99, 10) != ASSH_OK)
|
||||
return -1;
|
||||
|
||||
struct assh_session_s *session;
|
||||
|
||||
if (assh_session_create(context, &session) != ASSH_OK)
|
||||
return -1;
|
||||
|
||||
int rnd_fd = open("/dev/urandom", O_RDONLY);
|
||||
assert(rnd_fd >= 0);
|
||||
|
||||
assh_error_t err;
|
||||
|
||||
struct assh_event_hndl_table_s ev_table;
|
||||
assh_event_table_init(&ev_table);
|
||||
|
||||
struct assh_fd_context_s fd_ctx;
|
||||
assh_fd_events_register(&ev_table, &fd_ctx, sock, rnd_fd);
|
||||
|
||||
while (1)
|
||||
{
|
||||
struct assh_event_s event;
|
||||
|
||||
err = assh_event_table_run(session, &ev_table, &event);
|
||||
if (ASSH_ERR_ERROR(err) != ASSH_OK)
|
||||
{
|
||||
fprintf(stderr, "assh error %x sv %x in main loop (errno=%i)\n",
|
||||
ASSH_ERR_ERROR(err), ASSH_ERR_SEVERITY(err), errno);
|
||||
if (ASSH_ERR_ERROR(err) == ASSH_ERR_CLOSED)
|
||||
goto err_;
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (event.id)
|
||||
{
|
||||
case ASSH_EVENT_KEX_HOSTKEY_LOOKUP: {
|
||||
/* XXX the key validity may be checked before adding
|
||||
the key to the list of known hosts. */
|
||||
if (assh_key_validate(context, event.kex.hostkey_lookup.key))
|
||||
break;
|
||||
|
||||
event.kex.hostkey_lookup.accept = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
case ASSH_EVENT_USERAUTH_CLIENT_USER: {
|
||||
event.userauth_client.user.username.str = "test";
|
||||
event.userauth_client.user.username.len = 4;
|
||||
break;
|
||||
}
|
||||
|
||||
case ASSH_EVENT_USERAUTH_CLIENT_METHODS: {
|
||||
if (event.userauth_client.methods.use_pub_key)
|
||||
{
|
||||
#if 0
|
||||
if (assh_load_key_filename(context, &event.userauth_client.methods.pub_keys,
|
||||
&assh_key_dsa, ASSH_ALGO_SIGN, "dsa_user_key",
|
||||
ASSH_KEY_FMT_PV_RFC2440_PEM_ASN1) != ASSH_OK)
|
||||
fprintf(stderr, "unable to load user dsa key\n");
|
||||
#endif
|
||||
#if 1
|
||||
if (assh_load_key_filename(context, &event.userauth_client.methods.pub_keys,
|
||||
&assh_key_rsa, ASSH_ALGO_SIGN, "rsa_user_key",
|
||||
ASSH_KEY_FMT_PV_RFC2440_PEM_ASN1) != ASSH_OK)
|
||||
fprintf(stderr, "unable to load user rsa key\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
#if 1
|
||||
if (event.userauth_client.methods.use_password)
|
||||
{
|
||||
fprintf(stderr, "password input\n");
|
||||
event.userauth_client.methods.password.str = "plouf";
|
||||
event.userauth_client.methods.password.len = 5;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
printf("Don't know how to handle event %u\n", event.id);
|
||||
}
|
||||
|
||||
err = assh_event_done(session, &event);
|
||||
if (err != ASSH_OK)
|
||||
fprintf(stderr, "assh error %x in main loop (errno=%i)\n", err, errno);
|
||||
}
|
||||
|
||||
err_:
|
||||
assh_session_release(session);
|
||||
assh_context_release(context);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
|
||||
libassh - asynchronous ssh2 client/server library.
|
||||
|
||||
Copyright (C) 2013 Alexandre Becoulet <alexandre.becoulet@free.fr>
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#include <assh/assh_context.h>
|
||||
|
||||
#include <assh/key_rsa.h>
|
||||
#include <assh/key_dsa.h>
|
||||
#include <assh/key_eddsa.h>
|
||||
|
||||
#ifdef CONFIG_ASSH_USE_GCRYPT
|
||||
# include <gcrypt.h>
|
||||
#endif
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
#ifdef CONFIG_ASSH_USE_GCRYPT
|
||||
if (!gcry_check_version(GCRYPT_VERSION))
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
size_t bits = 0;
|
||||
if (argc > 1)
|
||||
bits = atoi(argv[1]);
|
||||
|
||||
const struct assh_key_s *key;
|
||||
|
||||
struct assh_context_s *context;
|
||||
|
||||
if (assh_context_create(&context, ASSH_SERVER, NULL, NULL))
|
||||
abort();
|
||||
|
||||
if (context == NULL)
|
||||
abort();
|
||||
|
||||
if (assh_context_prng(context, NULL))
|
||||
abort();
|
||||
|
||||
if (assh_key_create(context, &key, bits, &assh_key_dsa, ASSH_ALGO_ANY))
|
||||
abort();
|
||||
|
||||
if (assh_key_validate(context, key))
|
||||
abort();
|
||||
|
||||
size_t len;
|
||||
|
||||
if (key->algo->f_output(context, key, NULL, &len, ASSH_KEY_FMT_PV_OPENSSH_V1_KEY))
|
||||
abort();
|
||||
|
||||
uint8_t blob[len];
|
||||
|
||||
if (key->algo->f_output(context, key, blob, &len, ASSH_KEY_FMT_PV_OPENSSH_V1_KEY))
|
||||
abort();
|
||||
|
||||
FILE *f = fopen("dsa_key", "wb");
|
||||
fwrite(blob, len, 1, f);
|
||||
fclose(f);
|
||||
|
||||
assh_context_release(context);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,267 @@
|
|||
/*
|
||||
|
||||
libassh - asynchronous ssh2 client/server library.
|
||||
|
||||
Copyright (C) 2013 Alexandre Becoulet <alexandre.becoulet@free.fr>
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#include <assh/assh_session.h>
|
||||
#include <assh/assh_context.h>
|
||||
#include <assh/assh_service.h>
|
||||
#include <assh/assh_userauth_server.h>
|
||||
#include <assh/assh_connection.h>
|
||||
#include <assh/assh_event.h>
|
||||
#include <assh/assh_algo.h>
|
||||
#include <assh/assh_packet.h>
|
||||
|
||||
#include <assh/helper_fd.h>
|
||||
#include <assh/helper_key.h>
|
||||
|
||||
#include <assh/key_rsa.h>
|
||||
#include <assh/key_dsa.h>
|
||||
#include <assh/key_eddsa.h>
|
||||
|
||||
#ifdef CONFIG_ASSH_USE_GCRYPT
|
||||
# include <gcrypt.h>
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <poll.h>
|
||||
#include <string.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <pthread.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
#ifdef CONFIG_ASSH_USE_GCRYPT
|
||||
if (!gcry_check_version(GCRYPT_VERSION))
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
int sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
assert(sock >= 0);
|
||||
|
||||
int tmp = 1;
|
||||
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
|
||||
|
||||
struct sockaddr_in addr =
|
||||
{
|
||||
.sin_port = htons(22222),
|
||||
.sin_family = AF_INET,
|
||||
};
|
||||
|
||||
if (bind(sock, (struct sockaddr*)&addr, sizeof (struct sockaddr_in)) < 0)
|
||||
abort();
|
||||
|
||||
if (listen(sock, 8) < 0)
|
||||
abort();
|
||||
|
||||
/** init a server context */
|
||||
struct assh_context_s *context;
|
||||
|
||||
if (assh_context_create(&context, ASSH_SERVER, NULL, NULL))
|
||||
abort();
|
||||
|
||||
/** register authentication and connection services */
|
||||
if (assh_service_register_default(context) != ASSH_OK)
|
||||
return -1;
|
||||
|
||||
/** register algorithms */
|
||||
if (assh_algo_register_default(context, 99, 10) != ASSH_OK)
|
||||
return -1;
|
||||
|
||||
/** load host key */
|
||||
#if 1
|
||||
if (assh_load_hostkey_filename(context, &assh_key_dsa, ASSH_ALGO_SIGN, "dsa_host_key",
|
||||
ASSH_KEY_FMT_PV_RFC2440_PEM_ASN1) != ASSH_OK)
|
||||
fprintf(stderr, "unable to load dsa key\n");
|
||||
|
||||
if (assh_load_hostkey_filename(context, &assh_key_dsa, ASSH_ALGO_SIGN, "dsa2048_host_key",
|
||||
ASSH_KEY_FMT_PV_RFC2440_PEM_ASN1) != ASSH_OK)
|
||||
fprintf(stderr, "unable to load dsa 2048 key\n");
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
if (assh_load_hostkey_filename(context, &assh_key_rsa, ASSH_ALGO_SIGN, "rsa_host_key",
|
||||
ASSH_KEY_FMT_PV_RFC2440_PEM_ASN1) != ASSH_OK)
|
||||
fprintf(stderr, "unable to load rsa key\n");
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
if (assh_load_hostkey_filename(context, &assh_key_ed25519, ASSH_ALGO_SIGN, "ed25519_host_key",
|
||||
ASSH_KEY_FMT_PV_OPENSSH_V1_KEY) != ASSH_OK)
|
||||
fprintf(stderr, "unable to load ed25519 key\n");
|
||||
#endif
|
||||
|
||||
if (assh_load_hostkey_filename(context, &assh_key_eddsa_e382, ASSH_ALGO_SIGN, "e382_host_key",
|
||||
ASSH_KEY_FMT_PV_OPENSSH_V1_KEY) != ASSH_OK)
|
||||
fprintf(stderr, "unable to load eddsa e382 key\n");
|
||||
|
||||
if (assh_load_hostkey_filename(context, &assh_key_eddsa_e521, ASSH_ALGO_SIGN, "e521_host_key",
|
||||
ASSH_KEY_FMT_PV_OPENSSH_V1_KEY) != ASSH_OK)
|
||||
fprintf(stderr, "unable to load eddsa e521 key\n");
|
||||
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
/** random data source */
|
||||
int rnd_fd = open("/dev/urandom", O_RDONLY);
|
||||
if (rnd_fd < 0)
|
||||
return -1;
|
||||
|
||||
while (1)
|
||||
{
|
||||
struct sockaddr_in con_addr;
|
||||
socklen_t addr_size = sizeof(con_addr);
|
||||
|
||||
int conn = accept(sock, (struct sockaddr*)&con_addr, &addr_size);
|
||||
|
||||
/** init a session for the incoming connection */
|
||||
struct assh_session_s *session;
|
||||
if (assh_session_create(context, &session) != ASSH_OK)
|
||||
return -1;
|
||||
|
||||
time_t t = time(0);
|
||||
fprintf(stderr, "============== %s\n", ctime(&t));
|
||||
|
||||
/** rely on an event table to handle most events returned by the assh core */
|
||||
struct assh_event_hndl_table_s ev_table;
|
||||
assh_event_table_init(&ev_table);
|
||||
|
||||
/** register helper event handlers to process io events using
|
||||
file descriptors. */
|
||||
struct assh_fd_context_s fd_ctx;
|
||||
assh_fd_events_register(&ev_table, &fd_ctx, conn, rnd_fd);
|
||||
|
||||
#if 0
|
||||
/** register helper event handlers to process ssh-connection
|
||||
(rfc4254) events in a way to serve shell */
|
||||
struct assh_unix_shell_server_s ush_ctx;
|
||||
assh_unix_shell_server_register(&ev_table, &ush_ctx);
|
||||
#endif
|
||||
|
||||
while (1)
|
||||
{
|
||||
struct assh_event_s event;
|
||||
|
||||
/** get events from the core and use registered event
|
||||
handlers to process most events. */
|
||||
assh_error_t err = assh_event_table_run(session, &ev_table, &event);
|
||||
if (ASSH_ERR_ERROR(err) != ASSH_OK)
|
||||
{
|
||||
fprintf(stderr, "assh error %x in main loop (errno=%i)\n", err, errno);
|
||||
|
||||
if (ASSH_ERR_ERROR(err) == ASSH_ERR_CLOSED)
|
||||
{
|
||||
close(conn);
|
||||
break;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/** we still have to process events not handled in the table */
|
||||
switch (event.id)
|
||||
{
|
||||
case ASSH_EVENT_USERAUTH_SERVER_USERKEY: {
|
||||
/* XXX check that event public key is in the list of
|
||||
user authorized keys. */
|
||||
|
||||
#warning validate key ? keys should be validated once when added to the list
|
||||
|
||||
event.userauth_server.userkey.found = 1;
|
||||
err = assh_event_done(session, &event);
|
||||
break;
|
||||
}
|
||||
|
||||
case ASSH_EVENT_USERAUTH_SERVER_PASSWORD:
|
||||
/* XXX check that event user/password pair matches. */
|
||||
event.userauth_server.password.success = 1;
|
||||
err = assh_event_done(session, &event);
|
||||
break;
|
||||
|
||||
case ASSH_EVENT_CHANNEL_OPEN: {
|
||||
struct assh_event_channel_open_s *co_e = &event.connection.channel_open;
|
||||
|
||||
if (!assh_buffer_strcmp(&co_e->type, "session"))
|
||||
{
|
||||
co_e->reply = ASSH_CONNECTION_REPLY_SUCCESS;
|
||||
}
|
||||
err = assh_event_done(session, &event);
|
||||
break;
|
||||
}
|
||||
|
||||
case ASSH_EVENT_REQUEST: {
|
||||
struct assh_event_request_s *rq_e = &event.connection.request;
|
||||
|
||||
if (!assh_buffer_strcmp(&rq_e->type, "shell"))
|
||||
{
|
||||
rq_e->reply = ASSH_CONNECTION_REPLY_SUCCESS;
|
||||
}
|
||||
else if (!assh_buffer_strcmp(&rq_e->type, "pty-req"))
|
||||
{
|
||||
rq_e->reply = ASSH_CONNECTION_REPLY_SUCCESS;
|
||||
}
|
||||
err = assh_event_done(session, &event);
|
||||
break;
|
||||
}
|
||||
|
||||
case ASSH_EVENT_CHANNEL_DATA: {
|
||||
struct assh_event_channel_data_s *dt_e = &event.connection.channel_data;
|
||||
|
||||
uint8_t *data;
|
||||
size_t size = dt_e->data.size;
|
||||
|
||||
/* allocate output data packet */
|
||||
assh_error_t perr = assh_channel_data_alloc(dt_e->ch, &data, &size, size);
|
||||
|
||||
if (perr == ASSH_OK) /* copy input data to output buffer */
|
||||
memcpy(data, dt_e->data.data, size);
|
||||
|
||||
/* acknowledge input data event before sending */
|
||||
err = assh_event_done(session, &event);
|
||||
|
||||
if (perr == ASSH_OK) /* send output data */
|
||||
err = assh_channel_data_send(dt_e->ch, size);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
printf("Don't know how to handle event %u\n", event.id);
|
||||
err = assh_event_done(session, &event);
|
||||
}
|
||||
|
||||
if (err != ASSH_OK)
|
||||
fprintf(stderr, "assh error %i in main loop (errno=%i)\n", err, errno);
|
||||
}
|
||||
|
||||
assh_session_release(session);
|
||||
break;
|
||||
}
|
||||
|
||||
assh_context_release(context);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,437 @@
|
|||
# Helper functions for option handling. -*- Autoconf -*-
|
||||
#
|
||||
# Copyright (C) 2004-2005, 2007-2009, 2011-2015 Free Software
|
||||
# Foundation, Inc.
|
||||
# Written by Gary V. Vaughan, 2004
|
||||
#
|
||||
# This file is free software; the Free Software Foundation gives
|
||||
# unlimited permission to copy and/or distribute it, with or without
|
||||
# modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 8 ltoptions.m4
|
||||
|
||||
# This is to help aclocal find these macros, as it can't see m4_define.
|
||||
AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])])
|
||||
|
||||
|
||||
# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME)
|
||||
# ------------------------------------------
|
||||
m4_define([_LT_MANGLE_OPTION],
|
||||
[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])])
|
||||
|
||||
|
||||
# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME)
|
||||
# ---------------------------------------
|
||||
# Set option OPTION-NAME for macro MACRO-NAME, and if there is a
|
||||
# matching handler defined, dispatch to it. Other OPTION-NAMEs are
|
||||
# saved as a flag.
|
||||
m4_define([_LT_SET_OPTION],
|
||||
[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl
|
||||
m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]),
|
||||
_LT_MANGLE_DEFUN([$1], [$2]),
|
||||
[m4_warning([Unknown $1 option '$2'])])[]dnl
|
||||
])
|
||||
|
||||
|
||||
# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET])
|
||||
# ------------------------------------------------------------
|
||||
# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
|
||||
m4_define([_LT_IF_OPTION],
|
||||
[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])])
|
||||
|
||||
|
||||
# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET)
|
||||
# -------------------------------------------------------
|
||||
# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME
|
||||
# are set.
|
||||
m4_define([_LT_UNLESS_OPTIONS],
|
||||
[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
|
||||
[m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option),
|
||||
[m4_define([$0_found])])])[]dnl
|
||||
m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3
|
||||
])[]dnl
|
||||
])
|
||||
|
||||
|
||||
# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST)
|
||||
# ----------------------------------------
|
||||
# OPTION-LIST is a space-separated list of Libtool options associated
|
||||
# with MACRO-NAME. If any OPTION has a matching handler declared with
|
||||
# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about
|
||||
# the unknown option and exit.
|
||||
m4_defun([_LT_SET_OPTIONS],
|
||||
[# Set options
|
||||
m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
|
||||
[_LT_SET_OPTION([$1], _LT_Option)])
|
||||
|
||||
m4_if([$1],[LT_INIT],[
|
||||
dnl
|
||||
dnl Simply set some default values (i.e off) if boolean options were not
|
||||
dnl specified:
|
||||
_LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no
|
||||
])
|
||||
_LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no
|
||||
])
|
||||
dnl
|
||||
dnl If no reference was made to various pairs of opposing options, then
|
||||
dnl we run the default mode handler for the pair. For example, if neither
|
||||
dnl 'shared' nor 'disable-shared' was passed, we enable building of shared
|
||||
dnl archives by default:
|
||||
_LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED])
|
||||
_LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC])
|
||||
_LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC])
|
||||
_LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install],
|
||||
[_LT_ENABLE_FAST_INSTALL])
|
||||
_LT_UNLESS_OPTIONS([LT_INIT], [aix-soname=aix aix-soname=both aix-soname=svr4],
|
||||
[_LT_WITH_AIX_SONAME([aix])])
|
||||
])
|
||||
])# _LT_SET_OPTIONS
|
||||
|
||||
|
||||
## --------------------------------- ##
|
||||
## Macros to handle LT_INIT options. ##
|
||||
## --------------------------------- ##
|
||||
|
||||
# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME)
|
||||
# -----------------------------------------
|
||||
m4_define([_LT_MANGLE_DEFUN],
|
||||
[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])])
|
||||
|
||||
|
||||
# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE)
|
||||
# -----------------------------------------------
|
||||
m4_define([LT_OPTION_DEFINE],
|
||||
[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl
|
||||
])# LT_OPTION_DEFINE
|
||||
|
||||
|
||||
# dlopen
|
||||
# ------
|
||||
LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes
|
||||
])
|
||||
|
||||
AU_DEFUN([AC_LIBTOOL_DLOPEN],
|
||||
[_LT_SET_OPTION([LT_INIT], [dlopen])
|
||||
AC_DIAGNOSE([obsolete],
|
||||
[$0: Remove this warning and the call to _LT_SET_OPTION when you
|
||||
put the 'dlopen' option into LT_INIT's first parameter.])
|
||||
])
|
||||
|
||||
dnl aclocal-1.4 backwards compatibility:
|
||||
dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], [])
|
||||
|
||||
|
||||
# win32-dll
|
||||
# ---------
|
||||
# Declare package support for building win32 dll's.
|
||||
LT_OPTION_DEFINE([LT_INIT], [win32-dll],
|
||||
[enable_win32_dll=yes
|
||||
|
||||
case $host in
|
||||
*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*)
|
||||
AC_CHECK_TOOL(AS, as, false)
|
||||
AC_CHECK_TOOL(DLLTOOL, dlltool, false)
|
||||
AC_CHECK_TOOL(OBJDUMP, objdump, false)
|
||||
;;
|
||||
esac
|
||||
|
||||
test -z "$AS" && AS=as
|
||||
_LT_DECL([], [AS], [1], [Assembler program])dnl
|
||||
|
||||
test -z "$DLLTOOL" && DLLTOOL=dlltool
|
||||
_LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl
|
||||
|
||||
test -z "$OBJDUMP" && OBJDUMP=objdump
|
||||
_LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl
|
||||
])# win32-dll
|
||||
|
||||
AU_DEFUN([AC_LIBTOOL_WIN32_DLL],
|
||||
[AC_REQUIRE([AC_CANONICAL_HOST])dnl
|
||||
_LT_SET_OPTION([LT_INIT], [win32-dll])
|
||||
AC_DIAGNOSE([obsolete],
|
||||
[$0: Remove this warning and the call to _LT_SET_OPTION when you
|
||||
put the 'win32-dll' option into LT_INIT's first parameter.])
|
||||
])
|
||||
|
||||
dnl aclocal-1.4 backwards compatibility:
|
||||
dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], [])
|
||||
|
||||
|
||||
# _LT_ENABLE_SHARED([DEFAULT])
|
||||
# ----------------------------
|
||||
# implement the --enable-shared flag, and supports the 'shared' and
|
||||
# 'disable-shared' LT_INIT options.
|
||||
# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'.
|
||||
m4_define([_LT_ENABLE_SHARED],
|
||||
[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl
|
||||
AC_ARG_ENABLE([shared],
|
||||
[AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@],
|
||||
[build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])],
|
||||
[p=${PACKAGE-default}
|
||||
case $enableval in
|
||||
yes) enable_shared=yes ;;
|
||||
no) enable_shared=no ;;
|
||||
*)
|
||||
enable_shared=no
|
||||
# Look at the argument we got. We use all the common list separators.
|
||||
lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
|
||||
for pkg in $enableval; do
|
||||
IFS=$lt_save_ifs
|
||||
if test "X$pkg" = "X$p"; then
|
||||
enable_shared=yes
|
||||
fi
|
||||
done
|
||||
IFS=$lt_save_ifs
|
||||
;;
|
||||
esac],
|
||||
[enable_shared=]_LT_ENABLE_SHARED_DEFAULT)
|
||||
|
||||
_LT_DECL([build_libtool_libs], [enable_shared], [0],
|
||||
[Whether or not to build shared libraries])
|
||||
])# _LT_ENABLE_SHARED
|
||||
|
||||
LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])])
|
||||
LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])])
|
||||
|
||||
# Old names:
|
||||
AC_DEFUN([AC_ENABLE_SHARED],
|
||||
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared])
|
||||
])
|
||||
|
||||
AC_DEFUN([AC_DISABLE_SHARED],
|
||||
[_LT_SET_OPTION([LT_INIT], [disable-shared])
|
||||
])
|
||||
|
||||
AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)])
|
||||
AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)])
|
||||
|
||||
dnl aclocal-1.4 backwards compatibility:
|
||||
dnl AC_DEFUN([AM_ENABLE_SHARED], [])
|
||||
dnl AC_DEFUN([AM_DISABLE_SHARED], [])
|
||||
|
||||
|
||||
|
||||
# _LT_ENABLE_STATIC([DEFAULT])
|
||||
# ----------------------------
|
||||
# implement the --enable-static flag, and support the 'static' and
|
||||
# 'disable-static' LT_INIT options.
|
||||
# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'.
|
||||
m4_define([_LT_ENABLE_STATIC],
|
||||
[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl
|
||||
AC_ARG_ENABLE([static],
|
||||
[AS_HELP_STRING([--enable-static@<:@=PKGS@:>@],
|
||||
[build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])],
|
||||
[p=${PACKAGE-default}
|
||||
case $enableval in
|
||||
yes) enable_static=yes ;;
|
||||
no) enable_static=no ;;
|
||||
*)
|
||||
enable_static=no
|
||||
# Look at the argument we got. We use all the common list separators.
|
||||
lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
|
||||
for pkg in $enableval; do
|
||||
IFS=$lt_save_ifs
|
||||
if test "X$pkg" = "X$p"; then
|
||||
enable_static=yes
|
||||
fi
|
||||
done
|
||||
IFS=$lt_save_ifs
|
||||
;;
|
||||
esac],
|
||||
[enable_static=]_LT_ENABLE_STATIC_DEFAULT)
|
||||
|
||||
_LT_DECL([build_old_libs], [enable_static], [0],
|
||||
[Whether or not to build static libraries])
|
||||
])# _LT_ENABLE_STATIC
|
||||
|
||||
LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])])
|
||||
LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])])
|
||||
|
||||
# Old names:
|
||||
AC_DEFUN([AC_ENABLE_STATIC],
|
||||
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static])
|
||||
])
|
||||
|
||||
AC_DEFUN([AC_DISABLE_STATIC],
|
||||
[_LT_SET_OPTION([LT_INIT], [disable-static])
|
||||
])
|
||||
|
||||
AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)])
|
||||
AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)])
|
||||
|
||||
dnl aclocal-1.4 backwards compatibility:
|
||||
dnl AC_DEFUN([AM_ENABLE_STATIC], [])
|
||||
dnl AC_DEFUN([AM_DISABLE_STATIC], [])
|
||||
|
||||
|
||||
|
||||
# _LT_ENABLE_FAST_INSTALL([DEFAULT])
|
||||
# ----------------------------------
|
||||
# implement the --enable-fast-install flag, and support the 'fast-install'
|
||||
# and 'disable-fast-install' LT_INIT options.
|
||||
# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'.
|
||||
m4_define([_LT_ENABLE_FAST_INSTALL],
|
||||
[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl
|
||||
AC_ARG_ENABLE([fast-install],
|
||||
[AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@],
|
||||
[optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])],
|
||||
[p=${PACKAGE-default}
|
||||
case $enableval in
|
||||
yes) enable_fast_install=yes ;;
|
||||
no) enable_fast_install=no ;;
|
||||
*)
|
||||
enable_fast_install=no
|
||||
# Look at the argument we got. We use all the common list separators.
|
||||
lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
|
||||
for pkg in $enableval; do
|
||||
IFS=$lt_save_ifs
|
||||
if test "X$pkg" = "X$p"; then
|
||||
enable_fast_install=yes
|
||||
fi
|
||||
done
|
||||
IFS=$lt_save_ifs
|
||||
;;
|
||||
esac],
|
||||
[enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT)
|
||||
|
||||
_LT_DECL([fast_install], [enable_fast_install], [0],
|
||||
[Whether or not to optimize for fast installation])dnl
|
||||
])# _LT_ENABLE_FAST_INSTALL
|
||||
|
||||
LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])])
|
||||
LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])])
|
||||
|
||||
# Old names:
|
||||
AU_DEFUN([AC_ENABLE_FAST_INSTALL],
|
||||
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install])
|
||||
AC_DIAGNOSE([obsolete],
|
||||
[$0: Remove this warning and the call to _LT_SET_OPTION when you put
|
||||
the 'fast-install' option into LT_INIT's first parameter.])
|
||||
])
|
||||
|
||||
AU_DEFUN([AC_DISABLE_FAST_INSTALL],
|
||||
[_LT_SET_OPTION([LT_INIT], [disable-fast-install])
|
||||
AC_DIAGNOSE([obsolete],
|
||||
[$0: Remove this warning and the call to _LT_SET_OPTION when you put
|
||||
the 'disable-fast-install' option into LT_INIT's first parameter.])
|
||||
])
|
||||
|
||||
dnl aclocal-1.4 backwards compatibility:
|
||||
dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], [])
|
||||
dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], [])
|
||||
|
||||
|
||||
# _LT_WITH_AIX_SONAME([DEFAULT])
|
||||
# ----------------------------------
|
||||
# implement the --with-aix-soname flag, and support the `aix-soname=aix'
|
||||
# and `aix-soname=both' and `aix-soname=svr4' LT_INIT options. DEFAULT
|
||||
# is either `aix', `both' or `svr4'. If omitted, it defaults to `aix'.
|
||||
m4_define([_LT_WITH_AIX_SONAME],
|
||||
[m4_define([_LT_WITH_AIX_SONAME_DEFAULT], [m4_if($1, svr4, svr4, m4_if($1, both, both, aix))])dnl
|
||||
shared_archive_member_spec=
|
||||
case $host,$enable_shared in
|
||||
power*-*-aix[[5-9]]*,yes)
|
||||
AC_MSG_CHECKING([which variant of shared library versioning to provide])
|
||||
AC_ARG_WITH([aix-soname],
|
||||
[AS_HELP_STRING([--with-aix-soname=aix|svr4|both],
|
||||
[shared library versioning (aka "SONAME") variant to provide on AIX, @<:@default=]_LT_WITH_AIX_SONAME_DEFAULT[@:>@.])],
|
||||
[case $withval in
|
||||
aix|svr4|both)
|
||||
;;
|
||||
*)
|
||||
AC_MSG_ERROR([Unknown argument to --with-aix-soname])
|
||||
;;
|
||||
esac
|
||||
lt_cv_with_aix_soname=$with_aix_soname],
|
||||
[AC_CACHE_VAL([lt_cv_with_aix_soname],
|
||||
[lt_cv_with_aix_soname=]_LT_WITH_AIX_SONAME_DEFAULT)
|
||||
with_aix_soname=$lt_cv_with_aix_soname])
|
||||
AC_MSG_RESULT([$with_aix_soname])
|
||||
if test aix != "$with_aix_soname"; then
|
||||
# For the AIX way of multilib, we name the shared archive member
|
||||
# based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o',
|
||||
# and 'shr.imp' or 'shr_64.imp', respectively, for the Import File.
|
||||
# Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag,
|
||||
# the AIX toolchain works better with OBJECT_MODE set (default 32).
|
||||
if test 64 = "${OBJECT_MODE-32}"; then
|
||||
shared_archive_member_spec=shr_64
|
||||
else
|
||||
shared_archive_member_spec=shr
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
with_aix_soname=aix
|
||||
;;
|
||||
esac
|
||||
|
||||
_LT_DECL([], [shared_archive_member_spec], [0],
|
||||
[Shared archive member basename, for filename based shared library versioning on AIX])dnl
|
||||
])# _LT_WITH_AIX_SONAME
|
||||
|
||||
LT_OPTION_DEFINE([LT_INIT], [aix-soname=aix], [_LT_WITH_AIX_SONAME([aix])])
|
||||
LT_OPTION_DEFINE([LT_INIT], [aix-soname=both], [_LT_WITH_AIX_SONAME([both])])
|
||||
LT_OPTION_DEFINE([LT_INIT], [aix-soname=svr4], [_LT_WITH_AIX_SONAME([svr4])])
|
||||
|
||||
|
||||
# _LT_WITH_PIC([MODE])
|
||||
# --------------------
|
||||
# implement the --with-pic flag, and support the 'pic-only' and 'no-pic'
|
||||
# LT_INIT options.
|
||||
# MODE is either 'yes' or 'no'. If omitted, it defaults to 'both'.
|
||||
m4_define([_LT_WITH_PIC],
|
||||
[AC_ARG_WITH([pic],
|
||||
[AS_HELP_STRING([--with-pic@<:@=PKGS@:>@],
|
||||
[try to use only PIC/non-PIC objects @<:@default=use both@:>@])],
|
||||
[lt_p=${PACKAGE-default}
|
||||
case $withval in
|
||||
yes|no) pic_mode=$withval ;;
|
||||
*)
|
||||
pic_mode=default
|
||||
# Look at the argument we got. We use all the common list separators.
|
||||
lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
|
||||
for lt_pkg in $withval; do
|
||||
IFS=$lt_save_ifs
|
||||
if test "X$lt_pkg" = "X$lt_p"; then
|
||||
pic_mode=yes
|
||||
fi
|
||||
done
|
||||
IFS=$lt_save_ifs
|
||||
;;
|
||||
esac],
|
||||
[pic_mode=m4_default([$1], [default])])
|
||||
|
||||
_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl
|
||||
])# _LT_WITH_PIC
|
||||
|
||||
LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])])
|
||||
LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])])
|
||||
|
||||
# Old name:
|
||||
AU_DEFUN([AC_LIBTOOL_PICMODE],
|
||||
[_LT_SET_OPTION([LT_INIT], [pic-only])
|
||||
AC_DIAGNOSE([obsolete],
|
||||
[$0: Remove this warning and the call to _LT_SET_OPTION when you
|
||||
put the 'pic-only' option into LT_INIT's first parameter.])
|
||||
])
|
||||
|
||||
dnl aclocal-1.4 backwards compatibility:
|
||||
dnl AC_DEFUN([AC_LIBTOOL_PICMODE], [])
|
||||
|
||||
## ----------------- ##
|
||||
## LTDL_INIT Options ##
|
||||
## ----------------- ##
|
||||
|
||||
m4_define([_LTDL_MODE], [])
|
||||
LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive],
|
||||
[m4_define([_LTDL_MODE], [nonrecursive])])
|
||||
LT_OPTION_DEFINE([LTDL_INIT], [recursive],
|
||||
[m4_define([_LTDL_MODE], [recursive])])
|
||||
LT_OPTION_DEFINE([LTDL_INIT], [subproject],
|
||||
[m4_define([_LTDL_MODE], [subproject])])
|
||||
|
||||
m4_define([_LTDL_TYPE], [])
|
||||
LT_OPTION_DEFINE([LTDL_INIT], [installable],
|
||||
[m4_define([_LTDL_TYPE], [installable])])
|
||||
LT_OPTION_DEFINE([LTDL_INIT], [convenience],
|
||||
[m4_define([_LTDL_TYPE], [convenience])])
|
|
@ -0,0 +1,124 @@
|
|||
# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*-
|
||||
#
|
||||
# Copyright (C) 2004-2005, 2007-2008, 2011-2015 Free Software
|
||||
# Foundation, Inc.
|
||||
# Written by Gary V. Vaughan, 2004
|
||||
#
|
||||
# This file is free software; the Free Software Foundation gives
|
||||
# unlimited permission to copy and/or distribute it, with or without
|
||||
# modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 6 ltsugar.m4
|
||||
|
||||
# This is to help aclocal find these macros, as it can't see m4_define.
|
||||
AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])])
|
||||
|
||||
|
||||
# lt_join(SEP, ARG1, [ARG2...])
|
||||
# -----------------------------
|
||||
# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their
|
||||
# associated separator.
|
||||
# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier
|
||||
# versions in m4sugar had bugs.
|
||||
m4_define([lt_join],
|
||||
[m4_if([$#], [1], [],
|
||||
[$#], [2], [[$2]],
|
||||
[m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])])
|
||||
m4_define([_lt_join],
|
||||
[m4_if([$#$2], [2], [],
|
||||
[m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])])
|
||||
|
||||
|
||||
# lt_car(LIST)
|
||||
# lt_cdr(LIST)
|
||||
# ------------
|
||||
# Manipulate m4 lists.
|
||||
# These macros are necessary as long as will still need to support
|
||||
# Autoconf-2.59, which quotes differently.
|
||||
m4_define([lt_car], [[$1]])
|
||||
m4_define([lt_cdr],
|
||||
[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])],
|
||||
[$#], 1, [],
|
||||
[m4_dquote(m4_shift($@))])])
|
||||
m4_define([lt_unquote], $1)
|
||||
|
||||
|
||||
# lt_append(MACRO-NAME, STRING, [SEPARATOR])
|
||||
# ------------------------------------------
|
||||
# Redefine MACRO-NAME to hold its former content plus 'SEPARATOR''STRING'.
|
||||
# Note that neither SEPARATOR nor STRING are expanded; they are appended
|
||||
# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked).
|
||||
# No SEPARATOR is output if MACRO-NAME was previously undefined (different
|
||||
# than defined and empty).
|
||||
#
|
||||
# This macro is needed until we can rely on Autoconf 2.62, since earlier
|
||||
# versions of m4sugar mistakenly expanded SEPARATOR but not STRING.
|
||||
m4_define([lt_append],
|
||||
[m4_define([$1],
|
||||
m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])])
|
||||
|
||||
|
||||
|
||||
# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...])
|
||||
# ----------------------------------------------------------
|
||||
# Produce a SEP delimited list of all paired combinations of elements of
|
||||
# PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list
|
||||
# has the form PREFIXmINFIXSUFFIXn.
|
||||
# Needed until we can rely on m4_combine added in Autoconf 2.62.
|
||||
m4_define([lt_combine],
|
||||
[m4_if(m4_eval([$# > 3]), [1],
|
||||
[m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl
|
||||
[[m4_foreach([_Lt_prefix], [$2],
|
||||
[m4_foreach([_Lt_suffix],
|
||||
]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[,
|
||||
[_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])])
|
||||
|
||||
|
||||
# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ])
|
||||
# -----------------------------------------------------------------------
|
||||
# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited
|
||||
# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ.
|
||||
m4_define([lt_if_append_uniq],
|
||||
[m4_ifdef([$1],
|
||||
[m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1],
|
||||
[lt_append([$1], [$2], [$3])$4],
|
||||
[$5])],
|
||||
[lt_append([$1], [$2], [$3])$4])])
|
||||
|
||||
|
||||
# lt_dict_add(DICT, KEY, VALUE)
|
||||
# -----------------------------
|
||||
m4_define([lt_dict_add],
|
||||
[m4_define([$1($2)], [$3])])
|
||||
|
||||
|
||||
# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE)
|
||||
# --------------------------------------------
|
||||
m4_define([lt_dict_add_subkey],
|
||||
[m4_define([$1($2:$3)], [$4])])
|
||||
|
||||
|
||||
# lt_dict_fetch(DICT, KEY, [SUBKEY])
|
||||
# ----------------------------------
|
||||
m4_define([lt_dict_fetch],
|
||||
[m4_ifval([$3],
|
||||
m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]),
|
||||
m4_ifdef([$1($2)], [m4_defn([$1($2)])]))])
|
||||
|
||||
|
||||
# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE])
|
||||
# -----------------------------------------------------------------
|
||||
m4_define([lt_if_dict_fetch],
|
||||
[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4],
|
||||
[$5],
|
||||
[$6])])
|
||||
|
||||
|
||||
# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...])
|
||||
# --------------------------------------------------------------
|
||||
m4_define([lt_dict_filter],
|
||||
[m4_if([$5], [], [],
|
||||
[lt_join(m4_quote(m4_default([$4], [[, ]])),
|
||||
lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]),
|
||||
[lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl
|
||||
])
|
|
@ -0,0 +1,23 @@
|
|||
# ltversion.m4 -- version numbers -*- Autoconf -*-
|
||||
#
|
||||
# Copyright (C) 2004, 2011-2015 Free Software Foundation, Inc.
|
||||
# Written by Scott James Remnant, 2004
|
||||
#
|
||||
# This file is free software; the Free Software Foundation gives
|
||||
# unlimited permission to copy and/or distribute it, with or without
|
||||
# modifications, as long as this notice is preserved.
|
||||
|
||||
# @configure_input@
|
||||
|
||||
# serial 4179 ltversion.m4
|
||||
# This file is part of GNU Libtool
|
||||
|
||||
m4_define([LT_PACKAGE_VERSION], [2.4.6])
|
||||
m4_define([LT_PACKAGE_REVISION], [2.4.6])
|
||||
|
||||
AC_DEFUN([LTVERSION_VERSION],
|
||||
[macro_version='2.4.6'
|
||||
macro_revision='2.4.6'
|
||||
_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?])
|
||||
_LT_DECL(, macro_revision, 0)
|
||||
])
|
|
@ -0,0 +1,99 @@
|
|||
# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*-
|
||||
#
|
||||
# Copyright (C) 2004-2005, 2007, 2009, 2011-2015 Free Software
|
||||
# Foundation, Inc.
|
||||
# Written by Scott James Remnant, 2004.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation gives
|
||||
# unlimited permission to copy and/or distribute it, with or without
|
||||
# modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 5 lt~obsolete.m4
|
||||
|
||||
# These exist entirely to fool aclocal when bootstrapping libtool.
|
||||
#
|
||||
# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN),
|
||||
# which have later been changed to m4_define as they aren't part of the
|
||||
# exported API, or moved to Autoconf or Automake where they belong.
|
||||
#
|
||||
# The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN
|
||||
# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us
|
||||
# using a macro with the same name in our local m4/libtool.m4 it'll
|
||||
# pull the old libtool.m4 in (it doesn't see our shiny new m4_define
|
||||
# and doesn't know about Autoconf macros at all.)
|
||||
#
|
||||
# So we provide this file, which has a silly filename so it's always
|
||||
# included after everything else. This provides aclocal with the
|
||||
# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything
|
||||
# because those macros already exist, or will be overwritten later.
|
||||
# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6.
|
||||
#
|
||||
# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here.
|
||||
# Yes, that means every name once taken will need to remain here until
|
||||
# we give up compatibility with versions before 1.7, at which point
|
||||
# we need to keep only those names which we still refer to.
|
||||
|
||||
# This is to help aclocal find these macros, as it can't see m4_define.
|
||||
AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])])
|
||||
|
||||
m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])])
|
||||
m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])])
|
||||
m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])])
|
||||
m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])])
|
||||
m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])])
|
||||
m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])])
|
||||
m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])])
|
||||
m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])])
|
||||
m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])])
|
||||
m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])])
|
||||
m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])])
|
||||
m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])])
|
||||
m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])])
|
||||
m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])])
|
||||
m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])])
|
||||
m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])])
|
||||
m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])])
|
||||
m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])])
|
||||
m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])])
|
||||
m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])])
|
||||
m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])])
|
||||
m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])])
|
||||
m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])])
|
||||
m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])])
|
||||
m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])])
|
||||
m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])])
|
||||
m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])])
|
||||
m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])])
|
||||
m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])])
|
||||
m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])])
|
||||
m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])])
|
||||
m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])])
|
||||
m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])])
|
||||
m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])])
|
||||
m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])])
|
||||
m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])])
|
||||
m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])])
|
||||
m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])])
|
||||
m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])])
|
||||
m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])])
|
||||
m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])])
|
||||
m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])])
|
||||
m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])])
|
||||
m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])])
|
||||
m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])])
|
||||
m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])])
|
||||
m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])])
|
||||
m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])])
|
||||
m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])])
|
||||
m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])])
|
||||
m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])])
|
||||
m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])])
|
||||
m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])])
|
||||
m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])])
|
||||
m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])])
|
||||
m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])])
|
||||
m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])])
|
||||
m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])])
|
||||
m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])])
|
||||
m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])])
|
||||
m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])])
|
|
@ -0,0 +1,58 @@
|
|||
# Copyright (C) 2013 Alexandre Becoulet
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 2.1 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this program. If not, see
|
||||
# <http://www.gnu.org/licenses/>.
|
||||
|
||||
AM_CPPFLAGS = -I$(top_builddir)/src/assh
|
||||
SUBDIRS = assh
|
||||
|
||||
lib_LTLIBRARIES = libassh.la
|
||||
|
||||
libassh_la_SOURCES = assh_context.c assh_session.c assh_packet.c \
|
||||
assh_event.c assh_transport.c assh_kex.c assh_hash.c \
|
||||
assh_algo.c assh_key.c assh_service.c assh_map.c assh_bignum.c \
|
||||
assh_connection.c assh_userauth_client.c assh_userauth_server.c \
|
||||
kex_none.c kex_dh.c kex_dh_gex.c kex_rsa.c kex_ecdh_montgomery.c \
|
||||
cipher_none.c \
|
||||
mac_none.c \
|
||||
key_dsa.c key_rsa.c key_eddsa.c \
|
||||
sign_dsa.c sign_rsa.c sign_eddsa.c sign_none.c \
|
||||
compress_none.c \
|
||||
helper_key.c helper_fd.c hash_sha3_builtin.c
|
||||
|
||||
if COND_gcrypt_hash
|
||||
libassh_la_SOURCES += hash_gcrypt.c mac_gcrypt.c
|
||||
else
|
||||
libassh_la_SOURCES += hash_md5_builtin.c hash_sha1_builtin.c hash_sha2_builtin.c mac_builtin.c
|
||||
endif
|
||||
|
||||
if COND_gcrypt_bignum
|
||||
libassh_la_SOURCES += bignum_gcrypt.c
|
||||
else
|
||||
libassh_la_SOURCES += bignum_builtin.c
|
||||
endif
|
||||
|
||||
if COND_gcrypt_prng
|
||||
libassh_la_SOURCES += prng_gcrypt.c
|
||||
else
|
||||
libassh_la_SOURCES += prng_xswap_builtin.c
|
||||
endif
|
||||
|
||||
if COND_gcrypt_ciphers
|
||||
libassh_la_SOURCES += cipher_gcrypt.c
|
||||
else
|
||||
libassh_la_SOURCES += cipher_arc4_builtin.c cipher_aes_builtin.c
|
||||
endif
|
||||
|
||||
|
|
@ -0,0 +1 @@
|
|||
/assh_config.h
|
|
@ -0,0 +1,32 @@
|
|||
# Copyright (C) 2013 Alexandre Becoulet
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 2.1 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this program. If not, see
|
||||
# <http://www.gnu.org/licenses/>.
|
||||
|
||||
BUILT_SOURCES = assh_config.h
|
||||
DISTCLEANFILES = assh_config.h
|
||||
nodist_pkginclude_HEADERS = assh_config.h
|
||||
|
||||
pkgincludedir = $(includedir)/assh
|
||||
pkginclude_HEADERS = assh.h assh_algo.h assh_alloc.h assh_bignum.h \
|
||||
assh_cipher.h assh_compress.h assh_config.h assh_connection.h \
|
||||
assh_context.h assh_event.h assh_hash.h assh_kex.h assh_key.h \
|
||||
assh_mac.h assh_map.h assh_packet.h assh_platform.h assh_prng.h \
|
||||
assh_queue.h assh_service.h assh_session.h assh_sign.h \
|
||||
assh_transport.h assh_userauth_client.h assh_userauth_server.h \
|
||||
helper_fd.h helper_key.h key_dsa.h key_eddsa.h key_rsa.h
|
||||
|
||||
assh_config.h: $(top_builddir)/config.h
|
||||
grep CONFIG_ASSH $(top_builddir)/config.h > $@ || true
|
||||
|
|
@ -0,0 +1,325 @@
|
|||
/*
|
||||
|
||||
libassh - asynchronous ssh2 client/server library.
|
||||
|
||||
Copyright (C) 2013 Alexandre Becoulet <alexandre.becoulet@free.fr>
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@file
|
||||
@short Some constants and forward declarations of structures
|
||||
*/
|
||||
|
||||
#ifndef ASSH_H_
|
||||
#define ASSH_H_
|
||||
|
||||
#include "assh_platform.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "assh_config.h"
|
||||
#endif
|
||||
|
||||
#if !defined(CONFIG_ASSH_SERVER) && !defined(CONFIG_ASSH_CLIENT)
|
||||
# error CONFIG_ASSH_SERVER and CONFIG_ASSH_CLIENT are both undefined
|
||||
#endif
|
||||
|
||||
/* make event fields written by the library read-only for user. */
|
||||
#ifndef ASSH_EV_CONST
|
||||
/** @internal */
|
||||
# define ASSH_EV_CONST const
|
||||
#endif
|
||||
|
||||
struct assh_context_s;
|
||||
struct assh_session_s;
|
||||
struct assh_packet_s;
|
||||
struct assh_channel_s;
|
||||
struct assh_bignum_s;
|
||||
struct assh_key_s;
|
||||
struct assh_kex_keys_s;
|
||||
struct assh_algo_s;
|
||||
struct assh_algo_kex_s;
|
||||
struct assh_hash_algo_s;
|
||||
struct assh_hash_ctx_s;
|
||||
struct assh_prng_s;
|
||||
struct assh_algo_cipher_s;
|
||||
struct assh_algo_mac_s;
|
||||
struct assh_algo_sign_s;
|
||||
struct assh_event_s;
|
||||
struct assh_service_s;
|
||||
struct assh_event_hndl_table_s;
|
||||
struct assh_event_s;
|
||||
struct assh_queue_entry_s;
|
||||
struct assh_queue_s;
|
||||
|
||||
enum assh_alloc_type_e;
|
||||
enum assh_key_format_e;
|
||||
enum assh_alloc_type_e;
|
||||
enum assh_ssh_msg_e;
|
||||
enum assh_algo_class_e;
|
||||
|
||||
/** boolean type */
|
||||
typedef char assh_bool_t;
|
||||
|
||||
/** error code type */
|
||||
typedef int assh_error_t;
|
||||
|
||||
/** @This specify the error severity and must be used along with error
|
||||
code constants (@ref assh_error_e).
|
||||
|
||||
These values indicate how the state of the session has been
|
||||
impacted by the error.
|
||||
|
||||
Multiple error severity bits may be ored together; in this case
|
||||
the highest bit set prevails. This allows increasing the error
|
||||
severity returned by a callee from the caller function. */
|
||||
enum assh_error_severity_e
|
||||
{
|
||||
/** The error did not changed the internal state of the library. */
|
||||
ASSH_ERRSV_CONTINUE = 0x0000,
|
||||
/** The error prevent further communication with the remote host but
|
||||
a disconnect packet may still be send before closing the connection. */
|
||||
ASSH_ERRSV_DISCONNECT = 0x2000,
|
||||
/** The error prevent further communication with the remote host due
|
||||
to irrecoverable protocol error. */
|
||||
ASSH_ERRSV_FIN = 0x4000,
|
||||
/** The error is due to a bad use of the assh library or a bug in
|
||||
the library. It's not possible to continue, cleanup functions
|
||||
may be called. This should never happen. */
|
||||
ASSH_ERRSV_FATAL = 0x8000,
|
||||
};
|
||||
|
||||
/** @This specify possible return codes returned by @em libassh
|
||||
functions. All codes indicating an error must always be ored with
|
||||
a severity code (@ref assh_error_severity_e). */
|
||||
enum assh_error_e
|
||||
{
|
||||
/** Success error code. */
|
||||
ASSH_OK = 0,
|
||||
/** No data were available, this is not fatal. */
|
||||
ASSH_NO_DATA = 1,
|
||||
/** The requested entry was not found, this is not fatal. */
|
||||
ASSH_NOT_FOUND = 2,
|
||||
|
||||
/** IO error. */
|
||||
ASSH_ERR_IO = 0x100,
|
||||
/** Memory allocation error. */
|
||||
ASSH_ERR_MEM = 0x101,
|
||||
/** Buffer overflow in input data. Input data contains bad or
|
||||
corrupt data which would result in memory access outside allowed bounds. */
|
||||
ASSH_ERR_INPUT_OVERFLOW = 0x102,
|
||||
/** Output buffer is not large enough to write expected data. */
|
||||
ASSH_ERR_OUTPUT_OVERFLOW = 0x103,
|
||||
/** Arithmetic overflow on big number. */
|
||||
ASSH_ERR_NUM_OVERFLOW = 0x104,
|
||||
/** Compare failed on big number. */
|
||||
ASSH_ERR_NUM_COMPARE_FAILED = 0x105,
|
||||
/** Bad version of the ssh protocol. */
|
||||
ASSH_ERR_BAD_VERSION = 0x106,
|
||||
/** Packet or buffer contains unexpected or corrupt data. */
|
||||
ASSH_ERR_BAD_DATA = 0x107,
|
||||
/** Invalid function arguments */
|
||||
ASSH_ERR_BAD_ARG = 0x108,
|
||||
/** Message authentication code error. */
|
||||
ASSH_ERR_MAC = 0x109,
|
||||
/** Packet content doesn't match current state of the protocol. */
|
||||
ASSH_ERR_PROTOCOL = 0x10a,
|
||||
/** The function can not be called in the current state of the protocol. */
|
||||
ASSH_ERR_STATE = 0x10b,
|
||||
/** Crypto initialization or processing error. */
|
||||
ASSH_ERR_CRYPTO = 0x10c,
|
||||
/** Unsupported parameter value. */
|
||||
ASSH_ERR_NOTSUP = 0x10d,
|
||||
/** The key exchange has failed */
|
||||
ASSH_ERR_KEX_FAILED = 0x10f,
|
||||
/** The required key is not available. */
|
||||
ASSH_ERR_MISSING_KEY = 0x110,
|
||||
/** The required algorithm is not available. */
|
||||
ASSH_ERR_MISSING_ALGO = 0x111,
|
||||
/** The host key verification has failed */
|
||||
ASSH_ERR_HOSTKEY_SIGNATURE = 0x113,
|
||||
/** The requested service is not available */
|
||||
ASSH_ERR_SERVICE_NA = 0x114,
|
||||
/** No more authentication method available. */
|
||||
ASSH_ERR_NO_AUTH = 0x115,
|
||||
/** The remote host sent a disconnect packet. */
|
||||
ASSH_ERR_DISCONNECTED = 0x116,
|
||||
/** The client has reached the end of list of services to request. */
|
||||
ASSH_ERR_NO_MORE_SERVICE = 0x117,
|
||||
/** The session is closed. */
|
||||
ASSH_ERR_CLOSED = 0x118,
|
||||
/** Algorithm or key security level is below defined threshold. */
|
||||
ASSH_ERR_WEAK_ALGORITHM = 0x119,
|
||||
};
|
||||
|
||||
/** @This extracts the @ref assh_error_e part of an error code
|
||||
returned by a function. */
|
||||
#define ASSH_ERR_ERROR(code) ((err) & 0xfff)
|
||||
/** @This extracts the @ref assh_error_severity_e part of an error
|
||||
code returned by a function. */
|
||||
#define ASSH_ERR_SEVERITY(code) ((err) & 0xf000)
|
||||
|
||||
/** @internal Log2 of smallest packet size bucket in the packet
|
||||
allocator pool. */
|
||||
#define ASSH_PCK_POOL_MIN 6
|
||||
/** @internal Log2 of largest packet size bucket in the packet
|
||||
allocator pool. */
|
||||
#define ASSH_PCK_POOL_MAX 16
|
||||
/** @internal Number of buckets in the packet allocator pool */
|
||||
#define ASSH_PCK_POOL_SIZE (ASSH_PCK_POOL_MAX - ASSH_PCK_POOL_MIN)
|
||||
|
||||
/** @internal Size of the context registered algorithms pointer array */
|
||||
#define ASSH_MAX_ALGORITHMS 64
|
||||
|
||||
/** @internal Size of the context registered services pointer array */
|
||||
#define ASSH_MAX_SERVICES 4
|
||||
|
||||
/** @internal Maximum size of hash algorithms output in bytes. */
|
||||
#define ASSH_MAX_HASH_SIZE 64
|
||||
|
||||
/** @internal Maximum size of cipher algorithms keys in bytes. */
|
||||
#define ASSH_MAX_EKEY_SIZE 64
|
||||
|
||||
/** @internal Maximum size of mac algorithms keys in bytes. */
|
||||
#define ASSH_MAX_IKEY_SIZE 64
|
||||
|
||||
/** @internal Maximum cipher block size in bytes. must be >= 16. */
|
||||
#define ASSH_MAX_BLOCK_SIZE 16
|
||||
|
||||
/** @internal Maximum size of cipher/mac keys or iv in bytes. */
|
||||
#define ASSH_MAX_SYMKEY_SIZE 64
|
||||
|
||||
/** @internal Maximum mac output size in bytes. */
|
||||
#define ASSH_MAX_MAC_SIZE 64
|
||||
|
||||
/** @internal Maximum size of incoming packet length, including header and mac. */
|
||||
#define ASSH_MAX_PCK_LEN 35000
|
||||
|
||||
/** @internal Default key re-echange threshold in bytes */
|
||||
#define ASSH_REKEX_THRESHOLD (1 << 31)
|
||||
|
||||
/** @internal Maximum size of packet payload */
|
||||
#define ASSH_MAX_PCK_PAYLOAD_SIZE \
|
||||
(ASSH_MAX_PCK_LEN - /* sizeof(struct assh_packet_head_s) */ 6 \
|
||||
- ASSH_MAX_MAC_SIZE - ASSH_MAX_BLOCK_SIZE)
|
||||
|
||||
|
||||
/** @internal */
|
||||
#define ASSH_ASSERT(expr) do { assh_error_t _e_ = (expr); assert((_e_ & 0xfff) == ASSH_OK); } while(0)
|
||||
|
||||
#ifndef CONFIG_ASSH_DEBUG
|
||||
|
||||
/** @internal */
|
||||
# define ASSH_DEBUG(...)
|
||||
|
||||
/** @internal */
|
||||
ASSH_INLINE void
|
||||
assh_hexdump(const char *name, const void *data, unsigned int len)
|
||||
{
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
# define ASSH_ERR_GTO(expr, label) do { if ((err = (expr)) & 0x100) goto label; err &= 0xff; } while (0)
|
||||
/** @internal */
|
||||
# define ASSH_ERR_RET(expr) do { if ((err = (expr)) & 0x100) return err; err &= 0xff; } while (0)
|
||||
|
||||
#else
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/** @internal */
|
||||
# define ASSH_DEBUG(...) fprintf(stderr, "assh_debug: " __VA_ARGS__)
|
||||
|
||||
/** @internal */
|
||||
void assh_hexdump(const char *name, const void *data, unsigned int len);
|
||||
|
||||
/** @internal */
|
||||
# define ASSH_ERR_GTO(expr, label) \
|
||||
do { \
|
||||
err = (expr); \
|
||||
if (err & 0x100) \
|
||||
{ \
|
||||
fprintf(stderr, "%s:%u:assh ERROR %u in %s, expr:`%s'\n", \
|
||||
__FILE__, __LINE__, err, __func__, #expr); \
|
||||
goto label; \
|
||||
} \
|
||||
else { \
|
||||
err &= 0xff; \
|
||||
/* fprintf(stderr, "%s:%u:assh in %s.\n", \
|
||||
__FILE__, __LINE__, __func__); */ \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/** @internal */
|
||||
# define ASSH_ERR_RET(expr) \
|
||||
do { \
|
||||
err = (expr); \
|
||||
if (err & 0x100) \
|
||||
{ \
|
||||
fprintf(stderr, "%s:%u:assh ERROR %u in %s, expr:`%s'\n", \
|
||||
__FILE__, __LINE__, err, __func__, #expr); \
|
||||
return err; \
|
||||
} \
|
||||
else { \
|
||||
err &= 0xff; \
|
||||
/* fprintf(stderr, "%s:%u:assh in %s.\n", \
|
||||
__FILE__, __LINE__, __func__); */ \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
|
||||
/** @internal */
|
||||
# define ASSH_CHK_GTO(cond, err, label) ASSH_ERR_GTO(cond ? err : 0, label)
|
||||
|
||||
/** @internal */
|
||||
# define ASSH_CHK_RET(cond, err) ASSH_ERR_RET(cond ? err : 0)
|
||||
|
||||
/** @This holds a pointer and a size value used as a string or buffer */
|
||||
struct assh_buffer_s
|
||||
{
|
||||
union {
|
||||
char *str;
|
||||
uint8_t *data;
|
||||
};
|
||||
union {
|
||||
size_t size;
|
||||
size_t len;
|
||||
};
|
||||
};
|
||||
|
||||
/** @internal SSH implementation identification string */
|
||||
#define ASSH_IDENT "SSH-2.0-LIBASSH\r\n"
|
||||
|
||||
/** @internal This macro specifies the prototype of a memory allocator function. */
|
||||
#define ASSH_ALLOCATOR(n) assh_error_t (n)(void *alloc_pv, void **ptr, \
|
||||
size_t size, enum assh_alloc_type_e type)
|
||||
|
||||
/** Memory allocator function type, same behavior as standard @tt realloc. */
|
||||
typedef ASSH_ALLOCATOR(assh_allocator_t);
|
||||
|
||||
/** @internal @hidecontent */
|
||||
#define ASSH_FIRST_FIELD_ASSERT(struct_name, field) \
|
||||
/** @hidden */ \
|
||||
typedef int field##_must_be_the_first_field_in_struct_##struct_name \
|
||||
[-(int)offsetof(struct struct_name, field)];
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,174 @@
|
|||
/*
|
||||
|
||||
libassh - asynchronous ssh2 client/server library.
|
||||
|
||||
Copyright (C) 2013 Alexandre Becoulet <alexandre.becoulet@free.fr>
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@file
|
||||
@short SSH algorithms base descriptor structure and related functions
|
||||
*/
|
||||
|
||||
#ifndef ASSH_ALGO_H_
|
||||
#define ASSH_ALGO_H_
|
||||
|
||||
#include "assh.h"
|
||||
|
||||
/** @internal @see assh_algo_suitable_key_t */
|
||||
#define ASSH_ALGO_SUITABLE_KEY_FCN(n) assh_bool_t (n) \
|
||||
(struct assh_context_s *c, \
|
||||
const struct assh_algo_s *algo, \
|
||||
const struct assh_key_s *key)
|
||||
|
||||
/** @internal @This defines the function type for the key
|
||||
compatibility checking operation common to all the algorithm
|
||||
module interfaces. @see assh_algo_suitable_key */
|
||||
typedef ASSH_ALGO_SUITABLE_KEY_FCN(assh_algo_suitable_key_t);
|
||||
|
||||
/** @internal @This specifies classes of SSH algorithm */
|
||||
enum assh_algo_class_e
|
||||
{
|
||||
ASSH_ALGO_KEX,
|
||||
ASSH_ALGO_SIGN,
|
||||
ASSH_ALGO_CIPHER,
|
||||
ASSH_ALGO_MAC,
|
||||
ASSH_ALGO_COMPRESS,
|
||||
ASSH_ALGO_ANY,
|
||||
};
|
||||
|
||||
/** @internalmembers @This is the generic algorithm descriptor
|
||||
structure. Other algorithm descriptor structures iherit from this
|
||||
type. */
|
||||
struct assh_algo_s
|
||||
{
|
||||
/** SSH algorithm identifier, used during key exchange */
|
||||
const char *name;
|
||||
|
||||
/** Variant description string, used when multiple declarations of
|
||||
the same algorithm name exist. */
|
||||
const char *variant;
|
||||
|
||||
/** Class of algorithm */
|
||||
enum assh_algo_class_e class_;
|
||||
|
||||
/** Pointer to associated key operations, may be @tt NULL. */
|
||||
const struct assh_key_ops_s *key;
|
||||
|
||||
/** Test if a key can be used with the algorithm, may be @tt NULL. */
|
||||
assh_algo_suitable_key_t *f_suitable_key;
|
||||
|
||||
/** Safety factor in range [0, 99] */
|
||||
int_fast16_t safety;
|
||||
/** Speed factor in range [0, 99] */
|
||||
int_fast16_t speed;
|
||||
/** Used to choose between variants having the same name */
|
||||
int_fast8_t priority;
|
||||
};
|
||||
|
||||
/**
|
||||
@This registers the specified @ref assh_algo_s objects for use by
|
||||
the given context. The last parameter must be @tt NULL.
|
||||
|
||||
The algorithms are sorted depending on their safety factor and
|
||||
speed factor. The @tt safety parameter indicates how algorithms
|
||||
safety must be favored over speed. Valid range for this parameter
|
||||
is [0, 99]. Algorithms with a safety factor less than @tt
|
||||
min_safety are skipped.
|
||||
|
||||
The Safety factor is defined follow:
|
||||
|
||||
@list
|
||||
@item 0-19: weak, broken
|
||||
@item 20-25: borderline
|
||||
@item 26-49: suitable for general use
|
||||
@item 50-99: strong
|
||||
@end list
|
||||
|
||||
If multiple implementations of the same algorithm are registered,
|
||||
the variant which appears first in the list after sorting is kept
|
||||
and subsequent variants with the same name are discarded. This
|
||||
should retain the less secure variants of the same algorithm not
|
||||
filtered by the value of @tt min_safety.
|
||||
*/
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_algo_register_va(struct assh_context_s *c, unsigned int safety,
|
||||
unsigned int min_safety, ...);
|
||||
|
||||
/**
|
||||
@This registers the specified @ref assh_algo_s objects for use by
|
||||
the given context. The last table entry must be @tt NULL.
|
||||
@see assh_algo_register_va
|
||||
*/
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_algo_register(struct assh_context_s *c, unsigned int safety,
|
||||
unsigned int min_safety, const struct assh_algo_s *table[]);
|
||||
|
||||
/** NULL terminated array of available algorithms. */
|
||||
extern const struct assh_algo_s *assh_algo_table[];
|
||||
|
||||
/** @This returns registered algorithms indexed from 0. @tt NULL is
|
||||
returned when out of range. */
|
||||
const struct assh_algo_s *
|
||||
assh_algo_registered(struct assh_context_s *c, uint_fast16_t i);
|
||||
|
||||
/** @internal @This registers the default set of available algorithms
|
||||
depending on the library configuration. It relies on the @ref
|
||||
assh_algo_register_va function. */
|
||||
ASSH_INLINE ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_algo_register_default(struct assh_context_s *c,
|
||||
unsigned int safety,
|
||||
unsigned int min_safety)
|
||||
{
|
||||
return assh_algo_register(c, safety, min_safety, assh_algo_table);
|
||||
}
|
||||
|
||||
/** Unregister all algorithms */
|
||||
void assh_algo_unregister(struct assh_context_s *c);
|
||||
|
||||
/** @internal @This finds a registered algorithm with matching class
|
||||
and name. */
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_algo_by_name(struct assh_context_s *c,
|
||||
enum assh_algo_class_e class_, const char *name,
|
||||
size_t name_len, const struct assh_algo_s **algo);
|
||||
|
||||
/** @internal @This finds a registered algorithm which can be used
|
||||
with the given key. If the @tt pos parameter is not @tt NULL, it
|
||||
specifies the starting index of the search and it will be updated
|
||||
with the index of the matching entry. */
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_algo_by_key(struct assh_context_s *c,
|
||||
const struct assh_key_s *key, uint_fast16_t *pos,
|
||||
const struct assh_algo_s **algo);
|
||||
|
||||
/** @internal @This returns true if the provided key can be used with
|
||||
the algorithm and has been loaded or created for that purpose.
|
||||
When the @tt key parameter is @tt NULL, the return value indicates
|
||||
if the algorithm needs a key when used during a key exchange.
|
||||
|
||||
This does not check the validity of the key, the @ref
|
||||
assh_key_validate function is provided for that purpose. */
|
||||
assh_bool_t
|
||||
assh_algo_suitable_key(struct assh_context_s *c,
|
||||
const struct assh_algo_s *algo,
|
||||
const struct assh_key_s *key);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
|
||||
libassh - asynchronous ssh2 client/server library.
|
||||
|
||||
Copyright (C) 2013 Alexandre Becoulet <alexandre.becoulet@free.fr>
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@file @internal
|
||||
@short Pluggable memory allocation functions used by the library
|
||||
*/
|
||||
|
||||
#ifndef ASSH_ALLOC_H_
|
||||
#define ASSH_ALLOC_H_
|
||||
|
||||
#include "assh_context.h"
|
||||
|
||||
/** @internal @This specifies the type of data to be stored in the
|
||||
allocated memory. */
|
||||
enum assh_alloc_type_e
|
||||
{
|
||||
ASSH_ALLOC_NONE,
|
||||
/** General purpose allocation in non-secur memory. */
|
||||
ASSH_ALLOC_INTERNAL,
|
||||
/** Buffer allocation in secur memory which don't last longer than a
|
||||
function call. */
|
||||
ASSH_ALLOC_SCRATCH,
|
||||
/** Cryptographic allocation in secur memory. */
|
||||
ASSH_ALLOC_SECUR,
|
||||
/** SSH packet allocation. Used to store enciphered and clear text
|
||||
packets. */
|
||||
ASSH_ALLOC_PACKET,
|
||||
};
|
||||
|
||||
/** @internal @This allocates memory. */
|
||||
ASSH_INLINE ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_alloc(struct assh_context_s *c, size_t size,
|
||||
enum assh_alloc_type_e type, void **result)
|
||||
{
|
||||
*result = NULL;
|
||||
return c->f_alloc(c->alloc_pv, result, size, type);
|
||||
}
|
||||
|
||||
/** @internal @This reallocates memory. */
|
||||
ASSH_INLINE ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_realloc(struct assh_context_s *c, void **ptr, size_t size,
|
||||
enum assh_alloc_type_e type)
|
||||
{
|
||||
return c->f_alloc(c->alloc_pv, ptr, size, type);
|
||||
}
|
||||
|
||||
/** @internal @This releases memory. */
|
||||
ASSH_INLINE void assh_free(struct assh_context_s *c, void *ptr)
|
||||
{
|
||||
if (ptr != NULL)
|
||||
(void)c->f_alloc(c->alloc_pv, &ptr, 0, ASSH_ALLOC_NONE);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ASSH_ALLOCA
|
||||
|
||||
# include <alloca.h>
|
||||
|
||||
/** @internal @This allocates memory not used after current function
|
||||
return.
|
||||
|
||||
Depending on the value of @ref #CONFIG_ASSH_ALLOCA, this macro
|
||||
either relies on the @tt alloca function or calls the @ref
|
||||
assh_alloc function using the @ref ASSH_ALLOC_SCRATCH type.
|
||||
|
||||
@see #ASSH_SCRATCH_FREE.
|
||||
*/
|
||||
# define ASSH_SCRATCH_ALLOC(context, type, name, size, sv, lbl) \
|
||||
size_t name##_size = (size) * sizeof(type); \
|
||||
type *name = (type*)alloca(name##_size);
|
||||
|
||||
/** @internal @This releases memory allocated by @ref
|
||||
#ASSH_SCRATCH_ALLOC. */
|
||||
# define ASSH_SCRATCH_FREE(context, name) \
|
||||
do { memset(name, 0, name##_size) } while (0)
|
||||
|
||||
#else
|
||||
|
||||
# define ASSH_SCRATCH_ALLOC(context, type, name, size, sv, lbl) \
|
||||
type *name; \
|
||||
ASSH_ERR_GTO(assh_alloc(context, (size) * sizeof(type), \
|
||||
ASSH_ALLOC_SCRATCH, (void**)&name) | sv, lbl);
|
||||
|
||||
# define ASSH_SCRATCH_FREE(context, name) \
|
||||
do { assh_free(context, name); } while (0)
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,671 @@
|
|||
/*
|
||||
|
||||
libassh - asynchronous ssh2 client/server library.
|
||||
|
||||
Copyright (C) 2013 Alexandre Becoulet <alexandre.becoulet@free.fr>
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@file
|
||||
@short Big number engine module interface
|
||||
@internal
|
||||
|
||||
The big number computations in libassh are expressed using a
|
||||
dedicated bytecode. A big number module is in charge of executing
|
||||
this bytecode.
|
||||
*/
|
||||
|
||||
#ifndef ASSH_BIGNUM_H_
|
||||
#define ASSH_BIGNUM_H_
|
||||
|
||||
#include "assh_context.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
/** @internal
|
||||
|
||||
@This is the big number bytecode instruction word. The instruction
|
||||
binary formats is as follow:
|
||||
|
||||
@code R
|
||||
op(6) c(26)
|
||||
xxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
|
||||
op(6) c(20) d(6)
|
||||
xxxxxx xxxxxxxxxxxxxxxxxxxx xxxxxx
|
||||
|
||||
op(6) b(12) c(8) d(6)
|
||||
xxxxxx xxxxxxxxxxxx xxxxxxxx xxxxxx
|
||||
|
||||
op(6) a(6) b(6) c(8) d(6)
|
||||
xxxxxx xxxxxx xxxxxx xxxxxxxx xxxxxx
|
||||
@end code
|
||||
@see #ASSH_BOP_FMT1
|
||||
@see #ASSH_BOP_FMT2
|
||||
@see #ASSH_BOP_FMT3
|
||||
@see #ASSH_BOP_FMT4
|
||||
*/
|
||||
typedef uint32_t assh_bignum_op_t;
|
||||
|
||||
/** @internal @This generates bytecode instruction format 4 */
|
||||
#define ASSH_BOP_FMT4(op, a, b, c, d) (((op) << 26) | ((a) << 20) | ((b) << 14) | ((c) << 6) | (d))
|
||||
/** @internal @This generates bytecode instruction format 3 */
|
||||
#define ASSH_BOP_FMT3(op, b, c, d) (((op) << 26) | ((b) << 14) | ((c) << 6) | (d))
|
||||
/** @internal @This generates bytecode instruction format 2 */
|
||||
#define ASSH_BOP_FMT2(op, c, d) (((op) << 26) | ((c) << 6) | (d))
|
||||
/** @internal @This generates bytecode instruction format 1 */
|
||||
#define ASSH_BOP_FMT1(op, d) (((op) << 26) | (d))
|
||||
|
||||
|
||||
/** @internal @This specifies various storage formats of big numbers. */
|
||||
enum assh_bignum_fmt_e
|
||||
{
|
||||
/** Native big number representation, stored as a
|
||||
@ref assh_bignum_s object. */
|
||||
ASSH_BIGNUM_NATIVE = 'N',
|
||||
/** Same representation as @ref ASSH_BIGNUM_NATIVE, used as a
|
||||
temporary value during bytecode execution. */
|
||||
ASSH_BIGNUM_TEMP = 'T',
|
||||
/** Secret temporary, @see ASSH_BIGNUM_TEMP. */
|
||||
ASSH_BIGNUM_STEMP = 'X',
|
||||
/** SSH mpint representation. */
|
||||
ASSH_BIGNUM_MPINT = 'M',
|
||||
/** ASN1 integer representation. */
|
||||
ASSH_BIGNUM_ASN1 = 'A',
|
||||
/** RAW MSB data embedded in a SSH string */
|
||||
ASSH_BIGNUM_STRING = 'S',
|
||||
/** RAW MSB first data without header */
|
||||
ASSH_BIGNUM_MSB_RAW = 'D',
|
||||
/** RAW LSB first data without header */
|
||||
ASSH_BIGNUM_LSB_RAW = 'd',
|
||||
/** NUL terminated hexadecimal representation */
|
||||
ASSH_BIGNUM_HEX = 'H',
|
||||
/** NUL terminated decimal string representation */
|
||||
ASSH_BIGNUM_DEC = 'd',
|
||||
/** Intptr_t value interpreted as a number value. */
|
||||
ASSH_BIGNUM_INT = 'i',
|
||||
/** Intptr_t value interpreted as a bit size. */
|
||||
ASSH_BIGNUM_SIZE = 's',
|
||||
/** Ladder object. see assh_bignum_lad_s */
|
||||
ASSH_BIGNUM_LAD = 'L',
|
||||
/** Temporary montgomery multiplication context. */
|
||||
ASSH_BIGNUM_MT = 'm',
|
||||
};
|
||||
|
||||
/** @internal @This represents a big number in native format. The
|
||||
number object is empty if no internal representation of the number
|
||||
is currently allocated (@ref n is @tt NULL). */
|
||||
struct assh_bignum_s
|
||||
{
|
||||
/** Bits size */
|
||||
uint16_t bits;
|
||||
/** Whether the number is secret */
|
||||
uint16_t secret:1;
|
||||
/** Whether the number is a montgomery modulus */
|
||||
uint16_t montgomery:1;
|
||||
/** Number data */
|
||||
void *n;
|
||||
};
|
||||
|
||||
/** @internal @This contains a ladder state which can be
|
||||
used during bytecode execution. @see #ASSH_BOP_LADLOOP @see
|
||||
#ASSH_BOP_LADSWAP @see #ASSH_BOP_LADJMP */
|
||||
struct assh_bignum_lad_s
|
||||
{
|
||||
/** Input data */
|
||||
const uint8_t *data;
|
||||
/** Number of bits in data */
|
||||
uint16_t count;
|
||||
/** Set when data are stored most significant bit first in a byte. */
|
||||
assh_bool_t msbit_1st:1;
|
||||
/** Set when data are most significant byte first in the buffer. */
|
||||
assh_bool_t msbyte_1st:1;
|
||||
};
|
||||
|
||||
/* test current ladder bit */
|
||||
static inline assh_bool_t
|
||||
assh_bignum_lad(struct assh_bignum_lad_s *lad)
|
||||
{
|
||||
uint16_t bit = lad->count - 1;
|
||||
|
||||
if (!lad->msbit_1st)
|
||||
bit ^= 7;
|
||||
if (lad->msbyte_1st)
|
||||
return (lad->data[0] >> (bit & 7)) & 1;
|
||||
else
|
||||
return (lad->data[bit / 8] >> (bit & 7)) & 1;
|
||||
}
|
||||
|
||||
/** @internal @see assh_bignum_bytecode_t */
|
||||
#define ASSH_BIGNUM_BYTECODE_FCN(n) \
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t \
|
||||
(n)(struct assh_context_s *c, \
|
||||
const assh_bignum_op_t *ops, \
|
||||
const char *format, va_list ap)
|
||||
|
||||
/** @internal @This defines the function type for the byte code
|
||||
execution operation of the big number module interface.
|
||||
@see assh_bignum_bytecode */
|
||||
typedef ASSH_BIGNUM_BYTECODE_FCN(assh_bignum_bytecode_t);
|
||||
|
||||
|
||||
/** @internal @see assh_bignum_convert_t */
|
||||
#define ASSH_BIGNUM_CONVERT_FCN(n) \
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t \
|
||||
(n)(struct assh_context_s *c, \
|
||||
enum assh_bignum_fmt_e srcfmt, \
|
||||
enum assh_bignum_fmt_e dstfmt, \
|
||||
const void *src, void *dst)
|
||||
|
||||
/** @internal @This defines the function type for the number
|
||||
conversion operation of the big number module interface. @see
|
||||
assh_bignum_convert */
|
||||
typedef ASSH_BIGNUM_CONVERT_FCN(assh_bignum_convert_t);
|
||||
|
||||
|
||||
/** @internal @see assh_bignum_release_t */
|
||||
#define ASSH_BIGNUM_RELEASE_FCN(n) \
|
||||
void (n)(struct assh_context_s *ctx, struct assh_bignum_s *bn)
|
||||
|
||||
/** @internal @This defines the function type for the release
|
||||
operation of the big number module interface. @see
|
||||
assh_bignum_release */
|
||||
typedef ASSH_BIGNUM_RELEASE_FCN(assh_bignum_release_t);
|
||||
|
||||
/** @internal @This is the big number engine module interface structure. */
|
||||
struct assh_bignum_algo_s
|
||||
{
|
||||
const char *name;
|
||||
assh_bignum_bytecode_t *f_bytecode;
|
||||
assh_bignum_convert_t *f_convert;
|
||||
assh_bignum_release_t *f_release;
|
||||
};
|
||||
|
||||
/** @internal @This executes big number operations specified by the
|
||||
given bytecode. Operations are performed on arguments and
|
||||
temporarie values as specified by the @tt format argument.
|
||||
|
||||
The format string indicates the types of arguments passed to the
|
||||
function and the number of temporary values. The format string is
|
||||
composed of characters defined in @ref assh_bignum_fmt_e. An extra
|
||||
argument must be passed to the function for each non-temporary
|
||||
entry in the format string.
|
||||
|
||||
The @ref #ASSH_BOP_MOVE instruction can be used to convert between
|
||||
native big numbers (arguments or temporaries) and other types of
|
||||
arguments. Unless specified otherwise, all other instructions are
|
||||
designed to be used on native big numbers only.
|
||||
|
||||
Native big number arguments are passed as pointers to @ref
|
||||
assh_bignum_s objects. The size of big numbers can only be changed
|
||||
by the @ref #ASSH_BOP_SIZE family of instructions. The destination
|
||||
big number used with other instructions must be large enough to
|
||||
store the result as the number will not be dynamically
|
||||
resized. Working on numbers with a predefined storage size helps
|
||||
with constant time execution.
|
||||
|
||||
Resources used by temporary numbers are automatically released when
|
||||
the function returns. */
|
||||
ASSH_INLINE ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_bignum_bytecode(struct assh_context_s *c,
|
||||
const assh_bignum_op_t *ops,
|
||||
const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
assh_error_t err;
|
||||
va_start(ap, format);
|
||||
err = c->bignum->f_bytecode(c, ops, format, ap);
|
||||
va_end(ap);
|
||||
return err;
|
||||
}
|
||||
|
||||
/** @internal @This converts between a big number in @ref
|
||||
ASSH_BIGNUM_NATIVE format and a number in an alternate format. The
|
||||
native big number argument points to an @ref assh_bignum_s object.
|
||||
|
||||
When converting to a native big number from a number in @ref
|
||||
ASSH_BIGNUM_STRING, @ref ASSH_BIGNUM_ASN1 or @ref
|
||||
ASSH_BIGNUM_MPINT format, the source number must have a properly
|
||||
initialized or checked size header. When converting from a source
|
||||
number in @ref ASSH_BIGNUM_MSB_RAW or @ref ASSH_BIGNUM_LSB_RAW
|
||||
format, the bit size of the destination number is used; leading
|
||||
bits in the most significant byte of the source are ignored.
|
||||
|
||||
In all other cases, the buffer size is expected to be appropriate
|
||||
for the bits size of the native big number involved in the
|
||||
conversion, as returned by the @ref assh_bignum_size_of_bits and
|
||||
@ref assh_bignum_size_of_num functions.
|
||||
|
||||
When converting between two native big numbers, the current bits
|
||||
size of the source might be larger than the size of the destination
|
||||
provided that the actual value fits in the destination. */
|
||||
ASSH_INLINE ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_bignum_convert(struct assh_context_s *c,
|
||||
enum assh_bignum_fmt_e src_fmt,
|
||||
enum assh_bignum_fmt_e dst_fmt,
|
||||
const void *src, void *dst)
|
||||
{
|
||||
return c->bignum->f_convert(c, src_fmt, dst_fmt, src, dst);
|
||||
}
|
||||
|
||||
/** @internal @This returns the byte size needed to store a big number
|
||||
of given bit size using the specified format. */
|
||||
size_t assh_bignum_size_of_bits(enum assh_bignum_fmt_e dst_fmt, size_t bits);
|
||||
|
||||
/** @internal @This returns the byte size needed to store the given
|
||||
big number object. */
|
||||
ASSH_INLINE size_t
|
||||
assh_bignum_size_of_num(enum assh_bignum_fmt_e dst_fmt,
|
||||
const struct assh_bignum_s *bn)
|
||||
{
|
||||
return assh_bignum_size_of_bits(dst_fmt, bn->bits);
|
||||
}
|
||||
|
||||
/** @internal @This evaluates the storage size in bytes, the actual
|
||||
embedded value size in bytes and the bit size of the big number
|
||||
value. The @tt fmt parameter indicates the input format of @tt data. No
|
||||
bound checking is performed, the buffer size of the input data
|
||||
must have been checked previously. Some value checks are performed
|
||||
on the format of the data.
|
||||
|
||||
Either @tt size, @tt val_size or @tt bits may be @tt NULL. When
|
||||
the input format is either @ref ASSH_BIGNUM_MSB_RAW or
|
||||
@ref ASSH_BIGNUM_LSB_RAW, the @tt size parameter must be used to
|
||||
pass the bytes size of the buffer. */
|
||||
assh_error_t ASSH_WARN_UNUSED_RESULT
|
||||
assh_bignum_size_of_data(enum assh_bignum_fmt_e fmt,
|
||||
const void *data, size_t *size,
|
||||
size_t *val_size, size_t *bits);
|
||||
|
||||
/** @internal @This initializes a big number object. No buffer is
|
||||
allocated, the big number is left empty. */
|
||||
ASSH_INLINE void
|
||||
assh_bignum_init(struct assh_context_s *c,
|
||||
struct assh_bignum_s *bn,
|
||||
size_t bits, assh_bool_t secret)
|
||||
{
|
||||
bn->bits = bits;
|
||||
bn->secret = secret;
|
||||
bn->montgomery = 0;
|
||||
bn->n = NULL;
|
||||
}
|
||||
|
||||
/** @internal @This returns the number of bits of a big number. */
|
||||
ASSH_INLINE size_t
|
||||
assh_bignum_bits(const struct assh_bignum_s *bn)
|
||||
{
|
||||
return bn->bits;
|
||||
}
|
||||
|
||||
/** @internal @This test if a big number is actually stored in the
|
||||
object or if it's empty. */
|
||||
ASSH_INLINE assh_bool_t
|
||||
assh_bignum_isempty(const struct assh_bignum_s *bn)
|
||||
{
|
||||
return bn->n == NULL;
|
||||
}
|
||||
|
||||
/** @internal @This releases the internal storage of a bignum. The big
|
||||
number object become empty as if the @ref assh_bignum_init
|
||||
function has just been called. */
|
||||
ASSH_INLINE void
|
||||
assh_bignum_release(struct assh_context_s *ctx,
|
||||
struct assh_bignum_s *bn)
|
||||
{
|
||||
ctx->bignum->f_release(ctx, bn);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
enum assh_bignum_opcode_e
|
||||
{
|
||||
ASSH_BIGNUM_OP_END,
|
||||
ASSH_BIGNUM_OP_MOVE,
|
||||
ASSH_BIGNUM_OP_SIZER,
|
||||
ASSH_BIGNUM_OP_SIZE,
|
||||
ASSH_BIGNUM_OP_ADD,
|
||||
ASSH_BIGNUM_OP_SUB,
|
||||
ASSH_BIGNUM_OP_MUL,
|
||||
ASSH_BIGNUM_OP_DIV,
|
||||
ASSH_BIGNUM_OP_GCD,
|
||||
ASSH_BIGNUM_OP_EXPM,
|
||||
ASSH_BIGNUM_OP_INV,
|
||||
ASSH_BIGNUM_OP_SHR,
|
||||
ASSH_BIGNUM_OP_SHL,
|
||||
ASSH_BIGNUM_OP_RAND,
|
||||
ASSH_BIGNUM_OP_CMP,
|
||||
ASSH_BIGNUM_OP_TESTC,
|
||||
ASSH_BIGNUM_OP_TESTS,
|
||||
ASSH_BIGNUM_OP_UINT,
|
||||
ASSH_BIGNUM_OP_LADJMP,
|
||||
ASSH_BIGNUM_OP_LADSWAP,
|
||||
ASSH_BIGNUM_OP_LADLOOP,
|
||||
ASSH_BIGNUM_OP_MTINIT,
|
||||
ASSH_BIGNUM_OP_MTTO,
|
||||
ASSH_BIGNUM_OP_MTFROM,
|
||||
ASSH_BIGNUM_OP_MTONE,
|
||||
ASSH_BIGNUM_OP_PRIME,
|
||||
ASSH_BIGNUM_OP_ISPRIM,
|
||||
ASSH_BIGNUM_OP_PRIVACY,
|
||||
ASSH_BIGNUM_OP_PRINT,
|
||||
};
|
||||
|
||||
/** @internal */
|
||||
#define ASSH_BIGNUM_OP_NAMES { \
|
||||
"end", "move", "sizer", "size", "add", \
|
||||
"sub", "mul", "div", "gcd", \
|
||||
"expm", "inv", "shr", "shl", \
|
||||
"rand", "cmp", "testc", "tests", "uint", \
|
||||
"ladjmp", "ladswap", "ladloop", \
|
||||
"mtinit", "mtto", "mtfrom", "mtone", \
|
||||
"prime", "isprim", "privacy", "print" \
|
||||
}
|
||||
|
||||
/** @internal Reserved big number bytecode register id. */
|
||||
#define ASSH_BOP_NOREG 63
|
||||
|
||||
/** @mgroup{Bytecode instructions}
|
||||
@internal This instruction terminates execution of the bytecode. */
|
||||
#define ASSH_BOP_END() \
|
||||
ASSH_BOP_FMT3(ASSH_BIGNUM_OP_END, 0, 0, 0)
|
||||
|
||||
/** @mgroup{Bytecode instructions}
|
||||
@internal This instruction moves and converts values in various
|
||||
formats. It is equivalent to the @ref assh_bignum_convert_t function. */
|
||||
#define ASSH_BOP_MOVE(dst, src) \
|
||||
ASSH_BOP_FMT2(ASSH_BIGNUM_OP_MOVE, dst, src)
|
||||
|
||||
/** @mgroup{Bytecode instructions}
|
||||
@internal This initializes a temporary montgomery multiplication
|
||||
context from a modulus number. The context is released at the end
|
||||
of the bytecode execution. */
|
||||
#define ASSH_BOP_MTINIT(mt, mod) \
|
||||
ASSH_BOP_FMT2(ASSH_BIGNUM_OP_MTINIT, mt, mod)
|
||||
|
||||
/** @mgroup{Bytecode instructions}
|
||||
@internal This converts the source number to montgomery representation.
|
||||
|
||||
The resulting value can be further processed by the @ref #ASSH_BOP_ADDM,
|
||||
@ref #ASSH_BOP_SUBM, @ref #ASSH_BOP_MULM, @ref #ASSH_BOP_EXPM,
|
||||
@ref ASSH_BOP_INV and @ref #ASSH_BOP_MTFROM instructions.
|
||||
The @tt mt operand is a montgomery context initialized from the modulus
|
||||
using the @ref #ASSH_BOP_MTINIT instruction. */
|
||||
#define ASSH_BOP_MTTO(dst1, dst2, src, mt) \
|
||||
ASSH_BOP_FMT4(ASSH_BIGNUM_OP_MTTO, dst2 - dst1 + 1, dst1, src, mt)
|
||||
|
||||
/** @mgroup{Bytecode instructions}
|
||||
@internal This converts the source number from montgomery representation.
|
||||
The resulting number is reduced according to the modulus.
|
||||
@see #ASSH_BOP_MTTO */
|
||||
#define ASSH_BOP_MTFROM(dst1, dst2, src, mt) \
|
||||
ASSH_BOP_FMT4(ASSH_BIGNUM_OP_MTFROM, dst2 - dst1 + 1, dst1, src, mt)
|
||||
|
||||
#define ASSH_BOP_MTONE(dst, mt) \
|
||||
ASSH_BOP_FMT2(ASSH_BIGNUM_OP_MTFROM, dst2 - dst1 + 1, dst1, src, mt)
|
||||
|
||||
/** @mgroup{Bytecode instructions}
|
||||
@internal This instruction changes the bit size of a number. It is
|
||||
equivalent to a call to the @ref assh_bignum_init function on the
|
||||
destination, with the source operand being evaluated by a call to
|
||||
@ref assh_bignum_size_of_data. */
|
||||
#define ASSH_BOP_SIZE(dst, src) \
|
||||
ASSH_BOP_FMT4(ASSH_BIGNUM_OP_SIZE, dst, src, 0, 32)
|
||||
|
||||
/** @mgroup{Bytecode instructions}
|
||||
@internal This instruction has the same behavior as the @ref
|
||||
#ASSH_BOP_SIZE instruction with shift and offset of the source
|
||||
size value. */
|
||||
#define ASSH_BOP_SIZEM(dst, src, cadd, cshift) \
|
||||
ASSH_BOP_FMT4(ASSH_BIGNUM_OP_SIZE, dst, src, cadd, cshift + 32)
|
||||
|
||||
/** @mgroup{Bytecode instructions}
|
||||
@internal This instruction has the same behavior as the @ref
|
||||
#ASSH_BOP_SIZE instruction applied to a range of destination
|
||||
registers. */
|
||||
#define ASSH_BOP_SIZER(dst1, dst2, src) \
|
||||
ASSH_BOP_FMT4(ASSH_BIGNUM_OP_SIZER, dst1, src, dst2, 0)
|
||||
|
||||
/** @mgroup{Bytecode instructions}
|
||||
@internal This instruction computes @tt {dst = (src1 + src2) %
|
||||
mod} in constant time. The bit size of the destination number must be
|
||||
@tt {max(bits(src1), bits(src2))} or larger. The @tt mod
|
||||
operand can be either a big number or a montgomery context.
|
||||
The value of the modulus is subtracted on overflow. */
|
||||
#define ASSH_BOP_ADDM(dst, src1, src2, mod) \
|
||||
ASSH_BOP_FMT4(ASSH_BIGNUM_OP_ADD, dst, src1, src2, mod)
|
||||
|
||||
/** @mgroup{Bytecode instructions}
|
||||
@internal This instruction computes @tt {dst = (src1 - src2) %
|
||||
mod}. Same behavior as @ref #ASSH_BOP_ADDM. */
|
||||
#define ASSH_BOP_SUBM(dst, src1, src2, mod) \
|
||||
ASSH_BOP_FMT4(ASSH_BIGNUM_OP_SUB, dst, src1, src2, mod)
|
||||
|
||||
/** @mgroup{Bytecode instructions}
|
||||
@internal This instruction computes @tt {dst = (src1 + src2)} in
|
||||
constant time. The bit size of the destination number must
|
||||
be @tt {max(bits(src1), bits(src2))} or larger. */
|
||||
#define ASSH_BOP_ADD(dst, src1, src2) \
|
||||
ASSH_BOP_FMT4(ASSH_BIGNUM_OP_ADD, dst, src1, src2, ASSH_BOP_NOREG)
|
||||
|
||||
/** @mgroup{Bytecode instructions}
|
||||
@internal This instruction computes @tt {dst = (src1 - src2) %
|
||||
mod}. Same behavior as @ref #ASSH_BOP_ADD */
|
||||
#define ASSH_BOP_SUB(dst, src1, src2) \
|
||||
ASSH_BOP_FMT4(ASSH_BIGNUM_OP_SUB, dst, src1, src2, ASSH_BOP_NOREG)
|
||||
|
||||
/** @mgroup{Bytecode instructions}
|
||||
@internal This instruction computes @tt {dst = (src1 * src2) %
|
||||
mod}. The bit size of the destination number must be
|
||||
@tt {bits(mod)} or larger. The @tt mod operand can be either a
|
||||
big number or a montgomery context. In the later case the bit
|
||||
size of all operands must match the size of the montgomery
|
||||
context and the operation is computed in constant time. */
|
||||
#define ASSH_BOP_MULM(dst, src1, src2, mod) \
|
||||
ASSH_BOP_FMT4(ASSH_BIGNUM_OP_MUL, dst, src1, src2, mod)
|
||||
|
||||
/** @mgroup{Bytecode instructions}
|
||||
@internal This instruction computes @tt {dst = (src1 * src2)} in
|
||||
constant time. The bit size of the destination number must
|
||||
be @tt {bits(src1) + bits(src2)} or larger.*/
|
||||
#define ASSH_BOP_MUL(dst, src1, src2) \
|
||||
ASSH_BOP_FMT4(ASSH_BIGNUM_OP_MUL, dst, src1, src2, ASSH_BOP_NOREG)
|
||||
|
||||
/** @mgroup{Bytecode instructions}
|
||||
@internal This instruction computes @tt {dst2 = src1 % src2} and
|
||||
@tt {dst1 = src1 / src2}. @see #ASSH_BOP_MOD @see #ASSH_BOP_DIV */
|
||||
#define ASSH_BOP_DIVMOD(dstq, dstr, src1, src2) \
|
||||
ASSH_BOP_FMT4(ASSH_BIGNUM_OP_DIV, dstq, dstr, src1, src2)
|
||||
|
||||
/** @mgroup{Bytecode instructions}
|
||||
@internal This instruction computes @tt {dst2 = src1 % src2}.
|
||||
@see #ASSH_BOP_DIVMOD */
|
||||
#define ASSH_BOP_MOD(dst, src1, src2) \
|
||||
ASSH_BOP_FMT4(ASSH_BIGNUM_OP_DIV, ASSH_BOP_NOREG, dst, src1, src2)
|
||||
|
||||
/** @mgroup{Bytecode instructions}
|
||||
@internal This instruction computes @tt {dst2 = src1 / src2}.
|
||||
@see #ASSH_BOP_DIVMOD */
|
||||
#define ASSH_BOP_DIV(dst, src1, src2) \
|
||||
ASSH_BOP_FMT4(ASSH_BIGNUM_OP_DIV, dst, ASSH_BOP_NOREG, src1, src2)
|
||||
|
||||
/** @mgroup{Bytecode instructions}
|
||||
@internal This instruction computes @tt {dst = gcd(src1, src2)}. */
|
||||
#define ASSH_BOP_GCD(dst, src1, src2) \
|
||||
ASSH_BOP_FMT3(ASSH_BIGNUM_OP_GCD, dst, src1, src2)
|
||||
|
||||
/** @mgroup{Bytecode instructions}
|
||||
@internal This instruction computes @tt {dst = (src1 ^ src2) % mod}.
|
||||
The @tt mod operand must be a montgomery context. The @tt src1 and
|
||||
@tt dst operands are montgomery numbers and their bit size must
|
||||
match the size of the montgomery context.
|
||||
@see #ASSH_BOP_EXPM */
|
||||
#define ASSH_BOP_EXPM(dst, src1, src2, mod) \
|
||||
ASSH_BOP_FMT4(ASSH_BIGNUM_OP_EXPM, dst, src1, src2, mod)
|
||||
|
||||
/** @mgroup{Bytecode instructions}
|
||||
@internal This instruction computes @tt {dst = invmod(src1, src2)}.
|
||||
If @tt src2 is a montgomery context, the modulus must be prime as
|
||||
the operation is performed in constant time using the Fermat
|
||||
little theorem. */
|
||||
#define ASSH_BOP_INV(dst, src1, src2) \
|
||||
ASSH_BOP_FMT3(ASSH_BIGNUM_OP_INV, dst, src1, src2)
|
||||
|
||||
/** @mgroup{Bytecode instructions}
|
||||
@internal This instruction computes @tt {dst = shift_right(src1,
|
||||
val + size(src2))} in constant time. @tt val must be in range
|
||||
@tt{[-128, +127]} and @tt src2 can be @ref #ASSH_BOP_NOREG.
|
||||
The source and destination operands must have the same bit
|
||||
length and the shift amount must be less than the length. */
|
||||
#define ASSH_BOP_SHR(dst, src, val, src2) \
|
||||
ASSH_BOP_FMT4(ASSH_BIGNUM_OP_SHR, dst, src, 128 + (val), src2)
|
||||
|
||||
/** @mgroup{Bytecode instructions}
|
||||
@internal This instruction is similar to @ref #ASSH_BOP_SHR but
|
||||
perform a left shift. */
|
||||
#define ASSH_BOP_SHL(dst, src, val, src2) \
|
||||
ASSH_BOP_FMT4(ASSH_BIGNUM_OP_SHL, dst, src, 128 + (val), src2)
|
||||
|
||||
/** @mgroup{Bytecode instructions}
|
||||
@internal This instruction initializes a big number with random
|
||||
data. A new value is generated until it does fall in the specified
|
||||
range. The @tt min and @tt max bounds can be @ref #ASSH_BOP_NOREG.
|
||||
The quality operand is of type @ref assh_prng_quality_e. The result
|
||||
is flagged secret if the requested quality is not weak. */
|
||||
#define ASSH_BOP_RAND(dst, min, max, quality) \
|
||||
ASSH_BOP_FMT4(ASSH_BIGNUM_OP_RAND, dst, min, max, quality)
|
||||
|
||||
/** @mgroup{Bytecode instructions}
|
||||
@internal This instruction performs a comparison in constant time.
|
||||
It changes the program counter if the two numbers are equal.
|
||||
The bytecode execution is aborted with the @ref
|
||||
ASSH_ERR_NUM_COMPARE_FAILED error if the condition is false and
|
||||
the value of @tt pcdiff is 0.
|
||||
|
||||
It can be used with values of different bit length. It is possible
|
||||
to test if an @ref assh_bignum_s object is empty by comparing
|
||||
against @ref #ASSH_BOP_NOREG. */
|
||||
#define ASSH_BOP_CMPEQ(src1, src2, pcdiff) \
|
||||
ASSH_BOP_FMT4(ASSH_BIGNUM_OP_CMP, src1, src2, 128 + pcdiff, 0)
|
||||
/** @mgroup{Bytecode instructions}
|
||||
@internal This instruction is similar to @ref #ASSH_BOP_CMPEQ. */
|
||||
#define ASSH_BOP_CMPNE(src1, src2, pcdiff) \
|
||||
ASSH_BOP_FMT4(ASSH_BIGNUM_OP_CMP, src1, src2, 128 + pcdiff, 1)
|
||||
/** @mgroup{Bytecode instructions}
|
||||
@internal This instruction is similar to @ref #ASSH_BOP_CMPEQ. */
|
||||
#define ASSH_BOP_CMPLT(src1, src2, pcdiff) \
|
||||
ASSH_BOP_FMT4(ASSH_BIGNUM_OP_CMP, src1, src2, 128 + pcdiff, 2)
|
||||
/** @mgroup{Bytecode instructions}
|
||||
@internal This instruction is similar to @ref #ASSH_BOP_CMPEQ. */
|
||||
#define ASSH_BOP_CMPLTEQ(src1, src2, pcdiff) \
|
||||
ASSH_BOP_FMT4(ASSH_BIGNUM_OP_CMP, src1, src2, 128 + pcdiff, 3)
|
||||
|
||||
/** @mgroup{Bytecode instructions}
|
||||
@internal This instruction jump to a different bytecode location. */
|
||||
#define ASSH_BOP_JMP(pcdiff) \
|
||||
ASSH_BOP_FMT4(ASSH_BIGNUM_OP_CMP, 0, 0, 128 + pcdiff, 0)
|
||||
|
||||
/** @mgroup{Bytecode instructions}
|
||||
@internal This instruction tests a bit in @tt src1 and jumps to a
|
||||
different bytecode location if the bit is cleared. When the @tt
|
||||
src2 operand is @ref #ASSH_BOP_NOREG, the tested bit position is
|
||||
@tt{val}. In the other case, the tested bit position is @tt
|
||||
{size(src2) - val)}. @tt val must be in the range @tt{[0, 64]}. */
|
||||
#define ASSH_BOP_TESTC(src1, val, src2, pcdiff) \
|
||||
ASSH_BOP_FMT4(ASSH_BIGNUM_OP_TESTC, src1, val, 128 + pcdiff, src2)
|
||||
|
||||
/** @mgroup{Bytecode instructions}
|
||||
@internal This instruction is similar to @ref #ASSH_BOP_TESTC. */
|
||||
#define ASSH_BOP_TESTS(src1, val, src2, pcdiff) \
|
||||
ASSH_BOP_FMT4(ASSH_BIGNUM_OP_TESTS, src1, val, 128 + pcdiff, src2)
|
||||
|
||||
/** @mgroup{Bytecode instructions}
|
||||
@internal This instruction initializes a big number from a 20 bits
|
||||
unsigned integer constant. */
|
||||
#define ASSH_BOP_UINT(dst, value) \
|
||||
ASSH_BOP_FMT2(ASSH_BIGNUM_OP_UINT, value, dst)
|
||||
|
||||
/** @mgroup{Bytecode instructions}
|
||||
@internal This instruction performs a conditional jump between two
|
||||
values depending on the current state of the @ref
|
||||
assh_bignum_lad_s object. It is useful to implement a fast
|
||||
variant of the ladder algorithm when constant time execution is
|
||||
not required. @see #ASSH_BOP_LADLOOP @see ASSH_BIGNUM_LAD */
|
||||
#define ASSH_BOP_LADJMP(lad, pcdiff) \
|
||||
ASSH_BOP_FMT2(ASSH_BIGNUM_OP_LADJMP, 128 + pcdiff, lad)
|
||||
|
||||
/** @mgroup{Bytecode instructions}
|
||||
@internal This instruction performs a conditional swap between two
|
||||
values depending on the current state of the @ref
|
||||
assh_bignum_lad_s object. It is useful to implement a
|
||||
ladder. @see #ASSH_BOP_LADLOOP @see ASSH_BIGNUM_LAD */
|
||||
#define ASSH_BOP_LADSWAP(src1, src2, lad) \
|
||||
ASSH_BOP_FMT3(ASSH_BIGNUM_OP_LADSWAP, src1, src2, lad)
|
||||
|
||||
/** @mgroup{Bytecode instructions}
|
||||
@internal This instruction conditionally jump backward depending
|
||||
on the current state of the @ref assh_bignum_lad_s object and
|
||||
advances the state of the ladder object to the next data bit. It
|
||||
is useful to implement a ladder.
|
||||
@see #ASSH_BOP_LADSWAP @see ASSH_BIGNUM_LAD */
|
||||
#define ASSH_BOP_LADLOOP(rel, lad) \
|
||||
ASSH_BOP_FMT2(ASSH_BIGNUM_OP_LADLOOP, rel, lad)
|
||||
|
||||
/** @mgroup{Bytecode instructions}
|
||||
@internal This instruction generates a prime number in the range
|
||||
(min, max). If @tt min is @tt ASSH_BOP_NOREG, no lower bound is
|
||||
used. If @tt max is @tt ASSH_BOP_NOREG, the most significant bit
|
||||
of the destination will be set so that the bit size of the
|
||||
generated number is large. */
|
||||
#define ASSH_BOP_PRIME(dst, min, max) \
|
||||
ASSH_BOP_FMT3(ASSH_BIGNUM_OP_PRIME, dst, min, max)
|
||||
|
||||
/** @mgroup{Bytecode instructions}
|
||||
@internal This instruction changes the program counter if the
|
||||
number is a prime greater than 2. The bytecode execution is
|
||||
aborted with the @ref ASSH_ERR_NUM_OVERFLOW error if the number is
|
||||
not prime and the value of @tt pcdiff is 0. */
|
||||
#define ASSH_BOP_ISPRIM(src, pcdiff) \
|
||||
ASSH_BOP_FMT3(ASSH_BIGNUM_OP_ISPRIM, 1, pcdiff + 128, src)
|
||||
|
||||
/** @mgroup{Bytecode instructions}
|
||||
@internal This instruction is similar to @ref #ASSH_BOP_ISPRIM. */
|
||||
#define ASSH_BOP_ISNTPRIM(src, pcdiff) \
|
||||
ASSH_BOP_FMT3(ASSH_BIGNUM_OP_ISPRIM, 0, pcdiff + 128, src)
|
||||
|
||||
/** @mgroup{Bytecode instructions}
|
||||
@internal The secret flag is forwarded to results of operations
|
||||
on big numbers. This instruction can be used to change the secret
|
||||
flag of a value. */
|
||||
#define ASSH_BOP_PRIVACY(src, secret) \
|
||||
ASSH_BOP_FMT2(ASSH_BIGNUM_OP_PRIVACY, secret, src)
|
||||
|
||||
/** @mgroup{Bytecode instructions}
|
||||
@internal This instruction prints a big number argument for
|
||||
debugging purpose. The id argument is an ASCII integer constant. */
|
||||
#define ASSH_BOP_PRINT(src, id) \
|
||||
ASSH_BOP_FMT2(ASSH_BIGNUM_OP_PRINT, id, src)
|
||||
|
||||
/** @multiple @internal @This is a big number engine implementation
|
||||
descriptor. */
|
||||
#ifdef CONFIG_ASSH_USE_GCRYPT_BIGNUM
|
||||
extern const struct assh_bignum_algo_s assh_bignum_gcrypt;
|
||||
#endif
|
||||
|
||||
extern const struct assh_bignum_algo_s assh_bignum_builtin;
|
||||
|
||||
#endif
|
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
|
||||
libassh - asynchronous ssh2 client/server library.
|
||||
|
||||
Copyright (C) 2013 Alexandre Becoulet <alexandre.becoulet@free.fr>
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@file
|
||||
@short SSH cipher module interface
|
||||
*/
|
||||
|
||||
#ifndef ASSH_CIPHER_H_
|
||||
#define ASSH_CIPHER_H_
|
||||
|
||||
#include "assh_algo.h"
|
||||
|
||||
/** @internal @see assh_cipher_init_t */
|
||||
#define ASSH_CIPHER_INIT_FCN(n) \
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t (n)(struct assh_context_s *c, void *ctx_, \
|
||||
const uint8_t *key, const uint8_t *iv, \
|
||||
assh_bool_t encrypt)
|
||||
|
||||
/** @internal @This defines the function type for the cipher
|
||||
initialization operation of the cipher module interface. The @tt
|
||||
ctx_ argument must points to a buffer allocated in secure memory
|
||||
of size given by @ref assh_algo_cipher_s::ctx_size. */
|
||||
typedef ASSH_CIPHER_INIT_FCN(assh_cipher_init_t);
|
||||
|
||||
/** @internal @see assh_cipher_process_t */
|
||||
#define ASSH_CIPHER_PROCESS_FCN(n) \
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t (n)(void *ctx_, uint8_t *data, size_t len)
|
||||
|
||||
/** @internal @This defines the function type for the data processing
|
||||
operation of the cipher module interface. */
|
||||
typedef ASSH_CIPHER_PROCESS_FCN(assh_cipher_process_t);
|
||||
|
||||
/** @internal @see assh_cipher_cleanup_t */
|
||||
#define ASSH_CIPHER_CLEANUP_FCN(n) \
|
||||
void (n)(struct assh_context_s *c, void *ctx_)
|
||||
|
||||
/** @internal @This defines the function type for the context cleanup
|
||||
operation of the cipher module interface. */
|
||||
typedef ASSH_CIPHER_CLEANUP_FCN(assh_cipher_cleanup_t);
|
||||
|
||||
|
||||
/** @internalmembers @This is the cipher algorithm descriptor
|
||||
structure. It can be casted to the @ref assh_algo_s type. */
|
||||
struct assh_algo_cipher_s
|
||||
{
|
||||
struct assh_algo_s algo;
|
||||
/** Size of the context structure needed to initialize the algorithm. */
|
||||
size_t ctx_size;
|
||||
/** Cipher block size in bytes, not less than 8. */
|
||||
size_t block_size;
|
||||
/** Cipher key size in bytes. */
|
||||
size_t key_size;
|
||||
/** This indicates if the algorithm is a block cipher or a stream cipher */
|
||||
assh_bool_t is_stream;
|
||||
assh_bool_t clear_len;
|
||||
assh_cipher_init_t *f_init;
|
||||
assh_cipher_process_t *f_process;
|
||||
assh_cipher_cleanup_t *f_cleanup;
|
||||
};
|
||||
|
||||
ASSH_FIRST_FIELD_ASSERT(assh_algo_cipher_s, algo);
|
||||
|
||||
/** Dummy cipher algorithm. */
|
||||
extern const struct assh_algo_cipher_s assh_cipher_none;
|
||||
|
||||
/** @multiple @This is a cipher algorithm implementation descriptor. */
|
||||
extern const struct assh_algo_cipher_s assh_cipher_arc4;
|
||||
extern const struct assh_algo_cipher_s assh_cipher_arc4_128;
|
||||
extern const struct assh_algo_cipher_s assh_cipher_arc4_256;
|
||||
|
||||
extern const struct assh_algo_cipher_s assh_cipher_aes128_cbc;
|
||||
extern const struct assh_algo_cipher_s assh_cipher_aes192_cbc;
|
||||
extern const struct assh_algo_cipher_s assh_cipher_aes256_cbc;
|
||||
extern const struct assh_algo_cipher_s assh_cipher_aes128_ctr;
|
||||
extern const struct assh_algo_cipher_s assh_cipher_aes192_ctr;
|
||||
extern const struct assh_algo_cipher_s assh_cipher_aes256_ctr;
|
||||
|
||||
# ifdef CONFIG_ASSH_USE_GCRYPT_CIPHERS
|
||||
|
||||
/** @multiple @This is a cipher algorithm implementation descriptor. */
|
||||
extern const struct assh_algo_cipher_s assh_cipher_tdes_cbc;
|
||||
extern const struct assh_algo_cipher_s assh_cipher_tdes_ctr;
|
||||
|
||||
extern const struct assh_algo_cipher_s assh_cipher_cast128_cbc;
|
||||
extern const struct assh_algo_cipher_s assh_cipher_cast128_ctr;
|
||||
|
||||
extern const struct assh_algo_cipher_s assh_cipher_blowfish_cbc;
|
||||
extern const struct assh_algo_cipher_s assh_cipher_blowfish_ctr;
|
||||
|
||||
extern const struct assh_algo_cipher_s assh_cipher_twofish128_cbc;
|
||||
extern const struct assh_algo_cipher_s assh_cipher_twofish256_cbc;
|
||||
extern const struct assh_algo_cipher_s assh_cipher_twofish128_ctr;
|
||||
extern const struct assh_algo_cipher_s assh_cipher_twofish256_ctr;
|
||||
|
||||
extern const struct assh_algo_cipher_s assh_cipher_serpent128_cbc;
|
||||
extern const struct assh_algo_cipher_s assh_cipher_serpent192_cbc;
|
||||
extern const struct assh_algo_cipher_s assh_cipher_serpent256_cbc;
|
||||
extern const struct assh_algo_cipher_s assh_cipher_serpent128_ctr;
|
||||
extern const struct assh_algo_cipher_s assh_cipher_serpent192_ctr;
|
||||
extern const struct assh_algo_cipher_s assh_cipher_serpent256_ctr;
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
|
||||
libassh - asynchronous ssh2 client/server library.
|
||||
|
||||
Copyright (C) 2013 Alexandre Becoulet <alexandre.becoulet@free.fr>
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@file
|
||||
@short SSH compression module interface
|
||||
*/
|
||||
|
||||
#ifndef ASSH_COMPRESS_H_
|
||||
#define ASSH_COMPRESS_H_
|
||||
|
||||
#include "assh_algo.h"
|
||||
|
||||
/** @internal @see assh_compress_init_t */
|
||||
#define ASSH_COMPRESS_INIT_FCN(n) \
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t (n)(struct assh_context_s *c, \
|
||||
void *ctx_, assh_bool_t compress)
|
||||
|
||||
/** @internal @This defines the function type for the
|
||||
initialization operation of the compression module interface. */
|
||||
typedef ASSH_COMPRESS_INIT_FCN(assh_compress_init_t);
|
||||
|
||||
/** @internal @see assh_compress_process_t */
|
||||
#define ASSH_COMPRESS_PROCESS_FCN(n) \
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t (n)(void *ctx_, struct assh_packet_s *p)
|
||||
|
||||
/** @internal @This defines the function type for the data processing
|
||||
operation of the compression module interface. */
|
||||
typedef ASSH_COMPRESS_PROCESS_FCN(assh_compress_process_t);
|
||||
|
||||
/** @internal @see assh_compress_cleanup_t */
|
||||
#define ASSH_COMPRESS_CLEANUP_FCN(n) \
|
||||
void (n)(struct assh_context_s *c, void *ctx_)
|
||||
|
||||
/** @internal @This defines the function type for the hash context
|
||||
cleanup operation of the hash module interface. */
|
||||
typedef ASSH_COMPRESS_CLEANUP_FCN(assh_compress_cleanup_t);
|
||||
|
||||
/** @internalmembers @This is the compression algorithm descriptor
|
||||
structure. It can be casted to the @ref assh_algo_s type. */
|
||||
struct assh_algo_compress_s
|
||||
{
|
||||
struct assh_algo_s algo;
|
||||
/** Size of the context structure needed to initialize the algorithm. */
|
||||
size_t ctx_size;
|
||||
assh_compress_init_t *f_init;
|
||||
assh_compress_process_t *f_process;
|
||||
assh_compress_cleanup_t *f_cleanup;
|
||||
};
|
||||
|
||||
ASSH_FIRST_FIELD_ASSERT(assh_algo_compress_s, algo);
|
||||
|
||||
extern const struct assh_algo_compress_s assh_compress_none;
|
||||
extern const struct assh_algo_compress_s assh_compress_zlib;
|
||||
extern const struct assh_algo_compress_s assh_compress_zlib_openssh;
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,788 @@
|
|||
/*
|
||||
|
||||
libassh - asynchronous ssh2 client/server library.
|
||||
|
||||
Copyright (C) 2013 Alexandre Becoulet <alexandre.becoulet@free.fr>
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@file
|
||||
@short SSH connection service (rfc4254)
|
||||
|
||||
This header file defines events and functions which are used
|
||||
when the @tt ssh-connection service is running.
|
||||
|
||||
This standard service described in rfc4254 is implemented as a
|
||||
pluggable service module for libassh.
|
||||
*/
|
||||
|
||||
#ifndef ASSH_SRV_CONNECTION_H_
|
||||
#define ASSH_SRV_CONNECTION_H_
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#ifdef ASSH_EVENT_H_
|
||||
# warning The assh/assh_event.h header should be included after assh_connection.h
|
||||
#endif
|
||||
|
||||
#include "assh.h"
|
||||
#include "assh_map.h"
|
||||
#include "assh_queue.h"
|
||||
|
||||
/** @This specifies request status */
|
||||
enum assh_request_status_e
|
||||
{
|
||||
/** Outgoing request; not replied by remote host. */
|
||||
ASSH_REQUEST_ST_WAIT_REPLY,
|
||||
/** Incoming request; reply postponed by the library user. */
|
||||
ASSH_REQUEST_ST_REPLY_POSTPONED,
|
||||
/** Incoming request; blocked by previous requests in queue. */
|
||||
ASSH_REQUEST_ST_REPLY_READY,
|
||||
};
|
||||
|
||||
/** @internal
|
||||
@This is the @em ssh-connection service request object.
|
||||
|
||||
Requests are created either by calling the @ref assh_request
|
||||
function or when the @ref ASSH_EVENT_REQUEST event is reported.
|
||||
The library user does not have to destroy request objects.
|
||||
*/
|
||||
struct assh_request_s
|
||||
{
|
||||
struct assh_queue_entry_s qentry;
|
||||
|
||||
enum assh_request_status_e status;
|
||||
struct assh_session_s *session;
|
||||
struct assh_channel_s *ch;
|
||||
struct assh_packet_s *reply_pck;
|
||||
void *pv;
|
||||
};
|
||||
|
||||
ASSH_FIRST_FIELD_ASSERT(assh_request_s, qentry);
|
||||
|
||||
/** @This specifies channel status */
|
||||
enum assh_channel_status_e
|
||||
{
|
||||
/** An open message has been sent to the remote host */
|
||||
ASSH_CHANNEL_ST_OPEN_SENT,
|
||||
/** An open reply message has been received, action must be taken in
|
||||
order to acknowledge the channel open. */
|
||||
ASSH_CHANNEL_ST_OPEN_RECEIVED,
|
||||
/** The channel is open. */
|
||||
ASSH_CHANNEL_ST_OPEN,
|
||||
/** The channel is open half way. */
|
||||
ASSH_CHANNEL_ST_EOF_SENT,
|
||||
/** The channel is open half way. */
|
||||
ASSH_CHANNEL_ST_EOF_RECEIVED,
|
||||
/** A pair of channel EOF messages has been exchanged, a channel
|
||||
close message was sent. */
|
||||
ASSH_CHANNEL_ST_EOF_CLOSE,
|
||||
/** The @ref assh_channel_close function has been called and a close
|
||||
message was sent but the remote host has not replied yet. */
|
||||
ASSH_CHANNEL_ST_CLOSE_CALLED,
|
||||
/** A channel close message has been received and a reply was
|
||||
sent. Some request/data related events may still be reported
|
||||
before the channel object is released. */
|
||||
ASSH_CHANNEL_ST_CLOSING,
|
||||
/** The @ref assh_channel_close function was called at some point
|
||||
and the channel is closing as in @ref ASSH_CHANNEL_ST_CLOSING state. */
|
||||
ASSH_CHANNEL_ST_CLOSE_CALLED_CLOSING,
|
||||
};
|
||||
|
||||
/** @internal
|
||||
@This is the @em ssh-connection service channel object.
|
||||
|
||||
Channels are created either by calling the @ref assh_channel_open
|
||||
function or when the @ref ASSH_EVENT_CHANNEL_OPEN event is reported.
|
||||
The library user does not have to destroy channel objects.
|
||||
*/
|
||||
struct assh_channel_s
|
||||
{
|
||||
union {
|
||||
/** channel queue entry, valid when the channel is waiting for close. */
|
||||
struct assh_queue_entry_s qentry;
|
||||
/** channel map entry, valid when the channel is open. */
|
||||
struct assh_map_entry_s mentry;
|
||||
};
|
||||
|
||||
enum assh_channel_status_e status;
|
||||
struct assh_session_s *session;
|
||||
struct assh_packet_s *data_pck;
|
||||
void *pv;
|
||||
|
||||
struct assh_queue_s request_rqueue; //< requests we have to acknowledge
|
||||
struct assh_queue_s request_lqueue; //< requests waiting for a reply from the remote host
|
||||
|
||||
uint32_t remote_id;
|
||||
uint32_t rpkt_size; //< remote packet size
|
||||
uint32_t lpkt_size; //< local packet size
|
||||
uint32_t lwin_size; //< local window size
|
||||
|
||||
uint32_t rwin_left; //< remote window bytes left
|
||||
uint32_t lwin_left; //< local window bytes left
|
||||
};
|
||||
|
||||
ASSH_FIRST_FIELD_ASSERT(assh_channel_s, qentry);
|
||||
ASSH_FIRST_FIELD_ASSERT(assh_channel_s, mentry);
|
||||
|
||||
/** @This specifies standard values for channel open failure reason
|
||||
code as defined in rfc4254 section 5.1 */
|
||||
enum assh_channel_open_reason_e
|
||||
{
|
||||
SSH_OPEN_SUCCESS = 0,
|
||||
SSH_OPEN_ADMINISTRATIVELY_PROHIBITED = 1,
|
||||
SSH_OPEN_CONNECT_FAILED = 2,
|
||||
SSH_OPEN_UNKNOWN_CHANNEL_TYPE = 3,
|
||||
SSH_OPEN_RESOURCE_SHORTAGE = 4,
|
||||
};
|
||||
|
||||
/** @This specifies reply codes used by request and channel events */
|
||||
enum assh_connection_reply_e
|
||||
{
|
||||
/** Failure report by/to remote host. */
|
||||
ASSH_CONNECTION_REPLY_FAILED,
|
||||
/** Success report by/to remote host. */
|
||||
ASSH_CONNECTION_REPLY_SUCCESS,
|
||||
/** Reply will be send later */
|
||||
ASSH_CONNECTION_REPLY_POSTPONED,
|
||||
/** The remote host has closed the channel/connection */
|
||||
ASSH_CONNECTION_REPLY_CLOSED,
|
||||
};
|
||||
|
||||
#define ASSH_SRV_CN_DEFAULT_PKTSIZE (ASSH_MAX_PCK_PAYLOAD_SIZE - 8)
|
||||
#define ASSH_SRV_CN_DEFAULT_WINDOW (ASSH_SRV_CN_DEFAULT_PKTSIZE * 3)
|
||||
|
||||
/** This function sets the value of the channel private pointer. */
|
||||
ASSH_INLINE void
|
||||
assh_channel_set_pv(struct assh_channel_s *ch, void *pv)
|
||||
{
|
||||
ch->pv = pv;
|
||||
}
|
||||
|
||||
/** This function returns the value of the channel private pointer. */
|
||||
ASSH_INLINE void *
|
||||
assh_channel_pv(const struct assh_channel_s *ch)
|
||||
{
|
||||
return ch->pv;
|
||||
}
|
||||
|
||||
/** This returns the current channel status */
|
||||
ASSH_INLINE enum assh_channel_status_e
|
||||
assh_channel_status(const struct assh_channel_s *ch)
|
||||
{
|
||||
return ch->status;
|
||||
}
|
||||
|
||||
/** This set the maximum size of the local window. The next window
|
||||
adjust packet will increase the window size to match the given value. */
|
||||
ASSH_INLINE void assh_channel_set_win_size(struct assh_channel_s *ch,
|
||||
uint32_t win_size)
|
||||
{
|
||||
ch->lwin_size = ASSH_MAX(win_size, ch->lpkt_size * 2);
|
||||
}
|
||||
|
||||
/** This returns the number of bytes left in current windows for a channel */
|
||||
ASSH_INLINE void assh_channel_get_win_size(const struct assh_channel_s *ch,
|
||||
uint32_t *local, uint32_t *remote)
|
||||
{
|
||||
if (local != NULL)
|
||||
*local = ch->lwin_left;
|
||||
if (remote != NULL)
|
||||
*remote = ch->rwin_left;
|
||||
}
|
||||
|
||||
/** This returns the maximum packet size for a channel */
|
||||
ASSH_INLINE void assh_channel_get_pkt_size(const struct assh_channel_s *ch,
|
||||
uint32_t *local, uint32_t *remote)
|
||||
{
|
||||
if (local != NULL)
|
||||
*local = ch->lpkt_size;
|
||||
if (remote != NULL)
|
||||
*remote = ch->rpkt_size;
|
||||
}
|
||||
|
||||
/** This function sets the value of the request private pointer. */
|
||||
ASSH_INLINE void
|
||||
assh_request_set_pv(struct assh_request_s *rq, void *pv)
|
||||
{
|
||||
rq->pv = pv;
|
||||
}
|
||||
|
||||
/** This function returns the value of the request private pointer. */
|
||||
ASSH_INLINE void *
|
||||
assh_request_pv(const struct assh_request_s *rq)
|
||||
{
|
||||
return rq->pv;
|
||||
}
|
||||
|
||||
/** This returns the current channel status */
|
||||
ASSH_INLINE enum assh_request_status_e
|
||||
assh_request_status(struct assh_request_s *rq)
|
||||
{
|
||||
return rq->status;
|
||||
}
|
||||
|
||||
/************************************************* service start */
|
||||
|
||||
/**
|
||||
This event is reported when the @tt ssh-connection service has
|
||||
just started. The channel related and request related functions
|
||||
can be used from this point.
|
||||
|
||||
@see ASSH_EVENT_CONNECTION_START
|
||||
*/
|
||||
struct assh_event_connection_start_s
|
||||
{
|
||||
};
|
||||
|
||||
/************************************************* incoming request */
|
||||
|
||||
/**
|
||||
This event is reported when the @tt ssh-connection service is
|
||||
running and a @ref SSH_MSG_GLOBAL_REQUEST message or a @ref
|
||||
SSH_MSG_CHANNEL_REQUEST message has been received. The request type
|
||||
name and associated specific request data are available in the @ref
|
||||
type and @ref rq_data fields. These buffers will not remain valid
|
||||
after the call to @ref assh_event_done.
|
||||
|
||||
The @ref ch field is @tt NULL for global requests.
|
||||
|
||||
If the @ref rq pointer field is not @tt NULL, the remote host
|
||||
excepts a reply for this request. In this case, the @ref reply
|
||||
field can be set to @ref ASSH_CONNECTION_REPLY_SUCCESS in order to
|
||||
successfully acknowledge the request and some response data may
|
||||
optionally be passed in the @ref rsp_data field. The default value
|
||||
of the @ref reply field is @ref ASSH_CONNECTION_REPLY_FAILED. In
|
||||
both cases, the @ref assh_request_s object will be release when
|
||||
calling the @ref assh_event_done function.
|
||||
|
||||
If it's not possible to acknowledge the request when calling the
|
||||
@ref assh_event_done function, the @ref
|
||||
ASSH_CONNECTION_REPLY_POSTPONED value must be used instead. In this
|
||||
case, either the @ref assh_request_success_reply function or the
|
||||
@ref assh_request_failed_reply function must be called later in
|
||||
order to release the @ref assh_request_s object and send the reply
|
||||
expected by the remote host. Care should be taken not to postpone
|
||||
too many requests in order to avoid resource-exhaustion attacks.
|
||||
|
||||
If some incoming requests are left unreplied when the @ref
|
||||
ASSH_EVENT_CHANNEL_CLOSE event is reported, all postponed request
|
||||
objects associated with the channel are released along with the
|
||||
channel.
|
||||
|
||||
@see ASSH_EVENT_REQUEST
|
||||
*/
|
||||
struct assh_event_request_s
|
||||
{
|
||||
struct assh_channel_s * ASSH_EV_CONST ch; //< input
|
||||
struct assh_request_s * ASSH_EV_CONST rq; //< input
|
||||
ASSH_EV_CONST struct assh_buffer_s type; //< input
|
||||
ASSH_EV_CONST struct assh_buffer_s rq_data; //< input
|
||||
enum assh_connection_reply_e reply; //< output
|
||||
struct assh_buffer_s rsp_data; //< output
|
||||
};
|
||||
|
||||
/**
|
||||
This function acknowledge and release a previously received global
|
||||
or channel request which has not been replied yet due to the use of
|
||||
the @ref ASSH_CONNECTION_REPLY_POSTPONED value in the @tt reply
|
||||
field of the associated event.
|
||||
|
||||
Some response data may optionally be included in the response by
|
||||
using the @tt rsp_data and @tt rsp_data_len parameters.
|
||||
|
||||
If multiple requests on the same queue (global or per channel) are
|
||||
waiting for a reply, the replies will be sent in the received
|
||||
order. This function can be called in any order but a non replied
|
||||
request may further postpone replies to subsequent requests.
|
||||
|
||||
If this function is called on a closing channel which has not yet
|
||||
been reported by the appropriate event, this function returns @ref
|
||||
ASSH_NO_DATA to indicate that it was not able to send the reply.
|
||||
|
||||
This function will fail if either the @tt ssh-connection service is
|
||||
not started or the last event has not been acknowledged by calling
|
||||
the @ref assh_event_done function.
|
||||
|
||||
@see assh_request_failed_reply
|
||||
*/
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_request_success_reply(struct assh_request_s *rq,
|
||||
const uint8_t *rsp_data,
|
||||
size_t rsp_data_len);
|
||||
|
||||
/**
|
||||
@This has the same behavior as @ref assh_request_success_reply but
|
||||
reports a request failure to the remote host.
|
||||
*/
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_request_failed_reply(struct assh_request_s *rq);
|
||||
|
||||
/************************************************* outgoing request */
|
||||
|
||||
/**
|
||||
This event is reported for every successful call to the @ref
|
||||
assh_request function with the @tt want_reply parameter set.
|
||||
|
||||
The @ref reply field indicates if the request has been successfully
|
||||
acknowledged by the remote host. In this case, some response
|
||||
specific data may be available in the @ref rsp_data field. This
|
||||
field may also indicate that the request has failed or that the
|
||||
connection or channel associated with the request has been closed.
|
||||
|
||||
The @ref ch field is @tt NULL for global requests.
|
||||
|
||||
The request object is released when the @ref assh_event_done
|
||||
function is called.
|
||||
|
||||
@see ASSH_EVENT_REQUEST_REPLY
|
||||
*/
|
||||
struct assh_event_request_reply_s
|
||||
{
|
||||
struct assh_channel_s * ASSH_EV_CONST ch; //< input
|
||||
struct assh_request_s * ASSH_EV_CONST rq; //< input
|
||||
ASSH_EV_CONST enum assh_connection_reply_e reply; //< input
|
||||
ASSH_EV_CONST struct assh_buffer_s rsp_data; //< input
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
This function sends either a @ref SSH_MSG_GLOBAL_REQUEST message
|
||||
or a @ref SSH_MSG_CHANNEL_REQUEST message to the remote host.
|
||||
If the @tt ch parameter is @tt NULL, a global request is sent.
|
||||
|
||||
If this function is called after the remote host disconnected or
|
||||
sent a channel close message which has not yet been reported by the
|
||||
appropriate event, this function returns @ref ASSH_NO_DATA to
|
||||
indicate that it was not able to send the request due to the channel
|
||||
closing.
|
||||
|
||||
If the @tt rq parameter is not @tt NULL, a reply from the remote
|
||||
host is expected. If we want a reply and the function returns
|
||||
@ref ASSH_OK, a new @ref assh_request_s object is allocated and an
|
||||
@ref ASSH_EVENT_REQUEST_REPLY event will later indicate if this
|
||||
request is successful.
|
||||
|
||||
Even if a channel close or disconnection occurs, the expected event
|
||||
will be reported at some point by the @ref assh_event_get function.
|
||||
|
||||
This function will fail if either the @tt ssh-connection service is
|
||||
not started or the last event has not been acknowledged by calling
|
||||
the @ref assh_event_done function.
|
||||
*/
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_request(struct assh_session_s *s,
|
||||
struct assh_channel_s *ch,
|
||||
const char *type, size_t type_len,
|
||||
const uint8_t *data, size_t data_len,
|
||||
struct assh_request_s **rq);
|
||||
|
||||
/************************************************* incoming channel open */
|
||||
|
||||
/**
|
||||
This event is reported when the @tt ssh-connection service is
|
||||
running and a @ref SSH_MSG_CHANNEL_OPEN message is received from
|
||||
the remote host. The channel type name and specific data are
|
||||
available in the @ref type and @ref rq_data fields. These buffers
|
||||
will not remain valid after the call to @ref assh_event_done.
|
||||
|
||||
The @ref pkt_size and the @ref win_size fields initially contain
|
||||
the maximum packet size accepted by the remote host for this
|
||||
channel and the initial window data size. The values can be
|
||||
modified if they need to be different for the other channel
|
||||
direction. The maximum packet size value will be reduced if larger
|
||||
than what the libassh transport layer can handle.
|
||||
|
||||
The @ref reply field can be set to @ref
|
||||
ASSH_CONNECTION_REPLY_SUCCESS in order to successfully acknowledge
|
||||
the channel open. In this case, some response data may optionally
|
||||
be passed in the @ref rsp_data field.
|
||||
|
||||
The default value of the @ref reply field is @ref
|
||||
ASSH_CONNECTION_REPLY_FAILED. If an open failure is sent, the @ref
|
||||
assh_channel_s object will be release when calling the @ref
|
||||
assh_event_done function.
|
||||
|
||||
If it's not possible to reply to the channel open when calling the
|
||||
@ref assh_event_done function, the @ref
|
||||
ASSH_CONNECTION_REPLY_POSTPONED value must be used instead. In this
|
||||
case, either the @ref assh_channel_open_success_reply or the @ref
|
||||
assh_channel_open_failed_reply function must be called later to
|
||||
send the reply expected by the remote host. Care should be taken
|
||||
not to postpone or accept too many channel open requests in order
|
||||
to avoid resource-exhaustion attacks.
|
||||
|
||||
@see ASSH_EVENT_CHANNEL_OPEN
|
||||
*/
|
||||
struct assh_event_channel_open_s
|
||||
{
|
||||
struct assh_channel_s * ASSH_EV_CONST ch; //< input
|
||||
ASSH_EV_CONST struct assh_buffer_s type; //< input
|
||||
ASSH_EV_CONST struct assh_buffer_s rq_data; //< input
|
||||
enum assh_connection_reply_e reply; //< output
|
||||
enum assh_channel_open_reason_e reason; //< output
|
||||
uint32_t win_size; //< input/output
|
||||
uint32_t pkt_size; //< input/output
|
||||
struct assh_buffer_s rsp_data; //< output
|
||||
};
|
||||
|
||||
/**
|
||||
This function is similar to @ref assh_channel_open_success_reply
|
||||
but allows to specify the maximum packet size and the initial
|
||||
window size for the output direction of the channel.
|
||||
|
||||
@see assh_channel_open_success_reply
|
||||
*/
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_channel_open_success_reply2(struct assh_channel_s *ch,
|
||||
uint32_t pkt_size, uint32_t win_size,
|
||||
const uint8_t *rsp_data,
|
||||
size_t rsp_data_len);
|
||||
|
||||
/**
|
||||
This function acknowledge a channel open message which has not been
|
||||
replied yet due to the use of the @ref ASSH_CONNECTION_REPLY_POSTPONED
|
||||
value in the @tt reply field of the @ref ASSH_EVENT_CHANNEL_OPEN event.
|
||||
|
||||
Some response data may optionally be included in the response by
|
||||
using the @tt rsp_data and @tt rsp_data_len parameters.
|
||||
|
||||
Channel open replies can be send in any order.
|
||||
|
||||
This function will fail if either the @tt ssh-connection service is
|
||||
not started or the last event has not been acknowledged by calling
|
||||
the @ref assh_event_done function.
|
||||
|
||||
@see assh_channel_open_failed_reply
|
||||
*/
|
||||
ASSH_INLINE ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_channel_open_success_reply(struct assh_channel_s *ch,
|
||||
const uint8_t *rsp_data,
|
||||
size_t rsp_data_len)
|
||||
{
|
||||
return assh_channel_open_success_reply2(ch, ch->lpkt_size, ch->lwin_size,
|
||||
rsp_data, rsp_data_len);
|
||||
}
|
||||
|
||||
/**
|
||||
This function acknowledge a channel open message which has not been
|
||||
replied yet due to the use of the @ref ASSH_CONNECTION_REPLY_POSTPONED
|
||||
value in the @tt reply field of the @ref ASSH_EVENT_CHANNEL_OPEN event.
|
||||
|
||||
Channel open replies can be send in any order.
|
||||
|
||||
This function will fail if either the @tt ssh-connection service is
|
||||
not started or the last event has not been acknowledged by calling
|
||||
the @ref assh_event_done function.
|
||||
|
||||
@see assh_channel_open_success_reply
|
||||
*/
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_channel_open_failed_reply(struct assh_channel_s *ch,
|
||||
enum assh_channel_open_reason_e reason);
|
||||
|
||||
/************************************************* outgoing channel open */
|
||||
|
||||
/**
|
||||
This event is reported for every successful call to the @ref
|
||||
assh_channel_open function. The @ref reply field indicates if
|
||||
the channel open has been confirmed by the remote side.
|
||||
|
||||
If the open is successful, some response specific data may be
|
||||
available in the @ref rsp_data field.
|
||||
|
||||
If the open has failed, the associated @ref assh_channel_s object
|
||||
will be released when the @ref assh_event_done function is called.
|
||||
|
||||
@see ASSH_EVENT_CHANNEL_OPEN_REPLY
|
||||
*/
|
||||
struct assh_event_channel_open_reply_s
|
||||
{
|
||||
struct assh_channel_s * ASSH_EV_CONST ch; //< input
|
||||
ASSH_EV_CONST enum assh_connection_reply_e reply; //< input
|
||||
ASSH_EV_CONST enum assh_channel_open_reason_e reason; //< input
|
||||
ASSH_EV_CONST struct assh_buffer_s rsp_data; //< input
|
||||
};
|
||||
|
||||
/**
|
||||
This function is similar to @ref assh_channel_open but allows to
|
||||
specify the maximum packet size and the initial window size for the
|
||||
output direction of the channel.
|
||||
|
||||
@see assh_channel_open
|
||||
*/
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_channel_open2(struct assh_session_s *s,
|
||||
const char *type, size_t type_len,
|
||||
const uint8_t *data, size_t data_len,
|
||||
uint32_t pkt_size, uint32_t win_size,
|
||||
struct assh_channel_s **ch);
|
||||
|
||||
/**
|
||||
This function allocates an @ref assh_channel_s object and send a
|
||||
@ref SSH_MSG_CHANNEL_OPEN message to the remote host. If the
|
||||
function returns @ref ASSH_OK, an @ref ASSH_EVENT_CHANNEL_OPEN
|
||||
event will later indicate if the remote host has accepted the
|
||||
channel open request.
|
||||
|
||||
The @tt data and @tt data_len parameters allow sending some channel
|
||||
type specific data may along with the channel open message.
|
||||
|
||||
Even if a disconnection occurs, the expected event will be reported
|
||||
at some point by the @ref assh_event_get function.
|
||||
|
||||
This function will fail if either the @tt ssh-connection service is
|
||||
not started or the last event has not been acknowledged by calling
|
||||
the @ref assh_event_done function.
|
||||
*/
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
ASSH_INLINE assh_channel_open(struct assh_session_s *s,
|
||||
const char *type, size_t type_len,
|
||||
const uint8_t *data, size_t data_len,
|
||||
struct assh_channel_s **ch)
|
||||
{
|
||||
return assh_channel_open2(s, type, type_len, data, data_len,
|
||||
ASSH_SRV_CN_DEFAULT_PKTSIZE,
|
||||
ASSH_SRV_CN_DEFAULT_WINDOW,
|
||||
ch);
|
||||
}
|
||||
|
||||
/************************************************* incoming channel data */
|
||||
|
||||
/**
|
||||
This event is reported when the @tt ssh-connection service is
|
||||
running and some incoming channel data are available. The data
|
||||
buffers will not remain valid after the call to @ref
|
||||
assh_event_done.
|
||||
|
||||
@see ASSH_EVENT_CHANNEL_DATA
|
||||
*/
|
||||
struct assh_event_channel_data_s
|
||||
{
|
||||
struct assh_channel_s * ASSH_EV_CONST ch; //< input
|
||||
ASSH_EV_CONST assh_bool_t ext; //< input
|
||||
ASSH_EV_CONST uint32_t ext_type; //< input
|
||||
ASSH_EV_CONST struct assh_buffer_s data; //< input
|
||||
};
|
||||
|
||||
/**
|
||||
This event is reported when the @tt ssh-connection service is
|
||||
running and a channel window message has been received.
|
||||
|
||||
This event indicates that more data can be sent.
|
||||
|
||||
@see ASSH_EVENT_CHANNEL_WINDOW
|
||||
*/
|
||||
struct assh_event_channel_window_s
|
||||
{
|
||||
struct assh_channel_s * ASSH_EV_CONST ch; //< input
|
||||
ASSH_EV_CONST uint32_t old_size; //< input
|
||||
ASSH_EV_CONST uint32_t new_size; //< input
|
||||
};
|
||||
|
||||
/************************************************* outgoing channel data */
|
||||
|
||||
/**
|
||||
This function internally pre-allocates a data packet suitable to
|
||||
transmit at least @tt min_size bytes and up to @tt *size bytes
|
||||
through an open channel.
|
||||
|
||||
If the function is successful, the @tt size parameter is updated
|
||||
with the actual size of the available data buffer and the @tt data
|
||||
parameter is updated with the address of the buffer. The data will
|
||||
be sent when calling the @ref assh_channel_data_send function.
|
||||
|
||||
The value @ref ASSH_NO_DATA is returned if @tt min_size is either
|
||||
larger than the maximum packet size for the channel or larger than
|
||||
the channel current window. In this case no packet is allocated but
|
||||
the @tt size parameter is still updated with the current largest
|
||||
possible size. The largest possible size is 0 either if there is no
|
||||
window space left or if the channel is closing.
|
||||
|
||||
It's ok to call this function more than once without actually
|
||||
sending the packet.
|
||||
|
||||
This function will fail if the @tt ssh-connection service is not
|
||||
started. It is @em ok to call this function between calls to the
|
||||
@ref assh_event_get and @ref assh_event_done functions.
|
||||
*/
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_channel_data_alloc(struct assh_channel_s *ch,
|
||||
uint8_t **data, size_t *size,
|
||||
size_t min_size);
|
||||
|
||||
/**
|
||||
This function is similar to @ref assh_channel_data_alloc. It
|
||||
prepares a @ref SSH_MSG_CHANNEL_EXTENDED_DATA message instead of a
|
||||
@ref SSH_MSG_CHANNEL_DATA message
|
||||
|
||||
@see assh_channel_data_alloc
|
||||
*/
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_channel_data_alloc_ext(struct assh_channel_s *ch,
|
||||
uint32_t ext_type,
|
||||
uint8_t **data, size_t *size,
|
||||
size_t min_size);
|
||||
|
||||
/**
|
||||
This function sends the data packet previously allocated by the
|
||||
@ref assh_channel_data_alloc function. The @tt size parameter must
|
||||
not be greater than what has been pre-allocated.
|
||||
|
||||
If this function is called on a closing channel, @ref ASSH_NO_DATA
|
||||
is returned to indicate that it was not able to send data.
|
||||
|
||||
This function will fail if either the @tt ssh-connection service is
|
||||
not started or the last event has not been acknowledged by calling
|
||||
the @ref assh_event_done function.
|
||||
*/
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_channel_data_send(struct assh_channel_s *ch, size_t size);
|
||||
|
||||
/**
|
||||
This function transmits data to the remote host through an open
|
||||
channel. It's a convenience function which calls @ref
|
||||
assh_channel_data_alloc then @tt memcpy and finally @ref
|
||||
assh_channel_data_send.
|
||||
|
||||
This @tt size parameter is updated with the actually transmitted
|
||||
size.
|
||||
|
||||
This function will fail if either the @tt ssh-connection service is
|
||||
not started or the last event has not been acknowledged by calling
|
||||
the @ref assh_event_done function.
|
||||
*/
|
||||
ASSH_INLINE ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_channel_data(struct assh_channel_s *ch,
|
||||
const uint8_t *data, size_t *size)
|
||||
{
|
||||
uint8_t *d;
|
||||
assh_error_t err;
|
||||
if ((err = assh_channel_data_alloc(ch, &d, size, 1)))
|
||||
return err;
|
||||
memcpy(d, data, *size);
|
||||
return assh_channel_data_send(ch, *size);
|
||||
}
|
||||
|
||||
/**
|
||||
This function is similar to @ref assh_channel_data. It
|
||||
sends a @ref SSH_MSG_CHANNEL_EXTENDED_DATA message instead of a
|
||||
@ref SSH_MSG_CHANNEL_DATA message
|
||||
|
||||
@see assh_channel_data
|
||||
*/
|
||||
ASSH_INLINE ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_channel_data_ext(struct assh_channel_s *ch, uint32_t ext_type,
|
||||
const uint8_t *data, size_t *size)
|
||||
{
|
||||
uint8_t *d;
|
||||
assh_error_t err;
|
||||
if ((err = assh_channel_data_alloc_ext(ch, ext_type, &d, size, 1)))
|
||||
return err;
|
||||
memcpy(d, data, *size);
|
||||
return assh_channel_data_send(ch, *size);
|
||||
}
|
||||
|
||||
/************************************************* incoming channel close/eof */
|
||||
|
||||
/**
|
||||
This event is reported when the @tt ssh-connection service is
|
||||
running and the remote host has sent the @ref
|
||||
SSH_MSG_CHANNEL_EOF message.
|
||||
|
||||
If the channel has already been half-closed in the other direction
|
||||
when receiving this messages, an @ref SSH_MSG_CHANNEL_CLOSE
|
||||
message is sent and the channel state changes to @ref ASSH_CHANNEL_ST_CLOSING.
|
||||
|
||||
@see ASSH_EVENT_CHANNEL_EOF
|
||||
*/
|
||||
struct assh_event_channel_eof_s
|
||||
{
|
||||
struct assh_channel_s * ASSH_EV_CONST ch; //< input
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
This event is reported for open channels when the channel is in
|
||||
@ref ASSH_CHANNEL_ST_CLOSING state and all data and requests
|
||||
associated with the channel have been reported using appropriate
|
||||
events.
|
||||
|
||||
@see ASSH_EVENT_CHANNEL_CLOSE
|
||||
*/
|
||||
struct assh_event_channel_close_s
|
||||
{
|
||||
struct assh_channel_s * ASSH_EV_CONST ch; //< input
|
||||
};
|
||||
|
||||
/************************************************* outgoing channel close/eof */
|
||||
|
||||
/**
|
||||
This function sends a @ref SSH_MSG_CHANNEL_EOF message and marks
|
||||
the channel as half-closed. The @ref assh_channel_data function
|
||||
can not be called successfully on the channel once this
|
||||
function has been called.
|
||||
|
||||
If the channel is already half-closed in the other direction, this
|
||||
function acts as the @ref assh_channel_close function.
|
||||
|
||||
This function will fail if either the @tt ssh-connection service is
|
||||
not started or the last event has not been acknowledged by calling
|
||||
the @ref assh_event_done function.
|
||||
*/
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_channel_eof(struct assh_channel_s *ch);
|
||||
|
||||
/**
|
||||
This function sends a @ref SSH_MSG_CHANNEL_CLOSE message to the
|
||||
remote host. The channel state will change to @ref
|
||||
ASSH_CHANNEL_ST_CLOSING when the channel close reply is received.
|
||||
|
||||
The channel is not released until the @ref ASSH_EVENT_CHANNEL_CLOSE
|
||||
event is reported. In the mean time, some request and data related
|
||||
events can still be reported for the channel.
|
||||
|
||||
This function will fail if either the @tt ssh-connection service is
|
||||
not started or the last event has not been acknowledged by calling
|
||||
the @ref assh_event_done function.
|
||||
*/
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_channel_close(struct assh_channel_s *ch);
|
||||
|
||||
/**************************************************/
|
||||
|
||||
/** @This contains all @tt ssh-connection service related events */
|
||||
union assh_event_connection_u
|
||||
{
|
||||
struct assh_event_connection_start_s start;
|
||||
struct assh_event_request_s request;
|
||||
struct assh_event_request_reply_s request_reply;
|
||||
struct assh_event_channel_open_s channel_open;
|
||||
struct assh_event_channel_open_reply_s channel_open_reply;
|
||||
struct assh_event_channel_data_s channel_data;
|
||||
struct assh_event_channel_window_s channel_window;
|
||||
struct assh_event_channel_eof_s channel_eof;
|
||||
struct assh_event_channel_close_s channel_close;
|
||||
};
|
||||
|
||||
/** @This is the @tt ssh-connection service module descriptor. */
|
||||
extern const struct assh_service_s assh_service_connection;
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,171 @@
|
|||
/*
|
||||
|
||||
libassh - asynchronous ssh2 client/server library.
|
||||
|
||||
Copyright (C) 2013 Alexandre Becoulet <alexandre.becoulet@free.fr>
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@file
|
||||
@short Main context structure and related functions
|
||||
|
||||
The library main context structure hold stuff common to multiple
|
||||
sessions. This includes registered algorithms and host keys.
|
||||
*/
|
||||
|
||||
#ifndef ASSH_CONTEXT_H_
|
||||
#define ASSH_CONTEXT_H_
|
||||
|
||||
#include "assh.h"
|
||||
|
||||
/** This specifies the type of ssh session. */
|
||||
enum assh_context_type_e
|
||||
{
|
||||
ASSH_SERVER,
|
||||
ASSH_CLIENT,
|
||||
ASSH_CLIENT_SERVER,
|
||||
};
|
||||
|
||||
/** @internal @This is the packet pool allocator bucket
|
||||
structure. Freed packets are inserted in the linked list of the
|
||||
bucket associated with their size. */
|
||||
struct assh_packet_pool_s
|
||||
{
|
||||
struct assh_packet_s *pck;
|
||||
size_t count;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
/** @internalmembers @This is the library main context structure. */
|
||||
struct assh_context_s
|
||||
{
|
||||
/** User private data */
|
||||
void *user_pv;
|
||||
|
||||
/** Number of initialized sessions attached to this context. */
|
||||
unsigned int session_count;
|
||||
|
||||
/** Client/server context type. */
|
||||
enum assh_context_type_e type;
|
||||
|
||||
/** Memory allocator function */
|
||||
assh_allocator_t *f_alloc;
|
||||
/** Memory allocator private data */
|
||||
void *alloc_pv;
|
||||
|
||||
/** Pseudo random number generator */
|
||||
const struct assh_prng_s *prng;
|
||||
/** Pseudo random number generator private data, allocated by the
|
||||
@ref assh_prng_init_t function and freed by @ref
|
||||
assh_prng_cleanup_t. */
|
||||
void *prng_pv;
|
||||
/** Current amount of entropy in the prng pool. a negative value
|
||||
will make the @ref assh_event_get function return an @ref
|
||||
ASSH_EVENT_PRNG_FEED event. */
|
||||
int prng_entropy;
|
||||
|
||||
/** Head of loaded keys list */
|
||||
const struct assh_key_s *keys;
|
||||
|
||||
/** Estimated size of the kex init packet, computed when new
|
||||
algorithm are registered. */
|
||||
size_t kex_init_size;
|
||||
|
||||
/** Packet pool maximum allocated size in a single bucket. */
|
||||
size_t pck_pool_max_bsize;
|
||||
/** Packet pool maximum allocated size. */
|
||||
size_t pck_pool_max_size;
|
||||
/** Packet pool current allocated size. */
|
||||
size_t pck_pool_size;
|
||||
|
||||
/** Packet pool buckets of spare packets by size. */
|
||||
struct assh_packet_pool_s pool[ASSH_PCK_POOL_SIZE];
|
||||
|
||||
/** Registered algorithms */
|
||||
const struct assh_algo_s *algos[ASSH_MAX_ALGORITHMS];
|
||||
/** Number of registered algorithms */
|
||||
size_t algos_count;
|
||||
|
||||
/** Registered services. */
|
||||
const struct assh_service_s *srvs[ASSH_MAX_SERVICES];
|
||||
/** Number of registered services */
|
||||
size_t srvs_count;
|
||||
|
||||
/** Big number engine */
|
||||
const struct assh_bignum_algo_s *bignum;
|
||||
};
|
||||
|
||||
/** @This allocates and initializes a context. The @tt alloc parameter
|
||||
may be @tt NULL. @see assh_context_init */
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_context_create(struct assh_context_s **ctx,
|
||||
enum assh_context_type_e type,
|
||||
assh_allocator_t *alloc, void *alloc_pv);
|
||||
|
||||
/** @This initializes a context for use as a client or server. This
|
||||
can be used to initialize a statically allocated context
|
||||
object. The @tt alloc parameter may be @tt NULL.
|
||||
|
||||
When a stable ABI is needed, use the @ref assh_context_create
|
||||
function instead. */
|
||||
void assh_context_init(struct assh_context_s *ctx,
|
||||
enum assh_context_type_e type,
|
||||
assh_allocator_t *alloc,
|
||||
void *alloc_pv);
|
||||
|
||||
/** @This releases resources associated with a context. All existing
|
||||
@ref assh_session_s objects must have been released when calling
|
||||
this function. @see assh_context_init */
|
||||
void assh_context_cleanup(struct assh_context_s *ctx);
|
||||
|
||||
/** @This cleanups and releases a context created by the @ref
|
||||
assh_context_create function. All existing @ref assh_session_s
|
||||
objects must have been released when calling this function. @see
|
||||
assh_context_create */
|
||||
void assh_context_release(struct assh_context_s *ctx);
|
||||
|
||||
/** @This set the user private pointer of the context. */
|
||||
ASSH_INLINE void
|
||||
assh_context_set_pv(struct assh_context_s *ctx,
|
||||
void *private)
|
||||
{
|
||||
ctx->user_pv = private;
|
||||
}
|
||||
|
||||
/** @This get the user private pointer of the context. */
|
||||
ASSH_INLINE void *
|
||||
assh_context_get_pv(struct assh_context_s *ctx)
|
||||
{
|
||||
return ctx->user_pv;
|
||||
}
|
||||
|
||||
/** @This setups the pseudo-random number generator for use with
|
||||
this context. If an other prng has already been setup, it will be
|
||||
released.
|
||||
|
||||
If this function is called with @tt NULL as @tt prng parameter and
|
||||
no prng has already been registered, a default prng is setup.
|
||||
This is performed automatically when calling the @ref
|
||||
assh_session_init function. */
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_context_prng(struct assh_context_s *s,
|
||||
const struct assh_prng_s *prng);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,233 @@
|
|||
/*
|
||||
|
||||
libassh - asynchronous ssh2 client/server library.
|
||||
|
||||
Copyright (C) 2013 Alexandre Becoulet <alexandre.becoulet@free.fr>
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@file
|
||||
@short Event reporting structure and related functions
|
||||
*/
|
||||
|
||||
#ifndef ASSH_EVENT_H_
|
||||
#define ASSH_EVENT_H_
|
||||
|
||||
#include "assh.h"
|
||||
|
||||
/** @This specifies event types. */
|
||||
enum assh_event_id_e
|
||||
{
|
||||
/** @internal This event id is not valid and can be used to mark
|
||||
non-initialized event objects. */
|
||||
ASSH_EVENT_INVALID,
|
||||
|
||||
/** @see assh_event_transport_read_s */
|
||||
ASSH_EVENT_READ,
|
||||
/** @see assh_event_transport_write_s */
|
||||
ASSH_EVENT_WRITE,
|
||||
|
||||
/** @see assh_event_prng_feed_s */
|
||||
ASSH_EVENT_PRNG_FEED,
|
||||
|
||||
/** @see assh_event_kex_hostkey_lookup_s */
|
||||
ASSH_EVENT_KEX_HOSTKEY_LOOKUP,
|
||||
|
||||
/** @see assh_event_userauth_client_user_s */
|
||||
ASSH_EVENT_USERAUTH_CLIENT_USER,
|
||||
/** @see assh_event_userauth_client_methods_s */
|
||||
ASSH_EVENT_USERAUTH_CLIENT_METHODS,
|
||||
|
||||
/** @see assh_event_userauth_server_userkey_s */
|
||||
ASSH_EVENT_USERAUTH_SERVER_USERKEY,
|
||||
/** @see assh_event_userauth_server_password_s */
|
||||
ASSH_EVENT_USERAUTH_SERVER_PASSWORD,
|
||||
|
||||
/** @see assh_event_connection_start_s */
|
||||
ASSH_EVENT_CONNECTION_START,
|
||||
/** @see assh_event_request_s */
|
||||
ASSH_EVENT_REQUEST,
|
||||
/** @see assh_event_request_reply_s */
|
||||
ASSH_EVENT_REQUEST_REPLY,
|
||||
/** @see assh_event_channel_open_s */
|
||||
ASSH_EVENT_CHANNEL_OPEN,
|
||||
/** @see assh_event_channel_open_reply_s */
|
||||
ASSH_EVENT_CHANNEL_OPEN_REPLY,
|
||||
/** @see assh_event_channel_data_s */
|
||||
ASSH_EVENT_CHANNEL_DATA,
|
||||
/** @see assh_event_channel_window_s */
|
||||
ASSH_EVENT_CHANNEL_WINDOW,
|
||||
/** @see assh_event_channel_eof_s */
|
||||
ASSH_EVENT_CHANNEL_EOF,
|
||||
/** @see assh_event_channel_close_s */
|
||||
ASSH_EVENT_CHANNEL_CLOSE,
|
||||
|
||||
/** @internal */
|
||||
ASSH_EVENT_COUNT,
|
||||
};
|
||||
|
||||
/** @internal @see assh_event_done_t */
|
||||
#define ASSH_EVENT_DONE_FCN(n) \
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t (n)(struct assh_session_s *s, \
|
||||
struct assh_event_s *e)
|
||||
|
||||
/** @internal @This is called when the event has been processed.
|
||||
@see assh_event_done */
|
||||
typedef ASSH_EVENT_DONE_FCN(assh_event_done_t);
|
||||
|
||||
union assh_event_transport_u;
|
||||
union assh_event_prng_u;
|
||||
union assh_event_kex_u;
|
||||
union assh_event_userauth_client_u;
|
||||
union assh_event_userauth_server_u;
|
||||
union assh_event_connection_u;
|
||||
|
||||
/** @This hold an event returned by the library. */
|
||||
struct assh_event_s
|
||||
{
|
||||
/** Id of the event. */
|
||||
enum assh_event_id_e id;
|
||||
|
||||
/** @internal Pointer to the event acknowledge function, if any. */
|
||||
assh_event_done_t *f_done;
|
||||
|
||||
/** @internal Private data for the event acknowledge function. */
|
||||
void *done_pv;
|
||||
|
||||
union {
|
||||
|
||||
#ifdef ASSH_TRANSPORT_H_
|
||||
union assh_event_transport_u transport;
|
||||
#endif
|
||||
|
||||
#ifdef ASSH_PRNG_H_
|
||||
union assh_event_prng_u prng;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ASSH_CLIENT
|
||||
# ifdef ASSH_KEX_H_
|
||||
union assh_event_kex_u kex;
|
||||
# endif
|
||||
|
||||
# ifdef ASSH_SRV_USERAUTH_CLIENT_H_
|
||||
union assh_event_userauth_client_u userauth_client;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ASSH_SERVER
|
||||
# ifdef ASSH_SRV_USERAUTH_SERVER_H_
|
||||
union assh_event_userauth_server_u userauth_server;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef ASSH_SRV_CONNECTION_H_
|
||||
union assh_event_connection_u connection;
|
||||
#endif
|
||||
|
||||
#ifdef ASSH_USER_EVENTS_UNION
|
||||
ASSH_USER_EVENTS_UNION;
|
||||
#endif
|
||||
|
||||
/** @internal Padding */
|
||||
long params[10];
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
/** @hidden check sizeof event union */
|
||||
#define ASSH_EVENT_SIZE_SASSERT(name) \
|
||||
typedef char assh_event_##name##_larger_than_padding \
|
||||
[(sizeof(union assh_event_##name##_u) \
|
||||
<= sizeof(((struct assh_event_s*)0)->params)) - 1];
|
||||
|
||||
/** This function runs the various state machines which implement the
|
||||
ssh protocol including the currently running service. It then
|
||||
reports the next available event.
|
||||
|
||||
The @ref assh_event_done function must be called after each
|
||||
successful call to this function, before requesting the next event.
|
||||
|
||||
This function can be called in a loop until the @ref
|
||||
ASSH_ERR_CLOSED error code is returned. Other error codes
|
||||
can be returned but calling this function again may still return
|
||||
more pending events. The @ref ASSH_ERR_CLOSED error is only
|
||||
returned when no more events are pending.
|
||||
*/
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_event_get(struct assh_session_s *s,
|
||||
struct assh_event_s *e);
|
||||
|
||||
/** @This acknowledges the last event returned by the @ref
|
||||
assh_event_get function. */
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_event_done(struct assh_session_s *s,
|
||||
struct assh_event_s *e);
|
||||
|
||||
/** @internal @see assh_event_hndl_func_t */
|
||||
#define ASSH_EVENT_HANDLER_FCN(n) \
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t (n)(struct assh_session_s *s, \
|
||||
struct assh_event_s *e, \
|
||||
struct assh_event_s *n, \
|
||||
void *ctx)
|
||||
|
||||
/** @internal @This is called to handle the event after a call to @ref
|
||||
assh_event_get and before calling @ref assh_event_done. This
|
||||
function may return @ref ASSH_NO_DATA to indicate that it did not
|
||||
handled the event, making the @ref assh_event_table_run function
|
||||
report the event as if there was no registered handler. */
|
||||
typedef ASSH_EVENT_HANDLER_FCN(assh_event_hndl_func_t);
|
||||
|
||||
/** @internal @This stores the event handling function along with its
|
||||
private context. */
|
||||
struct assh_event_hndl_s
|
||||
{
|
||||
assh_event_hndl_func_t *f_handler;
|
||||
void *ctx;
|
||||
struct assh_event_hndl_s *next;
|
||||
};
|
||||
|
||||
/** This table is designed to store an event handler for each possible event. */
|
||||
struct assh_event_hndl_table_s
|
||||
{
|
||||
struct assh_event_hndl_s *table[ASSH_EVENT_COUNT];
|
||||
};
|
||||
|
||||
/** @This initializes an empty event handler table. */
|
||||
void assh_event_table_init(struct assh_event_hndl_table_s *t);
|
||||
|
||||
void assh_event_table_register(struct assh_event_hndl_table_s *t,
|
||||
enum assh_event_id_e id,
|
||||
struct assh_event_hndl_s *h,
|
||||
assh_event_hndl_func_t *f, void *ctx);
|
||||
|
||||
/** @This calls @ref assh_event_get and try to handle the event using
|
||||
the appropriate registered handler in the table. If there is no
|
||||
suitable event handler in the table or if the handler is not able
|
||||
to handle the event, this function reports the event.
|
||||
|
||||
When an event is handled by one of the registered function, the
|
||||
@ref assh_event_done function is called and the process is started
|
||||
again. */
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_event_table_run(struct assh_session_s *s,
|
||||
struct assh_event_hndl_table_s *t,
|
||||
struct assh_event_s *e);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,193 @@
|
|||
/*
|
||||
|
||||
libassh - asynchronous ssh2 client/server library.
|
||||
|
||||
Copyright (C) 2013 Alexandre Becoulet <alexandre.becoulet@free.fr>
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@file
|
||||
@short Hashing module interface
|
||||
@internal
|
||||
*/
|
||||
|
||||
#ifndef ASSH_HASH_H_
|
||||
#define ASSH_HASH_H_
|
||||
|
||||
#include "assh.h"
|
||||
|
||||
struct assh_hash_algo_s;
|
||||
|
||||
/** @internal @This is the base structure for hash contexts */
|
||||
struct assh_hash_ctx_s
|
||||
{
|
||||
const struct assh_hash_algo_s *algo;
|
||||
};
|
||||
|
||||
/** @internal @see assh_hash_init_t */
|
||||
#define ASSH_HASH_INIT_FCN(n) \
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t (n)(struct assh_context_s *c, \
|
||||
struct assh_hash_ctx_s *hctx, \
|
||||
const struct assh_hash_algo_s *algo)
|
||||
|
||||
/** @internal @This defines the function type for the hash initialization
|
||||
operation of the hash module interface. @see assh_hash_init */
|
||||
typedef ASSH_HASH_INIT_FCN(assh_hash_init_t);
|
||||
|
||||
/** @internal @see assh_hash_copy_t */
|
||||
#define ASSH_HASH_COPY_FCN(n) \
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t (n)(struct assh_hash_ctx_s *hctx_dst, \
|
||||
const struct assh_hash_ctx_s *hctx_src)
|
||||
|
||||
/** @internal @This defines the function type for the hash context copy
|
||||
operation of the hash module interface. @see assh_hash_copy. */
|
||||
typedef ASSH_HASH_COPY_FCN(assh_hash_copy_t);
|
||||
|
||||
/** @internal @see assh_hash_update_t */
|
||||
#define ASSH_HASH_UPDATE_FCN(n) \
|
||||
void (n)(struct assh_hash_ctx_s *hctx, const void *data, size_t len)
|
||||
|
||||
/** @internal @This defines the function type for the hash update
|
||||
operation of the hash module interface. @see assh_hash_update */
|
||||
typedef ASSH_HASH_UPDATE_FCN(assh_hash_update_t);
|
||||
|
||||
/** @internal @see assh_hash_final_t */
|
||||
#define ASSH_HASH_FINAL_FCN(n) \
|
||||
void (n)(struct assh_hash_ctx_s *hctx, uint8_t *hash, size_t len)
|
||||
|
||||
/** @internal @This defines the function type for the hash output
|
||||
operation of the hash module interface. @see assh_hash_final */
|
||||
typedef ASSH_HASH_FINAL_FCN(assh_hash_final_t);
|
||||
|
||||
/** @internal @see assh_hash_cleanup_t */
|
||||
#define ASSH_HASH_CLEANUP_FCN(n) \
|
||||
void (n)(struct assh_hash_ctx_s *hctx)
|
||||
|
||||
/** @internal @This defines the function type for the hash context cleanup
|
||||
operation of the hash module interface. @see assh_hash_cleanup */
|
||||
typedef ASSH_HASH_CLEANUP_FCN(assh_hash_cleanup_t);
|
||||
|
||||
/** @internal @This is the hashing module interface structure. */
|
||||
struct assh_hash_algo_s
|
||||
{
|
||||
const char *name;
|
||||
assh_hash_init_t *f_init;
|
||||
assh_hash_copy_t *f_copy;
|
||||
assh_hash_update_t *f_update;
|
||||
assh_hash_final_t *f_final;
|
||||
assh_hash_cleanup_t *f_cleanup;
|
||||
/** Size of the context structure needed to initialize the algorithm. */
|
||||
size_t ctx_size;
|
||||
/** Hash function output size, 0 for variable size output. */
|
||||
size_t hash_size;
|
||||
/** Hash algorithm block size. */
|
||||
size_t block_size;
|
||||
};
|
||||
|
||||
/** @internal @This hashes a ssh string. The string must contain a
|
||||
valid 32 bits size header. No bound checking is performed by this
|
||||
function. */
|
||||
void assh_hash_string(struct assh_hash_ctx_s *hctx, const uint8_t *str);
|
||||
|
||||
/** @internal @This hashes an array of bytes as if it was stored as a
|
||||
ssh string. This means that a 32 bits headers with the array
|
||||
length is first generated and hashed. */
|
||||
void assh_hash_bytes_as_string(struct assh_hash_ctx_s *hctx,
|
||||
const uint8_t *bytes, size_t len);
|
||||
|
||||
/** @internal @This convert the big number to the ssh mpint
|
||||
representation and hash the resulting buffer. */
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_hash_bignum(struct assh_context_s *ctx,
|
||||
struct assh_hash_ctx_s *hctx,
|
||||
const struct assh_bignum_s *bn);
|
||||
|
||||
/** @internal @This hash the packet payload. The packet must contain a
|
||||
valid 32 bits size header; not check is performed by this
|
||||
function. */
|
||||
void assh_hash_payload_as_string(struct assh_hash_ctx_s *hctx,
|
||||
const struct assh_packet_s *p);
|
||||
|
||||
/** @internal @This initializes an hash algorithm context. The @tt
|
||||
hctx argument must points to a buffer allocated in secure memory
|
||||
of size given by @ref assh_hash_algo_s::ctx_size. */
|
||||
ASSH_INLINE ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_hash_init(struct assh_context_s *c,
|
||||
struct assh_hash_ctx_s *hctx,
|
||||
const struct assh_hash_algo_s *algo)
|
||||
{
|
||||
hctx->algo = algo;
|
||||
return algo->f_init(c, hctx, algo);
|
||||
}
|
||||
|
||||
/** @internal @This creates a copy of the hash algorithm context. The
|
||||
new context must be released as if it was created by @ref
|
||||
assh_hash_init. */
|
||||
ASSH_INLINE ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_hash_copy(struct assh_hash_ctx_s *hctx_dst,
|
||||
struct assh_hash_ctx_s *hctx_src)
|
||||
{
|
||||
return hctx_src->algo->f_copy(hctx_dst, hctx_src);
|
||||
}
|
||||
|
||||
/** @internal @This updates the hash context with new input data. */
|
||||
ASSH_INLINE void
|
||||
assh_hash_update(struct assh_hash_ctx_s *hctx, const void *data, size_t len)
|
||||
{
|
||||
return hctx->algo->f_update(hctx, data, len);
|
||||
}
|
||||
|
||||
/** @internal @This produce the hash output. It can be called multiple
|
||||
times when the hash algorithm has a variable length output. */
|
||||
ASSH_INLINE void
|
||||
assh_hash_final(struct assh_hash_ctx_s *hctx, uint8_t *hash, size_t len)
|
||||
{
|
||||
hctx->algo->f_final(hctx, hash, len);
|
||||
}
|
||||
|
||||
/** @internal @This releases resources allocated by the @ref
|
||||
assh_hash_init and @ref assh_hash_copy functions. @see
|
||||
assh_hash_cleanup. */
|
||||
ASSH_INLINE void
|
||||
assh_hash_cleanup(struct assh_hash_ctx_s *hctx)
|
||||
{
|
||||
if (hctx->algo->f_cleanup != NULL)
|
||||
hctx->algo->f_cleanup(hctx);
|
||||
}
|
||||
|
||||
/** @multiple @internal @This is an hash algorithm implementation
|
||||
descriptor. */
|
||||
extern const struct assh_hash_algo_s assh_hash_md5;
|
||||
|
||||
extern const struct assh_hash_algo_s assh_hash_sha1;
|
||||
|
||||
extern const struct assh_hash_algo_s assh_hash_sha224;
|
||||
extern const struct assh_hash_algo_s assh_hash_sha256;
|
||||
extern const struct assh_hash_algo_s assh_hash_sha384;
|
||||
extern const struct assh_hash_algo_s assh_hash_sha512;
|
||||
|
||||
extern const struct assh_hash_algo_s assh_hash_sha3_224;
|
||||
extern const struct assh_hash_algo_s assh_hash_sha3_256;
|
||||
extern const struct assh_hash_algo_s assh_hash_sha3_384;
|
||||
extern const struct assh_hash_algo_s assh_hash_sha3_512;
|
||||
extern const struct assh_hash_algo_s assh_hash_shake_128;
|
||||
extern const struct assh_hash_algo_s assh_hash_shake_256;
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,332 @@
|
|||
/*
|
||||
|
||||
libassh - asynchronous ssh2 client/server library.
|
||||
|
||||
Copyright (C) 2013 Alexandre Becoulet <alexandre.becoulet@free.fr>
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@file
|
||||
@short SSH key exchange module interface and helpers
|
||||
|
||||
@ifnopt hide_internal
|
||||
This headed file defines the interface to use for pluggable
|
||||
key exchange algorithm implementations.
|
||||
|
||||
The key exchange process involve several functions calls performed
|
||||
in the following order:
|
||||
@list
|
||||
@item The @ref assh_kex_send_init and @ref assh_kex_got_init
|
||||
function are called by the transport layer code.
|
||||
@item The @ref assh_kex_init_t function of the pluggable algorithm
|
||||
module is called from @ref assh_kex_got_init.
|
||||
@item The @ref assh_kex_process_t function of the module is called
|
||||
multiple times so that the module key-exchange FSM code can execute.
|
||||
It may return events.
|
||||
@item The @ref assh_kex_new_keys function must be called once from
|
||||
the @ref assh_kex_process_t function when the shared secret is
|
||||
available.
|
||||
@item The @ref assh_kex_end function must be called once from the
|
||||
@ref assh_kex_process_t function when the key exchange is over.
|
||||
This calls the @ref assh_kex_cleanup_t function and a
|
||||
@ref SSH_MSG_NEWKEYS packet is sent.
|
||||
@end list
|
||||
|
||||
The server host key must be verified during the key exchange by
|
||||
using the pluggable signature algorithm given in @ref
|
||||
assh_session_s::host_sign_algo.
|
||||
|
||||
Some helper functions are provided to compute the exchange-hash and
|
||||
deals with the host key signature.
|
||||
@end if
|
||||
*/
|
||||
|
||||
#ifndef ASSH_KEX_H_
|
||||
#define ASSH_KEX_H_
|
||||
|
||||
#ifdef ASSH_EVENT_H_
|
||||
# warning The assh/assh_event.h header should be included after assh_kex.h
|
||||
#endif
|
||||
|
||||
#include "assh_algo.h"
|
||||
|
||||
/** This function sets the amount of ssh stream that can flow between
|
||||
the client and server between re-keying requests. */
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_kex_set_threshold(struct assh_session_s *s, uint32_t bytes);
|
||||
|
||||
/** @internal This function is called internally by the transport layer
|
||||
when a key-exchange must be performed.
|
||||
|
||||
This function send the kex exchange init packet. A copy of the
|
||||
packet is kept in @ref assh_session_s::kex_init_local for hashing
|
||||
by the kex-exchange algorithm. */
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_kex_send_init(struct assh_session_s *s);
|
||||
|
||||
/** @internal This function is called internally by the transport layer
|
||||
when a key exchange init packet is received from the remote host. A
|
||||
copy of the packet is kept in @ref assh_session_s::kex_init_remote
|
||||
for hashing by the kex-exchange algorithm.
|
||||
|
||||
This function selects the various algorithms from the client and
|
||||
server advertised lists and then initialize the pluggable key
|
||||
exchange module by calling its @ref assh_kex_init_t function. */
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_kex_got_init(struct assh_session_s *s, struct assh_packet_s *p);
|
||||
|
||||
#ifdef CONFIG_ASSH_CLIENT
|
||||
|
||||
/** @internal This client side helper function can be used in
|
||||
key-exchange modules to perform some hashing needed for computing
|
||||
the exchange hash. @see assh_kex_client_hash2 */
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_kex_client_hash1(struct assh_session_s *s,
|
||||
struct assh_hash_ctx_s *hash_ctx,
|
||||
const uint8_t *k_str);
|
||||
|
||||
/** @internal This client side helper function can be used in
|
||||
key-exchange modules to the generate exchange hash, check the
|
||||
associated signature and setup the resulting symmetric keys.
|
||||
@see assh_kex_client_hash2 */
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_kex_client_hash2(struct assh_session_s *s, struct assh_hash_ctx_s *hash_ctx,
|
||||
const struct assh_key_s *host_key, const uint8_t *secret_str,
|
||||
const uint8_t *h_str);
|
||||
|
||||
/** @internal This client side helper function can be used in
|
||||
key-exchange modules to load the host key and initialize an host
|
||||
key lookup event. */
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_kex_client_get_key(struct assh_session_s *s, const struct assh_key_s **key,
|
||||
const uint8_t *ks_str, struct assh_event_s *e,
|
||||
assh_error_t (*done)(struct assh_session_s *s,
|
||||
struct assh_event_s *e), void *pv);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ASSH_SERVER
|
||||
|
||||
/** @internal This server side helper function can be used in
|
||||
key-exchange modules to allocate a @ref SSH_MSG_KEX_DH_REPLY key
|
||||
exchange packet, adds public host key fields and updates the hash
|
||||
context with various values including the host key.
|
||||
|
||||
More fields may be added hashed or added to the packet before
|
||||
calling the @ref assh_kex_server_hash2 function.
|
||||
*/
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_kex_server_hash1(struct assh_session_s *s, size_t kex_len,
|
||||
struct assh_hash_ctx_s *hash_ctx,
|
||||
struct assh_packet_s **pout, size_t *sign_len,
|
||||
const struct assh_key_s **host_key,
|
||||
enum assh_ssh_msg_e msg);
|
||||
|
||||
/** @internal This server side helper function can be used in
|
||||
key-exchange modules to hash the secret key then add the signature
|
||||
to the @ref SSH_MSG_KEX_DH_REPLY packet and finally call @ref
|
||||
assh_kex_new_keys function.
|
||||
|
||||
@see assh_kex_server_hash1
|
||||
*/
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_kex_server_hash2(struct assh_session_s *s,
|
||||
struct assh_hash_ctx_s *hash_ctx,
|
||||
struct assh_packet_s *pout, size_t sign_len,
|
||||
const struct assh_key_s *host_key,
|
||||
const uint8_t *secret_str);
|
||||
|
||||
#endif
|
||||
|
||||
/** @internal This function is called by the pluggable key exchange
|
||||
module when the exchange hash and the shared secret are
|
||||
available. It will use the provided hash algorithm to derive the
|
||||
various symmetric cipher keys from these values and then
|
||||
initialize the associated algorithms.
|
||||
|
||||
Two new @ref assh_kex_keys_s objects will bed ready for use and will
|
||||
replace the old keys when the next @ref SSH_MSG_NEWKEYS packets
|
||||
are processed by the transport layer in each direction. */
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_kex_new_keys(struct assh_session_s *s,
|
||||
const struct assh_hash_algo_s *hash_algo,
|
||||
const uint8_t *ex_hash,
|
||||
const uint8_t *secret_str);
|
||||
|
||||
/**
|
||||
@internal This function is called by the pluggable key exchange
|
||||
module when the exchange is over. It will call the @ref
|
||||
assh_kex_cleanup_t function of the module and release init packets.
|
||||
|
||||
If the @tt accept parameter is not zero, a @ref SSH_MSG_NEWKEYS
|
||||
packet is sent. If the @tt accept parameter is zero, the key
|
||||
exchange fails.
|
||||
*/
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_kex_end(struct assh_session_s *s, assh_bool_t accept);
|
||||
|
||||
/**
|
||||
@internal This function is called internally when a @ref
|
||||
assh_kex_keys_s object and its associated resources have to be
|
||||
released.
|
||||
*/
|
||||
void assh_kex_keys_cleanup(struct assh_session_s *s,
|
||||
struct assh_kex_keys_s *keys);
|
||||
|
||||
/** @internal @see assh_kex_init_t */
|
||||
#define ASSH_KEX_INIT_FCN(n) assh_error_t (n)(struct assh_session_s *s, \
|
||||
size_t cipher_key_size)
|
||||
/** @internal @This defines the function type for the initialization
|
||||
operation of the key-exchange module interface. @This is called
|
||||
when a key exchange starts. It may allocate a private
|
||||
context and store it in the @ref assh_session_s::kex_pv field. */
|
||||
typedef ASSH_KEX_INIT_FCN(assh_kex_init_t);
|
||||
|
||||
/** @internal @see assh_kex_cleanup_t */
|
||||
#define ASSH_KEX_CLEANUP_FCN(n) void (n)(struct assh_session_s *s)
|
||||
/** @internal @This defines the function type for the cleanup
|
||||
operation of the key-exchange module interface. @This is called
|
||||
when the key exchange is over if the @ref assh_session_s::kex_pv
|
||||
field is not @tt NULL. It has to release the key exchange private
|
||||
context and set this field back to @tt NULL. */
|
||||
typedef ASSH_KEX_CLEANUP_FCN(assh_kex_cleanup_t);
|
||||
|
||||
#define ASSH_KEX_PROCESS_FCN(n) assh_error_t (n)(struct assh_session_s *s, \
|
||||
struct assh_packet_s *p, \
|
||||
struct assh_event_s *e)
|
||||
|
||||
/** @internal @This defines the function type for event processing
|
||||
of the key-exchange module interface. @This is called from
|
||||
the @ref assh_transport_dispatch function when the current state
|
||||
of the transport layer is @ref ASSH_TR_KEX_RUNNING.
|
||||
|
||||
A packet may be passed to the function for processing by the
|
||||
key-exchange protocol. If no new received packet is available, the
|
||||
parameter is @tt NULL. This is the case on the first call to this
|
||||
function after the key-exchange initialization.
|
||||
|
||||
The function may initialize the passed event object, in this case
|
||||
the event will be propagated to the caller of the @ref
|
||||
assh_event_get function.
|
||||
*/
|
||||
typedef ASSH_KEX_PROCESS_FCN(assh_kex_process_t);
|
||||
|
||||
/** @internal This object contains the various symmetric cipher
|
||||
algorithm contexts initialized from the shared secret. This is
|
||||
used by the transport layer code to process the ssh packet stream. */
|
||||
struct assh_kex_keys_s
|
||||
{
|
||||
const struct assh_algo_cipher_s *cipher;
|
||||
void *cipher_ctx;
|
||||
const struct assh_algo_mac_s *mac;
|
||||
void *mac_ctx;
|
||||
const struct assh_algo_compress_s *cmp;
|
||||
void *cmp_ctx;
|
||||
};
|
||||
|
||||
/**
|
||||
The @ref ASSH_EVENT_KEX_HOSTKEY_LOOKUP event is returned when a
|
||||
client needs to lookup a server host key in the local database. The
|
||||
@ref accept field must be updated accordingly before calling the
|
||||
@ref assh_event_done function.
|
||||
*/
|
||||
struct assh_event_kex_hostkey_lookup_s
|
||||
{
|
||||
const struct assh_key_s * ASSH_EV_CONST key; //< input
|
||||
assh_bool_t accept; //< output
|
||||
};
|
||||
|
||||
/** @internal */
|
||||
union assh_event_kex_u
|
||||
{
|
||||
struct assh_event_kex_hostkey_lookup_s hostkey_lookup;
|
||||
};
|
||||
|
||||
/** @internalmembers This defines the interface of a pluggable key
|
||||
exchange algorithm. It can be casted to the @ref assh_algo_s
|
||||
type. */
|
||||
struct assh_algo_kex_s
|
||||
{
|
||||
struct assh_algo_s algo;
|
||||
assh_kex_init_t *f_init;
|
||||
assh_kex_cleanup_t *f_cleanup;
|
||||
assh_kex_process_t *f_process;
|
||||
};
|
||||
|
||||
/** Dummy key-exchange algorithm using a not so secret value. */
|
||||
extern const struct assh_algo_kex_s assh_kex_none;
|
||||
|
||||
/** Standard @tt diffie-hellman-group1-sha1 algorithm specified in
|
||||
rfc4253. */
|
||||
extern const struct assh_algo_kex_s assh_kex_dh_group1_sha1;
|
||||
|
||||
/** Standard @tt diffie-hellman-group1-sha14 algorithm specified in
|
||||
rfc4253. */
|
||||
extern const struct assh_algo_kex_s assh_kex_dh_group14_sha1;
|
||||
|
||||
/** The @tt curve25519-sha256 algorithm defined in @tt
|
||||
curve25519-sha256@libssh.org.txt by the libssh project. This
|
||||
offers 125 bit security and relies on a Montgomery elliptic curve.
|
||||
|
||||
See @url {http://safecurves.cr.yp.to/} */
|
||||
extern const struct assh_algo_kex_s assh_kex_curve25519_sha256;
|
||||
|
||||
/** Same protocol as @ref assh_kex_curve25519_sha256 using the stronger
|
||||
M383 Montgomery curve.
|
||||
|
||||
See @url {http://safecurves.cr.yp.to/} */
|
||||
extern const struct assh_algo_kex_s assh_kex_m383_sha384;
|
||||
|
||||
/** Same protocol as @ref assh_kex_curve25519_sha256 using the stronger
|
||||
M511 Montgomery curve.
|
||||
|
||||
See @url {http://safecurves.cr.yp.to/} */
|
||||
extern const struct assh_algo_kex_s assh_kex_m511_sha512;
|
||||
|
||||
/** Standard @tt diffie-hellman-group-exchange-sha1 algorithm
|
||||
specified in rfc4419, favors group size of n^2/12 bits and allows
|
||||
groups size of n^2/16 bits where n is the size of the symmetric
|
||||
cipher key. */
|
||||
extern const struct assh_algo_kex_s assh_kex_dh_gex_sha1;
|
||||
|
||||
/** Standard @tt diffie-hellman-group-exchange-sha256 algorithm
|
||||
specified in rfc4419, favors group size of n^2/12 bits and allows
|
||||
groups size of n^2/16 bits where n is the size of the symmetric
|
||||
cipher key. */
|
||||
extern const struct assh_algo_kex_s assh_kex_dh_gex_sha256_12;
|
||||
|
||||
/** Standard @tt diffie-hellman-group-exchange-sha256 algorithm
|
||||
specified in rfc4419, favors group size of n^2/8 bits and allows
|
||||
groups size of n^2/12 bits where n is the size of the symmetric
|
||||
cipher key. */
|
||||
extern const struct assh_algo_kex_s assh_kex_dh_gex_sha256_8;
|
||||
|
||||
/** Standard @tt diffie-hellman-group-exchange-sha256 algorithm
|
||||
specified in rfc4419, favors group size of n^2/4 bits and allows
|
||||
groups size of n^2/8 bits where n is the size of the symmetric
|
||||
cipher key. */
|
||||
extern const struct assh_algo_kex_s assh_kex_dh_gex_sha256_4;
|
||||
|
||||
/** Standard @tt rsa1024-sha1 algorithm specified in rfc4432. */
|
||||
extern const struct assh_algo_kex_s assh_kex_rsa1024_sha1;
|
||||
|
||||
/** Standard @tt rsa2048-sha256 algorithm specified in rfc4432. */
|
||||
extern const struct assh_algo_kex_s assh_kex_rsa2048_sha256;
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,238 @@
|
|||
/*
|
||||
|
||||
libassh - asynchronous ssh2 client/server library.
|
||||
|
||||
Copyright (C) 2013 Alexandre Becoulet <alexandre.becoulet@free.fr>
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@file
|
||||
@short SSH keys base structure and related functions
|
||||
*/
|
||||
|
||||
#ifndef ASSH_KEY_H_
|
||||
#define ASSH_KEY_H_
|
||||
|
||||
#include "assh_algo.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/** @This specifies the storage formats of SSH keys. */
|
||||
enum assh_key_format_e
|
||||
{
|
||||
/** Public key in rfc4716, base64 ascii format. */
|
||||
ASSH_KEY_FMT_PUB_RFC4716,
|
||||
/** Public key in rfc4253, section 6.6 binary format. */
|
||||
ASSH_KEY_FMT_PUB_RFC4253_6_6,
|
||||
|
||||
/** Keys openssh-key-v1 base64 format */
|
||||
ASSH_KEY_FMT_OPENSSH_V1,
|
||||
/** Keys blob openssh-key-v1 binary format */
|
||||
ASSH_KEY_FMT_OPENSSH_V1_BLOB,
|
||||
/** Private key used inside openssh-key-v1 binary format */
|
||||
ASSH_KEY_FMT_PV_OPENSSH_V1_KEY,
|
||||
/** Private key in rfc2440 like, base64 ascii format with PEM Asn1 inside. */
|
||||
ASSH_KEY_FMT_PV_RFC2440_PEM_ASN1,
|
||||
/** Private key in PEM Asn1 DER binary format. */
|
||||
ASSH_KEY_FMT_PV_PEM_ASN1,
|
||||
};
|
||||
|
||||
/** @internal @see assh_key_load_t */
|
||||
#define ASSH_KEY_LOAD_FCN(n) ASSH_WARN_UNUSED_RESULT assh_error_t (n) \
|
||||
(struct assh_context_s *c, \
|
||||
const struct assh_key_ops_s *algo, \
|
||||
const uint8_t *blob, size_t blob_len, \
|
||||
struct assh_key_s **key, \
|
||||
enum assh_key_format_e format)
|
||||
|
||||
/** @internal @This defines the function type for the key loading
|
||||
operation of the key module interface. @see assh_key_load */
|
||||
typedef ASSH_KEY_LOAD_FCN(assh_key_load_t);
|
||||
|
||||
/** @internal @see assh_key_create_t */
|
||||
#define ASSH_KEY_CREATE_FCN(n) ASSH_WARN_UNUSED_RESULT assh_error_t (n) \
|
||||
(struct assh_context_s *c, \
|
||||
const struct assh_key_ops_s *algo, \
|
||||
size_t bits, struct assh_key_s **key)
|
||||
|
||||
/** @internal @This defines the function type for the key create
|
||||
operation of the key module interface. @see assh_key_create */
|
||||
typedef ASSH_KEY_CREATE_FCN(assh_key_create_t);
|
||||
|
||||
/** @internal @see assh_key_validate_t */
|
||||
#define ASSH_KEY_VALIDATE_FCN(n) ASSH_WARN_UNUSED_RESULT assh_error_t (n) \
|
||||
(struct assh_context_s *c, \
|
||||
const struct assh_key_s *key)
|
||||
|
||||
/** @internal @This defines the function type for the key validation
|
||||
operation of the key module interface. @see assh_key_validate */
|
||||
typedef ASSH_KEY_VALIDATE_FCN(assh_key_validate_t);
|
||||
|
||||
/** @internal @see assh_key_output_t */
|
||||
#define ASSH_KEY_OUTPUT_FCN(n) ASSH_WARN_UNUSED_RESULT assh_error_t (n) \
|
||||
(struct assh_context_s *c, \
|
||||
const struct assh_key_s *key, \
|
||||
uint8_t *blob, size_t *blob_len, \
|
||||
enum assh_key_format_e format)
|
||||
|
||||
/** @internal @This defines the function type for the key output
|
||||
operation of the key module interface. @see assh_key_output */
|
||||
typedef ASSH_KEY_OUTPUT_FCN(assh_key_output_t);
|
||||
|
||||
/** @internal @see assh_key_cmp_t */
|
||||
#define ASSH_KEY_CMP_FCN(n) ASSH_WARN_UNUSED_RESULT assh_bool_t (n) \
|
||||
(struct assh_context_s *c, \
|
||||
const struct assh_key_s *key, \
|
||||
const struct assh_key_s *b, assh_bool_t pub)
|
||||
|
||||
/** @internal @This defines the function type for the key compare
|
||||
operation of the key module interface. @see assh_key_cmp */
|
||||
typedef ASSH_KEY_CMP_FCN(assh_key_cmp_t);
|
||||
|
||||
/** @internal @see assh_key_cleanup_t */
|
||||
#define ASSH_KEY_CLEANUP_FCN(n) void (n) \
|
||||
(struct assh_context_s *c, \
|
||||
struct assh_key_s *key)
|
||||
|
||||
/** @internal @This defines the function type for the key cleanup
|
||||
operation of the key module interface.
|
||||
@see assh_key_drop @see assh_key_flush */
|
||||
typedef ASSH_KEY_CLEANUP_FCN(assh_key_cleanup_t);
|
||||
|
||||
/** @internal @This is the operations descriptor structure of the SSH
|
||||
key module interface. It defines functions associated to a given
|
||||
type of key. */
|
||||
struct assh_key_ops_s
|
||||
{
|
||||
const char *type;
|
||||
assh_key_load_t *f_load;
|
||||
assh_key_create_t *f_create;
|
||||
assh_key_output_t *f_output;
|
||||
assh_key_validate_t *f_validate;
|
||||
assh_key_cmp_t *f_cmp;
|
||||
assh_key_cleanup_t *f_cleanup;
|
||||
};
|
||||
|
||||
/** @internal @This is the generic SSH key structure. Other key
|
||||
structures inherit from this type. */
|
||||
struct assh_key_s
|
||||
{
|
||||
/* Next key in the list */
|
||||
const struct assh_key_s *next;
|
||||
|
||||
/* Functions operating on this key */
|
||||
const struct assh_key_ops_s *algo;
|
||||
|
||||
/* Class of algorithm the key is intended to be used with */
|
||||
enum assh_algo_class_e role;
|
||||
};
|
||||
|
||||
/** @internal @This allocates and intiailizes the key structure from
|
||||
the passed key blob data. This function may only support some
|
||||
binary key formats. Ascii formats are handled by helper
|
||||
functions. @see @assh/helper_key.h */
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_key_load(struct assh_context_s *c,
|
||||
const struct assh_key_s **key,
|
||||
const struct assh_key_ops_s *algo,
|
||||
enum assh_algo_class_e role,
|
||||
enum assh_key_format_e format,
|
||||
const uint8_t *blob, size_t blob_len);
|
||||
|
||||
/** @internal @This creates a new key of specified type and bits
|
||||
size. */
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_key_create(struct assh_context_s *c,
|
||||
const struct assh_key_s **key, size_t bits,
|
||||
const struct assh_key_ops_s *algo,
|
||||
enum assh_algo_class_e role);
|
||||
|
||||
/** @internal This function write the key in blob representation to
|
||||
the @tt blob buffer. The @tt blob_len parameter indicates the size
|
||||
of the buffer and is updated with the actual size of the key blob.
|
||||
|
||||
If the @tt blob parameter is @tt NULL, the function updates the
|
||||
@tt blob_len parmeter with a size value which is greater or equal
|
||||
to what is needed to hold the blob.
|
||||
|
||||
This function may only support the @ref
|
||||
ASSH_KEY_FMT_PUB_RFC4253_6_6 format.
|
||||
*/
|
||||
ASSH_INLINE ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_key_output(struct assh_context_s *c,
|
||||
const struct assh_key_s *key,
|
||||
uint8_t *blob, size_t *blob_len,
|
||||
enum assh_key_format_e format)
|
||||
{
|
||||
return key->algo->f_output(c, key, blob, blob_len, format);
|
||||
}
|
||||
|
||||
/** @This function returns true if both keys are equals. If the @tt
|
||||
pub parameter is set, only the public parts of the key are taken
|
||||
into account. */
|
||||
ASSH_INLINE ASSH_WARN_UNUSED_RESULT assh_bool_t
|
||||
assh_key_cmp(struct assh_context_s *c, const struct assh_key_s *key,
|
||||
const struct assh_key_s *b, assh_bool_t pub)
|
||||
{
|
||||
return key->algo->f_cmp(c, key, b, pub);
|
||||
}
|
||||
|
||||
/** @This releases the first key on the linked list. */
|
||||
void assh_key_drop(struct assh_context_s *c,
|
||||
const struct assh_key_s **head);
|
||||
|
||||
/** @This releases all the keys on the linked list
|
||||
and set the list head to @tt NULL. */
|
||||
ASSH_INLINE void
|
||||
assh_key_flush(struct assh_context_s *c,
|
||||
const struct assh_key_s **head)
|
||||
{
|
||||
while (*head != NULL)
|
||||
assh_key_drop(c, head);
|
||||
}
|
||||
|
||||
/** @internal @This inserts a key in a list of keys. */
|
||||
ASSH_INLINE void
|
||||
assh_key_insert(const struct assh_key_s **head,
|
||||
const struct assh_key_s *key)
|
||||
{
|
||||
((struct assh_key_s *)key)->next = *head;
|
||||
*head = key;
|
||||
}
|
||||
|
||||
/** @This checks the validity of the key. */
|
||||
ASSH_INLINE ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_key_validate(struct assh_context_s *c,
|
||||
const struct assh_key_s *key)
|
||||
{
|
||||
return key->algo->f_validate(c, key);
|
||||
}
|
||||
|
||||
/** @internal @This looks for a key usable with the given algorithm
|
||||
among keys registered on the context. */
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_key_lookup(struct assh_context_s *c,
|
||||
const struct assh_key_s **key,
|
||||
const struct assh_algo_s *algo);
|
||||
|
||||
/** Dummy key algorithm */
|
||||
extern const struct assh_key_ops_s assh_key_none;
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
|
||||
libassh - asynchronous ssh2 client/server library.
|
||||
|
||||
Copyright (C) 2013 Alexandre Becoulet <alexandre.becoulet@free.fr>
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@file
|
||||
@short SSH message authentication code module interface
|
||||
*/
|
||||
|
||||
#ifndef ASSH_MAC_H_
|
||||
#define ASSH_MAC_H_
|
||||
|
||||
#include "assh_algo.h"
|
||||
|
||||
/** @internal @see assh_mac_init_t */
|
||||
#define ASSH_MAC_INIT_FCN(n) \
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t (n)(struct assh_context_s *c, \
|
||||
void *ctx_, const uint8_t *key)
|
||||
|
||||
/** @internal @This defines the function type for the mac
|
||||
initialization operation of the mac module interface. The @tt
|
||||
ctx_ argument must points to a buffer allocated in secure memory
|
||||
of size given by @ref assh_algo_mac_s::ctx_size. */
|
||||
typedef ASSH_MAC_INIT_FCN(assh_mac_init_t);
|
||||
|
||||
/** @internal @see assh_mac_compute_t */
|
||||
#define ASSH_MAC_COMPUTE_FCN(n) \
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t (n)(void *ctx_, uint32_t seq, \
|
||||
const uint8_t *data, size_t len, \
|
||||
uint8_t *mac)
|
||||
|
||||
/** @internal @This defines the function type for the mac computation
|
||||
operation of the mac module interface. */
|
||||
typedef ASSH_MAC_COMPUTE_FCN(assh_mac_compute_t);
|
||||
|
||||
/** @internal @see assh_mac_check_t */
|
||||
#define ASSH_MAC_CHECK_FCN(n) \
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t (n)(void *ctx_, uint32_t seq, \
|
||||
const uint8_t *data, size_t len, \
|
||||
const uint8_t *mac)
|
||||
|
||||
/** @internal @This defines the function type for the mac checking
|
||||
operation of the mac module interface. */
|
||||
typedef ASSH_MAC_CHECK_FCN(assh_mac_check_t);
|
||||
|
||||
/** @internal @see assh_mac_cleanup_t */
|
||||
#define ASSH_MAC_CLEANUP_FCN(n) void (n)(struct assh_context_s *c, void *ctx_)
|
||||
|
||||
/** @internal @This defines the function type for the cleanup
|
||||
operation of the mac module interface. */
|
||||
typedef ASSH_MAC_CLEANUP_FCN(assh_mac_cleanup_t);
|
||||
|
||||
/** @internalmembers @This is the mac algorithm descriptor
|
||||
structure. It can be casted to the @ref assh_algo_s type. */
|
||||
struct assh_algo_mac_s
|
||||
{
|
||||
struct assh_algo_s algo;
|
||||
/** Size of the context structure needed to initialize the algorithm. */
|
||||
size_t ctx_size;
|
||||
/** Mac key size in bytes. */
|
||||
size_t key_size;
|
||||
/** Authentication tag size. */
|
||||
size_t mac_size;
|
||||
assh_mac_init_t *f_init;
|
||||
assh_mac_compute_t *f_compute;
|
||||
assh_mac_check_t *f_check;
|
||||
assh_mac_cleanup_t *f_cleanup;
|
||||
};
|
||||
|
||||
/** @multiple @This is a mac algorithm implementation descriptor. */
|
||||
extern const struct assh_algo_mac_s assh_hmac_none;
|
||||
extern const struct assh_algo_mac_s assh_hmac_md5;
|
||||
extern const struct assh_algo_mac_s assh_hmac_md5_96;
|
||||
extern const struct assh_algo_mac_s assh_hmac_sha1;
|
||||
extern const struct assh_algo_mac_s assh_hmac_sha1_96;
|
||||
extern const struct assh_algo_mac_s assh_hmac_sha256;
|
||||
extern const struct assh_algo_mac_s assh_hmac_sha512;
|
||||
|
||||
#ifdef CONFIG_ASSH_USE_GCRYPT_HASH
|
||||
extern const struct assh_algo_mac_s assh_hmac_ripemd160;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
|
||||
libassh - asynchronous ssh2 client/server library.
|
||||
|
||||
Copyright (C) 2013 Alexandre Becoulet <alexandre.becoulet@free.fr>
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@file
|
||||
@short Associative container
|
||||
@internal
|
||||
*/
|
||||
|
||||
#ifndef ASSH_MAP_H_
|
||||
#define ASSH_MAP_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/** @internal Associative container key type */
|
||||
typedef uint32_t assh_map_id_t;
|
||||
|
||||
/** @internal Associative container entry */
|
||||
struct assh_map_entry_s
|
||||
{
|
||||
struct assh_map_entry_s *link[2];
|
||||
assh_map_id_t id;
|
||||
uint_fast8_t lz;
|
||||
};
|
||||
|
||||
/* @internal @This inserts an item in the container, @tt item->id must
|
||||
be initialized. This function returns a pointer to the colliding
|
||||
item if the insertion fails. */
|
||||
struct assh_map_entry_s *
|
||||
assh_map_insert(struct assh_map_entry_s **root,
|
||||
struct assh_map_entry_s *item);
|
||||
|
||||
/* @internal @This removes an item from the container. The parent
|
||||
pointer can be obtained by calling @ref assh_map_lookup or @ref
|
||||
assh_map_head. */
|
||||
void
|
||||
assh_map_remove(struct assh_map_entry_s **parent,
|
||||
struct assh_map_entry_s *item);
|
||||
|
||||
/* @internal @This finds a node in the container. This function will
|
||||
also return the parent pointer to the node if the @tt parent
|
||||
parameter is not @tt NULL. */
|
||||
struct assh_map_entry_s *
|
||||
assh_map_lookup(struct assh_map_entry_s **root,
|
||||
assh_map_id_t id, struct assh_map_entry_s ***parent);
|
||||
|
||||
/* @internal @This returns the first item in the container. This
|
||||
function will also return the parent pointer to the node if the @tt
|
||||
parent parameter is not @tt NULL. */
|
||||
struct assh_map_entry_s *
|
||||
assh_map_head(struct assh_map_entry_s **root,
|
||||
struct assh_map_entry_s ***parent);
|
||||
|
||||
/* @internal @This finds and removes an item from the container. */
|
||||
ASSH_INLINE struct assh_map_entry_s *
|
||||
assh_map_remove_id(struct assh_map_entry_s **root,
|
||||
assh_map_id_t id)
|
||||
{
|
||||
struct assh_map_entry_s *x = assh_map_lookup(root, id, &root);
|
||||
if (x)
|
||||
assh_map_remove(root, x);
|
||||
return x;
|
||||
}
|
||||
|
||||
/* @internal @This iterates over items in the container. */
|
||||
void assh_map_iter(struct assh_map_entry_s *root, void *ctx,
|
||||
void (*iter)(struct assh_map_entry_s *, void *));
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,336 @@
|
|||
/*
|
||||
|
||||
libassh - asynchronous ssh2 client/server library.
|
||||
|
||||
Copyright (C) 2013 Alexandre Becoulet <alexandre.becoulet@free.fr>
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@file
|
||||
@short SSH packets management
|
||||
@internal
|
||||
*/
|
||||
|
||||
#ifndef ASSH_PACKET_H_
|
||||
#define ASSH_PACKET_H_
|
||||
|
||||
#include "assh.h"
|
||||
#include "assh_queue.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/** @internal SSH protocol packet header */
|
||||
struct assh_packet_head_s
|
||||
{
|
||||
uint8_t pck_len[4];
|
||||
uint8_t pad_len;
|
||||
uint8_t msg;
|
||||
uint8_t end[0];
|
||||
};
|
||||
|
||||
/** @internal SSH packet object */
|
||||
struct assh_packet_s
|
||||
{
|
||||
union {
|
||||
/** Packet queue entry, valid when packet is allocated. */
|
||||
struct assh_queue_entry_s entry;
|
||||
/** Spare packet pool entry, valid when packet has been released. */
|
||||
struct assh_packet_s *pool_next;
|
||||
};
|
||||
|
||||
/** Associated assh context */
|
||||
struct assh_context_s *ctx;
|
||||
|
||||
/** Size of the allocated packet data buffer. */
|
||||
uint_fast32_t alloc_size;
|
||||
/** Amount of valid packet data. This value is increased when adding
|
||||
data to the packet and is used when the packet is finally sent out. */
|
||||
uint_fast32_t data_size;
|
||||
|
||||
/** Number of references to this packet. */
|
||||
uint_fast16_t ref_count;
|
||||
|
||||
union {
|
||||
uint8_t data[0];
|
||||
struct assh_packet_head_s head;
|
||||
};
|
||||
};
|
||||
|
||||
ASSH_FIRST_FIELD_ASSERT(assh_packet_s, entry);
|
||||
|
||||
/** @internal @This specifies the standard values for ssh message ids. */
|
||||
enum assh_ssh_msg_e
|
||||
{
|
||||
SSH_MSG_INVALID = 0,
|
||||
|
||||
/** @multiple SSH transport related messages */
|
||||
SSH_MSG_DISCONNECT = 1,
|
||||
SSH_MSG_IGNORE = 2,
|
||||
SSH_MSG_UNIMPLEMENTED = 3,
|
||||
SSH_MSG_DEBUG = 4,
|
||||
SSH_MSG_SERVICE_REQUEST = 5,
|
||||
SSH_MSG_SERVICE_ACCEPT = 6,
|
||||
SSH_MSG_KEXINIT = 20,
|
||||
SSH_MSG_NEWKEYS = 21,
|
||||
|
||||
/** @multiple SSH key-exchange related messages */
|
||||
SSH_MSG_KEX_DH_REQUEST = 30,
|
||||
SSH_MSG_KEX_DH_REPLY = 31,
|
||||
SSH_MSG_KEX_ECDH_INIT = 30,
|
||||
SSH_MSG_KEX_ECDH_REPLY = 31,
|
||||
|
||||
SSH_MSG_KEX_DH_GEX_REQUEST_OLD = 30,
|
||||
SSH_MSG_KEX_DH_GEX_GROUP = 31,
|
||||
SSH_MSG_KEX_DH_GEX_INIT = 32,
|
||||
SSH_MSG_KEX_DH_GEX_REPLY = 33,
|
||||
SSH_MSG_KEX_DH_GEX_REQUEST = 34,
|
||||
|
||||
SSH_MSG_KEXRSA_PUBKEY = 30,
|
||||
SSH_MSG_KEXRSA_SECRET = 31,
|
||||
SSH_MSG_KEXRSA_DONE = 32,
|
||||
|
||||
/** @multiple SSH user authentication related messages */
|
||||
SSH_MSG_USERAUTH_REQUEST = 50,
|
||||
SSH_MSG_USERAUTH_FAILURE = 51,
|
||||
SSH_MSG_USERAUTH_SUCCESS = 52,
|
||||
SSH_MSG_USERAUTH_BANNER = 53,
|
||||
SSH_MSG_USERAUTH_PK_OK = 60,
|
||||
SSH_MSG_USERAUTH_PASSWD_CHANGEREQ = 60,
|
||||
|
||||
/** @multiple SSH connection service related messages */
|
||||
SSH_MSG_GLOBAL_REQUEST = 80,
|
||||
SSH_MSG_REQUEST_SUCCESS = 81,
|
||||
SSH_MSG_REQUEST_FAILURE = 82,
|
||||
SSH_MSG_CHANNEL_OPEN = 90,
|
||||
SSH_MSG_CHANNEL_OPEN_CONFIRMATION = 91,
|
||||
SSH_MSG_CHANNEL_OPEN_FAILURE = 92,
|
||||
SSH_MSG_CHANNEL_WINDOW_ADJUST = 93,
|
||||
SSH_MSG_CHANNEL_DATA = 94,
|
||||
SSH_MSG_CHANNEL_EXTENDED_DATA = 95,
|
||||
SSH_MSG_CHANNEL_EOF = 96,
|
||||
SSH_MSG_CHANNEL_CLOSE = 97,
|
||||
SSH_MSG_CHANNEL_REQUEST = 98,
|
||||
SSH_MSG_CHANNEL_SUCCESS = 99,
|
||||
SSH_MSG_CHANNEL_FAILURE = 100,
|
||||
};
|
||||
|
||||
/** @internal @This specifies standard ssh disconnect reasons. */
|
||||
enum assh_ssh_disconnect_e
|
||||
{
|
||||
SSH_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT = 1,
|
||||
SSH_DISCONNECT_PROTOCOL_ERROR = 2,
|
||||
SSH_DISCONNECT_KEY_EXCHANGE_FAILED = 3,
|
||||
SSH_DISCONNECT_RESERVED = 4,
|
||||
SSH_DISCONNECT_MAC_ERROR = 5,
|
||||
SSH_DISCONNECT_COMPRESSION_ERROR = 6,
|
||||
SSH_DISCONNECT_SERVICE_NOT_AVAILABLE = 7,
|
||||
SSH_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED = 8,
|
||||
SSH_DISCONNECT_HOST_KEY_NOT_VERIFIABLE = 9,
|
||||
SSH_DISCONNECT_CONNECTION_LOST = 10,
|
||||
SSH_DISCONNECT_BY_APPLICATION = 11,
|
||||
SSH_DISCONNECT_TOO_MANY_CONNECTIONS = 12,
|
||||
SSH_DISCONNECT_AUTH_CANCELLED_BY_USER = 13,
|
||||
SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE = 14,
|
||||
SSH_DISCONNECT_ILLEGAL_USER_NAME = 15,
|
||||
};
|
||||
|
||||
/** @internal @This allocates a new packet. The @tt alloc_size
|
||||
parameter specifies total allocated size. No range checking is
|
||||
performed on the size parameter. */
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_packet_alloc2(struct assh_context_s *c,
|
||||
uint8_t msg, size_t alloc_size,
|
||||
struct assh_packet_s **p);
|
||||
|
||||
/** @internal @This allocates a new packet. The @tt
|
||||
payload_size parameter specifies the amount of bytes needed
|
||||
between the message id byte and the mac bytes. */
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_packet_alloc(struct assh_context_s *c,
|
||||
uint8_t msg, size_t payload_size,
|
||||
struct assh_packet_s **result);
|
||||
|
||||
/** @internal @This decreases the reference counter of the
|
||||
packet and release the packet if the new counter value is
|
||||
zero. */
|
||||
void assh_packet_release(struct assh_packet_s *p);
|
||||
|
||||
/** @internal @This increase the reference counter of the packet. */
|
||||
ASSH_INLINE struct assh_packet_s *
|
||||
assh_packet_refinc(struct assh_packet_s *p)
|
||||
{
|
||||
p->ref_count++;
|
||||
return p;
|
||||
}
|
||||
|
||||
/** @internal @This creates a copy of a packet. */
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_packet_dup(struct assh_packet_s *p,
|
||||
struct assh_packet_s **copy);
|
||||
|
||||
/** @internal @This allocates an array of bytes in a packet
|
||||
and returns a pointer to the array. If there is not enough space
|
||||
left in the packet, an error is returned. */
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_packet_add_array(struct assh_packet_s *p, size_t len, uint8_t **result);
|
||||
|
||||
/** @internal @This allocates an unsigned 32 bits integer in a packet
|
||||
and sets its value. If there is not enough space left in the
|
||||
packet, an error is returned. */
|
||||
ASSH_INLINE ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_packet_add_u32(struct assh_packet_s *p, uint32_t value)
|
||||
{
|
||||
uint8_t *be;
|
||||
assh_error_t err = assh_packet_add_array(p, 4, &be);
|
||||
if (!err)
|
||||
assh_store_u32(be, value);
|
||||
return err;
|
||||
}
|
||||
|
||||
/** @internal @This allocates a string in a packet and returns
|
||||
a pointer to the first char of the string. If there is not enough
|
||||
space left in the packet, and error is returned. */
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_packet_add_string(struct assh_packet_s *p, size_t len, uint8_t **result);
|
||||
|
||||
/** @internal @This enlarges a string previously allocated in
|
||||
a packet and returns a pointer to the first additional char of the
|
||||
string. If there is not enough space left in the packet, an error
|
||||
is returned. The string must be the last allocated thing in the
|
||||
packet when this function is called. */
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_packet_enlarge_string(struct assh_packet_s *p, uint8_t *str,
|
||||
size_t len, uint8_t **result);
|
||||
|
||||
/** @internal @This reduces the size of a string previously
|
||||
allocated in a packet. The string must be the last allocated thing
|
||||
in the packet when this function is called. */
|
||||
void
|
||||
assh_packet_shrink_string(struct assh_packet_s *p, uint8_t *str,
|
||||
size_t new_len);
|
||||
|
||||
/** @internal @This update the size of the packet using the
|
||||
size header of the string. The string must be the last allocated
|
||||
thing in the packet when this function is called. */
|
||||
void assh_packet_string_resized(struct assh_packet_s *p, uint8_t *str);
|
||||
|
||||
/** @internal @This allocates a string in a packet and writes
|
||||
the given big number in mpint representation as string content. A
|
||||
storage size large enough to store the number may be passed to the
|
||||
function or 0 if it is not known. */
|
||||
assh_error_t ASSH_WARN_UNUSED_RESULT
|
||||
assh_packet_add_mpint(struct assh_context_s *ctx,
|
||||
struct assh_packet_s *p,
|
||||
const struct assh_bignum_s *bn);
|
||||
|
||||
/** @internal @This checks that an array is well inside a
|
||||
buffer. If no error is returned, the @tt next parameter is set to
|
||||
point to the first byte following the array in the buffer. */
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_check_array(const uint8_t *buffer, size_t buffer_len,
|
||||
const uint8_t *array, size_t array_len, uint8_t **next);
|
||||
|
||||
/** @internal @This checks that a string is well inside a
|
||||
buffer. If no error is returned, the @tt next parameter is set to
|
||||
point to the first byte following the string in the buffer. */
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_check_string(const uint8_t *buffer, size_t buffer_len,
|
||||
const uint8_t *str, uint8_t **next);
|
||||
|
||||
/** @internal @This checks that an asn1 DER value is well inside a
|
||||
buffer. If no error is returned, the @tt value parameter is set to
|
||||
point to the first byte of the value and the @tt next parameter is
|
||||
set to point to the first byte in the buffer following the
|
||||
value. Any of these two parameters may be @tt NULL. */
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_check_asn1(const uint8_t *buffer, size_t buffer_len, const uint8_t *str,
|
||||
uint8_t **value, uint8_t **next);
|
||||
|
||||
/** @internal @This checks that a string is well inside packet
|
||||
bounds. @see assh_check_string */
|
||||
ASSH_INLINE ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_packet_check_string(const struct assh_packet_s *p, const uint8_t *str,
|
||||
uint8_t **next)
|
||||
{
|
||||
return assh_check_string(p->data, p->data_size, str, next);
|
||||
}
|
||||
|
||||
/** @internal @This checks that an array is well inside packet
|
||||
bounds. @see assh_check_array */
|
||||
ASSH_INLINE ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_packet_check_array(const struct assh_packet_s *p, const uint8_t *array,
|
||||
size_t array_len, uint8_t **next)
|
||||
{
|
||||
return assh_check_array(p->data, p->data_size, array, array_len, next);
|
||||
}
|
||||
|
||||
/** @internal @This checks that a 32 bits integer is well
|
||||
inside packet bounds and converts the value from network byte
|
||||
order. @see assh_packet_check_array */
|
||||
ASSH_INLINE ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_packet_check_u32(struct assh_packet_s *p, uint32_t *u32,
|
||||
const uint8_t *data, uint8_t **next)
|
||||
{
|
||||
assh_error_t err = assh_packet_check_array(p, data, 4, next);
|
||||
if (!err)
|
||||
*u32 = assh_load_u32(data);
|
||||
return err;
|
||||
}
|
||||
|
||||
/** @internal @This compare two buffers of byte of the same length in
|
||||
constant time. */
|
||||
ASSH_INLINE ASSH_WARN_UNUSED_RESULT assh_bool_t
|
||||
assh_memcmp(const uint8_t *nula, const uint8_t *nulb, size_t len)
|
||||
{
|
||||
assh_bool_t r = 0;
|
||||
while (len--)
|
||||
r |= nula[len] ^ nulb[len];
|
||||
return r;
|
||||
}
|
||||
|
||||
/** @internal @This compares a ssh string with a size header to a @tt
|
||||
NUL terminated string. No bound checking is performed. */
|
||||
ASSH_INLINE ASSH_WARN_UNUSED_RESULT int
|
||||
assh_ssh_string_compare(const uint8_t *ssh_str, const char *nul_str)
|
||||
{
|
||||
size_t l = assh_load_u32(ssh_str);
|
||||
return strncmp((const char*)ssh_str + 4, nul_str, l) || nul_str[l] != '\0';
|
||||
}
|
||||
|
||||
/** @internal @This copies a ssh string to a nul terminated
|
||||
string. An error is returned if the size of the buffer is not
|
||||
large enough to store the string along with its nul terminating
|
||||
byte. */
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_ssh_string_copy(const uint8_t *ssh_str, char *nul_str, size_t max_len);
|
||||
|
||||
/** @internal @This compares the content of an @ref assh_buffer_s
|
||||
object with a nul terminated string. */
|
||||
ASSH_INLINE ASSH_WARN_UNUSED_RESULT uint_fast8_t
|
||||
assh_buffer_strcmp(const struct assh_buffer_s *buf, const char *nul_str)
|
||||
{
|
||||
uint_fast16_t i;
|
||||
for (i = 0; i < buf->len; i++)
|
||||
if (!nul_str[i] || buf->str[i] != nul_str[i])
|
||||
return 1;
|
||||
return nul_str[i];
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,181 @@
|
|||
/*
|
||||
|
||||
libassh - asynchronous ssh2 client/server library.
|
||||
|
||||
Copyright (C) 2013 Alexandre Becoulet <alexandre.becoulet@free.fr>
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
/**
|
||||
@file
|
||||
@short PLatform dependent definitions
|
||||
@internal
|
||||
*/
|
||||
|
||||
#ifndef ASSH_PLATFORM_H_
|
||||
#define ASSH_PLATFORM_H_
|
||||
|
||||
#ifdef __GNUC__
|
||||
# define ASSH_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
|
||||
#else
|
||||
# define ASSH_WARN_UNUSED_RESULT
|
||||
#endif
|
||||
|
||||
#define ASSH_INLINE static inline
|
||||
|
||||
#define CONFIG_ASSH_NONALIGNED_ACCESS
|
||||
|
||||
/** @internal @This stores a 32 bits value in network byte
|
||||
order into a non-aligned location. */
|
||||
ASSH_INLINE void assh_store_u32(uint8_t *s, uint32_t x)
|
||||
{
|
||||
#ifdef CONFIG_ASSH_NONALIGNED_ACCESS
|
||||
*(uint32_t*)s = htonl(x);
|
||||
#else
|
||||
s[0] = x >> 24;
|
||||
s[1] = x >> 16;
|
||||
s[2] = x >> 8;
|
||||
s[3] = x;
|
||||
#endif
|
||||
}
|
||||
|
||||
/** @internal @This stores a 32 bits value in little endian byte
|
||||
order into a non-aligned location. */
|
||||
ASSH_INLINE void assh_store_u32le(uint8_t *s, uint32_t x)
|
||||
{
|
||||
s[3] = x >> 24;
|
||||
s[2] = x >> 16;
|
||||
s[1] = x >> 8;
|
||||
s[0] = x;
|
||||
}
|
||||
|
||||
/** @internal @This stores a 64 bits value in network byte
|
||||
order into a non-aligned location. */
|
||||
ASSH_INLINE void assh_store_u64(uint8_t *s, uint64_t x)
|
||||
{
|
||||
#ifdef CONFIG_ASSH_NONALIGNED_ACCESS
|
||||
*(uint32_t*)(s) = htonl(x >> 32);
|
||||
*(uint32_t*)(s + 4) = htonl(x);
|
||||
#else
|
||||
s[0] = x >> 56;
|
||||
s[1] = x >> 48;
|
||||
s[2] = x >> 40;
|
||||
s[3] = x >> 32;
|
||||
s[4] = x >> 24;
|
||||
s[5] = x >> 16;
|
||||
s[6] = x >> 8;
|
||||
s[7] = x;
|
||||
#endif
|
||||
}
|
||||
|
||||
/** @internal @This stores a 64 bits value in little endian byte
|
||||
order into a non-aligned location. */
|
||||
ASSH_INLINE void assh_store_u64le(uint8_t *s, uint64_t x)
|
||||
{
|
||||
s[7] = x >> 56;
|
||||
s[6] = x >> 48;
|
||||
s[5] = x >> 40;
|
||||
s[4] = x >> 32;
|
||||
s[3] = x >> 24;
|
||||
s[2] = x >> 16;
|
||||
s[1] = x >> 8;
|
||||
s[0] = x;
|
||||
}
|
||||
|
||||
/** @internal @This loads a 32 bits value in network byte
|
||||
order from a non-aligned location. */
|
||||
ASSH_INLINE uint32_t assh_load_u32(const uint8_t *s)
|
||||
{
|
||||
#ifdef CONFIG_ASSH_NONALIGNED_ACCESS
|
||||
return htonl(*(const uint32_t*)s);
|
||||
#else
|
||||
return s[3] + (s[2] << 8) + (s[1] << 16) + (s[0] << 24);
|
||||
#endif
|
||||
}
|
||||
|
||||
/** @internal @This loads a 32 bits value in little endian
|
||||
byte order from a non-aligned location. */
|
||||
ASSH_INLINE uint32_t assh_load_u32le(const uint8_t *s)
|
||||
{
|
||||
return s[0] + (s[1] << 8) + (s[2] << 16) + (s[3] << 24);
|
||||
}
|
||||
|
||||
/** @internal @This loads a 64 bits value in network byte
|
||||
order from a non-aligned location. */
|
||||
ASSH_INLINE uint64_t assh_load_u64(const uint8_t *s)
|
||||
{
|
||||
return ((uint64_t)s[7] << 0) + ((uint64_t)s[6] << 8) +
|
||||
((uint64_t)s[5] << 16) + ((uint64_t)s[4] << 24) +
|
||||
((uint64_t)s[3] << 32) + ((uint64_t)s[2] << 40) +
|
||||
((uint64_t)s[1] << 48) + ((uint64_t)s[0] << 56);
|
||||
}
|
||||
|
||||
/** @internal @This loads a 64 bits value in little endian
|
||||
byte order from a non-aligned location. */
|
||||
ASSH_INLINE uint64_t assh_load_u64le(const uint8_t *s)
|
||||
{
|
||||
return ((uint64_t)s[0] << 0) + ((uint64_t)s[1] << 8) +
|
||||
((uint64_t)s[2] << 16) + ((uint64_t)s[3] << 24) +
|
||||
((uint64_t)s[4] << 32) + ((uint64_t)s[5] << 40) +
|
||||
((uint64_t)s[6] << 48) + ((uint64_t)s[7] << 56);
|
||||
}
|
||||
|
||||
/** @internal @This performs a byte swap of a 32 bits value. */
|
||||
ASSH_INLINE uint32_t assh_swap_u32(uint32_t x)
|
||||
{
|
||||
x = (x << 16) | (x >> 16);
|
||||
x = ((x & 0x00ff00ff) << 8) | ((x & 0xff00ff00) >> 8);
|
||||
return x;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
#define ASSH_MAX(a, b) ({ typeof(a) __a = (a); typeof(b) __b = (b); __a > __b ? __a : __b; })
|
||||
|
||||
/** @internal */
|
||||
#define ASSH_MIN(a, b) ({ typeof(a) __a = (a); typeof(b) __b = (b); __a < __b ? __a : __b; })
|
||||
|
||||
/** @internal */
|
||||
#define ASSH_SWAP(a, b) do { typeof(a) __a = (a); typeof(b) __b = (b); (a) = __b; (b) = __a; } while(0)
|
||||
|
||||
/** @internal */
|
||||
#define ASSH_CLZ8(x) (__builtin_clz((uint8_t)(x)) + 8 - sizeof(int) * 8)
|
||||
/** @internal */
|
||||
#define ASSH_CLZ16(x) (__builtin_clz((uint16_t)(x)) + 16 - sizeof(int) * 8)
|
||||
/** @internal */
|
||||
#define ASSH_CLZ32(x) (__builtin_clzl((uint32_t)(x)) + 32 - sizeof(long) * 8)
|
||||
/** @internal */
|
||||
#define ASSH_CLZ64(x) (__builtin_clzll((uint64_t)(x)) + 64 - sizeof(long long) * 8)
|
||||
|
||||
/** @internal */
|
||||
#define ASSH_CTZ8(x) __builtin_ctz(x)
|
||||
/** @internal */
|
||||
#define ASSH_CTZ16(x) __builtin_ctz(x)
|
||||
/** @internal */
|
||||
#define ASSH_CTZ32(x) __builtin_ctzl(x)
|
||||
/** @internal */
|
||||
#define ASSH_CTZ64(x) __builtin_ctzll(x)
|
||||
|
||||
/** @internal */
|
||||
#define ASSH_ALIGN8(x) ((((x) - 1) | 7) + 1)
|
||||
|
||||
#endif
|
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
|
||||
libassh - asynchronous ssh2 client/server library.
|
||||
|
||||
Copyright (C) 2013 Alexandre Becoulet <alexandre.becoulet@free.fr>
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@file
|
||||
@short Random generator module interface
|
||||
*/
|
||||
|
||||
#ifndef ASSH_PRNG_H_
|
||||
#define ASSH_PRNG_H_
|
||||
|
||||
#ifdef ASSH_EVENT_H_
|
||||
# warning The assh/assh_event.h header should be included after assh_prng.h
|
||||
#endif
|
||||
|
||||
#include "assh_algo.h"
|
||||
#include "assh_context.h"
|
||||
|
||||
/** @This specifies quality of randomly generated data. */
|
||||
enum assh_prng_quality_e
|
||||
{
|
||||
/** weak random data for use in the testsuite */
|
||||
ASSH_PRNG_QUALITY_WEAK,
|
||||
/** random data for use as nonce in signature algorithms */
|
||||
ASSH_PRNG_QUALITY_NONCE,
|
||||
/** random data for use in ephemeral key generation */
|
||||
ASSH_PRNG_QUALITY_EPHEMERAL_KEY,
|
||||
/** random data for use in long term key generation */
|
||||
ASSH_PRNG_QUALITY_LONGTERM_KEY,
|
||||
};
|
||||
|
||||
/** The @ref ASSH_EVENT_PRNG_FEED event is returned when the prng
|
||||
module needs some entropy input. The @ref buf buffer must be
|
||||
updated to point to random data before calling the @ref
|
||||
assh_event_done function. The @ref size field gives the requested
|
||||
amount of random data. */
|
||||
struct assh_event_prng_feed_s
|
||||
{
|
||||
size_t size; //< input/output
|
||||
uint8_t buf[32]; //< output
|
||||
};
|
||||
|
||||
/** @internal */
|
||||
union assh_event_prng_u
|
||||
{
|
||||
struct assh_event_prng_feed_s feed;
|
||||
};
|
||||
|
||||
/** @internal @see assh_prng_init_t */
|
||||
#define ASSH_PRNG_INIT_FCN(n) \
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t (n)(struct assh_context_s *c)
|
||||
|
||||
/** @internal @This defines the function type for the initialization
|
||||
operation of the prng module interface. The prng can store its private
|
||||
data in @ref assh_context_s::prng_pv. */
|
||||
typedef ASSH_PRNG_INIT_FCN(assh_prng_init_t);
|
||||
|
||||
/** @internal @see assh_prng_t */
|
||||
#define ASSH_PRNG_GET_FCN(n) \
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t (n)(struct assh_context_s *c, \
|
||||
uint8_t *rdata, size_t rdata_len, \
|
||||
enum assh_prng_quality_e quality)
|
||||
/** @internal @This defines the function type for the random generation
|
||||
operation of the prng module interface. @see assh_prng_get */
|
||||
typedef ASSH_PRNG_GET_FCN(assh_prng_t);
|
||||
|
||||
/** @internal @see assh_prng_feed_t */
|
||||
#define ASSH_PRNG_FEED_FCN(n) \
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t (n)(struct assh_context_s *c, \
|
||||
const uint8_t *rdata, size_t rdata_len)
|
||||
|
||||
/** @internal @This defines the function type for the entry feed
|
||||
operation of the prng module interface. */
|
||||
typedef ASSH_PRNG_FEED_FCN(assh_prng_feed_t);
|
||||
|
||||
/** @internal @see assh_prng_cleanup_t */
|
||||
#define ASSH_PRNG_CLEANUP_FCN(n) void (n)(struct assh_context_s *c)
|
||||
|
||||
/** @internal @This defines the function type for the cleanup
|
||||
operation of the prng module interface. */
|
||||
typedef ASSH_PRNG_CLEANUP_FCN(assh_prng_cleanup_t);
|
||||
|
||||
/** @internalmembers @This is the prng module interface descriptor
|
||||
structure. */
|
||||
struct assh_prng_s
|
||||
{
|
||||
assh_prng_init_t *f_init;
|
||||
assh_prng_t *f_get;
|
||||
assh_prng_feed_t *f_feed;
|
||||
assh_prng_cleanup_t *f_cleanup;
|
||||
};
|
||||
|
||||
/** @internal @This fills the buffer with random data. */
|
||||
ASSH_INLINE ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_prng_get(struct assh_context_s *c,
|
||||
uint8_t *rdata, size_t rdata_len,
|
||||
enum assh_prng_quality_e quality)
|
||||
{
|
||||
return c->prng->f_get(c, rdata, rdata_len, quality);
|
||||
}
|
||||
|
||||
/** @multiple @This is a prng algorithm implementation descriptor. */
|
||||
extern const struct assh_prng_s assh_prng_xswap;
|
||||
|
||||
#ifdef CONFIG_ASSH_USE_GCRYPT_PRNG
|
||||
extern const struct assh_prng_s assh_prng_gcrypt;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
|
||||
libassh - asynchronous ssh2 client/server library.
|
||||
|
||||
Copyright (C) 2013 Alexandre Becoulet <alexandre.becoulet@free.fr>
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@file
|
||||
@short Linked list container
|
||||
@internal
|
||||
*/
|
||||
|
||||
#ifndef ASSH_QUEUE_H_
|
||||
#define ASSH_QUEUE_H_
|
||||
|
||||
#include "assh.h"
|
||||
|
||||
/** @internal Link list entry */
|
||||
struct assh_queue_entry_s
|
||||
{
|
||||
struct assh_queue_entry_s *next, *prev;
|
||||
};
|
||||
|
||||
/** @internal Link list head */
|
||||
struct assh_queue_s
|
||||
{
|
||||
struct assh_queue_entry_s head;
|
||||
int count;
|
||||
};
|
||||
|
||||
/** @internal */
|
||||
ASSH_INLINE void assh_queue_init(struct assh_queue_s *q)
|
||||
{
|
||||
q->head.next = q->head.prev = &q->head;
|
||||
q->count = 0;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
ASSH_INLINE struct assh_queue_entry_s *
|
||||
assh_queue_front(struct assh_queue_s *q)
|
||||
{
|
||||
return q->head.next == &q->head ? NULL : q->head.next;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
ASSH_INLINE struct assh_queue_entry_s *
|
||||
assh_queue_back(struct assh_queue_s *q)
|
||||
{
|
||||
return q->head.prev == &q->head ? NULL : q->head.prev;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
ASSH_INLINE struct assh_queue_entry_s *
|
||||
assh_queue_next(struct assh_queue_s *q, struct assh_queue_entry_s *e)
|
||||
{
|
||||
return e->next == &q->head ? NULL : e->next;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
ASSH_INLINE struct assh_queue_entry_s *
|
||||
assh_queue_prev(struct assh_queue_s *q, struct assh_queue_entry_s *e)
|
||||
{
|
||||
return e->prev == &q->head ? NULL : e->prev;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
ASSH_INLINE void assh_queue_remove(struct assh_queue_s *q,
|
||||
struct assh_queue_entry_s *e)
|
||||
{
|
||||
e->prev->next = e->next;
|
||||
e->next->prev = e->prev;
|
||||
q->count--;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
ASSH_INLINE void assh_queue_push_front(struct assh_queue_s *q,
|
||||
struct assh_queue_entry_s *b)
|
||||
{
|
||||
struct assh_queue_entry_s *a = &q->head;
|
||||
b->prev = a;
|
||||
a->next->prev = b;
|
||||
b->next = a->next;
|
||||
a->next = b;
|
||||
q->count++;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
ASSH_INLINE void assh_queue_push_back(struct assh_queue_s *q,
|
||||
struct assh_queue_entry_s *b)
|
||||
{
|
||||
struct assh_queue_entry_s *a = &q->head;
|
||||
b->next = a;
|
||||
a->prev->next = b;
|
||||
b->prev = a->prev;
|
||||
a->prev = b;
|
||||
q->count++;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
ASSH_INLINE void assh_queue_concat(struct assh_queue_s *q,
|
||||
struct assh_queue_s *r)
|
||||
{
|
||||
struct assh_queue_entry_s *a = &q->head;
|
||||
struct assh_queue_entry_s *b = &r->head;
|
||||
|
||||
if (r->count == 0)
|
||||
return;
|
||||
|
||||
b->prev->next = a;
|
||||
b->next->prev = a->prev;
|
||||
a->prev->next = b->next;
|
||||
a->prev = b->prev;
|
||||
q->count += r->count;
|
||||
|
||||
b->next = b->prev = b;
|
||||
r->count = 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
|
||||
libassh - asynchronous ssh2 client/server library.
|
||||
|
||||
Copyright (C) 2013 Alexandre Becoulet <alexandre.becoulet@free.fr>
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@file
|
||||
@short SSH service module interface
|
||||
*/
|
||||
|
||||
#ifndef ASSH_SERVICE_H_
|
||||
#define ASSH_SERVICE_H_
|
||||
|
||||
#include "assh_context.h"
|
||||
|
||||
/** @internal @see assh_service_init_t */
|
||||
#define ASSH_SERVICE_INIT_FCN(n) \
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t (n)(struct assh_session_s *s)
|
||||
|
||||
/** @internal @This defines the function type for the initialization
|
||||
operation of the ssh service module interface. This function is
|
||||
called when a service request is successful. This function must
|
||||
set the @ref assh_session_s::srv field and may set the @ref
|
||||
assh_session_s::srv_pv field as well to store its private data. */
|
||||
typedef ASSH_SERVICE_INIT_FCN(assh_service_init_t);
|
||||
|
||||
/** @internal @see assh_service_cleanup_t */
|
||||
#define ASSH_SERVICE_CLEANUP_FCN(n) \
|
||||
void (n)(struct assh_session_s *s)
|
||||
|
||||
/** @internal @This defines the function type for the cleanup
|
||||
operation of the ssh service module interface. This function is
|
||||
called when the service terminates or when the session cleanup
|
||||
occurs. It has to free the resources allocated by the service
|
||||
initialization function and set the @ref assh_session_s::srv and
|
||||
assh_session_s::srv_pv fields to @tt {NULL}. */
|
||||
typedef ASSH_SERVICE_CLEANUP_FCN(assh_service_cleanup_t);
|
||||
|
||||
/** @internal @This defines the function type for event processing of
|
||||
the ssh service module interface. This function is called from the
|
||||
@ref assh_transport_dispatch function when the current state of
|
||||
the transport layer is @ref ASSH_TR_SERVICE, @ref
|
||||
ASSH_TR_SERVICE_KEX or @ref ASSH_TR_FIN.
|
||||
|
||||
A packet may be passed to the function for processing by the
|
||||
running service. If no new received packet is available, the
|
||||
parameter is @tt NULL.
|
||||
|
||||
The function may initialize the passed event object, in this case
|
||||
the event will be reported to the caller of the @ref
|
||||
assh_event_get function.
|
||||
|
||||
The function can return the @ref ASSH_NO_DATA value to indicate
|
||||
that the provided packet has not been processed and must be
|
||||
provided again on the next call. If no event is reported and @ref
|
||||
ASSH_NO_DATA is returned, the function is called again
|
||||
immediately.
|
||||
|
||||
This function should check the current state of the transport
|
||||
layer and report any termination related events when the state is
|
||||
@ref ASSH_TR_FIN. If the function reports no event and return
|
||||
@ref ASSH_OK when the state is @ref ASSH_TR_FIN, the state will
|
||||
change to ASSH_TR_CLOSED and the function will not be called any more. */
|
||||
#define ASSH_SERVICE_PROCESS_FCN(n) assh_error_t (n)(struct assh_session_s *s, \
|
||||
struct assh_packet_s *p, \
|
||||
struct assh_event_s *e)
|
||||
typedef ASSH_SERVICE_PROCESS_FCN(assh_service_process_t);
|
||||
|
||||
/** @This describes the implementation of an ssh service. */
|
||||
struct assh_service_s
|
||||
{
|
||||
const char *name;
|
||||
enum assh_context_type_e side;
|
||||
assh_service_init_t *f_init;
|
||||
assh_service_cleanup_t *f_cleanup;
|
||||
assh_service_process_t *f_process;
|
||||
};
|
||||
|
||||
/** @This function registers a single @ref assh_service_s for use by
|
||||
the given context. @see assh_service_register_va */
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_service_register(struct assh_context_s *c,
|
||||
struct assh_service_s *srv);
|
||||
|
||||
/** @This function registers one or more @ref assh_service_s for use
|
||||
by the given context.
|
||||
|
||||
When registering services onto a client context, the registration
|
||||
order determines the order in which the services will be
|
||||
requested. @see assh_service_register */
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_service_register_va(struct assh_context_s *c, ...);
|
||||
|
||||
/** @This function registers the standard @tt ssh-userauth and @tt
|
||||
ssh-connection services. The appropriate client or server services
|
||||
are used depending on the context type. */
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_service_register_default(struct assh_context_s *c);
|
||||
|
||||
/** @internal */
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_service_got_request(struct assh_session_s *s,
|
||||
struct assh_packet_s *p);
|
||||
|
||||
/** @internal */
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_service_got_accept(struct assh_session_s *s,
|
||||
struct assh_packet_s *p);
|
||||
|
||||
/** @internal */
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_service_send_request(struct assh_session_s *s);
|
||||
|
||||
/** @This lookup a registered service. */
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_service_by_name(struct assh_context_s *c,
|
||||
size_t name_len, const char *name,
|
||||
const struct assh_service_s **srv_);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,203 @@
|
|||
/*
|
||||
|
||||
libassh - asynchronous ssh2 client/server library.
|
||||
|
||||
Copyright (C) 2013 Alexandre Becoulet <alexandre.becoulet@free.fr>
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@file
|
||||
@short Session structure and related functions
|
||||
*/
|
||||
|
||||
#ifndef ASSH_SESSION_H_
|
||||
#define ASSH_SESSION_H_
|
||||
|
||||
#include "assh_transport.h"
|
||||
#include "assh_queue.h"
|
||||
|
||||
/** @internalmembers @This is the session context structure. */
|
||||
struct assh_session_s
|
||||
{
|
||||
/** User private pointer */
|
||||
void *user_pv;
|
||||
|
||||
/** Pointer to associated main context. */
|
||||
struct assh_context_s *ctx;
|
||||
|
||||
/** Current state of the transport layer. */
|
||||
enum assh_transport_state_e tr_st;
|
||||
|
||||
/** Key exchange algorithm. This pointer is setup when the @ref
|
||||
assh_kex_got_init function select a new key exchange algorithm. */
|
||||
const struct assh_algo_kex_s *kex;
|
||||
/** Key exchange private context used during key exchange only. */
|
||||
void *kex_pv;
|
||||
|
||||
/** Pointer to the last key exechange packet sent by client. Valid
|
||||
during key exechange. */
|
||||
struct assh_packet_s *kex_init_local;
|
||||
/** Pointer to the last key exechange packet sent by client. Valid
|
||||
during key exechange. */
|
||||
struct assh_packet_s *kex_init_remote;
|
||||
|
||||
/** amount of data transfered since last kex */
|
||||
uint32_t kex_bytes;
|
||||
|
||||
/** kex re-exchange threshold */
|
||||
uint32_t kex_max_bytes;
|
||||
|
||||
/** This flag indicates if we have to skip the first kex packet from
|
||||
the remote side. */
|
||||
assh_bool_t kex_bad_guess;
|
||||
|
||||
/** Session id is first "exchange hash" H */
|
||||
uint8_t session_id[ASSH_MAX_HASH_SIZE];
|
||||
/** Session id length */
|
||||
size_t session_id_len;
|
||||
|
||||
/** Copy of the ident string sent by the remote host. */
|
||||
uint8_t ident_str[255];
|
||||
/** Size of the ident string sent by the remote host. */
|
||||
int ident_len;
|
||||
|
||||
/** Host keys signature algorithm */
|
||||
const struct assh_algo_sign_s *host_sign_algo;
|
||||
|
||||
#ifdef CONFIG_ASSH_CLIENT
|
||||
/** Index of the next service to request in the context services array. */
|
||||
unsigned int srv_index;
|
||||
/** Requested service. */
|
||||
const struct assh_service_s *srv_rq;
|
||||
#endif
|
||||
/** Current service. */
|
||||
const struct assh_service_s *srv;
|
||||
/** Current service private data. */
|
||||
void *srv_pv;
|
||||
|
||||
/****************** ssh output stream state */
|
||||
|
||||
/** Currrent output ssh stream generator state. */
|
||||
enum assh_stream_out_state_e stream_out_st;
|
||||
|
||||
/** Queue of ssh output packets. Packets in this queue will be
|
||||
enciphered and sent. */
|
||||
struct assh_queue_s out_queue;
|
||||
/** Alternate queue of ssh output packets, used to store services
|
||||
packets during a key exchange. */
|
||||
struct assh_queue_s alt_queue;
|
||||
/** Size of already sent data of the top packet in the @ref out_queue queue. */
|
||||
size_t stream_out_size;
|
||||
|
||||
/** Pointer to output keys and algorithms in current use. */
|
||||
struct assh_kex_keys_s *cur_keys_out;
|
||||
/** Pointer to next output keys and algorithms on SSH_MSG_NEWKEYS transmitted. */
|
||||
struct assh_kex_keys_s *new_keys_out;
|
||||
/** Output packet sequence number */
|
||||
uint32_t out_seq;
|
||||
|
||||
/****************** ssh input stream state */
|
||||
|
||||
/** Current input ssh stream parser state. */
|
||||
enum assh_stream_in_state_e stream_in_st;
|
||||
|
||||
/** Current input ssh stream header buffer. */
|
||||
uint8_t stream_in_pck_head[ASSH_MAX_BLOCK_SIZE];
|
||||
/** Current input ssh stream packet. This packet is currently being
|
||||
read from the input ssh stream and has not yet been deciphered. */
|
||||
struct assh_packet_s *stream_in_pck;
|
||||
/** Size of valid data in the @ref stream_in_pck packet */
|
||||
size_t stream_in_size;
|
||||
|
||||
/** Current ssh input packet. This packet is the last deciphered
|
||||
packets and is waiting for dispatch and processing. */
|
||||
struct assh_packet_s *in_pck;
|
||||
|
||||
/** Pointer to input keys and algorithms in current use. */
|
||||
struct assh_kex_keys_s *cur_keys_in;
|
||||
/** Pointer to next input keys and algorithms on SSH_MSG_NEWKEYS received. */
|
||||
struct assh_kex_keys_s *new_keys_in;
|
||||
/** Input packet sequence number */
|
||||
uint32_t in_seq;
|
||||
};
|
||||
|
||||
/** @This set the user private pointer of the session. */
|
||||
ASSH_INLINE void
|
||||
assh_session_set_pv(struct assh_session_s *ctx,
|
||||
void *private)
|
||||
{
|
||||
ctx->user_pv = private;
|
||||
}
|
||||
|
||||
/** @This get the user private pointer of the session. */
|
||||
ASSH_INLINE void *
|
||||
assh_session_get_pv(struct assh_session_s *ctx)
|
||||
{
|
||||
return ctx->user_pv;
|
||||
}
|
||||
|
||||
/** @internal This changes the current transport state */
|
||||
ASSH_INLINE void assh_transport_state(struct assh_session_s *s,
|
||||
enum assh_transport_state_e st)
|
||||
{
|
||||
#ifdef CONFIG_ASSH_DEBUG_PROTOCOL
|
||||
ASSH_DEBUG("transport state=%u\n", st);
|
||||
#endif
|
||||
s->tr_st = st;
|
||||
}
|
||||
|
||||
/** @This initializes a new ssh session object. When a stable ABI is
|
||||
needed, use the @ref assh_context_create function instead. This
|
||||
can be used to initialize a statically allocated session
|
||||
object. The @tt alloc parameter may be @tt NULL. */
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_session_init(struct assh_context_s *c,
|
||||
struct assh_session_s *s);
|
||||
|
||||
/** @This allocates and initializes a ssh session. The @tt alloc
|
||||
parameter may be @tt NULL. @see assh_session_init */
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_session_create(struct assh_context_s *c,
|
||||
struct assh_session_s **s);
|
||||
|
||||
/** @This cleanups a ssh session object. */
|
||||
void assh_session_cleanup(struct assh_session_s *s);
|
||||
|
||||
/** @This cleanups and releases a session created by the @ref
|
||||
assh_session_create function. */
|
||||
void assh_session_release(struct assh_session_s *s);
|
||||
|
||||
/** @internal This changes the session state according to the provided
|
||||
error code and associated severity level.
|
||||
|
||||
This function returns the original error code but the error
|
||||
severity level may be increased. This function is responsible for
|
||||
sending the session close message to the remote hsot.
|
||||
|
||||
This function is called from the @ref assh_event_get, @ref
|
||||
assh_event_done and @ref assh_event_table_run functions. It is
|
||||
also called from other functions of the public API which can
|
||||
modify the session state.
|
||||
|
||||
@see assh_error_e @see assh_error_severity_e
|
||||
*/
|
||||
assh_error_t assh_session_error(struct assh_session_s *s, assh_error_t err);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,154 @@
|
|||
/*
|
||||
|
||||
libassh - asynchronous ssh2 client/server library.
|
||||
|
||||
Copyright (C) 2013 Alexandre Becoulet <alexandre.becoulet@free.fr>
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@file
|
||||
@short SSH signature module interface
|
||||
*/
|
||||
|
||||
#ifndef ASSH_SIGN_H_
|
||||
#define ASSH_SIGN_H_
|
||||
|
||||
#include "assh_algo.h"
|
||||
#include "assh_key.h"
|
||||
|
||||
/** @internal @see assh_sign_generate_t */
|
||||
#define ASSH_SIGN_GENERATE_FCN(n) ASSH_WARN_UNUSED_RESULT assh_error_t(n) \
|
||||
(struct assh_context_s *c, \
|
||||
const struct assh_key_s *key, size_t data_count, \
|
||||
const uint8_t * const data[], size_t const data_len[], \
|
||||
uint8_t *sign, size_t *sign_len)
|
||||
|
||||
/** @internal @This defines the function type for the signature
|
||||
generation operation of the signature module interface.
|
||||
@see assh_sign_generate */
|
||||
typedef ASSH_SIGN_GENERATE_FCN(assh_sign_generate_t);
|
||||
|
||||
/** @internal @see assh_sign_check_t */
|
||||
#define ASSH_SIGN_CHECK_FCN(n) ASSH_WARN_UNUSED_RESULT assh_error_t (n) \
|
||||
(struct assh_context_s *c, \
|
||||
const struct assh_key_s *key, size_t data_count, \
|
||||
const uint8_t * const data[], size_t const data_len[], \
|
||||
const uint8_t *sign, size_t sign_len)
|
||||
|
||||
/** @internal @This defines the function type for the signature
|
||||
checking operation of the signature module interface.
|
||||
@see assh_sign_check */
|
||||
typedef ASSH_SIGN_CHECK_FCN(assh_sign_check_t);
|
||||
|
||||
|
||||
struct assh_algo_sign_s
|
||||
{
|
||||
struct assh_algo_s algo;
|
||||
assh_sign_generate_t *f_generate;
|
||||
assh_sign_check_t *f_check;
|
||||
};
|
||||
|
||||
/** @internal @This computes the signature of the passed data using
|
||||
the provided key then writes it to the @tt sign buffer. The @tt
|
||||
sign_len parameter indicates the size of the buffer and is updated
|
||||
with the actual size of the signature blob.
|
||||
|
||||
The data to sign can be split into multiple buffers. The @tt
|
||||
data_count parameter must specify the number of data buffers to use.
|
||||
|
||||
If the @tt sign parameter is @tt NULL, the function updates the
|
||||
@tt sign_len parmeter with a size value which is greater or equal
|
||||
to what is needed to hold the signature blob. In this case, the
|
||||
@tt data_* parameters are not used. */
|
||||
ASSH_INLINE ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_sign_generate(struct assh_context_s *c, const struct assh_algo_sign_s *algo,
|
||||
const struct assh_key_s *key, size_t data_count,
|
||||
const uint8_t * const data[], size_t const data_len[],
|
||||
uint8_t *sign, size_t *sign_len)
|
||||
{
|
||||
return algo->f_generate(c, key, data_count, data, data_len, sign, sign_len);
|
||||
}
|
||||
|
||||
/** @internal @This checks the signature of the passed data using the
|
||||
provided key. The data can be split into multiple buffers. The @tt
|
||||
data_count parameter must specify the number of data buffers used. */
|
||||
ASSH_INLINE ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_sign_check(struct assh_context_s *c, const struct assh_algo_sign_s *algo,
|
||||
const struct assh_key_s *key, size_t data_count,
|
||||
const uint8_t * const data[], size_t const data_len[],
|
||||
const uint8_t *sign, size_t sign_len)
|
||||
{
|
||||
return algo->f_check(c, key, data_count, data, data_len, sign, sign_len);
|
||||
}
|
||||
|
||||
/** Dummy signature algorithm */
|
||||
extern const struct assh_algo_sign_s assh_sign_none;
|
||||
|
||||
/** Use SHA1 and a dsa key with L = 1024 and N = 160. */
|
||||
extern const struct assh_algo_sign_s assh_sign_dsa;
|
||||
|
||||
/** Use SHA224 and a dsa key with L >= 2048 and N = 224. */
|
||||
extern const struct assh_algo_sign_s assh_sign_dsa2048_sha224;
|
||||
|
||||
/** Use SHA256 and a dsa key with L >= 2048 and N = 256. */
|
||||
extern const struct assh_algo_sign_s assh_sign_dsa2048_sha256;
|
||||
|
||||
/** Use SHA256 and a dsa key with L >= 3072 and N = 256. */
|
||||
extern const struct assh_algo_sign_s assh_sign_dsa3072_sha256;
|
||||
|
||||
/** Accept sha* and md5 RSA signatures, generate sha1 signatures.
|
||||
Reject keys with modulus size less than 768 bits. */
|
||||
extern const struct assh_algo_sign_s assh_sign_rsa_sha1_md5;
|
||||
|
||||
/** Accept sha* RSA signatures, generate sha1 signatures,
|
||||
Reject keys with modulus size less than 1024 bits. */
|
||||
extern const struct assh_algo_sign_s assh_sign_rsa_sha1;
|
||||
|
||||
/** Accept sha* RSA signatures, generate sha1 signatures.
|
||||
Reject keys with modulus size less than 2048 bits. */
|
||||
extern const struct assh_algo_sign_s assh_sign_rsa_sha1_2048;
|
||||
|
||||
/** Accept sha2, RSA signatures, generate sha256 signatures.
|
||||
Reject keys with modulus size less than 2048 bits. */
|
||||
extern const struct assh_algo_sign_s assh_sign_rsa_sha256_2048;
|
||||
|
||||
/** Accept sha2 RSA signatures, generate sha256 signatures.
|
||||
Reject keys with modulus size less than 3072 bits. */
|
||||
extern const struct assh_algo_sign_s assh_sign_rsa_sha256_3072;
|
||||
|
||||
/** The ssh-ed25519 algorithm as implemented by openssh. This offerrs
|
||||
125 bits security and relies on an Edward elliptic curve.
|
||||
|
||||
See @url {http://safecurves.cr.yp.to/} */
|
||||
extern const struct assh_algo_sign_s assh_sign_ed25519;
|
||||
|
||||
/** Same algorithm as @ref assh_sign_ed25519 with the stronger E382
|
||||
edward curve and the shake256 hash function.
|
||||
|
||||
See @url {http://safecurves.cr.yp.to/} */
|
||||
extern const struct assh_algo_sign_s assh_sign_eddsa_e382;
|
||||
|
||||
/** Same algorithm as @ref assh_sign_ed25519 with the stronger E521
|
||||
edward curve and the shake256 hash function.
|
||||
|
||||
See @url {http://safecurves.cr.yp.to/} */
|
||||
extern const struct assh_algo_sign_s assh_sign_eddsa_e521;
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,154 @@
|
|||
/*
|
||||
|
||||
libassh - asynchronous ssh2 client/server library.
|
||||
|
||||
Copyright (C) 2013 Alexandre Becoulet <alexandre.becoulet@free.fr>
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@file
|
||||
@short SSH transport layer protocol (rfc4253)
|
||||
*/
|
||||
|
||||
#ifndef ASSH_TRANSPORT_H_
|
||||
#define ASSH_TRANSPORT_H_
|
||||
|
||||
#ifdef ASSH_EVENT_H_
|
||||
# warning The assh/assh_event.h header should be included after assh_transport.h
|
||||
#endif
|
||||
|
||||
#include "assh.h"
|
||||
|
||||
/** @internal @This specifies the transport status of an ssh session. */
|
||||
enum assh_transport_state_e
|
||||
{
|
||||
/** send a @ref SSH_MSG_KEXINIT packet then go to @ref ASSH_TR_KEX_WAIT */
|
||||
ASSH_TR_KEX_INIT,
|
||||
/** We wait for a @ref SSH_MSG_KEXINIT packet. */
|
||||
ASSH_TR_KEX_WAIT,
|
||||
/** Both @ref SSH_MSG_KEXINIT packet were sent, the key exchange is taking place. */
|
||||
ASSH_TR_KEX_RUNNING,
|
||||
/** The key exchange is over and a @ref SSH_MSG_NEWKEYS packet is expected. */
|
||||
ASSH_TR_NEWKEY,
|
||||
/** No key exchange is running, service packets are allowed. */
|
||||
ASSH_TR_SERVICE,
|
||||
/** Key re-exchange packet sent but not received, service packets are allowed. */
|
||||
ASSH_TR_SERVICE_KEX,
|
||||
/** Do not exchange packets with the remote side anymore. Report last events. */
|
||||
ASSH_TR_FIN,
|
||||
/** Session closed, no more event will be reported. */
|
||||
ASSH_TR_CLOSED,
|
||||
};
|
||||
|
||||
/** @internal @This specifies state of the input stream parser */
|
||||
enum assh_stream_in_state_e
|
||||
{
|
||||
ASSH_TR_IN_IDENT,
|
||||
ASSH_TR_IN_IDENT_DONE,
|
||||
ASSH_TR_IN_HEAD,
|
||||
ASSH_TR_IN_HEAD_DONE,
|
||||
ASSH_TR_IN_PAYLOAD,
|
||||
ASSH_TR_IN_PAYLOAD_DONE,
|
||||
};
|
||||
|
||||
/** @internal @This specifies state of the output stream generator */
|
||||
enum assh_stream_out_state_e
|
||||
{
|
||||
ASSH_TR_OUT_IDENT,
|
||||
ASSH_TR_OUT_IDENT_PAUSE,
|
||||
ASSH_TR_OUT_IDENT_DONE,
|
||||
ASSH_TR_OUT_PACKETS,
|
||||
ASSH_TR_OUT_PACKETS_ENCIPHERED,
|
||||
ASSH_TR_OUT_PACKETS_PAUSE,
|
||||
ASSH_TR_OUT_PACKETS_DONE,
|
||||
};
|
||||
|
||||
/** The @ref ASSH_EVENT_READ event is reported in order to gather
|
||||
incoming ssh stream data from the remote host.
|
||||
|
||||
The @ref buf field have to be filled with incoming data
|
||||
stream. The @ref assh_event_done function must be called once the
|
||||
data have been copied to the buffer and the @ref transferred field
|
||||
have been set to the amount of available data.
|
||||
|
||||
If not enough data is available, it's ok to provide less than
|
||||
requested or even no data. The buffer will be provided again the
|
||||
next time this event is reported.
|
||||
*/
|
||||
struct assh_event_transport_read_s
|
||||
{
|
||||
ASSH_EV_CONST struct assh_buffer_s buf; //< input
|
||||
size_t transferred; //< output
|
||||
};
|
||||
|
||||
/** The @ref ASSH_EVENT_WRITE event is reported when some ssh stream
|
||||
data is available for sending to the remote host. The @ref buf
|
||||
field provides a buffer which contain the output data. The @ref
|
||||
transferred field must be set to the amount of data sent. The @ref
|
||||
assh_event_done function can then be called once the output data
|
||||
have been sent so that the packet buffer is released.
|
||||
|
||||
It's ok to set the @ref transferred field to a value less than the
|
||||
buffer size. If no data at all can be sent, the default value of
|
||||
the field can be left untouched. The buffer will remain valid and
|
||||
will be provided again the next time this event is returned.
|
||||
*/
|
||||
struct assh_event_transport_write_s
|
||||
{
|
||||
ASSH_EV_CONST struct assh_buffer_s buf; //< input
|
||||
size_t transferred; //< output
|
||||
};
|
||||
|
||||
/** @internal */
|
||||
union assh_event_transport_u
|
||||
{
|
||||
struct assh_event_transport_read_s read;
|
||||
struct assh_event_transport_write_s write;
|
||||
};
|
||||
|
||||
/** @internal This function puts a packet in the output queue. The
|
||||
packet will be released once it has been enciphered and sent. */
|
||||
void assh_transport_push(struct assh_session_s *s,
|
||||
struct assh_packet_s *p);
|
||||
|
||||
/** @internal This function executes the transport output FSM code
|
||||
which enciphers packets and builds the output stream. It may
|
||||
report the @ref ASSH_EVENT_READ event. It is called from the @ref
|
||||
assh_event_get function. */
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_transport_write(struct assh_session_s *s,
|
||||
struct assh_event_s *e);
|
||||
|
||||
/** @internal This function executes the transport input FSM code
|
||||
which extracts packets from the stream and decipher them. It may
|
||||
report the @ref ASSH_EVENT_WRITE event. It is called from the @ref
|
||||
assh_event_get function. */
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_transport_read(struct assh_session_s *s,
|
||||
struct assh_event_s *e);
|
||||
|
||||
/** @internal This function dispatches incoming packets depending on
|
||||
packet message id and transport layer state. It is called from the
|
||||
@ref assh_event_get function. */
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_transport_dispatch(struct assh_session_s *s,
|
||||
struct assh_event_s *e);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
|
||||
libassh - asynchronous ssh2 client/server library.
|
||||
|
||||
Copyright (C) 2013 Alexandre Becoulet <alexandre.becoulet@free.fr>
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@file
|
||||
@short Implementation of the client side ssh-userauth service (rfc4252)
|
||||
|
||||
This header file defines events which are reported to the
|
||||
application when the client side @tt ssh-userauth service is
|
||||
running.
|
||||
|
||||
This standard service described in rfc4252 is implemented as a
|
||||
pluggable service module for libassh.
|
||||
*/
|
||||
|
||||
#ifndef ASSH_SRV_USERAUTH_CLIENT_H_
|
||||
#define ASSH_SRV_USERAUTH_CLIENT_H_
|
||||
|
||||
#ifdef ASSH_EVENT_H_
|
||||
# warning The assh/assh_event.h header should be included after assh_userauth_client.h
|
||||
#endif
|
||||
|
||||
#include "assh.h"
|
||||
|
||||
/** This event is reported when the client-side user authentication
|
||||
service is running and the service needs to provide a user name
|
||||
to the server.
|
||||
|
||||
@see ASSH_EVENT_USERAUTH_CLIENT_USER
|
||||
*/
|
||||
struct assh_event_userauth_client_user_s
|
||||
{
|
||||
struct assh_buffer_s username; //< output
|
||||
};
|
||||
|
||||
/** This event is reported when the client-side user authentication
|
||||
service is running. The @ref use_password and @ref use_pub_key
|
||||
fields indicate the authentication methods that are accepted by
|
||||
the server.
|
||||
|
||||
The @ref password and @ref pub_keys fields are initially set to
|
||||
@tt NULL and can be modified to enable one or more authentication
|
||||
methods among those supported.
|
||||
|
||||
The @ref pub_keys linked list can be populated by calling either
|
||||
the @ref assh_key_load, @ref assh_load_key_file or @ref
|
||||
assh_load_key_filename functions. Multiple keys can be loaded. The
|
||||
assh library will take care of releasing the provided keys.
|
||||
|
||||
This event may be reported multiple times until the authentication
|
||||
is successful. The authentication fails if no password or key is
|
||||
provided.
|
||||
|
||||
@see ASSH_EVENT_USERAUTH_CLIENT_METHODS
|
||||
*/
|
||||
struct assh_event_userauth_client_methods_s
|
||||
{
|
||||
ASSH_EV_CONST assh_bool_t use_password; //< input
|
||||
ASSH_EV_CONST assh_bool_t use_pub_key; //< input
|
||||
struct assh_buffer_s password; //< output
|
||||
const struct assh_key_s *pub_keys; //< output
|
||||
};
|
||||
|
||||
/** @This contains all client side user authentication related events */
|
||||
union assh_event_userauth_client_u
|
||||
{
|
||||
struct assh_event_userauth_client_user_s user;
|
||||
struct assh_event_userauth_client_methods_s methods;
|
||||
};
|
||||
|
||||
/** @This implements the standard client side @tt ssh-userauth service. */
|
||||
extern const struct assh_service_s assh_service_userauth_client;
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
|
||||
libassh - asynchronous ssh2 client/server library.
|
||||
|
||||
Copyright (C) 2013 Alexandre Becoulet <alexandre.becoulet@free.fr>
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@file
|
||||
@short Implementation of the server side ssh-userauth service (rfc4252)
|
||||
|
||||
This header file defines events which are reported to the
|
||||
application when the server side @tt ssh-userauth service is
|
||||
running.
|
||||
|
||||
This standard service described in rfc4252 is implemented as a
|
||||
pluggable service module for libassh.
|
||||
*/
|
||||
|
||||
#ifndef ASSH_SRV_USERAUTH_SERVER_H_
|
||||
#define ASSH_SRV_USERAUTH_SERVER_H_
|
||||
|
||||
#ifdef ASSH_EVENT_H_
|
||||
# warning The assh/assh_event.h header should be included after assh_userauth_server.h
|
||||
#endif
|
||||
|
||||
#include "assh.h"
|
||||
|
||||
/** This event is reported when the server-side user authentication
|
||||
service is running. The user public key @tt pub_key must be
|
||||
searched in the list of authorized keys for the user on this
|
||||
server. The @tt found field must be updated accordingly before
|
||||
calling the @ref assh_event_done function.
|
||||
@see ASSH_EVENT_USERAUTH_SERVER_USERKEY */
|
||||
struct assh_event_userauth_server_userkey_s
|
||||
{
|
||||
ASSH_EV_CONST struct assh_buffer_s username;
|
||||
const struct assh_key_s * ASSH_EV_CONST pub_key;
|
||||
assh_bool_t found;
|
||||
};
|
||||
|
||||
/** This event is reported when the server-side user authentication
|
||||
service is running. The user name and password pair must be
|
||||
checked and the @tt success field must be updated accordingly
|
||||
before calling the @ref assh_event_done function. @see
|
||||
ASSH_EVENT_USERAUTH_SERVER_PASSWORD */
|
||||
struct assh_event_userauth_server_password_s
|
||||
{
|
||||
ASSH_EV_CONST struct assh_buffer_s username;
|
||||
ASSH_EV_CONST struct assh_buffer_s password;
|
||||
assh_bool_t success;
|
||||
};
|
||||
|
||||
/** @This contains all server side user authentication related events */
|
||||
union assh_event_userauth_server_u
|
||||
{
|
||||
struct assh_event_userauth_server_userkey_s userkey;
|
||||
struct assh_event_userauth_server_password_s password;
|
||||
};
|
||||
|
||||
/** @This implements the standard server side @tt ssh-userauth service. */
|
||||
extern const struct assh_service_s assh_service_userauth_server;
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
|
||||
libassh - asynchronous ssh2 client/server library.
|
||||
|
||||
Copyright (C) 2013 Alexandre Becoulet <alexandre.becoulet@free.fr>
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef ASSH_HELPER_FD_H_
|
||||
#define ASSH_HELPER_FD_H_
|
||||
|
||||
#include "assh_event.h"
|
||||
|
||||
struct assh_fd_context_s
|
||||
{
|
||||
int ssh_fd;
|
||||
int rand_fd;
|
||||
|
||||
struct assh_event_hndl_s h_read;
|
||||
struct assh_event_hndl_s h_write;
|
||||
struct assh_event_hndl_s h_prng_feed;
|
||||
};
|
||||
|
||||
void assh_fd_events_register(struct assh_event_hndl_table_s *t,
|
||||
struct assh_fd_context_s *ctx,
|
||||
int ssh_fd, int rand_fd);
|
||||
|
||||
ASSH_EVENT_HANDLER_FCN(assh_fd_event_read);
|
||||
ASSH_EVENT_HANDLER_FCN(assh_fd_event_write);
|
||||
ASSH_EVENT_HANDLER_FCN(assh_fd_event_prng_feed);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
|
||||
libassh - asynchronous ssh2 client/server library.
|
||||
|
||||
Copyright (C) 2013 Alexandre Becoulet <alexandre.becoulet@free.fr>
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@file
|
||||
@short SSH keys loaders
|
||||
*/
|
||||
|
||||
#ifndef ASSH_HELPER_KEY_H_
|
||||
#define ASSH_HELPER_KEY_H_
|
||||
|
||||
#include "assh_sign.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/** @internal @This loads a key from a file handle and inserts the key
|
||||
in a linked list. Both binary and text key formats are
|
||||
supported. This function relies on @ref assh_key_load to load the
|
||||
binary key blob. */
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_load_key_file(struct assh_context_s *c,
|
||||
const struct assh_key_s **head,
|
||||
const struct assh_key_ops_s *algo,
|
||||
enum assh_algo_class_e role,
|
||||
FILE *file, enum assh_key_format_e format);
|
||||
|
||||
/** @internal @This loads a key from a file name and inserts the key
|
||||
in a linked list. This function relies on @ref
|
||||
assh_load_key_file. */
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_load_key_filename(struct assh_context_s *c,
|
||||
const struct assh_key_s **head,
|
||||
const struct assh_key_ops_s *algo,
|
||||
enum assh_algo_class_e role,
|
||||
const char *filename,
|
||||
enum assh_key_format_e format);
|
||||
|
||||
/** @This loads a key from a file handler and register the key on the
|
||||
library context. @see assh_load_key_file */
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_load_hostkey_file(struct assh_context_s *c,
|
||||
const struct assh_key_ops_s *algo,
|
||||
enum assh_algo_class_e role,
|
||||
FILE *file,
|
||||
enum assh_key_format_e format);
|
||||
|
||||
/** @This loads a key from a file name and register the key on the
|
||||
library context. @see assh_load_key_filename */
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_load_hostkey_filename(struct assh_context_s *c,
|
||||
const struct assh_key_ops_s *algo,
|
||||
enum assh_algo_class_e role,
|
||||
const char *filename,
|
||||
enum assh_key_format_e format);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
|
||||
libassh - asynchronous ssh2 client/server library.
|
||||
|
||||
Copyright (C) 2013 Alexandre Becoulet <alexandre.becoulet@free.fr>
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@file
|
||||
@short Key support for the Digitial Signature Algorithm
|
||||
@internal
|
||||
*/
|
||||
|
||||
#ifndef ASSH_KEY_DSA_H_
|
||||
#define ASSH_KEY_DSA_H_
|
||||
|
||||
#include <assh/assh_key.h>
|
||||
#include <assh/assh_bignum.h>
|
||||
|
||||
/** @internal DSA key storage */
|
||||
struct assh_key_dsa_s
|
||||
{
|
||||
struct assh_key_s key;
|
||||
/** public p */
|
||||
struct assh_bignum_s pn;
|
||||
/** public q */
|
||||
struct assh_bignum_s qn;
|
||||
/** public g */
|
||||
struct assh_bignum_s gn;
|
||||
/** public y */
|
||||
struct assh_bignum_s yn;
|
||||
/** private x, may be empty */
|
||||
struct assh_bignum_s xn;
|
||||
};
|
||||
|
||||
ASSH_FIRST_FIELD_ASSERT(assh_key_dsa_s, key);
|
||||
|
||||
/** @internal Key operations descriptor for DSA keys */
|
||||
extern const struct assh_key_ops_s assh_key_dsa;
|
||||
|
||||
/** @internal */
|
||||
#define ASSH_DSA_ID "\x00\x00\x00\x07ssh-dss"
|
||||
/** @internal */
|
||||
#define ASSH_DSA_ID_LEN (sizeof(ASSH_DSA_ID) - 1)
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,164 @@
|
|||
/*
|
||||
|
||||
libassh - asynchronous ssh2 client/server library.
|
||||
|
||||
Copyright (C) 2013 Alexandre Becoulet <alexandre.becoulet@free.fr>
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@file
|
||||
@short Key support for the EdDSA signature algorithm
|
||||
@internal
|
||||
*/
|
||||
|
||||
#ifndef ASSH_KEY_EDDSA_H_
|
||||
#define ASSH_KEY_EDDSA_H_
|
||||
|
||||
#include <assh/assh_key.h>
|
||||
#include <assh/assh_bignum.h>
|
||||
|
||||
/** @internal Edward elliptic curve parameters decriptor.
|
||||
@em {a*x^2+y^2 = 1+d*x^2y^2} */
|
||||
struct assh_edward_curve_s
|
||||
{
|
||||
const uint8_t *p;
|
||||
const uint8_t *l; /* order */
|
||||
const uint8_t *bx; /* basepoint x */
|
||||
const uint8_t *by; /* basepoint y */
|
||||
const uint8_t *a;
|
||||
const uint8_t *d;
|
||||
const uint8_t *i; /* sqrt(-1), used when p%8 == 5 */
|
||||
size_t bits;
|
||||
uint_fast8_t cofactor;
|
||||
};
|
||||
|
||||
/** @internal EdDSA key storage */
|
||||
struct assh_key_eddsa_s
|
||||
{
|
||||
struct assh_key_s key;
|
||||
|
||||
const struct assh_edward_curve_s *curve;
|
||||
const struct assh_hash_algo_s *hash;
|
||||
|
||||
assh_bool_t private;
|
||||
|
||||
/** public + secret key data */
|
||||
uint8_t data[0];
|
||||
};
|
||||
|
||||
ASSH_FIRST_FIELD_ASSERT(assh_key_eddsa_s, key);
|
||||
|
||||
/** @multiple @internal Key operations descriptor for EdDSA keys */
|
||||
extern const struct assh_key_ops_s assh_key_ed25519;
|
||||
extern const struct assh_key_ops_s assh_key_eddsa_e382;
|
||||
extern const struct assh_key_ops_s assh_key_eddsa_e521;
|
||||
|
||||
/** @multiple @internal Edward curve parameters */
|
||||
extern const struct assh_edward_curve_s assh_ed25519_curve;
|
||||
extern const struct assh_edward_curve_s assh_e382_curve;
|
||||
extern const struct assh_edward_curve_s assh_e521_curve;
|
||||
|
||||
/** @internal Adjust blob for use with edward curvre */
|
||||
ASSH_INLINE void
|
||||
assh_edward_adjust(const struct assh_edward_curve_s *curve, uint8_t *blob)
|
||||
{
|
||||
uint_fast8_t i = (8 - curve->bits) & 7;
|
||||
uint_fast8_t j = (curve->bits - 1) / 8;
|
||||
|
||||
blob[0] -= blob[0] % curve->cofactor;
|
||||
blob[j] &= 0xff >> i;
|
||||
blob[j] |= 0x80 >> i;
|
||||
}
|
||||
|
||||
/** @internal Edward curve point encoding */
|
||||
ASSH_INLINE void
|
||||
assh_edward_encode(const struct assh_edward_curve_s *curve,
|
||||
uint8_t y[], const uint8_t x[])
|
||||
{
|
||||
uint_fast8_t j = (curve->bits - 1) / 8;
|
||||
y[j] |= ((x[0] & 1) << 7);
|
||||
}
|
||||
|
||||
/** @internal addition on twisted edward curve, projective
|
||||
coordinate. 20 ops */
|
||||
#define ASSH_BOP_TEDWARD_PADD(X3, Y3, Z3, X1, Y1, Z1, \
|
||||
X2, Y2, Z2, T0, T1, A, D, P) \
|
||||
/* A = Z1*Z2 */ \
|
||||
ASSH_BOP_MULM( Z3, Z1, Z2, P ), \
|
||||
/* I = (X1+Y1)*(X2+Y2) */ \
|
||||
ASSH_BOP_ADDM( T0, X1, Y1, P ), \
|
||||
ASSH_BOP_ADDM( T1, X2, Y2, P ), \
|
||||
ASSH_BOP_MULM( T0, T0, T1, P ), \
|
||||
/* C = X1*X2 */ \
|
||||
ASSH_BOP_MULM( X3, X1, X2, P ), \
|
||||
/* D = Y1*Y2 */ \
|
||||
ASSH_BOP_MULM( Y3, Y1, Y2, P ), \
|
||||
/* E = d*C*D */ \
|
||||
ASSH_BOP_MULM( T1, X3, Y3, P ), \
|
||||
ASSH_BOP_MULM( T1, T1, D , P ), \
|
||||
/* H = A*(I-C-D) */ \
|
||||
ASSH_BOP_SUBM( T0, T0, X3, P ), \
|
||||
ASSH_BOP_SUBM( T0, T0, Y3, P ), \
|
||||
ASSH_BOP_MULM( T0, T0, Z3, P ), \
|
||||
/* J = (D-a*C)*A */ \
|
||||
ASSH_BOP_MULM( X3, X3, A, P ), \
|
||||
ASSH_BOP_SUBM( Y3, Y3, X3, P ), \
|
||||
ASSH_BOP_MULM( Y3, Y3, Z3, P ), \
|
||||
/* F = A*A - E */ \
|
||||
ASSH_BOP_MULM( Z3, Z3, Z3, P ), \
|
||||
ASSH_BOP_SUBM( X3, Z3, T1, P ), \
|
||||
/* G = A*A + E */ \
|
||||
ASSH_BOP_ADDM( Z3, Z3, T1, P ), \
|
||||
/* Y3 = G*J */ \
|
||||
ASSH_BOP_MULM( Y3, Y3, Z3, P ), \
|
||||
/* Z3 = F*G */ \
|
||||
ASSH_BOP_MULM( Z3, Z3, X3, P ), \
|
||||
/* X3 = F*H */ \
|
||||
ASSH_BOP_MULM( X3, X3, T0, P )
|
||||
|
||||
/** @internal doubling on twisted edward curve, projective
|
||||
coordinate. 15 ops */
|
||||
#define ASSH_BOP_TEDWARD_PDBL(X3, Y3, Z3, X1, Y1, Z1, T0, T1, P)\
|
||||
/* C = X1^2 */ \
|
||||
ASSH_BOP_MULM( X3, X1, X1, P ), \
|
||||
/* D = Y1^2 */ \
|
||||
ASSH_BOP_MULM( Y3, Y1, Y1, P ), \
|
||||
/* B = (X1+Y1)^2-C-D */ \
|
||||
ASSH_BOP_ADDM( T0, X1, Y1, P ), \
|
||||
ASSH_BOP_MULM( T0, T0, T0, P ), \
|
||||
ASSH_BOP_SUBM( T0, T0, X3, P ), \
|
||||
ASSH_BOP_SUBM( T0, T0, Y3, P ), \
|
||||
/* E = a*C */ \
|
||||
ASSH_BOP_MULM( X3, X3, A, P ), \
|
||||
/* F = E+D */ \
|
||||
ASSH_BOP_ADDM( Z3, X3, Y3, P ), \
|
||||
/* Y3 = F*(E-D) */ \
|
||||
ASSH_BOP_SUBM( Y3, X3, Y3, P ), \
|
||||
ASSH_BOP_MULM( Y3, Z3, Y3, P ), \
|
||||
/* J = F-2*Z1^2 */ \
|
||||
ASSH_BOP_MULM( T1, Z1, Z1, P ), \
|
||||
ASSH_BOP_ADDM( T1, T1, T1, P ), \
|
||||
ASSH_BOP_SUBM( T1, Z3, T1, P ), \
|
||||
/* X3 = B*J */ \
|
||||
ASSH_BOP_MULM( X3, T0, T1, P ), \
|
||||
/* Z3 = F*J */ \
|
||||
ASSH_BOP_MULM( Z3, Z3, T1, P )
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
|
||||
libassh - asynchronous ssh2 client/server library.
|
||||
|
||||
Copyright (C) 2013 Alexandre Becoulet <alexandre.becoulet@free.fr>
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@file
|
||||
@short Key support for the RSA signature algorithm
|
||||
@internal
|
||||
*/
|
||||
|
||||
#ifndef ASSH_KEY_RSA_H_
|
||||
#define ASSH_KEY_RSA_H_
|
||||
|
||||
#include <assh/assh_key.h>
|
||||
#include <assh/assh_bignum.h>
|
||||
|
||||
/** @internal RSA key storage */
|
||||
struct assh_key_rsa_s
|
||||
{
|
||||
struct assh_key_s key;
|
||||
/** RSA modulus */
|
||||
struct assh_bignum_s nn;
|
||||
/** RSA exponent */
|
||||
struct assh_bignum_s en;
|
||||
/** RSA exponent */
|
||||
struct assh_bignum_s dn;
|
||||
};
|
||||
|
||||
ASSH_FIRST_FIELD_ASSERT(assh_key_rsa_s, key);
|
||||
|
||||
/** @internal Key operations descriptor for RSA keys */
|
||||
extern const struct assh_key_ops_s assh_key_rsa;
|
||||
|
||||
/** @internal */
|
||||
#define ASSH_RSA_ID "\x00\x00\x00\x07ssh-rsa"
|
||||
/** @internal */
|
||||
#define ASSH_RSA_ID_LEN (sizeof(ASSH_RSA_ID) - 1)
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,317 @@
|
|||
/*
|
||||
|
||||
libassh - asynchronous ssh2 client/server library.
|
||||
|
||||
Copyright (C) 2013 Alexandre Becoulet <alexandre.becoulet@free.fr>
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include <assh/assh_context.h>
|
||||
#include <assh/assh_algo.h>
|
||||
#include <assh/assh_kex.h>
|
||||
#include <assh/assh_cipher.h>
|
||||
#include <assh/assh_mac.h>
|
||||
#include <assh/assh_sign.h>
|
||||
#include <assh/assh_compress.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
static int assh_algo_order(const struct assh_algo_s *a,
|
||||
const struct assh_algo_s *b,
|
||||
unsigned int safety)
|
||||
{
|
||||
if (a->class_ != b->class_)
|
||||
return a->class_ - b->class_;
|
||||
return ((b->speed * (99 - safety) + b->safety * safety) -
|
||||
(a->speed * (99 - safety) + a->safety * safety));
|
||||
}
|
||||
|
||||
static void assh_algo_udpate(struct assh_context_s *c,
|
||||
unsigned int safety,
|
||||
unsigned int min_safety)
|
||||
{
|
||||
/* sort algorithms by class and safety/speed factor */
|
||||
int_fast16_t i, j, k;
|
||||
for (i = 0; i < c->algos_count; i++)
|
||||
{
|
||||
const struct assh_algo_s *a = c->algos[i];
|
||||
for (j = i - 1; j >= 0; j--)
|
||||
{
|
||||
const struct assh_algo_s *b = c->algos[j];
|
||||
if (assh_algo_order(a, b, safety) > 0)
|
||||
break;
|
||||
c->algos[j + 1] = b;
|
||||
}
|
||||
c->algos[j + 1] = a;
|
||||
}
|
||||
|
||||
/* remove duplicated names in the same class */
|
||||
for (i = 0; i < c->algos_count; i++)
|
||||
{
|
||||
for (k = j = i + 1; j < c->algos_count; j++)
|
||||
{
|
||||
const struct assh_algo_s *a = c->algos[i];
|
||||
const struct assh_algo_s *b = c->algos[j];
|
||||
|
||||
int d = a->class_ != b->class_;
|
||||
if (k < j)
|
||||
c->algos[k] = b;
|
||||
else if (d)
|
||||
goto next;
|
||||
if (d || strcmp(a->name, b->name))
|
||||
k++;
|
||||
else if (a->priority < b->priority)
|
||||
ASSH_SWAP(c->algos[k], c->algos[i]);
|
||||
}
|
||||
c->algos_count = k;
|
||||
next:;
|
||||
}
|
||||
|
||||
/* estimate size of the kex init packet */
|
||||
size_t kex_init_size = /* random cookie */ 16;
|
||||
enum assh_algo_class_e last = ASSH_ALGO_ANY;
|
||||
for (i = 0; i < c->algos_count; i++)
|
||||
{
|
||||
const struct assh_algo_s *a = c->algos[i];
|
||||
size_t l = 0;
|
||||
|
||||
if (a->class_ == last)
|
||||
l++; /* strlen(",") */
|
||||
else
|
||||
l += 4; /* string header */
|
||||
l += strlen(a->name);
|
||||
switch (a->class_)
|
||||
{
|
||||
case ASSH_ALGO_KEX:
|
||||
case ASSH_ALGO_SIGN:
|
||||
kex_init_size += l;
|
||||
break;
|
||||
case ASSH_ALGO_CIPHER:
|
||||
case ASSH_ALGO_MAC:
|
||||
case ASSH_ALGO_COMPRESS:
|
||||
kex_init_size += l * 2;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
last = a->class_;
|
||||
}
|
||||
kex_init_size += /* empty languages */ 4 * 2 + /* fkpf */ 1 + /* reserved */ 4;
|
||||
c->kex_init_size = kex_init_size;
|
||||
}
|
||||
|
||||
assh_error_t assh_algo_register(struct assh_context_s *c, unsigned int safety,
|
||||
unsigned int min_safety, const struct assh_algo_s *table[])
|
||||
{
|
||||
assh_error_t err = ASSH_OK;
|
||||
size_t i, count = c->algos_count;
|
||||
|
||||
ASSH_CHK_RET(safety > 99, ASSH_ERR_BAD_ARG);
|
||||
|
||||
for (i = 0; table[i] != NULL; i++)
|
||||
{
|
||||
const struct assh_algo_s *algo = table[i];
|
||||
if (algo->safety < min_safety)
|
||||
continue;
|
||||
ASSH_CHK_RET(count == ASSH_MAX_ALGORITHMS, ASSH_ERR_MEM);
|
||||
c->algos[count++] = algo;
|
||||
}
|
||||
|
||||
c->algos_count = count;
|
||||
assh_algo_udpate(c, safety, min_safety);
|
||||
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
const struct assh_algo_s *
|
||||
assh_algo_registered(struct assh_context_s *c, uint_fast16_t i)
|
||||
{
|
||||
if (i >= c->algos_count)
|
||||
return NULL;
|
||||
return c->algos[i];
|
||||
}
|
||||
|
||||
assh_error_t assh_algo_register_va(struct assh_context_s *c, unsigned int safety,
|
||||
unsigned int min_safety, ...)
|
||||
{
|
||||
assh_error_t err = ASSH_OK;
|
||||
va_list ap;
|
||||
size_t count = c->algos_count;
|
||||
|
||||
ASSH_CHK_RET(safety > 99, ASSH_ERR_BAD_ARG);
|
||||
|
||||
va_start(ap, min_safety);
|
||||
|
||||
/* append algorithms to the array */
|
||||
while (1)
|
||||
{
|
||||
struct assh_algo_s *algo = va_arg(ap, void*);
|
||||
if (algo == NULL)
|
||||
break;
|
||||
if (algo->safety < min_safety)
|
||||
continue;
|
||||
ASSH_CHK_GTO(count == ASSH_MAX_ALGORITHMS, ASSH_ERR_MEM, err_);
|
||||
c->algos[count++] = algo;
|
||||
}
|
||||
|
||||
c->algos_count = count;
|
||||
assh_algo_udpate(c, safety, min_safety);
|
||||
|
||||
err_:
|
||||
va_end(ap);
|
||||
return err;
|
||||
}
|
||||
|
||||
void assh_algo_unregister(struct assh_context_s *c)
|
||||
{
|
||||
c->algos_count = 0;
|
||||
}
|
||||
|
||||
const struct assh_algo_s *assh_algo_table[] = {
|
||||
/* kex */
|
||||
&assh_kex_curve25519_sha256.algo,
|
||||
&assh_kex_m383_sha384.algo,
|
||||
&assh_kex_m511_sha512.algo,
|
||||
&assh_kex_dh_group1_sha1.algo,
|
||||
&assh_kex_dh_group14_sha1.algo,
|
||||
&assh_kex_dh_gex_sha1.algo,
|
||||
&assh_kex_dh_gex_sha256_12.algo,
|
||||
&assh_kex_dh_gex_sha256_8.algo,
|
||||
&assh_kex_dh_gex_sha256_4.algo,
|
||||
&assh_kex_rsa1024_sha1.algo,
|
||||
&assh_kex_rsa2048_sha256.algo,
|
||||
/* sign */
|
||||
&assh_sign_dsa.algo,
|
||||
&assh_sign_dsa2048_sha224.algo,
|
||||
&assh_sign_dsa2048_sha256.algo,
|
||||
&assh_sign_dsa3072_sha256.algo,
|
||||
&assh_sign_rsa_sha1_md5.algo,
|
||||
&assh_sign_rsa_sha1.algo,
|
||||
&assh_sign_rsa_sha1_2048.algo,
|
||||
&assh_sign_rsa_sha256_2048.algo,
|
||||
&assh_sign_rsa_sha256_3072.algo,
|
||||
&assh_sign_ed25519.algo,
|
||||
&assh_sign_eddsa_e382.algo,
|
||||
&assh_sign_eddsa_e521.algo,
|
||||
/* ciphers */
|
||||
#ifdef CONFIG_ASSH_USE_GCRYPT_CIPHERS
|
||||
&assh_cipher_tdes_cbc.algo,
|
||||
&assh_cipher_tdes_ctr.algo,
|
||||
&assh_cipher_cast128_cbc.algo,
|
||||
&assh_cipher_cast128_ctr.algo,
|
||||
&assh_cipher_blowfish_cbc.algo,
|
||||
&assh_cipher_blowfish_ctr.algo,
|
||||
&assh_cipher_twofish128_cbc.algo,
|
||||
&assh_cipher_twofish256_cbc.algo,
|
||||
&assh_cipher_twofish128_ctr.algo,
|
||||
&assh_cipher_twofish256_ctr.algo,
|
||||
&assh_cipher_serpent128_cbc.algo,
|
||||
&assh_cipher_serpent192_cbc.algo,
|
||||
&assh_cipher_serpent256_cbc.algo,
|
||||
&assh_cipher_serpent128_ctr.algo,
|
||||
&assh_cipher_serpent192_ctr.algo,
|
||||
&assh_cipher_serpent256_ctr.algo,
|
||||
#endif
|
||||
&assh_cipher_arc4.algo,
|
||||
&assh_cipher_arc4_128.algo,
|
||||
&assh_cipher_arc4_256.algo,
|
||||
&assh_cipher_aes128_cbc.algo,
|
||||
&assh_cipher_aes192_cbc.algo,
|
||||
&assh_cipher_aes256_cbc.algo,
|
||||
&assh_cipher_aes128_ctr.algo,
|
||||
&assh_cipher_aes192_ctr.algo,
|
||||
&assh_cipher_aes256_ctr.algo,
|
||||
/* mac */
|
||||
&assh_hmac_md5.algo,
|
||||
&assh_hmac_md5_96.algo,
|
||||
&assh_hmac_sha1.algo,
|
||||
&assh_hmac_sha1_96.algo,
|
||||
&assh_hmac_sha256.algo,
|
||||
&assh_hmac_sha512.algo,
|
||||
#ifdef CONFIG_ASSH_USE_GCRYPT_HASH
|
||||
&assh_hmac_ripemd160.algo,
|
||||
#endif
|
||||
/* compress */
|
||||
&assh_compress_none.algo,
|
||||
NULL
|
||||
};
|
||||
|
||||
assh_error_t assh_algo_by_name(struct assh_context_s *c,
|
||||
enum assh_algo_class_e class_, const char *name,
|
||||
size_t name_len, const struct assh_algo_s **algo)
|
||||
{
|
||||
uint_fast16_t i;
|
||||
const struct assh_algo_s *a;
|
||||
|
||||
for (i = 0; i < c->algos_count; i++)
|
||||
{
|
||||
a = c->algos[i];
|
||||
|
||||
if (a->class_ == class_ &&
|
||||
!strncmp(name, a->name, name_len) &&
|
||||
a->name[name_len] == '\0')
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == c->algos_count)
|
||||
return ASSH_NOT_FOUND;
|
||||
|
||||
*algo = a;
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
assh_error_t assh_algo_by_key(struct assh_context_s *c,
|
||||
const struct assh_key_s *key, uint_fast16_t *pos,
|
||||
const struct assh_algo_s **algo)
|
||||
{
|
||||
uint_fast16_t i = pos == NULL ? 0 : *pos;
|
||||
const struct assh_algo_s *a;
|
||||
|
||||
for (; i < c->algos_count; i++)
|
||||
{
|
||||
a = c->algos[i];
|
||||
|
||||
if (a->class_ == key->role &&
|
||||
a->f_suitable_key != NULL &&
|
||||
a->f_suitable_key(c, a, key))
|
||||
break;
|
||||
}
|
||||
|
||||
if (i >= c->algos_count)
|
||||
return ASSH_NOT_FOUND;
|
||||
|
||||
if (pos != NULL)
|
||||
*pos = i;
|
||||
*algo = a;
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
assh_bool_t
|
||||
assh_algo_suitable_key(struct assh_context_s *c,
|
||||
const struct assh_algo_s *algo,
|
||||
const struct assh_key_s *key)
|
||||
{
|
||||
if (algo->f_suitable_key == NULL)
|
||||
return 0;
|
||||
if (key != NULL &&
|
||||
key->role != algo->class_)
|
||||
return 0;
|
||||
return algo->f_suitable_key(c, algo, key);
|
||||
}
|
||||
|
|
@ -0,0 +1,225 @@
|
|||
/*
|
||||
|
||||
libassh - asynchronous ssh2 client/server library.
|
||||
|
||||
Copyright (C) 2013 Alexandre Becoulet <alexandre.becoulet@free.fr>
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#include <assh/assh_bignum.h>
|
||||
#include <assh/assh_packet.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
size_t assh_bignum_size_of_bits(enum assh_bignum_fmt_e fmt, size_t bits)
|
||||
{
|
||||
assh_error_t err;
|
||||
size_t l, n = ASSH_ALIGN8(bits) / 8; /* bytes size */
|
||||
|
||||
switch (fmt)
|
||||
{
|
||||
case ASSH_BIGNUM_NATIVE:
|
||||
case ASSH_BIGNUM_STEMP:
|
||||
case ASSH_BIGNUM_TEMP:
|
||||
l = sizeof(struct assh_bignum_s);
|
||||
break;
|
||||
case ASSH_BIGNUM_MPINT:
|
||||
l = /* size header */ 4 + /* 00 sign */ 1 + /* data */ n;
|
||||
break;
|
||||
case ASSH_BIGNUM_STRING:
|
||||
l = /* size header */ 4 + /* data */ n;
|
||||
break;
|
||||
case ASSH_BIGNUM_MSB_RAW:
|
||||
case ASSH_BIGNUM_LSB_RAW:
|
||||
l = n;
|
||||
break;
|
||||
case ASSH_BIGNUM_ASN1:
|
||||
l = n < (1 << 7) ? n + 2 :
|
||||
n < (1 << 8) ? n + 3 :
|
||||
n < (1 << 16) ? n + 4 :
|
||||
n < (1 << 24) ? n + 5 : n + 6;
|
||||
break;
|
||||
case ASSH_BIGNUM_HEX:
|
||||
l = n * 2;
|
||||
break;
|
||||
case ASSH_BIGNUM_INT:
|
||||
ASSH_CHK_RET(bits >= sizeof(intptr_t) * 8, ASSH_ERR_INPUT_OVERFLOW);
|
||||
l = sizeof(intptr_t);
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
static void assh_asn1_size(const uint8_t *asn1, size_t *head_len, size_t *val_len)
|
||||
{
|
||||
size_t n = 2, l = asn1[1];
|
||||
asn1 += 2;
|
||||
if (l & 0x80) /* long length form ? */
|
||||
{
|
||||
size_t ll = l & 0x7f;
|
||||
for (l = 0; ll > 0; ll--, asn1++, n++)
|
||||
l = (l << 8) | *asn1;
|
||||
}
|
||||
if (head_len != NULL)
|
||||
*head_len = n;
|
||||
if (val_len != NULL)
|
||||
*val_len = l;
|
||||
}
|
||||
|
||||
/* clz on hex digit */
|
||||
static inline uint8_t assh_hex_clz(char c)
|
||||
{
|
||||
/* perfect hash on hex chars in "7f08192a3b4c5d6e" order */
|
||||
uint32_t x = ((0x20DB6DC0 * (uint32_t)(c | 32)) >> 27);
|
||||
/* shift based lookup table */
|
||||
return (0x11122331 >> (x & 30)) & 3;
|
||||
}
|
||||
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_bignum_size_of_data(enum assh_bignum_fmt_e fmt,
|
||||
const void *data, size_t *size,
|
||||
size_t *val_size, size_t *bits)
|
||||
{
|
||||
assh_error_t err;
|
||||
size_t l, n, b;
|
||||
|
||||
switch (fmt)
|
||||
{
|
||||
case ASSH_BIGNUM_NATIVE:
|
||||
case ASSH_BIGNUM_STEMP:
|
||||
case ASSH_BIGNUM_TEMP: {
|
||||
const struct assh_bignum_s *bn = data;
|
||||
l = sizeof(struct assh_bignum_s);
|
||||
b = bn->bits;
|
||||
n = ASSH_ALIGN8(b) / 8;
|
||||
break;
|
||||
}
|
||||
|
||||
case ASSH_BIGNUM_MPINT: {
|
||||
const uint8_t *mpint = data;
|
||||
n = assh_load_u32(mpint);
|
||||
l = n + 4;
|
||||
if (n > 0)
|
||||
{
|
||||
ASSH_CHK_RET(mpint[4] & 0x80, ASSH_ERR_NUM_OVERFLOW);
|
||||
if (mpint[4] == 0)
|
||||
{
|
||||
mpint++, n--;
|
||||
ASSH_CHK_RET(n == 0, ASSH_ERR_BAD_DATA);
|
||||
ASSH_CHK_RET((mpint[4] & 0x80) == 0, ASSH_ERR_BAD_DATA);
|
||||
}
|
||||
}
|
||||
ASSH_CHK_RET(n > 0 && mpint[4] == 0, ASSH_ERR_BAD_DATA);
|
||||
b = n * 8;
|
||||
if (n)
|
||||
b -= ASSH_CLZ8(mpint[4]);
|
||||
break;
|
||||
}
|
||||
|
||||
case ASSH_BIGNUM_STRING: {
|
||||
const uint8_t *str = data;
|
||||
n = assh_load_u32(str);
|
||||
l = n + 4;
|
||||
while (n > 0 && str[0] == 0)
|
||||
str++, n--;
|
||||
b = n * 8;
|
||||
if (n)
|
||||
b -= ASSH_CLZ8(str[0]);
|
||||
break;
|
||||
}
|
||||
|
||||
case ASSH_BIGNUM_ASN1: {
|
||||
const uint8_t *asn1 = data;
|
||||
ASSH_CHK_RET(*asn1 != 0x02, ASSH_ERR_BAD_DATA);
|
||||
assh_asn1_size(asn1, &l, &n);
|
||||
#warning reject negative numbers as in mpint?
|
||||
asn1 += l;
|
||||
l += n;
|
||||
while (n > 0 && asn1[0] == 0)
|
||||
asn1++, n--;
|
||||
b = n * 8;
|
||||
if (n)
|
||||
b -= ASSH_CLZ8(asn1[0]);
|
||||
break;
|
||||
}
|
||||
|
||||
case ASSH_BIGNUM_LSB_RAW: {
|
||||
assert(size != NULL);
|
||||
const uint8_t *raw = data;
|
||||
n = l = *size;
|
||||
while (n > 0 && raw[n - 1] == 0)
|
||||
n--;
|
||||
b = n * 8;
|
||||
if (b)
|
||||
b -= ASSH_CLZ8(raw[n - 1]);
|
||||
break;
|
||||
}
|
||||
|
||||
case ASSH_BIGNUM_MSB_RAW: {
|
||||
assert(size != NULL);
|
||||
const uint8_t *raw = data;
|
||||
n = l = *size;
|
||||
while (n > 0 && raw[0] == 0)
|
||||
raw++, n--;
|
||||
b = n * 8;
|
||||
if (b)
|
||||
b -= ASSH_CLZ8(raw[0]);
|
||||
break;
|
||||
}
|
||||
|
||||
case ASSH_BIGNUM_HEX: {
|
||||
const char *hex = data;
|
||||
l = strlen(hex);
|
||||
n = l;
|
||||
while (n > 0 && hex[0] == '0')
|
||||
hex++, n--;
|
||||
b = n * 4;
|
||||
if (n)
|
||||
b -= assh_hex_clz(hex[0]);
|
||||
break;
|
||||
}
|
||||
|
||||
case ASSH_BIGNUM_INT: {
|
||||
n = l = sizeof(intptr_t);
|
||||
b = l * 8;
|
||||
break;
|
||||
}
|
||||
|
||||
case ASSH_BIGNUM_SIZE:
|
||||
b = (intptr_t)data;
|
||||
n = l = ASSH_ALIGN8(b) / 8;
|
||||
break;
|
||||
default:
|
||||
ASSH_ERR_RET(ASSH_ERR_BAD_ARG);
|
||||
}
|
||||
|
||||
if (size != NULL)
|
||||
*size = l;
|
||||
|
||||
if (val_size != NULL)
|
||||
*val_size = n;
|
||||
|
||||
if (bits != NULL)
|
||||
*bits = b;
|
||||
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,242 @@
|
|||
/*
|
||||
|
||||
libassh - asynchronous ssh2 client/server library.
|
||||
|
||||
Copyright (C) 2013 Alexandre Becoulet <alexandre.becoulet@free.fr>
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#warning write a perl script to check error RET/GTO order
|
||||
|
||||
#include <assh/assh_context.h>
|
||||
#include <assh/assh_packet.h>
|
||||
#include <assh/assh_algo.h>
|
||||
#include <assh/assh_key.h>
|
||||
#include <assh/assh_kex.h>
|
||||
#include <assh/assh_prng.h>
|
||||
#include <assh/assh_alloc.h>
|
||||
#include <assh/assh_bignum.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef CONFIG_ASSH_USE_GCRYPT
|
||||
# include <gcrypt.h>
|
||||
#endif
|
||||
|
||||
static ASSH_ALLOCATOR(assh_default_allocator)
|
||||
{
|
||||
assh_error_t err;
|
||||
|
||||
#ifdef CONFIG_ASSH_USE_GCRYPT_ALLOCATOR
|
||||
if (size == 0)
|
||||
{
|
||||
gcry_free(*ptr);
|
||||
return ASSH_OK;
|
||||
}
|
||||
else if (*ptr == NULL)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case ASSH_ALLOC_INTERNAL:
|
||||
case ASSH_ALLOC_PACKET:
|
||||
*ptr = gcry_malloc(size);
|
||||
break;
|
||||
case ASSH_ALLOC_SECUR:
|
||||
case ASSH_ALLOC_SCRATCH:
|
||||
*ptr = gcry_malloc_secure(size);
|
||||
break;
|
||||
}
|
||||
ASSH_CHK_RET(*ptr == NULL, ASSH_ERR_MEM);
|
||||
return ASSH_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
*ptr = gcry_realloc(*ptr, size);
|
||||
ASSH_CHK_RET(*ptr == NULL, ASSH_ERR_MEM);
|
||||
return ASSH_OK;
|
||||
}
|
||||
#else
|
||||
# warning The default allocator relies on the standard non-secur realloc function
|
||||
*ptr = realloc(*ptr, size);
|
||||
ASSH_CHK_RET(size != 0 && *ptr == NULL, ASSH_ERR_MEM);
|
||||
return ASSH_OK;
|
||||
#endif
|
||||
}
|
||||
|
||||
void assh_context_init(struct assh_context_s *c,
|
||||
enum assh_context_type_e type,
|
||||
assh_allocator_t *alloc,
|
||||
void *alloc_pv)
|
||||
{
|
||||
c->session_count = 0;
|
||||
|
||||
assert(
|
||||
#ifdef CONFIG_ASSH_CLIENT
|
||||
type == ASSH_CLIENT ||
|
||||
#endif
|
||||
#ifdef CONFIG_ASSH_SERVER
|
||||
type == ASSH_SERVER ||
|
||||
#endif
|
||||
0);
|
||||
|
||||
c->type = type;
|
||||
|
||||
if (alloc == NULL)
|
||||
alloc = assh_default_allocator;
|
||||
c->f_alloc = alloc;
|
||||
c->alloc_pv = alloc_pv;
|
||||
|
||||
c->prng = NULL;
|
||||
c->keys = NULL;
|
||||
c->kex_init_size = 0;
|
||||
|
||||
c->algos_count = 0;
|
||||
|
||||
int i;
|
||||
for (i = 0; i < ASSH_PCK_POOL_SIZE; i++)
|
||||
{
|
||||
c->pool[i].pck = NULL;
|
||||
c->pool[i].count = 0;
|
||||
c->pool[i].size = 0;
|
||||
}
|
||||
|
||||
c->pck_pool_max_size = 1 << 20;
|
||||
c->pck_pool_max_bsize = c->pck_pool_max_size / ASSH_PCK_POOL_SIZE;
|
||||
c->pck_pool_size = 0;
|
||||
|
||||
c->srvs_count = 0;
|
||||
|
||||
#ifdef CONFIG_ASSH_USE_GCRYPT_BIGNUM
|
||||
c->bignum = &assh_bignum_gcrypt;
|
||||
#else
|
||||
c->bignum = &assh_bignum_builtin;
|
||||
#endif
|
||||
}
|
||||
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_context_create(struct assh_context_s **ctx,
|
||||
enum assh_context_type_e type,
|
||||
assh_allocator_t *alloc, void *alloc_pv)
|
||||
{
|
||||
assh_error_t err;
|
||||
|
||||
if (alloc == NULL)
|
||||
{
|
||||
alloc = assh_default_allocator;
|
||||
alloc_pv = NULL;
|
||||
}
|
||||
|
||||
*ctx = NULL;
|
||||
ASSH_ERR_RET(alloc(alloc_pv, (void**)ctx, sizeof(struct assh_context_s), ASSH_ALLOC_INTERNAL));
|
||||
|
||||
assh_context_init(*ctx, type, alloc, alloc_pv);
|
||||
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
void assh_context_release(struct assh_context_s *ctx)
|
||||
{
|
||||
assh_context_cleanup(ctx);
|
||||
assh_free(ctx, ctx);
|
||||
}
|
||||
|
||||
static void assh_pck_pool_cleanup(struct assh_context_s *c)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < ASSH_PCK_POOL_SIZE; i++)
|
||||
{
|
||||
struct assh_packet_s *n, *p;
|
||||
struct assh_packet_pool_s *pl = c->pool + i;
|
||||
|
||||
for (p = pl->pck; p != NULL; p = n)
|
||||
{
|
||||
n = p->pool_next;
|
||||
pl->size -= p->alloc_size;
|
||||
pl->count--;
|
||||
assh_free(c, p);
|
||||
}
|
||||
|
||||
assert(pl->count == 0);
|
||||
assert(pl->size == 0);
|
||||
pl->pck = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void assh_context_cleanup(struct assh_context_s *c)
|
||||
{
|
||||
assert(c->session_count == 0);
|
||||
|
||||
assh_pck_pool_cleanup(c);
|
||||
|
||||
assh_key_flush(c, &c->keys);
|
||||
|
||||
if (c->prng != NULL)
|
||||
c->prng->f_cleanup(c);
|
||||
}
|
||||
|
||||
assh_error_t assh_context_prng(struct assh_context_s *c,
|
||||
const struct assh_prng_s *prng)
|
||||
{
|
||||
assh_error_t err;
|
||||
|
||||
if (prng == NULL)
|
||||
{
|
||||
if (c->prng != NULL)
|
||||
return ASSH_OK;
|
||||
#ifdef CONFIG_ASSH_USE_GCRYPT_PRNG
|
||||
prng = &assh_prng_gcrypt;
|
||||
#else
|
||||
prng = &assh_prng_xswap;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (c->prng != NULL)
|
||||
c->prng->f_cleanup(c);
|
||||
|
||||
c->prng = prng;
|
||||
ASSH_ERR_RET(prng->f_init(c));
|
||||
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ASSH_DEBUG
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
void assh_hexdump(const char *name, const void *data, unsigned int len)
|
||||
{
|
||||
int i, j;
|
||||
const uint8_t *data_ = data;
|
||||
const int width = 32;
|
||||
|
||||
fprintf(stderr, "--- %s (%u bytes) ---\n", name, len);
|
||||
for (i = 0; i < len; i += width)
|
||||
{
|
||||
for (j = 0; j < width && i + j < len; j++)
|
||||
fprintf(stderr, "%02x ", data_[i + j]);
|
||||
for (; j < width; j++)
|
||||
fputs(" ", stderr);
|
||||
for (j = 0; j < width && i + j < len; j++)
|
||||
fprintf(stderr, "%c", (unsigned)data_[i + j] - 32 < 96 ? data_[i + j] : '.');
|
||||
fputc('\n', stderr);
|
||||
}
|
||||
fputc('\n', stderr);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,196 @@
|
|||
/*
|
||||
|
||||
libassh - asynchronous ssh2 client/server library.
|
||||
|
||||
Copyright (C) 2013 Alexandre Becoulet <alexandre.becoulet@free.fr>
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#define ASSH_EV_CONST /* write access to event const fields */
|
||||
|
||||
#include <assh/assh_context.h>
|
||||
#include <assh/assh_transport.h>
|
||||
#include <assh/assh_packet.h>
|
||||
#include <assh/assh_session.h>
|
||||
#include <assh/assh_kex.h>
|
||||
#include <assh/assh_prng.h>
|
||||
#include <assh/assh_service.h>
|
||||
#include <assh/assh_event.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
static ASSH_EVENT_DONE_FCN(assh_event_random_done)
|
||||
{
|
||||
return s->ctx->prng->f_feed(s->ctx, e->prng.feed.buf,
|
||||
e->prng.feed.size);
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
assh_error_t assh_event_get(struct assh_session_s *s,
|
||||
struct assh_event_s *event)
|
||||
{
|
||||
assh_error_t err;
|
||||
|
||||
ASSH_CHK_RET(s->tr_st == ASSH_TR_CLOSED,
|
||||
ASSH_ERR_CLOSED | ASSH_ERRSV_FIN);
|
||||
|
||||
/* need to get some entropy for the prng */
|
||||
if (s->ctx->prng_entropy < 0)
|
||||
{
|
||||
event->id = ASSH_EVENT_PRNG_FEED;
|
||||
event->f_done = &assh_event_random_done;
|
||||
event->prng.feed.size = ASSH_MIN(-s->ctx->prng_entropy,
|
||||
sizeof (event->prng.feed.buf));
|
||||
goto done;
|
||||
}
|
||||
|
||||
event->id = ASSH_EVENT_INVALID;
|
||||
|
||||
/* process the next incoming deciphered packet */
|
||||
ASSH_ERR_GTO(assh_transport_dispatch(s, event), err);
|
||||
|
||||
if (event->id != ASSH_EVENT_INVALID)
|
||||
goto done;
|
||||
|
||||
/* key re-exchange should have occured at this point */
|
||||
ASSH_CHK_RET(s->kex_bytes > ASSH_REKEX_THRESHOLD + ASSH_MAX_PCK_LEN * 16,
|
||||
ASSH_ERR_PROTOCOL | ASSH_ERRSV_DISCONNECT);
|
||||
|
||||
/* initiate key re-exchange */
|
||||
if (s->tr_st == ASSH_TR_SERVICE && s->kex_bytes > s->kex_max_bytes)
|
||||
{
|
||||
ASSH_ERR_RET(assh_kex_send_init(s) | ASSH_ERRSV_DISCONNECT);
|
||||
assh_transport_state(s, ASSH_TR_SERVICE_KEX);
|
||||
}
|
||||
|
||||
/* run the state machine which converts output packets to enciphered
|
||||
ssh stream */
|
||||
ASSH_ERR_GTO(assh_transport_write(s, event), err);
|
||||
|
||||
if (event->id != ASSH_EVENT_INVALID)
|
||||
goto done;
|
||||
|
||||
if (s->tr_st == ASSH_TR_FIN)
|
||||
{
|
||||
/* all events have been reported, end of session. */
|
||||
assh_transport_state(s, ASSH_TR_CLOSED);
|
||||
ASSH_ERR_RET(ASSH_ERR_CLOSED | ASSH_ERRSV_FIN);
|
||||
}
|
||||
|
||||
/* run the state machine which extracts deciphered packets from the
|
||||
input ssh stream. */
|
||||
ASSH_ERR_GTO(assh_transport_read(s, event), err);
|
||||
|
||||
done:
|
||||
#ifdef CONFIG_ASSH_DEBUG_EVENT
|
||||
if (event->id > 2)
|
||||
ASSH_DEBUG("event id=%u\n", event->id);
|
||||
#endif
|
||||
return ASSH_OK;
|
||||
|
||||
err:
|
||||
return assh_session_error(s, err);
|
||||
}
|
||||
|
||||
assh_error_t
|
||||
assh_event_done(struct assh_session_s *s,
|
||||
struct assh_event_s *e)
|
||||
{
|
||||
assh_error_t err;
|
||||
|
||||
ASSH_CHK_RET(s->tr_st == ASSH_TR_CLOSED,
|
||||
ASSH_ERR_CLOSED | ASSH_ERRSV_FIN);
|
||||
|
||||
#ifdef CONFIG_ASSH_DEBUG_EVENT
|
||||
if (e->id > 2)
|
||||
ASSH_DEBUG("event done id=%u\n", e->id);
|
||||
#endif
|
||||
|
||||
if (e->f_done == NULL)
|
||||
return ASSH_OK;
|
||||
|
||||
ASSH_ERR_GTO(e->f_done(s, e), err);
|
||||
|
||||
return ASSH_OK;
|
||||
err:
|
||||
return assh_session_error(s, err);
|
||||
}
|
||||
|
||||
void assh_event_table_init(struct assh_event_hndl_table_s *t)
|
||||
{
|
||||
unsigned int i;
|
||||
for (i = 0; i < ASSH_EVENT_COUNT; i++)
|
||||
t->table[i] = NULL;
|
||||
}
|
||||
|
||||
void assh_event_table_register(struct assh_event_hndl_table_s *t,
|
||||
enum assh_event_id_e id,
|
||||
struct assh_event_hndl_s *h,
|
||||
assh_event_hndl_func_t *f, void *ctx)
|
||||
{
|
||||
struct assh_event_hndl_s **t_ = t->table + id;
|
||||
|
||||
h->next = *t_;
|
||||
*t_ = h;
|
||||
h->f_handler = f;
|
||||
h->ctx = ctx;
|
||||
}
|
||||
|
||||
assh_error_t
|
||||
assh_event_table_run(struct assh_session_s *s,
|
||||
struct assh_event_hndl_table_s *t,
|
||||
struct assh_event_s *e)
|
||||
{
|
||||
assh_error_t err;
|
||||
struct assh_event_hndl_s *h;
|
||||
|
||||
continue_:
|
||||
ASSH_ERR_RET(assh_event_get(s, e));
|
||||
|
||||
cont_:
|
||||
for (h = t->table[e->id]; h != NULL; h = h->next)
|
||||
{
|
||||
struct assh_event_s n;
|
||||
n.id = ASSH_EVENT_INVALID;
|
||||
ASSH_ERR_GTO(h->f_handler(s, e, &n, h->ctx), err);
|
||||
|
||||
switch (err)
|
||||
{
|
||||
case ASSH_OK:
|
||||
ASSH_ERR_RET(assh_event_done(s, e));
|
||||
if (n.id != ASSH_EVENT_INVALID)
|
||||
{
|
||||
memcpy(e, &n, sizeof(n));
|
||||
goto cont_;
|
||||
}
|
||||
goto continue_;
|
||||
|
||||
case ASSH_NO_DATA:
|
||||
continue;
|
||||
|
||||
default:
|
||||
ASSH_ERR_RET(err);
|
||||
}
|
||||
}
|
||||
|
||||
return ASSH_OK;
|
||||
|
||||
err:
|
||||
return assh_session_error(s, err);
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
|
||||
libassh - asynchronous ssh2 client/server library.
|
||||
|
||||
Copyright (C) 2013 Alexandre Becoulet <alexandre.becoulet@free.fr>
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#include <assh/assh_hash.h>
|
||||
#include <assh/assh_bignum.h>
|
||||
#include <assh/assh_packet.h>
|
||||
#include <assh/assh_alloc.h>
|
||||
|
||||
void assh_hash_bytes_as_string(struct assh_hash_ctx_s *hctx,
|
||||
const uint8_t *bytes, size_t len)
|
||||
{
|
||||
uint8_t s[4];
|
||||
assh_store_u32(s, len);
|
||||
hctx->algo->f_update(hctx, s, 4);
|
||||
hctx->algo->f_update(hctx, bytes, len);
|
||||
}
|
||||
|
||||
void assh_hash_string(struct assh_hash_ctx_s *hctx, const uint8_t *str)
|
||||
{
|
||||
uint32_t s = assh_load_u32(str);
|
||||
hctx->algo->f_update(hctx, str, s + 4);
|
||||
}
|
||||
|
||||
assh_error_t assh_hash_bignum(struct assh_context_s *ctx,
|
||||
struct assh_hash_ctx_s *hctx,
|
||||
const struct assh_bignum_s *bn)
|
||||
{
|
||||
assh_error_t err;
|
||||
size_t l = assh_bignum_size_of_num(ASSH_BIGNUM_MPINT, bn);
|
||||
|
||||
ASSH_SCRATCH_ALLOC(ctx, uint8_t, s, l, ASSH_ERRSV_CONTINUE, err);
|
||||
|
||||
ASSH_ERR_GTO(assh_bignum_convert(ctx,
|
||||
ASSH_BIGNUM_NATIVE, ASSH_BIGNUM_MPINT, bn, s), err_alloc);
|
||||
|
||||
hctx->algo->f_update(hctx, s, assh_load_u32(s) + 4);
|
||||
|
||||
err = ASSH_OK;
|
||||
|
||||
err_alloc:
|
||||
ASSH_SCRATCH_FREE(ctx, s);
|
||||
err:
|
||||
return err;
|
||||
}
|
||||
|
||||
void assh_hash_payload_as_string(struct assh_hash_ctx_s *hctx,
|
||||
const struct assh_packet_s *p)
|
||||
{
|
||||
uint32_t len = assh_load_u32(p->data) /* pad_len */ - 1 /* padding */ - p->head.pad_len;
|
||||
uint8_t s[4];
|
||||
assert(len < p->data_size);
|
||||
assh_store_u32(s, len);
|
||||
hctx->algo->f_update(hctx, s, 4);
|
||||
hctx->algo->f_update(hctx, p->data + 5, len);
|
||||
}
|
||||
|
|
@ -0,0 +1,790 @@
|
|||
/*
|
||||
|
||||
libassh - asynchronous ssh2 client/server library.
|
||||
|
||||
Copyright (C) 2013 Alexandre Becoulet <alexandre.becoulet@free.fr>
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#define ASSH_EV_CONST /* write access to event const fields */
|
||||
|
||||
#include <assh/assh_context.h>
|
||||
#include <assh/assh_kex.h>
|
||||
#include <assh/assh_packet.h>
|
||||
#include <assh/assh_transport.h>
|
||||
#include <assh/assh_session.h>
|
||||
#include <assh/assh_cipher.h>
|
||||
#include <assh/assh_mac.h>
|
||||
#include <assh/assh_hash.h>
|
||||
#include <assh/assh_sign.h>
|
||||
#include <assh/assh_key.h>
|
||||
#include <assh/assh_prng.h>
|
||||
#include <assh/assh_compress.h>
|
||||
#include <assh/assh_alloc.h>
|
||||
#include <assh/assh_event.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static const enum assh_algo_class_e assh_kex_algos_classes[8] = {
|
||||
ASSH_ALGO_KEX, ASSH_ALGO_SIGN,
|
||||
ASSH_ALGO_CIPHER, ASSH_ALGO_CIPHER,
|
||||
ASSH_ALGO_MAC, ASSH_ALGO_MAC,
|
||||
ASSH_ALGO_COMPRESS, ASSH_ALGO_COMPRESS
|
||||
};
|
||||
|
||||
assh_error_t assh_kex_send_init(struct assh_session_s *s)
|
||||
{
|
||||
assh_error_t err;
|
||||
struct assh_context_s *c = s->ctx;
|
||||
|
||||
struct assh_packet_s *p;
|
||||
ASSH_ERR_RET(assh_packet_alloc(c, SSH_MSG_KEXINIT,
|
||||
c->kex_init_size, &p) | ASSH_ERRSV_DISCONNECT);
|
||||
|
||||
uint8_t *cookie;
|
||||
ASSH_ERR_GTO(assh_packet_add_array(p, 16, &cookie), err_pck);
|
||||
ASSH_ERR_GTO(assh_prng_get(c, cookie,
|
||||
16, ASSH_PRNG_QUALITY_NONCE)
|
||||
| ASSH_ERRSV_DISCONNECT, err_pck);
|
||||
|
||||
unsigned int ac = c->algos_count;
|
||||
|
||||
/* lists of algorithms */
|
||||
unsigned int i = 0, j;
|
||||
for (j = ASSH_ALGO_KEX; j <= ASSH_ALGO_COMPRESS; j++)
|
||||
{
|
||||
assh_bool_t first = 0;
|
||||
uint8_t *list;
|
||||
ASSH_ERR_GTO(assh_packet_add_string(p, 0, &list)
|
||||
| ASSH_ERRSV_DISCONNECT, err_pck);
|
||||
|
||||
for (; i < ac; i++)
|
||||
{
|
||||
const struct assh_algo_s *a = c->algos[i];
|
||||
if (a->class_ != j)
|
||||
break;
|
||||
|
||||
/* check host key availability for this algorithm */
|
||||
if (assh_algo_suitable_key(c, a, NULL) &&
|
||||
assh_key_lookup(c, NULL, a) != ASSH_OK)
|
||||
continue;
|
||||
|
||||
/* append name to the list */
|
||||
uint8_t *tail;
|
||||
size_t l = strlen(a->name);
|
||||
ASSH_ERR_GTO(assh_packet_enlarge_string(p, list, first + l, &tail)
|
||||
| ASSH_ERRSV_DISCONNECT, err_pck);
|
||||
memcpy(tail + first, a->name, l);
|
||||
if (first)
|
||||
tail[0] = ',';
|
||||
first = 1;
|
||||
}
|
||||
|
||||
if (j >= ASSH_ALGO_CIPHER) /* duplicate list */
|
||||
{
|
||||
size_t len = assh_load_u32(list - 4);
|
||||
uint8_t *list2;
|
||||
ASSH_ERR_GTO(assh_packet_add_string(p, len, &list2)
|
||||
| ASSH_ERRSV_DISCONNECT, err_pck);
|
||||
memcpy(list2, list, len);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *x;
|
||||
|
||||
/* empty languages */
|
||||
ASSH_ERR_GTO(assh_packet_add_string(p, 0, &x)
|
||||
| ASSH_ERRSV_DISCONNECT, err_pck);
|
||||
ASSH_ERR_GTO(assh_packet_add_string(p, 0, &x)
|
||||
| ASSH_ERRSV_DISCONNECT, err_pck);
|
||||
|
||||
ASSH_ERR_GTO(assh_packet_add_array(p, 5, &x)
|
||||
| ASSH_ERRSV_DISCONNECT, err_pck);
|
||||
|
||||
/* fkpf + reserved */
|
||||
memset(x, 0, 5);
|
||||
|
||||
/* keep a copy of our KEX_INIT packet, will be needed for hashing */
|
||||
assert(s->kex_init_local == NULL);
|
||||
|
||||
struct assh_packet_s *pc;
|
||||
ASSH_ERR_GTO(assh_packet_dup(p, &pc)
|
||||
| ASSH_ERRSV_DISCONNECT, err_pck);
|
||||
s->kex_init_local = pc;
|
||||
|
||||
/* setup packet len and padding fields of the copy */
|
||||
assh_store_u32(pc->data, pc->data_size - 4);
|
||||
pc->head.pad_len = 0;
|
||||
|
||||
assh_transport_push(s, p);
|
||||
return ASSH_OK;
|
||||
|
||||
err_pck:
|
||||
assh_packet_release(p);
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ASSH_SERVER
|
||||
/* select server side algorithms based on KEX init lists from client */
|
||||
static assh_error_t
|
||||
assh_kex_server_algos(struct assh_context_s *c, uint8_t *lists[9],
|
||||
const struct assh_algo_s *algos[8], assh_bool_t *guessed)
|
||||
{
|
||||
assh_error_t err;
|
||||
unsigned int i;
|
||||
|
||||
*guessed = 1;
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
char *start = (char*)(lists[i] + 4);
|
||||
char *end = (char*)lists[i+1];
|
||||
|
||||
/* iterate over name-list */
|
||||
while (start < end)
|
||||
{
|
||||
char *n = start;
|
||||
while (*n != ',' && n < end)
|
||||
n++;
|
||||
|
||||
/* lookup in registered algorithms */
|
||||
const struct assh_algo_s *a;
|
||||
if (assh_algo_by_name(c, assh_kex_algos_classes[i],
|
||||
start, n - start, &a) != ASSH_OK)
|
||||
goto next;
|
||||
|
||||
/* check algorithm key availability */
|
||||
if (assh_algo_suitable_key(c, a, NULL) &&
|
||||
assh_key_lookup(c, NULL, a) != ASSH_OK)
|
||||
goto next;
|
||||
|
||||
algos[i] = a;
|
||||
goto done;
|
||||
|
||||
next:
|
||||
start = n + 1;
|
||||
if (i < 2) /* KEX or HOST KEY algorithm */
|
||||
*guessed = 0;
|
||||
}
|
||||
|
||||
ASSH_ERR_RET(ASSH_ERR_MISSING_ALGO | ASSH_ERRSV_DISCONNECT);
|
||||
done:;
|
||||
}
|
||||
|
||||
return ASSH_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ASSH_CLIENT
|
||||
/* select client side algorithms based on KEX init lists from server */
|
||||
static assh_error_t
|
||||
assh_kex_client_algos(struct assh_context_s *c, uint8_t *lists[9],
|
||||
const struct assh_algo_s *algos[8], assh_bool_t *guessed)
|
||||
{
|
||||
assh_error_t err;
|
||||
unsigned int i, j;
|
||||
|
||||
*guessed = 1;
|
||||
for (j = i = 0; i < 8; i++)
|
||||
{
|
||||
/* iterate over available algorithms */
|
||||
for (; ; j++)
|
||||
{
|
||||
ASSH_CHK_RET(j == c->algos_count,
|
||||
ASSH_ERR_MISSING_ALGO | ASSH_ERRSV_DISCONNECT);
|
||||
|
||||
const struct assh_algo_s *a = c->algos[j];
|
||||
if (a->class_ < assh_kex_algos_classes[i])
|
||||
continue;
|
||||
ASSH_CHK_RET(a->class_ > assh_kex_algos_classes[i],
|
||||
ASSH_ERR_MISSING_ALGO | ASSH_ERRSV_DISCONNECT);
|
||||
|
||||
char *start = (char*)(lists[i] + 4);
|
||||
char *end = (char*)lists[i+1];
|
||||
|
||||
/* iterate over name-list */
|
||||
while (start < end)
|
||||
{
|
||||
char *n = start;
|
||||
while (*n != ',' && n < end)
|
||||
n++;
|
||||
|
||||
/* check algorithm name match */
|
||||
if (!strncmp(start, a->name, n - start)
|
||||
&& a->name[n - start] == '\0')
|
||||
{
|
||||
algos[i] = a;
|
||||
goto done;
|
||||
}
|
||||
|
||||
start = n + 1;
|
||||
if (i < 2) /* KEX or HOST KEY algorithm */
|
||||
*guessed = 0;
|
||||
}
|
||||
}
|
||||
done:;
|
||||
}
|
||||
|
||||
return ASSH_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
assh_error_t assh_kex_got_init(struct assh_session_s *s, struct assh_packet_s *p)
|
||||
{
|
||||
assh_error_t err;
|
||||
|
||||
uint8_t *lists[11];
|
||||
unsigned int i;
|
||||
|
||||
/* get pointers to the 10 name-lists while checking bounds */
|
||||
lists[0] = p->head.end /* cookie */ + 16;
|
||||
for (i = 0; i < 10; i++)
|
||||
ASSH_ERR_RET(assh_packet_check_string(p, lists[i], lists + i + 1)
|
||||
| ASSH_ERRSV_DISCONNECT);
|
||||
|
||||
ASSH_ERR_RET(assh_packet_check_array(p, lists[10], 1, NULL)
|
||||
| ASSH_ERRSV_DISCONNECT);
|
||||
|
||||
assh_bool_t guess_follows = *lists[10];
|
||||
assh_bool_t good_guess;
|
||||
|
||||
const struct assh_algo_s *algos[8];
|
||||
|
||||
/* select proper algorithms based on registered algorithms and name-lists */
|
||||
switch (s->ctx->type)
|
||||
{
|
||||
#ifdef CONFIG_ASSH_SERVER
|
||||
case ASSH_SERVER:
|
||||
ASSH_ERR_RET(assh_kex_server_algos(s->ctx, lists, algos, &good_guess)
|
||||
| ASSH_ERRSV_DISCONNECT);
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_ASSH_CLIENT
|
||||
case ASSH_CLIENT:
|
||||
ASSH_ERR_RET(assh_kex_client_algos(s->ctx, lists, algos, &good_guess)
|
||||
| ASSH_ERRSV_DISCONNECT);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
||||
s->kex_bad_guess = guess_follows && !good_guess;
|
||||
|
||||
const struct assh_algo_kex_s *kex = (const void *)algos[0];
|
||||
const struct assh_algo_sign_s *sign = (const void *)algos[1];
|
||||
const struct assh_algo_cipher_s *cipher_in = (const void *)algos[2];
|
||||
const struct assh_algo_cipher_s *cipher_out = (const void *)algos[3];
|
||||
const struct assh_algo_mac_s *mac_in = (const void *)algos[4];
|
||||
const struct assh_algo_mac_s *mac_out = (const void *)algos[5];
|
||||
const struct assh_algo_compress_s *cmp_in = (const void *)algos[6];
|
||||
const struct assh_algo_compress_s *cmp_out = (const void *)algos[7];
|
||||
|
||||
#ifdef CONFIG_ASSH_DEBUG_KEX
|
||||
ASSH_DEBUG("kex algorithms:\n"
|
||||
" kex: %s (%s)\n"
|
||||
" sign: %s (%s)\n"
|
||||
" cipher in: %s\n cipher out: %s\n"
|
||||
" mac in: %s\n mac out: %s\n comp in: %s\n comp out: %s\n"
|
||||
" guess: follows=%x good=%x\n",
|
||||
kex->algo.name, kex->algo.variant,
|
||||
sign->algo.name, sign->algo.variant,
|
||||
cipher_in->algo.name, cipher_out->algo.name,
|
||||
mac_in->algo.name, mac_out->algo.name,
|
||||
cmp_in->algo.name, cmp_out->algo.name,
|
||||
guess_follows, good_guess);
|
||||
#endif
|
||||
|
||||
/* keep the remote KEX_INIT packet, will be needed for hashing */
|
||||
assert(s->kex_init_remote == NULL);
|
||||
assh_packet_refinc(p);
|
||||
s->kex_init_remote = p;
|
||||
|
||||
/* alloacte input and output keys and associated cipher/mac/compress contexts */
|
||||
struct assh_kex_keys_s *kin;
|
||||
ASSH_ERR_RET(assh_alloc(s->ctx, sizeof(*kin) + cipher_in->ctx_size
|
||||
+ mac_in->ctx_size + cmp_in->ctx_size, ASSH_ALLOC_SECUR, (void**)&kin)
|
||||
| ASSH_ERRSV_DISCONNECT);
|
||||
|
||||
struct assh_kex_keys_s *kout;
|
||||
ASSH_ERR_GTO(assh_alloc(s->ctx, sizeof(*kout) + cipher_out->ctx_size
|
||||
+ mac_out->ctx_size + cmp_out->ctx_size, ASSH_ALLOC_SECUR, (void**)&kout)
|
||||
| ASSH_ERRSV_DISCONNECT, err_kin);
|
||||
|
||||
size_t key_size = ASSH_MAX(cipher_in->key_size, cipher_out->key_size) * 8;
|
||||
|
||||
/* initialize key exchange algorithm */
|
||||
ASSH_ERR_GTO(kex->f_init(s, key_size) | ASSH_ERRSV_DISCONNECT, err_kout);
|
||||
|
||||
s->kex = kex;
|
||||
s->host_sign_algo = sign;
|
||||
|
||||
/* initialize input keys structure */
|
||||
kin->cmp_ctx = kin->mac_ctx = kin->cipher_ctx = NULL;
|
||||
kin->cipher = cipher_in;
|
||||
kin->mac = mac_in;
|
||||
kin->cmp = cmp_in;
|
||||
assh_kex_keys_cleanup(s, s->new_keys_in);
|
||||
s->new_keys_in = kin;
|
||||
|
||||
/* initialize output keys structure */
|
||||
kout->cmp_ctx = kout->mac_ctx = kout->cipher_ctx = NULL;
|
||||
kout->cipher = cipher_out;
|
||||
kout->mac = mac_out;
|
||||
kout->cmp = cmp_out;
|
||||
assh_kex_keys_cleanup(s, s->new_keys_out);
|
||||
s->new_keys_out = kout;
|
||||
|
||||
return ASSH_OK;
|
||||
|
||||
err_kout:
|
||||
assh_free(s->ctx, kout);
|
||||
err_kin:
|
||||
assh_free(s->ctx, kin);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* derive cipher/mac/iv key from shared secret */
|
||||
static assh_error_t assh_kex_new_key(struct assh_session_s *s,
|
||||
struct assh_hash_ctx_s *hash_ctx,
|
||||
const struct assh_hash_algo_s *hash_algo,
|
||||
const uint8_t *ex_hash, const uint8_t *secret_str,
|
||||
char c, uint8_t *key, size_t key_size)
|
||||
{
|
||||
assh_error_t err;
|
||||
|
||||
ASSH_SCRATCH_ALLOC(s->ctx, uint8_t, buf, ASSH_MAX_SYMKEY_SIZE + ASSH_MAX_HASH_SIZE,
|
||||
ASSH_ERRSV_CONTINUE, err);
|
||||
|
||||
assert(key_size <= ASSH_MAX_SYMKEY_SIZE);
|
||||
|
||||
/* derive key */
|
||||
size_t hash_size = hash_algo->hash_size ? hash_algo->hash_size : key_size;
|
||||
ASSH_ERR_GTO(assh_hash_init(s->ctx, hash_ctx, hash_algo), err_scratch);
|
||||
|
||||
/* setup session id */
|
||||
if (s->session_id_len == 0)
|
||||
memcpy(s->session_id, ex_hash, s->session_id_len = hash_size);
|
||||
|
||||
assh_hash_update(hash_ctx, secret_str, assh_load_u32(secret_str) + 4);
|
||||
assh_hash_update(hash_ctx, ex_hash, hash_size);
|
||||
assh_hash_update(hash_ctx, &c, 1);
|
||||
assh_hash_update(hash_ctx, s->session_id, s->session_id_len);
|
||||
|
||||
assh_hash_final(hash_ctx, buf, hash_size);
|
||||
assh_hash_cleanup(hash_ctx);
|
||||
|
||||
/* further enlarge derived key if needed */
|
||||
size_t size;
|
||||
for (size = hash_size; size < key_size; size += hash_size)
|
||||
{
|
||||
assert(size + hash_size
|
||||
<= ASSH_MAX_SYMKEY_SIZE + ASSH_MAX_HASH_SIZE);
|
||||
|
||||
ASSH_ERR_GTO(assh_hash_init(s->ctx, hash_ctx, hash_algo), err_scratch);
|
||||
assh_hash_update(hash_ctx, secret_str, assh_load_u32(secret_str) + 4);
|
||||
assh_hash_update(hash_ctx, ex_hash, hash_size);
|
||||
assh_hash_update(hash_ctx, buf, size);
|
||||
|
||||
assh_hash_final(hash_ctx, buf + size, hash_size);
|
||||
assh_hash_cleanup(hash_ctx);
|
||||
}
|
||||
|
||||
memcpy(key, buf, key_size);
|
||||
|
||||
err = ASSH_OK;
|
||||
|
||||
err_scratch:
|
||||
ASSH_SCRATCH_FREE(s->ctx, buf);
|
||||
err:
|
||||
return err;
|
||||
}
|
||||
|
||||
assh_error_t
|
||||
assh_kex_new_keys(struct assh_session_s *s,
|
||||
const struct assh_hash_algo_s *hash_algo,
|
||||
const uint8_t *ex_hash,
|
||||
const uint8_t *secret_str)
|
||||
{
|
||||
assh_error_t err;
|
||||
#if defined(CONFIG_ASSH_SERVER) && defined(CONFIG_ASSH_CLIENT)
|
||||
const char *c = s->ctx->type == ASSH_SERVER ? "ACBDEF" : "BDACFE";
|
||||
#elif defined(CONFIG_ASSH_CLIENT)
|
||||
const char *c = "BDACFE";
|
||||
#elif defined(CONFIG_ASSH_SERVER)
|
||||
const char *c = "ACBDEF";
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ASSH_DEBUG_KEX
|
||||
assh_hexdump("exchange hash", ex_hash, hash_algo->hash_size);
|
||||
#endif
|
||||
|
||||
ASSH_SCRATCH_ALLOC(s->ctx, uint8_t, scratch, hash_algo->ctx_size +
|
||||
/* iv */ ASSH_MAX_BLOCK_SIZE +
|
||||
/* key */ ASSH_MAX(ASSH_MAX_EKEY_SIZE, ASSH_MAX_IKEY_SIZE),
|
||||
ASSH_ERRSV_DISCONNECT, err);
|
||||
|
||||
void *hash_ctx = scratch;
|
||||
uint8_t *iv = scratch + hash_algo->ctx_size;
|
||||
uint8_t *key = iv + ASSH_MAX_BLOCK_SIZE;
|
||||
|
||||
struct assh_kex_keys_s *kin = s->new_keys_in;
|
||||
struct assh_kex_keys_s *kout = s->new_keys_out;
|
||||
|
||||
/* get input cipher iv/key and init cipher */
|
||||
if (!kin->cipher->is_stream)
|
||||
ASSH_ERR_GTO(assh_kex_new_key(s, hash_ctx, hash_algo, ex_hash,
|
||||
secret_str, *c,
|
||||
iv, kin->cipher->block_size)
|
||||
| ASSH_ERRSV_DISCONNECT, err_scratch);
|
||||
c++;
|
||||
|
||||
ASSH_ERR_GTO(assh_kex_new_key(s, hash_ctx, hash_algo, ex_hash,
|
||||
secret_str, *c++,
|
||||
key, kin->cipher->key_size)
|
||||
| ASSH_ERRSV_DISCONNECT, err_scratch);
|
||||
kin->cipher_ctx = (void*)(kin + 1);
|
||||
|
||||
#ifdef CONFIG_ASSH_DEBUG_KEX
|
||||
assh_hexdump("in iv", iv, kin->cipher->block_size);
|
||||
assh_hexdump("in ekey", key, kin->cipher->key_size);
|
||||
#endif
|
||||
|
||||
ASSH_ERR_GTO(kin->cipher->f_init(s->ctx, kin->cipher_ctx, key, iv, 0)
|
||||
| ASSH_ERRSV_DISCONNECT, err_cipher_in);
|
||||
|
||||
/* get output cipher iv/key and init cipher */
|
||||
if (!kout->cipher->is_stream)
|
||||
ASSH_ERR_GTO(assh_kex_new_key(s, hash_ctx, hash_algo, ex_hash,
|
||||
secret_str, *c,
|
||||
iv, kout->cipher->block_size)
|
||||
| ASSH_ERRSV_DISCONNECT, err_scratch);
|
||||
c++;
|
||||
|
||||
ASSH_ERR_GTO(assh_kex_new_key(s, hash_ctx, hash_algo, ex_hash,
|
||||
secret_str, *c++,
|
||||
key, kout->cipher->key_size)
|
||||
| ASSH_ERRSV_DISCONNECT, err_cipher_out);
|
||||
kout->cipher_ctx = (void*)(kout + 1);
|
||||
|
||||
#ifdef CONFIG_ASSH_DEBUG_KEX
|
||||
assh_hexdump("out iv", iv, kout->cipher->block_size);
|
||||
assh_hexdump("out ekey", key, kout->cipher->key_size);
|
||||
#endif
|
||||
|
||||
ASSH_ERR_GTO(kout->cipher->f_init(s->ctx, kout->cipher_ctx, key, iv, 1)
|
||||
| ASSH_ERRSV_DISCONNECT, err_cipher_out);
|
||||
|
||||
/* get input integrity key and init mac */
|
||||
ASSH_ERR_GTO(assh_kex_new_key(s, hash_ctx, hash_algo, ex_hash,
|
||||
secret_str, *c++,
|
||||
key, kin->mac->key_size)
|
||||
| ASSH_ERRSV_DISCONNECT, err_mac_in);
|
||||
kin->mac_ctx = (void*)((uint8_t*)(kin->cipher_ctx) + kin->cipher->ctx_size);
|
||||
ASSH_ERR_GTO(kin->mac->f_init(s->ctx, kin->mac_ctx, key)
|
||||
| ASSH_ERRSV_DISCONNECT, err_mac_in);
|
||||
#ifdef CONFIG_ASSH_DEBUG_KEX
|
||||
assh_hexdump("in ikey", key, kin->mac->key_size);
|
||||
#endif
|
||||
|
||||
/* get output integrity key and init mac */
|
||||
ASSH_ERR_GTO(assh_kex_new_key(s, hash_ctx, hash_algo, ex_hash,
|
||||
secret_str, *c++,
|
||||
key, kout->mac->key_size)
|
||||
| ASSH_ERRSV_DISCONNECT, err_mac_out);
|
||||
kout->mac_ctx = (void*)((uint8_t*)(kout->cipher_ctx) + kout->cipher->ctx_size);
|
||||
ASSH_ERR_GTO(kout->mac->f_init(s->ctx, kout->mac_ctx, key)
|
||||
| ASSH_ERRSV_DISCONNECT, err_mac_out);
|
||||
#ifdef CONFIG_ASSH_DEBUG_KEX
|
||||
assh_hexdump("out ikey", key, kout->mac->key_size);
|
||||
#endif
|
||||
|
||||
/* init input compression */
|
||||
kin->cmp_ctx = (void*)((uint8_t*)(kin->mac_ctx) + kin->mac->ctx_size);
|
||||
ASSH_ERR_GTO(kin->cmp->f_init(s->ctx, kin->cmp_ctx, 0)
|
||||
| ASSH_ERRSV_DISCONNECT, err_cmp_in);
|
||||
|
||||
/* init output compression */
|
||||
kout->cmp_ctx = (void*)((uint8_t*)(kout->mac_ctx) + kout->mac->ctx_size);
|
||||
ASSH_ERR_GTO(kout->cmp->f_init(s->ctx, kout->cmp_ctx, 1)
|
||||
| ASSH_ERRSV_DISCONNECT, err_cmp_out);
|
||||
|
||||
ASSH_SCRATCH_FREE(s->ctx, scratch);
|
||||
return ASSH_OK;
|
||||
|
||||
err_cmp_out:
|
||||
kout->cmp_ctx = NULL;
|
||||
kin->cmp->f_cleanup(s->ctx, kin->cmp_ctx);
|
||||
err_cmp_in:
|
||||
kin->cmp_ctx = NULL;
|
||||
kout->mac->f_cleanup(s->ctx, kout->mac_ctx);
|
||||
err_mac_out:
|
||||
kout->mac_ctx = NULL;
|
||||
kin->mac->f_cleanup(s->ctx, kin->mac_ctx);
|
||||
err_mac_in:
|
||||
kin->mac_ctx = NULL;
|
||||
kout->cipher->f_cleanup(s->ctx, kout->cipher_ctx);
|
||||
err_cipher_out:
|
||||
kout->cipher_ctx = NULL;
|
||||
kin->cipher->f_cleanup(s->ctx, kin->cipher_ctx);
|
||||
err_cipher_in:
|
||||
kin->cipher_ctx = NULL;
|
||||
err_scratch:
|
||||
ASSH_SCRATCH_FREE(s->ctx, scratch);
|
||||
err:
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ASSH_CLIENT
|
||||
assh_error_t
|
||||
assh_kex_client_get_key(struct assh_session_s *s,
|
||||
const struct assh_key_s **host_key,
|
||||
const uint8_t *ks_str,
|
||||
struct assh_event_s *e,
|
||||
assh_error_t (*done)(struct assh_session_s *s,
|
||||
struct assh_event_s *e), void *pv)
|
||||
{
|
||||
assh_error_t err;
|
||||
|
||||
/* load key */
|
||||
const struct assh_algo_sign_s *sign_algo = s->host_sign_algo;
|
||||
|
||||
ASSH_ERR_RET(assh_key_load(s->ctx, host_key, sign_algo->algo.key, ASSH_ALGO_SIGN,
|
||||
ASSH_KEY_FMT_PUB_RFC4253_6_6, ks_str + 4,
|
||||
assh_load_u32(ks_str))
|
||||
| ASSH_ERRSV_DISCONNECT);
|
||||
|
||||
/* check if the key can be used by the algorithm */
|
||||
ASSH_CHK_GTO(!assh_algo_suitable_key(s->ctx, &sign_algo->algo, *host_key),
|
||||
ASSH_ERR_WEAK_ALGORITHM | ASSH_ERRSV_DISCONNECT, err_hk);
|
||||
|
||||
/* Return an host key lookup event */
|
||||
e->id = ASSH_EVENT_KEX_HOSTKEY_LOOKUP;
|
||||
e->f_done = done;
|
||||
e->done_pv = pv;
|
||||
e->kex.hostkey_lookup.key = *host_key;
|
||||
e->kex.hostkey_lookup.accept = 0;
|
||||
|
||||
return ASSH_OK;
|
||||
|
||||
err_hk:
|
||||
assh_key_flush(s->ctx, host_key);
|
||||
return err;
|
||||
}
|
||||
|
||||
assh_error_t
|
||||
assh_kex_client_hash1(struct assh_session_s *s,
|
||||
struct assh_hash_ctx_s *hash_ctx,
|
||||
const uint8_t *k_str)
|
||||
{
|
||||
/* compute the exchange hash H */
|
||||
|
||||
assh_hash_bytes_as_string(hash_ctx, (const uint8_t*)ASSH_IDENT,
|
||||
sizeof(ASSH_IDENT) /* \r\n\0 */ - 3);
|
||||
assh_hash_bytes_as_string(hash_ctx, s->ident_str, s->ident_len);
|
||||
assh_hash_payload_as_string(hash_ctx, s->kex_init_local);
|
||||
assh_hash_payload_as_string(hash_ctx, s->kex_init_remote);
|
||||
assh_hash_string(hash_ctx, k_str);
|
||||
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
assh_error_t
|
||||
assh_kex_client_hash2(struct assh_session_s *s,
|
||||
struct assh_hash_ctx_s *hash_ctx,
|
||||
const struct assh_key_s *host_key,
|
||||
const uint8_t *secret_str,
|
||||
const uint8_t *h_str)
|
||||
{
|
||||
assh_error_t err;
|
||||
struct assh_context_s *c = s->ctx;
|
||||
|
||||
assh_hash_string(hash_ctx, secret_str);
|
||||
|
||||
size_t hash_size = hash_ctx->algo->hash_size;
|
||||
assert(hash_size);
|
||||
|
||||
uint8_t ex_hash[hash_size];
|
||||
assh_hash_final(hash_ctx, ex_hash, hash_size);
|
||||
|
||||
const uint8_t *sign_ptrs[1] = { ex_hash };
|
||||
size_t sign_sizes[1] = { hash_size };
|
||||
|
||||
const struct assh_algo_sign_s *sign_algo = s->host_sign_algo;
|
||||
|
||||
ASSH_CHK_RET(assh_sign_check(c, sign_algo, host_key, 1, sign_ptrs, sign_sizes,
|
||||
h_str + 4, assh_load_u32(h_str)) != ASSH_OK,
|
||||
ASSH_ERR_HOSTKEY_SIGNATURE | ASSH_ERRSV_DISCONNECT);
|
||||
|
||||
/* setup new keys */
|
||||
ASSH_ERR_RET(assh_kex_new_keys(s, hash_ctx->algo, ex_hash, secret_str)
|
||||
| ASSH_ERRSV_DISCONNECT);
|
||||
|
||||
return ASSH_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ASSH_SERVER
|
||||
assh_error_t
|
||||
assh_kex_server_hash1(struct assh_session_s *s, size_t kex_len,
|
||||
struct assh_hash_ctx_s *hash_ctx,
|
||||
struct assh_packet_s **pout, size_t *sign_len,
|
||||
const struct assh_key_s **host_key,
|
||||
enum assh_ssh_msg_e msg)
|
||||
{
|
||||
assh_error_t err;
|
||||
struct assh_context_s *c = s->ctx;
|
||||
|
||||
/* look for an host key pair which can be used with the selected algorithm. */
|
||||
const struct assh_algo_sign_s *sign_algo = s->host_sign_algo;
|
||||
|
||||
ASSH_ERR_RET(assh_key_lookup(c, host_key, &s->host_sign_algo->algo)
|
||||
| ASSH_ERRSV_DISCONNECT);
|
||||
const struct assh_key_s *hk = *host_key;
|
||||
|
||||
/* alloc reply packet */
|
||||
size_t ks_len;
|
||||
ASSH_ERR_RET(assh_key_output(c, hk, NULL, &ks_len,
|
||||
ASSH_KEY_FMT_PUB_RFC4253_6_6)
|
||||
| ASSH_ERRSV_DISCONNECT);
|
||||
|
||||
ASSH_ERR_RET(assh_sign_generate(c, sign_algo, hk, 0, NULL, NULL, NULL, sign_len)
|
||||
| ASSH_ERRSV_DISCONNECT);
|
||||
|
||||
ASSH_ERR_RET(assh_packet_alloc(c, msg,
|
||||
(4 + ks_len) + kex_len + (4 + *sign_len), pout)
|
||||
| ASSH_ERRSV_DISCONNECT);
|
||||
|
||||
/* append public host key to packet. */
|
||||
uint8_t *ks_str;
|
||||
ASSH_ASSERT(assh_packet_add_string(*pout, ks_len, &ks_str));
|
||||
ASSH_ERR_GTO(assh_key_output(c, hk, ks_str, &ks_len,
|
||||
ASSH_KEY_FMT_PUB_RFC4253_6_6)
|
||||
| ASSH_ERRSV_DISCONNECT, err_p);
|
||||
|
||||
assh_packet_shrink_string(*pout, ks_str, ks_len);
|
||||
|
||||
assh_hash_bytes_as_string(hash_ctx, s->ident_str, s->ident_len);
|
||||
assh_hash_bytes_as_string(hash_ctx, (const uint8_t*)ASSH_IDENT,
|
||||
sizeof(ASSH_IDENT) /* \r\n\0 */ - 3);
|
||||
assh_hash_payload_as_string(hash_ctx, s->kex_init_remote);
|
||||
assh_hash_payload_as_string(hash_ctx, s->kex_init_local);
|
||||
assh_hash_string(hash_ctx, ks_str - 4);
|
||||
|
||||
return ASSH_OK;
|
||||
err_p:
|
||||
assh_packet_release(*pout);
|
||||
return err;
|
||||
}
|
||||
|
||||
assh_error_t
|
||||
assh_kex_server_hash2(struct assh_session_s *s,
|
||||
struct assh_hash_ctx_s *hash_ctx,
|
||||
struct assh_packet_s *pout, size_t sign_len,
|
||||
const struct assh_key_s *host_key,
|
||||
const uint8_t *secret_str)
|
||||
{
|
||||
assh_error_t err;
|
||||
struct assh_context_s *c = s->ctx;
|
||||
const struct assh_algo_sign_s *sign_algo = s->host_sign_algo;
|
||||
|
||||
assh_hash_string(hash_ctx, secret_str);
|
||||
|
||||
size_t hash_size = hash_ctx->algo->hash_size;
|
||||
assert(hash_size);
|
||||
|
||||
uint8_t ex_hash[hash_size];
|
||||
assh_hash_final(hash_ctx, ex_hash, hash_size);
|
||||
|
||||
const uint8_t *sign_ptrs[1] = { ex_hash };
|
||||
size_t sign_sizes[1] = { hash_size };
|
||||
|
||||
/* append the signature */
|
||||
uint8_t *sign;
|
||||
ASSH_ASSERT(assh_packet_add_string(pout, sign_len, &sign));
|
||||
|
||||
ASSH_ERR_RET(assh_sign_generate(c, sign_algo, host_key, 1,
|
||||
sign_ptrs, sign_sizes, sign, &sign_len)
|
||||
| ASSH_ERRSV_DISCONNECT);
|
||||
assh_packet_shrink_string(pout, sign, sign_len);
|
||||
|
||||
/* setup new symmetric keys */
|
||||
ASSH_ERR_RET(assh_kex_new_keys(s, hash_ctx->algo, ex_hash, secret_str)
|
||||
| ASSH_ERRSV_DISCONNECT);
|
||||
|
||||
return ASSH_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
void assh_kex_keys_cleanup(struct assh_session_s *s, struct assh_kex_keys_s *keys)
|
||||
{
|
||||
if (keys == NULL)
|
||||
return;
|
||||
|
||||
if (keys->cipher_ctx != NULL)
|
||||
keys->cipher->f_cleanup(s->ctx, keys->cipher_ctx);
|
||||
if (keys->mac_ctx != NULL)
|
||||
keys->mac->f_cleanup(s->ctx, keys->mac_ctx);
|
||||
if (keys->cmp_ctx != NULL)
|
||||
keys->cmp->f_cleanup(s->ctx, keys->cmp_ctx);
|
||||
|
||||
assh_free(s->ctx, keys);
|
||||
}
|
||||
|
||||
assh_error_t assh_kex_end(struct assh_session_s *s, assh_bool_t accept)
|
||||
{
|
||||
assh_error_t err;
|
||||
|
||||
if (s->kex_pv != NULL)
|
||||
s->kex->f_cleanup(s);
|
||||
assert(s->kex_pv == NULL);
|
||||
|
||||
/* release KEX init packets */
|
||||
assh_packet_release(s->kex_init_local);
|
||||
s->kex_init_local = NULL;
|
||||
|
||||
assh_packet_release(s->kex_init_remote);
|
||||
s->kex_init_remote = NULL;
|
||||
|
||||
ASSH_CHK_RET(!accept, ASSH_ERR_KEX_FAILED | ASSH_ERRSV_DISCONNECT);
|
||||
|
||||
s->kex_bytes = 0;
|
||||
|
||||
/* next state is wait for NEWKEY packet */
|
||||
assh_transport_state(s, ASSH_TR_NEWKEY);
|
||||
|
||||
/* send a NEWKEY packet */
|
||||
struct assh_packet_s *p;
|
||||
ASSH_ERR_RET(assh_packet_alloc(s->ctx, SSH_MSG_NEWKEYS, 0, &p) | ASSH_ERRSV_DISCONNECT);
|
||||
assh_transport_push(s, p);
|
||||
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
assh_error_t
|
||||
assh_kex_set_threshold(struct assh_session_s *s, uint32_t bytes)
|
||||
{
|
||||
assh_error_t err;
|
||||
|
||||
ASSH_CHK_RET(bytes < 1 || bytes > ASSH_REKEX_THRESHOLD,
|
||||
ASSH_ERR_BAD_ARG | ASSH_ERRSV_CONTINUE);
|
||||
|
||||
s->kex_max_bytes = bytes;
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
|
||||
libassh - asynchronous ssh2 client/server library.
|
||||
|
||||
Copyright (C) 2013 Alexandre Becoulet <alexandre.becoulet@free.fr>
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#include <assh/assh_key.h>
|
||||
#include <assh/assh_sign.h>
|
||||
#include <assh/assh_algo.h>
|
||||
#include <assh/assh_packet.h>
|
||||
#include <assh/assh_context.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
static const struct assh_key_ops_s *
|
||||
assh_key_algo_guess(struct assh_context_s *c,
|
||||
enum assh_key_format_e format,
|
||||
const uint8_t *blob, size_t blob_len,
|
||||
enum assh_algo_class_e role)
|
||||
{
|
||||
const struct assh_key_ops_s *algo;
|
||||
|
||||
switch (format)
|
||||
{
|
||||
case ASSH_KEY_FMT_PUB_RFC4253_6_6: {
|
||||
uint8_t *end;
|
||||
if (assh_check_string(blob, blob_len, blob, &end))
|
||||
return NULL;
|
||||
const char *name = (const char*)blob + 4;
|
||||
size_t name_len = end - blob - 4;
|
||||
uint_fast16_t i;
|
||||
|
||||
for (i = 0; ; i++)
|
||||
{
|
||||
if (i == c->algos_count)
|
||||
return NULL;
|
||||
algo = c->algos[i]->key;
|
||||
if (algo != NULL && c->algos[i]->class_ != role &&
|
||||
!strncmp(algo->type, name, name_len) &&
|
||||
!algo->type[name_len])
|
||||
return algo;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
assh_error_t assh_key_load(struct assh_context_s *c,
|
||||
const struct assh_key_s **key,
|
||||
const struct assh_key_ops_s *algo,
|
||||
enum assh_algo_class_e role,
|
||||
enum assh_key_format_e format,
|
||||
const uint8_t *blob, size_t blob_len)
|
||||
{
|
||||
assh_error_t err;
|
||||
|
||||
if (algo == NULL)
|
||||
algo = assh_key_algo_guess(c, format, blob, blob_len, role);
|
||||
ASSH_CHK_RET(algo == NULL, ASSH_ERR_MISSING_ALGO);
|
||||
|
||||
struct assh_key_s *k;
|
||||
|
||||
ASSH_ERR_RET(algo->f_load(c, algo, blob, blob_len, &k, format));
|
||||
|
||||
k->role = role;
|
||||
k->next = *key;
|
||||
*key = k;
|
||||
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
assh_error_t
|
||||
assh_key_create(struct assh_context_s *c,
|
||||
const struct assh_key_s **key, size_t bits,
|
||||
const struct assh_key_ops_s *algo,
|
||||
enum assh_algo_class_e role)
|
||||
{
|
||||
assh_error_t err;
|
||||
struct assh_key_s *k;
|
||||
|
||||
ASSH_ERR_RET(algo->f_create(c, algo, bits, &k));
|
||||
|
||||
k->role = role;
|
||||
k->next = *key;
|
||||
*key = k;
|
||||
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
void assh_key_drop(struct assh_context_s *c,
|
||||
const struct assh_key_s **head)
|
||||
{
|
||||
const struct assh_key_s *k = *head;
|
||||
if (k == NULL)
|
||||
return;
|
||||
*head = k->next;
|
||||
k->algo->f_cleanup(c, (struct assh_key_s *)k);
|
||||
}
|
||||
|
||||
assh_error_t
|
||||
assh_key_lookup(struct assh_context_s *c,
|
||||
const struct assh_key_s **key,
|
||||
const struct assh_algo_s *algo)
|
||||
{
|
||||
const struct assh_key_s *k = c->keys;
|
||||
|
||||
while (k != NULL && !assh_algo_suitable_key(c, algo, k))
|
||||
k = k->next;
|
||||
if (k == NULL)
|
||||
return ASSH_NOT_FOUND;
|
||||
|
||||
if (key != NULL)
|
||||
*key = k;
|
||||
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
|
||||
libassh - asynchronous ssh2 client/server library.
|
||||
|
||||
Copyright (C) 2013 Alexandre Becoulet <alexandre.becoulet@free.fr>
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#include <assh/assh.h>
|
||||
#include <assh/assh_map.h>
|
||||
|
||||
#define ASSH_MAP_W (sizeof(assh_map_id_t) * 8)
|
||||
|
||||
struct assh_map_entry_s *
|
||||
assh_map_insert(struct assh_map_entry_s **root,
|
||||
struct assh_map_entry_s *item)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
struct assh_map_entry_s *e = *root;
|
||||
if (e == NULL)
|
||||
{
|
||||
item->lz = ASSH_MAP_W;
|
||||
item->link[0] = item->link[1] = 0;
|
||||
*root = item;
|
||||
return NULL;
|
||||
}
|
||||
assh_map_id_t a = item->id, b = e->id, x = a ^ b;
|
||||
if (x & (-2LL << (ASSH_MAP_W - 1 - e->lz)))
|
||||
{
|
||||
item->lz = ASSH_CLZ32(x);
|
||||
item->link[0] = 0;
|
||||
item->link[1] = e;
|
||||
*root = item;
|
||||
return NULL;
|
||||
}
|
||||
if (a == b)
|
||||
return e;
|
||||
root = &e->link[(x >> (ASSH_MAP_W - 1 - e->lz)) & 1];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
assh_map_remove(struct assh_map_entry_s **parent,
|
||||
struct assh_map_entry_s *item)
|
||||
{
|
||||
if (!item->link[0])
|
||||
{
|
||||
*parent = item->link[1];
|
||||
return;
|
||||
}
|
||||
|
||||
struct assh_map_entry_s **p = &item->link[0], *e = *p;
|
||||
while (e->link[0])
|
||||
{
|
||||
p = &e->link[0];
|
||||
e = *p;
|
||||
}
|
||||
*p = e->link[1];
|
||||
*parent = e;
|
||||
e->lz = item->lz;
|
||||
e->link[0] = item->link[0];
|
||||
e->link[1] = item->link[1];
|
||||
}
|
||||
|
||||
struct assh_map_entry_s *
|
||||
assh_map_lookup(struct assh_map_entry_s **root,
|
||||
assh_map_id_t id, struct assh_map_entry_s ***parent)
|
||||
{
|
||||
struct assh_map_entry_s *r = *root;
|
||||
|
||||
while (r != NULL)
|
||||
{
|
||||
assh_map_id_t x = id ^ r->id;
|
||||
if (!x)
|
||||
break;
|
||||
if ((x & (-2LL << (ASSH_MAP_W - 1 - r->lz))))
|
||||
return NULL;
|
||||
root = r->link + ((x >> (ASSH_MAP_W - 1 - r->lz)) & 1);
|
||||
r = *root;
|
||||
}
|
||||
if (parent != NULL)
|
||||
*parent = root;
|
||||
return r;
|
||||
}
|
||||
|
||||
struct assh_map_entry_s *
|
||||
assh_map_head(struct assh_map_entry_s **root,
|
||||
struct assh_map_entry_s ***parent)
|
||||
{
|
||||
struct assh_map_entry_s *r = *root;
|
||||
|
||||
while (r != NULL)
|
||||
{
|
||||
root = r->link + 0;
|
||||
r = *root;
|
||||
}
|
||||
if (parent != NULL)
|
||||
*parent = root;
|
||||
return r;
|
||||
}
|
||||
|
||||
void assh_map_iter(struct assh_map_entry_s *root, void *ctx,
|
||||
void (*iter)(struct assh_map_entry_s *, void *))
|
||||
{
|
||||
struct assh_map_entry_s *stack[ASSH_MAP_W], *next, *l1;
|
||||
int i = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
for (; root != NULL; root = next)
|
||||
{
|
||||
next = root->link[0];
|
||||
l1 = root->link[1];
|
||||
if (l1 != NULL)
|
||||
stack[i++] = l1;
|
||||
iter(root, ctx);
|
||||
}
|
||||
if (i == 0)
|
||||
break;
|
||||
root = stack[--i];
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,278 @@
|
|||
/*
|
||||
|
||||
libassh - asynchronous ssh2 client/server library.
|
||||
|
||||
Copyright (C) 2013 Alexandre Becoulet <alexandre.becoulet@free.fr>
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#include <assh/assh_packet.h>
|
||||
#include <assh/assh_bignum.h>
|
||||
#include <assh/assh_queue.h>
|
||||
#include <assh/assh_session.h>
|
||||
#include <assh/assh_alloc.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
/* This function returns the index of the bucket associated to a given
|
||||
packet size in the allocator pool. */
|
||||
static inline struct assh_packet_pool_s *
|
||||
assh_packet_pool(struct assh_context_s *c, uint32_t size)
|
||||
{
|
||||
int i = sizeof(int) * 8 - ASSH_CLZ32(size) - ASSH_PCK_POOL_MIN;
|
||||
if (i < 0)
|
||||
i = 0;
|
||||
else if (i >= ASSH_PCK_POOL_SIZE)
|
||||
i = ASSH_PCK_POOL_SIZE - 1;
|
||||
return c->pool + i;
|
||||
}
|
||||
|
||||
assh_error_t
|
||||
assh_packet_alloc(struct assh_context_s *c,
|
||||
uint8_t msg, size_t payload_size,
|
||||
struct assh_packet_s **result)
|
||||
{
|
||||
assh_error_t err;
|
||||
|
||||
ASSH_CHK_RET(payload_size > ASSH_MAX_PCK_PAYLOAD_SIZE, ASSH_ERR_OUTPUT_OVERFLOW);
|
||||
|
||||
size_t size = /* pck_len */ 4 + /* pad_len */ 1 + /* msg */ 1 + payload_size +
|
||||
/* mac */ ASSH_MAX_MAC_SIZE + /* padding */ (4 + ASSH_MAX_BLOCK_SIZE - 1);
|
||||
|
||||
ASSH_ERR_RET(assh_packet_alloc2(c, msg, size, result));
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
assh_error_t
|
||||
assh_packet_alloc2(struct assh_context_s *c,
|
||||
uint8_t msg, size_t size,
|
||||
struct assh_packet_s **result)
|
||||
{
|
||||
struct assh_packet_s *p, **r;
|
||||
assh_error_t err;
|
||||
struct assh_packet_pool_s *pl = assh_packet_pool(c, size);
|
||||
|
||||
/* get from pool */
|
||||
for (r = &pl->pck; (p = *r) != NULL; r = &(*r)->pool_next)
|
||||
{
|
||||
if (p->alloc_size >= size)
|
||||
{
|
||||
*r = p->pool_next;
|
||||
pl->size -= p->alloc_size;
|
||||
pl->count--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* fallback to alloc */
|
||||
if (p == NULL)
|
||||
{
|
||||
ASSH_ERR_RET(assh_alloc(c, sizeof(*p) + size, ASSH_ALLOC_PACKET, (void*)&p));
|
||||
p->alloc_size = size;
|
||||
}
|
||||
|
||||
/* init */
|
||||
p->ref_count = 1;
|
||||
p->ctx = c;
|
||||
p->data_size = /* pck_len */ 4 + /* pad_len */ 1 + /* msg */ 1;
|
||||
memset(p->data, 0, p->alloc_size);
|
||||
p->head.msg = msg;
|
||||
|
||||
*result = p;
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
void assh_packet_release(struct assh_packet_s *p)
|
||||
{
|
||||
if (p == NULL || --p->ref_count > 0)
|
||||
return;
|
||||
|
||||
assert(p->ref_count == 0);
|
||||
|
||||
struct assh_context_s *c = p->ctx;
|
||||
struct assh_packet_pool_s *pl = assh_packet_pool(c, p->alloc_size);
|
||||
|
||||
if (pl->size + p->alloc_size >= c->pck_pool_max_bsize ||
|
||||
c->pck_pool_size + p->alloc_size >= c->pck_pool_max_size)
|
||||
{
|
||||
assh_free(c, p);
|
||||
}
|
||||
else
|
||||
{
|
||||
p->pool_next = pl->pck;
|
||||
pl->pck = p;
|
||||
pl->count++;
|
||||
pl->size += p->alloc_size;
|
||||
}
|
||||
}
|
||||
|
||||
ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_packet_dup(struct assh_packet_s *p, struct assh_packet_s **copy)
|
||||
{
|
||||
assh_error_t err;
|
||||
|
||||
ASSH_ERR_RET(assh_packet_alloc2(p->ctx, 0, p->alloc_size, copy));
|
||||
struct assh_packet_s *r = *copy;
|
||||
|
||||
memcpy(r->data, p->data, p->data_size);
|
||||
r->data_size = p->data_size;
|
||||
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
assh_error_t assh_packet_add_mpint(struct assh_context_s *ctx,
|
||||
struct assh_packet_s *p,
|
||||
const struct assh_bignum_s *bn)
|
||||
{
|
||||
assh_error_t err;
|
||||
size_t l = assh_bignum_size_of_num(ASSH_BIGNUM_MPINT, bn);
|
||||
|
||||
uint8_t *s;
|
||||
ASSH_ERR_RET(assh_packet_add_array(p, l, &s));
|
||||
|
||||
ASSH_ERR_RET(assh_bignum_convert(ctx,
|
||||
ASSH_BIGNUM_NATIVE, ASSH_BIGNUM_MPINT, bn, s));
|
||||
|
||||
p->data_size -= l - assh_load_u32(s) - 4;
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
assh_error_t
|
||||
assh_check_asn1(const uint8_t *buffer, size_t buffer_len, const uint8_t *str,
|
||||
uint8_t **value, uint8_t **next)
|
||||
{
|
||||
assh_error_t err;
|
||||
|
||||
const uint8_t *e = buffer + buffer_len;
|
||||
ASSH_CHK_RET(str < buffer || str > e - 2, ASSH_ERR_INPUT_OVERFLOW);
|
||||
|
||||
str++; /* discard type identifer */
|
||||
unsigned int l = *str++;
|
||||
if (l & 0x80) /* long length form ? */
|
||||
{
|
||||
unsigned int ll = l & 0x7f;
|
||||
ASSH_CHK_RET(e - str < ll, ASSH_ERR_INPUT_OVERFLOW);
|
||||
for (l = 0; ll > 0; ll--)
|
||||
l = (l << 8) | *str++;
|
||||
}
|
||||
ASSH_CHK_RET(e - str < l, ASSH_ERR_INPUT_OVERFLOW);
|
||||
if (value != NULL)
|
||||
*value = (uint8_t*)str;
|
||||
if (next != NULL)
|
||||
*next = (uint8_t*)str + l;
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
assh_error_t
|
||||
assh_check_string(const uint8_t *buffer, size_t buffer_len,
|
||||
const uint8_t *str, uint8_t **next)
|
||||
{
|
||||
assh_error_t err;
|
||||
|
||||
const uint8_t *e = buffer + buffer_len;
|
||||
ASSH_CHK_RET(str < buffer || str > e - 4, ASSH_ERR_INPUT_OVERFLOW);
|
||||
uint32_t s = assh_load_u32(str);
|
||||
ASSH_CHK_RET(e - 4 - str < s, ASSH_ERR_INPUT_OVERFLOW);
|
||||
if (next != NULL)
|
||||
*next = (uint8_t*)str + 4 + s;
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
assh_error_t
|
||||
assh_check_array(const uint8_t *buffer, size_t buffer_len,
|
||||
const uint8_t *array, size_t array_len, uint8_t **next)
|
||||
{
|
||||
assh_error_t err;
|
||||
|
||||
const uint8_t *e = buffer + buffer_len;
|
||||
ASSH_CHK_RET(array < buffer || array > e, ASSH_ERR_INPUT_OVERFLOW);
|
||||
ASSH_CHK_RET(e - array < array_len, ASSH_ERR_INPUT_OVERFLOW);
|
||||
if (next != NULL)
|
||||
*next = (uint8_t*)array + array_len;
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
assh_error_t
|
||||
assh_packet_add_array(struct assh_packet_s *p, size_t len, uint8_t **result)
|
||||
{
|
||||
assh_error_t err;
|
||||
|
||||
ASSH_CHK_RET(p->data_size + len > p->alloc_size, ASSH_ERR_OUTPUT_OVERFLOW);
|
||||
uint8_t *d = p->data + p->data_size;
|
||||
p->data_size += len;
|
||||
*result = d;
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
assh_error_t
|
||||
assh_packet_add_string(struct assh_packet_s *p, size_t len, uint8_t **result)
|
||||
{
|
||||
assh_error_t err;
|
||||
|
||||
uint8_t *d;
|
||||
ASSH_ERR_RET(assh_packet_add_array(p, len + 4, &d));
|
||||
assh_store_u32(d, len);
|
||||
if (result != NULL)
|
||||
*result = d + 4;
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
assh_error_t
|
||||
assh_packet_enlarge_string(struct assh_packet_s *p, uint8_t *str,
|
||||
size_t len, uint8_t **result)
|
||||
{
|
||||
assh_error_t err;
|
||||
|
||||
size_t olen = assh_load_u32(str - 4);
|
||||
assert(str + olen == p->data + p->data_size);
|
||||
ASSH_ERR_RET(assh_packet_add_array(p, len, result));
|
||||
assh_store_u32(str - 4, olen + len);
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
void
|
||||
assh_packet_shrink_string(struct assh_packet_s *p, uint8_t *str,
|
||||
size_t new_len)
|
||||
{
|
||||
size_t olen = assh_load_u32(str - 4);
|
||||
assert(str + olen == p->data + p->data_size);
|
||||
assert(olen >= new_len);
|
||||
assh_store_u32(str - 4, new_len);
|
||||
p->data_size -= olen - new_len;
|
||||
}
|
||||
|
||||
void
|
||||
assh_packet_string_resized(struct assh_packet_s *p, uint8_t *str)
|
||||
{
|
||||
size_t len = assh_load_u32(str - 4);
|
||||
p->data_size = str - p->data + len;
|
||||
}
|
||||
|
||||
assh_error_t
|
||||
assh_ssh_string_copy(const uint8_t *ssh_str, char *nul_str, size_t max_len)
|
||||
{
|
||||
assh_error_t err;
|
||||
|
||||
size_t len = assh_load_u32(ssh_str);
|
||||
assert(max_len > 0);
|
||||
ASSH_CHK_RET(len > max_len - 1, ASSH_ERR_OUTPUT_OVERFLOW);
|
||||
memcpy(nul_str, ssh_str + 4, len);
|
||||
nul_str[len] = '\0';
|
||||
return ASSH_OK;
|
||||
}
|
|
@ -0,0 +1,206 @@
|
|||
/*
|
||||
|
||||
libassh - asynchronous ssh2 client/server library.
|
||||
|
||||
Copyright (C) 2013 Alexandre Becoulet <alexandre.becoulet@free.fr>
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#include <assh/assh_context.h>
|
||||
#include <assh/assh_session.h>
|
||||
#include <assh/assh_service.h>
|
||||
#include <assh/assh_packet.h>
|
||||
#include <assh/assh_transport.h>
|
||||
|
||||
#include <assh/assh_userauth_client.h>
|
||||
#include <assh/assh_userauth_server.h>
|
||||
#include <assh/assh_connection.h>
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
|
||||
assh_error_t assh_service_register(struct assh_context_s *c,
|
||||
struct assh_service_s *srv)
|
||||
{
|
||||
assh_error_t err;
|
||||
|
||||
ASSH_CHK_RET(srv->side != ASSH_CLIENT_SERVER &&
|
||||
srv->side != c->type, ASSH_ERR_NOTSUP);
|
||||
|
||||
ASSH_CHK_RET(c->srvs_count == ASSH_MAX_SERVICES, ASSH_ERR_MEM);
|
||||
|
||||
c->srvs[c->srvs_count++] = srv;
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
assh_error_t
|
||||
assh_service_register_va(struct assh_context_s *c, ...)
|
||||
{
|
||||
assh_error_t err = ASSH_OK;
|
||||
va_list ap;
|
||||
va_start(ap, c);
|
||||
|
||||
while (1)
|
||||
{
|
||||
struct assh_service_s *srv = va_arg(ap, void*);
|
||||
if (srv == NULL)
|
||||
break;
|
||||
ASSH_ERR_GTO(assh_service_register(c, srv), err_);
|
||||
}
|
||||
err_:
|
||||
|
||||
va_end(ap);
|
||||
return err;
|
||||
}
|
||||
|
||||
assh_error_t assh_service_register_default(struct assh_context_s *c)
|
||||
{
|
||||
assh_error_t err;
|
||||
|
||||
switch (c->type)
|
||||
{
|
||||
#ifdef CONFIG_ASSH_CLIENT
|
||||
case ASSH_CLIENT:
|
||||
ASSH_ERR_RET(assh_service_register_va(c, &assh_service_userauth_client,
|
||||
&assh_service_connection, NULL));
|
||||
return ASSH_OK;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ASSH_SERVER
|
||||
case ASSH_SERVER:
|
||||
ASSH_ERR_RET(assh_service_register_va(c, &assh_service_userauth_server,
|
||||
&assh_service_connection, NULL));
|
||||
return ASSH_OK;
|
||||
#endif
|
||||
|
||||
default:
|
||||
assert(!"possible");
|
||||
}
|
||||
}
|
||||
|
||||
assh_error_t assh_service_by_name(struct assh_context_s *c,
|
||||
size_t name_len, const char *name,
|
||||
const struct assh_service_s **srv_)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
/* lookup service name */
|
||||
for (i = 0; i < c->srvs_count; i++)
|
||||
{
|
||||
const struct assh_service_s *srv = c->srvs[i];
|
||||
|
||||
if (!strncmp(srv->name, name, name_len) &&
|
||||
srv->name[name_len] == '\0')
|
||||
{
|
||||
*srv_ = srv;
|
||||
return ASSH_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return ASSH_NOT_FOUND;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ASSH_SERVER
|
||||
assh_error_t assh_service_got_request(struct assh_session_s *s,
|
||||
struct assh_packet_s *p)
|
||||
{
|
||||
assh_error_t err;
|
||||
|
||||
ASSH_CHK_RET(s->srv != NULL, ASSH_ERR_PROTOCOL);
|
||||
|
||||
uint8_t *name = p->head.end, *name_end;
|
||||
ASSH_ERR_RET(assh_packet_check_string(p, name, &name_end));
|
||||
|
||||
size_t name_len = name_end - name - 4;
|
||||
|
||||
/* lookup service */
|
||||
const struct assh_service_s *srv;
|
||||
ASSH_CHK_RET(assh_service_by_name(s->ctx, name_len,
|
||||
(const char *)name + 4, &srv) != ASSH_OK,
|
||||
ASSH_ERR_SERVICE_NA);
|
||||
|
||||
struct assh_packet_s *pout;
|
||||
ASSH_ERR_RET(assh_packet_alloc(s->ctx, SSH_MSG_SERVICE_ACCEPT,
|
||||
name_len + 4, &pout));
|
||||
|
||||
/* init service */
|
||||
ASSH_ERR_GTO(srv->f_init(s), err_pkt);
|
||||
|
||||
/* send accept packet */
|
||||
ASSH_ASSERT(assh_packet_add_string(pout, name_len, &name));
|
||||
memcpy(name, srv->name, name_len);
|
||||
assh_transport_push(s, pout);
|
||||
|
||||
return ASSH_OK;
|
||||
err_pkt:
|
||||
assh_packet_release(pout);
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ASSH_CLIENT
|
||||
assh_error_t assh_service_got_accept(struct assh_session_s *s,
|
||||
struct assh_packet_s *p)
|
||||
{
|
||||
assh_error_t err;
|
||||
|
||||
ASSH_CHK_RET(s->srv_rq == NULL || s->srv != NULL, ASSH_ERR_PROTOCOL);
|
||||
|
||||
/* check accepted service name */
|
||||
uint8_t *name = p->head.end, *name_end;
|
||||
ASSH_ERR_RET(assh_packet_check_string(p, name, &name_end));
|
||||
|
||||
ASSH_CHK_RET(assh_ssh_string_compare(name, s->srv_rq->name),
|
||||
ASSH_ERR_PROTOCOL);
|
||||
|
||||
/* init service */
|
||||
const struct assh_service_s *srv = s->srv_rq;
|
||||
s->srv_rq = NULL;
|
||||
ASSH_ERR_RET(srv->f_init(s));
|
||||
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
assh_error_t assh_service_send_request(struct assh_session_s *s)
|
||||
{
|
||||
assh_error_t err;
|
||||
|
||||
/** get next service to request */
|
||||
ASSH_CHK_RET(s->srv_index >= s->ctx->srvs_count,
|
||||
ASSH_ERR_NO_MORE_SERVICE | ASSH_ERRSV_DISCONNECT);
|
||||
|
||||
const struct assh_service_s *srv = s->ctx->srvs[s->srv_index];
|
||||
|
||||
/* send request packet */
|
||||
struct assh_packet_s *pout;
|
||||
size_t name_len = strlen(srv->name);
|
||||
uint8_t *name;
|
||||
|
||||
ASSH_ERR_RET(assh_packet_alloc(s->ctx, SSH_MSG_SERVICE_REQUEST,
|
||||
name_len + 4, &pout));
|
||||
ASSH_ASSERT(assh_packet_add_string(pout, name_len, &name));
|
||||
|
||||
memcpy(name, srv->name, name_len);
|
||||
assh_transport_push(s, pout);
|
||||
|
||||
s->srv_index++;
|
||||
s->srv_rq = srv;
|
||||
|
||||
return ASSH_OK;
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,260 @@
|
|||
/*
|
||||
|
||||
libassh - asynchronous ssh2 client/server library.
|
||||
|
||||
Copyright (C) 2013 Alexandre Becoulet <alexandre.becoulet@free.fr>
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include <assh/assh_session.h>
|
||||
#include <assh/assh_context.h>
|
||||
#include <assh/assh_packet.h>
|
||||
#include <assh/assh_kex.h>
|
||||
#include <assh/assh_prng.h>
|
||||
#include <assh/assh_queue.h>
|
||||
#include <assh/assh_service.h>
|
||||
#include <assh/assh_transport.h>
|
||||
#include <assh/assh_alloc.h>
|
||||
|
||||
assh_error_t assh_session_init(struct assh_context_s *c,
|
||||
struct assh_session_s *s)
|
||||
{
|
||||
assh_error_t err;
|
||||
|
||||
ASSH_ERR_RET(assh_context_prng(c, NULL));
|
||||
s->ctx = c;
|
||||
|
||||
assh_transport_state(s, ASSH_TR_KEX_INIT);
|
||||
|
||||
s->ident_len = 0;
|
||||
s->session_id_len = 0;
|
||||
|
||||
s->kex_init_local = NULL;
|
||||
s->kex_init_remote = NULL;
|
||||
s->kex_pv = NULL;
|
||||
s->kex_bytes = 0;
|
||||
s->kex_max_bytes = ASSH_REKEX_THRESHOLD;
|
||||
|
||||
#ifdef CONFIG_ASSH_CLIENT
|
||||
s->srv_rq = NULL;
|
||||
s->srv_index = 0;
|
||||
#endif
|
||||
s->srv = NULL;
|
||||
|
||||
s->stream_out_st = ASSH_TR_OUT_IDENT;
|
||||
assh_queue_init(&s->out_queue);
|
||||
assh_queue_init(&s->alt_queue);
|
||||
s->stream_out_size = 0;
|
||||
s->cur_keys_out = NULL;
|
||||
s->new_keys_out = NULL;
|
||||
s->out_seq = 0;
|
||||
|
||||
s->stream_in_st = ASSH_TR_IN_IDENT;
|
||||
s->stream_in_pck = NULL;
|
||||
s->stream_in_size = 0;
|
||||
s->in_pck = NULL;
|
||||
s->cur_keys_in = NULL;
|
||||
s->new_keys_in = NULL;
|
||||
s->in_seq = 0;
|
||||
|
||||
c->session_count++;
|
||||
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
assh_error_t assh_session_create(struct assh_context_s *c,
|
||||
struct assh_session_s **s)
|
||||
{
|
||||
assh_error_t err;
|
||||
ASSH_ERR_RET(assh_alloc(c, sizeof(**s), ASSH_ALLOC_INTERNAL, (void**)s));
|
||||
ASSH_ERR_GTO(assh_session_init(c, *s), err);
|
||||
return ASSH_OK;
|
||||
err:
|
||||
assh_free(c, *s);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void assh_pck_queue_cleanup(struct assh_queue_s *q)
|
||||
{
|
||||
while (q->count > 0)
|
||||
{
|
||||
struct assh_queue_entry_s *e = assh_queue_front(q);
|
||||
assh_queue_remove(q, e);
|
||||
|
||||
struct assh_packet_s *p = (struct assh_packet_s*)e;
|
||||
assh_packet_release(p);
|
||||
}
|
||||
}
|
||||
|
||||
void assh_session_release(struct assh_session_s *s)
|
||||
{
|
||||
assh_session_cleanup(s);
|
||||
assh_free(s->ctx, s);
|
||||
}
|
||||
|
||||
void assh_session_cleanup(struct assh_session_s *s)
|
||||
{
|
||||
if (s->kex_pv != NULL)
|
||||
s->kex->f_cleanup(s);
|
||||
assert(s->kex_pv == NULL);
|
||||
|
||||
if (s->srv != NULL)
|
||||
s->srv->f_cleanup(s);
|
||||
|
||||
assh_packet_release(s->kex_init_local);
|
||||
assh_packet_release(s->kex_init_remote);
|
||||
|
||||
assh_pck_queue_cleanup(&s->out_queue);
|
||||
assh_pck_queue_cleanup(&s->alt_queue);
|
||||
|
||||
assh_kex_keys_cleanup(s, s->cur_keys_in);
|
||||
assh_kex_keys_cleanup(s, s->cur_keys_out);
|
||||
assh_kex_keys_cleanup(s, s->new_keys_in);
|
||||
assh_kex_keys_cleanup(s, s->new_keys_out);
|
||||
|
||||
assh_packet_release(s->in_pck);
|
||||
assh_packet_release(s->stream_in_pck);
|
||||
|
||||
s->ctx->session_count--;
|
||||
}
|
||||
|
||||
assh_error_t assh_session_error(struct assh_session_s *s, assh_error_t inerr)
|
||||
{
|
||||
if ((inerr & ASSH_ERRSV_FATAL) || s->tr_st == ASSH_TR_CLOSED)
|
||||
{
|
||||
assh_transport_state(s, ASSH_TR_CLOSED);
|
||||
return inerr | ASSH_ERRSV_FATAL;
|
||||
}
|
||||
|
||||
if ((inerr & ASSH_ERRSV_FIN) || s->tr_st == ASSH_TR_FIN)
|
||||
{
|
||||
assh_transport_state(s, ASSH_TR_FIN);
|
||||
return inerr | ASSH_ERRSV_FIN;
|
||||
}
|
||||
|
||||
uint32_t reason = SSH_DISCONNECT_RESERVED;
|
||||
const char *desc = NULL;
|
||||
|
||||
switch (inerr & 0xfff)
|
||||
{
|
||||
case ASSH_ERR_BAD_DATA:
|
||||
case ASSH_ERR_PROTOCOL:
|
||||
#ifdef CONFIG_ASSH_VERBOSE_ERROR
|
||||
reason = SSH_DISCONNECT_PROTOCOL_ERROR;
|
||||
break;
|
||||
#endif
|
||||
|
||||
case ASSH_ERR_INPUT_OVERFLOW:
|
||||
case ASSH_ERR_OUTPUT_OVERFLOW:
|
||||
case ASSH_ERR_IO:
|
||||
case ASSH_ERR_BAD_VERSION:
|
||||
case ASSH_ERR_DISCONNECTED:
|
||||
case ASSH_ERR_CLOSED:
|
||||
assh_transport_state(s, ASSH_TR_FIN);
|
||||
return inerr | ASSH_ERRSV_FIN;
|
||||
|
||||
case ASSH_ERR_STATE:
|
||||
assh_transport_state(s, ASSH_TR_CLOSED);
|
||||
return inerr | ASSH_ERRSV_FATAL;
|
||||
|
||||
case ASSH_ERR_MEM:
|
||||
reason = SSH_DISCONNECT_RESERVED;
|
||||
#ifdef CONFIG_ASSH_VERBOSE_ERROR
|
||||
desc = "memory resource shortage";
|
||||
#endif
|
||||
break;
|
||||
case ASSH_ERR_NUM_OVERFLOW:
|
||||
reason = SSH_DISCONNECT_RESERVED;
|
||||
#ifdef CONFIG_ASSH_VERBOSE_ERROR
|
||||
desc = "numerical overflow";
|
||||
#endif
|
||||
break;
|
||||
case ASSH_ERR_MAC:
|
||||
#ifdef CONFIG_ASSH_VERBOSE_ERROR
|
||||
desc = "mac error";
|
||||
#endif
|
||||
reason = SSH_DISCONNECT_MAC_ERROR;
|
||||
break;
|
||||
case ASSH_ERR_CRYPTO:
|
||||
#ifdef CONFIG_ASSH_VERBOSE_ERROR
|
||||
desc = "crypto error";
|
||||
#endif
|
||||
reason = SSH_DISCONNECT_RESERVED;
|
||||
break;
|
||||
case ASSH_ERR_NOTSUP:
|
||||
desc = "not supported";
|
||||
reason = SSH_DISCONNECT_RESERVED;
|
||||
break;
|
||||
case ASSH_ERR_KEX_FAILED:
|
||||
reason = SSH_DISCONNECT_KEY_EXCHANGE_FAILED;
|
||||
break;
|
||||
case ASSH_ERR_MISSING_KEY:
|
||||
desc = "missing key";
|
||||
reason = SSH_DISCONNECT_RESERVED;
|
||||
break;
|
||||
case ASSH_ERR_MISSING_ALGO:
|
||||
desc = "algorithm not available";
|
||||
reason = SSH_DISCONNECT_RESERVED;
|
||||
break;
|
||||
case ASSH_ERR_HOSTKEY_SIGNATURE:
|
||||
reason = SSH_DISCONNECT_HOST_KEY_NOT_VERIFIABLE;
|
||||
break;
|
||||
case ASSH_ERR_SERVICE_NA:
|
||||
reason = SSH_DISCONNECT_SERVICE_NOT_AVAILABLE;
|
||||
break;
|
||||
case ASSH_ERR_NO_AUTH:
|
||||
reason = SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE;
|
||||
break;
|
||||
case ASSH_ERR_NO_MORE_SERVICE:
|
||||
reason = SSH_DISCONNECT_BY_APPLICATION;
|
||||
break;
|
||||
case ASSH_ERR_WEAK_ALGORITHM:
|
||||
desc = "weak key or algorithm parameters";
|
||||
reason = SSH_DISCONNECT_RESERVED;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!(inerr & ASSH_ERRSV_DISCONNECT))
|
||||
return inerr;
|
||||
|
||||
ASSH_DEBUG("disconnect packet reason: %u (%s)\n", reason, desc);
|
||||
|
||||
struct assh_packet_s *pout;
|
||||
size_t sz = 0;
|
||||
if (desc != NULL)
|
||||
sz = 4 + strlen(desc);
|
||||
|
||||
if (assh_packet_alloc(s->ctx, SSH_MSG_DISCONNECT, 3 * 4 + sz, &pout) == ASSH_OK)
|
||||
{
|
||||
ASSH_ASSERT(assh_packet_add_u32(pout, reason)); /* reason code */
|
||||
|
||||
uint8_t *str;
|
||||
ASSH_ASSERT(assh_packet_add_string(pout, sz, &str)); /* description */
|
||||
if (desc != NULL)
|
||||
memcpy(str, desc, sz - 4);
|
||||
|
||||
ASSH_ASSERT(assh_packet_add_string(pout, 0, NULL)); /* language */
|
||||
|
||||
assh_transport_push(s, pout);
|
||||
}
|
||||
|
||||
assh_transport_state(s, ASSH_TR_FIN);
|
||||
return inerr | ASSH_ERRSV_FIN;
|
||||
}
|
||||
|
|
@ -0,0 +1,621 @@
|
|||
/*
|
||||
|
||||
libassh - asynchronous ssh2 client/server library.
|
||||
|
||||
Copyright (C) 2013 Alexandre Becoulet <alexandre.becoulet@free.fr>
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#define ASSH_EV_CONST /* write access to event const fields */
|
||||
|
||||
#include <assh/assh_transport.h>
|
||||
|
||||
#include <assh/assh_context.h>
|
||||
#include <assh/assh_session.h>
|
||||
#include <assh/assh_packet.h>
|
||||
#include <assh/assh_queue.h>
|
||||
#include <assh/assh_service.h>
|
||||
#include <assh/assh_cipher.h>
|
||||
#include <assh/assh_mac.h>
|
||||
#include <assh/assh_kex.h>
|
||||
#include <assh/assh_event.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
ASSH_EVENT_SIZE_SASSERT(transport);
|
||||
|
||||
void assh_transport_push(struct assh_session_s *s,
|
||||
struct assh_packet_s *p)
|
||||
{
|
||||
struct assh_queue_s *q = &s->out_queue;
|
||||
|
||||
/* service packets are postponed during kex */
|
||||
assh_bool_t kex_msg = p->head.msg <= 49 &&
|
||||
p->head.msg != SSH_MSG_SERVICE_REQUEST &&
|
||||
p->head.msg != SSH_MSG_SERVICE_ACCEPT;
|
||||
|
||||
switch (s->tr_st)
|
||||
{
|
||||
case ASSH_TR_KEX_INIT:
|
||||
case ASSH_TR_KEX_WAIT:
|
||||
case ASSH_TR_KEX_RUNNING:
|
||||
case ASSH_TR_NEWKEY:
|
||||
case ASSH_TR_SERVICE_KEX:
|
||||
if (!kex_msg)
|
||||
q = &s->alt_queue;
|
||||
assh_queue_push_back(q, &p->entry);
|
||||
break;
|
||||
|
||||
case ASSH_TR_SERVICE:
|
||||
assh_queue_push_back(q, &p->entry);
|
||||
break;
|
||||
|
||||
case ASSH_TR_FIN:
|
||||
case ASSH_TR_CLOSED:
|
||||
assh_packet_release(p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static ASSH_EVENT_DONE_FCN(assh_event_read_done)
|
||||
{
|
||||
assh_error_t err;
|
||||
struct assh_kex_keys_s *k = s->cur_keys_in;
|
||||
unsigned int bsize = k == NULL ? 16 : ASSH_MAX(k->cipher->block_size, 16);
|
||||
|
||||
size_t rd_size = e->transport.read.transferred;
|
||||
assert(rd_size <= e->transport.read.buf.size);
|
||||
s->stream_in_size += rd_size;
|
||||
|
||||
switch (s->stream_in_st)
|
||||
{
|
||||
/* process ident text lines */
|
||||
case ASSH_TR_IN_IDENT_DONE: {
|
||||
unsigned int i;
|
||||
|
||||
/* look for End of Line */
|
||||
for (i = s->stream_in_size - rd_size; i < s->stream_in_size; i++)
|
||||
if (s->ident_str[i] == '\n')
|
||||
{
|
||||
s->stream_in_size -= i + 1;
|
||||
|
||||
/* test line prefix */
|
||||
if (i >= 7 && !strncmp((char*)s->ident_str, "SSH-", 4))
|
||||
{
|
||||
ASSH_CHK_RET(strncmp((char*)s->ident_str + 4, "2.0", 3),
|
||||
ASSH_ERR_BAD_VERSION | ASSH_ERRSV_FIN);
|
||||
|
||||
/* copy remaining unused bytes to packet header buffer */
|
||||
memcpy(s->stream_in_pck_head, s->ident_str + i + 1, s->stream_in_size);
|
||||
|
||||
/* ajust and keep ident string length */
|
||||
if (s->ident_str[i - 1] == '\r')
|
||||
i--;
|
||||
s->ident_len = i;
|
||||
|
||||
s->stream_in_st = ASSH_TR_IN_HEAD;
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
/* discard this line */
|
||||
memmove(s->ident_str, s->ident_str + i + 1, s->stream_in_size);
|
||||
i = 0;
|
||||
}
|
||||
|
||||
ASSH_CHK_RET(s->stream_in_size >= sizeof(s->ident_str),
|
||||
ASSH_ERR_INPUT_OVERFLOW | ASSH_ERRSV_FIN);
|
||||
|
||||
s->stream_in_st = ASSH_TR_IN_IDENT;
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
/* decipher packet head, compute packet length and allocate packet */
|
||||
case ASSH_TR_IN_HEAD_DONE: {
|
||||
|
||||
if (s->stream_in_size < bsize)
|
||||
{
|
||||
/* not enough header data yet to decipher the 1st block */
|
||||
s->stream_in_st = ASSH_TR_IN_HEAD;
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
/* decipher */
|
||||
if (k != NULL)
|
||||
ASSH_ERR_RET(k->cipher->f_process(k->cipher_ctx,
|
||||
s->stream_in_pck_head, bsize) | ASSH_ERRSV_DISCONNECT);
|
||||
|
||||
/* compute various length values */
|
||||
size_t len = assh_load_u32(s->stream_in_pck_head);
|
||||
uint8_t pad_len = s->stream_in_pck_head[4];
|
||||
unsigned int align = k == NULL ? 8 : ASSH_MAX(k->cipher->block_size, 8);
|
||||
|
||||
ASSH_CHK_RET(len > ASSH_MAX_PCK_LEN - 4 || len < 12,
|
||||
ASSH_ERR_INPUT_OVERFLOW | ASSH_ERRSV_DISCONNECT);
|
||||
|
||||
len += 4;
|
||||
ASSH_CHK_RET(len % align || pad_len < 4,
|
||||
ASSH_ERR_INPUT_OVERFLOW | ASSH_ERRSV_DISCONNECT);
|
||||
|
||||
if (k != NULL)
|
||||
len += k->mac->mac_size;
|
||||
|
||||
/* allocate actual packet and copy header */
|
||||
struct assh_packet_s *p;
|
||||
ASSH_ERR_RET(assh_packet_alloc2(s->ctx, 0, len - 6, &p) | ASSH_ERRSV_DISCONNECT);
|
||||
|
||||
memcpy(p->data, s->stream_in_pck_head, s->stream_in_size);
|
||||
p->data_size = len;
|
||||
s->stream_in_pck = p;
|
||||
|
||||
if (len > s->stream_in_size)
|
||||
{
|
||||
s->stream_in_st = ASSH_TR_IN_PAYLOAD;
|
||||
return ASSH_OK;
|
||||
}
|
||||
}
|
||||
|
||||
/* decipher remaining packet data, check MAC and accept packet */
|
||||
case ASSH_TR_IN_PAYLOAD_DONE: {
|
||||
struct assh_packet_s *p = s->stream_in_pck;
|
||||
|
||||
if (s->stream_in_size < p->data_size)
|
||||
{
|
||||
/* not enough data for the whole packet yet */
|
||||
s->stream_in_st = ASSH_TR_IN_PAYLOAD;
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
size_t mac_len = 0;
|
||||
|
||||
if (k != NULL)
|
||||
{
|
||||
mac_len = k->mac->mac_size;
|
||||
|
||||
/* decipher */
|
||||
ASSH_ERR_RET(k->cipher->f_process(
|
||||
k->cipher_ctx, p->data + bsize,
|
||||
p->data_size - bsize - mac_len) | ASSH_ERRSV_DISCONNECT);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ASSH_DEBUG_PROTOCOL
|
||||
ASSH_DEBUG("incoming packet: session=%p tr_st=%i, size=%zu, msg=%u\n",
|
||||
s, s->tr_st, p->data_size, p->head.msg);
|
||||
assh_hexdump("in packet", p->data, p->data_size);
|
||||
#endif
|
||||
|
||||
if (k != NULL)
|
||||
{
|
||||
/* compute and compare MAC */
|
||||
ASSH_ERR_RET(k->mac->f_check(k->mac_ctx, s->in_seq, p->data,
|
||||
p->data_size - mac_len,
|
||||
p->data + p->data_size - mac_len)
|
||||
| ASSH_ERRSV_DISCONNECT);
|
||||
|
||||
#warning FIXME decompress
|
||||
}
|
||||
|
||||
s->kex_bytes += p->data_size;
|
||||
|
||||
/* reduce packet size to actual payload */
|
||||
p->data_size -= mac_len + p->head.pad_len;
|
||||
|
||||
/* push completed incoming packet for dispatch */
|
||||
assert(s->in_pck == NULL);
|
||||
s->in_pck = p;
|
||||
|
||||
/* reinit input state */
|
||||
s->in_seq++;
|
||||
s->stream_in_pck = NULL;
|
||||
s->stream_in_st = ASSH_TR_IN_HEAD;
|
||||
s->stream_in_size = 0;
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
default:
|
||||
ASSH_ERR_RET(ASSH_ERR_STATE | ASSH_ERRSV_FATAL);
|
||||
}
|
||||
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
assh_error_t assh_transport_read(struct assh_session_s *s,
|
||||
struct assh_event_s *e)
|
||||
{
|
||||
assh_error_t err;
|
||||
struct assh_kex_keys_s *k = s->cur_keys_in;
|
||||
uint8_t **data = &e->transport.read.buf.data;
|
||||
size_t *size = &e->transport.read.buf.size;
|
||||
|
||||
switch (s->stream_in_st)
|
||||
{
|
||||
/* read stream into ident buffer */
|
||||
case ASSH_TR_IN_IDENT:
|
||||
*data = s->ident_str + s->stream_in_size;
|
||||
*size = ASSH_MIN(16, sizeof(s->ident_str) - s->stream_in_size);
|
||||
s->stream_in_st = ASSH_TR_IN_IDENT_DONE;
|
||||
break;
|
||||
|
||||
/* read stream into packet head buffer */
|
||||
case ASSH_TR_IN_HEAD: {
|
||||
unsigned int bsize = k == NULL ? 16 : ASSH_MAX(k->cipher->block_size, 16);
|
||||
*data = s->stream_in_pck_head + s->stream_in_size;
|
||||
*size = bsize - s->stream_in_size;
|
||||
s->stream_in_st = ASSH_TR_IN_HEAD_DONE;
|
||||
break;
|
||||
}
|
||||
|
||||
/* read stream into actual packet buffer */
|
||||
case ASSH_TR_IN_PAYLOAD: {
|
||||
struct assh_packet_s *p = s->stream_in_pck;
|
||||
*data = p->data + s->stream_in_size;
|
||||
*size = p->data_size - s->stream_in_size;
|
||||
s->stream_in_st = ASSH_TR_IN_PAYLOAD_DONE;
|
||||
assert(s->in_pck == NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
ASSH_ERR_RET(ASSH_ERR_STATE | ASSH_ERRSV_FATAL);
|
||||
}
|
||||
|
||||
e->id = ASSH_EVENT_READ;
|
||||
e->f_done = &assh_event_read_done;
|
||||
e->transport.read.transferred = 0;
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
static ASSH_EVENT_DONE_FCN(assh_event_write_done)
|
||||
{
|
||||
assh_error_t err;
|
||||
|
||||
size_t wr_size = e->transport.write.transferred;
|
||||
assert(wr_size <= e->transport.write.buf.size);
|
||||
s->stream_out_size += wr_size;
|
||||
|
||||
switch (s->stream_out_st)
|
||||
{
|
||||
/* check if sending of ident string has completed */
|
||||
case ASSH_TR_OUT_IDENT_DONE:
|
||||
s->stream_out_st = s->stream_out_size >= sizeof(ASSH_IDENT) - 1
|
||||
? ASSH_TR_OUT_PACKETS : ASSH_TR_OUT_IDENT_PAUSE;
|
||||
return ASSH_OK;
|
||||
|
||||
/* check if sending of packet has completed */
|
||||
case ASSH_TR_OUT_PACKETS_DONE: {
|
||||
assert(s->out_queue.count > 0);
|
||||
|
||||
struct assh_queue_entry_s *e = assh_queue_front(&s->out_queue);
|
||||
struct assh_packet_s *p = (void*)e;
|
||||
|
||||
if (s->stream_out_size < p->data_size)
|
||||
{
|
||||
/* packet partially sent, need to report one more write
|
||||
event later. Yield to the input state machine for now. */
|
||||
s->stream_out_st = ASSH_TR_OUT_PACKETS_PAUSE;
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
/* pop and release packet */
|
||||
assh_queue_remove(&s->out_queue, e);
|
||||
assh_packet_release(p);
|
||||
|
||||
s->stream_out_st = ASSH_TR_OUT_PACKETS;
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
default:
|
||||
ASSH_ERR_RET(ASSH_ERR_STATE | ASSH_ERRSV_FATAL);
|
||||
}
|
||||
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
assh_error_t assh_transport_write(struct assh_session_s *s,
|
||||
struct assh_event_s *e)
|
||||
{
|
||||
assh_error_t err;
|
||||
uint8_t **data = &e->transport.write.buf.data;
|
||||
size_t *size = &e->transport.write.buf.size;
|
||||
|
||||
switch (s->stream_out_st)
|
||||
{
|
||||
/* the write stream buffer is the constant ident string */
|
||||
case ASSH_TR_OUT_IDENT: {
|
||||
*data = (uint8_t*)ASSH_IDENT + s->stream_out_size;
|
||||
*size = sizeof(ASSH_IDENT) - 1 - s->stream_out_size;
|
||||
s->stream_out_st = ASSH_TR_OUT_IDENT_DONE;
|
||||
break;
|
||||
}
|
||||
|
||||
/* the last ident buffer write was incomplete, yield to input */
|
||||
case ASSH_TR_OUT_IDENT_PAUSE:
|
||||
s->stream_out_st = ASSH_TR_OUT_IDENT;
|
||||
return ASSH_OK;
|
||||
|
||||
/* the next output packet must be enciphered before write */
|
||||
case ASSH_TR_OUT_PACKETS: {
|
||||
|
||||
/* nothing to output, yield to input */
|
||||
if (s->out_queue.count == 0)
|
||||
return ASSH_OK;
|
||||
|
||||
struct assh_packet_s *p = (void*)assh_queue_front(&s->out_queue);
|
||||
|
||||
/* compute various length and payload pointer values */
|
||||
struct assh_kex_keys_s *k = s->cur_keys_out;
|
||||
unsigned int align = 8;
|
||||
size_t mac_len = 0;
|
||||
|
||||
if (k != NULL)
|
||||
{
|
||||
align = ASSH_MAX(k->cipher->block_size, 8);
|
||||
mac_len = k->mac->mac_size;
|
||||
}
|
||||
|
||||
size_t pad_len = align - p->data_size % align;
|
||||
if (pad_len < 4)
|
||||
pad_len += align;
|
||||
|
||||
assert(pad_len >= 4 && pad_len < 255);
|
||||
|
||||
p->data_size += pad_len + mac_len;
|
||||
assert(p->data_size <= p->alloc_size);
|
||||
|
||||
assh_store_u32(p->data, p->data_size - 4 - mac_len);
|
||||
p->head.pad_len = pad_len;
|
||||
uint8_t *mac_ptr = p->data + p->data_size - mac_len;
|
||||
uint8_t *pad = mac_ptr - pad_len;
|
||||
|
||||
if (pad_len > 0)
|
||||
memset(pad, 42, pad_len);
|
||||
|
||||
#warning FIXME compress
|
||||
|
||||
#ifdef CONFIG_ASSH_DEBUG_PROTOCOL
|
||||
ASSH_DEBUG("outgoing packet: session=%p tr_st=%i, size=%zu, msg=%u\n",
|
||||
s, s->tr_st, p->data_size, p->head.msg);
|
||||
assh_hexdump("out packet", p->data, p->data_size);
|
||||
#endif
|
||||
|
||||
assh_bool_t newkey = p->head.msg == SSH_MSG_NEWKEYS;
|
||||
|
||||
/* compute MAC and encrypt packet */
|
||||
if (k != NULL)
|
||||
{
|
||||
ASSH_ERR_RET(k->mac->f_compute(k->mac_ctx, s->out_seq, p->data,
|
||||
p->data_size - mac_len, mac_ptr) | ASSH_ERRSV_FIN);
|
||||
|
||||
ASSH_ERR_RET(k->cipher->f_process(k->cipher_ctx, p->data,
|
||||
p->data_size - mac_len) | ASSH_ERRSV_FIN);
|
||||
}
|
||||
|
||||
if (newkey)
|
||||
{
|
||||
/* release the old output cipher/mac context and install the new one */
|
||||
assh_kex_keys_cleanup(s, s->cur_keys_out);
|
||||
s->cur_keys_out = s->new_keys_out;
|
||||
s->new_keys_out = NULL;
|
||||
}
|
||||
|
||||
s->kex_bytes += p->data_size;
|
||||
s->out_seq++;
|
||||
|
||||
/* reinit output state */
|
||||
s->stream_out_size = 0;
|
||||
*data = p->data;
|
||||
*size = p->data_size;
|
||||
s->stream_out_st = ASSH_TR_OUT_PACKETS_DONE;
|
||||
break;
|
||||
}
|
||||
|
||||
/* the write stream buffer is an already enciphered output packet */
|
||||
case ASSH_TR_OUT_PACKETS_ENCIPHERED: {
|
||||
|
||||
assert(s->out_queue.count != 0);
|
||||
struct assh_packet_s *p = (void*)assh_queue_front(&s->out_queue);
|
||||
|
||||
*data = p->data + s->stream_out_size;
|
||||
*size = p->data_size - s->stream_out_size;
|
||||
s->stream_out_st = ASSH_TR_OUT_PACKETS_DONE;
|
||||
break;
|
||||
}
|
||||
|
||||
/* the last packet buffer write was incomplete, yield to input */
|
||||
case ASSH_TR_OUT_PACKETS_PAUSE:
|
||||
s->stream_out_st = ASSH_TR_OUT_PACKETS_ENCIPHERED;
|
||||
return ASSH_OK;
|
||||
|
||||
default:
|
||||
ASSH_ERR_RET(ASSH_ERR_STATE | ASSH_ERRSV_FATAL);
|
||||
}
|
||||
|
||||
/* a buffer is available for output, return a write event */
|
||||
e->id = ASSH_EVENT_WRITE;
|
||||
e->f_done = &assh_event_write_done;
|
||||
e->transport.write.transferred = 0;
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
assh_error_t assh_transport_dispatch(struct assh_session_s *s,
|
||||
struct assh_event_s *e)
|
||||
{
|
||||
assh_error_t err = ASSH_OK;
|
||||
enum assh_ssh_msg_e msg = SSH_MSG_INVALID;
|
||||
struct assh_packet_s *p = s->tr_st < ASSH_TR_FIN ? s->in_pck : NULL;
|
||||
|
||||
if (p != NULL)
|
||||
{
|
||||
msg = p->head.msg;
|
||||
|
||||
/* handle common packets */
|
||||
switch (msg)
|
||||
{
|
||||
case SSH_MSG_INVALID:
|
||||
ASSH_ERR_RET(ASSH_ERR_PROTOCOL | ASSH_ERRSV_FIN);
|
||||
|
||||
case SSH_MSG_DISCONNECT:
|
||||
ASSH_ERR_RET(ASSH_ERR_DISCONNECTED | ASSH_ERRSV_FIN);
|
||||
|
||||
case SSH_MSG_DEBUG:
|
||||
case SSH_MSG_IGNORE:
|
||||
goto done;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* transport protocol state machine */
|
||||
switch (s->tr_st)
|
||||
{
|
||||
/* send first kex init packet during session init */
|
||||
case ASSH_TR_KEX_INIT:
|
||||
ASSH_ERR_RET(assh_kex_send_init(s) | ASSH_ERRSV_DISCONNECT);
|
||||
assh_transport_state(s, ASSH_TR_KEX_WAIT);
|
||||
|
||||
/* wait for initial kex init packet during session init */
|
||||
case ASSH_TR_KEX_WAIT:
|
||||
if (msg == SSH_MSG_INVALID)
|
||||
goto done;
|
||||
ASSH_CHK_RET(msg != SSH_MSG_KEXINIT, ASSH_ERR_PROTOCOL | ASSH_ERRSV_DISCONNECT);
|
||||
kex_init:
|
||||
ASSH_ERR_RET(assh_kex_got_init(s, p) | ASSH_ERRSV_DISCONNECT);
|
||||
|
||||
/* switch to key exchange running state */
|
||||
assh_transport_state(s, ASSH_TR_KEX_RUNNING);
|
||||
p = NULL;
|
||||
msg = 0;
|
||||
|
||||
/* key exchange algorithm is running (session init or rekeying) */
|
||||
case ASSH_TR_KEX_RUNNING:
|
||||
/* allowed msgs are 0 (no packet),
|
||||
1-4, 7-19, 20-29, 30-49 */
|
||||
ASSH_CHK_RET(msg > 49 || msg == SSH_MSG_SERVICE_REQUEST || msg == SSH_MSG_SERVICE_ACCEPT,
|
||||
ASSH_ERR_PROTOCOL | ASSH_ERRSV_DISCONNECT);
|
||||
|
||||
if (!s->kex_bad_guess || msg == SSH_MSG_INVALID)
|
||||
ASSH_ERR_RET(s->kex->f_process(s, p, e) | ASSH_ERRSV_DISCONNECT);
|
||||
else
|
||||
s->kex_bad_guess = 0;
|
||||
goto done;
|
||||
|
||||
/* kex exchange is over, NEWKEYS packet expected */
|
||||
case ASSH_TR_NEWKEY:
|
||||
if (msg == SSH_MSG_INVALID)
|
||||
goto done;
|
||||
ASSH_CHK_RET(msg != SSH_MSG_NEWKEYS, ASSH_ERR_PROTOCOL | ASSH_ERRSV_DISCONNECT);
|
||||
|
||||
/* release the old input cipher/mac context and install the new one */
|
||||
assert(s->new_keys_in != NULL);
|
||||
assh_kex_keys_cleanup(s, s->cur_keys_in);
|
||||
s->cur_keys_in = s->new_keys_in;
|
||||
s->new_keys_in = NULL;
|
||||
|
||||
/* move postponed service packets to output queue */
|
||||
assh_queue_concat(&s->out_queue, &s->alt_queue);
|
||||
|
||||
/* switch to service running state */
|
||||
p = NULL;
|
||||
msg = 0;
|
||||
|
||||
assh_transport_state(s, ASSH_TR_SERVICE);
|
||||
|
||||
/* service is running or have to be started */
|
||||
service:
|
||||
case ASSH_TR_SERVICE:
|
||||
switch (msg)
|
||||
{
|
||||
/* received a rekeying request, reply and switch to ASSH_TR_KEX_RUNNING */
|
||||
case SSH_MSG_KEXINIT:
|
||||
ASSH_CHK_RET(s->new_keys_out != NULL, ASSH_ERR_PROTOCOL | ASSH_ERRSV_FIN);
|
||||
ASSH_ERR_RET(assh_kex_send_init(s) | ASSH_ERRSV_DISCONNECT);
|
||||
goto kex_init;
|
||||
|
||||
/* handle a service request packet */
|
||||
case SSH_MSG_SERVICE_REQUEST:
|
||||
#ifdef CONFIG_ASSH_SERVER
|
||||
if (s->ctx->type == ASSH_SERVER)
|
||||
ASSH_ERR_RET(assh_service_got_request(s, p) | ASSH_ERRSV_DISCONNECT);
|
||||
else
|
||||
#endif
|
||||
ASSH_ERR_RET(ASSH_ERR_PROTOCOL | ASSH_ERRSV_DISCONNECT);
|
||||
p = NULL;
|
||||
break;
|
||||
|
||||
/* handle a service accept packet */
|
||||
case SSH_MSG_SERVICE_ACCEPT:
|
||||
#ifdef CONFIG_ASSH_CLIENT
|
||||
if (s->ctx->type == ASSH_CLIENT)
|
||||
ASSH_ERR_RET(assh_service_got_accept(s, p) | ASSH_ERRSV_DISCONNECT);
|
||||
else
|
||||
#endif
|
||||
ASSH_ERR_RET(ASSH_ERR_PROTOCOL | ASSH_ERRSV_DISCONNECT);
|
||||
p = NULL;
|
||||
break;
|
||||
|
||||
/* dispatch packet to running service */
|
||||
default:
|
||||
ASSH_CHK_RET(s->srv == NULL, ASSH_ERR_PROTOCOL | ASSH_ERRSV_DISCONNECT);
|
||||
|
||||
/* no packet */
|
||||
case SSH_MSG_INVALID:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
/* service is running, key re-exchange initiated */
|
||||
case ASSH_TR_SERVICE_KEX:
|
||||
if (msg == SSH_MSG_KEXINIT)
|
||||
goto kex_init;
|
||||
goto service;
|
||||
|
||||
case ASSH_TR_FIN:
|
||||
if (s->srv == NULL)
|
||||
return ASSH_OK;
|
||||
break;
|
||||
|
||||
case ASSH_TR_CLOSED:
|
||||
ASSH_ERR_RET(ASSH_ERR_STATE | ASSH_ERRSV_FATAL);
|
||||
}
|
||||
|
||||
if (s->srv == NULL)
|
||||
{
|
||||
#ifdef CONFIG_ASSH_CLIENT
|
||||
/* client send a service request if no service is currently running */
|
||||
if (s->ctx->type == ASSH_CLIENT && s->srv_rq == NULL)
|
||||
ASSH_ERR_RET(assh_service_send_request(s) | ASSH_ERRSV_DISCONNECT);
|
||||
#endif
|
||||
goto done;
|
||||
}
|
||||
|
||||
do {
|
||||
/* call service processing function, with or without a packet */
|
||||
err = s->srv->f_process(s, p, e);
|
||||
} while (err == ASSH_NO_DATA && e->id == ASSH_EVENT_INVALID);
|
||||
|
||||
if (err == ASSH_NO_DATA)
|
||||
return ASSH_OK;
|
||||
|
||||
done:
|
||||
assh_packet_release(s->in_pck);
|
||||
s->in_pck = NULL;
|
||||
ASSH_ERR_RET(err | ASSH_ERRSV_DISCONNECT);
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
|
@ -0,0 +1,575 @@
|
|||
/*
|
||||
|
||||
libassh - asynchronous ssh2 client/server library.
|
||||
|
||||
Copyright (C) 2013 Alexandre Becoulet <alexandre.becoulet@free.fr>
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#define ASSH_EV_CONST /* write access to event const fields */
|
||||
|
||||
#include <assh/assh_userauth_client.h>
|
||||
|
||||
#include <assh/assh_service.h>
|
||||
#include <assh/assh_session.h>
|
||||
#include <assh/assh_packet.h>
|
||||
#include <assh/assh_transport.h>
|
||||
#include <assh/assh_event.h>
|
||||
#include <assh/assh_key.h>
|
||||
#include <assh/assh_sign.h>
|
||||
#include <assh/assh_alloc.h>
|
||||
|
||||
#ifdef CONFIG_ASSH_CLIENT
|
||||
|
||||
ASSH_EVENT_SIZE_SASSERT(userauth_client);
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
enum assh_userauth_state_e
|
||||
{
|
||||
ASSH_USERAUTH_INIT,
|
||||
ASSH_USERAUTH_GET_USERNAME,
|
||||
ASSH_USERAUTH_SENT_NONE_RQ,
|
||||
#ifdef CONFIG_ASSH_CLIENT_AUTH_PUBLICKEY
|
||||
ASSH_USERAUTH_SENT_PUB_KEY_RQ,
|
||||
ASSH_USERAUTH_SENT_PUB_KEY,
|
||||
#endif
|
||||
#ifdef CONFIG_ASSH_CLIENT_AUTH_PASSWORD
|
||||
ASSH_USERAUTH_SENT_PASSWORD_RQ,
|
||||
#endif
|
||||
ASSH_USERAUTH_GET_AUTHDATA,
|
||||
};
|
||||
|
||||
struct assh_userauth_context_s
|
||||
{
|
||||
enum assh_userauth_state_e state;
|
||||
const struct assh_service_s *srv;
|
||||
char username[CONFIG_ASSH_AUTH_USERNAME_LEN];
|
||||
size_t username_len;
|
||||
|
||||
#ifdef CONFIG_ASSH_CLIENT_AUTH_PUBLICKEY
|
||||
const struct assh_algo_s *algo;
|
||||
uint_fast16_t algo_idx;
|
||||
const struct assh_key_s *pub_keys;
|
||||
#endif
|
||||
#ifdef CONFIG_ASSH_CLIENT_AUTH_PASSWORD
|
||||
char password[CONFIG_ASSH_AUTH_PASSWORD_LEN];
|
||||
size_t password_len;
|
||||
#endif
|
||||
};
|
||||
|
||||
static ASSH_SERVICE_INIT_FCN(assh_userauth_client_init)
|
||||
{
|
||||
struct assh_userauth_context_s *pv;
|
||||
assh_error_t err;
|
||||
|
||||
ASSH_CHK_RET(s->srv_index >= s->ctx->srvs_count, ASSH_ERR_SERVICE_NA);
|
||||
|
||||
ASSH_ERR_RET(assh_alloc(s->ctx, sizeof(*pv),
|
||||
ASSH_ALLOC_SECUR, (void**)&pv));
|
||||
|
||||
pv->state = ASSH_USERAUTH_INIT;
|
||||
|
||||
s->srv = &assh_service_userauth_client;
|
||||
s->srv_pv = pv;
|
||||
|
||||
#ifdef CONFIG_ASSH_CLIENT_AUTH_PUBLICKEY
|
||||
pv->pub_keys = NULL;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ASSH_CLIENT_AUTH_PASSWORD
|
||||
pv->password_len = 0;
|
||||
#endif
|
||||
|
||||
/* get next client requested service */
|
||||
pv->srv = s->ctx->srvs[s->srv_index];
|
||||
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
static ASSH_SERVICE_CLEANUP_FCN(assh_userauth_client_cleanup)
|
||||
{
|
||||
struct assh_userauth_context_s *pv = s->srv_pv;
|
||||
|
||||
#ifdef CONFIG_ASSH_CLIENT_AUTH_PUBLICKEY
|
||||
assh_key_flush(s->ctx, &pv->pub_keys);
|
||||
#endif
|
||||
|
||||
assh_free(s->ctx, pv);
|
||||
|
||||
s->srv_pv = NULL;
|
||||
s->srv = NULL;
|
||||
}
|
||||
|
||||
/* allocate a packet and append user name, service name and auth method name fields. */
|
||||
static assh_error_t assh_userauth_client_pck_head(struct assh_session_s *s,
|
||||
struct assh_packet_s **pout,
|
||||
const char *method,
|
||||
size_t extra_len)
|
||||
{
|
||||
struct assh_userauth_context_s *pv = s->srv_pv;
|
||||
assh_error_t err;
|
||||
|
||||
size_t srvname_len = strlen(pv->srv->name);
|
||||
size_t method_len = strlen(method);
|
||||
|
||||
ASSH_ERR_RET(assh_packet_alloc(s->ctx, SSH_MSG_USERAUTH_REQUEST,
|
||||
4 + pv->username_len + 4 + srvname_len +
|
||||
4 + method_len + extra_len, pout) | ASSH_ERRSV_DISCONNECT);
|
||||
uint8_t *str;
|
||||
ASSH_ASSERT(assh_packet_add_string(*pout, pv->username_len, &str));
|
||||
memcpy(str, pv->username, pv->username_len);
|
||||
ASSH_ASSERT(assh_packet_add_string(*pout, srvname_len, &str));
|
||||
memcpy(str, pv->srv->name, srvname_len);
|
||||
ASSH_ASSERT(assh_packet_add_string(*pout, method_len, &str));
|
||||
memcpy(str, method, method_len);
|
||||
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
/******************************************************************* password */
|
||||
|
||||
#ifdef CONFIG_ASSH_CLIENT_AUTH_PASSWORD
|
||||
/* send a password authentication request */
|
||||
static assh_error_t assh_userauth_client_req_password(struct assh_session_s *s)
|
||||
{
|
||||
struct assh_userauth_context_s *pv = s->srv_pv;
|
||||
assh_error_t err;
|
||||
|
||||
uint8_t *bool_, *str;
|
||||
|
||||
struct assh_packet_s *pout;
|
||||
ASSH_ERR_RET(assh_userauth_client_pck_head(s, &pout, "password",
|
||||
1 + 4 + pv->password_len) | ASSH_ERRSV_DISCONNECT);
|
||||
ASSH_ASSERT(assh_packet_add_array(pout, 1, &bool_));
|
||||
*bool_ = 0; // FALSE
|
||||
|
||||
ASSH_ASSERT(assh_packet_add_string(pout, pv->password_len, &str));
|
||||
memcpy(str, pv->password, pv->password_len);
|
||||
assh_transport_push(s, pout);
|
||||
|
||||
pv->state = ASSH_USERAUTH_SENT_PASSWORD_RQ;
|
||||
|
||||
return ASSH_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
/******************************************************************* public key */
|
||||
|
||||
#ifdef CONFIG_ASSH_CLIENT_AUTH_PUBLICKEY
|
||||
/* allocate a packet and append common fileds for a publickey request */
|
||||
static assh_error_t assh_userauth_client_pck_pubkey(struct assh_session_s *s,
|
||||
struct assh_packet_s **pout,
|
||||
assh_bool_t second,
|
||||
size_t extra_len)
|
||||
{
|
||||
struct assh_userauth_context_s *pv = s->srv_pv;
|
||||
const struct assh_key_s *pub_key = pv->pub_keys;
|
||||
assh_error_t err;
|
||||
|
||||
size_t algo_name_len = strlen(pv->algo->name);
|
||||
|
||||
size_t blob_len;
|
||||
ASSH_ERR_RET(assh_key_output(s->ctx, pub_key,
|
||||
NULL, &blob_len, ASSH_KEY_FMT_PUB_RFC4253_6_6) | ASSH_ERRSV_DISCONNECT);
|
||||
|
||||
ASSH_ERR_RET(assh_userauth_client_pck_head(s, pout, "publickey",
|
||||
1 + 4 + algo_name_len + 4 + blob_len + extra_len) | ASSH_ERRSV_DISCONNECT);
|
||||
|
||||
/* add boolean */
|
||||
uint8_t *str;
|
||||
ASSH_ASSERT(assh_packet_add_array(*pout, 1, &str));
|
||||
*str = second;
|
||||
|
||||
/* add signature algorithm name */
|
||||
uint8_t *algo_name;
|
||||
ASSH_ASSERT(assh_packet_add_string(*pout, algo_name_len, &algo_name));
|
||||
memcpy(algo_name, pv->algo->name, algo_name_len);
|
||||
|
||||
/* add public key blob */
|
||||
uint8_t *blob;
|
||||
ASSH_ASSERT(assh_packet_add_string(*pout, blob_len, &blob));
|
||||
ASSH_ERR_GTO(assh_key_output(s->ctx, pub_key, blob, &blob_len,
|
||||
ASSH_KEY_FMT_PUB_RFC4253_6_6) | ASSH_ERRSV_DISCONNECT, err_packet);
|
||||
assh_packet_shrink_string(*pout, blob, blob_len);
|
||||
|
||||
return ASSH_OK;
|
||||
|
||||
err_packet:
|
||||
assh_packet_release(*pout);
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ASSH_CLIENT_AUTH_PUBLICKEY
|
||||
/* send a public key authentication request with signature */
|
||||
static assh_error_t assh_userauth_client_req_pubkey_sign(struct assh_session_s *s)
|
||||
{
|
||||
struct assh_userauth_context_s *pv = s->srv_pv;
|
||||
const struct assh_algo_sign_s *algo = (const void *)pv->algo;
|
||||
assh_error_t err;
|
||||
|
||||
size_t sign_len;
|
||||
ASSH_ERR_RET(assh_sign_generate(s->ctx, algo, pv->pub_keys, 0,
|
||||
NULL, NULL, NULL, &sign_len) | ASSH_ERRSV_DISCONNECT);
|
||||
|
||||
struct assh_packet_s *pout;
|
||||
ASSH_ERR_RET(assh_userauth_client_pck_pubkey(s, &pout,
|
||||
1, 4 + sign_len) | ASSH_ERRSV_DISCONNECT);
|
||||
|
||||
uint8_t sid_len[4]; /* fake string header for session id */
|
||||
assh_store_u32(sid_len, s->session_id_len);
|
||||
|
||||
/* buffers that must be signed by the client */
|
||||
const uint8_t *sign_ptrs[3] =
|
||||
{ sid_len, s->session_id, &pout->head.msg };
|
||||
size_t sign_sizes[3] =
|
||||
{ 4, s->session_id_len, pout->data_size - 5 };
|
||||
|
||||
/* append the signature */
|
||||
uint8_t *sign;
|
||||
ASSH_ASSERT(assh_packet_add_string(pout, sign_len, &sign));
|
||||
ASSH_ERR_GTO(assh_sign_generate(s->ctx, algo, pv->pub_keys,
|
||||
3, sign_ptrs, sign_sizes, sign, &sign_len)
|
||||
| ASSH_ERRSV_DISCONNECT, err_packet);
|
||||
assh_packet_shrink_string(pout, sign, sign_len);
|
||||
|
||||
assh_transport_push(s, pout);
|
||||
|
||||
pv->state = ASSH_USERAUTH_SENT_PUB_KEY_RQ;
|
||||
return ASSH_OK;
|
||||
|
||||
err_packet:
|
||||
assh_packet_release(pout);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* send a public key authentication probing request */
|
||||
static assh_error_t assh_userauth_client_req_pubkey(struct assh_session_s *s)
|
||||
{
|
||||
struct assh_userauth_context_s *pv = s->srv_pv;
|
||||
assh_error_t err;
|
||||
|
||||
#ifdef CONFIG_ASSH_CLIENT_AUTH_USE_PKOK /* send a public key lookup first */
|
||||
struct assh_packet_s *pout;
|
||||
ASSH_ERR_RET(assh_userauth_client_pck_pubkey(s, &pout,
|
||||
0, 0) | ASSH_ERRSV_DISCONNECT);
|
||||
assh_transport_push(s, pout);
|
||||
pv->state = ASSH_USERAUTH_SENT_PUB_KEY;
|
||||
#else /* compute and send the signature directly */
|
||||
ASSH_ERR_RET(assh_userauth_client_req_pubkey_sign(s) | ASSH_ERRSV_DISCONNECT);
|
||||
#endif
|
||||
return ASSH_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
/********************************************************************/
|
||||
|
||||
static ASSH_EVENT_DONE_FCN(assh_userauth_client_username_done)
|
||||
{
|
||||
struct assh_userauth_context_s *pv = s->srv_pv;
|
||||
assh_error_t err;
|
||||
|
||||
struct assh_packet_s *pout;
|
||||
ASSH_CHK_RET(pv->state != ASSH_USERAUTH_GET_USERNAME,
|
||||
ASSH_ERR_STATE | ASSH_ERRSV_FATAL);
|
||||
|
||||
/* keep username */
|
||||
size_t ulen = e->userauth_client.user.username.len;
|
||||
ASSH_CHK_RET(ulen > sizeof(pv->username),
|
||||
ASSH_ERR_OUTPUT_OVERFLOW | ASSH_ERRSV_DISCONNECT);
|
||||
memcpy(pv->username, e->userauth_client.user.username.str,
|
||||
pv->username_len = ulen);
|
||||
|
||||
/* send auth request with the "none" method */
|
||||
ASSH_ERR_RET(assh_userauth_client_pck_head(s, &pout, "none", 0)
|
||||
| ASSH_ERRSV_DISCONNECT);
|
||||
assh_transport_push(s, pout);
|
||||
|
||||
pv->state = ASSH_USERAUTH_SENT_NONE_RQ;
|
||||
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
static ASSH_EVENT_DONE_FCN(assh_userauth_client_methods_done)
|
||||
{
|
||||
struct assh_userauth_context_s *pv = s->srv_pv;
|
||||
assh_error_t err;
|
||||
|
||||
ASSH_CHK_RET(pv->state != ASSH_USERAUTH_GET_AUTHDATA,
|
||||
ASSH_ERR_STATE | ASSH_ERRSV_FATAL);
|
||||
|
||||
#ifdef CONFIG_ASSH_CLIENT_AUTH_PASSWORD
|
||||
const char *password = e->userauth_client.methods.password.str;
|
||||
if (password != NULL)
|
||||
{
|
||||
size_t password_len = e->userauth_client.methods.password.len;
|
||||
ASSH_CHK_RET(password_len > sizeof(pv->password),
|
||||
ASSH_ERR_OUTPUT_OVERFLOW | ASSH_ERRSV_DISCONNECT);
|
||||
memcpy(pv->password, password, pv->password_len = password_len);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ASSH_CLIENT_AUTH_PUBLICKEY
|
||||
const struct assh_key_s *k = e->userauth_client.methods.pub_keys;
|
||||
|
||||
while (k != NULL)
|
||||
{
|
||||
/* check usable keys */
|
||||
pv->algo_idx = 0;
|
||||
if (assh_algo_by_key(s->ctx, k, &pv->algo_idx, &pv->algo) == ASSH_OK)
|
||||
{
|
||||
/* insert provided keys in internal list */
|
||||
const struct assh_key_s *next = k->next;
|
||||
assh_key_insert(&pv->pub_keys, k);
|
||||
k = next;
|
||||
}
|
||||
else
|
||||
assh_key_drop(s->ctx, &k);
|
||||
}
|
||||
|
||||
if (pv->pub_keys != NULL)
|
||||
{
|
||||
ASSH_ERR_RET(assh_userauth_client_req_pubkey(s) | ASSH_ERRSV_DISCONNECT);
|
||||
return ASSH_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ASSH_CLIENT_AUTH_PASSWORD
|
||||
if (pv->password_len != 0)
|
||||
{
|
||||
ASSH_ERR_RET(assh_userauth_client_req_password(s) | ASSH_ERRSV_DISCONNECT);
|
||||
return ASSH_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
ASSH_ERR_RET(ASSH_ERR_NO_AUTH | ASSH_ERRSV_DISCONNECT);
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
/* cleanup the authentication service and start the next service. */
|
||||
static assh_error_t assh_userauth_client_success(struct assh_session_s *s)
|
||||
{
|
||||
assh_error_t err;
|
||||
struct assh_userauth_context_s *pv = s->srv_pv;
|
||||
const struct assh_service_s *srv = pv->srv;
|
||||
|
||||
assh_userauth_client_cleanup(s);
|
||||
|
||||
ASSH_ERR_RET(srv->f_init(s) | ASSH_ERRSV_DISCONNECT);
|
||||
s->srv_index++;
|
||||
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
/* extract the list of acceptable authentication methods from a failure packet */
|
||||
static assh_error_t assh_userauth_client_failure(struct assh_session_s *s,
|
||||
struct assh_packet_s *p,
|
||||
struct assh_event_s *e)
|
||||
{
|
||||
struct assh_userauth_context_s *pv = s->srv_pv;
|
||||
assh_error_t err;
|
||||
|
||||
switch (pv->state)
|
||||
{
|
||||
case ASSH_USERAUTH_SENT_PUB_KEY_RQ:
|
||||
case ASSH_USERAUTH_SENT_PUB_KEY:
|
||||
/* try next algorithm usable with the same key */
|
||||
pv->algo_idx++;
|
||||
while (pv->pub_keys != NULL &&
|
||||
assh_algo_by_key(s->ctx, pv->pub_keys,
|
||||
&pv->algo_idx, &pv->algo) != ASSH_OK)
|
||||
{
|
||||
/* drop used key */
|
||||
assh_key_drop(s->ctx, &pv->pub_keys);
|
||||
pv->algo_idx = 0;
|
||||
}
|
||||
break;
|
||||
case ASSH_USERAUTH_SENT_PASSWORD_RQ:
|
||||
/* drop used password */
|
||||
pv->password_len = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
uint8_t *methods = p->head.end;
|
||||
uint8_t *partial_success, *n;
|
||||
ASSH_ERR_RET(assh_packet_check_string(p, methods, &partial_success)
|
||||
| ASSH_ERRSV_DISCONNECT);
|
||||
ASSH_ERR_RET(assh_packet_check_array(p, partial_success, 1, NULL)
|
||||
| ASSH_ERRSV_DISCONNECT);
|
||||
|
||||
#ifdef CONFIG_ASSH_CLIENT_AUTH_PASSWORD
|
||||
e->userauth_client.methods.use_password = 0;
|
||||
#endif
|
||||
#ifdef CONFIG_ASSH_CLIENT_AUTH_PUBLICKEY
|
||||
e->userauth_client.methods.use_pub_key = 0;
|
||||
#endif
|
||||
int count = 0;
|
||||
|
||||
for (methods += 4; methods < partial_success; methods = n + 1)
|
||||
{
|
||||
n = methods;
|
||||
while (*n != ',' && n < partial_success)
|
||||
n++;
|
||||
|
||||
switch (n - methods)
|
||||
{
|
||||
#ifdef CONFIG_ASSH_CLIENT_AUTH_PASSWORD
|
||||
case 8:
|
||||
if (!strncmp((const char*)methods, "password", 8))
|
||||
{
|
||||
if (pv->password_len != 0)
|
||||
{
|
||||
/* a password string is already available */
|
||||
ASSH_ERR_RET(assh_userauth_client_req_password(s)
|
||||
| ASSH_ERRSV_DISCONNECT);
|
||||
return ASSH_OK;
|
||||
}
|
||||
e->userauth_client.methods.use_password = 1;
|
||||
count++;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ASSH_CLIENT_AUTH_PUBLICKEY
|
||||
case 9:
|
||||
if (!strncmp((const char*)methods, "publickey", 9))
|
||||
{
|
||||
if (pv->pub_keys != NULL)
|
||||
{
|
||||
/* some user keys are already available */
|
||||
ASSH_ERR_RET(assh_userauth_client_req_pubkey(s)
|
||||
| ASSH_ERRSV_DISCONNECT);
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
e->userauth_client.methods.use_pub_key = 1;
|
||||
count++;
|
||||
}
|
||||
#endif
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ASSH_CHK_RET(count == 0, ASSH_ERR_NO_AUTH | ASSH_ERRSV_DISCONNECT);
|
||||
|
||||
#ifdef CONFIG_ASSH_CLIENT_AUTH_PASSWORD
|
||||
e->userauth_client.methods.password.str = NULL;
|
||||
e->userauth_client.methods.password.len = 0;
|
||||
#endif
|
||||
#ifdef CONFIG_ASSH_CLIENT_AUTH_PUBLICKEY
|
||||
e->userauth_client.methods.pub_keys = NULL;
|
||||
#endif
|
||||
e->id = ASSH_EVENT_USERAUTH_CLIENT_METHODS;
|
||||
e->f_done = &assh_userauth_client_methods_done;
|
||||
|
||||
pv->state = ASSH_USERAUTH_GET_AUTHDATA;
|
||||
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
static ASSH_SERVICE_PROCESS_FCN(assh_userauth_client_process)
|
||||
{
|
||||
struct assh_userauth_context_s *pv = s->srv_pv;
|
||||
assh_error_t err;
|
||||
|
||||
if (s->tr_st >= ASSH_TR_FIN)
|
||||
return ASSH_OK;
|
||||
|
||||
switch (pv->state)
|
||||
{
|
||||
case ASSH_USERAUTH_INIT:
|
||||
ASSH_CHK_RET(p != NULL, ASSH_ERR_PROTOCOL | ASSH_ERRSV_DISCONNECT);
|
||||
e->id = ASSH_EVENT_USERAUTH_CLIENT_USER;
|
||||
e->f_done = &assh_userauth_client_username_done;
|
||||
e->userauth_client.user.username.str = NULL;
|
||||
e->userauth_client.user.username.len = 0;
|
||||
pv->state = ASSH_USERAUTH_GET_USERNAME;
|
||||
return ASSH_OK;
|
||||
|
||||
case ASSH_USERAUTH_SENT_NONE_RQ:
|
||||
#ifdef CONFIG_ASSH_CLIENT_AUTH_PASSWORD
|
||||
case ASSH_USERAUTH_SENT_PASSWORD_RQ:
|
||||
#endif
|
||||
#ifdef CONFIG_ASSH_CLIENT_AUTH_PUBLICKEY
|
||||
case ASSH_USERAUTH_SENT_PUB_KEY_RQ:
|
||||
#endif
|
||||
if (p == NULL)
|
||||
return ASSH_OK;
|
||||
|
||||
switch (p->head.msg)
|
||||
{
|
||||
case SSH_MSG_USERAUTH_SUCCESS:
|
||||
ASSH_ERR_RET(assh_userauth_client_success(s) | ASSH_ERRSV_DISCONNECT);
|
||||
return ASSH_OK;
|
||||
|
||||
case SSH_MSG_USERAUTH_PASSWD_CHANGEREQ:
|
||||
#ifdef CONFIG_ASSH_CLIENT_AUTH_PASSWORD
|
||||
ASSH_CHK_RET(pv->state != ASSH_USERAUTH_SENT_PASSWORD_RQ,
|
||||
ASSH_ERR_PROTOCOL | ASSH_ERRSV_DISCONNECT);
|
||||
#endif
|
||||
case SSH_MSG_USERAUTH_FAILURE:
|
||||
ASSH_ERR_RET(assh_userauth_client_failure(s, p, e) | ASSH_ERRSV_DISCONNECT);
|
||||
return ASSH_OK;
|
||||
|
||||
default:
|
||||
ASSH_ERR_RET(ASSH_ERR_PROTOCOL | ASSH_ERRSV_DISCONNECT);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ASSH_CLIENT_AUTH_PUBLICKEY
|
||||
case ASSH_USERAUTH_SENT_PUB_KEY:
|
||||
if (p == NULL)
|
||||
return ASSH_OK;
|
||||
|
||||
switch(p->head.msg)
|
||||
{
|
||||
case SSH_MSG_USERAUTH_PK_OK:
|
||||
ASSH_ERR_RET(assh_userauth_client_req_pubkey_sign(s) | ASSH_ERRSV_DISCONNECT);
|
||||
return ASSH_OK;
|
||||
|
||||
case SSH_MSG_USERAUTH_FAILURE:
|
||||
ASSH_ERR_RET(assh_userauth_client_failure(s, p, e) | ASSH_ERRSV_DISCONNECT);
|
||||
return ASSH_OK;
|
||||
|
||||
default:
|
||||
ASSH_ERR_RET(ASSH_ERR_PROTOCOL | ASSH_ERRSV_DISCONNECT);
|
||||
}
|
||||
#endif
|
||||
|
||||
default:
|
||||
ASSH_ERR_RET(ASSH_ERR_STATE | ASSH_ERRSV_FATAL);
|
||||
}
|
||||
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
const struct assh_service_s assh_service_userauth_client =
|
||||
{
|
||||
.name = "ssh-userauth",
|
||||
.side = ASSH_CLIENT,
|
||||
.f_init = assh_userauth_client_init,
|
||||
.f_cleanup = assh_userauth_client_cleanup,
|
||||
.f_process = assh_userauth_client_process,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,570 @@
|
|||
/*
|
||||
|
||||
libassh - asynchronous ssh2 client/server library.
|
||||
|
||||
Copyright (C) 2013 Alexandre Becoulet <alexandre.becoulet@free.fr>
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#define ASSH_EV_CONST /* write access to event const fields */
|
||||
|
||||
#include <assh/assh_userauth_server.h>
|
||||
|
||||
#include <assh/assh_service.h>
|
||||
#include <assh/assh_session.h>
|
||||
#include <assh/assh_transport.h>
|
||||
#include <assh/assh_event.h>
|
||||
#include <assh/assh_packet.h>
|
||||
#include <assh/assh_algo.h>
|
||||
#include <assh/assh_sign.h>
|
||||
#include <assh/assh_key.h>
|
||||
#include <assh/assh_alloc.h>
|
||||
|
||||
#ifdef CONFIG_ASSH_SERVER
|
||||
|
||||
ASSH_EVENT_SIZE_SASSERT(userauth_server);
|
||||
|
||||
#ifdef CONFIG_ASSH_SERVER_AUTH_NONE
|
||||
# warning CONFIG_ASSH_SERVER_AUTH_NONE is defined, server authentication is bypassed
|
||||
# undef CONFIG_ASSH_SERVER_AUTH_PASSWORD
|
||||
# undef CONFIG_ASSH_SERVER_AUTH_PUBLICKEY
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
enum assh_userauth_state_e
|
||||
{
|
||||
ASSH_USERAUTH_WAIT_RQ, //< intial state
|
||||
#ifdef CONFIG_ASSH_SERVER_AUTH_PASSWORD
|
||||
ASSH_USERAUTH_PASSWORD, //< the password event handler must check the user password
|
||||
#endif
|
||||
#ifdef CONFIG_ASSH_SERVER_AUTH_PUBLICKEY
|
||||
ASSH_USERAUTH_PUBKEY_PKOK, //< the public key event handler may send PK_OK
|
||||
ASSH_USERAUTH_PUBKEY_VERIFY , //< the public key event handler may check the signature
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ASSH_SERVER_AUTH_PUBLICKEY
|
||||
enum assh_userauth_pubkey_state_e
|
||||
{
|
||||
ASSH_USERAUTH_PUBKEY_NONE,
|
||||
ASSH_USERAUTH_PUBKEY_NEW,
|
||||
ASSH_USERAUTH_PUBKEY_FOUND,
|
||||
};
|
||||
#endif
|
||||
|
||||
struct assh_userauth_context_s
|
||||
{
|
||||
enum assh_userauth_state_e state;
|
||||
unsigned int retry;
|
||||
|
||||
const struct assh_service_s *srv;
|
||||
char method_name[10];
|
||||
char username[CONFIG_ASSH_AUTH_USERNAME_LEN + 1];
|
||||
|
||||
#ifdef CONFIG_ASSH_SERVER_AUTH_PASSWORD
|
||||
char password[CONFIG_ASSH_AUTH_PASSWORD_LEN + 1];
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ASSH_SERVER_AUTH_PUBLICKEY
|
||||
enum assh_userauth_pubkey_state_e pubkey_state;
|
||||
const struct assh_key_s *pub_key;
|
||||
struct assh_algo_sign_s *algo;
|
||||
struct assh_packet_s *sign_pck;
|
||||
uint8_t *sign;
|
||||
#endif
|
||||
};
|
||||
|
||||
static ASSH_SERVICE_INIT_FCN(assh_userauth_server_init)
|
||||
{
|
||||
assh_error_t err;
|
||||
struct assh_userauth_context_s *pv;
|
||||
|
||||
ASSH_ERR_RET(assh_alloc(s->ctx, sizeof(*pv),
|
||||
ASSH_ALLOC_SECUR, (void**)&pv));
|
||||
|
||||
s->srv = &assh_service_userauth_server;
|
||||
s->srv_pv = pv;
|
||||
|
||||
pv->state = ASSH_USERAUTH_WAIT_RQ;
|
||||
pv->retry = 10;
|
||||
pv->srv = NULL;
|
||||
|
||||
#ifdef CONFIG_ASSH_SERVER_AUTH_PUBLICKEY
|
||||
pv->pub_key = NULL;
|
||||
pv->pubkey_state = ASSH_USERAUTH_PUBKEY_NONE;
|
||||
pv->sign_pck = NULL;
|
||||
#endif
|
||||
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
static void assh_userauth_server_flush_state(struct assh_session_s *s)
|
||||
{
|
||||
struct assh_userauth_context_s *pv = s->srv_pv;
|
||||
|
||||
pv->state = ASSH_USERAUTH_WAIT_RQ;
|
||||
pv->srv = NULL;
|
||||
|
||||
#ifdef CONFIG_ASSH_SERVER_AUTH_PUBLICKEY
|
||||
assh_key_flush(s->ctx, &pv->pub_key);
|
||||
pv->pubkey_state = ASSH_USERAUTH_PUBKEY_NONE;
|
||||
|
||||
assh_packet_release(pv->sign_pck);
|
||||
pv->sign_pck = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
static ASSH_SERVICE_CLEANUP_FCN(assh_userauth_server_cleanup)
|
||||
{
|
||||
struct assh_userauth_context_s *pv = s->srv_pv;
|
||||
|
||||
assh_userauth_server_flush_state(s);
|
||||
|
||||
assh_free(s->ctx, pv);
|
||||
|
||||
s->srv_pv = NULL;
|
||||
s->srv = NULL;
|
||||
}
|
||||
|
||||
/* handle authentication failure */
|
||||
static assh_error_t assh_userauth_server_failure(struct assh_session_s *s)
|
||||
{
|
||||
struct assh_userauth_context_s *pv = s->srv_pv;
|
||||
assh_error_t err;
|
||||
|
||||
/* flush state */
|
||||
assh_userauth_server_flush_state(s);
|
||||
|
||||
/* check auth attempts count */
|
||||
ASSH_CHK_RET(pv->retry == 0, ASSH_ERR_NO_AUTH | ASSH_ERRSV_DISCONNECT);
|
||||
|
||||
/* send the authentication failure packet */
|
||||
struct assh_packet_s *pout;
|
||||
#if defined(CONFIG_ASSH_SERVER_AUTH_PUBLICKEY) && defined(CONFIG_ASSH_SERVER_AUTH_PASSWORD)
|
||||
const char *list_ = "publickey,password";
|
||||
#elif defined(CONFIG_ASSH_SERVER_AUTH_PUBLICKEY)
|
||||
const char *list_ = "publickey";
|
||||
#elif defined(CONFIG_ASSH_SERVER_AUTH_PASSWORD)
|
||||
const char *list_ = "password";
|
||||
#else
|
||||
const char *list_ = "none";
|
||||
#endif
|
||||
uint8_t *list, *partial_success;
|
||||
size_t list_len = strlen(list_);
|
||||
|
||||
ASSH_ERR_RET(assh_packet_alloc(s->ctx, SSH_MSG_USERAUTH_FAILURE,
|
||||
4 + list_len + 1, &pout) | ASSH_ERRSV_DISCONNECT);
|
||||
|
||||
ASSH_ASSERT(assh_packet_add_string(pout, list_len, &list));
|
||||
memcpy(list, list_, list_len);
|
||||
ASSH_ASSERT(assh_packet_add_array(pout, 1, &partial_success));
|
||||
*partial_success = 0;
|
||||
assh_transport_push(s, pout);
|
||||
pv->retry--;
|
||||
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
/* handle authentication success */
|
||||
static assh_error_t assh_userauth_server_success(struct assh_session_s *s)
|
||||
{
|
||||
assh_error_t err;
|
||||
struct assh_userauth_context_s *pv = s->srv_pv;
|
||||
const struct assh_service_s *srv = pv->srv;
|
||||
|
||||
/* cleanup the authentication service */
|
||||
assh_userauth_server_cleanup(s);
|
||||
|
||||
/* send the authentication success packet */
|
||||
struct assh_packet_s *pout;
|
||||
ASSH_ERR_RET(assh_packet_alloc(s->ctx, SSH_MSG_USERAUTH_SUCCESS, 0, &pout)
|
||||
| ASSH_ERRSV_DISCONNECT);
|
||||
assh_transport_push(s, pout);
|
||||
|
||||
/* start the next requested service */
|
||||
ASSH_ERR_RET(srv->f_init(s) | ASSH_ERRSV_DISCONNECT);
|
||||
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
/******************************************************************* password */
|
||||
|
||||
#ifdef CONFIG_ASSH_SERVER_AUTH_PASSWORD
|
||||
|
||||
static ASSH_EVENT_DONE_FCN(assh_userauth_server_password_done)
|
||||
{
|
||||
struct assh_userauth_context_s *pv = s->srv_pv;
|
||||
assh_error_t err;
|
||||
|
||||
ASSH_CHK_RET(pv->state != ASSH_USERAUTH_PASSWORD, ASSH_ERR_STATE | ASSH_ERRSV_FATAL);
|
||||
|
||||
if (e->userauth_server.password.success)
|
||||
ASSH_ERR_RET(assh_userauth_server_success(s) | ASSH_ERRSV_DISCONNECT);
|
||||
else
|
||||
ASSH_ERR_RET(assh_userauth_server_failure(s) | ASSH_ERRSV_DISCONNECT);
|
||||
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
/* handle password request packet */
|
||||
static assh_error_t assh_userauth_server_req_password(struct assh_session_s *s,
|
||||
struct assh_packet_s *p,
|
||||
struct assh_event_s *e,
|
||||
uint8_t *auth_data)
|
||||
{
|
||||
struct assh_userauth_context_s *pv = s->srv_pv;
|
||||
assh_error_t err;
|
||||
|
||||
uint8_t *second = auth_data;
|
||||
uint8_t *password;
|
||||
|
||||
ASSH_ERR_RET(assh_packet_check_array(p, second, 1, &password) | ASSH_ERRSV_DISCONNECT);
|
||||
ASSH_CHK_RET(*second != 0, ASSH_ERR_PROTOCOL | ASSH_ERRSV_DISCONNECT);
|
||||
|
||||
/* copy password */
|
||||
ASSH_ERR_RET(assh_packet_check_string(p, password, NULL) | ASSH_ERRSV_DISCONNECT);
|
||||
ASSH_ERR_RET(assh_ssh_string_copy(password, pv->password, sizeof(pv->password))
|
||||
| ASSH_ERRSV_DISCONNECT);
|
||||
|
||||
/* return event to check the user password */
|
||||
e->id = ASSH_EVENT_USERAUTH_SERVER_PASSWORD;
|
||||
e->f_done = assh_userauth_server_password_done;
|
||||
e->userauth_server.password.username.str = pv->username;
|
||||
e->userauth_server.password.username.len = strlen(pv->username);
|
||||
e->userauth_server.password.password.str = pv->password;
|
||||
e->userauth_server.password.password.len = strlen(pv->password);
|
||||
e->userauth_server.password.success = 0;
|
||||
|
||||
pv->state = ASSH_USERAUTH_PASSWORD;
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/******************************************************************* public key */
|
||||
|
||||
#ifdef CONFIG_ASSH_SERVER_AUTH_PUBLICKEY
|
||||
|
||||
static assh_error_t assh_userauth_server_pubkey_check(struct assh_session_s *s,
|
||||
struct assh_packet_s *p,
|
||||
uint8_t *sign)
|
||||
{
|
||||
struct assh_userauth_context_s *pv = s->srv_pv;
|
||||
assh_error_t err;
|
||||
|
||||
uint8_t *end;
|
||||
ASSH_ERR_RET(assh_packet_check_string(p, sign, &end) | ASSH_ERRSV_DISCONNECT);
|
||||
|
||||
uint8_t sid_len[4]; /* fake string header for session id */
|
||||
assh_store_u32(sid_len, s->session_id_len);
|
||||
|
||||
/* buffers that have been signed by the client */
|
||||
const uint8_t *sign_ptrs[3] =
|
||||
{ sid_len, s->session_id, &p->head.msg };
|
||||
size_t sign_sizes[3] =
|
||||
{ 4, s->session_id_len, sign - &p->head.msg };
|
||||
|
||||
/* check the signature */
|
||||
if (assh_sign_check(s->ctx, pv->algo, pv->pub_key, 3,
|
||||
sign_ptrs, sign_sizes, sign + 4, end - sign - 4) == ASSH_OK)
|
||||
ASSH_ERR_RET(assh_userauth_server_success(s) | ASSH_ERRSV_DISCONNECT);
|
||||
else
|
||||
ASSH_ERR_RET(assh_userauth_server_failure(s) | ASSH_ERRSV_DISCONNECT);
|
||||
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
static ASSH_EVENT_DONE_FCN(assh_userauth_server_userkey_done)
|
||||
{
|
||||
struct assh_userauth_context_s *pv = s->srv_pv;
|
||||
assh_error_t err;
|
||||
|
||||
switch (pv->state)
|
||||
{
|
||||
case ASSH_USERAUTH_PUBKEY_PKOK: { /* may need to send PK_OK */
|
||||
pv->state = ASSH_USERAUTH_WAIT_RQ;
|
||||
|
||||
if (!e->userauth_server.userkey.found)
|
||||
{
|
||||
ASSH_ERR_RET(assh_userauth_server_failure(s) | ASSH_ERRSV_DISCONNECT);
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
/* alloc packet */
|
||||
size_t algo_name_len = strlen(pv->algo->algo.name);
|
||||
|
||||
size_t blob_len;
|
||||
ASSH_ERR_RET(assh_key_output(s->ctx, pv->pub_key,
|
||||
NULL, &blob_len, ASSH_KEY_FMT_PUB_RFC4253_6_6) | ASSH_ERRSV_DISCONNECT);
|
||||
|
||||
struct assh_packet_s *pout;
|
||||
ASSH_ERR_RET(assh_packet_alloc(s->ctx, SSH_MSG_USERAUTH_PK_OK,
|
||||
4 + algo_name_len + 4 + blob_len, &pout) | ASSH_ERRSV_DISCONNECT);
|
||||
|
||||
/* add sign algorithm name */
|
||||
uint8_t *algo_name;
|
||||
ASSH_ASSERT(assh_packet_add_string(pout, algo_name_len, &algo_name));
|
||||
memcpy(algo_name, pv->algo->algo.name, algo_name_len);
|
||||
|
||||
/* add public key blob */
|
||||
uint8_t *blob;
|
||||
ASSH_ASSERT(assh_packet_add_string(pout, blob_len, &blob));
|
||||
ASSH_ERR_GTO(assh_key_output(s->ctx, pv->pub_key,
|
||||
blob, &blob_len, ASSH_KEY_FMT_PUB_RFC4253_6_6)
|
||||
| ASSH_ERRSV_DISCONNECT, err_packet);
|
||||
assh_packet_shrink_string(pout, blob, blob_len);
|
||||
|
||||
assh_transport_push(s, pout);
|
||||
pv->pubkey_state = ASSH_USERAUTH_PUBKEY_FOUND;
|
||||
|
||||
return ASSH_OK;
|
||||
err_packet:
|
||||
assh_packet_release(pout);
|
||||
return err;
|
||||
}
|
||||
|
||||
case ASSH_USERAUTH_PUBKEY_VERIFY: {
|
||||
pv->state = ASSH_USERAUTH_WAIT_RQ;
|
||||
|
||||
if (!e->userauth_server.userkey.found)
|
||||
ASSH_ERR_RET(assh_userauth_server_failure(s)
|
||||
| ASSH_ERRSV_DISCONNECT);
|
||||
else
|
||||
ASSH_ERR_RET(assh_userauth_server_pubkey_check(s, pv->sign_pck, pv->sign)
|
||||
| ASSH_ERRSV_DISCONNECT);
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
default:
|
||||
ASSH_ERR_RET(ASSH_ERR_STATE | ASSH_ERRSV_FATAL);
|
||||
}
|
||||
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
/* handle public key request packet */
|
||||
static assh_error_t assh_userauth_server_req_pubkey(struct assh_session_s *s,
|
||||
struct assh_packet_s *p,
|
||||
struct assh_event_s *e,
|
||||
uint8_t *auth_data)
|
||||
{
|
||||
struct assh_userauth_context_s *pv = s->srv_pv;
|
||||
assh_error_t err;
|
||||
|
||||
uint8_t *second = auth_data;
|
||||
uint8_t *algo_name, *pub_blob, *sign;
|
||||
|
||||
ASSH_ERR_RET(assh_packet_check_array(p, second, 1, &algo_name) | ASSH_ERRSV_DISCONNECT);
|
||||
ASSH_ERR_RET(assh_packet_check_string(p, algo_name, &pub_blob) | ASSH_ERRSV_DISCONNECT);
|
||||
ASSH_ERR_RET(assh_packet_check_string(p, pub_blob, &sign) | ASSH_ERRSV_DISCONNECT);
|
||||
|
||||
const struct assh_algo_s *algo;
|
||||
|
||||
/* check if we support the requested signature algorithm */
|
||||
if (assh_algo_by_name(s->ctx, ASSH_ALGO_SIGN, (char*)algo_name + 4,
|
||||
pub_blob - algo_name - 4, &algo) != ASSH_OK)
|
||||
{
|
||||
ASSH_ERR_RET(assh_userauth_server_failure(s) | ASSH_ERRSV_DISCONNECT);
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
const struct assh_key_s *pub_key = NULL;
|
||||
|
||||
/* load the public key from the client provided blob */
|
||||
ASSH_ERR_RET(assh_key_load(s->ctx, &pub_key, algo->key, ASSH_ALGO_SIGN,
|
||||
ASSH_KEY_FMT_PUB_RFC4253_6_6, pub_blob + 4,
|
||||
sign - pub_blob - 4) | ASSH_ERRSV_DISCONNECT);
|
||||
|
||||
/* check if the key can be used by the algorithm */
|
||||
if (!assh_algo_suitable_key(s->ctx, algo, pub_key))
|
||||
{
|
||||
assh_key_drop(s->ctx, &pub_key);
|
||||
ASSH_ERR_RET(assh_userauth_server_failure(s) | ASSH_ERRSV_DISCONNECT);
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
/* test if the key has been previously found in the list of authorized user keys. */
|
||||
assh_bool_t new_key = (pv->pubkey_state == ASSH_USERAUTH_PUBKEY_NONE ||
|
||||
!assh_key_cmp(s->ctx, pub_key, pv->pub_key, 1));
|
||||
|
||||
if (new_key)
|
||||
{
|
||||
assh_key_flush(s->ctx, &pv->pub_key);
|
||||
pv->pub_key = pub_key;
|
||||
pv->algo = (void*)algo;
|
||||
pv->pubkey_state = ASSH_USERAUTH_PUBKEY_NEW;
|
||||
}
|
||||
else
|
||||
{
|
||||
assh_key_drop(s->ctx, &pub_key);
|
||||
}
|
||||
|
||||
/* the packet contains a signature to check */
|
||||
if (*second)
|
||||
{
|
||||
if (pv->pubkey_state == ASSH_USERAUTH_PUBKEY_FOUND)
|
||||
{
|
||||
ASSH_ERR_RET(assh_userauth_server_pubkey_check(s, p, sign)
|
||||
| ASSH_ERRSV_DISCONNECT);
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
assh_packet_refinc(p);
|
||||
pv->sign_pck = p;
|
||||
pv->sign = sign;
|
||||
|
||||
pv->state = ASSH_USERAUTH_PUBKEY_VERIFY;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pv->pubkey_state == ASSH_USERAUTH_PUBKEY_FOUND)
|
||||
return ASSH_OK;
|
||||
|
||||
pv->state = ASSH_USERAUTH_PUBKEY_PKOK;
|
||||
}
|
||||
|
||||
/* return an event to lookup the key in the list of authorized user keys */
|
||||
e->id = ASSH_EVENT_USERAUTH_SERVER_USERKEY;
|
||||
e->f_done = assh_userauth_server_userkey_done;
|
||||
e->userauth_server.userkey.username.str = pv->username;
|
||||
e->userauth_server.userkey.username.len = strlen(pv->username);
|
||||
e->userauth_server.userkey.pub_key = pv->pub_key;
|
||||
e->userauth_server.userkey.found = 0;
|
||||
|
||||
return ASSH_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
/********************************************************************/
|
||||
|
||||
/* flush the authentication state on new request */
|
||||
static assh_error_t assh_userauth_server_req_new(struct assh_session_s *s,
|
||||
uint8_t *srv_name,
|
||||
uint8_t *username,
|
||||
uint8_t *method_name)
|
||||
{
|
||||
struct assh_userauth_context_s *pv = s->srv_pv;
|
||||
assh_error_t err;
|
||||
|
||||
if (pv->srv == NULL ||
|
||||
!assh_ssh_string_compare(srv_name, pv->srv->name) ||
|
||||
!assh_ssh_string_compare(username, pv->username) ||
|
||||
!assh_ssh_string_compare(method_name, pv->method_name))
|
||||
{
|
||||
assh_userauth_server_flush_state(s);
|
||||
|
||||
/* lookup service name */
|
||||
if (assh_service_by_name(s->ctx, assh_load_u32(srv_name),
|
||||
(char*)srv_name + 4, &pv->srv))
|
||||
{
|
||||
ASSH_ERR_RET(assh_userauth_server_failure(s) | ASSH_ERRSV_DISCONNECT);
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
/* keep method name and user name */
|
||||
ASSH_ERR_RET(assh_ssh_string_copy(username, pv->username, sizeof(pv->username))
|
||||
| ASSH_ERRSV_DISCONNECT);
|
||||
ASSH_ERR_RET(assh_ssh_string_copy(method_name, pv->method_name, sizeof(pv->method_name))
|
||||
| ASSH_ERRSV_DISCONNECT);
|
||||
}
|
||||
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
static ASSH_SERVICE_PROCESS_FCN(assh_userauth_server_process)
|
||||
{
|
||||
struct assh_userauth_context_s *pv = s->srv_pv;
|
||||
assh_error_t err;
|
||||
|
||||
if (s->tr_st >= ASSH_TR_FIN)
|
||||
return ASSH_OK;
|
||||
|
||||
if (p == NULL)
|
||||
return ASSH_OK;
|
||||
|
||||
ASSH_CHK_RET(pv->state != ASSH_USERAUTH_WAIT_RQ,
|
||||
ASSH_ERR_STATE | ASSH_ERRSV_FATAL);
|
||||
|
||||
ASSH_CHK_RET(p->head.msg != SSH_MSG_USERAUTH_REQUEST,
|
||||
ASSH_ERR_PROTOCOL | ASSH_ERRSV_DISCONNECT);
|
||||
|
||||
uint8_t *username = p->head.end;
|
||||
uint8_t *srv_name, *method_name, *auth_data;
|
||||
|
||||
ASSH_ERR_RET(assh_packet_check_string(p, username, &srv_name) | ASSH_ERRSV_DISCONNECT);
|
||||
ASSH_ERR_RET(assh_packet_check_string(p, srv_name, &method_name) | ASSH_ERRSV_DISCONNECT);
|
||||
ASSH_ERR_RET(assh_packet_check_string(p, method_name, &auth_data) | ASSH_ERRSV_DISCONNECT);
|
||||
|
||||
switch (/* method name len */ auth_data - method_name - 4)
|
||||
{
|
||||
#ifdef CONFIG_ASSH_SERVER_AUTH_NONE
|
||||
case 4:
|
||||
if (!assh_ssh_string_compare(method_name, "none"))
|
||||
{
|
||||
ASSH_ERR_RET(assh_userauth_server_req_new(s, srv_name, username, method_name)
|
||||
| ASSH_ERRSV_DISCONNECT);
|
||||
ASSH_ERR_RET(assh_userauth_server_success(s)
|
||||
| ASSH_ERRSV_DISCONNECT);
|
||||
return ASSH_OK;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ASSH_SERVER_AUTH_PASSWORD
|
||||
case 8:
|
||||
if (!assh_ssh_string_compare(method_name, "password"))
|
||||
{
|
||||
ASSH_ERR_RET(assh_userauth_server_req_new(s, srv_name, username, method_name)
|
||||
| ASSH_ERRSV_DISCONNECT);
|
||||
ASSH_ERR_RET(assh_userauth_server_req_password(s, p, e, auth_data)
|
||||
| ASSH_ERRSV_DISCONNECT);
|
||||
return ASSH_OK;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ASSH_SERVER_AUTH_PUBLICKEY
|
||||
case 9:
|
||||
if (!assh_ssh_string_compare(method_name, "publickey"))
|
||||
{
|
||||
ASSH_ERR_RET(assh_userauth_server_req_new(s, srv_name, username, method_name)
|
||||
| ASSH_ERRSV_DISCONNECT);
|
||||
ASSH_ERR_RET(assh_userauth_server_req_pubkey(s, p, e, auth_data)
|
||||
| ASSH_ERRSV_DISCONNECT);
|
||||
return ASSH_OK;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
ASSH_ERR_RET(assh_userauth_server_failure(s) | ASSH_ERRSV_DISCONNECT);
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
const struct assh_service_s assh_service_userauth_server =
|
||||
{
|
||||
.name = "ssh-userauth",
|
||||
.side = ASSH_SERVER,
|
||||
.f_init = assh_userauth_server_init,
|
||||
.f_cleanup = assh_userauth_server_cleanup,
|
||||
.f_process = assh_userauth_server_process,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,763 @@
|
|||
/*
|
||||
|
||||
libassh - asynchronous ssh2 client/server library.
|
||||
|
||||
Copyright (C) 2013 Alexandre Becoulet <alexandre.becoulet@free.fr>
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#include <assh/assh_bignum.h>
|
||||
#include <assh/assh_context.h>
|
||||
#include <assh/assh_packet.h>
|
||||
#include <assh/assh_prng.h>
|
||||
#include <assh/assh_alloc.h>
|
||||
|
||||
#include <gcrypt.h>
|
||||
|
||||
static ASSH_WARN_UNUSED_RESULT assh_error_t
|
||||
assh_gcrypt_bignum_rand(struct assh_context_s *c,
|
||||
struct assh_bignum_s *bn,
|
||||
const struct assh_bignum_s *min,
|
||||
const struct assh_bignum_s *max,
|
||||
enum assh_prng_quality_e quality)
|
||||
{
|
||||
assh_error_t err;
|
||||
|
||||
ASSH_CHK_RET(c->prng == NULL, ASSH_ERR_MISSING_ALGO);
|
||||
|
||||
size_t bits = bn->bits;
|
||||
|
||||
if (max != NULL)
|
||||
bits = ASSH_MIN(bits, gcry_mpi_get_nbits(max->n));
|
||||
|
||||
size_t n = ASSH_ALIGN8(bn->bits);
|
||||
|
||||
if (c->prng == &assh_prng_gcrypt)
|
||||
{
|
||||
enum gcry_random_level level;
|
||||
switch (quality)
|
||||
{
|
||||
case ASSH_PRNG_QUALITY_WEAK:
|
||||
level = GCRY_WEAK_RANDOM;
|
||||
break;
|
||||
case ASSH_PRNG_QUALITY_NONCE:
|
||||
case ASSH_PRNG_QUALITY_EPHEMERAL_KEY:
|
||||
level = GCRY_STRONG_RANDOM;
|
||||
break;
|
||||
case ASSH_PRNG_QUALITY_LONGTERM_KEY:
|
||||
default:
|
||||
level = GCRY_VERY_STRONG_RANDOM;
|
||||
break;
|
||||
}
|
||||
|
||||
if (bn->n == NULL)
|
||||
bn->n = gcry_mpi_snew(n);
|
||||
|
||||
gcry_mpi_randomize(bn->n, n, level);
|
||||
gcry_mpi_rshift(bn->n, bn->n, n - bits);
|
||||
|
||||
gcry_mpi_t t = NULL;
|
||||
|
||||
while ((min != NULL && gcry_mpi_cmp(bn->n, min->n) <= 0) ||
|
||||
(max != NULL && gcry_mpi_cmp(bn->n, max->n) >= 0))
|
||||
{
|
||||
if (t == NULL)
|
||||
t = gcry_mpi_snew(8);
|
||||
|
||||
gcry_mpi_rshift(bn->n, bn->n, 8);
|
||||
gcry_mpi_randomize(t, 8, level);
|
||||
if (bits >= 8)
|
||||
gcry_mpi_lshift(t, t, bits - 8);
|
||||
else
|
||||
gcry_mpi_rshift(t, t, 8 - bits);
|
||||
gcry_mpi_add(bn->n, bn->n, t);
|
||||
}
|
||||
|
||||
gcry_mpi_release(t);
|
||||
|
||||
err = ASSH_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSH_SCRATCH_ALLOC(c, uint8_t, rnd, n / 8, ASSH_ERRSV_CONTINUE, err_);
|
||||
|
||||
ASSH_ERR_GTO(c->prng->f_get(c, rnd, n / 8, quality), err_sc);
|
||||
|
||||
while (1)
|
||||
{
|
||||
gcry_mpi_release(bn->n);
|
||||
bn->n = NULL;
|
||||
ASSH_CHK_GTO(gcry_mpi_scan((gcry_mpi_t*)&bn->n,
|
||||
GCRYMPI_FMT_USG, rnd, n / 8, NULL), ASSH_ERR_CRYPTO, err_sc);
|
||||
gcry_mpi_rshift(bn->n, bn->n, n - bits);
|
||||
|
||||
if ((min == NULL || gcry_mpi_cmp(bn->n, min->n) > 0) &&
|
||||
(max == NULL || gcry_mpi_cmp(bn->n, max->n) < 0))
|
||||
break;
|
||||
|
||||
memmove(rnd + 1, rnd, n / 8 - 1);
|
||||
ASSH_ERR_GTO(c->prng->f_get(c, rnd, 1, quality), err_sc);
|
||||
}
|
||||
|
||||
err = ASSH_OK;
|
||||
err_sc:
|
||||
ASSH_SCRATCH_FREE(c, rnd);
|
||||
err_:;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void assh_bignum_gcrypt_lsb(uint8_t *data, size_t size)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < size / 2; i++)
|
||||
ASSH_SWAP(data[i], data[size - i - 1]);
|
||||
}
|
||||
|
||||
static ASSH_BIGNUM_CONVERT_FCN(assh_bignum_gcrypt_convert)
|
||||
{
|
||||
assh_error_t err;
|
||||
|
||||
const struct assh_bignum_s *srcn = src;
|
||||
struct assh_bignum_s *dstn = dst;
|
||||
|
||||
if (srcfmt == ASSH_BIGNUM_NATIVE ||
|
||||
srcfmt == ASSH_BIGNUM_STEMP ||
|
||||
srcfmt == ASSH_BIGNUM_TEMP)
|
||||
{
|
||||
size_t s = ASSH_ALIGN8(srcn->bits) / 8;
|
||||
size_t z = s;
|
||||
|
||||
switch (dstfmt)
|
||||
{
|
||||
case ASSH_BIGNUM_NATIVE:
|
||||
case ASSH_BIGNUM_STEMP:
|
||||
case ASSH_BIGNUM_TEMP:
|
||||
ASSH_CHK_RET(dstn->bits < gcry_mpi_get_nbits(srcn->n), ASSH_ERR_NUM_OVERFLOW);
|
||||
gcry_mpi_release(dstn->n);
|
||||
dstn->n = gcry_mpi_snew(dstn->bits);
|
||||
ASSH_CHK_RET(dstn->n == NULL, ASSH_ERR_MEM);
|
||||
dstn->n = gcry_mpi_set(dstn->n, srcn->n);
|
||||
break;
|
||||
case ASSH_BIGNUM_STRING:
|
||||
assh_store_u32(dst, s);
|
||||
dst += 4;
|
||||
ASSH_CHK_RET(gcry_mpi_print(GCRYMPI_FMT_USG, dst, s, &z, srcn->n),
|
||||
ASSH_ERR_NUM_OVERFLOW);
|
||||
break;
|
||||
case ASSH_BIGNUM_MPINT:
|
||||
ASSH_CHK_RET(gcry_mpi_print(GCRYMPI_FMT_SSH, dst, s + 5, NULL, srcn->n),
|
||||
ASSH_ERR_NUM_OVERFLOW);
|
||||
break;
|
||||
case ASSH_BIGNUM_LSB_RAW:
|
||||
case ASSH_BIGNUM_MSB_RAW:
|
||||
ASSH_CHK_RET(gcry_mpi_print(GCRYMPI_FMT_USG, dst, s, &z, srcn->n),
|
||||
ASSH_ERR_NUM_OVERFLOW);
|
||||
break;
|
||||
default:
|
||||
ASSH_ERR_RET(ASSH_ERR_NOTSUP);
|
||||
}
|
||||
|
||||
/* shift and zero pad */
|
||||
if (z < s)
|
||||
{
|
||||
size_t d = s - z;
|
||||
memmove(dst + d, dst, z);
|
||||
memset(dst, 0, d);
|
||||
}
|
||||
|
||||
/* reverse byte order */
|
||||
if (dstfmt == ASSH_BIGNUM_LSB_RAW)
|
||||
assh_bignum_gcrypt_lsb(dst, s);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(dstfmt == ASSH_BIGNUM_NATIVE ||
|
||||
dstfmt == ASSH_BIGNUM_STEMP ||
|
||||
dstfmt == ASSH_BIGNUM_TEMP);
|
||||
size_t s, n, b;
|
||||
|
||||
if (srcfmt == ASSH_BIGNUM_MSB_RAW ||
|
||||
srcfmt == ASSH_BIGNUM_LSB_RAW)
|
||||
{
|
||||
b = dstn->bits;
|
||||
n = s = ASSH_ALIGN8(b) / 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSH_ERR_RET(assh_bignum_size_of_data(srcfmt, src, &s, &n, &b));
|
||||
ASSH_CHK_RET(dstn->bits < b, ASSH_ERR_NUM_OVERFLOW);
|
||||
}
|
||||
|
||||
gcry_mpi_release(dstn->n);
|
||||
dstn->n = NULL;
|
||||
|
||||
switch (srcfmt)
|
||||
{
|
||||
case ASSH_BIGNUM_STRING:
|
||||
case ASSH_BIGNUM_MPINT: {
|
||||
const uint8_t *mpint = src;
|
||||
ASSH_CHK_RET(gcry_mpi_scan((gcry_mpi_t*)&dstn->n, GCRYMPI_FMT_USG,
|
||||
mpint + 4, s - 4, NULL),
|
||||
ASSH_ERR_NUM_OVERFLOW);
|
||||
break;
|
||||
}
|
||||
|
||||
case ASSH_BIGNUM_ASN1: {
|
||||
const uint8_t *asn1 = src;
|
||||
ASSH_CHK_RET(gcry_mpi_scan((gcry_mpi_t*)&dstn->n, GCRYMPI_FMT_USG,
|
||||
asn1 + s - n, n, NULL),
|
||||
ASSH_ERR_NUM_OVERFLOW);
|
||||
break;
|
||||
}
|
||||
|
||||
case ASSH_BIGNUM_LSB_RAW: {
|
||||
ASSH_SCRATCH_ALLOC(c, uint8_t, lsb, s,
|
||||
ASSH_ERRSV_CONTINUE, err_lsb);
|
||||
memcpy(lsb, src, s);
|
||||
assh_bignum_gcrypt_lsb(lsb, s);
|
||||
ASSH_CHK_GTO(gcry_mpi_scan((gcry_mpi_t*)&dstn->n, GCRYMPI_FMT_USG,
|
||||
lsb, s, NULL),
|
||||
ASSH_ERR_NUM_OVERFLOW, err_lsb_scan);
|
||||
gcry_mpi_clear_highbit((gcry_mpi_t)dstn->n, b);
|
||||
|
||||
ASSH_SCRATCH_FREE(c, lsb);
|
||||
break;
|
||||
|
||||
err_lsb_scan:
|
||||
ASSH_SCRATCH_FREE(c, lsb);
|
||||
err_lsb:
|
||||
return err;
|
||||
}
|
||||
|
||||
case ASSH_BIGNUM_MSB_RAW: {
|
||||
ASSH_CHK_RET(gcry_mpi_scan((gcry_mpi_t*)&dstn->n, GCRYMPI_FMT_USG,
|
||||
src, s, NULL),
|
||||
ASSH_ERR_NUM_OVERFLOW);
|
||||
gcry_mpi_clear_highbit((gcry_mpi_t)dstn->n, b);
|
||||
break;
|
||||
}
|
||||
|
||||
case ASSH_BIGNUM_HEX: {
|
||||
ASSH_CHK_RET(gcry_mpi_scan((gcry_mpi_t*)&dstn->n, GCRYMPI_FMT_HEX,
|
||||
src, 0, NULL),
|
||||
ASSH_ERR_NUM_OVERFLOW);
|
||||
break;
|
||||
}
|
||||
|
||||
case ASSH_BIGNUM_INT: {
|
||||
ASSH_CHK_RET(dstn->bits < sizeof(intptr_t) * 8, ASSH_ERR_NUM_OVERFLOW);
|
||||
dstn->n = gcry_mpi_set_ui(dstn->n, (uintptr_t)src);
|
||||
break;
|
||||
}
|
||||
|
||||
case ASSH_BIGNUM_SIZE: {
|
||||
if (b > 0)
|
||||
dstn->n = gcry_mpi_snew(b);
|
||||
dstn->bits = b;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
ASSH_ERR_RET(ASSH_ERR_NOTSUP);
|
||||
}
|
||||
|
||||
ASSH_CHK_RET(dstn->n == NULL, ASSH_ERR_MEM);
|
||||
ASSH_CHK_RET(gcry_mpi_is_neg(dstn->n), ASSH_ERR_NUM_OVERFLOW);
|
||||
ASSH_CHK_RET(gcry_mpi_get_nbits(dstn->n) > dstn->bits, ASSH_ERR_NUM_OVERFLOW);
|
||||
}
|
||||
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
struct assh_gcrypt_prime_s
|
||||
{
|
||||
gcry_mpi_t min;
|
||||
gcry_mpi_t max;
|
||||
};
|
||||
|
||||
static int assh_gcrypt_prime_chk(void *arg, int mode,
|
||||
gcry_mpi_t candidate)
|
||||
{
|
||||
struct assh_gcrypt_prime_s *p = arg;
|
||||
|
||||
if (p->min != NULL && gcry_mpi_cmp(candidate, p->min) <= 0)
|
||||
return 0;
|
||||
if (p->max != NULL && gcry_mpi_cmp(candidate, p->max) >= 0)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static ASSH_BIGNUM_BYTECODE_FCN(assh_bignum_gcrypt_bytecode)
|
||||
{
|
||||
uint_fast8_t flen, tlen = 0;
|
||||
assh_error_t err;
|
||||
uint_fast8_t i, j, pc = 0;
|
||||
|
||||
/* find number of arguments and temporaries */
|
||||
for (tlen = flen = 0; format[flen]; flen++)
|
||||
if (format[flen] == 'T' ||
|
||||
format[flen] == 'X' ||
|
||||
format[flen] == 'm')
|
||||
tlen++;
|
||||
|
||||
void *args[flen];
|
||||
struct assh_bignum_s tmp[tlen];
|
||||
memset(tmp, 0, sizeof(tmp));
|
||||
|
||||
for (j = i = 0; i < flen; i++)
|
||||
switch (format[i])
|
||||
{
|
||||
case ASSH_BIGNUM_STEMP:
|
||||
tmp[j].secret = 1;
|
||||
case ASSH_BIGNUM_TEMP:
|
||||
case ASSH_BIGNUM_MT:
|
||||
args[i] = &tmp[j];
|
||||
j++;
|
||||
break;
|
||||
case ASSH_BIGNUM_SIZE:
|
||||
args[i] = (void*)va_arg(ap, size_t);
|
||||
break;
|
||||
default:
|
||||
args[i] = va_arg(ap, void *);
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
uint32_t opc = ops[pc];
|
||||
enum assh_bignum_opcode_e op = opc >> 26;
|
||||
uint_fast8_t oa = (opc >> 20) & 0x3f;
|
||||
uint_fast8_t ob = (opc >> 14) & 0x3f;
|
||||
uint_fast8_t oc = (opc >> 6) & 0xff;
|
||||
uint_fast8_t od = opc & 0x3f;
|
||||
uint_fast32_t value = (opc >> 6) & 0xfffff;
|
||||
|
||||
#if defined(CONFIG_ASSH_DEBUG) && 1
|
||||
const char *opnames[] = ASSH_BIGNUM_OP_NAMES;
|
||||
ASSH_DEBUG("exec=%p, pc=%u, op=%s, a=%u, b=%u, c=%u, d=%u, value=%u\n",
|
||||
ops, pc, opnames[op], oa, ob, oc, od, value);
|
||||
#if 1
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < flen; i++)
|
||||
if (format[i] == ASSH_BIGNUM_NATIVE ||
|
||||
format[i] == ASSH_BIGNUM_TEMP ||
|
||||
format[i] == ASSH_BIGNUM_STEMP)
|
||||
{
|
||||
struct assh_bignum_s *src = args[i];
|
||||
ASSH_DEBUG("%u: 0x", i);
|
||||
if (src->n)
|
||||
gcry_mpi_dump(src->n);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
pc++;
|
||||
switch (op)
|
||||
{
|
||||
case ASSH_BIGNUM_OP_END:
|
||||
goto end;
|
||||
|
||||
case ASSH_BIGNUM_OP_MOVE:
|
||||
ASSH_ERR_GTO(assh_bignum_gcrypt_convert(c, format[od], format[oc],
|
||||
args[od], args[oc]), err_sc);
|
||||
break;
|
||||
|
||||
case ASSH_BIGNUM_OP_SIZER:
|
||||
case ASSH_BIGNUM_OP_SIZE: {
|
||||
size_t b, i;
|
||||
ASSH_ERR_GTO(assh_bignum_size_of_data(format[ob], args[ob],
|
||||
NULL, NULL, &b), err_sc);
|
||||
if (op == ASSH_BIGNUM_OP_SIZE)
|
||||
{
|
||||
struct assh_bignum_s *dst = args[oa];
|
||||
dst->bits = ((od >= 32) ? (b << (od - 32))
|
||||
: (b >> (32 - od))) + (intptr_t)(int8_t)oc;
|
||||
}
|
||||
else
|
||||
for (i = oa; i <= oc; i++)
|
||||
{
|
||||
struct assh_bignum_s *dst = args[i];
|
||||
dst->bits = b;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ASSH_BIGNUM_OP_MTINIT: {
|
||||
struct assh_bignum_s *src = args[od];
|
||||
struct assh_bignum_s *dst = args[oc];
|
||||
gcry_mpi_release(dst->n);
|
||||
dst->n = gcry_mpi_copy(src->n);
|
||||
dst->bits = src->bits;
|
||||
break;
|
||||
}
|
||||
|
||||
case ASSH_BIGNUM_OP_MTFROM:
|
||||
case ASSH_BIGNUM_OP_MTTO: {
|
||||
uint_fast8_t i;
|
||||
for (i = 0; i < oa; i++)
|
||||
{
|
||||
if (oc == ob)
|
||||
continue;
|
||||
struct assh_bignum_s *src = args[oc + i];
|
||||
struct assh_bignum_s *dst = args[ob + i];
|
||||
gcry_mpi_release(dst->n);
|
||||
dst->n = gcry_mpi_copy(src->n);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ASSH_BIGNUM_OP_EXPM:
|
||||
assert(format[od] == ASSH_BIGNUM_MT);
|
||||
case ASSH_BIGNUM_OP_ADD:
|
||||
case ASSH_BIGNUM_OP_SUB:
|
||||
case ASSH_BIGNUM_OP_MUL: {
|
||||
struct assh_bignum_s *dst = args[oa];
|
||||
if (dst->n == NULL)
|
||||
{
|
||||
dst->n = gcry_mpi_snew(dst->bits);
|
||||
ASSH_CHK_GTO(dst->n == NULL, ASSH_ERR_MEM, err_sc);
|
||||
}
|
||||
|
||||
struct assh_bignum_s *src1 = args[ob];
|
||||
struct assh_bignum_s *src2 = args[oc];
|
||||
if (od == ASSH_BOP_NOREG)
|
||||
{
|
||||
assert(dst->bits >= src1->bits &&
|
||||
dst->bits >= src2->bits);
|
||||
switch (op)
|
||||
{
|
||||
case ASSH_BIGNUM_OP_ADD:
|
||||
gcry_mpi_add(dst->n, src1->n, src2->n);
|
||||
ASSH_CHK_GTO(gcry_mpi_get_nbits(dst->n) > dst->bits,
|
||||
ASSH_ERR_NUM_OVERFLOW, err_sc);
|
||||
break;
|
||||
case ASSH_BIGNUM_OP_SUB:
|
||||
gcry_mpi_sub(dst->n, src1->n, src2->n);
|
||||
ASSH_CHK_GTO(gcry_mpi_get_nbits(dst->n) > dst->bits,
|
||||
ASSH_ERR_NUM_OVERFLOW, err_sc);
|
||||
ASSH_CHK_GTO(gcry_mpi_is_neg(dst->n),
|
||||
ASSH_ERR_NUM_OVERFLOW, err_sc);
|
||||
break;
|
||||
case ASSH_BIGNUM_OP_MUL:
|
||||
assert(dst->bits >= src1->bits + src2->bits);
|
||||
gcry_mpi_mul(dst->n, src1->n, src2->n);
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
struct assh_bignum_s *mod = args[od];
|
||||
switch (op)
|
||||
{
|
||||
case ASSH_BIGNUM_OP_ADD:
|
||||
gcry_mpi_addm(dst->n, src1->n, src2->n, mod->n);
|
||||
break;
|
||||
case ASSH_BIGNUM_OP_SUB:
|
||||
gcry_mpi_subm(dst->n, src1->n, src2->n, mod->n);
|
||||
ASSH_CHK_GTO(gcry_mpi_is_neg(dst->n),
|
||||
ASSH_ERR_NUM_OVERFLOW, err_sc);
|
||||
break;
|
||||
case ASSH_BIGNUM_OP_MUL:
|
||||
gcry_mpi_mulm(dst->n, src1->n, src2->n, mod->n);
|
||||
break;
|
||||
case ASSH_BIGNUM_OP_EXPM:
|
||||
gcry_mpi_powm(dst->n, src1->n, src2->n, mod->n);
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ASSH_BIGNUM_OP_DIV: {
|
||||
gcry_mpi_t q = NULL, r = NULL;
|
||||
if (oa != ASSH_BOP_NOREG)
|
||||
{
|
||||
struct assh_bignum_s *dst = args[oa];
|
||||
if (dst->n == NULL)
|
||||
{
|
||||
dst->n = gcry_mpi_snew(dst->bits);
|
||||
ASSH_CHK_GTO(dst->n == NULL, ASSH_ERR_MEM, err_sc);
|
||||
}
|
||||
q = dst->n;
|
||||
}
|
||||
if (ob != ASSH_BOP_NOREG)
|
||||
{
|
||||
struct assh_bignum_s *dst = args[ob];
|
||||
if (dst->n == NULL)
|
||||
{
|
||||
dst->n = gcry_mpi_snew(dst->bits);
|
||||
ASSH_CHK_GTO(dst->n == NULL, ASSH_ERR_MEM, err_sc);
|
||||
}
|
||||
r = dst->n;
|
||||
}
|
||||
struct assh_bignum_s *src1 = args[oc];
|
||||
struct assh_bignum_s *src2 = args[od];
|
||||
ASSH_CHK_RET(!gcry_mpi_cmp_ui(src2->n, 0), ASSH_ERR_NUM_OVERFLOW);
|
||||
gcry_mpi_div(q, r, src1->n, src2->n, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
case ASSH_BIGNUM_OP_INV:
|
||||
case ASSH_BIGNUM_OP_GCD: {
|
||||
struct assh_bignum_s *dst = args[ob];
|
||||
struct assh_bignum_s *src1 = args[oc];
|
||||
struct assh_bignum_s *src2 = args[od];
|
||||
if (dst->n == NULL)
|
||||
{
|
||||
dst->n = gcry_mpi_snew(dst->bits);
|
||||
ASSH_CHK_GTO(dst->n == NULL, ASSH_ERR_MEM, err_sc);
|
||||
}
|
||||
switch (op)
|
||||
{
|
||||
case ASSH_BIGNUM_OP_GCD:
|
||||
gcry_mpi_gcd(dst->n, src1->n, src2->n);
|
||||
break;
|
||||
case ASSH_BIGNUM_OP_INV:
|
||||
gcry_mpi_invm(dst->n, src1->n, src2->n);
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ASSH_BIGNUM_OP_SHR:
|
||||
case ASSH_BIGNUM_OP_SHL: {
|
||||
struct assh_bignum_s *dst = args[oa];
|
||||
struct assh_bignum_s *src = args[ob];
|
||||
size_t b = 0;
|
||||
ASSH_CHK_RET(dst->bits != src->bits, ASSH_ERR_OUTPUT_OVERFLOW);
|
||||
if (od != ASSH_BOP_NOREG)
|
||||
{
|
||||
ASSH_ERR_GTO(assh_bignum_size_of_data(format[od], args[od],
|
||||
NULL, NULL, &b), err_sc);
|
||||
}
|
||||
if (dst->n == NULL)
|
||||
{
|
||||
dst->n = gcry_mpi_snew(dst->bits);
|
||||
ASSH_CHK_GTO(dst->n == NULL, ASSH_ERR_MEM, err_sc);
|
||||
}
|
||||
switch (op)
|
||||
{
|
||||
case ASSH_BIGNUM_OP_SHR:
|
||||
gcry_mpi_rshift(dst->n, src->n, b + oc - 128);
|
||||
break;
|
||||
case ASSH_BIGNUM_OP_SHL:
|
||||
gcry_mpi_lshift(dst->n, src->n, b + oc - 128);
|
||||
gcry_mpi_clear_highbit(dst->n, dst->bits);
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ASSH_BIGNUM_OP_RAND: {
|
||||
ASSH_ERR_GTO(assh_gcrypt_bignum_rand(c, args[oa],
|
||||
ob == ASSH_BOP_NOREG ? NULL : args[ob],
|
||||
oc == ASSH_BOP_NOREG ? NULL : args[oc],
|
||||
od), err_sc);
|
||||
break;
|
||||
}
|
||||
|
||||
case ASSH_BIGNUM_OP_CMP: {
|
||||
int r = 0;
|
||||
struct assh_bignum_s *src1 = args[oa];
|
||||
struct assh_bignum_s *src2 = args[ob];
|
||||
if (ob == ASSH_BOP_NOREG)
|
||||
r = src1->n != NULL;
|
||||
else if (ob != oa)
|
||||
r = gcry_mpi_cmp(src1->n, src2->n);
|
||||
switch (od)
|
||||
{
|
||||
case 0: /* cmpeq */
|
||||
r = r != 0;
|
||||
break;
|
||||
case 1: /* cmpne */
|
||||
r = r == 0;
|
||||
break;
|
||||
case 2: /* cmplt */
|
||||
r = r >= 0;
|
||||
break;
|
||||
case 3: /* cmplteq */
|
||||
r = r > 0;
|
||||
break;
|
||||
}
|
||||
if (r)
|
||||
ASSH_CHK_GTO(oc == 128, ASSH_ERR_NUM_COMPARE_FAILED, err_sc);
|
||||
else
|
||||
pc += oc - 128;
|
||||
break;
|
||||
}
|
||||
|
||||
case ASSH_BIGNUM_OP_TESTS:
|
||||
case ASSH_BIGNUM_OP_TESTC: {
|
||||
struct assh_bignum_s *src1 = args[oa];
|
||||
size_t b = ob;
|
||||
if (od != ASSH_BOP_NOREG)
|
||||
{
|
||||
ASSH_ERR_GTO(assh_bignum_size_of_data(format[od], args[od],
|
||||
NULL, NULL, &b), err_sc);
|
||||
b -= ob;
|
||||
}
|
||||
if (!gcry_mpi_test_bit(src1->n, b) ^ (op == ASSH_BIGNUM_OP_TESTC))
|
||||
ASSH_CHK_GTO(oc == 128, ASSH_ERR_NUM_COMPARE_FAILED, err_sc);
|
||||
else
|
||||
pc += oc - 128;
|
||||
break;
|
||||
}
|
||||
|
||||
case ASSH_BIGNUM_OP_UINT: {
|
||||
struct assh_bignum_s *dst = args[od];
|
||||
dst->n = gcry_mpi_set_ui(dst->n, value);
|
||||
ASSH_CHK_GTO(dst->n == NULL, ASSH_ERR_MEM, err_sc);
|
||||
break;
|
||||
}
|
||||
|
||||
case ASSH_BIGNUM_OP_LADJMP: {
|
||||
if (assh_bignum_lad(args[od]))
|
||||
pc += oc - 128;
|
||||
break;
|
||||
}
|
||||
|
||||
case ASSH_BIGNUM_OP_LADSWAP: {
|
||||
struct assh_bignum_s *src1 = args[ob];
|
||||
struct assh_bignum_s *src2 = args[oc];
|
||||
|
||||
if (assh_bignum_lad(args[od]))
|
||||
gcry_mpi_swap(src1->n, src2->n);
|
||||
break;
|
||||
}
|
||||
|
||||
case ASSH_BIGNUM_OP_LADLOOP: {
|
||||
struct assh_bignum_lad_s *lad = args[od];
|
||||
uint16_t bit = --lad->count;
|
||||
if (bit)
|
||||
{
|
||||
if (lad->msbyte_1st && (bit & 7) == 0)
|
||||
lad->data++;
|
||||
pc -= oc;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ASSH_BIGNUM_OP_PRIME: {
|
||||
struct assh_bignum_s *dst = args[ob];
|
||||
struct assh_gcrypt_prime_s pchk = { NULL, NULL };
|
||||
size_t bits = dst->bits;
|
||||
if (oc != ASSH_BOP_NOREG)
|
||||
{
|
||||
struct assh_bignum_s *min = args[oc];
|
||||
pchk.min = min->n;
|
||||
assert(min->bits == dst->bits);
|
||||
}
|
||||
if (od != ASSH_BOP_NOREG)
|
||||
{
|
||||
struct assh_bignum_s *max = args[od];
|
||||
pchk.max = max->n;
|
||||
assert(max->bits == dst->bits);
|
||||
bits = gcry_mpi_get_nbits(pchk.max);
|
||||
}
|
||||
if (dst->n)
|
||||
gcry_mpi_release(dst->n);
|
||||
|
||||
/* FIXME call gcry_random_add_bytes here */
|
||||
ASSH_CHK_GTO(gcry_prime_generate((struct gcry_mpi **)&dst->n,
|
||||
bits, 0, NULL, assh_gcrypt_prime_chk,
|
||||
&pchk, GCRY_STRONG_RANDOM, 0),
|
||||
ASSH_ERR_CRYPTO, err_sc);
|
||||
break;
|
||||
}
|
||||
|
||||
case ASSH_BIGNUM_OP_ISPRIM: {
|
||||
struct assh_bignum_s *src = args[od];
|
||||
if (ob ^ (gcry_mpi_cmp_ui(src->n, 2) <= 0 ||
|
||||
gcry_prime_check(src->n, 0)))
|
||||
pc += oc - 128;
|
||||
else
|
||||
ASSH_CHK_GTO(oc == 128, ASSH_ERR_NUM_OVERFLOW, err_sc);
|
||||
break;
|
||||
}
|
||||
|
||||
case ASSH_BIGNUM_OP_PRIVACY: {
|
||||
struct assh_bignum_s *src = args[od];
|
||||
src->secret = oc;
|
||||
break;
|
||||
}
|
||||
|
||||
case ASSH_BIGNUM_OP_PRINT: {
|
||||
#ifdef CONFIG_ASSH_DEBUG
|
||||
struct assh_bignum_s *src = args[od];
|
||||
char id[5];
|
||||
id[4] = 0;
|
||||
assh_store_u32le((uint8_t*)id, oc);
|
||||
fprintf(stderr, "[pc=%u, id=%s, type=%c] ", pc, id, format[od]);
|
||||
switch (format[od])
|
||||
{
|
||||
case ASSH_BIGNUM_NATIVE:
|
||||
case ASSH_BIGNUM_STEMP:
|
||||
case ASSH_BIGNUM_TEMP:
|
||||
fprintf(stderr, "[bits=%zu] ", src->bits);
|
||||
if (src->n != NULL)
|
||||
gcry_mpi_dump(src->n);
|
||||
else
|
||||
fprintf(stderr, "NULL");
|
||||
break;
|
||||
case ASSH_BIGNUM_SIZE:
|
||||
fprintf(stderr, "%u", (unsigned)(uintptr_t)args[od]);
|
||||
break;
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
err = ASSH_OK;
|
||||
err_sc:;
|
||||
for (i = 0; i < tlen; i++)
|
||||
if (tmp[i].n != NULL)
|
||||
gcry_mpi_release(tmp[i].n);
|
||||
return err;
|
||||
}
|
||||
|
||||
static ASSH_BIGNUM_RELEASE_FCN(assh_bignum_gcrypt_release)
|
||||
{
|
||||
gcry_mpi_release(bn->n);
|
||||
bn->n = NULL;
|
||||
}
|
||||
|
||||
const struct assh_bignum_algo_s assh_bignum_gcrypt =
|
||||
{
|
||||
.name = "gcrypt",
|
||||
.f_bytecode = assh_bignum_gcrypt_bytecode,
|
||||
.f_convert = assh_bignum_gcrypt_convert,
|
||||
.f_release = assh_bignum_gcrypt_release,
|
||||
};
|
||||
|
|
@ -0,0 +1,448 @@
|
|||
/*
|
||||
|
||||
libassh - asynchronous ssh2 client/server library.
|
||||
|
||||
Copyright (C) 2013 Alexandre Becoulet <alexandre.becoulet@free.fr>
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#include <assh/assh_cipher.h>
|
||||
#include <assh/assh_packet.h>
|
||||
|
||||
struct assh_cipher_aes_context_s
|
||||
{
|
||||
union {
|
||||
uint32_t rkey[15][4];
|
||||
uint32_t key[8];
|
||||
};
|
||||
uint32_t iv[4];
|
||||
uint8_t rounds;
|
||||
assh_bool_t encrypt;
|
||||
};
|
||||
|
||||
static inline void aes_subst_bytes(void *b, uint_fast8_t s)
|
||||
{
|
||||
static const uint8_t aes_sbox[256] = {
|
||||
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
|
||||
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
|
||||
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
|
||||
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
|
||||
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
|
||||
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
|
||||
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
|
||||
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
|
||||
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
|
||||
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
|
||||
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
|
||||
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
|
||||
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
|
||||
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
|
||||
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
|
||||
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
|
||||
};
|
||||
|
||||
uint8_t *buf = b;
|
||||
|
||||
while (s--)
|
||||
buf[s] = aes_sbox[buf[s]];
|
||||
}
|
||||
|
||||
static inline void aes_unsubst_bytes(void *b)
|
||||
{
|
||||
static const uint8_t aes_sbox_inv[256] = {
|
||||
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
|
||||
0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
|
||||
0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
|
||||
0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
|
||||
0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
|
||||
0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
|
||||
0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
|
||||
0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
|
||||
0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
|
||||
0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
|
||||
0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
|
||||
0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
|
||||
0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
|
||||
0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
|
||||
0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
|
||||
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
|
||||
};
|
||||
|
||||
uint8_t *buf = b;
|
||||
uint_fast8_t s = 16;
|
||||
|
||||
while (s--)
|
||||
buf[s] = aes_sbox_inv[buf[s]];
|
||||
}
|
||||
|
||||
static inline void aes_add_round_key(uint32_t b[4], uint32_t k[4])
|
||||
{
|
||||
b[0] ^= k[0];
|
||||
b[1] ^= k[1];
|
||||
b[2] ^= k[2];
|
||||
b[3] ^= k[3];
|
||||
}
|
||||
|
||||
static inline void aes_shift_rows(uint32_t b[4])
|
||||
{
|
||||
uint32_t b1 = b[1];
|
||||
uint32_t b2 = b[2];
|
||||
uint32_t b3 = b[3];
|
||||
|
||||
b[1] = (b1 << 24) | (b1 >> 8 );
|
||||
b[2] = (b2 << 16) | (b2 >> 16);
|
||||
b[3] = (b3 << 8 ) | (b3 >> 24);
|
||||
}
|
||||
|
||||
static inline void aes_unshift_rows(uint32_t b[4])
|
||||
{
|
||||
uint32_t b1 = b[1];
|
||||
uint32_t b2 = b[2];
|
||||
uint32_t b3 = b[3];
|
||||
|
||||
b[1] = (b1 << 8 ) | (b1 >> 24);
|
||||
b[2] = (b2 << 16) | (b2 >> 16);
|
||||
b[3] = (b3 << 24) | (b3 >> 8 );
|
||||
}
|
||||
|
||||
static inline void aes_transpose(uint32_t b[4])
|
||||
{
|
||||
uint32_t b0 = b[0];
|
||||
uint32_t b1 = b[1];
|
||||
uint32_t b2 = b[2];
|
||||
uint32_t b3 = b[3];
|
||||
|
||||
uint32_t a0 = ((b0 & 0x000000ff) ) | ((b1 & 0x000000ff) << 8 )
|
||||
| ((b2 & 0x000000ff) << 16) | ((b3 & 0x000000ff) << 24);
|
||||
uint32_t a1 = ((b0 & 0x0000ff00) >> 8 ) | ((b1 & 0x0000ff00) )
|
||||
| ((b2 & 0x0000ff00) << 8 ) | ((b3 & 0x0000ff00) << 16);
|
||||
uint32_t a2 = ((b0 & 0x00ff0000) >> 16) | ((b1 & 0x00ff0000) >> 8 )
|
||||
| ((b2 & 0x00ff0000) ) | ((b3 & 0x00ff0000) << 8 );
|
||||
uint32_t a3 = ((b0 & 0xff000000) >> 24) | ((b1 & 0xff000000) >> 16)
|
||||
| ((b2 & 0xff000000) >> 8 ) | ((b3 & 0xff000000) );
|
||||
|
||||
b[0] = a0;
|
||||
b[1] = a1;
|
||||
b[2] = a2;
|
||||
b[3] = a3;
|
||||
}
|
||||
|
||||
static inline uint32_t aes_simd_x2(uint32_t x)
|
||||
{
|
||||
uint32_t z = (x & 0x80808080) >> 7;
|
||||
uint32_t y = (x & 0x7f7f7f7f) << 1;
|
||||
z |= z << 3;
|
||||
return y ^ z ^ (z << 1);
|
||||
}
|
||||
|
||||
static inline uint32_t aes_simd_x4(uint32_t x)
|
||||
{
|
||||
uint32_t z = (x & 0xc0c0c0c0) >> 6;
|
||||
uint32_t y = (x & 0x3f3f3f3f) << 2;
|
||||
z |= z << 3;
|
||||
return y ^ z ^ (z << 1);
|
||||
}
|
||||
|
||||
static inline void aes_mix_columns(uint32_t b[4])
|
||||
{
|
||||
uint32_t b0 = b[0];
|
||||
uint32_t b1 = b[1];
|
||||
uint32_t b2 = b[2];
|
||||
uint32_t b3 = b[3];
|
||||
uint32_t x = b0 ^ b1 ^ b2 ^ b3;
|
||||
b[0] ^= x ^ aes_simd_x2(b0 ^ b1);
|
||||
b[1] ^= x ^ aes_simd_x2(b1 ^ b2);
|
||||
b[2] ^= x ^ aes_simd_x2(b2 ^ b3);
|
||||
b[3] ^= x ^ aes_simd_x2(b3 ^ b0);
|
||||
}
|
||||
|
||||
static inline void aes_unmix_columns(uint32_t b[4])
|
||||
{
|
||||
uint32_t b0 = b[0];
|
||||
uint32_t b1 = b[1];
|
||||
uint32_t b2 = b[2];
|
||||
uint32_t b3 = b[3];
|
||||
uint32_t w = b0 ^ b1 ^ b2 ^ b3;
|
||||
uint32_t z = aes_simd_x2(w);
|
||||
uint32_t y = w ^ aes_simd_x4(z ^ b1 ^ b3);
|
||||
uint32_t x = w ^ aes_simd_x4(z ^ b0 ^ b2);
|
||||
b[0] ^= x ^ aes_simd_x2(b0 ^ b1);
|
||||
b[1] ^= y ^ aes_simd_x2(b1 ^ b2);
|
||||
b[2] ^= x ^ aes_simd_x2(b2 ^ b3);
|
||||
b[3] ^= y ^ aes_simd_x2(b3 ^ b0);
|
||||
}
|
||||
|
||||
static void aes_expand_key(uint32_t *b, uint_fast8_t c, uint_fast8_t r)
|
||||
{
|
||||
uint8_t rcon = 1;
|
||||
uint_fast8_t i, j;
|
||||
|
||||
for (j = c; j < 4 * r; j += c)
|
||||
{
|
||||
uint32_t b3 = b[j - 1];
|
||||
b3 = (b3 << 24) | (b3 >> 8);
|
||||
aes_subst_bytes(&b3, 4);
|
||||
b[j] = b3 ^ b[j - c] ^ rcon;
|
||||
|
||||
for (i = 1; i < c; i++)
|
||||
{
|
||||
if (i + j == 4 * r)
|
||||
return;
|
||||
uint32_t x = b[i + j - 1];
|
||||
if (c == 8 && i == 4)
|
||||
aes_subst_bytes(&x, 4);
|
||||
b[i + j] = x ^ b[i + j - c];
|
||||
}
|
||||
|
||||
rcon = (rcon << 1) | (((int8_t)(rcon & 0x80) >> 7) & 0x1b);
|
||||
}
|
||||
}
|
||||
|
||||
static void aes_encrypt(struct assh_cipher_aes_context_s *ctx, uint32_t b[4])
|
||||
{
|
||||
uint_fast8_t i;
|
||||
|
||||
aes_transpose(b);
|
||||
aes_add_round_key(b, ctx->rkey[0]);
|
||||
|
||||
for (i = 1; i < ctx->rounds - 1; i++)
|
||||
{
|
||||
aes_subst_bytes(b, 16);
|
||||
aes_shift_rows(b);
|
||||
aes_mix_columns(b);
|
||||
aes_add_round_key(b, ctx->rkey[i]);
|
||||
}
|
||||
|
||||
aes_subst_bytes(b, 16);
|
||||
aes_shift_rows(b);
|
||||
aes_add_round_key(b, ctx->rkey[i]);
|
||||
aes_transpose(b);
|
||||
}
|
||||
|
||||
static void aes_decrypt(struct assh_cipher_aes_context_s *ctx, uint32_t b[4])
|
||||
{
|
||||
uint_fast8_t i = ctx->rounds - 1;
|
||||
|
||||
aes_transpose(b);
|
||||
aes_add_round_key(b, ctx->rkey[i]);
|
||||
aes_unshift_rows(b);
|
||||
aes_unsubst_bytes(b);
|
||||
|
||||
while (--i > 0)
|
||||
{
|
||||
aes_add_round_key(b, ctx->rkey[i]);
|
||||
aes_unmix_columns(b);
|
||||
aes_unshift_rows(b);
|
||||
aes_unsubst_bytes(b);
|
||||
}
|
||||
|
||||
aes_add_round_key(b, ctx->rkey[0]);
|
||||
aes_transpose(b);
|
||||
}
|
||||
|
||||
static void assh_aes_init(struct assh_cipher_aes_context_s *ctx,
|
||||
uint_fast8_t r, uint_fast8_t l,
|
||||
const uint8_t *key, const uint8_t *iv,
|
||||
assh_bool_t encrypt)
|
||||
{
|
||||
uint_fast8_t i;
|
||||
|
||||
ctx->rounds = r;
|
||||
ctx->encrypt = encrypt;
|
||||
|
||||
for (i = 0; i < l; i++)
|
||||
ctx->key[i] = assh_load_u32le(key + i * 4);
|
||||
|
||||
aes_expand_key(ctx->rkey[0], l, r);
|
||||
for (i = 0; i < r; i++)
|
||||
aes_transpose(ctx->rkey[i]);
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
ctx->iv[i] = assh_load_u32le(iv + i * 4);
|
||||
}
|
||||
|
||||
static ASSH_CIPHER_INIT_FCN(assh_aes128_init)
|
||||
{
|
||||
assh_aes_init(ctx_, 11, 4, key, iv, encrypt);
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
static ASSH_CIPHER_INIT_FCN(assh_aes192_init)
|
||||
{
|
||||
assh_aes_init(ctx_, 13, 6, key, iv, encrypt);
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
static ASSH_CIPHER_INIT_FCN(assh_aes256_init)
|
||||
{
|
||||
assh_aes_init(ctx_, 15, 8, key, iv, encrypt);
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
static ASSH_CIPHER_PROCESS_FCN(assh_aes_cbc_process)
|
||||
{
|
||||
struct assh_cipher_aes_context_s *ctx = ctx_;
|
||||
assh_error_t err;
|
||||
uint32_t b[4];
|
||||
uint_fast8_t i;
|
||||
|
||||
if (ctx->encrypt)
|
||||
{
|
||||
uint32_t *iv = ctx->iv;
|
||||
for (; len >= 16; len -= 16)
|
||||
{
|
||||
for (i = 0; i < 4; i++)
|
||||
b[i] = iv[i] ^ assh_load_u32le(data + i * 4);
|
||||
aes_encrypt(ctx, b);
|
||||
for (i = 0; i < 4; i++)
|
||||
assh_store_u32le(data + i * 4, b[i]);
|
||||
iv = b;
|
||||
data += 16;
|
||||
}
|
||||
for (i = 0; i < 4; i++)
|
||||
ctx->iv[i] = iv[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t t[4];
|
||||
for (; len >= 16; len -= 16)
|
||||
{
|
||||
for (i = 0; i < 4; i++)
|
||||
t[i] = b[i] = assh_load_u32le(data + i * 4);
|
||||
aes_decrypt(ctx, b);
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
assh_store_u32le(data + i * 4, b[i] ^ ctx->iv[i]);
|
||||
ctx->iv[i] = t[i];
|
||||
}
|
||||
data += 16;
|
||||
}
|
||||
}
|
||||
|
||||
ASSH_CHK_RET(len != 0, ASSH_ERR_BAD_ARG);
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
static ASSH_CIPHER_PROCESS_FCN(assh_aes_ctr_process)
|
||||
{
|
||||
struct assh_cipher_aes_context_s *ctx = ctx_;
|
||||
assh_error_t err;
|
||||
uint32_t b[4];
|
||||
uint32_t *iv = ctx->iv;
|
||||
uint_fast8_t i;
|
||||
|
||||
for ( ;len >= 16; len -= 16)
|
||||
{
|
||||
for (i = 0; i < 4; i++)
|
||||
b[i] = iv[i];
|
||||
aes_encrypt(ctx, b);
|
||||
|
||||
for (i = 0; i < 128; i += 8)
|
||||
*data++ ^= b[i / 32] >> (i % 32);
|
||||
|
||||
uint64_t t = 0x100000000ULL;
|
||||
for (i = 0; i < 4; i++)
|
||||
iv[3-i] = assh_swap_u32(t = (t >> 32) + assh_swap_u32(iv[3-i]));
|
||||
}
|
||||
|
||||
ASSH_CHK_RET(len != 0, ASSH_ERR_BAD_ARG);
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
static ASSH_CIPHER_CLEANUP_FCN(assh_aes_cleanup)
|
||||
{
|
||||
}
|
||||
|
||||
const struct assh_algo_cipher_s assh_cipher_aes128_cbc =
|
||||
{
|
||||
.algo = { .name = "aes128-cbc", .class_ = ASSH_ALGO_CIPHER,
|
||||
.safety = 40, .speed = 70 },
|
||||
.ctx_size = sizeof(struct assh_cipher_aes_context_s),
|
||||
.block_size = 16,
|
||||
.key_size = 16,
|
||||
.is_stream = 0,
|
||||
.f_init = assh_aes128_init,
|
||||
.f_process = assh_aes_cbc_process,
|
||||
.f_cleanup = assh_aes_cleanup,
|
||||
};
|
||||
|
||||
const struct assh_algo_cipher_s assh_cipher_aes192_cbc =
|
||||
{
|
||||
.algo = { .name = "aes192-cbc", .class_ = ASSH_ALGO_CIPHER,
|
||||
.safety = 50, .speed = 65 },
|
||||
.ctx_size = sizeof(struct assh_cipher_aes_context_s),
|
||||
.block_size = 16,
|
||||
.key_size = 24,
|
||||
.is_stream = 0,
|
||||
.f_init = assh_aes192_init,
|
||||
.f_process = assh_aes_cbc_process,
|
||||
.f_cleanup = assh_aes_cleanup,
|
||||
};
|
||||
|
||||
const struct assh_algo_cipher_s assh_cipher_aes256_cbc =
|
||||
{
|
||||
.algo = { .name = "aes256-cbc", .class_ = ASSH_ALGO_CIPHER,
|
||||
.safety = 60, .speed = 60 },
|
||||
.ctx_size = sizeof(struct assh_cipher_aes_context_s),
|
||||
.block_size = 16,
|
||||
.key_size = 32,
|
||||
.is_stream = 0,
|
||||
.f_init = assh_aes256_init,
|
||||
.f_process = assh_aes_cbc_process,
|
||||
.f_cleanup = assh_aes_cleanup,
|
||||
};
|
||||
|
||||
const struct assh_algo_cipher_s assh_cipher_aes128_ctr =
|
||||
{
|
||||
.algo = { .name = "aes128-ctr", .class_ = ASSH_ALGO_CIPHER,
|
||||
.safety = 41, .speed = 70 },
|
||||
.ctx_size = sizeof(struct assh_cipher_aes_context_s),
|
||||
.block_size = 16,
|
||||
.key_size = 16,
|
||||
.is_stream = 0,
|
||||
.f_init = assh_aes128_init,
|
||||
.f_process = assh_aes_ctr_process,
|
||||
.f_cleanup = assh_aes_cleanup,
|
||||
};
|
||||
|
||||
const struct assh_algo_cipher_s assh_cipher_aes192_ctr =
|
||||
{
|
||||
.algo = { .name = "aes192-ctr", .class_ = ASSH_ALGO_CIPHER,
|
||||
.safety = 51, .speed = 65 },
|
||||
.ctx_size = sizeof(struct assh_cipher_aes_context_s),
|
||||
.block_size = 16,
|
||||
.key_size = 24,
|
||||
.is_stream = 0,
|
||||
.f_init = assh_aes192_init,
|
||||
.f_process = assh_aes_ctr_process,
|
||||
.f_cleanup = assh_aes_cleanup,
|
||||
};
|
||||
|
||||
const struct assh_algo_cipher_s assh_cipher_aes256_ctr =
|
||||
{
|
||||
.algo = { .name = "aes256-ctr", .class_ = ASSH_ALGO_CIPHER,
|
||||
.safety = 61, .speed = 60 },
|
||||
.ctx_size = sizeof(struct assh_cipher_aes_context_s),
|
||||
.block_size = 16,
|
||||
.key_size = 32,
|
||||
.is_stream = 0,
|
||||
.f_init = assh_aes256_init,
|
||||
.f_process = assh_aes_ctr_process,
|
||||
.f_cleanup = assh_aes_cleanup,
|
||||
};
|
||||
|
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
|
||||
libassh - asynchronous ssh2 client/server library.
|
||||
|
||||
Copyright (C) 2013 Alexandre Becoulet <alexandre.becoulet@free.fr>
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#include <assh/assh_cipher.h>
|
||||
|
||||
struct assh_cipher_arc4_context_s
|
||||
{
|
||||
uint8_t a, b;
|
||||
uint8_t s[256];
|
||||
};
|
||||
|
||||
static void assh_arc4_set_key(struct assh_cipher_arc4_context_s *ctx,
|
||||
const uint8_t *key, size_t klen)
|
||||
{
|
||||
ctx->a = ctx->b = 0;
|
||||
unsigned int i;
|
||||
for (i = 0; i < 256; i++)
|
||||
ctx->s[i] = i;
|
||||
|
||||
unsigned int a, b;
|
||||
for (a = b = 0; a < 256; a++)
|
||||
{
|
||||
uint8_t tmp = ctx->s[a];
|
||||
b = (uint8_t)(b + tmp + key[a % klen]);
|
||||
ctx->s[a] = ctx->s[b];
|
||||
ctx->s[b] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
static void assh_arc4_run(struct assh_cipher_arc4_context_s *ctx,
|
||||
uint8_t *data, size_t len)
|
||||
{
|
||||
unsigned int a = ctx->a, b = ctx->b;
|
||||
|
||||
while (len--)
|
||||
{
|
||||
a = (uint8_t)(a + 1);
|
||||
b = (uint8_t)(b + ctx->s[a]);
|
||||
uint8_t tmp = ctx->s[b];
|
||||
ctx->s[b] = ctx->s[a];
|
||||
ctx->s[a] = tmp;
|
||||
if (data != NULL)
|
||||
*data++ ^= ctx->s[(uint8_t)(ctx->s[a] + ctx->s[b])];
|
||||
}
|
||||
|
||||
ctx->a = a;
|
||||
ctx->b = b;
|
||||
}
|
||||
|
||||
static ASSH_CIPHER_INIT_FCN(assh_arc4_init)
|
||||
{
|
||||
struct assh_cipher_arc4_context_s *ctx = ctx_;
|
||||
assh_arc4_set_key(ctx, key, 16);
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
static ASSH_CIPHER_INIT_FCN(assh_arc4_128_init)
|
||||
{
|
||||
struct assh_cipher_arc4_context_s *ctx = ctx_;
|
||||
assh_arc4_set_key(ctx, key, 16);
|
||||
assh_arc4_run(ctx, NULL, 1536);
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
static ASSH_CIPHER_INIT_FCN(assh_arc4_256_init)
|
||||
{
|
||||
struct assh_cipher_arc4_context_s *ctx = ctx_;
|
||||
assh_arc4_set_key(ctx, key, 32);
|
||||
assh_arc4_run(ctx, NULL, 1536);
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
static ASSH_CIPHER_PROCESS_FCN(assh_arc4_process)
|
||||
{
|
||||
struct assh_cipher_arc4_context_s *ctx = ctx_;
|
||||
assh_arc4_run(ctx, data, len);
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
static ASSH_CIPHER_CLEANUP_FCN(assh_arc4_cleanup)
|
||||
{
|
||||
}
|
||||
|
||||
const struct assh_algo_cipher_s assh_cipher_arc4 =
|
||||
{
|
||||
.algo = { .name = "arcfour", .class_ = ASSH_ALGO_CIPHER, .safety = 5, .speed = 80 },
|
||||
.ctx_size = sizeof(struct assh_cipher_arc4_context_s),
|
||||
.block_size = 8,
|
||||
.key_size = 16,
|
||||
.is_stream = 1,
|
||||
.f_init = assh_arc4_init,
|
||||
.f_process = assh_arc4_process,
|
||||
.f_cleanup = assh_arc4_cleanup,
|
||||
};
|
||||
|
||||
const struct assh_algo_cipher_s assh_cipher_arc4_128 =
|
||||
{
|
||||
.algo = { .name = "arcfour128", .class_ = ASSH_ALGO_CIPHER, .safety = 10, .speed = 80 },
|
||||
.ctx_size = sizeof(struct assh_cipher_arc4_context_s),
|
||||
.block_size = 8,
|
||||
.key_size = 16,
|
||||
.is_stream = 1,
|
||||
.f_init = assh_arc4_128_init,
|
||||
.f_process = assh_arc4_process,
|
||||
.f_cleanup = assh_arc4_cleanup,
|
||||
};
|
||||
|
||||
const struct assh_algo_cipher_s assh_cipher_arc4_256 =
|
||||
{
|
||||
.algo = { .name = "arcfour256", .class_ = ASSH_ALGO_CIPHER, .safety = 15, .speed = 80 },
|
||||
.ctx_size = sizeof(struct assh_cipher_arc4_context_s),
|
||||
.block_size = 8,
|
||||
.key_size = 32,
|
||||
.is_stream = 1,
|
||||
.f_init = assh_arc4_256_init,
|
||||
.f_process = assh_arc4_process,
|
||||
.f_cleanup = assh_arc4_cleanup,
|
||||
};
|
||||
|
|
@ -0,0 +1,163 @@
|
|||
/*
|
||||
|
||||
libassh - asynchronous ssh2 client/server library.
|
||||
|
||||
Copyright (C) 2013 Alexandre Becoulet <alexandre.becoulet@free.fr>
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#include <assh/assh_cipher.h>
|
||||
|
||||
#include <gcrypt.h>
|
||||
|
||||
struct assh_cipher_gcrypt_context_s
|
||||
{
|
||||
gcry_cipher_hd_t hd;
|
||||
assh_bool_t encrypt;
|
||||
};
|
||||
|
||||
static assh_error_t
|
||||
assh_cipher_gcrypt_init(const struct assh_algo_cipher_s *cipher,
|
||||
struct assh_cipher_gcrypt_context_s *ctx,
|
||||
const uint8_t *key, const uint8_t *iv,
|
||||
int algo, int mode, assh_bool_t encrypt)
|
||||
{
|
||||
assh_error_t err;
|
||||
|
||||
ASSH_CHK_RET(gcry_cipher_open(&ctx->hd, algo, mode, 0),
|
||||
ASSH_ERR_CRYPTO);
|
||||
|
||||
ASSH_CHK_GTO(gcry_cipher_setkey(ctx->hd, key, cipher->key_size),
|
||||
ASSH_ERR_CRYPTO, err_open);
|
||||
|
||||
ctx->encrypt = encrypt;
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case GCRY_CIPHER_MODE_CBC:
|
||||
ASSH_CHK_GTO(gcry_cipher_setiv(ctx->hd, iv, cipher->block_size),
|
||||
ASSH_ERR_CRYPTO, err_open);
|
||||
break;
|
||||
|
||||
case GCRY_CIPHER_MODE_CTR:
|
||||
ASSH_CHK_GTO(gcry_cipher_setctr(ctx->hd, iv, cipher->block_size),
|
||||
ASSH_ERR_CRYPTO, err_open);
|
||||
break;
|
||||
|
||||
case GCRY_CIPHER_MODE_STREAM:
|
||||
assert(cipher->is_stream);
|
||||
|
||||
if (cipher == &assh_cipher_arc4_128 ||
|
||||
cipher == &assh_cipher_arc4_256)
|
||||
{
|
||||
uint8_t dummy[128];
|
||||
unsigned int i;
|
||||
|
||||
memset(dummy, 0, sizeof(dummy));
|
||||
for (i = 0; i < 1536; i += sizeof(dummy))
|
||||
if (encrypt)
|
||||
ASSH_CHK_GTO(gcry_cipher_encrypt(ctx->hd, dummy, sizeof(dummy), NULL, 0),
|
||||
ASSH_ERR_CRYPTO, err_open);
|
||||
else
|
||||
ASSH_CHK_GTO(gcry_cipher_decrypt(ctx->hd, dummy, sizeof(dummy), NULL, 0),
|
||||
ASSH_ERR_CRYPTO, err_open);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return ASSH_OK;
|
||||
|
||||
err_open:
|
||||
gcry_cipher_close(ctx->hd);
|
||||
return err;
|
||||
}
|
||||
|
||||
static ASSH_CIPHER_PROCESS_FCN(assh_cipher_gcrypt_process)
|
||||
{
|
||||
assh_error_t err;
|
||||
struct assh_cipher_gcrypt_context_s *ctx = ctx_;
|
||||
|
||||
if (ctx->encrypt)
|
||||
ASSH_CHK_RET(gcry_cipher_encrypt(ctx->hd, data, len, NULL, 0),
|
||||
ASSH_ERR_CRYPTO);
|
||||
else
|
||||
ASSH_CHK_RET(gcry_cipher_decrypt(ctx->hd, data, len, NULL, 0),
|
||||
ASSH_ERR_CRYPTO);
|
||||
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
static ASSH_CIPHER_CLEANUP_FCN(assh_cipher_gcrypt_cleanup)
|
||||
{
|
||||
struct assh_cipher_gcrypt_context_s *ctx = ctx_;
|
||||
gcry_cipher_close(ctx->hd);
|
||||
}
|
||||
|
||||
#define ASSH_GCRYPT_CIPHER(id_, name_, algo_, mode_, bsize_, ksize_, saf_, spd_, is_stream_) \
|
||||
extern const struct assh_algo_cipher_s assh_cipher_##id_; \
|
||||
\
|
||||
static ASSH_CIPHER_INIT_FCN(assh_cipher_gcrypt_##id_##_init) \
|
||||
{ \
|
||||
return assh_cipher_gcrypt_init(&assh_cipher_##id_, ctx_, key, iv, \
|
||||
algo_, mode_, encrypt); \
|
||||
} \
|
||||
\
|
||||
const struct assh_algo_cipher_s assh_cipher_##id_ = \
|
||||
{ \
|
||||
.algo = { .name = name_, .class_ = ASSH_ALGO_CIPHER, .safety = saf_, .speed = spd_ }, \
|
||||
.ctx_size = sizeof(struct assh_cipher_gcrypt_context_s), \
|
||||
.block_size = bsize_, \
|
||||
.key_size = ksize_, \
|
||||
.is_stream = is_stream_, \
|
||||
.f_init = assh_cipher_gcrypt_##id_##_init, \
|
||||
.f_process = assh_cipher_gcrypt_process, \
|
||||
.f_cleanup = assh_cipher_gcrypt_cleanup, \
|
||||
};
|
||||
|
||||
ASSH_GCRYPT_CIPHER(arc4, "arcfour", GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM, 1, 16, 5, 80, 1);
|
||||
ASSH_GCRYPT_CIPHER(arc4_128, "arcfour128", GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM, 1, 16, 10, 80, 1);
|
||||
ASSH_GCRYPT_CIPHER(arc4_256, "arcfour256", GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM, 1, 32, 15, 80, 1);
|
||||
|
||||
ASSH_GCRYPT_CIPHER(tdes_cbc, "3des-cbc", GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_CBC, 8, 24, 20, 30, 0);
|
||||
ASSH_GCRYPT_CIPHER(tdes_ctr, "3des-ctr", GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_CTR, 8, 24, 21, 30, 0);
|
||||
|
||||
ASSH_GCRYPT_CIPHER(cast128_cbc, "cast128-cbc", GCRY_CIPHER_CAST5, GCRY_CIPHER_MODE_CBC, 16, 16, 25, 50, 0);
|
||||
ASSH_GCRYPT_CIPHER(cast128_ctr, "cast128-ctr", GCRY_CIPHER_CAST5, GCRY_CIPHER_MODE_CTR, 16, 16, 26, 50, 0);
|
||||
|
||||
ASSH_GCRYPT_CIPHER(blowfish_cbc, "blowfish-cbc", GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_CBC, 8, 16, 30, 60, 0);
|
||||
ASSH_GCRYPT_CIPHER(blowfish_ctr, "blowfish-ctr", GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_CTR, 8, 32, 35, 60, 0);
|
||||
|
||||
ASSH_GCRYPT_CIPHER(aes128_cbc, "aes128-cbc", GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CBC, 16, 16, 40, 70, 0);
|
||||
ASSH_GCRYPT_CIPHER(aes192_cbc, "aes192-cbc", GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_CBC, 16, 24, 50, 65, 0);
|
||||
ASSH_GCRYPT_CIPHER(aes256_cbc, "aes256-cbc", GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 16, 32, 60, 60, 0);
|
||||
ASSH_GCRYPT_CIPHER(aes128_ctr, "aes128-ctr", GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CTR, 16, 16, 41, 70, 0);
|
||||
ASSH_GCRYPT_CIPHER(aes192_ctr, "aes192-ctr", GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_CTR, 16, 24, 51, 65, 0);
|
||||
ASSH_GCRYPT_CIPHER(aes256_ctr, "aes256-ctr", GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CTR, 16, 32, 61, 60, 0);
|
||||
|
||||
ASSH_GCRYPT_CIPHER(twofish128_cbc, "twofish128-cbc", GCRY_CIPHER_TWOFISH128, GCRY_CIPHER_MODE_CBC, 16, 16, 50, 60, 0);
|
||||
ASSH_GCRYPT_CIPHER(twofish256_cbc, "twofish256-cbc", GCRY_CIPHER_TWOFISH , GCRY_CIPHER_MODE_CBC, 16, 32, 70, 60, 0);
|
||||
ASSH_GCRYPT_CIPHER(twofish128_ctr, "twofish128-ctr", GCRY_CIPHER_TWOFISH128, GCRY_CIPHER_MODE_CTR, 16, 16, 51, 60, 0);
|
||||
ASSH_GCRYPT_CIPHER(twofish256_ctr, "twofish256-ctr", GCRY_CIPHER_TWOFISH, GCRY_CIPHER_MODE_CTR, 16, 32, 71, 60, 0);
|
||||
|
||||
ASSH_GCRYPT_CIPHER(serpent128_cbc, "serpent128-cbc", GCRY_CIPHER_SERPENT128, GCRY_CIPHER_MODE_CBC, 16, 16, 55, 40, 0);
|
||||
ASSH_GCRYPT_CIPHER(serpent192_cbc, "serpent192-cbc", GCRY_CIPHER_SERPENT192, GCRY_CIPHER_MODE_CBC, 16, 24, 65, 40, 0);
|
||||
ASSH_GCRYPT_CIPHER(serpent256_cbc, "serpent256-cbc", GCRY_CIPHER_SERPENT256, GCRY_CIPHER_MODE_CBC, 16, 32, 75, 40, 0);
|
||||
ASSH_GCRYPT_CIPHER(serpent128_ctr, "serpent128-ctr", GCRY_CIPHER_SERPENT128, GCRY_CIPHER_MODE_CTR, 16, 16, 56, 40, 0);
|
||||
ASSH_GCRYPT_CIPHER(serpent192_ctr, "serpent192-ctr", GCRY_CIPHER_SERPENT192, GCRY_CIPHER_MODE_CTR, 16, 24, 66, 40, 0);
|
||||
ASSH_GCRYPT_CIPHER(serpent256_ctr, "serpent256-ctr", GCRY_CIPHER_SERPENT256, GCRY_CIPHER_MODE_CTR, 16, 32, 76, 40, 0);
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
|
||||
libassh - asynchronous ssh2 client/server library.
|
||||
|
||||
Copyright (C) 2013 Alexandre Becoulet <alexandre.becoulet@free.fr>
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#include <assh/assh_cipher.h>
|
||||
|
||||
static ASSH_CIPHER_INIT_FCN(assh_none_init)
|
||||
{
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
static ASSH_CIPHER_PROCESS_FCN(assh_none_process)
|
||||
{
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
static ASSH_CIPHER_CLEANUP_FCN(assh_none_cleanup)
|
||||
{
|
||||
}
|
||||
|
||||
const struct assh_algo_cipher_s assh_cipher_none =
|
||||
{
|
||||
.algo = { .name = "none", .class_ = ASSH_ALGO_CIPHER, .safety = 0, .speed = 99 },
|
||||
.ctx_size = 0,
|
||||
.block_size = 8,
|
||||
.key_size = 8,
|
||||
.is_stream = 0,
|
||||
.f_init = assh_none_init,
|
||||
.f_process = assh_none_process,
|
||||
.f_cleanup = assh_none_cleanup,
|
||||
};
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
|
||||
libassh - asynchronous ssh2 client/server library.
|
||||
|
||||
Copyright (C) 2013 Alexandre Becoulet <alexandre.becoulet@free.fr>
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include <assh/assh_compress.h>
|
||||
|
||||
static ASSH_COMPRESS_INIT_FCN(assh_compress_none_init)
|
||||
{
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
static ASSH_COMPRESS_PROCESS_FCN(assh_compress_none_process)
|
||||
{
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
static ASSH_COMPRESS_CLEANUP_FCN(assh_compress_none_cleanup)
|
||||
{
|
||||
}
|
||||
|
||||
const struct assh_algo_compress_s assh_compress_none =
|
||||
{
|
||||
.algo = { .name = "none", .class_ = ASSH_ALGO_COMPRESS, .safety = 99, .speed = 99 },
|
||||
.ctx_size = 0,
|
||||
.f_init = assh_compress_none_init,
|
||||
.f_process = assh_compress_none_process,
|
||||
.f_cleanup = assh_compress_none_cleanup,
|
||||
};
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
|
||||
libassh - asynchronous ssh2 client/server library.
|
||||
|
||||
Copyright (C) 2013 Alexandre Becoulet <alexandre.becoulet@free.fr>
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#include <assh/assh_hash.h>
|
||||
|
||||
#include <gcrypt.h>
|
||||
|
||||
struct assh_hash_gcrypt_context_s
|
||||
{
|
||||
struct assh_hash_ctx_s ctx;
|
||||
gcry_md_hd_t hd;
|
||||
};
|
||||
|
||||
ASSH_FIRST_FIELD_ASSERT(assh_hash_gcrypt_context_s, ctx);
|
||||
|
||||
static ASSH_HASH_COPY_FCN(assh_gcrypt_hash_copy)
|
||||
{
|
||||
const struct assh_hash_gcrypt_context_s *src = (const void*)hctx_src;
|
||||
struct assh_hash_gcrypt_context_s *dst = (void*)hctx_dst;
|
||||
assh_error_t err;
|
||||
|
||||
dst->ctx = src->ctx;
|
||||
ASSH_CHK_RET(gcry_md_copy(&dst->hd, src->hd),
|
||||
ASSH_ERR_CRYPTO);
|
||||
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
static ASSH_HASH_UPDATE_FCN(assh_gcrypt_hash_update)
|
||||
{
|
||||
struct assh_hash_gcrypt_context_s *gctx = (void*)hctx;
|
||||
|
||||
gcry_md_write(gctx->hd, data, len);
|
||||
}
|
||||
|
||||
#define ASSH_GCRYPT_HASH(id_, algo_, hsize_, bsize_) \
|
||||
\
|
||||
static ASSH_HASH_INIT_FCN(assh_gcrypt_hash_##id_##_init) \
|
||||
{ \
|
||||
struct assh_hash_gcrypt_context_s *gctx = (void*)hctx; \
|
||||
assh_error_t err; \
|
||||
\
|
||||
ASSH_CHK_RET(gcry_md_open(&gctx->hd, algo_, GCRY_MD_FLAG_SECURE), \
|
||||
ASSH_ERR_CRYPTO); \
|
||||
\
|
||||
return ASSH_OK; \
|
||||
} \
|
||||
\
|
||||
static ASSH_HASH_FINAL_FCN(assh_gcrypt_hash_##id_##_final) \
|
||||
{ \
|
||||
struct assh_hash_gcrypt_context_s *gctx = (void*)hctx; \
|
||||
\
|
||||
assert(len == hsize_); \
|
||||
\
|
||||
if (hash != NULL) \
|
||||
memcpy(hash, gcry_md_read(gctx->hd, 0), hsize_); \
|
||||
\
|
||||
gcry_md_close(gctx->hd); \
|
||||
} \
|
||||
\
|
||||
const struct assh_hash_algo_s assh_hash_##id_ = \
|
||||
{ \
|
||||
.name = #id_, \
|
||||
.ctx_size = sizeof(struct assh_hash_gcrypt_context_s), \
|
||||
.hash_size = hsize_, \
|
||||
.block_size = bsize_, \
|
||||
.f_init = assh_gcrypt_hash_##id_##_init, \
|
||||
.f_copy = assh_gcrypt_hash_copy, \
|
||||
.f_update = assh_gcrypt_hash_update, \
|
||||
.f_final = assh_gcrypt_hash_##id_##_final, \
|
||||
};
|
||||
|
||||
ASSH_GCRYPT_HASH(md5, GCRY_MD_MD5, 16, 64);
|
||||
ASSH_GCRYPT_HASH(sha1, GCRY_MD_SHA1, 20, 64);
|
||||
ASSH_GCRYPT_HASH(sha224, GCRY_MD_SHA224, 28, 64);
|
||||
ASSH_GCRYPT_HASH(sha256, GCRY_MD_SHA256, 32, 64);
|
||||
ASSH_GCRYPT_HASH(sha384, GCRY_MD_SHA384, 48, 128);
|
||||
ASSH_GCRYPT_HASH(sha512, GCRY_MD_SHA512, 64, 128);
|
||||
|
|
@ -0,0 +1,217 @@
|
|||
/*
|
||||
|
||||
libassh - asynchronous ssh2 client/server library.
|
||||
|
||||
Copyright (C) 2013 Alexandre Becoulet <alexandre.becoulet@free.fr>
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#include <assh/assh_hash.h>
|
||||
#include <assh/assh_packet.h>
|
||||
|
||||
/* based on public domain code from Colin Plumb, 1993 */
|
||||
|
||||
#include <string.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#define MD5_BLOCK_LENGTH 64
|
||||
|
||||
struct assh_hash_md5_context_s
|
||||
{
|
||||
struct assh_hash_ctx_s ctx;
|
||||
uint32_t state[4];
|
||||
uint64_t count;
|
||||
uint8_t buffer[MD5_BLOCK_LENGTH];
|
||||
};
|
||||
|
||||
ASSH_FIRST_FIELD_ASSERT(assh_hash_md5_context_s, ctx);
|
||||
|
||||
static ASSH_HASH_INIT_FCN(assh_md5_init)
|
||||
{
|
||||
struct assh_hash_md5_context_s *ctx = (void*)hctx;
|
||||
|
||||
ctx->count = 0;
|
||||
ctx->state[0] = 0x67452301;
|
||||
ctx->state[1] = 0xefcdab89;
|
||||
ctx->state[2] = 0x98badcfe;
|
||||
ctx->state[3] = 0x10325476;
|
||||
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
static ASSH_HASH_COPY_FCN(assh_md5_copy)
|
||||
{
|
||||
memcpy(hctx_dst, hctx_src, sizeof(struct assh_hash_md5_context_s));
|
||||
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
#define MD5F1(x, y, z) (z ^ (x & (y ^ z)))
|
||||
#define MD5F2(x, y, z) MD5F1(z, x, y)
|
||||
#define MD5F3(x, y, z) (x ^ y ^ z)
|
||||
#define MD5F4(x, y, z) (y ^ (x | ~z))
|
||||
|
||||
#define MD5STEP(f, w, x, y, z, data, s) \
|
||||
do { \
|
||||
w += MD5##f(x, y, z) + data; \
|
||||
w = w<<s | w>>(32-s); \
|
||||
w += x; \
|
||||
} while (0)
|
||||
|
||||
static void
|
||||
assh_md5_transform(uint32_t state[4], const uint8_t block[MD5_BLOCK_LENGTH])
|
||||
{
|
||||
uint32_t a = state[0];
|
||||
uint32_t b = state[1];
|
||||
uint32_t c = state[2];
|
||||
uint32_t d = state[3];
|
||||
uint32_t x;
|
||||
uint_fast8_t i;
|
||||
|
||||
static const uint32_t key[64] = {
|
||||
0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
|
||||
0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
|
||||
0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
|
||||
0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
|
||||
0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
|
||||
0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
|
||||
0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
|
||||
0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391,
|
||||
};
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
MD5STEP(F1, a, b, c, d, assh_load_u32le(block + i * 4) + key[i],
|
||||
((0x16110c07 >> ((i & 3) * 8)) & 0xff));
|
||||
(x = a), (a = d), (d = c), (c = b), (b = x);
|
||||
}
|
||||
|
||||
for (; i < 32; i++)
|
||||
{
|
||||
MD5STEP(F2, a, b, c, d, assh_load_u32le(block + (20 * i + 4) % 64) + key[i],
|
||||
((0x140e0905 >> ((i & 3) * 8)) & 0xff));
|
||||
(x = a), (a = d), (d = c), (c = b), (b = x);
|
||||
}
|
||||
|
||||
for (; i < 48; i++)
|
||||
{
|
||||
MD5STEP(F3, a, b, c, d, assh_load_u32le(block + (12 * i + 20) % 64) + key[i],
|
||||
((0x17100b04 >> ((i & 3) * 8)) & 0xff));
|
||||
(x = a), (a = d), (d = c), (c = b), (b = x);
|
||||
}
|
||||
|
||||
for (; i < 64; i++)
|
||||
{
|
||||
MD5STEP(F4, a, b, c, d, assh_load_u32le(block + (28 * i) % 64) + key[i],
|
||||
((0x150f0a06 >> ((i & 3) * 8)) & 0xff));
|
||||
(x = a), (a = d), (d = c), (c = b), (b = x);
|
||||
}
|
||||
|
||||
state[0] += a;
|
||||
state[1] += b;
|
||||
state[2] += c;
|
||||
state[3] += d;
|
||||
}
|
||||
|
||||
|
||||
static ASSH_HASH_UPDATE_FCN(assh_md5_update)
|
||||
{
|
||||
struct assh_hash_md5_context_s *ctx = (void*)hctx;
|
||||
size_t have, need;
|
||||
|
||||
have = (ctx->count / 8) % MD5_BLOCK_LENGTH;
|
||||
need = MD5_BLOCK_LENGTH - have;
|
||||
|
||||
ctx->count += len * 8;
|
||||
|
||||
if (len >= need)
|
||||
{
|
||||
/* Append to data from a previous call and transform 1 block. */
|
||||
if (have != 0)
|
||||
{
|
||||
memcpy(ctx->buffer + have, data, need);
|
||||
assh_md5_transform(ctx->state, ctx->buffer);
|
||||
data += need;
|
||||
len -= need;
|
||||
have = 0;
|
||||
}
|
||||
|
||||
/* Process data in MD5_BLOCK_LENGTH chunks. */
|
||||
while (len >= MD5_BLOCK_LENGTH)
|
||||
{
|
||||
assh_md5_transform(ctx->state, data);
|
||||
data += MD5_BLOCK_LENGTH;
|
||||
len -= MD5_BLOCK_LENGTH;
|
||||
}
|
||||
}
|
||||
|
||||
/* Keep any remaining bytes of data for next call. */
|
||||
if (len != 0)
|
||||
memcpy(ctx->buffer + have, data, len);
|
||||
}
|
||||
|
||||
static const uint8_t assh_md5_padding[16 + 1] = { 0x80 };
|
||||
|
||||
static ASSH_HASH_FINAL_FCN(assh_md5_final)
|
||||
{
|
||||
struct assh_hash_md5_context_s *ctx = (void*)hctx;
|
||||
|
||||
assert(len == 16);
|
||||
|
||||
uint8_t count[8];
|
||||
size_t padlen;
|
||||
int i;
|
||||
|
||||
assh_store_u64le(count, ctx->count);
|
||||
|
||||
/* Pad out to 56 mod 64. */
|
||||
padlen = MD5_BLOCK_LENGTH - (ctx->count / 8) % MD5_BLOCK_LENGTH;
|
||||
if (padlen < 1 + 8)
|
||||
padlen += MD5_BLOCK_LENGTH;
|
||||
/* padlen - 8 <= 64 */
|
||||
padlen -= 8;
|
||||
|
||||
const uint8_t *pad = assh_md5_padding;
|
||||
while (padlen > 16)
|
||||
{
|
||||
assh_md5_update(hctx, pad, 16);
|
||||
pad = assh_md5_padding + 1;
|
||||
padlen -= 16;
|
||||
}
|
||||
assh_md5_update(hctx, pad, padlen);
|
||||
|
||||
|
||||
assh_md5_update(hctx, count, 8);
|
||||
|
||||
if (hash != NULL)
|
||||
for (i = 0; i < 4; i++)
|
||||
assh_store_u32le(hash + i * 4, ctx->state[i]);
|
||||
}
|
||||
|
||||
const struct assh_hash_algo_s assh_hash_md5 =
|
||||
{
|
||||
.name = "md5",
|
||||
.ctx_size = sizeof(struct assh_hash_md5_context_s),
|
||||
.hash_size = 16,
|
||||
.block_size = 64,
|
||||
.f_init = assh_md5_init,
|
||||
.f_copy = assh_md5_copy,
|
||||
.f_update = assh_md5_update,
|
||||
.f_final = assh_md5_final,
|
||||
};
|
||||
|
|
@ -0,0 +1,209 @@
|
|||
/*
|
||||
|
||||
libassh - asynchronous ssh2 client/server library.
|
||||
|
||||
Copyright (C) 2013 Alexandre Becoulet <alexandre.becoulet@free.fr>
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include <assh/assh_hash.h>
|
||||
#include <assh/assh_packet.h>
|
||||
|
||||
/*
|
||||
based on public domain SHA-1 in C
|
||||
by Steve Reid <steve@edmweb.com>
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
struct assh_hash_sha1_context_s
|
||||
{
|
||||
struct assh_hash_ctx_s ctx;
|
||||
uint32_t state[5];
|
||||
uint64_t count;
|
||||
uint8_t buffer[64];
|
||||
};
|
||||
|
||||
ASSH_FIRST_FIELD_ASSERT(assh_hash_sha1_context_s, ctx);
|
||||
|
||||
static inline uint32_t rol(uint32_t value, unsigned int bits)
|
||||
{
|
||||
return (((value) << (bits)) | ((value) >> (32 - (bits))));
|
||||
}
|
||||
|
||||
/* BLK0() and BLK() perform the initial expand. */
|
||||
/* I got the idea of expanding during the round function from SSLeay */
|
||||
|
||||
#define BLK0(i) (block[i])
|
||||
#define BLK(i) (block[i&15] = rol(block[(i + 13)&15] ^ block[(i + 8)&15] \
|
||||
^ block[(i + 2)&15] ^ block[i&15], 1))
|
||||
|
||||
/* (R0 + R1), R2, R3, R4 are the different operations used in SHA1 */
|
||||
#define R0(v, w, x, y, z, i) do { z += ((w&(x ^ y)) ^ y) + BLK0(i) + 0x5A827999 + rol(v, 5);w = rol(w, 30); } while (0)
|
||||
#define R1(v, w, x, y, z, i) do { z += ((w&(x ^ y)) ^ y) + BLK(i) + 0x5A827999 + rol(v, 5);w = rol(w, 30); } while (0)
|
||||
#define R2(v, w, x, y, z, i) do { z += (w ^ x ^ y) + BLK(i) + 0x6ED9EBA1 + rol(v, 5);w = rol(w, 30); } while (0)
|
||||
#define R3(v, w, x, y, z, i) do { z += (((w|x)&y)|(w&x)) + BLK(i) + 0x8F1BBCDC + rol(v, 5);w = rol(w, 30); } while (0)
|
||||
#define R4(v, w, x, y, z, i) do { z += (w ^ x ^ y) + BLK(i) + 0xCA62C1D6 + rol(v, 5);w = rol(w, 30); } while (0)
|
||||
|
||||
|
||||
/* Hash a single 512-bit block. This is the core of the algorithm. */
|
||||
static void assh_sha1_transform(uint32_t state[5], const uint8_t buffer[64])
|
||||
{
|
||||
uint32_t a, b, c, d, e, x;
|
||||
uint32_t block[16];
|
||||
uint_fast8_t i;
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
block[i] = assh_load_u32(buffer + i * 4);
|
||||
|
||||
a = state[0];
|
||||
b = state[1];
|
||||
c = state[2];
|
||||
d = state[3];
|
||||
e = state[4];
|
||||
|
||||
/* 4 rounds of 20 operations each. */
|
||||
|
||||
for (i = 0; i <= 15; i++)
|
||||
{
|
||||
R0(a, b, c, d, e, i);
|
||||
(x = a), (a = e), (e = d), (d = c), (c = b), (b = x);
|
||||
}
|
||||
for (; i <= 19; i++)
|
||||
{
|
||||
R1(a, b, c, d, e, i);
|
||||
(x = a), (a = e), (e = d), (d = c), (c = b), (b = x);
|
||||
}
|
||||
for (; i <= 39; i++)
|
||||
{
|
||||
R2(a, b, c, d, e, i);
|
||||
(x = a), (a = e), (e = d), (d = c), (c = b), (b = x);
|
||||
}
|
||||
for (; i <= 59; i++)
|
||||
{
|
||||
R3(a, b, c, d, e, i);
|
||||
(x = a), (a = e), (e = d), (d = c), (c = b), (b = x);
|
||||
}
|
||||
for (; i <= 79; i++)
|
||||
{
|
||||
R4(a, b, c, d, e, i);
|
||||
(x = a), (a = e), (e = d), (d = c), (c = b), (b = x);
|
||||
}
|
||||
|
||||
/* Add the working vars back into context.state[] */
|
||||
state[0] += a;
|
||||
state[1] += b;
|
||||
state[2] += c;
|
||||
state[3] += d;
|
||||
state[4] += e;
|
||||
}
|
||||
|
||||
|
||||
static ASSH_HASH_INIT_FCN(assh_sha1_init)
|
||||
{
|
||||
struct assh_hash_sha1_context_s *ctx = (void*)hctx;
|
||||
|
||||
/* SHA1 initialization constants */
|
||||
ctx->state[0] = 0x67452301;
|
||||
ctx->state[1] = 0xefcdab89;
|
||||
ctx->state[2] = 0x98badcfe;
|
||||
ctx->state[3] = 0x10325476;
|
||||
ctx->state[4] = 0xc3d2e1f0;
|
||||
ctx->count = 0;
|
||||
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
static ASSH_HASH_COPY_FCN(assh_sha1_copy)
|
||||
{
|
||||
memcpy(hctx_dst, hctx_src, sizeof(struct assh_hash_sha1_context_s));
|
||||
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
static ASSH_HASH_UPDATE_FCN(assh_sha1_update)
|
||||
{
|
||||
struct assh_hash_sha1_context_s *ctx = (void*)hctx;
|
||||
const uint8_t *data_ = data;
|
||||
uint32_t i, j;
|
||||
|
||||
j = (ctx->count >> 3) & 63;
|
||||
ctx->count += len * 8;
|
||||
|
||||
if ((j + len) > 63)
|
||||
{
|
||||
i = 64 - j;
|
||||
memcpy(&ctx->buffer[j], data_, i);
|
||||
|
||||
assh_sha1_transform(ctx->state, ctx->buffer);
|
||||
for ( ; i + 63 < len; i += 64)
|
||||
assh_sha1_transform(ctx->state, &data_[i]);
|
||||
|
||||
j = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
i = 0;
|
||||
}
|
||||
|
||||
memcpy(&ctx->buffer[j], &data_[i], len - i);
|
||||
}
|
||||
|
||||
|
||||
static ASSH_HASH_FINAL_FCN(assh_sha1_final)
|
||||
{
|
||||
struct assh_hash_sha1_context_s *ctx = (void*)hctx;
|
||||
|
||||
assert(len == 20);
|
||||
|
||||
unsigned int i;
|
||||
uint8_t count[8];
|
||||
uint8_t c;
|
||||
|
||||
if (hash == NULL)
|
||||
return;
|
||||
|
||||
assh_store_u64(count, ctx->count);
|
||||
|
||||
c = 0200;
|
||||
assh_sha1_update(hctx, &c, 1);
|
||||
while ((ctx->count & 504) != 448)
|
||||
{
|
||||
c = 0000;
|
||||
assh_sha1_update(hctx, &c, 1);
|
||||
}
|
||||
|
||||
assh_sha1_update(hctx, count, 8);
|
||||
for (i = 0; i < 20; i++)
|
||||
hash[i] = (uint8_t)((ctx->state[i >> 2] >> ((3 - (i & 3)) * 8) ) & 0xff);
|
||||
}
|
||||
|
||||
const struct assh_hash_algo_s assh_hash_sha1 =
|
||||
{
|
||||
.name = "sha1",
|
||||
.ctx_size = sizeof(struct assh_hash_sha1_context_s),
|
||||
.hash_size = 20,
|
||||
.block_size = 64,
|
||||
.f_init = assh_sha1_init,
|
||||
.f_copy = assh_sha1_copy,
|
||||
.f_update = assh_sha1_update,
|
||||
.f_final = assh_sha1_final,
|
||||
};
|
||||
|
|
@ -0,0 +1,549 @@
|
|||
/*
|
||||
|
||||
libassh - asynchronous ssh2 client/server library.
|
||||
|
||||
Copyright (C) 2013 Alexandre Becoulet <alexandre.becoulet@free.fr>
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#include <assh/assh_hash.h>
|
||||
#include <assh/assh_packet.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
struct assh_hash_sha512_context_s
|
||||
{
|
||||
struct assh_hash_ctx_s ctx;
|
||||
uint64_t count;
|
||||
uint64_t state[8];
|
||||
uint8_t buffer[128];
|
||||
};
|
||||
|
||||
ASSH_FIRST_FIELD_ASSERT(assh_hash_sha512_context_s, ctx);
|
||||
|
||||
struct assh_hash_sha256_context_s
|
||||
{
|
||||
struct assh_hash_ctx_s ctx;
|
||||
uint64_t count;
|
||||
uint32_t state[8];
|
||||
uint8_t buffer[64];
|
||||
};
|
||||
|
||||
ASSH_FIRST_FIELD_ASSERT(assh_hash_sha256_context_s, ctx);
|
||||
|
||||
/*
|
||||
* FIPS-180-2 compliant SHA2 implementation
|
||||
* based on PUBLIC DOMAIN sha256 by Christophe Devine
|
||||
*/
|
||||
|
||||
static inline uint32_t ror32(uint32_t value, unsigned int bits)
|
||||
{
|
||||
return (((value) >> (bits)) | ((value) << (32 - (bits))));
|
||||
}
|
||||
|
||||
static inline uint64_t ror64(uint64_t value, unsigned int bits)
|
||||
{
|
||||
return (((value) >> (bits)) | ((value) << (64 - (bits))));
|
||||
}
|
||||
|
||||
|
||||
#define S256_0(x) (ror32(x, 7) ^ ror32(x, 18) ^ (x >> 3))
|
||||
#define S256_1(x) (ror32(x, 17) ^ ror32(x, 19) ^ (x >> 10))
|
||||
|
||||
#define S256_2(x) (ror32(x, 2) ^ ror32(x, 13) ^ ror32(x, 22))
|
||||
#define S256_3(x) (ror32(x, 6) ^ ror32(x, 11) ^ ror32(x, 25))
|
||||
|
||||
#define S512_0(x) (ror64(x, 1) ^ ror64(x, 8) ^ (x >> 7))
|
||||
#define S512_1(x) (ror64(x, 19) ^ ror64(x, 61) ^ (x >> 6))
|
||||
|
||||
#define S512_2(x) (ror64(x, 28) ^ ror64(x, 34) ^ ror64(x, 39))
|
||||
#define S512_3(x) (ror64(x, 14) ^ ror64(x, 18) ^ ror64(x, 41))
|
||||
|
||||
#define F0(x,y,z) ((x & y) | (z & (x | y)))
|
||||
#define F1(x,y,z) (z ^ (x & (y ^ z)))
|
||||
|
||||
#define R(A, t) \
|
||||
( \
|
||||
w[t] = S##A##_1(w[t - 2]) + w[t - 7] + \
|
||||
S##A##_0(w[t - 15]) + w[t - 16] \
|
||||
)
|
||||
|
||||
#define P(A, a, b, c, d, e, f, g, h, x, K) \
|
||||
{ \
|
||||
temp1 = h + S##A##_3(e) + F1(e,f,g) + K + x; \
|
||||
temp2 = S##A##_2(a) + F0(a,b,c); \
|
||||
d += temp1; h = temp1 + temp2; \
|
||||
}
|
||||
|
||||
static const uint8_t assh_sha2_padding[16 + 1] = { 0x80 };
|
||||
|
||||
static void sha256_process(struct assh_hash_sha256_context_s *ctx,
|
||||
const uint8_t data[64])
|
||||
{
|
||||
uint32_t temp1, temp2, w[64];
|
||||
uint_fast8_t i;
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
w[i] = assh_load_u32(data + i * 4);
|
||||
|
||||
uint32_t a = ctx->state[0];
|
||||
uint32_t b = ctx->state[1];
|
||||
uint32_t c = ctx->state[2];
|
||||
uint32_t d = ctx->state[3];
|
||||
uint32_t e = ctx->state[4];
|
||||
uint32_t f = ctx->state[5];
|
||||
uint32_t g = ctx->state[6];
|
||||
uint32_t h = ctx->state[7];
|
||||
|
||||
static const uint32_t keys[64] = {
|
||||
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
||||
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
||||
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
||||
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
|
||||
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
||||
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
||||
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
||||
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
|
||||
};
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
P(256, a, b, c, d, e, f, g, h, w[i], keys[i]);
|
||||
uint32_t x = h;
|
||||
(h = g), (g = f), (f = e), (e = d), (d = c), (c = b), (b = a), (a = x);
|
||||
}
|
||||
|
||||
for (; i < 64; i++)
|
||||
{
|
||||
P(256, a, b, c, d, e, f, g, h, R(256, i), keys[i]);
|
||||
uint32_t x = h;
|
||||
(h = g), (g = f), (f = e), (e = d), (d = c), (c = b), (b = a), (a = x);
|
||||
}
|
||||
|
||||
ctx->state[0] += a;
|
||||
ctx->state[1] += b;
|
||||
ctx->state[2] += c;
|
||||
ctx->state[3] += d;
|
||||
ctx->state[4] += e;
|
||||
ctx->state[5] += f;
|
||||
ctx->state[6] += g;
|
||||
ctx->state[7] += h;
|
||||
}
|
||||
|
||||
static void sha512_process(struct assh_hash_sha512_context_s *ctx,
|
||||
const uint8_t data[128])
|
||||
{
|
||||
uint64_t temp1, temp2, w[80];
|
||||
uint_fast8_t i;
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
w[i] = assh_load_u64(data + i * 8);
|
||||
|
||||
uint64_t a = ctx->state[0];
|
||||
uint64_t b = ctx->state[1];
|
||||
uint64_t c = ctx->state[2];
|
||||
uint64_t d = ctx->state[3];
|
||||
uint64_t e = ctx->state[4];
|
||||
uint64_t f = ctx->state[5];
|
||||
uint64_t g = ctx->state[6];
|
||||
uint64_t h = ctx->state[7];
|
||||
|
||||
static const uint64_t keys[80] = {
|
||||
0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc, 0x3956c25bf348b538,
|
||||
0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, 0xd807aa98a3030242, 0x12835b0145706fbe,
|
||||
0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2, 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235,
|
||||
0xc19bf174cf692694, 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65,
|
||||
0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5, 0x983e5152ee66dfab,
|
||||
0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4, 0xc6e00bf33da88fc2, 0xd5a79147930aa725,
|
||||
0x06ca6351e003826f, 0x142929670a0e6e70, 0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed,
|
||||
0x53380d139d95b3df, 0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b,
|
||||
0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30, 0xd192e819d6ef5218,
|
||||
0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8, 0x19a4c116b8d2d0c8, 0x1e376c085141ab53,
|
||||
0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8, 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373,
|
||||
0x682e6ff3d6b2b8a3, 0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec,
|
||||
0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b, 0xca273eceea26619c,
|
||||
0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, 0x06f067aa72176fba, 0x0a637dc5a2c898a6,
|
||||
0x113f9804bef90dae, 0x1b710b35131c471b, 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc,
|
||||
0x431d67c49c100d4c, 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817
|
||||
};
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
P(512, a, b, c, d, e, f, g, h, w[i], keys[i]);
|
||||
uint64_t x = h;
|
||||
(h = g), (g = f), (f = e), (e = d), (d = c), (c = b), (b = a), (a = x);
|
||||
}
|
||||
|
||||
for (; i < 80; i++)
|
||||
{
|
||||
P(512, a, b, c, d, e, f, g, h, R(512, i), keys[i]);
|
||||
uint64_t x = h;
|
||||
(h = g), (g = f), (f = e), (e = d), (d = c), (c = b), (b = a), (a = x);
|
||||
}
|
||||
|
||||
ctx->state[0] += a;
|
||||
ctx->state[1] += b;
|
||||
ctx->state[2] += c;
|
||||
ctx->state[3] += d;
|
||||
ctx->state[4] += e;
|
||||
ctx->state[5] += f;
|
||||
ctx->state[6] += g;
|
||||
ctx->state[7] += h;
|
||||
}
|
||||
|
||||
static void assh_sha256_update_(struct assh_hash_sha256_context_s *ctx,
|
||||
const void *data, size_t len)
|
||||
{
|
||||
uint32_t left, fill;
|
||||
const uint8_t *input = data;
|
||||
|
||||
if (len == 0)
|
||||
return;
|
||||
|
||||
left = ctx->count & 0x3f;
|
||||
fill = 64 - left;
|
||||
|
||||
ctx->count += len;
|
||||
|
||||
if (left && len >= fill)
|
||||
{
|
||||
memcpy((ctx->buffer + left), input, fill);
|
||||
sha256_process(ctx, ctx->buffer);
|
||||
len -= fill;
|
||||
input += fill;
|
||||
left = 0;
|
||||
}
|
||||
|
||||
while (len >= 64)
|
||||
{
|
||||
sha256_process(ctx, input);
|
||||
len -= 64;
|
||||
input += 64;
|
||||
}
|
||||
|
||||
if (len)
|
||||
memcpy((ctx->buffer + left), input, len);
|
||||
}
|
||||
|
||||
static void assh_sha256_final_(struct assh_hash_sha256_context_s *ctx)
|
||||
{
|
||||
uint32_t last, padn;
|
||||
uint8_t msglen[8];
|
||||
|
||||
assh_store_u64(msglen, ctx->count * 8);
|
||||
|
||||
last = ctx->count & 63;
|
||||
padn = (last < 56) ? (56 - last) : (120 - last);
|
||||
|
||||
const uint8_t *pad = assh_sha2_padding;
|
||||
while (padn > 16)
|
||||
{
|
||||
assh_sha256_update_(ctx, pad, 16);
|
||||
pad = assh_sha2_padding + 1;
|
||||
padn -= 16;
|
||||
}
|
||||
assh_sha256_update_(ctx, pad, padn);
|
||||
assh_sha256_update_(ctx, msglen, 8);
|
||||
}
|
||||
|
||||
static void assh_sha512_update_(struct assh_hash_sha512_context_s *ctx,
|
||||
const void *data, size_t len)
|
||||
{
|
||||
uint64_t left, fill;
|
||||
const uint8_t *input = data;
|
||||
|
||||
if (len == 0)
|
||||
return;
|
||||
|
||||
left = ctx->count & 0x7f;
|
||||
fill = 128 - left;
|
||||
|
||||
ctx->count += len;
|
||||
|
||||
if (left && len >= fill)
|
||||
{
|
||||
memcpy((ctx->buffer + left), input, fill);
|
||||
sha512_process(ctx, ctx->buffer);
|
||||
len -= fill;
|
||||
input += fill;
|
||||
left = 0;
|
||||
}
|
||||
|
||||
while (len >= 128)
|
||||
{
|
||||
sha512_process(ctx, input);
|
||||
len -= 128;
|
||||
input += 128;
|
||||
}
|
||||
|
||||
if (len)
|
||||
memcpy((ctx->buffer + left), input, len);
|
||||
}
|
||||
|
||||
static void assh_sha512_final_(struct assh_hash_sha512_context_s *ctx)
|
||||
{
|
||||
uint64_t last, padn;
|
||||
uint8_t msglen[16];
|
||||
|
||||
assh_store_u64(msglen, 0);
|
||||
assh_store_u64(msglen + 8, ctx->count * 8);
|
||||
|
||||
last = ctx->count & 127;
|
||||
padn = (last < 112) ? (112 - last) : (240 - last);
|
||||
|
||||
const uint8_t *pad = assh_sha2_padding;
|
||||
while (padn > 16)
|
||||
{
|
||||
assh_sha512_update_(ctx, pad, 16);
|
||||
pad = assh_sha2_padding + 1;
|
||||
padn -= 16;
|
||||
}
|
||||
assh_sha512_update_(ctx, pad, padn);
|
||||
assh_sha512_update_(ctx, msglen, 16);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static ASSH_HASH_INIT_FCN(assh_sha224_init)
|
||||
{
|
||||
struct assh_hash_sha256_context_s *ctx = (void*)hctx;
|
||||
uint_fast8_t i;
|
||||
|
||||
ctx->count = 0;
|
||||
|
||||
static const uint32_t init[8] = {
|
||||
0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939,
|
||||
0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4,
|
||||
};
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
ctx->state[i] = init[i];
|
||||
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
static ASSH_HASH_COPY_FCN(assh_sha224_copy)
|
||||
{
|
||||
memcpy(hctx_dst, hctx_src, sizeof(struct assh_hash_sha256_context_s));
|
||||
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
static ASSH_HASH_UPDATE_FCN(assh_sha224_update)
|
||||
{
|
||||
assh_sha256_update_((void*)hctx, data, len);
|
||||
}
|
||||
|
||||
static ASSH_HASH_FINAL_FCN(assh_sha224_final)
|
||||
{
|
||||
struct assh_hash_sha256_context_s *ctx = (void*)hctx;
|
||||
uint_fast8_t i;
|
||||
|
||||
assert(len == 28);
|
||||
|
||||
assh_sha256_final_(ctx);
|
||||
|
||||
if (hash != NULL)
|
||||
for (i = 0; i < 7; i++)
|
||||
assh_store_u32(hash + i * 4, ctx->state[i]);
|
||||
}
|
||||
|
||||
const struct assh_hash_algo_s assh_hash_sha224 =
|
||||
{
|
||||
.name = "sha224",
|
||||
.ctx_size = sizeof(struct assh_hash_sha256_context_s),
|
||||
.hash_size = 28,
|
||||
.block_size = 64,
|
||||
.f_init = assh_sha224_init,
|
||||
.f_copy = assh_sha224_copy,
|
||||
.f_update = assh_sha224_update,
|
||||
.f_final = assh_sha224_final,
|
||||
};
|
||||
|
||||
|
||||
|
||||
static ASSH_HASH_INIT_FCN(assh_sha256_init)
|
||||
{
|
||||
struct assh_hash_sha256_context_s *ctx = (void*)hctx;
|
||||
uint_fast8_t i;
|
||||
|
||||
ctx->count = 0;
|
||||
|
||||
static const uint32_t init[8] = {
|
||||
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
|
||||
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
|
||||
};
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
ctx->state[i] = init[i];
|
||||
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
static ASSH_HASH_COPY_FCN(assh_sha256_copy)
|
||||
{
|
||||
memcpy(hctx_dst, hctx_src, sizeof(struct assh_hash_sha256_context_s));
|
||||
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
static ASSH_HASH_UPDATE_FCN(assh_sha256_update)
|
||||
{
|
||||
assh_sha256_update_((void*)hctx, data, len);
|
||||
}
|
||||
|
||||
static ASSH_HASH_FINAL_FCN(assh_sha256_final)
|
||||
{
|
||||
struct assh_hash_sha256_context_s *ctx = (void*)hctx;
|
||||
uint_fast8_t i;
|
||||
|
||||
assert(len == 32);
|
||||
|
||||
assh_sha256_final_(ctx);
|
||||
|
||||
if (hash != NULL)
|
||||
for (i = 0; i < 8; i++)
|
||||
assh_store_u32(hash + i * 4, ctx->state[i]);
|
||||
}
|
||||
|
||||
const struct assh_hash_algo_s assh_hash_sha256 =
|
||||
{
|
||||
.name = "sha256",
|
||||
.ctx_size = sizeof(struct assh_hash_sha256_context_s),
|
||||
.hash_size = 32,
|
||||
.block_size = 64,
|
||||
.f_init = assh_sha256_init,
|
||||
.f_copy = assh_sha256_copy,
|
||||
.f_update = assh_sha256_update,
|
||||
.f_final = assh_sha256_final,
|
||||
};
|
||||
|
||||
|
||||
static ASSH_HASH_INIT_FCN(assh_sha384_init)
|
||||
{
|
||||
struct assh_hash_sha512_context_s *ctx = (void*)hctx;
|
||||
uint_fast8_t i;
|
||||
|
||||
ctx->count = 0;
|
||||
|
||||
static const uint64_t init[8] = {
|
||||
0xcbbb9d5dc1059ed8, 0x629a292a367cd507, 0x9159015a3070dd17, 0x152fecd8f70e5939,
|
||||
0x67332667ffc00b31, 0x8eb44a8768581511, 0xdb0c2e0d64f98fa7, 0x47b5481dbefa4fa4,
|
||||
};
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
ctx->state[i] = init[i];
|
||||
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
static ASSH_HASH_COPY_FCN(assh_sha384_copy)
|
||||
{
|
||||
memcpy(hctx_dst, hctx_src, sizeof(struct assh_hash_sha512_context_s));
|
||||
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
static ASSH_HASH_UPDATE_FCN(assh_sha384_update)
|
||||
{
|
||||
assh_sha512_update_((void*)hctx, data, len);
|
||||
}
|
||||
|
||||
static ASSH_HASH_FINAL_FCN(assh_sha384_final)
|
||||
{
|
||||
struct assh_hash_sha512_context_s *ctx = (void*)hctx;
|
||||
uint_fast8_t i;
|
||||
|
||||
assert(len == 48);
|
||||
|
||||
assh_sha512_final_(ctx);
|
||||
|
||||
if (hash != NULL)
|
||||
for (i = 0; i < 6; i++)
|
||||
assh_store_u64(hash + i * 8, ctx->state[i]);
|
||||
}
|
||||
|
||||
const struct assh_hash_algo_s assh_hash_sha384 =
|
||||
{
|
||||
.name = "sha384",
|
||||
.ctx_size = sizeof(struct assh_hash_sha512_context_s),
|
||||
.hash_size = 48,
|
||||
.block_size = 128,
|
||||
.f_init = assh_sha384_init,
|
||||
.f_copy = assh_sha384_copy,
|
||||
.f_update = assh_sha384_update,
|
||||
.f_final = assh_sha384_final,
|
||||
};
|
||||
|
||||
|
||||
static ASSH_HASH_INIT_FCN(assh_sha512_init)
|
||||
{
|
||||
struct assh_hash_sha512_context_s *ctx = (void*)hctx;
|
||||
uint_fast8_t i;
|
||||
|
||||
ctx->count = 0;
|
||||
|
||||
static const uint64_t init[8] = {
|
||||
0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1,
|
||||
0x510e527fade682d1, 0x9b05688c2b3e6c1f, 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179,
|
||||
};
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
ctx->state[i] = init[i];
|
||||
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
static ASSH_HASH_COPY_FCN(assh_sha512_copy)
|
||||
{
|
||||
memcpy(hctx_dst, hctx_src, sizeof(struct assh_hash_sha512_context_s));
|
||||
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
static ASSH_HASH_UPDATE_FCN(assh_sha512_update)
|
||||
{
|
||||
assh_sha512_update_((void*)hctx, data, len);
|
||||
}
|
||||
|
||||
static ASSH_HASH_FINAL_FCN(assh_sha512_final)
|
||||
{
|
||||
struct assh_hash_sha512_context_s *ctx = (void*)hctx;
|
||||
uint_fast8_t i;
|
||||
|
||||
assert(len == 64);
|
||||
|
||||
assh_sha512_final_(ctx);
|
||||
|
||||
if (hash != NULL)
|
||||
for (i = 0; i < 8; i++)
|
||||
assh_store_u64(hash + i * 8, ctx->state[i]);
|
||||
}
|
||||
|
||||
const struct assh_hash_algo_s assh_hash_sha512 =
|
||||
{
|
||||
.name = "sha512",
|
||||
.ctx_size = sizeof(struct assh_hash_sha512_context_s),
|
||||
.hash_size = 64,
|
||||
.block_size = 128,
|
||||
.f_init = assh_sha512_init,
|
||||
.f_copy = assh_sha512_copy,
|
||||
.f_update = assh_sha512_update,
|
||||
.f_final = assh_sha512_final,
|
||||
};
|
|
@ -0,0 +1,299 @@
|
|||
/*
|
||||
|
||||
libassh - asynchronous ssh2 client/server library.
|
||||
|
||||
Copyright (C) 2013 Alexandre Becoulet <alexandre.becoulet@free.fr>
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#include <assh/assh_hash.h>
|
||||
#include <assh/assh_packet.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
struct assh_hash_sha3_context_s
|
||||
{
|
||||
struct assh_hash_ctx_s ctx;
|
||||
const struct assh_hash_algo_s *algo;
|
||||
uint64_t a[25];
|
||||
uint8_t buf[200];
|
||||
uint8_t padding;
|
||||
uint_fast8_t i;
|
||||
};
|
||||
|
||||
ASSH_FIRST_FIELD_ASSERT(assh_hash_sha3_context_s, ctx);
|
||||
|
||||
static inline uint64_t keccak_rotate(uint64_t x, uint8_t n)
|
||||
{
|
||||
return (x << n) | (x >> (64 - n));
|
||||
}
|
||||
|
||||
#define ASSH_KECCAK_WRAP(i) ((i) % 5)
|
||||
|
||||
#define ASSH_KECCAK_WRAP2(i, j) (ASSH_KECCAK_WRAP(i) + 5 * ASSH_KECCAK_WRAP(j))
|
||||
|
||||
#if defined(__OPTIMIZE_SIZE__)
|
||||
# define ASSH_KECCAK_LOOP(var, ...) \
|
||||
for (var = 0; var < 5; var++) \
|
||||
{ __VA_ARGS__ }
|
||||
#else
|
||||
# define ASSH_KECCAK_LOOP(var, ...) \
|
||||
do { \
|
||||
var = 0; { __VA_ARGS__ } \
|
||||
var = 1; { __VA_ARGS__ } \
|
||||
var = 2; { __VA_ARGS__ } \
|
||||
var = 3; { __VA_ARGS__ } \
|
||||
var = 4; { __VA_ARGS__ } \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
static void assh_keccak(struct assh_hash_sha3_context_s *ctx)
|
||||
{
|
||||
static const uint64_t rc[24] =
|
||||
{
|
||||
0x0000000000000001ULL, 0x0000000000008082ULL, 0x800000000000808aULL,
|
||||
0x8000000080008000ULL, 0x000000000000808bULL, 0x0000000080000001ULL,
|
||||
0x8000000080008081ULL, 0x8000000000008009ULL, 0x000000000000008aULL,
|
||||
0x0000000000000088ULL, 0x0000000080008009ULL, 0x000000008000000aULL,
|
||||
0x000000008000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL,
|
||||
0x8000000000008003ULL, 0x8000000000008002ULL, 0x8000000000000080ULL,
|
||||
0x000000000000800aULL, 0x800000008000000aULL, 0x8000000080008081ULL,
|
||||
0x8000000000008080ULL, 0x0000000080000001ULL, 0x8000000080008008ULL,
|
||||
};
|
||||
|
||||
static const uint8_t r[25] =
|
||||
{
|
||||
0, 1, 62, 28, 27,
|
||||
36, 44, 6, 55, 20,
|
||||
3, 10, 43, 25, 39,
|
||||
41, 45, 15, 21, 8,
|
||||
18, 2, 61, 56, 14
|
||||
};
|
||||
|
||||
uint_fast8_t n, i, j, k;
|
||||
|
||||
for (n = 0; n < 24; n++)
|
||||
{
|
||||
uint64_t c[5], b[25];
|
||||
|
||||
ASSH_KECCAK_LOOP(i, {
|
||||
c[i] = ctx->a[ASSH_KECCAK_WRAP2(i, 0)] ^ ctx->a[ASSH_KECCAK_WRAP2(i, 1)]
|
||||
^ ctx->a[ASSH_KECCAK_WRAP2(i, 2)] ^ ctx->a[ASSH_KECCAK_WRAP2(i, 3)]
|
||||
^ ctx->a[ASSH_KECCAK_WRAP2(i, 4)];
|
||||
});
|
||||
|
||||
ASSH_KECCAK_LOOP(i, {
|
||||
uint64_t d = c[ASSH_KECCAK_WRAP(i + 4)]
|
||||
^ keccak_rotate(c[ASSH_KECCAK_WRAP(i + 1)], 1);
|
||||
ASSH_KECCAK_LOOP(j, {
|
||||
ctx->a[ASSH_KECCAK_WRAP2(i, j)] ^= d;
|
||||
});
|
||||
});
|
||||
|
||||
ASSH_KECCAK_LOOP(i, {
|
||||
ASSH_KECCAK_LOOP(j, {
|
||||
k = ASSH_KECCAK_WRAP2(i, j);
|
||||
b[ASSH_KECCAK_WRAP2(j, i * 2 + j * 3)] = keccak_rotate(ctx->a[k], r[k]);
|
||||
});
|
||||
});
|
||||
|
||||
ASSH_KECCAK_LOOP(i, {
|
||||
ASSH_KECCAK_LOOP(j, {
|
||||
k = ASSH_KECCAK_WRAP2(i, j);
|
||||
ctx->a[k] = b[k] ^ (~b[ASSH_KECCAK_WRAP2(i + 1, j)]
|
||||
& b[ASSH_KECCAK_WRAP2(i + 2, j)]);
|
||||
});
|
||||
});
|
||||
|
||||
ctx->a[0] ^= rc[n];
|
||||
}
|
||||
}
|
||||
|
||||
static void assh_keccak_xorin(struct assh_hash_sha3_context_s *ctx)
|
||||
{
|
||||
uint_fast8_t i;
|
||||
|
||||
for (i = 0; i < ctx->ctx.algo->block_size / 8; i++)
|
||||
ctx->a[i] ^= assh_load_u64le(ctx->buf + i * 8);
|
||||
|
||||
assh_keccak(ctx);
|
||||
}
|
||||
|
||||
static ASSH_HASH_INIT_FCN(assh_sha3_init)
|
||||
{
|
||||
struct assh_hash_sha3_context_s *ctx = (void*)hctx;
|
||||
uint_fast8_t i;
|
||||
|
||||
ctx->algo = algo;
|
||||
ctx->i = 0;
|
||||
ctx->padding = algo->hash_size ? 0x06 : 0x1f;
|
||||
|
||||
for (i = 0; i < 25; i++)
|
||||
ctx->a[i] = 0;
|
||||
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
static ASSH_HASH_COPY_FCN(assh_sha3_copy)
|
||||
{
|
||||
memcpy(hctx_dst, hctx_src, sizeof(struct assh_hash_sha3_context_s));
|
||||
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
static ASSH_HASH_UPDATE_FCN(assh_sha3_update)
|
||||
{
|
||||
struct assh_hash_sha3_context_s *ctx = (void*)hctx;
|
||||
const uint8_t *d = data;
|
||||
|
||||
assert(ctx->padding);
|
||||
|
||||
uint_fast8_t i = ctx->i;
|
||||
uint_fast8_t bs = ctx->algo->block_size;
|
||||
|
||||
while (len--)
|
||||
{
|
||||
ctx->buf[i++] = *d++;
|
||||
|
||||
if (i == bs)
|
||||
{
|
||||
assh_keccak_xorin(ctx);
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
|
||||
ctx->i = i;
|
||||
}
|
||||
|
||||
static ASSH_HASH_FINAL_FCN(assh_sha3_final)
|
||||
{
|
||||
struct assh_hash_sha3_context_s *ctx = (void*)hctx;
|
||||
|
||||
uint_fast8_t i = ctx->i;
|
||||
uint_fast8_t bs = ctx->algo->block_size;
|
||||
|
||||
assert(!ctx->algo->hash_size || ctx->algo->hash_size == len);
|
||||
|
||||
if (ctx->padding)
|
||||
{
|
||||
if (i == bs - 1)
|
||||
{
|
||||
ctx->buf[i++] = ctx->padding | 0x80;
|
||||
assh_keccak_xorin(ctx);
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx->buf[i++] = ctx->padding;
|
||||
while (i < bs - 1)
|
||||
ctx->buf[i++] = 0;
|
||||
ctx->buf[i++] = 0x80;
|
||||
assh_keccak_xorin(ctx);
|
||||
}
|
||||
|
||||
i = 0;
|
||||
ctx->padding = 0;
|
||||
}
|
||||
|
||||
while (len--)
|
||||
{
|
||||
*hash++ = ctx->a[i >> 3] >> ((i & 7) * 8);
|
||||
if (++i == bs)
|
||||
{
|
||||
assh_keccak(ctx);
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
|
||||
ctx->i = i;
|
||||
}
|
||||
|
||||
const struct assh_hash_algo_s assh_hash_sha3_224 =
|
||||
{
|
||||
.name = "sha3-224",
|
||||
.ctx_size = sizeof(struct assh_hash_sha3_context_s),
|
||||
.hash_size = 28,
|
||||
.block_size = 144,
|
||||
.f_init = assh_sha3_init,
|
||||
.f_copy = assh_sha3_copy,
|
||||
.f_update = assh_sha3_update,
|
||||
.f_final = assh_sha3_final,
|
||||
};
|
||||
|
||||
|
||||
const struct assh_hash_algo_s assh_hash_sha3_256 =
|
||||
{
|
||||
.name = "sha3-256",
|
||||
.ctx_size = sizeof(struct assh_hash_sha3_context_s),
|
||||
.hash_size = 32,
|
||||
.block_size = 136,
|
||||
.f_init = assh_sha3_init,
|
||||
.f_copy = assh_sha3_copy,
|
||||
.f_update = assh_sha3_update,
|
||||
.f_final = assh_sha3_final,
|
||||
};
|
||||
|
||||
|
||||
const struct assh_hash_algo_s assh_hash_sha3_384 =
|
||||
{
|
||||
.name = "sha3-384",
|
||||
.ctx_size = sizeof(struct assh_hash_sha3_context_s),
|
||||
.hash_size = 48,
|
||||
.block_size = 104,
|
||||
.f_init = assh_sha3_init,
|
||||
.f_copy = assh_sha3_copy,
|
||||
.f_update = assh_sha3_update,
|
||||
.f_final = assh_sha3_final,
|
||||
};
|
||||
|
||||
|
||||
const struct assh_hash_algo_s assh_hash_sha3_512 =
|
||||
{
|
||||
.name = "sha3-512",
|
||||
.ctx_size = sizeof(struct assh_hash_sha3_context_s),
|
||||
.hash_size = 64,
|
||||
.block_size = 72,
|
||||
.f_init = assh_sha3_init,
|
||||
.f_copy = assh_sha3_copy,
|
||||
.f_update = assh_sha3_update,
|
||||
.f_final = assh_sha3_final,
|
||||
};
|
||||
|
||||
|
||||
const struct assh_hash_algo_s assh_hash_shake_128 =
|
||||
{
|
||||
.name = "shake128",
|
||||
.ctx_size = sizeof(struct assh_hash_sha3_context_s),
|
||||
.block_size = 168,
|
||||
.f_init = assh_sha3_init,
|
||||
.f_copy = assh_sha3_copy,
|
||||
.f_update = assh_sha3_update,
|
||||
.f_final = assh_sha3_final,
|
||||
};
|
||||
|
||||
|
||||
const struct assh_hash_algo_s assh_hash_shake_256 =
|
||||
{
|
||||
.name = "shake256",
|
||||
.ctx_size = sizeof(struct assh_hash_sha3_context_s),
|
||||
.block_size = 136,
|
||||
.f_init = assh_sha3_init,
|
||||
.f_copy = assh_sha3_copy,
|
||||
.f_update = assh_sha3_update,
|
||||
.f_final = assh_sha3_final,
|
||||
};
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
|
||||
libassh - asynchronous ssh2 client/server library.
|
||||
|
||||
Copyright (C) 2013 Alexandre Becoulet <alexandre.becoulet@free.fr>
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <assh/assh_session.h>
|
||||
#include <assh/assh_transport.h>
|
||||
#include <assh/assh_prng.h>
|
||||
|
||||
#include <assh/helper_fd.h>
|
||||
|
||||
ASSH_EVENT_HANDLER_FCN(assh_fd_event_read)
|
||||
{
|
||||
assh_error_t err;
|
||||
struct assh_fd_context_s *ctx_ = ctx;
|
||||
struct assh_event_transport_read_s *te = &e->transport.read;
|
||||
ssize_t r = read(ctx_->ssh_fd, te->buf.data, te->buf.size);
|
||||
switch (r)
|
||||
{
|
||||
case -1:
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK)
|
||||
break;
|
||||
case 0:
|
||||
ASSH_ERR_RET(ASSH_ERR_IO | ASSH_ERRSV_FIN);
|
||||
default:
|
||||
te->transferred = r;
|
||||
}
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
ASSH_EVENT_HANDLER_FCN(assh_fd_event_write)
|
||||
{
|
||||
assh_error_t err;
|
||||
struct assh_fd_context_s *ctx_ = ctx;
|
||||
struct assh_event_transport_write_s *te = &e->transport.write;
|
||||
ssize_t r = write(ctx_->ssh_fd, te->buf.data, te->buf.size);
|
||||
switch (r)
|
||||
{
|
||||
case -1:
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK)
|
||||
break;
|
||||
case 0:
|
||||
ASSH_ERR_RET(ASSH_ERR_IO | ASSH_ERRSV_FIN);
|
||||
default:
|
||||
te->transferred = r;
|
||||
}
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
ASSH_EVENT_HANDLER_FCN(assh_fd_event_prng_feed)
|
||||
{
|
||||
assh_error_t err;
|
||||
struct assh_fd_context_s *ctx_ = ctx;
|
||||
|
||||
ssize_t r = read(ctx_->rand_fd, e->prng.feed.buf, e->prng.feed.size);
|
||||
switch (r)
|
||||
{
|
||||
case -1:
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK)
|
||||
break;
|
||||
case 0:
|
||||
ASSH_ERR_RET(ASSH_ERR_IO | ASSH_ERRSV_FIN);
|
||||
default:
|
||||
e->prng.feed.size = r;
|
||||
}
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
void assh_fd_events_register(struct assh_event_hndl_table_s *t,
|
||||
struct assh_fd_context_s *ctx,
|
||||
int ssh_fd, int rand_fd)
|
||||
{
|
||||
ctx->ssh_fd = ssh_fd;
|
||||
|
||||
assh_event_table_register(t, ASSH_EVENT_READ, &ctx->h_read,
|
||||
assh_fd_event_read, ctx);
|
||||
|
||||
assh_event_table_register(t, ASSH_EVENT_WRITE, &ctx->h_write,
|
||||
assh_fd_event_write, ctx);
|
||||
|
||||
if (rand_fd >= 0)
|
||||
{
|
||||
ctx->rand_fd = rand_fd;
|
||||
|
||||
assh_event_table_register(t, ASSH_EVENT_PRNG_FEED, &ctx->h_prng_feed,
|
||||
assh_fd_event_prng_feed, ctx);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,262 @@
|
|||
/*
|
||||
|
||||
libassh - asynchronous ssh2 client/server library.
|
||||
|
||||
Copyright (C) 2013 Alexandre Becoulet <alexandre.becoulet@free.fr>
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#include <assh/helper_key.h>
|
||||
#include <assh/assh_context.h>
|
||||
#include <assh/assh_packet.h>
|
||||
#include <assh/assh_alloc.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
struct assh_base64_ctx_s
|
||||
{
|
||||
uint8_t *out, *out_start, *out_end;
|
||||
int in, pad;
|
||||
uint32_t x;
|
||||
};
|
||||
|
||||
static void assh_base64_init(struct assh_base64_ctx_s *ctx, uint8_t *out,
|
||||
size_t out_len)
|
||||
{
|
||||
ctx->out_start = ctx->out = out;
|
||||
ctx->out_end = out + out_len;
|
||||
ctx->pad = ctx->in = 0;
|
||||
ctx->x = 0;
|
||||
}
|
||||
|
||||
static assh_error_t assh_base64_update(struct assh_base64_ctx_s *ctx,
|
||||
const uint8_t *b64, size_t b64_len)
|
||||
{
|
||||
static const int8_t codes[128] =
|
||||
{
|
||||
-4, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, /* blanks */
|
||||
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
|
||||
-2, -2, -2, -2, -2, -2, -2, -2, -2, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1,
|
||||
62, -1, -1, -1, 63, /* '+' and '/' */
|
||||
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, /* '0' to '9' */
|
||||
-1, -1, -1, -3, -1, -1, -1, /* '=' */
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, /* A to Z */
|
||||
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
|
||||
-1, -1, -1, -1, -1, -1,
|
||||
26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, /* a to z */
|
||||
39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
|
||||
-1, -1, -1, -1, -1
|
||||
};
|
||||
|
||||
assh_error_t err;
|
||||
|
||||
while (b64_len--)
|
||||
{
|
||||
int8_t x = *b64++, c = codes[(x | (x >> 7)) & 0x7f];
|
||||
switch (c)
|
||||
{
|
||||
case -1:
|
||||
ASSH_ERR_RET(ASSH_ERR_BAD_DATA);
|
||||
case -3: /* padding char = */
|
||||
ASSH_CHK_RET(ctx->pad++ >= 2, ASSH_ERR_BAD_DATA);
|
||||
case -2:
|
||||
continue; /* ignore blank chars */
|
||||
case -4:
|
||||
return ASSH_OK; /* NUL termination */
|
||||
default:
|
||||
ASSH_CHK_RET(ctx->pad > 0, ASSH_ERR_BAD_DATA);
|
||||
ctx->x = (ctx->x << 6) | c;
|
||||
if ((++ctx->in & 3) != 0)
|
||||
continue;
|
||||
ASSH_CHK_RET(ctx->out + 2 >= ctx->out_end, ASSH_ERR_OUTPUT_OVERFLOW);
|
||||
*ctx->out++ = ctx->x >> 16;
|
||||
*ctx->out++ = ctx->x >> 8;
|
||||
*ctx->out++ = ctx->x;
|
||||
ctx->x = 0;
|
||||
}
|
||||
}
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
static assh_error_t assh_base64_final(struct assh_base64_ctx_s *ctx)
|
||||
{
|
||||
assh_error_t err;
|
||||
|
||||
ASSH_CHK_RET((ctx->in + ctx->pad) & 3, ASSH_ERR_BAD_DATA);
|
||||
|
||||
ASSH_CHK_RET(ctx->out + ((2 - ctx->pad) % 2) >= ctx->out_end,
|
||||
ASSH_ERR_OUTPUT_OVERFLOW);
|
||||
switch (ctx->pad)
|
||||
{
|
||||
case 2:
|
||||
*ctx->out++ = ctx->x >> 4;
|
||||
break;
|
||||
case 1:
|
||||
*ctx->out++ = ctx->x >> 10;
|
||||
*ctx->out++ = ctx->x >> 2;
|
||||
case 0:;
|
||||
}
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
static inline size_t assh_base64_size(struct assh_base64_ctx_s *ctx)
|
||||
{
|
||||
return ctx->out - ctx->out_start;
|
||||
}
|
||||
|
||||
static assh_error_t assh_load_rfc4716(FILE *file, uint8_t *kdata, size_t *klen)
|
||||
{
|
||||
struct assh_base64_ctx_s ctx;
|
||||
assh_error_t err;
|
||||
char in[80], *l;
|
||||
int state = 0;
|
||||
assh_base64_init(&ctx, kdata, *klen);
|
||||
|
||||
while ((l = fgets(in, sizeof(in), file)))
|
||||
{
|
||||
size_t len = strlen(l);
|
||||
|
||||
while (len && l[len - 1] <= ' ')
|
||||
l[--len] = '\0';
|
||||
if (!len)
|
||||
continue;
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case 0:
|
||||
if (l[0] != '-' || !strstr(l, "BEGIN "))
|
||||
continue;
|
||||
state = 1;
|
||||
continue;
|
||||
case 1:
|
||||
state = 3;
|
||||
if (!strchr(l, ':'))
|
||||
break;
|
||||
case 2:
|
||||
state = 1;
|
||||
if (l[len - 1] == '\\')
|
||||
state = 2;
|
||||
continue;
|
||||
case 3:
|
||||
if (l[0] != '-')
|
||||
break;
|
||||
ASSH_CHK_RET(!strstr(l, "END "), ASSH_ERR_BAD_DATA);
|
||||
state = 0;
|
||||
ASSH_ERR_RET(assh_base64_final(&ctx));
|
||||
*klen = assh_base64_size(&ctx);
|
||||
return ASSH_OK;
|
||||
}
|
||||
ASSH_ERR_RET(assh_base64_update(&ctx, (const uint8_t*)l, len));
|
||||
}
|
||||
|
||||
ASSH_ERR_RET(ASSH_ERR_BAD_DATA);
|
||||
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
assh_error_t assh_load_key_file(struct assh_context_s *c,
|
||||
const struct assh_key_s **head,
|
||||
const struct assh_key_ops_s *algo,
|
||||
enum assh_algo_class_e role,
|
||||
FILE *file, enum assh_key_format_e format)
|
||||
{
|
||||
assh_error_t err;
|
||||
size_t blob_len = 4096;
|
||||
|
||||
ASSH_SCRATCH_ALLOC(c, uint8_t, blob, blob_len,
|
||||
ASSH_ERRSV_CONTINUE, err_);
|
||||
|
||||
switch (format)
|
||||
{
|
||||
case ASSH_KEY_FMT_PUB_RFC4716:
|
||||
assh_load_rfc4716(file, blob, &blob_len);
|
||||
format = ASSH_KEY_FMT_PUB_RFC4253_6_6;
|
||||
break;
|
||||
|
||||
case ASSH_KEY_FMT_PV_RFC2440_PEM_ASN1:
|
||||
assh_load_rfc4716(file, blob, &blob_len);
|
||||
format = ASSH_KEY_FMT_PV_PEM_ASN1;
|
||||
break;
|
||||
|
||||
case ASSH_KEY_FMT_OPENSSH_V1:
|
||||
assh_load_rfc4716(file, blob, &blob_len);
|
||||
format = ASSH_KEY_FMT_OPENSSH_V1_BLOB;
|
||||
break;
|
||||
|
||||
default:
|
||||
blob_len = fread(blob, 1, blob_len, file);
|
||||
break;
|
||||
}
|
||||
|
||||
ASSH_ERR_GTO(assh_key_load(c, head, algo, role, format, blob, blob_len), err_sc);
|
||||
|
||||
err = ASSH_OK;
|
||||
|
||||
err_sc:
|
||||
ASSH_SCRATCH_FREE(c, blob);
|
||||
err_:
|
||||
return err;
|
||||
}
|
||||
|
||||
assh_error_t assh_load_key_filename(struct assh_context_s *c,
|
||||
const struct assh_key_s **head,
|
||||
const struct assh_key_ops_s *algo,
|
||||
enum assh_algo_class_e role,
|
||||
const char *filename,
|
||||
enum assh_key_format_e format)
|
||||
{
|
||||
assh_error_t err;
|
||||
|
||||
FILE *file = fopen(filename, "r");
|
||||
ASSH_CHK_RET(file == NULL, ASSH_ERR_IO);
|
||||
|
||||
ASSH_ERR_GTO(assh_load_key_file(c, head, algo, role, file, format), err_);
|
||||
|
||||
err_:
|
||||
fclose(file);
|
||||
return err;
|
||||
}
|
||||
|
||||
assh_error_t assh_load_hostkey_file(struct assh_context_s *c,
|
||||
const struct assh_key_ops_s *algo,
|
||||
enum assh_algo_class_e role,
|
||||
FILE *file,
|
||||
enum assh_key_format_e format)
|
||||
{
|
||||
#ifdef CONFIG_ASSH_SERVER
|
||||
if (c->type == ASSH_SERVER)
|
||||
return assh_load_key_file(c, &c->keys, algo, role, file, format);
|
||||
#endif
|
||||
return ASSH_ERR_NOTSUP;
|
||||
}
|
||||
|
||||
assh_error_t assh_load_hostkey_filename(struct assh_context_s *c,
|
||||
const struct assh_key_ops_s *algo,
|
||||
enum assh_algo_class_e role,
|
||||
const char *filename,
|
||||
enum assh_key_format_e format)
|
||||
{
|
||||
#ifdef CONFIG_ASSH_SERVER
|
||||
if (c->type == ASSH_SERVER)
|
||||
return assh_load_key_filename(c, &c->keys, algo, role, filename, format);
|
||||
#endif
|
||||
return ASSH_ERR_NOTSUP;
|
||||
}
|
||||
|
|
@ -0,0 +1,585 @@
|
|||
/*
|
||||
|
||||
libassh - asynchronous ssh2 client/server library.
|
||||
|
||||
Copyright (C) 2013 Alexandre Becoulet <alexandre.becoulet@free.fr>
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#include <assh/assh_kex.h>
|
||||
#include <assh/assh_session.h>
|
||||
#include <assh/assh_packet.h>
|
||||
#include <assh/assh_transport.h>
|
||||
#include <assh/assh_bignum.h>
|
||||
#include <assh/assh_sign.h>
|
||||
#include <assh/assh_prng.h>
|
||||
#include <assh/assh_event.h>
|
||||
#include <assh/assh_alloc.h>
|
||||
#include <assh/assh_hash.h>
|
||||
#include <assh/assh_cipher.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define DH_MAX_GRSIZE 8192
|
||||
|
||||
struct assh_kex_dh_group_s
|
||||
{
|
||||
size_t size;
|
||||
const uint8_t *generator;
|
||||
const uint8_t *prime;
|
||||
};
|
||||
|
||||
enum assh_kex_dh_state_e
|
||||
{
|
||||
#ifdef CONFIG_ASSH_CLIENT
|
||||
ASSH_KEX_DH_CLIENT_WAIT_F,
|
||||
ASSH_KEX_DH_CLIENT_INIT,
|
||||
ASSH_KEX_DH_CLIENT_LOOKUP_HOST_KEY_WAIT,
|
||||
#endif
|
||||
#ifdef CONFIG_ASSH_SERVER
|
||||
ASSH_KEX_DH_SERVER_WAIT_E,
|
||||
#endif
|
||||
};
|
||||
|
||||
struct assh_kex_dh_private_s
|
||||
{
|
||||
const struct assh_kex_dh_group_s *group;
|
||||
enum assh_kex_dh_state_e state;
|
||||
|
||||
union {
|
||||
#ifdef CONFIG_ASSH_SERVER
|
||||
struct {
|
||||
size_t exp_n;
|
||||
};
|
||||
#endif
|
||||
#ifdef CONFIG_ASSH_CLIENT
|
||||
struct {
|
||||
struct assh_bignum_s en;
|
||||
struct assh_bignum_s xn;
|
||||
const struct assh_key_s *host_key;
|
||||
struct assh_packet_s *pck;
|
||||
};
|
||||
#endif
|
||||
};
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ASSH_CLIENT
|
||||
static assh_error_t assh_kex_dh_client_send_expmod(struct assh_session_s *s)
|
||||
{
|
||||
struct assh_kex_dh_private_s *pv = s->kex_pv;
|
||||
const struct assh_kex_dh_group_s *gr = pv->group;
|
||||
struct assh_context_s *c = s->ctx;
|
||||
assh_error_t err;
|
||||
|
||||
struct assh_packet_s *p;
|
||||
size_t e_size = assh_bignum_size_of_bits(ASSH_BIGNUM_MPINT, gr->size);
|
||||
|
||||
ASSH_ERR_RET(assh_packet_alloc(c, SSH_MSG_KEX_DH_REQUEST, e_size, &p)
|
||||
| ASSH_ERRSV_DISCONNECT);
|
||||
|
||||
uint8_t *e_str;
|
||||
ASSH_ASSERT(assh_packet_add_array(p, e_size, &e_str));
|
||||
|
||||
enum bytecode_args_e
|
||||
{
|
||||
G_mpint, P_mpint, E_mpint,
|
||||
E, X, G_n,
|
||||
G, P, MT
|
||||
};
|
||||
|
||||
static const assh_bignum_op_t bytecode[] = {
|
||||
ASSH_BOP_SIZE( G, G_n ),
|
||||
ASSH_BOP_SIZE( P, G_n ),
|
||||
|
||||
ASSH_BOP_MOVE( G, G_mpint ),
|
||||
ASSH_BOP_MOVE( P, P_mpint ),
|
||||
|
||||
/* generate private exponent in range [ group bits, p - 2 ] */
|
||||
ASSH_BOP_UINT( E, DH_MAX_GRSIZE ),
|
||||
ASSH_BOP_RAND( X, E, P,
|
||||
ASSH_PRNG_QUALITY_EPHEMERAL_KEY),
|
||||
|
||||
/* compute dh public key */
|
||||
ASSH_BOP_MTINIT( MT, P ),
|
||||
ASSH_BOP_MTTO( G, G, G, MT ),
|
||||
ASSH_BOP_EXPM( E, G, X, MT ),
|
||||
ASSH_BOP_MTFROM( E, E, E, MT ),
|
||||
|
||||
ASSH_BOP_MOVE( E_mpint, E ),
|
||||
|
||||
ASSH_BOP_END(),
|
||||
};
|
||||
|
||||
ASSH_ERR_GTO(assh_bignum_bytecode(c, bytecode, "MMMNNsTTm",
|
||||
/* M */ gr->generator, gr->prime, e_str,
|
||||
/* N */ &pv->en, &pv->xn, gr->size), err_p);
|
||||
|
||||
assh_packet_string_resized(p, e_str + 4);
|
||||
|
||||
assh_transport_push(s, p);
|
||||
pv->state = ASSH_KEX_DH_CLIENT_WAIT_F;
|
||||
return ASSH_OK;
|
||||
|
||||
err_p:
|
||||
assh_packet_release(p);
|
||||
return err;
|
||||
}
|
||||
|
||||
static ASSH_EVENT_DONE_FCN(assh_kex_dh_host_key_lookup_done)
|
||||
{
|
||||
struct assh_kex_dh_private_s *pv = s->kex_pv;
|
||||
const struct assh_kex_dh_group_s *gr = pv->group;
|
||||
assh_error_t err;
|
||||
|
||||
ASSH_CHK_RET(pv->state != ASSH_KEX_DH_CLIENT_LOOKUP_HOST_KEY_WAIT,
|
||||
ASSH_ERR_STATE | ASSH_ERRSV_FATAL);
|
||||
|
||||
if (!e->kex.hostkey_lookup.accept)
|
||||
{
|
||||
ASSH_ERR_RET(assh_kex_end(s, 0) | ASSH_ERRSV_DISCONNECT);
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
struct assh_packet_s *p = pv->pck;
|
||||
|
||||
uint8_t *ks_str = p->head.end;
|
||||
uint8_t *f_str, *h_str;
|
||||
|
||||
ASSH_ERR_RET(assh_packet_check_string(p, ks_str, &f_str)
|
||||
| ASSH_ERRSV_DISCONNECT);
|
||||
ASSH_ERR_RET(assh_packet_check_string(p, f_str, &h_str)
|
||||
| ASSH_ERRSV_DISCONNECT);
|
||||
ASSH_ERR_RET(assh_packet_check_string(p, h_str, NULL)
|
||||
| ASSH_ERRSV_DISCONNECT);
|
||||
|
||||
ASSH_SCRATCH_ALLOC(s->ctx, uint8_t, scratch,
|
||||
assh_bignum_size_of_bits(ASSH_BIGNUM_MPINT, gr->size) +
|
||||
assh_hash_sha1.ctx_size,
|
||||
ASSH_ERRSV_CONTINUE, err_);
|
||||
|
||||
void *hash_ctx = scratch;
|
||||
uint8_t *secret = scratch + assh_hash_sha1.ctx_size;
|
||||
|
||||
enum bytecode_args_e
|
||||
{
|
||||
G_mpint, P_mpint, F_mpint, K_mpint,
|
||||
X, G_n,
|
||||
G, P, F, T, K, MT
|
||||
};
|
||||
|
||||
static const assh_bignum_op_t bytecode[] = {
|
||||
ASSH_BOP_SIZER( G, K, G_n ),
|
||||
|
||||
ASSH_BOP_MOVE( F, F_mpint ),
|
||||
ASSH_BOP_MOVE( G, G_mpint ),
|
||||
ASSH_BOP_MOVE( P, P_mpint ),
|
||||
|
||||
/* check server public exponent */
|
||||
ASSH_BOP_UINT( T, 2 ),
|
||||
ASSH_BOP_CMPLTEQ( T, F, 0 /* f >= 2 */ ),
|
||||
ASSH_BOP_SUB( T, P, T ),
|
||||
ASSH_BOP_CMPLTEQ( F, T, 0 /* f <= p-2 */),
|
||||
|
||||
/* FIXME check that log_g(pub) is not trivial */
|
||||
|
||||
/* compute shared secret */
|
||||
ASSH_BOP_MTINIT( MT, P ),
|
||||
ASSH_BOP_MTTO( F, F, F, MT ),
|
||||
ASSH_BOP_EXPM( T, F, X, MT ),
|
||||
ASSH_BOP_MTFROM( K, K, T, MT ),
|
||||
|
||||
/* check shared secret range */
|
||||
ASSH_BOP_UINT( T, 2 ),
|
||||
ASSH_BOP_CMPLTEQ( T, K, 0 /* k >= 2 */ ),
|
||||
ASSH_BOP_SUB( T, P, T ),
|
||||
ASSH_BOP_CMPLTEQ( K, T, 0 /* k <= p-2 */),
|
||||
|
||||
ASSH_BOP_MOVE( K_mpint, K ),
|
||||
|
||||
ASSH_BOP_END(),
|
||||
};
|
||||
|
||||
ASSH_ERR_GTO(assh_bignum_bytecode(s->ctx, bytecode, "MMMMNsTTTTTm",
|
||||
/* M */ gr->generator, gr->prime, f_str, secret,
|
||||
/* N */ &pv->xn, gr->size), err_scratch);
|
||||
|
||||
ASSH_ERR_GTO(assh_hash_init(s->ctx, hash_ctx, &assh_hash_sha1), err_scratch);
|
||||
|
||||
ASSH_ERR_GTO(assh_kex_client_hash1(s, hash_ctx, ks_str)
|
||||
| ASSH_ERRSV_DISCONNECT, err_hash);
|
||||
|
||||
ASSH_ERR_GTO(assh_hash_bignum(s->ctx, hash_ctx, &pv->en)
|
||||
| ASSH_ERRSV_DISCONNECT, err_hash);
|
||||
|
||||
assh_hash_string(hash_ctx, f_str);
|
||||
|
||||
ASSH_ERR_GTO(assh_kex_client_hash2(s, hash_ctx,
|
||||
pv->host_key, secret, h_str)
|
||||
| ASSH_ERRSV_DISCONNECT, err_hash);
|
||||
|
||||
ASSH_ERR_GTO(assh_kex_end(s, 1) | ASSH_ERRSV_DISCONNECT, err_hash);
|
||||
|
||||
err = ASSH_OK;
|
||||
|
||||
err_hash:
|
||||
assh_hash_cleanup(hash_ctx);
|
||||
err_scratch:
|
||||
ASSH_SCRATCH_FREE(s->ctx, scratch);
|
||||
err_:
|
||||
return err;
|
||||
}
|
||||
|
||||
static assh_error_t assh_kex_dh_client_wait_f(struct assh_session_s *s,
|
||||
struct assh_packet_s *p,
|
||||
struct assh_event_s *e)
|
||||
{
|
||||
struct assh_kex_dh_private_s *pv = s->kex_pv;
|
||||
assh_error_t err;
|
||||
|
||||
ASSH_CHK_RET(p->head.msg != SSH_MSG_KEX_DH_REPLY, ASSH_ERR_PROTOCOL
|
||||
| ASSH_ERRSV_DISCONNECT);
|
||||
|
||||
uint8_t *ks_str = p->head.end;
|
||||
uint8_t *f_str, *h_str;
|
||||
|
||||
ASSH_ERR_RET(assh_packet_check_string(p, ks_str, &f_str)
|
||||
| ASSH_ERRSV_DISCONNECT);
|
||||
ASSH_ERR_RET(assh_packet_check_string(p, f_str, &h_str)
|
||||
| ASSH_ERRSV_DISCONNECT);
|
||||
ASSH_ERR_RET(assh_packet_check_string(p, h_str, NULL)
|
||||
| ASSH_ERRSV_DISCONNECT);
|
||||
|
||||
ASSH_ERR_RET(assh_kex_client_get_key(s, &pv->host_key, ks_str, e,
|
||||
&assh_kex_dh_host_key_lookup_done, pv));
|
||||
|
||||
pv->state = ASSH_KEX_DH_CLIENT_LOOKUP_HOST_KEY_WAIT;
|
||||
pv->pck = assh_packet_refinc(p);
|
||||
|
||||
return ASSH_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ASSH_SERVER
|
||||
|
||||
static assh_error_t assh_kex_dh_server_wait_e(struct assh_session_s *s,
|
||||
struct assh_packet_s *p)
|
||||
{
|
||||
struct assh_kex_dh_private_s *pv = s->kex_pv;
|
||||
const struct assh_kex_dh_group_s *gr = pv->group;
|
||||
struct assh_context_s *c = s->ctx;
|
||||
assh_error_t err;
|
||||
|
||||
ASSH_CHK_RET(p->head.msg != SSH_MSG_KEX_DH_REQUEST,
|
||||
ASSH_ERR_PROTOCOL | ASSH_ERRSV_DISCONNECT);
|
||||
|
||||
/* compute DH */
|
||||
uint8_t *e_str = p->head.end;
|
||||
|
||||
ASSH_ERR_RET(assh_packet_check_string(p, e_str, NULL)
|
||||
| ASSH_ERRSV_DISCONNECT);
|
||||
|
||||
size_t l = assh_bignum_size_of_bits(ASSH_BIGNUM_MPINT, gr->size);
|
||||
|
||||
ASSH_SCRATCH_ALLOC(s->ctx, uint8_t, scratch,
|
||||
l + assh_hash_sha1.ctx_size,
|
||||
ASSH_ERRSV_CONTINUE, err_);
|
||||
|
||||
void *hash_ctx = scratch;
|
||||
uint8_t *secret = scratch + assh_hash_sha1.ctx_size;
|
||||
|
||||
ASSH_ERR_GTO(assh_hash_init(s->ctx, hash_ctx, &assh_hash_sha1), err_scratch);
|
||||
|
||||
struct assh_packet_s *pout;
|
||||
const struct assh_key_s *hk;
|
||||
size_t slen;
|
||||
|
||||
ASSH_ERR_GTO(assh_kex_server_hash1(s, l, hash_ctx, &pout,
|
||||
&slen, &hk, SSH_MSG_KEX_DH_REPLY), err_hash);
|
||||
|
||||
uint8_t *f_str;
|
||||
ASSH_ASSERT(assh_packet_add_array(pout, l, &f_str));
|
||||
|
||||
enum bytecode_args_e
|
||||
{
|
||||
G_mpint, P_mpint, E_mpint, F_mpint, K_mpint,
|
||||
X_n, G_n,
|
||||
F, G, P, E, X, K, T, MT
|
||||
};
|
||||
|
||||
static const assh_bignum_op_t bytecode[] = {
|
||||
ASSH_BOP_SIZER( F, T, G_n ),
|
||||
|
||||
ASSH_BOP_MOVE( G, G_mpint ),
|
||||
ASSH_BOP_MOVE( P, P_mpint ),
|
||||
ASSH_BOP_MOVE( E, E_mpint ),
|
||||
|
||||
/* check client public key */
|
||||
ASSH_BOP_UINT( T, 2 ),
|
||||
ASSH_BOP_CMPLTEQ( T, E, 0 /* f >= 2 */ ),
|
||||
ASSH_BOP_SUB( T, P, T ),
|
||||
ASSH_BOP_CMPLTEQ( E, T, 0 /* f <= p-2 */),
|
||||
|
||||
/* FIXME check that log_g(pub) is not trivial */
|
||||
|
||||
/* generate private exponent */
|
||||
ASSH_BOP_UINT( T, DH_MAX_GRSIZE ),
|
||||
ASSH_BOP_RAND( X, T, P,
|
||||
ASSH_PRNG_QUALITY_EPHEMERAL_KEY),
|
||||
|
||||
/* compute dh public key and shared secret */
|
||||
ASSH_BOP_MTINIT( MT, P ),
|
||||
ASSH_BOP_MTTO( G, G, G, MT ),
|
||||
ASSH_BOP_EXPM( F, G, X, MT ),
|
||||
ASSH_BOP_MTFROM( F, F, F, MT ),
|
||||
ASSH_BOP_MTTO( E, E, E, MT ),
|
||||
ASSH_BOP_EXPM( K, E, X, MT ),
|
||||
ASSH_BOP_MTFROM( K, K, K, MT ),
|
||||
|
||||
/* check shared secret range */
|
||||
ASSH_BOP_UINT( T, 2 ),
|
||||
ASSH_BOP_CMPLTEQ( T, K, 0 /* k >= 2 */ ),
|
||||
ASSH_BOP_SUB( T, P, T ),
|
||||
ASSH_BOP_CMPLTEQ( K, T, 0 /* k <= p-2 */),
|
||||
|
||||
ASSH_BOP_MOVE( K_mpint, K ),
|
||||
ASSH_BOP_MOVE( F_mpint, F ),
|
||||
|
||||
ASSH_BOP_END(),
|
||||
};
|
||||
|
||||
ASSH_ERR_GTO(assh_bignum_bytecode(c, bytecode, "MMMMMssTTTTXTTm",
|
||||
gr->generator, gr->prime, e_str, f_str, secret,
|
||||
pv->exp_n, gr->size), err_p);
|
||||
|
||||
assh_packet_string_resized(pout, f_str + 4);
|
||||
|
||||
/* hash both ephemeral public keys */
|
||||
assh_hash_string(hash_ctx, e_str);
|
||||
assh_hash_string(hash_ctx, f_str);
|
||||
|
||||
ASSH_ERR_GTO(assh_kex_server_hash2(s, hash_ctx, pout,
|
||||
slen, hk, secret), err_p);
|
||||
|
||||
assh_transport_push(s, pout);
|
||||
|
||||
ASSH_ERR_GTO(assh_kex_end(s, 1) | ASSH_ERRSV_DISCONNECT, err_hash);
|
||||
|
||||
err = ASSH_OK;
|
||||
goto err_hash;
|
||||
|
||||
err_p:
|
||||
assh_packet_release(pout);
|
||||
err_hash:
|
||||
assh_hash_cleanup(hash_ctx);
|
||||
err_scratch:
|
||||
ASSH_SCRATCH_FREE(c, scratch);
|
||||
err_:
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static ASSH_KEX_PROCESS_FCN(assh_kex_dh_process)
|
||||
{
|
||||
struct assh_kex_dh_private_s *pv = s->kex_pv;
|
||||
assh_error_t err;
|
||||
|
||||
switch (pv->state)
|
||||
{
|
||||
#ifdef CONFIG_ASSH_CLIENT
|
||||
case ASSH_KEX_DH_CLIENT_INIT:
|
||||
assert(p == NULL);
|
||||
ASSH_ERR_RET(assh_kex_dh_client_send_expmod(s)
|
||||
| ASSH_ERRSV_DISCONNECT);
|
||||
return ASSH_OK;
|
||||
|
||||
case ASSH_KEX_DH_CLIENT_WAIT_F:
|
||||
if (p == NULL)
|
||||
return ASSH_OK;
|
||||
ASSH_ERR_RET(assh_kex_dh_client_wait_f(s, p, e)
|
||||
| ASSH_ERRSV_DISCONNECT);
|
||||
return ASSH_OK;
|
||||
|
||||
case ASSH_KEX_DH_CLIENT_LOOKUP_HOST_KEY_WAIT:
|
||||
ASSH_ERR_RET(ASSH_ERR_STATE | ASSH_ERRSV_FATAL);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ASSH_SERVER
|
||||
case ASSH_KEX_DH_SERVER_WAIT_E:
|
||||
if (p == NULL)
|
||||
return ASSH_OK;
|
||||
ASSH_ERR_RET(assh_kex_dh_server_wait_e(s, p)
|
||||
| ASSH_ERRSV_DISCONNECT);
|
||||
return ASSH_OK;
|
||||
#endif
|
||||
}
|
||||
|
||||
abort();
|
||||
}
|
||||
|
||||
static assh_error_t assh_kex_dh_init(struct assh_session_s *s,
|
||||
size_t cipher_key_size,
|
||||
const struct assh_kex_dh_group_s *group)
|
||||
{
|
||||
assh_error_t err;
|
||||
struct assh_kex_dh_private_s *pv;
|
||||
|
||||
size_t exp_n = cipher_key_size * 2;
|
||||
|
||||
/* allocate DH private context */
|
||||
ASSH_ERR_RET(assh_alloc(s->ctx, sizeof(*pv), ASSH_ALLOC_INTERNAL, (void**)&pv)
|
||||
| ASSH_ERRSV_DISCONNECT);
|
||||
|
||||
switch (s->ctx->type)
|
||||
{
|
||||
#ifdef CONFIG_ASSH_CLIENT
|
||||
case ASSH_CLIENT: {
|
||||
pv->state = ASSH_KEX_DH_CLIENT_INIT;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#ifdef CONFIG_ASSH_SERVER
|
||||
case ASSH_SERVER:
|
||||
pv->state = ASSH_KEX_DH_SERVER_WAIT_E;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
||||
s->kex_pv = pv;
|
||||
pv->group = group;
|
||||
|
||||
switch (s->ctx->type)
|
||||
{
|
||||
#ifdef CONFIG_ASSH_CLIENT
|
||||
case ASSH_CLIENT:
|
||||
assh_bignum_init(s->ctx, &pv->en, group->size, 0);
|
||||
assh_bignum_init(s->ctx, &pv->xn, exp_n, 1);
|
||||
pv->host_key = NULL;
|
||||
pv->pck = NULL;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ASSH_SERVER
|
||||
case ASSH_SERVER:
|
||||
pv->exp_n = exp_n;
|
||||
break;
|
||||
#endif
|
||||
default:;
|
||||
}
|
||||
|
||||
return ASSH_OK;
|
||||
}
|
||||
|
||||
static ASSH_KEX_CLEANUP_FCN(assh_kex_dh_cleanup)
|
||||
{
|
||||
struct assh_kex_dh_private_s *pv = s->kex_pv;
|
||||
struct assh_context_s *c = s->ctx;
|
||||
|
||||
switch (c->type)
|
||||
{
|
||||
#ifdef CONFIG_ASSH_CLIENT
|
||||
case ASSH_CLIENT:
|
||||
assh_bignum_release(c, &pv->en);
|
||||
assh_bignum_release(c, &pv->xn);
|
||||
assh_key_flush(s->ctx, &pv->host_key);
|
||||
assh_packet_release(pv->pck);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ASSH_SERVER
|
||||
case ASSH_SERVER:
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
||||
assh_free(c, s->kex_pv);
|
||||
s->kex_pv = NULL;
|
||||
}
|
||||
|
||||
static ASSH_KEX_INIT_FCN(assh_kex_dh_group1_sha1_init)
|
||||
{
|
||||
static const struct assh_kex_dh_group_s group =
|
||||
{
|
||||
.size = 1024,
|
||||
.generator = (const uint8_t*)"\x00\x00\x00\x01\x02",
|
||||
.prime = (const uint8_t*)"\x00\x00\x00\x81"
|
||||
"\x00\xff\xff\xff\xff\xff\xff\xff\xff\xc9\x0f\xda\xa2\x21\x68\xc2\x34"
|
||||
"\xc4\xc6\x62\x8b\x80\xdc\x1c\xd1\x29\x02\x4e\x08\x8a\x67\xcc\x74"
|
||||
"\x02\x0b\xbe\xa6\x3b\x13\x9b\x22\x51\x4a\x08\x79\x8e\x34\x04\xdd"
|
||||
"\xef\x95\x19\xb3\xcd\x3a\x43\x1b\x30\x2b\x0a\x6d\xf2\x5f\x14\x37"
|
||||
"\x4f\xe1\x35\x6d\x6d\x51\xc2\x45\xe4\x85\xb5\x76\x62\x5e\x7e\xc6"
|
||||
"\xf4\x4c\x42\xe9\xa6\x37\xed\x6b\x0b\xff\x5c\xb6\xf4\x06\xb7\xed"
|
||||
"\xee\x38\x6b\xfb\x5a\x89\x9f\xa5\xae\x9f\x24\x11\x7c\x4b\x1f\xe6"
|
||||
"\x49\x28\x66\x51\xec\xe6\x53\x81\xff\xff\xff\xff\xff\xff\xff\xff"
|
||||
};
|
||||
|
||||
return assh_kex_dh_init(s, cipher_key_size, &group);
|
||||
}
|
||||
|
||||
const struct assh_algo_kex_s assh_kex_dh_group1_sha1 =
|
||||
{
|
||||
.algo = { .name = "diffie-hellman-group1-sha1",
|
||||
.class_ = ASSH_ALGO_KEX, .safety = 10, .speed = 40 },
|
||||
.f_init = assh_kex_dh_group1_sha1_init,
|
||||
.f_cleanup = assh_kex_dh_cleanup,
|
||||
.f_process = assh_kex_dh_process,
|
||||
};
|
||||
|
||||
static ASSH_KEX_INIT_FCN(assh_kex_dh_group14_sha1_init)
|
||||
{
|
||||
static const struct assh_kex_dh_group_s group =
|
||||
{
|
||||
.size = 2048,
|
||||
.generator = (const uint8_t*)"\x00\x00\x00\x01\x02",
|
||||
.prime = (const uint8_t*)"\x00\x00\x01\x01"
|
||||
"\x00\xff\xff\xff\xff\xff\xff\xff\xff\xc9\x0f\xda\xa2\x21\x68\xc2\x34"
|
||||
"\xc4\xc6\x62\x8b\x80\xdc\x1c\xd1\x29\x02\x4e\x08\x8a\x67\xcc\x74"
|
||||
"\x02\x0b\xbe\xa6\x3b\x13\x9b\x22\x51\x4a\x08\x79\x8e\x34\x04\xdd"
|
||||
"\xef\x95\x19\xb3\xcd\x3a\x43\x1b\x30\x2b\x0a\x6d\xf2\x5f\x14\x37"
|
||||
"\x4f\xe1\x35\x6d\x6d\x51\xc2\x45\xe4\x85\xb5\x76\x62\x5e\x7e\xc6"
|
||||
"\xf4\x4c\x42\xe9\xa6\x37\xed\x6b\x0b\xff\x5c\xb6\xf4\x06\xb7\xed"
|
||||
"\xee\x38\x6b\xfb\x5a\x89\x9f\xa5\xae\x9f\x24\x11\x7c\x4b\x1f\xe6"
|
||||
"\x49\x28\x66\x51\xec\xe4\x5b\x3d\xc2\x00\x7c\xb8\xa1\x63\xbf\x05"
|
||||
"\x98\xda\x48\x36\x1c\x55\xd3\x9a\x69\x16\x3f\xa8\xfd\x24\xcf\x5f"
|
||||
"\x83\x65\x5d\x23\xdc\xa3\xad\x96\x1c\x62\xf3\x56\x20\x85\x52\xbb"
|
||||
"\x9e\xd5\x29\x07\x70\x96\x96\x6d\x67\x0c\x35\x4e\x4a\xbc\x98\x04"
|
||||
"\xf1\x74\x6c\x08\xca\x18\x21\x7c\x32\x90\x5e\x46\x2e\x36\xce\x3b"
|
||||
"\xe3\x9e\x77\x2c\x18\x0e\x86\x03\x9b\x27\x83\xa2\xec\x07\xa2\x8f"
|
||||
"\xb5\xc5\x5d\xf0\x6f\x4c\x52\xc9\xde\x2b\xcb\xf6\x95\x58\x17\x18"
|
||||
"\x39\x95\x49\x7c\xea\x95\x6a\xe5\x15\xd2\x26\x18\x98\xfa\x05\x10"
|
||||
"\x15\x72\x8e\x5a\x8a\xac\xaa\x68\xff\xff\xff\xff\xff\xff\xff\xff"
|
||||
};
|
||||
|
||||
return assh_kex_dh_init(s, cipher_key_size, &group);
|
||||
}
|
||||
|
||||
const struct assh_algo_kex_s assh_kex_dh_group14_sha1 =
|
||||
{
|
||||
.algo = { .name = "diffie-hellman-group14-sha1",
|
||||
.class_ = ASSH_ALGO_KEX, .safety = 20, .speed = 30 },
|
||||
.f_init = assh_kex_dh_group14_sha1_init,
|
||||
.f_cleanup = assh_kex_dh_cleanup,
|
||||
.f_process = assh_kex_dh_process,
|
||||
};
|
||||
|
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue