Compare commits

...

5 Commits

Author SHA1 Message Date
Cedric BAIL 1649ad765c ecore_con: first initial addition of Ecore_Con_Ssh object. 2015-04-26 17:20:23 +02:00
Cedric BAIL a0111289ba gitignore: ignore assh generated files. 2015-04-26 16:43:43 +02:00
Cedric BAIL 161831a77a assh: another update. 2015-04-26 10:03:24 +02:00
Cedric BAIL d80958648b assh: update with latest assh version. 2015-04-26 10:03:24 +02:00
Cedric BAIL c39786bd95 assh: add libassh following the same pattern as liblz4.
libassh is a library that provide a ssh implementation designed to be
integrated into a UI toolkit. It is based on a state machine with callbacks.
This will be the basis of an Ecore_Con_Ssh that can be used for shared
configuration for a user or make terminology a ssh client.
2015-04-26 10:03:24 +02:00
128 changed files with 71269 additions and 3 deletions

View File

@ -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):

View File

@ -24,6 +24,9 @@ check_PROGRAMS =
TESTS =
EXTRA_DIST =
if ! ENABLE_LIBASSH
SUBDIRS += static_libs/assh
endif
EFL_INSTALL_EXEC_HOOK=

View File

@ -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

View File

@ -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

View File

@ -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"

View File

@ -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;
}
}

View File

@ -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 *;
}
}
}

View File

@ -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;
}
}

9
src/static_libs/assh/.gitignore vendored Normal file
View File

@ -0,0 +1,9 @@
/INSTALL
/assh.pc
/autom4te.cache/
/config.status
/libtool
/stamp-h1
/config.h

View File

@ -0,0 +1,3 @@
Alexandre Becoulet <alexandre.becoulet@free.fr>.

View File

@ -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!

View File

View File

@ -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

View File

View File

1157
src/static_libs/assh/aclocal.m4 vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -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/

View File

@ -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:

1421
src/static_libs/assh/build/config.guess vendored Executable file

File diff suppressed because it is too large Load Diff

1807
src/static_libs/assh/build/config.sub vendored Executable file

File diff suppressed because it is too large Load Diff

View File

@ -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:

View File

@ -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

View File

@ -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:

View File

@ -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

14796
src/static_libs/assh/configure vendored Executable file

File diff suppressed because it is too large Load Diff

View File

@ -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
])

View File

@ -0,0 +1,3 @@
/client
/keygen
/server

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

8369
src/static_libs/assh/m4/libtool.m4 vendored Normal file

File diff suppressed because it is too large Load Diff

437
src/static_libs/assh/m4/ltoptions.m4 vendored Normal file
View File

@ -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])])

124
src/static_libs/assh/m4/ltsugar.m4 vendored Normal file
View File

@ -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
])

23
src/static_libs/assh/m4/ltversion.m4 vendored Normal file
View File

@ -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)
])

99
src/static_libs/assh/m4/lt~obsolete.m4 vendored Normal file
View File

@ -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])])

View File

@ -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

View File

@ -0,0 +1 @@
/assh_config.h

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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];
}
}

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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,
};

View File

@ -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,
};

View File

@ -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,
};

View File

@ -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);

View File

@ -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,
};

View File

@ -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,
};

View File

@ -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);

View File

@ -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,
};

View File

@ -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,
};

View File

@ -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,
};

View File

@ -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,
};

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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