From 5d31fc6daeb5202df32cf560345cce3e735b49e2 Mon Sep 17 00:00:00 2001 From: Will Cosgrove Date: Mon, 30 Aug 2021 17:45:20 +0000 Subject: [PATCH 1/5] Host Key RSA 256/512 support #536 --- src/hostkey.c | 161 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 161 insertions(+) diff --git a/src/hostkey.c b/src/hostkey.c index d87a4c74..ddf13c36 100644 --- a/src/hostkey.c +++ b/src/hostkey.c @@ -227,6 +227,139 @@ hostkey_method_ssh_rsa_signv(LIBSSH2_SESSION * session, #endif } +/* + * hostkey_method_ssh_rsa_sha2_256_sig_verify + * + * Verify signature created by remote + */ + +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 +} + + /* * hostkey_method_ssh_rsa_dtor * @@ -260,6 +393,32 @@ static const LIBSSH2_HOSTKEY_METHOD hostkey_method_ssh_rsa = { NULL, /* encrypt */ hostkey_method_ssh_rsa_dtor, }; + + +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 */ #if LIBSSH2_DSA @@ -1043,6 +1202,8 @@ static const LIBSSH2_HOSTKEY_METHOD *hostkey_methods[] = { &hostkey_method_ssh_ed25519, #endif #if LIBSSH2_RSA + &hostkey_method_ssh_rsa_sha2_512, + &hostkey_method_ssh_rsa_sha2_256, &hostkey_method_ssh_rsa, #endif /* LIBSSH2_RSA */ #if LIBSSH2_DSA From b10ccc7633932207cf406d022b125251fe86b466 Mon Sep 17 00:00:00 2001 From: Will Cosgrove Date: Mon, 30 Aug 2021 23:05:56 +0000 Subject: [PATCH 2/5] Host Key RSA 256/512 support libssh2 #536 --- docs/HACKING-CRYPTO | 26 +++++++++++ src/crypto.h | 13 ++++++ src/hostkey.c | 8 ++++ src/libgcrypt.h | 1 + src/mbedtls.h | 1 + src/openssl.c | 107 +++++++++++++++++++++++++++++++++++++++----- src/openssl.h | 2 + src/os400qc3.h | 1 + src/wincng.h | 1 + 9 files changed, 150 insertions(+), 10 deletions(-) diff --git a/docs/HACKING-CRYPTO b/docs/HACKING-CRYPTO index ca947728..d0173553 100644 --- a/docs/HACKING-CRYPTO +++ b/docs/HACKING-CRYPTO @@ -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 diff --git a/src/crypto.h b/src/crypto.h index f512d603..efaf1564 100644 --- a/src/crypto.h +++ b/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, diff --git a/src/hostkey.c b/src/hostkey.c index ddf13c36..8040a4ea 100644 --- a/src/hostkey.c +++ b/src/hostkey.c @@ -232,6 +232,7 @@ hostkey_method_ssh_rsa_signv(LIBSSH2_SESSION * session, * * Verify signature created by remote */ +#if LIBSSH2_RSA_SHA2 static int hostkey_method_ssh_rsa_sha2_256_sig_verify(LIBSSH2_SESSION * session, @@ -359,6 +360,8 @@ hostkey_method_ssh_rsa_sha2_512_signv(LIBSSH2_SESSION * session, #endif } +#endif /* LIBSSH2_RSA_SHA2 */ + /* * hostkey_method_ssh_rsa_dtor @@ -394,6 +397,7 @@ static const LIBSSH2_HOSTKEY_METHOD hostkey_method_ssh_rsa = { hostkey_method_ssh_rsa_dtor, }; +#if LIBSSH2_RSA_SHA2 static const LIBSSH2_HOSTKEY_METHOD hostkey_method_ssh_rsa_sha2_256 = { "rsa-sha2-256", @@ -419,6 +423,8 @@ static const LIBSSH2_HOSTKEY_METHOD hostkey_method_ssh_rsa_sha2_512 = { hostkey_method_ssh_rsa_dtor, }; +#endif /* LIBSSH2_RSA_SHA2 */ + #endif /* LIBSSH2_RSA */ #if LIBSSH2_DSA @@ -1202,8 +1208,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 diff --git a/src/libgcrypt.h b/src/libgcrypt.h index 298c65ed..95876b96 100644 --- a/src/libgcrypt.h +++ b/src/libgcrypt.h @@ -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 diff --git a/src/mbedtls.h b/src/mbedtls.h index 671932c5..0450113f 100644 --- a/src/mbedtls.h +++ b/src/mbedtls.h @@ -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 diff --git a/src/openssl.c b/src/openssl.c index 7a6810f1..8b5327d4 100644 --- a/src/openssl.c +++ b/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; } - ret = RSA_sign(NID_sha1, hash, hash_len, sig, &sig_len, rsactx); + 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,32 @@ _libssh2_dh_dtor(_libssh2_dh_ctx *dhctx) *dhctx = NULL; } +#pragma mark PANIC + +int +_libssh2_cipher_crypt_buffer(_libssh2_cipher_ctx * ctx, + _libssh2_cipher_type(algo), + int encrypt, unsigned int seqno, unsigned char *buf, + size_t buf_len, unsigned char *out_buf, int blocksize) +{ + int ret = 0; + + while (buf_len >= blocksize) { + +#ifdef HAVE_OPAQUE_STRUCTS + ret = EVP_Cipher(*ctx, out_buf, buf, blocksize); +#else + ret = EVP_Cipher(ctx, out_buf, buf, blocksize); +#endif + + buf_len -= blocksize; /* less bytes left */ + out_buf += blocksize; /* advance write pointer */ + buf += blocksize; /* advance read pointer */ + } + + return ret == 1 ? 0 : 1; +} + +#pragma mark END PANIC + #endif /* LIBSSH2_OPENSSL */ diff --git a/src/openssl.h b/src/openssl.h index 658b040d..2a002b41 100644 --- a/src/openssl.h +++ b/src/openssl.h @@ -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 diff --git a/src/os400qc3.h b/src/os400qc3.h index e3602d9f..7bcef233 100644 --- a/src/os400qc3.h +++ b/src/os400qc3.h @@ -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 diff --git a/src/wincng.h b/src/wincng.h index eaf6f905..538cc431 100755 --- a/src/wincng.h +++ b/src/wincng.h @@ -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 From 33e98c4595ea82efe2d796ebdb2bbaf4a63f4f04 Mon Sep 17 00:00:00 2001 From: Will Cosgrove Date: Mon, 30 Aug 2021 23:07:49 +0000 Subject: [PATCH 3/5] Remove unnecessary code --- src/openssl.c | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/src/openssl.c b/src/openssl.c index 8b5327d4..60f715ad 100644 --- a/src/openssl.c +++ b/src/openssl.c @@ -3342,32 +3342,4 @@ _libssh2_dh_dtor(_libssh2_dh_ctx *dhctx) *dhctx = NULL; } -#pragma mark PANIC - -int -_libssh2_cipher_crypt_buffer(_libssh2_cipher_ctx * ctx, - _libssh2_cipher_type(algo), - int encrypt, unsigned int seqno, unsigned char *buf, - size_t buf_len, unsigned char *out_buf, int blocksize) -{ - int ret = 0; - - while (buf_len >= blocksize) { - -#ifdef HAVE_OPAQUE_STRUCTS - ret = EVP_Cipher(*ctx, out_buf, buf, blocksize); -#else - ret = EVP_Cipher(ctx, out_buf, buf, blocksize); -#endif - - buf_len -= blocksize; /* less bytes left */ - out_buf += blocksize; /* advance write pointer */ - buf += blocksize; /* advance read pointer */ - } - - return ret == 1 ? 0 : 1; -} - -#pragma mark END PANIC - #endif /* LIBSSH2_OPENSSL */ From f8db95b1d2502dd2729a1d3f14cee913ae7db962 Mon Sep 17 00:00:00 2001 From: Will Cosgrove Date: Thu, 2 Sep 2021 20:28:42 +0000 Subject: [PATCH 4/5] formatting --- src/hostkey.c | 12 ++++++++---- src/openssl.c | 16 ++++++++-------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/hostkey.c b/src/hostkey.c index 8040a4ea..5939ffc9 100644 --- a/src/hostkey.c +++ b/src/hostkey.c @@ -244,13 +244,15 @@ hostkey_method_ssh_rsa_sha2_256_sig_verify(LIBSSH2_SESSION * session, libssh2_rsa_ctx *rsactx = (libssh2_rsa_ctx *) (*abstract); (void) session; - /* Skip past keyname_len(4) + keyname(12){"rsa-sha2-256"} + signature_len(4) */ + /* 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); + return _libssh2_rsa_sha2_verify(rsactx, SHA256_DIGEST_LENGTH, sig, sig_len, + m, m_len); } /* @@ -310,13 +312,15 @@ hostkey_method_ssh_rsa_sha2_512_sig_verify(LIBSSH2_SESSION * session, libssh2_rsa_ctx *rsactx = (libssh2_rsa_ctx *) (*abstract); (void) session; - /* Skip past keyname_len(4) + keyname(12){"rsa-sha2-512"} + signature_len(4) */ + /* 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); + return _libssh2_rsa_sha2_verify(rsactx, SHA512_DIGEST_LENGTH, sig, + sig_len, m, m_len); } diff --git a/src/openssl.c b/src/openssl.c index 60f715ad..537031e1 100644 --- a/src/openssl.c +++ b/src/openssl.c @@ -163,7 +163,7 @@ _libssh2_rsa_sha2_verify(libssh2_rsa_ctx * rsactx, int ret; int nid_type; unsigned char *hash = malloc(hash_len); - if (hash == NULL) + if(hash == NULL) return -1; if(hash_len == SHA_DIGEST_LENGTH) { @@ -182,8 +182,7 @@ _libssh2_rsa_sha2_verify(libssh2_rsa_ctx * rsactx, else ret = -1; /* unsupported digest */ - if(ret != 0) - { + if(ret != 0) { free(hash); return -1; /* failure */ } @@ -202,7 +201,8 @@ _libssh2_rsa_sha1_verify(libssh2_rsa_ctx * rsactx, unsigned long sig_len, const unsigned char *m, unsigned long m_len) { - return _libssh2_rsa_sha2_verify(rsactx, SHA_DIGEST_LENGTH, sig, sig_len, m, m_len); + return _libssh2_rsa_sha2_verify(rsactx, SHA_DIGEST_LENGTH, sig, sig_len, m, + m_len); } #if LIBSSH2_DSA @@ -1959,10 +1959,10 @@ _libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session, 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); - } +{ + return _libssh2_rsa_sha2_sign(session, rsactx, hash, hash_len, + signature, signature_len); +} #if LIBSSH2_DSA From 9cc16ee3820e7aee924c58cf73ae5c520b331e36 Mon Sep 17 00:00:00 2001 From: Anders Borum Date: Tue, 26 Oct 2021 22:48:31 +0200 Subject: [PATCH 5/5] prefer rsa-sha2-256 over ssh-rsa in publickey auth --- src/userauth.c | 39 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/src/userauth.c b/src/userauth.c index 40ef9153..39da3ecf 100644 --- a/src/userauth.c +++ b/src/userauth.c @@ -480,6 +480,24 @@ libssh2_userauth_password_ex(LIBSSH2_SESSION *session, const char *username, return rc; } +/* + * upgrade_publickey_method + * + * Change method from ssh-rsa to rsa-sha2-256 is RSA SHA2 is supported. + */ +static void upgrade_publickey_method(LIBSSH2_SESSION * session, + unsigned char **method, + size_t *method_len) { +#if LIBSSH2_RSA_SHA2 + if(*method_len == 7 && memcmp(*method, "ssh-rsa", 7) == 0) { + LIBSSH2_FREE(session, *method); + *method_len = 12; + *method = LIBSSH2_ALLOC(session, 12); + memcpy(*method, "rsa-sha2-256", 12); + } +#endif +} + static int memory_read_publickey(LIBSSH2_SESSION * session, unsigned char **method, size_t *method_len, @@ -546,6 +564,9 @@ memory_read_publickey(LIBSSH2_SESSION * session, unsigned char **method, *method = pubkey; *method_len = sp1 - pubkey - 1; + /* upgrade to sha2 for rsa keys when supported */ + upgrade_publickey_method(session, method, method_len); + *pubkeydata = tmp; *pubkeydata_len = tmp_len; @@ -648,6 +669,9 @@ file_read_publickey(LIBSSH2_SESSION * session, unsigned char **method, * it a wash */ *method = pubkey; *method_len = sp1 - pubkey - 1; + + /* upgrade to sha2 for rsa keys when supported */ + upgrade_publickey_method(session, method, method_len); *pubkeydata = tmp; *pubkeydata_len = tmp_len; @@ -1150,10 +1174,19 @@ _libssh2_userauth_publickey(LIBSSH2_SESSION *session, * 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"); + _libssh2_ntohu32(pubkeydata)) { + + // we accept mismatch if public key is "ssh-rsa" and + // method has prefix "rsa-sha2-" to satisfy RFC 8332 + if(session->userauth_pblc_method_len < 9 || + _libssh2_ntohu32(pubkeydata) != 7 || + memcmp(pubkeydata + 4, "ssh-rsa", 7) || + memcmp(session->userauth_pblc_method, "rsa-sha2-", 9)) { + return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED, + "Invalid public key"); + } + } /* * 45 = packet_type(1) + username_len(4) + servicename_len(4) + * service_name(14)"ssh-connection" + authmethod_len(4) +