1
0
mirror of https://github.com/libssh2/libssh2.git synced 2026-10-24 03:48:58 +03:00

src: disable SHA1-based hostkey methods and signatures by default, fix fallouts

They are `ssh-rsa` and `ssh-rsa-cert-v01@openssh.com`, and insecure due
to their reliance on SHA1 hashes.

Also:
- hostkey: fix to accept all RSA hostkey methods in common
  `hostkey_method_ssh_rsa_init()`.
- mbedtls: add missing RSA SHA1/SHA2 guards.
- mbedtls: cleanup on error in `mbed_pub_priv_key()`.
- os400qc3: add missing RSA SHA1/SHA2 guards. (untested)
- wincng: add missing RSA SHA1/SHA2 guards.
- crypto.h: add missing `#endif` comments.
- GHA: move stray `-DLIBSSH2_DSA_ENABLE` to its place.
  Follow-up to b7ab0faa70 #1435
- tests: fix to guard RSA tests with `LIBSSH2_RSA`, replacing
  `LIBSSH2_RSA_SHA1` to keep test coverage. Keep using the latter for
  testing SHA1-based signatures in `test_auth_pubkey_ok_rsa_signed`.

Follow-up to 3e14d67d26 #2444
Follow-up to 99f935358d #2443

Closes #2501
This commit is contained in:
Viktor Szakats
2026-08-03 13:31:35 +02:00
parent 6c639b1867
commit 079eeb852b
13 changed files with 71 additions and 58 deletions

View File

@@ -506,7 +506,7 @@ jobs:
cflags=''
if [[ ( "${MATRIX_CRYPTO}" = 'Libgcrypt' && "${MATRIX_ZLIB}" = 'OFF' ) || "${MATRIX_TEST}" = 'legacy-options' ]]; then
cflags+=' -DLIBSSH2_KEX_SHA1_ENABLE -DLIBSSH2_MD5_ENABLE -DLIBSSH2_MD5_PEM_ENABLE -DLIBSSH2_HMAC_SHA1_ENABLE -DLIBSSH2_HMAC_RIPEMD_ENABLE'
cflags+=' -DLIBSSH2_BLOWFISH_ENABLE -DLIBSSH2_RC4_ENABLE -DLIBSSH2_CAST_ENABLE -DLIBSSH2_3DES_ENABLE'
cflags+=' -DLIBSSH2_RSA_SHA1_ENABLE -DLIBSSH2_BLOWFISH_ENABLE -DLIBSSH2_RC4_ENABLE -DLIBSSH2_CAST_ENABLE -DLIBSSH2_3DES_ENABLE'
fi
if [ "${MATRIX_TARGET}" = 'distcheck' ]; then
cflags+=' -DLIBSSH2_DSA_ENABLE' # build test only, it cannot pass test in CI
@@ -874,7 +874,8 @@ jobs:
cflags=''
if [ "${MATRIX_TEST}" = 'legacy-options' ]; then
cflags+=' -DLIBSSH2_KEX_SHA1_ENABLE -DLIBSSH2_MD5_ENABLE -DLIBSSH2_MD5_PEM_ENABLE -DLIBSSH2_HMAC_SHA1_ENABLE -DLIBSSH2_HMAC_RIPEMD_ENABLE'
cflags+=' -DLIBSSH2_BLOWFISH_ENABLE -DLIBSSH2_RC4_ENABLE -DLIBSSH2_CAST_ENABLE -DLIBSSH2_3DES_ENABLE'
cflags+=' -DLIBSSH2_RSA_SHA1_ENABLE -DLIBSSH2_BLOWFISH_ENABLE -DLIBSSH2_RC4_ENABLE -DLIBSSH2_CAST_ENABLE -DLIBSSH2_3DES_ENABLE'
cflags+=' -DLIBSSH2_DSA_ENABLE'
fi
if [ "${MATRIX_BUILD}" = 'CM' ]; then
if [[ "${MATRIX_ENV}" = 'clang'* ]]; then
@@ -893,7 +894,6 @@ jobs:
fi
elif [ "${MATRIX_TEST}" = 'no-options' ]; then
options+=' -DLIBSSH2_NO_DEPRECATED=ON'
cflags+=' -DLIBSSH2_DSA_ENABLE'
cflags+=' -DLIBSSH2_NO_AES_CBC -DLIBSSH2_NO_AES_CTR'
fi
if [[ "${MATRIX_TEST}" = *'unicode'* ]]; then

