wolfssh/wolfssh/internal.h

2343 lines
83 KiB
C

/* internal.h
*
* Copyright (C) 2014-2026 wolfSSL Inc.
*
* This file is part of wolfSSH.
*
* wolfSSH is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* wolfSSH is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with wolfSSH. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* The internal module contains the private data and functions. The public
* API calls into this module to do the work of processing the connections.
*/
#ifndef _WOLFSSH_INTERNAL_H_
#define _WOLFSSH_INTERNAL_H_
#include <wolfssh/ssh.h>
#include <wolfssh/wolfsftp.h>
#include <wolfssl/version.h>
#include <wolfssl/wolfcrypt/hash.h>
#include <wolfssl/wolfcrypt/random.h>
#include <wolfssl/wolfcrypt/aes.h>
#include <wolfssl/wolfcrypt/dh.h>
#include <wolfssl/wolfcrypt/ecc.h>
#include <wolfssl/wolfcrypt/rsa.h>
#include <wolfssl/wolfcrypt/curve25519.h>
#include <wolfssl/wolfcrypt/ed25519.h>
#ifdef HAVE_ED448
#include <wolfssl/wolfcrypt/ed448.h>
#endif
#ifndef WOLFSSL_WOLFSSH
#error "wolfssh requires wolfSSL built with WOLFSSL_WOLFSSH"
#endif
#ifdef HAVE_DILITHIUM
#include <wolfssl/wolfcrypt/dilithium.h>
#endif
#ifdef WOLFSSH_SCP
#include <wolfssh/wolfscp.h>
#endif
#ifdef WOLFSSH_AGENT
#include <wolfssh/agent.h>
#endif /* WOLFSSH_AGENT */
#ifdef WOLFSSH_CERTS
#include <wolfssh/certman.h>
#endif /* WOLFSSH_CERTS */
#ifdef WOLFSSH_WINDOWS_CERT_STORE
#ifndef WOLFSSH_CERTS
#error "WOLFSSH_WINDOWS_CERT_STORE requires WOLFSSH_CERTS"
#endif
#if !defined(_WIN32) && !defined(USE_WINDOWS_API)
#error "WOLFSSH_WINDOWS_CERT_STORE requires a Windows target"
#endif
#endif /* WOLFSSH_WINDOWS_CERT_STORE */
#ifdef WOLFSSH_TPM
#include <wolftpm/tpm2_wrap.h>
#endif /* WOLFSSH_TPM */
#if !defined (ALIGN16)
#if defined (__GNUC__)
#define ALIGN16 __attribute__ ( (aligned (16)))
#elif defined(_MSC_VER)
/* disable align warning, we want alignment ! */
#pragma warning(disable: 4324)
#define ALIGN16 __declspec (align (16))
#else
#define ALIGN16
#endif
#endif
#ifdef __cplusplus
extern "C" {
#endif
/*
* Check options set by wolfSSL and set wolfSSH options as appropriate. If
* the derived options and any override options leave wolfSSH without
* at least one algorithm to use, throw an error.
*/
#if defined(NO_WOLFSSH_SERVER) && defined(NO_WOLFSSH_CLIENT)
#error "Both NO_WOLFSSH_SERVER and NO_WOLFSSH_CLIENT are defined. Omit one of --disable-server or --disable-client."
#endif
#ifdef NO_RSA
#undef WOLFSSH_NO_RSA
#define WOLFSSH_NO_RSA
#endif
#ifndef HAVE_ECC
#undef WOLFSSH_NO_ECDSA
#define WOLFSSH_NO_ECDSA
#undef WOLFSSH_NO_ECDH
#define WOLFSSH_NO_ECDH
#endif
#ifdef NO_DH
#undef WOLFSSH_NO_DH
#define WOLFSSH_NO_DH
#endif
/* wolfSSL_CertManager_up_ref() was added in wolfSSL 4.6.0 */
#define WOLFSSL_V4_6_0 0x04006000
#define WOLFSSL_V5_0_0 0x05000000
#define WOLFSSL_V5_7_0 0x05007000
#define WOLFSSL_V5_7_2 0x05007002
#define WOLFSSL_V5_8_0 0x05008000
#define WOLFSSL_V5_9_2 0x05009002
/* wolfSSL 5.8.0 added the trusted-certificate PEM header, both the
* TRUSTED_CERT_TYPE enum and PemToDer()'s fallback to it. */
#if defined(WOLFSSH_CERTS) && (LIBWOLFSSL_VERSION_HEX >= WOLFSSL_V5_8_0)
#define WOLFSSH_HAVE_TRUSTED_CERT_PEM
#endif
/* wc_MlDsaKey_* / WC_MLDSA_* naming replaced the wc_Dilithium_* API in
* wolfSSL 5.9.2. HAVE_DILITHIUM alone doesn't distinguish the two, so
* require the version that has the new API too. */
#if !defined(HAVE_DILITHIUM) || \
(LIBWOLFSSL_VERSION_HEX < WOLFSSL_V5_9_2)
#undef WOLFSSH_NO_MLDSA
#define WOLFSSH_NO_MLDSA
#undef WOLFSSH_NO_MLDSA44
#undef WOLFSSH_NO_MLDSA65
#undef WOLFSSH_NO_MLDSA87
#define WOLFSSH_NO_MLDSA44
#define WOLFSSH_NO_MLDSA65
#define WOLFSSH_NO_MLDSA87
#endif
#ifdef NO_SHA
#undef WOLFSSH_NO_SHA1
#define WOLFSSH_NO_SHA1
#endif
#if !defined(HAVE_ED25519) \
|| !defined(WOLFSSL_ED25519_STREAMING_VERIFY) \
|| !defined(HAVE_ED25519_KEY_IMPORT) \
|| !defined(HAVE_ED25519_KEY_EXPORT)
#undef WOLFSSH_NO_ED25519
#define WOLFSSH_NO_ED25519
#endif
#if defined(NO_HMAC) || defined(WOLFSSH_NO_SHA1)
#undef WOLFSSH_NO_HMAC_SHA1
#define WOLFSSH_NO_HMAC_SHA1
#endif
#if defined(NO_HMAC) || defined(WOLFSSH_NO_SHA1)
#undef WOLFSSH_NO_HMAC_SHA1_96
#define WOLFSSH_NO_HMAC_SHA1_96
#endif
#if defined(NO_HMAC) || defined(NO_SHA256)
#undef WOLFSSH_NO_HMAC_SHA2_256
#define WOLFSSH_NO_HMAC_SHA2_256
#endif
#if defined(NO_HMAC) || defined(NO_SHA512)
#undef WOLFSSH_NO_HMAC_SHA2_512
#define WOLFSSH_NO_HMAC_SHA2_512
#endif
#if defined(WOLFSSH_NO_HMAC_SHA1) && \
defined(WOLFSSH_NO_HMAC_SHA1_96) && \
defined(WOLFSSH_NO_HMAC_SHA2_256) && \
defined(WOLFSSH_NO_HMAC_SHA2_512)
#error "You need at least one MAC algorithm."
#endif
/* The SHA-1 MACs only join the default algorithm list when the soft disable
* is lifted. Without them there is nothing left to offer, and an empty
* default list can never negotiate. */
#if defined(WOLFSSH_NO_HMAC_SHA2_256) && \
defined(WOLFSSH_NO_HMAC_SHA2_512) && \
!defined(WOLFSSH_NO_SHA1_SOFT_DISABLE)
#error "The only MAC algorithms left are soft-disabled. Define " \
"WOLFSSH_NO_SHA1_SOFT_DISABLE to offer them."
#endif
#if defined(WOLFSSH_NO_DH) || defined(WOLFSSH_NO_SHA1)
#undef WOLFSSH_NO_DH_GROUP1_SHA1
#define WOLFSSH_NO_DH_GROUP1_SHA1
#endif
#if defined(WOLFSSH_NO_DH) || defined(WOLFSSH_NO_SHA1)
#undef WOLFSSH_NO_DH_GROUP14_SHA1
#define WOLFSSH_NO_DH_GROUP14_SHA1
#endif
#if defined(WOLFSSH_NO_DH) || defined(WOLFSSH_NO_SHA256)
#undef WOLFSSH_NO_DH_GROUP14_SHA256
#define WOLFSSH_NO_DH_GROUP14_SHA256
#endif
#if defined(WOLFSSH_NO_DH) || defined(WOLFSSH_NO_SHA512)
#undef WOLFSSH_NO_DH_GROUP16_SHA512
#define WOLFSSH_NO_DH_GROUP16_SHA512
#endif
#if defined(WOLFSSH_NO_DH) || defined(NO_SHA256)
#undef WOLFSSH_NO_DH_GEX_SHA256
#define WOLFSSH_NO_DH_GEX_SHA256
#endif
#ifdef WOLFSSH_NO_MLDSA
#undef WOLFSSH_NO_MLDSA44
#undef WOLFSSH_NO_MLDSA65
#undef WOLFSSH_NO_MLDSA87
#define WOLFSSH_NO_MLDSA44
#define WOLFSSH_NO_MLDSA65
#define WOLFSSH_NO_MLDSA87
#endif
#if defined(WOLFSSH_NO_ECDH) \
|| defined(NO_SHA256) || defined(NO_ECC256)
#undef WOLFSSH_NO_ECDH_SHA2_NISTP256
#define WOLFSSH_NO_ECDH_SHA2_NISTP256
#endif
#if defined(WOLFSSH_NO_ECDH) \
|| !defined(WOLFSSL_SHA384) || \
(!defined(HAVE_ECC384) && !defined(HAVE_ALL_CURVES))
#undef WOLFSSH_NO_ECDH_SHA2_NISTP384
#define WOLFSSH_NO_ECDH_SHA2_NISTP384
#endif
#if defined(WOLFSSH_NO_ECDH) \
|| !defined(WOLFSSL_SHA512) || \
(!defined(HAVE_ECC521) && !defined(HAVE_ALL_CURVES))
#undef WOLFSSH_NO_ECDH_SHA2_NISTP521
#define WOLFSSH_NO_ECDH_SHA2_NISTP521
#endif
#if !defined(WOLFSSL_HAVE_MLKEM) || defined(NO_SHA256) \
|| defined(WOLFSSH_NO_ECDH_SHA2_NISTP256)
#undef WOLFSSH_NO_NISTP256_MLKEM768_SHA256
#define WOLFSSH_NO_NISTP256_MLKEM768_SHA256
#endif
#if !defined(WOLFSSL_HAVE_MLKEM) || !defined(WOLFSSL_SHA384) \
|| defined(WOLFSSH_NO_ECDH_SHA2_NISTP384)
#undef WOLFSSH_NO_NISTP384_MLKEM1024_SHA384
#define WOLFSSH_NO_NISTP384_MLKEM1024_SHA384
#endif
#if !defined(WOLFSSL_HAVE_MLKEM) || defined(NO_SHA256) \
|| !defined(HAVE_CURVE25519)
#undef WOLFSSH_NO_CURVE25519_MLKEM768_SHA256
#define WOLFSSH_NO_CURVE25519_MLKEM768_SHA256
#endif
#if !defined(HAVE_CURVE25519) || defined(NO_SHA256)
#undef WOLFSSH_NO_CURVE25519_SHA256
#define WOLFSSH_NO_CURVE25519_SHA256
#endif
#if defined(WOLFSSH_NO_DH_GROUP1_SHA1) && \
defined(WOLFSSH_NO_DH_GROUP14_SHA1) && \
defined(WOLFSSH_NO_DH_GROUP14_SHA256) && \
defined(WOLFSSH_NO_DH_GROUP16_SHA512) && \
defined(WOLFSSH_NO_DH_GEX_SHA256) && \
defined(WOLFSSH_NO_ECDH_SHA2_NISTP256) && \
defined(WOLFSSH_NO_ECDH_SHA2_NISTP384) && \
defined(WOLFSSH_NO_ECDH_SHA2_NISTP521) && \
defined(WOLFSSH_NO_NISTP256_MLKEM768_SHA256) && \
defined(WOLFSSH_NO_NISTP384_MLKEM1024_SHA384) && \
defined(WOLFSSH_NO_CURVE25519_MLKEM768_SHA256) && \
defined(WOLFSSH_NO_CURVE25519_SHA256)
#error "You need at least one key agreement algorithm."
#endif
/* Likewise, the SHA-1 groups are the only soft-disabled KEX names. */
#if defined(WOLFSSH_NO_DH_GROUP14_SHA256) && \
defined(WOLFSSH_NO_DH_GROUP16_SHA512) && \
defined(WOLFSSH_NO_DH_GEX_SHA256) && \
defined(WOLFSSH_NO_ECDH_SHA2_NISTP256) && \
defined(WOLFSSH_NO_ECDH_SHA2_NISTP384) && \
defined(WOLFSSH_NO_ECDH_SHA2_NISTP521) && \
defined(WOLFSSH_NO_NISTP256_MLKEM768_SHA256) && \
defined(WOLFSSH_NO_NISTP384_MLKEM1024_SHA384) && \
defined(WOLFSSH_NO_CURVE25519_MLKEM768_SHA256) && \
defined(WOLFSSH_NO_CURVE25519_SHA256) && \
!defined(WOLFSSH_NO_SHA1_SOFT_DISABLE)
#error "The only key agreement algorithms left are soft-disabled. " \
"Define WOLFSSH_NO_SHA1_SOFT_DISABLE to offer them."
#endif
#if defined(WOLFSSH_NO_DH_GROUP1_SHA1) && \
defined(WOLFSSH_NO_DH_GROUP14_SHA1) && \
defined(WOLFSSH_NO_DH_GROUP14_SHA256) && \
defined(WOLFSSH_NO_DH_GROUP16_SHA512) && \
defined(WOLFSSH_NO_DH_GEX_SHA256)
#undef WOLFSSH_NO_DH
#define WOLFSSH_NO_DH
#endif
#if defined(WOLFSSH_NO_ECDH_SHA2_NISTP256) && \
defined(WOLFSSH_NO_ECDH_SHA2_NISTP384) && \
defined(WOLFSSH_NO_ECDH_SHA2_NISTP521)
#undef WOLFSSH_NO_ECDH
#define WOLFSSH_NO_ECDH
#endif
#if defined(WOLFSSH_NO_RSA) || defined(WOLFSSH_NO_SHA1)
#undef WOLFSSH_NO_SSH_RSA_SHA1
#define WOLFSSH_NO_SSH_RSA_SHA1
#endif
#if defined(WOLFSSH_NO_RSA) || defined(NO_SHA256)
#undef WOLFSSH_NO_RSA_SHA2_256
#define WOLFSSH_NO_RSA_SHA2_256
#endif
#if defined(WOLFSSH_NO_RSA) || !defined(WOLFSSL_SHA512)
#undef WOLFSSH_NO_RSA_SHA2_512
#define WOLFSSH_NO_RSA_SHA2_512
#endif
#if defined(WOLFSSH_NO_ECDSA) || \
defined(NO_SHA256) || defined(NO_ECC256)
#undef WOLFSSH_NO_ECDSA_SHA2_NISTP256
#define WOLFSSH_NO_ECDSA_SHA2_NISTP256
#endif
#if defined(WOLFSSH_NO_ECDSA) || \
!defined(WOLFSSL_SHA384) || \
(!defined(HAVE_ECC384) && !defined(HAVE_ALL_CURVES))
#undef WOLFSSH_NO_ECDSA_SHA2_NISTP384
#define WOLFSSH_NO_ECDSA_SHA2_NISTP384
#endif
#if defined(WOLFSSH_NO_ECDSA) || \
!defined(WOLFSSL_SHA512) || \
(!defined(HAVE_ECC521) && !defined(HAVE_ALL_CURVES))
#undef WOLFSSH_NO_ECDSA_SHA2_NISTP521
#define WOLFSSH_NO_ECDSA_SHA2_NISTP521
#endif
#if defined(WOLFSSH_NO_SSH_RSA_SHA1) && \
defined(WOLFSSH_NO_RSA_SHA2_256) && \
defined(WOLFSSH_NO_RSA_SHA2_512) && \
defined(WOLFSSH_NO_ECDSA_SHA2_NISTP256) && \
defined(WOLFSSH_NO_ECDSA_SHA2_NISTP384) && \
defined(WOLFSSH_NO_ECDSA_SHA2_NISTP521) && \
defined(WOLFSSH_NO_ED25519) && \
defined(WOLFSSH_NO_MLDSA44) && \
defined(WOLFSSH_NO_MLDSA65) && \
defined(WOLFSSH_NO_MLDSA87)
#error "You need at least one signing algorithm."
#endif
/* ssh-rsa is the only soft-disabled signing name. Client-only: a server
* negotiates host keys from ctx->publicKeyAlgo, not cannedKeyAlgoNames, so
* an empty canned list only costs it the server-sig-algs advertisement. */
#if !defined(NO_WOLFSSH_CLIENT) && \
defined(WOLFSSH_NO_RSA_SHA2_256) && \
defined(WOLFSSH_NO_RSA_SHA2_512) && \
defined(WOLFSSH_NO_ECDSA_SHA2_NISTP256) && \
defined(WOLFSSH_NO_ECDSA_SHA2_NISTP384) && \
defined(WOLFSSH_NO_ECDSA_SHA2_NISTP521) && \
defined(WOLFSSH_NO_ED25519) && \
defined(WOLFSSH_NO_MLDSA44) && \
defined(WOLFSSH_NO_MLDSA65) && \
defined(WOLFSSH_NO_MLDSA87) && \
!defined(WOLFSSH_NO_SHA1_SOFT_DISABLE)
#error "The only signing algorithms left are soft-disabled. Define " \
"WOLFSSH_NO_SHA1_SOFT_DISABLE to offer them."
#endif
#if defined(WOLFSSH_NO_SSH_RSA_SHA1) && \
defined(WOLFSSH_NO_RSA_SHA2_256) && \
defined(WOLFSSH_NO_RSA_SHA2_512)
#undef WOLFSSH_NO_RSA
#define WOLFSSH_NO_RSA
#endif
#if defined(WOLFSSH_NO_ECDSA_SHA2_NISTP256) && \
defined(WOLFSSH_NO_ECDSA_SHA2_NISTP384) && \
defined(WOLFSSH_NO_ECDSA_SHA2_NISTP521)
#undef WOLFSSH_NO_ECDSA
#define WOLFSSH_NO_ECDSA
#endif
#if defined(WOLFSSH_NO_RSA) && defined(WOLFSSH_NO_ECDSA) && \
defined(WOLFSSH_NO_ED25519) && defined(WOLFSSH_NO_MLDSA)
#undef WOLFSSH_NO_PUBKEY_AUTH
#define WOLFSSH_NO_PUBKEY_AUTH
#endif
/* A composite needs an ML-DSA level and a traditional algorithm. */
#if (defined(WOLFSSH_NO_MLDSA44) && defined(WOLFSSH_NO_MLDSA65) && \
defined(WOLFSSH_NO_MLDSA87)) || \
(defined(WOLFSSH_NO_ECDSA) && defined(WOLFSSH_NO_ED25519) && \
!defined(HAVE_ED448))
#undef WOLFSSH_NO_MLDSA_COMPOSITES
#define WOLFSSH_NO_MLDSA_COMPOSITES
#endif
#if defined(WOLFSSH_NO_RSA) || \
(defined(WOLFSSH_NO_RSA_SHA2_256) && defined(WOLFSSH_NO_RSA_SHA2_512))
#undef WOLFSSH_NO_OSSH_CERT_RSA
#define WOLFSSH_NO_OSSH_CERT_RSA
#endif
#ifdef WOLFSSH_NO_AEAD
#undef WOLFSSH_NO_AES_GCM
#define WOLFSSH_NO_AES_GCM
#endif
#if defined(NO_AES) || !defined(HAVE_AES_CBC)
#undef WOLFSSH_NO_AES_CBC
#define WOLFSSH_NO_AES_CBC
#endif
#if defined(NO_AES) || !defined(WOLFSSL_AES_COUNTER)
#undef WOLFSSH_NO_AES_CTR
#define WOLFSSH_NO_AES_CTR
#endif
#if defined(NO_AES) || !defined(HAVE_AESGCM)
#undef WOLFSSH_NO_AES_GCM
#define WOLFSSH_NO_AES_GCM
#endif
#if defined(WOLFSSH_NO_AES_CBC) && \
defined(WOLFSSH_NO_AES_CTR) && \
defined(WOLFSSH_NO_AES_GCM)
#error "You need at least one encryption algorithm."
#endif
/* AES-CBC is the only soft-disabled cipher. */
#if defined(WOLFSSH_NO_AES_CTR) && \
defined(WOLFSSH_NO_AES_GCM) && \
!defined(WOLFSSH_NO_AES_CBC_SOFT_DISABLE)
#error "The only encryption algorithms left are soft-disabled. Define " \
"WOLFSSH_NO_AES_CBC_SOFT_DISABLE to offer them."
#endif
#if defined(WOLFSSH_NO_AES_GCM)
#undef WOLFSSH_NO_AEAD
#define WOLFSSH_NO_AEAD
#endif
/* FPKI support turned off if wolfSSL linking to is not compiled with FPKI */
#if !defined(WOLFSSL_FPKI)
#undef WOLFSSH_NO_FPKI
#define WOLFSSH_NO_FPKI
#endif
WOLFSSH_LOCAL const char* GetErrorString(int err);
enum {
/* Any of the items can be none. */
ID_NONE,
/* Encryption IDs */
ID_AES128_CBC,
ID_AES192_CBC,
ID_AES256_CBC,
ID_AES128_CTR,
ID_AES192_CTR,
ID_AES256_CTR,
ID_AES128_GCM,
ID_AES192_GCM,
ID_AES256_GCM,
/* Integrity IDs */
ID_HMAC_SHA1,
ID_HMAC_SHA1_96,
ID_HMAC_SHA2_256,
ID_HMAC_SHA2_512,
/* Key Exchange IDs */
ID_DH_GROUP1_SHA1,
ID_DH_GROUP14_SHA1,
ID_DH_GROUP14_SHA256,
ID_DH_GROUP16_SHA512,
ID_DH_GEX_SHA256,
ID_ECDH_SHA2_NISTP256,
ID_ECDH_SHA2_NISTP384,
ID_ECDH_SHA2_NISTP521,
#ifndef WOLFSSH_NO_NISTP256_MLKEM768_SHA256
ID_NISTP256_MLKEM768_SHA256,
#endif
#ifndef WOLFSSH_NO_NISTP384_MLKEM1024_SHA384
ID_NISTP384_MLKEM1024_SHA384,
#endif
#ifndef WOLFSSH_NO_CURVE25519_MLKEM768_SHA256
ID_CURVE25519_MLKEM768_SHA256,
#endif
#ifndef WOLFSSH_NO_CURVE25519_SHA256
ID_CURVE25519_SHA256,
ID_CURVE25519_SHA256_LIBSSH,
#endif
ID_EXTINFO_S, /* Pseudo-KEX to indicate server extensions. */
ID_EXTINFO_C, /* Pseudo-KEX to indicate client extensions. */
/* Public Key IDs */
ID_SSH_RSA,
ID_RSA_SHA2_256,
ID_RSA_SHA2_512,
ID_ECDSA_SHA2_NISTP256,
ID_ECDSA_SHA2_NISTP384,
ID_ECDSA_SHA2_NISTP521,
ID_ED25519,
/* ML-DSA enum values shift with configs.
* Internal-only, never serialized. */
#ifndef WOLFSSH_NO_MLDSA
ID_MLDSA44,
ID_MLDSA65,
ID_MLDSA87,
/* always declared */
ID_MLDSA44_ES256,
ID_MLDSA65_ES256,
ID_MLDSA87_ES384,
ID_MLDSA44_ED25519,
ID_MLDSA65_ED25519,
ID_MLDSA87_ED448,
#endif
ID_X509V3_SSH_RSA,
ID_X509V3_ECDSA_SHA2_NISTP256,
ID_X509V3_ECDSA_SHA2_NISTP384,
ID_X509V3_ECDSA_SHA2_NISTP521,
#ifndef WOLFSSH_NO_MLDSA
ID_X509V3_MLDSA44,
ID_X509V3_MLDSA65,
ID_X509V3_MLDSA87,
#endif
/* OpenSSH cert algorithms. Internal-only, never serialized. */
#ifdef WOLFSSH_OSSH_CERTS
ID_OSSH_CERT_RSA,
ID_OSSH_CERT_ECDSA_SHA2_NISTP256,
ID_OSSH_CERT_ECDSA_SHA2_NISTP384,
ID_OSSH_CERT_ECDSA_SHA2_NISTP521,
ID_OSSH_CERT_ED25519,
#endif
/* Service IDs */
ID_SERVICE_USERAUTH,
ID_SERVICE_CONNECTION,
/* UserAuth IDs */
ID_USERAUTH_PASSWORD,
ID_USERAUTH_PUBLICKEY,
#ifdef WOLFSSH_KEYBOARD_INTERACTIVE
ID_USERAUTH_KEYBOARD,
#endif
/* Channel Type IDs */
ID_CHANTYPE_SESSION,
ID_CHANTYPE_TCPIP_FORWARD,
ID_CHANTYPE_TCPIP_DIRECT,
ID_CHANTYPE_AUTH_AGENT,
/* Global Request IDs */
ID_GLOBREQ_TCPIP_FWD,
ID_GLOBREQ_TCPIP_FWD_CANCEL,
ID_EXTINFO_SERVER_SIG_ALGS,
ID_CURVE_NISTP256,
ID_CURVE_NISTP384,
ID_CURVE_NISTP521,
ID_UNKNOWN
};
enum NameIdType {
TYPE_KEX, TYPE_KEY, TYPE_CIPHER, TYPE_MAC, TYPE_OTHER
};
#define WOLFSSH_MAX_NAMESZ 32
#ifndef WOLFSSH_MAX_CHN_NAMESZ
#define WOLFSSH_MAX_CHN_NAMESZ 4096
#endif
#define MAX_ENCRYPTION 3
#define MAX_INTEGRITY 2
#define MAX_KEY_EXCHANGE 2
#define MAX_PUBLIC_KEY 1
#define MIN_RSA_SIG_SZ 2
#define MAX_HMAC_SZ WC_MAX_DIGEST_SIZE
#define MIN_BLOCK_SZ 8
#define COOKIE_SZ 16
#define PAD_LENGTH_SZ 1
#define MIN_PAD_LENGTH 4
#define BOOLEAN_SZ 1
#define MSG_ID_SZ 1
#define SHA1_96_SZ 12
#define UINT32_SZ 4
#define LENGTH_SZ UINT32_SZ
#define SSH_PROTO_SZ 8 /* "SSH-2.0-" */
#define TERMINAL_MODE_SZ 5 /* opcode byte + argument uint32 */
#define TERMINAL_MODES_MAX_SZ 4096
#define TERMINAL_WIDTH_DEFAULT 80 /* used when there is no terminal */
#define TERMINAL_HEIGHT_DEFAULT 24
#define TERMINAL_DIMENSION_MAX 65535 /* what struct winsize can hold */
#define AEAD_IMP_IV_SZ 4
#define AEAD_EXP_IV_SZ 8
#define AEAD_NONCE_SZ (AEAD_IMP_IV_SZ+AEAD_EXP_IV_SZ)
#ifndef DEFAULT_HIGHWATER_MARK
#define DEFAULT_HIGHWATER_MARK ((1024 * 1024 * 1024) - (32 * 1024))
#endif
#ifndef WOLFSSH_DEFAULT_MSG_HIGHWATER_MARK
#define WOLFSSH_DEFAULT_MSG_HIGHWATER_MARK 0x80000000U
#endif
#ifndef DEFAULT_WINDOW_SZ
#define DEFAULT_WINDOW_SZ (128 * 1024)
#endif
#ifndef WINDOW_SZ_UPPER_BOUND
/* Upper bound accepted by wolfSSH_CTX_SetWindowPacketSize(). */
#define WINDOW_SZ_UPPER_BOUND (256 * 1024)
#endif
#ifndef DEFAULT_MAX_PACKET_SZ
/* This is from RFC 4253 section 6.1. */
#define DEFAULT_MAX_PACKET_SZ 32768
#endif
#ifndef DEFAULT_NEXT_CHANNEL
#define DEFAULT_NEXT_CHANNEL 0
#endif
#ifndef DEFAULT_MAX_AUTH_ATTEMPTS
/* Server-side cap on failed userauth attempts, same value as the OpenSSH
* MaxAuthTries default. */
#define DEFAULT_MAX_AUTH_ATTEMPTS 6
#endif
#ifndef MAX_PACKET_SZ
/* This is from RFC 4253 section 6.1. */
#define MAX_PACKET_SZ 35000
#endif
#ifndef WOLFSSH_MAX_NAMELIST_SZ
/* Per-field byte cap on a peer-supplied SSH name-list. */
#define WOLFSSH_MAX_NAMELIST_SZ 4096
#endif
#ifndef WOLFSSH_MAX_NAMELIST_CNT
/* Per-field cap on the number of names in a name-list. */
#define WOLFSSH_MAX_NAMELIST_CNT 64
#endif
#ifndef WOLFSSH_DEFAULT_GEXDH_MIN
#define WOLFSSH_DEFAULT_GEXDH_MIN 2048
#endif
#ifndef WOLFSSH_RSA_MIN_KEY_BITS
/* Minimum accepted RSA public-key size (bits) for user authentication.
* Per NIST SP 800-131A; override at build time if a smaller key must be
* accepted. */
#define WOLFSSH_RSA_MIN_KEY_BITS 2048
#endif
#ifndef WOLFSSH_DEFAULT_GEXDH_PREFERRED
#define WOLFSSH_DEFAULT_GEXDH_PREFERRED 3072
#endif
#ifndef WOLFSSH_DEFAULT_GEXDH_MAX
#define WOLFSSH_DEFAULT_GEXDH_MAX 8192
#endif
/* Floor on the GEX modulus, enforced when the server selects a group and when
* the client accepts one (RFC 8270). Lowering it below 2048 re-enables group
* 1, when group 1 is compiled in. */
#ifndef WOLFSSH_DH_GEX_MIN_BITS
#define WOLFSSH_DH_GEX_MIN_BITS 2048
#endif
/* Size of the buffer holding the server's KEX public value f. For DH this
* bounds the modulus: a p of n bytes needs n+1 here for the mpint sign pad. */
#ifndef KEX_F_SIZE
#ifndef WOLFSSH_NO_NISTP384_MLKEM1024_SHA384
/* Size of ML-KEM-1024 ciphertext (1568) plus ECC P-384 component
* (97). */
#define KEX_F_SIZE 1700
#elif !defined(WOLFSSH_NO_NISTP256_MLKEM768_SHA256) || \
!defined(WOLFSSH_NO_CURVE25519_MLKEM768_SHA256)
/* Size of ML-KEM-768 public key (1184) plus ECC/X25519 component. */
#define KEX_F_SIZE 1300
#elif !defined(WOLFSSH_NO_DH_GROUP16_SHA512)
#define KEX_F_SIZE (512 + 1)
#else
#define KEX_F_SIZE (256 + 1)
#endif
#endif
/* The KeyAgree*_server paths do not bound-check KEX_F_SIZE at runtime, so
* assert here that an override still holds every enabled algorithm's f. DH GEX
* needs no assert: SelectKexDhGexGroup caps itself at (KEX_F_SIZE - 1) * 8
* bits. A DH-disabled build writes no DH f and its ECDH points fit the 257-byte
* default, so the DH floor is guarded on WOLFSSH_NO_DH. */
#ifndef WOLFSSH_NO_DH
#if KEX_F_SIZE < (256 + 1)
#error "KEX_F_SIZE too small for DH group 14 (2048-bit p needs 257 bytes)"
#endif
#endif
#if !defined(WOLFSSH_NO_NISTP384_MLKEM1024_SHA384) && KEX_F_SIZE < 1700
#error "KEX_F_SIZE too small for the ML-KEM-1024 ciphertext"
#endif
#if (!defined(WOLFSSH_NO_NISTP256_MLKEM768_SHA256) || \
!defined(WOLFSSH_NO_CURVE25519_MLKEM768_SHA256)) && KEX_F_SIZE < 1300
#error "KEX_F_SIZE too small for the ML-KEM-768 artifact"
#endif
#if !defined(WOLFSSH_NO_DH_GROUP16_SHA512) && KEX_F_SIZE < (512 + 1)
#error "KEX_F_SIZE too small for DH group 16 (4096-bit p needs 513 bytes)"
#endif
#ifndef MAX_KEX_KEY_SZ
#ifndef WOLFSSH_NO_NISTP384_MLKEM1024_SHA384
/* Private key size of ML-KEM 1024. Biggest artifact. */
#define MAX_KEX_KEY_SZ 3168
#elif !defined(WOLFSSH_NO_NISTP256_MLKEM768_SHA256) || \
!defined(WOLFSSH_NO_CURVE25519_MLKEM768_SHA256)
/* Private key size of ML-KEM 768. Biggest artifact. */
#define MAX_KEX_KEY_SZ 2400
#else
/* This is based on the 8192-bit DH key that is the max size. */
#define MAX_KEX_KEY_SZ (WOLFSSH_DEFAULT_GEXDH_MAX / 8)
#endif
#endif
#ifndef WOLFSSH_MR_ROUNDS
#define WOLFSSH_MR_ROUNDS 8
#endif
#ifndef WOLFSSH_MAX_FILE_SIZE
#define WOLFSSH_MAX_FILE_SIZE (1024ul * 1024ul * 4)
#endif
#ifndef WOLFSSH_MAX_PVT_KEYS
/* 3 default host keys (RSA, ECDSA, Ed25519) + 3 plain ML-DSA levels +
* 6 ML-DSA composite combos, with headroom for future combos. */
#define WOLFSSH_MAX_PVT_KEYS 16
#endif
#ifndef WOLFSSH_MAX_PUB_KEY_ALGO
#define WOLFSSH_MAX_PUB_KEY_ALGO (WOLFSSH_MAX_PVT_KEYS + 2)
#endif
#ifndef WOLFSSH_KEY_QUANTITY_REQ
#define WOLFSSH_KEY_QUANTITY_REQ 1
#endif
/* Maximum pre-version banner lines accepted by DoProtoId (RFC 4253 4.2)
* before requiring the SSH version string. Each line is also capped at
* 255 bytes by GetInputLine. */
#ifndef WOLFSSH_MAX_BANNER_LINES
#define WOLFSSH_MAX_BANNER_LINES 10
#endif
/* RFC 4253 4.2. Documented as a literal 255 on
* wolfSSH_CTX_SetSshProtoIdStr() in the public ssh.h; keep in sync. */
#define WOLFSSH_PROTOID_LIMIT 255
/* Keep track of keying state for both sides of the connection.
* WOLFSSH_SELF_IS_KEYING gets set on sending KEX init and
* WOLFSSH_PEER_IS_KEYING gets set on receiving KEX init */
#define WOLFSSH_PEER_IS_KEYING 0x01
#define WOLFSSH_SELF_IS_KEYING 0x02
WOLFSSH_LOCAL byte NameToId(const char* name, word32 nameSz);
WOLFSSH_LOCAL const char* IdToName(byte id);
WOLFSSH_LOCAL const char* NameByIndexType(byte type, word32* idx);
/* Validate a comma-separated algorithm list against a category (a TYPE_* value).
* Unknown names are skipped, so a caller can pass a portable superset; a known
* name of the wrong category is rejected, and at least one usable name must
* remain. One trailing comma is allowed, as the canned lists carry one; any
* other empty element is rejected, since only that one is stripped before the
* list goes on the wire. "none" is rejected for TYPE_KEY, and accepted for
* TYPE_CIPHER/TYPE_MAC only under WOLFSSH_ALLOW_NONE_CIPHER
* (--enable-none-cipher) -- an insecure, testing-only plaintext transport.
* Returns WS_SUCCESS or WS_INVALID_ALGO_ID; a NULL list is invalid. */
WOLFSSH_LOCAL int CheckAlgoList(const char* list, byte type);
/* For cases when openssl coexist is used */
#ifdef WC_NO_COMPAT_AES_BLOCK_SIZE
#define AES_BLOCK_SIZE WC_AES_BLOCK_SIZE
#endif
#define STATIC_BUFFER_LEN AES_BLOCK_SIZE
/* This is one AES block size. We always grab one
* block size first to decrypt to find the size of
* the rest of the data. */
/* Channel data packet overhead: transport framing, the larger channel data
* header (CHANNEL_EXTENDED_DATA), worst-case BundlePacket() padding, and the
* largest MAC. Spelled twice because AES_BLOCK_SIZE and MAX_HMAC_SZ are enum
* constants that #if reads as zero. The literal is a ceiling: 101 with a
* 64-byte MAC, less with a smaller digest. */
#define CHANNEL_PACKET_OVERHEAD_SZ \
(LENGTH_SZ + PAD_LENGTH_SZ \
+ MSG_ID_SZ + (UINT32_SZ * 2) + LENGTH_SZ \
+ (AES_BLOCK_SIZE + MIN_PAD_LENGTH - 1) \
+ MAX_HMAC_SZ)
#define CHANNEL_PACKET_OVERHEAD_MAX 101
/* Largest channel payload that still fits MAX_PACKET_SZ on the wire, which
* bounds the whole binary packet. At most 35000 - 101 = 34899. Derived, not
* a tunable, so deliberately not overridable. */
#define MAX_CHANNEL_PACKET_SZ (MAX_PACKET_SZ - CHANNEL_PACKET_OVERHEAD_SZ)
/* Both sizes are overridable, and CtxInit() takes DEFAULT_MAX_PACKET_SZ
* unchecked, so assert the default frames too. */
#if DEFAULT_MAX_PACKET_SZ > (MAX_PACKET_SZ - CHANNEL_PACKET_OVERHEAD_MAX)
#error "DEFAULT_MAX_PACKET_SZ too large to frame inside MAX_PACKET_SZ"
#endif
typedef struct WOLFSSH_BUFFER {
void* heap; /* Heap for allocations */
int plainSz; /* amount of plain text bytes to send with WANT_WRITE */
word32 length; /* total buffer length used */
word32 idx; /* idx to part of length already consumed */
byte* buffer; /* place holder for actual buffer */
word32 bufferSz; /* current buffer size */
ALIGN16 byte staticBuffer[STATIC_BUFFER_LEN];
byte dynamicFlag; /* dynamic memory currently in use */
} WOLFSSH_BUFFER;
WOLFSSH_LOCAL int BufferInit(WOLFSSH_BUFFER* buffer, word32 size, void* heap);
WOLFSSH_LOCAL int GrowBuffer(WOLFSSH_BUFFER* buf, word32 sz);
WOLFSSH_LOCAL void ShrinkBuffer(WOLFSSH_BUFFER* buf, int forcedFree);
typedef struct WOLFSSH_PVT_KEY {
byte* key;
/* List of pointers to raw private keys. Owned by CTX. */
word32 keySz;
#ifdef WOLFSSH_CERTS
byte* cert;
/* Pointer to certificates for the private key. Owned by CTX. */
word32 certSz;
#endif
byte publicKeyFmt;
/* Public key format for the private key. Note, some public key
* formats are used with multiple public key signing algorithms. */
#ifdef WOLFSSH_TPM
byte isTpm;
/* When set, the host key material lives in the TPM and key/keySz are
* unused; signing and the public K_S come from ctx->tpmKey. */
#endif
#ifdef WOLFSSH_WINDOWS_CERT_STORE
byte useCertStore;
/* Flag indicating if this key is from MS Certificate Store. */
void* certStoreContext;
/* Windows certificate context (PCCERT_CONTEXT) for MS Certificate Store.
* Owned by CTX, must be freed with CertFreeCertificateContext. */
#endif /* WOLFSSH_WINDOWS_CERT_STORE */
} WOLFSSH_PVT_KEY;
#ifdef WOLFSSH_WINDOWS_CERT_STORE
/* Returns 1 when the value is exactly one assigned CERT_SYSTEM_STORE_*
* location with no control flags set. Defined in certman.c. */
WOLFSSH_LOCAL int wolfSSH_CertStoreLocationValid(word32 dwFlags);
#endif
#ifdef WOLFSSH_CERTS
/* Records the local endpoint (WOLFSSH_ENDPOINT_SERVER or _CLIENT) so the
* RFC 6187 key purpose check knows whether a user or host certificate is
* being verified. Unset accepts either. Defined in certman.c. */
WOLFSSH_LOCAL void wolfSSH_CERTMAN_SetSide(WOLFSSH_CERTMAN* cm, int side);
#endif
/* our wolfSSH Context */
struct WOLFSSH_CTX {
void* heap; /* heap hint */
WS_CallbackIORecv ioRecvCb; /* I/O Receive Callback */
WS_CallbackIOSend ioSendCb; /* I/O Send Callback */
WS_CallbackUserAuth userAuthCb; /* User Authentication Callback */
WS_CallbackUserAuthTypes userAuthTypesCb; /* Authentication Types Allowed */
WS_CallbackUserAuthResult userAuthResultCb; /* User Authentication Result */
WS_CallbackHighwater highwaterCb; /* Data Highwater Mark Callback */
WS_CallbackGlobalReq globalReqCb; /* Global Request Callback */
WS_CallbackReqSuccess reqSuccessCb; /* Global Request Success Callback */
WS_CallbackReqSuccess reqFailureCb; /* Global Request Failure Callback */
WS_CallbackChannelOpen channelOpenCb; /* Channel Open Requested */
WS_CallbackChannelOpen channelOpenConfCb; /* Channel Open Confirm */
WS_CallbackChannelOpen channelOpenFailCb; /* Channel Open Fail */
WS_CallbackChannelReq channelReqShellCb; /* Channel Request "Shell" */
WS_CallbackChannelReq channelReqExecCb; /* Channel Request "Exec" */
WS_CallbackChannelReq channelReqSubsysCb; /* Channel Request "Subsystem" */
WS_CallbackChannelEof channelEofCb; /* Channel Eof Callback */
WS_CallbackChannelClose channelCloseCb; /* Channel Close Callback */
#ifdef WOLFSSH_SCP
WS_CallbackScpRecv scpRecvCb; /* SCP receive callback */
WS_CallbackScpSend scpSendCb; /* SCP send callback */
#endif
#ifdef WOLFSSH_AGENT
WS_CallbackAgent agentCb; /* WOLFSSH-AGENT callback */
WS_CallbackAgentIO agentIoCb; /* WOLFSSH-AGENT IO callback */
#endif /* WOLFSSH_AGENT */
#ifdef WOLFSSH_FWD
WS_CallbackFwd fwdCb; /* WOLFSSH-FWD callback */
WS_CallbackFwdIO fwdIoCb; /* WOLFSSH-FWD IO callback */
#endif /* WOLFSSH_FWD */
#ifdef WOLFSSH_CERTS
WOLFSSH_CERTMAN* certMan;
#endif /* WOLFSSH_CERTS */
WS_CallbackPublicKeyCheck publicKeyCheckCb;
/* Check server's public key callback */
WOLFSSH_PVT_KEY privateKey[WOLFSSH_MAX_PVT_KEYS];
word32 privateKeyCount;
byte publicKeyAlgo[WOLFSSH_MAX_PUB_KEY_ALGO];
word32 publicKeyAlgoCount;
word32 highwaterMark;
word32 msgHighwaterMark;
const char* banner;
const char* sshProtoIdStr;
const char* algoListKex;
const char* algoListKey;
const char* algoListCipher;
const char* algoListMac;
const char* algoListKeyAccepted;
word32 bannerSz;
word32 windowSz;
word32 maxPacketSz;
word32 maxAuthAttempts; /* server cap on failed userauth */
byte side; /* client or server */
byte showBanner;
#ifdef WOLFSSH_AGENT
byte agentEnabled;
#endif /* WOLFSSH_AGENT */
#ifdef WOLFSSH_TPM
WOLFTPM2_DEV* tpmDev;
WOLFTPM2_KEY* tpmKey;
#endif /* WOLFSSH_TPM */
WS_CallbackKeyingCompletion keyingCompletionCb;
};
typedef struct Ciphers {
Aes aes;
byte cipherType;
byte isInit;
} Ciphers;
typedef struct Keys {
byte iv[AES_BLOCK_SIZE];
byte ivSz;
byte encKey[AES_256_KEY_SIZE];
byte encKeySz;
byte macKey[MAX_HMAC_SZ];
byte macKeySz;
} Keys;
typedef struct HandshakeInfo {
byte expectMsgId;
byte kexId;
byte kexHashId;
byte pubKeyId;
byte encryptId;
byte macId;
byte aeadMode;
byte peerEncryptId;
byte peerMacId;
byte peerAeadMode;
byte blockSz;
byte macSz;
byte peerBlockSz;
byte peerMacSz;
word32 bannerLines;
Keys keys;
Keys peerKeys;
wc_HashAlg kexHash;
byte e[MAX_KEX_KEY_SZ+1]; /* May have a leading zero for unsigned
or is a Q_S value. */
word32 eSz;
byte x[MAX_KEX_KEY_SZ+1]; /* May have a leading zero, for unsigned. */
word32 xSz;
byte* kexInit;
word32 kexInitSz;
#ifndef WOLFSSH_NO_DH
word32 dhGexMinSz;
word32 dhGexPreferredSz;
word32 dhGexMaxSz;
/* GEX group cache, role-dependent. Server: SendKexDhGexGroup stores the
* group it chose and leaves generator NULL, meaning dhGenerator. Client:
* DoKexDhGexGroup stores the group the peer sent and its generator. A NULL
* primeGroup means no GROUP crossed the wire. */
byte* primeGroup;
word32 primeGroupSz;
byte* generator;
word32 generatorSz;
#endif
byte ignoreNextKexMsg:1;
byte useDh:1;
byte useEcdh:1;
byte useCurve25519:1;
byte useMlKem:1;
#ifdef WOLFSSH_TPM
byte useTpm:1;
#endif
union {
#ifndef WOLFSSH_NO_DH
DhKey dh;
#endif
#ifndef WOLFSSH_NO_ECDH
ecc_key ecc;
#endif
#if !defined(WOLFSSH_NO_CURVE25519_SHA256) || \
!defined(WOLFSSH_NO_CURVE25519_MLKEM768_SHA256)
curve25519_key curve25519;
#endif
} privKey;
} HandshakeInfo;
#if (defined(WOLFSSH_SFTP) || defined(WOLFSSH_SCP)) && \
!defined(NO_WOLFSSH_SERVER)
WOLFSSH_LOCAL int wolfSSH_GetPath(const char* defaultPath, byte* in,
word32 inSz, char* out, word32* outSz);
#endif
#ifdef WOLFSSH_SFTP
#define WOLFSSH_MAX_SFTPOFST 3
/* Maximum number of open handles tracked per session, applied separately to
* the file list and the directory list, so the worst case for one session is
* twice this value. Bounds memory use and keeps the linear handle lookup from
* becoming a CPU DoS vector. Must be at least 1; there is no "unlimited"
* setting, and 0 yields a cap of one handle per list. */
#ifndef WOLFSSH_MAX_SFTP_HANDLES
#define WOLFSSH_MAX_SFTP_HANDLES 64
#endif
/* The counts are unsigned, so a value below 1 would either cap at one handle
* or, for a negative value, never compare true and drop the cap entirely. */
#if WOLFSSH_MAX_SFTP_HANDLES < 1
#error "WOLFSSH_MAX_SFTP_HANDLES must be at least 1"
#endif
#ifndef NO_WOLFSSH_DIR
typedef struct WS_DIR_LIST WS_DIR_LIST;
#endif
typedef struct WS_FILE_LIST WS_FILE_LIST;
typedef struct SFTP_OFST {
word32 offset[2];
char from[WOLFSSH_MAX_FILENAME];
char to[WOLFSSH_MAX_FILENAME];
} SFTP_OFST;
struct WS_SFTP_RECV_INIT_STATE;
struct WS_SFTP_GET_STATE;
struct WS_SFTP_PUT_STATE;
struct WS_SFTP_LSTAT_STATE;
struct WS_SFTP_OPEN_STATE;
struct WS_SFTP_CLOSE_STATE;
struct WS_SFTP_SEND_READ_STATE;
struct WS_SFTP_SEND_WRITE_STATE;
struct WS_SFTP_GET_HANDLE_STATE;
struct WS_SFTP_PUT_STATE;
struct WS_SFTP_RENAME_STATE;
#ifdef USE_WINDOWS_API
#define MAX_DRIVE_LETTER 26
#endif /* USE_WINDOWS_API */
#endif /* WOLFSSH_SFTP */
#ifdef USE_WINDOWS_API
#ifndef WOLFSSL_MAX_ESCBUF
#define WOLFSSL_MAX_ESCBUF 19
#endif
#endif
struct WOLFSSH_AGENT_CTX;
#ifdef WOLFSSH_FWD
/* Most want-reply global requests a session may have outstanding at once. The
* peer gives a slot back by answering, so a peer that never does would
* otherwise let the queue grow for the life of the session. Set high enough
* that a non-blocking application pipelining setups stays well under it. */
#ifndef WOLFSSH_MAX_FWD_REPLIES
#define WOLFSSH_MAX_FWD_REPLIES 1024
#endif
/* A remote forward this client asked the peer to listen on with
* wolfSSH_FwdRemoteSetup(), kept so an inbound forwarded-tcpip open can be
* matched against it. */
typedef struct WOLFSSH_FWD_REMOTE {
struct WOLFSSH_FWD_REMOTE* next;
char* bindAddr;
word32 bindPort; /* port the peer bound, 0 while still unknown */
byte portPending; /* asked for port 0, so the reply names the port */
byte confirmed; /* the peer bound it, or nothing will ever say */
} WOLFSSH_FWD_REMOTE;
/* One want-reply global request waiting on the peer. Replies carry no request
* id, so the queue answers them in send order. Requests an application sent
* through wolfSSH_global_request() queue here too with a NULL entry, so their
* replies consume their own slot instead of a forward's.
*
* Several requests can name one forward, and this queue is the only record of
* which are outstanding and of the order they will be answered in. What the
* application last asked for is the last slot naming the forward. */
typedef struct WOLFSSH_FWD_REPLY {
struct WOLFSSH_FWD_REPLY* next;
WOLFSSH_FWD_REMOTE* entry; /* forward answered, NULL once it is gone or if
* the application sent the request */
const char* bindAddr; /* bind this slot will name once it commits, so
* the scans can see it meanwhile. Borrowed from
* the caller and dropped at commit, the same
* lifetime WOLFSSH_FWD_PENDING assumes. NULL
* once committed. */
word32 bindPort;
word32 port; /* port a parked answer named */
byte isCancel; /* answers cancel-tcpip-forward */
byte uncommitted; /* its request has not reached the wire, so the
* sender still owns this slot */
byte answered; /* answered while still uncommitted, so the
* verdict is parked here for the commit */
byte success; /* what that parked answer said */
} WOLFSSH_FWD_REPLY;
/* Bookkeeping for a global request that has not been sent yet. Everything that
* can fail is allocated into one of these first, so a caller that gets an error
* back knows nothing reached the peer.
*
* Sending runs application callbacks that may reenter the library and send
* requests of their own, so one of these is on the session's list of requests
* in flight for the length of its send. That is what lets a reentrant request
* see the forward the request it interrupted is registering, and what keeps a
* request from resolving to a registration made after it went out. Nothing on
* the list outlives its send: the frame that owns it cannot return until every
* call it made has. */
typedef struct WOLFSSH_FWD_PENDING {
struct WOLFSSH_FWD_PENDING* next; /* next request in flight */
WOLFSSH_FWD_REMOTE* entry; /* new registration to link on commit */
WOLFSSH_FWD_REMOTE* found; /* registration this request named, if it was
* already there. Cleared if it is freed
* mid-send, so a commit never settles a
* registration that is gone or one that
* replaced it. */
WOLFSSH_FWD_REPLY* reply; /* reply slot to queue on commit */
byte isCancel;
} WOLFSSH_FWD_PENDING;
#endif /* WOLFSSH_FWD */
/* our wolfSSH session */
struct WOLFSSH {
WOLFSSH_CTX* ctx; /* owner context */
int error;
WS_SOCKET_T rfd;
WS_SOCKET_T wfd;
void* ioReadCtx; /* I/O Read Context handle */
void* ioWriteCtx; /* I/O Write Context handle */
int rflags; /* optional read flags */
int wflags; /* optional write flags */
word32 txCount;
word32 rxCount;
word32 txMsgCount; /* Packets sent under current keys */
word32 rxMsgCount; /* Packets received under current keys */
word32 txFlushCount; /* Output buffer drained, whatever came after */
word32 highwaterMark;
word32 msgHighwaterMark; /* Per-key packet limit (RFC 4344 Sec 3.1) */
byte highwaterFlag; /* Set when highwater CB called */
byte msgHighwaterFlag; /* Set when msg-count highwater CB called */
void* highwaterCtx; /* Highwater CB context */
void* globalReqCtx; /* Global Request CB context */
void* reqSuccessCtx; /* Global Request Success CB context */
void* reqFailureCtx; /* Global Request Failure CB context */
void* channelOpenCtx; /* Channel Open CB context */
void* channelReqCtx; /* Channel Request CB context */
void* channelEofCtx; /* Channel EOF CB context */
void* channelCloseCtx; /* Channel Close CB context */
void* fs; /* File system handle */
word32 curSz;
word32 seq;
word32 peerSeq;
word32 packetStartIdx; /* Current send packet start index */
const char* algoListKex;
const char* algoListKey;
const char* algoListCipher;
const char* algoListMac;
const char* algoListKeyAccepted;
byte acceptState;
byte connectState;
byte clientState;
byte serverState;
byte processReplyState;
byte isKeying;
byte authId; /* if using public key or password */
byte supportedAuth[4]; /* supported auth IDs public key , password */
#ifdef WOLFSSH_SCP
byte scpState;
byte scpNextState;
byte scpRequestState;
byte scpFileState;
byte scpDirection; /* indicates sending TO (t) of FROM (f) */
int scpConfirm; /* confirmation state (OK|WARN|FATAL) */
char* scpConfirmMsg; /* dynamic, confirm message string */
word32 scpConfirmMsgSz; /* length of confirmMsg, not including \0 */
char* scpRecvMsg; /* reading up to newline delimiter */
int scpRecvMsgSz; /* current size of scp recv message */
const char* scpBasePath; /* base path, ptr into channelList->command */
/* alter base path instead of using chdir */
char* scpBasePathDynamic; /* dynamic base path */
word32 scpBasePathSz;
byte scpIsRecursive; /* recursive transfer requested */
byte scpRequestType; /* directory or single file */
byte scpMsgType;
int scpFileMode; /* mode/permission of file/dir */
word32 scpFileSz; /* total size of file/dir being transferred */
char* scpFileName; /* file name, dynamic */
char* scpFileReName; /* file rename case, points to scpFileName */
word32 scpFileNameSz; /* length of fileName, not including \0 */
word32 scpFileNameCap; /* bytes allocated for scpFileName, including
* room for the terminating \0 */
byte scpTimestamp; /* did peer request timestamp? {0:1} */
word64 scpATime; /* scp file access time, secs since epoch */
word64 scpMTime; /* scp file modification time, secs epoch */
byte* scpFileBuffer; /* transfer buffer, dynamic */
word32 scpFileBufferSz; /* size of transfer buffer, octets */
word32 scpFileOffset; /* current offset into file transfer */
word32 scpBufferedSz; /* bytes buffered to send to peer */
byte scpFileHeaderSent; /* file header already sent for current file */
byte scpNoProgress; /* send callback already handed back 0 bytes
* with file data still outstanding */
word32 scpDirDepth; /* SCP nested NEW_DIR depth below base path */
#ifdef WOLFSSL_NUCLEUS
int scpFd; /* SCP receive callback context handle */
#endif
void* scpRecvCtx; /* SCP receive callback context handle */
void* scpSendCtx; /* SCP send callback context handle */
#if !defined(WOLFSSH_SCP_USER_CALLBACKS) && !defined(NO_FILESYSTEM)
ScpSendCtx scpSendCbCtx; /* used in default case to for send cb ctx */
#endif
#endif
byte connReset;
byte isClosed;
/* Set when a DISCONNECT is sent or received. Gates the public send
* calls, so nothing more goes out. Reads still hand back what arrived
* before the disconnect; the head-of-list reads report it once their
* buffer runs dry. wolfSSH_worker() reports it as well, so a drive loop
* stops turning; wolfSSH_shutdown() drops the channel first and so never
* pumps it. DoPacket() skips the inbound dispatch too, for every message
* but a DISCONNECT, so nothing arriving afterward is buffered, answered
* or reported through the channel callbacks. */
byte disconnected;
/* Set once SendDisconnect() has bundled our own DISCONNECT into the
* output buffer, and cleared once wolfSSH_SendPacket() drains it, so it
* means "a flush is owed" rather than "one was sent". The flag above
* cannot stand in for this: it does not say whose disconnect it was,
* and a peer's leaves only unrelated traffic queued. */
byte disconnectTxd;
byte clientOpenSSH;
#ifdef WOLFSSH_FWD
byte fwdCbMissingWarned; /* one-shot: missing fwdCb warned this session */
#endif
byte chanOpenCbMissingWarned; /* one-shot: missing channelOpenCb warned */
byte kexId;
byte blockSz;
byte encryptId;
byte macId;
byte macSz;
byte aeadMode;
byte peerBlockSz;
byte peerEncryptId;
byte peerMacId;
byte peerMacSz;
byte peerAeadMode;
#ifndef WOLFSSH_NO_DH
word32 primeGroupSz;
#endif
Ciphers encryptCipher;
Ciphers decryptCipher;
word32 nextChannel;
WOLFSSH_CHANNEL* channelList;
word32 channelListSz;
word32 defaultPeerChannelId;
word32 connectChannelId;
byte* channelName;
word32 channelNameSz;
word32 lastRxId;
WOLFSSH_BUFFER inputBuffer;
WOLFSSH_BUFFER outputBuffer;
WC_RNG* rng;
byte h[WC_MAX_DIGEST_SIZE];
word32 hSz;
byte k[MAX_KEX_KEY_SZ+1]; /* May have a leading zero, for unsigned. */
word32 kSz;
byte sessionId[WC_MAX_DIGEST_SIZE];
word32 sessionIdSz;
Keys keys;
Keys peerKeys;
HandshakeInfo* handshake;
void* userAuthCtx;
void* userAuthResultCtx;
#ifdef WOLFSSH_KEYBOARD_INTERACTIVE
void* keyboardAuthCtx;
#endif
char* userName;
word32 userNameSz;
char* password;
word32 passwordSz;
byte* pkBlob;
word32 pkBlobSz;
byte* peerProtoId; /* Save for rekey */
word32 peerProtoIdSz;
void* publicKeyCheckCtx;
byte sendTerminalRequest;
byte userAuthPkDone;
byte sendExtInfo;
byte extInfoSent; /* track if the ext info has already been sent */
byte* peerSigId;
word32 peerSigIdSz;
#ifdef USE_WINDOWS_API
word32 defaultAttr; /* default windows attributes */
byte defaultAttrSet;
byte escBuf[WOLFSSL_MAX_ESCBUF]; /* console codes are about 3 byte and
* have max arguments of 16 */
byte escBufSz;
byte escState; /* current console translation state */
#endif
#ifdef WOLFSSH_SFTP
word32 reqId;
byte sftpState;
byte realState;
byte sftpInt;
SFTP_OFST sftpOfst[WOLFSSH_MAX_SFTPOFST];
char* sftpDefaultPath; /* where a session starts, base for relative paths */
char* sftpConfinePath; /* jail root, NULL or "/" for unconfined */
#ifndef NO_WOLFSSH_DIR
WS_DIR_LIST* dirList;
#endif
/* Shared counter for both file and directory handle IDs. A single
* namespace guarantees IDs are unique across files and directories so a
* close request cannot match the wrong resource type. */
word32 handleIdCount[2];
WS_FILE_LIST* fileList;
struct WS_SFTP_RECV_INIT_STATE* recvInitState;
struct WS_SFTP_RECV_STATE* recvState;
struct WS_SFTP_RMDIR_STATE* rmdirState;
struct WS_SFTP_MKDIR_STATE* mkdirState;
struct WS_SFTP_RM_STATE* rmState;
struct WS_SFTP_READDIR_STATE* readDirState;
struct WS_SFTP_SETATR_STATE* setatrState;
struct WS_SFTP_CHMOD_STATE* chmodState;
struct WS_SFTP_LS_STATE* lsState;
struct WS_SFTP_SEND_STATE* sendState;
struct WS_SFTP_NAME_STATE* nameState;
struct WS_SFTP_GET_STATE* getState;
struct WS_SFTP_PUT_STATE* putState;
struct WS_SFTP_LSTAT_STATE* lstatState;
struct WS_SFTP_OPEN_STATE* openState;
struct WS_SFTP_CLOSE_STATE* closeState;
struct WS_SFTP_SEND_READ_STATE* sendReadState;
struct WS_SFTP_SEND_WRITE_STATE* sendWriteState;
struct WS_SFTP_GET_HANDLE_STATE* getHandleState;
struct WS_SFTP_RENAME_STATE* renameState;
#ifdef USE_WINDOWS_API
char driveList[MAX_DRIVE_LETTER];
word16 driveListCount;
word16 driveIdx;
#endif
#endif
#ifdef WOLFSSH_AGENT
struct WOLFSSH_AGENT_CTX* agent;
void* agentCbCtx;
byte useAgent;
byte agentEnabled;
#endif /* WOLFSSH_AGENT */
#ifdef WOLFSSH_FWD
void* fwdCbCtx;
WOLFSSH_FWD_REMOTE* fwdRemoteList; /* remote forwards this client asked for */
WOLFSSH_FWD_REPLY* fwdReplyHead; /* oldest want-reply request owed */
WOLFSSH_FWD_REPLY* fwdReplyTail;
WOLFSSH_FWD_PENDING* fwdPendingHead; /* requests inside their own send */
word32 fwdReplyCount; /* slots queued, kept off the walk it bounds */
byte fwdRemoteMatch; /* WOLFSSH_FWD_MATCH_*, how strictly an inbound
* forwarded-tcpip must name a registration */
#endif /* WOLFSSH_FWD */
#ifdef WOLFSSH_TERM
WS_CallbackTerminalSize termResizeCb;
void* termCtx;
word32 widthChar; /* current terminal width */
word32 heightRows; /* current terminal height */
word32 widthPixels; /* pixel width */
word32 heightPixels; /* pixel height */
byte* modes;
word32 modesSz;
#endif
#if defined(WOLFSSH_TERM) || defined(WOLFSSH_SHELL)
word32 exitStatus;
#endif
void* keyingCompletionCtx;
#ifdef WOLFSSH_KEYBOARD_INTERACTIVE
WS_UserAuthData_Keyboard kbAuth;
byte kbAuthAttempts;
byte kbSetupPending; /* server sent INFO_REQUEST, awaiting a response */
#endif
#ifdef WOLFSSH_TPM
byte tpmPubkeyTried; /* client tried TPM publickey; allow auth fallback */
#endif
#ifdef WOLFSSH_TEST_INTERNAL
word32 testSftpSendCap; /* test hook: cap per-call SFTP buffer send */
word32 testSftpStallPending; /* test hook: force N flush-only resumes */
#endif
byte userAuthSeen; /* a userauth request has bound the username */
word32 maxAuthAttempts; /* server cap on failed userauth attempts */
word32 authFailures; /* count of failed userauth attempts */
word32 authRequests; /* count of userauth requests received */
};
struct WOLFSSH_CHANNEL {
byte channelType;
byte sessionType;
byte closeRxd : 1;
byte closeTxd : 1;
byte eofRxd : 1;
byte eofTxd : 1;
byte openConfirmed : 1;
byte ptyReq : 1; /* flag for if interactive pty request was received */
byte fwdSetupTxd : 1; /* a LOCAL_SETUP succeeded, a cleanup is owed */
word32 channel;
word32 windowSz;
word32 maxPacketSz;
word32 peerChannel;
word32 peerWindowSz;
word32 peerMaxPacketSz;
word32 pendingWindowAdjust; /* Receive-window credit owed to the peer but not
* sent yet: a rekey was in progress (RFC 4253
* section 7.1) or the WINDOW_ADJUST send failed.
* ChannelCreditWindow() folds it into the next
* adjust; SendPendingChannelWindowAdjust()
* flushes it when keying completes. */
#ifdef WOLFSSH_FWD
char* host;
word32 hostPort;
char* origin;
word32 originPort;
int fwdFd;
int isDirect;
#endif /* WOLFSSH_FWD */
WOLFSSH_BUFFER inputBuffer;
WOLFSSH_BUFFER extDataBuffer; /* Buffered extended data (stderr) awaiting the
* app, per channel like inputBuffer. Shares the
* receive window with ordinary data (RFC 4254
* section 5.2): charged against windowSz on
* arrival, credited back as the app drains it.
* Accumulates unread data, does not overwrite
* it. */
char* command;
struct WOLFSSH* ssh;
struct WOLFSSH_CHANNEL* next;
};
WOLFSSH_LOCAL WOLFSSH_CTX* CtxInit(WOLFSSH_CTX* ctx, byte side, void* heap);
WOLFSSH_LOCAL void CtxResourceFree(WOLFSSH_CTX* ctx);
WOLFSSH_LOCAL WOLFSSH* SshInit(WOLFSSH* ssh, WOLFSSH_CTX* ctx);
WOLFSSH_LOCAL void SshResourceFree(WOLFSSH* ssh, void* heap);
WOLFSSH_LOCAL WOLFSSH_CHANNEL* ChannelNew(WOLFSSH* ssh, byte channelType,
word32 initialWindowSz, word32 maxPacketSz);
WOLFSSH_LOCAL int ChannelUpdatePeer(WOLFSSH_CHANNEL* channel,
word32 peerChannelId, word32 peerInitialWindowSz,
word32 peerMaxPacketSz);
WOLFSSH_LOCAL int ChannelUpdateForward(WOLFSSH_CHANNEL* channel,
const char* host, word32 hostPort,
const char* origin, word32 originPort, int isDirect);
WOLFSSH_LOCAL int ChannelAppend(WOLFSSH* ssh, WOLFSSH_CHANNEL* channel);
WOLFSSH_LOCAL void ChannelDelete(WOLFSSH_CHANNEL* channel, void* heap);
WOLFSSH_LOCAL WOLFSSH_CHANNEL* ChannelFind(WOLFSSH* ssh, word32 channel,
byte peer);
WOLFSSH_LOCAL int ChannelRemove(WOLFSSH* ssh, word32 channel, byte peer);
WOLFSSH_LOCAL int ChannelPutData(WOLFSSH_CHANNEL* channel, byte* data,
word32 dataSz);
WOLFSSH_LOCAL int ChannelCreditWindow(WOLFSSH* ssh, WOLFSSH_CHANNEL* channel,
word32 amount);
WOLFSSH_LOCAL void RefreshPublicKeyAlgo(WOLFSSH_CTX* ctx);
WOLFSSH_LOCAL int wolfSSH_ProcessBuffer(WOLFSSH_CTX* ctx,
const byte* in, word32 inSz,
int format, int type);
#ifdef WOLFSSH_HAVE_TRUSTED_CERT_PEM
WOLFSSH_LOCAL int IsTrustedCertPem(const byte* in, word32 inSz);
#endif
#ifdef WOLFSSH_TPM
WOLFSSH_LOCAL int wolfSSH_SetHostTpmKey(WOLFSSH_CTX* ctx, byte keyId);
#endif
WOLFSSH_LOCAL int wolfSSH_FwdWorker(WOLFSSH* ssh);
#ifndef WOLFSSH_NO_MLDSA
/* Shared shape for a composite key's ML-DSA+traditional pair; reused
* in src/internal.c so the copies can't drift apart. */
typedef struct WS_MlDsaCompositeBody {
MlDsaKey mldsa;
union {
#ifndef WOLFSSH_NO_ECDSA
ecc_key ecc;
#endif
#ifndef WOLFSSH_NO_ED25519
ed25519_key ed25519;
#endif
#ifdef HAVE_ED448
ed448_key ed448;
#endif
#if defined(WOLFSSH_NO_ECDSA) && defined(WOLFSSH_NO_ED25519) && \
!defined(HAVE_ED448)
/* keep union non-empty */
byte placeholder;
#endif
} trad;
} WS_MlDsaCompositeBody;
#endif /* WOLFSSH_NO_MLDSA */
typedef struct WS_KeySignature {
byte keyId;
byte sigId;
word32 sigSz;
const char *keyName;
const char *sigName;
void *heap;
word32 keyNameSz;
word32 sigNameSz;
union {
#ifndef WOLFSSH_NO_RSA
struct {
RsaKey key;
} rsa;
#endif
#ifndef WOLFSSH_NO_ECDSA
struct {
ecc_key key;
} ecc;
#endif
#ifndef WOLFSSH_NO_ED25519
struct {
ed25519_key key;
} ed25519;
#endif
#ifndef WOLFSSH_NO_MLDSA
struct {
MlDsaKey key;
} mldsa;
WS_MlDsaCompositeBody mldsa_composite;
#endif /* WOLFSSH_NO_MLDSA */
} ks;
} WS_KeySignature;
#ifndef WOLFSSH_NO_ECDSA
#define ECDSA_ASN_SIG_SZ 256
#endif
#ifndef WOLFSSH_NO_MLDSA
#define TRAD_TYPE_ECC 1
#define TRAD_TYPE_ED25519 2
#define TRAD_TYPE_ED448 3
#define COMPOSITE_DOMAIN_PREFIX "CompositeAlgorithmSignatures2025"
#define COMPOSITE_DOMAIN_PREFIX_SZ 32
/* max label size */
#define COMPOSITE_MAX_LABEL_SZ 33
#define ECC_P256_COORD_SZ 32
#define ECC_P384_COORD_SZ 48
/* Max enabled ML-DSA raw public key size for buffers. */
#ifndef WOLFSSH_NO_MLDSA87
#define WOLFSSH_MLDSA_MAX_PUB_KEY_SZ WC_MLDSA_87_PUB_KEY_SIZE
#elif !defined(WOLFSSH_NO_MLDSA65)
#define WOLFSSH_MLDSA_MAX_PUB_KEY_SZ WC_MLDSA_65_PUB_KEY_SIZE
#else
#define WOLFSSH_MLDSA_MAX_PUB_KEY_SZ WC_MLDSA_44_PUB_KEY_SIZE
#endif
/* max trad pubkey size */
#define COMPOSITE_MAX_TRAD_PUB_SZ (1 + (2 * ECC_P384_COORD_SZ))
/* max trad privkey size */
#ifdef HAVE_ED448
#define COMPOSITE_MAX_TRAD_PRIV_SZ ED448_KEY_SIZE
#else
#define COMPOSITE_MAX_TRAD_PRIV_SZ ECC_P384_COORD_SZ
#endif
/* max trad sig size */
#ifdef HAVE_ED448
#define COMPOSITE_MAX_TRAD_SIG_SZ ED448_SIG_SIZE
#else
#define COMPOSITE_MAX_TRAD_SIG_SZ (2 * (LENGTH_SZ + ECC_P384_COORD_SZ + 1))
#endif
/* alloc slack */
#define COMPOSITE_SIG_ALLOC_SLACK_SZ 32
typedef struct CompositeParams {
const char* label;
word32 mldsaSigSz;
word32 mldsaPubSz;
word32 tradHashSz;
word32 labelSz;
word32 tradPubSz;
word32 tradSigSz;
word32 tradPrivSz;
enum wc_HashType tradHashId;
byte keyId;
byte mldsaLevel;
byte tradType;
int eccCurveId;
} CompositeParams;
/* trad dispatch table */
typedef struct CompositeTradOps {
int (*init)(void* key, void* heap);
void (*free)(void* key);
int (*makeKey)(void* key, WC_RNG* rng, const CompositeParams* params);
int (*importPub)(void* key, const byte* pub, word32 pubSz);
int (*importPriv)(void* key, const byte* priv, word32 privSz,
const byte* pub, word32 pubSz);
int (*exportPrivOnly)(void* key, byte* out, word32* outSz);
int (*exportPub)(void* key, byte* out, word32* outSz);
int (*sign)(void* key, WC_RNG* rng, void* heap,
enum wc_HashType tradHashId, word32 tradHashSz,
const byte* mPrime, word32 mPrimeLen,
byte* wireSig, word32* wireSigSz);
int (*verify)(void* key, void* heap,
enum wc_HashType tradHashId, word32 tradHashSz,
const byte* wireSig, word32 wireSigSz,
const byte* mPrime, word32 mPrimeLen);
byte tradType;
} CompositeTradOps;
WOLFSSH_LOCAL int WS_GetCompositeParams(byte keyId, CompositeParams* params);
WOLFSSH_LOCAL const CompositeTradOps* WS_GetTradOps(byte tradType);
/* Init composite key pair */
WOLFSSH_LOCAL int InitCompositeKeyPair(const CompositeParams* params,
MlDsaKey* mldsa, void* tradKey, const CompositeTradOps* ops,
void* heap, int* mldsaInit, int* tradInit);
WOLFSSH_LOCAL int WS_Hash_Helper(enum wc_HashType hashId, const byte* msg,
word32 msgSz, byte* hash, word32 hashSz);
#endif
WOLFSSH_LOCAL int IdentifyAsn1Key(const byte* in, word32 inSz, int isPrivate, void* heap,
WS_KeySignature **pkey);
WOLFSSH_LOCAL void wolfSSH_KEY_clean(WS_KeySignature* key);
WOLFSSH_LOCAL int IdentifyOpenSshKey(const byte* in, word32 inSz, void* heap);
WOLFSSH_LOCAL int GetOpenSshKey(WS_KeySignature *key,
const byte* buf, word32 len, word32* idx);
#ifdef WOLFSSH_TPM
WOLFSSH_LOCAL int GetOpenSshPublicKey(WS_KeySignature *key,
const byte* buf, word32 len, word32* idx);
#endif
#ifdef WOLFSSH_CERTS
WOLFSSH_LOCAL int IdentifyCert(const byte* in, word32 inSz, void* heap);
#endif
WOLFSSH_LOCAL int WS_StripOpenSshPem(const byte* in, word32 inSz,
byte* out, word32* outSz);
/* Parsing functions */
WOLFSSH_LOCAL int GetBoolean(byte* v,
const byte* buf, word32 len, word32* idx);
WOLFSSH_LOCAL int GetUint32(word32* v,
const byte* buf, word32 len, word32* idx);
#ifdef WOLFSSH_OSSH_CERTS
WOLFSSH_LOCAL int GetUint64(word64* v,
const byte* buf, word32 len, word32* idx);
#endif
WOLFSSH_LOCAL int GetSize(word32* v,
const byte* buf, word32 len, word32* idx);
WOLFSSH_LOCAL int GetSkip(const byte* buf, word32 len, word32* idx);
WOLFSSH_LOCAL int GetMpint(word32* mpintSz, const byte** mpint,
const byte* buf, word32 len, word32* idx);
WOLFSSH_LOCAL int GetString(char* s, word32* sSz,
const byte* buf, word32 len, word32* idx);
WOLFSSH_LOCAL int GetStringAlloc(void* heap, char** s, word32* sSz,
const byte* buf, word32 len, word32* idx);
WOLFSSH_LOCAL int GetStringRef(word32* strSz, const byte **str,
const byte* buf, word32 len, word32* idx);
#ifndef WOLFSSH_USER_IO
/* default I/O handlers */
WOLFSSH_LOCAL int wsEmbedRecv(WOLFSSH* ssh, void* data, word32 sz, void* ctx);
WOLFSSH_LOCAL int wsEmbedSend(WOLFSSH* ssh, void* data, word32 sz, void* ctx);
#endif /* WOLFSSH_USER_IO */
enum ChannelOpenFailReasons {
OPEN_OK = 0,
OPEN_ADMINISTRATIVELY_PROHIBITED,
OPEN_CONNECT_FAILED,
OPEN_UNKNOWN_CHANNEL_TYPE,
OPEN_RESOURCE_SHORTAGE
};
WOLFSSH_LOCAL int DoReceive(WOLFSSH* ssh);
WOLFSSH_LOCAL int DoProtoId(WOLFSSH* ssh);
WOLFSSH_LOCAL int wolfSSH_SendPacket(WOLFSSH* ssh);
WOLFSSH_LOCAL int wolfSSH_OutputPending(WOLFSSH* ssh);
WOLFSSH_LOCAL int SendProtoId(WOLFSSH* ssh);
WOLFSSH_LOCAL int ValidateProtoId(const char* protoIdStr, word32 len);
WOLFSSH_LOCAL int SendKexInit(WOLFSSH* ssh);
WOLFSSH_LOCAL int SendKexDhInit(WOLFSSH* ssh);
WOLFSSH_LOCAL int SendKexDhReply(WOLFSSH* ssh);
WOLFSSH_LOCAL int SendKexDhGexRequest(WOLFSSH* ssh);
WOLFSSH_LOCAL int SendKexDhGexGroup(WOLFSSH* ssh);
WOLFSSH_LOCAL int SendNewKeys(WOLFSSH* ssh);
WOLFSSH_LOCAL int SendUnimplemented(WOLFSSH* ssh);
WOLFSSH_LOCAL int SendDisconnect(WOLFSSH* ssh, word32 reason);
WOLFSSH_LOCAL int SendIgnore(WOLFSSH* ssh, const unsigned char* data,
word32 dataSz);
WOLFSSH_LOCAL int SendGlobalRequestFwdSuccess(WOLFSSH * ssh, int success,
word32 port);
/* The optional sent out-param reports whether the request is on its way to the
* peer -- flushed, or still framed for the next flush -- which the return does
* not answer: the highwater callback runs after the last byte goes out, so its
* failure surfaces as this call's. */
WOLFSSH_LOCAL int SendGlobalRequest(WOLFSSH * ssh,
const unsigned char * data, word32 dataSz, int reply, int* sent);
#ifdef WOLFSSH_FWD
/* Sends the request and settles pend with it: committed once the request is on
* its way to the peer, discarded when it never left. Both happen before the
* post-send highwater callback runs, so a request that callback sends commits
* behind this one. */
WOLFSSH_LOCAL int SendGlobalRequestFwd(WOLFSSH* ssh,
const char* bindAddr, word32 bindPort, int isCancel, int wantReply,
WOLFSSH_FWD_PENDING* pend);
/* On success pend holds what to commit once the request reaches the wire; on
* error it is zeroed, so there is nothing to commit or give back. */
WOLFSSH_LOCAL int FwdRemotePrepare(WOLFSSH* ssh, const char* bindAddr,
word32 bindPort, int wantReply, int isCancel,
WOLFSSH_FWD_PENDING* pend);
WOLFSSH_LOCAL int FwdReplyPrepare(WOLFSSH* ssh, WOLFSSH_FWD_PENDING* pend);
WOLFSSH_LOCAL void FwdPendingCommit(WOLFSSH* ssh, WOLFSSH_FWD_PENDING* pend);
WOLFSSH_LOCAL void FwdPendingDiscard(WOLFSSH* ssh, WOLFSSH_FWD_PENDING* pend);
WOLFSSH_LOCAL void FwdRemoteFreeList(WOLFSSH* ssh, void* heap);
#endif
WOLFSSH_LOCAL int SendDebug(WOLFSSH* ssh, byte alwaysDisplay, const char* msg);
WOLFSSH_LOCAL int SendServiceRequest(WOLFSSH* ssh, byte serviceId);
WOLFSSH_LOCAL int SendServiceAccept(WOLFSSH* ssh, byte serviceId);
WOLFSSH_LOCAL int SendExtInfo(WOLFSSH* ssh);
WOLFSSH_LOCAL int SendUserAuthRequest(WOLFSSH* ssh, byte authType, int addSig);
#ifdef WOLFSSH_KEYBOARD_INTERACTIVE
WOLFSSH_LOCAL int SendUserAuthKeyboardResponse(WOLFSSH* ssh);
/* Send an INFO_REQUEST for keyboard-interactive auth. Set counted when the
* caller already charged a failure for this message, so a declined setup
* callback doesn't charge it twice. */
WOLFSSH_LOCAL int SendUserAuthKeyboardRequest(WOLFSSH* ssh,
WS_UserAuthData* authData);
#endif
WOLFSSH_LOCAL int SendUserAuthSuccess(WOLFSSH* ssh);
WOLFSSH_LOCAL int SendUserAuthFailure(WOLFSSH* ssh, byte partialSuccess);
WOLFSSH_LOCAL int SendUserAuthBanner(WOLFSSH* ssh);
WOLFSSH_LOCAL int SendUserAuthPkOk(WOLFSSH* ssh,
const byte* algoName, word32 algoNameSz,
const byte* publicKey, word32 publicKeySz);
WOLFSSH_LOCAL int SendRequestSuccess(WOLFSSH* ssh, int success);
WOLFSSH_LOCAL int SendChannelOpenSession(WOLFSSH* ssh,
WOLFSSH_CHANNEL* channel);
WOLFSSH_LOCAL int SendChannelOpenForward(WOLFSSH* ssh,
WOLFSSH_CHANNEL* channel);
WOLFSSH_LOCAL int SendChannelOpenConf(WOLFSSH* ssh, WOLFSSH_CHANNEL* channel);
WOLFSSH_LOCAL int SendChannelOpenFail(WOLFSSH* ssh, word32 channel,
word32 reason, const char* description, const char* language);
WOLFSSH_LOCAL int SendChannelEof(WOLFSSH* ssh, word32 peerChannelId);
WOLFSSH_LOCAL int SendChannelEow(WOLFSSH* ssh, word32 peerChannelId);
WOLFSSH_LOCAL int SendChannelClose(WOLFSSH* ssh, word32 peerChannelId);
WOLFSSH_LOCAL int SendChannelExit(WOLFSSH* ssh, word32 peerChannelId,
int status);
WOLFSSH_LOCAL int SendChannelData(WOLFSSH* ssh, word32 channelId,
byte* data, word32 dataSz);
WOLFSSH_LOCAL int SendChannelExtendedData(WOLFSSH* ssh, word32 channelId,
byte* data, word32 dataSz);
WOLFSSH_LOCAL int SendChannelWindowAdjust(WOLFSSH* ssh, word32 channelId,
word32 bytesToAdd, byte* bundled);
WOLFSSH_LOCAL int SendChannelRequest(WOLFSSH* ssh, byte* name, word32 nameSz);
WOLFSSH_LOCAL int SendChannelTerminalResize(WOLFSSH* ssh, word32 columns,
word32 rows, word32 widthPixels, word32 heightPixels);
WOLFSSH_LOCAL int SendChannelTerminalRequest(WOLFSSH* ssh);
WOLFSSH_LOCAL int SendChannelAgentRequest(WOLFSSH* ssh);
WOLFSSH_LOCAL int SendChannelSuccess(WOLFSSH* ssh, word32 channelId,
int success);
WOLFSSH_LOCAL int SendChannelExitStatus(WOLFSSH* ssh, word32 channelId,
word32 exitStatus);
WOLFSSH_LOCAL int GenerateKey(byte hashId, byte keyId, byte* key,
word32 keySz, const byte* k, word32 kSz,
const byte* h, word32 hSz,
const byte* sessionId, word32 sessionIdSz,
byte doKeyPad);
#if !defined(WOLFSSH_NO_ECDSA) || !defined(WOLFSSH_NO_ECDH)
WOLFSSH_LOCAL int wcPrimeForId(byte id);
#endif
WOLFSSH_LOCAL enum wc_HashType HashForId(byte id);
#ifdef WOLFSSH_CERTS
WOLFSSH_LOCAL byte CertTypeForId(byte id);
#endif
#if defined(WOLFSSH_WINDOWS_CERT_STORE) && defined(WOLFSSH_CERTS)
WOLFSSH_LOCAL word32 FindPvtKeyIdx(const WOLFSSH_CTX* ctx, byte fmt);
#endif
enum AcceptStates {
ACCEPT_BEGIN = 0,
ACCEPT_SERVER_VERSION_SENT,
ACCEPT_CLIENT_VERSION_DONE,
ACCEPT_SERVER_KEXINIT_SENT,
ACCEPT_KEYED,
ACCEPT_CLIENT_USERAUTH_REQUEST_DONE,
ACCEPT_SERVER_USERAUTH_ACCEPT_SENT,
ACCEPT_CLIENT_USERAUTH_DONE,
ACCEPT_SERVER_USERAUTH_SENT,
ACCEPT_SERVER_CHANNEL_ACCEPT_SENT,
ACCEPT_CLIENT_SESSION_ESTABLISHED,
#ifdef WOLFSSH_SCP
ACCEPT_INIT_SCP_TRANSFER,
#endif
#ifdef WOLFSSH_SFTP
ACCEPT_INIT_SFTP,
#endif
#ifdef WOLFSSH_AGENT
ACCEPT_INIT_AGENT,
#endif
};
enum ConnectStates {
CONNECT_BEGIN = 0,
CONNECT_CLIENT_VERSION_SENT,
CONNECT_SERVER_VERSION_DONE,
CONNECT_CLIENT_KEXINIT_SENT,
CONNECT_SERVER_KEXINIT_DONE,
CONNECT_CLIENT_KEXDH_INIT_SENT,
CONNECT_KEYED,
CONNECT_CLIENT_USERAUTH_REQUEST_SENT,
CONNECT_SERVER_USERAUTH_REQUEST_DONE,
CONNECT_CLIENT_USERAUTH_SENT,
CONNECT_SERVER_USERAUTH_ACCEPT_DONE,
CONNECT_CLIENT_CHANNEL_OPEN_SESSION_SENT,
CONNECT_SERVER_CHANNEL_OPEN_SESSION_DONE,
CONNECT_CLIENT_CHANNEL_AGENT_REQUEST_SENT,
CONNECT_CLIENT_CHANNEL_TERMINAL_REQUEST_SENT,
CONNECT_CLIENT_CHANNEL_REQUEST_SENT,
CONNECT_SERVER_CHANNEL_REQUEST_DONE,
CONNECT_CLIENT_AGENT_REQUEST_SENT,
CONNECT_SERVER_AGENT_REQUEST_DONE,
CONNECT_DONE
};
enum ClientStates {
CLIENT_BEGIN = 0,
CLIENT_VERSION_DONE,
CLIENT_KEXINIT_DONE,
CLIENT_KEXDH_INIT_DONE,
CLIENT_USERAUTH_REQUEST_DONE,
CLIENT_USERAUTH_DONE,
CLIENT_CHANNEL_OPEN_DONE,
CLIENT_DONE
};
enum ServerStates {
SERVER_BEGIN = 0,
SERVER_VERSION_DONE,
SERVER_KEXINIT_DONE,
SERVER_USERAUTH_REQUEST_DONE,
SERVER_USERAUTH_ACCEPT_DONE,
SERVER_CHANNEL_OPEN_DONE,
SERVER_DONE
};
enum ProcessReplyStates {
PROCESS_INIT,
PROCESS_PACKET_LENGTH,
PROCESS_PACKET_FINISH,
PROCESS_PACKET
};
enum WS_MessageIds {
MSGID_NONE = 0,
MSGID_DISCONNECT = 1,
MSGID_IGNORE = 2,
MSGID_UNIMPLEMENTED = 3,
MSGID_DEBUG = 4,
MSGID_SERVICE_REQUEST = 5,
MSGID_SERVICE_ACCEPT = 6,
MSGID_EXT_INFO = 7,
MSGID_KEXINIT = 20,
MSGID_NEWKEYS = 21,
MSGID_KEXDH_INIT = 30,
MSGID_KEXECDH_INIT = 30,
MSGID_KEXKEM_INIT = 30,
MSGID_KEXDH_REPLY = 31,
MSGID_KEXECDH_REPLY = 31,
MSGID_KEXKEM_REPLY = 31,
MSGID_KEXDH_GEX_GROUP = 31,
MSGID_KEXDH_GEX_INIT = 32,
MSGID_KEXDH_GEX_REPLY = 33,
MSGID_KEXDH_GEX_REQUEST = 34,
MSGID_USERAUTH_REQUEST = 50,
MSGID_USERAUTH_FAILURE = 51,
MSGID_USERAUTH_SUCCESS = 52,
MSGID_USERAUTH_BANNER = 53,
MSGID_USERAUTH_PK_OK = 60, /* Public Key OK */
MSGID_USERAUTH_PW_CHRQ = 60, /* Password Change Request */
MSGID_USERAUTH_INFO_REQUEST = 60,
MSGID_USERAUTH_INFO_RESPONSE = 61,
MSGID_GLOBAL_REQUEST = 80,
MSGID_REQUEST_SUCCESS = 81,
MSGID_REQUEST_FAILURE = 82,
MSGID_CHANNEL_OPEN = 90,
MSGID_CHANNEL_OPEN_CONF = 91,
MSGID_CHANNEL_OPEN_FAIL = 92,
MSGID_CHANNEL_WINDOW_ADJUST = 93,
MSGID_CHANNEL_DATA = 94,
MSGID_CHANNEL_EXTENDED_DATA = 95,
MSGID_CHANNEL_EOF = 96,
MSGID_CHANNEL_CLOSE = 97,
MSGID_CHANNEL_REQUEST = 98,
MSGID_CHANNEL_SUCCESS = 99,
MSGID_CHANNEL_FAILURE = 100
};
/* The following message ID ranges are described in RFC 5251, section 7. */
enum WS_MessageIdLimits {
/* Transport Layer Protocol: */
MSGIDLIMIT_TRANS_MIN = 1,
MSGIDLIMIT_TRANS_GEN_MIN = 1,
MSGIDLIMIT_TRANS_GEN_MAX = 19,
MSGIDLIMIT_TRANS_ALGO_MIN = 20,
MSGIDLIMIT_TRANS_ALGO_MAX = 29,
MSGIDLIMIT_TRANS_KEX_MIN = 30,
MSGIDLIMIT_TRANS_KEX_MAX = 49,
MSGIDLIMIT_TRANS_MAX = 49,
/* User Authentication Protocol: */
MSGIDLIMIT_AUTH_MIN = 50,
MSGIDLIMIT_AUTH_GEN_MIN = 50,
MSGIDLIMIT_AUTH_GEN_MAX = 59,
MSGIDLIMIT_AUTH_METH_MIN = 60,
MSGIDLIMIT_AUTH_METH_MAX = 79,
MSGIDLIMIT_AUTH_MAX = 79,
/* Connection Protocol: */
MSGIDLIMIT_CONN_MIN = 80,
MSGIDLIMIT_CONN_GEN_MIN = 80,
MSGIDLIMIT_CONN_GEN_MAX = 89,
MSGIDLIMIT_CONN_CHAN_MIN = 90,
MSGIDLIMIT_CONN_CHAN_MAX = 127,
MSGIDLIMIT_CONN_MAX = 127,
/* Reserved For Client Protocols: */
MSGIDLIMIT_RESERVED_MIN = 128,
MSGIDLIMIT_RESERVED_MAX = 191,
/* Local Extensions: */
MSGIDLIMIT_EXTENDED_MIN = 192,
MSGIDLIMIT_EXTENDED_MAX = 255
};
/* Message ID bounds checking. */
#define MSGIDLIMIT_BOUND(x,y,z) ((x) >= (y) && (x) <= (z))
#define MSGIDLIMIT_COMP(x,name) \
MSGIDLIMIT_BOUND((x),MSGIDLIMIT_##name##_MIN,MSGIDLIMIT_##name##_MAX)
#define MSGIDLIMIT_TRANS(x) MSGIDLIMIT_COMP((x),TRANS)
#define MSGIDLIMIT_TRANS_GEN(x) MSGIDLIMIT_COMP((x),TRANS_GEN)
#define MSGIDLIMIT_TRANS_ALGO(x) MSGIDLIMIT_COMP((x),TRANS_ALGO)
#define MSGIDLIMIT_TRANS_KEX(x) MSGIDLIMIT_COMP((x),TRANS_KEX)
#define MSGIDLIMIT_AUTH(x) MSGIDLIMIT_COMP((x),AUTH)
#define MSGIDLIMIT_AUTH_GEN(x) MSGIDLIMIT_COMP((x),AUTH_GEN)
#define MSGIDLIMIT_AUTH_METH(x) MSGIDLIMIT_COMP((x),AUTH_METH)
#define MSGIDLIMIT_CONN(x) MSGIDLIMIT_COMP((x),CONN)
#define MSGIDLIMIT_CONN_GEN(x) MSGIDLIMIT_COMP((x),CONN_GEN)
#define MSGIDLIMIT_CONN_CHAN(x) MSGIDLIMIT_COMP((x),CONN_CHAN)
#define MSGIDLIMIT_RESERVED(x) MSGIDLIMIT_COMP((x),RESERVED)
#define MSGIDLIMIT_EXTENDED(x) MSGIDLIMIT_COMP((x),EXTENDED)
#define MSGIDLIMIT_POST_USERAUTH(x) ((x) >= MSGIDLIMIT_CONN_MIN)
#define CHANNEL_EXTENDED_DATA_STDERR WOLFSSH_EXT_DATA_STDERR
/* Used when checking IsMessageAllowed() to determine if creating and sending
* the message or receiving the message is allowed */
#define WS_MSG_SEND 1
#define WS_MSG_RECV 2
#ifdef WOLFSSH_TEST_INTERNAL
WOLFSSH_API int wolfSSH_TestDoProtoId(WOLFSSH* ssh);
WOLFSSH_API int wolfSSH_TestIsMessageAllowed(WOLFSSH* ssh, byte msg,
byte state);
WOLFSSH_API int wolfSSH_TestDoReceive(WOLFSSH* ssh);
WOLFSSH_API int wolfSSH_TestDoPacket(WOLFSSH* ssh,
byte* bufferConsumed);
WOLFSSH_API int wolfSSH_TestDoUserAuthBanner(WOLFSSH* ssh, byte* buf,
word32 len, word32* idx);
WOLFSSH_API int wolfSSH_TestPrepareUserAuthRequestPassword(WOLFSSH* ssh,
word32* payloadSz, const WS_UserAuthData* authData);
WOLFSSH_API int wolfSSH_TestDoChannelRequest(WOLFSSH* ssh, byte* buf,
word32 len, word32* idx);
WOLFSSH_API int wolfSSH_TestDoChannelSuccess(WOLFSSH* ssh, byte* buf,
word32 len, word32* idx);
WOLFSSH_API int wolfSSH_TestDoChannelFailure(WOLFSSH* ssh, byte* buf,
word32 len, word32* idx);
WOLFSSH_API int wolfSSH_TestDoChannelData(WOLFSSH* ssh, byte* buf,
word32 len, word32* idx);
WOLFSSH_API int wolfSSH_TestDoChannelExtendedData(WOLFSSH* ssh, byte* buf,
word32 len, word32* idx);
WOLFSSH_API int wolfSSH_TestDoChannelWindowAdjust(WOLFSSH* ssh, byte* buf,
word32 len, word32* idx);
WOLFSSH_API int wolfSSH_TestSendPendingChannelWindowAdjust(WOLFSSH* ssh);
WOLFSSH_API int wolfSSH_TestDoKexInit(WOLFSSH* ssh, byte* buf,
word32 len, word32* idx);
WOLFSSH_API int wolfSSH_TestDoNewKeys(WOLFSSH* ssh, byte* buf,
word32 len, word32* idx);
WOLFSSH_API int wolfSSH_TestDoExtInfo(WOLFSSH* ssh, byte* buf,
word32 len, word32* idx);
WOLFSSH_API int wolfSSH_TestGenerateKeys(WOLFSSH* ssh, byte hashId);
WOLFSSH_API void wolfSSH_TestFreeHandshake(WOLFSSH* ssh);
WOLFSSH_API int wolfSSH_TestDoKexDhInit(WOLFSSH* ssh, byte* buf,
word32 len, word32* idx);
WOLFSSH_API int wolfSSH_TestDoKexDhReply(WOLFSSH* ssh, byte* buf,
word32 len, word32* idx);
WOLFSSH_API int wolfSSH_TestChannelPutData(WOLFSSH_CHANNEL* channel,
byte* data, word32 dataSz);
WOLFSSH_API int wolfSSH_TestBuildNameList(char* buf, word32 bufSz,
const byte* src, word32 srcSz);
WOLFSSH_API int wolfSSH_TestDoUserAuthRequest(WOLFSSH* ssh, byte* buf,
word32 len, word32* idx);
#ifdef WOLFSSH_KEYBOARD_INTERACTIVE
WOLFSSH_API int wolfSSH_TestDoUserAuthInfoResponse(WOLFSSH* ssh, byte* buf,
word32 len, word32* idx);
#endif
WOLFSSH_API int wolfSSH_TestSendUserAuthFailure(WOLFSSH* ssh,
byte partialSuccess);
WOLFSSH_API int wolfSSH_TestHighwaterCheck(WOLFSSH* ssh, byte side);
#ifdef WOLFSSH_SCP
WOLFSSH_API int wolfSSH_TestScpGetFileMode(WOLFSSH* ssh, byte* buf,
word32 bufSz, word32* inOutIdx);
WOLFSSH_API int wolfSSH_TestScpGetFileSize(WOLFSSH* ssh, byte* buf,
word32 bufSz, word32* inOutIdx);
WOLFSSH_API int wolfSSH_TestScpGetTimestamp(WOLFSSH* ssh, byte* buf,
word32 bufSz, word32* inOutIdx);
WOLFSSH_API int wolfSSH_TestScpGetFileName(WOLFSSH* ssh, byte* buf,
word32 bufSz, word32* inOutIdx);
#if !defined(WOLFSSH_SCP_USER_CALLBACKS) && !defined(NO_FILESYSTEM)
WOLFSSH_API int wolfSSH_TestScpPushDir(const char* path);
#endif
#endif /* WOLFSSH_SCP */
#ifndef WOLFSSH_NO_DH
WOLFSSH_API int wolfSSH_TestKeyAgreeDh_client(WOLFSSH* ssh, byte hashId,
const byte* f, word32 fSz);
WOLFSSH_API int wolfSSH_TestKeyAgreeDh_server(WOLFSSH* ssh, byte hashId,
byte* f, word32* fSz);
WOLFSSH_API int wolfSSH_TestSetDhKexKey(WOLFSSH* ssh);
WOLFSSH_API int wolfSSH_TestGetDHPrimeGroup(WOLFSSH* ssh,
const byte** primeGroup, word32* primeGroupSz,
const byte** generator, word32* generatorSz);
#endif /* !WOLFSSH_NO_DH */
#ifndef WOLFSSH_NO_ECDH
WOLFSSH_API int wolfSSH_TestKeyAgreeEcdh_server(WOLFSSH* ssh, byte hashId,
byte* f, word32* fSz);
WOLFSSH_API int wolfSSH_TestKeyAgreeEcdh_client(WOLFSSH* ssh, byte hashId,
const byte* f, word32 fSz);
#endif /* !WOLFSSH_NO_ECDH */
#ifndef WOLFSSH_NO_DH_GEX_SHA256
WOLFSSH_API int wolfSSH_TestSendKexDhGexRequest(WOLFSSH* ssh);
WOLFSSH_API int wolfSSH_TestDoKexDhGexRequest(WOLFSSH* ssh, byte* buf,
word32 len, word32* idx);
WOLFSSH_API int wolfSSH_TestDoKexDhGexGroup(WOLFSSH* ssh, byte* buf,
word32 len, word32* idx);
WOLFSSH_API int wolfSSH_TestValidateKexDhGexGroup(const byte* primeGroup,
word32 primeGroupSz, const byte* generator, word32 generatorSz,
word32 minBits, word32 maxBits, WC_RNG* rng);
WOLFSSH_API int wolfSSH_TestSelectKexDhGexGroup(word32 minBits,
word32 preferredBits, word32 maxBits, const byte** primeGroup,
word32* primeGroupSz);
#endif /* !WOLFSSH_NO_DH_GEX_SHA256 */
#ifndef WOLFSSH_NO_RSA
WOLFSSH_API int wolfSSH_TestRsaVerify(const byte* sig, word32 sigSz,
const byte* encDigest, word32 encDigestSz,
RsaKey* key, void* heap);
WOLFSSH_API int wolfSSH_TestDoUserAuthRequestRsa(WOLFSSH* ssh,
WS_UserAuthData_PublicKey* pk, int hashId, byte* digest,
word32 digestSz);
#ifdef WOLFSSH_CERTS
WOLFSSH_API int wolfSSH_TestDoUserAuthRequestRsaCert(WOLFSSH* ssh,
WS_UserAuthData_PublicKey* pk, int hashId, byte* digest,
word32 digestSz);
#endif /* WOLFSSH_CERTS */
WOLFSSH_API int wolfSSH_TestParseRSAPubKey(WOLFSSH* ssh, byte* pubKey,
word32 pubKeySz);
#endif /* !WOLFSSH_NO_RSA */
#ifdef WOLFSSH_CERTS
WOLFSSH_API int wolfSSH_TestParseLeafCert(byte* in, word32 inSz,
byte** leafOut, word32* leafOutSz);
#endif /* WOLFSSH_CERTS */
#ifndef WOLFSSH_NO_ECDSA
WOLFSSH_API int wolfSSH_TestParseECCPubKey(WOLFSSH* ssh, byte* pubKey,
word32 pubKeySz);
#ifdef WOLFSSH_CERTS
WOLFSSH_API int wolfSSH_TestParseECCPubKeyCert(WOLFSSH* ssh, byte* pubKey,
word32 pubKeySz);
#endif /* WOLFSSH_CERTS */
#endif /* !WOLFSSH_NO_ECDSA */
#ifndef WOLFSSH_NO_ED25519
WOLFSSH_API int wolfSSH_TestParseEd25519PubKey(WOLFSSH* ssh, byte* pubKey,
word32 pubKeySz);
WOLFSSH_API int wolfSSH_TestDoUserAuthRequestEd25519(WOLFSSH* ssh,
WS_UserAuthData* authData);
#endif /* !WOLFSSH_NO_ED25519 */
#ifndef WOLFSSH_NO_MLDSA
WOLFSSH_API int wolfSSH_TestDoUserAuthRequestMlDsa(WOLFSSH* ssh,
WS_UserAuthData* authData, word32 pubKeyBlobSz);
WOLFSSH_API int wolfSSH_TestPrepareUserAuthRequestMlDsa(WOLFSSH* ssh,
word32* payloadSz, const WS_UserAuthData* authData,
WS_KeySignature* keySig);
#ifdef WOLFSSH_CERTS
WOLFSSH_API int wolfSSH_TestPrepareUserAuthRequestMlDsaCert(WOLFSSH* ssh,
word32* payloadSz, const WS_UserAuthData* authData,
WS_KeySignature* keySig);
#endif /* WOLFSSH_CERTS */
WOLFSSH_API int wolfSSH_TestBuildUserAuthRequestMlDsa(WOLFSSH* ssh,
byte* output, word32* idx, const WS_UserAuthData* authData,
const byte* sigStart, word32 sigStartIdx, WS_KeySignature* keySig);
WOLFSSH_API int wolfSSH_TestDoUserAuthRequestMlDsaComposite(WOLFSSH* ssh,
WS_UserAuthData* authData, byte keyId, word32 pubKeyBlobSz);
WOLFSSH_API int wolfSSH_TestPrepareUserAuthRequestMlDsaComposite(
WOLFSSH* ssh, word32* payloadSz, const WS_UserAuthData* authData,
WS_KeySignature* keySig);
WOLFSSH_API int wolfSSH_TestSignHMlDsaComposite(WOLFSSH* ssh, byte* sig,
word32* sigSz, byte keyId);
WOLFSSH_API int wolfSSH_TestBuildUserAuthRequestMlDsaComposite(
WOLFSSH* ssh, byte* output, word32* idx,
const WS_UserAuthData* authData, const byte* sigStart,
word32 sigStartIdx, WS_KeySignature* keySig);
#endif /* !WOLFSSH_NO_MLDSA */
#if defined(WOLFSSH_SCP) && !defined(WOLFSSH_SCP_USER_CALLBACKS)
WOLFSSH_API int wolfSSH_TestScpExtractFileName(const char* filePath,
char* fileName, word32 fileNameSz);
#endif /* WOLFSSH_SCP && !WOLFSSH_SCP_USER_CALLBACKS */
#ifndef WOLFSSH_NO_AEAD
WOLFSSH_API void wolfSSH_TestAeadIncrementExpIv(byte* iv);
WOLFSSH_API int wolfSSH_TestEncryptAead(WOLFSSH* ssh, byte* cipher,
const byte* input, word32 sz,
byte* authTag, const byte* auth, word32 authSz);
WOLFSSH_API int wolfSSH_TestDecryptAead(WOLFSSH* ssh, byte* plain,
const byte* input, word32 sz,
const byte* authTag, const byte* auth, word32 authSz);
#endif /* !WOLFSSH_NO_AEAD */
#endif /* WOLFSSH_TEST_INTERNAL */
/* dynamic memory types */
enum WS_DynamicTypes {
DYNTYPE_STRING = 500,
DYNTYPE_CTX,
DYNTYPE_SSH,
DYNTYPE_CHANNEL,
DYNTYPE_BUFFER,
DYNTYPE_ID,
DYNTYPE_HS,
DYNTYPE_CA,
DYNTYPE_CERT,
DYNTYPE_PRIVKEY,
DYNTYPE_PUBKEY,
DYNTYPE_DH,
DYNTYPE_RNG,
DYNTYPE_MPINT,
DYNTYPE_SCPCTX,
DYNTYPE_SCPDIR,
DYNTYPE_SFTP,
DYNTYPE_SFTP_STATE,
DYNTYPE_AGENT,
DYNTYPE_AGENT_ID,
DYNTYPE_AGENT_KEY,
DYNTYPE_AGENT_BUFFER,
DYNTYPE_CERTMAN,
DYNTYPE_FILE,
DYNTYPE_TEMP,
DYNTYPE_PATH,
DYNTYPE_SSHD,
DYNTYPE_FWD
};
enum WS_BufferTypes {
BUFTYPE_CA,
BUFTYPE_CERT,
BUFTYPE_PRIVKEY,
BUFTYPE_PUBKEY
};
#ifdef WOLFSSH_SCP
#define SCP_MODE_OCTET_LEN 4 /* file mode is 4 characters (ex: 0777) */
#define SCP_MIN_CONFIRM_SZ 2 /* [cmd_byte]/0 */
#define SCP_CONFIRM_OK 0x00 /* binary 0 */
#define SCP_CONFIRM_ERR 0x01 /* binary 1 */
#define SCP_CONFIRM_FATAL 0x02 /* binary 2 */
enum WS_ScpStates {
SCP_SETUP = 0,
SCP_PARSE_COMMAND,
SCP_SINK,
SCP_SINK_BEGIN,
SCP_TRANSFER,
SCP_SOURCE,
SCP_SOURCE_BEGIN,
SCP_SOURCE_INIT,
SCP_RECEIVE_MESSAGE,
SCP_SEND_CONFIRMATION,
SCP_CONFIRMATION_WITH_RECEIPT,
SCP_RECEIVE_CONFIRMATION_WITH_RECEIPT,
SCP_RECEIVE_CONFIRMATION,
SCP_SEND_FILE,
SCP_RECEIVE_FILE,
SCP_SEND_FILE_HEADER,
SCP_SEND_ENTER_DIRECTORY,
SCP_SEND_EXIT_DIRECTORY,
SCP_SEND_EXIT_DIRECTORY_FINAL,
SCP_SEND_TIMESTAMP,
SCP_DONE
};
enum WS_ScpMsgTypes {
WOLFSSH_SCP_MSG_FILE = 0,
WOLFSSH_SCP_MSG_TIME,
WOLFSSH_SCP_MSG_DIR,
WOLFSSH_SCP_MSG_END_DIR
};
enum WS_ScpDirection {
WOLFSSH_SCP_DIR_NONE = 0,
WOLFSSH_SCP_TO,
WOLFSSH_SCP_FROM
};
WOLFSSH_LOCAL int ChannelCommandIsScp(WOLFSSH* ssh);
WOLFSSH_LOCAL int DoScpRequest(WOLFSSH* ssh);
WOLFSSH_LOCAL int DoScpSink(WOLFSSH* ssh);
WOLFSSH_LOCAL int DoScpSource(WOLFSSH* ssh);
WOLFSSH_LOCAL int ParseScpCommand(WOLFSSH* ssh);
WOLFSSH_LOCAL int ReceiveScpMessage(WOLFSSH* ssh);
WOLFSSH_LOCAL int ReceiveScpFile(WOLFSSH* ssh);
WOLFSSH_LOCAL int SendScpConfirmation(WOLFSSH* ssh);
WOLFSSH_LOCAL int ReceiveScpConfirmation(WOLFSSH* ssh);
/* default SCP callbacks */
WOLFSSH_LOCAL int wsScpRecvCallback(WOLFSSH* ssh, int state,
const char* basePath,
const char* fileName, int fileMode,
word64 mTime, word64 aTime,
word32 totalFileSz, byte* buf,
word32 bufSz, word32 fileOffset,
void* ctx);
WOLFSSH_LOCAL int wsScpSendCallback(WOLFSSH* ssh, int state,
const char* peerRequest, char* fileName,
word32 fileNameSz, word64* mTime,
word64* aTime, int* fileMode,
word32 fileOffset, word32* totalFileSz,
byte* buf, word32 bufSz, void* ctx);
#if !defined(WOLFSSH_SCP_USER_CALLBACKS) && !defined(NO_FILESYSTEM)
WOLFSSH_LOCAL void ScpSendCtxFreeDirs(void* fs, ScpSendCtx* ctx, void* heap);
#endif
#endif
WOLFSSH_LOCAL int wolfSSH_CleanPath(WOLFSSH* ssh, char* in, int inSz);
#ifndef WOLFSSH_NO_RSA
WOLFSSH_LOCAL int wolfSSH_RsaVerify(
const byte *sig, word32 sigSz,
const byte* encDigest, word32 encDigestSz,
RsaKey* key, void* heap, const char* loc);
#endif
WOLFSSH_LOCAL void DumpOctetString(const byte* input, word32 inputSz);
WOLFSSH_LOCAL int wolfSSH_oct2dec(WOLFSSH* ssh, byte* oct, word32 octSz);
WOLFSSH_LOCAL void AddAssign64(word32* addend1, word32 addend2);
#ifdef WOLFSSH_TERM
/* values from section 8 of rfc 4254 */
enum TerminalModes {
WOLFSSH_TTY_OP_END = 0,
WOLFSSH_VINTR,
WOLFSSH_VQUIT,
WOLFSSH_VERASE,
WOLFSSH_VKILL,
WOLFSSH_VEOF,
WOLFSSH_VEOL,
WOLFSSH_VEOL2,
WOLFSSH_VSTART,
WOLFSSH_VSTOP,
WOLFSSH_VSUSP,
WOLFSSH_VDSUSP,
WOLFSSH_VREPRINT,
WOLFSSH_VWERASE,
WOLFSSH_VLNEXT,
WOLFSSH_VFLUSH,
WOLFSSH_VSWTCH,
WOLFSSH_VSTATUS,
WOLFSSH_VDISCARD,
WOLFSSH_IGNPAR = 30,
WOLFSSH_PARMRK,
WOLFSSH_INPCK,
WOLFSSH_ISTRIP,
WOLFSSH_INLCR,
WOLFSSH_IGNCR,
WOLFSSH_ICRNL,
WOLFSSH_IUCLC,
WOLFSSH_IXON,
WOLFSSH_IXANY,
WOLFSSH_IXOFF,
WOLFSSH_IMAXBEL,
WOLFSSH_IUTF8 = 42,
WOLFSSH_ISIG = 50,
WOLFSSH_ICANON,
WOLFSSH_XCASE,
WOLFSSH_ECHO,
WOLFSSH_ECHOE,
WOLFSSH_ECHOK,
WOLFSSH_ECHONL,
WOLFSSH_NOFLSH,
WOLFSSH_TOSTOP,
WOLFSSH_IEXTEN,
WOLFSSH_ECHOCTL,
WOLFSSH_ECHOKE,
WOLFSSH_PENDIN,
WOLFSSH_OPOST = 70,
WOLFSSH_OLCUC,
WOLFSSH_ONLCR,
WOLFSSH_OCRNL,
WOLFSSH_ONOCR,
WOLFSSH_ONLRET,
WOLFSSH_CS7 = 90,
WOLFSSH_CS8,
WOLFSSH_PARENB,
WOLFSSH_PARODD,
WOLFSSH_TTY_OP_ISPEED = 128,
WOLFSSH_TTY_OP_OSPEED,
WOLFSSH_TTY_INVALID = 160
};
#endif /* WOLFSSH_TERM */
#ifdef __cplusplus
}
#endif
#endif /* _WOLFSSH_INTERNAL_H_ */