1
1

Fix _libssh2_random() silently discarding errors (#520)

Notes:
* Make _libssh2_random return code consistent

Previously, _libssh2_random was advertized in HACKING.CRYPTO as
returning `void` (and was implemented that way in os400qc3.c), but that
was in other crypto backends a lie; _libssh2_random is (a macro
expanding) to an int-value expression or function.

Moreover, that returned code was:
  — 0 or success, -1 on error for the MbedTLS & WinCNG crypto backends
But also:
  — 1 on success, -1 or 0 on error for the OpenSSL backend!
  – 1 on success, error cannot happen for libgcrypt!

This commit makes explicit that _libssh2_random can fail (because most of
the underlying crypto functions can indeed fail!), and it makes its result
code consistent: 0 on success, -1 on error.

This is related to issue #519 https://github.com/libssh2/libssh2/issues/519
It fixes the first half of it.

* Don't silent errors of _libssh2_random

Make sure to check the returned code of _libssh2_random(), and
propagates any failure.

A new LIBSSH_ERROR_RANDGEN constant is added to libssh2.h
None of the existing error constants seemed fit.

This commit is related to d74285b68450c0e9ea6d5f8070450837fb1e74a7
and to https://github.com/libssh2/libssh2/issues/519 (see the issue
for more info.)  It closes #519.

Credit:
Paul Capron
Этот коммит содержится в:
Paul Capron 2021-05-11 23:06:18 +02:00 коммит произвёл GitHub
родитель 1270fdfe4b
Коммит b3a8a6d27c
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
9 изменённых файлов: 24 добавлений и 8 удалений

Просмотреть файл

@ -897,5 +897,6 @@ In example, this is needed to preset unused structure slacks on platforms
requiring it. requiring it.
If this is not needed, it should be defined as an empty macro. If this is not needed, it should be defined as an empty macro.
void _libssh2_random(unsigned char *buf, int len); int _libssh2_random(unsigned char *buf, int len);
Store len random bytes at buf. Store len random bytes at buf.
Returns 0 if OK, else -1.

Просмотреть файл

