Compare commits

...

492 Commits

Author SHA1 Message Date
Jakub Jelen
1b3c061aae Reproducer for memory leak from parsing knonw hosts
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <norbertpocs0@gmail.com>
2026-02-03 18:01:36 +01:00
Jakub Jelen
1525ea3dda knownhosts: Avoid memory leaks on invalid entries
When `known_hosts` file contained matching valid entry followed by
invalid entry, the first record was already allocated in
`ssh_known_hosts_read_entries()`, but not freed on error.

This could cause possible memory leaks in client, but we do not
consider them as security relevant as the leaks do not add up and
successful exploitaition is hard or impossible.

Originally reported by Kang Yang.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <norbertpocs0@gmail.com>
2026-02-03 18:01:35 +01:00
Jakub Jelen
a189c2ef4d gssapi: Sanitize input parameters
Originally reported with this patch by Brian Carpenter from Deep Fork Cyber.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Pavol Žáčik <pzacik@redhat.com>
2026-02-03 12:09:17 +01:00
Jakub Jelen
b2abcf8534 cmake: Propagate WITH_FINAL to abimap conditionally
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Pavol Žáčik <pzacik@redhat.com>
2026-02-02 19:32:16 +01:00
Jakub Jelen
809f9b7729 Require abimap 0.4.0
The version 0.4.0 fixed the issues of multi-digit version numbers
which we hit with releaseing libssh ABI version 4_10 with last
release.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Pavol Žáčik <pzacik@redhat.com>
2026-02-02 19:32:16 +01:00
Jakub Jelen
d297621c33 tests: Workaround softhsm-2.7.0 bug in hashed ECDSA
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Pavol Žáčik <pzacik@redhat.com>
2026-02-02 19:32:16 +01:00
Jakub Jelen
d936b7e81d mlkem: Use fprintf instead of internal logging function
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Pavol Žáčik <pzacik@redhat.com>
2026-02-02 19:32:16 +01:00
Shreyas Mahajan
971d44107e ci: Test against latest LibreSSL
Signed-off-by: Shreyas Mahajan <shreyasmahajan05@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2026-02-02 18:37:54 +01:00
Shreyas Mahajan
a1e49728ba crypto: Add support for Poly1305 from LibreSSL
Signed-off-by: Shreyas Mahajan <shreyasmahajan05@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2026-02-02 18:37:54 +01:00
Shreyas Mahajan
6c5459e7fc reformat libcrypto.c
Signed-off-by: Shreyas Mahajan <shreyasmahajan05@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2026-02-02 18:37:53 +01:00
Shreyas Mahajan
f47d1c797a ci: add CLI helper to run GitLab CI jobs locally
Signed-off-by: Shreyas Mahajan <shreyasmahajan05@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2026-02-02 18:37:00 +01:00
Madhav Vasisth
da27d23125 docs: document sftp_session public API type
Signed-off-by: Madhav Vasisth <mv2363@srmist.edu.in>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2026-02-02 18:35:35 +01:00
Jakub Jelen
34db488e4d Native ML-KEM768 implementation
for cryptographic backends that do not have support for ML-KEM (old
OpenSSL and Gcrypt; MbedTLS).

Based on the libcrux implementation used in OpenSSH, taken from this
revision:

https://github.com/openssh/openssh-portable/blob/6aba700/libcrux_mlkem768_sha3.h

But refactored to separate C and header file to support testing and
removed unused functions (to make compiler happy).

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Pavol Žáčik <pzacik@redhat.com>
2026-01-15 12:48:06 +01:00
Jakub Jelen
9780fa2f01 tests: Apply verbosity also for the ssh_bind
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Pavol Žáčik <pzacik@redhat.com>
2026-01-15 12:23:42 +01:00
Jakub Jelen
5a795ce47c Add missing check in ML-KEM implementation of gcrypt
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Pavol Žáčik <pzacik@redhat.com>
2026-01-15 12:23:42 +01:00
Jakub Jelen
b33a90d20b tests: Provide minimal openssl configuration file
When we use empty configuration file, some stuff go south in c10s
and for example fips mode detection does not work anymore.

Providing minimal configuration file avoids the issues of loading
the provider too early, while keeping fips mode activation working
and tests happy.

It also configures the pkcs11-provider to assume the token provides
FIPS approved crypto so the tests can work.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Pavol Žáčik <pzacik@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-15 12:22:10 +01:00
Jakub Jelen
ef45b8ae8c options: Fix doc string
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Pavol Žáčik <pzacik@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-15 12:22:10 +01:00
Jakub Jelen
3c2b254206 config: Pass the right types to OPTIONS_RSA_MIN_SIZE
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Pavol Žáčik <pzacik@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-15 12:22:10 +01:00
Jakub Jelen
7dea005729 tests: Avoid needless skip in testcases
the whole unit is skipped in fips mode

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Pavol Žáčik <pzacik@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-15 12:22:10 +01:00
Jakub Jelen
ad8d0c1e03 ci: Use pkcs11-provider on c9s
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Pavol Žáčik <pzacik@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-15 12:22:10 +01:00
Jakub Jelen
cb0f7d963e tests: Remove trailing whitespace
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Pavol Žáčik <pzacik@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-15 12:22:10 +01:00
Jakub Jelen
c90b239230 tests: Skip agent forwarding test if we are too deep in filesystem
The maximal lenght of unix domain socket path is 108 characters. When
the build directory (and UID wrapper home directories) are too deep
in the filesystem, OpenSSH will fail to create the socket file,
which is failing this test.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Pavol Žáčik <pzacik@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-15 12:22:10 +01:00
Jakub Jelen
18ec01c980 tests: Authentication with Ed25519 pkcs11 key
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Pavol Žáčik <pzacik@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-15 12:22:10 +01:00
Jakub Jelen
a983142a07 tests: Set explicit kex algorithm
without explicitly setting the algorithms, they might be set by
some other configuration file, for example crypto policies pulled
from `/etc/libssh/libssh_server.config` during RPM build.

Log also the generated configuration file and change the other case
to use standard logging mechanism instead of fprintf.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Pavol Žáčik <pzacik@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-15 12:22:10 +01:00
Jakub Jelen
89d51ced0d tests: Log server messages to separate files
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Pavol Žáčik <pzacik@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-15 12:22:10 +01:00
Jakub Jelen
16771cc574 tests: Remove needless goto
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Pavol Žáčik <pzacik@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-15 12:22:10 +01:00
Jakub Jelen
247ebb4d7f tests: Remove unused variable
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Pavol Žáčik <pzacik@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-15 12:22:10 +01:00
Jakub Jelen
acd5dace66 tests: Print read bytes to debug failures
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Pavol Žáčik <pzacik@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-15 12:22:10 +01:00
Jakub Jelen
5545b8808b sntrup: Avoid linking issues in external_override tests
This linking worked only in CI and local builds, but not during
the build in RPM as it fails on missing symbols that were defined
only in the main library. This is solved as with the other digest
dependencies in external crypto by removing the intermediate
function. We are already linking the md_*.o objects.

The error was like this

sh: symbol lookup error: /path/libssh/libssh-0.12.0-build/libssh-0.12.0/redhat-linux-build/lib/libsntrup761_override.so: undefined symbol: crypto_hash_sha512

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Pavol Žáčik <pzacik@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-15 12:22:10 +01:00
Jakub Jelen
be5a900ed0 tests: Reformat torture_auth_pkcs11
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Pavol Žáčik <pzacik@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-15 12:22:10 +01:00
Andreas Schneider
40ba3c6c80 cmake: Download doxygen theme during build not configure run
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2026-01-12 15:25:40 +01:00
Jakub Jelen
57225a7168 ci: Include internal docs in the docs coverage reports
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-07 16:10:19 +01:00
Jakub Jelen
02ae2ace35 cmake: Make the WITH_INTERNAL_DOC function do something
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-07 16:10:19 +01:00
Jakub Jelen
76c6ee9ccf Add ML-KEM implementation for gcrypt
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-07 15:46:33 +01:00
Jakub Jelen
9a3351934b gssapi: Fix typo
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-07 15:44:52 +01:00
Jakub Jelen
1f1309c915 pki: Improve documentation about pubkey import functions
Resolves: #253 and #254

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-07 15:44:52 +01:00
Jakub Jelen
a8ca282033 dh-gex: Initialize best_size to make the code mode straight-forward
Coverity thought that the best_nlines could underflow, but the best_size is
initialized to 0 before calling this function so its moot. Adjusting the code
to be better understandable to static analyzers by initializing the variable
inside of the function.

Thanks coverity!

CID 1548873

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-07 14:46:07 +01:00
Jakub Jelen
b61bb3f8ac connector: Avoid possible underflow ...
... if underlying functions read or write more than expected.

This should never happen, but static analysis tools are inventive.

Thanks coverity!

CID 1548868

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-07 14:46:07 +01:00
Jakub Jelen
c9abf5ebbb connect: Avoid calling close with negative argument
The `first` is intialized to -1 and if we reach this without setting this, we
needlessly call close(-1). It should be no-op, but better be safe.

Thanks coverity!

CID 1644001

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-07 14:46:07 +01:00
Jakub Jelen
48fdf4b80a gssapi: Avoid possible memory leak on error condition
Thanks coverity!

CID 1643999

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-07 14:46:07 +01:00
Jakub Jelen
f5eb3e532b gssapi: Check return value from ssh_gssapi_init()
Checking the session->gssapi is resulting in the very same results, but this
approach is more direct and makes static analysis tools more happy.

Thanks coverity!

CID 1644000

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-07 14:46:07 +01:00
anshul agrawal
3f0007895c Add Keyboard Interactive
Signed-off-by: anshul agrawal <anshulagrawal2902@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2026-01-06 22:56:44 +05:30
nikhil-nari
06186279a8 feat: Add interoperability tests for PuTTY
Signed-off-by: Nikhil V <nikhilgreyshines@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2026-01-05 17:28:15 +01:00
Jakub Jelen
c36bd2304a connect: Close possibly leaking socket
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-05 13:32:01 +01:00
Jakub Jelen
82db6a7ab3 tests: Test proxyjump configuration parsing
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-05 13:32:01 +01:00
Jakub Jelen
deffea5ad2 socket: Properly close the proxyjump FD when proxy connection fails
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-05 13:32:01 +01:00
Jakub Jelen
320844669a config: Allow setting username from configuration
... file, even if it was already set before. The options
level handles what was already set.

The proxyJump implementation sets the username from the proxyjump, which
is setting it to NULL, effectively writing the current username to the
new session, which was not possible to override due to the following check.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-05 13:32:01 +01:00
Pavol Žáčik
d0d45c8915 gssapi: free session->gssapi->user before assigning
To prevent memory leaks with multiple authentication attempts.

Signed-off-by: Pavol Žáčik <pzacik@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-05 12:24:13 +01:00
Pavol Žáčik
65abae059e ci: Add bug links as reasoning why some tests are not run
Signed-off-by: Pavol Žáčik <pzacik@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-05 12:24:13 +01:00
Pavol Žáčik
7c2574682c tests: test pubkey auth after gssapi-keyex with null host key
We want to make sure it suceeds because it could fail if
the client tries to send a hostbound public key authentication
request.

Signed-off-by: Pavol Žáčik <pzacik@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-05 12:24:13 +01:00
Pavol Žáčik
d2bb1ba889 auth: do not prefer hostbound auth if there is no host key
If there is no host key (e.g., because we are doing
gssapi-keyex with "null" host key algorithm), it does not
make sense to use host bound authentication.

Signed-off-by: Pavol Žáčik <pzacik@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-05 12:24:13 +01:00
Pavol Žáčik
9b4ee9c6d4 gssapi: enable gssapi-keyex in FIPS mode
All gssapi-keyex tests have to be disabled in Centos Stream 8
because the KEX is not allowed in FIPS. In Centos Stream 9,
only tests against OpenSSH have to be disabled because
OpenSSH only enables gssapi-keyex since Centos Stream 10.

Signed-off-by: Pavol Žáčik <pzacik@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-05 12:24:13 +01:00
Pavol Žáčik
d3e80d9a19 tests: test fallback to regular key exchange from gssapi-keyex
If the parties cannot agree on a gssapi-keyex method.

Signed-off-by: Pavol Žáčik <pzacik@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-05 12:24:13 +01:00
Pavol Žáčik
4d3da7819c bind: adjust hostkey error messages to be more precise
Signed-off-by: Pavol Žáčik <pzacik@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-05 12:24:13 +01:00
Pavol Žáčik
b79a681ebb auth: check for strdup allocation failure in ssh_userauth_gssapi_keyex
Signed-off-by: Pavol Žáčik <pzacik@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-05 12:24:13 +01:00
Pavol Žáčik
f7cad4245a tests: reenable wait in torture_gssapi_server_key_exchange_null
And setup a KDC server before pinging the server so we
can connect.

Signed-off-by: Pavol Žáčik <pzacik@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-05 12:24:13 +01:00
Pavol Žáčik
11c4b29e20 packet_cb: adjust response to NEWKEYS w.r.t. GSSAPI
Do not try to verify mic if gssapi-keyex was not performed,
and fix a memory leak of the mic on error.

Signed-off-by: Pavol Žáčik <pzacik@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-05 12:24:13 +01:00
Pavol Žáčik
e04d753ace gssapi: add null checks for session->gssapi before using it
These are not strictly necessary because we always check
that we performed GSSAPI KEX, but they won't hurt us.

Signed-off-by: Pavol Žáčik <pzacik@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-05 12:24:13 +01:00
Pavol Žáčik
06eea93ded packet: complete GSSAPI packet filter
Reject all GSSAPI-related messages when compiled
without GSSAPI support.

Signed-off-by: Pavol Žáčik <pzacik@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-05 12:24:13 +01:00
Pavol Žáčik
06edb2db5e options: replace SSH_OPTIONS_GSSAPI_KEY_EXCHANGE_ALGS example
The ECDH-based GSS KEX methods are more modern.

Signed-off-by: Pavol Žáčik <pzacik@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-05 12:24:13 +01:00
Pavol Žáčik
ced98d41cf doc: document support for gssapi-keyex and related KEX methods
Signed-off-by: Pavol Žáčik <pzacik@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-05 12:24:13 +01:00
Pavol Žáčik
88c2ea6752 gssapi: Add support for ECDH GSSAPI KEX
In particular, gss-nistp256-sha256-* and
gss-curve25519-sha256-*.

Signed-off-by: Pavol Žáčik <pzacik@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-05 12:24:13 +01:00
Pavol Žáčik
5fed1bc8be torture_packet: use SSH2_MSG_IGNORE type of test packet
With packet filtering now implemented for type 65,
the current test packet would be rejected, resulting
in failed tests.

Signed-off-by: Pavol Žáčik <pzacik@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-05 12:24:13 +01:00
Pavol Žáčik
a30ba0091f libgcrypt: make bignum_dup usable with const_bignum
Both gcry_mpi_copy and gcry_mpi_set take a pointer to
const gcry_mpi, which const_bignum is not.

Signed-off-by: Pavol Žáčik <pzacik@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-05 12:24:13 +01:00
Pavol Žáčik
ad23fe8c27 curve25519: Make ssh_curve25519_build_k public
This is necessary to reuse the function
in gss-curve25519-sha256-* KEX.

Signed-off-by: Pavol Žáčik <pzacik@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-05 12:24:13 +01:00
Pavol Žáčik
3710b31d24 session: Refactor ssh_get_publickey_hash
Make it use the one-shot API of hash functions,
and remove the FIPS restriction for OpenSSL 3.5+
where we can fetch the MD5 implementation from
a non-FIPS provider to use for non-crypto purposes.

Signed-off-by: Pavol Žáčik <pzacik@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-05 12:24:13 +01:00
Pavol Žáčik
2c5bb17211 md: Implement one-shot md5
Which can be used for non-cryptographic purposes
even in FIPS mode.

Signed-off-by: Pavol Žáčik <pzacik@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-05 12:24:13 +01:00
Jakub Jelen
83ae6b3f0a gssapi: reformat parts
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-05 12:24:13 +01:00
Jakub Jelen
06cefe1d67 packet: Implement packet filter for non-implemented GSSAPI messages
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-05 12:24:13 +01:00
Jakub Jelen
043b1fb133 Move GSSAPI KEX messages to be numerically sorted
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-05 12:24:13 +01:00
Gauravsingh Sisodia
f1490170f3 tests: add test for gssapi server key exchange with null hostkey and no tgt
Signed-off-by: Gauravsingh Sisodia <xaerru@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-05 12:24:13 +01:00
Gauravsingh Sisodia
4ba0746135 fix: some possible memory leaks
Signed-off-by: Gauravsingh Sisodia <xaerru@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-05 12:24:13 +01:00
Gauravsingh Sisodia
e94fd6ccd1 tests: add config tests for SSH_OPTIONS_GSSAPI_KEY_EXCHANGE
Signed-off-by: Gauravsingh Sisodia <xaerru@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-05 12:24:13 +01:00
Gauravsingh Sisodia
83114b636f fix: move ssh_gssapi_check_client_config() from ssh_options_set to ssh_options_apply
Signed-off-by: Gauravsingh Sisodia <xaerru@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-05 12:24:13 +01:00
Gauravsingh Sisodia
5a99cf9c7f refactor: remove extra else if branch for disable_hostkeys
Signed-off-by: Gauravsingh Sisodia <xaerru@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-05 12:24:13 +01:00
Gauravsingh Sisodia
213556ce01 reformat: some nits
Signed-off-by: Gauravsingh Sisodia <xaerru@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-05 12:24:13 +01:00
Gauravsingh Sisodia
5d06ee459b refactor: remove issue link from .gitlab-ci.yml
Signed-off-by: Gauravsingh Sisodia <xaerru@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-05 12:24:13 +01:00
Gauravsingh Sisodia
96807b9313 tests: add valgrind suppressions
Signed-off-by: Gauravsingh Sisodia <xaerru@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-05 12:24:13 +01:00
Gauravsingh Sisodia
6d81ecddbe fix: replace pthread_exit in gssapi tests
Signed-off-by: Gauravsingh Sisodia <xaerru@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-05 12:24:13 +01:00
Gauravsingh Sisodia
d0e5cf78d0 fix: use strcmp instead of strncmp to avoid prefix match
Signed-off-by: Gauravsingh Sisodia <xaerru@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-05 12:24:13 +01:00
Gauravsingh Sisodia
a0707afc3e reformat: gssapi key exchange
Signed-off-by: Gauravsingh Sisodia <xaerru@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-05 12:24:13 +01:00
Gauravsingh Sisodia
06b61f75fa feat: implement packet filter for SSH2_MSG_KEXGSS_COMPLETE
Signed-off-by: Gauravsingh Sisodia <xaerru@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-05 12:24:13 +01:00
Gauravsingh Sisodia
f9d7cadf4b fix: create fopen wrapper and block default hostkey paths
Signed-off-by: Gauravsingh Sisodia <xaerru@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-05 12:24:13 +01:00
Gauravsingh Sisodia
c1aab9903f feat: add null hostkey for server
fix: skip gssapi tests in fips mode

fix: skip gssapi_key_exchange_null test on ubuntu and tumbleweed

fix: return early when rc != 0 to show error

tests: replace int asserts by ssh return code asserts

fix: add fatal error when hostkeys are not found and gssapi kex is not enabled

ci: add comment linking gssapi null kex bug in ubuntu and tumbleweed

fix: don't specify hostkeys in config instead of deleting files

tests: assert kex method was null

refactor: remove redundant include

refactor: better error message

fix: check null before accessing in gssapi.c

fix: allow setting no hostkeys
Signed-off-by: Gauravsingh Sisodia <xaerru@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-05 12:24:13 +01:00
Gauravsingh Sisodia
fd1c3e8878 feat: test null hostkey on ci
Signed-off-by: Gauravsingh Sisodia <xaerru@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-05 12:24:13 +01:00
Gauravsingh Sisodia
d730b40b91 feat: add SSH2_MSG_KEXGSS_HOSTKEY support to client and server
Signed-off-by: Gauravsingh Sisodia <xaerru@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-05 12:24:13 +01:00
Gauravsingh Sisodia
9044fcdb52 feat: add "gssapi-keyex" for server
feat: add negative auth client tests, and more key exchange server tests

feat: add function for checkinf if GSSAPI key exchange was performed
Signed-off-by: Gauravsingh Sisodia <xaerru@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-05 12:24:13 +01:00
Gauravsingh Sisodia
bc5211d055 feat: add gssapi key exchange
feat: add generic functions for importing name and initializing ctx

feat: add suffix to gsskex algs dynamically

feat: move gssapi key exchange to another file

feat: add gssapi key exchange for server

refactor: remove unnecessary fields in gssapi struct

refactor: add some documentation and improve logging

fix: remove gss_dh callbacks

feat: add a check to see if GSSAPI is configured correctly

fix: memory leaks

feat: add client side "gssapi-keyex" auth

feat: add gssapi_key_exchange_algs for server

fix: some memory issues

feat: add gssapi kex options to config

feat: add check to see if GSSAPI key exchange was performed

feat: add more tests for gssapi key exchange

fix: add valgrind supp

Signed-off-by: Gauravsingh Sisodia <xaerru@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-05 12:24:00 +01:00
Jakub Jelen
701a2155a7 tests: Improve test coverage of comparing certificates
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-05 12:21:43 +01:00
Jakub Jelen
38f3d158f6 pki: Fix comparing public key of certificate
When the first key object is a certificate object, this match will
fall through to the generic key comparison that is unable to handle
the ed25519 keys and fails.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-05 12:21:43 +01:00
Jakub Jelen
0d5a2652b4 pki: Avoild false positive matches when comparing certificates in mbedtls and gcrypt
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-05 12:21:43 +01:00
Jakub Jelen
5c496acef7 pkd: Run openssh client with SK keys
Fixes: #331

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Pavol Žáčik <pzacik@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-05 12:20:28 +01:00
Jakub Jelen
3e074a3fba tests: Use standard way of setting cmake variables
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Pavol Žáčik <pzacik@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-05 12:20:28 +01:00
Samir Benmendil
98a844ceb2 tidy(unittests): zero-init config string pointers
Signed-off-by: Samir Benmendil <me@rmz.io>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-02 21:44:45 +00:00
Samir Benmendil
ce45ba8c61 tests: suppress leaks from NSS modules
Signed-off-by: Samir Benmendil <me@rmz.io>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-02 14:34:11 +00:00
Samir Benmendil
62c85a59a9 ssh_client: Return non-zero on config parsing failure
Signed-off-by: Samir Benmendil <me@rmz.io>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-02 14:34:11 +00:00
Samir Benmendil
c4f1a70a89 connect: Support AddressFamily option
* allow parsing of AddressFamily in config and cli
  * supports options "any", "inet" and "inet6"
* introduce SSH_OPTIONS_ADDRESS_FAMILY

Signed-off-by: Samir Benmendil <me@rmz.io>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-02 14:34:11 +00:00
Jakub Jelen
f52be27114 connect: Improve logging around the connection code
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-02 14:34:11 +00:00
Jakub Jelen
228208af5e Happy new year 2026!
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2026-01-02 14:36:19 +01:00
Jakub Jelen
163373c9d9 tests: Reproducer for missing value to LogLevel
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-12-19 22:08:15 +01:00
Jakub Jelen
e82677a923 config: Fix error paths of configuration parsing
Thanks coverity, oss-fuzz and Ram-Z reporting this independently.

CID 1643770

https://oss-fuzz.com/issue/4969113899565056
https://oss-fuzz.com/issue/6448013813022720

Fixes up 1833ce86f9.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-12-19 22:08:15 +01:00
Nikhil V
79966eb924 fix : modify ssh_connector_free to accept NULL values
Signed-off-by: Nikhil V <nikhilgreyshines@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-12-18 13:44:05 +01:00
Nikhil V
4feb0dd79d Improve doxygen documentation
Signed-off-by: Nikhil V <nikhilgreyshines@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-12-18 13:44:05 +01:00
nikhil-nari
f8d943afda Improve doxygen docs
Signed-off-by: Nikhil V <nikhilgreyshines@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-12-18 13:44:05 +01:00
Pavol Žáčik
4bad7cc08f hybrid_mlkem: Convert ECDH shared secret to a fixed-size string
The shared secret is derived as bignum, and draft-ietf-sshm-mlkem-hybrid-kex
mandates that it is converted to a fixed-size byte array. Not doing this
would lead to incompatibilities with other implementations when the derived
shared secret happens to start with zero bytes.

Signed-off-by: Pavol Žáčik <pzacik@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-12-17 14:51:29 +01:00
Mike Frysinger
3526e02dee use standard O_NONBLOCK naming
Systems define O_NONBLOCK & O_NDELAY as the same thing.  POSIX however
only defines O_NONBLOCK.  Rename the current define to be portable.

Signed-off-by: Mike Frysinger <vapier@chromium.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-12-12 18:18:02 +01:00
abdallah elhdad
ecea5b6052 Support new '-o' option parsing to client
Signed-off-by: abdallah elhdad <abdallahselhdad@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-12-12 18:15:42 +01:00
abdallah elhdad
1833ce86f9 refactor auth options handler
Signed-off-by: abdallah elhdad <abdallahselhdad@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-12-12 18:15:41 +01:00
abdallah elhdad
3938e5e850 set log level when debug option is increased
Signed-off-by: abdallah elhdad <abdallahselhdad@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-12-12 18:15:40 +01:00
Norbert Pocs
dd80a56029 libcrypto.c: Use openssl const algorithm names
Use the openssl constants algorithm names instead of string
representations. They should not change, but it's clearer to have it
this way.

Signed-off-by: Norbert Pocs <norbertpocs0@gmail.com>
Signed-off-by: Norbert Pocs <norbertp@openssl.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-12-12 18:12:13 +01:00
Jakub Jelen
9d6df9d0fa ssh_known_hosts_get_algorithms: Simplify cleanup ...
...  and prevent memory leak of host_port on memory allocation failure.

Thanks Xiaoke Wang for the report!

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Pavol Žáčik <pzacik@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-12-12 18:06:47 +01:00
Jakub Jelen
ee180c660e server: Check strdup allocation failure
Thanks Xiaoke Wang for the report!

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Pavol Žáčik <pzacik@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-12-12 18:06:45 +01:00
abdallah elhdad
541cd39f14 zeroize sensitive buffers in ssh_sntrup761x25519_build_k
Signed-off-by: abdallah elhdad <abdallahselhdad@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-12-12 18:03:21 +01:00
abdallah elhdad
64f72ed55f Replace explicit_bzero with ssh_burn
Signed-off-by: abdallah elhdad <abdallahselhdad@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-12-12 18:03:19 +01:00
Pavol Žáčik
0ef79018b3 kex: Implement remaining hybrid ML-KEM methods
This builds on top of a9c8f94. The pure ML-KEM
code is now separated from the hybrid parts,
with the hybrid implementation generalized to
support NIST curves.

Signed-off-by: Pavol Žáčik <pzacik@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-11-25 17:57:42 +01:00
Pavol Žáčik
7911580304 ecdh: Factor out keypair generation
This adds a new internal API function (ssh_ecdh_init),
similar to how it's done in curve25519 implementation.
The new function can be used in hybrid key exchange
constructions.

Signed-off-by: Pavol Žáčik <pzacik@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-11-25 17:57:41 +01:00
Andreas Schneider
e5108f2ffc docs: Use a modern doxygen theme
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-11-21 17:49:52 +01:00
Andreas Schneider
5ce4b65abb cmake: Add .cmake-format.yaml
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-11-21 17:49:52 +01:00
Andreas Schneider
b62675b435 chore(editorconfig): Put CMakeLists.txt in its own section
This is read by neocmakelsp for formatting.

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-11-21 17:49:52 +01:00
Jakub Jelen
f333d95013 ci: Avoid repetitive definitions
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-11-19 17:31:53 +01:00
Jakub Jelen
92d0f8aba6 ci: Remove GSSAPI from minimal build
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-11-19 17:31:37 +01:00
Jakub Jelen
66460578b1 ci: Remove marco from the whitelist
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-11-19 17:31:37 +01:00
Jakub Jelen
b93db6c3d1 ci: Replace ad-hoc exports with variables
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-11-19 17:31:37 +01:00
Jakub Jelen
1c3143ff00 ci: Add cmocka.cfg to avoid false positives reports from csbuild
Based on cmocka changes:

https://gitlab.com/cmocka/cmocka/-/blob/master/cppcheck/cmocka.cfg

https://gitlab.com/cmocka/cmocka/-/blob/master/.gitlab-ci.yml#L148

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-11-19 17:31:31 +01:00
Praneeth Sarode
47305a2f72 docs(fido2): add FIDO2/U2F security key support chapter to documentation
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
2025-11-13 15:28:23 +05:30
Praneeth Sarode
5bbaecfaa7 feat(pki): extend the sshsig API to support security keys along with tests
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
2025-11-13 15:28:14 +05:30
Praneeth Sarode
6e5d0a935f tests(fido2): add tests for SK ECDSA and SK Ed25519 public key authentication
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
2025-11-13 15:27:48 +05:30
Praneeth Sarode
5d4d9f8208 tests(rsa): add test for RSA key generation using the newer ssh_pki_generate_key API
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
2025-11-13 15:27:48 +05:30
Praneeth Sarode
c128cf8807 tests(pki): add torture tests for pki_sk functions
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
2025-11-13 15:27:48 +05:30
Praneeth Sarode
5937b5ba4e feat(torture_sk): add functions to validate security key signatures and to create PKI context
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
2025-11-13 15:27:48 +05:30
Praneeth Sarode
1241a3a8c9 tests(fido2): add sk-dummy support to the testing infrastructure
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
2025-11-13 15:27:48 +05:30
Praneeth Sarode
21d338737a tests(fido2): add sk key files to the testing infrastructure
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
2025-11-13 15:27:48 +05:30
Praneeth Sarode
d91630308d pki: add security key identities to session options
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
2025-11-13 15:27:48 +05:30
Praneeth Sarode
37f0e91814 feat(pki): add security key support with enrollment, signing, and resident key loading functions
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
2025-11-13 15:27:36 +05:30
Praneeth Sarode
32a256e157 feat(pki): add ssh_key getters to retrieve security key flags, application, and user ID
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
2025-11-13 15:11:53 +05:30
Praneeth Sarode
14bd26e71c feat(pki): add support for user ID in ssh_key structure
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
2025-11-13 15:11:53 +05:30
Praneeth Sarode
97e71606e0 feat(pki): add ssh_pki_ctx to ssh_session
The session struct now contains an ssh_pki_ctx struct as its member to allow for passing user configured pki options across many functions.
The ssh_options_set API has been extended to allow users to set this member.

Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
2025-11-13 15:11:53 +05:30
Praneeth Sarode
d4b0de702b feat(pki): implement PKI context API
A new generic struct is introduced which contains the various configuration options that can be used by pki operations.
API functions have been provided to configure all the options.

Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
2025-11-13 15:11:53 +05:30
Praneeth Sarode
acc080ac03 tests(fido2): add tests for the usb-hid security key callbacks
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
2025-11-13 15:11:46 +05:30
Praneeth Sarode
e56af9fa79 feat(torture_sk): add validation functions for security key callback responses and resident keys
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
2025-11-09 05:52:48 +05:30
Praneeth Sarode
c4b2bd34a8 feat(torture): add torture_get_sk_pin function to retrieve PIN from environment
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
2025-11-09 05:52:48 +05:30
Praneeth Sarode
50ee6411f2 fido2: implement the default sk_callbacks for FIDO2/U2F keys using the usb-hid protocol
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
2025-11-09 05:52:45 +05:30
Praneeth Sarode
c1dd30b47b fido2: add helper functions for writing FIDO2/U2F callbacks
Add some common helper functions that can be used by any developer
writing callbacks for interacting with FIDO2/U2F devices.

Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
2025-11-09 05:04:38 +05:30
Praneeth Sarode
8ba9e931e8 fido2: declare callbacks for sk operations
Declare ssh_sk_callbacks_struct so that the users can define custom functions as callbacks for interacting with FIDO2/U2F devices.

Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
2025-11-09 05:04:38 +05:30
Praneeth Sarode
eda5c6576b tests(torture_sk): validate sk_flags against allowed security key flags
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
2025-11-09 05:04:38 +05:30
Praneeth Sarode
302d868875 fido2: add sk_api.h
The sk_api.h file added is a copy of the sk-api.h file in openSSH, including only the struct and constant definitions.
This has been done to ensure compatibility with any security key middleware developed for openSSH.

Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
2025-11-09 05:04:38 +05:30
Praneeth Sarode
7db75e8fd0 ci: enable FIDO2/U2F support in some images
Build with WITH_FIDO2=ON in the default fedora, tumbleweed, centos, ubuntu, and visualstudio images.

Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
2025-11-09 05:04:38 +05:30
Praneeth Sarode
ebe632cf8f cmake: add build option to enable FIDO2/U2F support
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
2025-11-09 05:04:38 +05:30
Praneeth Sarode
150d606db7 cmake: add cmake module to find libfido2
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
2025-11-09 05:04:37 +05:30
Jakub Jelen
63fbf00efe pki: Use constant for minimal RSA key size in FIPS
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-11-06 16:25:25 +01:00
Jakub Jelen
ae33ced0dc coverage: Ignore parse errors again
Without this, the gcov is crashing with some suspicious coverage reports on
functions like `uint32_divmod_uint14()` from internal sntrup implementation.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-11-06 16:25:25 +01:00
Jakub Jelen
ee6e2c69e1 Bump minimal RSA key size to 1024
Fixes: #326

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-11-06 16:25:25 +01:00
Jakub Jelen
cefc4f8c97 pkd: Run tests with ecdsa and ed25519 keys with dropbear
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-11-06 16:25:25 +01:00
Jakub Jelen
b64e7f67d3 pkd: Run ed25519 tests with dropbear
Resolves: #336

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-11-06 16:25:25 +01:00
Jakub Jelen
491cd81a32 kex: Place PQC KEX methods first
The ML-KEMx25519 is now preferred algorithm in OpenSSH so follow the suit

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-11-06 16:24:47 +01:00
Jakub Jelen
3444f4c449 Remove references to (unused) pre-release ssh messages SSH2_MSG_ECMQV_*
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-11-06 16:24:47 +01:00
Pavol Žáčik
80541ab828 mlkem768: Fix missing jumps in error handling
Signed-off-by: Pavol Žáčik <pzacik@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-11-06 12:10:03 +01:00
Jakub Jelen
b042477f83 Suppress remaining OpenSSL 3.5 memory leaks
Reported as

https://github.com/openssl/openssl/issues/29077

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-11-05 17:52:24 +01:00
Jakub Jelen
950abbbd81 tests: Remove the -E which is overridden by followed -E on ctest CLI
The threads_pki_rsa was running and working under valgrind for some
time already without anyone noticing this syntax does not work.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-11-05 17:52:24 +01:00
Jakub Jelen
b9c6701c68 tests: Avoid needless pthread_exit()
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-11-05 17:52:24 +01:00
Jakub Jelen
a94df4bb8f tests: Adjust valgrind supressions for Fedora 43
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-11-05 17:52:24 +01:00
Pavol Žáčik
41b8b3326c client: Reset session packet state on disconnect
When reusing session structures for multiple
connections, the packet state could be SIZE_READ
before disconnect, causing initial packets of the
next connection to be misinterpreted.

Signed-off-by: Pavol Žáčik <pzacik@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-11-05 17:44:33 +01:00
Sahana Prasad
a9c8f942a5 kex: Implement mlkem768x25519-sha256
The implementation largely follows that of sntrup761x25519-sha512.

Most of the work was done by Sahana with the help of Claude,
Pavol provided fixes to match specs and did a final clean up.

Co-Authored-By: Sahana Prasad <sahana@redhat.com>
Co-Authored-By: Pavol Žáčik <pzacik@redhat.com>
Co-Authored-By: Claude <noreply@anthropic.com>

Signed-off-by: Pavol Žáčik <pzacik@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-11-05 17:44:33 +01:00
Jakub Jelen
d307bfa239 pki_crypto: Avoid potential memory leak if malloc fails
Thanks oss-fuzz and nalloc.

https://issues.oss-fuzz.com/issues/449101878

Thanks Andreas for review and nugging into rewriting it to something readable.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-11-04 16:08:58 +01:00
Mike Frysinger
66e8491f73 ttyopts: make non-POSIX defines optional
This file uses a bunch of defines that, while common, are not in POSIX.
https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/termios.h.html

Add more ifdef checks around them to fix building on platforms that omit
them.

Signed-off-by: Mike Frysinger <vapier@chromium.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-11-04 14:46:58 +01:00
Mike Frysinger
e93c1f6a61 libcrypto: update EVP API usage
The EVP_CIPHER_CTX_init API is deprecated and doesn't exist in some
OpenSSL versions.  Switch to EVP_CIPHER_CTX_reset which works with
1.1.x which is the min version libssh requires.

Signed-off-by: Mike Frysinger <vapier@chromium.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-11-04 14:45:39 +01:00
Jakub Jelen
358553e976 scp: Workaround for Cisco devices not handling single quotes
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-10-10 16:20:54 +02:00
Jakub Jelen
07d099f652 examples: Support passing port to libssh_scp to simplify testing
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-10-10 16:20:53 +02:00
Praneeth Sarode
f3d70e54e9 tests(string): add tests for ssh_string_from_data function
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-10-10 14:00:22 +02:00
Praneeth Sarode
74d1bf51b5 feat(string): add ssh_string_from_data function to create ssh_string from data buffer
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-10-10 14:00:22 +02:00
Jakub Jelen
00f1d6fac2 Add RequiredRsaSize configuration option
to both client and server configuration file

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-10-01 16:06:43 +02:00
Jakub Jelen
029754efb3 examples: Reformat
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-10-01 16:04:59 +02:00
Jakub Jelen
a49e0c2a84 examples: Replace magic numbers with FD constants
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-10-01 16:04:58 +02:00
Jakub Jelen
8966e577ab connector: Improve logging
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-10-01 16:04:57 +02:00
Jakub Jelen
dc45b8f3f1 channels: Improve logging information about channels
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-10-01 16:04:56 +02:00
Jakub Jelen
c932790b82 connector: Fix default connector flags
Originally reported by Jeremy Cross <jcross@beyondtrust.com> in #461

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-10-01 16:04:55 +02:00
Jakub Jelen
8a0aa17bca connector: Reformat
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-10-01 16:04:55 +02:00
Jakub Jelen
ecb11f1a18 tests: Fix wording in comment to make sense
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-10-01 16:04:54 +02:00
Jakub Jelen
6aea779918 sftpserver: Fix loop termination
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-10-01 16:03:46 +02:00
Jakub Jelen
a51384fe4e sftpserver: Remove some needless parts
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-10-01 16:03:45 +02:00
Jakub Jelen
c55140272f examples: Add more flexibility to set verbosity
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-10-01 16:03:44 +02:00
Jakub Jelen
607dad040b mbedtls: Warn about missing featues of mbedTLS build
The libssh requires mbedTLS to have support for threading. Given the
way how the mbedTLS builds are configured (at least to my limited
understanding), by modifying mbedtls_config.h header file, this
changes the silent failure to a message on stderr pointing the
user in the right direction.

Fixes: #304

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-09-30 13:16:34 +02:00
Praneeth Sarode
55bb909252 refactor(pki): separate the sk signature buffer packing to a separate function
The logic for creating the buffer to be verified from an sk signature from ssh_pki_signature_verify has been separated into a new function named pki_prepare_sk_signature_buffer to allow for convenient reuse of this logic.

Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-09-30 12:42:56 +02:00
Praneeth Sarode
08cbbea461 pki: update RSA key generation to use default size when parameter is 0
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-09-25 15:04:57 +02:00
Praneeth Sarode
8c4e337ab7 pki: define RSA_DEFAULT_KEY_SIZE
Define a new constant for the default RSA key size for consistency.

Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-09-25 15:04:56 +02:00
Praneeth Sarode
8541b6584f test(buffer): add unit tests for ssh_buffer_dup function
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-09-25 15:04:18 +02:00
Praneeth Sarode
2f77727796 feat(buffer): add ssh_buffer_dup function to duplicate existing buffers
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-09-25 15:04:17 +02:00
Jakub Jelen
a3c5d3b256 tests: Rewrite all fuzzers to LLVMFuzzerInitialize and nalloc
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-09-25 15:03:07 +02:00
Philippe Antoine
59a502ede6 fuzz: test allocations failures
Signed-off-by: Philippe Antoine <p.antoine@catenacyber.fr>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-09-25 15:03:04 +02:00
Francesco Rollo
c94e2efcf1 fix(bind): Remove code duplication in ssh_bind_listen
Signed-off-by: Francesco Rollo <eferollo@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-09-18 13:57:12 +02:00
Jakub Jelen
3d3b12891f tests: Avoid prefix matching when selecting algorithmms
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-09-10 13:05:50 +02:00
Jakub Jelen
6ca59307d4 Add non-namespaced alias sntrup761x25519-sha512 that is being standardized
The specification is now in the last call, data point is allocated so there is
no need to stick to the namespaces alias anymore

https://datatracker.ietf.org/doc/draft-ietf-sshm-ntruprime-ssh/

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-09-10 12:23:08 +02:00
Praneeth Sarode
e8bbd194c7 refactor(pki): Define RSA_MIN_KEY_SIZE and update related checks
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-09-09 12:53:43 +02:00
Jakub Jelen
df4e907dff poll: Use is_locked helper where possible
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-08-14 10:33:58 +02:00
Philippe Antoine
c99261437f socket: do not free poll object if it is locked
As it may a cause a use after free if `send` fails when
ssh_poll_ctx_dopoll does its callback
ssh_poll_ctx_dopoll still wants to use the poll object later

Signed-off-by: Philippe Antoine <p.antoine@catenacyber.fr>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-08-14 10:33:57 +02:00
Andreas Schneider
53ac23ded4 CVE-2025-8114: Fix NULL pointer dereference after allocation failure
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-08-14 10:32:55 +02:00
Jakub Jelen
ffed80f8c0 CVE-2025-8277: mbedtls: Avoid leaking ecdh keys
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-08-14 10:32:24 +02:00
Jakub Jelen
9ada7aa0e4 CVE-2025-8277: wrapper: Free cv25519 private key on cleanup
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-08-14 10:32:19 +02:00
Jakub Jelen
d357a9f3e2 tests: Invoke all combinations of wrong guesses during rekey
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-08-14 10:32:13 +02:00
Jakub Jelen
c9d95ab0c7 CVE-2025-8277: ecdh: Free previously allocated pubkeys
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-08-14 10:32:10 +02:00
Francesco Rollo
ccff22d378 CVE-2025-8277: Fix memory leak of unused ephemeral key pair after client's wrong KEX guess
Signed-off-by: Francesco Rollo <eferollo@gmail.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-08-14 10:32:05 +02:00
Jakub Jelen
4310a696f2 CVE-2025-8277: packet: Adjust packet filter to work when DH-GEX is guessed wrongly
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-08-14 10:31:51 +02:00
Jakub Jelen
771e19a7a9 tests: Enable all key exchange methods in ssh_ping
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-08-14 10:31:30 +02:00
Jakub Jelen
118a747acd socket: Free poll handle when resetting socket state
Since 07cb0be12 we are not closing the user provided FDs,
but the above change also resulted in memory leak during
ssh_disconnect that left the poll_handle allocated during
reset.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-08-12 12:13:31 +02:00
Jakub Jelen
5691e0f609 poll: Initialize ssh_poll_handle pointers
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-08-12 12:13:31 +02:00
Jakub Jelen
5a6e2fd02a poll: Fix memory leak on failed realloc()
In cases where this is the initial allocation, the shrinking of the polltrs
buffer would result in 0B realloc, which really does not make sense. Also,
when this second realloc fails, the memory is never freed as the outer code
believes there is nothing allocated on the poll_ctx

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-08-12 12:13:31 +02:00
Jakub Jelen
e8099375fe poll: Check return value of ssh_poll_ctx_add()
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-08-12 12:13:27 +02:00
Jakub Jelen
d00f267bc6 Make ssh_socket_set_fd() return errors
and properly check the return value where it is used

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-08-12 12:12:47 +02:00
Jakub Jelen
35d337834b options: Avoid memory leaks on allocation failures
When allocation during tilde expansion fails, libssh could
leak a memory.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-08-12 12:12:47 +02:00
Jakub Jelen
ba1e8303f8 reformat remains of poll.c
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-08-12 12:12:43 +02:00
Jakub Jelen
ef50a3c0f0 tests: Remove tests of operations on freed channels
These tests are flaky because even though the care was taken to guess if
the ssh_channel_free() really freed the channel, it might not always be correct
and call to operation on the freed channel results in use after free.

Generally, no operation should be called after the channel is freed by the user.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-08-06 11:18:45 +02:00
Jakub Jelen
e7cffe7e1b pki: Simplify ed25519 private key duplication
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-08-06 11:18:20 +02:00
Jakub Jelen
d1bf9068a9 Use calloc instead of zeroizing structure after malloc
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-08-06 11:16:58 +02:00
Jakub Jelen
737f9ecc3c agent: Reformat the rest of the file
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-08-06 11:16:58 +02:00
Praneeth Sarode
cc667021e5 tests(pki): add torture tests for security keys
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-08-01 15:28:58 +05:30
Praneeth Sarode
f9f8c939bc tests(pki): add security key testing helper functions to torture library
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-08-01 15:28:54 +05:30
Praneeth Sarode
aab6ce364a tests(pki): add sk type keys to the testing infrastructure
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-08-01 15:28:41 +05:30
Praneeth Sarode
0cec257077 pki: add security key file import/export functionality
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-08-01 15:28:36 +05:30
Praneeth Sarode
957efe51a2 format(pki): format the pki_import_privkey_buffer function
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-08-01 00:29:27 +05:30
Praneeth Sarode
bb85492d4f feat(pki): add support for SK key types in signature handling
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-07-30 23:00:53 +05:30
Praneeth Sarode
22c1b6970c pki: add security key fields to ssh_key_struct and update compare, copying and cleaning functions
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-07-30 22:47:59 +05:30
Praneeth Sarode
09155adb19 tests(string): add unit tests for ssh_string_cmp function
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-07-30 16:06:32 +02:00
Praneeth Sarode
95f8cbc7f0 feat(string): add ssh_string_cmp function for comparing ssh_strings
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-07-30 16:06:31 +02:00
Praneeth Sarode
3423399f98 fix(pki): remove redundant key type_c assignment in pki_import_pubkey_buffer
We already assign the correct key type_c using ssh_key_type_to_char before this point.

Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-07-30 16:05:52 +02:00
Praneeth Sarode
ccbec9c275 fix(pki): remove redundant key type_c assignment in build pubkey and privkey functions
Whenever the pki_pubkey_build_ecdsa and pki_privkey_build_ecdsa functions are called, the key type assignment is already done. So, we don't need to assign it again. Moreover, because the pki_key_ecdsa_nid_to_name function was used, for key types like the SSH_KEYTYPE_SK_ECDSA, we assign the wrong type string to the key, based on the nid.

Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-07-30 16:05:51 +02:00
Praneeth Sarode
ed52c88a03 feat(misc): add burn_free function and BURN_FREE macro for secure memory deallocation
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-07-30 12:35:12 +02:00
Till Wimmer
0f0ac314d2 session: add err messages for most common WSA error codes (+ applied clang-format to file)
Signed-off-by: Till Wimmer <github@tonarchiv.ch>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
2025-07-30 12:33:42 +02:00
Navid Fayezi
95e4c39e8a Refactor: fix inconsistency in ssh_callback_struct
Signed-off-by: Navid Fayezi <navidfayezi.98@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-07-30 12:31:07 +02:00
Jakub Jelen
8c89633a45 pki: Avoid possible memory leak
Actually the condition was duplicated at the beginning of the function and this
one could not be hit (again), but it is an error to be fixed anyway.

Thanks Coverity!

CID 1618865

CID 1618864

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-07-29 15:39:37 +02:00
Rémi Coulom
8069679033 remove unused ssh_string in ssh_channel_open_forward_unix
Signed-off-by: Rémi Coulom <remi.coulom@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-07-25 19:52:37 +02:00
Jakub Jelen
c2e9d39dbe tests: Fix build script to work also on MacOS correctly
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-07-25 16:40:56 +02:00
Jakub Jelen
ab44f606b2 tests: Add more valgrind supressions for krb5
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-07-25 13:20:15 +02:00
Jakub Jelen
444982b38a tests: Avoid needless call to pthread_exit()
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-07-25 13:20:15 +02:00
Jakub Jelen
3df61a4e86 pkd: Cleanup OpenSSL context
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-07-25 13:20:15 +02:00
Jakub Jelen
961c79637c options: Fix possible memory leaks on error conditions when setting keys for bind
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-07-25 13:20:15 +02:00
Jakub Jelen
7eefbbd478 tests: Cleanup OpenSSL in the forked server processes
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-07-25 13:20:15 +02:00
Jakub Jelen
c4c28c6473 tests: Skip test leaking handle under valgrind
This is leaking memory allocated in process_open(), which is stored in the
handles list in the sftpserver session. Given that the data is provided by the
use callbacks, we can not universally free them on our side, but we should, in
the long term, introduce some way for the implementers to free outstanding
handles that were not closed by misbehaving clients.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-07-25 13:20:15 +02:00
Jakub Jelen
08a32ac381 tests: Cleanup OpenSSL in tests when GSSAPI is built
also from the fuzzer tests

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-07-25 13:20:15 +02:00
Jakub Jelen
62762bbbc9 Cleanup the loaded pkcs11 provider
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-07-25 13:20:15 +02:00
Jakub Jelen
ab3e08c2b5 Finalize OpenSSL context from tests to make the valgrind output clean
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-07-25 13:20:15 +02:00
Jakub Jelen
809898b980 tests: Adjust valgrind supression to match new calls stack
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-07-25 13:20:15 +02:00
Jakub Jelen
51bd08027e CentOS 9 and 10 were updated to OpenSSL 3.5
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-07-25 13:20:15 +02:00
Praneeth Sarode
0b4b71cc11 fix(callbacks): make is_callback_valid's behaviour consistent with its name
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-07-24 16:10:54 +02:00
Praneeth Sarode
5d3ef7261c refactor(callbacks): reformat to improve readability
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-07-24 16:10:53 +02:00
Jakub Jelen
9817392e26 pkd: Run hmac-sha1 tests with OpenSSH
This was initially in hurry disabled in
ca4c874a9e because dropbear dropped support for
these HMACs. The follow-up commit enabled running these tests on old dropbear in
c17112f070, but still did not run them on openssh,
when the new dropbear was installed.

This fixes up the above commit to run the HMAC-SHA1 tests with OpenSSH even if
the new dropbear is installed.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-07-24 16:09:55 +02:00
Nguyễn Thái Ngọc Duy
168302b9d6 Fix ssh_handle_key_exchange() timeout
See libssh-mirror#311 for background. But in some case, it's possible to
trigger the code in ssh_handle_key_exchange() to move session state
directly to SSH_SESSION_STATE_AUTHENTICATED. The exit condition for this
function is SSH_SESSION_STATE_AUTHENTICATING though, so when it happens,
ssh_handle_key_exchange() will time out eventually.

The fix is straightforward. Tested with the problematic
client (trilead-ssh2) and made sure the bad condition happened (and not
cause timeout)

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-07-24 13:08:46 +02:00
Jakub Jelen
82c8bbc504 tests: Add missing header file to unbreak build on freebsd
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-07-24 11:13:35 +02:00
Jakub Jelen
1ea1782036 Add simple sshsig fuzzer
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-07-24 11:13:34 +02:00
abdallah elhdad
c17112f070 Enable HMAC SHA1 tests for dropbear <2025.87
Signed-off-by: abdallah elhdad <abdallahselhdad@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-07-24 10:49:51 +02:00
Nicolas Graves
28c0056bca Add logging for private API functions
Signed-off-by: Nicolas Graves <ngraves@ngraves.fr>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
2025-07-10 11:21:44 +02:00
Nicolas Graves
7e4f08e22a Add logging to public API functions
Signed-off-by: Nicolas Graves <ngraves@ngraves.fr>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
2025-07-10 11:21:44 +02:00
Nicolas Graves
aeb0b2ec6f Add unittests for sshsig functions
Signed-off-by: Nicolas Graves <ngraves@ngraves.fr>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
2025-07-10 11:21:44 +02:00
Nicolas Graves
67cf8e3702 Implement sshsig functions
Signed-off-by: Nicolas Graves <ngraves@ngraves.fr>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
2025-07-02 14:38:07 +02:00
Nicolas Graves
309f36fa83 pki: Add key_to_type_hash helper
Signed-off-by: Nicolas Graves <ngraves@ngraves.fr>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
2025-07-02 14:38:07 +02:00
Praneeth Sarode
7a2a743a39 fix(string): handle empty string case in ssh_string_copy
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-07-02 13:58:51 +02:00
Theo Buehler
ccb8cf88c8 Unbreak torture_config_make_absolute() on OpenBSD
The torture_config_make_absolute() and its _no_sshdir() version both
segfault on OpenBSD. The reason for this is that the storage returned
by getpwuid() is backed by mmap and is unapped by the getpwnam() call
in ssh_path_expand_tilde(), so a later access to home segfaults. The
possibility of this happening (getpwnam() overwriting values returned
by getpwuid()) is explicitly called out in POSIX.

A simple fix is to work with copies of username and homedir.

Signed-off-by: Theo Buehler <tb@openbsd.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-07-01 20:50:25 +02:00
Praneeth Sarode
b43392c31d tests(string): add unit tests for ssh_string functions
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-07-01 20:49:39 +02:00
Andreas Schneider
5fc65e7270 agent: Fix resource leak
CID 1611718

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-07-01 20:48:52 +02:00
Navid Fayezi
8310b8cc2b Remove redundant line and change strlen(buffer) to sizeof(buffer) in examples/authentication.c
Signed-off-by: Navid Fayezi <navidfayezi.98@gmail.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-07-01 20:47:55 +02:00
Navid
b0063b52d8 Remove more redundant casts
Signed-off-by: Navid Fayezi navidfayezi.98@gmail.com
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-07-01 20:38:03 +02:00
Navid
33a947dcb0 Remove unnecessary char* cast in memset call in examples/examples_common.h
Signed-off-by: Navid Fayezi navidfayezi.98@gmail.com
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-07-01 20:38:03 +02:00
Jakub Jelen
72c282434b dh-gex: Reformat the dhgex_server_callbacks structure
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-24 10:14:29 +02:00
Jakub Jelen
ba9642882d dh-gex.c: Fix typo in the constant name
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-24 10:14:25 +02:00
Jakub Jelen
a6b73219e2 packet: Implement missing packet filter for DH GEX
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-24 10:14:21 +02:00
Jakub Jelen
e2afe196d8 CVE-2025-5372 libgcrypto: Simplify error checking and handling of return codes in ssh_kdf()
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-23 15:24:30 +02:00
Jakub Jelen
32833b40bc libgcrypto: Reformat ssh_kdf()
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-23 15:24:30 +02:00
Jakub Jelen
bc4804aa9b CVE-2025-5987 libcrypto: Correctly detect failures of chacha initialization
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-23 15:24:30 +02:00
Jakub Jelen
acb158e827 CVE-2025-5351 pki_crypto: Avoid double-free on low-memory conditions
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-23 15:24:30 +02:00
Jakub Jelen
faf9caafc6 pki_crypto: Reformat pki_key_to_blob()
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-23 15:24:30 +02:00
Jakub Jelen
8dc29f140b CVE-2025-4878 legacy: Properly check return value to avoid NULL pointer dereference
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-23 15:24:30 +02:00
Jakub Jelen
7501ca1e08 examples: Fix possible pass of NULL into strchr()
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-23 15:24:30 +02:00
Jakub Jelen
2eb2af4426 CVE-2025-4878 Initialize pointers where possible
This is mostly mechanical change initializing all the pointers I was able to
find with some grep and manual review of sources and examples.

Used the following greps (which yield some false positives though):

    git grep "    \w* *\* *\w*;$"
    git grep " ssh_session \w*;"
    git grep " ssh_channel \w*;"
    git grep " struct ssh_iterator \*\w*;"
    git grep " ssh_bind \w*;"
    git grep " ssh_key \w*;"
    git grep " ssh_string \w*;"
    git grep " ssh_buffer \w*;"
    git grep " HMACCTX \w*;"
    git grep " SHACTX \w*;"
    grep -rinP '^(?!.*=)\s*(?:\w+\s+)*\w+\s*\*\s*\w+\s*;'

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-23 15:24:30 +02:00
Jakub Jelen
5d27f69494 string: Reformat
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-23 15:24:30 +02:00
Jakub Jelen
6fc1bf6901 session: Reformat ssh_get_publickey_hash
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-23 15:24:30 +02:00
Jakub Jelen
a85813e6e6 poll: Reformat ssh_poll_ctx_resize
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-23 15:24:30 +02:00
Jakub Jelen
f039edd85d examples: Reformat sshnetcat.c
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-23 15:24:30 +02:00
Andreas Schneider
1229ad650b src: Reformat pki_gcrypt.c
clang-format -i pki_gcrypt.c

Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-06-23 15:24:18 +02:00
Jakub Jelen
937552aed2 pki: Reformat ssh_pki_copy_cert_to_privkey()
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-23 13:48:16 +02:00
Jakub Jelen
f6709b03e6 misc: Reformat
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-23 13:48:16 +02:00
Jakub Jelen
96595d1674 messages: Reformat
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-23 13:48:16 +02:00
Jakub Jelen
c799a18d89 channels: Reformat
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-23 13:48:16 +02:00
Jakub Jelen
babd891e82 examples: Reformat senddata.c
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-23 13:48:16 +02:00
Jakub Jelen
320e5154b2 examples: Reformat scp_download.c
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-23 13:48:16 +02:00
Jakub Jelen
986e0c593f examples: Reformat connect_ssh.c
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-23 13:48:16 +02:00
Jakub Jelen
d38007c4be CVE-2025-5449 sftpserver: Use constant for return values
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-23 13:37:06 +02:00
Jakub Jelen
c22bfa792f CVE-2025-5449 tests: Reproducer for payload length overrun
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-23 13:37:06 +02:00
Jakub Jelen
926d45b6dd CVE-2025-5449 sftpserver: Fix possible read behind buffer on 32bit arch
On 32b architecture when processing the SFTP packets, the value
0x7ffffffc in the payload_len will overflow to negative integer values,
causing these checks to pass and possibly reading behind the buffer
bounds later.

This affects only SFTP server implementations running on 32b
architecture.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-23 13:37:06 +02:00
Jakub Jelen
681a5aaa26 CVE-2025-5449 tests: Reproducer for server processing invalid handles
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-23 13:37:06 +02:00
Jakub Jelen
e322e8f50c CVE-2025-5449 sftpserver: Avoid NULL dereference for invalid handles
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-23 13:37:06 +02:00
Jakub Jelen
a4118ddc06 CVE-2025-5449 tests: Reproducer for sftp handles exhaustion
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-23 13:37:06 +02:00
Jakub Jelen
db7f101d1c CVE-2025-5449 sftpserver: Avoid memory leak when we run out of handles during sftp_open
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-23 13:37:06 +02:00
Jakub Jelen
ae8881dfe5 CVE-2025-5318: sftpserver: Fix possible buffer overrun
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-23 13:37:06 +02:00
Jakub Jelen
00f09acbec CVE-2025-4877 base64: Prevent integer overflow and potential OOB
Set maximum input to 256MB to have safe margin to the 1GB trigger point
for 32b arch.

The OOB should not be reachable by any internal code paths as most of
the buffers and strings we use as input for this operation already have
similar limit and none really allows this much of data.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-23 13:33:10 +02:00
Lucas Mulling
74eb01f26d tests: Cleanup torture_channel_exit_signal
Signed-off-by: Lucas Mulling <lucas.mulling@suse.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-06-04 19:46:12 +02:00
Jakub Jelen
4f239f79c6 mbedtls: Avoid one more memory leak
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
2025-06-03 15:38:24 +02:00
Jakub Jelen
b8e587e498 pki: Set ECDSA signature buffers secure
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
2025-06-03 15:38:24 +02:00
Jakub Jelen
b314fd3e04 mbedtls: Rename label to match the current meaning
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
2025-06-03 15:38:24 +02:00
Jakub Jelen
d1ad796496 mbedtls: Avoid code duplication between v2 and v3 branches
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
2025-06-03 15:38:24 +02:00
Jakub Jelen
e2064b743d pki: Make sure the buffer is zeroized too
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
2025-06-03 15:38:24 +02:00
Jakub Jelen
6d2a3e4eb6 pki_mbedtls: Simplify memory cleanup
The spread out initialization and variable definition (and alising)
was hell to keep up with and was causing memory issues as reported by valgrind:

==4480== 128 bytes in 1 blocks are definitely lost in loss record 1 of 12
==4480==    at 0x48463F3: calloc (vg_replace_malloc.c:1675)
==4480==    by 0x487D152: mbedtls_mpi_grow (bignum.c:218)
==4480==    by 0x487D6C5: mbedtls_mpi_copy (bignum.c:334)
==4480==    by 0x48B9627: mbedtls_rsa_export (rsa.c:899)
==4480==    by 0x283955: pki_key_to_blob (pki_mbedcrypto.c:976)
==4480==    by 0x24F162: ssh_pki_export_privkey_blob (pki.c:2188)
==4480==    by 0x278001: ssh_pki_openssh_privkey_export (pki_container_openssh.c:546)
==4480==    by 0x24D7D2: ssh_pki_export_privkey_file_format (pki.c:1122)
==4480==    by 0x24D916: torture_pki_rsa_write_privkey_format (torture_pki_rsa.c:895)
==4480==    by 0x24D916: torture_pki_rsa_write_privkey (torture_pki_rsa.c:962)
==4480==    by 0x4865499: ??? (in /usr/lib64/libcmocka.so.0.8.0)
==4480==    by 0x4865C0B: _cmocka_run_group_tests (in /usr/lib64/libcmocka.so.0.8.0)
==4480==    by 0x252115: torture_run_tests (torture_pki_rsa.c:1160)
==4480==    by 0x2546B8: main (torture.c:1984)
==4480==

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
2025-06-03 15:38:24 +02:00
Jakub Jelen
7c34fa783d mbedcrypto: Refromat pki_key_to_blob()
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
2025-06-03 15:38:24 +02:00
Jakub Jelen
2a2c714dfa tests: Auth without none method
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <norbertpocs0@gmail.com>
2025-06-03 10:23:17 +02:00
Jakub Jelen
12baa5200a auth: Process outstanding packets before selecting signature algorithm
Originally reported by Till on mailing list here:

https://archive.libssh.org/libssh/2025-05/0000000.html

After some debugging, it turns out the client code does not guarantee
the extensions are processed before making decisions on the signature algorithm
that is being used for authentication, causing false-positive failures.

This does not happen in the tests, where we initially call ssh_userauth_none,
which enumerates authentications methods and as a side effect processes
outstanding packets such as SSH_EXT_INFO message with the server-sig-algs
extension.

When the first function called after `ssh_connect()` is
`ssh_userauth_publickey()`, the `ssh_userauth_request_service()` was wrongly
called only after the signature algorithm compatibility was checked.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <norbertpocs0@gmail.com>
2025-06-03 10:23:17 +02:00
Jakub Jelen
f2b64abcbd buffer: Use sizeof instead of magic number
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <norbertpocs0@gmail.com>
2025-06-03 10:23:17 +02:00
Nicolas Graves
4135154b6d cmocka_unit_test_setup_teardown: Comply with codespell style.
Signed-off-by: Nicolas Graves <ngraves@ngraves.fr>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-05-30 20:11:51 +02:00
Praneeth Sarode
ca4c874a9e tests: remove unsupported SHA1 HMAC tests for compatibility with latest dropbear version
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-05-27 13:50:03 +02:00
Rohan Eden
c7b6ffad0e Remove height due to inconsistent display in browser
Signed-off-by: Rohan Eden <rohan.eden@citypaine.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-05-20 18:27:46 +02:00
salonidabgar
c1fb0d872d Reformatted torture_auth_cert.c
Signed-off-by: salonidabgar <salonidabgar@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-05-14 13:45:23 +02:00
salonidabgar
3a167a89b5 Added tests for auth agent forwarding
Signed-off-by: salonidabgar <salonidabgar@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-05-14 13:45:23 +02:00
salonidabgar
dfa9421e01 Added preprocessor directives for Windows
Signed-off-by: salonidabgar <salonidabgar@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-05-14 13:45:23 +02:00
salonidabgar
efc5bc633f Reformatted torture.c and torture.h
Signed-off-by: salonidabgar <salonidabgar@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-05-14 13:45:23 +02:00
salonidabgar
3a4ba8b763 Fix file permissions: remove executable bit from CMakeLists.txt as it's a configuration file
Signed-off-by: salonidabgar <salonidabgar@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-05-14 13:45:23 +02:00
salonidabgar
47db54b7c1 Move torture_setup_ssh_agent() and torture_cleanup_ssh_agent() to torture.c
Signed-off-by: salonidabgar <salonidabgar@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-05-14 13:45:23 +02:00
salonidabgar
d1c2d3db9d Added .DS_Store to .gitignore
Signed-off-by: salonidabgar <salonidabgar@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-05-14 13:45:23 +02:00
Praneeth Sarode
dcb65fe584 refactor(curve25519): split the single file curve25519.c into multiple files for better readability
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-05-06 22:03:18 +02:00
Lucas Mulling
d758990d39 misc: Fix OpenSSH banner parsing
Signed-off-by: Lucas Mulling <lucas.mulling@suse.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <norbertpocs0@gmail.com>
2025-04-28 14:56:27 -03:00
Andreas Schneider
bfae56634c tests:unittests: Fix tests on FreeBSD
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-04-24 10:47:26 +02:00
Jakub Jelen
3d0226cadc examples: Avoid using uninitialized memory
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <norbertpocs0@gmail.com>
2025-04-16 17:41:22 +02:00
Jakub Jelen
0bcd7d12d8 dh-gex: Avoid reading the EOF stream
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <norbertpocs0@gmail.com>
2025-04-16 17:41:22 +02:00
Jakub Jelen
bd10ec1162 tests: Use fseek instead of rewind to simplify error checking
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <norbertpocs0@gmail.com>
2025-04-16 17:41:22 +02:00
Jakub Jelen
69c169e4cb sftpserver: Free memory on error condition
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <norbertpocs0@gmail.com>
2025-04-16 17:41:22 +02:00
Jakub Jelen
f0b9db586b test: Fix potential leak of fds on error
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <norbertpocs0@gmail.com>
2025-04-16 17:41:22 +02:00
Jakub Jelen
c735b44f83 test: Fix unused variables and potential memory leaks
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <norbertpocs0@gmail.com>
2025-04-16 17:41:22 +02:00
Jakub Jelen
3b4b8033de tests: Make the static ananlyzers happy with the threads
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <norbertpocs0@gmail.com>
2025-04-16 17:41:22 +02:00
Jakub Jelen
0068fdd594 examples: Fix possible null pointer passed to open()
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <norbertpocs0@gmail.com>
2025-04-16 16:19:42 +02:00
Praneeth Sarode
344235c954 fix(tests): improve synchronization in torture_forwarded_tcpip_callback tests
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-04-16 14:49:40 +02:00
Jakub Jelen
d00f7b1bf9 Make sure we pass right parameters to buffer_pack
Fixes: #299

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
Reviewed-by: Norbert Pocs <norbertpocs0@gmail.com>
2025-04-15 16:15:52 +02:00
Jakub Jelen
b14018ecab tests: Do not build zlib test when built without
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
Reviewed-by: Norbert Pocs <norbertpocs0@gmail.com>
2025-04-15 16:15:52 +02:00
Jakub Jelen
5e47b1c1c2 kex: Add more noisy errors to simplify debugging ssh_make_sessionid
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
Reviewed-by: Norbert Pocs <norbertpocs0@gmail.com>
2025-04-15 16:15:52 +02:00
Jakub Jelen
9ce885b168 ci: Add mbedTLS + clang build combination
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
Reviewed-by: Norbert Pocs <norbertpocs0@gmail.com>
2025-04-15 16:15:52 +02:00
Jakub Jelen
184dad101d Move the PKCS#11 provider environment variable where it needs to be
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
Reviewed-by: Norbert Pocs <norbertpocs0@gmail.com>
2025-04-15 16:15:52 +02:00
RaviRaaja
04a58919f8 Fix: NULL pointer check in ssh_channel_is_closed
The ssh_channel_is_closed function would crash when
accessing channel->session->alive if session is NULL.
This patch adds a null check before accessing the session
pointer.

- build succeeded
- unit test passed
- no new unit test added

https://gitlab.com/libssh/libssh-mirror/-/issues/239

Signed-off-by: Raviraaja Lakshmanan <mailstoraviraaja@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-04-14 22:20:35 +02:00
Norbert Pocs
b106211d92 clang-format: Align consecutive macros
This option makes padding between macro names and the values based on
the longest macro name in a consecutive list of macro lines.

Signed-off-by: Norbert Pocs <norbertpocs0@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-04-14 22:20:08 +02:00
Norbert Pocs
af10857aa3 CmakeLists: Fix multiple digit major version for OpenSSH
Signed-off-by: Norbert Pocs <norbertpocs0@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-04-14 22:19:18 +02:00
Praneeth Sarode
f3b389d112 tests: add unit test for direct-tcpip channel open request
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-04-07 14:02:41 +02:00
Praneeth Sarode
18e7423e70 Add direct-tcpip channel open request callback support
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-04-07 14:02:21 +02:00
Praneeth Sarode
8c8d3ceef7 tests: add unit test for forwarded-tcpip callback
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-04-07 10:57:21 +02:00
Praneeth Sarode
0d0ed4b1f8 curve25519: add support for gcrypt's Curve25519 implementation
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-04-03 11:28:44 +02:00
Arek Ouzounian
8dc234c909 Add clarification to INSTALL for unit testing on Windows via the cmocka dependency
Signed-off-by: Arek Ouzounian <agouzo777@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-04-03 11:27:45 +02:00
Praneeth Sarode
2e686c5cea cmake: fix MbedTLS version detection
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-04-03 11:27:08 +02:00
Jakub Jelen
d3706d5940 Add missing symbol to the map
This was omitted from the 84d02e74 and caused issues to build when abimap is
not present.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-04-02 10:59:53 +02:00
Praneeth Sarode
d92a057090 tests: fix torture_server_x11 and add it to tests
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-04-01 10:19:14 +02:00
Jakub Jelen
1434f24911 auth: Avoid forward-null pointer dereference
This could happen only if the function would really be called with the NULL
session, but this was never the case as the session is dereferenced already on
all code paths toward this place.

This is just to make the scanner happy that the session can not really be NULL
here.

Thanks coverity!

CID 1593926

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <norbertpocs0@gmail.com>
2025-03-31 11:05:37 +02:00
Aditya Sinha
cce600f980 test for ssh_get_kex_algo()
Signed-off-by: Aditya Sinha <aditya072006@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-03-30 13:10:53 +02:00
Aditya Sinha
95150b1137 Adding the missing Algorithms to ssh_get_kex_algo() function
Signed-off-by: Aditya Sinha <aditya072006@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-03-30 13:10:52 +02:00
Aditya Sinha
65b2591b91 Reformatting the ssh_get_kex_aglo() function
Signed-off-by: Aditya Sinha <aditya072006@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-03-30 13:10:51 +02:00
Praneeth Sarode
a5e9529ca7 curve25519: refactor mbedTLS code to remove code duplication
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-03-30 13:04:48 +02:00
Praneeth Sarode
49a355c272 curve25519: Use mbedTLS curve25519 for ECDH, if available
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-03-30 13:04:47 +02:00
David Wedderwille
84d02e7440 kex: Make existing convenience features available
Signed-off-by: David Wedderwille <davidwe@posteo.de>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-03-30 12:17:42 +02:00
David Wedderwille
0b91ba779c kex: Improved naming of variables.
Signed-off-by: David Wedderwille <davidwe@posteo.de>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-03-30 12:17:41 +02:00
Yuvraj Saxena
d02163546d fuzz: Add ProxyJump misconfiguration cases to ssh_client_config_fuzzer_corpus
This commit adds test cases to catch issues where ProxyJump configurations lead to infinite loops or incorrect username usage, as reported in issue #287, and issue #291

Signed-off-by: Yuvraj Saxena <ysaxenax@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-03-30 12:14:37 +02:00
AsadaShino
a93e84efb9 authenticate_console:Stop authentication after SSH session disconnection to avoid hanging up in poll
Signed-off-by: AsadaShino <1164429449@qq.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-03-20 15:29:59 +01:00
Eshan Kelkar
a59d587060 sftpserver.c: Add support for O_TRUNC while opening files
Signed-off-by: Eshan Kelkar <eshankelkar@galorithm.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-03-18 18:13:52 +01:00
Eshan Kelkar
6c4e4a9e1c torture_sftpserver.c: Add test for O_TRUNC while opening files
Signed-off-by: Eshan Kelkar <eshankelkar@galorithm.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-03-18 18:13:51 +01:00
Abdallah Alhadad
aa681c268e extensions: Host-bound public key authentication
Signed-off-by: Abdallah Alhadad <abdallahselhdad@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-03-18 17:34:04 +02:00
Abdallah Alhadad
fe381d6aa4 refactor: Extract build_pubkey_auth_request function for public key authentication
Signed-off-by: Abdallah Alhadad <abdallahselhdad@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-03-18 17:33:57 +02:00
Abdallah Alhadad
1f76cc0c6a reformat: functions related to pubkey authentication
Signed-off-by: Abdallah Alhadad <abdallahselhdad@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-03-15 22:16:46 +00:00
John Thacker
bf2b8954e8 CMake: Add Requires.private information for GSSAPI to .pc file
Try to find GSSAPI via pkg-config. If found, add the appropriate
module name, depending on the flavor, to the libssh.pc file so that
the pkg-config can report the list of libraries needed when linking
against the static library version of libssh.

Fix #293

Signed-off-by: John Thacker <johnthacker@gmail.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-03-12 15:05:57 +01:00
Jakub Jelen
7e3935e7d2 Add timeout extension requirement to the MR template
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-03-11 14:03:23 +01:00
Jakub Jelen
d38b471fd8 ci: Move MR template from webui to git
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-03-11 14:03:22 +01:00
Jakub Jelen
735a4368c2 Document the need to extend the CI timeout
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-03-11 14:03:21 +01:00
Jakub Jelen
a25f9d211d tests: Fix variable names to avoid codespell issues
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-03-04 16:00:33 +01:00
Jakub Jelen
3a52bf1679 tests: Reproducer for graceful failure on ignored Match arguments
https://gitlab.com/libssh/libssh-mirror/-/issues/291#note_2376323499
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-03-04 16:00:33 +01:00
Jakub Jelen
f7bdd779d6 config: Be less strict when parsing unknown Match keywords
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-03-04 16:00:33 +01:00
Jakub Jelen
8ef249a4a4 config: Fix copy&paste error in error message
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-03-04 14:09:08 +01:00
Praneeth Sarode
d9da8f212d docs: Add section on ABI versioning and symbol management to CONTRIBUTING.
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-03-04 13:00:27 +01:00
Norbert Pocs
9613e9508d tests/torture_proxyjump: Fix codespell issues
Signed-off-by: Norbert Pocs <norbertpocs0@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-03-03 11:20:48 +01:00
Norbert Pocs
6b9a6529bd tests: Add torture_proxyjump_multiple_users_sshd_jump with Doe
Tests proxyjump with two servers and two users.

Signed-off-by: Norbert Pocs <norbertpocs0@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-03-03 11:20:48 +01:00
Norbert Pocs
b14cde6d2a tests: Add multiple server proxyjump testcase
Tests proxyjump with the same user through two servers.

Signed-off-by: Norbert Pocs <norbertpocs0@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-03-03 11:20:48 +01:00
Norbert Pocs
e01c32f41e tests: Add torture_setup_sshd_servers
Starts a second sshd. This enables to test proxyjump through
multiple servers.

Signed-off-by: Norbert Pocs <norbertpocs0@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-02-28 10:05:12 +01:00
Jakub Jelen
dd6a711354 Use windows-compatible access() function to unbreak windows build
Fixes up 3372c2ad78 which did not properly check
the included header file.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-02-27 13:31:35 +01:00
Jakub Jelen
c1a7de78d1 tests: Add PKCS#11 URI tests with Ed25519 keys
This will work only with pkcs11 provider. Not tested with engines.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-02-27 10:52:17 +01:00
Jakub Jelen
9735f074ba tests: Skip Ed25519 keys in FIPS mode
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-02-27 10:52:17 +01:00
Jakub Jelen
b2b56151c0 pki: Fail more gracefully when parsing Ed25519 keys in FIPS mode
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-02-27 10:52:17 +01:00
Jakub Jelen
de7903a633 Do not import Ed25519 keys in FIPS Mode
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-02-27 10:52:17 +01:00
Jakub Jelen
a089513e40 pki_crypto: OpenSSL 1.1.1 compatible Ed25519 key duplication
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-02-27 10:52:17 +01:00
Jakub Jelen
ec9d7d13fd Use Ed25519 in OpenSSL through the EVP_PKEY API
... instead of keeping around public and private key blobs.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-02-27 10:52:17 +01:00
Jakub Jelen
f14568262a tests: Update PKCS#11 tests to follow global verbosity
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-02-27 10:52:17 +01:00
Jakub Jelen
257e8eb2c1 tests: Add PEM public Ed25519 key
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-02-27 10:52:17 +01:00
Jakub Jelen
99fcd56135 tests: Remove p11-kit remoting from pkcs11 tests
The p11-kit remoting was initially introduced because softhsm
was crashing during cleanup with OpenSSL 3.0. This was resolved
since then and this code introduces a lot of complexity and
possible bugs, such as when using the mechanisms from PKCS#11 3.0
that are unknown to the p11-kit remoting tool. It decides to remove
them from the list as demonstrated here:

https://github.com/p11-glue/p11-kit/issues/668

This resulted in pkcs11-provider not registering EDDSA siganture
methods to the OpenSSL and failing when asked to provide a singature
by the Ed25519 key from the PKCS#11 token.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-02-27 10:52:17 +01:00
Jakub Jelen
8922e43578 tests: Improve logging on failures in ed25519 test
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-02-27 10:52:17 +01:00
Jakub Jelen
e36ca61e36 pki: Fix error message
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-02-27 10:52:17 +01:00
Jakub Jelen
02c092d3d9 pki: Avoid needless assignment
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-02-27 10:52:17 +01:00
Jakub Jelen
520f758902 pki_crypto: Reformat pki_key_compare
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-02-27 10:52:17 +01:00
Jakub Jelen
12b8eed093 pki_crypto: Reformat pki_private_key_to_pem
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-02-27 10:52:17 +01:00
Lucas Mulling
3372c2ad78 cmake: Add option WITH_HERMETIC_USR
Add a cmake option to enable hermetic-usr, i.e., use of config files in /usr/.
If turned on, GLOBAL_*_CONFIG is prepended with /usr/ and defined as
USR_GLOBAL_*_CONFIG. Config lookup follows this path GLOBAL_*_CONFIG ->
USR_GLOBAL_*_CONFIG.

Introduce a ssh_config_parse primitive. This avoids convoluted checks for file
presence (without modifing the behaviour of ssh_config_parse_file) and allows
marking whether the config is global at the call site.

Signed-off-by: Lucas Mulling <lucas.mulling@suse.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-02-27 10:24:42 +01:00
John Thacker
6b83aa9a40 CMake: Use GSSAPI_INCLUDE_DIR consistently
The GSSAPI find module sets GSSAPI_INCLUDE_DIR (singular) only and
passes that to find_package_handle_standard_arguments, but later
tests and marks as advanced GSSAPI_INCLUDE_DIRS (plural), which doesn't
exist. GSSAPI_INCLUDE_DIR is what's used in src/CMakeLists.txt

This hasn't had a major effect, because GSSAPI_FOUND gets set by
find_package_handle_standard_args, so the if statement that tests
GSSAPI_INCLUDE_DIRS (and never succeeded) would have been a no-op
in any case, so remove it. Standardize on the singular version when
marking as advanced.

Signed-off-by: John Thacker <johnthacker@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-02-26 10:14:59 +01:00
Jakub Jelen
7f045e2d91 tests: Unit test nested quotes
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-02-11 13:20:20 +01:00
Jakub Jelen
2b916b3b88 tests: Reformat test list
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-02-11 12:17:34 +01:00
Jakub Jelen
a10553ae57 Reproducer for #291
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-02-11 12:17:34 +01:00
Jakub Jelen
d1ce336ae3 config: Allow escaping quotes inside of quoted tokens
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-02-11 12:17:34 +01:00
Praneeth Sarode
79ac8b85d8 tests: add tests for users-groups-by-id@openssh.com on client side
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
2025-02-05 17:01:40 +05:30
Praneeth Sarode
9a9cafeed5 sftp: add users-groups-by-id@openssh.com extension for client
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
2025-02-05 17:01:20 +05:30
Andreas Schneider
a0a5292692 gitlab-ci: Improve abidiff
Only fail if it is an ABI incompatible change.

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-01-31 11:39:01 +01:00
Eshan Kelkar
1a64c577f6 sftp.c: Validate that the SSH session is in nonblocking mode
The sftp API functions cannot interoperate properly with a
nonblocking ssh session.

Therefore code has been added in sftp_new() due to which the
function will return failure if the caller passes a non
blocking session without even trying to connect.

Signed-off-by: Eshan Kelkar <eshankelkar@galorithm.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-01-29 13:52:51 +01:00
Jakub Jelen
c03d0d4823 ci: Do not run macos tests on third-party MRs
The macos images are not available for third-party contributors and
they prevent the CI to continue from the tests stage.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-01-26 22:14:59 +01:00
Jakub Jelen
d5456931cc examples: Fix format string unearthed during macos build
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-01-21 11:35:12 +01:00
Jakub Jelen
dc18b41357 cmake: Do not attempt to use -fstack-clash-protection on MacOS M1 chips
This is supported in clang, but only on x86_64 so we need to back down to the
architecture checks. Otherwise the checks pass with warning, but the build
itself fails with errors (-Werror).

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-01-21 11:35:12 +01:00
DreadPirate07
0f5dec7fb7 ci: add macOS environment to GitLab CI
Fixes: #161

Co-Authored-By: DreadPirate07 <tanayraikhere@gmail.com>
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-01-21 11:35:12 +01:00
Jakub Jelen
0cda1c0e83 bignum: Make sure the padding is large enough for the number
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-01-21 11:32:49 +01:00
Jakub Jelen
1ea9708409 tests: Verify the right implementation is used
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-01-21 11:32:49 +01:00
Jakub Jelen
39fcaac3ca Use gcrypt implementation of ntruprime
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-01-21 11:32:49 +01:00
Jakub Jelen
dab51d8e20 buffer: Calculate correctly the bignum size in buffer
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-01-21 11:32:49 +01:00
Simon Josefsson
4becc8eb82 kex: Add sntrup761x25519-sha512@openssh.com.
All of the initial work was done by Simon. Jakub cleaned up the
formatting issues, resolved the padding of bignum to match specs
and be interoperable with OpenSSH (and few more minor details).

Closes: #194.

Signed-off-by: Simon Josefsson <simon@josefsson.org>
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-01-21 11:32:49 +01:00
Simon Josefsson
3468cc0dc5 tests: Allow killing processes to take more time.
A too low timeout caused spurious self-test failures in pkd_hello_i1.

Signed-off-by: Simon Josefsson <simon@josefsson.org>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-01-21 11:32:49 +01:00
Simon Josefsson
4bd8d8d362 curve25519: Add ssh_curve25519_create_k to allow code re-use.
Signed-off-by: Simon Josefsson <simon@josefsson.org>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-01-21 11:32:49 +01:00
Simon Josefsson
083a4781d8 curve25519: Drop static from ssh_curve25519_init to allow code re-use.
Signed-off-by: Simon Josefsson <simon@josefsson.org>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-01-21 11:32:49 +01:00
Simon Josefsson
7e3263d995 tests: Check buffer bignum behaviour.
Signed-off-by: Simon Josefsson <simon@josefsson.org>
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-01-21 11:32:49 +01:00
Simon Josefsson
fbf02d5936 buffer.c: Support 'F' for padded bignums
Signed-off-by: Simon Josefsson <simon@josefsson.org>
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-01-21 11:32:49 +01:00
Simon Josefsson
16fd55b4b2 tests: Check ssh_make_padded_bignum_string.
Signed-off-by: Simon Josefsson <simon@josefsson.org>
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-01-21 11:32:49 +01:00
Jakub Jelen
799557384d bignum: Add ssh_make_unpadded_bignum_string.
Signed-off-by: Simon Josefsson <simon@josefsson.org>
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-01-21 11:32:49 +01:00
Jakub Jelen
c6be50cc97 reformat enum ssh_key_exchange_e
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-01-21 11:32:49 +01:00
Jakub Jelen
af90168624 bignum: Reformat
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-01-21 11:32:49 +01:00
Jakub Jelen
9dbd1ec80b client: Reformat dh_handshake
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-01-21 11:32:49 +01:00
Jakub Jelen
9b9a2ea97d clang-format: Update config for clang 19
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-01-21 11:32:49 +01:00
Andreas Schneider
e9b76ff1bd torture_config: Use getpwuid() instead of env variables
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-01-15 13:24:41 +01:00
Andreas Schneider
e9046fc069 torture_misc: Do not rely on environment variables
The safest way is to use getpwuid().

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-01-15 13:22:38 +01:00
Jakub Jelen
0cd749a533 zlib: Move conditional compilation inside of the gzip.c
This implements stub for the compression functions and includes the
gzip.c in the compilation target uncoditionally, keeping the WITH_ZLIB
conditional compilation only in the gzip.c

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-01-14 14:47:44 +01:00
Jakub Jelen
e795849299 tests: fix spelling error
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-01-13 17:00:42 +01:00
Jakub Jelen
d887e1320a sftp: Avoid dead code and possible overruns
Coverity did not like the DEADCODE on 64b architecture.

After better look, the SFTP packet have read/write lengths in uint32 so
we really can not use the limits up to the uint64. Therefore we cap the
limits to uint32 while parsing and ignore any large value.

We then cap our reads/writes to this value, which is safe to cast to uint32
for wire format.

Thanks Coverity CID 1589435, CID 1589434, CID 1589432, CID 1589431

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-01-13 15:47:43 +01:00
Jakub Jelen
9eaa7a6394 sftp: Avoid memory leaks from extended attributes
Thanks coverity CID 1589433

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-01-13 15:47:43 +01:00
Jakub Jelen
4af88c84d4 sftp: Reformat read/write functions
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-01-13 15:47:43 +01:00
Jakub Jelen
00fce9cb6c gzip: Move cleanup to separate function
to avoid exposing gzip function into wrapper.c

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-01-13 15:28:13 +01:00
Jakub Jelen
a547b7f115 gzip: Avoid potential memory leak
Thanks coverity CID 1589436

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-01-13 13:38:33 +01:00
Jakub Jelen
8bf908a56f tests: Make sure to pass right type to buffer_pack
For some reason, the mingw64 builds were failing on these inputs quite reliably
as the passed value was interpretted as a value larger than UINT32_MAX.

This was not caught before because the value is casted from size_t to uint32_t
implicitly so the MSBs were not affecting the result.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-01-03 15:18:53 +01:00
Jakub Jelen
b7018c17c7 Fix implicit type conversions and warnings on windows builds
The visual studio windows builds spit dozens of lines of warnings
on these.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-01-03 15:18:53 +01:00
Jakub Jelen
a15c977cdc tests: Test vectors for related documentation
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-01-02 11:39:18 +01:00
Jakub Jelen
91e228b08b options: Clarify format of HOST option
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-01-02 11:39:18 +01:00
Jakub Jelen
cbcd6d6f46 Happy new year 2025!
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-01-02 11:35:55 +01:00
Jakub Jelen
49b0c859f9 packet: Implement logging of SSH2_MSG_DEBUG message
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2024-12-20 15:09:54 +01:00
Jakub Jelen
79ba546cde channels: Remove callbacks from freed channels
When the user frees the channel, they no longer expect any callbacks
to be triggered on it. When we delay the close before we receive
the remaining messages, we should not trigger the user callbacks
as it might be already freed.

I believe this is the random torture_session test failures and
errors we are getting from valgrind from time to time.

We keep the callbacks cleanup in the do_cleanup() in case the
calling application sets the callback after free for some reason.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2024-12-20 15:09:54 +01:00
Jakub Jelen
0ea982d4ec channels: Warn against executing multiple commands in single channel
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2024-12-20 15:09:54 +01:00
Jakub Jelen
c043122655 tests: Close channel before freeying
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2024-12-20 14:20:29 +01:00
Jakub Jelen
5da8963c1d tests: Verify channel requests return valid replies
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2024-12-20 14:20:29 +01:00
Jakub Jelen
f3d80833fe examples: Remove remaining references to default hostkeys
This is fixup of a9d1cfa9e2, where we missed this
corner case.

Fixes: #285
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2024-12-20 13:52:37 +01:00
Jakub Jelen
874b75429f tests: Fix random failure on too fast systems
On mingw we are frequently getting a failure like this:

[  ERROR   ] --- 451 is not within the range 1-450

This means the 50ms sleep did not manage to elapse the 50ms in the timeout
structure. Extending the range to 460 will give use more wiggle room if the
clock is not as it should be.

Related: #273
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2024-12-20 10:29:08 +01:00
Jakub Jelen
f8a6b1e2b3 ci: Skip torture_rand in mingw as it keeps hanging
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2024-12-20 10:12:44 +01:00
Andreas Schneider
5b9b901e48 gitlab-ci: Add abidiff
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2024-12-03 15:19:51 +01:00
Andreas Schneider
2966a4a33c tests: Call disable_secmem() before ssh_init()
ssh_init calls ssh_crypto_init() which initializes the secure memory of
gcrypt. Those should actually be just called by the application once.
Lets do that.

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2024-12-03 15:19:51 +01:00
Andreas Schneider
867630750c tests: Reformat cmocka_unit_test calls in torture_threads_pki_rsa.c
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2024-12-03 15:19:51 +01:00
Andreas Schneider
9a40d51162 gcrypt: Store random numbers in secure memory
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2024-12-03 15:19:51 +01:00
Andreas Schneider
259721e523 gcrypt: Allocate 32k of secure memory
In the meantime libgcrypt allocates 32k of secure memory, the minimum is
16k.

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2024-12-03 15:19:51 +01:00
Andreas Schneider
4bc40a47a3 tests:valgrind: Add suppression memleak in krb5_mcc_generate_new
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2024-12-03 15:19:51 +01:00
Norbert Pocs
f0b55391a8 gitlab-ci: Move Visual Studio builds back to test stage
The Visual Studio builds are completing in a manageable speed now.
Putting it back to the dependent chain of the CI to not cause any false
positive representation of the analysis stage (when the stage has all
skipped jobs, but the independent VS jobs succeed, the stage is shown as
success)

Reverting part of commit 91703202

Signed-off-by: Norbert Pocs <norbertpocs0@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2024-12-02 20:27:56 +01:00
Norbert Pocs
d2e5b69b02 gitlab-ci.yml: Bump openssl version numbers on runner titles
Signed-off-by: Norbert Pocs <norbertpocs0@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2024-11-13 18:41:05 +01:00
Norbert Pocs
2971e122d0 gitlab-ci.yml: Run fedora without pkcs11
Signed-off-by: Norbert Pocs <norbertpocs0@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2024-11-13 18:41:05 +01:00
Jakub Jelen
e2524538f6 curve25519: Avoid reading private curve25519 keys from OpenSSL structures
The previous code created private key curve25519 in OpenSSL, then exported
private key and during key generation, created a new OpenSSL private key object.
This is needless amount of copying potentially sensitive data back and forth and
this will not work when the private key would be backed with external OpenSSL
provider, such as pkcs11 provider or different crypto accelerator handling the
private key operations for us.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2024-11-12 17:47:04 +01:00
Jakub Jelen
d0ecb5388c sftpserver: Do not override the ssh error code
Fixes: https://gitlab.com/libssh/libssh-mirror/-/issues/275#note_2162076660

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2024-11-12 17:46:38 +01:00
Eshan Kelkar
72b6fad284 Add tests for sftp_recv_response_msg()
Signed-off-by: Eshan Kelkar <eshankelkar@galorithm.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2024-11-12 17:45:44 +01:00
Eshan Kelkar
258c2eef3b sftp_common (bug fix): Change the way sftp responses are received
This commit changes the way in which receiving sftp
responses is handled.

The old way polled/blocked on the channel before
checking the sftp response queue which could cause infinite
waiting by default if the required response is already present
in the response queue and no other sftp response is ever sent
by the server.

The new way checks the sftp response queue first for the
response before polling/blocking on the channel. This gets
rid of the potential infinite waiting bug.

Signed-off-by: Eshan Kelkar <eshankelkar@galorithm.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2024-11-12 17:45:42 +01:00
Eshan Kelkar
a02268a254 Add helper to receive sftp response messages
For the sake of reducing code repetition, this commit
adds a helper function to receive sftp response
messages. The function can operate in both blocking
and non-blocking modes.

Signed-off-by: Eshan Kelkar <eshankelkar@galorithm.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2024-11-12 17:45:41 +01:00
Eshan Kelkar
f16b3539da sftp_aio: Add tests for unordered waits
This commit adds tests to check that the sftp aio API works
properly if the API user waits for responses of the read/write
requests in an order different from the sending order of the
requests.

Signed-off-by: Eshan Kelkar <eshankelkar@galorithm.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2024-11-12 17:45:40 +01:00
Jakub Jelen
0306581f1c sftp: Do not fail if the status message does not contain error message
Some SFTP servers (Cisco) do not implement the v3 protocol correctly and do not
send the mandatory part of the status message. This falls back to the v2
behavior when the error message and language tag are not provided.

Fixes: #272

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2024-11-12 17:44:26 +01:00
Eshan Kelkar
d8f00aca20 priv.h, torture_misc.c: Fix clang-format formatting complaints
Fixed include order and formatting issues regarding the 80 char
column width limit

Signed-off-by: Eshan Kelkar <eshankelkar@galorithm.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2024-11-12 17:41:15 +01:00
Eshan Kelkar
e0aa182e7e log.c: Use localtime_r() in current_timestring()
Use localtime_r() instead of the thread unsafe localtime().

Signed-off-by: Eshan Kelkar <eshankelkar@galorithm.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2024-11-12 17:41:14 +01:00
Eshan Kelkar
0e756306f0 log.c: Fix current_timestring()
The second argument to strftime() should be the size of the buffer
as per the manpage.

The previous code used size - 1 as the second argument. This commit modifies
that behaviour to use buffer size as the second argument of strftime().

Signed-off-by: Eshan Kelkar <eshankelkar@galorithm.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2024-11-12 17:41:13 +01:00
Eshan Kelkar
904c3e024c torture_misc.c Add test for localtime_r()
Signed-off-by: Eshan Kelkar <eshankelkar@galorithm.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2024-11-12 17:41:11 +01:00
Eshan Kelkar
b58cb9f72b misc.c, priv.h: Add support for localtime_r() on Windows
Windows supports localtime_s() instead of POSIX's localtime_r()
and the function prototype of localtime_s() is different as compared
to localtime_r().

This commit introduces ssh_localtime() (having same prototype as localtime_r())
for Windows which acts as a wrapper for localtime_s(), and defines localtime_r
as a macro which expands to ssh_localtime for Windows.

As a result, libssh can now use localtime_r() on Windows in the same manner
as localtime_r() can be used on POSIX systems.

Signed-off-by: Eshan Kelkar <eshankelkar@galorithm.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2024-11-12 17:41:04 +01:00
Axel Lin
861590192f Add #ifndef __VA_NARG__ guard to avoid "__VA_NARG__" redefined warnings
Some SDK already defined __VA_NARG__, so without #ifndef __VA_NARG__ guard
we got a lot of "__VA_NARG__" redefined warnings.
Fix it by adding #ifndef __VA_NARG__ guard in include/libssh/priv.h.

Fixes: #279
Signed-off-by: Axel Lin <axel.lin@ingics.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2024-10-25 13:50:51 +02:00
JamesWrigley
9ad2f6b3b1 Add missing #include's to sftpserver.h
Presumably this header is always imported with all the other necessary ones so
it doesn't usually make a difference, but generating Julia bindings from the
header by itself requires all the types to be defined (e.g. ssh_session,
ssh_channel, etc).

Signed-off-by: James Wrigley <james@puiterwijk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2024-10-25 13:50:43 +02:00
JamesWrigley
ef8e90863b Make codespell ignore PENDIN in CI
This is the correct name of a terminal opcode.

Signed-off-by: James Wrigley <james@puiterwijk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2024-10-25 13:50:07 +02:00
Simon Josefsson
d29ed23010 tests: Permit slow systems to take 1-450 instead of 1-40ms.
Thanks to Jakub Jelen for debugging and suggested fix.  Fixes #273.

Signed-off-by: Simon Josefsson <simon@josefsson.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2024-10-25 13:48:58 +02:00
Jakub Jelen
46d7417620 tests: Do not use global openssl.cnf
The global openssl configuration file automatically loads a pkcs11
provider, but it does it before we set up the token, which makes
the pkcs11 tests failing.

The workaround is to not load the global configuration, which is
delaying the loading of the pkcs11 provider to the time of first
use.

Consequently, this will require separate integration end-to-end
test that will verify the libssh works correctly with the pkcs11
provider loaded early.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2024-10-25 13:46:22 +02:00
Jakub Jelen
c73a8a824e ci: Add Centos 10 development container
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2024-10-25 13:46:22 +02:00
Davidwed
7712c7d0f9 cmake: Fixed compatibility issues with "CPM.cmake" in combination with the libraries MBedTLS and libgcrypt.
Signed-off-by: Davidwed <davidwe@posteo.de>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2024-10-21 13:56:23 +02:00
Simon Josefsson
d7a0cbcfbb tests: Permit slow systems to take 300ms instead of 75ms.
Thanks to Jakub Jelen for debugging.  Fixes #273.

Reproduce problem by changing the value to 1ms.

Signed-off-by: Simon Josefsson <simon@josefsson.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2024-10-21 13:54:09 +02:00
Thomas Perale
cb0237e85b cmake: Only enable CXX when running the coverage
Commit 25a678190c introduced code coverage
collection. That also introduced a dependency to CXX language.

When cross-compiling libssh in an environment that doesn't have a C++ compiler
the following error is raised: "No CMAKE_CXX_COMPILER could be found.".

Since the C++ part is only needed for the coverage part, this commit only enable
that language dependency when actually needing it.

Signed-off-by: Thomas Perale <thomas.perale@mind.be>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2024-10-21 13:52:12 +02:00
JamesWrigley
5b0f480acd Document that most SFTP functions require a blocking ssh_session
Currently if a non-blocking `ssh_session` is passed most calls will fail because
they don't know how to handle `SSH_AGAIN`.

Signed-off-by: James Wrigley <james@puiterwijk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2024-10-21 13:48:56 +02:00
JamesWrigley
629ba3fd34 Fix typo
Renamed `process_unsupposed` to `process_unsupported`.

Signed-off-by: James Wrigley <james@puiterwijk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2024-10-21 13:48:14 +02:00
Jakub Jelen
48d474f78c ttyopts: Adjust the default TTY modes to be sane
The "sane" default is now based on the man stty "sane" alias with addition of
utf8.

Fixes: #270

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2024-08-29 09:07:25 +02:00
Carlo Bramini
e298600303 CYGWIN: fix build.
Signed-off-by: Carlo Bramini <carlo_bramini@users.sourceforge.net>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2024-08-19 13:12:27 +02:00
Jakub Jelen
8295945011 Add explicit -Werror=unused-variable
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
2024-08-19 13:12:27 +02:00
Jakub Jelen
8363929104 cmake: Do not build server examples and tests when built without server
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
2024-08-19 13:12:27 +02:00
Jakub Jelen
71e1baeb5f kex: Avoid unused variable when built without server
Fixes: #267

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
2024-08-19 13:12:27 +02:00
Jakub Jelen
82b363f294 config: Do not parse unsupported ControlPath/ControlMaster
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2024-08-19 13:12:27 +02:00
Jakub Jelen
8fb2c5d2fd tests: Do not crash on cleanup when sshd does not come up
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2024-08-19 13:12:27 +02:00
Jakub Jelen
9ce53b6972 tests: Do not override verbosity set by environment
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2024-08-19 13:12:27 +02:00
Jakub Jelen
7b89ff760a test: Workaround the new OpenSSH failure rate limiting
The new OpenSSH rate limits the failed authentication attempts per source
address and drops connection when the amount is reached, which is happening
in our testsuite.

By whitelisting the IP address of the client on the socket wrapper,
this allows the tests to pass.

https://man.openbsd.org/sshd_config.5#PerSourcePenaltyExemptList

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2024-08-19 13:12:27 +02:00
Andreas Schneider
362ab3a684 cpack: Make sure to not package .git file
Signed-off-by: Andreas Schneider <asn@samba.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2024-08-19 13:12:27 +02:00
Jakub Jelen
ea97d41bbb tests: Avoid unused variables
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2024-08-19 13:12:27 +02:00
Jakub Jelen
c85268c38b wrapper: Use calloc instead of zerostructp
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2024-08-19 13:12:27 +02:00
Jakub Jelen
c9cfeb9b83 wrapper: Avoid asymmetric termination of gzip context
For some reason, both compress and decompress contexts were terminated
with both compress and decompress end functions (if the deflateEnd worked),
which was causing for some another unexplained reasons issues on i686
architecture when running the torture_packet unit test.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2024-08-19 13:12:27 +02:00
Jakub Jelen
deedc0e108 tests: Describe reason for using internal-sftp
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2024-08-19 13:12:27 +02:00
Jakub Jelen
57073d588a tests: Remove needless printf
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2024-08-19 13:12:27 +02:00
Jakub Jelen
d416ef533f tests: Rewrite fs_wrapper for readability
includes also additional syscalls for 32b archs.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2024-08-19 13:12:27 +02:00
Jakub Jelen
2743b510ac tests: Assemble the output into single buffer
... before checking the content.

This test was failing randomly when the read returned only partial buffer.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2024-08-19 13:12:27 +02:00
Jakub Jelen
41d370864e tests: Be explicit about types.
Casting int to bool might not always work as expected

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2024-08-19 13:12:27 +02:00
JamesWrigley
7e4ea0d111 Use CMake's C_STANDARD property
This is more portable than specifying a compiler flag explicitly.

Signed-off-by: James Wrigley <james@puiterwijk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2024-08-15 09:53:52 +02:00
Francesco Rollo
b0b2e8fefd tests: add support for IPv4/IPv6 loopback network ID fallback in torture_config_match_localnetwork.c
Signed-off-by: Francesco <eferollo@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2024-08-02 11:19:05 +02:00
Jakub Jelen
b804aa9286 Fix proxy_disconnect on systems without pthread
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2024-08-02 11:00:47 +02:00
Jakub Jelen
ab10f5c2f7 match: Workaround matching on systems without IPv6
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2024-08-02 10:35:31 +02:00
Jakub Jelen
9634668258 Conditional compilation of localnetwork matching
Some architectures (esp32) might not have this API.

Fixes: #263

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2024-08-02 10:35:31 +02:00
322 changed files with 48602 additions and 11677 deletions

View File

@@ -22,8 +22,8 @@ BinPackArguments: false
BinPackParameters: false BinPackParameters: false
AllowAllArgumentsOnNextLine: false AllowAllArgumentsOnNextLine: false
AllowShortFunctionsOnASingleLine: Empty AllowShortFunctionsOnASingleLine: Empty
# TODO with Clang 19, replace the below with BreakAfterReturnType: ExceptShortType
# BreakAfterReturnType: ExceptShortType
AlwaysBreakAfterReturnType: AllDefinitions AlwaysBreakAfterReturnType: AllDefinitions
AlignEscapedNewlines: Left AlignEscapedNewlines: Left
ForEachMacros: ['ssh_callbacks_iterate'] ForEachMacros: ['ssh_callbacks_iterate']
AlignConsecutiveMacros: 'Consecutive'

1
.clang-format-ignore Normal file
View File

@@ -0,0 +1 @@
src/external/*

6
.cmake-format.yaml Normal file
View File

@@ -0,0 +1,6 @@
---
line_width: 80
tab_size: 4
use_tabchars: false
separate_ctrl_name_with_space: true
separate_fn_name_with_space: false

View File

@@ -12,7 +12,12 @@ indent_style = space
indent_size = 4 indent_size = 4
tab_width = 4 tab_width = 4
[{CMakeLists.txt,*.cmake}] [CMakeLists.txt]
indent_style = space
indent_size = 4
tab_width = 4
[*.cmake]
indent_style = space indent_style = space
indent_size = 4 indent_size = 4
tab_width = 4 tab_width = 4

1
.gitignore vendored
View File

@@ -10,3 +10,4 @@ tags
/build /build
/obj* /obj*
doc/tags.xml doc/tags.xml
.DS_Store

View File

@@ -3,6 +3,7 @@ variables:
BUILD_IMAGES_PROJECT: libssh/build-images BUILD_IMAGES_PROJECT: libssh/build-images
CENTOS8_BUILD: buildenv-c8s CENTOS8_BUILD: buildenv-c8s
CENTOS9_BUILD: buildenv-c9s CENTOS9_BUILD: buildenv-c9s
CENTOS10_BUILD: buildenv-c10s
FEDORA_BUILD: buildenv-fedora FEDORA_BUILD: buildenv-fedora
MINGW_BUILD: buildenv-mingw MINGW_BUILD: buildenv-mingw
TUMBLEWEED_BUILD: buildenv-tumbleweed TUMBLEWEED_BUILD: buildenv-tumbleweed
@@ -16,7 +17,7 @@ stages:
- analysis - analysis
# This is some black magic to select between branch pipelines and # This is some black magic to select between branch pipelines and
# merge request pipelines to avoid running same pipelines in twice # merge request pipelines to avoid running same pipelines twice
workflow: workflow:
rules: rules:
- if: '$CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS && $CI_PIPELINE_SOURCE == "push"' - if: '$CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS && $CI_PIPELINE_SOURCE == "push"'
@@ -26,13 +27,17 @@ workflow:
when: never when: never
- if: '$CI_COMMIT_BRANCH' - if: '$CI_COMMIT_BRANCH'
.build: .build_options:
stage: build
variables: variables:
CMAKE_DEFAULT_OPTIONS: "-DCMAKE_BUILD_TYPE=RelWithDebInfo -DPICKY_DEVELOPER=ON" CMAKE_DEFAULT_OPTIONS: "-DCMAKE_BUILD_TYPE=RelWithDebInfo -DPICKY_DEVELOPER=ON"
CMAKE_BUILD_OPTIONS: "-DWITH_BLOWFISH_CIPHER=ON -DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON -DWITH_DEBUG_CRYPTO=ON -DWITH_DEBUG_PACKET=ON -DWITH_DEBUG_CALLTRACE=ON" CMAKE_DEFAULT_DEBUG_OPTIONS: "-DCMAKE_C_FLAGS='-O0 -g -ggdb' -DPICKY_DEVELOPER=ON"
CMAKE_BUILD_OPTIONS: "-DWITH_BLOWFISH_CIPHER=ON -DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON -DWITH_FIDO2=ON -DWITH_DEBUG_CRYPTO=ON -DWITH_DEBUG_PACKET=ON -DWITH_DEBUG_CALLTRACE=ON"
CMAKE_TEST_OPTIONS: "-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON -DGSSAPI_TESTING=ON -DWITH_BENCHMARKS=ON -DFUZZ_TESTING=ON" CMAKE_TEST_OPTIONS: "-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON -DGSSAPI_TESTING=ON -DWITH_BENCHMARKS=ON -DFUZZ_TESTING=ON"
CMAKE_OPTIONS: $CMAKE_DEFAULT_OPTIONS $CMAKE_BUILD_OPTIONS $CMAKE_TEST_OPTIONS CMAKE_OPTIONS: $CMAKE_DEFAULT_OPTIONS $CMAKE_BUILD_OPTIONS $CMAKE_TEST_OPTIONS
.build:
extends: .build_options
stage: build
before_script: &build before_script: &build
- uname -a - uname -a
- cat /etc/os-release - cat /etc/os-release
@@ -74,12 +79,46 @@ workflow:
.fedora: .fedora:
extends: .tests extends: .tests
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
variables:
CMAKE_ADDITIONAL_OPTIONS: -DWITH_PKCS11_URI=ON
.tumbleweed: .tumbleweed:
extends: .tests extends: .tests
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$TUMBLEWEED_BUILD image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$TUMBLEWEED_BUILD
script:
# torture_gssapi_key_exchange_null is excluded because of a bug
# https://bugzilla.opensuse.org/show_bug.cgi?id=1254680
- cmake $CMAKE_OPTIONS $CMAKE_ADDITIONAL_OPTIONS .. &&
make -j$(nproc) &&
ctest --output-on-failure -E "^torture_gssapi_key_exchange_null$"
.centos:
extends: .tests
variables:
OPENSSL_ENABLE_SHA1_SIGNATURES: 1
.centos10:
extends: .centos
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$CENTOS10_BUILD
.centos9:
extends: .centos
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$CENTOS9_BUILD
# Unit testing only, no client and pkd testing, because cwrap is not available
# for MinGW
.mingw:
extends: .tests
variables:
WINEDEBUG: -all
script:
- $WINEBIN $CMAKE_DEFAULT_OPTIONS
-DWITH_SFTP=ON
-DWITH_SERVER=ON
-DWITH_ZLIB=ON
-DWITH_PCAP=ON
-DWITH_FIDO2=ON
-DUNIT_TESTING=ON .. &&
make -j$(nproc) &&
ctest --output-on-failure -E torture_rand
.fips: .fips:
extends: .tests extends: .tests
@@ -107,7 +146,7 @@ review:
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
script: script:
- ERROR=0 - ERROR=0
codespell --ignore-words-list=keypair,sorce,ned,nd,ue || ERROR=1; codespell --ignore-words-list=keypair,sorce,ned,nd,ue,pendin || ERROR=1;
./.gitlab-ci/clang-format-check.sh || ERROR=1; ./.gitlab-ci/clang-format-check.sh || ERROR=1;
./.gitlab-ci/git-check-signoff-trailer.sh ${CI_MERGE_REQUEST_DIFF_BASE_SHA} || ERROR=1; ./.gitlab-ci/git-check-signoff-trailer.sh ${CI_MERGE_REQUEST_DIFF_BASE_SHA} || ERROR=1;
./.gitlab-ci/shellcheck.sh || ERROR=1; ./.gitlab-ci/shellcheck.sh || ERROR=1;
@@ -122,13 +161,31 @@ review:
############################################################################### ###############################################################################
# CentOS builds # # CentOS builds #
############################################################################### ###############################################################################
centos9s/openssl_3.0.x/x86_64: centos10s/openssl_3.5.x/x86_64:
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$CENTOS9_BUILD extends: .centos10
extends: .tests
variables: variables:
CMAKE_ADDITIONAL_OPTIONS: -DWITH_PKCS11_URI=ON CMAKE_ADDITIONAL_OPTIONS: -DWITH_PKCS11_URI=ON -DWITH_PKCS11_PROVIDER=ON
script:
- cmake $CMAKE_OPTIONS $CMAKE_ADDITIONAL_OPTIONS .. &&
make -j$(nproc) &&
ctest --output-on-failure
centos10s/openssl_3.5.x/x86_64/fips:
extends: .fips
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$CENTOS10_BUILD
variables:
CMAKE_ADDITIONAL_OPTIONS: -DWITH_PKCS11_URI=ON -DWITH_PKCS11_PROVIDER=ON
OPENSSL_ENABLE_SHA1_SIGNATURES: 1
script:
- cmake $CMAKE_OPTIONS $CMAKE_ADDITIONAL_OPTIONS .. &&
make -j$(nproc) &&
OPENSSL_FORCE_FIPS_MODE=1 ctest --output-on-failure
centos9s/openssl_3.5.x/x86_64:
extends: .centos9
variables:
CMAKE_ADDITIONAL_OPTIONS: -DWITH_PKCS11_URI=ON -DWITH_PKCS11_PROVIDER=ON
script: script:
- export OPENSSL_ENABLE_SHA1_SIGNATURES=1
- cmake $CMAKE_OPTIONS $CMAKE_ADDITIONAL_OPTIONS .. && - cmake $CMAKE_OPTIONS $CMAKE_ADDITIONAL_OPTIONS .. &&
make -j$(nproc) && make -j$(nproc) &&
ctest --output-on-failure ctest --output-on-failure
@@ -139,14 +196,17 @@ centos9s/mbedtls_2.x/x86_64:
variables: variables:
CMAKE_ADDITIONAL_OPTIONS: "-DWITH_MBEDTLS=ON -DWITH_DEBUG_CRYPTO=ON -DWITH_BLOWFISH_CIPHER=OFF" CMAKE_ADDITIONAL_OPTIONS: "-DWITH_MBEDTLS=ON -DWITH_DEBUG_CRYPTO=ON -DWITH_BLOWFISH_CIPHER=OFF"
centos9s/openssl_3.0.x/x86_64/fips: centos9s/openssl_3.5.x/x86_64/fips:
extends: .fips extends: .fips
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$CENTOS9_BUILD image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$CENTOS9_BUILD
variables:
OPENSSL_ENABLE_SHA1_SIGNATURES: 1
script: script:
- export OPENSSL_ENABLE_SHA1_SIGNATURES=1 # torture_gssapi_key_exchange_* tests are excluded because gssapi-keyex is disabled
# by OpenSSH in FIPS mode in RHEL 9
- cmake $CMAKE_OPTIONS $CMAKE_ADDITIONAL_OPTIONS .. && - cmake $CMAKE_OPTIONS $CMAKE_ADDITIONAL_OPTIONS .. &&
make -j$(nproc) && make -j$(nproc) &&
OPENSSL_FORCE_FIPS_MODE=1 ctest --output-on-failure OPENSSL_FORCE_FIPS_MODE=1 ctest --output-on-failure -E "^torture_gssapi_key_exchange.*"
centos8s/openssl_1.1.1/x86_64: centos8s/openssl_1.1.1/x86_64:
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$CENTOS8_BUILD image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$CENTOS8_BUILD
@@ -162,9 +222,11 @@ centos8s/openssl_1.1.1/x86_64/fips:
extends: .fips extends: .fips
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$CENTOS8_BUILD image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$CENTOS8_BUILD
script: script:
# torture_gssapi_key_exchange_* and torture_gssapi_server_key_exchange_* tests are excluded
# because gssapi-keyex is not allowed in FIPS mode in RHEL 8
- cmake $CMAKE_OPTIONS $CMAKE_ADDITIONAL_OPTIONS .. && - cmake $CMAKE_OPTIONS $CMAKE_ADDITIONAL_OPTIONS .. &&
make -j$(nproc) && make -j$(nproc) &&
OPENSSL_FORCE_FIPS_MODE=1 ctest --output-on-failure OPENSSL_FORCE_FIPS_MODE=1 ctest --output-on-failure -E "^torture_gssapi.*key_exchange.*"
############################################################################### ###############################################################################
# Fedora builds # # Fedora builds #
@@ -177,14 +239,16 @@ fedora/docs:
extends: .build extends: .build
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
script: script:
- cmake .. && make docs_coverage && make docs - cmake -DWITH_INTERNAL_DOC=ON .. && make docs_coverage && make docs
coverage: '/^Documentation coverage is \d+.\d+%/' coverage: '/^Documentation coverage is \d+.\d+%/'
fedora/ninja: fedora/ninja:
extends: .fedora extends: .fedora
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
variables:
CTEST_OUTPUT_ON_FAILURE: 1
script: script:
- cmake -G Ninja $CMAKE_OPTIONS ../ && ninja && CTEST_OUTPUT_ON_FAILURE=1 ninja test - cmake -G Ninja $CMAKE_OPTIONS ../ && ninja && ninja test
fedora/coverage: fedora/coverage:
extends: .fedora extends: .fedora
@@ -204,15 +268,15 @@ fedora/coverage:
coverage_format: cobertura coverage_format: cobertura
path: obj/coverage_xml.xml path: obj/coverage_xml.xml
fedora/openssl_3.0.x/x86_64: fedora/openssl_3.x/x86_64:
extends: .fedora extends: .fedora
fedora/openssl_3.0.x/x86_64/pkcs11-provider: fedora/openssl_3.x/x86_64/pkcs11-provider:
variables: variables:
CMAKE_ADDITIONAL_OPTIONS: -DWITH_PKCS11_URI=ON -DWITH_PKCS11_PROVIDER=ON CMAKE_ADDITIONAL_OPTIONS: -DWITH_PKCS11_URI=ON -DWITH_PKCS11_PROVIDER=ON
extends: .fedora extends: .fedora
fedora/openssl_3.0.x/x86_64/minimal: fedora/openssl_3.x/x86_64/minimal:
extends: .fedora extends: .fedora
variables: variables:
script: script:
@@ -222,9 +286,10 @@ fedora/openssl_3.0.x/x86_64/minimal:
-DWITH_SERVER=OFF -DWITH_SERVER=OFF
-DWITH_ZLIB=OFF -DWITH_ZLIB=OFF
-DWITH_PCAP=OFF -DWITH_PCAP=OFF
-DWITH_GSSAPI=OFF
-DWITH_GEX=OFF
-DUNIT_TESTING=ON -DUNIT_TESTING=ON
-DCLIENT_TESTING=ON -DCLIENT_TESTING=ON .. &&
-DWITH_GEX=OFF .. &&
make -j$(nproc) make -j$(nproc)
.valgrind: .valgrind:
@@ -236,6 +301,37 @@ fedora/openssl_3.0.x/x86_64/minimal:
make test_memcheck make test_memcheck
- cat Testing/Temporary/MemoryChecker.*.log | wc -l | grep "^0$" - cat Testing/Temporary/MemoryChecker.*.log | wc -l | grep "^0$"
fedora/libressl/x86_64:
extends: .fedora
stage: test
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
variables:
LIBRESSL_VERSION: "4.2.1"
CMAKE_ADDITIONAL_OPTIONS: >
-DCMAKE_C_FLAGS="-I/opt/libressl/include"
-DOPENSSL_ROOT_DIR=/opt/libressl
-DOPENSSL_INCLUDE_DIR=/opt/libressl/include
-DOPENSSL_CRYPTO_LIBRARY=/opt/libressl/lib/libcrypto.so
-DOPENSSL_SSL_LIBRARY=/opt/libressl/lib/libssl.so
-DWITH_GSSAPI=OFF
-DWITH_FIDO2=OFF
before_script:
- *build
- dnf install -y perl-core autoconf automake libtool pkgconf-pkg-config
- curl -LO https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl-${LIBRESSL_VERSION}.tar.gz
- tar xf libressl-${LIBRESSL_VERSION}.tar.gz
- cd libressl-${LIBRESSL_VERSION}
- ./configure --prefix=/opt/libressl
- make -j$(nproc)
- make install
- cd ..
script:
- export PKG_CONFIG_PATH=/opt/libressl/lib/pkgconfig
- export LD_LIBRARY_PATH=/opt/libressl/lib
- cmake $CMAKE_OPTIONS $CMAKE_ADDITIONAL_OPTIONS .. &&
make -j$(nproc) &&
ctest --output-on-failure
# The PKCS#11 support is turned off as it brings dozens of memory issues from # The PKCS#11 support is turned off as it brings dozens of memory issues from
# engine_pkcs11 or openssl itself # engine_pkcs11 or openssl itself
fedora/valgrind/openssl: fedora/valgrind/openssl:
@@ -306,47 +402,26 @@ fedora/undefined-sanitizer:
fedora/libgcrypt/x86_64: fedora/libgcrypt/x86_64:
extends: .fedora extends: .fedora
variables: variables:
CMAKE_ADDITIONAL_OPTIONS: "-DWITH_GCRYPT=ON -DWITH_DEBUG_CRYPTO=ON" CMAKE_ADDITIONAL_OPTIONS: "-DWITH_GCRYPT=ON"
fedora/mbedtls_2.x/x86_64: fedora/mbedtls_3.x/x86_64:
extends: .fedora extends: .fedora
variables: variables:
CMAKE_ADDITIONAL_OPTIONS: "-DWITH_MBEDTLS=ON -DWITH_DEBUG_CRYPTO=ON " CMAKE_ADDITIONAL_OPTIONS: "-DWITH_MBEDTLS=ON"
# Unit testing only, no client and pkd testing, because cwrap is not available
# for MinGW
fedora/mingw64: fedora/mingw64:
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$MINGW_BUILD image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$MINGW_BUILD
extends: .tests extends: .mingw
script: variables:
- export WINEPATH=/usr/x86_64-w64-mingw32/sys-root/mingw/bin WINEPATH: /usr/x86_64-w64-mingw32/sys-root/mingw/bin
- export WINEDEBUG=-all WINEBIN: mingw64-cmake
- mingw64-cmake $CMAKE_DEFAULT_OPTIONS
-DWITH_SFTP=ON
-DWITH_SERVER=ON
-DWITH_ZLIB=ON
-DWITH_PCAP=ON
-DUNIT_TESTING=ON .. &&
make -j$(nproc) &&
ctest --output-on-failure
# Unit testing only, no client and pkd testing, because cwrap is not available
# for MinGW
fedora/mingw32: fedora/mingw32:
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$MINGW_BUILD image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$MINGW_BUILD
extends: .tests extends: .mingw
script: variables:
- export WINEPATH=/usr/i686-w64-mingw32/sys-root/mingw/bin WINEPATH: /usr/i686-w64-mingw32/sys-root/mingw/bin
- export WINEDEBUG=-all WINEBIN: mingw32-cmake
- mingw32-cmake $CMAKE_DEFAULT_OPTIONS
-DWITH_SFTP=ON
-DWITH_SERVER=ON
-DWITH_ZLIB=ON
-DWITH_PCAP=ON
-DUNIT_TESTING=ON .. &&
make -j$(nproc) &&
ctest --output-on-failure
############################################################################### ###############################################################################
# Fedora csbuild # # Fedora csbuild #
@@ -355,6 +430,8 @@ fedora/mingw32:
stage: analysis stage: analysis
variables: variables:
GIT_DEPTH: "100" GIT_DEPTH: "100"
CSCPPC_ADD_OPTS: "--library=./.gitlab-ci/cmocka.cfg"
CMAKE_OPTIONS: "-DCMAKE_BUILD_TYPE=Debug -DPICKY_DEVELOPER=ON -DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON -DFUZZ_TESTING=ON"
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
before_script: before_script:
- | - |
@@ -372,6 +449,14 @@ fedora/mingw32:
git branch --contains $CI_COMMIT_BEFORE_SHA 2>/dev/null || export CI_COMMIT_BEFORE_SHA=$(git rev-parse "${CI_COMMIT_SHA}~20") git branch --contains $CI_COMMIT_BEFORE_SHA 2>/dev/null || export CI_COMMIT_BEFORE_SHA=$(git rev-parse "${CI_COMMIT_SHA}~20")
export CI_COMMIT_RANGE="$CI_COMMIT_BEFORE_SHA..$CI_COMMIT_SHA" export CI_COMMIT_RANGE="$CI_COMMIT_BEFORE_SHA..$CI_COMMIT_SHA"
script:
- csbuild
--build-dir=obj-csbuild
--build-cmd "rm -rf CMakeFiles CMakeCache.txt && cmake $CMAKE_OPTIONS $CMAKE_ADDITIONAL_OPTIONS @SRCDIR@ && make clean && make -j$(nproc)"
--git-commit-range $CI_COMMIT_RANGE
--color
--print-current --print-fixed
tags: tags:
- saas-linux-small-amd64 - saas-linux-small-amd64
except: except:
@@ -384,36 +469,75 @@ fedora/mingw32:
paths: paths:
- obj-csbuild/ - obj-csbuild/
fedora/csbuild/openssl_3.0.x: fedora/csbuild/openssl_3.x:
extends: .csbuild extends: .csbuild
script:
- csbuild
--build-dir=obj-csbuild
--build-cmd "rm -rf CMakeFiles CMakeCache.txt && cmake -DCMAKE_BUILD_TYPE=Debug -DPICKY_DEVELOPER=ON -DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON -DFUZZ_TESTING=ON @SRCDIR@ && make clean && make -j$(nproc)"
--git-commit-range $CI_COMMIT_RANGE
--color
--print-current --print-fixed
fedora/csbuild/libgcrypt: fedora/csbuild/libgcrypt:
extends: .csbuild extends: .csbuild
script: variables:
- csbuild CMAKE_ADDITIONAL_OPTIONS: -DWITH_GCRYPT=ON
--build-dir=obj-csbuild
--build-cmd "rm -rf CMakeFiles CMakeCache.txt && cmake -DCMAKE_BUILD_TYPE=Debug -DPICKY_DEVELOPER=ON -DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON -DFUZZ_TESTING=ON -DWITH_GCRYPT=ON @SRCDIR@ && make clean && make -j$(nproc)"
--git-commit-range $CI_COMMIT_RANGE
--color
--print-current --print-fixed
fedora/csbuild/mbedtls: fedora/csbuild/mbedtls:
extends: .csbuild extends: .csbuild
script: variables:
- csbuild CMAKE_ADDITIONAL_OPTIONS: -DWITH_MBEDTLS=ON
--build-dir=obj-csbuild
--build-cmd "rm -rf CMakeFiles CMakeCache.txt && cmake -DCMAKE_BUILD_TYPE=Debug -DPICKY_DEVELOPER=ON -DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON -DFUZZ_TESTING=ON -DWITH_MBEDTLS=ON @SRCDIR@ && make clean && make -j$(nproc)"
--git-commit-range $CI_COMMIT_RANGE
--color
--print-current --print-fixed
###############################################################################
# Fedora abidiff #
###############################################################################
fedora/abidiff:
stage: analysis
variables:
GIT_DEPTH: "100"
CMAKE_OPTIONS: $CMAKE_DEFAULT_DEBUG_OPTIONS $CMAKE_BUILD_OPTIONS
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
before_script:
- uname -a
- cat /etc/os-release
- mount
- df -h
- cat /proc/swaps
- free -h
- |
# for merge requests
if [[ -n "$CI_MERGE_REQUEST_DIFF_BASE_SHA" ]]; then
export CI_COMMIT_BEFORE_SHA="$CI_MERGE_REQUEST_DIFF_BASE_SHA"
fi
# for branches run
if [[ -z "$CI_COMMIT_BEFORE_SHA" ]]; then
export CI_COMMIT_BEFORE_SHA=$(git rev-parse "${CI_COMMIT_SHA}~20")
fi
# Check if the commit exists in this branch
# This is not the case for a force push
git branch --contains $CI_COMMIT_BEFORE_SHA 2>/dev/null || export CI_COMMIT_BEFORE_SHA=$(git rev-parse "${CI_COMMIT_SHA}~20")
- mkdir -p obj-${CI_COMMIT_BEFORE_SHA}
- mkdir -p obj-${CI_COMMIT_SHA}
- export INSTALL_DIR1=$(pwd)/install/${CI_COMMIT_BEFORE_SHA}
- export INSTALL_DIR2=$(pwd)/install/${CI_COMMIT_SHA}
script:
- git checkout ${CI_COMMIT_BEFORE_SHA}
- pushd obj-${CI_COMMIT_BEFORE_SHA}
- cmake ${CMAKE_OPTIONS} -DCMAKE_INSTALL_PREFIX=${INSTALL_DIR1} .. &&
make -j$(nproc) && make -j$(nproc) install
- popd
- ls -l ${INSTALL_DIR1}/lib*/
- git checkout ${CI_COMMIT_SHA}
- pushd obj-${CI_COMMIT_SHA}
- cmake ${CMAKE_OPTIONS} -DCMAKE_INSTALL_PREFIX=${INSTALL_DIR2} .. &&
make -j$(nproc) && make -j$(nproc) install
- popd
- ls -l ${INSTALL_DIR2}/lib*/
- ./.gitlab-ci/checkabi.sh ${INSTALL_DIR1} ${INSTALL_DIR2}
tags:
- saas-linux-small-amd64
except:
- tags
only:
- merge_requests
############################################################################### ###############################################################################
# Ubuntu builds # # Ubuntu builds #
@@ -421,12 +545,18 @@ fedora/csbuild/mbedtls:
ubuntu/openssl_3.0.x/x86_64: ubuntu/openssl_3.0.x/x86_64:
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$UBUNTU_BUILD image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$UBUNTU_BUILD
extends: .tests extends: .tests
script:
# torture_gssapi_key_exchange_null is excluded because of a bug
# https://bugs.launchpad.net/ubuntu/+source/openssh/+bug/2134527
- cmake $CMAKE_OPTIONS $CMAKE_ADDITIONAL_OPTIONS .. &&
make -j$(nproc) &&
ctest --output-on-failure -E "^torture_gssapi_key_exchange_null$"
############################################################################### ###############################################################################
# Alpine builds # # Alpine builds #
############################################################################### ###############################################################################
alpine/openssl_3.0.x/musl: alpine/openssl_3.x/musl:
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$ALPINE_BUILD image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$ALPINE_BUILD
extends: .tests extends: .tests
script: script:
@@ -443,10 +573,10 @@ alpine/openssl_3.0.x/musl:
############################################################################### ###############################################################################
# Tumbleweed builds # # Tumbleweed builds #
############################################################################### ###############################################################################
tumbleweed/openssl_3.0.x/x86_64/gcc: tumbleweed/openssl_3.x/x86_64/gcc:
extends: .tumbleweed extends: .tumbleweed
tumbleweed/openssl_3.0.x/x86/gcc: tumbleweed/openssl_3.x/x86/gcc:
extends: .tumbleweed extends: .tumbleweed
script: script:
- cmake - cmake
@@ -459,12 +589,12 @@ tumbleweed/openssl_3.0.x/x86/gcc:
-DUNIT_TESTING=ON .. && -DUNIT_TESTING=ON .. &&
make -j$(nproc) make -j$(nproc)
tumbleweed/openssl_3.0.x/x86_64/gcc7: tumbleweed/openssl_3.x/x86_64/gcc7:
extends: .tumbleweed extends: .tumbleweed
variables: variables:
CMAKE_ADDITIONAL_OPTIONS: "-DCMAKE_C_COMPILER=gcc-7 -DCMAKE_CXX_COMPILER=g++-7" CMAKE_ADDITIONAL_OPTIONS: "-DCMAKE_C_COMPILER=gcc-7 -DCMAKE_CXX_COMPILER=g++-7"
tumbleweed/openssl_3.0.x/x86/gcc7: tumbleweed/openssl_3.x/x86/gcc7:
extends: .tumbleweed extends: .tumbleweed
script: script:
- cmake - cmake
@@ -476,7 +606,7 @@ tumbleweed/openssl_3.0.x/x86/gcc7:
make -j$(nproc) && make -j$(nproc) &&
ctest --output-on-failure ctest --output-on-failure
tumbleweed/openssl_3.0.x/x86_64/clang: tumbleweed/openssl_3.x/x86_64/clang:
extends: .tumbleweed extends: .tumbleweed
variables: variables:
CMAKE_ADDITIONAL_OPTIONS: "-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++" CMAKE_ADDITIONAL_OPTIONS: "-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++"
@@ -486,13 +616,19 @@ tumbleweed/mbedtls-3.6.x/x86_64/gcc:
variables: variables:
CMAKE_ADDITIONAL_OPTIONS: "-DKRB5_CONFIG=/usr/lib/mit/bin/krb5-config -DWITH_MBEDTLS=ON -DWITH_DEBUG_CRYPTO=ON -DWITH_BLOWFISH_CIPHER=OFF " CMAKE_ADDITIONAL_OPTIONS: "-DKRB5_CONFIG=/usr/lib/mit/bin/krb5-config -DWITH_MBEDTLS=ON -DWITH_DEBUG_CRYPTO=ON -DWITH_BLOWFISH_CIPHER=OFF "
tumbleweed/mbedtls-3.6.x/x86_64/clang:
extends: .tumbleweed
variables:
CMAKE_ADDITIONAL_OPTIONS: "-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DKRB5_CONFIG=/usr/lib/mit/bin/krb5-config -DWITH_MBEDTLS=ON -DWITH_DEBUG_CRYPTO=ON -DWITH_BLOWFISH_CIPHER=OFF "
tumbleweed/static-analysis: tumbleweed/static-analysis:
extends: .tests extends: .tests
stage: analysis stage: analysis
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$TUMBLEWEED_BUILD image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$TUMBLEWEED_BUILD
variables:
CCC_CC: clang
CCC_CXX: clang++
script: script:
- export CCC_CC=clang
- export CCC_CXX=clang++
- scan-build cmake - scan-build cmake
-DCMAKE_BUILD_TYPE=Debug -DCMAKE_BUILD_TYPE=Debug
-DCMAKE_C_COMPILER=clang -DCMAKE_C_COMPILER=clang
@@ -516,19 +652,12 @@ tumbleweed/static-analysis:
freebsd/openssl_1.1.1/x86_64: freebsd/openssl_1.1.1/x86_64:
image: image:
extends: .tests extends: .tests
variables:
CMAKE_OPTIONS: $CMAKE_DEFAULT_OPTIONS -DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON -DUNIT_TESTING=ON
before_script: before_script:
- mkdir -p obj && cd obj && cmake - mkdir -p obj && cd obj && cmake $CMAKE_OPTIONS ..
-DCMAKE_BUILD_TYPE=RelWithDebInfo
-DPICKY_DEVELOPER=ON
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON
-DUNIT_TESTING=ON ..
script: script:
- cmake $CMAKE_DEFAULT_OPTIONS - cmake $CMAKE_OPTIONS .. &&
-DWITH_SFTP=ON
-DWITH_SERVER=ON
-DWITH_ZLIB=ON
-DWITH_PCAP=ON
-DUNIT_TESTING=ON .. &&
make && make &&
ctest --output-on-failure ctest --output-on-failure
tags: tags:
@@ -538,7 +667,6 @@ freebsd/openssl_1.1.1/x86_64:
- branches@libssh/libssh-mirror - branches@libssh/libssh-mirror
- branches@cryptomilk/libssh-mirror - branches@cryptomilk/libssh-mirror
- branches@jjelen/libssh-mirror - branches@jjelen/libssh-mirror
- branches@marco.fortina/libssh-mirror
############################################################################### ###############################################################################
@@ -547,9 +675,7 @@ freebsd/openssl_1.1.1/x86_64:
# 2024-05-13: These jobs run out of the stages as they take extremely long and # 2024-05-13: These jobs run out of the stages as they take extremely long and
# usually timeout with the update to Gitlab 17.0 # usually timeout with the update to Gitlab 17.0
.vs: .vs:
stage: analysis stage: test
needs: []
allow_failure: true
cache: cache:
key: vcpkg.${CI_JOB_NAME} key: vcpkg.${CI_JOB_NAME}
paths: paths:
@@ -579,13 +705,14 @@ freebsd/openssl_1.1.1/x86_64:
- vcpkg install cmocka - vcpkg install cmocka
- vcpkg install openssl - vcpkg install openssl
- vcpkg install zlib - vcpkg install zlib
- vcpkg install libfido2
- vcpkg integrate install - vcpkg integrate install
- mkdir -p obj; if ($?) {cd obj}; if (! $?) {exit 1} - mkdir -p obj; if ($?) {cd obj}; if (! $?) {exit 1}
- cmake - cmake
-A $PLATFORM -A $PLATFORM
-DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake -DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake
-DPICKY_DEVELOPER=ON -DPICKY_DEVELOPER=ON
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON -DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON -DWITH_FIDO2=ON
-DUNIT_TESTING=ON .. -DUNIT_TESTING=ON ..
visualstudio/x86_64: visualstudio/x86_64:
@@ -641,3 +768,38 @@ coverity:
when: on_failure when: on_failure
paths: paths:
- obj/cov-int/*.txt - obj/cov-int/*.txt
###############################################################################
# MacOS #
###############################################################################
.macos:
extends: .build_options
tags:
- saas-macos-medium-m1
image: macos-14-xcode-15
before_script:
- echo "MacOS runner started"
- brew update
- brew install cmake openssl cmocka doxygen
- mkdir obj && cd obj
only:
- branches@libssh/libssh-mirror
- branches@cryptomilk/libssh-mirror
- branches@jjelen/libssh-mirror
# TODO add -DFUZZ_TESTING=ON clang cant find _LLVMFuzzerInitialize on arm64
macos-m1:
extends: .macos
variables:
HOMEBREW_NO_AUTO_UPDATE: 1
CMAKE_TEST_OPTIONS: "-DUNIT_TESTING=ON"
stage: test
script:
- cmake $CMAKE_OPTIONS .. &&
make -j$(sysctl -n hw.logicalcpu) &&
ctest --output-on-failure
artifacts:
expire_in: 1 week
when: on_failure
paths:
- obj/

42
.gitlab-ci/checkabi.sh Executable file
View File

@@ -0,0 +1,42 @@
#!/bin/bash
INSTALL_DIR1=${1}
INSTALL_DIR2=${2}
abidiff \
--headers-dir1 "${INSTALL_DIR1}/include/libssh/" \
--headers-dir2 "${INSTALL_DIR2}/include/libssh/" \
"${INSTALL_DIR1}/lib64/libssh.so" \
"${INSTALL_DIR2}/lib64/libssh.so" \
--fail-no-debug-info
abiret=$?
ABIDIFF_ERROR=$(((abiret & 0x01) != 0))
ABIDIFF_USAGE_ERROR=$(((abiret & 0x02) != 0))
ABIDIFF_ABI_CHANGE=$(((abiret & 0x04) != 0))
ABIDIFF_ABI_INCOMPATIBLE_CHANGE=$(((abiret & 0x08) != 0))
ABIDIFF_UNKNOWN_BIT_SET=$(((abiret & 0xf0) != 0))
if [ $ABIDIFF_ERROR -ne 0 ]; then
echo "abidiff reported ABIDIFF_ERROR."
exit 1
fi
if [ $ABIDIFF_USAGE_ERROR -ne 0 ]; then
echo "abidiff reported ABIDIFF_USAGE_ERROR."
exit 1
fi
if [ $ABIDIFF_UNKNOWN_BIT_SET -ne 0 ]; then
echo "abidiff reported ABIDIFF_UNKNOWN_BIT_SET."
exit 1
fi
if [ $ABIDIFF_ABI_INCOMPATIBLE_CHANGE -ne 0 ]; then
echo "abidiff result ABIDIFF_ABI_INCOMPATIBLE_CHANGE, this breaks the API!"
exit 1
fi
if [ $ABIDIFF_ABI_CHANGE -ne 0 ]; then
echo "Ignoring abidiff result ABI_CHANGE"
fi
exit 0

475
.gitlab-ci/cmocka.cfg Normal file
View File

@@ -0,0 +1,475 @@
<?xml version="1.0"?>
<!--
cppcheck library configuration for cmocka
This file provides cppcheck with information about cmocka's assertion functions
and their behavior, particularly that assertion failures do not return.
This helps cppcheck understand that after assert_non_null(ptr), the pointer
is guaranteed to be non-NULL, eliminating false positives like:
- nullPointerArithmeticOutOfMemory
- nullPointer
- etc.
Usage:
cppcheck --library=cmocka.cfg [other options] <source files>
For more information on cppcheck library format, see:
https://cppcheck.sourceforge.io/manual.html#library-configuration
-->
<def format="2">
<!-- Core functions -->
<function name="_fail">
<noreturn>true</noreturn>
<arg nr="1" direction="in">
<not-null/>
</arg>
<arg nr="2" direction="in"/>
</function>
<!-- Boolean assertions -->
<function name="_assert_true">
<arg nr="1" direction="in">
<valid>arg1 != 0</valid>
</arg>
<arg nr="2" direction="in">
<not-null/>
</arg>
<arg nr="3" direction="in">
<not-null/>
</arg>
<arg nr="4" direction="in"/>
</function>
<function name="_assert_false">
<arg nr="1" direction="in">
<valid>arg1 == 0</valid>
</arg>
<arg nr="2" direction="in">
<not-null/>
</arg>
<arg nr="3" direction="in">
<not-null/>
</arg>
<arg nr="4" direction="in"/>
</function>
<!-- Pointer assertions -->
<function name="_assert_ptr_equal_msg">
<arg nr="1" direction="in">
<valid>arg1 == arg2</valid>
</arg>
<arg nr="2" direction="in"/>
<arg nr="3" direction="in">
<not-null/>
</arg>
<arg nr="4" direction="in"/>
<arg nr="5" direction="in"/>
</function>
<function name="_assert_ptr_not_equal_msg">
<arg nr="1" direction="in">
<valid>arg1 != arg2</valid>
</arg>
<arg nr="2" direction="in"/>
<arg nr="3" direction="in">
<not-null/>
</arg>
<arg nr="4" direction="in"/>
<arg nr="5" direction="in"/>
</function>
<!-- Integer assertions -->
<function name="_assert_int_equal">
<arg nr="1" direction="in">
<valid>arg1 == arg2</valid>
</arg>
<arg nr="2" direction="in"/>
<arg nr="3" direction="in">
<not-null/>
</arg>
<arg nr="4" direction="in"/>
</function>
<function name="_assert_int_not_equal">
<arg nr="1" direction="in">
<valid>arg1 != arg2</valid>
</arg>
<arg nr="2" direction="in"/>
<arg nr="3" direction="in">
<not-null/>
</arg>
<arg nr="4" direction="in"/>
</function>
<function name="_assert_uint_equal">
<arg nr="1" direction="in">
<valid>arg1 == arg2</valid>
</arg>
<arg nr="2" direction="in"/>
<arg nr="3" direction="in">
<not-null/>
</arg>
<arg nr="4" direction="in"/>
</function>
<function name="_assert_uint_not_equal">
<arg nr="1" direction="in">
<valid>arg1 != arg2</valid>
</arg>
<arg nr="2" direction="in"/>
<arg nr="3" direction="in">
<not-null/>
</arg>
<arg nr="4" direction="in"/>
</function>
<!-- Float/double assertions -->
<function name="_assert_float_equal">
<arg nr="1" direction="in"/>
<arg nr="2" direction="in"/>
<arg nr="3" direction="in"/>
<arg nr="4" direction="in">
<not-null/>
</arg>
<arg nr="5" direction="in"/>
</function>
<function name="_assert_float_not_equal">
<arg nr="1" direction="in"/>
<arg nr="2" direction="in"/>
<arg nr="3" direction="in"/>
<arg nr="4" direction="in">
<not-null/>
</arg>
<arg nr="5" direction="in"/>
</function>
<function name="_assert_double_equal">
<arg nr="1" direction="in"/>
<arg nr="2" direction="in"/>
<arg nr="3" direction="in"/>
<arg nr="4" direction="in">
<not-null/>
</arg>
<arg nr="5" direction="in"/>
</function>
<function name="_assert_double_not_equal">
<arg nr="1" direction="in"/>
<arg nr="2" direction="in"/>
<arg nr="3" direction="in"/>
<arg nr="4" direction="in">
<not-null/>
</arg>
<arg nr="5" direction="in"/>
</function>
<!-- String assertions -->
<function name="_assert_string_equal">
<arg nr="1" direction="in">
<not-null/>
</arg>
<arg nr="2" direction="in">
<not-null/>
</arg>
<arg nr="3" direction="in">
<not-null/>
</arg>
<arg nr="4" direction="in"/>
</function>
<function name="_assert_string_not_equal">
<arg nr="1" direction="in">
<not-null/>
</arg>
<arg nr="2" direction="in">
<not-null/>
</arg>
<arg nr="3" direction="in">
<not-null/>
</arg>
<arg nr="4" direction="in"/>
</function>
<!-- Memory assertions -->
<function name="_assert_memory_equal">
<arg nr="1" direction="in">
<not-null/>
</arg>
<arg nr="2" direction="in">
<not-null/>
</arg>
<arg nr="3" direction="in"/>
<arg nr="4" direction="in">
<not-null/>
</arg>
<arg nr="5" direction="in"/>
</function>
<function name="_assert_memory_not_equal">
<arg nr="1" direction="in">
<not-null/>
</arg>
<arg nr="2" direction="in">
<not-null/>
</arg>
<arg nr="3" direction="in"/>
<arg nr="4" direction="in">
<not-null/>
</arg>
<arg nr="5" direction="in"/>
</function>
<!-- Range assertions -->
<function name="_assert_int_in_range">
<arg nr="1" direction="in">
<valid>arg2 &lt;= arg1 &amp;&amp; arg1 &lt;= arg3</valid>
</arg>
<arg nr="2" direction="in"/>
<arg nr="3" direction="in"/>
<arg nr="4" direction="in">
<not-null/>
</arg>
<arg nr="5" direction="in"/>
</function>
<function name="_assert_int_not_in_range">
<arg nr="1" direction="in">
<valid>arg1 &lt; arg2 || arg3 &lt; arg1</valid>
</arg>
<arg nr="2" direction="in"/>
<arg nr="3" direction="in"/>
<arg nr="4" direction="in">
<not-null/>
</arg>
<arg nr="5" direction="in"/>
</function>
<function name="_assert_uint_in_range">
<arg nr="1" direction="in">
<valid>arg2 &lt;= arg1 &amp;&amp; arg1 &lt;= arg3</valid>
</arg>
<arg nr="2" direction="in"/>
<arg nr="3" direction="in"/>
<arg nr="4" direction="in">
<not-null/>
</arg>
<arg nr="5" direction="in"/>
</function>
<function name="_assert_uint_not_in_range">
<arg nr="1" direction="in">
<valid>arg1 &lt; arg2 || arg3 &lt; arg1</valid>
</arg>
<arg nr="2" direction="in"/>
<arg nr="3" direction="in"/>
<arg nr="4" direction="in">
<not-null/>
</arg>
<arg nr="5" direction="in"/>
</function>
<function name="_assert_float_in_range">
<arg nr="1" direction="in"/>
<arg nr="2" direction="in"/>
<arg nr="3" direction="in"/>
<arg nr="4" direction="in"/>
<arg nr="5" direction="in">
<not-null/>
</arg>
<arg nr="6" direction="in"/>
</function>
<function name="_assert_float_not_in_range">
<arg nr="1" direction="in"/>
<arg nr="2" direction="in"/>
<arg nr="3" direction="in"/>
<arg nr="4" direction="in"/>
<arg nr="5" direction="in">
<not-null/>
</arg>
<arg nr="6" direction="in"/>
</function>
<!-- Set assertions -->
<function name="_assert_int_in_set">
<arg nr="1" direction="in"/>
<arg nr="2" direction="in">
<not-null/>
</arg>
<arg nr="3" direction="in"/>
<arg nr="4" direction="in">
<not-null/>
</arg>
<arg nr="5" direction="in">
<not-null/>
</arg>
<arg nr="6" direction="in"/>
</function>
<function name="_assert_int_not_in_set">
<arg nr="1" direction="in"/>
<arg nr="2" direction="in">
<not-null/>
</arg>
<arg nr="3" direction="in"/>
<arg nr="4" direction="in">
<not-null/>
</arg>
<arg nr="5" direction="in">
<not-null/>
</arg>
<arg nr="6" direction="in"/>
</function>
<function name="_assert_uint_in_set">
<arg nr="1" direction="in"/>
<arg nr="2" direction="in">
<not-null/>
</arg>
<arg nr="3" direction="in"/>
<arg nr="4" direction="in">
<not-null/>
</arg>
<arg nr="5" direction="in">
<not-null/>
</arg>
<arg nr="6" direction="in"/>
</function>
<function name="_assert_uint_not_in_set">
<arg nr="1" direction="in"/>
<arg nr="2" direction="in">
<not-null/>
</arg>
<arg nr="3" direction="in"/>
<arg nr="4" direction="in">
<not-null/>
</arg>
<arg nr="5" direction="in">
<not-null/>
</arg>
<arg nr="6" direction="in"/>
</function>
<function name="_assert_not_in_set">
<arg nr="1" direction="in"/>
<arg nr="2" direction="in">
<not-null/>
</arg>
<arg nr="3" direction="in"/>
<arg nr="4" direction="in">
<not-null/>
</arg>
<arg nr="5" direction="in">
<not-null/>
</arg>
<arg nr="6" direction="in"/>
</function>
<function name="_assert_float_in_set">
<arg nr="1" direction="in"/>
<arg nr="2" direction="in">
<not-null/>
</arg>
<arg nr="3" direction="in"/>
<arg nr="4" direction="in"/>
<arg nr="5" direction="in">
<not-null/>
</arg>
<arg nr="6" direction="in">
<not-null/>
</arg>
<arg nr="7" direction="in"/>
</function>
<function name="_assert_float_not_in_set">
<arg nr="1" direction="in"/>
<arg nr="2" direction="in">
<not-null/>
</arg>
<arg nr="3" direction="in"/>
<arg nr="4" direction="in"/>
<arg nr="5" direction="in">
<not-null/>
</arg>
<arg nr="6" direction="in">
<not-null/>
</arg>
<arg nr="7" direction="in"/>
</function>
<!-- Return code assertion -->
<function name="_assert_return_code">
<arg nr="1" direction="in">
<valid>0 &lt;= arg1</valid>
</arg>
<arg nr="2" direction="in"/>
<arg nr="3" direction="in">
<not-null/>
</arg>
<arg nr="4" direction="in">
<not-null/>
</arg>
<arg nr="5" direction="in"/>
</function>
<!-- Macro definitions -->
<!-- Boolean macros -->
<define name="assert_true(c)" value="_assert_true(cast_to_uintmax_type(c), #c, __FILE__, __LINE__)"/>
<define name="assert_false(c)" value="_assert_false(cast_to_uintmax_type(c), #c, __FILE__, __LINE__)"/>
<!-- Pointer macros -->
<define name="assert_non_null(c)" value="assert_ptr_not_equal((c), NULL)"/>
<define name="assert_non_null_msg(c, msg)" value="assert_ptr_not_equal_msg((c), NULL, (msg))"/>
<define name="assert_null(c)" value="assert_ptr_equal((c), NULL)"/>
<define name="assert_null_msg(c, msg)" value="assert_ptr_equal_msg((c), NULL, (msg))"/>
<define name="assert_ptr_equal(a, b)" value="assert_ptr_equal_msg((a), (b), NULL)"/>
<define name="assert_ptr_equal_msg(a, b, msg)" value="_assert_ptr_equal_msg((const void*)(a), (const void*)(b), __FILE__, __LINE__, (msg))"/>
<define name="assert_ptr_not_equal(a, b)" value="_assert_ptr_not_equal_msg((const void*)(a), (const void*)(b), __FILE__, __LINE__, NULL)"/>
<define name="assert_ptr_not_equal_msg(a, b, msg)" value="_assert_ptr_not_equal_msg((const void*)(a), (const void*)(b), __FILE__, __LINE__, (msg))"/>
<!-- Integer macros -->
<define name="assert_int_equal(a, b)" value="_assert_int_equal(cast_to_intmax_type(a), cast_to_intmax_type(b), __FILE__, __LINE__)"/>
<define name="assert_int_not_equal(a, b)" value="_assert_int_not_equal(cast_to_intmax_type(a), cast_to_intmax_type(b), __FILE__, __LINE__)"/>
<define name="assert_uint_equal(a, b)" value="_assert_uint_equal(cast_to_uintmax_type(a), cast_to_uintmax_type(b), __FILE__, __LINE__)"/>
<define name="assert_uint_not_equal(a, b)" value="_assert_uint_not_equal(cast_to_uintmax_type(a), cast_to_uintmax_type(b), __FILE__, __LINE__)"/>
<!-- Float/double macros -->
<define name="assert_float_equal(a, b, epsilon)" value="_assert_float_equal((float)(a), (float)(b), (float)(epsilon), __FILE__, __LINE__)"/>
<define name="assert_float_not_equal(a, b, epsilon)" value="_assert_float_not_equal((float)(a), (float)(b), (float)(epsilon), __FILE__, __LINE__)"/>
<define name="assert_double_equal(a, b, epsilon)" value="_assert_double_equal((double)(a), (double)(b), (double)(epsilon), __FILE__, __LINE__)"/>
<define name="assert_double_not_equal(a, b, epsilon)" value="_assert_double_not_equal((double)(a), (double)(b), (double)(epsilon), __FILE__, __LINE__)"/>
<!-- String macros -->
<define name="assert_string_equal(a, b)" value="_assert_string_equal((const char*)(a), (const char*)(b), __FILE__, __LINE__)"/>
<define name="assert_string_not_equal(a, b)" value="_assert_string_not_equal((const char*)(a), (const char*)(b), __FILE__, __LINE__)"/>
<!-- Memory macros -->
<define name="assert_memory_equal(a, b, size)" value="_assert_memory_equal((const void*)(a), (const void*)(b), size, __FILE__, __LINE__)"/>
<define name="assert_memory_not_equal(a, b, size)" value="_assert_memory_not_equal((const void*)(a), (const void*)(b), size, __FILE__, __LINE__)"/>
<!-- Range macros -->
<define name="assert_int_in_range(value, minimum, maximum)" value="_assert_int_in_range(cast_to_intmax_type(value), cast_to_intmax_type(minimum), cast_to_intmax_type(maximum), __FILE__, __LINE__)"/>
<define name="assert_int_not_in_range(value, minimum, maximum)" value="_assert_int_not_in_range(cast_to_intmax_type(value), cast_to_intmax_type(minimum), cast_to_intmax_type(maximum), __FILE__, __LINE__)"/>
<define name="assert_uint_in_range(value, minimum, maximum)" value="_assert_uint_in_range(cast_to_uintmax_type(value), cast_to_uintmax_type(minimum), cast_to_uintmax_type(maximum), __FILE__, __LINE__)"/>
<define name="assert_uint_not_in_range(value, minimum, maximum)" value="_assert_uint_not_in_range(cast_to_uintmax_type(value), cast_to_uintmax_type(minimum), cast_to_uintmax_type(maximum), __FILE__, __LINE__)"/>
<define name="assert_in_range(value, minimum, maximum)" value="assert_uint_in_range(value, minimum, maximum)"/>
<define name="assert_not_in_range(value, minimum, maximum)" value="assert_uint_not_in_range(value, minimum, maximum)"/>
<define name="assert_float_in_range(value, minimum, maximum, epsilon)" value="_assert_float_in_range((double)(value), (double)(minimum), (double)(maximum), (double)(epsilon), __FILE__, __LINE__)"/>
<define name="assert_float_not_in_range(value, minimum, maximum, epsilon)" value="_assert_float_not_in_range((double)(value), (double)(minimum), (double)(maximum), (double)(epsilon), __FILE__, __LINE__)"/>
<!-- Set macros -->
<define name="assert_in_set(value, values, number_of_values)" value="_assert_not_in_set(cast_to_uintmax_type(value), (uintmax_t*)(values), number_of_values, __FILE__, __LINE__, 0)"/>
<define name="assert_not_in_set(value, values, number_of_values)" value="_assert_not_in_set(cast_to_uintmax_type(value), (uintmax_t*)(values), number_of_values, __FILE__, __LINE__, 1)"/>
<define name="assert_int_in_set(value, values, number_of_values)" value="_assert_int_in_set(cast_to_intmax_type(value), (intmax_t*)(values), number_of_values, __FILE__, __LINE__, 0)"/>
<define name="assert_int_not_in_set(value, values, number_of_values)" value="_assert_int_not_in_set(cast_to_intmax_type(value), (intmax_t*)(values), number_of_values, __FILE__, __LINE__, 1)"/>
<define name="assert_uint_in_set(value, values, number_of_values)" value="_assert_uint_in_set(cast_to_uintmax_type(value), (uintmax_t*)(values), number_of_values, __FILE__, __LINE__, 0)"/>
<define name="assert_uint_not_in_set(value, values, number_of_values)" value="_assert_uint_not_in_set(cast_to_uintmax_type(value), (uintmax_t*)(values), number_of_values, __FILE__, __LINE__, 1)"/>
<define name="assert_float_in_set(value, values, number_of_values, epsilon)" value="_assert_float_in_set((double)(value), (double*)(values), number_of_values, (double)(epsilon), __FILE__, __LINE__, 0)"/>
<define name="assert_float_not_in_set(value, values, number_of_values, epsilon)" value="_assert_float_not_in_set((double)(value), (double*)(values), number_of_values, (double)(epsilon), __FILE__, __LINE__, 1)"/>
<!-- Return code macro -->
<define name="assert_return_code(rc, error)" value="_assert_return_code(cast_to_intmax_type(rc), (int32_t)(error), #rc, __FILE__, __LINE__)"/>
</def>

116
.gitlab-ci/local-ci.sh Executable file
View File

@@ -0,0 +1,116 @@
#!/usr/bin/env bash
set -e
RED="\033[1;31m"
GREEN="\033[1;32m"
YELLOW="\033[1;33m"
BLUE="\033[1;34m"
RESET="\033[0m"
export GCL_IGNORE_PREDEFINED_VARS=CI_REGISTRY
BASE_SHA=$(git merge-base HEAD origin/master 2>/dev/null || git rev-parse HEAD~1)
COMMON_ARGS=(
--variable "CI_MERGE_REQUEST_DIFF_BASE_SHA=$BASE_SHA"
--variable "CI_REGISTRY=registry.gitlab.com"
--json-schema-validation=false
)
check_requirements() {
for cmd in docker git gitlab-ci-local; do
if ! command -v "$cmd" >/dev/null 2>&1; then
echo -e "${RED}Missing dependency: $cmd${RESET}"
exit 1
fi
echo -e "${GREEN}Found: $cmd${RESET}"
done
if ! docker info >/dev/null 2>&1; then
echo -e "${RED}Docker daemon is not running or permission denied${RESET}"
exit 1
fi
}
list_jobs() {
gitlab-ci-local --list --json-schema-validation=false | awk 'NR>1 {print $1}'
}
run_job() {
JOB="$1"
echo -e "${YELLOW}Running CI job: $JOB${RESET}"
gitlab-ci-local "$JOB" "${COMMON_ARGS[@]}"
}
cleanup_images() {
echo -e "${BLUE}Removing libssh CI images only...${RESET}"
docker images --format "{{.Repository}}:{{.Tag}} {{.ID}}" \
| grep "$CI_REGISTRY/$BUILD_IMAGES_PROJECT" \
| awk '{print $2}' \
| xargs -r docker rmi -f
}
usage() {
echo
echo -e "${BLUE}Usage:${RESET}"
echo " $0 --list"
echo " $0 --run <job-name>"
echo " $0 --all"
echo " $0 --run <job-name> --clean"
echo " $0 --all --clean"
echo
exit 1
}
check_requirements
CLEAN=0
MODE=""
JOB=""
while [[ $# -gt 0 ]]; do
case "$1" in
--list)
MODE="list"
shift
;;
--run)
MODE="run"
JOB="$2"
shift 2
;;
--all)
MODE="all"
shift
;;
--clean)
CLEAN=1
shift
;;
*)
usage
;;
esac
done
case "$MODE" in
list)
list_jobs
;;
run)
[[ -z "$JOB" ]] && usage
run_job "$JOB"
[[ "$CLEAN" -eq 1 ]] && cleanup_images
;;
all)
for job in $(list_jobs); do
run_job "$job"
[[ "$CLEAN" -eq 1 ]] && cleanup_images
done
;;
*)
usage
;;
esac
echo -e "${GREEN}Done.${RESET}"

View File

@@ -0,0 +1,16 @@
Add a description of the new feature/bug fix. Reference any relevant bugs.
## Checklist
* [ ] Commits have `Signed-off-by:` with name/author being identical to the commit author
* [ ] Code modified for feature
* [ ] Test suite updated with functionality tests
* [ ] Test suite updated with negative tests
* [ ] Documentation updated
* [ ] The project pipelines timeout is [extended](https://docs.gitlab.com/ee/ci/pipelines/settings.html#set-a-limit-for-how-long-jobs-can-run) at least to 2 hours.
## Reviewer's checklist:
* [ ] Any issues marked for closing are addressed
* [ ] There is a test suite reasonably covering new functionality or modifications
* [ ] Function naming, parameters, return values, types, etc., are consistent and according to [CONTRIBUTING.md](https://gitlab.com/libssh/libssh-mirror/-/blob/master/CONTRIBUTING.md)
* [ ] This feature/change has adequate documentation added
* [ ] No obvious mistakes in the code

View File

@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.12.0) cmake_minimum_required(VERSION 3.14.0)
# Specify search path for CMake modules to be loaded by include() # Specify search path for CMake modules to be loaded by include()
# and find_package() # and find_package()
@@ -9,7 +9,7 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules")
include(DefineCMakeDefaults) include(DefineCMakeDefaults)
include(DefineCompilerFlags) include(DefineCompilerFlags)
project(libssh VERSION 0.11.00 LANGUAGES C CXX) project(libssh VERSION 0.11.00 LANGUAGES C)
# global needed variable # global needed variable
set(APPLICATION_NAME ${PROJECT_NAME}) set(APPLICATION_NAME ${PROJECT_NAME})
@@ -41,6 +41,8 @@ macro_ensure_out_of_source_build("${PROJECT_NAME} requires an out of source buil
# Copy library files to a lib sub-directory # Copy library files to a lib sub-directory
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib") set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
set(LIBSSSH_PC_REQUIRES_PRIVATE "")
# search for libraries # search for libraries
if (WITH_ZLIB) if (WITH_ZLIB)
find_package(ZLIB REQUIRED) find_package(ZLIB REQUIRED)
@@ -66,6 +68,7 @@ find_package(Threads)
if (WITH_GSSAPI) if (WITH_GSSAPI)
find_package(GSSAPI) find_package(GSSAPI)
list(APPEND LIBSSH_PC_REQUIRES_PRIVATE ${GSSAPI_PC_REQUIRES})
endif (WITH_GSSAPI) endif (WITH_GSSAPI)
if (WITH_NACL) if (WITH_NACL)
@@ -75,9 +78,19 @@ if (WITH_NACL)
endif (NOT NACL_FOUND) endif (NOT NACL_FOUND)
endif (WITH_NACL) endif (WITH_NACL)
if (WITH_FIDO2)
find_package(libfido2)
if (LIBFIDO2_FOUND)
set(HAVE_LIBFIDO2 ON)
else (LIBFIDO2_FOUND)
set(HAVE_LIBFIDO2 OFF)
message(WARNING "libfido2 was not found. Internal support for interacting with FIDO2/U2F devices using the USB HID protocol will not be available.")
endif (LIBFIDO2_FOUND)
endif (WITH_FIDO2)
# Disable symbol versioning in non UNIX platforms # Disable symbol versioning in non UNIX platforms
if (UNIX) if (UNIX)
find_package(ABIMap 0.3.1) find_package(ABIMap 0.4.0)
else (UNIX) else (UNIX)
set(WITH_SYMBOL_VERSIONING OFF) set(WITH_SYMBOL_VERSIONING OFF)
endif (UNIX) endif (UNIX)
@@ -168,6 +181,10 @@ if (WITH_SYMBOL_VERSIONING AND ABIMAP_FOUND)
set(ALLOW_ABI_BREAK "BREAK_ABI") set(ALLOW_ABI_BREAK "BREAK_ABI")
endif() endif()
if (WITH_FINAL)
set(FINAL "FINAL")
endif()
# Target we can depend on in 'make dist' # Target we can depend on in 'make dist'
set(_SYMBOL_TARGET "${PROJECT_NAME}.map") set(_SYMBOL_TARGET "${PROJECT_NAME}.map")
@@ -180,7 +197,7 @@ if (WITH_SYMBOL_VERSIONING AND ABIMAP_FOUND)
RELEASE_NAME_VERSION ${PROJECT_NAME}_${LIBRARY_VERSION} RELEASE_NAME_VERSION ${PROJECT_NAME}_${LIBRARY_VERSION}
CURRENT_MAP ${MAP_PATH} CURRENT_MAP ${MAP_PATH}
COPY_TO ${MAP_PATH} COPY_TO ${MAP_PATH}
FINAL ${FINAL}
${ALLOW_ABI_BREAK}) ${ALLOW_ABI_BREAK})
# Write the current version to the source # Write the current version to the source
@@ -190,12 +207,13 @@ endif (WITH_SYMBOL_VERSIONING AND ABIMAP_FOUND)
# Coverage # Coverage
if (WITH_COVERAGE) if (WITH_COVERAGE)
ENABLE_LANGUAGE(CXX)
include(CodeCoverage) include(CodeCoverage)
setup_target_for_coverage_lcov( setup_target_for_coverage_lcov(
NAME "coverage" NAME "coverage"
EXECUTABLE make test EXECUTABLE make test
DEPENDENCIES ssh tests) DEPENDENCIES ssh tests)
set(GCOVR_ADDITIONAL_ARGS --xml-pretty --exclude-unreachable-branches --print-summary) set(GCOVR_ADDITIONAL_ARGS --xml-pretty --exclude-unreachable-branches --print-summary --gcov-ignore-parse-errors)
setup_target_for_coverage_gcovr_xml( setup_target_for_coverage_gcovr_xml(
NAME "coverage_xml" NAME "coverage_xml"
EXECUTABLE make test EXECUTABLE make test
@@ -234,6 +252,10 @@ message(STATUS "Client code testing: ${CLIENT_TESTING}")
message(STATUS "Blowfish cipher support: ${HAVE_BLOWFISH}") message(STATUS "Blowfish cipher support: ${HAVE_BLOWFISH}")
message(STATUS "PKCS #11 URI support: ${WITH_PKCS11_URI}") message(STATUS "PKCS #11 URI support: ${WITH_PKCS11_URI}")
message(STATUS "With PKCS #11 provider support: ${WITH_PKCS11_PROVIDER}") message(STATUS "With PKCS #11 provider support: ${WITH_PKCS11_PROVIDER}")
message(STATUS "With FIDO2/U2F support: ${WITH_FIDO2}")
if (WITH_FIDO2)
message(STATUS "With libfido2 (internal usb-hid support): ${HAVE_LIBFIDO2}")
endif (WITH_FIDO2)
set(_SERVER_TESTING OFF) set(_SERVER_TESTING OFF)
if (WITH_SERVER) if (WITH_SERVER)
set(_SERVER_TESTING ${SERVER_TESTING}) set(_SERVER_TESTING ${SERVER_TESTING})
@@ -248,9 +270,15 @@ message(STATUS "Benchmarks: ${WITH_BENCHMARKS}")
message(STATUS "Symbol versioning: ${WITH_SYMBOL_VERSIONING}") message(STATUS "Symbol versioning: ${WITH_SYMBOL_VERSIONING}")
message(STATUS "Allow ABI break: ${WITH_ABI_BREAK}") message(STATUS "Allow ABI break: ${WITH_ABI_BREAK}")
message(STATUS "Release is final: ${WITH_FINAL}") message(STATUS "Release is final: ${WITH_FINAL}")
if (WITH_HERMETIC_USR)
message(STATUS "User global client config: ${USR_GLOBAL_CLIENT_CONFIG}")
endif ()
message(STATUS "Global client config: ${GLOBAL_CLIENT_CONFIG}") message(STATUS "Global client config: ${GLOBAL_CLIENT_CONFIG}")
if (WITH_SERVER) if (WITH_SERVER)
message(STATUS "Global bind config: ${GLOBAL_BIND_CONFIG}") if (WITH_HERMETIC_USR)
message(STATUS "User global bind config: ${USR_GLOBAL_BIND_CONFIG}")
endif ()
message(STATUS "Global bind config: ${GLOBAL_BIND_CONFIG}")
endif() endif()
message(STATUS "********************************************") message(STATUS "********************************************")

View File

@@ -117,6 +117,52 @@ libssh Developer's Certificate of Origin for each patch, or inside each
patch. Just the sign-off message is all that is required once we've patch. Just the sign-off message is all that is required once we've
received the initial email. received the initial email.
## Continuous Integration
Contributing patches through Merge Request workflow on Gitlab allows us to run
various checks on various configuration as part of Gitlab CI. Unfortunately,
some pipelines are slower (as they involve building dependencies) so the default
timeout of 1 hour needs to be extended at least to 2 hours. This can be done in
project settings of your libssh fork:
https://docs.gitlab.com/ee/ci/pipelines/settings.html#set-a-limit-for-how-long-jobs-can-run
Otherwise you will encounter errors like these, usually on visualstudio builds:
```
ERROR: Job failed: execution took longer than 1h0m0s seconds
The script exceeded the maximum execution time set for the job
```
Note, that the built dependencies are cached so after successful build in your
namespace, the rebuilds should be much faster.
## Running GitLab CI locally (optional helper)
For contributors working on CI, build system changes, or adding new CI jobs, it can be useful to run GitLab CI pipelines locally before pushing.
libssh provides a small helper script based on `gitlab-ci-local` that can:
- List all jobs defined in `.gitlab-ci.yml`
- Run a specific job or the full pipeline locally
- Automatically pick up new jobs when they are added to the CI configuration
- Optionally clean up CI Docker images after execution
### Requirements
- Docker (daemon running)
- git
- gitlab-ci-local
https://github.com/firecow/gitlab-ci-local
### Usage
```bash
./.gitlab-ci/local-ci.sh --list
./.gitlab-ci/local-ci.sh --run fedora/libressl/x86_64
./.gitlab-ci/local-ci.sh --all
./.gitlab-ci/local-ci.sh --run fedora/libressl/x86_64 --clean
```
# Coding conventions in the libssh tree # Coding conventions in the libssh tree
@@ -517,6 +563,37 @@ Bad example:
break; break;
} }
## ABI Versioning and Symbol Management
To maintain [ABI](https://en.wikipedia.org/wiki/Application_binary_interface) stability
and ensure backward compatibility, libssh uses **symbol versioning** to track and manage
exported functions and variables. This allows libssh to introduce new symbols or modify
existing functions in an ABI-compatible way.
When introducing a new symbol:
1. Use the `LIBSSH_API` macro to mark the symbol as part of the public API.
2. If you have [abimap](https://github.com/ansasaki/abimap) installed, the new symbols are
automatically generated in the `src/libssh_dev.map` file in the **build** directory and used automatically for building the updated library. But, depending on the version of `abimap` under use, you may face linker errors like: `unable to find version dependency LIBSSH_4_9_0`. In this case, you need to manually replace the existing `src/libssh.map` file with the generated `libssh_dev.map` file to update the symbol versioning.
3. If you do not have abimap installed, the modified/added symbols must manually be added to the
`src/libssh.map` file. The symbols must be added in the following format (assuming that 4_10_0 is the latest released version):
```
LIBSSH_AFTER_4_10_0
{
global:
new_function;
new_variable;
} LIBSSH_4_10_0;
```
4. After following either of the above steps, the library can be successfully built and
tested without any linker errors.
5. When submitting the patch, make sure that any new symbols have been added to `libssh.map` as described in step 3, so that the new additions may not be excluded from the next release due to human error.
Also, to maintain ABI compatibility, existing symbols must not be removed. Instead, they can
be marked as deprecated using the `LIBSSH_DEPRECATED` macro. This allows the symbol to be
removed in a future release without breaking the ABI.
Have fun and happy libssh hacking! Have fun and happy libssh hacking!

View File

@@ -10,7 +10,7 @@ set(CPACK_PACKAGE_VERSION ${PROJECT_VERSION})
# SOURCE GENERATOR # SOURCE GENERATOR
set(CPACK_SOURCE_GENERATOR "TXZ") set(CPACK_SOURCE_GENERATOR "TXZ")
set(CPACK_SOURCE_IGNORE_FILES "~$;[.]swp$;/[.]git/;/[.]clangd/;/[.]cache/;.gitignore;/build*;/obj*;tags;cscope.*;compile_commands.json;.*\.patch") set(CPACK_SOURCE_IGNORE_FILES "~$;[.]swp$;/[.]bare/;/[.]git/;/[.]git;/[.]clangd/;/[.]cache/;.gitignore;/build*;/obj*;tags;cscope.*;compile_commands.json;.*\.patch")
set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}") set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}")
### NSIS INSTALLER ### NSIS INSTALLER

View File

@@ -16,7 +16,6 @@ if (UNIX)
endif() endif()
endif() endif()
add_c_compiler_flag("-std=gnu99" SUPPORTED_COMPILER_FLAGS)
add_c_compiler_flag("-Wpedantic" SUPPORTED_COMPILER_FLAGS) add_c_compiler_flag("-Wpedantic" SUPPORTED_COMPILER_FLAGS)
add_c_compiler_flag("-Wall" SUPPORTED_COMPILER_FLAGS) add_c_compiler_flag("-Wall" SUPPORTED_COMPILER_FLAGS)
add_c_compiler_flag("-Wshadow" SUPPORTED_COMPILER_FLAGS) add_c_compiler_flag("-Wshadow" SUPPORTED_COMPILER_FLAGS)
@@ -49,6 +48,7 @@ if (UNIX)
add_c_compiler_flag("-Werror=implicit-int" SUPPORTED_COMPILER_FLAGS) add_c_compiler_flag("-Werror=implicit-int" SUPPORTED_COMPILER_FLAGS)
add_c_compiler_flag("-Wint-conversion" SUPPORTED_COMPILER_FLAGS) add_c_compiler_flag("-Wint-conversion" SUPPORTED_COMPILER_FLAGS)
add_c_compiler_flag("-Werror=int-conversion" SUPPORTED_COMPILER_FLAGS) add_c_compiler_flag("-Werror=int-conversion" SUPPORTED_COMPILER_FLAGS)
add_c_compiler_flag("-Werror=unused-variable" SUPPORTED_COMPILER_FLAGS)
check_c_compiler_flag("-Wformat" REQUIRED_FLAGS_WFORMAT) check_c_compiler_flag("-Wformat" REQUIRED_FLAGS_WFORMAT)
if (REQUIRED_FLAGS_WFORMAT) if (REQUIRED_FLAGS_WFORMAT)
@@ -92,9 +92,12 @@ if (UNIX)
endif (WITH_STACK_PROTECTOR_STRONG) endif (WITH_STACK_PROTECTOR_STRONG)
if (NOT WINDOWS AND NOT CYGWIN) if (NOT WINDOWS AND NOT CYGWIN)
check_c_compiler_flag_ssp("-fstack-clash-protection" WITH_STACK_CLASH_PROTECTION) # apple m* chips do not support this option
if (WITH_STACK_CLASH_PROTECTION) if (NOT ${CMAKE_SYSTEM_PROCESSOR} STREQUAL arm64)
list(APPEND SUPPORTED_COMPILER_FLAGS "-fstack-clash-protection") check_c_compiler_flag_ssp("-fstack-clash-protection" WITH_STACK_CLASH_PROTECTION)
if (WITH_STACK_CLASH_PROTECTION)
list(APPEND SUPPORTED_COMPILER_FLAGS "-fstack-clash-protection")
endif()
endif() endif()
endif() endif()

View File

@@ -64,6 +64,7 @@ check_include_file(arpa/inet.h HAVE_ARPA_INET_H)
check_include_file(byteswap.h HAVE_BYTESWAP_H) check_include_file(byteswap.h HAVE_BYTESWAP_H)
check_include_file(glob.h HAVE_GLOB_H) check_include_file(glob.h HAVE_GLOB_H)
check_include_file(valgrind/valgrind.h HAVE_VALGRIND_VALGRIND_H) check_include_file(valgrind/valgrind.h HAVE_VALGRIND_VALGRIND_H)
check_include_file(ifaddrs.h HAVE_IFADDRS_H)
if (WIN32) if (WIN32)
check_include_file(io.h HAVE_IO_H) check_include_file(io.h HAVE_IO_H)
@@ -103,6 +104,12 @@ if (OPENSSL_FOUND)
check_function_exists(RAND_priv_bytes HAVE_OPENSSL_RAND_PRIV_BYTES) check_function_exists(RAND_priv_bytes HAVE_OPENSSL_RAND_PRIV_BYTES)
check_function_exists(EVP_chacha20 HAVE_OPENSSL_EVP_CHACHA20) check_function_exists(EVP_chacha20 HAVE_OPENSSL_EVP_CHACHA20)
# Check for ML-KEM availability (OpenSSL 3.5+)
if (OPENSSL_VERSION VERSION_GREATER_EQUAL "3.5.0")
set(HAVE_OPENSSL_MLKEM 1)
set(HAVE_MLKEM1024 1)
endif ()
unset(CMAKE_REQUIRED_INCLUDES) unset(CMAKE_REQUIRED_INCLUDES)
unset(CMAKE_REQUIRED_LIBRARIES) unset(CMAKE_REQUIRED_LIBRARIES)
endif() endif()
@@ -133,6 +140,7 @@ check_function_exists(strncpy HAVE_STRNCPY)
check_function_exists(strndup HAVE_STRNDUP) check_function_exists(strndup HAVE_STRNDUP)
check_function_exists(strtoull HAVE_STRTOULL) check_function_exists(strtoull HAVE_STRTOULL)
check_function_exists(explicit_bzero HAVE_EXPLICIT_BZERO) check_function_exists(explicit_bzero HAVE_EXPLICIT_BZERO)
check_function_exists(memset_explicit HAVE_MEMSET_EXPLICIT)
check_function_exists(memset_s HAVE_MEMSET_S) check_function_exists(memset_s HAVE_MEMSET_S)
if (HAVE_GLOB_H) if (HAVE_GLOB_H)
@@ -225,7 +233,12 @@ if (GCRYPT_FOUND)
endif (GCRYPT_VERSION VERSION_GREATER "1.4.6") endif (GCRYPT_VERSION VERSION_GREATER "1.4.6")
if (NOT GCRYPT_VERSION VERSION_LESS "1.7.0") if (NOT GCRYPT_VERSION VERSION_LESS "1.7.0")
set(HAVE_GCRYPT_CHACHA_POLY 1) set(HAVE_GCRYPT_CHACHA_POLY 1)
set(HAVE_GCRYPT_CURVE25519 1)
endif (NOT GCRYPT_VERSION VERSION_LESS "1.7.0") endif (NOT GCRYPT_VERSION VERSION_LESS "1.7.0")
if (GCRYPT_VERSION VERSION_GREATER_EQUAL "1.10.1")
set(HAVE_GCRYPT_MLKEM 1)
set(HAVE_MLKEM1024 1)
endif ()
endif (GCRYPT_FOUND) endif (GCRYPT_FOUND)
if (MBEDTLS_FOUND) if (MBEDTLS_FOUND)
@@ -235,6 +248,13 @@ if (MBEDTLS_FOUND)
set(CMAKE_REQUIRED_INCLUDES "${MBEDTLS_INCLUDE_DIR}/mbedtls") set(CMAKE_REQUIRED_INCLUDES "${MBEDTLS_INCLUDE_DIR}/mbedtls")
check_include_file(chacha20.h HAVE_MBEDTLS_CHACHA20_H) check_include_file(chacha20.h HAVE_MBEDTLS_CHACHA20_H)
check_include_file(poly1305.h HAVE_MBEDTLS_POLY1305_H) check_include_file(poly1305.h HAVE_MBEDTLS_POLY1305_H)
if (MBEDTLS_VERSION VERSION_LESS "3.0.0")
check_symbol_exists(MBEDTLS_ECP_DP_CURVE25519_ENABLED "config.h" HAVE_MBEDTLS_CURVE25519)
else()
check_symbol_exists(MBEDTLS_ECP_DP_CURVE25519_ENABLED "mbedtls_config.h" HAVE_MBEDTLS_CURVE25519)
endif()
if (WITH_BLOWFISH_CIPHER) if (WITH_BLOWFISH_CIPHER)
check_include_file(blowfish.h HAVE_BLOWFISH) check_include_file(blowfish.h HAVE_BLOWFISH)
endif() endif()

View File

@@ -13,6 +13,7 @@ option(WITH_INTERNAL_DOC "Compile doxygen internal documentation" OFF)
option(BUILD_SHARED_LIBS "Build shared libraries" ON) option(BUILD_SHARED_LIBS "Build shared libraries" ON)
option(WITH_PKCS11_URI "Build with PKCS#11 URI support" OFF) option(WITH_PKCS11_URI "Build with PKCS#11 URI support" OFF)
option(WITH_PKCS11_PROVIDER "Use the PKCS#11 provider for accessing pkcs11 objects" OFF) option(WITH_PKCS11_PROVIDER "Use the PKCS#11 provider for accessing pkcs11 objects" OFF)
option(WITH_FIDO2 "Build with FIDO2/U2F support" OFF)
option(UNIT_TESTING "Build with unit tests" OFF) option(UNIT_TESTING "Build with unit tests" OFF)
option(CLIENT_TESTING "Build with client tests; requires openssh" OFF) option(CLIENT_TESTING "Build with client tests; requires openssh" OFF)
option(SERVER_TESTING "Build with server tests; requires openssh and dropbear" OFF) option(SERVER_TESTING "Build with server tests; requires openssh and dropbear" OFF)
@@ -27,6 +28,7 @@ option(WITH_INSECURE_NONE "Enable insecure none cipher and MAC algorithms (not s
option(WITH_EXEC "Enable libssh to execute arbitrary commands from configuration files or options (match exec, proxy commands and OpenSSH-based proxy-jumps)." ON) option(WITH_EXEC "Enable libssh to execute arbitrary commands from configuration files or options (match exec, proxy commands and OpenSSH-based proxy-jumps)." ON)
option(FUZZ_TESTING "Build with fuzzer for the server and client (automatically enables none cipher!)" OFF) option(FUZZ_TESTING "Build with fuzzer for the server and client (automatically enables none cipher!)" OFF)
option(PICKY_DEVELOPER "Build with picky developer flags" OFF) option(PICKY_DEVELOPER "Build with picky developer flags" OFF)
option(WITH_HERMETIC_USR "Build with support for hermetic /usr/" OFF)
if (WITH_ZLIB) if (WITH_ZLIB)
set(WITH_LIBZ ON) set(WITH_LIBZ ON)
@@ -59,6 +61,11 @@ if (NOT GLOBAL_CLIENT_CONFIG)
set(GLOBAL_CLIENT_CONFIG "/etc/ssh/ssh_config") set(GLOBAL_CLIENT_CONFIG "/etc/ssh/ssh_config")
endif (NOT GLOBAL_CLIENT_CONFIG) endif (NOT GLOBAL_CLIENT_CONFIG)
if (WITH_HERMETIC_USR)
set(USR_GLOBAL_BIND_CONFIG "/usr${GLOBAL_BIND_CONFIG}")
set(USR_GLOBAL_CLIENT_CONFIG "/usr${GLOBAL_CLIENT_CONFIG}")
endif (WITH_HERMETIC_USR)
if (FUZZ_TESTING) if (FUZZ_TESTING)
set(WITH_INSECURE_NONE ON) set(WITH_INSECURE_NONE ON)
endif (FUZZ_TESTING) endif (FUZZ_TESTING)

View File

@@ -38,14 +38,16 @@ First, you need to configure the compilation, using CMake. Go inside the
`build` dir. Create it if it doesn't exist. `build` dir. Create it if it doesn't exist.
GNU/Linux, MacOS X, MSYS/MinGW: GNU/Linux, MacOS X, MSYS/MinGW:
cmake -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Debug ..
cmake -DUNIT_TESTING=ON -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Debug ..
make make
On Windows you should choose a makefile generator with -G or use On Windows you should choose a makefile generator with -G or use
cmake-gui.exe .. cmake-gui.exe ..
To enable building tests use -DUNIT_TESTING=ON. For this, the
[cmocka](https://cmocka.org) dependency is required.
To enable additional client tests against a local OpenSSH server, add the To enable additional client tests against a local OpenSSH server, add the
compile option -DCLIENT_TESTING=ON. These tests require an OpenSSH compile option -DCLIENT_TESTING=ON. These tests require an OpenSSH
server package and some wrapper libraries (see optional requirements) to server package and some wrapper libraries (see optional requirements) to

View File

@@ -117,6 +117,7 @@ function(ADD_CMOCKA_TEST _TARGET_NAME)
${TARGET_SYSTEM_EMULATOR} ${_TARGET_NAME} ${TARGET_SYSTEM_EMULATOR} ${_TARGET_NAME}
) )
if (WITH_COVERAGE) if (WITH_COVERAGE)
ENABLE_LANGUAGE(CXX)
include(CodeCoverage) include(CodeCoverage)
append_coverage_compiler_flags_to_target(${_TARGET_NAME}) append_coverage_compiler_flags_to_target(${_TARGET_NAME})
endif (WITH_COVERAGE) endif (WITH_COVERAGE)

View File

@@ -39,6 +39,15 @@ find_path(GCRYPT_INCLUDE_DIR
include include
) )
find_path(GCRYPT_ERROR_INCLUDE_DIR
NAMES
gpg-error.h
HINTS
${_GCRYPT_ROOT_HINTS_AND_PATHS}
PATH_SUFFIXES
include
)
find_library(GCRYPT_LIBRARY find_library(GCRYPT_LIBRARY
NAMES NAMES
gcrypt gcrypt
@@ -56,8 +65,10 @@ find_library(GCRYPT_ERROR_LIBRARY
libgpg-error6-0 libgpg-error6-0
HINTS HINTS
${_GCRYPT_ROOT_HINTS_AND_PATHS} ${_GCRYPT_ROOT_HINTS_AND_PATHS}
PATH_SUFFIXES
lib
) )
set(GCRYPT_LIBRARIES ${GCRYPT_LIBRARY} ${GCRYPT_ERROR_LIBRARY}) set(GCRYPT_LIBRARIES ${GCRYPT_ERROR_LIBRARY} ${GCRYPT_LIBRARY})
if (GCRYPT_INCLUDE_DIR) if (GCRYPT_INCLUDE_DIR)
file(STRINGS "${GCRYPT_INCLUDE_DIR}/gcrypt.h" _gcrypt_version_str REGEX "^#define GCRYPT_VERSION \"[0-9]+\\.[0-9]+\\.[0-9]") file(STRINGS "${GCRYPT_INCLUDE_DIR}/gcrypt.h" _gcrypt_version_str REGEX "^#define GCRYPT_VERSION \"[0-9]+\\.[0-9]+\\.[0-9]")
@@ -83,5 +94,25 @@ else (GCRYPT_VERSION)
GCRYPT_LIBRARIES) GCRYPT_LIBRARIES)
endif (GCRYPT_VERSION) endif (GCRYPT_VERSION)
# show the GCRYPT_INCLUDE_DIRS and GCRYPT_LIBRARIES variables only in the advanced view # show the GCRYPT_INCLUDE_DIRS, GCRYPT_LIBRARIES and GCRYPT_ERROR_INCLUDE_DIR variables only in the advanced view
mark_as_advanced(GCRYPT_INCLUDE_DIR GCRYPT_LIBRARIES) mark_as_advanced(GCRYPT_INCLUDE_DIR GCRYPT_ERROR_INCLUDE_DIR GCRYPT_LIBRARIES)
if(GCRYPT_FOUND)
if(NOT TARGET libgcrypt::libgcrypt)
add_library(libgcrypt::libgcrypt UNKNOWN IMPORTED)
set_target_properties(libgcrypt::libgcrypt PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${GCRYPT_INCLUDE_DIR}"
INTERFACE_LINK_LIBRARIES libgcrypt::libgcrypt
IMPORTED_LINK_INTERFACE_LANGUAGES "C"
IMPORTED_LOCATION "${GCRYPT_LIBRARY}")
endif()
if(NOT TARGET libgpg-error::libgpg-error)
add_library(libgpg-error::libgpg-error UNKNOWN IMPORTED)
set_target_properties(libgpg-error::libgpg-error PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${GCRYPT_ERROR_INCLUDE_DIR}"
INTERFACE_LINK_LIBRARIES libgpg-error::libgpg-error
IMPORTED_LINK_INTERFACE_LANGUAGES "C"
IMPORTED_LOCATION "${GCRYPT_ERROR_LIBRARY}")
endif()
endif()

View File

@@ -11,6 +11,8 @@
# GSSAPI_INCLUDE_DIR - the GSSAPI include directory # GSSAPI_INCLUDE_DIR - the GSSAPI include directory
# GSSAPI_LIBRARIES - Link these to use GSSAPI # GSSAPI_LIBRARIES - Link these to use GSSAPI
# GSSAPI_DEFINITIONS - Compiler switches required for using GSSAPI # GSSAPI_DEFINITIONS - Compiler switches required for using GSSAPI
# GSSAPI_PC_REQUIRES - pkg-config module name if found, needed for
# Requires.private for static linking
# #
#============================================================================= #=============================================================================
# Copyright (c) 2013 Andreas Schneider <asn@cryptomilk.org> # Copyright (c) 2013 Andreas Schneider <asn@cryptomilk.org>
@@ -24,12 +26,23 @@
#============================================================================= #=============================================================================
# #
set(_mit_modname "mit-krb5-gssapi")
set(_heimdal_modname "heimdal-gssapi")
if(NOT _GSSAPI_ROOT_HINTS AND NOT _GSSAPI_ROOT_PATHS)
find_package(PkgConfig QUIET)
if (PKG_CONFIG_FOUND)
pkg_search_module(_GSSAPI ${_mit_modname} ${_heimdal_modname})
endif()
endif()
find_path(GSSAPI_ROOT_DIR find_path(GSSAPI_ROOT_DIR
NAMES NAMES
include/gssapi.h include/gssapi.h
include/gssapi/gssapi.h include/gssapi/gssapi.h
HINTS HINTS
${_GSSAPI_ROOT_HINTS} ${_GSSAPI_ROOT_HINTS}
"${_GSSAPI_INCLUDEDIR}"
PATHS PATHS
${_GSSAPI_ROOT_PATHS} ${_GSSAPI_ROOT_PATHS}
) )
@@ -317,9 +330,15 @@ endif (GSSAPI_FLAVOR_HEIMDAL)
include(FindPackageHandleStandardArgs) include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(GSSAPI DEFAULT_MSG GSSAPI_LIBRARIES GSSAPI_INCLUDE_DIR) find_package_handle_standard_args(GSSAPI DEFAULT_MSG GSSAPI_LIBRARIES GSSAPI_INCLUDE_DIR)
if (GSSAPI_INCLUDE_DIRS AND GSSAPI_LIBRARIES) if(GSSAPI_FOUND)
set(GSSAPI_FOUND TRUE) if(_GSSAPI_FOUND) # via pkg-config
endif (GSSAPI_INCLUDE_DIRS AND GSSAPI_LIBRARIES) if (GSSAPI_FLAVOR_MIT)
set(GSSAPI_PC_REQUIRES ${_mit_modname})
elseif (GSSAPI_FLAVOR_HEIMDAL)
set(GSSAPI_PC_REQUIRES ${_heimdal_modname})
endif()
endif()
endif()
# show the GSSAPI_INCLUDE_DIRS and GSSAPI_LIBRARIES variables only in the advanced view # show the GSSAPI_INCLUDE_DIR and GSSAPI_LIBRARIES variables only in the advanced view
mark_as_advanced(GSSAPI_INCLUDE_DIRS GSSAPI_LIBRARIES) mark_as_advanced(GSSAPI_INCLUDE_DIR GSSAPI_LIBRARIES)

View File

@@ -72,21 +72,23 @@ find_library(MBEDTLS_X509_LIBRARY
set(MBEDTLS_LIBRARIES ${MBEDTLS_SSL_LIBRARY} ${MBEDTLS_CRYPTO_LIBRARY} set(MBEDTLS_LIBRARIES ${MBEDTLS_SSL_LIBRARY} ${MBEDTLS_CRYPTO_LIBRARY}
${MBEDTLS_X509_LIBRARY}) ${MBEDTLS_X509_LIBRARY})
# mbedtls 2.8
if (MBEDTLS_INCLUDE_DIR AND EXISTS "${MBEDTLS_INCLUDE_DIR}/mbedtls/version.h") if (MBEDTLS_INCLUDE_DIR AND EXISTS "${MBEDTLS_INCLUDE_DIR}/mbedtls/version.h")
# mbedtls 2.8
file(STRINGS "${MBEDTLS_INCLUDE_DIR}/mbedtls/version.h" _mbedtls_version_str REGEX file(STRINGS "${MBEDTLS_INCLUDE_DIR}/mbedtls/version.h" _mbedtls_version_str REGEX
"^#[\t ]*define[\t ]+MBEDTLS_VERSION_STRING[\t ]+\"[0-9]+.[0-9]+.[0-9]+\"") "^#[\t ]*define[\t ]+MBEDTLS_VERSION_STRING[\t ]+\"[0-9]+.[0-9]+.[0-9]+\"")
string(REGEX REPLACE "^.*MBEDTLS_VERSION_STRING.*([0-9]+.[0-9]+.[0-9]+).*" string(REGEX REPLACE "^.*MBEDTLS_VERSION_STRING.*([0-9]+\\.[0-9]+\\.[0-9]+).*$"
"\\1" MBEDTLS_VERSION "${_mbedtls_version_str}") "\\1" MBEDTLS_VERSION "${_mbedtls_version_str}")
elseif (MBEDTLS_INCLUDE_DIR AND EXISTS "${MBEDTLS_INCLUDE_DIR}/mbedtls/build_info.h") endif()
# mbedtls 3.6
file(STRINGS "${MBEDTLS_INCLUDE_DIR}/mbedtls/version.h" _mbedtls_version_str REGEX # mbedtls 3.6
if (NOT MBEDTLS_VERSION AND MBEDTLS_INCLUDE_DIR AND EXISTS "${MBEDTLS_INCLUDE_DIR}/mbedtls/build_info.h")
file(STRINGS "${MBEDTLS_INCLUDE_DIR}/mbedtls/build_info.h" _mbedtls_version_str REGEX
"^#[\t ]*define[\t ]+MBEDTLS_VERSION_STRING[\t ]+\"[0-9]+.[0-9]+.[0-9]+\"") "^#[\t ]*define[\t ]+MBEDTLS_VERSION_STRING[\t ]+\"[0-9]+.[0-9]+.[0-9]+\"")
string(REGEX REPLACE "^.*MBEDTLS_VERSION_STRING.*([0-9]+.[0-9]+.[0-9]+).*" string(REGEX REPLACE "^.*MBEDTLS_VERSION_STRING.*([0-9]+\\.[0-9]+\\.[0-9]+).*$"
"\\1" MBEDTLS_VERSION "${_mbedtls_version_str}") "\\1" MBEDTLS_VERSION "${_mbedtls_version_str}")
endif () endif()
include(FindPackageHandleStandardArgs) include(FindPackageHandleStandardArgs)
if (MBEDTLS_VERSION) if (MBEDTLS_VERSION)
@@ -110,3 +112,32 @@ endif (MBEDTLS_VERSION)
# show the MBEDTLS_INCLUDE_DIRS and MBEDTLS_LIBRARIES variables only in the advanced view # show the MBEDTLS_INCLUDE_DIRS and MBEDTLS_LIBRARIES variables only in the advanced view
mark_as_advanced(MBEDTLS_INCLUDE_DIR MBEDTLS_LIBRARIES) mark_as_advanced(MBEDTLS_INCLUDE_DIR MBEDTLS_LIBRARIES)
if(MBEDTLS_FOUND)
if(NOT TARGET MbedTLS::mbedcrypto)
add_library(MbedTLS::mbedcrypto UNKNOWN IMPORTED)
set_target_properties(MbedTLS::mbedcrypto PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${MBEDTLS_INCLUDE_DIR}"
INTERFACE_LINK_LIBRARIES MbedTLS::mbedcrypto
IMPORTED_LINK_INTERFACE_LANGUAGES "C"
IMPORTED_LOCATION "${MBEDTLS_CRYPTO_LIBRARY}")
endif()
if(NOT TARGET MbedTLS::mbedx509)
add_library(MbedTLS::mbedx509 UNKNOWN IMPORTED)
set_target_properties(MbedTLS::mbedx509 PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${MBEDTLS_INCLUDE_DIR}"
INTERFACE_LINK_LIBRARIES MbedTLS::mbedx509
IMPORTED_LINK_INTERFACE_LANGUAGES "C"
IMPORTED_LOCATION "${MBEDTLS_X509_LIBRARY}")
endif()
if(NOT TARGET MbedTLS::mbedtls)
add_library(MbedTLS::mbedtls UNKNOWN IMPORTED)
set_target_properties(MbedTLS::mbedtls PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${MBEDTLS_INCLUDE_DIR}"
INTERFACE_LINK_LIBRARIES MbedTLS::mbedtls
IMPORTED_LINK_INTERFACE_LANGUAGES "C"
IMPORTED_LOCATION "${MBEDTLS_LIBRARY}")
endif()
endif()

View File

@@ -0,0 +1,63 @@
# - Try to find libfido2
# Once done this will define
#
# LIBFIDO2_ROOT_DIR - Set this variable to the root installation of libfido2
#
# Read-Only variables:
# LIBFIDO2_FOUND - system has libfido2
# LIBFIDO2_INCLUDE_DIR - the libfido2 include directory
# LIBFIDO2_LIBRARIES - Link these to use libfido2
#
# The libfido2 library provides support for communicating
# with FIDO2/U2F devices over USB/NFC.
#
# Copyright (c) 2025 Praneeth Sarode <praneethsarode@gmail.com>
#
# Redistribution and use is allowed according to the terms of the New
# BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
#
set(_LIBFIDO2_ROOT_HINTS
$ENV{LIBFIDO2_ROOT_DIR}
${LIBFIDO2_ROOT_DIR}
)
set(_LIBFIDO2_ROOT_PATHS
"$ENV{PROGRAMFILES}/libfido2"
)
set(_LIBFIDO2_ROOT_HINTS_AND_PATHS
HINTS ${_LIBFIDO2_ROOT_HINTS}
PATHS ${_LIBFIDO2_ROOT_PATHS}
)
find_path(LIBFIDO2_INCLUDE_DIR
NAMES
fido.h
HINTS
${_LIBFIDO2_ROOT_HINTS_AND_PATHS}
PATH_SUFFIXES
include
)
find_library(LIBFIDO2_LIBRARY
NAMES
fido2
HINTS
${_LIBFIDO2_ROOT_HINTS_AND_PATHS}
PATH_SUFFIXES
lib
lib64
)
set(LIBFIDO2_LIBRARIES
${LIBFIDO2_LIBRARY}
)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(libfido2 DEFAULT_MSG LIBFIDO2_LIBRARIES LIBFIDO2_INCLUDE_DIR)
# show the LIBFIDO2_INCLUDE_DIR and LIBFIDO2_LIBRARIES variables only in the advanced view
mark_as_advanced(LIBFIDO2_INCLUDE_DIR LIBFIDO2_LIBRARIES)

View File

@@ -9,9 +9,11 @@
#cmakedefine SOURCEDIR "${SOURCEDIR}" #cmakedefine SOURCEDIR "${SOURCEDIR}"
/* Global bind configuration file path */ /* Global bind configuration file path */
#cmakedefine USR_GLOBAL_BIND_CONFIG "${USR_GLOBAL_BIND_CONFIG}"
#cmakedefine GLOBAL_BIND_CONFIG "${GLOBAL_BIND_CONFIG}" #cmakedefine GLOBAL_BIND_CONFIG "${GLOBAL_BIND_CONFIG}"
/* Global client configuration file path */ /* Global client configuration file path */
#cmakedefine USR_GLOBAL_CLIENT_CONFIG "${USR_GLOBAL_CLIENT_CONFIG}"
#cmakedefine GLOBAL_CLIENT_CONFIG "${GLOBAL_CLIENT_CONFIG}" #cmakedefine GLOBAL_CLIENT_CONFIG "${GLOBAL_CLIENT_CONFIG}"
/************************** HEADER FILES *************************/ /************************** HEADER FILES *************************/
@@ -58,6 +60,9 @@
/* Define to 1 if you have the <stdint.h> header file. */ /* Define to 1 if you have the <stdint.h> header file. */
#cmakedefine HAVE_STDINT_H 1 #cmakedefine HAVE_STDINT_H 1
/* Define to 1 if you have the <ifaddrs.h> header file. */
#cmakedefine HAVE_IFADDRS_H 1
/* Define to 1 if you have the <openssl/aes.h> header file. */ /* Define to 1 if you have the <openssl/aes.h> header file. */
#cmakedefine HAVE_OPENSSL_AES_H 1 #cmakedefine HAVE_OPENSSL_AES_H 1
@@ -82,6 +87,9 @@
/* Define to 1 if you have elliptic curve cryptography in openssl */ /* Define to 1 if you have elliptic curve cryptography in openssl */
#cmakedefine HAVE_OPENSSL_ECC 1 #cmakedefine HAVE_OPENSSL_ECC 1
/* Define to 1 if mbedTLS supports curve25519 */
#cmakedefine HAVE_MBEDTLS_CURVE25519 1
/* Define to 1 if you have elliptic curve cryptography in gcrypt */ /* Define to 1 if you have elliptic curve cryptography in gcrypt */
#cmakedefine HAVE_GCRYPT_ECC 1 #cmakedefine HAVE_GCRYPT_ECC 1
@@ -94,6 +102,9 @@
/* Define to 1 if you have gcrypt with ChaCha20/Poly1305 support */ /* Define to 1 if you have gcrypt with ChaCha20/Poly1305 support */
#cmakedefine HAVE_GCRYPT_CHACHA_POLY 1 #cmakedefine HAVE_GCRYPT_CHACHA_POLY 1
/* Define to 1 if you have gcrypt with curve25519 support */
#cmakedefine HAVE_GCRYPT_CURVE25519
/*************************** FUNCTIONS ***************************/ /*************************** FUNCTIONS ***************************/
/* Define to 1 if you have the `EVP_chacha20' function. */ /* Define to 1 if you have the `EVP_chacha20' function. */
@@ -168,6 +179,9 @@
/* Define to 1 if you have the `explicit_bzero' function. */ /* Define to 1 if you have the `explicit_bzero' function. */
#cmakedefine HAVE_EXPLICIT_BZERO 1 #cmakedefine HAVE_EXPLICIT_BZERO 1
/* Define to 1 if you have the `memset_explicit' function. */
#cmakedefine HAVE_MEMSET_EXPLICIT 1
/* Define to 1 if you have the `memset_s' function. */ /* Define to 1 if you have the `memset_s' function. */
#cmakedefine HAVE_MEMSET_S 1 #cmakedefine HAVE_MEMSET_S 1
@@ -180,6 +194,15 @@
/* Define to 1 if we have support for blowfish */ /* Define to 1 if we have support for blowfish */
#cmakedefine HAVE_BLOWFISH 1 #cmakedefine HAVE_BLOWFISH 1
/* Define to 1 if we have support for ML-KEM in libgcrypt */
#cmakedefine HAVE_GCRYPT_MLKEM 1
/* Define to 1 if we have support for ML-KEM in OpenSSL */
#cmakedefine HAVE_OPENSSL_MLKEM 1
/* Define to 1 if we have support for ML-KEM1024 in either backend */
#cmakedefine HAVE_MLKEM1024 1
/*************************** LIBRARIES ***************************/ /*************************** LIBRARIES ***************************/
/* Define to 1 if you have the `crypto' library (-lcrypto). */ /* Define to 1 if you have the `crypto' library (-lcrypto). */
@@ -197,6 +220,10 @@
/* Define to 1 if you have the `cmocka' library (-lcmocka). */ /* Define to 1 if you have the `cmocka' library (-lcmocka). */
#cmakedefine HAVE_CMOCKA 1 #cmakedefine HAVE_CMOCKA 1
/* Define to 1 if you have the `libfido2' library (-lfido2).
* This is required for interacting with FIDO2/U2F devices over USB-HID. */
#cmakedefine HAVE_LIBFIDO2 1
/**************************** OPTIONS ****************************/ /**************************** OPTIONS ****************************/
#cmakedefine HAVE_GCC_THREAD_LOCAL_STORAGE 1 #cmakedefine HAVE_GCC_THREAD_LOCAL_STORAGE 1
@@ -263,6 +290,9 @@
/* Define to 1 if we want to build a support for PKCS #11 provider. */ /* Define to 1 if we want to build a support for PKCS #11 provider. */
#cmakedefine WITH_PKCS11_PROVIDER 1 #cmakedefine WITH_PKCS11_PROVIDER 1
/* Define to 1 if you want to enable FIDO2/U2F support */
#cmakedefine WITH_FIDO2 1
/*************************** ENDIAN *****************************/ /*************************** ENDIAN *****************************/
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most /* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most

View File

@@ -1,91 +1,247 @@
# #
# Build the documentation # Build the documentation
# #
if (${CMAKE_VERSION} VERSION_GREATER "3.8.99") # To build the documentation with a local doxygen-awesome-css directory:
#
# cmake -S . -B obj \
# -DDOXYGEN_AWESOME_CSS_DIR=/path/to/doxygen-awesome-css
# cmake --build obj --target docs
#
# The tarball can be downloaded from:
# https://github.com/jothepro/doxygen-awesome-css/archive/refs/tags/v2.4.1.tar.gz
#
find_package(Doxygen) find_package(Doxygen)
if (DOXYGEN_FOUND) if (DOXYGEN_FOUND)
set(DOXYGEN_AWESOME_CSS_PROJECT
"https://github.com/jothepro/doxygen-awesome-css")
set(DOXYGEN_AWESOME_CSS_VERSION "2.4.1")
set(DOXYGEN_AWESOME_CSS_URL
"${DOXYGEN_AWESOME_CSS_PROJECT}/archive/refs/tags/v${DOXYGEN_AWESOME_CSS_VERSION}.tar.gz"
)
# Allow specifying a local doxygen-awesome-css directory (useful for
# packaging)
if (NOT DEFINED DOXYGEN_AWESOME_CSS_DIR)
# Custom target to download doxygen-awesome-css at build time
add_custom_target(
doxygen-awesome-css
COMMAND
${CMAKE_COMMAND} -DURL=${DOXYGEN_AWESOME_CSS_URL}
-DDEST_DIR=${CMAKE_CURRENT_BINARY_DIR}
-DVERSION=${DOXYGEN_AWESOME_CSS_VERSION} -P
${CMAKE_CURRENT_SOURCE_DIR}/fetch_doxygen_awesome.cmake
COMMENT "Fetching doxygen-awesome-css theme")
set(AWESOME_CSS_DIR
"${CMAKE_CURRENT_BINARY_DIR}/doxygen-awesome-css-${DOXYGEN_AWESOME_CSS_VERSION}"
)
else ()
message(
STATUS
"Using doxygen-awesome-css from ${DOXYGEN_AWESOME_CSS_DIR}")
set(AWESOME_CSS_DIR "${DOXYGEN_AWESOME_CSS_DIR}")
endif ()
# Project title shown in documentation
set(DOXYGEN_PROJECT_NAME ${PROJECT_NAME}) set(DOXYGEN_PROJECT_NAME ${PROJECT_NAME})
# Project version number shown in documentation
set(DOXYGEN_PROJECT_NUMBER ${PROJECT_VERSION}) set(DOXYGEN_PROJECT_NUMBER ${PROJECT_VERSION})
# Brief description shown below project name
set(DOXYGEN_PROJECT_BRIEF "The SSH library") set(DOXYGEN_PROJECT_BRIEF "The SSH library")
# Project favicon (browser tab icon)
set(DOXYGEN_PROJECT_ICON ${CMAKE_CURRENT_SOURCE_DIR}/favicon.png)
# Number of spaces used for indentation in code blocks
set(DOXYGEN_TAB_SIZE 4) set(DOXYGEN_TAB_SIZE 4)
# Generate output optimized for C (vs C++)
set(DOXYGEN_OPTIMIZE_OUTPUT_FOR_C YES) set(DOXYGEN_OPTIMIZE_OUTPUT_FOR_C YES)
# Enable parsing of markdown in comments
set(DOXYGEN_MARKDOWN_SUPPORT YES) set(DOXYGEN_MARKDOWN_SUPPORT YES)
set(DOXYGEN_FULL_PATH_NAMES NO) # Warn about undocumented members to improve documentation quality
set(DOXYGEN_GENERATE_TAGFILE "tags.xml") set(DOXYGEN_WARN_IF_UNDOCUMENTED YES)
# Do not extract private class members
set(DOXYGEN_EXTRACT_PRIVATE NO)
if (WITH_INTERNAL_DOC)
# Include internal documentation
set(DOXYGEN_INTERNAL_DOCS YES)
else ()
# Do not include internal documentation
set(DOXYGEN_INTERNAL_DOCS NO)
endif( WITH_INTERNAL_DOC)
# Disable built-in clipboard (using doxygen-awesome extension instead)
set(DOXYGEN_HTML_COPY_CLIPBOARD NO)
# Disable page outline panel (using interactive TOC extension instead)
set(DOXYGEN_PAGE_OUTLINE_PANEL NO)
set(DOXYGEN_PREDEFINED DOXYGEN # Required configuration for doxygen-awesome-css theme Generate treeview
WITH_SERVER # sidebar for navigation
WITH_SFTP set(DOXYGEN_GENERATE_TREEVIEW YES)
# Enable default index pages
set(DOXYGEN_DISABLE_INDEX NO)
# Use top navigation bar instead of full sidebar (required for theme
# compatibility)
set(DOXYGEN_FULL_SIDEBAR NO)
# Use light color style (required for Doxygen >= 1.9.5)
set(DOXYGEN_HTML_COLORSTYLE LIGHT)
# Disable diagram generation (not relevant for C projects)
set(DOXYGEN_HAVE_DOT NO)
set(DOXYGEN_CLASS_DIAGRAMS NO)
set(DOXYGEN_CALL_GRAPH NO)
set(DOXYGEN_CALLER_GRAPH NO)
# Preprocessor defines to use when parsing code
set(DOXYGEN_PREDEFINED DOXYGEN WITH_SERVER WITH_SFTP
PRINTF_ATTRIBUTE\(x,y\)) PRINTF_ATTRIBUTE\(x,y\))
set(DOXYGEN_DOT_GRAPH_MAX_NODES 100)
set(DOXYGEN_EXCLUDE ${CMAKE_CURRENT_SOURCE_DIR}/that_style) # Exclude patterns for files we don't want to document
set(DOXYGEN_HTML_HEADER ${CMAKE_CURRENT_SOURCE_DIR}/that_style/header.html) set(DOXYGEN_EXCLUDE_PATTERNS */src/external/* fe25519.h ge25519.h sc25519.h
set(DOXYGEN_HTML_EXTRA_STYLESHEET ${CMAKE_CURRENT_SOURCE_DIR}/that_style/that_style.css) blf.h)
set(DOXYGEN_HTML_EXTRA_FILES ${CMAKE_CURRENT_SOURCE_DIR}/that_style/img/nav_edge_left.svg # Exclude internal structures from documentation
${CMAKE_CURRENT_SOURCE_DIR}/that_style/img/nav_edge_right.svg set(DOXYGEN_EXCLUDE_SYMBOLS_STRUCTS
${CMAKE_CURRENT_SOURCE_DIR}/that_style/img/nav_edge_inter.svg chacha20_poly1305_keysched,
${CMAKE_CURRENT_SOURCE_DIR}/that_style/img/sync_off.png dh_ctx,
${CMAKE_CURRENT_SOURCE_DIR}/that_style/img/sync_on.png dh_ctx,
${CMAKE_CURRENT_SOURCE_DIR}/that_style/img/splitbar_handle.svg dh_keypair,
${CMAKE_CURRENT_SOURCE_DIR}/that_style/img/doc.svg error_struct,
${CMAKE_CURRENT_SOURCE_DIR}/that_style/img/mag_glass.svg packet_struct,
${CMAKE_CURRENT_SOURCE_DIR}/that_style/img/folderclosed.svg pem_get_password_struct,
${CMAKE_CURRENT_SOURCE_DIR}/that_style/img/folderopen.svg ssh_tokens_st,
${CMAKE_CURRENT_SOURCE_DIR}/that_style/js/striped_bg.js) sftp_attributes_struct,
set(DOXYGEN_EXCLUDE_PATTERNS */src/external/* fe25519.h ge25519.h sc25519.h sftp_client_message_struct,
blf.h) sftp_dir_struct,
set(DOXYGEN_EXCLUDE_SYMBOLS_STRUCTS chacha20_poly1305_keysched,dh_ctx,dh_ctx,dh_keypair,error_struct, sftp_ext_struct,
packet_struct,pem_get_password_struct,ssh_tokens_st, sftp_file_struct,
sftp_attributes_struct,sftp_client_message_struct, sftp_message_struct,
sftp_dir_struct,sftp_ext_struct,sftp_file_struct,sftp_message_struct, sftp_packet_struct,
sftp_packet_struct,sftp_request_queue_struct,sftp_session_struct, sftp_request_queue_struct,
sftp_status_message_struct,ssh_agent_state_struct, sftp_session_struct,
ssh_agent_struct,ssh_auth_auto_state_struct,ssh_auth_request, sftp_status_message_struct,
ssh_bind_config_keyword_table_s,ssh_bind_config_match_keyword_table_s, ssh_agent_state_struct,
ssh_bind_struct,ssh_buffer_struct,ssh_channel_callbacks_struct, ssh_agent_struct,
ssh_channel_read_termination_struct,ssh_channel_request, ssh_auth_auto_state_struct,
ssh_channel_request_open,ssh_channel_struct,ssh_cipher_struct, ssh_auth_request,
ssh_common_struct,ssh_config_keyword_table_s, ssh_bind_config_keyword_table_s,
ssh_config_match_keyword_table_s,ssh_connector_struct, ssh_bind_config_match_keyword_table_s,
ssh_counter_struct,ssh_crypto_struct,ssh_event_fd_wrapper, ssh_bind_struct,
ssh_event_struct,ssh_global_request,ssh_gssapi_struct,ssh_hmac_struct, ssh_buffer_struct,
ssh_iterator,ssh_kbdint_struct,ssh_kex_struct,ssh_key_struct, ssh_channel_callbacks_struct,
ssh_knownhosts_entry,ssh_list,ssh_mac_ctx_struct,ssh_message_struct, ssh_channel_read_termination_struct,
ssh_packet_callbacks_struct,ssh_packet_header,ssh_poll_ctx_struct, ssh_channel_request,
ssh_poll_handle_struct,ssh_pollfd_struct,ssh_private_key_struct, ssh_channel_request_open,
ssh_public_key_struct,ssh_scp_struct,ssh_service_request, ssh_channel_struct,
ssh_session_struct,ssh_signature_struct,ssh_socket_struct, ssh_cipher_struct,
ssh_string_struct,ssh_threads_callbacks_struct,ssh_timestamp,) ssh_common_struct,
set(DOXYGEN_EXCLUDE_SYMBOLS_MACRO SSH_FXP*,SSH_SOCKET*,SERVERBANNER,SOCKOPT_TYPE_ARG4,SSH_FILEXFER*, ssh_config_keyword_table_s,
SSH_FXF*,SSH_S_*,SFTP_*,NSS_BUFLEN_PASSWD,CLOCK,MAX_LINE_SIZE, ssh_config_match_keyword_table_s,
PKCS11_URI,KNOWNHOSTS_MAXTYPES,) ssh_connector_struct,
set(DOXYGEN_EXCLUDE_SYMBOLS_TYPEDEFS sftp_attributes,sftp_client_message,sftp_dir,sftp_ext,sftp_file, ssh_counter_struct,
sftp_message,sftp_packet,sftp_request_queue,sftp_session, ssh_crypto_struct,
sftp_status_message,sftp_statvfs_t,poll_fn,ssh_callback_int, ssh_event_fd_wrapper,
ssh_callback_data,ssh_callback_int_int,ssh_message_callback, ssh_event_struct,
ssh_channel_callback_int,ssh_channel_callback_data,ssh_callbacks, ssh_global_request,
ssh_gssapi_select_oid_callback,ssh_gssapi_accept_sec_ctx_callback, ssh_gssapi_struct,
ssh_gssapi_verify_mic_callback,ssh_server_callbacks,ssh_socket_callbacks, ssh_hmac_struct,
ssh_packet_callbacks,ssh_channel_callbacks,ssh_bind,ssh_bind_callbacks,) ssh_iterator,
set(DOXYGEN_EXCLUDE_SYMBOLS ${DOXYGEN_EXCLUDE_SYMBOLS_STRUCTS} ssh_kbdint_struct,
${DOXYGEN_EXCLUDE_SYMBOLS_MACRO} ssh_kex_struct,
${DOXYGEN_EXCLUDE_SYMBOLS_TYPEDEFS}) ssh_key_struct,
ssh_knownhosts_entry,
ssh_list,
ssh_mac_ctx_struct,
ssh_message_struct,
ssh_packet_callbacks_struct,
ssh_packet_header,
ssh_poll_ctx_struct,
ssh_poll_handle_struct,
ssh_pollfd_struct,
ssh_private_key_struct,
ssh_public_key_struct,
ssh_scp_struct,
ssh_service_request,
ssh_session_struct,
ssh_signature_struct,
ssh_socket_struct,
ssh_string_struct,
ssh_threads_callbacks_struct,
ssh_timestamp)
set(DOXYGEN_EXCLUDE_SYMBOLS_MACRO
SSH_FXP*,
SSH_SOCKET*,
SERVERBANNER,
SOCKOPT_TYPE_ARG4,
SSH_FILEXFER*,
SSH_FXF*,
SSH_S_*,
SFTP_*,
NSS_BUFLEN_PASSWD,
CLOCK,
MAX_LINE_SIZE,
PKCS11_URI,
KNOWNHOSTS_MAXTYPES)
set(DOXYGEN_EXCLUDE_SYMBOLS_TYPEDEFS
sftp_attributes,
sftp_client_message,
sftp_dir,
sftp_ext,
sftp_file,
sftp_message,
sftp_packet,
sftp_request_queue,
sftp_status_message,
sftp_statvfs_t,
poll_fn,
ssh_callback_int,
ssh_callback_data,
ssh_callback_int_int,
ssh_message_callback,
ssh_channel_callback_int,
ssh_channel_callback_data,
ssh_callbacks,
ssh_gssapi_select_oid_callback,
ssh_gssapi_accept_sec_ctx_callback,
ssh_gssapi_verify_mic_callback,
ssh_server_callbacks,
ssh_socket_callbacks,
ssh_packet_callbacks,
ssh_channel_callbacks,
ssh_bind,
ssh_bind_callbacks)
set(DOXYGEN_EXCLUDE_SYMBOLS
${DOXYGEN_EXCLUDE_SYMBOLS_STRUCTS} ${DOXYGEN_EXCLUDE_SYMBOLS_MACRO}
${DOXYGEN_EXCLUDE_SYMBOLS_TYPEDEFS})
# Custom layout file to rename "Topics" to "API Reference" and simplify
# navigation
set(DOXYGEN_LAYOUT_FILE ${CMAKE_CURRENT_SOURCE_DIR}/DoxygenLayout.xml)
# Custom HTML header with doxygen-awesome extension initialization
set(DOXYGEN_HTML_HEADER ${CMAKE_CURRENT_SOURCE_DIR}/header.html)
# Modern CSS theme for documentation with custom libssh.org color scheme
set(DOXYGEN_HTML_EXTRA_STYLESHEET
${AWESOME_CSS_DIR}/doxygen-awesome.css
${CMAKE_CURRENT_SOURCE_DIR}/doxygen-custom.css)
# JavaScript extensions: dark mode toggle, copy button, paragraph links,
# interactive TOC
set(DOXYGEN_HTML_EXTRA_FILES
${AWESOME_CSS_DIR}/doxygen-awesome-darkmode-toggle.js
${AWESOME_CSS_DIR}/doxygen-awesome-fragment-copy-button.js
${AWESOME_CSS_DIR}/doxygen-awesome-paragraph-link.js
${AWESOME_CSS_DIR}/doxygen-awesome-interactive-toc.js)
# This updates the Doxyfile if we do changes here
set(_doxyfile_template "${CMAKE_BINARY_DIR}/CMakeDoxyfile.in") set(_doxyfile_template "${CMAKE_BINARY_DIR}/CMakeDoxyfile.in")
set(_target_doxyfile "${CMAKE_CURRENT_BINARY_DIR}/Doxyfile.docs") set(_target_doxyfile "${CMAKE_CURRENT_BINARY_DIR}/Doxyfile.docs")
configure_file("${_doxyfile_template}" "${_target_doxyfile}") configure_file("${_doxyfile_template}" "${_target_doxyfile}")
doxygen_add_docs(docs doxygen_add_docs(docs ${CMAKE_SOURCE_DIR}/include/libssh
${CMAKE_SOURCE_DIR}/include/libssh ${CMAKE_SOURCE_DIR}/src ${CMAKE_CURRENT_SOURCE_DIR})
${CMAKE_SOURCE_DIR}/src
${CMAKE_CURRENT_SOURCE_DIR})
add_custom_target(docs_coverage COMMAND ${CMAKE_SOURCE_DIR}/doc/doc_coverage.sh ${CMAKE_BINARY_DIR}) # Make docs depend on doxygen-awesome-css download (if not using local dir)
endif() # DOXYGEN_FOUND if (TARGET doxygen-awesome-css)
add_dependencies(docs doxygen-awesome-css)
endif ()
endif() # CMAKE_VERSION add_custom_target(
docs_coverage COMMAND ${CMAKE_SOURCE_DIR}/doc/doc_coverage.sh
${CMAKE_BINARY_DIR})
endif (DOXYGEN_FOUND)

242
doc/DoxygenLayout.xml Normal file
View File

@@ -0,0 +1,242 @@
<?xml version="1.0" encoding="UTF-8"?>
<doxygenlayout version="2.0">
<!-- Generated by doxygen 1.14.0 -->
<!-- Navigation index tabs for HTML output -->
<navindex>
<tab type="mainpage" visible="yes" title=""/>
<tab type="topics" visible="yes" title="API Reference" intro=""/>
<tab type="pages" visible="yes" title="" intro=""/>
<tab type="files" visible="yes" title="">
<tab type="filelist" visible="yes" title="" intro=""/>
<tab type="globals" visible="yes" title="" intro=""/>
</tab>
<tab type="structs" visible="yes" title="">
<tab type="structlist" visible="yes" title="" intro=""/>
<tab type="structindex" visible="$ALPHABETICAL_INDEX" title=""/>
</tab>
</navindex>
<!-- Layout definition for a class page -->
<class>
<briefdescription visible="yes"/>
<includes visible="$SHOW_HEADERFILE"/>
<inheritancegraph visible="yes"/>
<collaborationgraph visible="yes"/>
<memberdecl>
<nestedclasses visible="yes" title=""/>
<publictypes visible="yes" title=""/>
<services visible="yes" title=""/>
<interfaces visible="yes" title=""/>
<publicslots visible="yes" title=""/>
<signals visible="yes" title=""/>
<publicmethods visible="yes" title=""/>
<publicstaticmethods visible="yes" title=""/>
<publicattributes visible="yes" title=""/>
<publicstaticattributes visible="yes" title=""/>
<protectedtypes visible="yes" title=""/>
<protectedslots visible="yes" title=""/>
<protectedmethods visible="yes" title=""/>
<protectedstaticmethods visible="yes" title=""/>
<protectedattributes visible="yes" title=""/>
<protectedstaticattributes visible="yes" title=""/>
<packagetypes visible="yes" title=""/>
<packagemethods visible="yes" title=""/>
<packagestaticmethods visible="yes" title=""/>
<packageattributes visible="yes" title=""/>
<packagestaticattributes visible="yes" title=""/>
<properties visible="yes" title=""/>
<events visible="yes" title=""/>
<privatetypes visible="yes" title=""/>
<privateslots visible="yes" title=""/>
<privatemethods visible="yes" title=""/>
<privatestaticmethods visible="yes" title=""/>
<privateattributes visible="yes" title=""/>
<privatestaticattributes visible="yes" title=""/>
<friends visible="yes" title=""/>
<related visible="yes" title="" subtitle=""/>
<membergroups visible="yes"/>
</memberdecl>
<detaileddescription visible="yes" title=""/>
<memberdef>
<inlineclasses visible="yes" title=""/>
<typedefs visible="yes" title=""/>
<enums visible="yes" title=""/>
<services visible="yes" title=""/>
<interfaces visible="yes" title=""/>
<constructors visible="yes" title=""/>
<functions visible="yes" title=""/>
<related visible="yes" title=""/>
<variables visible="yes" title=""/>
<properties visible="yes" title=""/>
<events visible="yes" title=""/>
</memberdef>
<allmemberslink visible="yes"/>
<usedfiles visible="$SHOW_USED_FILES"/>
<authorsection visible="yes"/>
</class>
<!-- Layout definition for a namespace page -->
<namespace>
<briefdescription visible="yes"/>
<memberdecl>
<nestednamespaces visible="yes" title=""/>
<constantgroups visible="yes" title=""/>
<interfaces visible="yes" title=""/>
<classes visible="yes" title=""/>
<concepts visible="yes" title=""/>
<structs visible="yes" title=""/>
<exceptions visible="yes" title=""/>
<typedefs visible="yes" title=""/>
<sequences visible="yes" title=""/>
<dictionaries visible="yes" title=""/>
<enums visible="yes" title=""/>
<functions visible="yes" title=""/>
<variables visible="yes" title=""/>
<properties visible="yes" title=""/>
<membergroups visible="yes"/>
</memberdecl>
<detaileddescription visible="yes" title=""/>
<memberdef>
<inlineclasses visible="yes" title=""/>
<typedefs visible="yes" title=""/>
<sequences visible="yes" title=""/>
<dictionaries visible="yes" title=""/>
<enums visible="yes" title=""/>
<functions visible="yes" title=""/>
<variables visible="yes" title=""/>
<properties visible="yes" title=""/>
</memberdef>
<authorsection visible="yes"/>
</namespace>
<!-- Layout definition for a concept page -->
<concept>
<briefdescription visible="yes"/>
<includes visible="$SHOW_HEADERFILE"/>
<definition visible="yes" title=""/>
<detaileddescription visible="yes" title=""/>
<authorsection visible="yes"/>
</concept>
<!-- Layout definition for a file page -->
<file>
<briefdescription visible="yes"/>
<includes visible="$SHOW_INCLUDE_FILES"/>
<includegraph visible="yes"/>
<includedbygraph visible="yes"/>
<sourcelink visible="yes"/>
<memberdecl>
<interfaces visible="yes" title=""/>
<classes visible="yes" title=""/>
<structs visible="yes" title=""/>
<exceptions visible="yes" title=""/>
<namespaces visible="yes" title=""/>
<concepts visible="yes" title=""/>
<constantgroups visible="yes" title=""/>
<defines visible="yes" title=""/>
<typedefs visible="yes" title=""/>
<sequences visible="yes" title=""/>
<dictionaries visible="yes" title=""/>
<enums visible="yes" title=""/>
<functions visible="yes" title=""/>
<variables visible="yes" title=""/>
<properties visible="yes" title=""/>
<membergroups visible="yes"/>
</memberdecl>
<detaileddescription visible="yes" title=""/>
<memberdef>
<inlineclasses visible="yes" title=""/>
<defines visible="yes" title=""/>
<typedefs visible="yes" title=""/>
<sequences visible="yes" title=""/>
<dictionaries visible="yes" title=""/>
<enums visible="yes" title=""/>
<functions visible="yes" title=""/>
<variables visible="yes" title=""/>
<properties visible="yes" title=""/>
</memberdef>
<authorsection/>
</file>
<!-- Layout definition for a group page -->
<group>
<briefdescription visible="yes"/>
<groupgraph visible="yes"/>
<memberdecl>
<nestedgroups visible="yes" title=""/>
<modules visible="yes" title=""/>
<dirs visible="yes" title=""/>
<files visible="yes" title=""/>
<namespaces visible="yes" title=""/>
<concepts visible="yes" title=""/>
<classes visible="yes" title=""/>
<defines visible="yes" title=""/>
<typedefs visible="yes" title=""/>
<sequences visible="yes" title=""/>
<dictionaries visible="yes" title=""/>
<enums visible="yes" title=""/>
<enumvalues visible="yes" title=""/>
<functions visible="yes" title=""/>
<variables visible="yes" title=""/>
<signals visible="yes" title=""/>
<publicslots visible="yes" title=""/>
<protectedslots visible="yes" title=""/>
<privateslots visible="yes" title=""/>
<events visible="yes" title=""/>
<properties visible="yes" title=""/>
<friends visible="yes" title=""/>
<membergroups visible="yes"/>
</memberdecl>
<detaileddescription visible="yes" title=""/>
<memberdef>
<pagedocs/>
<inlineclasses visible="yes" title=""/>
<defines visible="yes" title=""/>
<typedefs visible="yes" title=""/>
<sequences visible="yes" title=""/>
<dictionaries visible="yes" title=""/>
<enums visible="yes" title=""/>
<enumvalues visible="yes" title=""/>
<functions visible="yes" title=""/>
<variables visible="yes" title=""/>
<signals visible="yes" title=""/>
<publicslots visible="yes" title=""/>
<protectedslots visible="yes" title=""/>
<privateslots visible="yes" title=""/>
<events visible="yes" title=""/>
<properties visible="yes" title=""/>
<friends visible="yes" title=""/>
</memberdef>
<authorsection visible="yes"/>
</group>
<!-- Layout definition for a C++20 module page -->
<module>
<briefdescription visible="yes"/>
<exportedmodules visible="yes"/>
<memberdecl>
<concepts visible="yes" title=""/>
<classes visible="yes" title=""/>
<enums visible="yes" title=""/>
<typedefs visible="yes" title=""/>
<functions visible="yes" title=""/>
<variables visible="yes" title=""/>
<membergroups visible="yes" title=""/>
</memberdecl>
<detaileddescription visible="yes" title=""/>
<memberdecl>
<files visible="yes"/>
</memberdecl>
</module>
<!-- Layout definition for a directory page -->
<directory>
<briefdescription visible="yes"/>
<directorygraph visible="yes"/>
<memberdecl>
<dirs visible="yes"/>
<files visible="yes"/>
</memberdecl>
<detaileddescription visible="yes" title=""/>
</directory>
</doxygenlayout>

View File

@@ -105,7 +105,7 @@ Here is a small example of password authentication:
@code @code
int authenticate_password(ssh_session session) int authenticate_password(ssh_session session)
{ {
char *password; char *password = NULL;
int rc; int rc;
password = getpass("Enter your password: "); password = getpass("Enter your password: ");
@@ -218,7 +218,7 @@ int authenticate_kbdint(ssh_session session)
rc = ssh_userauth_kbdint(session, NULL, NULL); rc = ssh_userauth_kbdint(session, NULL, NULL);
while (rc == SSH_AUTH_INFO) while (rc == SSH_AUTH_INFO)
{ {
const char *name, *instruction; const char *name = NULL, *instruction = NULL;
int nprompts, iprompt; int nprompts, iprompt;
name = ssh_userauth_kbdint_getname(session); name = ssh_userauth_kbdint_getname(session);
@@ -231,7 +231,7 @@ int authenticate_kbdint(ssh_session session)
printf("%s\n", instruction); printf("%s\n", instruction);
for (iprompt = 0; iprompt < nprompts; iprompt++) for (iprompt = 0; iprompt < nprompts; iprompt++)
{ {
const char *prompt; const char *prompt = NULL;
char echo; char echo;
prompt = ssh_userauth_kbdint_getprompt(session, iprompt, &echo); prompt = ssh_userauth_kbdint_getprompt(session, iprompt, &echo);
@@ -251,7 +251,7 @@ int authenticate_kbdint(ssh_session session)
} }
else else
{ {
char *ptr; char *ptr = NULL;
ptr = getpass(prompt); ptr = getpass(prompt);
if (ssh_userauth_kbdint_setanswer(session, iprompt, ptr) < 0) if (ssh_userauth_kbdint_setanswer(session, iprompt, ptr) < 0)
@@ -354,7 +354,7 @@ The following example shows how to retrieve and dispose the issue banner:
int display_banner(ssh_session session) int display_banner(ssh_session session)
{ {
int rc; int rc;
char *banner; char *banner = NULL;
/* /*
*** Does not work without calling ssh_userauth_none() first *** *** Does not work without calling ssh_userauth_none() first ***

View File

@@ -22,7 +22,7 @@ a SSH session that uses this channel:
@code @code
int show_remote_files(ssh_session session) int show_remote_files(ssh_session session)
{ {
ssh_channel channel; ssh_channel channel = NULL;
int rc; int rc;
channel = ssh_channel_new(session); channel = ssh_channel_new(session);
@@ -91,4 +91,10 @@ that it used:
} }
@endcode @endcode
Warning: In a single channel, only ONE command can be executed!
If you want to executed multiple commands, allocate separate channels for
them or consider opening interactive shell.
Attempting to run multiple consecutive commands in one channel will fail.
*/ */

127
doc/doxygen-custom.css Normal file
View File

@@ -0,0 +1,127 @@
/**
* Custom color scheme for libssh documentation
* Based on libssh.org color palette
*/
html {
/* Primary colors - using libssh.org orange accent */
--primary-color: #F78C40;
--primary-dark-color: #f57900;
--primary-light-color: #fab889;
/* Accent color - neutral gray */
--primary-lighter-color: #5A5A5A;
/* Page colors - clean white background */
--page-background-color: #ffffff;
--page-foreground-color: #333333;
--page-secondary-foreground-color: #666666;
/* Links - use the warm orange color */
--link-color: #F78C40;
--link-hover-color: #f0690a;
/* Code blocks and fragments - very light background */
--code-background: #f9f9f9;
--fragment-background: #f9f9f9;
/* Borders - subtle light grey */
--separator-color: #e0e0e0;
--border-light-color: #f0f0f0;
/* Side navigation - pure white */
--side-nav-background: #ffffff;
/* Menu colors - warm orange accent */
--menu-selected-background: #F78C40;
/* Tables and boxes - lighter */
--tablehead-background: #fbc7a2;
--tablehead-foreground: #333333;
}
/* Header styling with libssh brand colors */
#titlearea {
background-color: #5A5A5A;
background-image: linear-gradient(to right, #5A5A5A, #6a6a6a);
border-bottom: 3px solid #F78C40;
}
#projectname {
color: #ffffff !important;
}
#projectbrief {
color: #fab889 !important;
}
/* Top navigation tabs */
#top {
background: linear-gradient(to bottom, #5A5A5A 0%, #6a6a6a 100%);
}
.tabs, .tabs2, .tabs3 {
background-image: none;
background-color: transparent;
}
.tablist li {
background: rgba(255, 255, 255, 0.1);
border-right: 1px solid rgba(255, 255, 255, 0.2);
}
.tablist li:hover {
background: rgba(255, 255, 255, 0.2);
}
.tablist li.current {
background: #F78C40;
border-bottom: 3px solid #f57900;
}
/* Tab text colors - comprehensive selectors */
#nav-path ul li a,
.tabs a,
.tabs2 a,
.tabs3 a,
.tablist a,
.tablist a:link,
.tablist a:visited,
.tablist li a,
#main-nav a,
.sm > li > a,
.sm > li > a .sub-arrow {
color: #ffffff !important;
text-shadow: 0px 1px 2px rgba(0, 0, 0, 0.3);
}
/* Active/current tab text */
#nav-path ul li.current a,
.tabs .current a,
.tabs2 .current a,
.tabs3 .current a,
.tablist .current a,
.tablist .current a:link,
.tablist .current a:visited,
.tablist li.current a,
#main-nav .current a,
.sm .current a {
color: #333333 !important;
text-shadow: none;
}
/* Dropdown arrow - white color for top menu */
.sm-dox a span.sub-arrow {
border-right-color: #ffffff !important;
border-bottom-color: #ffffff !important;
}
/* Dropdown menu text - must be dark on white background */
/* Make this as specific as possible to override white color */
.sm-dox > li > ul > li > a,
.sm-dox li ul li a,
.sm-dox ul li a,
#main-menu ul li a {
color: #333333 !important;
text-shadow: none !important;
}

BIN
doc/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 858 B

View File

@@ -0,0 +1,41 @@
# Script to download doxygen-awesome-css at build time
#
# Usage:
# cmake -P fetch_doxygen_awesome.cmake \
# -DURL=<download_url> \
# -DDEST_DIR=<destination_directory> \
# -DVERSION=<version>
if(NOT DEFINED URL)
message(FATAL_ERROR "URL not specified")
endif()
if(NOT DEFINED DEST_DIR)
message(FATAL_ERROR "DEST_DIR not specified")
endif()
if(NOT DEFINED VERSION)
message(FATAL_ERROR "VERSION not specified")
endif()
set(EXTRACT_DIR "${DEST_DIR}/doxygen-awesome-css-${VERSION}")
if(NOT EXISTS "${EXTRACT_DIR}/doxygen-awesome.css")
message(STATUS "Downloading doxygen-awesome-css ${VERSION}...")
set(TARBALL "${DEST_DIR}/doxygen-awesome-css.tar.gz")
file(DOWNLOAD
"${URL}"
"${TARBALL}"
STATUS download_status
SHOW_PROGRESS
)
list(GET download_status 0 status_code)
if(NOT status_code EQUAL 0)
list(GET download_status 1 error_msg)
message(FATAL_ERROR "Download failed: ${error_msg}")
endif()
message(STATUS "Extracting doxygen-awesome-css...")
file(ARCHIVE_EXTRACT
INPUT "${TARBALL}"
DESTINATION "${DEST_DIR}"
)
file(REMOVE "${TARBALL}")
endif()

601
doc/fido2.dox Normal file
View File

@@ -0,0 +1,601 @@
/**
@page libssh_tutor_fido2 Chapter 11: FIDO2/U2F Keys Support
@section fido2_intro Introduction
The traditional SSH public key model stores the private key on disk
and anyone who obtains that file (and possibly its passphrase) can impersonate
the user. FIDO2 authenticators, such as USB security keys, are hardware tokens
that generate or securely store private key material within a secure element
and may require explicit user interaction such as a touch, PIN, or biometric
verification for use. Hence, security keys are far safer from theft or
exfiltration than traditional file-based SSH keys. libssh provides support
for FIDO2/U2F security keys as hardware-backed SSH authentication credentials.
This chapter explains the concepts, build prerequisites, the API, and
usage patterns for enrolling (creating) and using security key-backed SSH
keys, including resident (discoverable) credentials.
@subsection fido2_resident_keys Resident Keys
Two credential storage modes exist for security keys:
- Non-resident (default): A credential ID (key handle) and metadata are
stored on the client-side in a key file. This key handle must be
presented to the FIDO2/U2F device while signing. This is somewhat
similar to traditional SSH keys, except that the key handle is not the
private key itself, but used in combination with the device's master key
to derive the actual private key.
- Resident (discoverable): The credential (and metadata like user id) is
stored on the device. No local file is needed; the device can enumerate or
locate the credential internally when queried.
Advantages of resident keys include portability (using the same device
across hosts) and resilience (no loss if the local machine is destroyed).
Although, they may be limited by the storage of the authenticator.
@subsection fido2_presence_verification User Presence vs. User Verification
FIDO2 distinguishes between:
- User Presence (UP): A simple physical interaction (touch) to confirm a
human is present.
- User Verification (UV): Verification of the users identity through
biometric authentication or a PIN.
Requiring UV provides additional protection if the device is stolen
and used without the PIN/biometric.
libssh exposes flags controlling these requirements (see below).
@subsection fido2_callbacks The Callback Abstraction
Different environments may need to access security keys through different
transport layers (e.g., USB-HID, NFC, Bluetooth, etc.). To accommodate
this variability, libssh does not hard-code a single implementation.
Instead, it defines a small callback interface (`ssh_sk_callbacks`) used for all
security key operations. Any implementation of this callback interface can be used
by higher-level PKI functions to perform enroll/sign/load_resident_keys
operations without needing to know the transport specifics. Hence, users can
define their own implementations for these callbacks to support different
transport protocols or custom hardware. Refer @ref fido2_custom_callbacks
for additional details.
The callback interface is defined in `libssh/callbacks.h` and the behaviour
and return values are specified by `libssh/sk_api.h`, which is the same
interface defined by OpenSSH for its security key support. This means that
any callback implementations (also called "middleware" in OpenSSH terminology)
developed for OpenSSH can be adapted to libssh with minimal changes.
The following operations are abstracted by the callback interface:
- api_version(): Report the version of the SK API that the callback implementation
is based on, so that libssh can check whether this implementation would be
compatible with the SK API version that it supports.
Refer @ref fido2_custom_callbacks_version for additional details.
- enroll(): Create (enroll) a new credential, returning public key, key
handle, attestation data.
- sign(): Produce a signature for supplied inputs using an existing key
handle.
- load_resident_keys(): Enumerate resident (discoverable) credentials stored
on the authenticator.
libssh provides a default implementation of the `ssh_sk_callbacks` using
the libfido2 library for the USB-HID transport protocol. Hence, by default,
libssh can interact with any FIDO2/U2F device that supports USB-HID and is
compatible with libfido2, without requiring any additional modifications.
@subsection fido2_build Building with FIDO2 Support
To enable FIDO2/U2F support, libssh must be built with the WITH_FIDO2
build option as follows:
@verbatim
cmake -DWITH_FIDO2=ON <other options> ..
@endverbatim
libssh will also build the default USB-HID `ssh_sk_callbacks`, if the
libfido2 library and headers are installed on your system.
@warning If built without libfido2, support for interacting with FIDO2/U2F
devices over USB-HID will not be available.
@subsection fido2_api_overview API Overview
Security key operations are configured through the `ssh_pki_ctx`
which allows to specify both general PKI options and FIDO2-specific
options such as the sk_callbacks, challenge data, application string, flags, etc.
The following sections describe the options that can be configured and how
the `ssh_pki_ctx` is used in conjunction with `ssh_key` to perform
enrollment, signing, and resident key loading operations.
@subsection fido2_key_objects Security Key Objects & Metadata
Security keys are surfaced as `ssh_key` objects of type
`SSH_KEYTYPE_SK_ECDSA` and `SSH_KEYTYPE_SK_ED25519` (corresponding to the
OpenSSH public key algorithm names `sk-ecdsa-sha2-nistp256@openssh.com` and
`sk-ssh-ed25519@openssh.com`). In addition to standard key handling, libssh
exposes the following helper functions to retrieve embedded SK metadata:
- ssh_key_get_sk_application(): Returns the relying party / application
(RP ID) string. The Relying Party ID (RP ID) is a string
that identifies the application or service requesting key enrollment. It
ensures that a credential is bound to a specific origin, preventing
phishing across sites. During registration, the authenticator associates
the credential with this RP ID so that it can later only be used for
authentication requests from the same relying party. For SSH keys, the
common format is "ssh:user@host".
- ssh_key_get_sk_user_id(): Returns a copy of the user ID associated with a key
which represents a unique identifier for the user within the relying
party (application) context. It is typically a string (such as an
email, or a random identifier) that helps distinguish credentials
belonging to different users for the same application.
Though the user ID can be binary data according to the FIDO2 spec, libssh only
supports NUL-terminated strings for enrolling new keys in order to remain compatible
with the OpenSSH's sk-api interface.
However, libssh does support loading existing resident keys with user IDs containing
arbitrary binary data. It does so by using an `ssh_string` to store the loaded key's
user_id, and an `ssh_string` can contain arbitrary binary data that can not be stored
in a traditional NUL-terminated string (like null bytes).
@note The user_id is NOT stored in the key file for non-resident keys. It is only
available for resident (discoverable) keys loaded from the authenticator via
ssh_sk_resident_keys_load(). For keys imported from files, this function returns
NULL.
- ssh_key_get_sk_flags(): Returns the flags associated with the key. The
following are the supported flags and they can be combined using
bitwise OR:
- SSH_SK_USER_PRESENCE_REQD : Require user presence (touch).
- SSH_SK_USER_VERIFICATION_REQD : Require user verification
(PIN/biometric).
- SSH_SK_RESIDENT_KEY : Request a resident discoverable credential.
- SSH_SK_FORCE_OPERATION : Force resident (discoverable) credential
creation even if one with same application and user_id already
exists.
These functions perform no additional communication with the
authenticator, this metadata is captured during enrollment/loading and
cached in the `ssh_key`.
@subsection fido2_options Setting Security Key Context Options
Options are set via ssh_pki_ctx_options_set().
Representative security key options:
- SSH_PKI_OPTION_SK_APPLICATION (const char *): Required relying party ID
If not set, a default value of "ssh:" is used.
- SSH_PKI_OPTION_SK_FLAGS (uint8_t *): Flags described above. If not set,
defaults to SSH_SK_USER_PRESENCE_REQD. This is because OpenSSH `sshd`
requires user presence for security key authentication by default.
- SSH_PKI_OPTION_SK_USER_ID (const char *): Represents a unique identifier
for the user within the relying party (application) context.
It is typically a string (such as an email, or a random identifier) that
helps distinguish credentials belonging to different users for the same
application. If not set, defaults to 64 zeros.
- SSH_PKI_OPTION_SK_CHALLENGE (ssh_buffer): Custom challenge; if omitted a
random 32-byte challenge is generated.
- SSH_PKI_OPTION_SK_CALLBACKS (ssh_sk_callbacks): Replace the default
callbacks with custom callbacks.
PIN callback: Use ssh_pki_ctx_set_sk_pin_callback() to register a function
matching `ssh_auth_callback` to prompt for and supply a PIN. The callback may
be called multiple times to ask for the pin depending on the authenticator policy.
Callback options: Callback implementations may accept additional configuration
name/value options such as the path to the fido device. These options can be provided via
`ssh_pki_ctx_sk_callbacks_option_set()`. Refer @ref fido2_custom_callbacks_options
for additional details.
The built-in callback implementation provided by libssh supports additional options,
with their names defined in `libssh.h` prefixed with `SSH_SK_OPTION_NAME_*`, such as:
SSH_SK_OPTION_NAME_DEVICE_PATH: Used for specifying a device path.
If the device path is not specified and multiple devices are connected, then
depending upon the operation and the flags set, the callback implementation may
automatically select a suitable device, or the user may be prompted to touch the
device they want to use.
SSH_SK_OPTION_NAME_USER_ID: Used for setting the user ID.
Note that the user ID can also be set using the ssh_pki_ctx_options_set() API.
@subsection fido2_enrollment Enrollment Example
An enrollment operation creates a new credential on the authenticator and
returns an ssh_key object representing it. The application and user_id
fields are required for creating the credential. The other options are
optional. A successful enrollment returns the public key, key handle, and
metadata which are stored in the ssh_key object, and may optionally return
attestation data which is used for verifying the authenticator model and
firmware version.
Below is a simple example enrolling an Ed25519 security key (non-resident)
requiring user presence only:
@code
#include <libssh/libssh.h>
#include <string.h>
static int pin_cb(const char *prompt,
char *buf,
size_t len,
int echo,
int verify,
void *userdata)
{
(void)prompt;
(void)echo;
(void)verify;
(void)userdata;
/* In a real application, the user would be prompted to enter the PIN */
const char *pin = "4242";
size_t l = strlen(pin);
if (l + 1 > len) {
return SSH_ERROR;
}
memcpy(buf, pin, l + 1);
return SSH_OK;
}
int enroll_sk_key()
{
const char *app = "ssh:user@host";
const char *user_id = "alice";
uint8_t flags = SSH_SK_USER_PRESENCE_REQD | SSH_SK_USER_VERIFICATION_REQD;
const char *device_path = "/dev/hidraw6"; /* Optional device path */
ssh_pki_ctx pki_ctx = ssh_pki_ctx_new();
ssh_pki_ctx_options_set(pki_ctx, SSH_PKI_OPTION_SK_APPLICATION, app);
ssh_pki_ctx_options_set(pki_ctx, SSH_PKI_OPTION_SK_USER_ID, user_id);
ssh_pki_ctx_options_set(pki_ctx, SSH_PKI_OPTION_SK_FLAGS, &flags);
ssh_pki_ctx_set_sk_pin_callback(pki_ctx, pin_cb, NULL);
ssh_pki_ctx_sk_callbacks_option_set(pki_ctx,
SSH_SK_OPTION_NAME_DEVICE_PATH,
device_path,
true);
ssh_key enrolled = NULL;
int rc = ssh_pki_generate_key(SSH_KEYTYPE_SK_ED25519,
pki_ctx,
&enrolled); /* produces sk-ed25519 key */
/* Save enrolled key using ssh_pki_export_privkey_file, retrieve attestation
* buffer etc. */
/* Free context and key when done */
}
@endcode
After a successful enrollment, you can retrieve the attestation buffer
(if provided by the authenticator) from the PKI context:
@code
ssh_buffer att_buf = NULL;
rc = ssh_pki_ctx_get_sk_attestation_buffer(pki_ctx, &att_buf);
if (rc == SSH_OK && att_buf != NULL) {
/* att_buf now contains the serialized attestation
* ("ssh-sk-attest-v01"). You can inspect, save, or
* parse the buffer as needed
*/
ssh_buffer_free(att_buf);
}
@endcode
Notes:
- The attestation buffer is only populated if the enrollment operation
succeeds and the authenticator provides attestation data.
- `ssh_pki_ctx_get_sk_attestation_buffer()` returns a copy of the attestation
buffer; the caller must free it with `ssh_buffer_free()`.
@subsection fido2_signing Authenticating with a Stored Security Key Public Key
To authenticate using a security key, the application typically loads the
previously enrolled sk-* private key, establishes an SSH connection, and
calls `ssh_userauth_publickey()`. libssh automatically recognizes security
key types and transparently handles the required hardware-backed
authentication steps such as prompting for a touch or PIN using the
configured security key callbacks.
Example:
@code
#include <libssh/libssh.h>
#include <stdio.h>
int auth_with_sk_file(const char *host,
const char *user,
const char *privkey_path)
{
ssh_session session = NULL;
ssh_key privkey = NULL;
int rc = SSH_ERROR;
session = ssh_new();
ssh_options_set(session, SSH_OPTIONS_HOST, host);
ssh_options_set(session, SSH_OPTIONS_USER, user);
ssh_connect(session);
ssh_pki_import_privkey_file(privkey_path, NULL, NULL, NULL, &privkey);
ssh_pki_ctx pki_ctx = ssh_pki_ctx_new();
/* Optionally set PIN callback, device path, etc. */
/* ssh_pki_ctx_set_sk_pin_callback(pki_ctx, pin_cb, NULL); */
ssh_options_set(session, SSH_OPTIONS_PKI_CONTEXT, pki_ctx);
rc = ssh_userauth_publickey(session, user, privkey);
if (rc == SSH_AUTH_SUCCESS) {
printf("Authenticated with security key.\n");
rc = SSH_OK;
} else {
fprintf(stderr,
"Authentication failed rc=%d err=%s\n",
rc,
ssh_get_error(session));
rc = SSH_ERROR;
}
/* Free resources */
}
@endcode
@subsection fido2_resident Resident Key Enumeration
Resident keys stored on the device can be discovered and loaded with
ssh_sk_resident_keys_load() which takes a PKI context (configured with
a PIN callback) and returns each key as an ssh_key and the number of keys loaded.
Example:
@code
#include <libssh/libssh.h>
#include <stdio.h>
#include <string.h>
static int pin_cb(const char *prompt,
char *buf,
size_t len,
int echo,
int verify,
void *userdata)
{
(void)prompt;
(void)echo;
(void)verify;
(void)userdata;
const char *pin = "4242";
size_t l = strlen(pin);
if (l + 1 > len) {
return SSH_ERROR;
}
memcpy(buf, pin, l + 1);
return SSH_OK;
}
int auth_with_resident(const char *host,
const char *user,
const char *application,
const char *user_id)
{
ssh_pki_ctx pki_ctx = NULL;
size_t num_found = 0;
ssh_key *keys = NULL;
ssh_key final_key = NULL;
int rc = SSH_ERROR;
ssh_string cur_application = NULL;
ssh_string cur_user_id = NULL;
ssh_string expected_application = NULL;
ssh_string expected_user_id = NULL;
pki_ctx = ssh_pki_ctx_new();
ssh_pki_ctx_set_sk_pin_callback(pki_ctx, pin_cb, NULL);
expected_application = ssh_string_from_char(application);
expected_user_id = ssh_string_from_char(user_id);
rc = ssh_sk_resident_keys_load(pki_ctx, &keys, &num_found);
for (size_t i = 0; i < num_found; i++) {
cur_application = ssh_key_get_sk_application(keys[i]);
cur_user_id = ssh_key_get_sk_user_id(keys[i]);
if (ssh_string_cmp(cur_application, expected_application) == 0 &&
ssh_string_cmp(cur_user_id, expected_user_id) == 0) {
SSH_STRING_FREE(cur_application);
SSH_STRING_FREE(cur_user_id);
final_key = keys[i];
break;
}
SSH_STRING_FREE(cur_application);
SSH_STRING_FREE(cur_user_id);
}
SSH_STRING_FREE(expected_application);
SSH_STRING_FREE(expected_user_id);
/* Continue with authentication using the ssh_key with
* ssh_userauth_publickey as usual, and free resources when done. */
}
@endcode
@subsection fido2_sshsig Signing using the sshsig API
Security keys can also be used for general-purpose signing of arbitrary data
(without SSH authentication) using the existing `sshsig_sign()` and `sshsig_verify()`
functions. These functions work seamlessly with security key types
(`SSH_KEYTYPE_SK_ECDSA` and `SSH_KEYTYPE_SK_ED25519`) and will automatically
invoke the configured security key callbacks to perform hardware-backed signing
operations.
@subsection fido2_custom_callbacks Implementing Custom Callback Implementations
Users may need to implement custom callback implementations to support
different transport protocols (e.g., NFC, Bluetooth) beyond the default USB-HID
support. This section describes how to implement and integrate custom callback
implementations.
To implement custom callbacks, you must include the following headers:
@code
#include <libssh/callbacks.h> /* For ssh_sk_callbacks_struct */
#include <libssh/sk_api.h> /* For SK API constants and data structures */
@endcode
The `libssh/sk_api.h` header provides the complete interface specification including
request/response structures, flags, and version macros.
@subsubsection fido2_custom_callbacks_version API Version Compatibility
libssh validates callback implementations by checking the API version returned by
the `api_version()` callback. To ensure compatibility, libssh compares the major
version (upper 16 bits) of the returned value with `LIBSSH_SK_API_VERSION_MAJOR`.
If they don't match, libssh will reject the callback implementation.
This ensures that the callbacks' SK API matches the major version expected by libssh,
while allowing minor version differences.
@subsubsection fido2_custom_callbacks_implementation Implementation Example
Here's a minimal example of defining and using custom callbacks:
@code
#include <libssh/libssh.h>
#include <libssh/callbacks.h>
#include <libssh/sk_api.h>
/* Your custom API version callback */
static uint32_t my_sk_api_version(void)
{
/* Match the major version, set your own minor version */
return SSH_SK_VERSION_MAJOR | 0x0001;
}
/* Your custom enroll callback */
static int my_sk_enroll(uint32_t alg,
const uint8_t *challenge,
size_t challenge_len,
const char *application,
uint8_t flags,
const char *pin,
struct sk_option **options,
struct sk_enroll_response **enroll_response)
{
/* Parse options array to extract custom parameters */
if (options != NULL) {
for (size_t i = 0; options[i] != NULL; i++) {
if (strcmp(options[i]->name, "my_custom_option") == 0) {
/* Use options[i]->value */
}
}
}
/* Implement your enroll logic here */
/* ... */
return SSH_SK_ERR_GENERAL; /* Return appropriate error code */
}
/* Implement other required callbacks: sign, load_resident_keys */
/* ... */
/* Define your callback structure */
static struct ssh_sk_callbacks_struct my_sk_callbacks = {
.size = sizeof(struct ssh_sk_callbacks_struct),
.api_version = my_sk_api_version,
.enroll = my_sk_enroll,
.sign = my_sk_sign, /* Your implementation */
.load_resident_keys = my_sk_load_resident_keys, /* Your implementation */
};
/* Usage example */
void use_custom_callbacks(void)
{
ssh_pki_ctx pki_ctx = ssh_pki_ctx_new();
/* Set your custom callbacks */
ssh_pki_ctx_options_set(pki_ctx,
SSH_PKI_OPTION_SK_CALLBACKS,
&my_sk_callbacks);
/* Pass custom options to your callbacks */
ssh_pki_ctx_sk_callbacks_option_set(pki_ctx,
"my_custom_option",
"my_custom_value",
false);
/* Use the context for enrollment, signing, etc. */
}
@endcode
@subsubsection fido2_custom_callbacks_options Passing Custom Options
The `ssh_pki_ctx_sk_callbacks_option_set()` function allows you to pass
implementation-specific options as name/value string pairs:
@code
ssh_pki_ctx_sk_callbacks_option_set(pki_ctx,
"option_name",
"option_value",
required);
@endcode
Parameters:
- `option_name`: The name of the option (e.g., "device_path", "my_custom_param")
- `option_value`: The string value for this option
- `required`: If true, this option must be processed by the callback implementation
and cannot be ignored. If false, the option is advisory and can be skipped if the
callback implementation does not support it.
These options are passed to your callbacks in the `struct sk_option **options`
parameter as a NULL-terminated array. Each `sk_option` has the following fields:
- `name`: The option name (char *)
- `value`: The option value (char *)
- `required`: Whether the option must be processed (uint8_t, non-zero = required)
@subsubsection fido2_custom_callbacks_openssh OpenSSH Middleware Compatibility
Since libssh uses the same SK API as OpenSSH, middleware implementations developed
for OpenSSH can be adapted with minimal changes.
To adapt an OpenSSH middleware for libssh, create a wrapper that populates
`ssh_sk_callbacks_struct` with pointers to the middleware's functions.
@subsection fido2_testing Testing and Environment Variables
Unit tests covering USB-HID enroll/sign/load_resident_keys operations can be found
in the `tests/unittests/torture_sk_usbhid.c` file. To run these tests you
must have libfido2 installed and the WITH_FIDO2=ON build option set.
Additionally, you must ensure the following:
- An actual FIDO2 device must be connected to the test machine.
- The TORTURE_SK_USBHID environment variable must be set.
- The environment variable TORTURE_SK_PIN=<device PIN> must be set.
If these are not set, the tests are skipped.
The higher level PKI integration tests can be found in
`tests/unittests/torture_pki_sk.c` and the tests related to the sshsig API
can be found in `tests/unittests/torture_pki_sshsig.c`.
These use the callback implementation provided by OpenSSH's sk-dummy.so,
which simulates an authenticator without requiring any hardware. Hence, these tests
can be run in the CI environment.
However, these tests can also be configured to use the default USB-HID callbacks
by setting the same environment variables as described above.
The following devices were tested during development:
- Yubico Security Key NFC - USB-A
*/

View File

@@ -100,7 +100,7 @@ used to retrieve google's home page from the remote SSH server.
@code @code
int direct_forwarding(ssh_session session) int direct_forwarding(ssh_session session)
{ {
ssh_channel forwarding_channel; ssh_channel forwarding_channel = NULL;
int rc = SSH_ERROR; int rc = SSH_ERROR;
char *http_get = "GET / HTTP/1.1\nHost: www.google.com\n\n"; char *http_get = "GET / HTTP/1.1\nHost: www.google.com\n\n";
int nbytes, nwritten; int nbytes, nwritten;
@@ -161,7 +161,7 @@ local libssh application, which handles them:
int web_server(ssh_session session) int web_server(ssh_session session)
{ {
int rc; int rc;
ssh_channel channel; ssh_channel channel = NULL;
char buffer[256]; char buffer[256];
int nbytes, nwritten; int nbytes, nwritten;
int port = 0; int port = 0;

View File

@@ -79,7 +79,7 @@ Here is a small example of how to use it:
int main() int main()
{ {
ssh_session my_ssh_session; ssh_session my_ssh_session = NULL;
int verbosity = SSH_LOG_PROTOCOL; int verbosity = SSH_LOG_PROTOCOL;
int port = 22; int port = 22;
@@ -126,7 +126,7 @@ Here's an example:
int main() int main()
{ {
ssh_session my_ssh_session; ssh_session my_ssh_session = NULL;
int rc; int rc;
my_ssh_session = ssh_new(); my_ssh_session = ssh_new();
@@ -190,8 +190,8 @@ int verify_knownhost(ssh_session session)
ssh_key srv_pubkey = NULL; ssh_key srv_pubkey = NULL;
size_t hlen; size_t hlen;
char buf[10]; char buf[10];
char *hexa; char *hexa = NULL;
char *p; char *p = NULL;
int cmp; int cmp;
int rc; int rc;
@@ -317,9 +317,9 @@ The example below shows an authentication with password:
int main() int main()
{ {
ssh_session my_ssh_session; ssh_session my_ssh_session = NULL;
int rc; int rc;
char *password; char *password = NULL;
// Open session and set options // Open session and set options
my_ssh_session = ssh_new(); my_ssh_session = ssh_new();
@@ -380,7 +380,7 @@ The example below shows how to execute a remote command:
@code @code
int show_remote_processes(ssh_session session) int show_remote_processes(ssh_session session)
{ {
ssh_channel channel; ssh_channel channel = NULL;
int rc; int rc;
char buffer[256]; char buffer[256];
int nbytes; int nbytes;

92
doc/header.html Normal file
View File

@@ -0,0 +1,92 @@
<!-- HTML header for doxygen 1.14.0-->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="$langISO">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=11"/>
<meta name="generator" content="Doxygen $doxygenversion"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<!--BEGIN PROJECT_NAME--><title>$projectname: $title</title><!--END PROJECT_NAME-->
<!--BEGIN !PROJECT_NAME--><title>$title</title><!--END !PROJECT_NAME-->
<!--BEGIN PROJECT_ICON-->
<link rel="icon" href="$relpath^$projecticon" type="image/x-icon" />
<!--END PROJECT_ICON-->
<link href="$relpath^tabs.css" rel="stylesheet" type="text/css"/>
<!--BEGIN FULL_SIDEBAR-->
<script type="text/javascript">var page_layout=1;</script>
<!--END FULL_SIDEBAR-->
<script type="text/javascript" src="$relpath^jquery.js"></script>
<script type="text/javascript" src="$relpath^dynsections.js"></script>
<!--BEGIN COPY_CLIPBOARD-->
<script type="text/javascript" src="$relpath^clipboard.js"></script>
<!--END COPY_CLIPBOARD-->
$treeview
$search
$mathjax
$darkmode
<link href="$relpath^$stylesheet" rel="stylesheet" type="text/css" />
$extrastylesheet
<script type="text/javascript" src="$relpath^doxygen-awesome-darkmode-toggle.js"></script>
<script type="text/javascript">
DoxygenAwesomeDarkModeToggle.init()
</script>
<script type="text/javascript" src="$relpath^doxygen-awesome-fragment-copy-button.js"></script>
<script type="text/javascript">
DoxygenAwesomeFragmentCopyButton.init()
</script>
<script type="text/javascript" src="$relpath^doxygen-awesome-paragraph-link.js"></script>
<script type="text/javascript">
DoxygenAwesomeParagraphLink.init()
</script>
<script type="text/javascript" src="$relpath^doxygen-awesome-interactive-toc.js"></script>
<script type="text/javascript">
DoxygenAwesomeInteractiveToc.init()
</script>
</head>
<body>
<!--BEGIN FULL_SIDEBAR-->
<div id="side-nav" class="ui-resizable side-nav-resizable"><!-- do not remove this div, it is closed by doxygen! -->
<!--END FULL_SIDEBAR-->
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<!--BEGIN TITLEAREA-->
<div id="titlearea">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr id="projectrow">
<!--BEGIN PROJECT_LOGO-->
<td id="projectlogo"><img alt="Logo" src="$relpath^$projectlogo"$logosize/></td>
<!--END PROJECT_LOGO-->
<!--BEGIN PROJECT_NAME-->
<td id="projectalign">
<div id="projectname">$projectname<!--BEGIN PROJECT_NUMBER--><span id="projectnumber">&#160;$projectnumber</span><!--END PROJECT_NUMBER-->
</div>
<!--BEGIN PROJECT_BRIEF--><div id="projectbrief">$projectbrief</div><!--END PROJECT_BRIEF-->
</td>
<!--END PROJECT_NAME-->
<!--BEGIN !PROJECT_NAME-->
<!--BEGIN PROJECT_BRIEF-->
<td>
<div id="projectbrief">$projectbrief</div>
</td>
<!--END PROJECT_BRIEF-->
<!--END !PROJECT_NAME-->
<!--BEGIN DISABLE_INDEX-->
<!--BEGIN SEARCHENGINE-->
<!--BEGIN !FULL_SIDEBAR-->
<td>$searchbox</td>
<!--END !FULL_SIDEBAR-->
<!--END SEARCHENGINE-->
<!--END DISABLE_INDEX-->
</tr>
<!--BEGIN SEARCHENGINE-->
<!--BEGIN FULL_SIDEBAR-->
<tr><td colspan="2">$searchbox</td></tr>
<!--END FULL_SIDEBAR-->
<!--END SEARCHENGINE-->
</tbody>
</table>
</div>
<!--END TITLEAREA-->
<!-- end header part -->

View File

@@ -48,6 +48,8 @@ Table of contents:
@subpage libssh_tutor_sftp_aio @subpage libssh_tutor_sftp_aio
@subpage libssh_tutor_fido2
@subpage libssh_tutor_todo @subpage libssh_tutor_todo
*/ */

View File

@@ -19,12 +19,13 @@ the interesting functions as you go.
The libssh library provides: The libssh library provides:
- <strong>Key Exchange Methods</strong>: <i>curve25519-sha256, curve25519-sha256@libssh.org, ecdh-sha2-nistp256, ecdh-sha2-nistp384, ecdh-sha2-nistp521</i>, diffie-hellman-group1-sha1, diffie-hellman-group14-sha1 - <strong>Key Exchange Methods</strong>: <i>sntrup761x25519-sha512, sntrup761x25519-sha512@openssh.com, mlkem768x25519-sha256, mlkem768nistp256-sha256, mlkem1024nistp384-sha384, curve25519-sha256, curve25519-sha256@libssh.org, ecdh-sha2-nistp256, ecdh-sha2-nistp384, ecdh-sha2-nistp521</i>, diffie-hellman-group1-sha1, diffie-hellman-group14-sha1
- <strong>GSSAPI Key Exchange Methods</strong>: gss-group14-sha256-*, gss-group16-sha512-*, gss-nistp256-sha256-*, gss-curve25519-sha256-*
- <strong>Public Key Algorithms</strong>: ssh-ed25519, ecdsa-sha2-nistp256, ecdsa-sha2-nistp384, ecdsa-sha2-nistp521, ssh-rsa, rsa-sha2-512, rsa-sha2-256 - <strong>Public Key Algorithms</strong>: ssh-ed25519, ecdsa-sha2-nistp256, ecdsa-sha2-nistp384, ecdsa-sha2-nistp521, ssh-rsa, rsa-sha2-512, rsa-sha2-256
- <strong>Ciphers</strong>: <i>aes256-ctr, aes192-ctr, aes128-ctr</i>, aes256-cbc (rijndael-cbc@lysator.liu.se), aes192-cbc, aes128-cbc, 3des-cbc, blowfish-cbc - <strong>Ciphers</strong>: <i>aes256-ctr, aes192-ctr, aes128-ctr</i>, aes256-cbc (rijndael-cbc@lysator.liu.se), aes192-cbc, aes128-cbc, 3des-cbc, blowfish-cbc
- <strong>Compression Schemes</strong>: zlib, <i>zlib@openssh.com</i>, none - <strong>Compression Schemes</strong>: zlib, <i>zlib@openssh.com</i>, none
- <strong>MAC hashes</strong>: hmac-sha1, hmac-sha2-256, hmac-sha2-512, hmac-md5 - <strong>MAC hashes</strong>: hmac-sha1, hmac-sha2-256, hmac-sha2-512, hmac-md5
- <strong>Authentication</strong>: none, password, public-key, keyboard-interactive, <i>gssapi-with-mic</i> - <strong>Authentication</strong>: none, password, public-key, keyboard-interactive, <i>gssapi-with-mic, gssapi-keyex</i>
- <strong>Channels</strong>: shell, exec (incl. SCP wrapper), direct-tcpip, subsystem, <i>auth-agent-req@openssh.com</i> - <strong>Channels</strong>: shell, exec (incl. SCP wrapper), direct-tcpip, subsystem, <i>auth-agent-req@openssh.com</i>
- <strong>Global Requests</strong>: tcpip-forward, forwarded-tcpip - <strong>Global Requests</strong>: tcpip-forward, forwarded-tcpip
- <strong>Channel Requests</strong>: x11, pty, <i>exit-status, signal, exit-signal, keepalive@openssh.com, auth-agent-req@openssh.com</i> - <strong>Channel Requests</strong>: x11, pty, <i>exit-status, signal, exit-signal, keepalive@openssh.com, auth-agent-req@openssh.com</i>

View File

@@ -81,10 +81,6 @@ We recommend the users to provide a specific PKCS #11 URI so that it matches onl
If the engine discovers multiple slots that could potentially contain the private keys referenced If the engine discovers multiple slots that could potentially contain the private keys referenced
by the provided PKCS #11 URI, the engine will not try to authenticate. by the provided PKCS #11 URI, the engine will not try to authenticate.
For testing, the SoftHSM PKCS#11 library is used. But it has some issues with For testing, the SoftHSM PKCS#11 library is used.
OpenSSL initialization/cleanup when used with OpenSSL 3.0 so we are using it
indirectly through a p11-kit remoting as described in the following article:
https://p11-glue.github.io/p11-glue/p11-kit/manual/remoting.html
*/ */

View File

@@ -26,7 +26,7 @@ The code sample below achieves these tasks:
@code @code
int shell_session(ssh_session session) int shell_session(ssh_session session)
{ {
ssh_channel channel; ssh_channel channel = NULL;
int rc; int rc;
channel = ssh_channel_new(session); channel = ssh_channel_new(session);

View File

@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2017 Jan-Lukas Wynen
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,22 +0,0 @@
# that style
A plain, more modern HTML style for Doxygen
## Requirements
- Doxygen (tested with version 1.8.13)
- *optional*: a sass/scss compiler if you want to modify the style
## Simple usage
Tell Doxygen about the files for that style as shown in [doxyfile.conf](doxyfile.conf). You might need to adjust the
paths depending on where you installed that style.
When you run Doxygen, all files are copied into to generated HTML folder. So you don't need to keep the originals around
unless you want to re-generate the documentation.
## Advanced
that style uses a custom javascript to hack some nice stripes into some tables. It has to be loaded from HTML. Hence you need
to use the provided custom header. Since its default content may change when Doxygen is updated, there might be syntax error in
the generated HTML. If this is the case, you can remove the custom header (adjust your doxyfile.conf). This has no
disadvantages other than removing the stripes.
[that_style.css](that_style.css) was generated from the scss files in the folder [sass](sass). If you want to change the style,
use those files in order to have better control. For instance, you can easily change most colors by modifying the variables
in the beginning of [that_style.scss](sass/that_style.scss).

View File

@@ -1,56 +0,0 @@
<!-- HTML header for doxygen 1.8.13-->
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<meta name="generator" content="Doxygen $doxygenversion"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<!--BEGIN PROJECT_NAME--><title>$projectname: $title</title><!--END PROJECT_NAME-->
<!--BEGIN !PROJECT_NAME--><title>$title</title><!--END !PROJECT_NAME-->
<link href="$relpath^tabs.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="$relpath^jquery.js"></script>
<script type="text/javascript" src="$relpath^dynsections.js"></script>
$treeview
$search
$mathjax
<link href="$relpath^$stylesheet" rel="stylesheet" type="text/css" />
<script src="$relpath^striped_bg.js"></script>
$extrastylesheet
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<!--BEGIN TITLEAREA-->
<div id="titlearea">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr style="height: 56px;">
<!--BEGIN PROJECT_LOGO-->
<td id="projectlogo"><img alt="Logo" src="$relpath^$projectlogo"/></td>
<!--END PROJECT_LOGO-->
<!--BEGIN PROJECT_NAME-->
<td id="projectalign" style="padding-left: 0.5em;">
<div id="projectname">$projectname
<!--BEGIN PROJECT_NUMBER-->&#160;<span id="projectnumber">$projectnumber</span><!--END PROJECT_NUMBER-->
</div>
<!--BEGIN PROJECT_BRIEF--><div id="projectbrief">$projectbrief</div><!--END PROJECT_BRIEF-->
</td>
<!--END PROJECT_NAME-->
<!--BEGIN !PROJECT_NAME-->
<!--BEGIN PROJECT_BRIEF-->
<td style="padding-left: 0.5em;">
<div id="projectbrief">$projectbrief</div>
</td>
<!--END PROJECT_BRIEF-->
<!--END !PROJECT_NAME-->
<!--BEGIN DISABLE_INDEX-->
<!--BEGIN SEARCHENGINE-->
<td>$searchbox</td>
<!--END SEARCHENGINE-->
<!--END DISABLE_INDEX-->
</tr>
</tbody>
</table>
</div>
<!--END TITLEAREA-->
<!-- end header part -->

View File

@@ -1,97 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="24"
height="22"
viewBox="0 0 6.3499999 5.8208335"
version="1.1"
id="svg8"
sodipodi:docname="doc.svg"
inkscape:version="0.92.1 r">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="32"
inkscape:cx="11.139212"
inkscape:cy="14.811193"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:showpageshadow="false"
units="px"
inkscape:window-width="2560"
inkscape:window-height="1357"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-291.17915)">
<path
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#4d4d4d;stroke-width:0.26458329;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="M 3.315043,291.8406 H 1.4552083 v 4.49792 h 3.1749999 v -3.10055 z"
id="path5095"
inkscape:connector-curvature="0" />
<path
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#4d4d4d;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 3.1837239,291.84114 v 1.71186 h 1.4472656 v -0.31418 H 3.4473958 v -1.39768 z"
id="path5128"
inkscape:connector-curvature="0" />
<rect
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#4d4d4d;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.52916664;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
id="rect5132"
width="2.1166668"
height="0.26458332"
x="1.8520833"
y="293.82498" />
<rect
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#4d4d4d;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.52916664;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
id="rect5136"
width="1.0583334"
height="0.26458332"
x="1.8520832"
y="294.35416" />
<rect
y="294.88333"
x="1.8520832"
height="0.26458332"
width="1.8520833"
id="rect5138"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#4d4d4d;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.52916664;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<rect
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#4d4d4d;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.52916664;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
id="rect4543"
width="1.5875"
height="0.26458332"
x="1.8520832"
y="295.41248" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 6.5 KiB

View File

@@ -1,77 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="24"
height="22"
viewBox="0 0 6.3499998 5.8208335"
version="1.1"
id="svg8"
inkscape:version="0.92.1 r"
sodipodi:docname="folderclosed.svg"
inkscape:export-filename="/home/jl/Prog/doxygen_style/folderclosed.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="51.113139"
inkscape:cx="7.7057751"
inkscape:cy="12.584171"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:snap-global="false"
units="px"
inkscape:showpageshadow="false"
inkscape:window-width="2560"
inkscape:window-height="1357"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:measure-start="0,0"
inkscape:measure-end="0,0" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-291.17915)">
<path
inkscape:connector-curvature="0"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#4d4d4d;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:stroke fill markers;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 0.52916667,292.2374 -0.26458334,0.52925 v 3.43958 H 4.7625001 v -3.43958 H 2.38125 L 2.1166667,292.2374 Z"
id="rect4498"
sodipodi:nodetypes="cccccccc" />
<path
inkscape:connector-curvature="0"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#cccccc;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.66145831;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="M 2.9104167,292.76665 2.38125,293.56034 H 0.26458333 v 0.26464 H 2.38125 l 0.5291667,-0.79375 h 1.8520834 v -0.26458 z"
id="rect4500"
sodipodi:nodetypes="ccccccccc" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.4 KiB

View File

@@ -1,83 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="24"
height="22"
viewBox="0 0 6.3499998 5.8208335"
version="1.1"
id="svg8"
inkscape:version="0.92.1 r"
sodipodi:docname="folderopen.svg"
inkscape:export-filename="/home/jl/Prog/doxygen_style/folderopen.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="43.725861"
inkscape:cx="8.2043861"
inkscape:cy="13.464183"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:snap-global="false"
units="px"
inkscape:showpageshadow="false"
inkscape:window-width="2560"
inkscape:window-height="1357"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:measure-start="0,0"
inkscape:measure-end="0,0" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-291.17915)">
<path
inkscape:connector-curvature="0"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#4d4d4d;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.66145831;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 0.52916667,292.23748 -0.26458334,0.52917 v 3.43958 H 4.762461 l 7.8e-5,-3.43958 H 2.38125 l -0.2645833,-0.52917 z"
id="path5228"
sodipodi:nodetypes="cccccccc" />
<path
inkscape:connector-curvature="0"
id="path5279"
d="M 1.0583333,293.5604 H 5.55625 L 4.7625,296.20603 H 0.26458333 Z"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ececec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.66145831;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
sodipodi:nodetypes="ccccc" />
<path
sodipodi:nodetypes="ccccccc"
inkscape:connector-curvature="0"
id="path5234"
d="M 1.0583333,294.35415 H 3.175 l 0.5291667,-0.52917 H 5.55625 L 4.7625,296.20603 H 0.26458333 Z"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#4d4d4d;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.66145831;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.1 KiB

View File

@@ -1,73 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="22"
height="22"
viewBox="0 0 5.8208332 5.8208335"
version="1.1"
id="svg8"
inkscape:version="0.92.1 r"
sodipodi:docname="mag_glass.svg">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="32"
inkscape:cx="8.961936"
inkscape:cy="10.205344"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:showpageshadow="false"
inkscape:snap-bbox="false"
inkscape:bbox-nodes="true"
inkscape:window-width="2560"
inkscape:window-height="1357"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:snap-global="false" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-291.17915)">
<path
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#333333;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.99999988;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="M 6.9101562 2.4082031 C 3.1105656 2.4082031 -5.9211895e-16 5.5081643 0 9.3027344 C 0 13.097342 3.1105656 16.197266 6.9101562 16.197266 C 8.2869348 16.197266 9.5698699 15.787508 10.650391 15.087891 L 15.162109 19.587891 L 16.636719 18.115234 L 12.214844 13.707031 C 13.214837 12.510659 13.818359 10.974238 13.818359 9.3027344 C 13.818359 5.5081643 10.709747 2.4082031 6.9101562 2.4082031 z M 6.9101562 4.9101562 C 9.3624717 4.9101562 11.324219 6.8631249 11.324219 9.3027344 C 11.324219 11.742382 9.3624717 13.695312 6.9101562 13.695312 C 4.4578408 13.695312 2.5019531 11.742382 2.5019531 9.3027344 C 2.5019531 6.8631249 4.4578408 4.9101562 6.9101562 4.9101562 z "
transform="matrix(0.26458333,0,0,0.26458333,0,291.17915)"
id="rect4524" />
<path
transform="matrix(0.99422295,0,0,0.68955299,-0.83134947,91.755588)"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#333333;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.63466448;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
inkscape:transform-center-y="0.25905895"
d="m 5.6074138,294.49889 -1.0836583,-1.87695 2.1673165,0 z"
id="path4491" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.8 KiB

View File

@@ -1,73 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="10.53333"
height="32"
viewBox="0 0 9.8749964 30"
id="svg2"
version="1.1"
inkscape:version="0.92.1 r"
sodipodi:docname="nav_edge_inter.svg">
<defs
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="32"
inkscape:cx="8.6823304"
inkscape:cy="16.225639"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:snap-bbox="true"
inkscape:bbox-paths="false"
inkscape:bbox-nodes="true"
inkscape:snap-bbox-edge-midpoints="true"
inkscape:object-nodes="true"
inkscape:window-width="2560"
inkscape:window-height="1357"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-1022.3622)">
<path
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 0,1022.3622 v 15 15 l 8,-15 z"
id="path4143"
inkscape:connector-curvature="0" />
<path
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#333333;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.9375px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 1.2910156,1022.3496 -0.82421872,0.4473 7.87890622,14.5527 -7.87890622,14.5527 0.82421872,0.4473 8.1210938,-15 z"
id="path5240"
inkscape:connector-curvature="0" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.8 KiB

View File

@@ -1,73 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="8.5333338"
height="32"
viewBox="0 0 8.0000001 30"
id="svg2"
version="1.1"
inkscape:version="0.92.1 r"
sodipodi:docname="nav_edge_left.svg">
<defs
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="32"
inkscape:cx="5.3721385"
inkscape:cy="14.16429"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:snap-bbox="true"
inkscape:bbox-paths="false"
inkscape:bbox-nodes="false"
inkscape:snap-bbox-edge-midpoints="false"
inkscape:object-nodes="true"
inkscape:window-width="2560"
inkscape:window-height="1357"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-1022.3622)">
<path
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:6;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="M 0 0 L 0 32 L 8.5332031 16 L 0 0 z "
transform="matrix(0.93749998,0,0,0.93749998,0,1022.3622)"
id="rect4586" />
<path
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 0,1022.3622 v 15 15 l 8,-15 z"
id="path4143"
inkscape:connector-curvature="0" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.1 KiB

View File

@@ -1,73 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="8"
height="30"
viewBox="0 0 8.0000001 30"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="nav_edge.svg">
<defs
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="32"
inkscape:cx="5.3721385"
inkscape:cy="14.16429"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:snap-bbox="true"
inkscape:bbox-paths="false"
inkscape:bbox-nodes="false"
inkscape:snap-bbox-edge-midpoints="false"
inkscape:object-nodes="true"
inkscape:window-width="2560"
inkscape:window-height="1357"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-1022.3622)">
<path
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 0,1022.3622 0,15 0,15 8,-15 -8,-15 z"
id="path4143"
inkscape:connector-curvature="0" />
<path
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 1e-8,1022.3622 7.99999999,15 0,-15 -8,0 z m 7.99999999,15 -8,15 8,0 0,-15 z"
id="rect4136"
inkscape:connector-curvature="0" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.1 KiB

View File

@@ -1,120 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="6"
height="9"
viewBox="0 0 1.5875 2.3812501"
version="1.1"
id="svg8"
inkscape:version="0.92.1 r"
sodipodi:docname="splitbar_handle.svg">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="32"
inkscape:cx="8.7681488"
inkscape:cy="-2.7929517"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:showpageshadow="false"
showguides="false"
inkscape:window-width="2560"
inkscape:window-height="1357"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1">
<inkscape:grid
type="xygrid"
id="grid4487" />
</sodipodi:namedview>
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-294.61873)">
<rect
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.52916664;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
id="rect4485"
width="0.26458335"
height="0.26458332"
x="0.26458332"
y="294.8833" />
<rect
y="294.8833"
x="1.0583333"
height="0.26458332"
width="0.26458335"
id="rect4489"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.52916664;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<rect
y="295.41248"
x="0.26458329"
height="0.26458332"
width="0.26458335"
id="rect4491"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.52916664;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<rect
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.52916664;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
id="rect4493"
width="0.26458335"
height="0.26458332"
x="1.0583333"
y="295.41248" />
<rect
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.52916664;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
id="rect4495"
width="0.26458335"
height="0.26458332"
x="0.26458332"
y="295.94165" />
<rect
y="295.94165"
x="1.0583333"
height="0.26458332"
width="0.26458335"
id="rect4497"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.52916664;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<rect
y="296.47079"
x="0.26458329"
height="0.26458332"
width="0.26458335"
id="rect4499"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.52916664;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<rect
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.52916664;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
id="rect4501"
width="0.26458335"
height="0.26458332"
x="1.0583333"
y="296.47079" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 483 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 488 B

View File

@@ -1,32 +0,0 @@
// Adds extra CSS classes "even" and "odd" to .memberdecls to allow
// striped backgrounds.
function MemberDeclsStriper () {
var counter = 0;
this.stripe = function() {
$(".memberdecls tbody").children().each(function(i) {
// reset counter at every heading -> always start with even
if ($(this).is(".heading")) {
counter = 0;
}
// add extra classes
if (counter % 2 == 1) {
$(this).addClass("odd");
}
else {
$(this).addClass("even");
}
// advance counter at every separator
// this is the only way to reliably detect which table rows belong together
if ($(this).is('[class^="separator"]')) {
counter++;
}
});
}
}
// execute the function
$(document).ready(new MemberDeclsStriper().stripe);

File diff suppressed because it is too large Load Diff

View File

@@ -30,9 +30,11 @@ if (UNIX AND NOT WIN32)
target_compile_options(samplesftp PRIVATE ${DEFAULT_C_COMPILE_FLAGS}) target_compile_options(samplesftp PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
target_link_libraries(samplesftp ssh::ssh) target_link_libraries(samplesftp ssh::ssh)
add_executable(sample_sftpserver sample_sftpserver.c ${examples_SRCS}) if (WITH_SERVER)
target_compile_options(sample_sftpserver PRIVATE ${DEFAULT_C_COMPILE_FLAGS}) add_executable(sample_sftpserver sample_sftpserver.c ${examples_SRCS})
target_link_libraries(sample_sftpserver ssh::ssh ${ARGP_LIBRARIES}) target_compile_options(sample_sftpserver PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
target_link_libraries(sample_sftpserver ssh::ssh ${ARGP_LIBRARIES})
endif (WITH_SERVER)
endif (WITH_SFTP) endif (WITH_SFTP)
add_executable(ssh-client ssh_client.c ${examples_SRCS}) add_executable(ssh-client ssh_client.c ${examples_SRCS})

View File

@@ -30,8 +30,8 @@ int authenticate_kbdint(ssh_session session, const char *password)
err = ssh_userauth_kbdint(session, NULL, NULL); err = ssh_userauth_kbdint(session, NULL, NULL);
while (err == SSH_AUTH_INFO) { while (err == SSH_AUTH_INFO) {
const char *instruction; const char *instruction = NULL;
const char *name; const char *name = NULL;
char buffer[128]; char buffer[128];
int i, n; int i, n;
@@ -48,8 +48,8 @@ int authenticate_kbdint(ssh_session session, const char *password)
} }
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
const char *answer; const char *answer = NULL;
const char *prompt; const char *prompt = NULL;
char echo; char echo;
prompt = ssh_userauth_kbdint_getprompt(session, i, &echo); prompt = ssh_userauth_kbdint_getprompt(session, i, &echo);
@@ -58,7 +58,7 @@ int authenticate_kbdint(ssh_session session, const char *password)
} }
if (echo) { if (echo) {
char *p; char *p = NULL;
printf("%s", prompt); printf("%s", prompt);
@@ -66,7 +66,6 @@ int authenticate_kbdint(ssh_session session, const char *password)
return SSH_AUTH_ERROR; return SSH_AUTH_ERROR;
} }
buffer[sizeof(buffer) - 1] = '\0';
if ((p = strchr(buffer, '\n'))) { if ((p = strchr(buffer, '\n'))) {
*p = '\0'; *p = '\0';
} }
@@ -75,7 +74,7 @@ int authenticate_kbdint(ssh_session session, const char *password)
return SSH_AUTH_ERROR; return SSH_AUTH_ERROR;
} }
memset(buffer, 0, strlen(buffer)); memset(buffer, 0, sizeof(buffer));
} else { } else {
if (password && strstr(prompt, "Password:")) { if (password && strstr(prompt, "Password:")) {
answer = password; answer = password;
@@ -143,11 +142,11 @@ int authenticate_console(ssh_session session)
int rc; int rc;
int method; int method;
char password[128] = {0}; char password[128] = {0};
char *banner; char *banner = NULL;
// Try to authenticate // Try to authenticate
rc = ssh_userauth_none(session, NULL); rc = ssh_userauth_none(session, NULL);
if (rc == SSH_AUTH_ERROR) { if (rc == SSH_AUTH_ERROR || !ssh_is_connected(session)) {
error(session); error(session);
return rc; return rc;
} }
@@ -156,7 +155,7 @@ int authenticate_console(ssh_session session)
while (rc != SSH_AUTH_SUCCESS) { while (rc != SSH_AUTH_SUCCESS) {
if (method & SSH_AUTH_METHOD_GSSAPI_MIC){ if (method & SSH_AUTH_METHOD_GSSAPI_MIC){
rc = ssh_userauth_gssapi(session); rc = ssh_userauth_gssapi(session);
if(rc == SSH_AUTH_ERROR) { if (rc == SSH_AUTH_ERROR || !ssh_is_connected(session)) {
error(session); error(session);
return rc; return rc;
} else if (rc == SSH_AUTH_SUCCESS) { } else if (rc == SSH_AUTH_SUCCESS) {
@@ -166,7 +165,7 @@ int authenticate_console(ssh_session session)
// Try to authenticate with public key first // Try to authenticate with public key first
if (method & SSH_AUTH_METHOD_PUBLICKEY) { if (method & SSH_AUTH_METHOD_PUBLICKEY) {
rc = ssh_userauth_publickey_auto(session, NULL, NULL); rc = ssh_userauth_publickey_auto(session, NULL, NULL);
if (rc == SSH_AUTH_ERROR) { if (rc == SSH_AUTH_ERROR || !ssh_is_connected(session)) {
error(session); error(session);
return rc; return rc;
} else if (rc == SSH_AUTH_SUCCESS) { } else if (rc == SSH_AUTH_SUCCESS) {
@@ -206,7 +205,7 @@ int authenticate_console(ssh_session session)
// Try to authenticate with keyboard interactive"; // Try to authenticate with keyboard interactive";
if (method & SSH_AUTH_METHOD_INTERACTIVE) { if (method & SSH_AUTH_METHOD_INTERACTIVE) {
rc = authenticate_kbdint(session, NULL); rc = authenticate_kbdint(session, NULL);
if (rc == SSH_AUTH_ERROR) { if (rc == SSH_AUTH_ERROR || !ssh_is_connected(session)) {
error(session); error(session);
return rc; return rc;
} else if (rc == SSH_AUTH_SUCCESS) { } else if (rc == SSH_AUTH_SUCCESS) {
@@ -221,7 +220,7 @@ int authenticate_console(ssh_session session)
// Try to authenticate with password // Try to authenticate with password
if (method & SSH_AUTH_METHOD_PASSWORD) { if (method & SSH_AUTH_METHOD_PASSWORD) {
rc = ssh_userauth_password(session, NULL, password); rc = ssh_userauth_password(session, NULL, password);
if (rc == SSH_AUTH_ERROR) { if (rc == SSH_AUTH_ERROR || !ssh_is_connected(session)) {
error(session); error(session);
return rc; return rc;
} else if (rc == SSH_AUTH_SUCCESS) { } else if (rc == SSH_AUTH_SUCCESS) {

View File

@@ -21,47 +21,57 @@ clients must be made or how a client should react.
#include "examples_common.h" #include "examples_common.h"
#include <stdio.h> #include <stdio.h>
ssh_session connect_ssh(const char *host, const char *user,int verbosity){ ssh_session connect_ssh(const char *host, const char *port, const char *user, int verbosity)
ssh_session session; {
int auth=0; ssh_session session = NULL;
int auth = 0;
session=ssh_new(); session = ssh_new();
if (session == NULL) { if (session == NULL) {
return NULL; return NULL;
}
if(user != NULL){
if (ssh_options_set(session, SSH_OPTIONS_USER, user) < 0) {
ssh_free(session);
return NULL;
} }
}
if (ssh_options_set(session, SSH_OPTIONS_HOST, host) < 0) { if (user != NULL) {
ssh_free(session); if (ssh_options_set(session, SSH_OPTIONS_USER, user) < 0) {
return NULL; ssh_free(session);
} return NULL;
ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity); }
if(ssh_connect(session)){ }
fprintf(stderr,"Connection failed : %s\n",ssh_get_error(session));
if (port != NULL) {
if (ssh_options_set(session, SSH_OPTIONS_PORT_STR, port) < 0) {
ssh_free(session);
return NULL;
}
}
if (ssh_options_set(session, SSH_OPTIONS_HOST, host) < 0) {
ssh_free(session);
return NULL;
}
ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
if (ssh_connect(session)) {
fprintf(stderr, "Connection failed : %s\n", ssh_get_error(session));
ssh_disconnect(session);
ssh_free(session);
return NULL;
}
if (verify_knownhost(session) < 0) {
ssh_disconnect(session);
ssh_free(session);
return NULL;
}
auth = authenticate_console(session);
if (auth == SSH_AUTH_SUCCESS) {
return session;
} else if (auth == SSH_AUTH_DENIED) {
fprintf(stderr, "Authentication failed\n");
} else {
fprintf(stderr,
"Error while authenticating : %s\n",
ssh_get_error(session));
}
ssh_disconnect(session); ssh_disconnect(session);
ssh_free(session); ssh_free(session);
return NULL; return NULL;
}
if(verify_knownhost(session)<0){
ssh_disconnect(session);
ssh_free(session);
return NULL;
}
auth=authenticate_console(session);
if(auth==SSH_AUTH_SUCCESS){
return session;
} else if(auth==SSH_AUTH_DENIED){
fprintf(stderr,"Authentication failed\n");
} else {
fprintf(stderr,"Error while authenticating : %s\n",ssh_get_error(session));
}
ssh_disconnect(session);
ssh_free(session);
return NULL;
} }

View File

@@ -16,11 +16,11 @@ clients must be made or how a client should react.
#include <libssh/libssh.h> #include <libssh/libssh.h>
/** Zero a structure */ /** Zero a structure */
#define ZERO_STRUCT(x) memset((char *)&(x), 0, sizeof(x)) #define ZERO_STRUCT(x) memset(&(x), 0, sizeof(x))
int authenticate_console(ssh_session session); int authenticate_console(ssh_session session);
int authenticate_kbdint(ssh_session session, const char *password); int authenticate_kbdint(ssh_session session, const char *password);
int verify_knownhost(ssh_session session); int verify_knownhost(ssh_session session);
ssh_session connect_ssh(const char *hostname, const char *user, int verbosity); ssh_session connect_ssh(const char *hostname, const char *port, const char *user, int verbosity);
#endif /* EXAMPLES_COMMON_H_ */ #endif /* EXAMPLES_COMMON_H_ */

View File

@@ -5,13 +5,13 @@
#include "examples_common.h" #include "examples_common.h"
int main(void) { int main(void) {
ssh_session session; ssh_session session = NULL;
ssh_channel channel; ssh_channel channel = NULL;
char buffer[256]; char buffer[256];
int rbytes, wbytes, total = 0; int rbytes, wbytes, total = 0;
int rc; int rc;
session = connect_ssh("localhost", NULL, 0); session = connect_ssh("localhost", NULL, NULL, 0);
if (session == NULL) { if (session == NULL) {
ssh_finalize(); ssh_finalize();
return 1; return 1;

View File

@@ -350,7 +350,12 @@ int main(int argc, char *argv[])
goto end; goto end;
} }
if (arguments.action_list && arguments.file) { if (arguments.file == NULL) {
fprintf(stderr, "Error: Missing argument file\n");
goto end;
}
if (arguments.action_list) {
list_fingerprint(arguments.file); list_fingerprint(arguments.file);
goto end; goto end;
} }

View File

@@ -38,7 +38,7 @@ int verify_knownhost(ssh_session session)
char buf[10]; char buf[10];
unsigned char *hash = NULL; unsigned char *hash = NULL;
size_t hlen; size_t hlen;
ssh_key srv_pubkey; ssh_key srv_pubkey = NULL;
int rc; int rc;
rc = ssh_get_server_publickey(session, &srv_pubkey); rc = ssh_get_server_publickey(session, &srv_pubkey);

View File

@@ -26,10 +26,11 @@ program.
#define BUF_SIZE 16384 #define BUF_SIZE 16384
#endif #endif
static char **sources; static char **sources = NULL;
static int nsources; static int nsources;
static char *destination; static char *destination = NULL;
static int verbosity = 0; static int verbosity = 0;
static char *port = NULL;
struct location { struct location {
int is_ssh; int is_ssh;
@@ -49,9 +50,10 @@ enum {
static void usage(const char *argv0) { static void usage(const char *argv0) {
fprintf(stderr, "Usage : %s [options] [[user@]host1:]file1 ... \n" fprintf(stderr, "Usage : %s [options] [[user@]host1:]file1 ... \n"
" [[user@]host2:]destination\n" " [[user@]host2:]destination\n"
"sample scp client - libssh-%s\n", "sample scp client - libssh-%s\n"
// "Options :\n", "Options :\n"
// " -r : use RSA to verify host public key\n", " -P : use port to connect to remote host\n"
" -v : increase verbosity of libssh. Can be used multiple times\n",
argv0, argv0,
ssh_version(0)); ssh_version(0));
exit(0); exit(0);
@@ -60,11 +62,14 @@ static void usage(const char *argv0) {
static int opts(int argc, char **argv) { static int opts(int argc, char **argv) {
int i; int i;
while((i = getopt(argc, argv, "v")) != -1) { while((i = getopt(argc, argv, "P:v")) != -1) {
switch(i) { switch(i) {
case 'v': case 'v':
verbosity++; verbosity++;
break; break;
case 'P':
port = optarg;
break;
default: default:
fprintf(stderr, "unknown option %c\n", optopt); fprintf(stderr, "unknown option %c\n", optopt);
usage(argv[0]); usage(argv[0]);
@@ -114,9 +119,14 @@ static void location_free(struct location *loc)
} }
} }
static struct location *parse_location(char *loc) { static struct location *parse_location(char *loc)
struct location *location; {
char *ptr; struct location *location = NULL;
char *ptr = NULL;
if (loc == NULL) {
return NULL;
}
location = malloc(sizeof(struct location)); location = malloc(sizeof(struct location));
if (location == NULL) { if (location == NULL) {
@@ -178,7 +188,7 @@ static void close_location(struct location *loc) {
static int open_location(struct location *loc, int flag) { static int open_location(struct location *loc, int flag) {
if (loc->is_ssh && flag == WRITE) { if (loc->is_ssh && flag == WRITE) {
loc->session = connect_ssh(loc->host, loc->user, verbosity); loc->session = connect_ssh(loc->host, port, loc->user, verbosity);
if (!loc->session) { if (!loc->session) {
fprintf(stderr, "Couldn't connect to %s\n", loc->host); fprintf(stderr, "Couldn't connect to %s\n", loc->host);
return -1; return -1;
@@ -204,7 +214,7 @@ static int open_location(struct location *loc, int flag) {
} }
return 0; return 0;
} else if (loc->is_ssh && flag == READ) { } else if (loc->is_ssh && flag == READ) {
loc->session = connect_ssh(loc->host, loc->user, verbosity); loc->session = connect_ssh(loc->host, port, loc->user, verbosity);
if (!loc->session) { if (!loc->session) {
fprintf(stderr, "Couldn't connect to %s\n", loc->host); fprintf(stderr, "Couldn't connect to %s\n", loc->host);
return -1; return -1;

View File

@@ -35,8 +35,8 @@ clients must be made or how a client should react.
static int authenticated=0; static int authenticated=0;
static int tries = 0; static int tries = 0;
static int error = 0; static int error = 0;
static ssh_channel chan=NULL; static ssh_channel chan = NULL;
static char *username; static char *username = NULL;
static ssh_gssapi_creds client_creds = NULL; static ssh_gssapi_creds client_creds = NULL;
static int auth_password(ssh_session session, const char *user, static int auth_password(ssh_session session, const char *user,
@@ -204,11 +204,12 @@ static error_t parse_opt (int key, char *arg, struct argp_state *state) {
static struct argp argp = {options, parse_opt, args_doc, doc, NULL, NULL, NULL}; static struct argp argp = {options, parse_opt, args_doc, doc, NULL, NULL, NULL};
#endif /* HAVE_ARGP_H */ #endif /* HAVE_ARGP_H */
int main(int argc, char **argv){ int main(int argc, char **argv)
ssh_session session; {
ssh_bind sshbind; ssh_session session = NULL;
ssh_event mainloop; ssh_bind sshbind = NULL;
ssh_session client_session; ssh_event mainloop = NULL;
ssh_session client_session = NULL;
struct ssh_server_callbacks_struct cb = { struct ssh_server_callbacks_struct cb = {
.userdata = NULL, .userdata = NULL,
@@ -219,7 +220,7 @@ int main(int argc, char **argv){
char buf[BUF_SIZE]; char buf[BUF_SIZE];
char host[128]=""; char host[128]="";
char *ptr; char *ptr = NULL;
int i,r, rc; int i,r, rc;
sshbind=ssh_bind_new(); sshbind=ssh_bind_new();
@@ -336,4 +337,3 @@ int main(int argc, char **argv){
ssh_finalize(); ssh_finalize();
return 0; return 0;
} }

View File

@@ -148,6 +148,7 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state)
ssh_bind sshbind = state->input; ssh_bind sshbind = state->input;
static int no_default_keys = 0; static int no_default_keys = 0;
static int rsa_already_set = 0, ecdsa_already_set = 0; static int rsa_already_set = 0, ecdsa_already_set = 0;
static int verbosity = 0;
switch (key) switch (key)
{ {
@@ -176,8 +177,10 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state)
strncpy(authorizedkeys, arg, DEF_STR_SIZE - 1); strncpy(authorizedkeys, arg, DEF_STR_SIZE - 1);
break; break;
case 'v': case 'v':
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_LOG_VERBOSITY_STR, verbosity++;
"3"); ssh_bind_options_set(sshbind,
SSH_BIND_OPTIONS_LOG_VERBOSITY,
&verbosity);
break; break;
case ARGP_KEY_ARG: case ARGP_KEY_ARG:
if (state->arg_num >= 1) if (state->arg_num >= 1)
@@ -213,10 +216,7 @@ static struct argp argp = {options, parse_opt, args_doc, doc, NULL, NULL, NULL};
#endif /* HAVE_ARGP_H */ #endif /* HAVE_ARGP_H */
/* A userdata struct for channel. */ /* A userdata struct for channel. */
struct channel_data_struct struct channel_data_struct {
{
/* Event which is used to poll the above descriptors. */
ssh_event event;
sftp_session sftp; sftp_session sftp;
}; };
@@ -378,18 +378,11 @@ static void handle_session(ssh_event event, ssh_session session)
do { do {
/* Poll the main event which takes care of the session, the channel and /* Poll the main event which takes care of the session, the channel and
* even our child process's stdout/stderr (once it's started). */ * even our child process's stdout/stderr (once it's started). */
if (ssh_event_dopoll(event, -1) == SSH_ERROR) { if (ssh_event_dopoll(event, 100) == SSH_ERROR) {
ssh_channel_close(sdata.channel); ssh_channel_close(sdata.channel);
} }
} while (ssh_channel_is_open(sdata.channel) &&
/* If child process's stdout/stderr has been registered with the event, !ssh_channel_is_eof(sdata.channel));
* or the child process hasn't started yet, continue. */
if (cdata.event != NULL) {
continue;
}
/* FIXME The server keeps hanging in the poll above when the client
* closes the channel */
} while (ssh_channel_is_open(sdata.channel));
ssh_channel_send_eof(sdata.channel); ssh_channel_send_eof(sdata.channel);
ssh_channel_close(sdata.channel); ssh_channel_close(sdata.channel);

View File

@@ -244,10 +244,11 @@ static error_t parse_opt (int key, char *arg, struct argp_state *state) {
static struct argp argp = {options, parse_opt, args_doc, doc, NULL, NULL, NULL}; static struct argp argp = {options, parse_opt, args_doc, doc, NULL, NULL, NULL};
#endif /* HAVE_ARGP_H */ #endif /* HAVE_ARGP_H */
int main(int argc, char **argv){ int main(int argc, char **argv)
ssh_session session; {
ssh_bind sshbind; ssh_session session = NULL;
ssh_event mainloop; ssh_bind sshbind = NULL;
ssh_event mainloop = NULL;
struct ssh_server_callbacks_struct cb = { struct ssh_server_callbacks_struct cb = {
.userdata = NULL, .userdata = NULL,
.auth_none_function = auth_none, .auth_none_function = auth_none,
@@ -339,4 +340,3 @@ int main(int argc, char **argv){
ssh_finalize(); ssh_finalize();
return 0; return 0;
} }

View File

@@ -174,8 +174,8 @@ static error_t parse_opt (int key, char *arg, struct argp_state *state) {
static struct argp argp = {options, parse_opt, args_doc, doc, NULL, NULL, NULL}; static struct argp argp = {options, parse_opt, args_doc, doc, NULL, NULL, NULL};
#endif /* HAVE_ARGP_H */ #endif /* HAVE_ARGP_H */
static const char *name; static const char *name = NULL;
static const char *instruction; static const char *instruction = NULL;
static const char *prompts[2]; static const char *prompts[2];
static char echo[] = { 1, 0 }; static char echo[] = { 1, 0 };
@@ -279,11 +279,12 @@ static int authenticate(ssh_session session) {
return 0; return 0;
} }
int main(int argc, char **argv){ int main(int argc, char **argv)
ssh_session session; {
ssh_bind sshbind; ssh_session session = NULL;
ssh_message message; ssh_bind sshbind = NULL;
ssh_channel chan=0; ssh_message message = NULL;
ssh_channel chan = NULL;
char buf[BUF_SIZE]; char buf[BUF_SIZE];
int auth=0; int auth=0;
int shell=0; int shell=0;
@@ -411,4 +412,3 @@ int main(int argc, char **argv){
ssh_finalize(); ssh_finalize();
return 0; return 0;
} }

View File

@@ -32,151 +32,163 @@ static const char *createcommand =
"cd /tmp/libssh_tests && date > a && date > b && mkdir c && date > d"; "cd /tmp/libssh_tests && date > a && date > b && mkdir c && date > d";
static char *host = NULL; static char *host = NULL;
static void usage(const char *argv0){ static void usage(const char *argv0)
fprintf(stderr,"Usage : %s [options] host\n" {
"sample tiny scp downloader client - libssh-%s\n" fprintf(stderr,
"This program will create files in /tmp and try to fetch them\n", "Usage : %s [options] host\n"
// "Options :\n", "sample tiny scp downloader client - libssh-%s\n"
// " -r : use RSA to verify host public key\n", "This program will create files in /tmp and try to fetch them\n",
argv0, argv0,
ssh_version(0)); ssh_version(0));
exit(0); exit(0);
} }
static int opts(int argc, char **argv){ static int opts(int argc, char **argv)
int i; {
while((i=getopt(argc,argv,"v"))!=-1){ int i;
switch(i){
case 'v': while ((i = getopt(argc, argv, "v")) != -1) {
verbosity++; switch (i) {
break; case 'v':
default: verbosity++;
fprintf(stderr,"unknown option %c\n",optopt); break;
default:
fprintf(stderr, "unknown option %c\n", optopt);
usage(argv[0]);
return -1;
}
}
host = argv[optind];
if (host == NULL)
usage(argv[0]); usage(argv[0]);
return 0;
}
static void create_files(ssh_session session)
{
ssh_channel channel = ssh_channel_new(session);
char buffer[1];
int rc;
if (channel == NULL) {
fprintf(stderr, "Error creating channel: %s\n", ssh_get_error(session));
exit(EXIT_FAILURE);
}
if (ssh_channel_open_session(channel) != SSH_OK) {
fprintf(stderr, "Error creating channel: %s\n", ssh_get_error(session));
ssh_channel_free(channel);
exit(EXIT_FAILURE);
}
if (ssh_channel_request_exec(channel, createcommand) != SSH_OK) {
fprintf(stderr,
"Error executing command: %s\n",
ssh_get_error(session));
ssh_channel_close(channel);
ssh_channel_free(channel);
exit(EXIT_FAILURE);
}
while (!ssh_channel_is_eof(channel)) {
rc = ssh_channel_read(channel, buffer, 1, 1);
if (rc != 1) {
fprintf(stderr, "Error reading from channel\n");
ssh_channel_close(channel);
ssh_channel_free(channel);
return;
}
rc = write(1, buffer, 1);
if (rc < 0) {
fprintf(stderr, "Error writing to buffer\n");
ssh_channel_close(channel);
ssh_channel_free(channel);
return;
}
}
ssh_channel_close(channel);
ssh_channel_free(channel);
}
static int fetch_files(ssh_session session)
{
int size;
char buffer[BUF_SIZE];
int mode;
char *filename = NULL;
int r;
ssh_scp scp = ssh_scp_new(session,
SSH_SCP_READ | SSH_SCP_RECURSIVE,
"/tmp/libssh_tests/*");
if (ssh_scp_init(scp) != SSH_OK) {
fprintf(stderr, "error initializing scp: %s\n", ssh_get_error(session));
ssh_scp_free(scp);
return -1; return -1;
} }
} printf("Trying to download 3 files (a,b,d) and 1 directory (c)\n");
host = argv[optind]; do {
if(host == NULL) r = ssh_scp_pull_request(scp);
usage(argv[0]); switch (r) {
return 0; case SSH_SCP_REQUEST_NEWFILE:
size = ssh_scp_request_get_size(scp);
filename = strdup(ssh_scp_request_get_filename(scp));
mode = ssh_scp_request_get_permissions(scp);
printf("downloading file %s, size %d, perms 0%o\n",
filename,
size,
mode);
free(filename);
ssh_scp_accept_request(scp);
r = ssh_scp_read(scp, buffer, sizeof(buffer));
if (r == SSH_ERROR) {
fprintf(stderr,
"Error reading scp: %s\n",
ssh_get_error(session));
ssh_scp_close(scp);
ssh_scp_free(scp);
return -1;
}
printf("done\n");
break;
case SSH_ERROR:
fprintf(stderr, "Error: %s\n", ssh_get_error(session));
ssh_scp_close(scp);
ssh_scp_free(scp);
return -1;
case SSH_SCP_REQUEST_WARNING:
fprintf(stderr, "Warning: %s\n", ssh_scp_request_get_warning(scp));
break;
case SSH_SCP_REQUEST_NEWDIR:
filename = strdup(ssh_scp_request_get_filename(scp));
mode = ssh_scp_request_get_permissions(scp);
printf("downloading directory %s, perms 0%o\n", filename, mode);
free(filename);
ssh_scp_accept_request(scp);
break;
case SSH_SCP_REQUEST_ENDDIR:
printf("End of directory\n");
break;
case SSH_SCP_REQUEST_EOF:
printf("End of requests\n");
goto end;
}
} while (1);
end:
ssh_scp_close(scp);
ssh_scp_free(scp);
return 0;
} }
static void create_files(ssh_session session){ int main(int argc, char **argv)
ssh_channel channel=ssh_channel_new(session); {
char buffer[1]; ssh_session session = NULL;
int rc; if (opts(argc, argv) < 0)
return EXIT_FAILURE;
if(channel == NULL){ session = connect_ssh(host, NULL, NULL, verbosity);
fprintf(stderr,"Error creating channel: %s\n",ssh_get_error(session)); if (session == NULL)
exit(EXIT_FAILURE); return EXIT_FAILURE;
} create_files(session);
if(ssh_channel_open_session(channel) != SSH_OK){ fetch_files(session);
fprintf(stderr,"Error creating channel: %s\n",ssh_get_error(session)); ssh_disconnect(session);
ssh_channel_free(channel); ssh_free(session);
exit(EXIT_FAILURE); ssh_finalize();
} return 0;
if(ssh_channel_request_exec(channel,createcommand) != SSH_OK){
fprintf(stderr,"Error executing command: %s\n",ssh_get_error(session));
ssh_channel_close(channel);
ssh_channel_free(channel);
exit(EXIT_FAILURE);
}
while(!ssh_channel_is_eof(channel)){
rc = ssh_channel_read(channel,buffer,1,1);
if (rc != 1) {
fprintf(stderr, "Error reading from channel\n");
ssh_channel_close(channel);
ssh_channel_free(channel);
return;
}
rc = write(1, buffer, 1);
if (rc < 0) {
fprintf(stderr, "Error writing to buffer\n");
ssh_channel_close(channel);
ssh_channel_free(channel);
return;
}
}
ssh_channel_close(channel);
ssh_channel_free(channel);
}
static int fetch_files(ssh_session session){
int size;
char buffer[BUF_SIZE];
int mode;
char *filename;
int r;
ssh_scp scp=ssh_scp_new(session, SSH_SCP_READ | SSH_SCP_RECURSIVE, "/tmp/libssh_tests/*");
if(ssh_scp_init(scp) != SSH_OK){
fprintf(stderr,"error initializing scp: %s\n",ssh_get_error(session));
ssh_scp_free(scp);
return -1;
}
printf("Trying to download 3 files (a,b,d) and 1 directory (c)\n");
do {
r=ssh_scp_pull_request(scp);
switch(r){
case SSH_SCP_REQUEST_NEWFILE:
size=ssh_scp_request_get_size(scp);
filename=strdup(ssh_scp_request_get_filename(scp));
mode=ssh_scp_request_get_permissions(scp);
printf("downloading file %s, size %d, perms 0%o\n",filename,size,mode);
free(filename);
ssh_scp_accept_request(scp);
r=ssh_scp_read(scp,buffer,sizeof(buffer));
if(r==SSH_ERROR){
fprintf(stderr,"Error reading scp: %s\n",ssh_get_error(session));
ssh_scp_close(scp);
ssh_scp_free(scp);
return -1;
}
printf("done\n");
break;
case SSH_ERROR:
fprintf(stderr,"Error: %s\n",ssh_get_error(session));
ssh_scp_close(scp);
ssh_scp_free(scp);
return -1;
case SSH_SCP_REQUEST_WARNING:
fprintf(stderr,"Warning: %s\n",ssh_scp_request_get_warning(scp));
break;
case SSH_SCP_REQUEST_NEWDIR:
filename=strdup(ssh_scp_request_get_filename(scp));
mode=ssh_scp_request_get_permissions(scp);
printf("downloading directory %s, perms 0%o\n",filename,mode);
free(filename);
ssh_scp_accept_request(scp);
break;
case SSH_SCP_REQUEST_ENDDIR:
printf("End of directory\n");
break;
case SSH_SCP_REQUEST_EOF:
printf("End of requests\n");
goto end;
}
} while (1);
end:
ssh_scp_close(scp);
ssh_scp_free(scp);
return 0;
}
int main(int argc, char **argv){
ssh_session session;
if(opts(argc,argv)<0)
return EXIT_FAILURE;
session=connect_ssh(host,NULL,verbosity);
if(session == NULL)
return EXIT_FAILURE;
create_files(session);
fetch_files(session);
ssh_disconnect(session);
ssh_free(session);
ssh_finalize();
return 0;
} }

View File

@@ -5,60 +5,60 @@
#define LIMIT 0x100000000UL #define LIMIT 0x100000000UL
int main(void) { int main(void)
ssh_session session; {
ssh_channel channel; ssh_session session = NULL;
char buffer[1024*1024]; ssh_channel channel = NULL;
int rc; char buffer[1024 * 1024] = {0};
uint64_t total=0; int rc;
uint64_t lastshown=4096; uint64_t total = 0;
session = connect_ssh("localhost", NULL, 0); uint64_t lastshown = 4096;
if (session == NULL) { session = connect_ssh("localhost", NULL, NULL, 0);
return 1; if (session == NULL) {
} return 1;
channel = ssh_channel_new(session);
if (channel == NULL) {
ssh_disconnect(session);
return 1;
}
rc = ssh_channel_open_session(channel);
if (rc < 0) {
ssh_channel_close(channel);
ssh_disconnect(session);
return 1;
}
rc = ssh_channel_request_exec(channel, "cat > /dev/null");
if (rc < 0) {
ssh_channel_close(channel);
ssh_disconnect(session);
return 1;
}
while ((rc = ssh_channel_write(channel, buffer, sizeof(buffer))) > 0) {
total += rc;
if(total/2 >= lastshown){
printf("written %llx\n", (long long unsigned int) total);
lastshown=total;
} }
if(total > LIMIT)
break;
}
if (rc < 0) { channel = ssh_channel_new(session);
printf("error : %s\n",ssh_get_error(session)); if (channel == NULL) {
ssh_disconnect(session);
return 1;
}
rc = ssh_channel_open_session(channel);
if (rc < 0) {
ssh_channel_close(channel);
ssh_disconnect(session);
return 1;
}
rc = ssh_channel_request_exec(channel, "cat > /dev/null");
if (rc < 0) {
ssh_channel_close(channel);
ssh_disconnect(session);
return 1;
}
while ((rc = ssh_channel_write(channel, buffer, sizeof(buffer))) > 0) {
total += rc;
if (total / 2 >= lastshown) {
printf("written %llx\n", (long long unsigned int)total);
lastshown = total;
}
if (total > LIMIT)
break;
}
if (rc < 0) {
printf("error : %s\n", ssh_get_error(session));
ssh_channel_close(channel);
ssh_disconnect(session);
return 1;
}
ssh_channel_send_eof(channel);
ssh_channel_close(channel); ssh_channel_close(channel);
ssh_disconnect(session); ssh_disconnect(session);
return 1;
}
ssh_channel_send_eof(channel); return 0;
ssh_channel_close(channel);
ssh_disconnect(session);
return 0;
} }

View File

@@ -70,6 +70,7 @@
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <inttypes.h>
#include <poll.h> #include <poll.h>
#include <pthread.h> #include <pthread.h>
#include <stddef.h> #include <stddef.h>
@@ -231,7 +232,7 @@ static void _logging_callback(int priority, const char *function,
milliseconds = _current_timestamp(); milliseconds = _current_timestamp();
fprintf(fp, "[%s.%jd, %d] %s: %s\n", buf, milliseconds, priority, fprintf(fp, "[%s.%" PRId64 ", %d] %s: %s\n", buf, milliseconds, priority,
function, buffer); function, buffer);
fclose(fp); fclose(fp);
} }

View File

@@ -39,8 +39,6 @@
#include <libssh/callbacks.h> #include <libssh/callbacks.h>
#include <libssh/libssh.h> #include <libssh/libssh.h>
#include <libssh/sftp.h>
#include "examples_common.h" #include "examples_common.h"
#define MAXCMD 10 #define MAXCMD 10
@@ -53,7 +51,7 @@ static struct termios terminal;
static char *pcap_file = NULL; static char *pcap_file = NULL;
static char *proxycommand; static char *proxycommand = NULL;
static int auth_callback(const char *prompt, static int auth_callback(const char *prompt,
char *buf, char *buf,
@@ -88,22 +86,24 @@ static void add_cmd(char *cmd)
static void usage(void) static void usage(void)
{ {
fprintf(stderr, fprintf(
"Usage : ssh [options] [login@]hostname\n" stderr,
"sample client - libssh-%s\n" "Usage : ssh [options] [login@]hostname\n"
"Options :\n" "sample client - libssh-%s\n"
" -l user : log in as user\n" "Options :\n"
" -p port : connect to port\n" " -l user : log in as user\n"
" -r : use RSA to verify host public key\n" " -p port : connect to port\n"
" -F file : parse configuration file instead of default one\n" " -o option : set configuration option (e.g., -o Compression=yes)\n"
" -r : use RSA to verify host public key\n"
" -F file : parse configuration file instead of default one\n"
#ifdef WITH_PCAP #ifdef WITH_PCAP
" -P file : create a pcap debugging file\n" " -P file : create a pcap debugging file\n"
#endif #endif
#ifndef _WIN32 #ifndef _WIN32
" -T proxycommand : command to execute as a socket proxy\n" " -T proxycommand : command to execute as a socket proxy\n"
#endif #endif
"\n", "\n",
ssh_version(0)); ssh_version(0));
exit(0); exit(0);
} }
@@ -112,8 +112,8 @@ static int opts(int argc, char **argv)
{ {
int i; int i;
while((i = getopt(argc,argv,"T:P:F:")) != -1) { while ((i = getopt(argc, argv, "T:P:F:")) != -1) {
switch(i){ switch (i) {
case 'P': case 'P':
pcap_file = optarg; pcap_file = optarg;
break; break;
@@ -159,16 +159,14 @@ static void cfmakeraw(struct termios *termios_p)
static void do_cleanup(int i) static void do_cleanup(int i)
{ {
/* unused variable */ (void)i;
(void) i;
tcsetattr(0, TCSANOW, &terminal); tcsetattr(0, TCSANOW, &terminal);
} }
static void do_exit(int i) static void do_exit(int i)
{ {
/* unused variable */ (void)i;
(void) i;
do_cleanup(0); do_cleanup(0);
exit(0); exit(0);
@@ -179,7 +177,7 @@ static int signal_delayed = 0;
#ifdef SIGWINCH #ifdef SIGWINCH
static void sigwindowchanged(int i) static void sigwindowchanged(int i)
{ {
(void) i; (void)i;
signal_delayed = 1; signal_delayed = 1;
} }
#endif #endif
@@ -213,18 +211,18 @@ static void select_loop(ssh_session session,ssh_channel channel)
/* stdin */ /* stdin */
connector_in = ssh_connector_new(session); connector_in = ssh_connector_new(session);
ssh_connector_set_out_channel(connector_in, channel, SSH_CONNECTOR_STDINOUT); ssh_connector_set_out_channel(connector_in, channel, SSH_CONNECTOR_STDINOUT);
ssh_connector_set_in_fd(connector_in, 0); ssh_connector_set_in_fd(connector_in, STDIN_FILENO);
ssh_event_add_connector(event, connector_in); ssh_event_add_connector(event, connector_in);
/* stdout */ /* stdout */
connector_out = ssh_connector_new(session); connector_out = ssh_connector_new(session);
ssh_connector_set_out_fd(connector_out, 1); ssh_connector_set_out_fd(connector_out, STDOUT_FILENO);
ssh_connector_set_in_channel(connector_out, channel, SSH_CONNECTOR_STDINOUT); ssh_connector_set_in_channel(connector_out, channel, SSH_CONNECTOR_STDINOUT);
ssh_event_add_connector(event, connector_out); ssh_event_add_connector(event, connector_out);
/* stderr */ /* stderr */
connector_err = ssh_connector_new(session); connector_err = ssh_connector_new(session);
ssh_connector_set_out_fd(connector_err, 2); ssh_connector_set_out_fd(connector_err, STDERR_FILENO);
ssh_connector_set_in_channel(connector_err, channel, SSH_CONNECTOR_STDERR); ssh_connector_set_in_channel(connector_err, channel, SSH_CONNECTOR_STDERR);
ssh_event_add_connector(event, connector_err); ssh_event_add_connector(event, connector_err);
@@ -251,9 +249,9 @@ static void select_loop(ssh_session session,ssh_channel channel)
static void shell(ssh_session session) static void shell(ssh_session session)
{ {
ssh_channel channel; ssh_channel channel = NULL;
struct termios terminal_local; struct termios terminal_local;
int interactive=isatty(0); int interactive = isatty(0);
channel = ssh_channel_new(session); channel = ssh_channel_new(session);
if (channel == NULL) { if (channel == NULL) {
@@ -339,7 +337,7 @@ static void batch_shell(ssh_session session)
static int client(ssh_session session) static int client(ssh_session session)
{ {
int auth = 0; int auth = 0;
char *banner; char *banner = NULL;
int state; int state;
if (user) { if (user) {
@@ -357,10 +355,8 @@ static int client(ssh_session session)
} }
/* Parse configuration file if specified: The command-line options will /* Parse configuration file if specified: The command-line options will
* overwrite items loaded from configuration file */ * overwrite items loaded from configuration file */
if (config_file != NULL) { if (ssh_options_parse_config(session, config_file) < 0) {
ssh_options_parse_config(session, config_file); return -1;
} else {
ssh_options_parse_config(session, NULL);
} }
if (ssh_connect(session)) { if (ssh_connect(session)) {
@@ -423,7 +419,7 @@ static void cleanup_pcap(void)
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
ssh_session session; ssh_session session = NULL;
ssh_init(); ssh_init();
session = ssh_new(); session = ssh_new();

View File

@@ -192,9 +192,6 @@ static struct argp argp = {options, parse_opt, args_doc, doc, NULL, NULL, NULL};
static int static int
parse_opt(int argc, char **argv, ssh_bind sshbind) parse_opt(int argc, char **argv, ssh_bind sshbind)
{ {
int no_default_keys = 0;
int rsa_already_set = 0;
int ecdsa_already_set = 0;
int key; int key;
while((key = getopt(argc, argv, "a:e:k:p:P:r:u:v")) != -1) { while((key = getopt(argc, argv, "a:e:k:p:P:r:u:v")) != -1) {
@@ -202,16 +199,10 @@ parse_opt(int argc, char **argv, ssh_bind sshbind)
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDPORT_STR, optarg); ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDPORT_STR, optarg);
} else if (key == 'k') { } else if (key == 'k') {
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, optarg); ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, optarg);
/* We can't track the types of keys being added with this
option, so let's ensure we keep the keys we're adding
by just not setting the default keys */
no_default_keys = 1;
} else if (key == 'r') { } else if (key == 'r') {
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, optarg); ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, optarg);
rsa_already_set = 1;
} else if (key == 'e') { } else if (key == 'e') {
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, optarg); ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, optarg);
ecdsa_already_set = 1;
} else if (key == 'a') { } else if (key == 'a') {
strncpy(authorizedkeys, optarg, DEF_STR_SIZE-1); strncpy(authorizedkeys, optarg, DEF_STR_SIZE-1);
} else if (key == 'u') { } else if (key == 'u') {
@@ -256,12 +247,6 @@ parse_opt(int argc, char **argv, ssh_bind sshbind)
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDADDR, argv[optind]); ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDADDR, argv[optind]);
if (!no_default_keys) {
set_default_keys(sshbind,
rsa_already_set,
ecdsa_already_set);
}
return 0; return 0;
} }
#endif /* HAVE_ARGP_H */ #endif /* HAVE_ARGP_H */
@@ -646,6 +631,58 @@ auth_publickey(ssh_session session,
return SSH_AUTH_DENIED; return SSH_AUTH_DENIED;
} }
static int kbdint_check_response(ssh_session session)
{
int count, cmp;
const char *answer = NULL;
count = ssh_userauth_kbdint_getnanswers(session);
if (count != 2) {
return 0;
}
answer = ssh_userauth_kbdint_getanswer(session, 0);
cmp = strcasecmp("omnitrix", answer);
if (cmp != 0) {
return 0;
}
answer = ssh_userauth_kbdint_getanswer(session, 1);
cmp = strcmp("000", answer);
if (cmp != 0) {
return 0;
}
return 1;
}
static int
auth_kbdint(ssh_message message, ssh_session session, void *userdata)
{
struct session_data_struct *sdata = (struct session_data_struct *)userdata;
const char *name = "\n\nKeyboard-Interactive Fancy Authentication\n";
const char *instruction = "Most powerful weapon in the galaxy";
const char *prompts[2] = {"Name of the weapon: ", "Destruct Code: "};
char echo[] = {1, 0};
if (!ssh_message_auth_kbdint_is_response(message)) {
printf("User %s wants to auth with kbdint\n",
ssh_message_auth_user(message));
ssh_message_auth_interactive_request(message,
name,
instruction,
2,
prompts,
echo);
return SSH_AUTH_INFO;
} else {
if (kbdint_check_response(session)) {
sdata->authenticated = 1;
return SSH_AUTH_SUCCESS;
}
return SSH_AUTH_DENIED;
}
}
static ssh_channel static ssh_channel
channel_open(ssh_session session, void *userdata) channel_open(ssh_session session, void *userdata)
{ {
@@ -735,14 +772,15 @@ handle_session(ssh_event event, ssh_session session)
struct ssh_server_callbacks_struct server_cb = { struct ssh_server_callbacks_struct server_cb = {
.userdata = &sdata, .userdata = &sdata,
.auth_password_function = auth_password, .auth_password_function = auth_password,
.auth_kbdint_function = auth_kbdint,
.channel_open_request_session_function = channel_open, .channel_open_request_session_function = channel_open,
}; };
if (authorizedkeys[0]) { if (authorizedkeys[0]) {
server_cb.auth_pubkey_function = auth_publickey; server_cb.auth_pubkey_function = auth_publickey;
ssh_set_auth_methods(session, SSH_AUTH_METHOD_PASSWORD | SSH_AUTH_METHOD_PUBLICKEY); ssh_set_auth_methods(session, SSH_AUTH_METHOD_PASSWORD | SSH_AUTH_METHOD_PUBLICKEY | SSH_AUTH_METHOD_INTERACTIVE);
} else } else
ssh_set_auth_methods(session, SSH_AUTH_METHOD_PASSWORD); ssh_set_auth_methods(session, SSH_AUTH_METHOD_PASSWORD | SSH_AUTH_METHOD_INTERACTIVE);
ssh_callbacks_init(&server_cb); ssh_callbacks_init(&server_cb);
ssh_callbacks_init(&channel_cb); ssh_callbacks_init(&channel_cb);

View File

@@ -361,7 +361,7 @@ my_fd_data_function(UNUSED_PARAM(socket_t fd),
{ {
struct event_fd_data_struct *event_fd_data = (struct event_fd_data_struct *)userdata; struct event_fd_data_struct *event_fd_data = (struct event_fd_data_struct *)userdata;
ssh_channel channel = event_fd_data->channel; ssh_channel channel = event_fd_data->channel;
ssh_session session; ssh_session session = NULL;
int len, i, wr; int len, i, wr;
char buf[BUF_SIZE]; char buf[BUF_SIZE];
int blocking; int blocking;
@@ -455,8 +455,8 @@ open_tcp_socket(ssh_message msg)
{ {
struct sockaddr_in sin; struct sockaddr_in sin;
int forwardsock = -1; int forwardsock = -1;
struct hostent *host; struct hostent *host = NULL;
const char *dest_hostname; const char *dest_hostname = NULL;
int dest_port; int dest_port;
forwardsock = socket(AF_INET, SOCK_STREAM, 0); forwardsock = socket(AF_INET, SOCK_STREAM, 0);
@@ -499,8 +499,8 @@ message_callback(UNUSED_PARAM(ssh_session session),
UNUSED_PARAM(void *userdata)) UNUSED_PARAM(void *userdata))
{ {
ssh_channel channel; ssh_channel channel;
int socket_fd, *pFd; int socket_fd, *pFd = NULL;
struct ssh_channel_callbacks_struct *cb_chan; struct ssh_channel_callbacks_struct *cb_chan = NULL;
struct event_fd_data_struct *event_fd_data; struct event_fd_data_struct *event_fd_data;
_ssh_log(SSH_LOG_PACKET, "=== message_callback", "Message type: %d", _ssh_log(SSH_LOG_PACKET, "=== message_callback", "Message type: %d",
@@ -655,8 +655,8 @@ static struct argp argp = {options, parse_opt, args_doc, doc, NULL, NULL, NULL};
int int
main(int argc, char **argv) main(int argc, char **argv)
{ {
ssh_session session; ssh_session session = NULL;
ssh_bind sshbind; ssh_bind sshbind = NULL;
struct ssh_server_callbacks_struct cb = { struct ssh_server_callbacks_struct cb = {
.userdata = NULL, .userdata = NULL,
.auth_password_function = auth_password, .auth_password_function = auth_password,

View File

@@ -39,223 +39,237 @@ clients must be made or how a client should react.
#define BUF_SIZE 4096 #define BUF_SIZE 4096
#endif #endif
char *host; char *host = NULL;
const char *desthost="localhost"; const char *desthost = "localhost";
const char *port="22"; const char *port = "22";
#ifdef WITH_PCAP #ifdef WITH_PCAP
#include <libssh/pcap.h> #include <libssh/pcap.h>
char *pcap_file=NULL; char *pcap_file = NULL;
#endif #endif
static void usage(void) static void usage(void)
{ {
fprintf(stderr,"Usage : sshnetcat [user@]host forwarded_host forwarded_port\n"); fprintf(stderr,
exit(1); "Usage : sshnetcat [user@]host forwarded_host forwarded_port\n");
exit(1);
} }
static int opts(int argc, char **argv){ static int opts(int argc, char **argv)
{
int i; int i;
while((i=getopt(argc,argv,"P:"))!=-1){ while ((i = getopt(argc, argv, "P:")) != -1) {
switch(i){ switch (i) {
#ifdef WITH_PCAP #ifdef WITH_PCAP
case 'P': case 'P':
pcap_file=optarg; pcap_file = optarg;
break; break;
#endif #endif
default: default:
fprintf(stderr,"unknown option %c\n",optopt); fprintf(stderr, "unknown option %c\n", optopt);
usage(); usage();
} }
} }
if(optind < argc) if (optind < argc)
host=argv[optind++]; host = argv[optind++];
if(optind < argc) if (optind < argc)
desthost=argv[optind++]; desthost = argv[optind++];
if(optind < argc) if (optind < argc)
port=argv[optind++]; port = argv[optind++];
if(host==NULL) if (host == NULL)
usage(); usage();
return 0; return 0;
} }
static void select_loop(ssh_session session,ssh_channel channel){ static void select_loop(ssh_session session, ssh_channel channel)
fd_set fds; {
struct timeval timeout; fd_set fds;
char buffer[BUF_SIZE]; struct timeval timeout;
/* channels will be set to the channels to poll. char buffer[BUF_SIZE];
* outchannels will contain the result of the poll /* channels will be set to the channels to poll.
*/ * outchannels will contain the result of the poll
ssh_channel channels[2], outchannels[2]; */
int lus; ssh_channel channels[2], outchannels[2];
int eof=0; int lus;
int maxfd; int eof = 0;
int ret; int maxfd;
while(channel){ int ret;
do{ while (channel) {
do {
int fd; int fd;
ZERO_STRUCT(fds); ZERO_STRUCT(fds);
FD_ZERO(&fds); FD_ZERO(&fds);
if(!eof) if (!eof)
FD_SET(0,&fds); FD_SET(0, &fds);
timeout.tv_sec=30; timeout.tv_sec = 30;
timeout.tv_usec=0; timeout.tv_usec = 0;
fd = ssh_get_fd(session); fd = ssh_get_fd(session);
if (fd == -1) { if (fd == -1) {
fprintf(stderr, "Error getting the session file descriptor: %s\n", fprintf(stderr,
ssh_get_error(session)); "Error getting the session file descriptor: %s\n",
ssh_get_error(session));
return; return;
} }
FD_SET(fd, &fds); FD_SET(fd, &fds);
maxfd = fd + 1; maxfd = fd + 1;
channels[0]=channel; // set the first channel we want to read from channels[0] = channel; // set the first channel we want to read from
channels[1]=NULL; channels[1] = NULL;
ret=ssh_select(channels,outchannels,maxfd,&fds,&timeout); ret = ssh_select(channels, outchannels, maxfd, &fds, &timeout);
if(ret==EINTR) if (ret == EINTR)
continue; continue;
if(FD_ISSET(0,&fds)){ if (FD_ISSET(0, &fds)) {
lus=read(0,buffer,sizeof(buffer)); lus = read(0, buffer, sizeof(buffer));
if(lus) if (lus)
ssh_channel_write(channel,buffer,lus); ssh_channel_write(channel, buffer, lus);
else { else {
eof=1; eof = 1;
ssh_channel_send_eof(channel); ssh_channel_send_eof(channel);
} }
} }
if(channel && ssh_channel_is_closed(channel)){ if (channel && ssh_channel_is_closed(channel)) {
ssh_channel_free(channel); ssh_channel_free(channel);
channel=NULL; channel = NULL;
channels[0]=NULL; channels[0] = NULL;
} }
if(outchannels[0]){ if (outchannels[0]) {
while(channel && ssh_channel_is_open(channel) && ssh_channel_poll(channel,0)){ while (channel && ssh_channel_is_open(channel) &&
lus = ssh_channel_read(channel,buffer,sizeof(buffer),0); ssh_channel_poll(channel, 0)) {
if(lus==-1){ lus = ssh_channel_read(channel, buffer, sizeof(buffer), 0);
fprintf(stderr, "Error reading channel: %s\n", if (lus == -1) {
ssh_get_error(session)); fprintf(stderr,
return; "Error reading channel: %s\n",
} ssh_get_error(session));
if(lus==0){ return;
ssh_channel_free(channel);
channel=channels[0]=NULL;
} else {
ret = write(1, buffer, lus);
if (ret < 0) {
fprintf(stderr, "Error writing to stdin: %s",
strerror(errno));
return;
}
}
}
while(channel && ssh_channel_is_open(channel) && ssh_channel_poll(channel,1)){ /* stderr */
lus = ssh_channel_read(channel, buffer, sizeof(buffer), 1);
if(lus==-1){
fprintf(stderr, "Error reading channel: %s\n",
ssh_get_error(session));
return;
}
if(lus==0){
ssh_channel_free(channel);
channel=channels[0]=NULL;
} else {
ret = write(2, buffer, lus);
if (ret < 0) {
fprintf(stderr, "Error writing to stderr: %s",
strerror(errno));
return;
}
} }
} if (lus == 0) {
} ssh_channel_free(channel);
if(channel && ssh_channel_is_closed(channel)){ channel = channels[0] = NULL;
ssh_channel_free(channel); } else {
channel=NULL; ret = write(1, buffer, lus);
} if (ret < 0) {
} while (ret==EINTR || ret==SSH_EINTR); fprintf(stderr,
"Error writing to stdin: %s",
} strerror(errno));
return;
}
}
}
while (channel && ssh_channel_is_open(channel) &&
ssh_channel_poll(channel, 1)) { /* stderr */
lus = ssh_channel_read(channel, buffer, sizeof(buffer), 1);
if (lus == -1) {
fprintf(stderr,
"Error reading channel: %s\n",
ssh_get_error(session));
return;
}
if (lus == 0) {
ssh_channel_free(channel);
channel = channels[0] = NULL;
} else {
ret = write(2, buffer, lus);
if (ret < 0) {
fprintf(stderr,
"Error writing to stderr: %s",
strerror(errno));
return;
}
}
}
}
if (channel && ssh_channel_is_closed(channel)) {
ssh_channel_free(channel);
channel = NULL;
}
} while (ret == EINTR || ret == SSH_EINTR);
}
} }
static void forwarding(ssh_session session){ static void forwarding(ssh_session session)
{
ssh_channel channel; ssh_channel channel;
int r; int r;
channel = ssh_channel_new(session); channel = ssh_channel_new(session);
r = ssh_channel_open_forward(channel, desthost, atoi(port), "localhost", 22); r = ssh_channel_open_forward(channel, desthost, atoi(port), "localhost", 22);
if(r<0) { if (r < 0) {
printf("error forwarding port : %s\n",ssh_get_error(session)); printf("error forwarding port : %s\n", ssh_get_error(session));
return; return;
} }
select_loop(session,channel); select_loop(session, channel);
} }
static int client(ssh_session session){ static int client(ssh_session session)
int auth=0; {
char *banner; int auth = 0;
int state; char *banner = NULL;
int state;
if (ssh_options_set(session, SSH_OPTIONS_HOST ,host) < 0) if (ssh_options_set(session, SSH_OPTIONS_HOST, host) < 0)
return -1; return -1;
ssh_options_parse_config(session, NULL); ssh_options_parse_config(session, NULL);
if(ssh_connect(session)){ if (ssh_connect(session)) {
fprintf(stderr,"Connection failed : %s\n",ssh_get_error(session)); fprintf(stderr, "Connection failed : %s\n", ssh_get_error(session));
return -1; return -1;
} }
state=verify_knownhost(session); state = verify_knownhost(session);
if (state != 0) if (state != 0)
return -1; return -1;
ssh_userauth_none(session, NULL); ssh_userauth_none(session, NULL);
banner=ssh_get_issue_banner(session); banner = ssh_get_issue_banner(session);
if(banner){ if (banner) {
printf("%s\n",banner); printf("%s\n", banner);
free(banner); free(banner);
} }
auth=authenticate_console(session); auth = authenticate_console(session);
if(auth != SSH_AUTH_SUCCESS){ if (auth != SSH_AUTH_SUCCESS) {
return -1; return -1;
} }
forwarding(session); forwarding(session);
return 0; return 0;
} }
#ifdef WITH_PCAP #ifdef WITH_PCAP
ssh_pcap_file pcap; ssh_pcap_file pcap;
void set_pcap(ssh_session session); void set_pcap(ssh_session session);
void set_pcap(ssh_session session){ void set_pcap(ssh_session session)
if(!pcap_file) {
return; if (!pcap_file)
pcap=ssh_pcap_file_new(); return;
if(ssh_pcap_file_open(pcap,pcap_file) == SSH_ERROR){ pcap = ssh_pcap_file_new();
printf("Error opening pcap file\n"); if (ssh_pcap_file_open(pcap, pcap_file) == SSH_ERROR) {
ssh_pcap_file_free(pcap); printf("Error opening pcap file\n");
pcap=NULL; ssh_pcap_file_free(pcap);
return; pcap = NULL;
} return;
ssh_set_pcap_file(session,pcap); }
ssh_set_pcap_file(session, pcap);
} }
void cleanup_pcap(void); void cleanup_pcap(void);
void cleanup_pcap(void) void cleanup_pcap(void)
{ {
ssh_pcap_file_free(pcap); ssh_pcap_file_free(pcap);
pcap = NULL; pcap = NULL;
} }
#endif #endif
int main(int argc, char **argv){ int main(int argc, char **argv)
ssh_session session; {
ssh_session session = NULL;
session = ssh_new(); session = ssh_new();
if(ssh_options_getopt(session, &argc, argv)) { if (ssh_options_getopt(session, &argc, argv)) {
fprintf(stderr, "error parsing command line :%s\n", fprintf(stderr,
ssh_get_error(session)); "error parsing command line :%s\n",
usage(); ssh_get_error(session));
usage();
} }
opts(argc,argv); opts(argc, argv);
#ifdef WITH_PCAP #ifdef WITH_PCAP
set_pcap(session); set_pcap(session);
#endif #endif

View File

@@ -29,6 +29,13 @@ if (WITH_SERVER)
endif (WITH_SFTP) endif (WITH_SFTP)
endif (WITH_SERVER) endif (WITH_SERVER)
if (WITH_FIDO2)
set(libssh_HDRS
${libssh_HDRS}
sk_api.h
)
endif (WITH_FIDO2)
install( install(
FILES FILES
${libssh_HDRS} ${libssh_HDRS}

View File

@@ -52,42 +52,45 @@ typedef struct ssh_kbdint_struct* ssh_kbdint;
ssh_kbdint ssh_kbdint_new(void); ssh_kbdint ssh_kbdint_new(void);
void ssh_kbdint_clean(ssh_kbdint kbd); void ssh_kbdint_clean(ssh_kbdint kbd);
void ssh_kbdint_free(ssh_kbdint kbd); void ssh_kbdint_free(ssh_kbdint kbd);
int ssh_userauth_gssapi_keyex(ssh_session session);
/** @internal /** @internal
* States of authentication in the client-side. They describe * States of authentication in the client-side. They describe
* what was the last response from the server * what was the last response from the server
*/ */
enum ssh_auth_state_e { enum ssh_auth_state_e {
/** No authentication asked */ /** No authentication asked */
SSH_AUTH_STATE_NONE=0, SSH_AUTH_STATE_NONE = 0,
/** Last authentication response was a partial success */ /** Last authentication response was a partial success */
SSH_AUTH_STATE_PARTIAL, SSH_AUTH_STATE_PARTIAL,
/** Last authentication response was a success */ /** Last authentication response was a success */
SSH_AUTH_STATE_SUCCESS, SSH_AUTH_STATE_SUCCESS,
/** Last authentication response was failed */ /** Last authentication response was failed */
SSH_AUTH_STATE_FAILED, SSH_AUTH_STATE_FAILED,
/** Last authentication was erroneous */ /** Last authentication was erroneous */
SSH_AUTH_STATE_ERROR, SSH_AUTH_STATE_ERROR,
/** Last state was a keyboard-interactive ask for info */ /** Last state was a keyboard-interactive ask for info */
SSH_AUTH_STATE_INFO, SSH_AUTH_STATE_INFO,
/** Last state was a public key accepted for authentication */ /** Last state was a public key accepted for authentication */
SSH_AUTH_STATE_PK_OK, SSH_AUTH_STATE_PK_OK,
/** We asked for a keyboard-interactive authentication */ /** We asked for a keyboard-interactive authentication */
SSH_AUTH_STATE_KBDINT_SENT, SSH_AUTH_STATE_KBDINT_SENT,
/** We have sent an userauth request with gssapi-with-mic */ /** We have sent an userauth request with gssapi-with-mic */
SSH_AUTH_STATE_GSSAPI_REQUEST_SENT, SSH_AUTH_STATE_GSSAPI_REQUEST_SENT,
/** We are exchanging tokens until authentication */ /** We are exchanging tokens until authentication */
SSH_AUTH_STATE_GSSAPI_TOKEN, SSH_AUTH_STATE_GSSAPI_TOKEN,
/** We have sent the MIC and expecting to be authenticated */ /** We have sent the MIC and expecting to be authenticated */
SSH_AUTH_STATE_GSSAPI_MIC_SENT, SSH_AUTH_STATE_GSSAPI_MIC_SENT,
/** We have offered a pubkey to check if it is supported */ /** We have offered a pubkey to check if it is supported */
SSH_AUTH_STATE_PUBKEY_OFFER_SENT, SSH_AUTH_STATE_PUBKEY_OFFER_SENT,
/** We have sent pubkey and signature expecting to be authenticated */ /** We have sent pubkey and signature expecting to be authenticated */
SSH_AUTH_STATE_PUBKEY_AUTH_SENT, SSH_AUTH_STATE_PUBKEY_AUTH_SENT,
/** We have sent a password expecting to be authenticated */ /** We have sent a password expecting to be authenticated */
SSH_AUTH_STATE_PASSWORD_AUTH_SENT, SSH_AUTH_STATE_PASSWORD_AUTH_SENT,
/** We have sent a request without auth information (method 'none') */ /** We have sent a request without auth information (method 'none') */
SSH_AUTH_STATE_AUTH_NONE_SENT, SSH_AUTH_STATE_AUTH_NONE_SENT,
/** We have sent the MIC and expecting to be authenticated */
SSH_AUTH_STATE_GSSAPI_KEYEX_MIC_SENT,
}; };
/** @internal /** @internal

View File

@@ -31,6 +31,7 @@ extern "C" {
bignum ssh_make_string_bn(ssh_string string); bignum ssh_make_string_bn(ssh_string string);
ssh_string ssh_make_bignum_string(bignum num); ssh_string ssh_make_bignum_string(bignum num);
ssh_string ssh_make_padded_bignum_string(bignum num, size_t pad_len);
void ssh_print_bignum(const char *which, const_bignum num); void ssh_print_bignum(const char *which, const_bignum num);
#ifdef __cplusplus #ifdef __cplusplus

View File

@@ -54,6 +54,8 @@ struct ssh_bind_struct {
char *pubkey_accepted_key_types; char *pubkey_accepted_key_types;
char* moduli_file; char* moduli_file;
int rsa_min_size; int rsa_min_size;
bool gssapi_key_exchange;
char *gssapi_key_exchange_algs;
}; };
struct ssh_poll_handle_struct *ssh_bind_get_poll(struct ssh_bind_struct struct ssh_poll_handle_struct *ssh_bind_get_poll(struct ssh_bind_struct

View File

@@ -52,6 +52,7 @@ enum ssh_bind_config_opcode_e {
BIND_CFG_MATCH, BIND_CFG_MATCH,
BIND_CFG_PUBKEY_ACCEPTED_KEY_TYPES, BIND_CFG_PUBKEY_ACCEPTED_KEY_TYPES,
BIND_CFG_HOSTKEY_ALGORITHMS, BIND_CFG_HOSTKEY_ALGORITHMS,
BIND_CFG_REQUIRED_RSA_SIZE,
BIND_CFG_MAX /* Keep this one last in the list */ BIND_CFG_MAX /* Keep this one last in the list */
}; };

View File

@@ -74,6 +74,8 @@ ssh_string ssh_buffer_get_ssh_string(ssh_buffer buffer);
uint32_t ssh_buffer_pass_bytes_end(ssh_buffer buffer, uint32_t len); uint32_t ssh_buffer_pass_bytes_end(ssh_buffer buffer, uint32_t len);
uint32_t ssh_buffer_pass_bytes(ssh_buffer buffer, uint32_t len); uint32_t ssh_buffer_pass_bytes(ssh_buffer buffer, uint32_t len);
ssh_buffer ssh_buffer_dup(const ssh_buffer buffer);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -113,6 +113,17 @@ typedef void (*ssh_status_callback) (ssh_session session, float status,
typedef void (*ssh_global_request_callback) (ssh_session session, typedef void (*ssh_global_request_callback) (ssh_session session,
ssh_message message, void *userdata); ssh_message message, void *userdata);
/**
* @brief SSH connect status callback. These are functions that report the
* status of the connection i,e. a function indicating the completed percentage
* of the connection
* steps.
* @param userdata Userdata to be passed to the callback function.
* @param status Percentage of connection status, going from 0.0 to 1.0
* once connection is done.
*/
typedef void (*ssh_connect_status_callback)(void *userdata, float status);
/** /**
* @brief Handles an SSH new channel open X11 request. This happens when the server * @brief Handles an SSH new channel open X11 request. This happens when the server
* sends back an X11 connection attempt. This is a client-side API * sends back an X11 connection attempt. This is a client-side API
@@ -181,7 +192,7 @@ struct ssh_callbacks_struct {
* This function gets called during connection time to indicate the * This function gets called during connection time to indicate the
* percentage of connection steps completed. * percentage of connection steps completed.
*/ */
void (*connect_status_function)(void *userdata, float status); ssh_connect_status_callback connect_status_function;
/** /**
* This function will be called each time a global request is received. * This function will be called each time a global request is received.
*/ */
@@ -209,36 +220,41 @@ typedef struct ssh_callbacks_struct *ssh_callbacks;
* @param user User that wants to authenticate * @param user User that wants to authenticate
* @param password Password used for authentication * @param password Password used for authentication
* @param userdata Userdata to be passed to the callback function. * @param userdata Userdata to be passed to the callback function.
* @returns SSH_AUTH_SUCCESS Authentication is accepted. * @returns `SSH_AUTH_SUCCESS` Authentication is accepted.
* @returns SSH_AUTH_PARTIAL Partial authentication, more authentication means are needed. * @returns `SSH_AUTH_PARTIAL` Partial authentication, more authentication means
* @returns SSH_AUTH_DENIED Authentication failed. * are needed.
* @returns `SSH_AUTH_DENIED` Authentication failed.
*/ */
typedef int (*ssh_auth_password_callback) (ssh_session session, const char *user, const char *password, typedef int (*ssh_auth_password_callback) (ssh_session session, const char *user, const char *password,
void *userdata); void *userdata);
/** /**
* @brief SSH authentication callback. Tries to authenticates user with the "none" method * @brief SSH authentication callback. Tries to authenticates user with the
* which is anonymous or passwordless. * "none" method which is anonymous or passwordless.
* @param session Current session handler * @param session Current session handler
* @param user User that wants to authenticate * @param user User that wants to authenticate
* @param userdata Userdata to be passed to the callback function. * @param userdata Userdata to be passed to the callback function.
* @returns SSH_AUTH_SUCCESS Authentication is accepted. * @returns `SSH_AUTH_SUCCESS` Authentication is accepted.
* @returns SSH_AUTH_PARTIAL Partial authentication, more authentication means are needed. * @returns `SSH_AUTH_PARTIAL` Partial authentication, more authentication means
* @returns SSH_AUTH_DENIED Authentication failed. * are needed.
* @returns `SSH_AUTH_DENIED` Authentication failed.
*/ */
typedef int (*ssh_auth_none_callback) (ssh_session session, const char *user, void *userdata); typedef int (*ssh_auth_none_callback) (ssh_session session, const char *user, void *userdata);
/** /**
* @brief SSH authentication callback. Tries to authenticates user with the "gssapi-with-mic" method * @brief SSH authentication callback. Tries to authenticates user with the
* "gssapi-with-mic" method
* @param session Current session handler * @param session Current session handler
* @param user Username of the user (can be spoofed) * @param user Username of the user (can be spoofed)
* @param principal Authenticated principal of the user, including realm. * @param principal Authenticated principal of the user, including realm.
* @param userdata Userdata to be passed to the callback function. * @param userdata Userdata to be passed to the callback function.
* @returns SSH_AUTH_SUCCESS Authentication is accepted. * @returns `SSH_AUTH_SUCCESS` Authentication is accepted.
* @returns SSH_AUTH_PARTIAL Partial authentication, more authentication means are needed. * @returns `SSH_AUTH_PARTIAL` Partial authentication, more authentication means
* @returns SSH_AUTH_DENIED Authentication failed. * are needed.
* @warning Implementations should verify that parameter user matches in some way the principal. * @returns `SSH_AUTH_DENIED` Authentication failed.
* user and principal can be different. Only the latter is guaranteed to be safe. * @warning Implementations should verify that parameter user matches in some
* way the principal. user and principal can be different. Only the latter is
* guaranteed to be safe.
*/ */
typedef int (*ssh_auth_gssapi_mic_callback) (ssh_session session, const char *user, const char *principal, typedef int (*ssh_auth_gssapi_mic_callback) (ssh_session session, const char *user, const char *principal,
void *userdata); void *userdata);
@@ -248,17 +264,29 @@ typedef int (*ssh_auth_gssapi_mic_callback) (ssh_session session, const char *us
* @param session Current session handler * @param session Current session handler
* @param user User that wants to authenticate * @param user User that wants to authenticate
* @param pubkey public key used for authentication * @param pubkey public key used for authentication
* @param signature_state SSH_PUBLICKEY_STATE_NONE if the key is not signed (simple public key probe), * @param signature_state `SSH_PUBLICKEY_STATE_NONE` if the key is not signed
* SSH_PUBLICKEY_STATE_VALID if the signature is valid. Others values should be * (simple public key probe), `SSH_PUBLICKEY_STATE_VALID` if the signature is
* replied with a SSH_AUTH_DENIED. * valid. Others values should be replied with a `SSH_AUTH_DENIED`.
* @param userdata Userdata to be passed to the callback function. * @param userdata Userdata to be passed to the callback function.
* @returns SSH_AUTH_SUCCESS Authentication is accepted. * @returns `SSH_AUTH_SUCCESS` Authentication is accepted.
* @returns SSH_AUTH_PARTIAL Partial authentication, more authentication means are needed. * @returns `SSH_AUTH_PARTIAL` Partial authentication, more authentication means
* @returns SSH_AUTH_DENIED Authentication failed. * are needed.
* @returns `SSH_AUTH_DENIED` Authentication failed.
*/ */
typedef int (*ssh_auth_pubkey_callback) (ssh_session session, const char *user, struct ssh_key_struct *pubkey, typedef int (*ssh_auth_pubkey_callback) (ssh_session session, const char *user, struct ssh_key_struct *pubkey,
char signature_state, void *userdata); char signature_state, void *userdata);
/**
* @brief SSH authentication callback. Tries to authenticates user with the "keyboard-interactive" method
* @param message Current message
* @param session Current session handler
* @param userdata Userdata to be passed to the callback function.
* @returns SSH_AUTH_SUCCESS Authentication is accepted.
* @returns SSH_AUTH_INFO More info required for authentication.
* @returns SSH_AUTH_PARTIAL Partial authentication, more authentication means are needed.
* @returns SSH_AUTH_DENIED Authentication failed.
*/
typedef int (*ssh_auth_kbdint_callback) (ssh_message message, ssh_session session, void *userdata);
/** /**
* @brief Handles an SSH service request * @brief Handles an SSH service request
@@ -268,7 +296,6 @@ typedef int (*ssh_auth_pubkey_callback) (ssh_session session, const char *user,
* @returns 0 if the request is to be allowed * @returns 0 if the request is to be allowed
* @returns -1 if the request should not be allowed * @returns -1 if the request should not be allowed
*/ */
typedef int (*ssh_service_request_callback) (ssh_session session, const char *service, void *userdata); typedef int (*ssh_service_request_callback) (ssh_session session, const char *service, void *userdata);
/** /**
@@ -281,7 +308,7 @@ typedef int (*ssh_service_request_callback) (ssh_session session, const char *se
*/ */
typedef ssh_channel (*ssh_channel_open_request_session_callback) (ssh_session session, void *userdata); typedef ssh_channel (*ssh_channel_open_request_session_callback) (ssh_session session, void *userdata);
/* /**
* @brief handle the beginning of a GSSAPI authentication, server side. * @brief handle the beginning of a GSSAPI authentication, server side.
* Callback should select the oid and also acquire the server credential. * Callback should select the oid and also acquire the server credential.
* @param session current session handler * @param session current session handler
@@ -296,35 +323,57 @@ typedef ssh_channel (*ssh_channel_open_request_session_callback) (ssh_session se
typedef ssh_string (*ssh_gssapi_select_oid_callback) (ssh_session session, const char *user, typedef ssh_string (*ssh_gssapi_select_oid_callback) (ssh_session session, const char *user,
int n_oid, ssh_string *oids, void *userdata); int n_oid, ssh_string *oids, void *userdata);
/* /**
* @brief handle the negotiation of a security context, server side. * @brief handle the negotiation of a security context, server side.
* @param session current session handler * @param session current session handler
* @param[in] input_token input token provided by client * @param[in] input_token input token provided by client
* @param[out] output_token output of the gssapi accept_sec_context method, * @param[out] output_token output of the gssapi accept_sec_context method,
* NULL after completion. * NULL after completion.
* @returns SSH_OK if the token was generated correctly or accept_sec_context * @returns `SSH_OK` if the token was generated correctly or accept_sec_context
* returned GSS_S_COMPLETE * returned GSS_S_COMPLETE
* @returns SSH_ERROR in case of error * @returns `SSH_ERROR` in case of error
* @warning It is not necessary to fill this callback in if libssh is linked * @warning It is not necessary to fill this callback in if libssh is linked
* with libgssapi. * with libgssapi.
*/ */
typedef int (*ssh_gssapi_accept_sec_ctx_callback) (ssh_session session, typedef int (*ssh_gssapi_accept_sec_ctx_callback) (ssh_session session,
ssh_string input_token, ssh_string *output_token, void *userdata); ssh_string input_token, ssh_string *output_token, void *userdata);
/* /**
* @brief Verify and authenticates a MIC, server side. * @brief Verify and authenticates a MIC, server side.
* @param session current session handler * @param session current session handler
* @param[in] mic input mic to be verified provided by client * @param[in] mic input mic to be verified provided by client
* @param[in] mic_buffer buffer of data to be signed. * @param[in] mic_buffer buffer of data to be signed.
* @param[in] mic_buffer_size size of mic_buffer * @param[in] mic_buffer_size size of mic_buffer
* @returns SSH_OK if the MIC was authenticated correctly * @returns `SSH_OK` if the MIC was authenticated correctly
* @returns SSH_ERROR in case of error * @returns `SSH_ERROR` in case of error
* @warning It is not necessary to fill this callback in if libssh is linked * @warning It is not necessary to fill this callback in if libssh is linked
* with libgssapi. * with libgssapi.
*/ */
typedef int (*ssh_gssapi_verify_mic_callback) (ssh_session session, typedef int (*ssh_gssapi_verify_mic_callback) (ssh_session session,
ssh_string mic, void *mic_buffer, size_t mic_buffer_size, void *userdata); ssh_string mic, void *mic_buffer, size_t mic_buffer_size, void *userdata);
/**
* @brief Handles an SSH new channel open "direct-tcpip" request. This
* happens when the client forwards an incoming TCP connection on a port it
* wants to forward to the destination. This is a server-side API
* @param session current session handler
* @param destination_address the address that the TCP connection connected to
* @param destination_port the port that the TCP connection connected to
* @param originator_address the originator IP address
* @param originator_port the originator port
* @param userdata Userdata to be passed to the callback function.
* @returns a valid ssh_channel handle if the request is to be allowed
* @returns NULL if the request should not be allowed
* @warning The channel pointer returned by this callback must be closed by the
* application.
*/
typedef ssh_channel (*ssh_channel_open_request_direct_tcpip_callback)(
ssh_session session,
const char *destination_address,
int destination_port,
const char *originator_address,
int originator_port,
void *userdata);
/** /**
* This structure can be used to implement a libssh server, with appropriate callbacks. * This structure can be used to implement a libssh server, with appropriate callbacks.
@@ -372,9 +421,21 @@ struct ssh_server_callbacks_struct {
/** This function will be called when a gssapi token comes in. /** This function will be called when a gssapi token comes in.
*/ */
ssh_gssapi_accept_sec_ctx_callback gssapi_accept_sec_ctx_function; ssh_gssapi_accept_sec_ctx_callback gssapi_accept_sec_ctx_function;
/* This function will be called when a MIC needs to be verified. /** This function will be called when a MIC needs to be verified.
*/ */
ssh_gssapi_verify_mic_callback gssapi_verify_mic_function; ssh_gssapi_verify_mic_callback gssapi_verify_mic_function;
/**
* This function will be called when an incoming "direct-tcpip"
* request is received.
*/
ssh_channel_open_request_direct_tcpip_callback
channel_open_request_direct_tcpip_function;
/** This function gets called when a client tries to authenticate through
* keyboard interactive method.
*/
ssh_auth_kbdint_callback auth_kbdint_function;
}; };
typedef struct ssh_server_callbacks_struct *ssh_server_callbacks; typedef struct ssh_server_callbacks_struct *ssh_server_callbacks;
@@ -400,7 +461,7 @@ typedef struct ssh_server_callbacks_struct *ssh_server_callbacks;
* *
* @param cb The callback structure itself. * @param cb The callback structure itself.
* *
* @return SSH_OK on success, SSH_ERROR on error. * @return `SSH_OK` on success, `SSH_ERROR` on error.
*/ */
LIBSSH_API int ssh_set_server_callbacks(ssh_session session, ssh_server_callbacks cb); LIBSSH_API int ssh_set_server_callbacks(ssh_session session, ssh_server_callbacks cb);
@@ -531,14 +592,17 @@ typedef struct ssh_socket_callbacks_struct *ssh_socket_callbacks;
} \ } \
} while(0) } while(0)
/** @brief Prototype for a packet callback, to be called when a new packet arrives /** @brief Prototype for a packet callback, to be called when a new packet
* arrives
* @param session The current session of the packet * @param session The current session of the packet
* @param type packet type (see ssh2.h) * @param type packet type (see ssh2.h)
* @param packet buffer containing the packet, excluding size, type and padding fields * @param packet buffer containing the packet, excluding size, type and padding
* fields
* @param user user argument to the callback * @param user user argument to the callback
* and are called each time a packet shows up * and are called each time a packet shows up
* @returns SSH_PACKET_USED Packet was parsed and used * @returns `SSH_PACKET_USED` Packet was parsed and used
* @returns SSH_PACKET_NOT_USED Packet was not used or understood, processing must continue * @returns `SSH_PACKET_NOT_USED` Packet was not used or understood, processing
* must continue
*/ */
typedef int (*ssh_packet_callback) (ssh_session session, uint8_t type, ssh_buffer packet, void *user); typedef int (*ssh_packet_callback) (ssh_session session, uint8_t type, ssh_buffer packet, void *user);
@@ -597,7 +661,7 @@ typedef struct ssh_packet_callbacks_struct *ssh_packet_callbacks;
* *
* @param cb The callback structure itself. * @param cb The callback structure itself.
* *
* @return SSH_OK on success, SSH_ERROR on error. * @return `SSH_OK` on success, `SSH_ERROR` on error.
*/ */
LIBSSH_API int ssh_set_callbacks(ssh_session session, ssh_callbacks cb); LIBSSH_API int ssh_set_callbacks(ssh_session session, ssh_callbacks cb);
@@ -949,7 +1013,7 @@ typedef struct ssh_channel_callbacks_struct *ssh_channel_callbacks;
* *
* @param cb The callback structure itself. * @param cb The callback structure itself.
* *
* @return SSH_OK on success, SSH_ERROR on error. * @return `SSH_OK` on success, `SSH_ERROR` on error.
* @warning this function will not replace existing callbacks but set the * @warning this function will not replace existing callbacks but set the
* new one atop of them. * new one atop of them.
*/ */
@@ -968,7 +1032,7 @@ LIBSSH_API int ssh_set_channel_callbacks(ssh_channel channel,
* *
* @param cb The callback structure itself. * @param cb The callback structure itself.
* *
* @return SSH_OK on success, SSH_ERROR on error. * @return `SSH_OK` on success, `SSH_ERROR` on error.
* *
* @see ssh_set_channel_callbacks * @see ssh_set_channel_callbacks
*/ */
@@ -985,7 +1049,7 @@ LIBSSH_API int ssh_add_channel_callbacks(ssh_channel channel,
* *
* @param cb The callback structure to remove * @param cb The callback structure to remove
* *
* @returns SSH_OK on success, SSH_ERROR on error. * @returns `SSH_OK` on success, `SSH_ERROR` on error.
*/ */
LIBSSH_API int ssh_remove_channel_callbacks(ssh_channel channel, LIBSSH_API int ssh_remove_channel_callbacks(ssh_channel channel,
ssh_channel_callbacks cb); ssh_channel_callbacks cb);
@@ -1018,7 +1082,7 @@ struct ssh_threads_callbacks_struct {
* @param[in] cb A pointer to a ssh_threads_callbacks_struct structure, which * @param[in] cb A pointer to a ssh_threads_callbacks_struct structure, which
* contains the different callbacks to be set. * contains the different callbacks to be set.
* *
* @returns Always returns SSH_OK. * @returns Always returns `SSH_OK`.
* *
* @see ssh_threads_callbacks_struct * @see ssh_threads_callbacks_struct
* @see SSH_THREADS_PTHREAD * @see SSH_THREADS_PTHREAD
@@ -1115,6 +1179,177 @@ struct ssh_jump_callbacks_struct {
ssh_jump_authenticate_callback authenticate; ssh_jump_authenticate_callback authenticate;
}; };
/* Security key callbacks */
/*
* Forward declarations for structs that have been defined in sk_api.h.
* If you need to work with the fields inside them, please include
* libssh/sk_api.h
*/
struct sk_enroll_response;
struct sk_sign_response;
struct sk_resident_key;
struct sk_option;
#define LIBSSH_SK_API_VERSION_MAJOR 0x000a0000
/**
* @brief FIDO2/U2F SK API version callback.
*
* Returns the version of the FIDO2/U2F API that the callbacks implement.
* This callback allows custom callback implementations to specify their
* SK API version for compatibility checking with libssh's security key
* interface.
*
* @details Version compatibility is determined by comparing the major version
* portion (upper 16 bits) of the returned value with SSH_SK_VERSION_MAJOR.
*
* For compatibility, implementations should return a version where:
* (returned_version & SSH_SK_VERSION_MAJOR_MASK) == SSH_SK_VERSION_MAJOR
*
* This ensures that the callbacks' SK API matches the major version expected
* by libssh, while allowing minor version differences for backward
* compatibility.
*
* @see LIBSSH_SK_API_VERSION_MAJOR Current expected major API version
* @see SSH_SK_VERSION_MAJOR_MASK Mask for extracting major version (0xffff0000)
*/
typedef uint32_t (*sk_api_version_callback)(void);
/**
* @brief FIDO2/U2F key enrollment callback.
*
* Enrolls a new FIDO2/U2F security key credential (private key generation).
* This callback handles the creation of new FIDO2/U2F credentials, including
* both resident and non-resident keys.
*
* @param[in] alg The cryptographic algorithm to use
* @param[in] challenge Random challenge data for enrollment
* @param[in] challenge_len Length of the challenge data
* @param[in] application Application identifier (relying party ID)
* @param[in] flags Enrollment flags
* @param[in] pin PIN for user verification (may be NULL)
* @param[in] options Array of enrollment options (device path, user ID, etc.)
* @param[out] enroll_response Enrollment response containing public key,
* key handle, signature, and attestation data
*
* @returns SSH_OK on success, SSH_SK_ERR_* codes on failure.
*/
typedef int (*sk_enroll_callback)(uint32_t alg,
const uint8_t *challenge,
size_t challenge_len,
const char *application,
uint8_t flags,
const char *pin,
struct sk_option **options,
struct sk_enroll_response **enroll_response);
/**
* @brief FIDO2/U2F security key signing callback.
*
* Signs data using a FIDO2 security key credential. This callback performs
* cryptographic signing operations using previously enrolled FIDO2/U2F
* credentials.
*
* @param[in] alg The cryptographic algorithm used by the key
* @param[in] data Data to be signed
* @param[in] data_len Length of the data to sign
* @param[in] application Application identifier (relying party ID)
* @param[in] key_handle Key handle identifying the credential
* @param[in] key_handle_len Length of the key handle
* @param[in] flags Signing flags
* @param[in] pin PIN for user verification (may be NULL)
* @param[in] options Array of signing options (device path, etc.)
* @param[out] sign_response Signature response containing signature data,
* flags, and counter information
*
* @returns SSH_OK on success, SSH_SK_ERR_* codes on failure.
*/
typedef int (*sk_sign_callback)(uint32_t alg,
const uint8_t *data,
size_t data_len,
const char *application,
const uint8_t *key_handle,
size_t key_handle_len,
uint8_t flags,
const char *pin,
struct sk_option **options,
struct sk_sign_response **sign_response);
/**
* @brief FIDO2 security key resident keys loading callback.
*
* Enumerates and loads all resident keys (discoverable credentials) stored
* on FIDO2 devices. Resident keys are credentials stored directly on
* the device itself and can be discovered without prior knowledge
* of key handles.
*
* @param[in] pin PIN for accessing resident keys (required for most operations)
* @param[in] options Array of options (device path, etc.)
* @param[out] resident_keys Array of resident key structures containing key
* data, application IDs, user information, and metadata
* @param[out] num_keys_found Number of resident keys found and loaded
*
* @returns SSH_OK on success, SSH_SK_ERR_* codes on failure.
*/
typedef int (*sk_load_resident_keys_callback)(
const char *pin,
struct sk_option **options,
struct sk_resident_key ***resident_keys,
size_t *num_keys_found);
/**
* @brief FIDO2/U2F security key callbacks structure.
*
* This structure contains callbacks for FIDO2/U2F operations.
* It allows applications to provide custom implementations of FIDO2/U2F
* operations to override the default libfido2-based implementation.
*
* @warning These callbacks will only be called if libssh was built with
* FIDO2/U2F support enabled. (WITH_FIDO2 = ON).
*/
struct ssh_sk_callbacks_struct {
/** DON'T SET THIS use ssh_callbacks_init() instead. */
size_t size;
/**
* This callback returns the SK API version used by the callback
* implementation.
*
* @see sk_api_version_callback for detailed documentation
*/
sk_api_version_callback api_version;
/**
* This callback enrolls a new FIDO2/U2F credential, generating
* a new key pair and optionally storing it on the device itself
* (resident keys).
*
* @see sk_enroll_callback for detailed documentation
*/
sk_enroll_callback enroll;
/**
* This callback performs cryptographic signing operations using a
* previously enrolled FIDO2/U2F credential.
*
* @see sk_sign_callback for detailed documentation
*/
sk_sign_callback sign;
/**
* This callback enumerates and loads all resident keys (discoverable
* credentials) stored on the FIDO2 device.
*
* @see sk_load_resident_keys_callback for detailed documentation
*/
sk_load_resident_keys_callback load_resident_keys;
};
typedef struct ssh_sk_callbacks_struct *ssh_sk_callbacks;
const struct ssh_sk_callbacks_struct *ssh_sk_get_default_callbacks(void);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -24,6 +24,7 @@
#ifndef LIBSSH_CONFIG_H_ #ifndef LIBSSH_CONFIG_H_
#define LIBSSH_CONFIG_H_ #define LIBSSH_CONFIG_H_
#include "libssh/libssh.h"
enum ssh_config_opcode_e { enum ssh_config_opcode_e {
/* Unknown opcode */ /* Unknown opcode */
@@ -66,7 +67,14 @@ enum ssh_config_opcode_e {
SOC_CONTROLMASTER, SOC_CONTROLMASTER,
SOC_CONTROLPATH, SOC_CONTROLPATH,
SOC_CERTIFICATE, SOC_CERTIFICATE,
SOC_REQUIRED_RSA_SIZE,
SOC_ADDRESSFAMILY,
SOC_GSSAPIKEYEXCHANGE,
SOC_GSSAPIKEXALGORITHMS,
SOC_MAX /* Keep this one last in the list */ SOC_MAX /* Keep this one last in the list */
}; };
enum ssh_config_opcode_e ssh_config_get_opcode(char *keyword);
int ssh_config_parse_line_cli(ssh_session session, const char *line);
#endif /* LIBSSH_CONFIG_H_ */ #endif /* LIBSSH_CONFIG_H_ */

View File

@@ -45,10 +45,11 @@
#ifdef HAVE_OPENSSL_ECDH_H #ifdef HAVE_OPENSSL_ECDH_H
#include <openssl/ecdh.h> #include <openssl/ecdh.h>
#endif #endif
#include "libssh/curve25519.h"
#include "libssh/dh.h" #include "libssh/dh.h"
#include "libssh/ecdh.h" #include "libssh/ecdh.h"
#include "libssh/kex.h" #include "libssh/kex.h"
#include "libssh/curve25519.h" #include "libssh/sntrup761.h"
#define DIGEST_MAX_LEN 64 #define DIGEST_MAX_LEN 64
@@ -56,32 +57,52 @@
#define AES_GCM_IVLEN 12 #define AES_GCM_IVLEN 12
enum ssh_key_exchange_e { enum ssh_key_exchange_e {
/* diffie-hellman-group1-sha1 */ /* diffie-hellman-group1-sha1 */
SSH_KEX_DH_GROUP1_SHA1=1, SSH_KEX_DH_GROUP1_SHA1 = 1,
/* diffie-hellman-group14-sha1 */ /* diffie-hellman-group14-sha1 */
SSH_KEX_DH_GROUP14_SHA1, SSH_KEX_DH_GROUP14_SHA1,
#ifdef WITH_GEX #ifdef WITH_GEX
/* diffie-hellman-group-exchange-sha1 */ /* diffie-hellman-group-exchange-sha1 */
SSH_KEX_DH_GEX_SHA1, SSH_KEX_DH_GEX_SHA1,
/* diffie-hellman-group-exchange-sha256 */ /* diffie-hellman-group-exchange-sha256 */
SSH_KEX_DH_GEX_SHA256, SSH_KEX_DH_GEX_SHA256,
#endif /* WITH_GEX */ #endif /* WITH_GEX */
/* ecdh-sha2-nistp256 */ /* ecdh-sha2-nistp256 */
SSH_KEX_ECDH_SHA2_NISTP256, SSH_KEX_ECDH_SHA2_NISTP256,
/* ecdh-sha2-nistp384 */ /* ecdh-sha2-nistp384 */
SSH_KEX_ECDH_SHA2_NISTP384, SSH_KEX_ECDH_SHA2_NISTP384,
/* ecdh-sha2-nistp521 */ /* ecdh-sha2-nistp521 */
SSH_KEX_ECDH_SHA2_NISTP521, SSH_KEX_ECDH_SHA2_NISTP521,
/* curve25519-sha256@libssh.org */ /* curve25519-sha256@libssh.org */
SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG, SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG,
/* curve25519-sha256 */ /* curve25519-sha256 */
SSH_KEX_CURVE25519_SHA256, SSH_KEX_CURVE25519_SHA256,
/* diffie-hellman-group16-sha512 */ /* diffie-hellman-group16-sha512 */
SSH_KEX_DH_GROUP16_SHA512, SSH_KEX_DH_GROUP16_SHA512,
/* diffie-hellman-group18-sha512 */ /* diffie-hellman-group18-sha512 */
SSH_KEX_DH_GROUP18_SHA512, SSH_KEX_DH_GROUP18_SHA512,
/* diffie-hellman-group14-sha256 */ /* diffie-hellman-group14-sha256 */
SSH_KEX_DH_GROUP14_SHA256, SSH_KEX_DH_GROUP14_SHA256,
/* sntrup761x25519-sha512@openssh.com */
SSH_KEX_SNTRUP761X25519_SHA512_OPENSSH_COM,
/* sntrup761x25519-sha512 */
SSH_KEX_SNTRUP761X25519_SHA512,
/* mlkem768x25519-sha256 */
SSH_KEX_MLKEM768X25519_SHA256,
/* mlkem768nistp256-sha256 */
SSH_KEX_MLKEM768NISTP256_SHA256,
#ifdef HAVE_MLKEM1024
/* mlkem1024nistp384-sha384 */
SSH_KEX_MLKEM1024NISTP384_SHA384,
#endif /* HAVE_MLKEM1024 */
/* gss-group14-sha256-* */
SSH_GSS_KEX_DH_GROUP14_SHA256,
/* gss-group16-sha512-* */
SSH_GSS_KEX_DH_GROUP16_SHA512,
/* gss-nistp256-sha256-* */
SSH_GSS_KEX_ECDH_NISTP256_SHA256,
/* gss-curve25519-sha256-* */
SSH_GSS_KEX_CURVE25519_SHA256,
}; };
enum ssh_cipher_e { enum ssh_cipher_e {
@@ -105,6 +126,9 @@ struct dh_ctx;
struct ssh_crypto_struct { struct ssh_crypto_struct {
bignum shared_secret; bignum shared_secret;
ssh_string hybrid_client_init;
ssh_string hybrid_server_reply;
ssh_string hybrid_shared_secret;
struct dh_ctx *dh_ctx; struct dh_ctx *dh_ctx;
#ifdef WITH_GEX #ifdef WITH_GEX
size_t dh_pmin; size_t dh_pn; size_t dh_pmax; /* preferred group parameters */ size_t dh_pmin; size_t dh_pn; size_t dh_pmax; /* preferred group parameters */
@@ -125,9 +149,28 @@ struct ssh_crypto_struct {
ssh_string ecdh_server_pubkey; ssh_string ecdh_server_pubkey;
#endif #endif
#ifdef HAVE_CURVE25519 #ifdef HAVE_CURVE25519
#ifdef HAVE_LIBCRYPTO
EVP_PKEY *curve25519_privkey;
#elif defined(HAVE_GCRYPT_CURVE25519)
gcry_sexp_t curve25519_privkey;
#else
ssh_curve25519_privkey curve25519_privkey; ssh_curve25519_privkey curve25519_privkey;
#endif
ssh_curve25519_pubkey curve25519_client_pubkey; ssh_curve25519_pubkey curve25519_client_pubkey;
ssh_curve25519_pubkey curve25519_server_pubkey; ssh_curve25519_pubkey curve25519_server_pubkey;
#endif
#ifdef HAVE_OPENSSL_MLKEM
EVP_PKEY *mlkem_privkey;
#else
unsigned char *mlkem_privkey;
size_t mlkem_privkey_len;
#endif
ssh_string mlkem_client_pubkey;
ssh_string mlkem_ciphertext;
#ifdef HAVE_SNTRUP761
ssh_sntrup761_privkey sntrup761_privkey;
ssh_sntrup761_pubkey sntrup761_client_pubkey;
ssh_sntrup761_ciphertext sntrup761_ciphertext;
#endif #endif
ssh_string dh_server_signature; /* information used by dh_handshake. */ ssh_string dh_server_signature; /* information used by dh_handshake. */
size_t session_id_len; size_t session_id_len;
@@ -223,9 +266,8 @@ int sshkdf_derive_key(struct ssh_crypto_struct *crypto,
size_t requested_len); size_t requested_len);
int secure_memcmp(const void *s1, const void *s2, size_t n); int secure_memcmp(const void *s1, const void *s2, size_t n);
#if defined(HAVE_LIBCRYPTO) && !defined(WITH_PKCS11_PROVIDER)
ENGINE *pki_get_engine(void); void compress_cleanup(struct ssh_crypto_struct *crypto);
#endif /* HAVE_LIBCRYPTO */
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@@ -50,6 +50,10 @@ int crypto_scalarmult(unsigned char *q, const unsigned char *n, const unsigned c
typedef unsigned char ssh_curve25519_pubkey[CURVE25519_PUBKEY_SIZE]; typedef unsigned char ssh_curve25519_pubkey[CURVE25519_PUBKEY_SIZE];
typedef unsigned char ssh_curve25519_privkey[CURVE25519_PRIVKEY_SIZE]; typedef unsigned char ssh_curve25519_privkey[CURVE25519_PRIVKEY_SIZE];
int ssh_curve25519_init(ssh_session session);
int curve25519_do_create_k(ssh_session session, ssh_curve25519_pubkey k);
int ssh_curve25519_create_k(ssh_session session, ssh_curve25519_pubkey k);
int ssh_curve25519_build_k(ssh_session session);
int ssh_client_curve25519_init(ssh_session session); int ssh_client_curve25519_init(ssh_session session);
void ssh_client_curve25519_remove_callbacks(ssh_session session); void ssh_client_curve25519_remove_callbacks(ssh_session session);

View File

@@ -48,6 +48,7 @@ extern "C" {
extern struct ssh_packet_callbacks_struct ssh_ecdh_client_callbacks; extern struct ssh_packet_callbacks_struct ssh_ecdh_client_callbacks;
/* Backend-specific functions. */ /* Backend-specific functions. */
int ssh_ecdh_init(ssh_session session);
int ssh_client_ecdh_init(ssh_session session); int ssh_client_ecdh_init(ssh_session session);
void ssh_client_ecdh_remove_callbacks(ssh_session session); void ssh_client_ecdh_remove_callbacks(ssh_session session);
int ecdh_build_k(ssh_session session); int ecdh_build_k(ssh_session session);

View File

@@ -29,12 +29,41 @@
* @{ * @{
*/ */
/** @internal
* @brief ED25519 public key.
* Ed25519 public key consist of 32 bytes.
*/
#define ED25519_PK_LEN 32 #define ED25519_PK_LEN 32
/** @internal
* @brief ED25519 secret key.
* Ed25519 secret key consist of 64 bytes.
*/
#define ED25519_SK_LEN 64 #define ED25519_SK_LEN 64
/** @internal
* @brief ED25519 signature.
* Ed25519 signatures consist of 64 bytes.
*/
#define ED25519_SIG_LEN 64 #define ED25519_SIG_LEN 64
/** @internal
* @brief ED25519 public key.
* The public key consists of 32 bytes and can be used for signature
* verification.
*/
typedef uint8_t ed25519_pubkey[ED25519_PK_LEN]; typedef uint8_t ed25519_pubkey[ED25519_PK_LEN];
/** @internal
* @brief ED25519 private key.
* The private key consists of 64 bytes and should be kept secret.
*/
typedef uint8_t ed25519_privkey[ED25519_SK_LEN]; typedef uint8_t ed25519_privkey[ED25519_SK_LEN];
/** @internal
* @brief ED25519 signature.
* Ed25519 signatures consists of 64 bytes.
*/
typedef uint8_t ed25519_signature[ED25519_SIG_LEN]; typedef uint8_t ed25519_signature[ED25519_SIG_LEN];
#ifdef __cplusplus #ifdef __cplusplus
@@ -46,7 +75,7 @@ extern "C" {
* @param[out] pk generated public key * @param[out] pk generated public key
* @param[out] sk generated secret key * @param[out] sk generated secret key
* @return 0 on success, -1 on error. * @return 0 on success, -1 on error.
* */ */
int crypto_sign_ed25519_keypair(ed25519_pubkey pk, ed25519_privkey sk); int crypto_sign_ed25519_keypair(ed25519_pubkey pk, ed25519_privkey sk);
/** @internal /** @internal

View File

@@ -29,6 +29,11 @@
/* all OID begin with the tag identifier + length */ /* all OID begin with the tag identifier + length */
#define SSH_OID_TAG 06 #define SSH_OID_TAG 06
#define GSSAPI_KEY_EXCHANGE_SUPPORTED "gss-group14-sha256-," \
"gss-group16-sha512-," \
"gss-nistp256-sha256-," \
"gss-curve25519-sha256-"
typedef struct ssh_gssapi_struct *ssh_gssapi; typedef struct ssh_gssapi_struct *ssh_gssapi;
#ifdef __cplusplus #ifdef __cplusplus
@@ -44,14 +49,12 @@ enum ssh_gssapi_state_e {
struct ssh_gssapi_struct{ struct ssh_gssapi_struct{
enum ssh_gssapi_state_e state; /* current state */ enum ssh_gssapi_state_e state; /* current state */
struct gss_OID_desc_struct mech; /* mechanism being elected for auth */
gss_cred_id_t server_creds; /* credentials of server */ gss_cred_id_t server_creds; /* credentials of server */
gss_cred_id_t client_creds; /* creds delegated by the client */ gss_cred_id_t client_creds; /* creds delegated by the client */
gss_ctx_id_t ctx; /* the authentication context */ gss_ctx_id_t ctx; /* the authentication context */
gss_name_t client_name; /* Identity of the client */ gss_name_t client_name; /* Identity of the client */
char *user; /* username of client */ char *user; /* username of client */
char *canonic_user; /* canonic form of the client's username */ char *canonic_user; /* canonic form of the client's username */
char *service; /* name of the service */
struct { struct {
gss_name_t server_name; /* identity of server */ gss_name_t server_name; /* identity of server */
OM_uint32 flags; /* flags used for init context */ OM_uint32 flags; /* flags used for init context */
@@ -65,6 +68,7 @@ struct ssh_gssapi_struct{
int ssh_gssapi_handle_userauth(ssh_session session, const char *user, uint32_t n_oid, ssh_string *oids); int ssh_gssapi_handle_userauth(ssh_session session, const char *user, uint32_t n_oid, ssh_string *oids);
SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_token_server); SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_token_server);
SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_mic); SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_mic);
int ssh_gssapi_server_oids(gss_OID_set *selected);
#endif /* WITH_SERVER */ #endif /* WITH_SERVER */
SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_token); SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_token);
@@ -76,7 +80,20 @@ int ssh_gssapi_init(ssh_session session);
void ssh_gssapi_log_error(int verb, const char *msg_a, int maj_stat, int min_stat); void ssh_gssapi_log_error(int verb, const char *msg_a, int maj_stat, int min_stat);
int ssh_gssapi_auth_mic(ssh_session session); int ssh_gssapi_auth_mic(ssh_session session);
void ssh_gssapi_free(ssh_session session); void ssh_gssapi_free(ssh_session session);
int ssh_gssapi_client_identity(ssh_session session, gss_OID_set *valid_oids);
char *ssh_gssapi_name_to_char(gss_name_t name); char *ssh_gssapi_name_to_char(gss_name_t name);
int ssh_gssapi_import_name(struct ssh_gssapi_struct *gssapi, const char *host);
OM_uint32 ssh_gssapi_init_ctx(struct ssh_gssapi_struct *gssapi,
gss_buffer_desc *input_token,
gss_buffer_desc *output_token,
OM_uint32 *ret_flags);
char *ssh_gssapi_oid_hash(ssh_string oid);
char *ssh_gssapi_kex_mechs(ssh_session session);
int ssh_gssapi_check_client_config(ssh_session session);
ssh_buffer ssh_gssapi_build_mic(ssh_session session, const char *context);
int ssh_gssapi_auth_keyex_mic(ssh_session session,
gss_buffer_desc *mic_token_buf);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@@ -0,0 +1,51 @@
/*
* This file is part of the SSH Library
*
* Copyright (c) 2025 by Red Hat, Inc.
*
* Author: Sahana Prasad <sahana@redhat.com>
* Author: Pavol Žáčik <pzacik@redhat.com>
* Author: Claude (Anthropic)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef HYBRID_MLKEM_H_
#define HYBRID_MLKEM_H_
#include "libssh/mlkem.h"
#include "libssh/wrapper.h"
#include "config.h"
#ifdef __cplusplus
extern "C" {
#endif
#define NISTP256_SHARED_SECRET_SIZE 32
#define NISTP384_SHARED_SECRET_SIZE 48
int ssh_client_hybrid_mlkem_init(ssh_session session);
void ssh_client_hybrid_mlkem_remove_callbacks(ssh_session session);
#ifdef WITH_SERVER
void ssh_server_hybrid_mlkem_init(ssh_session session);
#endif /* WITH_SERVER */
#ifdef __cplusplus
}
#endif
#endif /* HYBRID_MLKEM_H_ */

36
include/libssh/kex-gss.h Normal file
View File

@@ -0,0 +1,36 @@
/*
* kex-gss.h - GSSAPI key exchange
*
* This file is part of the SSH Library
*
* Copyright (c) 2024 by Gauravsingh Sisodia <xaerru@gmail.com>
*
* The SSH Library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or (at your
* option) any later version.
*
* The SSH Library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the SSH Library; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
* MA 02111-1307, USA.
*/
#ifndef KEX_GSS_H_
#define KEX_GSS_H_
#include "config.h"
#ifdef WITH_GSSAPI
int ssh_client_gss_kex_init(ssh_session session);
void ssh_server_gss_kex_init(ssh_session session);
int ssh_server_gss_kex_process_init(ssh_session session, ssh_buffer packet);
void ssh_client_gss_kex_remove_callbacks(ssh_session session);
void ssh_client_gss_kex_remove_callback_hostkey(ssh_session session);
#endif /* WITH_GSSAPI */
#endif /* KEX_GSS_H_ */

View File

@@ -31,6 +31,9 @@ struct ssh_kex_struct {
char *methods[SSH_KEX_METHODS]; char *methods[SSH_KEX_METHODS];
}; };
/* crypto.h needs ssh_kex_struct so it is included below the struct definition */
#include "libssh/crypto.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@@ -52,10 +55,10 @@ char *ssh_prefix_default_algos(enum ssh_kex_types_e algo, const char *list);
char **ssh_space_tokenize(const char *chain); char **ssh_space_tokenize(const char *chain);
int ssh_get_kex1(ssh_session session); int ssh_get_kex1(ssh_session session);
char *ssh_find_matching(const char *in_d, const char *what_d); char *ssh_find_matching(const char *in_d, const char *what_d);
const char *ssh_kex_get_supported_method(uint32_t algo); const char *ssh_kex_get_supported_method(enum ssh_kex_types_e type);
const char *ssh_kex_get_default_methods(uint32_t algo); const char *ssh_kex_get_default_methods(enum ssh_kex_types_e type);
const char *ssh_kex_get_fips_methods(uint32_t algo); const char *ssh_kex_get_fips_methods(enum ssh_kex_types_e type);
const char *ssh_kex_get_description(uint32_t algo); const char *ssh_kex_get_description(enum ssh_kex_types_e type);
char *ssh_client_select_hostkeys(ssh_session session); char *ssh_client_select_hostkeys(ssh_session session);
int ssh_send_rekex(ssh_session session); int ssh_send_rekex(ssh_session session);
int server_set_kex(ssh_session session); int server_set_kex(ssh_session session);
@@ -64,6 +67,7 @@ int ssh_make_sessionid(ssh_session session);
int ssh_hashbufin_add_cookie(ssh_session session, unsigned char *cookie); int ssh_hashbufin_add_cookie(ssh_session session, unsigned char *cookie);
int ssh_hashbufout_add_cookie(ssh_session session); int ssh_hashbufout_add_cookie(ssh_session session);
int ssh_generate_session_keys(ssh_session session); int ssh_generate_session_keys(ssh_session session);
bool ssh_kex_is_gss(struct ssh_crypto_struct *crypto);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@@ -121,6 +121,15 @@ typedef BN_CTX* bignum_CTX;
ssh_string pki_key_make_ecpoint_string(const EC_GROUP *g, const EC_POINT *p); ssh_string pki_key_make_ecpoint_string(const EC_GROUP *g, const EC_POINT *p);
int pki_key_ecgroup_name_to_nid(const char *group); int pki_key_ecgroup_name_to_nid(const char *group);
#if defined(WITH_PKCS11_URI)
#if defined(WITH_PKCS11_PROVIDER)
int pki_load_pkcs11_provider(void);
#else
ENGINE *pki_get_engine(void);
#endif
#endif /* WITH_PKCS11_PROVIDER */
#endif /* HAVE_LIBCRYPTO */ #endif /* HAVE_LIBCRYPTO */
#endif /* LIBCRYPTO_H_ */ #endif /* LIBCRYPTO_H_ */

View File

@@ -98,9 +98,9 @@ int ssh_gcry_rand_range(bignum rnd, bignum max);
#define bignum_rand_range(rnd, max) ssh_gcry_rand_range(rnd, max); #define bignum_rand_range(rnd, max) ssh_gcry_rand_range(rnd, max);
#define bignum_dup(orig, dest) do { \ #define bignum_dup(orig, dest) do { \
if (*(dest) == NULL) { \ if (*(dest) == NULL) { \
*(dest) = gcry_mpi_copy(orig); \ *(dest) = gcry_mpi_copy((const gcry_mpi_t)orig); \
} else { \ } else { \
gcry_mpi_set(*(dest), orig); \ gcry_mpi_set(*(dest), (const gcry_mpi_t)orig); \
} \ } \
} while(0) } while(0)
/* Helper functions for data conversions. */ /* Helper functions for data conversions. */

View File

@@ -1,7 +1,7 @@
/* /*
* This file is part of the SSH Library * This file is part of the SSH Library
* *
* Copyright (c) 2003-2024 by Aris Adamantiadis and the libssh team * Copyright (c) 2003-2026 by Aris Adamantiadis and the libssh team
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@@ -49,9 +49,10 @@
#endif #endif
#endif #endif
#include <stdarg.h>
#include <stdint.h>
#include <inttypes.h> #include <inttypes.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#ifdef _MSC_VER #ifdef _MSC_VER
typedef int mode_t; typedef int mode_t;
@@ -106,6 +107,7 @@ typedef struct ssh_session_struct* ssh_session;
typedef struct ssh_string_struct* ssh_string; typedef struct ssh_string_struct* ssh_string;
typedef struct ssh_event_struct* ssh_event; typedef struct ssh_event_struct* ssh_event;
typedef struct ssh_connector_struct * ssh_connector; typedef struct ssh_connector_struct * ssh_connector;
typedef struct ssh_pki_ctx_struct *ssh_pki_ctx;
typedef void* ssh_gssapi_creds; typedef void* ssh_gssapi_creds;
/* Socket type */ /* Socket type */
@@ -150,13 +152,14 @@ enum ssh_auth_e {
}; };
/* auth flags */ /* auth flags */
#define SSH_AUTH_METHOD_UNKNOWN 0x0000u #define SSH_AUTH_METHOD_UNKNOWN 0x0000u
#define SSH_AUTH_METHOD_NONE 0x0001u #define SSH_AUTH_METHOD_NONE 0x0001u
#define SSH_AUTH_METHOD_PASSWORD 0x0002u #define SSH_AUTH_METHOD_PASSWORD 0x0002u
#define SSH_AUTH_METHOD_PUBLICKEY 0x0004u #define SSH_AUTH_METHOD_PUBLICKEY 0x0004u
#define SSH_AUTH_METHOD_HOSTBASED 0x0008u #define SSH_AUTH_METHOD_HOSTBASED 0x0008u
#define SSH_AUTH_METHOD_INTERACTIVE 0x0010u #define SSH_AUTH_METHOD_INTERACTIVE 0x0010u
#define SSH_AUTH_METHOD_GSSAPI_MIC 0x0020u #define SSH_AUTH_METHOD_GSSAPI_MIC 0x0020u
#define SSH_AUTH_METHOD_GSSAPI_KEYEX 0x0040u
/* messages */ /* messages */
enum ssh_requests_e { enum ssh_requests_e {
@@ -369,6 +372,12 @@ enum ssh_control_master_options_e {
SSH_CONTROL_MASTER_AUTOASK SSH_CONTROL_MASTER_AUTOASK
}; };
enum ssh_address_family_options_e {
SSH_ADDRESS_FAMILY_ANY,
SSH_ADDRESS_FAMILY_INET,
SSH_ADDRESS_FAMILY_INET6
};
enum ssh_options_e { enum ssh_options_e {
SSH_OPTIONS_HOST, SSH_OPTIONS_HOST,
SSH_OPTIONS_PORT, SSH_OPTIONS_PORT,
@@ -419,6 +428,10 @@ enum ssh_options_e {
SSH_OPTIONS_CERTIFICATE, SSH_OPTIONS_CERTIFICATE,
SSH_OPTIONS_PROXYJUMP, SSH_OPTIONS_PROXYJUMP,
SSH_OPTIONS_PROXYJUMP_CB_LIST_APPEND, SSH_OPTIONS_PROXYJUMP_CB_LIST_APPEND,
SSH_OPTIONS_PKI_CONTEXT,
SSH_OPTIONS_ADDRESS_FAMILY,
SSH_OPTIONS_GSSAPI_KEY_EXCHANGE,
SSH_OPTIONS_GSSAPI_KEY_EXCHANGE_ALGS,
}; };
enum { enum {
@@ -720,9 +733,17 @@ LIBSSH_API int ssh_key_cmp(const ssh_key k1,
const ssh_key k2, const ssh_key k2,
enum ssh_keycmp_e what); enum ssh_keycmp_e what);
LIBSSH_API ssh_key ssh_key_dup(const ssh_key key); LIBSSH_API ssh_key ssh_key_dup(const ssh_key key);
LIBSSH_API uint32_t ssh_key_get_sk_flags(const ssh_key key);
LIBSSH_API ssh_string ssh_key_get_sk_application(const ssh_key key);
LIBSSH_API ssh_string ssh_key_get_sk_user_id(const ssh_key key);
SSH_DEPRECATED LIBSSH_API int
ssh_pki_generate(enum ssh_keytypes_e type, int parameter, ssh_key *pkey);
LIBSSH_API int ssh_pki_generate_key(enum ssh_keytypes_e type,
ssh_pki_ctx pki_context,
ssh_key *pkey);
LIBSSH_API int ssh_pki_generate(enum ssh_keytypes_e type, int parameter,
ssh_key *pkey);
LIBSSH_API int ssh_pki_import_privkey_base64(const char *b64_key, LIBSSH_API int ssh_pki_import_privkey_base64(const char *b64_key,
const char *passphrase, const char *passphrase,
ssh_auth_callback auth_fn, ssh_auth_callback auth_fn,
@@ -843,6 +864,7 @@ LIBSSH_API int ssh_string_fill(ssh_string str, const void *data, size_t len);
do { if ((x) != NULL) { ssh_string_free(x); x = NULL; } } while(0) do { if ((x) != NULL) { ssh_string_free(x); x = NULL; } } while(0)
LIBSSH_API void ssh_string_free(ssh_string str); LIBSSH_API void ssh_string_free(ssh_string str);
LIBSSH_API ssh_string ssh_string_from_char(const char *what); LIBSSH_API ssh_string ssh_string_from_char(const char *what);
LIBSSH_API ssh_string ssh_string_from_data(const void *data, size_t len);
LIBSSH_API size_t ssh_string_len(ssh_string str); LIBSSH_API size_t ssh_string_len(ssh_string str);
LIBSSH_API ssh_string ssh_string_new(size_t size); LIBSSH_API ssh_string ssh_string_new(size_t size);
LIBSSH_API const char *ssh_string_get_char(ssh_string str); LIBSSH_API const char *ssh_string_get_char(ssh_string str);
@@ -850,6 +872,7 @@ LIBSSH_API char *ssh_string_to_char(ssh_string str);
#define SSH_STRING_FREE_CHAR(x) \ #define SSH_STRING_FREE_CHAR(x) \
do { if ((x) != NULL) { ssh_string_free_char(x); x = NULL; } } while(0) do { if ((x) != NULL) { ssh_string_free_char(x); x = NULL; } } while(0)
LIBSSH_API void ssh_string_free_char(char *s); LIBSSH_API void ssh_string_free_char(char *s);
LIBSSH_API int ssh_string_cmp(ssh_string s1, ssh_string s2);
LIBSSH_API int ssh_getpass(const char *prompt, char *buf, size_t len, int echo, LIBSSH_API int ssh_getpass(const char *prompt, char *buf, size_t len, int echo,
int verify); int verify);
@@ -874,6 +897,7 @@ LIBSSH_API const char* ssh_get_cipher_in(ssh_session session);
LIBSSH_API const char* ssh_get_cipher_out(ssh_session session); LIBSSH_API const char* ssh_get_cipher_out(ssh_session session);
LIBSSH_API const char* ssh_get_hmac_in(ssh_session session); LIBSSH_API const char* ssh_get_hmac_in(ssh_session session);
LIBSSH_API const char* ssh_get_hmac_out(ssh_session session); LIBSSH_API const char* ssh_get_hmac_out(ssh_session session);
LIBSSH_API const char *ssh_get_supported_methods(enum ssh_kex_types_e type);
LIBSSH_API ssh_buffer ssh_buffer_new(void); LIBSSH_API ssh_buffer ssh_buffer_new(void);
LIBSSH_API void ssh_buffer_free(ssh_buffer buffer); LIBSSH_API void ssh_buffer_free(ssh_buffer buffer);
@@ -886,6 +910,105 @@ LIBSSH_API void *ssh_buffer_get(ssh_buffer buffer);
LIBSSH_API uint32_t ssh_buffer_get_len(ssh_buffer buffer); LIBSSH_API uint32_t ssh_buffer_get_len(ssh_buffer buffer);
LIBSSH_API int ssh_session_set_disconnect_message(ssh_session session, const char *message); LIBSSH_API int ssh_session_set_disconnect_message(ssh_session session, const char *message);
/* SSHSIG hashes data independently from the key used, so we use a new enum
to avoid confusion. See
https://gitlab.com/jas/ietf-sshsig-format/-/blob/cc70a225cbd695d5a6f20aaebdb4b92b0818e43a/ietf-sshsig-format.md#L137
*/
enum sshsig_digest_e {
SSHSIG_DIGEST_SHA2_256 = 0,
SSHSIG_DIGEST_SHA2_512 = 1,
};
LIBSSH_API int sshsig_sign(const void *data,
size_t data_length,
ssh_key privkey,
ssh_pki_ctx pki_context,
const char *sig_namespace,
enum sshsig_digest_e hash_alg,
char **signature);
LIBSSH_API int sshsig_verify(const void *data,
size_t data_length,
const char *signature,
const char *sig_namespace,
ssh_key *sign_key);
/* PKI context API */
enum ssh_pki_options_e {
SSH_PKI_OPTION_RSA_KEY_SIZE,
/* Security Key options */
SSH_PKI_OPTION_SK_APPLICATION,
SSH_PKI_OPTION_SK_FLAGS,
SSH_PKI_OPTION_SK_USER_ID,
SSH_PKI_OPTION_SK_CHALLENGE,
SSH_PKI_OPTION_SK_CALLBACKS,
};
/* FIDO2/U2F Operation Flags */
/** Requires user presence confirmation (tap/touch) */
#ifndef SSH_SK_USER_PRESENCE_REQD
#define SSH_SK_USER_PRESENCE_REQD 0x01
#endif
/** Requires user verification (PIN/biometric) - FIDO2 only */
#ifndef SSH_SK_USER_VERIFICATION_REQD
#define SSH_SK_USER_VERIFICATION_REQD 0x04
#endif
/** Force resident key enrollment even if a resident key with given user ID
* already exists - FIDO2 only */
#ifndef SSH_SK_FORCE_OPERATION
#define SSH_SK_FORCE_OPERATION 0x10
#endif
/** Create/use resident key stored on authenticator - FIDO2 only */
#ifndef SSH_SK_RESIDENT_KEY
#define SSH_SK_RESIDENT_KEY 0x20
#endif
LIBSSH_API ssh_pki_ctx ssh_pki_ctx_new(void);
LIBSSH_API int ssh_pki_ctx_options_set(ssh_pki_ctx context,
enum ssh_pki_options_e option,
const void *value);
LIBSSH_API int ssh_pki_ctx_set_sk_pin_callback(ssh_pki_ctx context,
ssh_auth_callback pin_callback,
void *userdata);
#define SSH_SK_OPTION_NAME_DEVICE_PATH "device"
#define SSH_SK_OPTION_NAME_USER_ID "user"
LIBSSH_API int ssh_pki_ctx_sk_callbacks_option_set(ssh_pki_ctx context,
const char *name,
const char *value,
bool required);
LIBSSH_API int ssh_pki_ctx_sk_callbacks_options_clear(ssh_pki_ctx context);
LIBSSH_API int
ssh_pki_ctx_get_sk_attestation_buffer(const struct ssh_pki_ctx_struct *context,
ssh_buffer *attestation_buffer);
LIBSSH_API void ssh_pki_ctx_free(ssh_pki_ctx context);
#define SSH_PKI_CTX_FREE(x) \
do { \
if ((x) != NULL) { \
ssh_pki_ctx_free(x); \
x = NULL; \
} \
} while (0)
/* Security key resident keys API */
LIBSSH_API int
ssh_sk_resident_keys_load(const struct ssh_pki_ctx_struct *pki_context,
ssh_key **resident_keys_result,
size_t *num_keys_found_result);
#ifndef LIBSSH_LEGACY_0_4 #ifndef LIBSSH_LEGACY_0_4
#include "libssh/legacy.h" #include "libssh/legacy.h"
#endif #endif

View File

@@ -28,6 +28,7 @@ struct ssh_auth_request {
int method; int method;
char *password; char *password;
struct ssh_key_struct *pubkey; struct ssh_key_struct *pubkey;
struct ssh_key_struct *server_pubkey;
char *sigtype; char *sigtype;
enum ssh_publickey_state_e signature_state; enum ssh_publickey_state_e signature_state;
char kbdint_response; char kbdint_response;

73
include/libssh/mlkem.h Normal file
View File

@@ -0,0 +1,73 @@
/*
* This file is part of the SSH Library
*
* Copyright (c) 2025 by Red Hat, Inc.
*
* Author: Pavol Žáčik <pzacik@redhat.com>
*
* The SSH Library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 2.1 of the License.
*
* The SSH Library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the SSH Library; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
* MA 02111-1307, USA.
*/
#ifndef MLKEM_H_
#define MLKEM_H_
#include "libssh/crypto.h"
#include "libssh/libssh.h"
#include "libssh/session.h"
#include "config.h"
#ifdef __cplusplus
extern "C" {
#endif
struct mlkem_type_info {
size_t pubkey_size;
size_t ciphertext_size;
#ifdef HAVE_GCRYPT_MLKEM
size_t privkey_size;
enum gcry_kem_algos alg;
#elif defined(HAVE_OPENSSL_MLKEM)
const char *name;
#else
size_t privkey_size;
#endif
};
extern const struct mlkem_type_info MLKEM768_INFO;
#ifdef HAVE_MLKEM1024
extern const struct mlkem_type_info MLKEM1024_INFO;
#endif
#define MLKEM_SHARED_SECRET_SIZE 32
typedef unsigned char ssh_mlkem_shared_secret[MLKEM_SHARED_SECRET_SIZE];
const struct mlkem_type_info *
kex_type_to_mlkem_info(enum ssh_key_exchange_e kex_type);
int ssh_mlkem_init(ssh_session session);
int ssh_mlkem_encapsulate(ssh_session session,
ssh_mlkem_shared_secret shared_secret);
int ssh_mlkem_decapsulate(const ssh_session session,
ssh_mlkem_shared_secret shared_secret);
#ifdef __cplusplus
}
#endif
#endif /* MLKEM_H_ */

View File

@@ -0,0 +1,127 @@
/*
* This file is part of the SSH Library
*
* Copyright (c) 2025 by Red Hat, Inc.
*
* Author: Jakub Jelen <jjelen@redhat.com>
*
* The SSH Library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 2.1 of the License.
*
* The SSH Library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the SSH Library; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
* MA 02111-1307, USA.
*/
#ifndef MLKEM_NATIVE_H_
#define MLKEM_NATIVE_H_
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "config.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
A monomorphic instance of libcrux_ml_kem.types.MlKemPrivateKey
with const generics
- $2400size_t
*/
typedef struct libcrux_ml_kem_types_MlKemPrivateKey_d9_s {
uint8_t value[2400U];
} libcrux_ml_kem_types_MlKemPrivateKey_d9;
/**
A monomorphic instance of libcrux_ml_kem.types.MlKemPublicKey
with const generics
- $1184size_t
*/
typedef struct libcrux_ml_kem_types_MlKemPublicKey_30_s {
uint8_t value[1184U];
} libcrux_ml_kem_types_MlKemPublicKey_30;
typedef struct libcrux_ml_kem_mlkem768_MlKem768KeyPair_s {
libcrux_ml_kem_types_MlKemPrivateKey_d9 sk;
libcrux_ml_kem_types_MlKemPublicKey_30 pk;
} libcrux_ml_kem_mlkem768_MlKem768KeyPair;
typedef struct libcrux_ml_kem_mlkem768_MlKem768Ciphertext_s {
uint8_t value[1088U];
} libcrux_ml_kem_mlkem768_MlKem768Ciphertext;
/**
A monomorphic instance of K.
with types libcrux_ml_kem_types_MlKemCiphertext[[$1088size_t]],
uint8_t[32size_t]
*/
typedef struct tuple_c2_s {
libcrux_ml_kem_mlkem768_MlKem768Ciphertext fst;
uint8_t snd[32U];
} tuple_c2;
/**
Generate ML-KEM 768 Key Pair
*/
libcrux_ml_kem_mlkem768_MlKem768KeyPair
libcrux_ml_kem_mlkem768_portable_generate_key_pair(uint8_t randomness[64U]);
/**
Validate a public key.
Returns `true` if valid, and `false` otherwise.
*/
bool libcrux_ml_kem_mlkem768_portable_validate_public_key(
libcrux_ml_kem_types_MlKemPublicKey_30 *public_key);
/**
Encapsulate ML-KEM 768
Generates an ([`MlKem768Ciphertext`], [`MlKemSharedSecret`]) tuple.
The input is a reference to an [`MlKem768PublicKey`] and [`SHARED_SECRET_SIZE`]
bytes of `randomness`.
*/
tuple_c2 libcrux_ml_kem_mlkem768_portable_encapsulate(
libcrux_ml_kem_types_MlKemPublicKey_30 *public_key,
uint8_t randomness[32U]);
/**
Decapsulate ML-KEM 768
Generates an [`MlKemSharedSecret`].
The input is a reference to an [`MlKem768PrivateKey`] and an
[`MlKem768Ciphertext`].
*/
void libcrux_ml_kem_mlkem768_portable_decapsulate(
libcrux_ml_kem_types_MlKemPrivateKey_d9 *private_key,
libcrux_ml_kem_mlkem768_MlKem768Ciphertext *ciphertext,
uint8_t ret[32U]);
/* rename some types to be a bit more ergonomic */
#define libcrux_mlkem768_keypair libcrux_ml_kem_mlkem768_MlKem768KeyPair_s
#define libcrux_mlkem768_pk libcrux_ml_kem_types_MlKemPublicKey_30_s
#define libcrux_mlkem768_sk libcrux_ml_kem_types_MlKemPrivateKey_d9_s
#define libcrux_mlkem768_ciphertext libcrux_ml_kem_mlkem768_MlKem768Ciphertext_s
#define libcrux_mlkem768_enc_result tuple_c2_s
/* defines for PRNG inputs */
#define LIBCRUX_ML_KEM_KEY_PAIR_PRNG_LEN 64U
#define LIBCRUX_ML_KEM_ENC_PRNG_LEN 32
#ifdef __cplusplus
}
#endif
#endif /* MLKEM_NATIVE_H_ */

View File

@@ -25,6 +25,7 @@
extern "C" { extern "C" {
#endif #endif
int ssh_config_parse(ssh_session session, FILE *fp, bool global);
int ssh_config_parse_file(ssh_session session, const char *filename); int ssh_config_parse_file(ssh_session session, const char *filename);
int ssh_config_parse_string(ssh_session session, const char *input); int ssh_config_parse_string(ssh_session session, const char *input);
int ssh_options_set_algo(ssh_session session, int ssh_options_set_algo(ssh_session session,

View File

@@ -58,6 +58,7 @@ extern "C" {
SSH_PACKET_CALLBACK(ssh_packet_unimplemented); SSH_PACKET_CALLBACK(ssh_packet_unimplemented);
SSH_PACKET_CALLBACK(ssh_packet_disconnect_callback); SSH_PACKET_CALLBACK(ssh_packet_disconnect_callback);
SSH_PACKET_CALLBACK(ssh_packet_ignore_callback); SSH_PACKET_CALLBACK(ssh_packet_ignore_callback);
SSH_PACKET_CALLBACK(ssh_packet_debug_callback);
SSH_PACKET_CALLBACK(ssh_packet_dh_reply); SSH_PACKET_CALLBACK(ssh_packet_dh_reply);
SSH_PACKET_CALLBACK(ssh_packet_newkeys); SSH_PACKET_CALLBACK(ssh_packet_newkeys);
SSH_PACKET_CALLBACK(ssh_packet_service_accept); SSH_PACKET_CALLBACK(ssh_packet_service_accept);

View File

@@ -46,11 +46,24 @@
#define MAX_PUBKEY_SIZE 0x100000 /* 1M */ #define MAX_PUBKEY_SIZE 0x100000 /* 1M */
#define MAX_PRIVKEY_SIZE 0x400000 /* 4M */ #define MAX_PRIVKEY_SIZE 0x400000 /* 4M */
#define RSA_MIN_KEY_SIZE 1024
#define RSA_MIN_FIPS_KEY_SIZE 2048
#define RSA_DEFAULT_KEY_SIZE 3072
#define SSH_KEY_FLAG_EMPTY 0x0 #define SSH_KEY_FLAG_EMPTY 0x0
#define SSH_KEY_FLAG_PUBLIC 0x0001 #define SSH_KEY_FLAG_PUBLIC 0x0001
#define SSH_KEY_FLAG_PRIVATE 0x0002 #define SSH_KEY_FLAG_PRIVATE 0x0002
#define SSH_KEY_FLAG_PKCS11_URI 0x0004 #define SSH_KEY_FLAG_PKCS11_URI 0x0004
/* Constants matching the Lightweight Secure Shell Signature Format */
/* https://datatracker.ietf.org/doc/draft-josefsson-sshsig-format */
#define SSHSIG_VERSION 0x01
#define SSHSIG_MAGIC_PREAMBLE "SSHSIG"
#define SSHSIG_MAGIC_PREAMBLE_LEN (sizeof(SSHSIG_MAGIC_PREAMBLE) - 1)
#define SSHSIG_BEGIN_SIGNATURE "-----BEGIN SSH SIGNATURE-----"
#define SSHSIG_END_SIGNATURE "-----END SSH SIGNATURE-----"
#define SSHSIG_LINE_LENGTH 76
struct ssh_key_struct { struct ssh_key_struct {
enum ssh_keytypes_e type; enum ssh_keytypes_e type;
int flags; int flags;
@@ -63,11 +76,12 @@ struct ssh_key_struct {
mbedtls_pk_context *pk; mbedtls_pk_context *pk;
mbedtls_ecdsa_context *ecdsa; mbedtls_ecdsa_context *ecdsa;
#elif defined(HAVE_LIBCRYPTO) #elif defined(HAVE_LIBCRYPTO)
/* This holds either ENGINE key for PKCS#11 support or just key in /* This holds either ENGINE/PROVIDER key for PKCS#11 support
* high-level format */ * or just key in high-level format */
EVP_PKEY *key; EVP_PKEY *key;
/* keep this around for FIPS mode so we can parse the public keys. We won't
* be able to use them nor use the private keys though */
uint8_t *ed25519_pubkey; uint8_t *ed25519_pubkey;
uint8_t *ed25519_privkey;
#endif /* HAVE_LIBGCRYPT */ #endif /* HAVE_LIBGCRYPT */
#ifndef HAVE_LIBCRYPTO #ifndef HAVE_LIBCRYPTO
ed25519_pubkey *ed25519_pubkey; ed25519_pubkey *ed25519_pubkey;
@@ -76,6 +90,14 @@ struct ssh_key_struct {
ssh_string sk_application; ssh_string sk_application;
ssh_buffer cert; ssh_buffer cert;
enum ssh_keytypes_e cert_type; enum ssh_keytypes_e cert_type;
/* Security Key specific private data */
uint8_t sk_flags;
ssh_string sk_key_handle;
ssh_string sk_reserved;
/* Resident key specific metadata */
ssh_string sk_user_id;
}; };
struct ssh_signature_struct { struct ssh_signature_struct {
@@ -127,6 +149,11 @@ enum ssh_digest_e ssh_key_hash_from_name(const char *name);
((kt) >= SSH_KEYTYPE_ECDSA_P256_CERT01 &&\ ((kt) >= SSH_KEYTYPE_ECDSA_P256_CERT01 &&\
(kt) <= SSH_KEYTYPE_ED25519_CERT01)) (kt) <= SSH_KEYTYPE_ED25519_CERT01))
#define is_sk_key_type(kt) \
((kt) == SSH_KEYTYPE_SK_ECDSA || (kt) == SSH_KEYTYPE_SK_ED25519 || \
(kt) == SSH_KEYTYPE_SK_ECDSA_CERT01 || \
(kt) == SSH_KEYTYPE_SK_ED25519_CERT01)
/* SSH Signature Functions */ /* SSH Signature Functions */
ssh_signature ssh_signature_new(void); ssh_signature ssh_signature_new(void);
void ssh_signature_free(ssh_signature sign); void ssh_signature_free(ssh_signature sign);

View File

@@ -0,0 +1,103 @@
/*
* This file is part of the SSH Library
*
* Copyright (c) 2025 Praneeth Sarode <praneethsarode@gmail.com>
*
* The SSH Library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 2.1 of the License.
*
* The SSH Library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the SSH Library; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
* MA 02111-1307, USA.
*/
#ifndef PKI_CONTEXT_H
#define PKI_CONTEXT_H
#include "libssh/callbacks.h"
#include "libssh/libssh.h"
/**
* @brief Security key context structure
*
* Context structure containing all parameters and callbacks
* needed for FIDO2/U2F security key operations.
*/
struct ssh_pki_ctx_struct {
/** @brief Desired RSA modulus size in bits
*
* Specified size of RSA keys to generate. If set to 0, defaults to 3072
* bits. Must be greater than or equal to 1024, as anything below is
* considered insecure.
*/
int rsa_key_size;
/** @brief Security key callbacks
*
* Provides enroll/sign/load_resident_keys operations.
*/
const struct ssh_sk_callbacks_struct *sk_callbacks;
/** @brief Application identifier string for the security key credential
*
* FIDO2 relying party identifier, typically "ssh:user@hostname" format.
* This is required for all security key operations.
*/
char *sk_application;
/** @brief FIDO2 operation flags
*
* Bitfield controlling authenticator behavior. Combine with bitwise OR:
* - SSH_SK_USER_PRESENCE_REQD (0x01): Require user touch
* - SSH_SK_USER_VERIFICATION_REQD (0x04): Require PIN/biometric
* - SSH_SK_FORCE_OPERATION (0x10): Override duplicate detection
* - SSH_SK_RESIDENT_KEY (0x20): Create discoverable credential
*/
uint8_t sk_flags;
/** @brief PIN callback for authenticator user verification (optional)
*
* Callback invoked to obtain a PIN or perform user verification when
* SSH_SK_USER_VERIFICATION_REQD is set or the authenticator requires it.
* If NULL, no interactive PIN retrieval is performed.
*/
ssh_auth_callback sk_pin_callback;
/** @brief User supplied pointer passed to callbacks (optional)
*
* Generic pointer set by the application and forwarded to
* interactive callbacks (e.g. PIN callback) to allow applications to
* carry state context.
*/
void *sk_userdata;
/** @brief Custom challenge data for enrollment (optional)
*
* Buffer containing challenge data signed by the authenticator.
* If NULL, a random 32-byte challenge is automatically generated.
*/
ssh_buffer sk_challenge_buffer;
/** @brief Options to be passed to the sk_callbacks (optional)
*
* NULL-terminated array of sk_option pointers owned by this context.
*/
struct sk_option **sk_callbacks_options;
/** @brief The buffer used to store attestation information returned in a
* key enrollment operation
*/
ssh_buffer sk_attestation_buffer;
};
/* Internal PKI context functions */
ssh_pki_ctx ssh_pki_ctx_dup(const ssh_pki_ctx context);
#endif /* PKI_CONTEXT_H */

View File

@@ -61,6 +61,7 @@ enum ssh_digest_e ssh_key_type_to_hash(ssh_session session,
enum ssh_keytypes_e type); enum ssh_keytypes_e type);
/* SSH Key Functions */ /* SSH Key Functions */
ssh_key pki_key_dup_common_init(const ssh_key key, int demote);
ssh_key pki_key_dup(const ssh_key key, int demote); ssh_key pki_key_dup(const ssh_key key, int demote);
int pki_key_generate_rsa(ssh_key key, int parameter); int pki_key_generate_rsa(ssh_key key, int parameter);
int pki_key_generate_ecdsa(ssh_key key, int parameter); int pki_key_generate_ecdsa(ssh_key key, int parameter);
@@ -148,6 +149,7 @@ int pki_signature_from_ed25519_blob(ssh_signature sig, ssh_string sig_blob);
int pki_privkey_build_ed25519(ssh_key key, int pki_privkey_build_ed25519(ssh_key key,
ssh_string pubkey, ssh_string pubkey,
ssh_string privkey); ssh_string privkey);
int pki_pubkey_build_ed25519(ssh_key key, ssh_string pubkey);
/* PKI Container OpenSSH */ /* PKI Container OpenSSH */
ssh_key ssh_pki_openssh_pubkey_import(const char *text_key); ssh_key ssh_pki_openssh_pubkey_import(const char *text_key);
@@ -162,6 +164,16 @@ int pki_uri_import(const char *uri_name, ssh_key *key, enum ssh_key_e key_type);
#endif /* WITH_PKCS11_URI */ #endif /* WITH_PKCS11_URI */
bool ssh_key_size_allowed_rsa(int min_size, ssh_key key); bool ssh_key_size_allowed_rsa(int min_size, ssh_key key);
/* Security Key Helper Functions */
int pki_buffer_pack_sk_priv_data(ssh_buffer buffer, const ssh_key key);
int pki_buffer_unpack_sk_priv_data(ssh_buffer buffer, ssh_key key);
int pki_sk_signature_buffer_prepare(const ssh_key key,
const ssh_signature sig,
const unsigned char *input,
size_t input_len,
ssh_buffer *sk_buffer_out);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

90
include/libssh/pki_sk.h Normal file
View File

@@ -0,0 +1,90 @@
/*
* This file is part of the SSH Library
*
* Copyright (c) 2025 Praneeth Sarode <praneethsarode@gmail.com>
*
* The SSH Library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 2.1 of the License.
*
* The SSH Library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the SSH Library; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
* MA 02111-1307, USA.
*/
#ifndef PKI_SK_H
#define PKI_SK_H
#include "libssh/libssh.h"
#include "libssh/pki.h"
#include <stdint.h>
#define SSH_SK_MAX_USER_ID_LEN 64
/**
* @brief Enroll a new security key using a U2F/FIDO2 authenticator
*
* Creates a new security key credential configured according to the parameters
* in the PKI context. This function handles key enrollment for both ECDSA and
* Ed25519 algorithms, generates appropriate challenges, and returns the
* enrolled key with optional attestation data.
*
* The PKI context must be configured with appropriate security key parameters
* using ssh_pki_ctx_options_set() before calling this function. Required
* options include SSH_PKI_OPTION_SK_APPLICATION, SSH_PKI_OPTION_SK_USER_ID, and
* SSH_PKI_OPTION_SK_CALLBACKS.
*
* @param[in] context The PKI context containing security key configuration and
* parameters
* @param[in] key_type The type of key to enroll (SSH_KEYTYPE_SK_ECDSA or
* SSH_KEYTYPE_SK_ED25519)
* @param[out] enrolled_key_result Pointer to store the enrolled ssh_key
*
* @return SSH_OK on success, SSH_ERROR on failure
*
* @see ssh_pki_ctx_new()
* @see ssh_pki_ctx_options_set()
* @see ssh_pki_ctx_get_sk_attestation_buffer()
*/
int pki_sk_enroll_key(ssh_pki_ctx context,
enum ssh_keytypes_e key_type,
ssh_key *enrolled_key_result);
/**
* @brief Sign arbitrary data using a security key and a PKI context
*
* This function performs signing operations configured according to the
* parameters in the PKI context and returns a properly formatted
* ssh_signature. The caller must free the signature when it is no longer
* needed.
*
* The PKI context should be configured with appropriate security key parameters
* using ssh_pki_ctx_options_set() before calling this function. The security
* key must have been previously enrolled or loaded.
*
* @param[in] context The PKI context containing security key configuration and
* parameters
* @param[in] key The security key to use for signing
* @param[in] data The data to sign
* @param[in] data_len Length of data to sign
*
* @return A valid ssh_signature on success, NULL on failure
*
* @see ssh_pki_ctx_new()
* @see ssh_pki_ctx_options_set()
* @see pki_sk_enroll_key()
* @see ssh_signature_free()
*/
ssh_signature pki_sk_do_sign(ssh_pki_ctx context,
const ssh_key key,
const uint8_t *data,
size_t data_len);
#endif /* PKI_SK_H */

Some files were not shown because too many files have changed in this diff Show More