View File

@@ -4,6 +4,10 @@ Deprecation notices:
- This release disables these options by default:
- SHA1-based hostkey methods and signatures: `ssh-rsa`,
`ssh-rsa-cert-v01@openssh.com`
You can enable them with `-DLIBSSH2_RSA_SHA1_ENABLE`.
- SHA1-based key-exchange methods:
- `diffie-hellman-group1-sha1`
- `diffie-hellman-group14-sha1`

View File

@@ -157,7 +157,7 @@ int ssh2_rsa_sha2_verify(ssh2_rsa_ctx *rsa, size_t hash_len,
#ifndef ssh2_rsa_free
void ssh2_rsa_free(ssh2_rsa_ctx *rsa);
#endif
#endif
#endif /* LIBSSH2_RSA */
#if LIBSSH2_DSA
int ssh2_dsa_new(ssh2_dsa_ctx **dsa,
@@ -180,7 +180,7 @@ int ssh2_dsa_sha1_verify(ssh2_dsa_ctx *dsa,
#ifndef ssh2_dsa_free
void ssh2_dsa_free(ssh2_dsa_ctx *dsa);
#endif
#endif
#endif /* LIBSSH2_DSA */
#if LIBSSH2_ECDSA
/* Maximum uncompressed EC point length for NIST P-521:

View File

@@ -30,7 +30,7 @@
#define LIBSSH2_RSA 0
#endif
#ifdef LIBSSH2_NO_RSA_SHA1
#ifndef LIBSSH2_RSA_SHA1_ENABLE
#undef LIBSSH2_RSA_SHA1
#define LIBSSH2_RSA_SHA1 0
#endif

View File

@@ -86,23 +86,10 @@ static int hostkey_method_ssh_rsa_init(LIBSSH2_SESSION *session,
return -1;
/* we accept one of 3 header types */
#if LIBSSH2_RSA_SHA1
if(SSH2_IS_LITERAL(type, type_len, "ssh-rsa")) {
/* ssh-rsa */
}
else
#endif
#if LIBSSH2_RSA_SHA2
if(SSH2_IS_LITERAL(type, type_len, "rsa-sha2-256")) {
/* rsa-sha2-256 */
}
else if(SSH2_IS_LITERAL(type, type_len, "rsa-sha2-512")) {
/* rsa-sha2-512 */
}
else
#endif
{
ssh2_deb((session, LIBSSH2_TRACE_ERROR, "unexpected rsa type: %.*s",
if(!SSH2_IS_LITERAL(type, type_len, "ssh-rsa") &&
!SSH2_IS_LITERAL(type, type_len, "rsa-sha2-256") &&
!SSH2_IS_LITERAL(type, type_len, "rsa-sha2-512")) {
ssh2_deb((session, LIBSSH2_TRACE_ERROR, "unexpected RSA type: %.*s",
(int)type_len, type));
return -1;
}

View File

@@ -297,6 +297,7 @@ static int mbed_bn_random(ssh2_bn *bn, int bits, int top, int bottom)
* mbedTLS backend: RSA functions
*/
#if LIBSSH2_RSA
int ssh2_rsa_new(ssh2_rsa_ctx **rsa,
const unsigned char *edata, size_t elen,
const unsigned char *ndata, size_t nlen,
@@ -416,6 +417,7 @@ int ssh2_rsa_new_priv(ssh2_rsa_ctx **rsa,
return 0;
}
#if LIBSSH2_RSA_SHA2
int ssh2_rsa_sha2_verify(ssh2_rsa_ctx *rsa, size_t hash_len,
const unsigned char *sig, size_t sig_len,
const unsigned char *m, size_t m_len)
@@ -465,14 +467,6 @@ int ssh2_rsa_sha2_verify(ssh2_rsa_ctx *rsa, size_t hash_len,
return ret == 0 ? 0 : -1;
}
int ssh2_rsa_sha1_verify(ssh2_rsa_ctx *rsa,
const unsigned char *sig, size_t sig_len,
const unsigned char *m, size_t m_len)
{
return ssh2_rsa_sha2_verify(rsa, SSH2_SHA1_DIG_LEN,
sig, sig_len, m, m_len);
}
int ssh2_rsa_sha2_sign(ssh2_rsa_ctx *rsa, LIBSSH2_SESSION *session,
const unsigned char *hash, size_t hash_len,
unsigned char **signature, size_t *signature_len)
@@ -515,6 +509,16 @@ int ssh2_rsa_sha2_sign(ssh2_rsa_ctx *rsa, LIBSSH2_SESSION *session,
return ret == 0 ? 0 : -1;
}
#endif
#if LIBSSH2_RSA_SHA1
int ssh2_rsa_sha1_verify(ssh2_rsa_ctx *rsa,
const unsigned char *sig, size_t sig_len,
const unsigned char *m, size_t m_len)
{
return ssh2_rsa_sha2_verify(rsa, SSH2_SHA1_DIG_LEN,
sig, sig_len, m, m_len);
}
int ssh2_rsa_sha1_sign(ssh2_rsa_ctx *rsa, LIBSSH2_SESSION *session,
const unsigned char *hash, size_t hash_len,
@@ -523,6 +527,7 @@ int ssh2_rsa_sha1_sign(ssh2_rsa_ctx *rsa, LIBSSH2_SESSION *session,
return ssh2_rsa_sha2_sign(rsa, session, hash, hash_len,
signature, signature_len);
}
#endif
void ssh2_rsa_free(ssh2_rsa_ctx *rsa)
{
@@ -571,6 +576,7 @@ static unsigned char *mbed_gen_publickey_from_rsa(LIBSSH2_SESSION *session,
*keylen = (size_t)(p - key);
return key;
}
#endif /* LIBSSH2_RSA */
static int mbed_pub_priv_key(LIBSSH2_SESSION *session, char **method,
unsigned char **pubkeydata,
@@ -580,26 +586,28 @@ static int mbed_pub_priv_key(LIBSSH2_SESSION *session, char **method,
char *method_buf = NULL;
unsigned char *key = NULL;
size_t keylen = 0, method_buf_len = 0;
int ret;
mbedtls_rsa_context *rsa;
int ret = 0;
if(mbedtls_pk_get_type(pkey) != MBEDTLS_PK_RSA)
return ssh2_err(session, LIBSSH2_ERROR_FILE, "Key type not supported");
#if LIBSSH2_RSA
if(mbedtls_pk_get_type(pkey) == MBEDTLS_PK_RSA) {
mbedtls_rsa_context *rsa;
ret = 0;
/* write method */
method_buf_len = sizeof("ssh-rsa") - 1;
method_buf = SSH2_ALLOC(session, method_buf_len + 1);
if(method_buf)
memcpy(method_buf, "ssh-rsa", method_buf_len + 1);
else
ret = -1;
/* write method */
method_buf_len = sizeof("ssh-rsa") - 1;
method_buf = SSH2_ALLOC(session, method_buf_len + 1);
if(method_buf)
memcpy(method_buf, "ssh-rsa", method_buf_len + 1);
rsa = mbedtls_pk_rsa(*pkey);
key = mbed_gen_publickey_from_rsa(session, rsa, &keylen);
if(!key)
ret = -1;
}
else
ret = -1;
rsa = mbedtls_pk_rsa(*pkey);
key = mbed_gen_publickey_from_rsa(session, rsa, &keylen);
if(!key)
ret = -1;
#endif
ret = ssh2_err(session, LIBSSH2_ERROR_FILE, "Key type not supported");
/* write output */
if(ret) {

View File

@@ -94,7 +94,7 @@ static int sshrsapubkey(LIBSSH2_SESSION *session, char **sshpubkey,
struct asn1Element *params, struct asn1Element *key,
const char *method);
#if LIBSSH2_DSA != 0
#if LIBSSH2_DSA
/* dsaEncryption OID: 1.2.840.10040.4.1 */
static unsigned char OID_dsaEncryption[] = {
7, 40 + 2, 0x86, 0x48, 0xCE, 0x38, 4, 1
@@ -294,10 +294,10 @@ static struct {
struct asn1Element *key, const char *method);
const char *method;
} pka[] = {
#if LIBSSH2_RSA != 0
#if LIBSSH2_RSA
{ OID_rsaEncryption, sshrsapubkey, "ssh-rsa" },
#endif
#if LIBSSH2_DSA != 0
#if LIBSSH2_DSA
{ OID_dsaEncryption, sshdsapubkey, "ssh-dss" },
#endif
{ NULL, NULL, NULL }
@@ -1159,6 +1159,7 @@ int ssh2_cipher_crypt(ssh2_cipher_ctx *ctx, SSH2_CIPHER_T(algo),
*
*******************************************************************/
#if LIBSSH2_RSA
int ssh2_rsa_new(ssh2_rsa_ctx **rsa,
const unsigned char *edata, size_t elen,
const unsigned char *ndata, size_t nlen,
@@ -1255,6 +1256,7 @@ int ssh2_rsa_new(ssh2_rsa_ctx **rsa,
*rsa = ctx;
return ret;
}
#endif /* LIBSSH2_RSA */
/*******************************************************************
*
@@ -2288,6 +2290,7 @@ int ssh2_pub_privkey(LIBSSH2_SESSION *session, char **method,
passphrase);
}
#if LIBSSH2_RSA
static int os400_rsa_new_priv_from_file(ssh2_rsa_ctx **rsa,
LIBSSH2_SESSION *session,
const char *filename,
@@ -2394,6 +2397,7 @@ int ssh2_rsa_new_priv(ssh2_rsa_ctx **rsa,
blob, blob_len, passphrase);
}
#if LIBSSH2_RSA_SHA2
int ssh2_rsa_sha2_verify(ssh2_rsa_ctx *rsa, size_t hash_len,
const unsigned char *sig, size_t sig_len,
const unsigned char *m, size_t m_len)
@@ -2427,7 +2431,8 @@ int ssh2_rsa_sha2_verify(ssh2_rsa_ctx *rsa, size_t hash_len,
NULL, (char *)&errcode);
return errcode.Bytes_Available ? -1 : 0;
}
#endif
#if LIBSSH2_RSA_SHA1
int ssh2_rsa_sha1_verify(ssh2_rsa_ctx *rsa,
const unsigned char *sig, size_t sig_len,
const unsigned char *m, size_t m_len)
@@ -2435,6 +2440,7 @@ int ssh2_rsa_sha1_verify(ssh2_rsa_ctx *rsa,
return ssh2_rsa_sha2_verify(rsa, SSH2_SHA1_DIG_LEN,
sig, sig_len, m, m_len);
}
#endif
int ssh2_os400qc3_rsa_signv(ssh2_rsa_ctx *rsa, LIBSSH2_SESSION *session,
int algo,
@@ -2468,6 +2474,7 @@ int ssh2_os400qc3_rsa_signv(ssh2_rsa_ctx *rsa, LIBSSH2_SESSION *session,
*signature_len = siglen;
return 0;
}
#endif /* LIBSSH2_RSA */
#endif /* LIBSSH2_OS400QC3 */

View File

@@ -258,22 +258,28 @@ struct os400qc3_dh_ctx { /* Diffie-Hellman context. */
#define ssh2_cipher_dtor(ctx) ssh2_os400qc3_crypto_dtor(ctx)
#if LIBSSH2_RSA
#define ssh2_rsa_ctx struct os400qc3_crypto_ctx
#define ssh2_rsa_free(rsa) \
(ssh2_os400qc3_crypto_dtor(rsa), free((char *)rsa))
#define ssh2_prepare_iovec(vec, len) \
memset((char *)(vec), 0, (len) * sizeof(struct iovec))
#if LIBSSH2_RSA_SHA1
#define ssh2_rsa_sha1_signv(rsa, session, sig, siglen, count, vector) \
ssh2_os400qc3_rsa_signv(rsa, session, Qc3_SHA1, sig, siglen, count, vector)
#endif
#if LIBSSH2_RSA_SHA2
#define ssh2_rsa_sha2_256_signv(rsa, session, sig, siglen, cnt, vector) \
ssh2_os400qc3_rsa_signv(rsa, session, Qc3_SHA256, sig, siglen, cnt, vector)
#define ssh2_rsa_sha2_512_signv(rsa, session, sig, siglen, cnt, vector) \
ssh2_os400qc3_rsa_signv(rsa, session, Qc3_SHA512, sig, siglen, cnt, vector)
#endif
int ssh2_os400qc3_rsa_signv(ssh2_rsa_ctx *rsa, LIBSSH2_SESSION *session,
int algo,
unsigned char **signature, size_t *signature_len,
int veccount, const struct iovec vector[]);
#endif /* LIBSSH2_RSA */
#define ssh2_dh_ctx struct os400qc3_dh_ctx

View File

@@ -1307,7 +1307,6 @@ int ssh2_rsa_sha1_verify(ssh2_rsa_ctx *rsa,
BCRYPT_PAD_PKCS1);
}
#endif
#if LIBSSH2_RSA_SHA2
int ssh2_rsa_sha2_verify(ssh2_rsa_ctx *rsa, size_t hash_len,
const unsigned char *sig, size_t sig_len,
@@ -1375,6 +1374,7 @@ static int wcng_rsa_sha_sign(ssh2_rsa_ctx *rsa, LIBSSH2_SESSION *session,
return BCRYPT_SUCCESS(ret) ? 0 : -1;
}
#if LIBSSH2_RSA_SHA1
int ssh2_rsa_sha1_sign(ssh2_rsa_ctx *rsa, LIBSSH2_SESSION *session,
const unsigned char *hash, size_t hash_len,
unsigned char **signature, size_t *signature_len)
@@ -1382,7 +1382,8 @@ int ssh2_rsa_sha1_sign(ssh2_rsa_ctx *rsa, LIBSSH2_SESSION *session,
return wcng_rsa_sha_sign(rsa, session,
hash, hash_len, signature, signature_len);
}
#endif
#if LIBSSH2_RSA_SHA2
int ssh2_rsa_sha2_sign(ssh2_rsa_ctx *rsa, LIBSSH2_SESSION *session,
const unsigned char *hash, size_t hash_len,
unsigned char **signature, size_t *signature_len)
@@ -1390,6 +1391,7 @@ int ssh2_rsa_sha2_sign(ssh2_rsa_ctx *rsa, LIBSSH2_SESSION *session,
return wcng_rsa_sha_sign(rsa, session,
hash, hash_len, signature, signature_len);
}
#endif
void ssh2_rsa_free(ssh2_rsa_ctx *rsa)
{

View File

@@ -7,7 +7,7 @@
int test(LIBSSH2_SESSION *session)
{
#if LIBSSH2_RSA_SHA1
#if LIBSSH2_RSA
/* set in Dockerfile */
return test_auth_pubkey(session, 0,
"libssh2",

View File

@@ -7,7 +7,7 @@
int test(LIBSSH2_SESSION *session)
{
#if LIBSSH2_RSA_SHA1 && LIBSSH2_AES_GCM && \
#if LIBSSH2_RSA && LIBSSH2_AES_GCM && \
(defined(LIBSSH2_OPENSSL) || defined(LIBSSH2_WOLFSSL))
/* set in Dockerfile */
return test_auth_pubkey(session, 0,

View File

@@ -7,7 +7,7 @@
int test(LIBSSH2_SESSION *session)
{
#if LIBSSH2_RSA_SHA1 && LIBSSH2_MD5_PEM && LIBSSH2_AES_CBC
#if LIBSSH2_RSA && LIBSSH2_MD5_PEM && LIBSSH2_AES_CBC
/* set in Dockerfile */
return test_auth_pubkey(session, 0,
"libssh2",

View File

@@ -7,8 +7,7 @@
int test(LIBSSH2_SESSION *session)
{
#if LIBSSH2_RSA_SHA1 && \
(defined(LIBSSH2_OPENSSL) || defined(LIBSSH2_WOLFSSL))
#if LIBSSH2_RSA && (defined(LIBSSH2_OPENSSL) || defined(LIBSSH2_WOLFSSL))
/* set in Dockerfile */
return test_auth_pubkey(session, 0,
"libssh2",