mirror of
https://github.com/libssh2/libssh2.git
synced 2025-07-29 13:01:14 +03:00
Notes: * Host Key RSA 256/512 support #536 * Client side key hash upgrading for RFC 8332 * Support for server-sig-algs, ext-info-c server messages * Customizing preferred server-sig-algs via the preference LIBSSH2_METHOD_SIGN_ALGO Credit: Anders Borum, Will Cosgrove
This commit is contained in:
@ -637,6 +637,32 @@ Note: this procedure is not used if macro _libssh2_rsa_sha1_signv() is defined.
|
||||
void _libssh2_rsa_free(libssh2_rsa_ctx *rsactx);
|
||||
Releases the RSA computation context at rsactx.
|
||||
|
||||
LIBSSH2_RSA_SHA2
|
||||
#define as 1 if the crypto library supports RSA SHA2 256/512, else 0.
|
||||
If defined as 0, the rest of this section can be omitted.
|
||||
|
||||
int _libssh2_rsa_sha2_sign(LIBSSH2_SESSION * session,
|
||||
libssh2_rsa_ctx * rsactx,
|
||||
const unsigned char *hash,
|
||||
size_t hash_len,
|
||||
unsigned char **signature,
|
||||
size_t *signature_len);
|
||||
RSA signs the (hash, hashlen) SHA-2 hash bytes based on hash length and stores
|
||||
the allocated signature at (signature, signature_len).
|
||||
Signature buffer must be allocated from the given session.
|
||||
Returns 0 if OK, else -1.
|
||||
This procedure is already prototyped in crypto.h.
|
||||
Note: this procedure is not used if macro _libssh2_rsa_sha1_signv() is defined.
|
||||
|
||||
int _libssh2_rsa_sha2_verify(libssh2_rsa_ctx * rsa,
|
||||
size_t hash_len,
|
||||
const unsigned char *sig,
|
||||
unsigned long sig_len,
|
||||
const unsigned char *m, unsigned long m_len);
|
||||
Verify (sig, sig_len) signature of (m, m_len) using an SHA-2 hash based on
|
||||
hash length and the RSA context.
|
||||
Return 0 if OK, else -1.
|
||||
This procedure is already prototyped in crypto.h.
|
||||
|
||||
7.2) DSA
|
||||
LIBSSH2_DSA
|
||||
@ -900,3 +926,14 @@ If this is not needed, it should be defined as an empty macro.
|
||||
int _libssh2_random(unsigned char *buf, int len);
|
||||
Store len random bytes at buf.
|
||||
Returns 0 if OK, else -1.
|
||||
|
||||
const char * _libssh2_supported_key_sign_algorithms(LIBSSH2_SESSION *session,
|
||||
unsigned char *key_method,
|
||||
size_t key_method_len);
|
||||
|
||||
This function is for implementing key hash upgrading as defined in RFC 8332.
|
||||
|
||||
Based on the incoming key_method value, this function will return a
|
||||
list of supported algorithms that can upgrade the original key method algorithm
|
||||
as a comma seperated list, if there is no upgrade option this function should
|
||||
return NULL.
|
||||
|
@ -1,4 +1,4 @@
|
||||
.TH libssh2_session_methods 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
|
||||
.TH libssh2_session_methods 3 "8 Nov 2021" "libssh2 1.11" "libssh2 manual"
|
||||
.SH NAME
|
||||
libssh2_session_methods - return the currently active algorithms
|
||||
.SH SYNOPSIS
|
||||
@ -14,7 +14,8 @@ libssh2_session_methods(LIBSSH2_SESSION *session, int method_type);
|
||||
\fImethod_type\fP - one of the method type constants: LIBSSH2_METHOD_KEX,
|
||||
LIBSSH2_METHOD_HOSTKEY, LIBSSH2_METHOD_CRYPT_CS, LIBSSH2_METHOD_CRYPT_SC,
|
||||
LIBSSH2_METHOD_MAC_CS, LIBSSH2_METHOD_MAC_SC, LIBSSH2_METHOD_COMP_CS,
|
||||
LIBSSH2_METHOD_COMP_SC, LIBSSH2_METHOD_LANG_CS, LIBSSH2_METHOD_LANG_SC.
|
||||
LIBSSH2_METHOD_COMP_SC, LIBSSH2_METHOD_LANG_CS, LIBSSH2_METHOD_LANG_SC,
|
||||
LIBSSH2_METHOD_SIGN_ALGO.
|
||||
|
||||
Returns the actual method negotiated for a particular transport parameter.
|
||||
.SH RETURN VALUE
|
||||
|
@ -356,6 +356,7 @@ typedef struct _LIBSSH2_USERAUTH_KBDINT_RESPONSE
|
||||
#define LIBSSH2_METHOD_COMP_SC 7
|
||||
#define LIBSSH2_METHOD_LANG_CS 8
|
||||
#define LIBSSH2_METHOD_LANG_SC 9
|
||||
#define LIBSSH2_METHOD_SIGN_ALGO 10
|
||||
|
||||
/* flags */
|
||||
#define LIBSSH2_FLAG_SIGPIPE 1
|
||||
|
32
src/crypto.h
32
src/crypto.h
@ -93,6 +93,19 @@ int _libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session,
|
||||
size_t hash_len,
|
||||
unsigned char **signature,
|
||||
size_t *signature_len);
|
||||
#if LIBSSH2_RSA_SHA2
|
||||
int _libssh2_rsa_sha2_sign(LIBSSH2_SESSION * session,
|
||||
libssh2_rsa_ctx * rsactx,
|
||||
const unsigned char *hash,
|
||||
size_t hash_len,
|
||||
unsigned char **signature,
|
||||
size_t *signature_len);
|
||||
int _libssh2_rsa_sha2_verify(libssh2_rsa_ctx * rsa,
|
||||
size_t hash_len,
|
||||
const unsigned char *sig,
|
||||
unsigned long sig_len,
|
||||
const unsigned char *m, unsigned long m_len);
|
||||
#endif
|
||||
int _libssh2_rsa_new_private_frommemory(libssh2_rsa_ctx ** rsa,
|
||||
LIBSSH2_SESSION * session,
|
||||
const char *filedata,
|
||||
@ -245,4 +258,23 @@ int _libssh2_pub_priv_keyfilememory(LIBSSH2_SESSION *session,
|
||||
size_t privatekeydata_len,
|
||||
const char *passphrase);
|
||||
|
||||
|
||||
/**
|
||||
* @function _libssh2_supported_key_sign_algorithms
|
||||
* @abstract Returns supported algorithms used for upgrading public
|
||||
* key signing RFC 8332
|
||||
* @discussion Based on the incoming key_method value, this function
|
||||
* will return supported algorithms that can upgrade the key method
|
||||
* @related _libssh2_key_sign_algorithm()
|
||||
* @param key_method current key method, usually the default key sig method
|
||||
* @param key_method_len length of the key method buffer
|
||||
* @result comma seperated list of supported upgrade options per RFC 8332, if
|
||||
* there is no upgrade option return NULL
|
||||
*/
|
||||
|
||||
const char *
|
||||
_libssh2_supported_key_sign_algorithms(LIBSSH2_SESSION *session,
|
||||
unsigned char *key_method,
|
||||
size_t key_method_len);
|
||||
|
||||
#endif /* __LIBSSH2_CRYPTO_H */
|
||||
|
198
src/hostkey.c
198
src/hostkey.c
@ -64,8 +64,8 @@ hostkey_method_ssh_rsa_init(LIBSSH2_SESSION * session,
|
||||
void **abstract)
|
||||
{
|
||||
libssh2_rsa_ctx *rsactx;
|
||||
unsigned char *e, *n;
|
||||
size_t e_len, n_len;
|
||||
unsigned char *e, *n, *type;
|
||||
size_t e_len, n_len, type_len;
|
||||
struct string_buf buf;
|
||||
|
||||
if(*abstract) {
|
||||
@ -83,8 +83,27 @@ hostkey_method_ssh_rsa_init(LIBSSH2_SESSION * session,
|
||||
buf.dataptr = buf.data;
|
||||
buf.len = hostkey_data_len;
|
||||
|
||||
if(_libssh2_match_string(&buf, "ssh-rsa"))
|
||||
if(_libssh2_get_string(&buf, &type, &type_len)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* we accept one of 3 header types */
|
||||
if(type_len == 7 && strncmp("ssh-rsa", (char *)type, 7) == 0) {
|
||||
/* ssh-rsa */
|
||||
}
|
||||
#if LIBSSH2_RSA_SHA2
|
||||
else if(type_len == 12 && strncmp("rsa-sha2-256", (char *)type, 12) == 0) {
|
||||
/* rsa-sha2-256 */
|
||||
}
|
||||
else if(type_len == 12 && strncmp("rsa-sha2-512", (char *)type, 12) == 0) {
|
||||
/* rsa-sha2-512 */
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_ERROR,
|
||||
"unexpected rsa type: %.*s", type_len, type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(_libssh2_get_string(&buf, &e, &e_len))
|
||||
return -1;
|
||||
@ -227,6 +246,146 @@ hostkey_method_ssh_rsa_signv(LIBSSH2_SESSION * session,
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* hostkey_method_ssh_rsa_sha2_256_sig_verify
|
||||
*
|
||||
* Verify signature created by remote
|
||||
*/
|
||||
#if LIBSSH2_RSA_SHA2
|
||||
|
||||
static int
|
||||
hostkey_method_ssh_rsa_sha2_256_sig_verify(LIBSSH2_SESSION * session,
|
||||
const unsigned char *sig,
|
||||
size_t sig_len,
|
||||
const unsigned char *m,
|
||||
size_t m_len, void **abstract)
|
||||
{
|
||||
libssh2_rsa_ctx *rsactx = (libssh2_rsa_ctx *) (*abstract);
|
||||
(void) session;
|
||||
|
||||
/* Skip past keyname_len(4) + keyname(12){"rsa-sha2-256"} +
|
||||
signature_len(4) */
|
||||
if(sig_len < 20)
|
||||
return -1;
|
||||
|
||||
sig += 20;
|
||||
sig_len -= 20;
|
||||
return _libssh2_rsa_sha2_verify(rsactx, SHA256_DIGEST_LENGTH, sig, sig_len,
|
||||
m, m_len);
|
||||
}
|
||||
|
||||
/*
|
||||
* hostkey_method_ssh_rsa_sha2_256_signv
|
||||
*
|
||||
* Construct a signature from an array of vectors
|
||||
*/
|
||||
|
||||
static int
|
||||
hostkey_method_ssh_rsa_sha2_256_signv(LIBSSH2_SESSION * session,
|
||||
unsigned char **signature,
|
||||
size_t *signature_len,
|
||||
int veccount,
|
||||
const struct iovec datavec[],
|
||||
void **abstract)
|
||||
{
|
||||
libssh2_rsa_ctx *rsactx = (libssh2_rsa_ctx *) (*abstract);
|
||||
|
||||
#ifdef _libssh2_rsa_sha2_256_signv
|
||||
return _libssh2_rsa_sha2_256_signv(session, signature, signature_len,
|
||||
veccount, datavec, rsactx);
|
||||
#else
|
||||
int ret;
|
||||
int i;
|
||||
unsigned char hash[SHA256_DIGEST_LENGTH];
|
||||
libssh2_sha256_ctx ctx;
|
||||
|
||||
libssh2_sha256_init(&ctx);
|
||||
for(i = 0; i < veccount; i++) {
|
||||
libssh2_sha256_update(ctx, datavec[i].iov_base, datavec[i].iov_len);
|
||||
}
|
||||
libssh2_sha256_final(ctx, hash);
|
||||
|
||||
ret = _libssh2_rsa_sha2_sign(session, rsactx, hash, SHA256_DIGEST_LENGTH,
|
||||
signature, signature_len);
|
||||
if(ret) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* hostkey_method_ssh_rsa_sha2_512_sig_verify
|
||||
*
|
||||
* Verify signature created by remote
|
||||
*/
|
||||
|
||||
static int
|
||||
hostkey_method_ssh_rsa_sha2_512_sig_verify(LIBSSH2_SESSION * session,
|
||||
const unsigned char *sig,
|
||||
size_t sig_len,
|
||||
const unsigned char *m,
|
||||
size_t m_len, void **abstract)
|
||||
{
|
||||
libssh2_rsa_ctx *rsactx = (libssh2_rsa_ctx *) (*abstract);
|
||||
(void) session;
|
||||
|
||||
/* Skip past keyname_len(4) + keyname(12){"rsa-sha2-512"} +
|
||||
signature_len(4) */
|
||||
if(sig_len < 20)
|
||||
return -1;
|
||||
|
||||
sig += 20;
|
||||
sig_len -= 20;
|
||||
return _libssh2_rsa_sha2_verify(rsactx, SHA512_DIGEST_LENGTH, sig,
|
||||
sig_len, m, m_len);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* hostkey_method_ssh_rsa_sha2_512_signv
|
||||
*
|
||||
* Construct a signature from an array of vectors
|
||||
*/
|
||||
static int
|
||||
hostkey_method_ssh_rsa_sha2_512_signv(LIBSSH2_SESSION * session,
|
||||
unsigned char **signature,
|
||||
size_t *signature_len,
|
||||
int veccount,
|
||||
const struct iovec datavec[],
|
||||
void **abstract)
|
||||
{
|
||||
libssh2_rsa_ctx *rsactx = (libssh2_rsa_ctx *) (*abstract);
|
||||
|
||||
#ifdef _libssh2_rsa_sha2_512_signv
|
||||
return _libssh2_rsa_sha2_512_signv(session, signature, signature_len,
|
||||
veccount, datavec, rsactx);
|
||||
#else
|
||||
int ret;
|
||||
int i;
|
||||
unsigned char hash[SHA512_DIGEST_LENGTH];
|
||||
libssh2_sha512_ctx ctx;
|
||||
|
||||
libssh2_sha512_init(&ctx);
|
||||
for(i = 0; i < veccount; i++) {
|
||||
libssh2_sha512_update(ctx, datavec[i].iov_base, datavec[i].iov_len);
|
||||
}
|
||||
libssh2_sha512_final(ctx, hash);
|
||||
|
||||
ret = _libssh2_rsa_sha2_sign(session, rsactx, hash, SHA512_DIGEST_LENGTH,
|
||||
signature, signature_len);
|
||||
if(ret) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* LIBSSH2_RSA_SHA2 */
|
||||
|
||||
|
||||
/*
|
||||
* hostkey_method_ssh_rsa_dtor
|
||||
*
|
||||
@ -260,6 +419,35 @@ static const LIBSSH2_HOSTKEY_METHOD hostkey_method_ssh_rsa = {
|
||||
NULL, /* encrypt */
|
||||
hostkey_method_ssh_rsa_dtor,
|
||||
};
|
||||
|
||||
#if LIBSSH2_RSA_SHA2
|
||||
|
||||
static const LIBSSH2_HOSTKEY_METHOD hostkey_method_ssh_rsa_sha2_256 = {
|
||||
"rsa-sha2-256",
|
||||
SHA256_DIGEST_LENGTH,
|
||||
hostkey_method_ssh_rsa_init,
|
||||
hostkey_method_ssh_rsa_initPEM,
|
||||
hostkey_method_ssh_rsa_initPEMFromMemory,
|
||||
hostkey_method_ssh_rsa_sha2_256_sig_verify,
|
||||
hostkey_method_ssh_rsa_sha2_256_signv,
|
||||
NULL, /* encrypt */
|
||||
hostkey_method_ssh_rsa_dtor,
|
||||
};
|
||||
|
||||
static const LIBSSH2_HOSTKEY_METHOD hostkey_method_ssh_rsa_sha2_512 = {
|
||||
"rsa-sha2-512",
|
||||
SHA512_DIGEST_LENGTH,
|
||||
hostkey_method_ssh_rsa_init,
|
||||
hostkey_method_ssh_rsa_initPEM,
|
||||
hostkey_method_ssh_rsa_initPEMFromMemory,
|
||||
hostkey_method_ssh_rsa_sha2_512_sig_verify,
|
||||
hostkey_method_ssh_rsa_sha2_512_signv,
|
||||
NULL, /* encrypt */
|
||||
hostkey_method_ssh_rsa_dtor,
|
||||
};
|
||||
|
||||
#endif /* LIBSSH2_RSA_SHA2 */
|
||||
|
||||
#endif /* LIBSSH2_RSA */
|
||||
|
||||
#if LIBSSH2_DSA
|
||||
@ -1041,6 +1229,10 @@ static const LIBSSH2_HOSTKEY_METHOD *hostkey_methods[] = {
|
||||
&hostkey_method_ssh_ed25519,
|
||||
#endif
|
||||
#if LIBSSH2_RSA
|
||||
#if LIBSSH2_RSA_SHA2
|
||||
&hostkey_method_ssh_rsa_sha2_512,
|
||||
&hostkey_method_ssh_rsa_sha2_256,
|
||||
#endif /* LIBSSH2_RSA_SHA2 */
|
||||
&hostkey_method_ssh_rsa,
|
||||
#endif /* LIBSSH2_RSA */
|
||||
#if LIBSSH2_DSA
|
||||
|
22
src/kex.c
22
src/kex.c
@ -3026,6 +3026,17 @@ kex_method_ssh_curve25519_sha256 = {
|
||||
};
|
||||
#endif
|
||||
|
||||
/* this kex method signals that client can receive extensions
|
||||
* as described in https://datatracker.ietf.org/doc/html/rfc8308
|
||||
*/
|
||||
|
||||
static const LIBSSH2_KEX_METHOD
|
||||
kex_method_extension_negotiation = {
|
||||
"ext-info-c",
|
||||
NULL,
|
||||
0,
|
||||
};
|
||||
|
||||
static const LIBSSH2_KEX_METHOD *libssh2_kex_methods[] = {
|
||||
#if LIBSSH2_ED25519
|
||||
&kex_method_ssh_curve25519_sha256,
|
||||
@ -3043,6 +3054,7 @@ static const LIBSSH2_KEX_METHOD *libssh2_kex_methods[] = {
|
||||
&kex_method_diffie_helman_group14_sha1,
|
||||
&kex_method_diffie_helman_group1_sha1,
|
||||
&kex_method_diffie_helman_group_exchange_sha1,
|
||||
&kex_method_extension_negotiation,
|
||||
NULL
|
||||
};
|
||||
|
||||
@ -3978,6 +3990,11 @@ libssh2_session_method_pref(LIBSSH2_SESSION * session, int method_type,
|
||||
mlist = NULL;
|
||||
break;
|
||||
|
||||
case LIBSSH2_METHOD_SIGN_ALGO:
|
||||
prefvar = &session->sign_algo_prefs;
|
||||
mlist = NULL;
|
||||
break;
|
||||
|
||||
default:
|
||||
return _libssh2_error(session, LIBSSH2_ERROR_INVAL,
|
||||
"Invalid parameter specified for method_type");
|
||||
@ -4073,6 +4090,11 @@ LIBSSH2_API int libssh2_session_supported_algs(LIBSSH2_SESSION* session,
|
||||
_libssh2_comp_methods(session);
|
||||
break;
|
||||
|
||||
case LIBSSH2_METHOD_SIGN_ALGO:
|
||||
/* no built-in supported list due to backend support */
|
||||
mlist = NULL;
|
||||
break;
|
||||
|
||||
default:
|
||||
return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
|
||||
"Unknown method type");
|
||||
|
@ -664,4 +664,22 @@ _libssh2_dh_dtor(_libssh2_dh_ctx *dhctx)
|
||||
*dhctx = NULL;
|
||||
}
|
||||
|
||||
/* _libssh2_supported_key_sign_algorithms
|
||||
*
|
||||
* Return supported key hash algo upgrades, see crypto.h
|
||||
*
|
||||
*/
|
||||
|
||||
const char *
|
||||
_libssh2_supported_key_sign_algorithms(LIBSSH2_SESSION *session,
|
||||
unsigned char *key_method,
|
||||
size_t key_method_len)
|
||||
{
|
||||
(void)session;
|
||||
(void)key_method;
|
||||
(void)key_method_len;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* LIBSSH2_LIBGCRYPT */
|
||||
|
@ -55,6 +55,7 @@
|
||||
#define LIBSSH2_3DES 1
|
||||
|
||||
#define LIBSSH2_RSA 1
|
||||
#define LIBSSH2_RSA_SHA2 0
|
||||
#define LIBSSH2_DSA 1
|
||||
#define LIBSSH2_ECDSA 0
|
||||
#define LIBSSH2_ED25519 0
|
||||
|
@ -640,6 +640,13 @@ struct _LIBSSH2_SESSION
|
||||
unsigned char server_hostkey_sha256[SHA256_DIGEST_LENGTH];
|
||||
int server_hostkey_sha256_valid;
|
||||
|
||||
/* public key algorithms accepted as comma separated list */
|
||||
char *server_sign_algorithms;
|
||||
size_t server_sign_algorithms_len;
|
||||
|
||||
/* key signing algorithm preferences -- NULL yields server order */
|
||||
char *sign_algo_prefs;
|
||||
|
||||
/* (remote as source of data -- packet_read ) */
|
||||
libssh2_endpoint_data remote;
|
||||
|
||||
@ -1006,6 +1013,7 @@ _libssh2_debug(LIBSSH2_SESSION * session, int context, const char *format, ...)
|
||||
#define SSH_MSG_DEBUG 4
|
||||
#define SSH_MSG_SERVICE_REQUEST 5
|
||||
#define SSH_MSG_SERVICE_ACCEPT 6
|
||||
#define SSH_MSG_EXT_INFO 7
|
||||
|
||||
#define SSH_MSG_KEXINIT 20
|
||||
#define SSH_MSG_NEWKEYS 21
|
||||
|
@ -1247,5 +1247,24 @@ _libssh2_mbedtls_ecdsa_free(libssh2_ecdsa_ctx *ctx)
|
||||
mbedtls_free(ctx);
|
||||
}
|
||||
|
||||
|
||||
/* _libssh2_supported_key_sign_algorithms
|
||||
*
|
||||
* Return supported key hash algo upgrades, see crypto.h
|
||||
*
|
||||
*/
|
||||
|
||||
const char *
|
||||
_libssh2_supported_key_sign_algorithms(LIBSSH2_SESSION *session,
|
||||
unsigned char *key_method,
|
||||
size_t key_method_len)
|
||||
{
|
||||
(void)session;
|
||||
(void)key_method;
|
||||
(void)key_method_len;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* LIBSSH2_ECDSA */
|
||||
#endif /* LIBSSH2_MBEDTLS */
|
||||
|
@ -71,6 +71,7 @@
|
||||
#define LIBSSH2_3DES 1
|
||||
|
||||
#define LIBSSH2_RSA 1
|
||||
#define LIBSSH2_RSA_SHA2 0
|
||||
#define LIBSSH2_DSA 0
|
||||
#ifdef MBEDTLS_ECDSA_C
|
||||
# define LIBSSH2_ECDSA 1
|
||||
|
100
src/openssl.c
100
src/openssl.c
@ -153,20 +153,56 @@ _libssh2_rsa_new(libssh2_rsa_ctx ** rsa,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
_libssh2_rsa_sha2_verify(libssh2_rsa_ctx * rsactx,
|
||||
size_t hash_len,
|
||||
const unsigned char *sig,
|
||||
unsigned long sig_len,
|
||||
const unsigned char *m, unsigned long m_len)
|
||||
{
|
||||
int ret;
|
||||
int nid_type;
|
||||
unsigned char *hash = malloc(hash_len);
|
||||
if(hash == NULL)
|
||||
return -1;
|
||||
|
||||
if(hash_len == SHA_DIGEST_LENGTH) {
|
||||
nid_type = NID_sha1;
|
||||
ret = _libssh2_sha1(m, m_len, hash);
|
||||
}
|
||||
else if(hash_len == SHA256_DIGEST_LENGTH) {
|
||||
nid_type = NID_sha256;
|
||||
ret = _libssh2_sha256(m, m_len, hash);
|
||||
|
||||
}
|
||||
else if(hash_len == SHA512_DIGEST_LENGTH) {
|
||||
nid_type = NID_sha512;
|
||||
ret = _libssh2_sha512(m, m_len, hash);
|
||||
}
|
||||
else
|
||||
ret = -1; /* unsupported digest */
|
||||
|
||||
if(ret != 0) {
|
||||
free(hash);
|
||||
return -1; /* failure */
|
||||
}
|
||||
|
||||
ret = RSA_verify(nid_type, hash, hash_len,
|
||||
(unsigned char *) sig, sig_len, rsactx);
|
||||
|
||||
free(hash);
|
||||
|
||||
return (ret == 1) ? 0 : -1;
|
||||
}
|
||||
|
||||
int
|
||||
_libssh2_rsa_sha1_verify(libssh2_rsa_ctx * rsactx,
|
||||
const unsigned char *sig,
|
||||
unsigned long sig_len,
|
||||
const unsigned char *m, unsigned long m_len)
|
||||
{
|
||||
unsigned char hash[SHA_DIGEST_LENGTH];
|
||||
int ret;
|
||||
|
||||
if(_libssh2_sha1(m, m_len, hash))
|
||||
return -1; /* failure */
|
||||
ret = RSA_verify(NID_sha1, hash, SHA_DIGEST_LENGTH,
|
||||
(unsigned char *) sig, sig_len, rsactx);
|
||||
return (ret == 1) ? 0 : -1;
|
||||
return _libssh2_rsa_sha2_verify(rsactx, SHA_DIGEST_LENGTH, sig, sig_len, m,
|
||||
m_len);
|
||||
}
|
||||
|
||||
#if LIBSSH2_DSA
|
||||
@ -1876,7 +1912,7 @@ _libssh2_ed25519_new_public(libssh2_ed25519_ctx ** ed_ctx,
|
||||
|
||||
|
||||
int
|
||||
_libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session,
|
||||
_libssh2_rsa_sha2_sign(LIBSSH2_SESSION * session,
|
||||
libssh2_rsa_ctx * rsactx,
|
||||
const unsigned char *hash,
|
||||
size_t hash_len,
|
||||
@ -1893,7 +1929,17 @@ _libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(hash_len == SHA_DIGEST_LENGTH)
|
||||
ret = RSA_sign(NID_sha1, hash, hash_len, sig, &sig_len, rsactx);
|
||||
else if(hash_len == SHA256_DIGEST_LENGTH)
|
||||
ret = RSA_sign(NID_sha256, hash, hash_len, sig, &sig_len, rsactx);
|
||||
else if(hash_len == SHA512_DIGEST_LENGTH)
|
||||
ret = RSA_sign(NID_sha512, hash, hash_len, sig, &sig_len, rsactx);
|
||||
else {
|
||||
_libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
||||
"Unsupported hash digest length");
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
if(!ret) {
|
||||
LIBSSH2_FREE(session, sig);
|
||||
@ -1906,6 +1952,19 @@ _libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session,
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
_libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session,
|
||||
libssh2_rsa_ctx * rsactx,
|
||||
const unsigned char *hash,
|
||||
size_t hash_len,
|
||||
unsigned char **signature, size_t *signature_len)
|
||||
{
|
||||
return _libssh2_rsa_sha2_sign(session, rsactx, hash, hash_len,
|
||||
signature, signature_len);
|
||||
}
|
||||
|
||||
|
||||
#if LIBSSH2_DSA
|
||||
int
|
||||
_libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx,
|
||||
@ -3283,4 +3342,27 @@ _libssh2_dh_dtor(_libssh2_dh_ctx *dhctx)
|
||||
*dhctx = NULL;
|
||||
}
|
||||
|
||||
/* _libssh2_supported_key_sign_algorithms
|
||||
*
|
||||
* Return supported key hash algo upgrades, see crypto.h
|
||||
*
|
||||
*/
|
||||
|
||||
const char *
|
||||
_libssh2_supported_key_sign_algorithms(LIBSSH2_SESSION *session,
|
||||
unsigned char *key_method,
|
||||
size_t key_method_len)
|
||||
{
|
||||
(void)session;
|
||||
|
||||
#if LIBSSH2_RSA_SHA2
|
||||
if(key_method_len == 7 &&
|
||||
memcmp(key_method, "ssh-rsa", key_method_len) == 0) {
|
||||
return "rsa-sha2-512,rsa-sha2-256,ssh-rsa";
|
||||
}
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* LIBSSH2_OPENSSL */
|
||||
|
@ -64,8 +64,10 @@
|
||||
|
||||
#ifdef OPENSSL_NO_RSA
|
||||
# define LIBSSH2_RSA 0
|
||||
# define LIBSSH2_RSA_SHA2 0
|
||||
#else
|
||||
# define LIBSSH2_RSA 1
|
||||
# define LIBSSH2_RSA_SHA2 1
|
||||
#endif
|
||||
|
||||
#ifdef OPENSSL_NO_DSA
|
||||
|
@ -2409,6 +2409,24 @@ _libssh2_os400qc3_rsa_sha1_signv(LIBSSH2_SESSION *session,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* _libssh2_supported_key_sign_algorithms
|
||||
*
|
||||
* Return supported key hash algo upgrades, see crypto.h
|
||||
*
|
||||
*/
|
||||
|
||||
const char *
|
||||
_libssh2_supported_key_sign_algorithms(LIBSSH2_SESSION *session,
|
||||
unsigned char *key_method,
|
||||
size_t key_method_len)
|
||||
{
|
||||
(void)session;
|
||||
(void)key_method;
|
||||
(void)key_method_len;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* LIBSSH2_OS400QC3 */
|
||||
|
||||
/* vim: set expandtab ts=4 sw=4: */
|
||||
|
@ -175,6 +175,7 @@
|
||||
#define LIBSSH2_3DES 1
|
||||
|
||||
#define LIBSSH2_RSA 1
|
||||
#define LIBSSH2_RSA_SHA2 0
|
||||
#define LIBSSH2_DSA 0
|
||||
#define LIBSSH2_ECDSA 0
|
||||
#define LIBSSH2_ED25519 0
|
||||
|
69
src/packet.c
69
src/packet.c
@ -615,6 +615,75 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
session->packAdd_state = libssh2_NB_state_idle;
|
||||
return 0;
|
||||
|
||||
/*
|
||||
byte SSH_MSG_EXT_INFO
|
||||
uint32 nr-extensions
|
||||
[repeat "nr-extensions" times]
|
||||
string extension-name [RFC8308]
|
||||
string extension-value (binary)
|
||||
*/
|
||||
|
||||
case SSH_MSG_EXT_INFO:
|
||||
if(datalen >= 5) {
|
||||
uint32_t nr_extensions = 0;
|
||||
struct string_buf buf;
|
||||
buf.data = (unsigned char *)data;
|
||||
buf.dataptr = buf.data;
|
||||
buf.len = datalen;
|
||||
buf.dataptr += 1; /* advance past type */
|
||||
|
||||
if(_libssh2_get_u32(&buf, &nr_extensions) != 0) {
|
||||
rc = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
||||
"Invalid extension info received");
|
||||
}
|
||||
|
||||
while(rc == 0 && nr_extensions > 0) {
|
||||
|
||||
size_t name_len = 0;
|
||||
size_t value_len = 0;
|
||||
unsigned char *name = NULL;
|
||||
unsigned char *value = NULL;
|
||||
|
||||
nr_extensions -= 1;
|
||||
|
||||
_libssh2_get_string(&buf, &name, &name_len);
|
||||
_libssh2_get_string(&buf, &value, &value_len);
|
||||
|
||||
if(name != NULL && value != NULL) {
|
||||
_libssh2_debug(session,
|
||||
LIBSSH2_TRACE_KEX,
|
||||
"Server to Client extension %.*s: %.*s",
|
||||
name_len, name, value_len, value);
|
||||
}
|
||||
|
||||
if(name_len == 15 &&
|
||||
memcmp(name, "server-sig-algs", 15) == 0) {
|
||||
if(session->server_sign_algorithms) {
|
||||
LIBSSH2_FREE(session,
|
||||
session->server_sign_algorithms);
|
||||
}
|
||||
|
||||
session->server_sign_algorithms =
|
||||
LIBSSH2_ALLOC(session,
|
||||
value_len);
|
||||
|
||||
if(session->server_sign_algorithms) {
|
||||
session->server_sign_algorithms_len = value_len;
|
||||
memcpy(session->server_sign_algorithms,
|
||||
value, value_len);
|
||||
}
|
||||
else {
|
||||
rc = _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||
"memory for server sign algo");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LIBSSH2_FREE(session, data);
|
||||
session->packAdd_state = libssh2_NB_state_idle;
|
||||
return rc;
|
||||
|
||||
/*
|
||||
byte SSH_MSG_GLOBAL_REQUEST
|
||||
string request name in US-ASCII only
|
||||
|
159
src/userauth.c
159
src/userauth.c
@ -1086,6 +1086,148 @@ static int plain_method_len(const char *method, size_t method_len)
|
||||
return method_len;
|
||||
}
|
||||
|
||||
/**
|
||||
* @function _libssh2_key_sign_algorithm
|
||||
* @abstract Upgrades the algorithm used for public key signing RFC 8332
|
||||
* @discussion Based on the incoming key_method value, this function
|
||||
* will upgrade the key method input based on user preferences,
|
||||
* server support algos and crypto backend support
|
||||
* @related _libssh2_supported_key_sign_algorithms()
|
||||
* @param key_method current key method, usually the default key sig method
|
||||
* @param key_method_len length of the key method buffer
|
||||
* @result error code or zero on success
|
||||
*/
|
||||
|
||||
static int
|
||||
_libssh2_key_sign_algorithm(LIBSSH2_SESSION *session,
|
||||
unsigned char **key_method,
|
||||
size_t *key_method_len)
|
||||
{
|
||||
const char *s = NULL;
|
||||
const char *a = NULL;
|
||||
const char *match = NULL;
|
||||
const char *p = NULL;
|
||||
const char *f = NULL;
|
||||
char *i = NULL;
|
||||
int p_len = 0;
|
||||
int f_len = 0;
|
||||
int rc = 0;
|
||||
int match_len = 0;
|
||||
char *filtered_algs = NULL;
|
||||
|
||||
const char *supported_algs =
|
||||
_libssh2_supported_key_sign_algorithms(session,
|
||||
*key_method,
|
||||
*key_method_len);
|
||||
|
||||
if(supported_algs == NULL || session->server_sign_algorithms == NULL) {
|
||||
/* no upgrading key algorithm supported, do nothing */
|
||||
return LIBSSH2_ERROR_NONE;
|
||||
}
|
||||
|
||||
filtered_algs = LIBSSH2_ALLOC(session, strlen(supported_algs) + 1);
|
||||
if(!filtered_algs) {
|
||||
rc = _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||
"Unable to allocate filtered algs");
|
||||
return rc;
|
||||
}
|
||||
|
||||
s = session->server_sign_algorithms;
|
||||
i = filtered_algs;
|
||||
|
||||
/* this walks the server algo list and the supported algo list and creates
|
||||
a filtered list that includes matches */
|
||||
|
||||
while(s && *s) {
|
||||
p = strchr(s, ',');
|
||||
p_len = p ? (p - s) : (int) strlen(s);
|
||||
a = supported_algs;
|
||||
|
||||
while(a && *a) {
|
||||
f = strchr(a, ',');
|
||||
f_len = f ? (f - a) : (int) strlen(a);
|
||||
|
||||
if(f_len == p_len && memcmp(a, s, p_len)) {
|
||||
|
||||
if(i != filtered_algs) {
|
||||
memcpy(i, ",", 1);
|
||||
i += 1;
|
||||
}
|
||||
|
||||
memcpy(i, s, p_len);
|
||||
i += p_len;
|
||||
}
|
||||
|
||||
a = f ? (f + 1) : NULL;
|
||||
}
|
||||
|
||||
s = p ? (p + 1) : NULL;
|
||||
}
|
||||
|
||||
filtered_algs[i - filtered_algs] = '\0';
|
||||
|
||||
if(session->sign_algo_prefs) {
|
||||
s = session->sign_algo_prefs;
|
||||
}
|
||||
else {
|
||||
s = supported_algs;
|
||||
}
|
||||
|
||||
/* now that we have the possible supported algos, match based on the prefs
|
||||
or what is supported by the crypto backend, look for a match */
|
||||
|
||||
while(s && *s && !match) {
|
||||
p = strchr(s, ',');
|
||||
p_len = p ? (p - s) : (int) strlen(s);
|
||||
a = filtered_algs;
|
||||
|
||||
while(a && *a && !match) {
|
||||
f = strchr(a, ',');
|
||||
f_len = f ? (f - a) : (int) strlen(a);
|
||||
|
||||
if(f_len == p_len && memcmp(a, s, p_len)) {
|
||||
/* found a match, upgrade key method */
|
||||
match = s;
|
||||
match_len = p_len;
|
||||
}
|
||||
else {
|
||||
a = f ? (f + 1) : NULL;
|
||||
}
|
||||
}
|
||||
|
||||
s = p ? (p + 1) : NULL;
|
||||
}
|
||||
|
||||
if(match != NULL) {
|
||||
if(*key_method)
|
||||
LIBSSH2_FREE(session, *key_method);
|
||||
|
||||
*key_method = LIBSSH2_ALLOC(session, match_len);
|
||||
if(key_method) {
|
||||
memcpy(*key_method, match, match_len);
|
||||
*key_method_len = match_len;
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_KEX,
|
||||
"Signing using %.*s", match_len, match);
|
||||
}
|
||||
else {
|
||||
*key_method_len = 0;
|
||||
rc = _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||
"Unable to allocate key method upgrade");
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* no match was found */
|
||||
rc = _libssh2_error(session, LIBSSH2_ERROR_METHOD_NONE,
|
||||
"No signing signature matched");
|
||||
}
|
||||
|
||||
if(filtered_algs)
|
||||
LIBSSH2_FREE(session, filtered_algs);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
_libssh2_userauth_publickey(LIBSSH2_SESSION *session,
|
||||
const char *username,
|
||||
@ -1144,15 +1286,14 @@ _libssh2_userauth_publickey(LIBSSH2_SESSION *session,
|
||||
memcpy(session->userauth_pblc_method, pubkeydata + 4,
|
||||
session->userauth_pblc_method_len);
|
||||
}
|
||||
/*
|
||||
* The length of the method name read from plaintext prefix in the
|
||||
* file must match length embedded in the key.
|
||||
* TODO: The data should match too but we don't check that. Should we?
|
||||
*/
|
||||
else if(session->userauth_pblc_method_len !=
|
||||
_libssh2_ntohu32(pubkeydata))
|
||||
return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED,
|
||||
"Invalid public key");
|
||||
|
||||
/* upgrade key key signing algo needed */
|
||||
rc = _libssh2_key_sign_algorithm(session,
|
||||
&session->userauth_pblc_method,
|
||||
&session->userauth_pblc_method_len);
|
||||
|
||||
if(rc)
|
||||
return rc;
|
||||
|
||||
/*
|
||||
* 45 = packet_type(1) + username_len(4) + servicename_len(4) +
|
||||
|
18
src/wincng.c
18
src/wincng.c
@ -2591,4 +2591,22 @@ fb:
|
||||
return _libssh2_wincng_bignum_mod_exp(secret, f, dhctx->bn, p);
|
||||
}
|
||||
|
||||
/* _libssh2_supported_key_sign_algorithms
|
||||
*
|
||||
* Return supported key hash algo upgrades, see crypto.h
|
||||
*
|
||||
*/
|
||||
|
||||
const char *
|
||||
_libssh2_supported_key_sign_algorithms(LIBSSH2_SESSION *session,
|
||||
unsigned char *key_method,
|
||||
size_t key_method_len)
|
||||
{
|
||||
(void)session;
|
||||
(void)key_method;
|
||||
(void)key_method_len;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* LIBSSH2_WINCNG */
|
||||
|
@ -63,6 +63,7 @@
|
||||
#define LIBSSH2_3DES 1
|
||||
|
||||
#define LIBSSH2_RSA 1
|
||||
#define LIBSSH2_RSA_SHA2 0
|
||||
#define LIBSSH2_DSA 1
|
||||
#define LIBSSH2_ECDSA 0
|
||||
#define LIBSSH2_ED25519 0
|
||||
|
Reference in New Issue
Block a user