mirror of
https://github.com/libssh2/libssh2.git
synced 2025-08-08 19:02:07 +03:00
Merge remote-tracking branch 'upstream/master' into shellfish
# Conflicts: # buildconf # configure.ac # include/libssh2.h
This commit is contained in:
4
.github/stale.yml
vendored
4
.github/stale.yml
vendored
@@ -1,7 +1,7 @@
|
||||
# Number of days of inactivity before an issue becomes stale
|
||||
daysUntilStale: 90
|
||||
daysUntilStale: 120
|
||||
# Number of days of inactivity before a stale issue is closed
|
||||
daysUntilClose: 21
|
||||
daysUntilClose: 30
|
||||
# Issues with these labels will never be considered stale
|
||||
exemptLabels:
|
||||
- pinned
|
||||
|
67
.github/workflows/appveyor.yml
vendored
Normal file
67
.github/workflows/appveyor.yml
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
# Copyright (c) 2021 Marc Hoersken
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice, this
|
||||
# list of conditions and the following disclaimer.
|
||||
#
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
name: AppVeyor Docker Bridge
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
ssh_host:
|
||||
required: true
|
||||
ssh_port:
|
||||
required: true
|
||||
ssh_user:
|
||||
required: true
|
||||
ssh_forward:
|
||||
required: true
|
||||
ssh_hostkey:
|
||||
required: true
|
||||
ssh_privkey:
|
||||
required: true
|
||||
|
||||
jobs:
|
||||
daemon:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 60
|
||||
steps:
|
||||
- name: Setup SSH client configuration
|
||||
run: |
|
||||
cd ~
|
||||
mkdir .ssh
|
||||
chmod 0700 .ssh
|
||||
echo "ServerAliveInterval 45" > .ssh/config
|
||||
echo "Host ${{ github.event.inputs.ssh_host }}" >> .ssh/config
|
||||
echo "${{ github.event.inputs.ssh_forward }}" | sed 's/,/\n/g' | sed 's/^/\tRemoteForward /g' >> .ssh/config
|
||||
chmod 0600 .ssh/config
|
||||
cat .ssh/config
|
||||
echo "${{ github.event.inputs.ssh_host }} ${{ github.event.inputs.ssh_hostkey }}" | sed 's/,/\n${{ github.event.inputs.ssh_host }} /g' > .ssh/known_hosts
|
||||
chmod 0600 .ssh/known_hosts
|
||||
cat .ssh/known_hosts
|
||||
echo "${{ github.event.inputs.ssh_privkey }}" | sed 's/,/\n/g' > .ssh/id_rsa
|
||||
chmod 0600 .ssh/id_rsa
|
||||
|
||||
# we sleep explicitly to allow the remote system to kill the sleep process
|
||||
- name: Connect to AppVeyor and sleep
|
||||
run: |
|
||||
ssh -v -p ${{ github.event.inputs.ssh_port }} ${{ github.event.inputs.ssh_user }}@${{ github.event.inputs.ssh_host }} sleep 1h
|
105
.github/workflows/ci.yml
vendored
Normal file
105
.github/workflows/ci.yml
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
jobs:
|
||||
style-check:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Check Style
|
||||
run: ./ci/checksrc.sh
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
compiler: [gcc, clang]
|
||||
address_size: [64]
|
||||
crypto_backend: [OpenSSL, Libgcrypt, mbedTLS]
|
||||
build_shared_libs: [OFF, ON]
|
||||
enable_zlib_compression: [OFF, ON]
|
||||
b: [cmake]
|
||||
include:
|
||||
- compiler: gcc
|
||||
address_size: 64
|
||||
crypto_backend: OpenSSL
|
||||
build_shared_libs: OFF
|
||||
enable_zlib_compression: OFF
|
||||
b: configure
|
||||
- compiler: clang
|
||||
address_size: 64
|
||||
crypto_backend: OpenSSL
|
||||
build_shared_libs: OFF
|
||||
enable_zlib_compression: OFF
|
||||
b: configure
|
||||
env:
|
||||
CC: ${{ matrix.compiler }}
|
||||
CC_FOR_BUILD: ${{ matrix.compiler }}
|
||||
CRYPTO_BACKEND: ${{ matrix.crypto_backend }}
|
||||
BUILD_SHARED_LIBS: ${{ matrix.build_shared_libs }}
|
||||
ENABLE_ZLIB_COMPRESSION: ${{ matrix.enable_zlib_compression }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install 32 Bit Dependencies
|
||||
if: ${{ matrix.address_size == 32 }}
|
||||
run: |
|
||||
sudo dpkg --add-architecture i386
|
||||
sudo apt-get update -qq
|
||||
sudo apt-get install -y gcc-multilib
|
||||
sudo apt-get install -y libssl-dev:i386 libgcrypt20-dev:i386 zlib1g-dev:i386 build-essential gcc-multilib
|
||||
sudo dpkg --purge --force-depends gcc-multilib
|
||||
sudo dpkg --purge --force-depends libssl-dev
|
||||
echo "TOOLCHAIN_OPTION=-DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchain-Linux-32.cmake" >> $GITHUB_ENV
|
||||
- name: Install 64 Bit Dependencies
|
||||
if: ${{ matrix.address_size == 64 }}
|
||||
run: |
|
||||
sudo apt-get install -y libssl-dev
|
||||
sudo apt-get install -y libgcrypt-dev
|
||||
- name: Install mbedTLS Dependencies
|
||||
if: ${{ matrix.crypto_backend == 'mbedTLS' }}
|
||||
run: |
|
||||
MBEDTLSVER=mbedtls-2.7.0
|
||||
curl -L https://github.com/ARMmbed/mbedtls/archive/$MBEDTLSVER.tar.gz | tar -xzf -
|
||||
cd mbedtls-$MBEDTLSVER
|
||||
cmake $TOOLCHAIN_OPTION -DUSE_SHARED_MBEDTLS_LIBRARY=ON -DCMAKE_INSTALL_PREFIX:PATH=../usr .
|
||||
make -j3 install
|
||||
cd ..
|
||||
echo "LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD/usr/lib" >> $GITHUB_ENV
|
||||
echo "TOOLCHAIN_OPTION=$TOOLCHAIN_OPTION -DCMAKE_PREFIX_PATH=$PWD/usr" >> $GITHUB_ENV
|
||||
- name: Build with Configure
|
||||
if: ${{ matrix.b == 'configure' }}
|
||||
run: |
|
||||
autoreconf -fi
|
||||
./configure --enable-debug --enable-werror
|
||||
make
|
||||
make check
|
||||
- name: Build with CMake
|
||||
if: ${{ matrix.b == 'cmake' }}
|
||||
run: |
|
||||
mkdir bin
|
||||
cd bin
|
||||
cmake $TOOLCHAIN_OPTION -DCRYPTO_BACKEND=$CRYPTO_BACKEND -DBUILD_SHARED_LIBS=$BUILD_SHARED_LIBS -DENABLE_ZLIB_COMPRESSION=$ENABLE_ZLIB_COMPRESSION ..
|
||||
cmake --build .
|
||||
pushd ../tests
|
||||
docker build -t libssh2/openssh_server openssh_server
|
||||
popd
|
||||
CTEST_OUTPUT_ON_FAILURE=1 cmake --build . --target test
|
||||
cmake --build . --target package
|
||||
fuzzer:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
compiler: [gcc, clang]
|
||||
env:
|
||||
CC: ${{ matrix.compiler }}
|
||||
CC_FOR_BUILD: ${{ matrix.compiler }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Run Fuzzer
|
||||
run: GIT_REF=$GITHUB_REF ./ci/ossfuzz.sh
|
1
.gitignore
vendored
1
.gitignore
vendored
@@ -35,3 +35,4 @@ tags
|
||||
libssh2.pc
|
||||
TAGS
|
||||
*~
|
||||
.DS_Store
|
||||
|
21
.travis.yml
21
.travis.yml
@@ -46,10 +46,12 @@ compiler:
|
||||
|
||||
addons:
|
||||
chrome: stable
|
||||
matrix:
|
||||
include:
|
||||
- name: "Check style"
|
||||
script: ./ci/checksrc.sh
|
||||
|
||||
env:
|
||||
matrix:
|
||||
- B=style
|
||||
- ADDRESS_SIZE=64 CRYPTO_BACKEND=OpenSSL BUILD_SHARED_LIBS=OFF ENABLE_ZLIB_COMPRESSION=OFF B=configure
|
||||
- ADDRESS_SIZE=64 CRYPTO_BACKEND=OpenSSL BUILD_SHARED_LIBS=OFF ENABLE_ZLIB_COMPRESSION=OFF B=cmake
|
||||
- ADDRESS_SIZE=64 CRYPTO_BACKEND=OpenSSL BUILD_SHARED_LIBS=ON ENABLE_ZLIB_COMPRESSION=OFF B=cmake
|
||||
@@ -75,6 +77,7 @@ env:
|
||||
- ADDRESS_SIZE=32 CRYPTO_BACKEND=mbedTLS BUILD_SHARED_LIBS=ON ENABLE_ZLIB_COMPRESSION=OFF B=cmake
|
||||
- ADDRESS_SIZE=32 CRYPTO_BACKEND=mbedTLS BUILD_SHARED_LIBS=OFF ENABLE_ZLIB_COMPRESSION=ON B=cmake
|
||||
- ADDRESS_SIZE=32 CRYPTO_BACKEND=mbedTLS BUILD_SHARED_LIBS=ON ENABLE_ZLIB_COMPRESSION=ON B=cmake
|
||||
- B=fuzzer
|
||||
|
||||
before_install:
|
||||
- if [ $ADDRESS_SIZE = '32' ]; then sudo dpkg --add-architecture i386; fi
|
||||
@@ -86,7 +89,7 @@ before_install:
|
||||
- if [ $ADDRESS_SIZE = '64' ]; then sudo apt-get install -y libgcrypt11-dev; fi
|
||||
- if [ $ADDRESS_SIZE = '32' ]; then export TOOLCHAIN_OPTION="-DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchain-Linux-32.cmake"; fi
|
||||
- if [ $CRYPTO_BACKEND = 'mbedTLS' ]; then
|
||||
MBEDTLSVER=mbedtls-2.4.0;
|
||||
MBEDTLSVER=mbedtls-2.7.0;
|
||||
curl -L https://github.com/ARMmbed/mbedtls/archive/$MBEDTLSVER.tar.gz | tar -xzf -;
|
||||
cd mbedtls-$MBEDTLSVER;
|
||||
cmake $TOOLCHAIN_OPTION -DUSE_SHARED_MBEDTLS_LIBRARY=ON -DCMAKE_INSTALL_PREFIX:PATH=../usr .;
|
||||
@@ -99,10 +102,6 @@ before_install:
|
||||
install:
|
||||
|
||||
script:
|
||||
- |
|
||||
if [ "$B" = "style" ]; then
|
||||
perl src/checksrc.pl -i4 -m79 -ASIZEOFNOPAREN -ASNPRINTF -ACOPYRIGHT -AFOPENMODE -Wsrc/libssh2_config.h src/*.[ch] include/*.h example/*.c
|
||||
fi
|
||||
- |
|
||||
if [ "$B" = "configure" ]; then
|
||||
autoreconf -fi
|
||||
@@ -113,9 +112,15 @@ script:
|
||||
- |
|
||||
if [ "$B" = "cmake" ]; then
|
||||
mkdir bin
|
||||
cd bin
|
||||
cd tests
|
||||
docker build -t libssh2/openssh_server openssh_server
|
||||
cd ../bin
|
||||
cmake $TOOLCHAIN_OPTION -DCRYPTO_BACKEND=$CRYPTO_BACKEND -DBUILD_SHARED_LIBS=$BUILD_SHARED_LIBS -DENABLE_ZLIB_COMPRESSION=$ENABLE_ZLIB_COMPRESSION .. && cmake --build . && CTEST_OUTPUT_ON_FAILURE=1 cmake --build . --target test && cmake --build . --target package
|
||||
fi
|
||||
- |
|
||||
if [ "$B" = "fuzzer" ]; then
|
||||
GIT_REF=$TRAVIS_COMMIT ./ci/ossfuzz.sh
|
||||
fi
|
||||
|
||||
# whitelist branches to avoid testing feature branches twice (as branch and as pull request)
|
||||
branches:
|
||||
|
@@ -98,6 +98,14 @@ if(BUILD_TESTING)
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
|
||||
option(LINT "Check style while building" OFF)
|
||||
if(LINT)
|
||||
add_custom_target(lint ALL
|
||||
./ci/checksrc.sh
|
||||
WORKING_DIRECTORY ${libssh2_SOURCE_DIR})
|
||||
add_dependencies(libssh2 lint)
|
||||
endif()
|
||||
|
||||
add_subdirectory(docs)
|
||||
|
||||
feature_summary(WHAT ALL)
|
||||
|
4
COPYING
4
COPYING
@@ -2,8 +2,10 @@
|
||||
* Copyright (c) 2005,2006 Mikhail Gusarov <dottedmag@dottedmag.net>
|
||||
* Copyright (c) 2006-2007 The Written Word, Inc.
|
||||
* Copyright (c) 2007 Eli Fant <elifantu@mail.ru>
|
||||
* Copyright (c) 2009-2019 Daniel Stenberg
|
||||
* Copyright (c) 2009-2021 Daniel Stenberg
|
||||
* Copyright (C) 2008, 2009 Simon Josefsson
|
||||
* Copyright (c) 2000 Markus Friedl
|
||||
* Copyright (c) 2015 Microsoft Corp.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
|
@@ -119,7 +119,7 @@ $(DSP): win32/msvcproj.head win32/msvcproj.foot Makefile.am
|
||||
for file in $$sorted_hdrs; do \
|
||||
echo "# Begin Source File"; \
|
||||
echo ""; \
|
||||
if [ "$$file" == "libssh2_config.h" ]; \
|
||||
if [ "$$file" = "libssh2_config.h" ]; \
|
||||
then \
|
||||
echo "SOURCE=.\\"$$file; \
|
||||
else \
|
||||
@@ -149,4 +149,6 @@ $(VCPROJ): win32/vc8proj.head win32/vc8proj.foot Makefile.am
|
||||
awk '{printf("%s\r\n", gensub("\r", "", "g"))}' > $@ )
|
||||
|
||||
checksrc:
|
||||
perl src/checksrc.pl -i4 -m79 -ASIZEOFNOPAREN -ASNPRINTF -ACOPYRIGHT -AFOPENMODE -Wsrc/libssh2_config.h src/*.[ch] include/*.h example/*.c
|
||||
perl src/checksrc.pl -i4 -m79 -ASIZEOFNOPAREN -ASNPRINTF -ACOPYRIGHT \
|
||||
-AFOPENMODE -Wsrc/libssh2_config.h src/*.[ch] include/*.h example/*.c \
|
||||
tests/*.[ch]
|
||||
|
@@ -1,7 +1,7 @@
|
||||
CSOURCES = channel.c comp.c crypt.c hostkey.c kex.c mac.c misc.c \
|
||||
packet.c publickey.c scp.c session.c sftp.c userauth.c transport.c \
|
||||
version.c knownhost.c agent.c $(CRYPTO_CSOURCES) pem.c keepalive.c global.c \
|
||||
blowfish.c bcrypt_pbkdf.c
|
||||
blowfish.c bcrypt_pbkdf.c agent_win.c
|
||||
|
||||
HHEADERS = libssh2_priv.h $(CRYPTO_HHEADERS) transport.h channel.h comp.h \
|
||||
mac.h misc.h packet.h userauth.h session.h sftp.h crypto.h blf.h
|
||||
mac.h misc.h packet.h userauth.h session.h sftp.h crypto.h blf.h agent.h
|
||||
|
2
README
2
README
@@ -6,7 +6,7 @@ the revised BSD license.
|
||||
|
||||
Web site: https://www.libssh2.org/
|
||||
|
||||
Mailing list: https://cool.haxx.se/mailman/listinfo/libssh2-devel
|
||||
Mailing list: https://lists.haxx.se/listinfo/libssh2-devel
|
||||
|
||||
License: see COPYING
|
||||
|
||||
|
@@ -5,12 +5,12 @@ the revised BSD license.
|
||||
|
||||
[Web site](https://www.libssh2.org/)
|
||||
|
||||
[Mailing list](https://cool.haxx.se/mailman/listinfo/libssh2-devel)
|
||||
[Mailing list](https://lists.haxx.se/listinfo/libssh2-devel)
|
||||
|
||||
[BSD Licensed](https://libssh2.org/license.html)
|
||||
[BSD Licensed](https://www.libssh2.org/license.html)
|
||||
|
||||
[Web site source code](https://github.com/libssh2/www)
|
||||
|
||||
Installation instructions:
|
||||
- [for CMake](docs/INSTALL_CMAKE)
|
||||
- [for CMake](docs/INSTALL_CMAKE.md)
|
||||
- [for autotools](docs/INSTALL_AUTOTOOLS)
|
||||
|
@@ -1,44 +1,62 @@
|
||||
libssh2 1.9.0
|
||||
libssh2 1.10
|
||||
|
||||
This release includes the following enhancements and bugfixes:
|
||||
|
||||
o adds ECDSA keys and host key support when using OpenSSL
|
||||
o adds ED25519 key and host key support when using OpenSSL 1.1.1
|
||||
o adds OpenSSH style key file reading
|
||||
o adds AES CTR mode support when using WinCNG
|
||||
o adds PEM passphrase protected file support for Libgcrypt and WinCNG
|
||||
o adds SHA256 hostkey fingerprint
|
||||
o adds libssh2_agent_get_identity_path() and libssh2_agent_set_identity_path()
|
||||
o adds explicit zeroing of sensitive data in memory
|
||||
o adds additional bounds checks to network buffer reads
|
||||
o adds the ability to use the server default permissions when creating sftp directories
|
||||
o adds support for building with OpenSSL no engine flag
|
||||
o adds support for building with LibreSSL
|
||||
o increased sftp packet size to 256k
|
||||
o fixed oversized packet handling in sftp
|
||||
o fixed building with OpenSSL 1.1
|
||||
o fixed a possible crash if sftp stat gets an unexpected response
|
||||
o fixed incorrect parsing of the KEX preference string value
|
||||
o fixed conditional RSA and AES-CTR support
|
||||
o fixed a small memory leak during the key exchange process
|
||||
o fixed a possible memory leak of the ssh banner string
|
||||
o fixed various small memory leaks in the backends
|
||||
o fixed possible out of bounds read when parsing public keys from the server
|
||||
o fixed possible out of bounds read when parsing invalid PEM files
|
||||
o no longer null terminates the scp remote exec command
|
||||
o now handle errors when diffie hellman key pair generation fails
|
||||
o fixed compiling on Windows with the flag STDCALL=ON
|
||||
o improved building instructions
|
||||
o adds agent forwarding support
|
||||
o adds OpenSSH Agent support on Windows
|
||||
o adds ECDSA key support using the Mbed TLS backend
|
||||
o adds ECDSA cert authentication
|
||||
o adds diffie-hellman-group14-sha256, diffie-hellman-group16-sha512,
|
||||
diffie-hellman-group18-sha512 key exchanges
|
||||
o adds support for PKIX key reading when using ed25519 with OpenSSL
|
||||
o adds support for EWOULDBLOCK on VMS systems
|
||||
o adds support for building with OpenSSL 3
|
||||
o adds support for using FIPS mode in OpenSSL
|
||||
o adds debug symbols when building with MSVC
|
||||
o adds support for building on the 3DS
|
||||
o adds unicode build support on Windows
|
||||
o restores os400 building
|
||||
o increases min, max and opt Diffie Hellman group values
|
||||
o improves portiablity of the make file
|
||||
o improves timeout behavior with 2FA keyboard auth
|
||||
o various improvements to the Wincng backend
|
||||
o fixes reading parital packet replies when using an agent
|
||||
o fixes Diffie Hellman key exchange on Windows 1903+ builds
|
||||
o fixes building tests with older versions of OpenSSL
|
||||
o fixes possible multiple definition warnings
|
||||
o fixes potential cast issues _libssh2_ecdsa_key_get_curve_type()
|
||||
o fixes potential use after free if libssh2_init() is called twice
|
||||
o improved linking when using Mbed TLS
|
||||
o fixes call to libssh2_crypto_exit() if crypto hasn't been initialized
|
||||
o fixes crash when loading public keys with no id
|
||||
o fixes possible out of bounds read when exchanging keys
|
||||
o fixes possible out of bounds read when reading packets
|
||||
o fixes possible out of bounds read when opening an X11 connection
|
||||
o fixes possible out of bounds read when ecdh host keys
|
||||
o fixes possible hang when trying to read a disconnected socket
|
||||
o fixes a crash when using the delayed compression option
|
||||
o fixes read error with large known host entries
|
||||
o fixes various warnings
|
||||
o fixes various small memory leaks
|
||||
o improved error handling, various detailed errors will now be reported
|
||||
o builds are now using OSS-Fuzz
|
||||
o builds now use autoreconf instead of a custom build script
|
||||
o cmake now respects install directory
|
||||
o improved CI backend
|
||||
o updated HACKING-CRYPTO documentation
|
||||
o use markdown file extensions
|
||||
o improved unit tests
|
||||
|
||||
This release would not have looked like this without help, code, reports and
|
||||
advice from friends like these:
|
||||
|
||||
Peter Surge, Will Cosgrove, Daniel Stenberg, Alex Arslan, Alex Crichton,
|
||||
Thomas Bleeker, Keno Fischer, Marc Hörsken, Marcel Raad, Viktor Szakats,
|
||||
Kamil Dudka, Panos, Etienne Samson, Tseng Jun, Brendan Shanks, doublex,
|
||||
Erik B, Jakob Egger, Thomas Lochmatter, alex-weaver, Adrian Moran, Zenju,
|
||||
gartens, Matthew D. Fuller, Ryan Kelley, Zhen-Huan HWANG, Orivej Desh,
|
||||
Alexander Curtiss
|
||||
katzer, Orgad Shaneh, mark-i-m, Zenju, axjowa, Thilo Schulz,
|
||||
Etienne Samson, hlefebvre, seba30, Panos, jethrogb, Fabrice Fontaine,
|
||||
Will Cosgrove, Daniel Stenberg, Michael Buckley, Wallace Souza Silva,
|
||||
Romain-Geissler-1A, meierha, Tseng Jun, Thomas Klausner, Brendan Shanks,
|
||||
Harry Sintonen, monnerat, Koutheir Attouchi, Marc Hörsken, yann-morin-1998,
|
||||
Wez Furlong, TDi-jonesds, David Benjamin, Max Dymond, Igor Klevanets,
|
||||
Viktor Szakats, Laurent Stacul, Mstrodl, Gabriel Smith, MarcT512,
|
||||
Paul Capron, teottin, Tor Erik Ottinsen, Brian Inglis
|
||||
|
||||
(29 contributors)
|
||||
(40 contributors)
|
||||
|
61
appveyor.yml
61
appveyor.yml
@@ -1,5 +1,6 @@
|
||||
# Copyright (c) 2014, Ruslan Baratov
|
||||
# Copyright (c) 2014, 2016 Alexander Lamaison
|
||||
# Copyright (c) 2020, 2021 Marc Hoersken
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
@@ -29,18 +30,35 @@ environment:
|
||||
matrix:
|
||||
- GENERATOR: "Visual Studio 14 2015"
|
||||
BUILD_SHARED_LIBS: ON
|
||||
CRYPTO_BACKEND: "OpenSSL"
|
||||
|
||||
- GENERATOR: "Visual Studio 14 2015"
|
||||
BUILD_SHARED_LIBS: OFF
|
||||
CRYPTO_BACKEND: "OpenSSL"
|
||||
|
||||
- GENERATOR: "Visual Studio 12 2013"
|
||||
BUILD_SHARED_LIBS: ON
|
||||
CRYPTO_BACKEND: "OpenSSL"
|
||||
|
||||
- GENERATOR: "Visual Studio 12 2013"
|
||||
BUILD_SHARED_LIBS: OFF
|
||||
CRYPTO_BACKEND: "OpenSSL"
|
||||
|
||||
digitalocean_access_token:
|
||||
secure: 8qRitvrj69Xhf0Tmu27xnz5drmL2YhmOJLGpXIkYyTCC0JNtBoXW6fMcF3u4Uj1+pIQ+TjegQOwYimlz0oivKTro3v3EXro+osAMNJG6NKc=
|
||||
- GENERATOR: "Visual Studio 14 2015"
|
||||
BUILD_SHARED_LIBS: ON
|
||||
CRYPTO_BACKEND: "WinCNG"
|
||||
|
||||
- GENERATOR: "Visual Studio 14 2015"
|
||||
BUILD_SHARED_LIBS: OFF
|
||||
CRYPTO_BACKEND: "WinCNG"
|
||||
|
||||
- GENERATOR: "Visual Studio 12 2013"
|
||||
BUILD_SHARED_LIBS: ON
|
||||
CRYPTO_BACKEND: "WinCNG"
|
||||
|
||||
- GENERATOR: "Visual Studio 12 2013"
|
||||
BUILD_SHARED_LIBS: OFF
|
||||
CRYPTO_BACKEND: "WinCNG"
|
||||
|
||||
platform:
|
||||
- x86
|
||||
@@ -57,32 +75,47 @@ matrix:
|
||||
platform: x64
|
||||
|
||||
install:
|
||||
- choco install -y docker
|
||||
- choco install -y docker-machine
|
||||
# prepare local SSH server for reverse tunneling from GitHub Actions hosting our docker container
|
||||
- ps: |
|
||||
$env:OPENSSH_SERVER_PORT = Get-Random -Minimum 2000 -Maximum 2300
|
||||
[System.Environment]::SetEnvironmentVariable("OPENSSH_SERVER_PORT", $env:OPENSSH_SERVER_PORT)
|
||||
- ps: .\ci\appveyor\docker-bridge.ps1
|
||||
- choco install -y docker-cli
|
||||
|
||||
build_script:
|
||||
- ps: if($env:PLATFORM -eq "x64") { $env:CMAKE_GEN_SUFFIX=" Win64" }
|
||||
- cmake "-G%GENERATOR%%CMAKE_GEN_SUFFIX%" -DBUILD_SHARED_LIBS=%BUILD_SHARED_LIBS% -H. -B_builds
|
||||
- cmake "-G%GENERATOR%%CMAKE_GEN_SUFFIX%" -DBUILD_SHARED_LIBS=%BUILD_SHARED_LIBS% -DCRYPTO_BACKEND=%CRYPTO_BACKEND% -H. -B_builds
|
||||
- cmake --build _builds --config "%CONFIGURATION%"
|
||||
|
||||
before_test:
|
||||
- set DOCKER_MACHINE_NAME=appveyor-%APPVEYOR_PROJECT_SLUG%-%APPVEYOR_JOB_ID%
|
||||
- ps: if($env:digitalocean_access_token) { echo "Using DigitalOcean for testing." } else { echo "DigitalOcean not available. Skipping testing." }
|
||||
- ps: if($env:digitalocean_access_token) { docker-machine create --driver digitalocean --digitalocean-access-token $($env:digitalocean_access_token) $($env:DOCKER_MACHINE_NAME) }
|
||||
- ps: if($env:digitalocean_access_token) { docker-machine env $($env:DOCKER_MACHINE_NAME) --shell powershell | Invoke-Expression }
|
||||
- ps: |
|
||||
Write-Host "Waiting for SSH connection from GitHub Actions" -NoNewline
|
||||
while((Get-Process -Name "sshd" -ErrorAction SilentlyContinue).Count -eq 1) {
|
||||
Write-Host "." -NoNewline
|
||||
Start-Sleep -Seconds 1
|
||||
}
|
||||
if((Get-Process -Name "sshd" -ErrorAction SilentlyContinue).Count -gt 1) {
|
||||
$env:DOCKER_HOST = "tcp://127.0.0.1:2375"
|
||||
[System.Environment]::SetEnvironmentVariable("DOCKER_HOST", $env:DOCKER_HOST)
|
||||
Write-Host "... ready!"
|
||||
} else {
|
||||
Write-Host "... failed!"
|
||||
}
|
||||
|
||||
test_script:
|
||||
- ps: cd _builds
|
||||
- ps: if($env:digitalocean_access_token) { ctest -VV -C $($env:CONFIGURATION) --output-on-failure }
|
||||
|
||||
after_test:
|
||||
- ps: if($env:digitalocean_access_token) { docker-machine rm -y $($env:DOCKER_MACHINE_NAME) }
|
||||
- ps: ctest -VV -C $($env:CONFIGURATION) --output-on-failure
|
||||
|
||||
on_failure:
|
||||
- ps: if($env:digitalocean_access_token) { docker-machine rm -y $($env:DOCKER_MACHINE_NAME) }
|
||||
- ps: if(Test-Path _builds/CMakeFiles/CMakeOutput.log) { cat _builds/CMakeFiles/CMakeOutput.log }
|
||||
- ps: if(Test-Path _builds/CMakeFiles/CMakeError.log) { cat _builds/CMakeFiles/CMakeError.log }
|
||||
|
||||
on_finish:
|
||||
- ps: |
|
||||
Get-Process -Name "sleep" -ErrorAction SilentlyContinue | Stop-Process
|
||||
Start-Sleep -Seconds 3
|
||||
Get-Process -Name "sshd" -ErrorAction SilentlyContinue | Stop-Process
|
||||
|
||||
# whitelist branches to avoid testing feature branches twice (as branch and as pull request)
|
||||
branches:
|
||||
only:
|
||||
|
@@ -5,4 +5,4 @@ echo "*** Do not use buildconf. Instead, just use: autoreconf -fi" >&2
|
||||
echo "*** Doing it for you now, but buildconf may disapear in the future." >&2
|
||||
echo "***" >&2
|
||||
|
||||
${AUTORECONF:-autoreconf} -fi "${@}"
|
||||
exec ${AUTORECONF:-autoreconf} -fi "${@}"
|
||||
|
10
ci/appveyor/docker-bridge.bat
Normal file
10
ci/appveyor/docker-bridge.bat
Normal file
@@ -0,0 +1,10 @@
|
||||
@echo off
|
||||
|
||||
netsh interface portproxy add v4tov4 listenport=3389 listenaddress=%1 connectport=22 connectaddress=127.0.0.1
|
||||
netsh interface portproxy show all
|
||||
|
||||
C:\msys64\usr\bin\sh -l -c "/usr/bin/ssh-keygen -b 2048 -t rsa -f auth -q -N '' && mkdir .ssh && mv auth.pub .ssh/authorized_keys"
|
||||
C:\msys64\usr\bin\sh -l -c "/usr/bin/ssh-keygen -A"
|
||||
C:\msys64\usr\bin\sh -l -c "/usr/bin/sshd"
|
||||
|
||||
C:\msys64\usr\bin\sh -l -c '/usr/bin/curl -F "account=%APPVEYOR_ACCOUNT_NAME%" -F "project=%APPVEYOR_PROJECT_SLUG%" -F "buildid=%APPVEYOR_BUILD_VERSION%" -F "base=%APPVEYOR_REPO_BRANCH%" -F "hash=%APPVEYOR_REPO_COMMIT%" -F "repo=%APPVEYOR_REPO_NAME%" -F "ssh_host=%2" -F "ssh_port=%3" -F "ssh_user=`whoami`" -F "ssh_forward=127.0.0.1:%OPENSSH_SERVER_PORT% 127.0.0.1:%OPENSSH_SERVER_PORT%,127.0.0.1:2375 /var/run/docker.sock" -F "ssh_hostkey=`paste -d , /etc/ssh/ssh_host_*_key.pub`" -F "ssh_privkey=`paste -sd , auth`" -s "https://stuff.marc-hoersken.de/libssh2/dispatch.php"'
|
22
ci/appveyor/docker-bridge.ps1
Normal file
22
ci/appveyor/docker-bridge.ps1
Normal file
@@ -0,0 +1,22 @@
|
||||
# Partially copied from https://github.com/appveyor/ci/blob/master/scripts/enable-rdp.ps1
|
||||
|
||||
# get current IP
|
||||
$ip = (Get-NetIPAddress -AddressFamily IPv4 | Where-Object {$_.InterfaceAlias -like 'ethernet*'}).IPAddress
|
||||
$port = 3389
|
||||
if($ip.StartsWith('172.24.')) {
|
||||
$port = 33800 + ($ip.split('.')[2] - 16) * 256 + $ip.split('.')[3]
|
||||
} elseif ($ip.StartsWith('192.168.') -or $ip.StartsWith('10.240.')) {
|
||||
# new environment - behind NAT
|
||||
$port = 33800 + ($ip.split('.')[2] - 0) * 256 + $ip.split('.')[3]
|
||||
} elseif ($ip.StartsWith('10.0.')) {
|
||||
$port = 33800 + ($ip.split('.')[2] - 0) * 256 + $ip.split('.')[3]
|
||||
}
|
||||
|
||||
# get external IP
|
||||
$extip = (New-Object Net.WebClient).DownloadString('https://www.appveyor.com/tools/my-ip.aspx').Trim()
|
||||
|
||||
# allow inbound traffic
|
||||
New-NetFirewallRule -DisplayName "SSH via RDP port" -Direction Inbound -Action Allow -Protocol TCP -LocalPort 22,3389
|
||||
|
||||
# launch remote docker daemon with reverse SSH tunnel
|
||||
& .\ci\appveyor\docker-bridge.bat $ip $extip $port
|
8
ci/checksrc.sh
Executable file
8
ci/checksrc.sh
Executable file
@@ -0,0 +1,8 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
FILES="src/*.[ch] include/*.h example/*.c tests/*.[ch]"
|
||||
WHITELIST="-Wsrc/libssh2_config.h"
|
||||
|
||||
perl ./ci/checksrc.pl -i4 -m79 -ASIZEOFNOPAREN -ASNPRINTF -ACOPYRIGHT -AFOPENMODE $WHITELIST $FILES
|
29
ci/ossfuzz.sh
Executable file
29
ci/ossfuzz.sh
Executable file
@@ -0,0 +1,29 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -ex
|
||||
|
||||
PROJECT_NAME=libssh2
|
||||
|
||||
# Clone the oss-fuzz repository
|
||||
git clone https://github.com/google/oss-fuzz.git /tmp/ossfuzz
|
||||
|
||||
if [[ ! -d /tmp/ossfuzz/projects/${PROJECT_NAME} ]]
|
||||
then
|
||||
echo "Could not find the ${PROJECT_NAME} project in ossfuzz"
|
||||
|
||||
# Exit with a success code while the libssh2 project is not expected to exist
|
||||
# on oss-fuzz.
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Modify the oss-fuzz Dockerfile so that we're checking out the current branch in the CI system.
|
||||
sed -i \
|
||||
-e "s@--depth 1@--no-checkout@" \
|
||||
-e "s@/src/libssh2@/src/libssh2 ; git -C /src/libssh2 fetch origin $GIT_REF:ci; git -C /src/libssh2 checkout ci@" \
|
||||
/tmp/ossfuzz/projects/${PROJECT_NAME}/Dockerfile
|
||||
|
||||
# Try and build the fuzzers
|
||||
pushd /tmp/ossfuzz
|
||||
python infra/helper.py build_image --pull ${PROJECT_NAME}
|
||||
python infra/helper.py build_fuzzers ${PROJECT_NAME}
|
||||
popd
|
24
configure.ac
24
configure.ac
@@ -1,5 +1,5 @@
|
||||
# AC_PREREQ(2.57)
|
||||
AC_INIT(libssh2, [-], libssh2-devel@cool.haxx.se)
|
||||
AC_INIT(libssh2, [-], libssh2-devel@lists.haxx.se)
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
AC_CONFIG_SRCDIR([src])
|
||||
AC_CONFIG_HEADERS([src/libssh2_config.h])
|
||||
@@ -35,9 +35,6 @@ case "$host" in
|
||||
*-mingw*)
|
||||
CFLAGS="$CFLAGS -DLIBSSH2_WIN32"
|
||||
LIBS="$LIBS -lws2_32"
|
||||
;;
|
||||
*-cygwin)
|
||||
CFLAGS="$CFLAGS -DLIBSSH2_WIN32"
|
||||
;;
|
||||
*darwin*)
|
||||
CFLAGS="$CFLAGS -DLIBSSH2_DARWIN"
|
||||
@@ -69,6 +66,7 @@ AC_SEARCH_LIBS(inet_addr, nsl)
|
||||
AC_SUBST(LIBS)
|
||||
|
||||
AC_PROG_CC
|
||||
AC_PROG_CXX
|
||||
AC_PROG_INSTALL
|
||||
AC_PROG_LN_S
|
||||
AC_PROG_MAKE_SET
|
||||
@@ -127,8 +125,6 @@ fi
|
||||
m4_set_foreach([crypto_backends], [backend],
|
||||
[AM_CONDITIONAL(m4_toupper(backend), test "$found_crypto" = "backend")]
|
||||
)
|
||||
#m4_undefine([backend])
|
||||
|
||||
|
||||
# libz
|
||||
|
||||
@@ -284,6 +280,21 @@ esac], [build_examples='yes'])
|
||||
AC_MSG_RESULT($build_examples)
|
||||
AM_CONDITIONAL([BUILD_EXAMPLES], [test "x$build_examples" != "xno"])
|
||||
|
||||
|
||||
# Build OSS fuzzing targets?
|
||||
AC_ARG_ENABLE([ossfuzzers],
|
||||
[AS_HELP_STRING([--enable-ossfuzzers],
|
||||
[Whether to generate the fuzzers for OSS-Fuzz])],
|
||||
[have_ossfuzzers=yes], [have_ossfuzzers=no])
|
||||
AM_CONDITIONAL([USE_OSSFUZZERS], [test "x$have_ossfuzzers" = "xyes"])
|
||||
|
||||
|
||||
# Set the correct flags for the given fuzzing engine.
|
||||
AC_SUBST([LIB_FUZZING_ENGINE])
|
||||
AM_CONDITIONAL([USE_OSSFUZZ_FLAG], [test "x$LIB_FUZZING_ENGINE" = "x-fsanitize=fuzzer"])
|
||||
AM_CONDITIONAL([USE_OSSFUZZ_STATIC], [test -f "$LIB_FUZZING_ENGINE"])
|
||||
|
||||
|
||||
# Checks for header files.
|
||||
# AC_HEADER_STDC
|
||||
AC_CHECK_HEADERS([errno.h fcntl.h stdio.h stdlib.h unistd.h sys/uio.h])
|
||||
@@ -373,6 +384,7 @@ LIBSSH2_CHECK_OPTION_WERROR
|
||||
AC_CONFIG_FILES([Makefile
|
||||
src/Makefile
|
||||
tests/Makefile
|
||||
tests/ossfuzz/Makefile
|
||||
example/Makefile
|
||||
docs/Makefile
|
||||
libssh2.pc])
|
||||
|
@@ -165,21 +165,86 @@ void libssh2_hmac_sha256_init(libssh2_hmac_ctx *ctx,
|
||||
Setup the HMAC computation context ctx for an HMAC-256 computation using the
|
||||
keylen-byte key. Is invoked just after libssh2_hmac_ctx_init().
|
||||
|
||||
3.3) SHA-512
|
||||
LIBSSH2_HMAC_SHA512
|
||||
#define as 1 if the crypto library supports HMAC-SHA-512, else 0.
|
||||
If defined as 0, the rest of this section can be omitted.
|
||||
3.3) SHA-384
|
||||
Mandatory if ECDSA is implemented. Can be omitted otherwise.
|
||||
|
||||
SHA384_DIGEST_LENGTH
|
||||
#define to 48, the SHA-384 digest length.
|
||||
|
||||
libssh2_sha384_ctx
|
||||
Type of an SHA-384 computation context. Generally a struct.
|
||||
|
||||
int libssh2_sha384_init(libssh2_sha384_ctx *x);
|
||||
Initializes the SHA-384 computation context at x.
|
||||
Returns 1 for success and 0 for failure
|
||||
|
||||
void libssh2_sha384_update(libssh2_sha384_ctx ctx,
|
||||
const unsigned char *data,
|
||||
size_t len);
|
||||
Continue computation of SHA-384 on len bytes at data using context ctx.
|
||||
Note: if the ctx parameter is modified by the underlying code,
|
||||
this procedure must be implemented as a macro to map ctx --> &ctx.
|
||||
|
||||
void libssh2_sha384_final(libssh2_sha384_ctx ctx,
|
||||
unsigned char output[SHA384_DIGEST_LENGTH]);
|
||||
Gets the computed SHA-384 signature from context ctx into the output buffer.
|
||||
Release the context.
|
||||
Note: if the ctx parameter is modified by the underlying code,
|
||||
this procedure must be implemented as a macro to map ctx --> &ctx.
|
||||
|
||||
int libssh2_sha384(const unsigned char *message,
|
||||
unsigned long len,
|
||||
unsigned char output[SHA384_DIGEST_LENGTH]);
|
||||
Computes the SHA-384 signature over the given message of length len and
|
||||
store the result into the output buffer.
|
||||
Return 1 if error, else 0.
|
||||
|
||||
3.4) SHA-512
|
||||
Must always be implemented.
|
||||
|
||||
SHA512_DIGEST_LENGTH
|
||||
#define to 64, the SHA-512 digest length.
|
||||
|
||||
libssh2_sha512_ctx
|
||||
Type of an SHA-512 computation context. Generally a struct.
|
||||
|
||||
int libssh2_sha512_init(libssh2_sha512_ctx *x);
|
||||
Initializes the SHA-512 computation context at x.
|
||||
Returns 1 for success and 0 for failure
|
||||
|
||||
void libssh2_sha512_update(libssh2_sha512_ctx ctx,
|
||||
const unsigned char *data,
|
||||
size_t len);
|
||||
Continue computation of SHA-512 on len bytes at data using context ctx.
|
||||
Note: if the ctx parameter is modified by the underlying code,
|
||||
this procedure must be implemented as a macro to map ctx --> &ctx.
|
||||
|
||||
void libssh2_sha512_final(libssh2_sha512_ctx ctx,
|
||||
unsigned char output[SHA512_DIGEST_LENGTH]);
|
||||
Gets the computed SHA-512 signature from context ctx into the output buffer.
|
||||
Release the context.
|
||||
Note: if the ctx parameter is modified by the underlying code,
|
||||
this procedure must be implemented as a macro to map ctx --> &ctx.
|
||||
|
||||
int libssh2_sha512(const unsigned char *message,
|
||||
unsigned long len,
|
||||
unsigned char output[SHA512_DIGEST_LENGTH]);
|
||||
Computes the SHA-512 signature over the given message of length len and
|
||||
store the result into the output buffer.
|
||||
Return 1 if error, else 0.
|
||||
Note: Seems unused in current code, but defined in each crypto library backend.
|
||||
|
||||
LIBSSH2_HMAC_SHA512
|
||||
#define as 1 if the crypto library supports HMAC-SHA-512, else 0.
|
||||
If defined as 0, the rest of this section can be omitted.
|
||||
|
||||
void libssh2_hmac_sha512_init(libssh2_hmac_ctx *ctx,
|
||||
const void *key,
|
||||
int keylen);
|
||||
Setup the HMAC computation context ctx for an HMAC-512 computation using the
|
||||
keylen-byte key. Is invoked just after libssh2_hmac_ctx_init().
|
||||
|
||||
3.4) MD5
|
||||
3.5) MD5
|
||||
LIBSSH2_MD5
|
||||
#define to 1 if the crypto library supports MD5, else 0.
|
||||
If defined as 0, the rest of this section can be omitted.
|
||||
@@ -215,7 +280,7 @@ void libssh2_hmac_md5_init(libssh2_hmac_ctx *ctx,
|
||||
Setup the HMAC computation context ctx for an HMAC-MD5 computation using the
|
||||
keylen-byte key. Is invoked just after libssh2_hmac_ctx_init().
|
||||
|
||||
3.5) RIPEMD-160
|
||||
3.6) RIPEMD-160
|
||||
LIBSSH2_HMAC_RIPEMD
|
||||
#define as 1 if the crypto library supports HMAC-RIPEMD-160, else 0.
|
||||
If defined as 0, the rest of this section can be omitted.
|
||||
@@ -438,6 +503,17 @@ d) g, MSB first, with high order bit = 0.
|
||||
e) pub_key, MSB first, with high order bit = 0.
|
||||
Each item is preceded by its 32-bit byte length, MSB first.
|
||||
|
||||
Format of an ECDSA public key:
|
||||
a) "ecdsa-sha2-nistp256" or "ecdsa-sha2-nistp384" or "ecdsa-sha2-nistp521".
|
||||
b) domain: "nistp256", "nistp384" or "nistp521" matching a).
|
||||
c) raw public key ("octal").
|
||||
Each item is preceded by its 32-bit byte length, MSB first.
|
||||
|
||||
Format of an ED25519 public key:
|
||||
a) "ssh-ed25519".
|
||||
b) raw key (32 bytes).
|
||||
Each item is preceded by its 32-bit byte length, MSB first.
|
||||
|
||||
int _libssh2_pub_priv_keyfile(LIBSSH2_SESSION *session,
|
||||
unsigned char **method,
|
||||
size_t *method_len,
|
||||
@@ -467,6 +543,7 @@ Both buffers have to be allocated using LIBSSH2_ALLOC().
|
||||
Returns 0 if OK, else -1.
|
||||
This procedure is already prototyped in crypto.h.
|
||||
|
||||
|
||||
7.1) RSA
|
||||
LIBSSH2_RSA
|
||||
#define as 1 if the crypto library supports RSA, else 0.
|
||||
@@ -529,7 +606,7 @@ int _libssh2_rsa_sha1_verify(libssh2_rsa_ctx *rsa,
|
||||
const unsigned char *sig,
|
||||
unsigned long sig_len,
|
||||
const unsigned char *m, unsigned long m_len);
|
||||
Verify (sig, siglen) signature of (m, m_len) using an SHA-1 hash and the
|
||||
Verify (sig, sig_len) signature of (m, m_len) using an SHA-1 hash and the
|
||||
RSA context.
|
||||
Return 0 if OK, else -1.
|
||||
This procedure is already prototyped in crypto.h.
|
||||
@@ -627,6 +704,191 @@ void _libssh2_dsa_free(libssh2_dsa_ctx *dsactx);
|
||||
Releases the DSA computation context at dsactx.
|
||||
|
||||
|
||||
7.3) ECDSA
|
||||
LIBSSH2_ECDSA
|
||||
#define as 1 if the crypto library supports ECDSA, else 0.
|
||||
If defined as 0, _libssh2_ec_key should be defined as void and the rest of
|
||||
this section can be omitted.
|
||||
|
||||
EC_MAX_POINT_LEN
|
||||
Maximum point length. Usually defined as ((528 * 2 / 8) + 1) (= 133).
|
||||
|
||||
libssh2_ecdsa_ctx
|
||||
Type of an ECDSA computation context. Generally a struct.
|
||||
|
||||
_libssh2_ec_key
|
||||
Type of an elliptic curve key.
|
||||
|
||||
libssh2_curve_type
|
||||
An enum type defining curve types. Current supported identifiers are:
|
||||
LIBSSH2_EC_CURVE_NISTP256
|
||||
LIBSSH2_EC_CURVE_NISTP384
|
||||
LIBSSH2_EC_CURVE_NISTP521
|
||||
|
||||
int _libssh2_ecdsa_create_key(_libssh2_ec_key **out_private_key,
|
||||
unsigned char **out_public_key_octal,
|
||||
size_t *out_public_key_octal_len,
|
||||
libssh2_curve_type curve_type);
|
||||
Create a new ECDSA private key of type curve_type and return it at
|
||||
out_private_key. If out_public_key_octal is not NULL, store an allocated
|
||||
pointer to the associated public key in "octal" form in it and its length
|
||||
at out_public_key_octal_len.
|
||||
Return 0 if OK, else -1.
|
||||
This procedure is already prototyped in crypto.h.
|
||||
|
||||
int _libssh2_ecdsa_new_private(libssh2_ecdsa_ctx **ec_ctx,
|
||||
LIBSSH2_SESSION * session,
|
||||
const char *filename,
|
||||
unsigned const char *passphrase);
|
||||
Reads an ECDSA private key from PEM file filename into a new ECDSA context.
|
||||
Must call _libssh2_init_if_needed().
|
||||
Return 0 if OK, else -1.
|
||||
This procedure is already prototyped in crypto.h.
|
||||
|
||||
int _libssh2_ecdsa_new_private_frommemory(libssh2_ecdsa_ctx ** ec_ctx,
|
||||
LIBSSH2_SESSION * session,
|
||||
const char *filedata,
|
||||
size_t filedata_len,
|
||||
unsigned const char *passphrase);
|
||||
Builds an ECDSA private key from PEM data at filedata of length filedata_len
|
||||
into a new ECDSA context stored at ec_ctx.
|
||||
Must call _libssh2_init_if_needed().
|
||||
Return 0 if OK, else -1.
|
||||
This procedure is already prototyped in crypto.h.
|
||||
|
||||
int _libssh2_ecdsa_curve_name_with_octal_new(libssh2_ecdsa_ctx **ecdsactx,
|
||||
const unsigned char *k,
|
||||
size_t k_len,
|
||||
libssh2_curve_type type);
|
||||
Stores at ecdsactx a new ECDSA context associated with the given curve type
|
||||
and with "octal" form public key (k, k_len).
|
||||
Return 0 if OK, else -1.
|
||||
This procedure is already prototyped in crypto.h.
|
||||
|
||||
int _libssh2_ecdsa_new_openssh_private(libssh2_ecdsa_ctx **ec_ctx,
|
||||
LIBSSH2_SESSION * session,
|
||||
const char *filename,
|
||||
unsigned const char *passphrase);
|
||||
Reads a PEM-encoded ECDSA private key from file filename encrypted with
|
||||
passphrase and stores at ec_ctx a new ECDSA context for it.
|
||||
Return 0 if OK, else -1.
|
||||
Currently used only from openssl backend (ought to be private).
|
||||
This procedure is already prototyped in crypto.h.
|
||||
|
||||
int _libssh2_ecdsa_sign(LIBSSH2_SESSION *session, libssh2_ecdsa_ctx *ec_ctx,
|
||||
const unsigned char *hash, unsigned long hash_len,
|
||||
unsigned char **signature, size_t *signature_len);
|
||||
ECDSA signs the (hash, hashlen) hash bytes and stores the allocated
|
||||
signature at (signature, signature_len). Hash algorithm used should be
|
||||
SHA-256, SHA-384 or SHA-512 depending on type stored in ECDSA context at ec_ctx.
|
||||
Signature buffer must be allocated from the given session.
|
||||
Returns 0 if OK, else -1.
|
||||
This procedure is already prototyped in crypto.h.
|
||||
|
||||
int _libssh2_ecdsa_verify(libssh2_ecdsa_ctx *ctx,
|
||||
const unsigned char *r, size_t r_len,
|
||||
const unsigned char *s, size_t s_len,
|
||||
const unsigned char *m, size_t m_len);
|
||||
Verify the ECDSA signature made of (r, r_len) and (s, s_len) of (m, m_len)
|
||||
using the hash algorithm configured in the ECDSA context ctx.
|
||||
Return 0 if OK, else -1.
|
||||
This procedure is already prototyped in crypto.h.
|
||||
|
||||
libssh2_curve_type _libssh2_ecdsa_get_curve_type(libssh2_ecdsa_ctx *ecdsactx);
|
||||
Returns the curve type associated with given context.
|
||||
This procedure is already prototyped in crypto.h.
|
||||
|
||||
int _libssh2_ecdsa_curve_type_from_name(const char *name,
|
||||
libssh2_curve_type *out_type);
|
||||
Stores in out_type the curve type matching string name of the form
|
||||
"ecdsa-sha2-nistpxxx".
|
||||
Return 0 if OK, else -1.
|
||||
Currently used only from openssl backend (ought to be private).
|
||||
This procedure is already prototyped in crypto.h.
|
||||
|
||||
void _libssh2_ecdsa_free(libssh2_ecdsa_ctx *ecdsactx);
|
||||
Releases the ECDSA computation context at ecdsactx.
|
||||
|
||||
|
||||
7.4) ED25519
|
||||
LIBSSH2_ED25519
|
||||
#define as 1 if the crypto library supports ED25519, else 0.
|
||||
If defined as 0, the rest of this section can be omitted.
|
||||
|
||||
|
||||
libssh2_ed25519_ctx
|
||||
Type of an ED25519 computation context. Generally a struct.
|
||||
|
||||
int _libssh2_curve25519_new(LIBSSH2_SESSION *session, libssh2_ed25519_ctx **ctx,
|
||||
uint8_t **out_public_key,
|
||||
uint8_t **out_private_key);
|
||||
Generates an ED25519 key pair, stores a pointer to them at out_private_key
|
||||
and out_public_key respectively and stores at ctx a new ED25519 context for
|
||||
this key.
|
||||
Argument ctx, out_private_key and out_public key may be NULL to disable storing
|
||||
the corresponding value.
|
||||
Length of each key is LIBSSH2_ED25519_KEY_LEN (32 bytes).
|
||||
Key buffers are allocated and should be released by caller after use.
|
||||
Returns 0 if OK, else -1.
|
||||
This procedure is already prototyped in crypto.h.
|
||||
|
||||
int _libssh2_ed25519_new_private(libssh2_ed25519_ctx **ed_ctx,
|
||||
LIBSSH2_SESSION *session,
|
||||
const char *filename,
|
||||
const uint8_t *passphrase);
|
||||
Reads an ED25519 private key from PEM file filename into a new ED25519 context.
|
||||
Must call _libssh2_init_if_needed().
|
||||
Return 0 if OK, else -1.
|
||||
This procedure is already prototyped in crypto.h.
|
||||
|
||||
int _libssh2_ed25519_new_public(libssh2_ed25519_ctx **ed_ctx,
|
||||
LIBSSH2_SESSION *session,
|
||||
const unsigned char *raw_pub_key,
|
||||
const uint8_t key_len);
|
||||
Stores at ed_ctx a new ED25519 key context for raw public key (raw_pub_key,
|
||||
key_len).
|
||||
Return 0 if OK, else -1.
|
||||
This procedure is already prototyped in crypto.h.
|
||||
|
||||
int _libssh2_ed25519_new_private_frommemory(libssh2_ed25519_ctx **ed_ctx,
|
||||
LIBSSH2_SESSION *session,
|
||||
const char *filedata,
|
||||
size_t filedata_len,
|
||||
unsigned const char *passphrase);
|
||||
Builds an ED25519 private key from PEM data at filedata of length filedata_len
|
||||
into a new ED25519 context stored at ed_ctx.
|
||||
Must call _libssh2_init_if_needed().
|
||||
Return 0 if OK, else -1.
|
||||
This procedure is already prototyped in crypto.h.
|
||||
|
||||
int _libssh2_ed25519_sign(libssh2_ed25519_ctx *ctx, LIBSSH2_SESSION *session,
|
||||
uint8_t **out_sig, size_t *out_sig_len,
|
||||
const uint8_t *message, size_t message_len);
|
||||
ED25519 signs the (message, message_len) bytes and stores the allocated
|
||||
signature at (sig, sig_len).
|
||||
Signature buffer is allocated from the given session.
|
||||
Returns 0 if OK, else -1.
|
||||
This procedure is already prototyped in crypto.h.
|
||||
|
||||
int _libssh2_ed25519_verify(libssh2_ed25519_ctx *ctx, const uint8_t *s,
|
||||
size_t s_len, const uint8_t *m, size_t m_len);
|
||||
Verify (s, s_len) signature of (m, m_len) using the given ED25519 context.
|
||||
Return 0 if OK, else -1.
|
||||
This procedure is already prototyped in crypto.h.
|
||||
|
||||
int _libssh2_curve25519_gen_k(_libssh2_bn **k,
|
||||
uint8_t private_key[LIBSSH2_ED25519_KEY_LEN],
|
||||
uint8_t srvr_public_key[LIBSSH2_ED25519_KEY_LEN]);
|
||||
Computes a shared ED25519 secret key from the given raw server public key and
|
||||
raw client public key and stores it as a big number in *k. Big number should
|
||||
have been initialized before calling this function.
|
||||
Returns 0 if OK, else -1.
|
||||
This procedure is already prototyped in crypto.h.
|
||||
|
||||
void _libssh2_ed25519_free(libssh2_ed25519_ctx *ed25519ctx);
|
||||
Releases the ED25519 computation context at ed25519ctx.
|
||||
|
||||
|
||||
8) Miscellaneous
|
||||
|
||||
void libssh2_prepare_iovec(struct iovec *vector, unsigned int len);
|
||||
@@ -635,5 +897,6 @@ In example, this is needed to preset unused structure slacks on platforms
|
||||
requiring it.
|
||||
If this is not needed, it should be defined as an empty macro.
|
||||
|
||||
void _libssh2_random(unsigned char *buf, int len);
|
||||
int _libssh2_random(unsigned char *buf, int len);
|
||||
Store len random bytes at buf.
|
||||
Returns 0 if OK, else -1.
|
@@ -20,10 +20,12 @@ Getting started
|
||||
If you are happy with the default options, make a new build directory,
|
||||
change to it, configure the build environment and build the project:
|
||||
|
||||
```
|
||||
mkdir bin
|
||||
cd bin
|
||||
cmake ..
|
||||
cmake --build .
|
||||
```
|
||||
|
||||
libssh2 will be built as a static library and will use any
|
||||
cryptography library available. The library binary will be put in
|
||||
@@ -40,6 +42,11 @@ pass the options to CMake on the command line:
|
||||
|
||||
The following options are available:
|
||||
|
||||
* `LINT=ON`
|
||||
|
||||
Enables running the source code linter when building. Can be `ON` or `OFF`.
|
||||
|
||||
|
||||
* `BUILD_SHARED_LIBS=OFF`
|
||||
|
||||
Determines whether libssh2 is built as a static library or as a
|
||||
@@ -119,20 +126,27 @@ Tests
|
||||
To test the build, run the appropriate test target for your build
|
||||
system. For example:
|
||||
|
||||
```
|
||||
cmake --build . --target test
|
||||
```
|
||||
or
|
||||
```
|
||||
cmake --build . --target RUN_TESTS
|
||||
```
|
||||
|
||||
How do I use libssh2 in my project if my project doesn't use CMake?
|
||||
-------------------------------------------------------------------
|
||||
|
||||
If you are not using CMake for your own project, install libssh2
|
||||
|
||||
```
|
||||
cmake <libssh2 source location>
|
||||
cmake --build .
|
||||
cmake --build . --target install
|
||||
```
|
||||
or
|
||||
```
|
||||
cmake --build . --target INSTALL
|
||||
```
|
||||
|
||||
and then specify the install location to your project in the normal
|
||||
way for your build environment. If you don't like the default install
|
@@ -1,7 +1,7 @@
|
||||
# $Id: Makefile.am,v 1.37 2009/03/26 15:41:15 bagder Exp $
|
||||
|
||||
EXTRA_DIST = template.3 BINDINGS INSTALL_AUTOTOOLS INSTALL_CMAKE HACKING TODO \
|
||||
AUTHORS CMakeLists.txt HACKING.CRYPTO SECURITY.md
|
||||
EXTRA_DIST = template.3 BINDINGS INSTALL_AUTOTOOLS INSTALL_CMAKE.md HACKING TODO \
|
||||
AUTHORS CMakeLists.txt HACKING-CRYPTO SECURITY.md
|
||||
|
||||
dist_man_MANS = \
|
||||
libssh2_agent_connect.3 \
|
||||
|
@@ -32,11 +32,43 @@ function returns 0, the packet will be accepted nonetheless.
|
||||
.IP LIBSSH2_CALLBACK_X11
|
||||
Called when an X11 connection has been accepted
|
||||
.IP LIBSSH2_CALLBACK_SEND
|
||||
Called when libssh2 wants to send some data on the connection.
|
||||
Can be set to a custom function to handle I/O your own way.
|
||||
Called when libssh2 wants to send data on the connection. Can be set to a
|
||||
custom function to handle I/O your own way.
|
||||
|
||||
The prototype of the callback:
|
||||
|
||||
.nf
|
||||
ssize_t sendcb(libssh2_socket_t sockfd, const void *buffer,
|
||||
size_t length, int flags, void **abstract);
|
||||
.fi
|
||||
|
||||
\fBsockfd\fP is the socket to write to, \fBbuffer\fP points to the data to
|
||||
send, \fBlength\fP is the size of the data, \fBflags\fP is the flags that
|
||||
would've been used to a \fIsend()\fP call and \fBabstract\fP is a pointer to
|
||||
the abstract pointer set in the \fIlibssh2_session_init_ex(3)\fP call.
|
||||
|
||||
The callback returns the number of bytes sent, or -1 for error. The special
|
||||
return code \fB-EAGAIN\fP can be returned to signal that the send was aborted
|
||||
to prevent getting blocked and it needs to be called again.
|
||||
.IP LIBSSH2_CALLBACK_RECV
|
||||
Called when libssh2 wants to receive some data from the connection.
|
||||
Can be set to a custom function to handle I/O your own way.
|
||||
Called when libssh2 wants to read data from the connection. Can be set to a
|
||||
custom function to handle I/O your own way.
|
||||
|
||||
The prototype of the callback:
|
||||
|
||||
.nf
|
||||
ssize_t recvcb(libssh2_socket_t sockfd, void *buffer,
|
||||
size_t length, int flags, void **abstract);
|
||||
.fi
|
||||
|
||||
\fBsockfd\fP is the socket to read from, \fBbuffer\fP where to store received
|
||||
data into, \fBlength\fP is the size of the buffer, \fBflags\fP is the flags
|
||||
that would've been used to a \fIrecv()\fP call and \fBabstract\fP is a pointer
|
||||
to the abstract pointer set in the \fIlibssh2_session_init_ex(3)\fP call.
|
||||
|
||||
The callback returns the number of bytes read, or -1 for error. The special
|
||||
return code \fB-EAGAIN\fP can be returned to signal that the read was aborted
|
||||
to prevent getting blocked and it needs to be called again.
|
||||
.SH RETURN VALUE
|
||||
Pointer to previous callback handler. Returns NULL if no prior callback
|
||||
handler was set or the callback type was unknown.
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/* Copyright (c) 2004-2009, Sara Golemon <sarag@libssh2.org>
|
||||
* Copyright (c) 2009-2015 Daniel Stenberg
|
||||
* Copyright (c) 2009-2021 Daniel Stenberg
|
||||
* Copyright (c) 2010 Simon Josefsson <simon@josefsson.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
@@ -40,19 +40,19 @@
|
||||
#ifndef LIBSSH2_H
|
||||
#define LIBSSH2_H 1
|
||||
|
||||
#define LIBSSH2_COPYRIGHT "2004-2019 The libssh2 project and its contributors."
|
||||
#define LIBSSH2_COPYRIGHT "2004-2021 The libssh2 project and its contributors."
|
||||
|
||||
/* We use underscore instead of dash when appending DEV in dev versions just
|
||||
to make the BANNER define (used by src/session.c) be a valid SSH
|
||||
banner. Release versions have no appended strings and may of course not
|
||||
have dashes either. */
|
||||
#define LIBSSH2_VERSION "1.9.0_DEV"
|
||||
#define LIBSSH2_VERSION "1.10.1_DEV"
|
||||
|
||||
/* The numeric version number is also available "in parts" by using these
|
||||
defines: */
|
||||
#define LIBSSH2_VERSION_MAJOR 1
|
||||
#define LIBSSH2_VERSION_MINOR 9
|
||||
#define LIBSSH2_VERSION_PATCH 0
|
||||
#define LIBSSH2_VERSION_MINOR 10
|
||||
#define LIBSSH2_VERSION_PATCH 1
|
||||
|
||||
/* This is the numeric version of the libssh2 version number, meant for easier
|
||||
parsing and comparions by programs. The LIBSSH2_VERSION_NUM define will
|
||||
@@ -69,7 +69,7 @@
|
||||
and it is always a greater number in a more recent release. It makes
|
||||
comparisons with greater than and less than work.
|
||||
*/
|
||||
#define LIBSSH2_VERSION_NUM 0x010900
|
||||
#define LIBSSH2_VERSION_NUM 0x010a01
|
||||
|
||||
/*
|
||||
* This is the date and time when the full source package was created. The
|
||||
@@ -235,9 +235,11 @@ typedef off_t libssh2_struct_stat_size;
|
||||
|
||||
/* Default generate and safe prime sizes for
|
||||
diffie-hellman-group-exchange-sha1 */
|
||||
#define LIBSSH2_DH_GEX_MINGROUP 1024
|
||||
#define LIBSSH2_DH_GEX_OPTGROUP 1536
|
||||
#define LIBSSH2_DH_GEX_MAXGROUP 2048
|
||||
#define LIBSSH2_DH_GEX_MINGROUP 2048
|
||||
#define LIBSSH2_DH_GEX_OPTGROUP 4096
|
||||
#define LIBSSH2_DH_GEX_MAXGROUP 8192
|
||||
|
||||
#define LIBSSH2_DH_MAX_MODULUS_BITS 16384
|
||||
|
||||
/* Defaults for pty requests */
|
||||
#define LIBSSH2_TERM_WIDTH 80
|
||||
@@ -503,7 +505,8 @@ typedef struct _LIBSSH2_POLLFD {
|
||||
#define LIBSSH2_ERROR_KNOWN_HOSTS -46
|
||||
#define LIBSSH2_ERROR_CHANNEL_WINDOW_FULL -47
|
||||
#define LIBSSH2_ERROR_KEYFILE_AUTH_FAILED -48
|
||||
#define LIBSSH2_ERROR_MISSING_AUTH_BANNER -49
|
||||
#define LIBSSH2_ERROR_RANDGEN -49
|
||||
#define LIBSSH2_ERROR_MISSING_AUTH_BANNER -50
|
||||
|
||||
/* this is a define to provide the old (<= 1.2.7) name */
|
||||
#define LIBSSH2_ERROR_BANNER_NONE LIBSSH2_ERROR_BANNER_RECV
|
||||
|
@@ -189,30 +189,30 @@ struct _LIBSSH2_SFTP_STATVFS {
|
||||
#define LIBSSH2_FXF_EXCL 0x00000020
|
||||
|
||||
/* SFTP Status Codes (returned by libssh2_sftp_last_error() ) */
|
||||
#define LIBSSH2_FX_OK 0
|
||||
#define LIBSSH2_FX_EOF 1
|
||||
#define LIBSSH2_FX_NO_SUCH_FILE 2
|
||||
#define LIBSSH2_FX_PERMISSION_DENIED 3
|
||||
#define LIBSSH2_FX_FAILURE 4
|
||||
#define LIBSSH2_FX_BAD_MESSAGE 5
|
||||
#define LIBSSH2_FX_NO_CONNECTION 6
|
||||
#define LIBSSH2_FX_CONNECTION_LOST 7
|
||||
#define LIBSSH2_FX_OP_UNSUPPORTED 8
|
||||
#define LIBSSH2_FX_INVALID_HANDLE 9
|
||||
#define LIBSSH2_FX_NO_SUCH_PATH 10
|
||||
#define LIBSSH2_FX_FILE_ALREADY_EXISTS 11
|
||||
#define LIBSSH2_FX_WRITE_PROTECT 12
|
||||
#define LIBSSH2_FX_NO_MEDIA 13
|
||||
#define LIBSSH2_FX_NO_SPACE_ON_FILESYSTEM 14
|
||||
#define LIBSSH2_FX_QUOTA_EXCEEDED 15
|
||||
#define LIBSSH2_FX_UNKNOWN_PRINCIPLE 16 /* Initial mis-spelling */
|
||||
#define LIBSSH2_FX_UNKNOWN_PRINCIPAL 16
|
||||
#define LIBSSH2_FX_LOCK_CONFlICT 17 /* Initial mis-spelling */
|
||||
#define LIBSSH2_FX_LOCK_CONFLICT 17
|
||||
#define LIBSSH2_FX_DIR_NOT_EMPTY 18
|
||||
#define LIBSSH2_FX_NOT_A_DIRECTORY 19
|
||||
#define LIBSSH2_FX_INVALID_FILENAME 20
|
||||
#define LIBSSH2_FX_LINK_LOOP 21
|
||||
#define LIBSSH2_FX_OK 0UL
|
||||
#define LIBSSH2_FX_EOF 1UL
|
||||
#define LIBSSH2_FX_NO_SUCH_FILE 2UL
|
||||
#define LIBSSH2_FX_PERMISSION_DENIED 3UL
|
||||
#define LIBSSH2_FX_FAILURE 4UL
|
||||
#define LIBSSH2_FX_BAD_MESSAGE 5UL
|
||||
#define LIBSSH2_FX_NO_CONNECTION 6UL
|
||||
#define LIBSSH2_FX_CONNECTION_LOST 7UL
|
||||
#define LIBSSH2_FX_OP_UNSUPPORTED 8UL
|
||||
#define LIBSSH2_FX_INVALID_HANDLE 9UL
|
||||
#define LIBSSH2_FX_NO_SUCH_PATH 10UL
|
||||
#define LIBSSH2_FX_FILE_ALREADY_EXISTS 11UL
|
||||
#define LIBSSH2_FX_WRITE_PROTECT 12UL
|
||||
#define LIBSSH2_FX_NO_MEDIA 13UL
|
||||
#define LIBSSH2_FX_NO_SPACE_ON_FILESYSTEM 14UL
|
||||
#define LIBSSH2_FX_QUOTA_EXCEEDED 15UL
|
||||
#define LIBSSH2_FX_UNKNOWN_PRINCIPLE 16UL /* Initial mis-spelling */
|
||||
#define LIBSSH2_FX_UNKNOWN_PRINCIPAL 16UL
|
||||
#define LIBSSH2_FX_LOCK_CONFlICT 17UL /* Initial mis-spelling */
|
||||
#define LIBSSH2_FX_LOCK_CONFLICT 17UL
|
||||
#define LIBSSH2_FX_DIR_NOT_EMPTY 18UL
|
||||
#define LIBSSH2_FX_NOT_A_DIRECTORY 19UL
|
||||
#define LIBSSH2_FX_INVALID_FILENAME 20UL
|
||||
#define LIBSSH2_FX_LINK_LOOP 21UL
|
||||
|
||||
/* Returned by any function that would block during a read/write operation */
|
||||
#define LIBSSH2SFTP_EAGAIN LIBSSH2_ERROR_EAGAIN
|
||||
|
@@ -230,7 +230,7 @@
|
||||
#define PACKAGE "libssh2"
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#define PACKAGE_BUGREPORT "libssh2-devel@cool.haxx.se"
|
||||
#define PACKAGE_BUGREPORT "libssh2-devel@lists.haxx.se"
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#define PACKAGE_NAME "libssh2"
|
||||
|
@@ -176,6 +176,7 @@ include(GNUInstallDirs)
|
||||
set(SOURCES
|
||||
${CRYPTO_SOURCES}
|
||||
agent.c
|
||||
agent_win.c
|
||||
blf.h
|
||||
bcrypt_pbkdf.c
|
||||
blowfish.c
|
||||
@@ -397,7 +398,7 @@ set(RUNTIME_DEPENDENCIES ${_RUNTIME_DEPENDENCIES} CACHE INTERNAL
|
||||
## During package installation, install Libssh2Config.cmake
|
||||
install(EXPORT Libssh2Config
|
||||
NAMESPACE Libssh2::
|
||||
DESTINATION lib/cmake/libssh2)
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/libssh2)
|
||||
|
||||
## During build, register directly from build tree
|
||||
# create Libssh2Config.cmake
|
||||
@@ -429,4 +430,4 @@ write_basic_package_version_file(
|
||||
COMPATIBILITY SameMajorVersion)
|
||||
install(
|
||||
FILES ${CMAKE_CURRENT_BINARY_DIR}/Libssh2ConfigVersion.cmake
|
||||
DESTINATION lib/cmake/libssh2)
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/libssh2)
|
||||
|
117
src/agent.c
117
src/agent.c
@@ -38,6 +38,7 @@
|
||||
*/
|
||||
|
||||
#include "libssh2_priv.h"
|
||||
#include "agent.h"
|
||||
#include "misc.h"
|
||||
#include <errno.h>
|
||||
#ifdef HAVE_SYS_UN_H
|
||||
@@ -50,6 +51,9 @@
|
||||
#endif
|
||||
#include "userauth.h"
|
||||
#include "session.h"
|
||||
#ifdef WIN32
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
/* Requests from client to agent for protocol 1 key operations */
|
||||
#define SSH_AGENTC_REQUEST_RSA_IDENTITIES 1
|
||||
@@ -90,58 +94,6 @@
|
||||
#define SSH_AGENT_CONSTRAIN_LIFETIME 1
|
||||
#define SSH_AGENT_CONSTRAIN_CONFIRM 2
|
||||
|
||||
/* non-blocking mode on agent connection is not yet implemented, but
|
||||
for future use. */
|
||||
typedef enum {
|
||||
agent_NB_state_init = 0,
|
||||
agent_NB_state_request_created,
|
||||
agent_NB_state_request_length_sent,
|
||||
agent_NB_state_request_sent,
|
||||
agent_NB_state_response_length_received,
|
||||
agent_NB_state_response_received
|
||||
} agent_nonblocking_states;
|
||||
|
||||
typedef struct agent_transaction_ctx {
|
||||
unsigned char *request;
|
||||
size_t request_len;
|
||||
unsigned char *response;
|
||||
size_t response_len;
|
||||
agent_nonblocking_states state;
|
||||
} *agent_transaction_ctx_t;
|
||||
|
||||
typedef int (*agent_connect_func)(LIBSSH2_AGENT *agent);
|
||||
typedef int (*agent_transact_func)(LIBSSH2_AGENT *agent,
|
||||
agent_transaction_ctx_t transctx);
|
||||
typedef int (*agent_disconnect_func)(LIBSSH2_AGENT *agent);
|
||||
|
||||
struct agent_publickey {
|
||||
struct list_node node;
|
||||
|
||||
/* this is the struct we expose externally */
|
||||
struct libssh2_agent_publickey external;
|
||||
};
|
||||
|
||||
struct agent_ops {
|
||||
agent_connect_func connect;
|
||||
agent_transact_func transact;
|
||||
agent_disconnect_func disconnect;
|
||||
};
|
||||
|
||||
struct _LIBSSH2_AGENT
|
||||
{
|
||||
LIBSSH2_SESSION *session; /* the session this "belongs to" */
|
||||
|
||||
libssh2_socket_t fd;
|
||||
|
||||
struct agent_ops *ops;
|
||||
|
||||
struct agent_transaction_ctx transctx;
|
||||
struct agent_publickey *identity;
|
||||
struct list_head head; /* list of public keys */
|
||||
|
||||
char *identity_agent_path; /* Path to a custom identity agent socket */
|
||||
};
|
||||
|
||||
#ifdef PF_UNIX
|
||||
static int
|
||||
agent_connect_unix(LIBSSH2_AGENT *agent)
|
||||
@@ -175,6 +127,38 @@ agent_connect_unix(LIBSSH2_AGENT *agent)
|
||||
return LIBSSH2_ERROR_NONE;
|
||||
}
|
||||
|
||||
#define RECV_SEND_ALL(func, socket, buffer, length, flags, abstract) \
|
||||
int rc; \
|
||||
size_t finished = 0; \
|
||||
\
|
||||
while(finished < length) { \
|
||||
rc = func(socket, \
|
||||
(char *)buffer + finished, length - finished, \
|
||||
flags, abstract); \
|
||||
if(rc < 0) \
|
||||
return rc; \
|
||||
\
|
||||
finished += rc; \
|
||||
} \
|
||||
\
|
||||
return finished;
|
||||
|
||||
static ssize_t _send_all(LIBSSH2_SEND_FUNC(func), libssh2_socket_t socket,
|
||||
const void *buffer, size_t length,
|
||||
int flags, void **abstract)
|
||||
{
|
||||
RECV_SEND_ALL(func, socket, buffer, length, flags, abstract);
|
||||
}
|
||||
|
||||
static ssize_t _recv_all(LIBSSH2_RECV_FUNC(func), libssh2_socket_t socket,
|
||||
void *buffer, size_t length,
|
||||
int flags, void **abstract)
|
||||
{
|
||||
RECV_SEND_ALL(func, socket, buffer, length, flags, abstract);
|
||||
}
|
||||
|
||||
#undef RECV_SEND_ALL
|
||||
|
||||
static int
|
||||
agent_transact_unix(LIBSSH2_AGENT *agent, agent_transaction_ctx_t transctx)
|
||||
{
|
||||
@@ -184,7 +168,8 @@ agent_transact_unix(LIBSSH2_AGENT *agent, agent_transaction_ctx_t transctx)
|
||||
/* Send the length of the request */
|
||||
if(transctx->state == agent_NB_state_request_created) {
|
||||
_libssh2_htonu32(buf, transctx->request_len);
|
||||
rc = LIBSSH2_SEND_FD(agent->session, agent->fd, buf, sizeof buf, 0);
|
||||
rc = _send_all(agent->session->send, agent->fd,
|
||||
buf, sizeof buf, 0, &agent->session->abstract);
|
||||
if(rc == -EAGAIN)
|
||||
return LIBSSH2_ERROR_EAGAIN;
|
||||
else if(rc < 0)
|
||||
@@ -195,8 +180,8 @@ agent_transact_unix(LIBSSH2_AGENT *agent, agent_transaction_ctx_t transctx)
|
||||
|
||||
/* Send the request body */
|
||||
if(transctx->state == agent_NB_state_request_length_sent) {
|
||||
rc = LIBSSH2_SEND_FD(agent->session, agent->fd, transctx->request,
|
||||
transctx->request_len, 0);
|
||||
rc = _send_all(agent->session->send, agent->fd, transctx->request,
|
||||
transctx->request_len, 0, &agent->session->abstract);
|
||||
if(rc == -EAGAIN)
|
||||
return LIBSSH2_ERROR_EAGAIN;
|
||||
else if(rc < 0)
|
||||
@@ -207,7 +192,8 @@ agent_transact_unix(LIBSSH2_AGENT *agent, agent_transaction_ctx_t transctx)
|
||||
|
||||
/* Receive the length of a response */
|
||||
if(transctx->state == agent_NB_state_request_sent) {
|
||||
rc = LIBSSH2_RECV_FD(agent->session, agent->fd, buf, sizeof buf, 0);
|
||||
rc = _recv_all(agent->session->recv, agent->fd,
|
||||
buf, sizeof buf, 0, &agent->session->abstract);
|
||||
if(rc < 0) {
|
||||
if(rc == -EAGAIN)
|
||||
return LIBSSH2_ERROR_EAGAIN;
|
||||
@@ -225,8 +211,8 @@ agent_transact_unix(LIBSSH2_AGENT *agent, agent_transaction_ctx_t transctx)
|
||||
|
||||
/* Receive the response body */
|
||||
if(transctx->state == agent_NB_state_response_length_received) {
|
||||
rc = LIBSSH2_RECV_FD(agent->session, agent->fd, transctx->response,
|
||||
transctx->response_len, 0);
|
||||
rc = _recv_all(agent->session->recv, agent->fd, transctx->response,
|
||||
transctx->response_len, 0, &agent->session->abstract);
|
||||
if(rc < 0) {
|
||||
if(rc == -EAGAIN)
|
||||
return LIBSSH2_ERROR_EAGAIN;
|
||||
@@ -274,7 +260,7 @@ static int
|
||||
agent_connect_pageant(LIBSSH2_AGENT *agent)
|
||||
{
|
||||
HWND hwnd;
|
||||
hwnd = FindWindow("Pageant", "Pageant");
|
||||
hwnd = FindWindowA("Pageant", "Pageant");
|
||||
if(!hwnd)
|
||||
return _libssh2_error(agent->session, LIBSSH2_ERROR_AGENT_PROTOCOL,
|
||||
"failed connecting agent");
|
||||
@@ -297,14 +283,14 @@ agent_transact_pageant(LIBSSH2_AGENT *agent, agent_transaction_ctx_t transctx)
|
||||
return _libssh2_error(agent->session, LIBSSH2_ERROR_INVAL,
|
||||
"illegal input");
|
||||
|
||||
hwnd = FindWindow("Pageant", "Pageant");
|
||||
hwnd = FindWindowA("Pageant", "Pageant");
|
||||
if(!hwnd)
|
||||
return _libssh2_error(agent->session, LIBSSH2_ERROR_AGENT_PROTOCOL,
|
||||
"found no pageant");
|
||||
|
||||
snprintf(mapname, sizeof(mapname),
|
||||
"PageantRequest%08x%c", (unsigned)GetCurrentThreadId(), '\0');
|
||||
filemap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
|
||||
filemap = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
|
||||
0, PAGEANT_MAX_MSGLEN, mapname);
|
||||
|
||||
if(filemap == NULL || filemap == INVALID_HANDLE_VALUE)
|
||||
@@ -370,6 +356,7 @@ static struct {
|
||||
} supported_backends[] = {
|
||||
#ifdef WIN32
|
||||
{"Pageant", &agent_ops_pageant},
|
||||
{"OpenSSH", &agent_ops_openssh},
|
||||
#endif /* WIN32 */
|
||||
#ifdef PF_UNIX
|
||||
{"Unix", &agent_ops_unix},
|
||||
@@ -407,6 +394,7 @@ agent_sign(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len,
|
||||
_libssh2_store_u32(&s, 0);
|
||||
|
||||
transctx->request_len = s - transctx->request;
|
||||
transctx->send_recv_total = 0;
|
||||
transctx->state = agent_NB_state_request_created;
|
||||
}
|
||||
|
||||
@@ -507,6 +495,7 @@ agent_list_identities(LIBSSH2_AGENT *agent)
|
||||
if(transctx->state == agent_NB_state_init) {
|
||||
transctx->request = &c;
|
||||
transctx->request_len = 1;
|
||||
transctx->send_recv_total = 0;
|
||||
transctx->state = agent_NB_state_request_created;
|
||||
}
|
||||
|
||||
@@ -683,6 +672,12 @@ libssh2_agent_init(LIBSSH2_SESSION *session)
|
||||
agent->identity_agent_path = NULL;
|
||||
_libssh2_list_init(&agent->head);
|
||||
|
||||
#ifdef WIN32
|
||||
agent->pipe = INVALID_HANDLE_VALUE;
|
||||
memset(&agent->overlapped, 0, sizeof(OVERLAPPED));
|
||||
agent->pending_io = FALSE;
|
||||
#endif
|
||||
|
||||
return agent;
|
||||
}
|
||||
|
||||
|
112
src/agent.h
Normal file
112
src/agent.h
Normal file
@@ -0,0 +1,112 @@
|
||||
#ifndef __LIBSSH2_AGENT_H
|
||||
#define __LIBSSH2_AGENT_H
|
||||
/*
|
||||
* Copyright (c) 2009 by Daiki Ueno
|
||||
* Copyright (C) 2010-2014 by Daniel Stenberg
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
* that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* Neither the name of the copyright holder nor the names
|
||||
* of any other contributors may be used to endorse or
|
||||
* promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "libssh2_priv.h"
|
||||
#include "misc.h"
|
||||
#include "session.h"
|
||||
#ifdef WIN32
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
/* non-blocking mode on agent connection is not yet implemented, but
|
||||
for future use. */
|
||||
typedef enum {
|
||||
agent_NB_state_init = 0,
|
||||
agent_NB_state_request_created,
|
||||
agent_NB_state_request_length_sent,
|
||||
agent_NB_state_request_sent,
|
||||
agent_NB_state_response_length_received,
|
||||
agent_NB_state_response_received
|
||||
} agent_nonblocking_states;
|
||||
|
||||
typedef struct agent_transaction_ctx {
|
||||
unsigned char *request;
|
||||
size_t request_len;
|
||||
unsigned char *response;
|
||||
size_t response_len;
|
||||
agent_nonblocking_states state;
|
||||
size_t send_recv_total;
|
||||
} *agent_transaction_ctx_t;
|
||||
|
||||
typedef int (*agent_connect_func)(LIBSSH2_AGENT *agent);
|
||||
typedef int (*agent_transact_func)(LIBSSH2_AGENT *agent,
|
||||
agent_transaction_ctx_t transctx);
|
||||
typedef int (*agent_disconnect_func)(LIBSSH2_AGENT *agent);
|
||||
|
||||
struct agent_publickey {
|
||||
struct list_node node;
|
||||
|
||||
/* this is the struct we expose externally */
|
||||
struct libssh2_agent_publickey external;
|
||||
};
|
||||
|
||||
struct agent_ops {
|
||||
agent_connect_func connect;
|
||||
agent_transact_func transact;
|
||||
agent_disconnect_func disconnect;
|
||||
};
|
||||
|
||||
struct _LIBSSH2_AGENT
|
||||
{
|
||||
LIBSSH2_SESSION *session; /* the session this "belongs to" */
|
||||
|
||||
libssh2_socket_t fd;
|
||||
|
||||
struct agent_ops *ops;
|
||||
|
||||
struct agent_transaction_ctx transctx;
|
||||
struct agent_publickey *identity;
|
||||
struct list_head head; /* list of public keys */
|
||||
|
||||
char *identity_agent_path; /* Path to a custom identity agent socket */
|
||||
|
||||
#ifdef WIN32
|
||||
OVERLAPPED overlapped;
|
||||
HANDLE pipe;
|
||||
BOOL pending_io;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef WIN32
|
||||
extern struct agent_ops agent_ops_openssh;
|
||||
#endif
|
||||
|
||||
#endif /* __LIBSSH2_AGENT_H */
|
361
src/agent_win.c
Normal file
361
src/agent_win.c
Normal file
@@ -0,0 +1,361 @@
|
||||
/*
|
||||
* Copyright (c) 2009 by Daiki Ueno
|
||||
* Copyright (C) 2010-2014 by Daniel Stenberg
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
* that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* Neither the name of the copyright holder nor the names
|
||||
* of any other contributors may be used to endorse or
|
||||
* promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "libssh2_priv.h"
|
||||
#include "agent.h"
|
||||
#include "misc.h"
|
||||
#include <errno.h>
|
||||
#ifdef HAVE_SYS_UN_H
|
||||
#include <sys/un.h>
|
||||
#else
|
||||
/* Use the existence of sys/un.h as a test if Unix domain socket is
|
||||
supported. winsock*.h define PF_UNIX/AF_UNIX but do not actually
|
||||
support them. */
|
||||
#undef PF_UNIX
|
||||
#endif
|
||||
#include "userauth.h"
|
||||
#include "session.h"
|
||||
#ifdef WIN32
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
/* Code to talk to OpenSSH was taken and modified from the Win32 port of
|
||||
* Portable OpenSSH by the PowerShell team. Commit
|
||||
* 8ab565c53f3619d6a1f5ac229e212cad8a52852c of
|
||||
* https://github.com/PowerShell/openssh-portable.git was used as the base,
|
||||
* specificaly the following files:
|
||||
*
|
||||
* - contrib\win32\win32compat\fileio.c
|
||||
* - Structure of agent_connect_openssh from ssh_get_authentication_socket
|
||||
* - Structure of agent_transact_openssh from ssh_request_reply
|
||||
* - contrib\win32\win32compat\wmain_common.c
|
||||
* - Windows equivalent functions for common Unix functions, inlined into
|
||||
* this implementation
|
||||
* - fileio_connect replacing connect
|
||||
* - fileio_read replacing read
|
||||
* - fileio_write replacing write
|
||||
* - fileio_close replacing close
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* Functions for connecting the local authentication agent.
|
||||
*
|
||||
* As far as I am concerned, the code I have written for this software
|
||||
* can be used freely for any purpose. Any derived versions of this
|
||||
* software must be clearly marked as such, and if the derived work is
|
||||
* incompatible with the protocol description in the RFC file, it must be
|
||||
* called by a name other than "ssh" or "Secure Shell".
|
||||
*
|
||||
* SSH2 implementation,
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Copyright (c) 2015 Microsoft Corp.
|
||||
* All rights reserved
|
||||
*
|
||||
* Microsoft openssh win32 port
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#define WIN32_OPENSSH_AGENT_SOCK "\\\\.\\pipe\\openssh-ssh-agent"
|
||||
|
||||
static int
|
||||
agent_connect_openssh(LIBSSH2_AGENT *agent)
|
||||
{
|
||||
int ret = LIBSSH2_ERROR_NONE;
|
||||
const char *path;
|
||||
HANDLE pipe = INVALID_HANDLE_VALUE;
|
||||
HANDLE event = NULL;
|
||||
|
||||
path = agent->identity_agent_path;
|
||||
if(!path) {
|
||||
path = getenv("SSH_AUTH_SOCK");
|
||||
if(!path)
|
||||
path = WIN32_OPENSSH_AGENT_SOCK;
|
||||
}
|
||||
|
||||
for(;;) {
|
||||
pipe = CreateFileA(
|
||||
path,
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
0,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
/* Non-blocking mode for agent connections is not implemented at
|
||||
* the point this was implemented. The code for Win32 OpenSSH
|
||||
* should support non-blocking IO, but the code calling it doesn't
|
||||
* support it as of yet.
|
||||
* When non-blocking IO is implemented for the surrounding code,
|
||||
* uncomment the following line to enable support within the Win32
|
||||
* OpenSSH code.
|
||||
*/
|
||||
/* FILE_FLAG_OVERLAPPED | */
|
||||
SECURITY_SQOS_PRESENT |
|
||||
SECURITY_IDENTIFICATION,
|
||||
NULL
|
||||
);
|
||||
|
||||
if(pipe != INVALID_HANDLE_VALUE)
|
||||
break;
|
||||
if(GetLastError() != ERROR_PIPE_BUSY)
|
||||
break;
|
||||
|
||||
/* Wait up to 1 second for a pipe instance to become available */
|
||||
if(!WaitNamedPipeA(path, 1000))
|
||||
break;
|
||||
}
|
||||
|
||||
if(pipe == INVALID_HANDLE_VALUE) {
|
||||
ret = _libssh2_error(agent->session, LIBSSH2_ERROR_AGENT_PROTOCOL,
|
||||
"unable to connect to agent pipe");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if(SetHandleInformation(pipe, HANDLE_FLAG_INHERIT, 0) == FALSE) {
|
||||
ret = _libssh2_error(agent->session, LIBSSH2_ERROR_AGENT_PROTOCOL,
|
||||
"unable to set handle information of agent pipe");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
event = CreateEventA(NULL, TRUE, FALSE, NULL);
|
||||
if(event == NULL) {
|
||||
ret = _libssh2_error(agent->session, LIBSSH2_ERROR_AGENT_PROTOCOL,
|
||||
"unable to create async I/O event");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
agent->pipe = pipe;
|
||||
pipe = INVALID_HANDLE_VALUE;
|
||||
agent->overlapped.hEvent = event;
|
||||
event = NULL;
|
||||
agent->fd = 0; /* Mark as the connection has been established */
|
||||
|
||||
cleanup:
|
||||
if(event != NULL)
|
||||
CloseHandle(event);
|
||||
if(pipe != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(pipe);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define RECV_SEND_ALL(func, agent, buffer, length, total) \
|
||||
DWORD bytes_transfered; \
|
||||
BOOL ret; \
|
||||
DWORD err; \
|
||||
int rc; \
|
||||
\
|
||||
while(*total < length) { \
|
||||
if(!agent->pending_io) \
|
||||
ret = func(agent->pipe, (char *)buffer + *total, \
|
||||
(DWORD)(length - *total), &bytes_transfered, \
|
||||
&agent->overlapped); \
|
||||
else \
|
||||
ret = GetOverlappedResult(agent->pipe, &agent->overlapped, \
|
||||
&bytes_transfered, FALSE); \
|
||||
\
|
||||
*total += bytes_transfered; \
|
||||
if(!ret) { \
|
||||
err = GetLastError(); \
|
||||
if((!agent->pending_io && ERROR_IO_PENDING == err) \
|
||||
|| (agent->pending_io && ERROR_IO_INCOMPLETE == err)) { \
|
||||
agent->pending_io = TRUE; \
|
||||
return LIBSSH2_ERROR_EAGAIN; \
|
||||
} \
|
||||
\
|
||||
return LIBSSH2_ERROR_SOCKET_NONE; \
|
||||
} \
|
||||
agent->pending_io = FALSE; \
|
||||
} \
|
||||
\
|
||||
rc = (int)*total; \
|
||||
*total = 0; \
|
||||
return rc;
|
||||
|
||||
static int
|
||||
win32_openssh_send_all(LIBSSH2_AGENT *agent, void *buffer, size_t length,
|
||||
size_t *send_recv_total)
|
||||
{
|
||||
RECV_SEND_ALL(WriteFile, agent, buffer, length, send_recv_total)
|
||||
}
|
||||
|
||||
static int
|
||||
win32_openssh_recv_all(LIBSSH2_AGENT *agent, void *buffer, size_t length,
|
||||
size_t *send_recv_total)
|
||||
{
|
||||
RECV_SEND_ALL(ReadFile, agent, buffer, length, send_recv_total)
|
||||
}
|
||||
|
||||
#undef RECV_SEND_ALL
|
||||
|
||||
static int
|
||||
agent_transact_openssh(LIBSSH2_AGENT *agent, agent_transaction_ctx_t transctx)
|
||||
{
|
||||
unsigned char buf[4];
|
||||
int rc;
|
||||
|
||||
/* Send the length of the request */
|
||||
if(transctx->state == agent_NB_state_request_created) {
|
||||
_libssh2_htonu32(buf, (uint32_t)transctx->request_len);
|
||||
rc = win32_openssh_send_all(agent, buf, sizeof buf,
|
||||
&transctx->send_recv_total);
|
||||
if(rc == LIBSSH2_ERROR_EAGAIN)
|
||||
return LIBSSH2_ERROR_EAGAIN;
|
||||
else if(rc < 0)
|
||||
return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_SEND,
|
||||
"agent send failed");
|
||||
transctx->state = agent_NB_state_request_length_sent;
|
||||
}
|
||||
|
||||
/* Send the request body */
|
||||
if(transctx->state == agent_NB_state_request_length_sent) {
|
||||
rc = win32_openssh_send_all(agent, transctx->request,
|
||||
transctx->request_len,
|
||||
&transctx->send_recv_total);
|
||||
if(rc == LIBSSH2_ERROR_EAGAIN)
|
||||
return LIBSSH2_ERROR_EAGAIN;
|
||||
else if(rc < 0)
|
||||
return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_SEND,
|
||||
"agent send failed");
|
||||
transctx->state = agent_NB_state_request_sent;
|
||||
}
|
||||
|
||||
/* Receive the length of the body */
|
||||
if(transctx->state == agent_NB_state_request_sent) {
|
||||
rc = win32_openssh_recv_all(agent, buf, sizeof buf,
|
||||
&transctx->send_recv_total);
|
||||
if(rc == LIBSSH2_ERROR_EAGAIN)
|
||||
return LIBSSH2_ERROR_EAGAIN;
|
||||
else if(rc < 0)
|
||||
return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_RECV,
|
||||
"agent recv failed");
|
||||
|
||||
transctx->response_len = _libssh2_ntohu32(buf);
|
||||
transctx->response = LIBSSH2_ALLOC(agent->session,
|
||||
transctx->response_len);
|
||||
if(!transctx->response)
|
||||
return LIBSSH2_ERROR_ALLOC;
|
||||
|
||||
transctx->state = agent_NB_state_response_length_received;
|
||||
}
|
||||
|
||||
/* Receive the response body */
|
||||
if(transctx->state == agent_NB_state_response_length_received) {
|
||||
rc = win32_openssh_recv_all(agent, transctx->response,
|
||||
transctx->response_len,
|
||||
&transctx->send_recv_total);
|
||||
if(rc == LIBSSH2_ERROR_EAGAIN)
|
||||
return LIBSSH2_ERROR_EAGAIN;
|
||||
else if(rc < 0)
|
||||
return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_RECV,
|
||||
"agent recv failed");
|
||||
transctx->state = agent_NB_state_response_received;
|
||||
}
|
||||
|
||||
return LIBSSH2_ERROR_NONE;
|
||||
}
|
||||
|
||||
static int
|
||||
agent_disconnect_openssh(LIBSSH2_AGENT *agent)
|
||||
{
|
||||
if(!CancelIo(agent->pipe))
|
||||
return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_DISCONNECT,
|
||||
"failed to cancel pending IO of agent pipe");
|
||||
if(!CloseHandle(agent->overlapped.hEvent))
|
||||
return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_DISCONNECT,
|
||||
"failed to close handle to async I/O event");
|
||||
agent->overlapped.hEvent = NULL;
|
||||
/* let queued APCs (if any) drain */
|
||||
SleepEx(0, TRUE);
|
||||
if(!CloseHandle(agent->pipe))
|
||||
return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_DISCONNECT,
|
||||
"failed to close handle to agent pipe");
|
||||
|
||||
agent->pipe = INVALID_HANDLE_VALUE;
|
||||
agent->fd = LIBSSH2_INVALID_SOCKET;
|
||||
|
||||
return LIBSSH2_ERROR_NONE;
|
||||
}
|
||||
|
||||
struct agent_ops agent_ops_openssh = {
|
||||
agent_connect_openssh,
|
||||
agent_transact_openssh,
|
||||
agent_disconnect_openssh
|
||||
};
|
||||
#endif /* WIN32 */
|
@@ -81,7 +81,7 @@ bcrypt_hash(uint8_t *sha2pass, uint8_t *sha2salt, uint8_t *out)
|
||||
cdata[i] = Blowfish_stream2word(ciphertext, sizeof(ciphertext),
|
||||
&j);
|
||||
for(i = 0; i < 64; i++)
|
||||
blf_enc(&state, cdata, sizeof(cdata) / sizeof(uint64_t));
|
||||
blf_enc(&state, cdata, BCRYPT_BLOCKS / 2);
|
||||
|
||||
/* copy out */
|
||||
for(i = 0; i < BCRYPT_BLOCKS; i++) {
|
||||
@@ -127,7 +127,7 @@ bcrypt_pbkdf(const char *pass, size_t passlen, const uint8_t *salt,
|
||||
memcpy(countsalt, salt, saltlen);
|
||||
|
||||
/* collapse password */
|
||||
libssh2_sha512_init(&ctx);
|
||||
(void)libssh2_sha512_init(&ctx);
|
||||
libssh2_sha512_update(ctx, pass, passlen);
|
||||
libssh2_sha512_final(ctx, sha2pass);
|
||||
|
||||
@@ -139,7 +139,7 @@ bcrypt_pbkdf(const char *pass, size_t passlen, const uint8_t *salt,
|
||||
countsalt[saltlen + 3] = count & 0xff;
|
||||
|
||||
/* first round, salt is salt */
|
||||
libssh2_sha512_init(&ctx);
|
||||
(void)libssh2_sha512_init(&ctx);
|
||||
libssh2_sha512_update(ctx, countsalt, saltlen + 4);
|
||||
libssh2_sha512_final(ctx, sha2salt);
|
||||
|
||||
@@ -148,7 +148,7 @@ bcrypt_pbkdf(const char *pass, size_t passlen, const uint8_t *salt,
|
||||
|
||||
for(i = 1; i < rounds; i++) {
|
||||
/* subsequent rounds, salt is previous output */
|
||||
libssh2_sha512_init(&ctx);
|
||||
(void)libssh2_sha512_init(&ctx);
|
||||
libssh2_sha512_update(ctx, tmpout, sizeof(tmpout));
|
||||
libssh2_sha512_final(ctx, sha2salt);
|
||||
|
||||
|
@@ -1,3 +1,5 @@
|
||||
#ifndef __LIBSSH2_BLF_H
|
||||
#define __LIBSSH2_BLF_H
|
||||
/* $OpenBSD: blf.h,v 1.7 2007/03/14 17:59:41 grunk Exp $ */
|
||||
/*
|
||||
* Blowfish - a fast block cipher designed by Bruce Schneier
|
||||
@@ -31,9 +33,6 @@
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _BLF_H_
|
||||
#define _BLF_H_
|
||||
|
||||
#if !defined(HAVE_BCRYPT_PBKDF) && !defined(HAVE_BLH_H)
|
||||
|
||||
/* Schneier specifies a maximum key length of 56 bytes.
|
||||
@@ -87,4 +86,4 @@ int bcrypt_pbkdf(const char *pass, size_t passlen, const uint8_t *salt,
|
||||
uint8_t *key, size_t keylen, unsigned int rounds);
|
||||
|
||||
#endif /* !defined(HAVE_BCRYPT_PBKDF) && !defined(HAVE_BLH_H) */
|
||||
#endif /* _BLF_H */
|
||||
#endif /* __LIBSSH2_BLF_H */
|
||||
|
@@ -1140,6 +1140,8 @@ libssh2_channel_request_auth_agent(LIBSSH2_CHANNEL *channel)
|
||||
if(!channel)
|
||||
return LIBSSH2_ERROR_BAD_USE;
|
||||
|
||||
rc = LIBSSH2_ERROR_CHANNEL_UNKNOWN;
|
||||
|
||||
/* The current RFC draft for agent forwarding says you're supposed to
|
||||
* send "auth-agent-req," but most SSH servers out there right now
|
||||
* actually expect "auth-agent-req@openssh.com", so we try that
|
||||
@@ -1152,7 +1154,8 @@ libssh2_channel_request_auth_agent(LIBSSH2_CHANNEL *channel)
|
||||
|
||||
/* If we failed (but not with EAGAIN), then we move onto
|
||||
* the next step to try another request type. */
|
||||
if(rc != 0 && rc != LIBSSH2_ERROR_EAGAIN)
|
||||
if(rc != LIBSSH2_ERROR_NONE &&
|
||||
rc != LIBSSH2_ERROR_EAGAIN)
|
||||
channel->req_auth_agent_try_state = libssh2_NB_state_sent;
|
||||
}
|
||||
|
||||
@@ -1163,12 +1166,13 @@ libssh2_channel_request_auth_agent(LIBSSH2_CHANNEL *channel)
|
||||
|
||||
/* If we failed without an EAGAIN, then move on with this
|
||||
* state machine. */
|
||||
if(rc != 0 && rc != LIBSSH2_ERROR_EAGAIN)
|
||||
if(rc != LIBSSH2_ERROR_NONE &&
|
||||
rc != LIBSSH2_ERROR_EAGAIN)
|
||||
channel->req_auth_agent_try_state = libssh2_NB_state_sent1;
|
||||
}
|
||||
|
||||
/* If things are good, reset the try state. */
|
||||
if(rc == 0)
|
||||
if(rc == LIBSSH2_ERROR_NONE)
|
||||
channel->req_auth_agent_try_state = libssh2_NB_state_idle;
|
||||
|
||||
return rc;
|
||||
@@ -1338,7 +1342,11 @@ channel_x11_req(LIBSSH2_CHANNEL *channel, int single_connection,
|
||||
border */
|
||||
unsigned char buffer[(LIBSSH2_X11_RANDOM_COOKIE_LEN / 2) + 1];
|
||||
|
||||
_libssh2_random(buffer, LIBSSH2_X11_RANDOM_COOKIE_LEN / 2);
|
||||
if(_libssh2_random(buffer, LIBSSH2_X11_RANDOM_COOKIE_LEN / 2)) {
|
||||
return _libssh2_error(session, LIBSSH2_ERROR_RANDGEN,
|
||||
"Unable to get random bytes "
|
||||
"for x11-req cookie");
|
||||
}
|
||||
for(i = 0; i < (LIBSSH2_X11_RANDOM_COOKIE_LEN / 2); i++) {
|
||||
snprintf((char *)&s[i*2], 3, "%02X", buffer[i]);
|
||||
}
|
||||
|
@@ -39,6 +39,7 @@
|
||||
#include "libssh2_priv.h"
|
||||
#ifdef LIBSSH2_HAVE_ZLIB
|
||||
#include <zlib.h>
|
||||
#undef compress /* dodge name clash with ZLIB macro */
|
||||
#endif
|
||||
|
||||
#include "comp.h"
|
||||
|
@@ -1,6 +1,5 @@
|
||||
#ifndef __LIBSSH2_COMP_H
|
||||
#define __LIBSSH2_COMP_H
|
||||
|
||||
/* Copyright (C) 2009-2010 by Daniel Stenberg
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
|
10
src/crypto.h
10
src/crypto.h
@@ -1,3 +1,5 @@
|
||||
#ifndef __LIBSSH2_CRYPTO_H
|
||||
#define __LIBSSH2_CRYPTO_H
|
||||
/* Copyright (C) 2009, 2010 Simon Josefsson
|
||||
* Copyright (C) 2006, 2007 The Written Word, Inc. All rights reserved.
|
||||
* Copyright (C) 2010-2019 Daniel Stenberg
|
||||
@@ -35,8 +37,6 @@
|
||||
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef LIBSSH2_CRYPTO_H
|
||||
#define LIBSSH2_CRYPTO_H
|
||||
|
||||
#ifdef LIBSSH2_OPENSSL
|
||||
#include "openssl.h"
|
||||
@@ -181,8 +181,8 @@ _libssh2_ecdsa_curve_type_from_name(const char *name,
|
||||
#if LIBSSH2_ED25519
|
||||
|
||||
int
|
||||
_libssh2_curve25519_new(LIBSSH2_SESSION *session, libssh2_ed25519_ctx **ctx,
|
||||
uint8_t **out_public_key, uint8_t **out_private_key);
|
||||
_libssh2_curve25519_new(LIBSSH2_SESSION *session, uint8_t **out_public_key,
|
||||
uint8_t **out_private_key);
|
||||
|
||||
int
|
||||
_libssh2_curve25519_gen_k(_libssh2_bn **k,
|
||||
@@ -245,4 +245,4 @@ int _libssh2_pub_priv_keyfilememory(LIBSSH2_SESSION *session,
|
||||
size_t privatekeydata_len,
|
||||
const char *passphrase);
|
||||
|
||||
#endif
|
||||
#endif /* __LIBSSH2_CRYPTO_H */
|
||||
|
@@ -211,7 +211,7 @@ hostkey_method_ssh_rsa_signv(LIBSSH2_SESSION * session,
|
||||
unsigned char hash[SHA_DIGEST_LENGTH];
|
||||
libssh2_sha1_ctx ctx;
|
||||
|
||||
libssh2_sha1_init(&ctx);
|
||||
(void)libssh2_sha1_init(&ctx);
|
||||
for(i = 0; i < veccount; i++) {
|
||||
libssh2_sha1_update(ctx, datavec[i].iov_base, datavec[i].iov_len);
|
||||
}
|
||||
@@ -438,7 +438,7 @@ hostkey_method_ssh_dss_signv(LIBSSH2_SESSION * session,
|
||||
|
||||
*signature_len = 2 * SHA_DIGEST_LENGTH;
|
||||
|
||||
libssh2_sha1_init(&ctx);
|
||||
(void)libssh2_sha1_init(&ctx);
|
||||
for(i = 0; i < veccount; i++) {
|
||||
libssh2_sha1_update(ctx, datavec[i].iov_base, datavec[i].iov_len);
|
||||
}
|
||||
@@ -647,7 +647,7 @@ hostkey_method_ssh_ecdsa_sig_verify(LIBSSH2_SESSION * session,
|
||||
{
|
||||
unsigned char *r, *s, *name;
|
||||
size_t r_len, s_len, name_len;
|
||||
unsigned int len;
|
||||
uint32_t len;
|
||||
struct string_buf buf;
|
||||
libssh2_ecdsa_ctx *ctx = (libssh2_ecdsa_ctx *) (*abstract);
|
||||
|
||||
@@ -683,7 +683,7 @@ hostkey_method_ssh_ecdsa_sig_verify(LIBSSH2_SESSION * session,
|
||||
unsigned char hash[SHA##digest_type##_DIGEST_LENGTH]; \
|
||||
libssh2_sha##digest_type##_ctx ctx; \
|
||||
int i; \
|
||||
libssh2_sha##digest_type##_init(&ctx); \
|
||||
(void)libssh2_sha##digest_type##_init(&ctx); \
|
||||
for(i = 0; i < veccount; i++) { \
|
||||
libssh2_sha##digest_type##_update(ctx, datavec[i].iov_base, \
|
||||
datavec[i].iov_len); \
|
||||
@@ -783,6 +783,42 @@ static const LIBSSH2_HOSTKEY_METHOD hostkey_method_ecdsa_ssh_nistp521 = {
|
||||
hostkey_method_ssh_ecdsa_dtor,
|
||||
};
|
||||
|
||||
static const LIBSSH2_HOSTKEY_METHOD hostkey_method_ecdsa_ssh_nistp256_cert = {
|
||||
"ecdsa-sha2-nistp256-cert-v01@openssh.com",
|
||||
SHA256_DIGEST_LENGTH,
|
||||
NULL,
|
||||
hostkey_method_ssh_ecdsa_initPEM,
|
||||
hostkey_method_ssh_ecdsa_initPEMFromMemory,
|
||||
NULL,
|
||||
hostkey_method_ssh_ecdsa_signv,
|
||||
NULL, /* encrypt */
|
||||
hostkey_method_ssh_ecdsa_dtor,
|
||||
};
|
||||
|
||||
static const LIBSSH2_HOSTKEY_METHOD hostkey_method_ecdsa_ssh_nistp384_cert = {
|
||||
"ecdsa-sha2-nistp384-cert-v01@openssh.com",
|
||||
SHA384_DIGEST_LENGTH,
|
||||
NULL,
|
||||
hostkey_method_ssh_ecdsa_initPEM,
|
||||
hostkey_method_ssh_ecdsa_initPEMFromMemory,
|
||||
NULL,
|
||||
hostkey_method_ssh_ecdsa_signv,
|
||||
NULL, /* encrypt */
|
||||
hostkey_method_ssh_ecdsa_dtor,
|
||||
};
|
||||
|
||||
static const LIBSSH2_HOSTKEY_METHOD hostkey_method_ecdsa_ssh_nistp521_cert = {
|
||||
"ecdsa-sha2-nistp521-cert-v01@openssh.com",
|
||||
SHA512_DIGEST_LENGTH,
|
||||
NULL,
|
||||
hostkey_method_ssh_ecdsa_initPEM,
|
||||
hostkey_method_ssh_ecdsa_initPEMFromMemory,
|
||||
NULL,
|
||||
hostkey_method_ssh_ecdsa_signv,
|
||||
NULL, /* encrypt */
|
||||
hostkey_method_ssh_ecdsa_dtor,
|
||||
};
|
||||
|
||||
#endif /* LIBSSH2_ECDSA */
|
||||
|
||||
#if LIBSSH2_ED25519
|
||||
@@ -999,6 +1035,9 @@ static const LIBSSH2_HOSTKEY_METHOD *hostkey_methods[] = {
|
||||
&hostkey_method_ecdsa_ssh_nistp256,
|
||||
&hostkey_method_ecdsa_ssh_nistp384,
|
||||
&hostkey_method_ecdsa_ssh_nistp521,
|
||||
&hostkey_method_ecdsa_ssh_nistp256_cert,
|
||||
&hostkey_method_ecdsa_ssh_nistp384_cert,
|
||||
&hostkey_method_ecdsa_ssh_nistp521_cert,
|
||||
#endif
|
||||
#if LIBSSH2_ED25519
|
||||
&hostkey_method_ssh_ed25519,
|
||||
|
@@ -1,3 +1,5 @@
|
||||
#ifndef __LIBSSH2_LIBGCRYPT_H
|
||||
#define __LIBSSH2_LIBGCRYPT_H
|
||||
/*
|
||||
* Copyright (C) 2008, 2009, 2010 Simon Josefsson
|
||||
* Copyright (C) 2006, 2007, The Written Word, Inc.
|
||||
@@ -66,7 +68,7 @@
|
||||
#define EC_MAX_POINT_LEN ((528 * 2 / 8) + 1)
|
||||
|
||||
#define _libssh2_random(buf, len) \
|
||||
(gcry_randomize ((buf), (len), GCRY_STRONG_RANDOM), 1)
|
||||
(gcry_randomize ((buf), (len), GCRY_STRONG_RANDOM), 0)
|
||||
|
||||
#define libssh2_prepare_iovec(vec, len) /* Empty. */
|
||||
|
||||
@@ -232,3 +234,4 @@ extern int _libssh2_dh_secret(_libssh2_dh_ctx *dhctx, _libssh2_bn *secret,
|
||||
_libssh2_bn *f, _libssh2_bn *p);
|
||||
extern void _libssh2_dh_dtor(_libssh2_dh_ctx *dhctx);
|
||||
|
||||
#endif /* __LIBSSH2_LIBGCRYPT_H */
|
||||
|
@@ -1,3 +1,5 @@
|
||||
#ifndef __LIBSSH2_PRIV_H
|
||||
#define __LIBSSH2_PRIV_H
|
||||
/* Copyright (c) 2004-2008, 2010, Sara Golemon <sarag@libssh2.org>
|
||||
* Copyright (c) 2009-2014 by Daniel Stenberg
|
||||
* Copyright (c) 2010 Simon Josefsson
|
||||
@@ -37,9 +39,6 @@
|
||||
* OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef LIBSSH2_PRIV_H
|
||||
#define LIBSSH2_PRIV_H 1
|
||||
|
||||
#define LIBSSH2_LIBRARY
|
||||
#include "libssh2_config.h"
|
||||
|
||||
@@ -110,14 +109,19 @@
|
||||
#define inline __inline
|
||||
#endif
|
||||
|
||||
/* Provide iovec / writev on WIN32 platform. */
|
||||
#ifdef WIN32
|
||||
/* 3DS doesn't seem to have iovec */
|
||||
#if defined(WIN32) || defined(_3DS)
|
||||
|
||||
struct iovec {
|
||||
size_t iov_len;
|
||||
void *iov_base;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/* Provide iovec / writev on WIN32 platform. */
|
||||
#ifdef WIN32
|
||||
|
||||
static inline int writev(int sock, struct iovec *iov, int nvecs)
|
||||
{
|
||||
DWORD ret;
|
||||
@@ -1149,4 +1153,4 @@ endings either CRLF or LF so 't' is appropriate.
|
||||
#define FOPEN_APPENDTEXT "a"
|
||||
#endif
|
||||
|
||||
#endif /* LIBSSH2_H */
|
||||
#endif /* __LIBSSH2_PRIV_H */
|
||||
|
@@ -1,6 +1,5 @@
|
||||
#ifndef __LIBSSH2_MAC_H
|
||||
#define __LIBSSH2_MAC_H
|
||||
|
||||
/* Copyright (C) 2009-2010 by Daniel Stenberg
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
|
520
src/mbedtls.c
520
src/mbedtls.c
@@ -94,7 +94,7 @@ _libssh2_mbedtls_safe_free(void *buf, int len)
|
||||
|
||||
#ifdef LIBSSH2_CLEAR_MEMORY
|
||||
if(len > 0)
|
||||
memset(buf, 0, len);
|
||||
_libssh2_explicit_zero(buf, len);
|
||||
#endif
|
||||
|
||||
mbedtls_free(buf);
|
||||
@@ -730,4 +730,522 @@ _libssh2_dh_dtor(_libssh2_dh_ctx *dhctx)
|
||||
*dhctx = NULL;
|
||||
}
|
||||
|
||||
#if LIBSSH2_ECDSA
|
||||
|
||||
/*******************************************************************/
|
||||
/*
|
||||
* mbedTLS backend: ECDSA functions
|
||||
*/
|
||||
|
||||
/*
|
||||
* _libssh2_ecdsa_create_key
|
||||
*
|
||||
* Creates a local private key based on input curve
|
||||
* and returns octal value and octal length
|
||||
*
|
||||
*/
|
||||
|
||||
int
|
||||
_libssh2_mbedtls_ecdsa_create_key(LIBSSH2_SESSION *session,
|
||||
_libssh2_ec_key **privkey,
|
||||
unsigned char **pubkey_oct,
|
||||
size_t *pubkey_oct_len,
|
||||
libssh2_curve_type curve)
|
||||
{
|
||||
size_t plen = 0;
|
||||
|
||||
*privkey = LIBSSH2_ALLOC(session, sizeof(mbedtls_ecp_keypair));
|
||||
|
||||
if(*privkey == NULL)
|
||||
goto failed;
|
||||
|
||||
mbedtls_ecdsa_init(*privkey);
|
||||
|
||||
if(mbedtls_ecdsa_genkey(*privkey, (mbedtls_ecp_group_id)curve,
|
||||
mbedtls_ctr_drbg_random,
|
||||
&_libssh2_mbedtls_ctr_drbg) != 0)
|
||||
goto failed;
|
||||
|
||||
plen = 2 * mbedtls_mpi_size(&(*privkey)->grp.P) + 1;
|
||||
*pubkey_oct = LIBSSH2_ALLOC(session, plen);
|
||||
|
||||
if(*pubkey_oct == NULL)
|
||||
goto failed;
|
||||
|
||||
if(mbedtls_ecp_point_write_binary(&(*privkey)->grp, &(*privkey)->Q,
|
||||
MBEDTLS_ECP_PF_UNCOMPRESSED,
|
||||
pubkey_oct_len, *pubkey_oct, plen) == 0)
|
||||
return 0;
|
||||
|
||||
failed:
|
||||
|
||||
_libssh2_mbedtls_ecdsa_free(*privkey);
|
||||
_libssh2_mbedtls_safe_free(*pubkey_oct, plen);
|
||||
*privkey = NULL;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* _libssh2_ecdsa_curve_name_with_octal_new
|
||||
*
|
||||
* Creates a new public key given an octal string, length and type
|
||||
*
|
||||
*/
|
||||
|
||||
int
|
||||
_libssh2_mbedtls_ecdsa_curve_name_with_octal_new(libssh2_ecdsa_ctx **ctx,
|
||||
const unsigned char *k,
|
||||
size_t k_len,
|
||||
libssh2_curve_type curve)
|
||||
{
|
||||
*ctx = mbedtls_calloc(1, sizeof(mbedtls_ecp_keypair));
|
||||
|
||||
if(*ctx == NULL)
|
||||
goto failed;
|
||||
|
||||
mbedtls_ecdsa_init(*ctx);
|
||||
|
||||
if(mbedtls_ecp_group_load(&(*ctx)->grp, (mbedtls_ecp_group_id)curve) != 0)
|
||||
goto failed;
|
||||
|
||||
if(mbedtls_ecp_point_read_binary(&(*ctx)->grp, &(*ctx)->Q, k, k_len) != 0)
|
||||
goto failed;
|
||||
|
||||
if(mbedtls_ecp_check_pubkey(&(*ctx)->grp, &(*ctx)->Q) == 0)
|
||||
return 0;
|
||||
|
||||
failed:
|
||||
|
||||
_libssh2_mbedtls_ecdsa_free(*ctx);
|
||||
*ctx = NULL;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* _libssh2_ecdh_gen_k
|
||||
*
|
||||
* Computes the shared secret K given a local private key,
|
||||
* remote public key and length
|
||||
*/
|
||||
|
||||
int
|
||||
_libssh2_mbedtls_ecdh_gen_k(_libssh2_bn **k,
|
||||
_libssh2_ec_key *privkey,
|
||||
const unsigned char *server_pubkey,
|
||||
size_t server_pubkey_len)
|
||||
{
|
||||
mbedtls_ecp_point pubkey;
|
||||
int rc = 0;
|
||||
|
||||
if(*k == NULL)
|
||||
return -1;
|
||||
|
||||
mbedtls_ecp_point_init(&pubkey);
|
||||
|
||||
if(mbedtls_ecp_point_read_binary(&privkey->grp, &pubkey,
|
||||
server_pubkey, server_pubkey_len) != 0) {
|
||||
rc = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if(mbedtls_ecdh_compute_shared(&privkey->grp, *k,
|
||||
&pubkey, &privkey->d,
|
||||
mbedtls_ctr_drbg_random,
|
||||
&_libssh2_mbedtls_ctr_drbg) != 0) {
|
||||
rc = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if(mbedtls_ecp_check_privkey(&privkey->grp, *k) != 0)
|
||||
rc = -1;
|
||||
|
||||
cleanup:
|
||||
|
||||
mbedtls_ecp_point_free(&pubkey);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
#define LIBSSH2_MBEDTLS_ECDSA_VERIFY(digest_type) \
|
||||
{ \
|
||||
unsigned char hsh[SHA##digest_type##_DIGEST_LENGTH]; \
|
||||
\
|
||||
if(libssh2_sha##digest_type(m, m_len, hsh) == 0) { \
|
||||
rc = mbedtls_ecdsa_verify(&ctx->grp, hsh, \
|
||||
SHA##digest_type##_DIGEST_LENGTH, \
|
||||
&ctx->Q, &pr, &ps); \
|
||||
} \
|
||||
\
|
||||
}
|
||||
|
||||
/* _libssh2_ecdsa_sign
|
||||
*
|
||||
* Verifies the ECDSA signature of a hashed message
|
||||
*
|
||||
*/
|
||||
|
||||
int
|
||||
_libssh2_mbedtls_ecdsa_verify(libssh2_ecdsa_ctx *ctx,
|
||||
const unsigned char *r, size_t r_len,
|
||||
const unsigned char *s, size_t s_len,
|
||||
const unsigned char *m, size_t m_len)
|
||||
{
|
||||
mbedtls_mpi pr, ps;
|
||||
int rc = -1;
|
||||
|
||||
mbedtls_mpi_init(&pr);
|
||||
mbedtls_mpi_init(&ps);
|
||||
|
||||
if(mbedtls_mpi_read_binary(&pr, r, r_len) != 0)
|
||||
goto cleanup;
|
||||
|
||||
if(mbedtls_mpi_read_binary(&ps, s, s_len) != 0)
|
||||
goto cleanup;
|
||||
|
||||
switch(_libssh2_ecdsa_get_curve_type(ctx)) {
|
||||
case LIBSSH2_EC_CURVE_NISTP256:
|
||||
LIBSSH2_MBEDTLS_ECDSA_VERIFY(256);
|
||||
break;
|
||||
case LIBSSH2_EC_CURVE_NISTP384:
|
||||
LIBSSH2_MBEDTLS_ECDSA_VERIFY(384);
|
||||
break;
|
||||
case LIBSSH2_EC_CURVE_NISTP521:
|
||||
LIBSSH2_MBEDTLS_ECDSA_VERIFY(512);
|
||||
break;
|
||||
default:
|
||||
rc = -1;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
|
||||
mbedtls_mpi_free(&pr);
|
||||
mbedtls_mpi_free(&ps);
|
||||
|
||||
return (rc == 0) ? 0 : -1;
|
||||
}
|
||||
|
||||
static int
|
||||
_libssh2_mbedtls_parse_eckey(libssh2_ecdsa_ctx **ctx,
|
||||
mbedtls_pk_context *pkey,
|
||||
LIBSSH2_SESSION *session,
|
||||
const unsigned char *data,
|
||||
size_t data_len,
|
||||
const unsigned char *pwd)
|
||||
{
|
||||
size_t pwd_len;
|
||||
|
||||
pwd_len = pwd ? strlen((const char *) pwd) : 0;
|
||||
|
||||
if(mbedtls_pk_parse_key(pkey, data, data_len, pwd, pwd_len) != 0)
|
||||
goto failed;
|
||||
|
||||
if(mbedtls_pk_get_type(pkey) != MBEDTLS_PK_ECKEY)
|
||||
goto failed;
|
||||
|
||||
*ctx = LIBSSH2_ALLOC(session, sizeof(libssh2_ecdsa_ctx));
|
||||
|
||||
if(*ctx == NULL)
|
||||
goto failed;
|
||||
|
||||
mbedtls_ecdsa_init(*ctx);
|
||||
|
||||
if(mbedtls_ecdsa_from_keypair(*ctx, mbedtls_pk_ec(*pkey)) == 0)
|
||||
return 0;
|
||||
|
||||
failed:
|
||||
|
||||
_libssh2_mbedtls_ecdsa_free(*ctx);
|
||||
*ctx = NULL;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
_libssh2_mbedtls_parse_openssh_key(libssh2_ecdsa_ctx **ctx,
|
||||
LIBSSH2_SESSION *session,
|
||||
const unsigned char *data,
|
||||
size_t data_len,
|
||||
const unsigned char *pwd)
|
||||
{
|
||||
libssh2_curve_type type;
|
||||
unsigned char *name = NULL;
|
||||
struct string_buf *decrypted = NULL;
|
||||
size_t curvelen, exponentlen, pointlen;
|
||||
unsigned char *curve, *exponent, *point_buf;
|
||||
|
||||
if(_libssh2_openssh_pem_parse_memory(session, pwd,
|
||||
(const char *)data, data_len,
|
||||
&decrypted) != 0)
|
||||
goto failed;
|
||||
|
||||
if(_libssh2_get_string(decrypted, &name, NULL) != 0)
|
||||
goto failed;
|
||||
|
||||
if(_libssh2_mbedtls_ecdsa_curve_type_from_name((const char *)name,
|
||||
&type) != 0)
|
||||
goto failed;
|
||||
|
||||
if(_libssh2_get_string(decrypted, &curve, &curvelen) != 0)
|
||||
goto failed;
|
||||
|
||||
if(_libssh2_get_string(decrypted, &point_buf, &pointlen) != 0)
|
||||
goto failed;
|
||||
|
||||
if(_libssh2_get_bignum_bytes(decrypted, &exponent, &exponentlen) != 0)
|
||||
goto failed;
|
||||
|
||||
*ctx = LIBSSH2_ALLOC(session, sizeof(libssh2_ecdsa_ctx));
|
||||
|
||||
if(*ctx == NULL)
|
||||
goto failed;
|
||||
|
||||
mbedtls_ecdsa_init(*ctx);
|
||||
|
||||
if(mbedtls_ecp_group_load(&(*ctx)->grp, (mbedtls_ecp_group_id)type) != 0)
|
||||
goto failed;
|
||||
|
||||
if(mbedtls_mpi_read_binary(&(*ctx)->d, exponent, exponentlen) != 0)
|
||||
goto failed;
|
||||
|
||||
if(mbedtls_ecp_mul(&(*ctx)->grp, &(*ctx)->Q,
|
||||
&(*ctx)->d, &(*ctx)->grp.G,
|
||||
mbedtls_ctr_drbg_random,
|
||||
&_libssh2_mbedtls_ctr_drbg) != 0)
|
||||
goto failed;
|
||||
|
||||
if(mbedtls_ecp_check_privkey(&(*ctx)->grp, &(*ctx)->d) == 0)
|
||||
goto cleanup;
|
||||
|
||||
failed:
|
||||
|
||||
_libssh2_mbedtls_ecdsa_free(*ctx);
|
||||
*ctx = NULL;
|
||||
|
||||
cleanup:
|
||||
|
||||
if(decrypted) {
|
||||
_libssh2_string_buf_free(session, decrypted);
|
||||
}
|
||||
|
||||
return (*ctx == NULL) ? -1 : 0;
|
||||
}
|
||||
|
||||
/* _libssh2_ecdsa_new_private
|
||||
*
|
||||
* Creates a new private key given a file path and password
|
||||
*
|
||||
*/
|
||||
|
||||
int
|
||||
_libssh2_mbedtls_ecdsa_new_private(libssh2_ecdsa_ctx **ctx,
|
||||
LIBSSH2_SESSION *session,
|
||||
const char *filename,
|
||||
const unsigned char *pwd)
|
||||
{
|
||||
mbedtls_pk_context pkey;
|
||||
unsigned char *data;
|
||||
size_t data_len;
|
||||
|
||||
if(mbedtls_pk_load_file(filename, &data, &data_len) != 0)
|
||||
goto cleanup;
|
||||
|
||||
mbedtls_pk_init(&pkey);
|
||||
|
||||
if(_libssh2_mbedtls_parse_eckey(ctx, &pkey, session,
|
||||
data, data_len, pwd) == 0)
|
||||
goto cleanup;
|
||||
|
||||
_libssh2_mbedtls_parse_openssh_key(ctx, session, data, data_len, pwd);
|
||||
|
||||
cleanup:
|
||||
|
||||
mbedtls_pk_free(&pkey);
|
||||
|
||||
_libssh2_mbedtls_safe_free(data, data_len);
|
||||
|
||||
return (*ctx == NULL) ? -1 : 0;
|
||||
}
|
||||
|
||||
/* _libssh2_ecdsa_new_private
|
||||
*
|
||||
* Creates a new private key given a file data and password
|
||||
*
|
||||
*/
|
||||
|
||||
int
|
||||
_libssh2_mbedtls_ecdsa_new_private_frommemory(libssh2_ecdsa_ctx **ctx,
|
||||
LIBSSH2_SESSION *session,
|
||||
const char *data,
|
||||
size_t data_len,
|
||||
const unsigned char *pwd)
|
||||
{
|
||||
unsigned char *ntdata;
|
||||
mbedtls_pk_context pkey;
|
||||
|
||||
mbedtls_pk_init(&pkey);
|
||||
|
||||
ntdata = LIBSSH2_ALLOC(session, data_len + 1);
|
||||
|
||||
if(ntdata == NULL)
|
||||
goto cleanup;
|
||||
|
||||
memcpy(ntdata, data, data_len);
|
||||
|
||||
if(_libssh2_mbedtls_parse_eckey(ctx, &pkey, session,
|
||||
ntdata, data_len + 1, pwd) == 0)
|
||||
goto cleanup;
|
||||
|
||||
_libssh2_mbedtls_parse_openssh_key(ctx, session,
|
||||
ntdata, data_len + 1, pwd);
|
||||
|
||||
cleanup:
|
||||
|
||||
mbedtls_pk_free(&pkey);
|
||||
|
||||
_libssh2_mbedtls_safe_free(ntdata, data_len);
|
||||
|
||||
return (*ctx == NULL) ? -1 : 0;
|
||||
}
|
||||
|
||||
static unsigned char *
|
||||
_libssh2_mbedtls_mpi_write_binary(unsigned char *buf,
|
||||
const mbedtls_mpi *mpi,
|
||||
size_t bytes)
|
||||
{
|
||||
unsigned char *p = buf;
|
||||
|
||||
if(sizeof(&p) / sizeof(p[0]) < 4) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
p += 4;
|
||||
*p = 0;
|
||||
|
||||
if(bytes > 0) {
|
||||
mbedtls_mpi_write_binary(mpi, p + 1, bytes - 1);
|
||||
}
|
||||
|
||||
if(bytes > 0 && !(*(p + 1) & 0x80)) {
|
||||
memmove(p, p + 1, --bytes);
|
||||
}
|
||||
|
||||
_libssh2_htonu32(p - 4, bytes);
|
||||
|
||||
done:
|
||||
|
||||
return p + bytes;
|
||||
}
|
||||
|
||||
/* _libssh2_ecdsa_sign
|
||||
*
|
||||
* Computes the ECDSA signature of a previously-hashed message
|
||||
*
|
||||
*/
|
||||
|
||||
int
|
||||
_libssh2_mbedtls_ecdsa_sign(LIBSSH2_SESSION *session,
|
||||
libssh2_ecdsa_ctx *ctx,
|
||||
const unsigned char *hash,
|
||||
unsigned long hash_len,
|
||||
unsigned char **sign,
|
||||
size_t *sign_len)
|
||||
{
|
||||
size_t r_len, s_len, tmp_sign_len = 0;
|
||||
unsigned char *sp, *tmp_sign = NULL;
|
||||
mbedtls_mpi pr, ps;
|
||||
|
||||
mbedtls_mpi_init(&pr);
|
||||
mbedtls_mpi_init(&ps);
|
||||
|
||||
if(mbedtls_ecdsa_sign(&ctx->grp, &pr, &ps, &ctx->d,
|
||||
hash, hash_len,
|
||||
mbedtls_ctr_drbg_random,
|
||||
&_libssh2_mbedtls_ctr_drbg) != 0)
|
||||
goto cleanup;
|
||||
|
||||
r_len = mbedtls_mpi_size(&pr) + 1;
|
||||
s_len = mbedtls_mpi_size(&ps) + 1;
|
||||
tmp_sign_len = r_len + s_len + 8;
|
||||
|
||||
tmp_sign = LIBSSH2_CALLOC(session, tmp_sign_len);
|
||||
|
||||
if(tmp_sign == NULL)
|
||||
goto cleanup;
|
||||
|
||||
sp = tmp_sign;
|
||||
sp = _libssh2_mbedtls_mpi_write_binary(sp, &pr, r_len);
|
||||
sp = _libssh2_mbedtls_mpi_write_binary(sp, &ps, s_len);
|
||||
|
||||
*sign_len = (size_t)(sp - tmp_sign);
|
||||
|
||||
*sign = LIBSSH2_CALLOC(session, *sign_len);
|
||||
|
||||
if(*sign == NULL)
|
||||
goto cleanup;
|
||||
|
||||
memcpy(*sign, tmp_sign, *sign_len);
|
||||
|
||||
cleanup:
|
||||
|
||||
mbedtls_mpi_free(&pr);
|
||||
mbedtls_mpi_free(&ps);
|
||||
|
||||
_libssh2_mbedtls_safe_free(tmp_sign, tmp_sign_len);
|
||||
|
||||
return (*sign == NULL) ? -1 : 0;
|
||||
}
|
||||
|
||||
/* _libssh2_ecdsa_get_curve_type
|
||||
*
|
||||
* returns key curve type that maps to libssh2_curve_type
|
||||
*
|
||||
*/
|
||||
|
||||
libssh2_curve_type
|
||||
_libssh2_mbedtls_ecdsa_get_curve_type(libssh2_ecdsa_ctx *ctx)
|
||||
{
|
||||
return (libssh2_curve_type) ctx->grp.id;
|
||||
}
|
||||
|
||||
/* _libssh2_ecdsa_curve_type_from_name
|
||||
*
|
||||
* returns 0 for success, key curve type that maps to libssh2_curve_type
|
||||
*
|
||||
*/
|
||||
|
||||
int
|
||||
_libssh2_mbedtls_ecdsa_curve_type_from_name(const char *name,
|
||||
libssh2_curve_type *out_type)
|
||||
{
|
||||
int ret = 0;
|
||||
libssh2_curve_type type;
|
||||
|
||||
if(name == NULL || strlen(name) != 19)
|
||||
return -1;
|
||||
|
||||
if(strcmp(name, "ecdsa-sha2-nistp256") == 0)
|
||||
type = LIBSSH2_EC_CURVE_NISTP256;
|
||||
else if(strcmp(name, "ecdsa-sha2-nistp384") == 0)
|
||||
type = LIBSSH2_EC_CURVE_NISTP384;
|
||||
else if(strcmp(name, "ecdsa-sha2-nistp521") == 0)
|
||||
type = LIBSSH2_EC_CURVE_NISTP521;
|
||||
else {
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
if(ret == 0 && out_type) {
|
||||
*out_type = type;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
_libssh2_mbedtls_ecdsa_free(libssh2_ecdsa_ctx *ctx)
|
||||
{
|
||||
mbedtls_ecdsa_free(ctx);
|
||||
mbedtls_free(ctx);
|
||||
}
|
||||
|
||||
#endif /* LIBSSH2_ECDSA */
|
||||
#endif /* LIBSSH2_MBEDTLS */
|
||||
|
149
src/mbedtls.h
149
src/mbedtls.h
@@ -1,3 +1,5 @@
|
||||
#ifndef __LIBSSH2_MBEDTLS_H
|
||||
#define __LIBSSH2_MBEDTLS_H
|
||||
/* Copyright (c) 2016, Art <https://github.com/wildart>
|
||||
* All rights reserved.
|
||||
*
|
||||
@@ -43,6 +45,12 @@
|
||||
#include <mbedtls/rsa.h>
|
||||
#include <mbedtls/bignum.h>
|
||||
#include <mbedtls/cipher.h>
|
||||
#ifdef MBEDTLS_ECDH_C
|
||||
# include <mbedtls/ecdh.h>
|
||||
#endif
|
||||
#ifdef MBEDTLS_ECDSA_C
|
||||
# include <mbedtls/ecdsa.h>
|
||||
#endif
|
||||
#include <mbedtls/entropy.h>
|
||||
#include <mbedtls/ctr_drbg.h>
|
||||
#include <mbedtls/pk.h>
|
||||
@@ -64,7 +72,11 @@
|
||||
|
||||
#define LIBSSH2_RSA 1
|
||||
#define LIBSSH2_DSA 0
|
||||
#ifdef MBEDTLS_ECDSA_C
|
||||
# define LIBSSH2_ECDSA 1
|
||||
#else
|
||||
# define LIBSSH2_ECDSA 0
|
||||
#endif
|
||||
#define LIBSSH2_ED25519 0
|
||||
|
||||
#define MD5_DIGEST_LENGTH 16
|
||||
@@ -75,10 +87,6 @@
|
||||
|
||||
#define EC_MAX_POINT_LEN ((528 * 2 / 8) + 1)
|
||||
|
||||
#if LIBSSH2_ECDSA
|
||||
#else
|
||||
#define _libssh2_ec_key void
|
||||
#endif
|
||||
|
||||
/*******************************************************************/
|
||||
/*
|
||||
@@ -208,9 +216,10 @@
|
||||
#define libssh2_md5(data, datalen, hash) \
|
||||
_libssh2_mbedtls_hash(data, datalen, MBEDTLS_MD_MD5, hash)
|
||||
|
||||
|
||||
/*******************************************************************/
|
||||
/*
|
||||
* mbedTLS backend: RSA structure
|
||||
* mbedTLS backend: RSA functions
|
||||
*/
|
||||
|
||||
#define libssh2_rsa_ctx mbedtls_rsa_context
|
||||
@@ -239,6 +248,82 @@
|
||||
#define _libssh2_rsa_free(rsactx) \
|
||||
_libssh2_mbedtls_rsa_free(rsactx)
|
||||
|
||||
|
||||
/*******************************************************************/
|
||||
/*
|
||||
* mbedTLS backend: ECDSA structures
|
||||
*/
|
||||
|
||||
#if LIBSSH2_ECDSA
|
||||
|
||||
typedef enum {
|
||||
#ifdef MBEDTLS_ECP_DP_SECP256R1_ENABLED
|
||||
LIBSSH2_EC_CURVE_NISTP256 = MBEDTLS_ECP_DP_SECP256R1,
|
||||
#else
|
||||
LIBSSH2_EC_CURVE_NISTP256 = MBEDTLS_ECP_DP_NONE,
|
||||
#endif
|
||||
#ifdef MBEDTLS_ECP_DP_SECP384R1_ENABLED
|
||||
LIBSSH2_EC_CURVE_NISTP384 = MBEDTLS_ECP_DP_SECP384R1,
|
||||
#else
|
||||
LIBSSH2_EC_CURVE_NISTP384 = MBEDTLS_ECP_DP_NONE,
|
||||
#endif
|
||||
#ifdef MBEDTLS_ECP_DP_SECP521R1_ENABLED
|
||||
LIBSSH2_EC_CURVE_NISTP521 = MBEDTLS_ECP_DP_SECP521R1
|
||||
#else
|
||||
LIBSSH2_EC_CURVE_NISTP521 = MBEDTLS_ECP_DP_NONE,
|
||||
#endif
|
||||
} libssh2_curve_type;
|
||||
|
||||
# define _libssh2_ec_key mbedtls_ecp_keypair
|
||||
#else
|
||||
# define _libssh2_ec_key void
|
||||
#endif /* LIBSSH2_ECDSA */
|
||||
|
||||
|
||||
/*******************************************************************/
|
||||
/*
|
||||
* mbedTLS backend: ECDSA functions
|
||||
*/
|
||||
|
||||
#if LIBSSH2_ECDSA
|
||||
|
||||
#define libssh2_ecdsa_ctx mbedtls_ecdsa_context
|
||||
|
||||
#define _libssh2_ecdsa_create_key(session, privkey, pubkey_octal, \
|
||||
pubkey_octal_len, curve) \
|
||||
_libssh2_mbedtls_ecdsa_create_key(session, privkey, pubkey_octal, \
|
||||
pubkey_octal_len, curve)
|
||||
|
||||
#define _libssh2_ecdsa_curve_name_with_octal_new(ctx, k, k_len, curve) \
|
||||
_libssh2_mbedtls_ecdsa_curve_name_with_octal_new(ctx, k, k_len, curve)
|
||||
|
||||
#define _libssh2_ecdh_gen_k(k, privkey, server_pubkey, server_pubkey_len) \
|
||||
_libssh2_mbedtls_ecdh_gen_k(k, privkey, server_pubkey, server_pubkey_len)
|
||||
|
||||
#define _libssh2_ecdsa_verify(ctx, r, r_len, s, s_len, m, m_len) \
|
||||
_libssh2_mbedtls_ecdsa_verify(ctx, r, r_len, s, s_len, m, m_len)
|
||||
|
||||
#define _libssh2_ecdsa_new_private(ctx, session, filename, passphrase) \
|
||||
_libssh2_mbedtls_ecdsa_new_private(ctx, session, filename, passphrase)
|
||||
|
||||
#define _libssh2_ecdsa_new_private_frommemory(ctx, session, filedata, \
|
||||
filedata_len, passphrase) \
|
||||
_libssh2_mbedtls_ecdsa_new_private_frommemory(ctx, session, filedata, \
|
||||
filedata_len, passphrase)
|
||||
|
||||
#define _libssh2_ecdsa_sign(session, ctx, hash, hash_len, sign, sign_len) \
|
||||
_libssh2_mbedtls_ecdsa_sign(session, ctx, hash, hash_len, sign, sign_len)
|
||||
|
||||
#define _libssh2_ecdsa_get_curve_type(ctx) \
|
||||
_libssh2_mbedtls_ecdsa_get_curve_type(ctx)
|
||||
|
||||
#define _libssh2_ecdsa_free(ctx) \
|
||||
_libssh2_mbedtls_ecdsa_free(ctx)
|
||||
|
||||
#endif /* LIBSSH2_ECDSA */
|
||||
|
||||
|
||||
/*******************************************************************/
|
||||
/*
|
||||
* mbedTLS backend: Key functions
|
||||
*/
|
||||
@@ -255,6 +340,7 @@
|
||||
/*
|
||||
* mbedTLS backend: Cipher Context structure
|
||||
*/
|
||||
|
||||
#define _libssh2_cipher_ctx mbedtls_cipher_context_t
|
||||
|
||||
#define _libssh2_cipher_type(algo) mbedtls_cipher_type_t algo
|
||||
@@ -270,6 +356,8 @@
|
||||
#define _libssh2_cipher_cast5 MBEDTLS_CIPHER_NULL
|
||||
#define _libssh2_cipher_3des MBEDTLS_CIPHER_DES_EDE3_CBC
|
||||
|
||||
|
||||
/*******************************************************************/
|
||||
/*
|
||||
* mbedTLS backend: Cipher functions
|
||||
*/
|
||||
@@ -329,6 +417,7 @@
|
||||
/*
|
||||
* mbedTLS backend: forward declarations
|
||||
*/
|
||||
|
||||
void
|
||||
_libssh2_mbedtls_init(void);
|
||||
|
||||
@@ -434,6 +523,54 @@ _libssh2_mbedtls_pub_priv_keyfilememory(LIBSSH2_SESSION *session,
|
||||
const char *privatekeydata,
|
||||
size_t privatekeydata_len,
|
||||
const char *passphrase);
|
||||
#if LIBSSH2_ECDSA
|
||||
int
|
||||
_libssh2_mbedtls_ecdsa_create_key(LIBSSH2_SESSION *session,
|
||||
_libssh2_ec_key **privkey,
|
||||
unsigned char **pubkey_octal,
|
||||
size_t *pubkey_octal_len,
|
||||
libssh2_curve_type curve);
|
||||
int
|
||||
_libssh2_mbedtls_ecdsa_curve_name_with_octal_new(libssh2_ecdsa_ctx **ctx,
|
||||
const unsigned char *k,
|
||||
size_t k_len,
|
||||
libssh2_curve_type curve);
|
||||
int
|
||||
_libssh2_mbedtls_ecdh_gen_k(_libssh2_bn **k,
|
||||
_libssh2_ec_key *privkey,
|
||||
const unsigned char *server_pubkey,
|
||||
size_t server_pubkey_len);
|
||||
int
|
||||
_libssh2_mbedtls_ecdsa_verify(libssh2_ecdsa_ctx *ctx,
|
||||
const unsigned char *r, size_t r_len,
|
||||
const unsigned char *s, size_t s_len,
|
||||
const unsigned char *m, size_t m_len);
|
||||
int
|
||||
_libssh2_mbedtls_ecdsa_new_private(libssh2_ecdsa_ctx **ctx,
|
||||
LIBSSH2_SESSION *session,
|
||||
const char *filename,
|
||||
const unsigned char *passphrase);
|
||||
int
|
||||
_libssh2_mbedtls_ecdsa_new_private_frommemory(libssh2_ecdsa_ctx **ctx,
|
||||
LIBSSH2_SESSION *session,
|
||||
const char *filedata,
|
||||
size_t filedata_len,
|
||||
const unsigned char *passphrase);
|
||||
int
|
||||
_libssh2_mbedtls_ecdsa_sign(LIBSSH2_SESSION *session,
|
||||
libssh2_ecdsa_ctx *ctx,
|
||||
const unsigned char *hash,
|
||||
unsigned long hash_len,
|
||||
unsigned char **signature,
|
||||
size_t *signature_len);
|
||||
libssh2_curve_type
|
||||
_libssh2_mbedtls_ecdsa_key_get_curve_type(libssh2_ecdsa_ctx *ctx);
|
||||
int
|
||||
_libssh2_mbedtls_ecdsa_curve_type_from_name(const char *name,
|
||||
libssh2_curve_type *type);
|
||||
void
|
||||
_libssh2_mbedtls_ecdsa_free(libssh2_ecdsa_ctx *ctx);
|
||||
#endif /* LIBSSH2_ECDSA */
|
||||
|
||||
extern void
|
||||
_libssh2_dh_init(_libssh2_dh_ctx *dhctx);
|
||||
@@ -445,3 +582,5 @@ _libssh2_dh_secret(_libssh2_dh_ctx *dhctx, _libssh2_bn *secret,
|
||||
_libssh2_bn *f, _libssh2_bn *p);
|
||||
extern void
|
||||
_libssh2_dh_dtor(_libssh2_dh_ctx *dhctx);
|
||||
|
||||
#endif /* __LIBSSH2_MBEDTLS_H */
|
||||
|
219
src/openssl.c
219
src/openssl.c
@@ -427,10 +427,19 @@ _libssh2_cipher_crypt(_libssh2_cipher_ctx * ctx,
|
||||
#else
|
||||
ret = EVP_Cipher(ctx, buf, block, blocksize);
|
||||
#endif
|
||||
#if defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 3
|
||||
if(ret != -1) {
|
||||
#else
|
||||
if(ret == 1) {
|
||||
#endif
|
||||
memcpy(block, buf, blocksize);
|
||||
}
|
||||
|
||||
#if defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 3
|
||||
return ret != -1 ? 0 : 1;
|
||||
#else
|
||||
return ret == 1 ? 0 : 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if LIBSSH2_AES_CTR && !defined(HAVE_EVP_AES_128_CTR)
|
||||
@@ -445,6 +454,10 @@ typedef struct
|
||||
unsigned char ctr[AES_BLOCK_SIZE];
|
||||
} aes_ctr_ctx;
|
||||
|
||||
static EVP_CIPHER * aes_128_ctr_cipher = NULL;
|
||||
static EVP_CIPHER * aes_192_ctr_cipher = NULL;
|
||||
static EVP_CIPHER * aes_256_ctr_cipher = NULL;
|
||||
|
||||
static int
|
||||
aes_ctr_init(EVP_CIPHER_CTX *ctx, const unsigned char *key,
|
||||
const unsigned char *iv, int enc) /* init key */
|
||||
@@ -589,12 +602,16 @@ const EVP_CIPHER *
|
||||
_libssh2_EVP_aes_128_ctr(void)
|
||||
{
|
||||
#ifdef HAVE_OPAQUE_STRUCTS
|
||||
EVP_CIPHER * aes_ctr_cipher;
|
||||
return make_ctr_evp(16, &aes_ctr_cipher, NID_aes_128_ctr);
|
||||
return !aes_128_ctr_cipher ?
|
||||
make_ctr_evp(16, &aes_128_ctr_cipher, NID_aes_128_ctr) :
|
||||
aes_128_ctr_cipher;
|
||||
#else
|
||||
static EVP_CIPHER aes_ctr_cipher;
|
||||
EVP_CIPHER * aes_ctr_cipher_ptr = &aes_ctr_cipher;
|
||||
return make_ctr_evp(16, &aes_ctr_cipher_ptr, 0);
|
||||
if(!aes_128_ctr_cipher) {
|
||||
aes_128_ctr_cipher = &aes_ctr_cipher;
|
||||
make_ctr_evp(16, &aes_128_ctr_cipher, 0);
|
||||
}
|
||||
return aes_128_ctr_cipher;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -602,12 +619,16 @@ const EVP_CIPHER *
|
||||
_libssh2_EVP_aes_192_ctr(void)
|
||||
{
|
||||
#ifdef HAVE_OPAQUE_STRUCTS
|
||||
EVP_CIPHER * aes_ctr_cipher;
|
||||
return make_ctr_evp(24, &aes_ctr_cipher, NID_aes_192_ctr);
|
||||
return !aes_192_ctr_cipher ?
|
||||
make_ctr_evp(24, &aes_192_ctr_cipher, NID_aes_192_ctr) :
|
||||
aes_192_ctr_cipher;
|
||||
#else
|
||||
static EVP_CIPHER aes_ctr_cipher;
|
||||
EVP_CIPHER * aes_ctr_cipher_ptr = &aes_ctr_cipher;
|
||||
return make_ctr_evp(24, &aes_ctr_cipher_ptr, 0);
|
||||
if(!aes_192_ctr_cipher) {
|
||||
aes_192_ctr_cipher = &aes_ctr_cipher;
|
||||
make_ctr_evp(24, &aes_192_ctr_cipher, 0);
|
||||
}
|
||||
return aes_192_ctr_cipher;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -615,22 +636,20 @@ const EVP_CIPHER *
|
||||
_libssh2_EVP_aes_256_ctr(void)
|
||||
{
|
||||
#ifdef HAVE_OPAQUE_STRUCTS
|
||||
EVP_CIPHER * aes_ctr_cipher;
|
||||
return make_ctr_evp(32, &aes_ctr_cipher, NID_aes_256_ctr);
|
||||
return !aes_256_ctr_cipher ?
|
||||
make_ctr_evp(32, &aes_256_ctr_cipher, NID_aes_256_ctr) :
|
||||
aes_256_ctr_cipher;
|
||||
#else
|
||||
static EVP_CIPHER aes_ctr_cipher;
|
||||
EVP_CIPHER * aes_ctr_cipher_ptr = &aes_ctr_cipher;
|
||||
return make_ctr_evp(32, &aes_ctr_cipher_ptr, 0);
|
||||
if(!aes_256_ctr_cipher) {
|
||||
aes_256_ctr_cipher = &aes_ctr_cipher;
|
||||
make_ctr_evp(32, &aes_256_ctr_cipher, 0);
|
||||
}
|
||||
return aes_256_ctr_cipher;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* LIBSSH2_AES_CTR */
|
||||
|
||||
#ifndef HAVE_EVP_AES_128_CTR
|
||||
static EVP_CIPHER * aes_128_ctr_cipher = NULL;
|
||||
static EVP_CIPHER * aes_192_ctr_cipher = NULL;
|
||||
static EVP_CIPHER * aes_256_ctr_cipher = NULL;
|
||||
#endif
|
||||
#endif /* LIBSSH2_AES_CTR && !defined(HAVE_EVP_AES_128_CTR) */
|
||||
|
||||
void _libssh2_openssl_crypto_init(void)
|
||||
{
|
||||
@@ -649,19 +668,16 @@ void _libssh2_openssl_crypto_init(void)
|
||||
ENGINE_register_all_complete();
|
||||
#endif
|
||||
#endif
|
||||
#ifndef HAVE_EVP_AES_128_CTR
|
||||
if(!aes_128_ctr_cipher)
|
||||
#if LIBSSH2_AES_CTR && !defined(HAVE_EVP_AES_128_CTR)
|
||||
aes_128_ctr_cipher = (EVP_CIPHER *) _libssh2_EVP_aes_128_ctr();
|
||||
if(!aes_192_ctr_cipher)
|
||||
aes_192_ctr_cipher = (EVP_CIPHER *) _libssh2_EVP_aes_192_ctr();
|
||||
if(!aes_256_ctr_cipher)
|
||||
aes_256_ctr_cipher = (EVP_CIPHER *) _libssh2_EVP_aes_256_ctr();
|
||||
#endif
|
||||
}
|
||||
|
||||
void _libssh2_openssl_crypto_exit(void)
|
||||
{
|
||||
#ifndef HAVE_EVP_AES_128_CTR
|
||||
#if LIBSSH2_AES_CTR && !defined(HAVE_EVP_AES_128_CTR)
|
||||
#ifdef HAVE_OPAQUE_STRUCTS
|
||||
if(aes_128_ctr_cipher) {
|
||||
EVP_CIPHER_meth_free(aes_128_ctr_cipher);
|
||||
@@ -1458,75 +1474,53 @@ _libssh2_ecdsa_new_private_frommemory(libssh2_ecdsa_ctx ** ec_ctx,
|
||||
#if LIBSSH2_ED25519
|
||||
|
||||
int
|
||||
_libssh2_curve25519_new(LIBSSH2_SESSION *session, libssh2_x25519_ctx **out_ctx,
|
||||
_libssh2_curve25519_new(LIBSSH2_SESSION *session,
|
||||
unsigned char **out_public_key,
|
||||
unsigned char **out_private_key)
|
||||
{
|
||||
EVP_PKEY *key = NULL;
|
||||
EVP_PKEY_CTX *pctx = NULL;
|
||||
PKCS8_PRIV_KEY_INFO *info = NULL;
|
||||
ASN1_OCTET_STRING *oct = NULL;
|
||||
X509_PUBKEY *pubkey = NULL;
|
||||
libssh2_ed25519_ctx *ctx = NULL;
|
||||
const unsigned char *pkcs, *priv, *pub;
|
||||
int privLen, pubLen, pkcsLen;
|
||||
unsigned char *priv = NULL, *pub = NULL;
|
||||
size_t privLen, pubLen;
|
||||
int rc = -1;
|
||||
|
||||
pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_X25519, NULL);
|
||||
if(pctx == NULL)
|
||||
return -1;
|
||||
|
||||
EVP_PKEY_keygen_init(pctx);
|
||||
EVP_PKEY_keygen(pctx, &key);
|
||||
info = EVP_PKEY2PKCS8(key);
|
||||
|
||||
if(info == NULL || !PKCS8_pkey_get0(NULL, &pkcs, &pkcsLen, NULL, info))
|
||||
goto cleanExit;
|
||||
|
||||
oct = d2i_ASN1_OCTET_STRING(NULL, &pkcs, pkcsLen);
|
||||
if(oct == NULL) {
|
||||
if(EVP_PKEY_keygen_init(pctx) != 1 ||
|
||||
EVP_PKEY_keygen(pctx, &key) != 1) {
|
||||
goto cleanExit;
|
||||
}
|
||||
|
||||
priv = ASN1_STRING_get0_data(oct);
|
||||
privLen = ASN1_STRING_length(oct);
|
||||
|
||||
if(privLen != LIBSSH2_ED25519_KEY_LEN)
|
||||
goto cleanExit;
|
||||
|
||||
pubkey = X509_PUBKEY_new();
|
||||
if(pubkey == NULL || !X509_PUBKEY_set(&pubkey, key))
|
||||
goto cleanExit;
|
||||
|
||||
if(!X509_PUBKEY_get0_param(NULL, &pub, &pubLen, NULL, pubkey))
|
||||
goto cleanExit;
|
||||
|
||||
if(pubLen != LIBSSH2_ED25519_KEY_LEN)
|
||||
goto cleanExit;
|
||||
|
||||
if(out_private_key != NULL) {
|
||||
*out_private_key = LIBSSH2_ALLOC(session, LIBSSH2_ED25519_KEY_LEN);
|
||||
if(*out_private_key == NULL)
|
||||
privLen = LIBSSH2_ED25519_KEY_LEN;
|
||||
priv = LIBSSH2_ALLOC(session, privLen);
|
||||
if(priv == NULL)
|
||||
goto cleanExit;
|
||||
|
||||
memcpy(*out_private_key, priv, LIBSSH2_ED25519_KEY_LEN);
|
||||
if(EVP_PKEY_get_raw_private_key(key, priv, &privLen) != 1 ||
|
||||
privLen != LIBSSH2_ED25519_KEY_LEN) {
|
||||
goto cleanExit;
|
||||
}
|
||||
|
||||
*out_private_key = priv;
|
||||
priv = NULL;
|
||||
}
|
||||
|
||||
if(out_public_key != NULL) {
|
||||
*out_public_key = LIBSSH2_ALLOC(session, LIBSSH2_ED25519_KEY_LEN);
|
||||
if(*out_public_key == NULL)
|
||||
pubLen = LIBSSH2_ED25519_KEY_LEN;
|
||||
pub = LIBSSH2_ALLOC(session, pubLen);
|
||||
if(pub == NULL)
|
||||
goto cleanExit;
|
||||
|
||||
memcpy(*out_public_key, pub, LIBSSH2_ED25519_KEY_LEN);
|
||||
if(EVP_PKEY_get_raw_public_key(key, pub, &pubLen) != 1 ||
|
||||
pubLen != LIBSSH2_ED25519_KEY_LEN) {
|
||||
goto cleanExit;
|
||||
}
|
||||
|
||||
if(out_ctx != NULL) {
|
||||
ctx = EVP_PKEY_new_raw_private_key(EVP_PKEY_X25519, NULL, priv,
|
||||
LIBSSH2_ED25519_KEY_LEN);
|
||||
if(!ctx)
|
||||
goto cleanExit;
|
||||
|
||||
*out_ctx = ctx;
|
||||
*out_public_key = pub;
|
||||
pub = NULL;
|
||||
}
|
||||
|
||||
/* success */
|
||||
@@ -1534,16 +1528,14 @@ _libssh2_curve25519_new(LIBSSH2_SESSION *session, libssh2_x25519_ctx **out_ctx,
|
||||
|
||||
cleanExit:
|
||||
|
||||
if(info)
|
||||
PKCS8_PRIV_KEY_INFO_free(info);
|
||||
if(pctx)
|
||||
EVP_PKEY_CTX_free(pctx);
|
||||
if(oct)
|
||||
ASN1_OCTET_STRING_free(oct);
|
||||
if(pubkey)
|
||||
X509_PUBKEY_free(pubkey);
|
||||
if(key)
|
||||
EVP_PKEY_free(key);
|
||||
if(priv)
|
||||
LIBSSH2_FREE(session, priv);
|
||||
if(pub)
|
||||
LIBSSH2_FREE(session, pub);
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -1698,6 +1690,8 @@ gen_publickey_from_ed25519_openssh_priv_data(LIBSSH2_SESSION *session,
|
||||
|
||||
method_buf = LIBSSH2_ALLOC(session, 11); /* ssh-ed25519. */
|
||||
if(method_buf == NULL) {
|
||||
_libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||
"Unable to allocate memory for ED25519 key");
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
@@ -1706,6 +1700,8 @@ gen_publickey_from_ed25519_openssh_priv_data(LIBSSH2_SESSION *session,
|
||||
key_len = LIBSSH2_ED25519_KEY_LEN + 19;
|
||||
key = LIBSSH2_CALLOC(session, key_len);
|
||||
if(key == NULL) {
|
||||
_libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||
"Unable to allocate memory for ED25519 key");
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
@@ -2229,6 +2225,19 @@ _libssh2_sha512(const unsigned char *message, unsigned long len,
|
||||
int
|
||||
_libssh2_md5_init(libssh2_md5_ctx *ctx)
|
||||
{
|
||||
/* MD5 digest is not supported in OpenSSL FIPS mode
|
||||
* Trying to init it will result in a latent OpenSSL error:
|
||||
* "digital envelope routines:FIPS_DIGESTINIT:disabled for fips"
|
||||
* So, just return 0 in FIPS mode
|
||||
*/
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x000907000L && \
|
||||
defined(OPENSSL_VERSION_MAJOR) && \
|
||||
OPENSSL_VERSION_MAJOR < 3 && \
|
||||
!defined(LIBRESSL_VERSION_NUMBER)
|
||||
if(FIPS_mode() != 0)
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_OPAQUE_STRUCTS
|
||||
*ctx = EVP_MD_CTX_new();
|
||||
|
||||
@@ -2419,6 +2428,7 @@ gen_publickey_from_ecdsa_openssh_priv_data(LIBSSH2_SESSION *session,
|
||||
|
||||
if((rc = _libssh2_ecdsa_curve_name_with_octal_new(&ec_key, point_buf,
|
||||
pointlen, curve_type)) != 0) {
|
||||
rc = -1;
|
||||
_libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
||||
"ECDSA could not create key");
|
||||
goto fail;
|
||||
@@ -2427,6 +2437,8 @@ gen_publickey_from_ecdsa_openssh_priv_data(LIBSSH2_SESSION *session,
|
||||
bn_exponent = BN_new();
|
||||
if(bn_exponent == NULL) {
|
||||
rc = -1;
|
||||
_libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||
"Unable to allocate memory for private key data");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@@ -2453,15 +2465,10 @@ gen_publickey_from_ecdsa_openssh_priv_data(LIBSSH2_SESSION *session,
|
||||
return rc;
|
||||
|
||||
fail:
|
||||
|
||||
if(ec_key != NULL)
|
||||
EC_KEY_free(ec_key);
|
||||
|
||||
return _libssh2_error(session,
|
||||
LIBSSH2_ERROR_ALLOC,
|
||||
"Unable to allocate memory for private key data");
|
||||
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -3054,17 +3061,13 @@ _libssh2_pub_priv_openssh_keyfilememory(LIBSSH2_SESSION *session,
|
||||
if(key_ctx != NULL)
|
||||
*key_ctx = NULL;
|
||||
|
||||
if(session == NULL) {
|
||||
_libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
||||
if(session == NULL)
|
||||
return _libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
||||
"Session is required");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(key_type != NULL && (strlen(key_type) > 11 || strlen(key_type) < 7)) {
|
||||
_libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
||||
if(key_type != NULL && (strlen(key_type) > 11 || strlen(key_type) < 7))
|
||||
return _libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
||||
"type is invalid");
|
||||
return -1;
|
||||
}
|
||||
|
||||
_libssh2_init_if_needed();
|
||||
|
||||
@@ -3072,20 +3075,18 @@ _libssh2_pub_priv_openssh_keyfilememory(LIBSSH2_SESSION *session,
|
||||
privatekeydata,
|
||||
privatekeydata_len, &decrypted);
|
||||
|
||||
if(rc) {
|
||||
if(rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* We have a new key file, now try and parse it using supported types */
|
||||
rc = _libssh2_get_string(decrypted, &buf, NULL);
|
||||
|
||||
if(rc != 0 || buf == NULL) {
|
||||
_libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
||||
"Public key type in decrypted key data not found");
|
||||
return -1;
|
||||
}
|
||||
if(rc != 0 || buf == NULL)
|
||||
return _libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
||||
"Public key type in decrypted "
|
||||
"key data not found");
|
||||
|
||||
rc = -1;
|
||||
rc = LIBSSH2_ERROR_FILE;
|
||||
|
||||
#if LIBSSH2_ED25519
|
||||
if(strcmp("ssh-ed25519", (const char *)buf) == 0) {
|
||||
@@ -3139,6 +3140,11 @@ _libssh2_pub_priv_openssh_keyfilememory(LIBSSH2_SESSION *session,
|
||||
}
|
||||
#endif
|
||||
|
||||
if(rc == LIBSSH2_ERROR_FILE)
|
||||
rc = _libssh2_error(session, LIBSSH2_ERROR_FILE,
|
||||
"Unable to extract public key from private key file: "
|
||||
"invalid/unrecognized private key file format");
|
||||
|
||||
if(decrypted)
|
||||
_libssh2_string_buf_free(session, decrypted);
|
||||
|
||||
@@ -3178,10 +3184,10 @@ _libssh2_pub_priv_keyfilememory(LIBSSH2_SESSION *session,
|
||||
"Computing public key from private key.");
|
||||
|
||||
bp = BIO_new_mem_buf((char *)privatekeydata, privatekeydata_len);
|
||||
if(!bp) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(!bp)
|
||||
return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||
"Unable to allocate memory when"
|
||||
"computing public key");
|
||||
BIO_reset(bp);
|
||||
pk = PEM_read_bio_PrivateKey(bp, NULL, NULL, (void *)passphrase);
|
||||
BIO_free(bp);
|
||||
@@ -3196,15 +3202,8 @@ _libssh2_pub_priv_keyfilememory(LIBSSH2_SESSION *session,
|
||||
privatekeydata,
|
||||
privatekeydata_len,
|
||||
(unsigned const char *)passphrase);
|
||||
if(st != 0) {
|
||||
return _libssh2_error(session,
|
||||
LIBSSH2_ERROR_FILE,
|
||||
"Unable to extract public key "
|
||||
"from private key file: "
|
||||
"Wrong passphrase or invalid/unrecognized "
|
||||
"private key file format");
|
||||
}
|
||||
|
||||
if(st != 0)
|
||||
return st;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -1,3 +1,5 @@
|
||||
#ifndef __LIBSSH2_OPENSSL_H
|
||||
#define __LIBSSH2_OPENSSL_H
|
||||
/* Copyright (C) 2009, 2010 Simon Josefsson
|
||||
* Copyright (C) 2006, 2007 The Written Word, Inc. All rights reserved.
|
||||
*
|
||||
@@ -135,7 +137,7 @@
|
||||
|
||||
#define EC_MAX_POINT_LEN ((528 * 2 / 8) + 1)
|
||||
|
||||
#define _libssh2_random(buf, len) RAND_bytes ((buf), (len))
|
||||
#define _libssh2_random(buf, len) (RAND_bytes((buf), (len)) == 1 ? 0 : -1)
|
||||
|
||||
#define libssh2_prepare_iovec(vec, len) /* Empty. */
|
||||
|
||||
@@ -323,10 +325,8 @@ libssh2_curve_type;
|
||||
|
||||
#if LIBSSH2_ED25519
|
||||
#define libssh2_ed25519_ctx EVP_PKEY
|
||||
#define libssh2_x25519_ctx EVP_PKEY
|
||||
|
||||
#define _libssh2_ed25519_free(ctx) EVP_PKEY_free(ctx)
|
||||
#define _libssh2_x25519_free(ctx) EVP_PKEY_free(ctx)
|
||||
#endif /* ED25519 */
|
||||
|
||||
#define _libssh2_cipher_type(name) const EVP_CIPHER *(*name)(void)
|
||||
@@ -392,3 +392,5 @@ extern void _libssh2_dh_dtor(_libssh2_dh_ctx *dhctx);
|
||||
const EVP_CIPHER *_libssh2_EVP_aes_128_ctr(void);
|
||||
const EVP_CIPHER *_libssh2_EVP_aes_192_ctr(void);
|
||||
const EVP_CIPHER *_libssh2_EVP_aes_256_ctr(void);
|
||||
|
||||
#endif /* __LIBSSH2_OPENSSL_H */
|
||||
|
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2015-2016 Patrick Monnerat, D+H <patrick.monnerat@dh.com>
|
||||
* Copyright (C) 2020 Patrick Monnerat <patrick@monnerat.net>.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
@@ -883,11 +884,14 @@ _libssh2_bn_from_bn(_libssh2_bn *to, _libssh2_bn *from)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
int
|
||||
_libssh2_random(unsigned char *buf, int len)
|
||||
{
|
||||
Qc3GenPRNs(buf, len,
|
||||
Qc3PRN_TYPE_NORMAL, Qc3PRN_NO_PARITY, (char *) &ecnull);
|
||||
/* FIXME: any error is silently discarded! But Qc3GenPRNs could fail,
|
||||
including if "The system seed digest is not ready" dixit IBM doc. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -965,7 +969,7 @@ libssh2_os400qc3_hash_init(Qc3_Format_ALGD0100_T *x, unsigned int algorithm)
|
||||
|
||||
void
|
||||
libssh2_os400qc3_hash_update(Qc3_Format_ALGD0100_T *ctx,
|
||||
unsigned char *data, int len)
|
||||
const unsigned char *data, int len)
|
||||
{
|
||||
char dummy[64];
|
||||
|
||||
@@ -995,7 +999,7 @@ libssh2_os400qc3_hash(const unsigned char *message, unsigned long len,
|
||||
if(!libssh2_os400qc3_hash_init(&ctx, algo))
|
||||
return 1;
|
||||
|
||||
libssh2_os400qc3_hash_update(&ctx, (unsigned char *) message, len);
|
||||
libssh2_os400qc3_hash_update(&ctx, message, len);
|
||||
libssh2_os400qc3_hash_final(&ctx, out);
|
||||
return 0;
|
||||
}
|
||||
@@ -1390,8 +1394,7 @@ pbkdf1(LIBSSH2_SESSION *session, char **dk, const unsigned char *passphrase,
|
||||
|
||||
/* Initial hash. */
|
||||
libssh2_os400qc3_hash_init(&hctx, pkcs5->hash);
|
||||
libssh2_os400qc3_hash_update(&hctx, (unsigned char *) passphrase,
|
||||
strlen(passphrase));
|
||||
libssh2_os400qc3_hash_update(&hctx, passphrase, strlen(passphrase));
|
||||
hctx.Final_Op_Flag = Qc3_Final;
|
||||
Qc3CalculateHash((char *) pkcs5->salt, &len, Qc3_Data, (char *) &hctx,
|
||||
Qc3_Alg_Token, anycsp, NULL, *dk, (char *) &ecnull);
|
||||
|
@@ -1,5 +1,8 @@
|
||||
#ifndef __LIBSSH2_OS400QC3_H
|
||||
#define __LIBSSH2_OS400QC3_H
|
||||
/*
|
||||
* Copyright (C) 2015-2016 Patrick Monnerat, D+H <patrick.monnerat@dh.com>
|
||||
* Copyright (C) 2020 Patrick Monnerat <patrick@monnerat.net>.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
@@ -36,9 +39,6 @@
|
||||
* OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef LIBSSH2_OS400QC3_H
|
||||
#define LIBSSH2_OS400QC3_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -176,12 +176,21 @@
|
||||
|
||||
#define LIBSSH2_RSA 1
|
||||
#define LIBSSH2_DSA 0
|
||||
#define LIBSSH2_ECDSA 0
|
||||
#define LIBSSH2_ED25519 0
|
||||
|
||||
#define MD5_DIGEST_LENGTH 16
|
||||
#define SHA_DIGEST_LENGTH 20
|
||||
#define SHA256_DIGEST_LENGTH 32
|
||||
#define SHA384_DIGEST_LENGTH 48
|
||||
#define SHA512_DIGEST_LENGTH 64
|
||||
|
||||
#define EC_MAX_POINT_LEN ((528 * 2 / 8) + 1)
|
||||
|
||||
#if LIBSSH2_ECDSA
|
||||
#else
|
||||
#define _libssh2_ec_key void
|
||||
#endif
|
||||
|
||||
/*******************************************************************
|
||||
*
|
||||
@@ -225,6 +234,8 @@ typedef struct { /* Diffie-Hellman context. */
|
||||
|
||||
#define libssh2_sha1_ctx Qc3_Format_ALGD0100_T
|
||||
#define libssh2_sha256_ctx Qc3_Format_ALGD0100_T
|
||||
#define libssh2_sha384_ctx Qc3_Format_ALGD0100_T
|
||||
#define libssh2_sha512_ctx Qc3_Format_ALGD0100_T
|
||||
#define libssh2_md5_ctx Qc3_Format_ALGD0100_T
|
||||
#define libssh2_hmac_ctx _libssh2_os400qc3_crypto_ctx
|
||||
#define _libssh2_cipher_ctx _libssh2_os400qc3_crypto_ctx
|
||||
@@ -242,6 +253,22 @@ typedef struct { /* Diffie-Hellman context. */
|
||||
#define libssh2_sha256(message, len, out) \
|
||||
libssh2_os400qc3_hash(message, len, out, \
|
||||
Qc3_SHA256)
|
||||
#define libssh2_sha384_init(x) libssh2_os400qc3_hash_init(x, Qc3_SHA384)
|
||||
#define libssh2_sha384_update(ctx, data, len) \
|
||||
libssh2_os400qc3_hash_update(&(ctx), data, len)
|
||||
#define libssh2_sha384_final(ctx, out) \
|
||||
libssh2_os400qc3_hash_final(&(ctx), out)
|
||||
#define libssh2_sha384(message, len, out) \
|
||||
libssh2_os400qc3_hash(message, len, out, \
|
||||
Qc3_SHA384)
|
||||
#define libssh2_sha512_init(x) libssh2_os400qc3_hash_init(x, Qc3_SHA512)
|
||||
#define libssh2_sha512_update(ctx, data, len) \
|
||||
libssh2_os400qc3_hash_update(&(ctx), data, len)
|
||||
#define libssh2_sha512_final(ctx, out) \
|
||||
libssh2_os400qc3_hash_final(&(ctx), out)
|
||||
#define libssh2_sha512(message, len, out) \
|
||||
libssh2_os400qc3_hash(message, len, out, \
|
||||
Qc3_SHA512)
|
||||
#define libssh2_md5_init(x) libssh2_os400qc3_hash_init(x, Qc3_MD5)
|
||||
#define libssh2_md5_update(ctx, data, len) \
|
||||
libssh2_os400qc3_hash_update(&(ctx), data, len)
|
||||
@@ -333,12 +360,13 @@ extern int _libssh2_bn_from_bin(_libssh2_bn *bn, int len,
|
||||
const unsigned char *v);
|
||||
extern int _libssh2_bn_set_word(_libssh2_bn *bn, unsigned long val);
|
||||
extern int _libssh2_bn_to_bin(_libssh2_bn *bn, unsigned char *val);
|
||||
extern void _libssh2_random(unsigned char *buf, int len);
|
||||
extern int _libssh2_random(unsigned char *buf, int len);
|
||||
extern void _libssh2_os400qc3_crypto_dtor(_libssh2_os400qc3_crypto_ctx *x);
|
||||
extern int libssh2_os400qc3_hash_init(Qc3_Format_ALGD0100_T *x,
|
||||
unsigned int algo);
|
||||
extern void libssh2_os400qc3_hash_update(Qc3_Format_ALGD0100_T *ctx,
|
||||
unsigned char *data, int len);
|
||||
const unsigned char *data,
|
||||
int len);
|
||||
extern void libssh2_os400qc3_hash_final(Qc3_Format_ALGD0100_T *ctx,
|
||||
unsigned char *out);
|
||||
extern int libssh2_os400qc3_hash(const unsigned char *message,
|
||||
@@ -368,6 +396,6 @@ extern int _libssh2_os400qc3_dh_secret(_libssh2_dh_ctx *dhctx,
|
||||
_libssh2_bn *f, _libssh2_bn *p);
|
||||
extern void _libssh2_os400qc3_dh_dtor(_libssh2_dh_ctx *dhctx);
|
||||
|
||||
#endif
|
||||
#endif /* __LIBSSH2_OS400QC3_H */
|
||||
|
||||
/* vim: set expandtab ts=4 sw=4: */
|
||||
|
@@ -1323,9 +1323,11 @@ _libssh2_packet_requirev(LIBSSH2_SESSION *session,
|
||||
|
||||
if(strchr((char *) packet_types, ret)) {
|
||||
/* Be lazy, let packet_ask pull it out of the brigade */
|
||||
return _libssh2_packet_askv(session, packet_types, data,
|
||||
int ret = _libssh2_packet_askv(session, packet_types, data,
|
||||
data_len, match_ofs, match_buf,
|
||||
match_len);
|
||||
state->start = 0;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
#ifndef LIBSSH2_PACKET_H
|
||||
#define LIBSSH2_PACKET_H
|
||||
#ifndef __LIBSSH2_PACKET_H
|
||||
#define __LIBSSH2_PACKET_H
|
||||
/*
|
||||
* Copyright (C) 2010 by Daniel Stenberg
|
||||
* Author: Daniel Stenberg <daniel@haxx.se>
|
||||
@@ -73,4 +73,4 @@ int _libssh2_packet_write(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
int _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
size_t datalen, int macstate);
|
||||
|
||||
#endif /* LIBSSH2_PACKET_H */
|
||||
#endif /* __LIBSSH2_PACKET_H */
|
||||
|
31
src/pem.c
31
src/pem.c
@@ -176,6 +176,8 @@ _libssh2_pem_parse(LIBSSH2_SESSION * session,
|
||||
linelen = strlen(line);
|
||||
tmp = LIBSSH2_REALLOC(session, b64data, b64datalen + linelen);
|
||||
if(!tmp) {
|
||||
_libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||
"Unable to allocate memory for PEM parsing");
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
@@ -319,6 +321,8 @@ _libssh2_pem_parse_memory(LIBSSH2_SESSION * session,
|
||||
linelen = strlen(line);
|
||||
tmp = LIBSSH2_REALLOC(session, b64data, b64datalen + linelen);
|
||||
if(!tmp) {
|
||||
_libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||
"Unable to allocate memory for PEM parsing");
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
@@ -690,6 +694,8 @@ _libssh2_openssh_pem_parse(LIBSSH2_SESSION * session,
|
||||
linelen = strlen(line);
|
||||
tmp = LIBSSH2_REALLOC(session, b64data, b64datalen + linelen);
|
||||
if(!tmp) {
|
||||
_libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||
"Unable to allocate memory for PEM parsing");
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
@@ -738,17 +744,17 @@ _libssh2_openssh_pem_parse_memory(LIBSSH2_SESSION * session,
|
||||
size_t off = 0;
|
||||
int ret;
|
||||
|
||||
if(filedata == NULL || filedata_len <= 0) {
|
||||
return -1;
|
||||
}
|
||||
if(filedata == NULL || filedata_len <= 0)
|
||||
return _libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
||||
"Error parsing PEM: filedata missing");
|
||||
|
||||
do {
|
||||
|
||||
*line = '\0';
|
||||
|
||||
if(off >= filedata_len) {
|
||||
return -1;
|
||||
}
|
||||
if(off >= filedata_len)
|
||||
return _libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
||||
"Error parsing PEM: offset out of bounds");
|
||||
|
||||
if(readline_memory(line, LINE_SIZE, filedata, filedata_len, &off)) {
|
||||
return -1;
|
||||
@@ -766,7 +772,9 @@ _libssh2_openssh_pem_parse_memory(LIBSSH2_SESSION * session,
|
||||
linelen = strlen(line);
|
||||
tmp = LIBSSH2_REALLOC(session, b64data, b64datalen + linelen);
|
||||
if(!tmp) {
|
||||
ret = -1;
|
||||
ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||
"Unable to allocate memory for "
|
||||
"PEM parsing");
|
||||
goto out;
|
||||
}
|
||||
memcpy(tmp + b64datalen, line, linelen);
|
||||
@@ -777,7 +785,8 @@ _libssh2_openssh_pem_parse_memory(LIBSSH2_SESSION * session,
|
||||
*line = '\0';
|
||||
|
||||
if(off >= filedata_len) {
|
||||
ret = -1;
|
||||
ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
||||
"Error parsing PEM: offset out of bounds");
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -787,9 +796,9 @@ _libssh2_openssh_pem_parse_memory(LIBSSH2_SESSION * session,
|
||||
}
|
||||
} while(strcmp(line, OPENSSH_HEADER_END) != 0);
|
||||
|
||||
if(!b64data) {
|
||||
return -1;
|
||||
}
|
||||
if(!b64data)
|
||||
return _libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
||||
"Error parsing PEM: base 64 data missing");
|
||||
|
||||
ret = _libssh2_openssh_pem_parse_data(session, passphrase, b64data,
|
||||
b64datalen, decrypted_buf);
|
||||
|
@@ -219,7 +219,7 @@ banner_send(LIBSSH2_SESSION * session)
|
||||
}
|
||||
else {
|
||||
memcpy(banner_dup, banner, 255);
|
||||
banner[255] = '\0';
|
||||
banner_dup[255] = '\0';
|
||||
}
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_TRANS, "Sending Banner: %s",
|
||||
@@ -589,7 +589,7 @@ int _libssh2_wait_socket(LIBSSH2_SESSION *session, time_t start_time)
|
||||
session->err_code = LIBSSH2_ERROR_NONE;
|
||||
|
||||
rc = libssh2_keepalive_send(session, &seconds_to_next);
|
||||
if(rc < 0)
|
||||
if(rc)
|
||||
return rc;
|
||||
|
||||
ms_to_next = seconds_to_next * 1000;
|
||||
|
@@ -1,5 +1,5 @@
|
||||
#ifndef LIBSSH2_SESSION_H
|
||||
#define LIBSSH2_SESSION_H
|
||||
#ifndef __LIBSSH2_SESSION_H
|
||||
#define __LIBSSH2_SESSION_H
|
||||
/* Copyright (c) 2004-2007 Sara Golemon <sarag@libssh2.org>
|
||||
* Copyright (c) 2009-2010 by Daniel Stenberg
|
||||
* Copyright (c) 2010 Simon Josefsson <simon@josefsson.org>
|
||||
@@ -90,4 +90,4 @@ int _libssh2_wait_socket(LIBSSH2_SESSION *session, time_t entry_time);
|
||||
/* this is the lib-internal set blocking function */
|
||||
int _libssh2_session_set_blocking(LIBSSH2_SESSION * session, int blocking);
|
||||
|
||||
#endif /* LIBSSH2_SESSION_H */
|
||||
#endif /* __LIBSSH2_SESSION_H */
|
||||
|
52
src/sftp.c
52
src/sftp.c
@@ -765,7 +765,7 @@ LIBSSH2_CHANNEL_CLOSE_FUNC(libssh2_sftp_dtor)
|
||||
static LIBSSH2_SFTP *sftp_init(LIBSSH2_SESSION *session)
|
||||
{
|
||||
unsigned char *data;
|
||||
size_t data_len;
|
||||
size_t data_len = 0;
|
||||
ssize_t rc;
|
||||
LIBSSH2_SFTP *sftp_handle;
|
||||
struct string_buf buf;
|
||||
@@ -1561,7 +1561,7 @@ static ssize_t sftp_read(LIBSSH2_SFTP_HANDLE * handle, char *buffer,
|
||||
|
||||
while(chunk) {
|
||||
unsigned char *data;
|
||||
size_t data_len;
|
||||
size_t data_len = 0;
|
||||
uint32_t rc32;
|
||||
static const unsigned char read_responses[2] = {
|
||||
SSH_FXP_DATA, SSH_FXP_STATUS
|
||||
@@ -1751,7 +1751,7 @@ static ssize_t sftp_readdir(LIBSSH2_SFTP_HANDLE *handle, char *buffer,
|
||||
LIBSSH2_SFTP *sftp = handle->sftp;
|
||||
LIBSSH2_CHANNEL *channel = sftp->channel;
|
||||
LIBSSH2_SESSION *session = channel->session;
|
||||
size_t data_len;
|
||||
size_t data_len = 0;
|
||||
uint32_t num_names;
|
||||
/* 13 = packet_len(4) + packet_type(1) + request_id(4) + handle_len(4) */
|
||||
uint32_t packet_len = handle->handle_len + 13;
|
||||
@@ -2017,10 +2017,10 @@ static ssize_t sftp_write(LIBSSH2_SFTP_HANDLE *handle, const char *buffer,
|
||||
LIBSSH2_SFTP *sftp = handle->sftp;
|
||||
LIBSSH2_CHANNEL *channel = sftp->channel;
|
||||
LIBSSH2_SESSION *session = channel->session;
|
||||
size_t data_len;
|
||||
size_t data_len = 0;
|
||||
uint32_t retcode;
|
||||
uint32_t packet_len;
|
||||
unsigned char *s, *data;
|
||||
unsigned char *s, *data = NULL;
|
||||
ssize_t rc;
|
||||
struct sftp_pipeline_chunk *chunk;
|
||||
struct sftp_pipeline_chunk *next;
|
||||
@@ -2245,8 +2245,8 @@ static int sftp_fsync(LIBSSH2_SFTP_HANDLE *handle)
|
||||
/* 34 = packet_len(4) + packet_type(1) + request_id(4) +
|
||||
string_len(4) + strlen("fsync@openssh.com")(17) + handle_len(4) */
|
||||
uint32_t packet_len = handle->handle_len + 34;
|
||||
size_t data_len;
|
||||
unsigned char *packet, *s, *data;
|
||||
size_t data_len = 0;
|
||||
unsigned char *packet, *s, *data = NULL;
|
||||
ssize_t rc;
|
||||
uint32_t retcode;
|
||||
|
||||
@@ -2350,11 +2350,11 @@ static int sftp_fstat(LIBSSH2_SFTP_HANDLE *handle,
|
||||
LIBSSH2_SFTP *sftp = handle->sftp;
|
||||
LIBSSH2_CHANNEL *channel = sftp->channel;
|
||||
LIBSSH2_SESSION *session = channel->session;
|
||||
size_t data_len;
|
||||
size_t data_len = 0;
|
||||
/* 13 = packet_len(4) + packet_type(1) + request_id(4) + handle_len(4) */
|
||||
uint32_t packet_len =
|
||||
handle->handle_len + 13 + (setstat ? sftp_attrsize(attrs->flags) : 0);
|
||||
unsigned char *s, *data;
|
||||
unsigned char *s, *data = NULL;
|
||||
static const unsigned char fstat_responses[2] =
|
||||
{ SSH_FXP_ATTRS, SSH_FXP_STATUS };
|
||||
ssize_t rc;
|
||||
@@ -2575,7 +2575,7 @@ sftp_close_handle(LIBSSH2_SFTP_HANDLE *handle)
|
||||
LIBSSH2_SFTP *sftp = handle->sftp;
|
||||
LIBSSH2_CHANNEL *channel = sftp->channel;
|
||||
LIBSSH2_SESSION *session = channel->session;
|
||||
size_t data_len;
|
||||
size_t data_len = 0;
|
||||
/* 13 = packet_len(4) + packet_type(1) + request_id(4) + handle_len(4) */
|
||||
uint32_t packet_len = handle->handle_len + 13;
|
||||
unsigned char *s, *data = NULL;
|
||||
@@ -2705,11 +2705,11 @@ static int sftp_unlink(LIBSSH2_SFTP *sftp, const char *filename,
|
||||
{
|
||||
LIBSSH2_CHANNEL *channel = sftp->channel;
|
||||
LIBSSH2_SESSION *session = channel->session;
|
||||
size_t data_len;
|
||||
size_t data_len = 0;
|
||||
int retcode;
|
||||
/* 13 = packet_len(4) + packet_type(1) + request_id(4) + filename_len(4) */
|
||||
uint32_t packet_len = filename_len + 13;
|
||||
unsigned char *s, *data;
|
||||
unsigned char *s, *data = NULL;
|
||||
int rc;
|
||||
|
||||
if(sftp->unlink_state == libssh2_NB_state_idle) {
|
||||
@@ -2809,14 +2809,14 @@ static int sftp_rename(LIBSSH2_SFTP *sftp, const char *source_filename,
|
||||
{
|
||||
LIBSSH2_CHANNEL *channel = sftp->channel;
|
||||
LIBSSH2_SESSION *session = channel->session;
|
||||
size_t data_len;
|
||||
size_t data_len = 0;
|
||||
int retcode;
|
||||
uint32_t packet_len =
|
||||
source_filename_len + dest_filename_len + 17 + (sftp->version >=
|
||||
5 ? 4 : 0);
|
||||
/* packet_len(4) + packet_type(1) + request_id(4) +
|
||||
source_filename_len(4) + dest_filename_len(4) + flags(4){SFTP5+) */
|
||||
unsigned char *data;
|
||||
unsigned char *data = NULL;
|
||||
ssize_t rc;
|
||||
|
||||
if(sftp->version < 2) {
|
||||
@@ -2949,12 +2949,12 @@ static int sftp_fstatvfs(LIBSSH2_SFTP_HANDLE *handle, LIBSSH2_SFTP_STATVFS *st)
|
||||
LIBSSH2_SFTP *sftp = handle->sftp;
|
||||
LIBSSH2_CHANNEL *channel = sftp->channel;
|
||||
LIBSSH2_SESSION *session = channel->session;
|
||||
size_t data_len;
|
||||
size_t data_len = 0;
|
||||
/* 17 = packet_len(4) + packet_type(1) + request_id(4) + ext_len(4)
|
||||
+ handle_len (4) */
|
||||
/* 20 = strlen ("fstatvfs@openssh.com") */
|
||||
uint32_t packet_len = handle->handle_len + 20 + 17;
|
||||
unsigned char *packet, *s, *data;
|
||||
unsigned char *packet, *s, *data = NULL;
|
||||
ssize_t rc;
|
||||
unsigned int flag;
|
||||
static const unsigned char responses[2] =
|
||||
@@ -3085,12 +3085,12 @@ static int sftp_statvfs(LIBSSH2_SFTP *sftp, const char *path,
|
||||
{
|
||||
LIBSSH2_CHANNEL *channel = sftp->channel;
|
||||
LIBSSH2_SESSION *session = channel->session;
|
||||
size_t data_len;
|
||||
size_t data_len = 0;
|
||||
/* 17 = packet_len(4) + packet_type(1) + request_id(4) + ext_len(4)
|
||||
+ path_len (4) */
|
||||
/* 19 = strlen ("statvfs@openssh.com") */
|
||||
uint32_t packet_len = path_len + 19 + 17;
|
||||
unsigned char *packet, *s, *data;
|
||||
unsigned char *packet, *s, *data = NULL;
|
||||
ssize_t rc;
|
||||
unsigned int flag;
|
||||
static const unsigned char responses[2] =
|
||||
@@ -3225,10 +3225,10 @@ static int sftp_mkdir(LIBSSH2_SFTP *sftp, const char *path,
|
||||
LIBSSH2_SFTP_ATTRIBUTES attrs = {
|
||||
0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
size_t data_len;
|
||||
size_t data_len = 0;
|
||||
int retcode;
|
||||
ssize_t packet_len;
|
||||
unsigned char *packet, *s, *data;
|
||||
unsigned char *packet, *s, *data = NULL;
|
||||
int rc;
|
||||
|
||||
if(mode != LIBSSH2_SFTP_DEFAULT_MODE) {
|
||||
@@ -3340,11 +3340,11 @@ static int sftp_rmdir(LIBSSH2_SFTP *sftp, const char *path,
|
||||
{
|
||||
LIBSSH2_CHANNEL *channel = sftp->channel;
|
||||
LIBSSH2_SESSION *session = channel->session;
|
||||
size_t data_len;
|
||||
size_t data_len = 0;
|
||||
int retcode;
|
||||
/* 13 = packet_len(4) + packet_type(1) + request_id(4) + path_len(4) */
|
||||
ssize_t packet_len = path_len + 13;
|
||||
unsigned char *s, *data;
|
||||
unsigned char *s, *data = NULL;
|
||||
int rc;
|
||||
|
||||
if(sftp->rmdir_state == libssh2_NB_state_idle) {
|
||||
@@ -3442,13 +3442,13 @@ static int sftp_stat(LIBSSH2_SFTP *sftp, const char *path,
|
||||
{
|
||||
LIBSSH2_CHANNEL *channel = sftp->channel;
|
||||
LIBSSH2_SESSION *session = channel->session;
|
||||
size_t data_len;
|
||||
size_t data_len = 0;
|
||||
/* 13 = packet_len(4) + packet_type(1) + request_id(4) + path_len(4) */
|
||||
ssize_t packet_len =
|
||||
path_len + 13 +
|
||||
((stat_type ==
|
||||
LIBSSH2_SFTP_SETSTAT) ? sftp_attrsize(attrs->flags) : 0);
|
||||
unsigned char *s, *data;
|
||||
unsigned char *s, *data = NULL;
|
||||
static const unsigned char stat_responses[2] =
|
||||
{ SSH_FXP_ATTRS, SSH_FXP_STATUS };
|
||||
int rc;
|
||||
@@ -3580,12 +3580,12 @@ static int sftp_symlink(LIBSSH2_SFTP *sftp, const char *path,
|
||||
{
|
||||
LIBSSH2_CHANNEL *channel = sftp->channel;
|
||||
LIBSSH2_SESSION *session = channel->session;
|
||||
size_t data_len, link_len;
|
||||
size_t data_len = 0, link_len;
|
||||
/* 13 = packet_len(4) + packet_type(1) + request_id(4) + path_len(4) */
|
||||
ssize_t packet_len =
|
||||
path_len + 13 +
|
||||
((link_type == LIBSSH2_SFTP_SYMLINK) ? (4 + target_len) : 0);
|
||||
unsigned char *s, *data;
|
||||
unsigned char *s, *data = NULL;
|
||||
static const unsigned char link_responses[2] =
|
||||
{ SSH_FXP_NAME, SSH_FXP_STATUS };
|
||||
int retcode;
|
||||
|
@@ -1,5 +1,5 @@
|
||||
#ifndef _LIBSSH2_SFTP_H
|
||||
#define _LIBSSH2_SFTP_H
|
||||
#ifndef __LIBSSH2_SFTP_H
|
||||
#define __LIBSSH2_SFTP_H
|
||||
/*
|
||||
* Copyright (C) 2010 - 2012 by Daniel Stenberg
|
||||
* Author: Daniel Stenberg <daniel@haxx.se>
|
||||
@@ -235,4 +235,4 @@ struct _LIBSSH2_SFTP
|
||||
uint32_t symlink_request_id;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif /* __LIBSSH2_SFTP_H */
|
||||
|
@@ -323,7 +323,7 @@ int _libssh2_transport_read(LIBSSH2_SESSION * session)
|
||||
|
||||
do {
|
||||
if(session->socket_state == LIBSSH2_SOCKET_DISCONNECTED) {
|
||||
return LIBSSH2_ERROR_NONE;
|
||||
return LIBSSH2_ERROR_SOCKET_DISCONNECT;
|
||||
}
|
||||
|
||||
if(session->state & LIBSSH2_STATE_NEWKEYS) {
|
||||
@@ -465,7 +465,7 @@ int _libssh2_transport_read(LIBSSH2_SESSION * session)
|
||||
* or less (including length, padding length, payload,
|
||||
* padding, and MAC.)."
|
||||
*/
|
||||
if(total_num > LIBSSH2_PACKET_MAXPAYLOAD) {
|
||||
if(total_num > LIBSSH2_PACKET_MAXPAYLOAD || total_num == 0) {
|
||||
return LIBSSH2_ERROR_OUT_OF_BOUNDARY;
|
||||
}
|
||||
|
||||
@@ -488,6 +488,8 @@ int _libssh2_transport_read(LIBSSH2_SESSION * session)
|
||||
p->wptr += blocksize - 5; /* advance write pointer */
|
||||
}
|
||||
else {
|
||||
if(p->payload)
|
||||
LIBSSH2_FREE(session, p->payload);
|
||||
return LIBSSH2_ERROR_OUT_OF_BOUNDARY;
|
||||
}
|
||||
}
|
||||
@@ -570,6 +572,8 @@ int _libssh2_transport_read(LIBSSH2_SESSION * session)
|
||||
memcpy(p->wptr, &p->buf[p->readidx], numbytes);
|
||||
}
|
||||
else {
|
||||
if(p->payload)
|
||||
LIBSSH2_FREE(session, p->payload);
|
||||
return LIBSSH2_ERROR_OUT_OF_BOUNDARY;
|
||||
}
|
||||
|
||||
@@ -765,7 +769,7 @@ int _libssh2_transport_send(LIBSSH2_SESSION *session,
|
||||
((session->state & LIBSSH2_STATE_AUTHENTICATED) ||
|
||||
session->local.comp->use_in_auth);
|
||||
|
||||
if(encrypted && compressed) {
|
||||
if(encrypted && compressed && session->local.comp_abstract) {
|
||||
/* the idea here is that these function must fail if the output gets
|
||||
larger than what fits in the assigned buffer so thus they don't
|
||||
check the input size as we don't know how much it compresses */
|
||||
@@ -858,7 +862,10 @@ int _libssh2_transport_send(LIBSSH2_SESSION *session,
|
||||
p->outbuf[4] = (unsigned char)padding_length;
|
||||
|
||||
/* fill the padding area with random junk */
|
||||
_libssh2_random(p->outbuf + 5 + data_len, padding_length);
|
||||
if(_libssh2_random(p->outbuf + 5 + data_len, padding_length)) {
|
||||
return _libssh2_error(session, LIBSSH2_ERROR_RANDGEN,
|
||||
"Unable to get random bytes for packet padding");
|
||||
}
|
||||
|
||||
if(encrypted) {
|
||||
size_t i;
|
||||
|
@@ -1,6 +1,5 @@
|
||||
#ifndef __LIBSSH2_TRANSPORT_H
|
||||
#define __LIBSSH2_TRANSPORT_H
|
||||
|
||||
/* Copyright (C) 2007 The Written Word, Inc. All rights reserved.
|
||||
* Copyright (C) 2009-2010 by Daniel Stenberg
|
||||
* Author: Daniel Stenberg <daniel@haxx.se>
|
||||
|
@@ -897,11 +897,6 @@ userauth_hostbased_fromfile(LIBSSH2_SESSION *session,
|
||||
{
|
||||
int rc;
|
||||
|
||||
#if !LIBSSH2_RSA
|
||||
return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
|
||||
"RSA is not supported by crypto backend");
|
||||
#endif
|
||||
|
||||
if(session->userauth_host_state == libssh2_NB_state_idle) {
|
||||
const LIBSSH2_HOSTKEY_METHOD *privkeyobj;
|
||||
unsigned char *pubkeydata = NULL;
|
||||
@@ -1144,7 +1139,21 @@ libssh2_userauth_hostbased_fromfile_ex(LIBSSH2_SESSION *session,
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static int plain_method_len(const char *method, size_t method_len)
|
||||
{
|
||||
if(!strncmp("ecdsa-sha2-nistp256-cert-v01@openssh.com",
|
||||
method,
|
||||
method_len) ||
|
||||
!strncmp("ecdsa-sha2-nistp384-cert-v01@openssh.com",
|
||||
method,
|
||||
method_len) ||
|
||||
!strncmp("ecdsa-sha2-nistp521-cert-v01@openssh.com",
|
||||
method,
|
||||
method_len)) {
|
||||
return 19;
|
||||
}
|
||||
return method_len;
|
||||
}
|
||||
|
||||
int
|
||||
_libssh2_userauth_publickey(LIBSSH2_SESSION *session,
|
||||
@@ -1409,6 +1418,10 @@ _libssh2_userauth_publickey(LIBSSH2_SESSION *session,
|
||||
s = session->userauth_pblc_packet + session->userauth_pblc_packet_len;
|
||||
session->userauth_pblc_b = NULL;
|
||||
|
||||
session->userauth_pblc_method_len =
|
||||
plain_method_len((const char *)session->userauth_pblc_method,
|
||||
session->userauth_pblc_method_len);
|
||||
|
||||
_libssh2_store_u32(&s,
|
||||
4 + session->userauth_pblc_method_len + 4 +
|
||||
sig_len);
|
||||
@@ -1507,11 +1520,6 @@ userauth_publickey_frommemory(LIBSSH2_SESSION *session,
|
||||
void *abstract = &privkey_file;
|
||||
int rc;
|
||||
|
||||
#if !LIBSSH2_RSA
|
||||
return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
|
||||
"RSA is not supported by crypto backend");
|
||||
#endif
|
||||
|
||||
privkey_file.filename = privatekeydata;
|
||||
privkey_file.passphrase = passphrase;
|
||||
|
||||
@@ -1526,15 +1534,14 @@ userauth_publickey_frommemory(LIBSSH2_SESSION *session,
|
||||
}
|
||||
else if(privatekeydata_len && privatekeydata) {
|
||||
/* Compute public key from private key. */
|
||||
if(_libssh2_pub_priv_keyfilememory(session,
|
||||
rc = _libssh2_pub_priv_keyfilememory(session,
|
||||
&session->userauth_pblc_method,
|
||||
&session->userauth_pblc_method_len,
|
||||
&pubkeydata, &pubkeydata_len,
|
||||
privatekeydata, privatekeydata_len,
|
||||
passphrase))
|
||||
return _libssh2_error(session, LIBSSH2_ERROR_FILE,
|
||||
"Unable to extract public key "
|
||||
"from private key.");
|
||||
passphrase);
|
||||
if(rc)
|
||||
return rc;
|
||||
}
|
||||
else {
|
||||
return _libssh2_error(session, LIBSSH2_ERROR_FILE,
|
||||
@@ -1569,11 +1576,6 @@ userauth_publickey_fromfile(LIBSSH2_SESSION *session,
|
||||
void *abstract = &privkey_file;
|
||||
int rc;
|
||||
|
||||
#if !LIBSSH2_RSA
|
||||
return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
|
||||
"RSA is not supported by crypto backend");
|
||||
#endif
|
||||
|
||||
privkey_file.filename = privatekey;
|
||||
privkey_file.passphrase = passphrase;
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
#ifndef LIBSSH2_USERAUTH_H
|
||||
#define LIBSSH2_USERAUTH_H
|
||||
#ifndef __LIBSSH2_USERAUTH_H
|
||||
#define __LIBSSH2_USERAUTH_H
|
||||
/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
|
||||
* Copyright (c) 2009-2010 by Daniel Stenberg
|
||||
* All rights reserved.
|
||||
@@ -48,4 +48,4 @@ _libssh2_userauth_publickey(LIBSSH2_SESSION *session,
|
||||
((*sign_callback)),
|
||||
void *abstract);
|
||||
|
||||
#endif /* LIBSSH2_USERAUTH_H */
|
||||
#endif /* __LIBSSH2_USERAUTH_H */
|
||||
|
568
src/wincng.c
Executable file → Normal file
568
src/wincng.c
Executable file → Normal file
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2013-2015 Marc Hoersken <info@marc-hoersken.de>
|
||||
* Copyright (C) 2013-2020 Marc Hoersken <info@marc-hoersken.de>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
@@ -58,6 +58,7 @@
|
||||
|
||||
#include <windows.h>
|
||||
#include <bcrypt.h>
|
||||
#include <ntstatus.h>
|
||||
#include <math.h>
|
||||
#include "misc.h"
|
||||
|
||||
@@ -98,6 +99,10 @@
|
||||
#define BCRYPT_SHA256_ALGORITHM L"SHA256"
|
||||
#endif
|
||||
|
||||
#ifndef BCRYPT_SHA384_ALGORITHM
|
||||
#define BCRYPT_SHA384_ALGORITHM L"SHA384"
|
||||
#endif
|
||||
|
||||
#ifndef BCRYPT_SHA512_ALGORITHM
|
||||
#define BCRYPT_SHA512_ALGORITHM L"SHA512"
|
||||
#endif
|
||||
@@ -122,6 +127,15 @@
|
||||
#define BCRYPT_3DES_ALGORITHM L"3DES"
|
||||
#endif
|
||||
|
||||
#ifndef BCRYPT_DH_ALGORITHM
|
||||
#define BCRYPT_DH_ALGORITHM L"DH"
|
||||
#endif
|
||||
|
||||
/* BCRYPT_KDF_RAW_SECRET is available from Windows 8.1 and onwards */
|
||||
#ifndef BCRYPT_KDF_RAW_SECRET
|
||||
#define BCRYPT_KDF_RAW_SECRET L"TRUNCATE"
|
||||
#endif
|
||||
|
||||
#ifndef BCRYPT_ALG_HANDLE_HMAC_FLAG
|
||||
#define BCRYPT_ALG_HANDLE_HMAC_FLAG 0x00000008
|
||||
#endif
|
||||
@@ -208,40 +222,88 @@
|
||||
* Windows CNG backend: Generic functions
|
||||
*/
|
||||
|
||||
struct _libssh2_wincng_ctx _libssh2_wincng;
|
||||
|
||||
void
|
||||
_libssh2_wincng_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
(void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgRNG,
|
||||
memset(&_libssh2_wincng, 0, sizeof(_libssh2_wincng));
|
||||
|
||||
ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgRNG,
|
||||
BCRYPT_RNG_ALGORITHM, NULL, 0);
|
||||
if(!BCRYPT_SUCCESS(ret)) {
|
||||
_libssh2_wincng.hAlgRNG = NULL;
|
||||
}
|
||||
|
||||
(void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHashMD5,
|
||||
ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHashMD5,
|
||||
BCRYPT_MD5_ALGORITHM, NULL, 0);
|
||||
(void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHashSHA1,
|
||||
if(!BCRYPT_SUCCESS(ret)) {
|
||||
_libssh2_wincng.hAlgHashMD5 = NULL;
|
||||
}
|
||||
ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHashSHA1,
|
||||
BCRYPT_SHA1_ALGORITHM, NULL, 0);
|
||||
(void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHashSHA256,
|
||||
if(!BCRYPT_SUCCESS(ret)) {
|
||||
_libssh2_wincng.hAlgHashSHA1 = NULL;
|
||||
}
|
||||
ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHashSHA256,
|
||||
BCRYPT_SHA256_ALGORITHM, NULL, 0);
|
||||
(void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHashSHA512,
|
||||
if(!BCRYPT_SUCCESS(ret)) {
|
||||
_libssh2_wincng.hAlgHashSHA256 = NULL;
|
||||
}
|
||||
ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHashSHA384,
|
||||
BCRYPT_SHA384_ALGORITHM, NULL, 0);
|
||||
if(!BCRYPT_SUCCESS(ret)) {
|
||||
_libssh2_wincng.hAlgHashSHA384 = NULL;
|
||||
}
|
||||
ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHashSHA512,
|
||||
BCRYPT_SHA512_ALGORITHM, NULL, 0);
|
||||
if(!BCRYPT_SUCCESS(ret)) {
|
||||
_libssh2_wincng.hAlgHashSHA512 = NULL;
|
||||
}
|
||||
|
||||
(void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHmacMD5,
|
||||
ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHmacMD5,
|
||||
BCRYPT_MD5_ALGORITHM, NULL,
|
||||
BCRYPT_ALG_HANDLE_HMAC_FLAG);
|
||||
(void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHmacSHA1,
|
||||
if(!BCRYPT_SUCCESS(ret)) {
|
||||
_libssh2_wincng.hAlgHmacMD5 = NULL;
|
||||
}
|
||||
ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHmacSHA1,
|
||||
BCRYPT_SHA1_ALGORITHM, NULL,
|
||||
BCRYPT_ALG_HANDLE_HMAC_FLAG);
|
||||
(void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHmacSHA256,
|
||||
if(!BCRYPT_SUCCESS(ret)) {
|
||||
_libssh2_wincng.hAlgHmacSHA1 = NULL;
|
||||
}
|
||||
ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHmacSHA256,
|
||||
BCRYPT_SHA256_ALGORITHM, NULL,
|
||||
BCRYPT_ALG_HANDLE_HMAC_FLAG);
|
||||
(void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHmacSHA512,
|
||||
if(!BCRYPT_SUCCESS(ret)) {
|
||||
_libssh2_wincng.hAlgHmacSHA256 = NULL;
|
||||
}
|
||||
ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHmacSHA384,
|
||||
BCRYPT_SHA384_ALGORITHM, NULL,
|
||||
BCRYPT_ALG_HANDLE_HMAC_FLAG);
|
||||
if(!BCRYPT_SUCCESS(ret)) {
|
||||
_libssh2_wincng.hAlgHmacSHA384 = NULL;
|
||||
}
|
||||
ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHmacSHA512,
|
||||
BCRYPT_SHA512_ALGORITHM, NULL,
|
||||
BCRYPT_ALG_HANDLE_HMAC_FLAG);
|
||||
if(!BCRYPT_SUCCESS(ret)) {
|
||||
_libssh2_wincng.hAlgHmacSHA512 = NULL;
|
||||
}
|
||||
|
||||
(void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgRSA,
|
||||
ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgRSA,
|
||||
BCRYPT_RSA_ALGORITHM, NULL, 0);
|
||||
(void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgDSA,
|
||||
if(!BCRYPT_SUCCESS(ret)) {
|
||||
_libssh2_wincng.hAlgRSA = NULL;
|
||||
}
|
||||
ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgDSA,
|
||||
BCRYPT_DSA_ALGORITHM, NULL, 0);
|
||||
if(!BCRYPT_SUCCESS(ret)) {
|
||||
_libssh2_wincng.hAlgDSA = NULL;
|
||||
}
|
||||
|
||||
ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgAES_CBC,
|
||||
BCRYPT_AES_ALGORITHM, NULL, 0);
|
||||
@@ -251,7 +313,10 @@ _libssh2_wincng_init(void)
|
||||
(PBYTE)BCRYPT_CHAIN_MODE_CBC,
|
||||
sizeof(BCRYPT_CHAIN_MODE_CBC), 0);
|
||||
if(!BCRYPT_SUCCESS(ret)) {
|
||||
(void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgAES_CBC, 0);
|
||||
ret = BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgAES_CBC, 0);
|
||||
if(BCRYPT_SUCCESS(ret)) {
|
||||
_libssh2_wincng.hAlgAES_CBC = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -263,7 +328,10 @@ _libssh2_wincng_init(void)
|
||||
(PBYTE)BCRYPT_CHAIN_MODE_ECB,
|
||||
sizeof(BCRYPT_CHAIN_MODE_ECB), 0);
|
||||
if(!BCRYPT_SUCCESS(ret)) {
|
||||
(void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgAES_ECB, 0);
|
||||
ret = BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgAES_ECB, 0);
|
||||
if(BCRYPT_SUCCESS(ret)) {
|
||||
_libssh2_wincng.hAlgAES_ECB = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -275,7 +343,10 @@ _libssh2_wincng_init(void)
|
||||
(PBYTE)BCRYPT_CHAIN_MODE_NA,
|
||||
sizeof(BCRYPT_CHAIN_MODE_NA), 0);
|
||||
if(!BCRYPT_SUCCESS(ret)) {
|
||||
(void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgRC4_NA, 0);
|
||||
ret = BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgRC4_NA, 0);
|
||||
if(BCRYPT_SUCCESS(ret)) {
|
||||
_libssh2_wincng.hAlgRC4_NA = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -287,29 +358,58 @@ _libssh2_wincng_init(void)
|
||||
(PBYTE)BCRYPT_CHAIN_MODE_CBC,
|
||||
sizeof(BCRYPT_CHAIN_MODE_CBC), 0);
|
||||
if(!BCRYPT_SUCCESS(ret)) {
|
||||
(void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlg3DES_CBC,
|
||||
ret = BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlg3DES_CBC,
|
||||
0);
|
||||
if(BCRYPT_SUCCESS(ret)) {
|
||||
_libssh2_wincng.hAlg3DES_CBC = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgDH,
|
||||
BCRYPT_DH_ALGORITHM, NULL, 0);
|
||||
if(!BCRYPT_SUCCESS(ret)) {
|
||||
_libssh2_wincng.hAlgDH = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_libssh2_wincng_free(void)
|
||||
{
|
||||
if(_libssh2_wincng.hAlgRNG)
|
||||
(void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgRNG, 0);
|
||||
if(_libssh2_wincng.hAlgHashMD5)
|
||||
(void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHashMD5, 0);
|
||||
if(_libssh2_wincng.hAlgHashSHA1)
|
||||
(void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHashSHA1, 0);
|
||||
if(_libssh2_wincng.hAlgHashSHA256)
|
||||
(void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHashSHA256, 0);
|
||||
if(_libssh2_wincng.hAlgHashSHA384)
|
||||
(void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHashSHA384, 0);
|
||||
if(_libssh2_wincng.hAlgHashSHA512)
|
||||
(void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHashSHA512, 0);
|
||||
if(_libssh2_wincng.hAlgHmacMD5)
|
||||
(void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHmacMD5, 0);
|
||||
if(_libssh2_wincng.hAlgHmacSHA1)
|
||||
(void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHmacSHA1, 0);
|
||||
if(_libssh2_wincng.hAlgHmacSHA256)
|
||||
(void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHmacSHA256, 0);
|
||||
if(_libssh2_wincng.hAlgHmacSHA384)
|
||||
(void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHmacSHA384, 0);
|
||||
if(_libssh2_wincng.hAlgHmacSHA512)
|
||||
(void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHmacSHA512, 0);
|
||||
if(_libssh2_wincng.hAlgRSA)
|
||||
(void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgRSA, 0);
|
||||
if(_libssh2_wincng.hAlgDSA)
|
||||
(void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgDSA, 0);
|
||||
if(_libssh2_wincng.hAlgAES_CBC)
|
||||
(void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgAES_CBC, 0);
|
||||
if(_libssh2_wincng.hAlgRC4_NA)
|
||||
(void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgRC4_NA, 0);
|
||||
if(_libssh2_wincng.hAlg3DES_CBC)
|
||||
(void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlg3DES_CBC, 0);
|
||||
if(_libssh2_wincng.hAlgDH)
|
||||
(void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgDH, 0);
|
||||
|
||||
memset(&_libssh2_wincng, 0, sizeof(_libssh2_wincng));
|
||||
}
|
||||
@@ -342,6 +442,24 @@ _libssh2_wincng_safe_free(void *buf, int len)
|
||||
free(buf);
|
||||
}
|
||||
|
||||
/* Copy a big endian set of bits from src to dest.
|
||||
* if the size of src is smaller than dest then pad the "left" (MSB)
|
||||
* end with zeroes and copy the bits into the "right" (LSB) end. */
|
||||
static void
|
||||
memcpy_with_be_padding(unsigned char *dest, unsigned long dest_len,
|
||||
unsigned char *src, unsigned long src_len)
|
||||
{
|
||||
if(dest_len > src_len) {
|
||||
memset(dest, 0, dest_len - src_len);
|
||||
}
|
||||
memcpy((dest + dest_len) - src_len, src, src_len);
|
||||
}
|
||||
|
||||
static int
|
||||
round_down(int number, int multiple)
|
||||
{
|
||||
return (number / multiple) * multiple;
|
||||
}
|
||||
|
||||
/*******************************************************************/
|
||||
/*
|
||||
@@ -546,7 +664,7 @@ _libssh2_wincng_key_sha1_verify(_libssh2_wincng_key_ctx *ctx,
|
||||
static int
|
||||
_libssh2_wincng_load_pem(LIBSSH2_SESSION *session,
|
||||
const char *filename,
|
||||
const char *passphrase,
|
||||
const unsigned char *passphrase,
|
||||
const char *headerbegin,
|
||||
const char *headerend,
|
||||
unsigned char **data,
|
||||
@@ -572,7 +690,7 @@ _libssh2_wincng_load_pem(LIBSSH2_SESSION *session,
|
||||
static int
|
||||
_libssh2_wincng_load_private(LIBSSH2_SESSION *session,
|
||||
const char *filename,
|
||||
const char *passphrase,
|
||||
const unsigned char *passphrase,
|
||||
unsigned char **ppbEncoded,
|
||||
unsigned long *pcbEncoded,
|
||||
int tryLoadRSA, int tryLoadDSA)
|
||||
@@ -605,7 +723,7 @@ static int
|
||||
_libssh2_wincng_load_private_memory(LIBSSH2_SESSION *session,
|
||||
const char *privatekeydata,
|
||||
size_t privatekeydata_len,
|
||||
const char *passphrase,
|
||||
const unsigned char *passphrase,
|
||||
unsigned char **ppbEncoded,
|
||||
unsigned long *pcbEncoded,
|
||||
int tryLoadRSA, int tryLoadDSA)
|
||||
@@ -1030,8 +1148,7 @@ _libssh2_wincng_rsa_new_private(libssh2_rsa_ctx **rsa,
|
||||
|
||||
(void)session;
|
||||
|
||||
ret = _libssh2_wincng_load_private(session, filename,
|
||||
(const char *)passphrase,
|
||||
ret = _libssh2_wincng_load_private(session, filename, passphrase,
|
||||
&pbEncoded, &cbEncoded, 1, 0);
|
||||
if(ret) {
|
||||
return -1;
|
||||
@@ -1055,7 +1172,7 @@ _libssh2_wincng_rsa_new_private_frommemory(libssh2_rsa_ctx **rsa,
|
||||
LIBSSH2_SESSION *session,
|
||||
const char *filedata,
|
||||
size_t filedata_len,
|
||||
unsigned const char *passphrase)
|
||||
const unsigned char *passphrase)
|
||||
{
|
||||
#ifdef HAVE_LIBCRYPT32
|
||||
unsigned char *pbEncoded;
|
||||
@@ -1065,7 +1182,7 @@ _libssh2_wincng_rsa_new_private_frommemory(libssh2_rsa_ctx **rsa,
|
||||
(void)session;
|
||||
|
||||
ret = _libssh2_wincng_load_private_memory(session, filedata, filedata_len,
|
||||
(const char *)passphrase,
|
||||
passphrase,
|
||||
&pbEncoded, &cbEncoded, 1, 0);
|
||||
if(ret) {
|
||||
return -1;
|
||||
@@ -1329,8 +1446,7 @@ _libssh2_wincng_dsa_new_private(libssh2_dsa_ctx **dsa,
|
||||
unsigned long cbEncoded;
|
||||
int ret;
|
||||
|
||||
ret = _libssh2_wincng_load_private(session, filename,
|
||||
(const char *)passphrase,
|
||||
ret = _libssh2_wincng_load_private(session, filename, passphrase,
|
||||
&pbEncoded, &cbEncoded, 0, 1);
|
||||
if(ret) {
|
||||
return -1;
|
||||
@@ -1354,7 +1470,7 @@ _libssh2_wincng_dsa_new_private_frommemory(libssh2_dsa_ctx **dsa,
|
||||
LIBSSH2_SESSION *session,
|
||||
const char *filedata,
|
||||
size_t filedata_len,
|
||||
unsigned const char *passphrase)
|
||||
const unsigned char *passphrase)
|
||||
{
|
||||
#ifdef HAVE_LIBCRYPT32
|
||||
unsigned char *pbEncoded;
|
||||
@@ -1362,7 +1478,7 @@ _libssh2_wincng_dsa_new_private_frommemory(libssh2_dsa_ctx **dsa,
|
||||
int ret;
|
||||
|
||||
ret = _libssh2_wincng_load_private_memory(session, filedata, filedata_len,
|
||||
(const char *)passphrase,
|
||||
passphrase,
|
||||
&pbEncoded, &cbEncoded, 0, 1);
|
||||
if(ret) {
|
||||
return -1;
|
||||
@@ -1610,7 +1726,8 @@ _libssh2_wincng_pub_priv_keyfile(LIBSSH2_SESSION *session,
|
||||
unsigned long cbEncoded;
|
||||
int ret;
|
||||
|
||||
ret = _libssh2_wincng_load_private(session, privatekey, passphrase,
|
||||
ret = _libssh2_wincng_load_private(session, privatekey,
|
||||
(const unsigned char *)passphrase,
|
||||
&pbEncoded, &cbEncoded, 1, 1);
|
||||
if(ret) {
|
||||
return -1;
|
||||
@@ -1649,7 +1766,9 @@ _libssh2_wincng_pub_priv_keyfilememory(LIBSSH2_SESSION *session,
|
||||
int ret;
|
||||
|
||||
ret = _libssh2_wincng_load_private_memory(session, privatekeydata,
|
||||
privatekeydata_len, passphrase,
|
||||
privatekeydata_len,
|
||||
(const unsigned char *)
|
||||
passphrase,
|
||||
&pbEncoded, &cbEncoded, 1, 1);
|
||||
if(ret) {
|
||||
return -1;
|
||||
@@ -1914,7 +2033,8 @@ _libssh2_wincng_bignum_rand(_libssh2_bn *rnd, int bits, int top, int bottom)
|
||||
if(!rnd)
|
||||
return -1;
|
||||
|
||||
length = (unsigned long)(ceil((float)bits / 8) * sizeof(unsigned char));
|
||||
length = (unsigned long) (ceil(((double)bits) / 8.0) *
|
||||
sizeof(unsigned char));
|
||||
if(_libssh2_wincng_bignum_resize(rnd, length))
|
||||
return -1;
|
||||
|
||||
@@ -1925,15 +2045,17 @@ _libssh2_wincng_bignum_rand(_libssh2_bn *rnd, int bits, int top, int bottom)
|
||||
|
||||
/* calculate significant bits in most significant byte */
|
||||
bits %= 8;
|
||||
if(bits == 0)
|
||||
bits = 8;
|
||||
|
||||
/* fill most significant byte with zero padding */
|
||||
bignum[0] &= (1 << (8 - bits)) - 1;
|
||||
bignum[0] &= ((1 << bits) - 1);
|
||||
|
||||
/* set some special last bits in most significant byte */
|
||||
/* set most significant bits in most significant byte */
|
||||
if(top == 0)
|
||||
bignum[0] |= (1 << (7 - bits));
|
||||
bignum[0] |= (1 << (bits - 1));
|
||||
else if(top == 1)
|
||||
bignum[0] |= (3 << (6 - bits));
|
||||
bignum[0] |= (3 << (bits - 2));
|
||||
|
||||
/* make odd by setting first bit in least significant byte */
|
||||
if(bottom)
|
||||
@@ -1978,11 +2100,10 @@ _libssh2_wincng_bignum_mod_exp(_libssh2_bn *r,
|
||||
offset += p->length;
|
||||
|
||||
memcpy(key + offset, m->bignum, m->length);
|
||||
offset = 0;
|
||||
|
||||
ret = BCryptImportKeyPair(_libssh2_wincng.hAlgRSA, NULL,
|
||||
BCRYPT_RSAPUBLIC_BLOB, &hKey, key, keylen,
|
||||
BCRYPT_NO_KEY_VALIDATION);
|
||||
|
||||
BCRYPT_RSAPUBLIC_BLOB, &hKey, key, keylen, 0);
|
||||
if(BCRYPT_SUCCESS(ret)) {
|
||||
ret = BCryptEncrypt(hKey, a->bignum, a->length, NULL, NULL, 0,
|
||||
NULL, 0, &length, BCRYPT_PAD_NONE);
|
||||
@@ -1991,9 +2112,8 @@ _libssh2_wincng_bignum_mod_exp(_libssh2_bn *r,
|
||||
length = max(a->length, length);
|
||||
bignum = malloc(length);
|
||||
if(bignum) {
|
||||
offset = length - a->length;
|
||||
memset(bignum, 0, offset);
|
||||
memcpy(bignum + offset, a->bignum, a->length);
|
||||
memcpy_with_be_padding(bignum, length,
|
||||
a->bignum, a->length);
|
||||
|
||||
ret = BCryptEncrypt(hKey, bignum, length, NULL, NULL, 0,
|
||||
r->bignum, r->length, &offset,
|
||||
@@ -2032,8 +2152,9 @@ _libssh2_wincng_bignum_set_word(_libssh2_bn *bn, unsigned long word)
|
||||
number = word;
|
||||
while(number >>= 1)
|
||||
bits++;
|
||||
bits++;
|
||||
|
||||
length = (unsigned long) (ceil(((double)(bits + 1)) / 8.0) *
|
||||
length = (unsigned long) (ceil(((double)bits) / 8.0) *
|
||||
sizeof(unsigned char));
|
||||
if(_libssh2_wincng_bignum_resize(bn, length))
|
||||
return -1;
|
||||
@@ -2050,21 +2171,18 @@ _libssh2_wincng_bignum_bits(const _libssh2_bn *bn)
|
||||
unsigned char number;
|
||||
unsigned long offset, length, bits;
|
||||
|
||||
if(!bn)
|
||||
if(!bn || !bn->bignum || !bn->length)
|
||||
return 0;
|
||||
|
||||
length = bn->length - 1;
|
||||
|
||||
offset = 0;
|
||||
while(!(*(bn->bignum + offset)) && (offset < length))
|
||||
length = bn->length - 1;
|
||||
while(!bn->bignum[offset] && offset < length)
|
||||
offset++;
|
||||
|
||||
bits = (length - offset) * 8;
|
||||
number = bn->bignum[offset];
|
||||
|
||||
while(number >>= 1)
|
||||
bits++;
|
||||
|
||||
bits++;
|
||||
|
||||
return bits;
|
||||
@@ -2127,6 +2245,7 @@ _libssh2_wincng_bignum_free(_libssh2_bn *bn)
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************/
|
||||
/*
|
||||
* Windows CNG backend: Diffie-Hellman support.
|
||||
*/
|
||||
@@ -2134,35 +2253,342 @@ _libssh2_wincng_bignum_free(_libssh2_bn *bn)
|
||||
void
|
||||
_libssh2_dh_init(_libssh2_dh_ctx *dhctx)
|
||||
{
|
||||
*dhctx = _libssh2_wincng_bignum_init(); /* Random from client */
|
||||
}
|
||||
|
||||
int
|
||||
_libssh2_dh_key_pair(_libssh2_dh_ctx *dhctx, _libssh2_bn *public,
|
||||
_libssh2_bn *g, _libssh2_bn *p, int group_order)
|
||||
{
|
||||
/* Generate x and e */
|
||||
if(_libssh2_wincng_bignum_rand(*dhctx, group_order * 8 - 1, 0, -1))
|
||||
return -1;
|
||||
if(_libssh2_wincng_bignum_mod_exp(public, g, *dhctx, p))
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
_libssh2_dh_secret(_libssh2_dh_ctx *dhctx, _libssh2_bn *secret,
|
||||
_libssh2_bn *f, _libssh2_bn *p)
|
||||
{
|
||||
/* Compute the shared secret */
|
||||
_libssh2_wincng_bignum_mod_exp(secret, f, *dhctx, p);
|
||||
return 0;
|
||||
/* Random from client */
|
||||
dhctx->bn = NULL;
|
||||
dhctx->dh_handle = NULL;
|
||||
dhctx->dh_params = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
_libssh2_dh_dtor(_libssh2_dh_ctx *dhctx)
|
||||
{
|
||||
_libssh2_wincng_bignum_free(*dhctx);
|
||||
*dhctx = NULL;
|
||||
if(dhctx->dh_handle) {
|
||||
BCryptDestroyKey(dhctx->dh_handle);
|
||||
dhctx->dh_handle = NULL;
|
||||
}
|
||||
if(dhctx->dh_params) {
|
||||
/* Since public dh_params are shared in clear text,
|
||||
* we don't need to securely zero them out here */
|
||||
free(dhctx->dh_params);
|
||||
dhctx->dh_params = NULL;
|
||||
}
|
||||
if(dhctx->bn) {
|
||||
_libssh2_wincng_bignum_free(dhctx->bn);
|
||||
dhctx->bn = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Generates a Diffie-Hellman key pair using base `g', prime `p' and the given
|
||||
* `group_order'. Can use the given big number context `bnctx' if needed. The
|
||||
* private key is stored as opaque in the Diffie-Hellman context `*dhctx' and
|
||||
* the public key is returned in `public'. 0 is returned upon success, else
|
||||
* -1. */
|
||||
int
|
||||
_libssh2_dh_key_pair(_libssh2_dh_ctx *dhctx, _libssh2_bn *public,
|
||||
_libssh2_bn *g, _libssh2_bn *p, int group_order)
|
||||
{
|
||||
const int hasAlgDHwithKDF = _libssh2_wincng.hasAlgDHwithKDF;
|
||||
while(_libssh2_wincng.hAlgDH && hasAlgDHwithKDF != -1) {
|
||||
BCRYPT_DH_PARAMETER_HEADER *dh_params = NULL;
|
||||
unsigned long dh_params_len;
|
||||
unsigned char *blob = NULL;
|
||||
int status;
|
||||
/* Note that the DH provider requires that keys be multiples of 64 bits
|
||||
* in length. At the time of writing a practical observed group_order
|
||||
* value is 257, so we need to round down to 8 bytes of length (64/8)
|
||||
* in order for kex to succeed */
|
||||
DWORD key_length_bytes = max(round_down(group_order, 8),
|
||||
max(g->length, p->length));
|
||||
BCRYPT_DH_KEY_BLOB *dh_key_blob;
|
||||
LPCWSTR key_type;
|
||||
|
||||
/* Prepare a key pair; pass the in the bit length of the key,
|
||||
* but the key is not ready for consumption until it is finalized. */
|
||||
status = BCryptGenerateKeyPair(_libssh2_wincng.hAlgDH,
|
||||
&dhctx->dh_handle,
|
||||
key_length_bytes * 8, 0);
|
||||
if(!BCRYPT_SUCCESS(status)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
dh_params_len = sizeof(*dh_params) + 2 * key_length_bytes;
|
||||
blob = malloc(dh_params_len);
|
||||
if(!blob) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Populate DH parameters blob; after the header follows the `p`
|
||||
* value and the `g` value. */
|
||||
dh_params = (BCRYPT_DH_PARAMETER_HEADER*)blob;
|
||||
dh_params->cbLength = dh_params_len;
|
||||
dh_params->dwMagic = BCRYPT_DH_PARAMETERS_MAGIC;
|
||||
dh_params->cbKeyLength = key_length_bytes;
|
||||
memcpy_with_be_padding(blob + sizeof(*dh_params), key_length_bytes,
|
||||
p->bignum, p->length);
|
||||
memcpy_with_be_padding(blob + sizeof(*dh_params) + key_length_bytes,
|
||||
key_length_bytes, g->bignum, g->length);
|
||||
|
||||
status = BCryptSetProperty(dhctx->dh_handle, BCRYPT_DH_PARAMETERS,
|
||||
blob, dh_params_len, 0);
|
||||
if(hasAlgDHwithKDF == -1) {
|
||||
/* We know that the raw KDF is not supported, so discard this. */
|
||||
free(blob);
|
||||
}
|
||||
else {
|
||||
/* Pass ownership to dhctx; these parameters will be freed when
|
||||
* the context is destroyed. We need to keep the parameters more
|
||||
* easily available so that we have access to the `g` value when
|
||||
* _libssh2_dh_secret is called later. */
|
||||
dhctx->dh_params = dh_params;
|
||||
}
|
||||
dh_params = NULL;
|
||||
blob = NULL;
|
||||
|
||||
if(!BCRYPT_SUCCESS(status)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
status = BCryptFinalizeKeyPair(dhctx->dh_handle, 0);
|
||||
if(!BCRYPT_SUCCESS(status)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
key_length_bytes = 0;
|
||||
if(hasAlgDHwithKDF == 1) {
|
||||
/* Now we need to extract the public portion of the key so that we
|
||||
* set it in the `public` bignum to satisfy our caller.
|
||||
* First measure up the size of the required buffer. */
|
||||
key_type = BCRYPT_DH_PUBLIC_BLOB;
|
||||
}
|
||||
else {
|
||||
/* We also need to extract the private portion of the key to
|
||||
* set it in the `*dhctx' bignum if the raw KDF is not supported.
|
||||
* First measure up the size of the required buffer. */
|
||||
key_type = BCRYPT_DH_PRIVATE_BLOB;
|
||||
}
|
||||
status = BCryptExportKey(dhctx->dh_handle, NULL, key_type,
|
||||
NULL, 0, &key_length_bytes, 0);
|
||||
if(!BCRYPT_SUCCESS(status)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
blob = malloc(key_length_bytes);
|
||||
if(!blob) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
status = BCryptExportKey(dhctx->dh_handle, NULL, key_type,
|
||||
blob, key_length_bytes,
|
||||
&key_length_bytes, 0);
|
||||
if(!BCRYPT_SUCCESS(status)) {
|
||||
if(hasAlgDHwithKDF == 1) {
|
||||
/* We have no private data, because raw KDF is supported */
|
||||
free(blob);
|
||||
}
|
||||
else { /* we may have potentially private data, use secure free */
|
||||
_libssh2_wincng_safe_free(blob, key_length_bytes);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(hasAlgDHwithKDF == -1) {
|
||||
/* We know that the raw KDF is not supported, so discard this */
|
||||
BCryptDestroyKey(dhctx->dh_handle);
|
||||
dhctx->dh_handle = NULL;
|
||||
}
|
||||
|
||||
/* BCRYPT_DH_PUBLIC_BLOB corresponds to a BCRYPT_DH_KEY_BLOB header
|
||||
* followed by the Modulus, Generator and Public data. Those components
|
||||
* each have equal size, specified by dh_key_blob->cbKey. */
|
||||
dh_key_blob = (BCRYPT_DH_KEY_BLOB*)blob;
|
||||
if(_libssh2_wincng_bignum_resize(public, dh_key_blob->cbKey)) {
|
||||
if(hasAlgDHwithKDF == 1) {
|
||||
/* We have no private data, because raw KDF is supported */
|
||||
free(blob);
|
||||
}
|
||||
else { /* we may have potentially private data, use secure free */
|
||||
_libssh2_wincng_safe_free(blob, key_length_bytes);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Copy the public key data into the public bignum data buffer */
|
||||
memcpy(public->bignum,
|
||||
blob + sizeof(*dh_key_blob) + 2 * dh_key_blob->cbKey,
|
||||
dh_key_blob->cbKey);
|
||||
|
||||
if(dh_key_blob->dwMagic == BCRYPT_DH_PRIVATE_MAGIC) {
|
||||
/* BCRYPT_DH_PRIVATE_BLOB additionally contains the Private data */
|
||||
dhctx->bn = _libssh2_wincng_bignum_init();
|
||||
if(!dhctx->bn) {
|
||||
_libssh2_wincng_safe_free(blob, key_length_bytes);
|
||||
return -1;
|
||||
}
|
||||
if(_libssh2_wincng_bignum_resize(dhctx->bn, dh_key_blob->cbKey)) {
|
||||
_libssh2_wincng_safe_free(blob, key_length_bytes);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Copy the private key data into the dhctx bignum data buffer */
|
||||
memcpy(dhctx->bn->bignum,
|
||||
blob + sizeof(*dh_key_blob) + 3 * dh_key_blob->cbKey,
|
||||
dh_key_blob->cbKey);
|
||||
|
||||
/* Make sure the private key is an odd number, because only
|
||||
* odd primes can be used with the RSA-based fallback while
|
||||
* DH itself does not seem to care about it being odd or not. */
|
||||
if(!(dhctx->bn->bignum[dhctx->bn->length-1] % 2)) {
|
||||
_libssh2_wincng_safe_free(blob, key_length_bytes);
|
||||
/* discard everything first, then try again */
|
||||
_libssh2_dh_dtor(dhctx);
|
||||
_libssh2_dh_init(dhctx);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Generate x and e */
|
||||
dhctx->bn = _libssh2_wincng_bignum_init();
|
||||
if(!dhctx->bn)
|
||||
return -1;
|
||||
if(_libssh2_wincng_bignum_rand(dhctx->bn, group_order * 8 - 1, 0, -1))
|
||||
return -1;
|
||||
if(_libssh2_wincng_bignum_mod_exp(public, g, dhctx->bn, p))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Computes the Diffie-Hellman secret from the previously created context
|
||||
* `*dhctx', the public key `f' from the other party and the same prime `p'
|
||||
* used at context creation. The result is stored in `secret'. 0 is returned
|
||||
* upon success, else -1. */
|
||||
int
|
||||
_libssh2_dh_secret(_libssh2_dh_ctx *dhctx, _libssh2_bn *secret,
|
||||
_libssh2_bn *f, _libssh2_bn *p)
|
||||
{
|
||||
if(_libssh2_wincng.hAlgDH && _libssh2_wincng.hasAlgDHwithKDF != -1 &&
|
||||
dhctx->dh_handle && dhctx->dh_params && f) {
|
||||
BCRYPT_KEY_HANDLE peer_public = NULL;
|
||||
BCRYPT_SECRET_HANDLE agreement = NULL;
|
||||
ULONG secret_len_bytes = 0;
|
||||
unsigned char *blob;
|
||||
int status;
|
||||
unsigned char *start, *end;
|
||||
BCRYPT_DH_KEY_BLOB *public_blob = NULL;
|
||||
DWORD key_length_bytes = max(f->length, dhctx->dh_params->cbKeyLength);
|
||||
DWORD public_blob_len = sizeof(*public_blob) + 3 * key_length_bytes;
|
||||
|
||||
{
|
||||
/* Populate a BCRYPT_DH_KEY_BLOB; after the header follows the
|
||||
* Modulus, Generator and Public data. Those components must have
|
||||
* equal size in this representation. */
|
||||
unsigned char *dest;
|
||||
unsigned char *src;
|
||||
|
||||
blob = malloc(public_blob_len);
|
||||
if(!blob) {
|
||||
return -1;
|
||||
}
|
||||
public_blob = (BCRYPT_DH_KEY_BLOB*)blob;
|
||||
public_blob->dwMagic = BCRYPT_DH_PUBLIC_MAGIC;
|
||||
public_blob->cbKey = key_length_bytes;
|
||||
|
||||
dest = (unsigned char *)(public_blob + 1);
|
||||
src = (unsigned char *)(dhctx->dh_params + 1);
|
||||
|
||||
/* Modulus (the p-value from the first call) */
|
||||
memcpy_with_be_padding(dest, key_length_bytes, src,
|
||||
dhctx->dh_params->cbKeyLength);
|
||||
/* Generator (the g-value from the first call) */
|
||||
memcpy_with_be_padding(dest + key_length_bytes, key_length_bytes,
|
||||
src + dhctx->dh_params->cbKeyLength,
|
||||
dhctx->dh_params->cbKeyLength);
|
||||
/* Public from the peer */
|
||||
memcpy_with_be_padding(dest + 2*key_length_bytes, key_length_bytes,
|
||||
f->bignum, f->length);
|
||||
}
|
||||
|
||||
/* Import the peer public key information */
|
||||
status = BCryptImportKeyPair(_libssh2_wincng.hAlgDH, NULL,
|
||||
BCRYPT_DH_PUBLIC_BLOB, &peer_public, blob,
|
||||
public_blob_len, 0);
|
||||
if(!BCRYPT_SUCCESS(status)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Set up a handle that we can use to establish the shared secret
|
||||
* between ourselves (our saved dh_handle) and the peer. */
|
||||
status = BCryptSecretAgreement(dhctx->dh_handle, peer_public,
|
||||
&agreement, 0);
|
||||
if(!BCRYPT_SUCCESS(status)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Compute the size of the buffer that is needed to hold the derived
|
||||
* shared secret. */
|
||||
status = BCryptDeriveKey(agreement, BCRYPT_KDF_RAW_SECRET, NULL, NULL,
|
||||
0, &secret_len_bytes, 0);
|
||||
if(!BCRYPT_SUCCESS(status)) {
|
||||
if(status == STATUS_NOT_SUPPORTED) {
|
||||
_libssh2_wincng.hasAlgDHwithKDF = -1;
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Expand the secret bignum to be ready to receive the derived secret
|
||||
* */
|
||||
if(_libssh2_wincng_bignum_resize(secret, secret_len_bytes)) {
|
||||
status = STATUS_NO_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* And populate the secret bignum */
|
||||
status = BCryptDeriveKey(agreement, BCRYPT_KDF_RAW_SECRET, NULL,
|
||||
secret->bignum, secret_len_bytes,
|
||||
&secret_len_bytes, 0);
|
||||
if(!BCRYPT_SUCCESS(status)) {
|
||||
if(status == STATUS_NOT_SUPPORTED) {
|
||||
_libssh2_wincng.hasAlgDHwithKDF = -1;
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Counter to all the other data in the BCrypt APIs, the raw secret is
|
||||
* returned to us in host byte order, so we need to swap it to big
|
||||
* endian order. */
|
||||
start = secret->bignum;
|
||||
end = secret->bignum + secret->length - 1;
|
||||
while(start < end) {
|
||||
unsigned char tmp = *end;
|
||||
*end = *start;
|
||||
*start = tmp;
|
||||
start++;
|
||||
end--;
|
||||
}
|
||||
|
||||
status = 0;
|
||||
_libssh2_wincng.hasAlgDHwithKDF = 1;
|
||||
|
||||
out:
|
||||
if(peer_public) {
|
||||
BCryptDestroyKey(peer_public);
|
||||
}
|
||||
if(agreement) {
|
||||
BCryptDestroySecret(agreement);
|
||||
}
|
||||
if(status == STATUS_NOT_SUPPORTED &&
|
||||
_libssh2_wincng.hasAlgDHwithKDF == -1) {
|
||||
goto fb; /* fallback to RSA-based implementation */
|
||||
}
|
||||
return BCRYPT_SUCCESS(status) ? 0 : -1;
|
||||
}
|
||||
|
||||
fb:
|
||||
/* Compute the shared secret */
|
||||
return _libssh2_wincng_bignum_mod_exp(secret, f, dhctx->bn, p);
|
||||
}
|
||||
|
||||
#endif /* LIBSSH2_WINCNG */
|
||||
|
38
src/wincng.h
Executable file → Normal file
38
src/wincng.h
Executable file → Normal file
@@ -1,5 +1,7 @@
|
||||
#ifndef __LIBSSH2_WINCNG_H
|
||||
#define __LIBSSH2_WINCNG_H
|
||||
/*
|
||||
* Copyright (C) 2013-2015 Marc Hoersken <info@marc-hoersken.de>
|
||||
* Copyright (C) 2013-2020 Marc Hoersken <info@marc-hoersken.de>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
@@ -47,7 +49,6 @@
|
||||
#include <windows.h>
|
||||
#include <bcrypt.h>
|
||||
|
||||
|
||||
#define LIBSSH2_MD5 1
|
||||
|
||||
#define LIBSSH2_HMAC_RIPEMD 0
|
||||
@@ -69,6 +70,7 @@
|
||||
#define MD5_DIGEST_LENGTH 16
|
||||
#define SHA_DIGEST_LENGTH 20
|
||||
#define SHA256_DIGEST_LENGTH 32
|
||||
#define SHA384_DIGEST_LENGTH 48
|
||||
#define SHA512_DIGEST_LENGTH 64
|
||||
|
||||
#define EC_MAX_POINT_LEN ((528 * 2 / 8) + 1)
|
||||
@@ -88,10 +90,12 @@ struct _libssh2_wincng_ctx {
|
||||
BCRYPT_ALG_HANDLE hAlgHashMD5;
|
||||
BCRYPT_ALG_HANDLE hAlgHashSHA1;
|
||||
BCRYPT_ALG_HANDLE hAlgHashSHA256;
|
||||
BCRYPT_ALG_HANDLE hAlgHashSHA384;
|
||||
BCRYPT_ALG_HANDLE hAlgHashSHA512;
|
||||
BCRYPT_ALG_HANDLE hAlgHmacMD5;
|
||||
BCRYPT_ALG_HANDLE hAlgHmacSHA1;
|
||||
BCRYPT_ALG_HANDLE hAlgHmacSHA256;
|
||||
BCRYPT_ALG_HANDLE hAlgHmacSHA384;
|
||||
BCRYPT_ALG_HANDLE hAlgHmacSHA512;
|
||||
BCRYPT_ALG_HANDLE hAlgRSA;
|
||||
BCRYPT_ALG_HANDLE hAlgDSA;
|
||||
@@ -99,9 +103,11 @@ struct _libssh2_wincng_ctx {
|
||||
BCRYPT_ALG_HANDLE hAlgAES_ECB;
|
||||
BCRYPT_ALG_HANDLE hAlgRC4_NA;
|
||||
BCRYPT_ALG_HANDLE hAlg3DES_CBC;
|
||||
BCRYPT_ALG_HANDLE hAlgDH;
|
||||
volatile int hasAlgDHwithKDF; /* -1=no, 0=maybe, 1=yes */
|
||||
};
|
||||
|
||||
struct _libssh2_wincng_ctx _libssh2_wincng;
|
||||
extern struct _libssh2_wincng_ctx _libssh2_wincng;
|
||||
|
||||
|
||||
/*******************************************************************/
|
||||
@@ -162,7 +168,17 @@ typedef struct __libssh2_wincng_hash_ctx {
|
||||
#define libssh2_sha256(data, datalen, hash) \
|
||||
_libssh2_wincng_hash(data, datalen, _libssh2_wincng.hAlgHashSHA256, \
|
||||
hash, SHA256_DIGEST_LENGTH)
|
||||
|
||||
#define libssh2_sha384_ctx _libssh2_wincng_hash_ctx
|
||||
#define libssh2_sha384_init(ctx) \
|
||||
(_libssh2_wincng_hash_init(ctx, _libssh2_wincng.hAlgHashSHA384, \
|
||||
SHA384_DIGEST_LENGTH, NULL, 0) == 0)
|
||||
#define libssh2_sha384_update(ctx, data, datalen) \
|
||||
_libssh2_wincng_hash_update(&ctx, (unsigned char *) data, datalen)
|
||||
#define libssh2_sha384_final(ctx, hash) \
|
||||
_libssh2_wincng_hash_final(&ctx, hash)
|
||||
#define libssh2_sha384(data, datalen, hash) \
|
||||
_libssh2_wincng_hash(data, datalen, _libssh2_wincng.hAlgHashSHA384, \
|
||||
hash, SHA384_DIGEST_LENGTH)
|
||||
#define libssh2_sha512_ctx _libssh2_wincng_hash_ctx
|
||||
#define libssh2_sha512_init(ctx) \
|
||||
(_libssh2_wincng_hash_init(ctx, _libssh2_wincng.hAlgHashSHA512, \
|
||||
@@ -385,7 +401,17 @@ _libssh2_bn *_libssh2_wincng_bignum_init(void);
|
||||
* Windows CNG backend: Diffie-Hellman support
|
||||
*/
|
||||
|
||||
#define _libssh2_dh_ctx struct _libssh2_wincng_bignum *
|
||||
typedef struct {
|
||||
/* holds our private and public key components */
|
||||
BCRYPT_KEY_HANDLE dh_handle;
|
||||
/* records the parsed out modulus and generator
|
||||
* parameters that are shared with the peer */
|
||||
BCRYPT_DH_PARAMETER_HEADER *dh_params;
|
||||
/* records the parsed out private key component for
|
||||
* fallback if the DH API raw KDF is not supported */
|
||||
struct _libssh2_wincng_bignum *bn;
|
||||
} _libssh2_dh_ctx;
|
||||
|
||||
#define libssh2_dh_init(dhctx) _libssh2_dh_init(dhctx)
|
||||
#define libssh2_dh_key_pair(dhctx, public, g, p, group_order, bnctx) \
|
||||
_libssh2_dh_key_pair(dhctx, public, g, p, group_order)
|
||||
@@ -569,3 +595,5 @@ _libssh2_dh_secret(_libssh2_dh_ctx *dhctx, _libssh2_bn *secret,
|
||||
_libssh2_bn *f, _libssh2_bn *p);
|
||||
extern void
|
||||
_libssh2_dh_dtor(_libssh2_dh_ctx *dhctx);
|
||||
|
||||
#endif /* __LIBSSH2_WINCNG_H */
|
||||
|
@@ -130,6 +130,8 @@ if(CRYPTO_BACKEND STREQUAL "OpenSSL")
|
||||
public_key_auth_succeeds_with_correct_ed25519_key
|
||||
public_key_auth_succeeds_with_correct_encrypted_ed25519_key
|
||||
public_key_auth_succeeds_with_correct_ed25519_key_from_mem
|
||||
public_key_auth_succeeds_with_correct_ecdsa_key
|
||||
public_key_auth_succeeds_with_correct_signed_ecdsa_key
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
@@ -1,3 +1,5 @@
|
||||
SUBDIRS = ossfuzz
|
||||
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/include -I$(top_builddir)/src
|
||||
LDADD = ../src/libssh2.la
|
||||
|
||||
@@ -16,26 +18,64 @@ check_PROGRAMS = $(ctests)
|
||||
TESTS_ENVIRONMENT = SSHD=$(SSHD) EXEEXT=$(EXEEXT)
|
||||
TESTS_ENVIRONMENT += srcdir=$(top_srcdir)/tests builddir=$(top_builddir)/tests
|
||||
|
||||
EXTRA_DIST = ssh2.sh mansyntax.sh
|
||||
EXTRA_DIST += etc/host etc/host.pub etc/user etc/user.pub
|
||||
EXTRA_DIST += CMakeLists.txt libssh2_config_cmake.h.in sshd_fixture.sh.in
|
||||
EXTRA_DIST += key_dsa key_dsa.pub key_dsa_wrong key_dsa_wrong.pub key_rsa key_rsa.pub
|
||||
EXTRA_DIST += openssh_server/authorized_keys openssh_server/Dockerfile openssh_server/ssh_host_rsa_key
|
||||
EXTRA_DIST += openssh_fixture.c openssh_fixture.h runner.c session_fixture.c session_fixture.h
|
||||
EXTRA_DIST += test_hostkey.c test_hostkey_hash.c
|
||||
EXTRA_DIST += test_keyboard_interactive_auth_fails_with_wrong_response.c
|
||||
EXTRA_DIST += test_keyboard_interactive_auth_succeeds_with_correct_response.c
|
||||
EXTRA_DIST += test_password_auth_fails_with_wrong_password.c
|
||||
EXTRA_DIST += test_password_auth_fails_with_wrong_username.c
|
||||
EXTRA_DIST += test_password_auth_succeeds_with_correct_credentials.c
|
||||
EXTRA_DIST += test_public_key_auth_fails_with_wrong_key.c
|
||||
EXTRA_DIST += test_public_key_auth_succeeds_with_correct_dsa_key.c
|
||||
EXTRA_DIST += test_public_key_auth_succeeds_with_correct_rsa_key.c
|
||||
EXTRA_DIST += test_public_key_auth_succeeds_with_correct_encrypted_rsa_key.c
|
||||
if OPENSSL
|
||||
# TODO: need to add a test for specific openssl version some how
|
||||
# EXTRA_DIST += test_public_key_auth_succeeds_with_correct_ed25519_key.c
|
||||
# EXTRA_DIST += test_public_key_auth_succeeds_with_correct_encrypted_ed25519_key.c
|
||||
# EXTRA_DIST += test_public_key_auth_succeeds_with_correct_ed25519_key_from_mem.c
|
||||
EXTRA_DIST += test_public_key_auth_succeeds_with_correct_rsa_openssh_key.c
|
||||
endif
|
||||
EXTRA_DIST = \
|
||||
CMakeLists.txt \
|
||||
etc/host \
|
||||
etc/host.pub \
|
||||
etc/user \
|
||||
etc/user.pub \
|
||||
key_dsa \
|
||||
key_dsa.pub \
|
||||
key_dsa_wrong \
|
||||
key_dsa_wrong.pub \
|
||||
key_ecdsa \
|
||||
key_ecdsa.pub \
|
||||
signed_key_ecdsa \
|
||||
signed_key_ecdsa.pub \
|
||||
signed_key_ecdsa-cert.pub \
|
||||
key_ed25519 \
|
||||
key_ed25519.pub \
|
||||
key_ed25519_encrypted \
|
||||
key_ed25519_encrypted.pub \
|
||||
key_rsa \
|
||||
key_rsa.pub \
|
||||
key_rsa_encrypted \
|
||||
key_rsa_encrypted.pub \
|
||||
key_rsa_openssh \
|
||||
key_rsa_openssh.pub \
|
||||
libssh2_config_cmake.h.in \
|
||||
mansyntax.sh \
|
||||
openssh_fixture.c \
|
||||
openssh_fixture.h \
|
||||
openssh_server/Dockerfile \
|
||||
openssh_server/authorized_keys \
|
||||
openssh_server/ca_ecdsa \
|
||||
openssh_server/ca_ecdsa.pub \
|
||||
openssh_server/ssh_host_ecdsa_key \
|
||||
openssh_server/ssh_host_ed25519_key \
|
||||
openssh_server/ssh_host_rsa_key \
|
||||
runner.c \
|
||||
session_fixture.c \
|
||||
session_fixture.h \
|
||||
simple.c \
|
||||
ssh2.c \
|
||||
ssh2.sh \
|
||||
sshd_fixture.sh.in \
|
||||
test_agent_forward_succeeds.c \
|
||||
test_hostkey.c \
|
||||
test_hostkey_hash.c \
|
||||
test_keyboard_interactive_auth_fails_with_wrong_response.c \
|
||||
test_keyboard_interactive_auth_succeeds_with_correct_response.c \
|
||||
test_password_auth_fails_with_wrong_password.c \
|
||||
test_password_auth_fails_with_wrong_username.c \
|
||||
test_password_auth_succeeds_with_correct_credentials.c \
|
||||
test_public_key_auth_fails_with_wrong_key.c \
|
||||
test_public_key_auth_succeeds_with_correct_dsa_key.c \
|
||||
test_public_key_auth_succeeds_with_correct_ed25519_key.c \
|
||||
test_public_key_auth_succeeds_with_correct_ed25519_key_from_mem.c \
|
||||
test_public_key_auth_succeeds_with_correct_ecdsa_key.c \
|
||||
test_public_key_auth_succeeds_with_correct_signed_ecdsa_key.c \
|
||||
test_public_key_auth_succeeds_with_correct_encrypted_ed25519_key.c \
|
||||
test_public_key_auth_succeeds_with_correct_encrypted_rsa_key.c \
|
||||
test_public_key_auth_succeeds_with_correct_rsa_key.c \
|
||||
test_public_key_auth_succeeds_with_correct_rsa_openssh_key.c
|
||||
|
10
tests/key_ecdsa
Normal file
10
tests/key_ecdsa
Normal file
@@ -0,0 +1,10 @@
|
||||
-----BEGIN OPENSSH PRIVATE KEY-----
|
||||
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAiAAAABNlY2RzYS
|
||||
1zaGEyLW5pc3RwMzg0AAAACG5pc3RwMzg0AAAAYQTosiScH/oRSazpIpPSEFcY4YVZyNby
|
||||
peARi49N3qy78OE118KGc5T8eifd+n1PSb7z8PnfDwOL4jBHxW5nWx0RCocIt7tb2a349J
|
||||
gfEl8PegHGcF/DwC+eesIKJvv0MfkAAADIKLgw6yi4MOsAAAATZWNkc2Etc2hhMi1uaXN0
|
||||
cDM4NAAAAAhuaXN0cDM4NAAAAGEE6LIknB/6EUms6SKT0hBXGOGFWcjW8qXgEYuPTd6su/
|
||||
DhNdfChnOU/Hon3fp9T0m+8/D53w8Di+IwR8VuZ1sdEQqHCLe7W9mt+PSYHxJfD3oBxnBf
|
||||
w8AvnnrCCib79DH5AAAAMGYdHu+u2/L8zC/0S9bao9y6vKiLSuTEfZpCIsyE5jWj/vrS0n
|
||||
r1lzv9kKj+5A86aQAAAAA=
|
||||
-----END OPENSSH PRIVATE KEY-----
|
1
tests/key_ecdsa.pub
Normal file
1
tests/key_ecdsa.pub
Normal file
@@ -0,0 +1 @@
|
||||
ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBOiyJJwf+hFJrOkik9IQVxjhhVnI1vKl4BGLj03erLvw4TXXwoZzlPx6J936fU9JvvPw+d8PA4viMEfFbmdbHREKhwi3u1vZrfj0mB8SXw96AcZwX8PAL556wgom+/Qx+Q==
|
@@ -62,10 +62,12 @@
|
||||
static int run_command_varg(char **output, const char *command, va_list args)
|
||||
{
|
||||
FILE *pipe;
|
||||
char redirect_stderr[] = "%s 2>&1";
|
||||
char command_buf[BUFSIZ];
|
||||
char buf[BUFSIZ];
|
||||
char *p;
|
||||
int ret;
|
||||
size_t buf_len;
|
||||
|
||||
if(output) {
|
||||
*output = NULL;
|
||||
}
|
||||
@@ -78,26 +80,33 @@ static int run_command_varg(char **output, const char *command, va_list args)
|
||||
}
|
||||
|
||||
/* Rewrite the command to redirect stderr to stdout to we can output it */
|
||||
if(strlen(command_buf) + 6 >= sizeof(command_buf)) {
|
||||
if(strlen(command_buf) + strlen(redirect_stderr) >= sizeof(buf)) {
|
||||
fprintf(stderr, "Unable to rewrite command (%s)\n", command);
|
||||
return -1;
|
||||
}
|
||||
|
||||
strncat(command_buf, " 2>&1", 6);
|
||||
ret = snprintf(buf, sizeof(buf), redirect_stderr, command_buf);
|
||||
if(ret < 0 || ret >= BUFSIZ) {
|
||||
fprintf(stderr, "Unable to rewrite command (%s)\n", command);
|
||||
return -1;
|
||||
}
|
||||
|
||||
fprintf(stdout, "Command: %s\n", command);
|
||||
#ifdef WIN32
|
||||
pipe = _popen(command_buf, "r");
|
||||
pipe = _popen(buf, "r");
|
||||
#else
|
||||
pipe = popen(command_buf, "r");
|
||||
pipe = popen(buf, "r");
|
||||
#endif
|
||||
if(!pipe) {
|
||||
fprintf(stderr, "Unable to execute command '%s'\n", command);
|
||||
return -1;
|
||||
}
|
||||
p = buf;
|
||||
while(fgets(p, sizeof(buf) - (p - buf), pipe) != NULL)
|
||||
;
|
||||
buf[0] = 0;
|
||||
buf_len = 0;
|
||||
while(buf_len < (sizeof(buf) - 1) &&
|
||||
fgets(&buf[buf_len], sizeof(buf) - buf_len, pipe) != NULL) {
|
||||
buf_len = strlen(buf);
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
ret = _pclose(pipe);
|
||||
@@ -112,9 +121,9 @@ static int run_command_varg(char **output, const char *command, va_list args)
|
||||
if(output) {
|
||||
/* command output may contain a trailing newline, so we trim
|
||||
* whitespace here */
|
||||
size_t end = strlen(buf) - 1;
|
||||
while(end > 0 && isspace(buf[end])) {
|
||||
buf[end] = '\0';
|
||||
size_t end = strlen(buf);
|
||||
while(end > 0 && isspace(buf[end - 1])) {
|
||||
buf[end - 1] = '\0';
|
||||
}
|
||||
|
||||
*output = strdup(buf);
|
||||
@@ -134,16 +143,32 @@ static int run_command(char **output, const char *command, ...)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int build_openssh_server_docker_image()
|
||||
static int build_openssh_server_docker_image(void)
|
||||
{
|
||||
return run_command(NULL, "docker build -t libssh2/openssh_server openssh_server");
|
||||
return run_command(NULL, "docker build --quiet "
|
||||
"-t libssh2/openssh_server "
|
||||
"openssh_server");
|
||||
}
|
||||
|
||||
static const char *openssh_server_port(void)
|
||||
{
|
||||
return getenv("OPENSSH_SERVER_PORT");
|
||||
}
|
||||
|
||||
static int start_openssh_server(char **container_id_out)
|
||||
{
|
||||
const char *container_host_port = openssh_server_port();
|
||||
if(container_host_port != NULL) {
|
||||
return run_command(container_id_out,
|
||||
"docker run --detach -P libssh2/openssh_server"
|
||||
);
|
||||
"docker run --rm -d -p %s:22 "
|
||||
"libssh2/openssh_server",
|
||||
container_host_port);
|
||||
}
|
||||
else {
|
||||
return run_command(container_id_out,
|
||||
"docker run --rm -d -p 22 "
|
||||
"libssh2/openssh_server");
|
||||
}
|
||||
}
|
||||
|
||||
static int stop_openssh_server(char *container_id)
|
||||
@@ -151,11 +176,48 @@ static int stop_openssh_server(char *container_id)
|
||||
return run_command(NULL, "docker stop %s", container_id);
|
||||
}
|
||||
|
||||
static const char *docker_machine_name()
|
||||
static const char *docker_machine_name(void)
|
||||
{
|
||||
return getenv("DOCKER_MACHINE_NAME");
|
||||
}
|
||||
|
||||
static int is_running_inside_a_container()
|
||||
{
|
||||
#ifdef WIN32
|
||||
return 0;
|
||||
#else
|
||||
const char *cgroup_filename = "/proc/self/cgroup";
|
||||
FILE *f = NULL;
|
||||
char *line = NULL;
|
||||
size_t len = 0;
|
||||
ssize_t read = 0;
|
||||
int found = 0;
|
||||
f = fopen(cgroup_filename, "r");
|
||||
if(f == NULL) {
|
||||
/* Don't go further, we are not in a container */
|
||||
return 0;
|
||||
}
|
||||
while((read = getline(&line, &len, f)) != -1) {
|
||||
if(strstr(line, "docker") != NULL) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
free(line);
|
||||
return found;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void portable_sleep(unsigned int seconds)
|
||||
{
|
||||
#ifdef WIN32
|
||||
Sleep(seconds);
|
||||
#else
|
||||
sleep(seconds);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int ip_address_from_container(char *container_id, char **ip_address_out)
|
||||
{
|
||||
const char *active_docker_machine = docker_machine_name();
|
||||
@@ -167,9 +229,12 @@ static int ip_address_from_container(char *container_id, char **ip_address_out)
|
||||
int attempt_no = 0;
|
||||
int wait_time = 500;
|
||||
for(;;) {
|
||||
return run_command(ip_address_out, "docker-machine ip %s", active_docker_machine);
|
||||
|
||||
if(attempt_no > 5) {
|
||||
int ret = run_command(ip_address_out, "docker-machine ip %s",
|
||||
active_docker_machine);
|
||||
if(ret == 0) {
|
||||
return 0;
|
||||
}
|
||||
else if(attempt_no > 5) {
|
||||
fprintf(
|
||||
stderr,
|
||||
"Unable to get IP from docker-machine after %d attempts\n",
|
||||
@@ -177,36 +242,45 @@ static int ip_address_from_container(char *container_id, char **ip_address_out)
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
#ifdef WIN32
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4996)
|
||||
_sleep(wait_time);
|
||||
#pragma warning(pop)
|
||||
#else
|
||||
sleep(wait_time);
|
||||
#endif
|
||||
portable_sleep(wait_time);
|
||||
++attempt_no;
|
||||
wait_time *= 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(is_running_inside_a_container()) {
|
||||
return run_command(ip_address_out,
|
||||
"docker inspect --format "
|
||||
"\"{{ index (index (index .NetworkSettings.Ports "
|
||||
"\"{{ .NetworkSettings.IPAddress }}\""
|
||||
" %s",
|
||||
container_id);
|
||||
}
|
||||
else {
|
||||
return run_command(ip_address_out,
|
||||
"docker inspect --format "
|
||||
"\"{{ index (index (index "
|
||||
".NetworkSettings.Ports "
|
||||
"\\\"22/tcp\\\") 0) \\\"HostIp\\\" }}\" %s",
|
||||
container_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int port_from_container(char *container_id, char **port_out)
|
||||
{
|
||||
if(is_running_inside_a_container()) {
|
||||
*port_out = strdup("22");
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
return run_command(port_out,
|
||||
"docker inspect --format "
|
||||
"\"{{ index (index (index .NetworkSettings.Ports "
|
||||
"\\\"22/tcp\\\") 0) \\\"HostPort\\\" }}\" %s",
|
||||
container_id);
|
||||
}
|
||||
}
|
||||
|
||||
static int open_socket_to_container(char *container_id)
|
||||
{
|
||||
@@ -215,20 +289,31 @@ static int open_socket_to_container(char *container_id)
|
||||
unsigned long hostaddr;
|
||||
int sock;
|
||||
struct sockaddr_in sin;
|
||||
int counter = 0;
|
||||
|
||||
int ret = ip_address_from_container(container_id, &ip_address);
|
||||
if(ret != 0) {
|
||||
fprintf(stderr, "Failed to get IP address for container %s\n", container_id);
|
||||
fprintf(stderr, "Failed to get IP address for container %s\n",
|
||||
container_id);
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = port_from_container(container_id, &port_string);
|
||||
if(ret != 0) {
|
||||
fprintf(stderr, "Failed to get port for container %s\n", container_id);
|
||||
fprintf(stderr, "Failed to get port for container %s\n",
|
||||
container_id);
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
/* 0.0.0.0 is returned by Docker for Windows, because the container
|
||||
is reachable from anywhere. But we cannot connect to 0.0.0.0,
|
||||
instead we assume localhost and try to connect to 127.0.0.1. */
|
||||
if(ip_address && strcmp(ip_address, "0.0.0.0") == 0) {
|
||||
free(ip_address);
|
||||
ip_address = strdup("127.0.0.1");
|
||||
}
|
||||
|
||||
hostaddr = inet_addr(ip_address);
|
||||
if(hostaddr == (unsigned long)(-1)) {
|
||||
fprintf(stderr, "Failed to convert %s host address\n", ip_address);
|
||||
@@ -247,15 +332,26 @@ static int open_socket_to_container(char *container_id)
|
||||
sin.sin_port = htons((short)strtol(port_string, NULL, 0));
|
||||
sin.sin_addr.s_addr = hostaddr;
|
||||
|
||||
for(counter = 0; counter < 3; ++counter) {
|
||||
if(connect(sock, (struct sockaddr *)(&sin),
|
||||
sizeof(struct sockaddr_in)) != 0) {
|
||||
fprintf(stderr, "Failed to connect to %s:%s\n", ip_address, port_string);
|
||||
ret = -1;
|
||||
fprintf(stderr,
|
||||
"Connection to %s:%s attempt #%d failed: retrying...\n",
|
||||
ip_address, port_string, counter);
|
||||
portable_sleep(1 + 2*counter);
|
||||
}
|
||||
else {
|
||||
ret = sock;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(ret == -1) {
|
||||
fprintf(stderr, "Failed to connect to %s:%s\n",
|
||||
ip_address, port_string);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = sock;
|
||||
|
||||
cleanup:
|
||||
free(ip_address);
|
||||
free(port_string);
|
||||
|
@@ -58,10 +58,19 @@ COPY ssh_host_ed25519_key /tmp/etc/ssh/ssh_host_ed25519_key
|
||||
RUN mv /tmp/etc/ssh/ssh_host_ed25519_key /etc/ssh/ssh_host_ed25519_key
|
||||
RUN chmod 600 /etc/ssh/ssh_host_ed25519_key
|
||||
|
||||
COPY ca_ecdsa.pub /tmp/etc/ssh/ca_ecdsa.pub
|
||||
RUN mv /tmp/etc/ssh/ca_ecdsa.pub /etc/ssh/ca_ecdsa.pub
|
||||
RUN chmod 600 /etc/ssh/ca_ecdsa.pub
|
||||
|
||||
COPY ca_ecdsa /tmp/etc/ssh/ca_ecdsa
|
||||
RUN mv /tmp/etc/ssh/ca_ecdsa /etc/ssh/ca_ecdsa
|
||||
RUN chmod 600 /etc/ssh/ca_ecdsa
|
||||
|
||||
RUN adduser --disabled-password --gecos 'Test user for libssh2 integration tests' libssh2
|
||||
RUN echo 'libssh2:my test password' | chpasswd
|
||||
|
||||
RUN sed -i 's/ChallengeResponseAuthentication no/ChallengeResponseAuthentication yes/' /etc/ssh/sshd_config
|
||||
RUN echo "TrustedUserCAKeys /etc/ssh/ca_ecdsa.pub" >> /etc/ssh/sshd_config
|
||||
|
||||
# SSH login fix. Otherwise user is kicked off after login
|
||||
RUN sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/sshd
|
||||
|
@@ -4,3 +4,4 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC92YlGoc4PJy6DzX916JJZhxkvmkWBLGJdWOL7R9B6
|
||||
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDTe1lN2L/yet0Ma1JzXkQf3t1f+pauALec2FsGZy87KRJW1AOxcTTiePjlFwP1yfSK1lWXQ+uf0b61gkKqqR52FDky24HJWuYlfXlEQMn2d/PNDNVDDbO4TXKyNxxUHFJ6qYMNd4kWjOH+6rmYoWKsWV+3mDRbHagbVPEYL8wep8OTqKOqruVLVPzZyYZkBtn4XOFi6UE8WKiSVdK1Am1O5UxvlD95t32eYch6wQ9azgMqja6spe/L5UJgP83QZFknVC3wPZWkjqomVFql0FpaQclENwyY/OZMxr0cT/f7bCL6s4A/1XpbsGmC0xak4/THHbOn+0LdIej2nGV8JFoR
|
||||
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIxtdyg2ZRXE70UwyPVUH3UyfDBV8GX5cPF636P6hjom
|
||||
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICHxEyUTOVHXvdMFARedFQ+H9DW/n8Zy3daKKRqnTDMq
|
||||
ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBOiyJJwf+hFJrOkik9IQVxjhhVnI1vKl4BGLj03erLvw4TXXwoZzlPx6J936fU9JvvPw+d8PA4viMEfFbmdbHREKhwi3u1vZrfj0mB8SXw96AcZwX8PAL556wgom+/Qx+Q==
|
||||
|
12
tests/openssh_server/ca_ecdsa
Normal file
12
tests/openssh_server/ca_ecdsa
Normal file
@@ -0,0 +1,12 @@
|
||||
-----BEGIN OPENSSH PRIVATE KEY-----
|
||||
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAArAAAABNlY2RzYS
|
||||
1zaGEyLW5pc3RwNTIxAAAACG5pc3RwNTIxAAAAhQQAfv15s+G2xg56J+audKAM4G9qOTFr
|
||||
bZRo0CTwvkb/oHrf9/2RSWqYsx/0m5mYCZVlecnZqwRHAOolXbc/Yb4cGjsALUj3UDirsn
|
||||
YR7Ve+SwnunkpvW/H3a98sA3sS+HCpd5RbpfWClSBOI9JEAlPtS1CrEQ7EmO7hmlFOH2cL
|
||||
0qfHCyYAAAEA763VSe+t1UkAAAATZWNkc2Etc2hhMi1uaXN0cDUyMQAAAAhuaXN0cDUyMQ
|
||||
AAAIUEAH79ebPhtsYOeifmrnSgDOBvajkxa22UaNAk8L5G/6B63/f9kUlqmLMf9JuZmAmV
|
||||
ZXnJ2asERwDqJV23P2G+HBo7AC1I91A4q7J2Ee1XvksJ7p5Kb1vx92vfLAN7EvhwqXeUW6
|
||||
X1gpUgTiPSRAJT7UtQqxEOxJju4ZpRTh9nC9KnxwsmAAAAQgD8VJwi9RHYN13CAfhvdmjW
|
||||
xVjH55J5jDjPlENU2Z+cnm01SQ+9mPFEY4wDSvfiovD1VstNJX/P97WbHw+e5XL+HwAAAA
|
||||
JDQQ==
|
||||
-----END OPENSSH PRIVATE KEY-----
|
1
tests/openssh_server/ca_ecdsa.pub
Normal file
1
tests/openssh_server/ca_ecdsa.pub
Normal file
@@ -0,0 +1 @@
|
||||
ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBAB+/Xmz4bbGDnon5q50oAzgb2o5MWttlGjQJPC+Rv+get/3/ZFJapizH/SbmZgJlWV5ydmrBEcA6iVdtz9hvhwaOwAtSPdQOKuydhHtV75LCe6eSm9b8fdr3ywDexL4cKl3lFul9YKVIE4j0kQCU+1LUKsRDsSY7uGaUU4fZwvSp8cLJg== CA
|
2
tests/ossfuzz/.gitignore
vendored
Normal file
2
tests/ossfuzz/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
*.a
|
||||
ssh2_client_fuzzer
|
32
tests/ossfuzz/Makefile.am
Normal file
32
tests/ossfuzz/Makefile.am
Normal file
@@ -0,0 +1,32 @@
|
||||
AM_CPPFLAGS = -I$(top_builddir)/include
|
||||
LDADD = $(top_builddir)/src/libssh2.la
|
||||
|
||||
if USE_OSSFUZZ_FLAG
|
||||
FUZZ_FLAG = $(LIB_FUZZING_ENGINE)
|
||||
else
|
||||
if USE_OSSFUZZ_STATIC
|
||||
LDADD += $(LIB_FUZZING_ENGINE)
|
||||
FUZZ_FLAG =
|
||||
else
|
||||
LDADD += libstandaloneengine.a
|
||||
FUZZ_FLAG =
|
||||
endif
|
||||
endif
|
||||
|
||||
noinst_PROGRAMS =
|
||||
noinst_LIBRARIES =
|
||||
|
||||
if USE_OSSFUZZERS
|
||||
noinst_PROGRAMS += \
|
||||
ssh2_client_fuzzer
|
||||
|
||||
noinst_LIBRARIES += \
|
||||
libstandaloneengine.a
|
||||
endif
|
||||
|
||||
ssh2_client_fuzzer_SOURCES = ssh2_client_fuzzer.cc testinput.h
|
||||
ssh2_client_fuzzer_CXXFLAGS = $(AM_CXXFLAGS) $(FUZZ_FLAG)
|
||||
ssh2_client_fuzzer_LDFLAGS = $(AM_LDFLAGS) -static
|
||||
|
||||
libstandaloneengine_a_SOURCES = standaloneengine.cc
|
||||
libstandaloneengine_a_CXXFLAGS = $(AM_CXXFLAGS)
|
30
tests/ossfuzz/ossfuzz.sh
Executable file
30
tests/ossfuzz/ossfuzz.sh
Executable file
@@ -0,0 +1,30 @@
|
||||
#!/bin/bash -eu
|
||||
|
||||
# This script is called by the oss-fuzz main project when compiling the fuzz
|
||||
# targets. This script is regression tested by ci/ossfuzz.sh.
|
||||
|
||||
# Save off the current folder as the build root.
|
||||
export BUILD_ROOT=$PWD
|
||||
|
||||
echo "CC: $CC"
|
||||
echo "CXX: $CXX"
|
||||
echo "LIB_FUZZING_ENGINE: $LIB_FUZZING_ENGINE"
|
||||
echo "CFLAGS: $CFLAGS"
|
||||
echo "CXXFLAGS: $CXXFLAGS"
|
||||
echo "OUT: $OUT"
|
||||
|
||||
export MAKEFLAGS+="-j$(nproc)"
|
||||
|
||||
# Install dependencies
|
||||
apt-get -y install automake libtool libssl-dev zlib1g-dev
|
||||
|
||||
# Compile the fuzzer.
|
||||
./buildconf
|
||||
./configure --disable-shared \
|
||||
--enable-ossfuzzers \
|
||||
--disable-examples-build \
|
||||
--enable-debug
|
||||
make V=1
|
||||
|
||||
# Copy the fuzzer to the output directory.
|
||||
cp -v tests/ossfuzz/ssh2_client_fuzzer $OUT/
|
90
tests/ossfuzz/ssh2_client_fuzzer.cc
Normal file
90
tests/ossfuzz/ssh2_client_fuzzer.cc
Normal file
@@ -0,0 +1,90 @@
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#include <libssh2.h>
|
||||
#include "testinput.h"
|
||||
|
||||
#define FUZZ_ASSERT(COND) \
|
||||
if(!(COND)) \
|
||||
{ \
|
||||
fprintf(stderr, "Assertion failed: " #COND "\n%s", \
|
||||
strerror(errno)); \
|
||||
assert((COND)); \
|
||||
}
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
|
||||
{
|
||||
int socket_fds[2] = {-1, -1};
|
||||
ssize_t written;
|
||||
int rc;
|
||||
LIBSSH2_SESSION *session = NULL;
|
||||
int handshake_completed = 0;
|
||||
|
||||
rc = libssh2_init(0);
|
||||
|
||||
if(rc != 0) {
|
||||
fprintf(stderr, "libssh2 initialization failed (%d)\n", rc);
|
||||
goto EXIT_LABEL;
|
||||
}
|
||||
|
||||
// Create a socket pair so data can be sent in.
|
||||
rc = socketpair(AF_UNIX, SOCK_STREAM, 0, socket_fds);
|
||||
FUZZ_ASSERT(rc == 0);
|
||||
|
||||
written = send(socket_fds[1], data, size, 0);
|
||||
|
||||
if (written != size)
|
||||
{
|
||||
// Handle whatever error case we're in.
|
||||
fprintf(stderr, "send() of %zu bytes returned %zu (%d)\n",
|
||||
size,
|
||||
written,
|
||||
errno);
|
||||
goto EXIT_LABEL;
|
||||
}
|
||||
|
||||
rc = shutdown(socket_fds[1], SHUT_WR);
|
||||
if (rc != 0)
|
||||
{
|
||||
fprintf(stderr, "socket shutdown failed (%d)\n", rc);
|
||||
goto EXIT_LABEL;
|
||||
}
|
||||
|
||||
// Create a session and start the handshake using the fuzz data passed in.
|
||||
session = libssh2_session_init();
|
||||
if(session) {
|
||||
libssh2_session_set_blocking(session, 1);
|
||||
}
|
||||
|
||||
if(libssh2_session_handshake(session, socket_fds[0])) {
|
||||
goto EXIT_LABEL;
|
||||
}
|
||||
|
||||
// If we get here the handshake actually completed.
|
||||
handshake_completed = 1;
|
||||
|
||||
EXIT_LABEL:
|
||||
|
||||
if (session != NULL)
|
||||
{
|
||||
if (handshake_completed)
|
||||
{
|
||||
libssh2_session_disconnect(session,
|
||||
"Normal Shutdown, Thank you for playing");
|
||||
}
|
||||
|
||||
libssh2_session_free(session);
|
||||
}
|
||||
|
||||
libssh2_exit();
|
||||
|
||||
close(socket_fds[0]);
|
||||
close(socket_fds[1]);
|
||||
|
||||
return 0;
|
||||
}
|
74
tests/ossfuzz/standaloneengine.cc
Normal file
74
tests/ossfuzz/standaloneengine.cc
Normal file
@@ -0,0 +1,74 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "testinput.h"
|
||||
|
||||
/**
|
||||
* Main procedure for standalone fuzzing engine.
|
||||
*
|
||||
* Reads filenames from the argument array. For each filename, read the file
|
||||
* into memory and then call the fuzzing interface with the data.
|
||||
*/
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int ii;
|
||||
for(ii = 1; ii < argc; ii++)
|
||||
{
|
||||
FILE *infile;
|
||||
printf("[%s] ", argv[ii]);
|
||||
|
||||
/* Try and open the file. */
|
||||
infile = fopen(argv[ii], "rb");
|
||||
if(infile)
|
||||
{
|
||||
uint8_t *buffer = NULL;
|
||||
size_t buffer_len;
|
||||
|
||||
printf("Opened.. ");
|
||||
|
||||
/* Get the length of the file. */
|
||||
fseek(infile, 0L, SEEK_END);
|
||||
buffer_len = ftell(infile);
|
||||
|
||||
/* Reset the file indicator to the beginning of the file. */
|
||||
fseek(infile, 0L, SEEK_SET);
|
||||
|
||||
/* Allocate a buffer for the file contents. */
|
||||
buffer = (uint8_t *)calloc(buffer_len, sizeof(uint8_t));
|
||||
if(buffer)
|
||||
{
|
||||
/* Read all the text from the file into the buffer. */
|
||||
fread(buffer, sizeof(uint8_t), buffer_len, infile);
|
||||
printf("Read %zu bytes, fuzzing.. ", buffer_len);
|
||||
|
||||
/* Call the fuzzer with the data. */
|
||||
LLVMFuzzerTestOneInput(buffer, buffer_len);
|
||||
|
||||
printf("complete !!");
|
||||
|
||||
/* Free the buffer as it's no longer needed. */
|
||||
free(buffer);
|
||||
buffer = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr,
|
||||
"[%s] Failed to allocate %zu bytes \n",
|
||||
argv[ii],
|
||||
buffer_len);
|
||||
}
|
||||
|
||||
/* Close the file as it's no longer needed. */
|
||||
fclose(infile);
|
||||
infile = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Failed to open the file. Maybe wrong name or wrong permissions? */
|
||||
fprintf(stderr, "[%s] Open failed. \n", argv[ii]);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
}
|
3
tests/ossfuzz/testinput.h
Normal file
3
tests/ossfuzz/testinput.h
Normal file
@@ -0,0 +1,3 @@
|
||||
#include <inttypes.h>
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
|
10
tests/signed_key_ecdsa
Normal file
10
tests/signed_key_ecdsa
Normal file
@@ -0,0 +1,10 @@
|
||||
-----BEGIN OPENSSH PRIVATE KEY-----
|
||||
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAiAAAABNlY2RzYS
|
||||
1zaGEyLW5pc3RwMzg0AAAACG5pc3RwMzg0AAAAYQRv1/fnN1SuIkg222jYnySqIJ88J5M3
|
||||
bB6JGeloKhIvnZdPOSVFuFBjuF7NPrGrsm87QstQFbDiLhIlcDNHIq0VhS5itHNMjtC6Ym
|
||||
RRx7mlQSXPbRRF5MclxvDJCMyAIagAAADQekojnXpKI50AAAATZWNkc2Etc2hhMi1uaXN0
|
||||
cDM4NAAAAAhuaXN0cDM4NAAAAGEEb9f35zdUriJINtto2J8kqiCfPCeTN2weiRnpaCoSL5
|
||||
2XTzklRbhQY7hezT6xq7JvO0LLUBWw4i4SJXAzRyKtFYUuYrRzTI7QumJkUce5pUElz20U
|
||||
ReTHJcbwyQjMgCGoAAAAMQDmng9vaqXjHAhRssuBHeQylRKRwzOYOaToF8f+O0NmpmfLnc
|
||||
/c2wOcXf2f9GBAQdYAAAAAAQIDBAUGBw==
|
||||
-----END OPENSSH PRIVATE KEY-----
|
1
tests/signed_key_ecdsa-cert.pub
Normal file
1
tests/signed_key_ecdsa-cert.pub
Normal file
@@ -0,0 +1 @@
|
||||
ecdsa-sha2-nistp384-cert-v01@openssh.com AAAAKGVjZHNhLXNoYTItbmlzdHAzODQtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgQCXc1JaqZ4XzkudbzP/pgEUbkioo7pl9aB09h6sg7KYAAAAIbmlzdHAzODQAAABhBG/X9+c3VK4iSDbbaNifJKognzwnkzdsHokZ6WgqEi+dl085JUW4UGO4Xs0+sauybztCy1AVsOIuEiVwM0cirRWFLmK0c0yO0LpiZFHHuaVBJc9tFEXkxyXG8MkIzIAhqAAAAAAAAAABAAAAAQAAAAhpZGVudGl0eQAAAAsAAAAHbGlic3NoMgAAAAAAAAAA//////////8AAAAAAAAAggAAABVwZXJtaXQtWDExLWZvcndhcmRpbmcAAAAAAAAAF3Blcm1pdC1hZ2VudC1mb3J3YXJkaW5nAAAAAAAAABZwZXJtaXQtcG9ydC1mb3J3YXJkaW5nAAAAAAAAAApwZXJtaXQtcHR5AAAAAAAAAA5wZXJtaXQtdXNlci1yYwAAAAAAAAAAAAAArAAAABNlY2RzYS1zaGEyLW5pc3RwNTIxAAAACG5pc3RwNTIxAAAAhQQAfv15s+G2xg56J+audKAM4G9qOTFrbZRo0CTwvkb/oHrf9/2RSWqYsx/0m5mYCZVlecnZqwRHAOolXbc/Yb4cGjsALUj3UDirsnYR7Ve+SwnunkpvW/H3a98sA3sS+HCpd5RbpfWClSBOI9JEAlPtS1CrEQ7EmO7hmlFOH2cL0qfHCyYAAACnAAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAACMAAAAQgGxnhh8z8LNk5pMw0D9InyEtVRm8OJi23XEhqj/ieT/BsLZXbu65UAcMjrUn6DPdERxF9Dwe9pdIAWOLLjLHYEFBQAAAEIAlxz+XjUKa9Q2vpH0y8IgJMm0H1hTBUM1DQEoL8No1BVtgtIO20mac2fE3I35JxNDmmXoW+FuzmJnyrY9rxY+YXM= ./signed_key_ecdsa.pub
|
1
tests/signed_key_ecdsa.pub
Normal file
1
tests/signed_key_ecdsa.pub
Normal file
@@ -0,0 +1 @@
|
||||
ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBG/X9+c3VK4iSDbbaNifJKognzwnkzdsHokZ6WgqEi+dl085JUW4UGO4Xs0+sauybztCy1AVsOIuEiVwM0cirRWFLmK0c0yO0LpiZFHHuaVBJc9tFEXkxyXG8MkIzIAhqA==
|
12
tests/ssh2.c
12
tests/ssh2.c
@@ -84,7 +84,8 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
/* Create a session instance and start it up
|
||||
* This will trade welcome banners, exchange keys, and setup crypto, compression, and MAC layers
|
||||
* This will trade welcome banners, exchange keys,
|
||||
* and setup crypto, compression, and MAC layers
|
||||
*/
|
||||
session = libssh2_session_init();
|
||||
if(libssh2_session_startup(session, sock)) {
|
||||
@@ -93,8 +94,10 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
/* At this point we haven't authenticated,
|
||||
* The first thing to do is check the hostkey's fingerprint against our known hosts
|
||||
* Your app may have it hard coded, may go to a file, may present it to the user, that's your call
|
||||
* The first thing to do is check the hostkey's
|
||||
* fingerprint against our known hosts
|
||||
* Your app may have it hard coded, may go to a file,
|
||||
* may present it to the user, that's your call
|
||||
*/
|
||||
fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);
|
||||
printf("Fingerprint: ");
|
||||
@@ -118,7 +121,8 @@ int main(int argc, char *argv[])
|
||||
|
||||
if(auth_pw & 4) {
|
||||
/* Authenticate by public key */
|
||||
if(libssh2_userauth_publickey_fromfile(session, username, pubkeyfile, privkeyfile, password)) {
|
||||
if(libssh2_userauth_publickey_fromfile(session, username, pubkeyfile,
|
||||
privkeyfile, password)) {
|
||||
printf("\tAuthentication by public key failed!\n");
|
||||
goto shutdown;
|
||||
}
|
||||
|
@@ -4,9 +4,9 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
const char *USERNAME = "libssh2"; /* configured in Dockerfile */
|
||||
const char *USERNAME = "libssh2"; /* set in Dockerfile */
|
||||
const char *KEY_FILE_PRIVATE = "key_rsa";
|
||||
const char *KEY_FILE_PUBLIC = "key_rsa.pub"; /* configured in Dockerfile */
|
||||
const char *KEY_FILE_PUBLIC = "key_rsa.pub"; /* set in Dockerfile */
|
||||
|
||||
int test(LIBSSH2_SESSION *session)
|
||||
{
|
||||
@@ -42,8 +42,8 @@ int test(LIBSSH2_SESSION *session)
|
||||
|
||||
rc = libssh2_channel_request_auth_agent(channel);
|
||||
if(rc != 0) {
|
||||
fprintf(stderr, "Auth agent request for agent forwarding failed, error code %d\n",
|
||||
rc);
|
||||
fprintf(stderr, "Auth agent request for agent forwarding failed, "
|
||||
"error code %d\n", rc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@@ -32,11 +32,13 @@ int test(LIBSSH2_SESSION *session)
|
||||
|
||||
if(type == LIBSSH2_HOSTKEY_TYPE_ECDSA_256) {
|
||||
rc = libssh2_base64_decode(session, &expected_hostkey, &expected_len,
|
||||
EXPECTED_ECDSA_HOSTKEY, strlen(EXPECTED_ECDSA_HOSTKEY));
|
||||
EXPECTED_ECDSA_HOSTKEY,
|
||||
strlen(EXPECTED_ECDSA_HOSTKEY));
|
||||
}
|
||||
else if(type == LIBSSH2_HOSTKEY_TYPE_RSA) {
|
||||
rc = libssh2_base64_decode(session, &expected_hostkey, &expected_len,
|
||||
EXPECTED_RSA_HOSTKEY, strlen(EXPECTED_RSA_HOSTKEY));
|
||||
EXPECTED_RSA_HOSTKEY,
|
||||
strlen(EXPECTED_RSA_HOSTKEY));
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "Unexpected type of hostkey: %i\n", type);
|
||||
|
@@ -17,19 +17,23 @@ static const char *EXPECTED_ECDSA_HOSTKEY =
|
||||
"AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBC+/syyeKJD9dC2ZH"
|
||||
"9Q7iJGReR4YM3rUCMsSynkyXojdfSClGCMY7JvWlt30ESjYvxoTfSRGx6WvaqYK/vPoYQ4=";
|
||||
|
||||
static const char *EXPECTED_RSA_MD5_HASH_DIGEST = "0C0ED1A5BB10275F76924CE187CE5C5E";
|
||||
static const char *EXPECTED_RSA_MD5_HASH_DIGEST =
|
||||
"0C0ED1A5BB10275F76924CE187CE5C5E";
|
||||
|
||||
static const char *EXPECTED_RSA_SHA1_HASH_DIGEST =
|
||||
"F3CD59E2913F4422B80F7B0A82B2B89EAE449387";
|
||||
|
||||
static const char *EXPECTED_RSA_SHA256_HASH_DIGEST = "92E3DA49DF3C7F99A828F505ED8239397A5D1F62914459760F878F7510F563A3";
|
||||
static const char *EXPECTED_RSA_SHA256_HASH_DIGEST =
|
||||
"92E3DA49DF3C7F99A828F505ED8239397A5D1F62914459760F878F7510F563A3";
|
||||
|
||||
static const char *EXPECTED_ECDSA_MD5_HASH_DIGEST = "0402E4D897580BBC911379CBD88BCD3D";
|
||||
static const char *EXPECTED_ECDSA_MD5_HASH_DIGEST =
|
||||
"0402E4D897580BBC911379CBD88BCD3D";
|
||||
|
||||
static const char *EXPECTED_ECDSA_SHA1_HASH_DIGEST =
|
||||
"12FDAD1E3B31B10BABB00F2A8D1B9A62C326BD2F";
|
||||
|
||||
static const char *EXPECTED_ECDSA_SHA256_HASH_DIGEST = "56FCD975B166C3F0342D0036E44C311A86C0EAE40713B53FC776369BAE7F5264";
|
||||
static const char *EXPECTED_ECDSA_SHA256_HASH_DIGEST =
|
||||
"56FCD975B166C3F0342D0036E44C311A86C0EAE40713B53FC776369BAE7F5264";
|
||||
|
||||
static const int MD5_HASH_SIZE = 16;
|
||||
static const int SHA1_HASH_SIZE = 20;
|
||||
@@ -51,6 +55,7 @@ int test(LIBSSH2_SESSION *session)
|
||||
{
|
||||
char buf[BUFSIZ];
|
||||
|
||||
const char *hostkey;
|
||||
const char *md5_hash;
|
||||
const char *sha1_hash;
|
||||
const char *sha256_hash;
|
||||
@@ -61,7 +66,7 @@ int test(LIBSSH2_SESSION *session)
|
||||
(void)EXPECTED_RSA_HOSTKEY;
|
||||
(void)EXPECTED_ECDSA_HOSTKEY;
|
||||
|
||||
const char *hostkey = libssh2_session_hostkey(session, &len, &type);
|
||||
hostkey = libssh2_session_hostkey(session, &len, &type);
|
||||
if(hostkey == NULL) {
|
||||
print_last_session_error("libssh2_session_hostkey");
|
||||
return 1;
|
||||
@@ -79,8 +84,9 @@ int test(LIBSSH2_SESSION *session)
|
||||
calculate_digest(md5_hash, MD5_HASH_SIZE, buf, BUFSIZ);
|
||||
|
||||
if(strcmp(buf, EXPECTED_ECDSA_MD5_HASH_DIGEST) != 0) {
|
||||
fprintf(stderr, "ECDSA MD5 hash not as expected - digest %s != %s\n", buf,
|
||||
EXPECTED_ECDSA_MD5_HASH_DIGEST);
|
||||
fprintf(stderr,
|
||||
"ECDSA MD5 hash not as expected - digest %s != %s\n",
|
||||
buf, EXPECTED_ECDSA_MD5_HASH_DIGEST);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -94,12 +100,14 @@ int test(LIBSSH2_SESSION *session)
|
||||
calculate_digest(sha1_hash, SHA1_HASH_SIZE, buf, BUFSIZ);
|
||||
|
||||
if(strcmp(buf, EXPECTED_ECDSA_SHA1_HASH_DIGEST) != 0) {
|
||||
fprintf(stderr, "ECDSA SHA1 hash not as expected - digest %s != %s\n", buf,
|
||||
EXPECTED_ECDSA_SHA1_HASH_DIGEST);
|
||||
fprintf(stderr,
|
||||
"ECDSA SHA1 hash not as expected - digest %s != %s\n",
|
||||
buf, EXPECTED_ECDSA_SHA1_HASH_DIGEST);
|
||||
return 1;
|
||||
}
|
||||
|
||||
sha256_hash = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA256);
|
||||
sha256_hash = libssh2_hostkey_hash(session,
|
||||
LIBSSH2_HOSTKEY_HASH_SHA256);
|
||||
if(sha256_hash == NULL) {
|
||||
print_last_session_error(
|
||||
"libssh2_hostkey_hash(LIBSSH2_HOSTKEY_HASH_SHA256)");
|
||||
@@ -109,8 +117,9 @@ int test(LIBSSH2_SESSION *session)
|
||||
calculate_digest(sha256_hash, SHA256_HASH_SIZE, buf, BUFSIZ);
|
||||
|
||||
if(strcmp(buf, EXPECTED_ECDSA_SHA256_HASH_DIGEST) != 0) {
|
||||
fprintf(stderr, "ECDSA SHA256 hash not as expected - digest %s != %s\n", buf,
|
||||
EXPECTED_ECDSA_SHA256_HASH_DIGEST);
|
||||
fprintf(stderr,
|
||||
"ECDSA SHA256 hash not as expected - digest %s != %s\n",
|
||||
buf, EXPECTED_ECDSA_SHA256_HASH_DIGEST);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -127,8 +136,9 @@ int test(LIBSSH2_SESSION *session)
|
||||
calculate_digest(md5_hash, MD5_HASH_SIZE, buf, BUFSIZ);
|
||||
|
||||
if(strcmp(buf, EXPECTED_RSA_MD5_HASH_DIGEST) != 0) {
|
||||
fprintf(stderr, "MD5 hash not as expected - digest %s != %s\n", buf,
|
||||
EXPECTED_RSA_MD5_HASH_DIGEST);
|
||||
fprintf(stderr,
|
||||
"MD5 hash not as expected - digest %s != %s\n",
|
||||
buf, EXPECTED_RSA_MD5_HASH_DIGEST);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -142,12 +152,14 @@ int test(LIBSSH2_SESSION *session)
|
||||
calculate_digest(sha1_hash, SHA1_HASH_SIZE, buf, BUFSIZ);
|
||||
|
||||
if(strcmp(buf, EXPECTED_RSA_SHA1_HASH_DIGEST) != 0) {
|
||||
fprintf(stderr, "SHA1 hash not as expected - digest %s != %s\n", buf,
|
||||
EXPECTED_RSA_SHA1_HASH_DIGEST);
|
||||
fprintf(stderr,
|
||||
"SHA1 hash not as expected - digest %s != %s\n",
|
||||
buf, EXPECTED_RSA_SHA1_HASH_DIGEST);
|
||||
return 1;
|
||||
}
|
||||
|
||||
sha256_hash = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA256);
|
||||
sha256_hash = libssh2_hostkey_hash(session,
|
||||
LIBSSH2_HOSTKEY_HASH_SHA256);
|
||||
if(sha256_hash == NULL) {
|
||||
print_last_session_error(
|
||||
"libssh2_hostkey_hash(LIBSSH2_HOSTKEY_HASH_SHA256)");
|
||||
@@ -157,8 +169,9 @@ int test(LIBSSH2_SESSION *session)
|
||||
calculate_digest(sha256_hash, SHA256_HASH_SIZE, buf, BUFSIZ);
|
||||
|
||||
if(strcmp(buf, EXPECTED_RSA_SHA256_HASH_DIGEST) != 0) {
|
||||
fprintf(stderr, "SHA256 hash not as expected - digest %s != %s\n", buf,
|
||||
EXPECTED_RSA_SHA256_HASH_DIGEST);
|
||||
fprintf(stderr,
|
||||
"SHA256 hash not as expected - digest %s != %s\n",
|
||||
buf, EXPECTED_RSA_SHA256_HASH_DIGEST);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
@@ -4,11 +4,11 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
static const char *USERNAME = "libssh2"; /* configured in Dockerfile */
|
||||
static const char *USERNAME = "libssh2"; /* set in Dockerfile */
|
||||
static const char *WRONG_PASSWORD = "i'm not the password";
|
||||
|
||||
static void kbd_callback(const char *name, int name_len,
|
||||
const char *instruction, int instruction_len,
|
||||
const char *instruct, int instruct_len,
|
||||
int num_prompts,
|
||||
const LIBSSH2_USERAUTH_KBDINT_PROMPT *prompts,
|
||||
LIBSSH2_USERAUTH_KBDINT_RESPONSE *responses,
|
||||
@@ -17,7 +17,7 @@ static void kbd_callback(const char *name, int name_len,
|
||||
int i;
|
||||
(void)abstract;
|
||||
fprintf(stdout, "Kb-int name: %.*s\n", name_len, name);
|
||||
fprintf(stdout, "Kb-int instruction: %.*s\n", instruction_len, instruction);
|
||||
fprintf(stdout, "Kb-int instruction: %.*s\n", instruct_len, instruct);
|
||||
for(i = 0; i < num_prompts; ++i) {
|
||||
fprintf(stdout, "Kb-int prompt %d: %.*s\n", i, prompts[i].length,
|
||||
prompts[i].text);
|
||||
|
@@ -4,11 +4,12 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
static const char *USERNAME = "libssh2"; /* configured in Dockerfile */
|
||||
static const char *PASSWORD = "my test password"; /* configured in Dockerfile */
|
||||
/* configured in Dockerfile */
|
||||
static const char *USERNAME = "libssh2";
|
||||
static const char *PASSWORD = "my test password";
|
||||
|
||||
static void kbd_callback(const char *name, int name_len,
|
||||
const char *instruction, int instruction_len,
|
||||
const char *instruct, int instruct_len,
|
||||
int num_prompts,
|
||||
const LIBSSH2_USERAUTH_KBDINT_PROMPT *prompts,
|
||||
LIBSSH2_USERAUTH_KBDINT_RESPONSE *responses,
|
||||
@@ -18,7 +19,7 @@ static void kbd_callback(const char *name, int name_len,
|
||||
(void)abstract;
|
||||
|
||||
fprintf(stdout, "Kb-int name: %.*s\n", name_len, name);
|
||||
fprintf(stdout, "Kb-int instruction: %.*s\n", instruction_len, instruction);
|
||||
fprintf(stdout, "Kb-int instruction: %.*s\n", instruct_len, instruct);
|
||||
for(i = 0; i < num_prompts; ++i) {
|
||||
fprintf(stdout, "Kb-int prompt %d: %.*s\n", i, prompts[i].length,
|
||||
prompts[i].text);
|
||||
|
@@ -4,7 +4,7 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
static const char *USERNAME = "libssh2"; /* configured in Dockerfile */
|
||||
static const char *USERNAME = "libssh2"; /* set in Dockerfile */
|
||||
static const char *WRONG_PASSWORD = "i'm not the password";
|
||||
|
||||
int test(LIBSSH2_SESSION *session)
|
||||
|
@@ -4,7 +4,8 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
static const char *PASSWORD = "my test password"; /* configured in Dockerfile */
|
||||
/* configured in Dockerfile */
|
||||
static const char *PASSWORD = "my test password";
|
||||
static const char *WRONG_USERNAME = "i dont exist";
|
||||
|
||||
int test(LIBSSH2_SESSION *session)
|
||||
|
@@ -4,8 +4,9 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
static const char *USERNAME = "libssh2"; /* configured in Dockerfile */
|
||||
static const char *PASSWORD = "my test password"; /* configured in Dockerfile */
|
||||
/* configured in Dockerfile */
|
||||
static const char *USERNAME = "libssh2";
|
||||
static const char *PASSWORD = "my test password";
|
||||
|
||||
int test(LIBSSH2_SESSION *session)
|
||||
{
|
||||
|
@@ -4,7 +4,7 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
static const char *USERNAME = "libssh2"; /* configured in Dockerfile */
|
||||
static const char *USERNAME = "libssh2"; /* set in Dockerfile */
|
||||
static const char *KEY_FILE_PRIVATE = "key_dsa_wrong";
|
||||
static const char *KEY_FILE_PUBLIC = "key_dsa_wrong.pub";
|
||||
|
||||
|
@@ -4,9 +4,10 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
static const char *USERNAME = "libssh2"; /* configured in Dockerfile */
|
||||
/* configured in Dockerfile */
|
||||
static const char *USERNAME = "libssh2";
|
||||
static const char *KEY_FILE_PRIVATE = "key_dsa";
|
||||
static const char *KEY_FILE_PUBLIC = "key_dsa.pub"; /* configured in Dockerfile */
|
||||
static const char *KEY_FILE_PUBLIC = "key_dsa.pub";
|
||||
|
||||
int test(LIBSSH2_SESSION *session)
|
||||
{
|
||||
|
38
tests/test_public_key_auth_succeeds_with_correct_ecdsa_key.c
Normal file
38
tests/test_public_key_auth_succeeds_with_correct_ecdsa_key.c
Normal file
@@ -0,0 +1,38 @@
|
||||
#include "session_fixture.h"
|
||||
|
||||
#include <libssh2.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/* configured in Dockerfile */
|
||||
static const char *USERNAME = "libssh2";
|
||||
static const char *KEY_FILE_PRIVATE = "key_ecdsa";
|
||||
static const char *KEY_FILE_PUBLIC = "key_ecdsa.pub";
|
||||
|
||||
int test(LIBSSH2_SESSION *session)
|
||||
{
|
||||
int rc;
|
||||
const char *userauth_list = NULL;
|
||||
|
||||
userauth_list = libssh2_userauth_list(session, USERNAME, strlen(USERNAME));
|
||||
if(userauth_list == NULL) {
|
||||
print_last_session_error("libssh2_userauth_list");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(strstr(userauth_list, "publickey") == NULL) {
|
||||
fprintf(stderr, "'publickey' was expected in userauth list: %s\n",
|
||||
userauth_list);
|
||||
return 1;
|
||||
}
|
||||
|
||||
rc = libssh2_userauth_publickey_fromfile_ex(
|
||||
session, USERNAME, strlen(USERNAME), KEY_FILE_PUBLIC, KEY_FILE_PRIVATE,
|
||||
NULL);
|
||||
if(rc != 0) {
|
||||
print_last_session_error("libssh2_userauth_publickey_fromfile_ex");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@@ -4,9 +4,10 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
static const char *USERNAME = "libssh2"; /* configured in Dockerfile */
|
||||
/* configured in Dockerfile */
|
||||
static const char *USERNAME = "libssh2";
|
||||
static const char *KEY_FILE_PRIVATE = "key_ed25519";
|
||||
static const char *KEY_FILE_PUBLIC = "key_ed25519.pub"; /* configured in Dockerfile */
|
||||
static const char *KEY_FILE_PUBLIC = "key_ed25519.pub";
|
||||
|
||||
int test(LIBSSH2_SESSION *session)
|
||||
{
|
||||
|
@@ -5,7 +5,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static const char *USERNAME = "libssh2"; /* configured in Dockerfile */
|
||||
static const char *USERNAME = "libssh2"; /* set in Dockerfile */
|
||||
static const char *KEY_FILE_ED25519_PRIVATE = "key_ed25519";
|
||||
|
||||
int read_file(const char *path, char **buf, size_t *len);
|
||||
@@ -13,7 +13,6 @@ int read_file(const char *path, char **buf, size_t *len);
|
||||
int test(LIBSSH2_SESSION *session)
|
||||
{
|
||||
int rc;
|
||||
FILE *fp = NULL;
|
||||
char *buffer = NULL;
|
||||
size_t len = 0;
|
||||
const char *userauth_list = NULL;
|
||||
@@ -35,8 +34,11 @@ int test(LIBSSH2_SESSION *session)
|
||||
return 1;
|
||||
}
|
||||
|
||||
rc = libssh2_userauth_publickey_frommemory(session, USERNAME, strlen(USERNAME),
|
||||
NULL, 0, buffer, len, NULL);
|
||||
rc = libssh2_userauth_publickey_frommemory(session,
|
||||
USERNAME, strlen(USERNAME),
|
||||
NULL, 0,
|
||||
buffer, len,
|
||||
NULL);
|
||||
|
||||
free(buffer);
|
||||
|
||||
@@ -50,7 +52,6 @@ int test(LIBSSH2_SESSION *session)
|
||||
|
||||
int read_file(const char *path, char **out_buffer, size_t *out_len)
|
||||
{
|
||||
int rc;
|
||||
FILE *fp = NULL;
|
||||
char *buffer = NULL;
|
||||
size_t len = 0;
|
||||
|
@@ -4,10 +4,11 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
static const char *USERNAME = "libssh2"; /* configured in Dockerfile */
|
||||
/* configured in Dockerfile */
|
||||
static const char *USERNAME = "libssh2";
|
||||
static const char *PASSWORD = "libssh2";
|
||||
static const char *KEY_FILE_PRIVATE = "key_ed25519_encrypted";
|
||||
static const char *KEY_FILE_PUBLIC = "key_ed25519_encrypted.pub"; /* configured in Dockerfile */
|
||||
static const char *KEY_FILE_PUBLIC = "key_ed25519_encrypted.pub";
|
||||
|
||||
int test(LIBSSH2_SESSION *session)
|
||||
{
|
||||
|
@@ -4,10 +4,11 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
static const char *USERNAME = "libssh2"; /* configured in Dockerfile */
|
||||
/* configured in Dockerfile */
|
||||
static const char *USERNAME = "libssh2";
|
||||
static const char *PASSWORD = "libssh2";
|
||||
static const char *KEY_FILE_PRIVATE = "key_rsa_encrypted";
|
||||
static const char *KEY_FILE_PUBLIC = "key_rsa_encrypted.pub"; /* configured in Dockerfile */
|
||||
static const char *KEY_FILE_PUBLIC = "key_rsa_encrypted.pub";
|
||||
|
||||
int test(LIBSSH2_SESSION *session)
|
||||
{
|
||||
|
@@ -4,9 +4,10 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
static const char *USERNAME = "libssh2"; /* configured in Dockerfile */
|
||||
/* configured in Dockerfile */
|
||||
static const char *USERNAME = "libssh2";
|
||||
static const char *KEY_FILE_PRIVATE = "key_rsa";
|
||||
static const char *KEY_FILE_PUBLIC = "key_rsa.pub"; /* configured in Dockerfile */
|
||||
static const char *KEY_FILE_PUBLIC = "key_rsa.pub";
|
||||
|
||||
int test(LIBSSH2_SESSION *session)
|
||||
{
|
||||
|
@@ -4,9 +4,10 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
static const char *USERNAME = "libssh2"; /* configured in Dockerfile */
|
||||
/* configured in Dockerfile */
|
||||
static const char *USERNAME = "libssh2";
|
||||
static const char *KEY_FILE_PRIVATE = "key_rsa_openssh";
|
||||
static const char *KEY_FILE_PUBLIC = "key_rsa_openssh.pub"; /* configured in Dockerfile */
|
||||
static const char *KEY_FILE_PUBLIC = "key_rsa_openssh.pub";
|
||||
|
||||
int test(LIBSSH2_SESSION *session)
|
||||
{
|
||||
|
@@ -0,0 +1,38 @@
|
||||
#include "session_fixture.h"
|
||||
|
||||
#include <libssh2.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/* configured in Dockerfile */
|
||||
static const char *USERNAME = "libssh2";
|
||||
static const char *KEY_FILE_PRIVATE = "signed_key_ecdsa";
|
||||
static const char *KEY_FILE_PUBLIC = "signed_key_ecdsa-cert.pub";
|
||||
|
||||
int test(LIBSSH2_SESSION *session)
|
||||
{
|
||||
int rc;
|
||||
const char *userauth_list = NULL;
|
||||
|
||||
userauth_list = libssh2_userauth_list(session, USERNAME, strlen(USERNAME));
|
||||
if(userauth_list == NULL) {
|
||||
print_last_session_error("libssh2_userauth_list");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(strstr(userauth_list, "publickey") == NULL) {
|
||||
fprintf(stderr, "'publickey' was expected in userauth list: %s\n",
|
||||
userauth_list);
|
||||
return 1;
|
||||
}
|
||||
|
||||
rc = libssh2_userauth_publickey_fromfile_ex(
|
||||
session, USERNAME, strlen(USERNAME), KEY_FILE_PUBLIC, KEY_FILE_PRIVATE,
|
||||
NULL);
|
||||
if(rc != 0) {
|
||||
print_last_session_error("libssh2_userauth_publickey_fromfile_ex");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@@ -29,7 +29,7 @@ $ man2help -a [-.docs]AUTHORS.; libssh2.hlp -b 2
|
||||
$ man2help -a [-.docs]BINDINGS.; libssh2.hlp -b 2
|
||||
$ man2help -a [-.docs]HACKING.; libssh2.hlp -b 2
|
||||
$ if f$search("[]HACKING_CRYPTO.") .nes. "" then delete []HACKING_CRYPTO.;*
|
||||
$ copy [-.docs]HACKING.CRYPTO; []HACKING_CRYPTO.
|
||||
$ copy [-.docs]HACKING-CRYPTO; []HACKING_CRYPTO.
|
||||
$ man2help -a []HACKING_CRYPTO.; libssh2.hlp -b 2
|
||||
$ man2help -a [-.docs]TODO.; libssh2.hlp -b 2
|
||||
$!
|
||||
|
Reference in New Issue
Block a user