Fix Edge Cases in Password Callback Handling

Fixes #8441: Modify the password callback handling to reserve one byte in the buffer for a null terminator, ensuring compatibility with legacy behavior that puts a terminating null byte at the end.

Additionally, validate the length returned by the callback to ensure it does not exceed the given buffer size. If the returned length is too large, the process now stops gracefully with an appropriate error, enhancing robustness by preventing crashes from out-of-bounds access.

Reviewed-by: Dmitry Belyavskiy <beldmit@gmail.com>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/25330)
This commit is contained in:
erbsland-dev 2024-08-30 10:56:58 +02:00 committed by Tomas Mraz
parent fa6ae88a47
commit 5387b71acb
2 changed files with 10 additions and 6 deletions

View File

@ -173,7 +173,7 @@ EVP_PKEY *d2i_PKCS8PrivateKey_bio(BIO *bp, EVP_PKEY **x, pem_password_cb *cb,
X509_SIG *p8 = NULL; X509_SIG *p8 = NULL;
int klen; int klen;
EVP_PKEY *ret; EVP_PKEY *ret;
char psbuf[PEM_BUFSIZE]; char psbuf[PEM_BUFSIZE + 1]; /* reserve one byte at the end */
p8 = d2i_PKCS8_bio(bp, NULL); p8 = d2i_PKCS8_bio(bp, NULL);
if (p8 == NULL) if (p8 == NULL)
@ -182,7 +182,7 @@ EVP_PKEY *d2i_PKCS8PrivateKey_bio(BIO *bp, EVP_PKEY **x, pem_password_cb *cb,
klen = cb(psbuf, PEM_BUFSIZE, 0, u); klen = cb(psbuf, PEM_BUFSIZE, 0, u);
else else
klen = PEM_def_callback(psbuf, PEM_BUFSIZE, 0, u); klen = PEM_def_callback(psbuf, PEM_BUFSIZE, 0, u);
if (klen < 0) { if (klen < 0 || klen > PEM_BUFSIZE) {
ERR_raise(ERR_LIB_PEM, PEM_R_BAD_PASSWORD_READ); ERR_raise(ERR_LIB_PEM, PEM_R_BAD_PASSWORD_READ);
X509_SIG_free(p8); X509_SIG_free(p8);
return NULL; return NULL;

View File

@ -105,14 +105,18 @@ static int ui_read(UI *ui, UI_STRING *uis)
switch (UI_get_string_type(uis)) { switch (UI_get_string_type(uis)) {
case UIT_PROMPT: case UIT_PROMPT:
{ {
char result[PEM_BUFSIZE + 1]; int len;
char result[PEM_BUFSIZE + 1]; /* reserve one byte at the end */
const struct pem_password_cb_data *data = const struct pem_password_cb_data *data =
UI_method_get_ex_data(UI_get_method(ui), ui_method_data_index); UI_method_get_ex_data(UI_get_method(ui), ui_method_data_index);
int maxsize = UI_get_result_maxsize(uis); int maxsize = UI_get_result_maxsize(uis);
int len = data->cb(result,
maxsize > PEM_BUFSIZE ? PEM_BUFSIZE : maxsize,
data->rwflag, UI_get0_user_data(ui));
if (maxsize > PEM_BUFSIZE)
maxsize = PEM_BUFSIZE;
len = data->cb(result, maxsize, data->rwflag,
UI_get0_user_data(ui));
if (len > maxsize)
return -1;
if (len >= 0) if (len >= 0)
result[len] = '\0'; result[len] = '\0';
if (len < 0) if (len < 0)