@ -505,6 +505,7 @@ typedef struct _LIBSSH2_POLLFD {
#define LIBSSH2_ERROR_KNOWN_HOSTS -46 #define LIBSSH2_ERROR_KNOWN_HOSTS -46
#define LIBSSH2_ERROR_CHANNEL_WINDOW_FULL -47 #define LIBSSH2_ERROR_CHANNEL_WINDOW_FULL -47
#define LIBSSH2_ERROR_KEYFILE_AUTH_FAILED -48 #define LIBSSH2_ERROR_KEYFILE_AUTH_FAILED -48
#define LIBSSH2_ERROR_RANDGEN -49
/* this is a define to provide the old (<= 1.2.7) name */ /* this is a define to provide the old (<= 1.2.7) name */
#define LIBSSH2_ERROR_BANNER_NONE LIBSSH2_ERROR_BANNER_RECV #define LIBSSH2_ERROR_BANNER_NONE LIBSSH2_ERROR_BANNER_RECV

Просмотреть файл

@ -1338,7 +1338,11 @@ channel_x11_req(LIBSSH2_CHANNEL *channel, int single_connection,
border */ border */
unsigned char buffer[(LIBSSH2_X11_RANDOM_COOKIE_LEN / 2) + 1]; unsigned char buffer[(LIBSSH2_X11_RANDOM_COOKIE_LEN / 2) + 1];
_libssh2_random(buffer, LIBSSH2_X11_RANDOM_COOKIE_LEN / 2); if(_libssh2_random(buffer, LIBSSH2_X11_RANDOM_COOKIE_LEN / 2)) {
return _libssh2_error(session, LIBSSH2_ERROR_RANDGEN,
"Unable to get random bytes "
"for x11-req cookie");
}
for(i = 0; i < (LIBSSH2_X11_RANDOM_COOKIE_LEN / 2); i++) { for(i = 0; i < (LIBSSH2_X11_RANDOM_COOKIE_LEN / 2); i++) {
snprintf((char *)&s[i*2], 3, "%02X", buffer[i]); snprintf((char *)&s[i*2], 3, "%02X", buffer[i]);
} }

Просмотреть файл

@ -3176,7 +3176,11 @@ static int kexinit(LIBSSH2_SESSION * session)
*(s++) = SSH_MSG_KEXINIT; *(s++) = SSH_MSG_KEXINIT;
_libssh2_random(s, 16); if(_libssh2_random(s, 16)) {
return _libssh2_error(session, LIBSSH2_ERROR_RANDGEN,
"Unable to get random bytes "
"for KEXINIT cookie");
}
s += 16; s += 16;
/* Ennumerating through these lists twice is probably (certainly?) /* Ennumerating through these lists twice is probably (certainly?)

Просмотреть файл

@ -68,7 +68,7 @@
#define EC_MAX_POINT_LEN ((528 * 2 / 8) + 1) #define EC_MAX_POINT_LEN ((528 * 2 / 8) + 1)
#define _libssh2_random(buf, len) \ #define _libssh2_random(buf, len) \
(gcry_randomize ((buf), (len), GCRY_STRONG_RANDOM), 1) (gcry_randomize ((buf), (len), GCRY_STRONG_RANDOM), 0)
#define libssh2_prepare_iovec(vec, len) /* Empty. */ #define libssh2_prepare_iovec(vec, len) /* Empty. */

Просмотреть файл

@ -137,7 +137,7 @@
#define EC_MAX_POINT_LEN ((528 * 2 / 8) + 1) #define EC_MAX_POINT_LEN ((528 * 2 / 8) + 1)
#define _libssh2_random(buf, len) RAND_bytes ((buf), (len)) #define _libssh2_random(buf, len) (RAND_bytes((buf), (len)) == 1 ? 0 : -1)
#define libssh2_prepare_iovec(vec, len) /* Empty. */ #define libssh2_prepare_iovec(vec, len) /* Empty. */

Просмотреть файл

@ -884,11 +884,14 @@ _libssh2_bn_from_bn(_libssh2_bn *to, _libssh2_bn *from)
return 0; return 0;
} }
void int
_libssh2_random(unsigned char *buf, int len) _libssh2_random(unsigned char *buf, int len)
{ {
Qc3GenPRNs(buf, len, Qc3GenPRNs(buf, len,
Qc3PRN_TYPE_NORMAL, Qc3PRN_NO_PARITY, (char *) &ecnull); Qc3PRN_TYPE_NORMAL, Qc3PRN_NO_PARITY, (char *) &ecnull);
/* FIXME: any error is silently discarded! But Qc3GenPRNs could fail,
including if "The system seed digest is not ready" dixit IBM doc. */
return 0;
} }

Просмотреть файл

@ -360,7 +360,7 @@ extern int _libssh2_bn_from_bin(_libssh2_bn *bn, int len,
const unsigned char *v); const unsigned char *v);
extern int _libssh2_bn_set_word(_libssh2_bn *bn, unsigned long val); extern int _libssh2_bn_set_word(_libssh2_bn *bn, unsigned long val);
extern int _libssh2_bn_to_bin(_libssh2_bn *bn, unsigned char *val); extern int _libssh2_bn_to_bin(_libssh2_bn *bn, unsigned char *val);
extern void _libssh2_random(unsigned char *buf, int len); extern int _libssh2_random(unsigned char *buf, int len);
extern void _libssh2_os400qc3_crypto_dtor(_libssh2_os400qc3_crypto_ctx *x); extern void _libssh2_os400qc3_crypto_dtor(_libssh2_os400qc3_crypto_ctx *x);
extern int libssh2_os400qc3_hash_init(Qc3_Format_ALGD0100_T *x, extern int libssh2_os400qc3_hash_init(Qc3_Format_ALGD0100_T *x,
unsigned int algo); unsigned int algo);

Просмотреть файл

@ -862,7 +862,10 @@ int _libssh2_transport_send(LIBSSH2_SESSION *session,
p->outbuf[4] = (unsigned char)padding_length; p->outbuf[4] = (unsigned char)padding_length;
/* fill the padding area with random junk */ /* fill the padding area with random junk */
_libssh2_random(p->outbuf + 5 + data_len, padding_length); if(_libssh2_random(p->outbuf + 5 + data_len, padding_length)) {
return _libssh2_error(session, LIBSSH2_ERROR_RANDGEN,
"Unable to get random bytes for packet padding");
}
if(encrypted) { if(encrypted) {
size_t i; size_t i;