1
0
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:
Anders Borum
2021-10-13 22:13:53 +02:00
100 changed files with 4230 additions and 1659 deletions

4
.github/stale.yml vendored
View File

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

@@ -35,3 +35,4 @@ tags
libssh2.pc
TAGS
*~
.DS_Store

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

@@ -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 "${@}"

View 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"'

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -38,7 +38,8 @@
#include "libssh2_priv.h"
#ifdef LIBSSH2_HAVE_ZLIB
# include <zlib.h>
#include <zlib.h>
#undef compress /* dodge name clash with ZLIB macro */
#endif
#include "comp.h"

View File

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

View File

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

View File

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

1388
src/kex.c

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

@@ -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
#define LIBSSH2_ECDSA 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
*/
@@ -251,10 +336,11 @@
pk, pk_len, pw)
/*******************************************************************/
/*******************************************************************/
/*
* 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 */

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

@@ -0,0 +1 @@
ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBOiyJJwf+hFJrOkik9IQVxjhhVnI1vKl4BGLj03erLvw4TXXwoZzlPx6J936fU9JvvPw+d8PA4viMEfFbmdbHREKhwi3u1vZrfj0mB8SXw96AcZwX8PAL556wgom+/Qx+Q==

View File

@@ -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,35 +242,44 @@ 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);

View File

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

View File

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

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

View File

@@ -0,0 +1 @@
ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBAB+/Xmz4bbGDnon5q50oAzgb2o5MWttlGjQJPC+Rv+get/3/ZFJapizH/SbmZgJlWV5ydmrBEcA6iVdtz9hvhwaOwAtSPdQOKuydhHtV75LCe6eSm9b8fdr3ywDexL4cKl3lFul9YKVIE4j0kQCU+1LUKsRDsSY7uGaUU4fZwvSp8cLJg== CA

2
tests/ossfuzz/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
*.a
ssh2_client_fuzzer

32
tests/ossfuzz/Makefile.am Normal file
View 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
View 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/

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

View 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");
}
}

View 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
View File

@@ -0,0 +1,10 @@
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAiAAAABNlY2RzYS
1zaGEyLW5pc3RwMzg0AAAACG5pc3RwMzg0AAAAYQRv1/fnN1SuIkg222jYnySqIJ88J5M3
bB6JGeloKhIvnZdPOSVFuFBjuF7NPrGrsm87QstQFbDiLhIlcDNHIq0VhS5itHNMjtC6Ym
RRx7mlQSXPbRRF5MclxvDJCMyAIagAAADQekojnXpKI50AAAATZWNkc2Etc2hhMi1uaXN0
cDM4NAAAAAhuaXN0cDM4NAAAAGEEb9f35zdUriJINtto2J8kqiCfPCeTN2weiRnpaCoSL5
2XTzklRbhQY7hezT6xq7JvO0LLUBWw4i4SJXAzRyKtFYUuYrRzTI7QumJkUce5pUElz20U
ReTHJcbwyQjMgCGoAAAAMQDmng9vaqXjHAhRssuBHeQylRKRwzOYOaToF8f+O0NmpmfLnc
/c2wOcXf2f9GBAQdYAAAAAAQIDBAUGBw==
-----END OPENSSH PRIVATE KEY-----

View 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

View File

@@ -0,0 +1 @@
ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBG/X9+c3VK4iSDbbaNifJKognzwnkzdsHokZ6WgqEi+dl085JUW4UGO4Xs0+sauybztCy1AVsOIuEiVwM0cirRWFLmK0c0yO0LpiZFHHuaVBJc9tFEXkxyXG8MkIzIAhqA==

View File

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

View File

@@ -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)
{
@@ -15,12 +15,12 @@ int test(LIBSSH2_SESSION *session)
const char *userauth_list =
libssh2_userauth_list(session, USERNAME, strlen(USERNAME));
if (userauth_list == NULL) {
if(userauth_list == NULL) {
print_last_session_error("libssh2_userauth_list");
return 1;
}
if (strstr(userauth_list, "publickey") == NULL) {
if(strstr(userauth_list, "publickey") == NULL) {
fprintf(stderr, "'publickey' was expected in userauth list: %s\n",
userauth_list);
return 1;
@@ -29,21 +29,21 @@ int test(LIBSSH2_SESSION *session)
rc = libssh2_userauth_publickey_fromfile_ex(
session, USERNAME, strlen(USERNAME), KEY_FILE_PUBLIC, KEY_FILE_PRIVATE,
NULL);
if (rc != 0) {
if(rc != 0) {
print_last_session_error("libssh2_userauth_publickey_fromfile_ex");
return 1;
}
channel = libssh2_channel_open_session(session);
/* if (channel == NULL) { */
/* if(channel == NULL) { */
/* printf("Error opening channel\n"); */
/* return 1; */
/* } */
rc = libssh2_channel_request_auth_agent(channel);
if (rc != 0) {
fprintf(stderr, "Auth agent request for agent forwarding failed, error code %d\n",
rc);
if(rc != 0) {
fprintf(stderr, "Auth agent request for agent forwarding failed, "
"error code %d\n", rc);
return 1;
}

View File

@@ -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);
@@ -49,7 +51,7 @@ int test(LIBSSH2_SESSION *session)
}
if(len != expected_len) {
fprintf(stderr, "Hostkey does not have the expected length %ld != %d\n",
fprintf(stderr, "Hostkey does not have the expected length %ld!=%d\n",
(unsigned long)len, expected_len);
return 1;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View 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 = "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;
}

View File

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